Add Go frontend, libgo library, and Go testsuite.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 3 Dec 2010 04:34:57 +0000 (04:34 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 3 Dec 2010 04:34:57 +0000 (04:34 +0000)
gcc/:
* gcc.c (default_compilers): Add entry for ".go".
* common.opt: Add -static-libgo as a driver option.
* doc/install.texi (Configuration): Mention libgo as an option for
--enable-shared.  Mention go as an option for --enable-languages.
* doc/invoke.texi (Overall Options): Mention .go as a file name
suffix.  Mention go as a -x option.
* doc/frontends.texi (G++ and GCC): Mention Go as a supported
language.
* doc/sourcebuild.texi (Top Level): Mention libgo.
* doc/standards.texi (Standards): Add section on Go language.
Move references for other languages into their own section.
* doc/contrib.texi (Contributors): Mention that I contributed the
Go frontend.
gcc/testsuite/:
* lib/go.exp: New file.
* lib/go-dg.exp: New file.
* lib/go-torture.exp: New file.
* lib/target-supports.exp (check_compile): Match // Go.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167407 138bc75d-0d04-0410-961f-82ee72b054a4

1565 files changed:
gcc/ChangeLog
gcc/common.opt
gcc/doc/contrib.texi
gcc/doc/frontends.texi
gcc/doc/install.texi
gcc/doc/invoke.texi
gcc/doc/sourcebuild.texi
gcc/doc/standards.texi
gcc/gcc.c
gcc/go/Make-lang.in [new file with mode: 0644]
gcc/go/README.gcc [new file with mode: 0644]
gcc/go/config-lang.in [new file with mode: 0644]
gcc/go/gccgo.texi [new file with mode: 0644]
gcc/go/go-c.h [new file with mode: 0644]
gcc/go/go-lang.c [new file with mode: 0644]
gcc/go/go-system.h [new file with mode: 0644]
gcc/go/gofrontend/LICENSE [new file with mode: 0644]
gcc/go/gofrontend/README [new file with mode: 0644]
gcc/go/gofrontend/dataflow.cc [new file with mode: 0644]
gcc/go/gofrontend/dataflow.h [new file with mode: 0644]
gcc/go/gofrontend/export.cc [new file with mode: 0644]
gcc/go/gofrontend/export.h [new file with mode: 0644]
gcc/go/gofrontend/expressions.cc [new file with mode: 0644]
gcc/go/gofrontend/expressions.h [new file with mode: 0644]
gcc/go/gofrontend/go-dump.cc [new file with mode: 0644]
gcc/go/gofrontend/go-dump.h [new file with mode: 0644]
gcc/go/gofrontend/go.cc [new file with mode: 0644]
gcc/go/gofrontend/gogo-tree.cc [new file with mode: 0644]
gcc/go/gofrontend/gogo.cc [new file with mode: 0644]
gcc/go/gofrontend/gogo.h [new file with mode: 0644]
gcc/go/gofrontend/import-archive.cc [new file with mode: 0644]
gcc/go/gofrontend/import.cc [new file with mode: 0644]
gcc/go/gofrontend/import.h [new file with mode: 0644]
gcc/go/gofrontend/lex.cc [new file with mode: 0644]
gcc/go/gofrontend/lex.h [new file with mode: 0644]
gcc/go/gofrontend/operator.h [new file with mode: 0644]
gcc/go/gofrontend/parse.cc [new file with mode: 0644]
gcc/go/gofrontend/parse.h [new file with mode: 0644]
gcc/go/gofrontend/statements.cc [new file with mode: 0644]
gcc/go/gofrontend/statements.h [new file with mode: 0644]
gcc/go/gofrontend/types.cc [new file with mode: 0644]
gcc/go/gofrontend/types.h [new file with mode: 0644]
gcc/go/gofrontend/unsafe.cc [new file with mode: 0644]
gcc/go/gospec.c [new file with mode: 0644]
gcc/go/lang-specs.h [new file with mode: 0644]
gcc/go/lang.opt [new file with mode: 0644]
gcc/testsuite/ChangeLog
gcc/testsuite/go.dg/dg.exp [new file with mode: 0644]
gcc/testsuite/go.dg/err-1.go [new file with mode: 0644]
gcc/testsuite/go.dg/goto-1.go [new file with mode: 0644]
gcc/testsuite/go.dg/undef-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/array-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/array-2.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/chan-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/const-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/const-2.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/execute.exp [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/expr-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/for-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/for-2.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/function-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/function-2.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/go-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/go-2.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/go-3.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/goto-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/map-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/method-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/nested-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/pointer-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/return-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/return-2.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/return-3.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/select-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/string-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/string-2.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/struct-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/struct-2.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/switch-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/var-1.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/var-2.go [new file with mode: 0644]
gcc/testsuite/go.go-torture/execute/var-3.go [new file with mode: 0644]
gcc/testsuite/go.test/go-test.exp [new file with mode: 0644]
gcc/testsuite/go.test/test/235.go [new file with mode: 0644]
gcc/testsuite/go.test/test/64bit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/README.gcc [new file with mode: 0644]
gcc/testsuite/go.test/test/args.go [new file with mode: 0644]
gcc/testsuite/go.test/test/arm-pass.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/assign.go [new file with mode: 0644]
gcc/testsuite/go.test/test/assign1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/binary-tree-freelist.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/binary-tree-freelist.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/binary-tree.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/binary-tree.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/binary-tree.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/chameneosredux.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/chameneosredux.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/chameneosredux.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/clean.bash [new file with mode: 0755]
gcc/testsuite/go.test/test/bench/fannkuch-parallel.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/fannkuch-parallel.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/fannkuch.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/fannkuch.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/fannkuch.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/fasta-1000.out [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/fasta.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/fasta.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/fasta.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/k-nucleotide-parallel.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/k-nucleotide-parallel.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/k-nucleotide.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/k-nucleotide.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/k-nucleotide.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/mandelbrot.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/mandelbrot.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/mandelbrot.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/meteor-contest.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/meteor-contest.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/meteor-contest.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/nbody.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/nbody.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/nbody.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/pidigits.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/pidigits.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/pidigits.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/regex-dna-parallel.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/regex-dna-parallel.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/regex-dna.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/regex-dna.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/regex-dna.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/reverse-complement.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/reverse-complement.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/reverse-complement.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/spectral-norm-parallel.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/spectral-norm.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/spectral-norm.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/spectral-norm.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/threadring.c [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/threadring.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/threadring.txt [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/timing.log [new file with mode: 0644]
gcc/testsuite/go.test/test/bench/timing.sh [new file with mode: 0755]
gcc/testsuite/go.test/test/bigalg.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bigmap.go [new file with mode: 0644]
gcc/testsuite/go.test/test/blank.go [new file with mode: 0644]
gcc/testsuite/go.test/test/blank1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bugs/bug260.go [new file with mode: 0644]
gcc/testsuite/go.test/test/bugs/placeholder [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/doubleselect.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/fifo.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/goroutines.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/nonblock.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/perm.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/powser1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/powser2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/select.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/select2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/select3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/sieve1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chan/sieve2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/chancap.go [new file with mode: 0644]
gcc/testsuite/go.test/test/char_lit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/char_lit1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/closedchan.go [new file with mode: 0644]
gcc/testsuite/go.test/test/closure.go [new file with mode: 0644]
gcc/testsuite/go.test/test/cmp1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/cmp2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/cmp3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/cmp4.go [new file with mode: 0644]
gcc/testsuite/go.test/test/cmp5.go [new file with mode: 0644]
gcc/testsuite/go.test/test/cmplx.go [new file with mode: 0644]
gcc/testsuite/go.test/test/cmplxdivide.c [new file with mode: 0644]
gcc/testsuite/go.test/test/cmplxdivide.go [new file with mode: 0644]
gcc/testsuite/go.test/test/cmplxdivide1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/complit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/compos.go [new file with mode: 0644]
gcc/testsuite/go.test/test/const.go [new file with mode: 0644]
gcc/testsuite/go.test/test/const1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/const2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/const3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/convert.go [new file with mode: 0644]
gcc/testsuite/go.test/test/convert3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/convlit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/convlit1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/copy.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ddd.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ddd1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ddd2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ddd3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/decl.go [new file with mode: 0644]
gcc/testsuite/go.test/test/declbad.go [new file with mode: 0644]
gcc/testsuite/go.test/test/defer.go [new file with mode: 0644]
gcc/testsuite/go.test/test/deferprint.go [new file with mode: 0644]
gcc/testsuite/go.test/test/empty.go [new file with mode: 0644]
gcc/testsuite/go.test/test/env.go [new file with mode: 0644]
gcc/testsuite/go.test/test/errchk [new file with mode: 0755]
gcc/testsuite/go.test/test/escape.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug000.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug001.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug002.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug003.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug004.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug005.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug006.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug007.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug008.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug009.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug010.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug011.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug012.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug013.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug014.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug015.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug016.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug017.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug020.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug021.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug022.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug023.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug024.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug026.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug027.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug028.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug030.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug031.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug035.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug036.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug037.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug038.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug039.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug040.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug045.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug046.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug047.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug048.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug049.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug050.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug051.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug052.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug053.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug054.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug055.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug056.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug057.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug058.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug059.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug060.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug061.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug062.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug063.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug064.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug065.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug066.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug067.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug068.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug069.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug070.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug071.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug072.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug073.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug074.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug075.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug076.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug077.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug078.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug080.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug081.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug082.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug083.dir/bug0.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug083.dir/bug1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug083.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug084.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug085.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug086.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug087.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug088.dir/bug0.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug088.dir/bug1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug088.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug089.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug090.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug091.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug092.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug093.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug094.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug096.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug097.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug098.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug099.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug101.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug102.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug103.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug104.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug106.dir/bug0.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug106.dir/bug1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug106.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug107.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug108.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug109.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug110.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug111.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug112.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug113.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug114.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug115.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug116.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug117.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug118.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug119.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug120.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug121.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug122.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug123.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug126.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug127.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug128.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug129.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug130.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug131.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug132.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug133.dir/bug0.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug133.dir/bug1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug133.dir/bug2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug133.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug135.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug136.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug137.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug139.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug140.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug141.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug142.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug143.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug144.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug145.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug146.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug147.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug148.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug149.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug150.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug151.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug152.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug154.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug155.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug156.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug157.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug158.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug159.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug160.dir/x.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug160.dir/y.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug160.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug161.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug163.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug164.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug165.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug167.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug168.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug169.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug170.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug171.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug172.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug173.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug174.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug175.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug176.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug177.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug178.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug179.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug180.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug181.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug182.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug183.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug184.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug185.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug186.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug187.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug188.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug189.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug190.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug191.dir/a.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug191.dir/b.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug191.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug192.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug193.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug194.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug195.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug196.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug197.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug198.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug199.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug200.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug201.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug202.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug203.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug204.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug205.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug206.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug207.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug208.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug209.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug211.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug212.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug213.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug214.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug215.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug216.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug217.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug218.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug219.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug220.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug221.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug222.dir/chanbug.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug222.dir/chanbug2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug222.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug223.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug224.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug225.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug226.dir/x.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug226.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug227.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug228.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug229.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug230.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug231.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug232.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug233.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug234.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug235.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug236.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug237.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug238.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug239.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug240.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug241.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug242.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug243.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug244.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug245.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug246.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug247.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug0.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug248.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug249.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug250.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug251.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug252.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug253.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug254.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug255.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug256.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug257.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug258.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug259.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug261.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug262.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug263.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug264.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug265.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug266.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug267.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug268.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug269.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug270.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug271.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug272.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug273.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug274.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug275.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug276.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug277.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug278.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug279.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug280.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug281.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug282.dir/p1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug282.dir/p2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug282.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug283.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug284.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug285.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug286.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug287.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug288.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug289.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug290.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug291.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug292.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug293.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug294.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug295.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug296.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug297.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug298.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug299.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug300.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug301.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug302.dir/main.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug302.dir/p.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug302.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug303.go [new file with mode: 0644]
gcc/testsuite/go.test/test/fixedbugs/bug304.go [new file with mode: 0644]
gcc/testsuite/go.test/test/float_lit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/floatcmp.go [new file with mode: 0644]
gcc/testsuite/go.test/test/for.go [new file with mode: 0644]
gcc/testsuite/go.test/test/func.go [new file with mode: 0644]
gcc/testsuite/go.test/test/func1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/func2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/func3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/func4.go [new file with mode: 0644]
gcc/testsuite/go.test/test/func5.go [new file with mode: 0644]
gcc/testsuite/go.test/test/garbage/Makefile [new file with mode: 0644]
gcc/testsuite/go.test/test/garbage/parser.go [new file with mode: 0644]
gcc/testsuite/go.test/test/garbage/peano.go [new file with mode: 0644]
gcc/testsuite/go.test/test/garbage/tree.go [new file with mode: 0644]
gcc/testsuite/go.test/test/gc.go [new file with mode: 0644]
gcc/testsuite/go.test/test/gc1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/golden-arm.out [new file with mode: 0644]
gcc/testsuite/go.test/test/golden.out [new file with mode: 0644]
gcc/testsuite/go.test/test/hashmap.go [new file with mode: 0755]
gcc/testsuite/go.test/test/helloworld.go [new file with mode: 0644]
gcc/testsuite/go.test/test/if.go [new file with mode: 0644]
gcc/testsuite/go.test/test/if1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/import.go [new file with mode: 0644]
gcc/testsuite/go.test/test/import1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/import2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/import3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/import4.go [new file with mode: 0644]
gcc/testsuite/go.test/test/index.go [new file with mode: 0644]
gcc/testsuite/go.test/test/indirect.go [new file with mode: 0644]
gcc/testsuite/go.test/test/indirect1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/initcomma.go [new file with mode: 0644]
gcc/testsuite/go.test/test/initialize.go [new file with mode: 0644]
gcc/testsuite/go.test/test/initializerr.go [new file with mode: 0644]
gcc/testsuite/go.test/test/initsyscall.go [new file with mode: 0644]
gcc/testsuite/go.test/test/int_lit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/intcvt.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/bigdata.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/convert.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/convert1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/convert2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/embed.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/embed0.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/embed1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/explicit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/fail.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/fake.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/pointer.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/receiver.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/receiver1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/recursive.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/returntype.go [new file with mode: 0644]
gcc/testsuite/go.test/test/interface/struct.go [new file with mode: 0644]
gcc/testsuite/go.test/test/iota.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/array.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/chan.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/chan1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/complit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/cplx0.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/cplx1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/cplx2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/cplx3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/cplx4.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/cplx5.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/divconst.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/divmod.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/embed.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/for.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/interbasic.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/interfun.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/intervar.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/label.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/litfun.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/mfunc.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/modconst.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/ptrfun.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/ptrvar.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/range.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/rob1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/rob2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/robfor.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/robfunc.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/robif.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/shift.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/simparray.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/simpbool.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/simpconv.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/simpfun.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/simpprint.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/simpswitch.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/simpvar.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/slicearray.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/sliceslice.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/string.go [new file with mode: 0644]
gcc/testsuite/go.test/test/ken/strvar.go [new file with mode: 0644]
gcc/testsuite/go.test/test/literal.go [new file with mode: 0644]
gcc/testsuite/go.test/test/malloc1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/mallocfin.go [new file with mode: 0644]
gcc/testsuite/go.test/test/mallocrand.go [new file with mode: 0644]
gcc/testsuite/go.test/test/mallocrep.go [new file with mode: 0644]
gcc/testsuite/go.test/test/mallocrep1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/map.go [new file with mode: 0644]
gcc/testsuite/go.test/test/method.go [new file with mode: 0644]
gcc/testsuite/go.test/test/method1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/method2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/method3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/named.go [new file with mode: 0644]
gcc/testsuite/go.test/test/named1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nil.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/arrayindex.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/arrayindex1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/arraytoslice.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/arraytoslice1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/arraytoslice2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/slicearray.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/structfield.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/structfield1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/structfield2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nilptr/structfieldaddr.go [new file with mode: 0644]
gcc/testsuite/go.test/test/nul1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/parentype.go [new file with mode: 0644]
gcc/testsuite/go.test/test/peano.go [new file with mode: 0644]
gcc/testsuite/go.test/test/printbig.go [new file with mode: 0644]
gcc/testsuite/go.test/test/range.go [new file with mode: 0644]
gcc/testsuite/go.test/test/recover.go [new file with mode: 0644]
gcc/testsuite/go.test/test/recover1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/recover2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/recover3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/rename.go [new file with mode: 0644]
gcc/testsuite/go.test/test/rename1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/run [new file with mode: 0755]
gcc/testsuite/go.test/test/run-arm [new file with mode: 0755]
gcc/testsuite/go.test/test/runtime.go [new file with mode: 0644]
gcc/testsuite/go.test/test/sieve.go [new file with mode: 0644]
gcc/testsuite/go.test/test/sigchld.go [new file with mode: 0644]
gcc/testsuite/go.test/test/simassign.go [new file with mode: 0644]
gcc/testsuite/go.test/test/sinit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/solitaire.go [new file with mode: 0644]
gcc/testsuite/go.test/test/stack.go [new file with mode: 0644]
gcc/testsuite/go.test/test/string_lit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/stringrange.go [new file with mode: 0644]
gcc/testsuite/go.test/test/switch.go [new file with mode: 0644]
gcc/testsuite/go.test/test/switch1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/forvar.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/import.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/interface.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/semi1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/semi2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/semi3.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/semi4.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/semi5.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/semi6.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/semi7.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/topexpr.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/vareq.go [new file with mode: 0644]
gcc/testsuite/go.test/test/syntax/vareq1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/test0.go [new file with mode: 0644]
gcc/testsuite/go.test/test/turing.go [new file with mode: 0644]
gcc/testsuite/go.test/test/typeswitch.go [new file with mode: 0644]
gcc/testsuite/go.test/test/typeswitch1.go [new file with mode: 0644]
gcc/testsuite/go.test/test/typeswitch2.go [new file with mode: 0644]
gcc/testsuite/go.test/test/undef.go [new file with mode: 0644]
gcc/testsuite/go.test/test/utf.go [new file with mode: 0644]
gcc/testsuite/go.test/test/varerr.go [new file with mode: 0644]
gcc/testsuite/go.test/test/varinit.go [new file with mode: 0644]
gcc/testsuite/go.test/test/vectors.go [new file with mode: 0644]
gcc/testsuite/go.test/test/zerodivide.go [new file with mode: 0644]
gcc/testsuite/lib/go-dg.exp [new file with mode: 0644]
gcc/testsuite/lib/go-torture.exp [new file with mode: 0644]
gcc/testsuite/lib/go.exp [new file with mode: 0644]
gcc/testsuite/lib/target-supports.exp
libgo/LICENSE [new file with mode: 0644]
libgo/MERGE [new file with mode: 0644]
libgo/Makefile.am [new file with mode: 0644]
libgo/Makefile.in [new file with mode: 0644]
libgo/README [new file with mode: 0644]
libgo/README.gcc [new file with mode: 0644]
libgo/aclocal.m4 [new file with mode: 0644]
libgo/config.h.in [new file with mode: 0644]
libgo/config/README [new file with mode: 0644]
libgo/config/go.m4 [new file with mode: 0644]
libgo/config/libtool.m4 [new file with mode: 0644]
libgo/config/ltmain.sh [new file with mode: 0644]
libgo/config/ltoptions.m4 [new file with mode: 0644]
libgo/config/ltsugar.m4 [new file with mode: 0644]
libgo/config/ltversion.m4 [new file with mode: 0644]
libgo/config/lt~obsolete.m4 [new file with mode: 0644]
libgo/configure [new file with mode: 0644]
libgo/configure.ac [new file with mode: 0644]
libgo/go/archive/tar/common.go [new file with mode: 0644]
libgo/go/archive/tar/reader.go [new file with mode: 0644]
libgo/go/archive/tar/reader_test.go [new file with mode: 0644]
libgo/go/archive/tar/testdata/gnu.tar [new file with mode: 0644]
libgo/go/archive/tar/testdata/small.txt [new file with mode: 0644]
libgo/go/archive/tar/testdata/small2.txt [new file with mode: 0644]
libgo/go/archive/tar/testdata/star.tar [new file with mode: 0644]
libgo/go/archive/tar/testdata/v7.tar [new file with mode: 0644]
libgo/go/archive/tar/testdata/writer-big.tar [new file with mode: 0644]
libgo/go/archive/tar/testdata/writer.tar [new file with mode: 0644]
libgo/go/archive/tar/writer.go [new file with mode: 0644]
libgo/go/archive/tar/writer_test.go [new file with mode: 0644]
libgo/go/archive/zip/reader.go [new file with mode: 0644]
libgo/go/archive/zip/reader_test.go [new file with mode: 0644]
libgo/go/archive/zip/struct.go [new file with mode: 0644]
libgo/go/archive/zip/testdata/gophercolor16x16.png [new file with mode: 0644]
libgo/go/archive/zip/testdata/r.zip [new file with mode: 0644]
libgo/go/archive/zip/testdata/readme.notzip [new file with mode: 0644]
libgo/go/archive/zip/testdata/readme.zip [new file with mode: 0644]
libgo/go/archive/zip/testdata/test.zip [new file with mode: 0644]
libgo/go/asn1/asn1.go [new file with mode: 0644]
libgo/go/asn1/asn1_test.go [new file with mode: 0644]
libgo/go/asn1/common.go [new file with mode: 0644]
libgo/go/asn1/marshal.go [new file with mode: 0644]
libgo/go/asn1/marshal_test.go [new file with mode: 0644]
libgo/go/big/arith.go [new file with mode: 0644]
libgo/go/big/arith_decl.go [new file with mode: 0644]
libgo/go/big/arith_test.go [new file with mode: 0644]
libgo/go/big/calibrate_test.go [new file with mode: 0644]
libgo/go/big/hilbert_test.go [new file with mode: 0644]
libgo/go/big/int.go [new file with mode: 0644]
libgo/go/big/int_test.go [new file with mode: 0644]
libgo/go/big/nat.go [new file with mode: 0644]
libgo/go/big/nat_test.go [new file with mode: 0644]
libgo/go/big/rat.go [new file with mode: 0644]
libgo/go/big/rat_test.go [new file with mode: 0644]
libgo/go/bufio/bufio.go [new file with mode: 0644]
libgo/go/bufio/bufio_test.go [new file with mode: 0644]
libgo/go/bytes/buffer.go [new file with mode: 0644]
libgo/go/bytes/buffer_test.go [new file with mode: 0644]
libgo/go/bytes/bytes.go [new file with mode: 0644]
libgo/go/bytes/bytes_decl.go [new file with mode: 0644]
libgo/go/bytes/bytes_test.go [new file with mode: 0644]
libgo/go/bytes/export_test.go [new file with mode: 0644]
libgo/go/bytes/indexbyte.c [new file with mode: 0644]
libgo/go/cmath/abs.go [new file with mode: 0644]
libgo/go/cmath/asin.go [new file with mode: 0644]
libgo/go/cmath/cmath_test.go [new file with mode: 0644]
libgo/go/cmath/conj.go [new file with mode: 0644]
libgo/go/cmath/exp.go [new file with mode: 0644]
libgo/go/cmath/isinf.go [new file with mode: 0644]
libgo/go/cmath/isnan.go [new file with mode: 0644]
libgo/go/cmath/log.go [new file with mode: 0644]
libgo/go/cmath/phase.go [new file with mode: 0644]
libgo/go/cmath/polar.go [new file with mode: 0644]
libgo/go/cmath/pow.go [new file with mode: 0644]
libgo/go/cmath/rect.go [new file with mode: 0644]
libgo/go/cmath/sin.go [new file with mode: 0644]
libgo/go/cmath/sqrt.go [new file with mode: 0644]
libgo/go/cmath/tan.go [new file with mode: 0644]
libgo/go/compress/flate/deflate.go [new file with mode: 0644]
libgo/go/compress/flate/deflate_test.go [new file with mode: 0644]
libgo/go/compress/flate/flate_test.go [new file with mode: 0644]
libgo/go/compress/flate/huffman_bit_writer.go [new file with mode: 0644]
libgo/go/compress/flate/huffman_code.go [new file with mode: 0644]
libgo/go/compress/flate/inflate.go [new file with mode: 0644]
libgo/go/compress/flate/reverse_bits.go [new file with mode: 0644]
libgo/go/compress/flate/token.go [new file with mode: 0644]
libgo/go/compress/flate/util.go [new file with mode: 0644]
libgo/go/compress/gzip/gunzip.go [new file with mode: 0644]
libgo/go/compress/gzip/gunzip_test.go [new file with mode: 0644]
libgo/go/compress/gzip/gzip.go [new file with mode: 0644]
libgo/go/compress/gzip/gzip_test.go [new file with mode: 0644]
libgo/go/compress/zlib/reader.go [new file with mode: 0644]
libgo/go/compress/zlib/reader_test.go [new file with mode: 0644]
libgo/go/compress/zlib/testdata/e.txt [new file with mode: 0644]
libgo/go/compress/zlib/testdata/pi.txt [new file with mode: 0644]
libgo/go/compress/zlib/writer.go [new file with mode: 0644]
libgo/go/compress/zlib/writer_test.go [new file with mode: 0644]
libgo/go/container/heap/heap.go [new file with mode: 0644]
libgo/go/container/heap/heap_test.go [new file with mode: 0644]
libgo/go/container/list/list.go [new file with mode: 0755]
libgo/go/container/list/list_test.go [new file with mode: 0755]
libgo/go/container/ring/ring.go [new file with mode: 0644]
libgo/go/container/ring/ring_test.go [new file with mode: 0644]
libgo/go/container/vector/defs.go [new file with mode: 0644]
libgo/go/container/vector/intvector.go [new file with mode: 0644]
libgo/go/container/vector/intvector_test.go [new file with mode: 0644]
libgo/go/container/vector/nogen_test.go [new file with mode: 0644]
libgo/go/container/vector/numbers_test.go [new file with mode: 0644]
libgo/go/container/vector/stringvector.go [new file with mode: 0644]
libgo/go/container/vector/stringvector_test.go [new file with mode: 0644]
libgo/go/container/vector/vector.go [new file with mode: 0644]
libgo/go/container/vector/vector_test.go [new file with mode: 0644]
libgo/go/crypto/aes/aes_test.go [new file with mode: 0644]
libgo/go/crypto/aes/block.go [new file with mode: 0644]
libgo/go/crypto/aes/cipher.go [new file with mode: 0644]
libgo/go/crypto/aes/const.go [new file with mode: 0644]
libgo/go/crypto/block/cbc.go [new file with mode: 0644]
libgo/go/crypto/block/cbc_aes_test.go [new file with mode: 0644]
libgo/go/crypto/block/cfb.go [new file with mode: 0644]
libgo/go/crypto/block/cfb_aes_test.go [new file with mode: 0644]
libgo/go/crypto/block/cipher.go [new file with mode: 0644]
libgo/go/crypto/block/cmac.go [new file with mode: 0644]
libgo/go/crypto/block/cmac_aes_test.go [new file with mode: 0644]
libgo/go/crypto/block/ctr.go [new file with mode: 0644]
libgo/go/crypto/block/ctr_aes_test.go [new file with mode: 0644]
libgo/go/crypto/block/eax.go [new file with mode: 0644]
libgo/go/crypto/block/eax_aes_test.go [new file with mode: 0644]
libgo/go/crypto/block/ecb.go [new file with mode: 0644]
libgo/go/crypto/block/ecb_aes_test.go [new file with mode: 0644]
libgo/go/crypto/block/ecb_test.go [new file with mode: 0644]
libgo/go/crypto/block/ofb.go [new file with mode: 0644]
libgo/go/crypto/block/ofb_aes_test.go [new file with mode: 0644]
libgo/go/crypto/block/xor.go [new file with mode: 0644]
libgo/go/crypto/block/xor_test.go [new file with mode: 0644]
libgo/go/crypto/blowfish/block.go [new file with mode: 0644]
libgo/go/crypto/blowfish/blowfish_test.go [new file with mode: 0644]
libgo/go/crypto/blowfish/cipher.go [new file with mode: 0644]
libgo/go/crypto/blowfish/const.go [new file with mode: 0644]
libgo/go/crypto/cast5/cast5.go [new file with mode: 0644]
libgo/go/crypto/cast5/cast5_test.go [new file with mode: 0644]
libgo/go/crypto/hmac/hmac.go [new file with mode: 0644]
libgo/go/crypto/hmac/hmac_test.go [new file with mode: 0644]
libgo/go/crypto/md4/md4.go [new file with mode: 0644]
libgo/go/crypto/md4/md4_test.go [new file with mode: 0644]
libgo/go/crypto/md4/md4block.go [new file with mode: 0644]
libgo/go/crypto/md5/md5.go [new file with mode: 0644]
libgo/go/crypto/md5/md5_test.go [new file with mode: 0644]
libgo/go/crypto/md5/md5block.go [new file with mode: 0644]
libgo/go/crypto/ocsp/ocsp.go [new file with mode: 0644]
libgo/go/crypto/ocsp/ocsp_test.go [new file with mode: 0644]
libgo/go/crypto/rand/rand.go [new file with mode: 0644]
libgo/go/crypto/rand/rand_test.go [new file with mode: 0644]
libgo/go/crypto/rand/rand_unix.go [new file with mode: 0644]
libgo/go/crypto/rand/rand_windows.go [new file with mode: 0644]
libgo/go/crypto/rc4/rc4.go [new file with mode: 0644]
libgo/go/crypto/rc4/rc4_test.go [new file with mode: 0644]
libgo/go/crypto/ripemd160/ripemd160.go [new file with mode: 0644]
libgo/go/crypto/ripemd160/ripemd160_test.go [new file with mode: 0644]
libgo/go/crypto/ripemd160/ripemd160block.go [new file with mode: 0644]
libgo/go/crypto/rsa/pkcs1v15.go [new file with mode: 0644]
libgo/go/crypto/rsa/pkcs1v15_test.go [new file with mode: 0644]
libgo/go/crypto/rsa/rsa.go [new file with mode: 0644]
libgo/go/crypto/rsa/rsa_test.go [new file with mode: 0644]
libgo/go/crypto/sha1/sha1.go [new file with mode: 0644]
libgo/go/crypto/sha1/sha1_test.go [new file with mode: 0644]
libgo/go/crypto/sha1/sha1block.go [new file with mode: 0644]
libgo/go/crypto/sha256/sha256.go [new file with mode: 0644]
libgo/go/crypto/sha256/sha256_test.go [new file with mode: 0644]
libgo/go/crypto/sha256/sha256block.go [new file with mode: 0644]
libgo/go/crypto/sha512/sha512.go [new file with mode: 0644]
libgo/go/crypto/sha512/sha512_test.go [new file with mode: 0644]
libgo/go/crypto/sha512/sha512block.go [new file with mode: 0644]
libgo/go/crypto/subtle/constant_time.go [new file with mode: 0644]
libgo/go/crypto/subtle/constant_time_test.go [new file with mode: 0644]
libgo/go/crypto/tls/alert.go [new file with mode: 0644]
libgo/go/crypto/tls/ca_set.go [new file with mode: 0644]
libgo/go/crypto/tls/common.go [new file with mode: 0644]
libgo/go/crypto/tls/conn.go [new file with mode: 0644]
libgo/go/crypto/tls/generate_cert.go [new file with mode: 0644]
libgo/go/crypto/tls/handshake_client.go [new file with mode: 0644]
libgo/go/crypto/tls/handshake_messages.go [new file with mode: 0644]
libgo/go/crypto/tls/handshake_messages_test.go [new file with mode: 0644]
libgo/go/crypto/tls/handshake_server.go [new file with mode: 0644]
libgo/go/crypto/tls/handshake_server_test.go [new file with mode: 0644]
libgo/go/crypto/tls/prf.go [new file with mode: 0644]
libgo/go/crypto/tls/prf_test.go [new file with mode: 0644]
libgo/go/crypto/tls/tls.go [new file with mode: 0644]
libgo/go/crypto/x509/x509.go [new file with mode: 0644]
libgo/go/crypto/x509/x509_test.go [new file with mode: 0644]
libgo/go/crypto/xtea/block.go [new file with mode: 0644]
libgo/go/crypto/xtea/cipher.go [new file with mode: 0644]
libgo/go/crypto/xtea/xtea_test.go [new file with mode: 0644]
libgo/go/debug/dwarf/buf.go [new file with mode: 0644]
libgo/go/debug/dwarf/const.go [new file with mode: 0644]
libgo/go/debug/dwarf/entry.go [new file with mode: 0644]
libgo/go/debug/dwarf/open.go [new file with mode: 0644]
libgo/go/debug/dwarf/testdata/typedef.c [new file with mode: 0644]
libgo/go/debug/dwarf/testdata/typedef.elf [new file with mode: 0755]
libgo/go/debug/dwarf/testdata/typedef.macho [new file with mode: 0644]
libgo/go/debug/dwarf/type.go [new file with mode: 0644]
libgo/go/debug/dwarf/type_test.go [new file with mode: 0644]
libgo/go/debug/dwarf/unit.go [new file with mode: 0644]
libgo/go/debug/elf/elf.go [new file with mode: 0644]
libgo/go/debug/elf/elf_test.go [new file with mode: 0644]
libgo/go/debug/elf/file.go [new file with mode: 0644]
libgo/go/debug/elf/file_test.go [new file with mode: 0644]
libgo/go/debug/elf/testdata/gcc-386-freebsd-exec [new file with mode: 0755]
libgo/go/debug/elf/testdata/gcc-amd64-linux-exec [new file with mode: 0755]
libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o [new file with mode: 0644]
libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o [new file with mode: 0644]
libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o [new file with mode: 0644]
libgo/go/debug/gosym/pclinetest.h [new file with mode: 0644]
libgo/go/debug/gosym/pclinetest.s [new file with mode: 0644]
libgo/go/debug/gosym/pclntab.go [new file with mode: 0644]
libgo/go/debug/gosym/pclntab_test.go [new file with mode: 0644]
libgo/go/debug/gosym/symtab.go [new file with mode: 0644]
libgo/go/debug/macho/file.go [new file with mode: 0644]
libgo/go/debug/macho/file_test.go [new file with mode: 0644]
libgo/go/debug/macho/macho.go [new file with mode: 0644]
libgo/go/debug/macho/testdata/gcc-386-darwin-exec [new file with mode: 0755]
libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec [new file with mode: 0755]
libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec-debug [new file with mode: 0644]
libgo/go/debug/macho/testdata/hello.c [new file with mode: 0644]
libgo/go/debug/pe/file.go [new file with mode: 0644]
libgo/go/debug/pe/file_test.go [new file with mode: 0644]
libgo/go/debug/pe/pe.go [new file with mode: 0644]
libgo/go/debug/pe/testdata/gcc-386-mingw-exec [new file with mode: 0644]
libgo/go/debug/pe/testdata/gcc-386-mingw-obj [new file with mode: 0644]
libgo/go/debug/pe/testdata/hello.c [new file with mode: 0644]
libgo/go/debug/proc/proc.go [new file with mode: 0644]
libgo/go/debug/proc/proc_darwin.go [new file with mode: 0644]
libgo/go/debug/proc/proc_freebsd.go [new file with mode: 0644]
libgo/go/debug/proc/proc_linux.go [new file with mode: 0644]
libgo/go/debug/proc/proc_nacl.go [new file with mode: 0644]
libgo/go/debug/proc/proc_windows.go [new file with mode: 0644]
libgo/go/debug/proc/ptrace-nptl.txt [new file with mode: 0644]
libgo/go/debug/proc/regs_darwin_386.go [new file with mode: 0644]
libgo/go/debug/proc/regs_darwin_amd64.go [new file with mode: 0644]
libgo/go/debug/proc/regs_freebsd_386.go [new file with mode: 0644]
libgo/go/debug/proc/regs_freebsd_amd64.go [new file with mode: 0644]
libgo/go/debug/proc/regs_linux_386.go [new file with mode: 0644]
libgo/go/debug/proc/regs_linux_amd64.go [new file with mode: 0644]
libgo/go/debug/proc/regs_linux_arm.go [new file with mode: 0644]
libgo/go/debug/proc/regs_nacl_386.go [new file with mode: 0644]
libgo/go/debug/proc/regs_windows_386.go [new file with mode: 0644]
libgo/go/debug/proc/regs_windows_amd64.go [new file with mode: 0644]
libgo/go/ebnf/ebnf.go [new file with mode: 0644]
libgo/go/ebnf/ebnf_test.go [new file with mode: 0644]
libgo/go/ebnf/parser.go [new file with mode: 0644]
libgo/go/encoding/ascii85/ascii85.go [new file with mode: 0644]
libgo/go/encoding/ascii85/ascii85_test.go [new file with mode: 0644]
libgo/go/encoding/base64/base64.go [new file with mode: 0644]
libgo/go/encoding/base64/base64_test.go [new file with mode: 0644]
libgo/go/encoding/binary/binary.go [new file with mode: 0644]
libgo/go/encoding/binary/binary_test.go [new file with mode: 0644]
libgo/go/encoding/git85/git.go [new file with mode: 0644]
libgo/go/encoding/git85/git_test.go [new file with mode: 0644]
libgo/go/encoding/hex/hex.go [new file with mode: 0644]
libgo/go/encoding/hex/hex_test.go [new file with mode: 0644]
libgo/go/encoding/pem/pem.go [new file with mode: 0644]
libgo/go/encoding/pem/pem_test.go [new file with mode: 0644]
libgo/go/exec/exec.go [new file with mode: 0644]
libgo/go/exec/exec_test.go [new file with mode: 0644]
libgo/go/exec/lp_unix.go [new file with mode: 0644]
libgo/go/exec/lp_windows.go [new file with mode: 0644]
libgo/go/exp/4s/4s.go [new file with mode: 0644]
libgo/go/exp/4s/5s.go [new file with mode: 0644]
libgo/go/exp/4s/data.go [new file with mode: 0644]
libgo/go/exp/4s/xs.go [new file with mode: 0644]
libgo/go/exp/README [new file with mode: 0644]
libgo/go/exp/datafmt/datafmt.go [new file with mode: 0644]
libgo/go/exp/datafmt/datafmt_test.go [new file with mode: 0644]
libgo/go/exp/datafmt/parser.go [new file with mode: 0644]
libgo/go/exp/draw/draw.go [new file with mode: 0644]
libgo/go/exp/draw/draw_test.go [new file with mode: 0644]
libgo/go/exp/draw/event.go [new file with mode: 0644]
libgo/go/exp/draw/x11/auth.go [new file with mode: 0644]
libgo/go/exp/draw/x11/conn.go [new file with mode: 0644]
libgo/go/exp/eval/abort.go [new file with mode: 0644]
libgo/go/exp/eval/bridge.go [new file with mode: 0644]
libgo/go/exp/eval/compiler.go [new file with mode: 0644]
libgo/go/exp/eval/eval_test.go [new file with mode: 0644]
libgo/go/exp/eval/expr.go [new file with mode: 0644]
libgo/go/exp/eval/expr1.go [new file with mode: 0644]
libgo/go/exp/eval/expr_test.go [new file with mode: 0644]
libgo/go/exp/eval/func.go [new file with mode: 0644]
libgo/go/exp/eval/scope.go [new file with mode: 0644]
libgo/go/exp/eval/stmt.go [new file with mode: 0644]
libgo/go/exp/eval/stmt_test.go [new file with mode: 0644]
libgo/go/exp/eval/type.go [new file with mode: 0644]
libgo/go/exp/eval/typec.go [new file with mode: 0644]
libgo/go/exp/eval/value.go [new file with mode: 0644]
libgo/go/exp/eval/world.go [new file with mode: 0644]
libgo/go/exp/nacl/av/av.go [new file with mode: 0644]
libgo/go/exp/nacl/av/event.go [new file with mode: 0644]
libgo/go/exp/nacl/av/image.go [new file with mode: 0644]
libgo/go/exp/nacl/srpc/client.go [new file with mode: 0644]
libgo/go/exp/nacl/srpc/msg.go [new file with mode: 0644]
libgo/go/exp/nacl/srpc/server.go [new file with mode: 0644]
libgo/go/exp/ogle/abort.go [new file with mode: 0644]
libgo/go/exp/ogle/arch.go [new file with mode: 0644]
libgo/go/exp/ogle/cmd.go [new file with mode: 0644]
libgo/go/exp/ogle/event.go [new file with mode: 0644]
libgo/go/exp/ogle/frame.go [new file with mode: 0644]
libgo/go/exp/ogle/goroutine.go [new file with mode: 0644]
libgo/go/exp/ogle/main.go [new file with mode: 0644]
libgo/go/exp/ogle/process.go [new file with mode: 0644]
libgo/go/exp/ogle/rruntime.go [new file with mode: 0644]
libgo/go/exp/ogle/rtype.go [new file with mode: 0644]
libgo/go/exp/ogle/rvalue.go [new file with mode: 0644]
libgo/go/exp/ogle/vars.go [new file with mode: 0644]
libgo/go/exp/spacewar/code.go [new file with mode: 0644]
libgo/go/exp/spacewar/pdp1.go [new file with mode: 0644]
libgo/go/exp/spacewar/spacewar.go [new file with mode: 0644]
libgo/go/expvar/expvar.go [new file with mode: 0644]
libgo/go/expvar/expvar_test.go [new file with mode: 0644]
libgo/go/flag/flag.go [new file with mode: 0644]
libgo/go/flag/flag_test.go [new file with mode: 0644]
libgo/go/fmt/doc.go [new file with mode: 0644]
libgo/go/fmt/fmt_test.go [new file with mode: 0644]
libgo/go/fmt/format.go [new file with mode: 0644]
libgo/go/fmt/print.go [new file with mode: 0644]
libgo/go/fmt/scan.go [new file with mode: 0644]
libgo/go/fmt/scan_test.go [new file with mode: 0644]
libgo/go/fmt/stringer_test.go [new file with mode: 0644]
libgo/go/go/ast/ast.go [new file with mode: 0644]
libgo/go/go/ast/filter.go [new file with mode: 0644]
libgo/go/go/ast/print.go [new file with mode: 0644]
libgo/go/go/ast/scope.go [new file with mode: 0644]
libgo/go/go/ast/walk.go [new file with mode: 0644]
libgo/go/go/doc/comment.go [new file with mode: 0644]
libgo/go/go/doc/doc.go [new file with mode: 0644]
libgo/go/go/parser/interface.go [new file with mode: 0644]
libgo/go/go/parser/parser.go [new file with mode: 0644]
libgo/go/go/parser/parser_test.go [new file with mode: 0644]
libgo/go/go/printer/nodes.go [new file with mode: 0644]
libgo/go/go/printer/printer.go [new file with mode: 0644]
libgo/go/go/printer/printer_test.go [new file with mode: 0644]
libgo/go/go/printer/testdata/comments.golden [new file with mode: 0644]
libgo/go/go/printer/testdata/comments.input [new file with mode: 0644]
libgo/go/go/printer/testdata/comments.x [new file with mode: 0644]
libgo/go/go/printer/testdata/declarations.golden [new file with mode: 0644]
libgo/go/go/printer/testdata/declarations.input [new file with mode: 0644]
libgo/go/go/printer/testdata/empty.golden [new file with mode: 0644]
libgo/go/go/printer/testdata/empty.input [new file with mode: 0644]
libgo/go/go/printer/testdata/expressions.golden [new file with mode: 0644]
libgo/go/go/printer/testdata/expressions.input [new file with mode: 0644]
libgo/go/go/printer/testdata/expressions.raw [new file with mode: 0644]
libgo/go/go/printer/testdata/linebreaks.golden [new file with mode: 0644]
libgo/go/go/printer/testdata/linebreaks.input [new file with mode: 0644]
libgo/go/go/printer/testdata/statements.golden [new file with mode: 0644]
libgo/go/go/printer/testdata/statements.input [new file with mode: 0644]
libgo/go/go/scanner/errors.go [new file with mode: 0644]
libgo/go/go/scanner/scanner.go [new file with mode: 0644]
libgo/go/go/scanner/scanner_test.go [new file with mode: 0644]
libgo/go/go/token/token.go [new file with mode: 0644]
libgo/go/go/typechecker/scope.go [new file with mode: 0644]
libgo/go/go/typechecker/testdata/test0.go [new file with mode: 0644]
libgo/go/go/typechecker/testdata/test1.go [new file with mode: 0644]
libgo/go/go/typechecker/testdata/test3.go [new file with mode: 0644]
libgo/go/go/typechecker/testdata/test4.go [new file with mode: 0644]
libgo/go/go/typechecker/typechecker.go [new file with mode: 0644]
libgo/go/go/typechecker/typechecker_test.go [new file with mode: 0644]
libgo/go/go/typechecker/universe.go [new file with mode: 0644]
libgo/go/gob/codec_test.go [new file with mode: 0644]
libgo/go/gob/decode.go [new file with mode: 0644]
libgo/go/gob/decoder.go [new file with mode: 0644]
libgo/go/gob/doc.go [new file with mode: 0644]
libgo/go/gob/encode.go [new file with mode: 0644]
libgo/go/gob/encoder.go [new file with mode: 0644]
libgo/go/gob/encoder_test.go [new file with mode: 0644]
libgo/go/gob/error.go [new file with mode: 0644]
libgo/go/gob/type.go [new file with mode: 0644]
libgo/go/gob/type_test.go [new file with mode: 0644]
libgo/go/hash/adler32/adler32.go [new file with mode: 0644]
libgo/go/hash/adler32/adler32_test.go [new file with mode: 0644]
libgo/go/hash/crc32/crc32.go [new file with mode: 0644]
libgo/go/hash/crc32/crc32_test.go [new file with mode: 0644]
libgo/go/hash/crc64/crc64.go [new file with mode: 0644]
libgo/go/hash/crc64/crc64_test.go [new file with mode: 0644]
libgo/go/hash/hash.go [new file with mode: 0644]
libgo/go/html/doc.go [new file with mode: 0644]
libgo/go/html/entity.go [new file with mode: 0644]
libgo/go/html/escape.go [new file with mode: 0644]
libgo/go/html/testdata/webkit/README [new file with mode: 0644]
libgo/go/html/testdata/webkit/comments01.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/doctype01.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/dom2string.js [new file with mode: 0644]
libgo/go/html/testdata/webkit/entities01.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/entities02.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/scriptdata01.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests1.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests10.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests11.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests12.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests13.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests14.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests15.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests16.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests2.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests3.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests4.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests5.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests6.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests7.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests8.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/tests9.dat [new file with mode: 0644]
libgo/go/html/testdata/webkit/webkit01.dat [new file with mode: 0644]
libgo/go/html/token.go [new file with mode: 0644]
libgo/go/html/token_test.go [new file with mode: 0644]
libgo/go/http/chunked.go [new file with mode: 0644]
libgo/go/http/client.go [new file with mode: 0644]
libgo/go/http/client_test.go [new file with mode: 0644]
libgo/go/http/dump.go [new file with mode: 0644]
libgo/go/http/fs.go [new file with mode: 0644]
libgo/go/http/lex.go [new file with mode: 0644]
libgo/go/http/lex_test.go [new file with mode: 0644]
libgo/go/http/persist.go [new file with mode: 0644]
libgo/go/http/pprof/pprof.go [new file with mode: 0644]
libgo/go/http/readrequest_test.go [new file with mode: 0644]
libgo/go/http/request.go [new file with mode: 0644]
libgo/go/http/request_test.go [new file with mode: 0644]
libgo/go/http/requestwrite_test.go [new file with mode: 0644]
libgo/go/http/response.go [new file with mode: 0644]
libgo/go/http/response_test.go [new file with mode: 0644]
libgo/go/http/responsewrite_test.go [new file with mode: 0644]
libgo/go/http/server.go [new file with mode: 0644]
libgo/go/http/status.go [new file with mode: 0644]
libgo/go/http/transfer.go [new file with mode: 0644]
libgo/go/http/url.go [new file with mode: 0644]
libgo/go/http/url_test.go [new file with mode: 0644]
libgo/go/image/color.go [new file with mode: 0644]
libgo/go/image/format.go [new file with mode: 0644]
libgo/go/image/geom.go [new file with mode: 0644]
libgo/go/image/image.go [new file with mode: 0644]
libgo/go/image/jpeg/huffman.go [new file with mode: 0644]
libgo/go/image/jpeg/idct.go [new file with mode: 0644]
libgo/go/image/jpeg/reader.go [new file with mode: 0644]
libgo/go/image/names.go [new file with mode: 0644]
libgo/go/image/png/reader.go [new file with mode: 0644]
libgo/go/image/png/reader_test.go [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/README [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/README.original [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g01.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g01.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g02.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g02.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g04.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g04.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g08.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g08.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g16.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn0g16.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn2c08.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn2c08.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn2c16.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn2c16.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn3p01.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn3p01.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn3p02.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn3p02.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn3p04.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn3p04.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn3p08.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn3p08.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn4a08.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn4a08.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn4a16.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn4a16.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn6a08.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn6a08.sng [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn6a16.png [new file with mode: 0644]
libgo/go/image/png/testdata/pngsuite/basn6a16.sng [new file with mode: 0644]
libgo/go/image/png/writer.go [new file with mode: 0644]
libgo/go/image/png/writer_test.go [new file with mode: 0644]
libgo/go/index/suffixarray/suffixarray.go [new file with mode: 0644]
libgo/go/index/suffixarray/suffixarray_test.go [new file with mode: 0644]
libgo/go/io/io.go [new file with mode: 0644]
libgo/go/io/io_test.go [new file with mode: 0644]
libgo/go/io/ioutil/ioutil.go [new file with mode: 0644]
libgo/go/io/ioutil/ioutil_test.go [new file with mode: 0644]
libgo/go/io/ioutil/tempfile.go [new file with mode: 0644]
libgo/go/io/ioutil/tempfile_test.go [new file with mode: 0644]
libgo/go/io/multi.go [new file with mode: 0644]
libgo/go/io/multi_test.go [new file with mode: 0644]
libgo/go/io/pipe.go [new file with mode: 0644]
libgo/go/io/pipe_test.go [new file with mode: 0644]
libgo/go/json/decode.go [new file with mode: 0644]
libgo/go/json/decode_test.go [new file with mode: 0644]
libgo/go/json/encode.go [new file with mode: 0644]
libgo/go/json/indent.go [new file with mode: 0644]
libgo/go/json/scanner.go [new file with mode: 0644]
libgo/go/json/scanner_test.go [new file with mode: 0644]
libgo/go/json/stream.go [new file with mode: 0644]
libgo/go/json/stream_test.go [new file with mode: 0644]
libgo/go/log/log.go [new file with mode: 0644]
libgo/go/log/log_test.go [new file with mode: 0644]
libgo/go/math/acosh.go [new file with mode: 0644]
libgo/go/math/all_test.go [new file with mode: 0644]
libgo/go/math/asin.go [new file with mode: 0644]
libgo/go/math/asinh.go [new file with mode: 0644]
libgo/go/math/atan.go [new file with mode: 0644]
libgo/go/math/atan2.go [new file with mode: 0644]
libgo/go/math/atanh.go [new file with mode: 0644]
libgo/go/math/bits.go [new file with mode: 0644]
libgo/go/math/cbrt.go [new file with mode: 0644]
libgo/go/math/const.go [new file with mode: 0644]
libgo/go/math/copysign.go [new file with mode: 0644]
libgo/go/math/erf.go [new file with mode: 0644]
libgo/go/math/exp.go [new file with mode: 0644]
libgo/go/math/exp2.go [new file with mode: 0644]
libgo/go/math/expm1.go [new file with mode: 0644]
libgo/go/math/fabs.go [new file with mode: 0644]
libgo/go/math/fdim.go [new file with mode: 0644]
libgo/go/math/floor.go [new file with mode: 0644]
libgo/go/math/fmod.go [new file with mode: 0644]
libgo/go/math/frexp.go [new file with mode: 0644]
libgo/go/math/gamma.go [new file with mode: 0644]
libgo/go/math/hypot.go [new file with mode: 0644]
libgo/go/math/hypot_port.go [new file with mode: 0644]
libgo/go/math/hypot_test.go [new file with mode: 0644]
libgo/go/math/j0.go [new file with mode: 0644]
libgo/go/math/j1.go [new file with mode: 0644]
libgo/go/math/jn.go [new file with mode: 0644]
libgo/go/math/ldexp.go [new file with mode: 0644]
libgo/go/math/lgamma.go [new file with mode: 0644]
libgo/go/math/log.go [new file with mode: 0644]
libgo/go/math/log10.go [new file with mode: 0644]
libgo/go/math/log10_decl.go [new file with mode: 0644]
libgo/go/math/log1p.go [new file with mode: 0644]
libgo/go/math/logb.go [new file with mode: 0644]
libgo/go/math/modf.go [new file with mode: 0644]
libgo/go/math/nextafter.go [new file with mode: 0644]
libgo/go/math/pow.go [new file with mode: 0644]
libgo/go/math/pow10.go [new file with mode: 0644]
libgo/go/math/remainder.go [new file with mode: 0644]
libgo/go/math/signbit.go [new file with mode: 0644]
libgo/go/math/sin.go [new file with mode: 0644]
libgo/go/math/sincos.go [new file with mode: 0644]
libgo/go/math/sinh.go [new file with mode: 0644]
libgo/go/math/sqrt.go [new file with mode: 0644]
libgo/go/math/sqrt_decl.go [new file with mode: 0644]
libgo/go/math/sqrt_port.go [new file with mode: 0644]
libgo/go/math/sqrt_test.go [new file with mode: 0644]
libgo/go/math/tan.go [new file with mode: 0644]
libgo/go/math/tanh.go [new file with mode: 0644]
libgo/go/math/unsafe.go [new file with mode: 0644]
libgo/go/mime/grammar.go [new file with mode: 0644]
libgo/go/mime/mediatype.go [new file with mode: 0644]
libgo/go/mime/mediatype_test.go [new file with mode: 0644]
libgo/go/mime/mime_test.go [new file with mode: 0644]
libgo/go/mime/multipart/multipart.go [new file with mode: 0644]
libgo/go/mime/multipart/multipart_test.go [new file with mode: 0644]
libgo/go/mime/test.types [new file with mode: 0644]
libgo/go/mime/type.go [new file with mode: 0644]
libgo/go/net/dial.go [new file with mode: 0644]
libgo/go/net/dialgoogle_test.go [new file with mode: 0644]
libgo/go/net/dict/dict.go [new file with mode: 0644]
libgo/go/net/dnsclient.go [new file with mode: 0644]
libgo/go/net/dnsconfig.go [new file with mode: 0644]
libgo/go/net/dnsmsg.go [new file with mode: 0644]
libgo/go/net/dnsname_test.go [new file with mode: 0644]
libgo/go/net/fd.go [new file with mode: 0644]
libgo/go/net/fd_linux.go [new file with mode: 0644]
libgo/go/net/fd_rtems.go [new file with mode: 0644]
libgo/go/net/fd_windows.go [new file with mode: 0644]
libgo/go/net/hosts.go [new file with mode: 0644]
libgo/go/net/hosts_test.go [new file with mode: 0644]
libgo/go/net/hosts_testdata [new file with mode: 0644]
libgo/go/net/ip.go [new file with mode: 0644]
libgo/go/net/ip_test.go [new file with mode: 0644]
libgo/go/net/ipraw_test.go [new file with mode: 0644]
libgo/go/net/iprawsock.go [new file with mode: 0644]
libgo/go/net/ipsock.go [new file with mode: 0644]
libgo/go/net/net.go [new file with mode: 0644]
libgo/go/net/net_test.go [new file with mode: 0644]
libgo/go/net/newpollserver.go [new file with mode: 0644]
libgo/go/net/newpollserver_rtems.go [new file with mode: 0644]
libgo/go/net/parse.go [new file with mode: 0644]
libgo/go/net/parse_test.go [new file with mode: 0644]
libgo/go/net/pipe.go [new file with mode: 0644]
libgo/go/net/pipe_test.go [new file with mode: 0644]
libgo/go/net/port.go [new file with mode: 0644]
libgo/go/net/port_test.go [new file with mode: 0644]
libgo/go/net/resolv_windows.go [new file with mode: 0644]
libgo/go/net/server_test.go [new file with mode: 0644]
libgo/go/net/sock.go [new file with mode: 0644]
libgo/go/net/srv_test.go [new file with mode: 0644]
libgo/go/net/tcpsock.go [new file with mode: 0644]
libgo/go/net/textproto/pipeline.go [new file with mode: 0644]
libgo/go/net/textproto/reader.go [new file with mode: 0644]
libgo/go/net/textproto/reader_test.go [new file with mode: 0644]
libgo/go/net/textproto/textproto.go [new file with mode: 0644]
libgo/go/net/textproto/writer.go [new file with mode: 0644]
libgo/go/net/textproto/writer_test.go [new file with mode: 0644]
libgo/go/net/timeout_test.go [new file with mode: 0644]
libgo/go/net/udpsock.go [new file with mode: 0644]
libgo/go/net/unixsock.go [new file with mode: 0644]
libgo/go/netchan/common.go [new file with mode: 0644]
libgo/go/netchan/export.go [new file with mode: 0644]
libgo/go/netchan/import.go [new file with mode: 0644]
libgo/go/netchan/netchan_test.go [new file with mode: 0644]
libgo/go/os/dir.go [new file with mode: 0644]
libgo/go/os/env.go [new file with mode: 0644]
libgo/go/os/env_test.go [new file with mode: 0644]
libgo/go/os/env_unix.go [new file with mode: 0644]
libgo/go/os/env_windows.go [new file with mode: 0644]
libgo/go/os/error.go [new file with mode: 0644]
libgo/go/os/exec.go [new file with mode: 0644]
libgo/go/os/file.go [new file with mode: 0644]
libgo/go/os/file_unix.go [new file with mode: 0644]
libgo/go/os/getwd.go [new file with mode: 0644]
libgo/go/os/os_test.go [new file with mode: 0644]
libgo/go/os/path.go [new file with mode: 0644]
libgo/go/os/path_test.go [new file with mode: 0644]
libgo/go/os/proc.go [new file with mode: 0644]
libgo/go/os/signal/mkunix.sh [new file with mode: 0644]
libgo/go/os/signal/signal.go [new file with mode: 0644]
libgo/go/os/signal/signal_test.go [new file with mode: 0644]
libgo/go/os/stat.go [new file with mode: 0644]
libgo/go/os/sys_bsd.go [new file with mode: 0644]
libgo/go/os/sys_linux.go [new file with mode: 0644]
libgo/go/os/time.go [new file with mode: 0644]
libgo/go/os/types.go [new file with mode: 0644]
libgo/go/patch/apply.go [new file with mode: 0644]
libgo/go/patch/git.go [new file with mode: 0644]
libgo/go/patch/patch.go [new file with mode: 0644]
libgo/go/patch/patch_test.go [new file with mode: 0644]
libgo/go/patch/textdiff.go [new file with mode: 0644]
libgo/go/path/match.go [new file with mode: 0644]
libgo/go/path/match_test.go [new file with mode: 0644]
libgo/go/path/path.go [new file with mode: 0644]
libgo/go/path/path_test.go [new file with mode: 0644]
libgo/go/rand/exp.go [new file with mode: 0644]
libgo/go/rand/normal.go [new file with mode: 0644]
libgo/go/rand/rand.go [new file with mode: 0644]
libgo/go/rand/rand_test.go [new file with mode: 0644]
libgo/go/rand/rng.go [new file with mode: 0644]
libgo/go/rand/zipf.go [new file with mode: 0644]
libgo/go/reflect/all_test.go [new file with mode: 0644]
libgo/go/reflect/deepequal.go [new file with mode: 0644]
libgo/go/reflect/tostring_test.go [new file with mode: 0644]
libgo/go/reflect/type.go [new file with mode: 0644]
libgo/go/reflect/value.go [new file with mode: 0644]
libgo/go/regexp/all_test.go [new file with mode: 0644]
libgo/go/regexp/find_test.go [new file with mode: 0644]
libgo/go/regexp/regexp.go [new file with mode: 0644]
libgo/go/rpc/client.go [new file with mode: 0644]
libgo/go/rpc/debug.go [new file with mode: 0644]
libgo/go/rpc/jsonrpc/all_test.go [new file with mode: 0644]
libgo/go/rpc/jsonrpc/client.go [new file with mode: 0644]
libgo/go/rpc/jsonrpc/server.go [new file with mode: 0644]
libgo/go/rpc/server.go [new file with mode: 0644]
libgo/go/rpc/server_test.go [new file with mode: 0644]
libgo/go/runtime/debug.go [new file with mode: 0644]
libgo/go/runtime/error.go [new file with mode: 0644]
libgo/go/runtime/export_test.go [new file with mode: 0644]
libgo/go/runtime/extern.go [new file with mode: 0644]
libgo/go/runtime/pprof/pprof.go [new file with mode: 0644]
libgo/go/runtime/sig.go [new file with mode: 0644]
libgo/go/runtime/softfloat64.go [new file with mode: 0644]
libgo/go/runtime/softfloat64_test.go [new file with mode: 0644]
libgo/go/runtime/type.go [new file with mode: 0644]
libgo/go/scanner/scanner.go [new file with mode: 0644]
libgo/go/scanner/scanner_test.go [new file with mode: 0644]
libgo/go/smtp/auth.go [new file with mode: 0644]
libgo/go/smtp/smtp.go [new file with mode: 0644]
libgo/go/smtp/smtp_test.go [new file with mode: 0644]
libgo/go/sort/sort.go [new file with mode: 0644]
libgo/go/sort/sort_test.go [new file with mode: 0644]
libgo/go/strconv/atob.go [new file with mode: 0644]
libgo/go/strconv/atob_test.go [new file with mode: 0644]
libgo/go/strconv/atof.go [new file with mode: 0644]
libgo/go/strconv/atof_test.go [new file with mode: 0644]
libgo/go/strconv/atoi.go [new file with mode: 0644]
libgo/go/strconv/atoi_test.go [new file with mode: 0644]
libgo/go/strconv/decimal.go [new file with mode: 0644]
libgo/go/strconv/decimal_test.go [new file with mode: 0644]
libgo/go/strconv/fp_test.go [new file with mode: 0644]
libgo/go/strconv/ftoa.go [new file with mode: 0644]
libgo/go/strconv/ftoa_test.go [new file with mode: 0644]
libgo/go/strconv/internal_test.go [new file with mode: 0644]
libgo/go/strconv/itoa.go [new file with mode: 0644]
libgo/go/strconv/itoa_test.go [new file with mode: 0644]
libgo/go/strconv/quote.go [new file with mode: 0644]
libgo/go/strconv/quote_test.go [new file with mode: 0644]
libgo/go/strconv/testfp.txt [new file with mode: 0644]
libgo/go/strings/reader.go [new file with mode: 0644]
libgo/go/strings/strings.go [new file with mode: 0644]
libgo/go/strings/strings_test.go [new file with mode: 0644]
libgo/go/sync/cas.c [new file with mode: 0644]
libgo/go/sync/mutex.go [new file with mode: 0644]
libgo/go/sync/mutex_test.go [new file with mode: 0644]
libgo/go/sync/once.go [new file with mode: 0644]
libgo/go/sync/once_test.go [new file with mode: 0644]
libgo/go/sync/rwmutex.go [new file with mode: 0644]
libgo/go/sync/rwmutex_test.go [new file with mode: 0644]
libgo/go/sync/xadd_test.go [new file with mode: 0644]
libgo/go/syslog/syslog.go [new file with mode: 0644]
libgo/go/syslog/syslog_test.go [new file with mode: 0644]
libgo/go/tabwriter/tabwriter.go [new file with mode: 0644]
libgo/go/tabwriter/tabwriter_test.go [new file with mode: 0644]
libgo/go/template/format.go [new file with mode: 0644]
libgo/go/template/template.go [new file with mode: 0644]
libgo/go/template/template_test.go [new file with mode: 0644]
libgo/go/testing/benchmark.go [new file with mode: 0644]
libgo/go/testing/iotest/logger.go [new file with mode: 0644]
libgo/go/testing/iotest/reader.go [new file with mode: 0644]
libgo/go/testing/iotest/writer.go [new file with mode: 0644]
libgo/go/testing/quick/quick.go [new file with mode: 0644]
libgo/go/testing/quick/quick_test.go [new file with mode: 0644]
libgo/go/testing/script/script.go [new file with mode: 0644]
libgo/go/testing/script/script_test.go [new file with mode: 0644]
libgo/go/testing/testing.go [new file with mode: 0644]
libgo/go/time/format.go [new file with mode: 0644]
libgo/go/time/sleep.go [new file with mode: 0644]
libgo/go/time/sleep_test.go [new file with mode: 0644]
libgo/go/time/tick.go [new file with mode: 0644]
libgo/go/time/tick_test.go [new file with mode: 0644]
libgo/go/time/time.go [new file with mode: 0644]
libgo/go/time/time_test.go [new file with mode: 0644]
libgo/go/time/zoneinfo_unix.go [new file with mode: 0644]
libgo/go/time/zoneinfo_windows.go [new file with mode: 0644]
libgo/go/try/try.go [new file with mode: 0644]
libgo/go/try/try_test.go [new file with mode: 0644]
libgo/go/unicode/casetables.go [new file with mode: 0644]
libgo/go/unicode/digit.go [new file with mode: 0644]
libgo/go/unicode/digit_test.go [new file with mode: 0644]
libgo/go/unicode/letter.go [new file with mode: 0644]
libgo/go/unicode/letter_test.go [new file with mode: 0644]
libgo/go/unicode/script_test.go [new file with mode: 0644]
libgo/go/unicode/tables.go [new file with mode: 0644]
libgo/go/utf16/utf16.go [new file with mode: 0644]
libgo/go/utf16/utf16_test.go [new file with mode: 0644]
libgo/go/utf8/string.go [new file with mode: 0644]
libgo/go/utf8/string_test.go [new file with mode: 0644]
libgo/go/utf8/utf8.go [new file with mode: 0644]
libgo/go/utf8/utf8_test.go [new file with mode: 0644]
libgo/go/websocket/client.go [new file with mode: 0644]
libgo/go/websocket/server.go [new file with mode: 0644]
libgo/go/websocket/websocket.go [new file with mode: 0644]
libgo/go/websocket/websocket_test.go [new file with mode: 0644]
libgo/go/xml/embed_test.go [new file with mode: 0644]
libgo/go/xml/read.go [new file with mode: 0644]
libgo/go/xml/read_test.go [new file with mode: 0644]
libgo/go/xml/xml.go [new file with mode: 0644]
libgo/go/xml/xml_test.go [new file with mode: 0644]
libgo/merge.sh [new file with mode: 0644]
libgo/mksysinfo.sh [new file with mode: 0755]
libgo/runtime/array.h [new file with mode: 0644]
libgo/runtime/chan.goc [new file with mode: 0644]
libgo/runtime/channel.h [new file with mode: 0644]
libgo/runtime/defs.h [new file with mode: 0644]
libgo/runtime/go-alloc.h [new file with mode: 0644]
libgo/runtime/go-append.c [new file with mode: 0644]
libgo/runtime/go-assert-interface.c [new file with mode: 0644]
libgo/runtime/go-assert.c [new file with mode: 0644]
libgo/runtime/go-assert.h [new file with mode: 0644]
libgo/runtime/go-breakpoint.c [new file with mode: 0644]
libgo/runtime/go-byte-array-to-string.c [new file with mode: 0644]
libgo/runtime/go-caller.c [new file with mode: 0644]
libgo/runtime/go-can-convert-interface.c [new file with mode: 0644]
libgo/runtime/go-chan-cap.c [new file with mode: 0644]
libgo/runtime/go-chan-len.c [new file with mode: 0644]
libgo/runtime/go-check-interface.c [new file with mode: 0644]
libgo/runtime/go-close.c [new file with mode: 0644]
libgo/runtime/go-closed.c [new file with mode: 0644]
libgo/runtime/go-construct-map.c [new file with mode: 0644]
libgo/runtime/go-convert-interface.c [new file with mode: 0644]
libgo/runtime/go-defer.c [new file with mode: 0644]
libgo/runtime/go-defer.h [new file with mode: 0644]
libgo/runtime/go-deferred-recover.c [new file with mode: 0644]
libgo/runtime/go-eface-compare.c [new file with mode: 0644]
libgo/runtime/go-eface-val-compare.c [new file with mode: 0644]
libgo/runtime/go-getgoroot.c [new file with mode: 0644]
libgo/runtime/go-go.c [new file with mode: 0644]
libgo/runtime/go-gomaxprocs.c [new file with mode: 0644]
libgo/runtime/go-int-array-to-string.c [new file with mode: 0644]
libgo/runtime/go-int-to-string.c [new file with mode: 0644]
libgo/runtime/go-interface-compare.c [new file with mode: 0644]
libgo/runtime/go-interface-val-compare.c [new file with mode: 0644]
libgo/runtime/go-lock-os-thread.c [new file with mode: 0644]
libgo/runtime/go-main.c [new file with mode: 0644]
libgo/runtime/go-map-delete.c [new file with mode: 0644]
libgo/runtime/go-map-index.c [new file with mode: 0644]
libgo/runtime/go-map-len.c [new file with mode: 0644]
libgo/runtime/go-map-range.c [new file with mode: 0644]
libgo/runtime/go-nanotime.c [new file with mode: 0644]
libgo/runtime/go-new-channel.c [new file with mode: 0644]
libgo/runtime/go-new-map.c [new file with mode: 0644]
libgo/runtime/go-new.c [new file with mode: 0644]
libgo/runtime/go-note.c [new file with mode: 0644]
libgo/runtime/go-panic-defer.c [new file with mode: 0644]
libgo/runtime/go-panic.c [new file with mode: 0644]
libgo/runtime/go-panic.h [new file with mode: 0644]
libgo/runtime/go-print.c [new file with mode: 0644]
libgo/runtime/go-rec-big.c [new file with mode: 0644]
libgo/runtime/go-rec-nb-big.c [new file with mode: 0644]
libgo/runtime/go-rec-nb-small.c [new file with mode: 0644]
libgo/runtime/go-rec-small.c [new file with mode: 0644]
libgo/runtime/go-recover.c [new file with mode: 0644]
libgo/runtime/go-reflect-call.c [new file with mode: 0644]
libgo/runtime/go-reflect-chan.c [new file with mode: 0644]
libgo/runtime/go-reflect-map.c [new file with mode: 0644]
libgo/runtime/go-reflect.c [new file with mode: 0644]
libgo/runtime/go-rune.c [new file with mode: 0644]
libgo/runtime/go-runtime-error.c [new file with mode: 0644]
libgo/runtime/go-sched.c [new file with mode: 0644]
libgo/runtime/go-select.c [new file with mode: 0644]
libgo/runtime/go-semacquire.c [new file with mode: 0644]
libgo/runtime/go-send-big.c [new file with mode: 0644]
libgo/runtime/go-send-nb-big.c [new file with mode: 0644]
libgo/runtime/go-send-nb-small.c [new file with mode: 0644]
libgo/runtime/go-send-small.c [new file with mode: 0644]
libgo/runtime/go-signal.c [new file with mode: 0644]
libgo/runtime/go-signal.h [new file with mode: 0644]
libgo/runtime/go-strcmp.c [new file with mode: 0644]
libgo/runtime/go-string-to-byte-array.c [new file with mode: 0644]
libgo/runtime/go-string-to-int-array.c [new file with mode: 0644]
libgo/runtime/go-string.h [new file with mode: 0644]
libgo/runtime/go-strplus.c [new file with mode: 0644]
libgo/runtime/go-strslice.c [new file with mode: 0644]
libgo/runtime/go-trampoline.c [new file with mode: 0644]
libgo/runtime/go-type-eface.c [new file with mode: 0644]
libgo/runtime/go-type-error.c [new file with mode: 0644]
libgo/runtime/go-type-identity.c [new file with mode: 0644]
libgo/runtime/go-type-interface.c [new file with mode: 0644]
libgo/runtime/go-type-string.c [new file with mode: 0644]
libgo/runtime/go-type.h [new file with mode: 0644]
libgo/runtime/go-typedesc-equal.c [new file with mode: 0644]
libgo/runtime/go-typestring.c [new file with mode: 0644]
libgo/runtime/go-unreflect.c [new file with mode: 0644]
libgo/runtime/go-unsafe-new.c [new file with mode: 0644]
libgo/runtime/go-unsafe-newarray.c [new file with mode: 0644]
libgo/runtime/go-unsafe-pointer.c [new file with mode: 0644]
libgo/runtime/go-unwind.c [new file with mode: 0644]
libgo/runtime/goc2c.c [new file with mode: 0644]
libgo/runtime/iface.goc [new file with mode: 0644]
libgo/runtime/interface.h [new file with mode: 0644]
libgo/runtime/malloc.goc [new file with mode: 0644]
libgo/runtime/malloc.h [new file with mode: 0644]
libgo/runtime/map.goc [new file with mode: 0644]
libgo/runtime/map.h [new file with mode: 0644]
libgo/runtime/mcache.c [new file with mode: 0644]
libgo/runtime/mcentral.c [new file with mode: 0644]
libgo/runtime/mem.c [new file with mode: 0644]
libgo/runtime/mem_posix_memalign.c [new file with mode: 0644]
libgo/runtime/mfinal.c [new file with mode: 0644]
libgo/runtime/mfixalloc.c [new file with mode: 0644]
libgo/runtime/mgc0.c [new file with mode: 0644]
libgo/runtime/mheap.c [new file with mode: 0644]
libgo/runtime/mheapmap32.c [new file with mode: 0644]
libgo/runtime/mheapmap32.h [new file with mode: 0644]
libgo/runtime/mheapmap64.c [new file with mode: 0644]
libgo/runtime/mheapmap64.h [new file with mode: 0644]
libgo/runtime/mprof.goc [new file with mode: 0644]
libgo/runtime/msize.c [new file with mode: 0644]
libgo/runtime/proc.c [new file with mode: 0644]
libgo/runtime/reflect.goc [new file with mode: 0644]
libgo/runtime/rtems-task-variable-add.c [new file with mode: 0644]
libgo/runtime/runtime.h [new file with mode: 0644]
libgo/runtime/sigqueue.goc [new file with mode: 0644]
libgo/runtime/string.goc [new file with mode: 0644]
libgo/runtime/thread.c [new file with mode: 0644]
libgo/syscalls/errno.c [new file with mode: 0644]
libgo/syscalls/errstr.go [new file with mode: 0644]
libgo/syscalls/errstr_decl.go [new file with mode: 0644]
libgo/syscalls/errstr_decl_linux.go [new file with mode: 0644]
libgo/syscalls/errstr_decl_rtems.go [new file with mode: 0644]
libgo/syscalls/errstr_rtems.go [new file with mode: 0644]
libgo/syscalls/exec.go [new file with mode: 0644]
libgo/syscalls/exec_helpers.go [new file with mode: 0644]
libgo/syscalls/exec_stubs.go [new file with mode: 0644]
libgo/syscalls/socket.go [new file with mode: 0644]
libgo/syscalls/socket_bsd.go [new file with mode: 0644]
libgo/syscalls/socket_epoll.go [new file with mode: 0644]
libgo/syscalls/socket_linux.go [new file with mode: 0644]
libgo/syscalls/stringbyte.go [new file with mode: 0644]
libgo/syscalls/syscall.go [new file with mode: 0644]
libgo/syscalls/syscall_linux.go [new file with mode: 0644]
libgo/syscalls/syscall_linux_386.go [new file with mode: 0644]
libgo/syscalls/syscall_linux_amd64.go [new file with mode: 0644]
libgo/syscalls/syscall_stubs.go [new file with mode: 0644]
libgo/syscalls/syscall_unix.go [new file with mode: 0644]
libgo/syscalls/sysfile_linux.go [new file with mode: 0644]
libgo/syscalls/sysfile_posix.go [new file with mode: 0644]
libgo/syscalls/sysfile_rtems.go [new file with mode: 0644]
libgo/testsuite/Makefile.am [new file with mode: 0644]
libgo/testsuite/Makefile.in [new file with mode: 0644]
libgo/testsuite/config/default.exp [new file with mode: 0644]
libgo/testsuite/gotest [new file with mode: 0755]
libgo/testsuite/lib/libgo.exp [new file with mode: 0644]
libgo/testsuite/libgo.testmain/testmain.exp [new file with mode: 0644]

index fde41c8..0c23273 100644 (file)
@@ -1,3 +1,19 @@
+2010-12-02  Ian Lance Taylor  <iant@google.com>
+
+       * gcc.c (default_compilers): Add entry for ".go".
+       * common.opt: Add -static-libgo as a driver option.
+       * doc/install.texi (Configuration): Mention libgo as an option for
+       --enable-shared.  Mention go as an option for --enable-languages.
+       * doc/invoke.texi (Overall Options): Mention .go as a file name
+       suffix.  Mention go as a -x option.
+       * doc/frontends.texi (G++ and GCC): Mention Go as a supported
+       language.
+       * doc/sourcebuild.texi (Top Level): Mention libgo.
+       * doc/standards.texi (Standards): Add section on Go language.
+       Move references for other languages into their own section.
+       * doc/contrib.texi (Contributors): Mention that I contributed the
+       Go frontend.
+
 2010-12-03  Laurynas Biveinis  <laurynas.biveinis@gmail.com>
 
        * tree.h (struct call_expr_arg_iterator_d): Remove GTY tag.
index c21c676..25e516e 100644 (file)
@@ -2272,6 +2272,10 @@ Driver
 static-libstdc++
 Driver
 
+static-libgo
+Driver
+; Documented for Go, but always accepted by driver.
+
 symbolic
 Driver
 
index aae1146..e52dcf9 100644 (file)
@@ -900,8 +900,8 @@ Jeff Sturm for Java porting help, bug fixes, and encouragement.
 Shigeya Suzuki for this fixes for the bsdi platforms.
 
 @item
-Ian Lance Taylor for his mips16 work, general configury hacking,
-fixincludes, etc.
+Ian Lance Taylor for the Go frontend, the initial mips16 and mips64
+support, general configury hacking, fixincludes, etc.
 
 @item
 Holger Teutsch provided the support for the Clipper CPU@.
index 9c2d707..625e26d 100644 (file)
 @cindex GNU C Compiler
 @cindex Ada
 @cindex Fortran
+@cindex Go
 @cindex Java
 @cindex Objective-C
 @cindex Objective-C++
 GCC stands for ``GNU Compiler Collection''.  GCC is an integrated
 distribution of compilers for several major programming languages.  These
 languages currently include C, C++, Objective-C, Objective-C++, Java,
-Fortran, and Ada.
+Fortran, Ada, and Go.
 
 The abbreviation @dfn{GCC} has multiple meanings in common use.  The
 current official meaning is ``GNU Compiler Collection'', which refers
index 5bdd35b..fbb2d4c 100644 (file)
@@ -884,7 +884,7 @@ only for the listed packages.  For other packages, only static libraries
 will be built.  Package names currently recognized in the GCC tree are
 @samp{libgcc} (also known as @samp{gcc}), @samp{libstdc++} (not
 @samp{libstdc++-v3}), @samp{libffi}, @samp{zlib}, @samp{boehm-gc},
-@samp{ada}, @samp{libada}, @samp{libjava} and @samp{libobjc}.
+@samp{ada}, @samp{libada}, @samp{libjava}, @samp{libgo}, and @samp{libobjc}.
 Note @samp{libiberty} does not support shared libraries at all.
 
 Use @option{--disable-shared} to build only static libraries.  Note that
@@ -1305,15 +1305,12 @@ their runtime libraries should be built.  For a list of valid values for
 grep language= */config-lang.in
 @end smallexample
 Currently, you can use any of the following:
-@code{all}, @code{ada}, @code{c}, @code{c++}, @code{fortran}, @code{java},
-@code{objc}, @code{obj-c++}.
+@code{all}, @code{ada}, @code{c}, @code{c++}, @code{fortran},
+@code{go}, @code{java}, @code{objc}, @code{obj-c++}.
 Building the Ada compiler has special requirements, see below.
 If you do not pass this flag, or specify the option @code{all}, then all
 default languages available in the @file{gcc} sub-tree will be configured.
-Ada and Objective-C++ are not default languages; the rest are.
-Re-defining @code{LANGUAGES} when calling @samp{make} @strong{does not}
-work anymore, as those language sub-directories might not have been
-configured!
+Ada, Go and Objective-C++ are not default languages; the rest are.
 
 @item --enable-stage1-languages=@var{lang1},@var{lang2},@dots{}
 Specify that a particular subset of compilers and their runtime
index 94e8160..7c80415 100644 (file)
@@ -1070,6 +1070,9 @@ Free form Fortran source code which should not be preprocessed.
 Free form Fortran source code which must be preprocessed (with the
 traditional preprocessor).
 
+@item @var{file}.go
+Go source code.
+
 @c FIXME: Descriptions of Java file types.
 @c @var{file}.java
 @c @var{file}.class
@@ -1123,6 +1126,7 @@ objective-c++ objective-c++-header objective-c++-cpp-output
 assembler  assembler-with-cpp
 ada
 f77  f77-cpp-input f95  f95-cpp-input
+go
 java
 @end smallexample
 
index 239536c..012e680 100644 (file)
@@ -81,6 +81,10 @@ The GCC runtime library.
 @item libgfortran
 The Fortran runtime library.
 
+@item libgo
+The Go runtime library.  The bulk of this library is mirrored from the
+@uref{http://code.google.com/@/p/@/go, master Go repository}.
+
 @item libgomp
 The GNU OpenMP runtime library.
 
index 59fbf03..90ddd47 100644 (file)
@@ -271,6 +271,18 @@ The authoritative manual on Objective-C 2.0 is available from Apple:
 For more information concerning the history of Objective-C that is
 available online, see @uref{http://gcc.gnu.org/readings.html}
 
+@section Go language
+
+The Go language continues to evolve as of this writing; see the
+@uref{http://golang.org/@/doc/@/go_spec.html, current language
+specifications}.  At present there are no specific versions of Go, and
+there is no way to describe the language supported by GCC in terms of
+a specific version.  In general GCC tracks the evolving specification
+closely, and any given release will support the language as of the
+date that the release was frozen.
+
+@section References for other languages
+
 @xref{Top, GNAT Reference Manual, About This Guide, gnat_rm,
 GNAT Reference Manual}, for information on standard
 conformance and compatibility of the Ada compiler.
index ab11277..a0343fa 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -896,6 +896,7 @@ static const struct compiler default_compilers[] =
   {".p", "#Pascal", 0, 0, 0}, {".pas", "#Pascal", 0, 0, 0},
   {".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
   {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
+  {".go", "#Go", 0, 1, 0},
   /* Next come the entries for C.  */
   {".c", "@c", 0, 0, 1},
   {"@c",
diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in
new file mode 100644 (file)
index 0000000..971490c
--- /dev/null
@@ -0,0 +1,267 @@
+# Make-lang.in -- Top level -*- makefile -*- fragment for gcc Go frontend.
+
+# Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+# This file is part of GCC.
+
+# GCC 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, or (at your option)
+# any later version.
+
+# GCC 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
+# <http://www.gnu.org/licenses/>.
+
+# This file provides the language dependent support in the main Makefile.
+
+# Installation name.
+
+GCCGO_INSTALL_NAME := $(shell echo gccgo|sed '$(program_transform_name)')
+GCCGO_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccgo|sed '$(program_transform_name)')
+
+# The name for selecting go in LANGUAGES.
+go: go1$(exeext)
+
+.PHONY: go
+
+gospec.o: $(srcdir)/go/gospec.c $(SYSTEM_H) coretypes.h $(TM_H) $(GCC_H) \
+    $(CONFIG_H) opts.h
+       (SHLIB_LINK='$(SHLIB_LINK)'; \
+       $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(DRIVER_DEFINES) \
+               $(INCLUDES) $(srcdir)/go/gospec.c)
+
+GCCGO_OBJS = $(GCC_OBJS) gospec.o intl.o prefix.o version.o
+gccgo$(exeext): $(GCCGO_OBJS) $(EXTRA_GCC_OBJS) $(LIBDEPS)
+       $(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+         $(GCCGO_OBJS) $(EXTRA_GCC_OBJS) $(LIBS)
+
+# Use strict warnings.
+go-warn = $(STRICT_WARN)
+
+GO_OBJS = \
+       go/dataflow.o \
+       go/export.o \
+       go/expressions.o \
+       go/go-dump.o \
+       go/go-lang.o \
+       go/go.o \
+       go/gogo-tree.o \
+       go/gogo.o \
+       go/import.o \
+       go/import-archive.o \
+       go/lex.o \
+       go/parse.o \
+       go/statements.o \
+       go/types.o \
+       go/unsafe.o
+
+go1$(exeext): $(GO_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
+       $(CXX) $(ALL_CXXFLAGS) $(LDFLAGS) -o $@ \
+             $(GO_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
+
+# Documentation.
+
+GO_TEXI_FILES = \
+       go/gccgo.texi \
+       $(gcc_docdir)/include/fdl.texi \
+       $(gcc_docdir)/include/gpl_v3.texi \
+       $(gcc_docdir)/include/gcc-common.texi \
+       gcc-vers.texi
+
+doc/gccgo.info: $(GO_TEXI_FILES)
+       if test "x$(BUILD_INFO)" = xinfo; then \
+         rm -f doc/gccgo.info*; \
+         $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \
+               -I $(gcc_docdir)/include -o $@ $<; \
+       else true; fi
+
+doc/gccgo.dvi: $(GO_TEXI_FILES)
+       $(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
+
+doc/gccgo.pdf: $(GO_TEXI_FILES)
+       $(TEXI2PDF) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
+
+$(build_htmldir)/go/index.html: $(GO_TEXI_FILES)
+       $(mkinstalldirs) $(@D)
+       rm -f $(@D)/*
+       $(TEXI2HTML) -I $(gcc_docdir) -I $(gcc_docdir)/include \
+               -I $(srcdir)/go -o $(@D) $<
+
+.INTERMEDIATE: gccgo.pod
+
+gccgo.pod: go/gccgo.texi
+       -$(TEXI2POD) -D gccgo < $< > $@
+
+# Build hooks.
+
+go.all.cross: gccgo$(exeext)
+go.start.encap: gccgo$(exeext)
+go.rest.encap:
+go.info: doc/gccgo.info
+go.dvi: doc/gccgo.dvi
+go.pdf: doc/gccgo.pdf
+go.html: $(build_htmldir)/go/index.html
+go.srcinfo: doc/gccgo.info
+       -cp -p $^ $(srcdir)/doc
+go.srcextra:
+go.tags: force
+       cd $(srcdir)/go; \
+       etags -o TAGS.sub *.c *.h gofrontend/*.h gofrontend/*.cc; \
+       etags --include TAGS.sub --include ../TAGS.sub
+go.man: doc/gccgo.1
+go.srcman: doc/gccgo.1
+       -cp -p $^ $(srcdir)/doc
+
+check-go:
+lang_checks += check-go
+
+# Install hooks.
+
+go.install-common: installdirs
+       -rm -f $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext)
+       -rm -f $(DESTDIR)$(bindir)/$(GCCGO_TARGET_INSTALL_NAME)$(exeext)
+       $(INSTALL_PROGRAM) gccgo$(exeext) $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext)
+       if test -f $(DESTDIR)$(bindir)$(GCCGO_TARGET_INSTALL_NAME)$(exeext); then \
+         :; \
+       else \
+         cd $(DESTDIR)$(bindir) && \
+          $(LN) $(GCCGO_INSTALL_NAME)$(exeext) $(GCCGO_TARGET_INSTALL_NAME)$(exeext); \
+       fi
+
+go.install-plugin:
+
+go.install-info: $(DESTDIR)$(infodir)/gccgo.info
+
+go.install-pdf: doc/gccgo.pdf
+       @$(NORMAL_INSTALL)
+       test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
+       @for p in doc/gccgo.pdf; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         f=$(pdf__strip_dir) \
+         echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
+         $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
+       done
+
+go.install-html: $(build_htmldir)/go
+       @$(NORMAL_INSTALL)
+       test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
+       @for p in $(build_htmldir)/go; do \
+         if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
+         f=$(html__strip_dir) \
+         if test -d "$$d$$p"; then \
+           echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
+           $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+           echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+           $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
+         else \
+           echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
+           $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
+         fi; \
+       done
+
+go.install-man: $(DESTDIR)$(man1dir)/$(GCCGO_INSTALL_NAME)$(man1ext)
+
+$(DESTDIR)$(man1dir)/$(GCCGO_INSTALL_NAME)$(man1ext): doc/gccgo.1 installdirs
+       -rm -f $@
+       -$(INSTALL_DATA) $< $@
+       -chmod a-x $@
+
+go.uninstall:
+       rm -rf $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext)
+       rm -rf $(DESTDIR)$(man1dir)/$(GCCGO_INSTALL_NAME)$(man1ext)
+       rm -rf $(DESTDIR)$(bindir)/$(GCCGO_TARGET_INSTALL_NAME)$(exeext)
+       rm -rf $(DESTDIR)$(infodir)/gccgo.info*
+
+# Clean hooks.
+
+go.mostlyclean:
+       -rm -f go/*$(objext)
+       -rm -f go/*$(coverageexts)
+go.clean:
+go.distclean:
+go.maintainer-clean:
+       -rm -f $(docobjdir)/gccgo.1
+
+# Stage hooks.
+
+go.stage1: stage1-start
+       -mv go/*$(objext) stage1/go
+go.stage2: stage2-start
+       -mv go/*$(objext) stage2/go
+go.stage3: stage3-start
+       -mv go/*$(objext) stage3/go
+go.stage4: stage4-start
+       -mv go/*$(objext) stage4/go
+go.stageprofile: stageprofile-start
+       -mv go/*$(objext) stageprofile/go
+go.stagefeedback: stagefeedback-start
+       -mv go/*$(objext) stagefeedback/go
+
+GO_SYSTEM_H = go/go-system.h $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+       $(DIAGNOSTIC_CORE_H) $(INPUT_H)
+
+GO_C_H = go/go-c.h $(MACHMODE_H)
+GO_LEX_H = go/gofrontend/lex.h go/gofrontend/operator.h
+GO_PARSE_H = go/gofrontend/parse.h
+GO_GOGO_H = go/gofrontend/gogo.h
+GO_TYPES_H = go/gofrontend/types.h
+GO_STATEMENTS_H = go/gofrontend/statements.h go/gofrontend/operator.h
+GO_EXPRESSIONS_H = go/gofrontend/expressions.h go/gofrontend/operator.h
+GO_IMPORT_H = go/gofrontend/import.h go/gofrontend/export.h
+
+go/go-lang.o: go/go-lang.c $(GO_SYSTEM_H) coretypes.h opts.h $(TREE_H) \
+       $(GIMPLE_H) $(GGC_H) $(TOPLEV_H) debug.h options.h $(FLAGS_H) \
+       convert.h langhooks.h $(LANGHOOKS_DEF_H) $(EXCEPT_H) $(TARGET_H) \
+       $(DIAGNOSTIC_H) $(GO_C_H) gt-go-go-lang.h gtype-go.h
+
+GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
+
+go/%.o: go/gofrontend/%.cc
+       $(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
+
+go/dataflow.o: go/gofrontend/dataflow.cc $(GO_SYSTEM_H) $(GO_GOGO_H) \
+       $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) go/gofrontend/dataflow.h
+go/export.o: go/gofrontend/export.cc $(GO_SYSTEM_H) \
+       $(srcdir)/../include/sha1.h $(MACHMODE_H) output.h $(TARGET_H) \
+       $(GO_GOGO_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) go/gofrontend/export.h
+go/expressions.o: go/gofrontend/expressions.cc $(GO_SYSTEM_H) $(TOPLEV_H) \
+       intl.h $(TREE_H) $(GIMPLE_H) tree-iterator.h convert.h $(REAL_H) \
+       realmpfr.h $(TM_H) $(TM_P_H) $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) \
+       go/gofrontend/export.h $(GO_IMPORT_H) $(GO_STATEMENTS_H) $(GO_LEX_H) \
+       $(GO_EXPRESSIONS_H)
+go/go.o: go/gofrontend/go.cc $(GO_SYSTEM_H) $(GO_C_H) $(GO_LEX_H) \
+       $(GO_PARSE_H) $(GO_GOGO_H)
+go/go-dump.o: go/gofrontend/go-dump.cc $(GO_SYSTEM_H) $(GO_C_H) \
+       go/gofrontend/go-dump.h
+go/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TM_H) $(TOPLEV_H) \
+       $(TREE_H) $(GIMPLE_H) tree-iterator.h $(CGRAPH_H) langhooks.h \
+       convert.h output.h $(DIAGNOSTIC_H) $(RTL_H) $(GO_TYPES_H) \
+       $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_GOGO_H)
+go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) $(GO_C_H) \
+       go/gofrontend/go-dump.h $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) \
+       $(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_IMPORT_H) \
+       go/gofrontend/export.h $(GO_GOGO_H)
+go/import.o: go/gofrontend/import.cc $(GO_SYSTEM_H) \
+       $(srcdir)/../include/filenames.h $(srcdir)/../include/simple-object.h \
+       $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) go/gofrontend/export.h \
+       $(GO_IMPORT_H)
+go/import-archive.o: go/gofrontend/import-archive.cc $(GO_SYSTEM_H) \
+       $(GO_IMPORT_H)
+go/lex.o: go/gofrontend/lex.cc $(GO_LEX_H) $(GO_SYSTEM_H)
+go/parse.o: go/gofrontend/parse.cc $(GO_SYSTEM_H) $(GO_LEX_H) $(GO_GOGO_H) \
+       $(GO_TYPES_H) $(GO_STATEMENTS_H) $(GO_EXPRESSIONS_H) $(GO_PARSE_H)
+go/statements.o: go/gofrontend/statements.cc $(GO_SYSTEM_H) intl.h $(TREE_H) \
+       $(GIMPLE_H) convert.h tree-iterator.h $(TREE_FLOW_H) $(REAL_H) \
+       $(GO_C_H) $(GO_TYPES_H) $(GO_EXPRESSIONS_H) $(GO_GOGO_H) \
+       $(GO_STATEMENTS_H)
+go/types.o: go/gofrontend/types.cc $(GO_SYSTEM_H) $(TOPLEV_H) intl.h $(TREE_H) \
+       $(GIMPLE_H) $(REAL_H) convert.h $(GO_C_H) $(GO_GOGO_H) \
+       go/gofrontend/operator.h $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) \
+       go/gofrontend/export.h $(GO_IMPORT_H) $(GO_TYPES_H)
+go/unsafe.o: go/gofrontend/unsafe.cc $(GO_SYSTEM_H) $(GO_TYPES_H) $(GO_GOGO_H)
diff --git a/gcc/go/README.gcc b/gcc/go/README.gcc
new file mode 100644 (file)
index 0000000..3c764f7
--- /dev/null
@@ -0,0 +1,3 @@
+The files in the gofrontend subdirectory are mirrored from the
+gofrontend project hosted at http://code.google.com/p/gofrontend.
+These files are the ones in the go subdirectory of that project.
diff --git a/gcc/go/config-lang.in b/gcc/go/config-lang.in
new file mode 100644 (file)
index 0000000..47b2605
--- /dev/null
@@ -0,0 +1,37 @@
+# config-lang.in -- Top level configure fragment for gcc Go frontend.
+
+# Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+# This file is part of GCC.
+
+# GCC 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, or (at your option)
+# any later version.
+
+# GCC 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
+# <http://www.gnu.org/licenses/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language     - name of language as it would appear in $(LANGUAGES)
+# compilers    - value to add to $(COMPILERS)
+
+language="go"
+
+compilers="go1\$(exeext)"
+
+target_libs="target-libgo target-libffi"
+
+# The Go frontend is written in C++, so we need to build the C++
+# compiler during stage 1.
+lang_requires_boot_languages=c++
+
+gtfiles="\$(srcdir)/go/go-lang.c"
diff --git a/gcc/go/gccgo.texi b/gcc/go/gccgo.texi
new file mode 100644 (file)
index 0000000..0e41261
--- /dev/null
@@ -0,0 +1,348 @@
+\input texinfo @c -*-texinfo-*-
+@setfilename gccgo.info
+@settitle The GNU Go Compiler
+
+@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 gcc-common.texi
+
+@c Copyright years for this manual.
+@set copyrights-go 2010
+
+@copying
+@c man begin COPYRIGHT
+Copyright @copyright{} @value{copyrights-go} Free Software Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, the Front-Cover Texts being (a) (see below), and
+with the Back-Cover Texts being (b) (see below).
+A copy of the license is included in the
+@c man end
+section entitled ``GNU Free Documentation License''.
+@ignore
+@c man begin COPYRIGHT
+man page gfdl(7).
+@c man end
+@end ignore
+
+@c man begin COPYRIGHT
+
+(a) The FSF's Front-Cover Text is:
+
+     A GNU Manual
+
+(b) The FSF's Back-Cover Text is:
+
+     You have freedom to copy and modify this GNU Manual, like GNU
+     software.  Copies published by the Free Software Foundation raise
+     funds for GNU development.
+@c man end
+@end copying
+
+@ifinfo
+@format
+@dircategory Software development
+@direntry
+* Gccgo: (gccgo).           A GCC-based compiler for the Go language
+@end direntry
+@end format
+
+@insertcopying
+@end ifinfo
+
+@titlepage
+@title The GNU Go Compiler
+@versionsubtitle
+@author Ian Lance Taylor
+
+@page
+@vskip 0pt plus 1filll
+Published by the Free Software Foundation @*
+51 Franklin Street, Fifth Floor@*
+Boston, MA 02110-1301, USA@*
+@sp 1
+@insertcopying
+@end titlepage
+@contents
+@page
+
+@node Top
+@top Introduction
+
+This manual describes how to use @command{gccgo}, the GNU compiler for
+the Go programming language.  This manual is specifically about
+@command{gccgo}.  For more information about the Go programming
+language in general, including language specifications and standard
+package documentation, see @uref{http://golang.org/}.
+
+@menu
+* Copying::                     The GNU General Public License.
+* GNU Free Documentation License::
+                                How you can share and copy this manual.
+* Invoking gccgo::              How to run gccgo.
+* Import and Export::           Importing and exporting package data.
+* C Interoperability::          Calling C from Go and vice-vera.
+* Index::                       Index.
+@end menu
+
+
+@include gpl_v3.texi
+
+@include fdl.texi
+
+
+@node Invoking gccgo
+@chapter Invoking gccgo
+
+@c man title gccgo A GCC-based compiler for the Go language
+
+@ignore
+@c man begin SYNOPSIS gccgo
+gccgo [@option{-c}|@option{-S}]
+      [@option{-g}] [@option{-pg}] [@option{-O}@var{level}]
+      [@option{-I}@var{dir}@dots{}] [@option{-L}@var{dir}@dots{}]
+      [@option{-o} @var{outfile}] @var{infile}@dots{}
+
+Only the most useful options are listed here; see below for the
+remainder.
+@c man end
+@c man begin SEEALSO
+gpl(7), gfdl(7), fsf-funding(7), gcc(1)
+and the Info entries for @file{gccgo} and @file{gcc}.
+@c man end
+@end ignore
+
+@c man begin DESCRIPTION gccgo
+
+The @command{gccgo} command is a frontend to @command{gcc} and
+supports many of the same options.  @xref{Option Summary, , Option
+Summary, gcc, Using the GNU Compiler Collection (GCC)}.  This manual
+only documents the options specific to @command{gccgo}.
+
+The @command{gccgo} command may be used to compile Go source code into
+an object file, link a collection of object files together, or do both
+in sequence.
+
+Go source code is compiled as packages.  A package consists of one or
+more Go source files.  All the files in a single package must be
+compiled together, by passing all the files as arguments to
+@command{gccgo}.  A single invocation of @command{gccgo} may only
+compile a single package.
+
+One Go package may @code{import} a different Go package.  The imported
+package must have already been compiled; @command{gccgo} will read
+the import data directly from the compiled package.  When this package
+is later linked, the compiled form of the package must be included in
+the link command.
+
+@c man end
+
+@c man begin OPTIONS gccgo
+
+@table @gcctabopt
+@item -I@var{dir}
+@cindex @option{-I}
+Specify a directory to use when searching for an import package at
+compile time.
+
+@item -L@var{dir}
+@cindex @option{-L}
+When compiling, synonymous with @option{-I}.  When linking, specify a
+library search directory, as with @command{gcc}.
+
+@item -fgo-prefix=@var{string}
+@cindex @option{-fgo-prefix}
+Go permits a single program to include more than one package with the
+same name.  This option is required to make this work with
+@command{gccgo}.  The argument to this option may be any string.  Each
+package with the same name must use a distinct @option{-fgo-prefix}
+option.  The argument is typically the full path under which the
+package will be installed, as that must obviously be unique.
+
+@item -frequire-return-statement
+@itemx -fno-require-return-statement
+@cindex @option{-frequire-return-statement}
+@cindex @option{-fno-require-return-statement}
+By default @command{gccgo} will warn about functions which have one or
+more return parameters but lack an explicit @code{return} statement.
+This warning may be disabled using
+@option{-fno-require-return-statement}.
+@end table
+
+@c man end
+
+@node Import and Export
+@chapter Import and Export
+
+When @command{gccgo} compiles a package which exports anything, the
+export information will be stored directly in the object file.  When a
+package is imported, @command{gccgo} must be able to find the file.
+
+@cindex @file{.gox}
+When Go code imports the package @file{gopackage}, @command{gccgo}
+will look for the import data using the following filenames, using the
+first one that it finds.
+
+@table @file
+@item @var{gopackage}.gox
+@item lib@var{gopackage}.so
+@item lib@var{gopackage}.a
+@item @var{gopackage}.o
+@end table
+
+The compiler will search for these files in the directories named by
+any @option{-I} or @option{-L} options, in order in which the
+directories appear on the command line.  The compiler will then search
+several standard system directories.  Finally the compiler will search
+the current directory (to search the current directory earlier, use
+@samp{-I.}).
+
+The compiler will extract the export information directly from the
+compiled object file.  The file @file{@var{gopackage}.gox} will
+typically contain nothing but export data.  This can be generated from
+@file{@var{gopackage}.o} via
+
+@smallexample
+objcopy -j .go_export @var{gopackage}.o @var{gopackage}.gox
+@end smallexample
+
+For example, it may be desirable to extract the export information
+from several different packages into their independent
+@file{@var{gopackage}.gox} files, and then to combine the different
+package object files together into a single shared library or archive.
+
+At link time you must explicitly tell @command{gccgo} which files to
+link together into the executable, as is usual with @command{gcc}.
+This is different from the behaviour of other Go compilers.
+
+@node C Interoperability
+@chapter C Interoperability
+
+When using @command{gccgo} there is limited interoperability with C,
+or with C++ code compiled using @code{extern "C"}.
+
+@menu
+* C Type Interoperability::     How C and Go types match up.
+* Function Names::              How Go functions are named.
+@end menu
+
+@node C Type Interoperability
+@section C Type Interoperability
+
+Basic types map directly: an @code{int} in Go is an @code{int} in C,
+etc.  Go @code{byte} is equivalent to C @code{unsigned char}.
+Pointers in Go are pointers in C.  A Go @code{struct} is the same as C
+@code{struct} with the same field names and types.
+
+@cindex @code{string} in C
+The Go @code{string} type is currently defined as a two-element
+structure:
+
+@smallexample
+struct __go_string @{
+  const unsigned char *__data;
+  int __length;
+@};
+@end smallexample
+
+You can't pass arrays between C and Go.  However, a pointer to an
+array in Go is equivalent to a C pointer to the equivalent of the
+element type.  For example, Go @code{*[10]int} is equivalent to C
+@code{int*}, assuming that the C pointer does point to 10 elements.
+
+@cindex @code{slice} in C
+A slice in Go is a structure.  The current definition is:
+
+@smallexample
+struct __go_slice @{
+  void *__values;
+  int __count;
+  int __capacity;
+@};
+@end smallexample
+
+The type of a Go function with no receiver is equivalent to a C
+function whose parameter types are equivalent.  When a Go function
+returns more than one value, the C function returns a struct.  For
+example, these functions have equivalent types:
+
+@smallexample
+func GoFunction(int) (int, float)
+struct @{ int i; float f; @} CFunction(int)
+@end smallexample
+
+A pointer to a Go function is equivalent to a pointer to a C function
+when the functions have equivalent types.
+
+Go @code{interface}, @code{channel}, and @code{map} types have no
+corresponding C type (@code{interface} is a two-element struct and
+@code{channel} and @code{map} are pointers to structs in C, but the
+structs are deliberately undocumented).  C @code{enum} types
+correspond to some integer type, but precisely which one is difficult
+to predict in general; use a cast.  C @code{union} types have no
+corresponding Go type.  C @code{struct} types containing bitfields
+have no corresponding Go type.  C++ @code{class} types have no
+corresponding Go type.
+
+Memory allocation is completely different between C and Go, as Go uses
+garbage collection.  The exact guidelines in this area are
+undetermined, but it is likely that it will be permitted to pass a
+pointer to allocated memory from C to Go.  The responsibility of
+eventually freeing the pointer will remain with C side, and of course
+if the C side frees the pointer while the Go side still has a copy the
+program will fail.  When passing a pointer from Go to C, the Go
+function must retain a visible copy of it in some Go variable.
+Otherwise the Go garbage collector may delete the pointer while the C
+function is still using it.
+
+@node Function Names
+@section Function Names
+
+@cindex @code{__asm__}
+Go code can call C functions directly using a Go extension implemented
+in @command{gccgo}: a function declaration may be followed by
+@code{__asm__ ("@var{name}")}. For example, here is how the C function
+@code{open} can be declared in Go:
+
+@smallexample
+func c_open(name *byte, mode int, perm int) int __asm__ ("open");
+@end smallexample
+
+The C function naturally expects a nul terminated string, which in Go
+is equivalent to a pointer to an array (not a slice!) of @code{byte}
+with a terminating zero byte.  So a sample call from Go would look
+like (after importing the @code{os} package):
+
+@smallexample
+var name = [4]byte@{'f', 'o', 'o', 0@};
+i := c_open(&amp;name[0], os.O_RDONLY, 0);
+@end smallexample
+
+Note that this serves as an example only.  To open a file in Go please
+use Go's @code{os.Open} function instead.
+
+The name of Go functions accessed from C is subject to change.  At
+present the name of a Go function that does not have a receiver is
+@code{prefix.package.Functionname}.  The prefix is set by the
+@option{-fgo-prefix} option used when the package is compiled; if the
+option is not used, the default is simply @code{go}.  To call the
+function from C you must set the name using the @command{gcc}
+extension similar to the @command{gccgo} extension.
+
+@smallexample
+extern int go_function(int) __asm__ ("myprefix.mypackage.Function");
+@end smallexample
+
+@node Index
+@unnumbered Index
+
+@printindex cp
+
+@bye
diff --git a/gcc/go/go-c.h b/gcc/go/go-c.h
new file mode 100644 (file)
index 0000000..2075494
--- /dev/null
@@ -0,0 +1,66 @@
+/* go-c.h -- Header file for go frontend gcc C interface.
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GO_GO_C_H
+#define GO_GO_C_H
+
+#ifdef ENABLE_BUILD_WITH_CXX
+#define GO_EXTERN_C
+#else
+#define GO_EXTERN_C extern "C"
+#endif
+
+#if defined(__cplusplus) && !defined(ENABLE_BUILD_WITH_CXX)
+extern "C"
+{
+#endif
+
+#include "machmode.h"
+
+/* Functions defined in the Go frontend proper called by the GCC
+   interface.  */
+
+extern int go_enable_dump (const char*);
+extern void go_set_prefix (const char*);
+
+extern void go_add_search_path (const char*);
+
+extern void go_create_gogo (int int_type_size, int float_type_size,
+                           int pointer_size);
+
+extern void go_parse_input_files (const char**, unsigned int,
+                                 bool only_check_syntax,
+                                 bool require_return_statement);
+extern void go_write_globals (void);
+
+extern tree go_type_for_size (unsigned int bits, int unsignedp);
+extern tree go_type_for_mode (enum machine_mode, int unsignedp);
+
+/* Functions defined in the GCC interface called by the Go frontend
+   proper.  */
+
+extern void go_preserve_from_gc (tree);
+
+extern const char *go_localize_identifier (const char*);
+
+#if defined(__cplusplus) && !defined(ENABLE_BUILD_WITH_CXX)
+} /* End extern "C".  */
+#endif
+
+#endif /* !defined(GO_GO_C_H) */
diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.c
new file mode 100644 (file)
index 0000000..9c85ab7
--- /dev/null
@@ -0,0 +1,404 @@
+/* go-lang.c -- Go frontend gcc interface.
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "ansidecl.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+#include "gimple.h"
+#include "ggc.h"
+#include "toplev.h"
+#include "debug.h"
+#include "options.h"
+#include "flags.h"
+#include "convert.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "except.h"
+#include "target.h"
+
+#include <mpfr.h>
+
+#include "go-c.h"
+
+/* Language-dependent contents of a type.  */
+
+struct GTY(()) lang_type
+{
+  char dummy;
+};
+
+/* Language-dependent contents of a decl.  */
+
+struct GTY(()) lang_decl
+{
+  char dummy;
+};
+
+/* Language-dependent contents of an identifier.  This must include a
+   tree_identifier.  */
+
+struct GTY(()) lang_identifier
+{
+  struct tree_identifier common;
+};
+
+/* The resulting tree type.  */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+          chain_next ("(union lang_tree_node *) TREE_CHAIN (&%h.generic)")))
+lang_tree_node
+{
+  union tree_node GTY((tag ("0"),
+                      desc ("tree_node_structure (&%h)"))) generic;
+  struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function.  */
+
+struct GTY(()) language_function
+{
+  int dummy;
+};
+
+/* Language hooks.  */
+
+static bool
+go_langhook_init (void)
+{
+  build_common_tree_nodes (false);
+
+  /* The sizetype may be "unsigned long" or "unsigned long long".  */
+  if (TYPE_MODE (long_unsigned_type_node) == ptr_mode)
+    size_type_node = long_unsigned_type_node;
+  else if (TYPE_MODE (long_long_unsigned_type_node) == ptr_mode)
+    size_type_node = long_long_unsigned_type_node;
+  else
+    size_type_node = long_unsigned_type_node;
+  set_sizetype (size_type_node);
+
+  build_common_tree_nodes_2 (0);
+
+  /* We must create the gogo IR after calling build_common_tree_nodes
+     (because Gogo::define_builtin_function_trees refers indirectly
+     to, e.g., unsigned_char_type_node) but before calling
+     build_common_builtin_nodes (because it calls, indirectly,
+     go_type_for_size).  */
+  go_create_gogo (INT_TYPE_SIZE, FLOAT_TYPE_SIZE, POINTER_SIZE);
+
+  build_common_builtin_nodes ();
+
+  /* I don't know why this is not done by any of the above.  */
+  void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+  /* The default precision for floating point numbers.  This is used
+     for floating point constants with abstract type.  This may
+     eventually be controllable by a command line option.  */
+  mpfr_set_default_prec (128);
+
+  /* Go uses exceptions.  */
+  using_eh_for_cleanups ();
+
+  return true;
+}
+
+/* The option mask.  */
+
+static unsigned int
+go_langhook_option_lang_mask (void)
+{
+  return CL_Go;
+}
+
+/* Initialize the options structure.  */
+
+static void
+go_langhook_init_options_struct (struct gcc_options *opts)
+{
+  /* Go says that signed overflow is precisely defined.  */
+  opts->x_flag_wrapv = 1;
+
+  /* We default to using strict aliasing, since Go pointers are safe.
+     This is turned off for code that imports the "unsafe" package,
+     because using unsafe.pointer violates C style aliasing
+     requirements.  */
+  opts->x_flag_strict_aliasing = 1;
+
+  /* Default to avoiding range issues for complex multiply and
+     divide.  */
+  opts->x_flag_complex_method = 2;
+
+  /* The builtin math functions should not set errno.  */
+  opts->x_flag_errno_math = 0;
+
+  /* By default assume that floating point math does not trap.  */
+  opts->x_flag_trapping_math = 0;
+
+  /* We turn on stack splitting if we can.  */
+  if (targetm.supports_split_stack (false, opts))
+    opts->x_flag_split_stack = 1;
+
+  /* Exceptions are used to handle recovering from panics.  */
+  opts->x_flag_exceptions = 1;
+  opts->x_flag_non_call_exceptions = 1;
+}
+
+/* Handle Go specific options.  Return 0 if we didn't do anything.  */
+
+static bool
+go_langhook_handle_option (
+    size_t scode,
+    const char *arg,
+    int value ATTRIBUTE_UNUSED,
+    int kind ATTRIBUTE_UNUSED,
+    location_t loc ATTRIBUTE_UNUSED,
+    const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
+  enum opt_code code = (enum opt_code) scode;
+  bool ret = true;
+
+  switch (code)
+    {
+    case OPT_I:
+    case OPT_L:
+      /* For the compiler, we currently handle -I and -L exactly the
+        same way: they give us a directory to search for import
+        statements.  */
+      go_add_search_path (arg);
+      break;
+
+    case OPT_fgo_dump_:
+      ret = go_enable_dump (arg) ? true : false;
+      break;
+
+    case OPT_fgo_prefix_:
+      go_set_prefix (arg);
+      break;
+
+    default:
+      /* Just return 1 to indicate that the option is valid.  */
+      break;
+    }
+
+  return ret;
+}
+
+/* Run after parsing options.  */
+
+static bool
+go_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED)
+{
+  gcc_assert (num_in_fnames > 0);
+
+  if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT)
+    flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
+
+  /* Returning false means that the backend should be used.  */
+  return false;
+}
+
+static void
+go_langhook_parse_file (void)
+{
+  go_parse_input_files (in_fnames, num_in_fnames, flag_syntax_only,
+                       go_require_return_statement);
+}
+
+static tree
+go_langhook_type_for_size (unsigned int bits, int unsignedp)
+{
+  return go_type_for_size (bits, unsignedp);
+}
+
+static tree
+go_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
+{
+  return go_type_for_mode (mode, unsignedp);
+}
+
+/* Record a builtin function.  We just ignore builtin functions.  */
+
+static tree
+go_langhook_builtin_function (tree decl)
+{
+  return decl;
+}
+
+static int
+go_langhook_global_bindings_p (void)
+{
+  return current_function_decl == NULL ? 1 : 0;
+}
+
+/* Push a declaration into the current binding level.  We can't
+   usefully implement this since we don't want to convert from tree
+   back to one of our internal data structures.  I think the only way
+   this is used is to record a decl which is to be returned by
+   getdecls, and we could implement it for that purpose if
+   necessary.  */
+
+static tree
+go_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+/* This hook is used to get the current list of declarations as trees.
+   We don't support that; instead we use the write_globals hook.  This
+   can't simply crash because it is called by -gstabs.  */
+
+static tree
+go_langhook_getdecls (void)
+{
+  return NULL;
+}
+
+/* Write out globals.  */
+
+static void
+go_langhook_write_globals (void)
+{
+  go_write_globals ();
+}
+
+/* Go specific gimplification.  We need to gimplify
+   CALL_EXPR_STATIC_CHAIN, because the gimplifier doesn't handle
+   it.  */
+
+static int
+go_langhook_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
+{
+  if (TREE_CODE (*expr_p) == CALL_EXPR
+      && CALL_EXPR_STATIC_CHAIN (*expr_p) != NULL_TREE)
+    gimplify_expr (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, post_p,
+                  is_gimple_val, fb_rvalue);
+  return GS_UNHANDLED;
+}
+
+/* Return a decl for the exception personality function.  The function
+   itself is implemented in libgo/runtime/go-unwind.c.  */
+
+static tree
+go_langhook_eh_personality (void)
+{
+  static tree personality_decl;
+  if (personality_decl == NULL_TREE)
+    {
+      personality_decl = build_personality_function ("gccgo");
+      go_preserve_from_gc (personality_decl);
+    }
+  return personality_decl;
+}
+
+/* Functions called directly by the generic backend.  */
+
+tree
+convert (tree type, tree expr)
+{
+  if (type == error_mark_node
+      || expr == error_mark_node
+      || TREE_TYPE (expr) == error_mark_node)
+    return error_mark_node;
+
+  if (type == TREE_TYPE (expr))
+    return expr;
+
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
+    return fold_convert (type, expr);
+
+  switch (TREE_CODE (type))
+    {
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+      return fold_convert (type, expr);
+    case INTEGER_TYPE:
+      return fold (convert_to_integer (type, expr));
+    case POINTER_TYPE:
+      return fold (convert_to_pointer (type, expr));
+    case REAL_TYPE:
+      return fold (convert_to_real (type, expr));
+    case COMPLEX_TYPE:
+      return fold (convert_to_complex (type, expr));
+    default:
+      break;
+    }
+
+  gcc_unreachable ();
+}
+
+/* FIXME: This is a hack to preserve trees that we create from the
+   garbage collector.  */
+
+static GTY(()) tree go_gc_root;
+
+void
+go_preserve_from_gc (tree t)
+{
+  go_gc_root = tree_cons (NULL_TREE, t, go_gc_root);
+}
+
+/* Convert an identifier for use in an error message.  */
+
+const char *
+go_localize_identifier (const char *ident)
+{
+  return identifier_to_locale (ident);
+}
+
+#undef LANG_HOOKS_NAME
+#undef LANG_HOOKS_INIT
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#undef LANG_HOOKS_INIT_OPTIONS_STRUCT
+#undef LANG_HOOKS_HANDLE_OPTION
+#undef LANG_HOOKS_POST_OPTIONS
+#undef LANG_HOOKS_PARSE_FILE
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#undef LANG_HOOKS_PUSHDECL
+#undef LANG_HOOKS_GETDECLS
+#undef LANG_HOOKS_WRITE_GLOBALS
+#undef LANG_HOOKS_GIMPLIFY_EXPR
+#undef LANG_HOOKS_EH_PERSONALITY
+
+#define LANG_HOOKS_NAME                        "GNU Go"
+#define LANG_HOOKS_INIT                        go_langhook_init
+#define LANG_HOOKS_OPTION_LANG_MASK    go_langhook_option_lang_mask
+#define LANG_HOOKS_INIT_OPTIONS_STRUCT go_langhook_init_options_struct
+#define LANG_HOOKS_HANDLE_OPTION       go_langhook_handle_option
+#define LANG_HOOKS_POST_OPTIONS                go_langhook_post_options
+#define LANG_HOOKS_PARSE_FILE          go_langhook_parse_file
+#define LANG_HOOKS_TYPE_FOR_MODE       go_langhook_type_for_mode
+#define LANG_HOOKS_TYPE_FOR_SIZE       go_langhook_type_for_size
+#define LANG_HOOKS_BUILTIN_FUNCTION    go_langhook_builtin_function
+#define LANG_HOOKS_GLOBAL_BINDINGS_P   go_langhook_global_bindings_p
+#define LANG_HOOKS_PUSHDECL            go_langhook_pushdecl
+#define LANG_HOOKS_GETDECLS            go_langhook_getdecls
+#define LANG_HOOKS_WRITE_GLOBALS       go_langhook_write_globals
+#define LANG_HOOKS_GIMPLIFY_EXPR       go_langhook_gimplify_expr
+#define LANG_HOOKS_EH_PERSONALITY      go_langhook_eh_personality
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-go-go-lang.h"
+#include "gtype-go.h"
diff --git a/gcc/go/go-system.h b/gcc/go/go-system.h
new file mode 100644 (file)
index 0000000..e56952d
--- /dev/null
@@ -0,0 +1,153 @@
+// go-system.h -- Go frontend inclusion of gcc header files   -*- C++ -*-
+// Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC 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, or (at your option) any later
+// version.
+
+// GCC 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef GO_SYSTEM_H
+#define GO_SYSTEM_H
+
+#include "config.h"
+
+// These must be included before the #poison declarations in system.h.
+
+#include <algorithm>
+#include <string>
+#include <list>
+#include <map>
+#include <set>
+#include <vector>
+
+#if defined(HAVE_UNORDERED_MAP)
+
+# include <unordered_map>
+# include <unordered_set>
+
+# define Unordered_map(KEYTYPE, VALTYPE) \
+       std::unordered_map<KEYTYPE, VALTYPE>
+
+# define Unordered_map_hash(KEYTYPE, VALTYPE, HASHFN, EQFN) \
+       std::unordered_map<KEYTYPE, VALTYPE, HASHFN, EQFN>
+
+# define Unordered_set(KEYTYPE) \
+       std::unordered_set<KEYTYPE>
+
+# define Unordered_set_hash(KEYTYPE, HASHFN, EQFN) \
+       std::unordered_set<KEYTYPE, HASHFN, EQFN>
+
+#elif defined(HAVE_TR1_UNORDERED_MAP)
+
+# include <tr1/unordered_map>
+# include <tr1/unordered_set>
+
+# define Unordered_map(KEYTYPE, VALTYPE) \
+       std::tr1::unordered_map<KEYTYPE, VALTYPE>
+
+# define Unordered_map_hash(KEYTYPE, VALTYPE, HASHFN, EQFN) \
+       std::tr1::unordered_map<KEYTYPE, VALTYPE, HASHFN, EQFN>
+
+# define Unordered_set(KEYTYPE) \
+       std::tr1::unordered_set<KEYTYPE>
+
+# define Unordered_set_hash(KEYTYPE, HASHFN, EQFN) \
+       std::tr1::unordered_set<KEYTYPE, HASHFN, EQFN>
+
+#elif defined(HAVE_EXT_HASH_MAP)
+
+# include <ext/hash_map>
+# include <ext/hash_set>
+
+# define Unordered_map(KEYTYPE, VALTYPE) \
+       __gnu_cxx::hash_map<KEYTYPE, VALTYPE>
+
+# define Unordered_map_hash(KEYTYPE, VALTYPE, HASHFN, EQFN) \
+       __gnu_cxx::hash_map<KEYTYPE, VALTYPE, HASHFN, EQFN>
+
+# define Unordered_set(KEYTYPE) \
+       __gnu_cxx::hash_set<KEYTYPE>
+
+# define Unordered_set_hash(KEYTYPE, HASHFN, EQFN) \
+       __gnu_cxx::hash_set<KEYTYPE, HASHFN, EQFN>
+
+// Provide hash functions for strings and pointers.
+
+namespace __gnu_cxx
+{
+
+template<>
+struct hash<std::string>
+{
+  size_t
+  operator()(std::string s) const
+  { return __stl_hash_string(s.c_str()); }
+};
+
+template<typename T>
+struct hash<T*>
+{
+  size_t
+  operator()(T* p) const
+  { return reinterpret_cast<size_t>(p); }
+};
+
+}
+
+#else
+
+# define Unordered_map(KEYTYPE, VALTYPE) \
+       std::map<KEYTYPE, VALTYPE>
+
+# define Unordered_set(KEYTYPE) \
+       std::set<KEYTYPE>
+
+// We could make this work by writing an adapter class which
+// implemented operator< in terms of the hash function.
+# error "requires hash table type"
+
+#endif
+
+// We don't really need iostream, but some versions of gmp.h include
+// it when compiled with C++, which means that we need to include it
+// before the macro magic of safe-ctype.h, which is included by
+// system.h.
+#include <iostream>
+
+// Some versions of gmp.h assume that #include <iostream> will define
+// std::FILE.  This is not true with libstdc++ 4.3 and later.  This is
+// fixed in GMP 4.3, but at this point we don't know which version of
+// GMP is in use.  Since the top level configure script accepts GMP
+// 4.2, at least for now we #include <cstdio> to ensure that GMP 4.2
+// will work.  FIXME: This can be removed when we require GMP 4.3 or
+// later.
+#include <cstdio>
+
+#ifndef ENABLE_BUILD_WITH_CXX
+extern "C"
+{
+#endif
+
+#include "system.h"
+#include "ansidecl.h"
+#include "coretypes.h"
+
+#include "diagnostic-core.h"   /* For error_at and friends.  */
+#include "input.h"             /* For source_location.  */
+
+#ifndef ENABLE_BUILD_WITH_CXX
+} // End extern "C"
+#endif
+
+#endif // !defined(GO_SYSTEM_H)
diff --git a/gcc/go/gofrontend/LICENSE b/gcc/go/gofrontend/LICENSE
new file mode 100644 (file)
index 0000000..d77335f
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (c) 2009 The Go 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.
+//
+// Subject to the terms and conditions of this License, Google hereby
+// grants to You a perpetual, worldwide, non-exclusive, no-charge,
+// royalty-free, irrevocable (except as stated in this section) patent
+// license to make, have made, use, offer to sell, sell, import, and
+// otherwise transfer this implementation of Go, where such license
+// applies only to those patent claims licensable by Google that are
+// necessarily infringed by use of this implementation of Go. If You
+// institute patent litigation against any entity (including a
+// cross-claim or counterclaim in a lawsuit) alleging that this
+// implementation of Go or a Contribution incorporated within this
+// implementation of Go constitutes direct or contributory patent
+// infringement, then any patent licenses granted to You under this
+// License for this implementation of Go shall terminate as of the date
+// such litigation is filed.
diff --git a/gcc/go/gofrontend/README b/gcc/go/gofrontend/README
new file mode 100644 (file)
index 0000000..dd13710
--- /dev/null
@@ -0,0 +1,57 @@
+See ../README.
+
+The frontend is written in C++.
+
+The frontend lexes and parses the input into an IR specific to this
+frontend known as gogo.  It then runs a series of passes over the
+code.
+
+Finally it converts gogo to gcc's GENERIC.  A goal is to move the gcc
+support code into a gcc-interface subdirectory.  The gcc code will be
+put under the GPL.  The rest of the frontend will not include any gcc
+header files.
+
+Issues to be faced in this transition:
+
+* Representation of source locations.
+  + Currently the frontend uses gcc's source_location codes, using the
+    interface in libcpp/line-map.h.
+
+* Handling of error messages.
+  + Currently the frontend uses gcc's error_at and warning_at
+    functions.
+  + Currently the frontend uses gcc's diagnostic formatter, using
+    features such as %<%> for appropriate quoting.
+  + Localization may be an issue.
+
+* Use of gcc_assert and gcc_unreachable.
+
+This compiler works, but the code is a work in progress.  Notably, the
+support for garbage collection is ineffective and needs a complete
+rethinking.  The frontend pays little attention to its memory usage
+and rarely frees any memory.  The code could use a general cleanup
+which we have not had time to do.
+
+Contributing
+=============
+
+To contribute patches to the files in this directory, please see
+http://golang.org/doc/gccgo_contribute.html .
+
+Changes to these files require a copyright assignment to Google.  This
+is required to permit the changes to be copied to the gcc repository,
+as Google has a copyright assignment with the Free Software
+Foundation.
+
+If you are the copyright holder, you will need to agree to the
+individual contributor license agreement at
+http://code.google.com/legal/individual-cla-v1.0.html.  This agreement
+can be completed online.
+
+If your organization is the copyright holder, the organization will
+need to agree to the corporate contributor license agreement at
+http://code.google.com/legal/corporate-cla-v1.0.html.
+
+If the copyright holder for your code has already completed the
+agreement in connection with another Google open source project, it
+does not need to be completed again.
diff --git a/gcc/go/gofrontend/dataflow.cc b/gcc/go/gofrontend/dataflow.cc
new file mode 100644 (file)
index 0000000..8170d0a
--- /dev/null
@@ -0,0 +1,278 @@
+// dataflow.cc -- Go frontend dataflow.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "gogo.h"
+#include "expressions.h"
+#include "statements.h"
+#include "dataflow.h"
+
+// This class is used to traverse the tree to look for uses of
+// variables.
+
+class Dataflow_traverse_expressions : public Traverse
+{
+ public:
+  Dataflow_traverse_expressions(Dataflow* dataflow, Statement* statement)
+    : Traverse(traverse_blocks | traverse_expressions),
+      dataflow_(dataflow), statement_(statement)
+  { }
+
+ protected:
+  // Only look at top-level expressions: do not descend into blocks.
+  // They will be examined via Dataflow_traverse_statements.
+  int
+  block(Block*)
+  { return TRAVERSE_SKIP_COMPONENTS; }
+
+  int
+  expression(Expression**);
+
+ private:
+  // The dataflow information.
+  Dataflow* dataflow_;
+  // The Statement in which we are looking.
+  Statement* statement_;
+};
+
+// Given an expression, return the Named_object that it refers to, if
+// it is a local variable.
+
+static Named_object*
+get_var(Expression* expr)
+{
+  Var_expression* ve = expr->var_expression();
+  if (ve == NULL)
+    return NULL;
+  Named_object* no = ve->named_object();
+  gcc_assert(no->is_variable() || no->is_result_variable());
+  if (no->is_variable() && no->var_value()->is_global())
+    return NULL;
+  return no;
+}
+
+// Look for a reference to a variable in an expression.
+
+int
+Dataflow_traverse_expressions::expression(Expression** expr)
+{
+  Named_object* no = get_var(*expr);
+  if (no != NULL)
+    this->dataflow_->add_ref(no, this->statement_);
+  return TRAVERSE_CONTINUE;
+}
+
+// This class is used to handle an assignment statement.
+
+class Dataflow_traverse_assignment : public Traverse_assignments
+{
+ public:
+  Dataflow_traverse_assignment(Dataflow* dataflow, Statement* statement)
+    : dataflow_(dataflow), statement_(statement)
+  { }
+
+ protected:
+  void
+  initialize_variable(Named_object*);
+
+  void
+  assignment(Expression** lhs, Expression** rhs);
+
+  void
+  value(Expression**, bool, bool);
+
+ private:
+  // The dataflow information.
+  Dataflow* dataflow_;
+  // The Statement in which we are looking.
+  Statement* statement_;
+};
+
+// Handle a variable initialization.
+
+void
+Dataflow_traverse_assignment::initialize_variable(Named_object* var)
+{
+  Expression* init = var->var_value()->init();
+  this->dataflow_->add_def(var, init, this->statement_, true);
+  if (init != NULL)
+    {
+      Expression* e = init;
+      this->value(&e, true, true);
+      gcc_assert(e == init);
+    }
+}
+
+// Handle an assignment in a statement.
+
+void
+Dataflow_traverse_assignment::assignment(Expression** plhs, Expression** prhs)
+{
+  Named_object* no = get_var(*plhs);
+  if (no != NULL)
+    {
+      Expression* rhs = prhs == NULL ? NULL : *prhs;
+      this->dataflow_->add_def(no, rhs, this->statement_, false);
+    }
+  else
+    {
+      // If this is not a variable it may be some computed lvalue, and
+      // we want to look for references to variables in that lvalue.
+      this->value(plhs, false, false);
+    }
+  if (prhs != NULL)
+    this->value(prhs, true, false);
+}
+
+// Handle a value in a statement.
+
+void
+Dataflow_traverse_assignment::value(Expression** pexpr, bool, bool)
+{
+  Named_object* no = get_var(*pexpr);
+  if (no != NULL)
+    this->dataflow_->add_ref(no, this->statement_);
+  else
+    {
+      Dataflow_traverse_expressions dte(this->dataflow_, this->statement_);
+      Expression::traverse(pexpr, &dte);
+    }
+}
+
+// This class is used to traverse the tree to look for statements.
+
+class Dataflow_traverse_statements : public Traverse
+{
+ public:
+  Dataflow_traverse_statements(Dataflow* dataflow)
+    : Traverse(traverse_statements),
+      dataflow_(dataflow)
+  { }
+
+ protected:
+  int
+  statement(Block*, size_t* pindex, Statement*);
+
+ private:
+  // The dataflow information.
+  Dataflow* dataflow_;
+};
+
+// For each Statement, we look for expressions.
+
+int
+Dataflow_traverse_statements::statement(Block* block, size_t* pindex,
+                                       Statement *statement)
+{
+  Dataflow_traverse_assignment dta(this->dataflow_, statement);
+  if (!statement->traverse_assignments(&dta))
+    {
+      Dataflow_traverse_expressions dte(this->dataflow_, statement);
+      statement->traverse(block, pindex, &dte);
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Compare variables.
+
+bool
+Dataflow::Compare_vars::operator()(const Named_object* no1,
+                                  const Named_object* no2) const
+{
+  if (no1->name() < no2->name())
+    return true;
+  if (no1->name() > no2->name())
+    return false;
+
+  // We can have two different variables with the same name.
+  source_location loc1 = no1->location();
+  source_location loc2 = no2->location();
+  if (loc1 < loc2)
+    return false;
+  if (loc1 > loc2)
+    return true;
+
+  if (no1 == no2)
+    return false;
+
+  // We can't have two variables with the same name in the same
+  // location.
+  gcc_unreachable();
+}
+
+// Class Dataflow.
+
+Dataflow::Dataflow()
+  : defs_(), refs_()
+{
+}
+
+// Build the dataflow information.
+
+void
+Dataflow::initialize(Gogo* gogo)
+{
+  Dataflow_traverse_statements dts(this);
+  gogo->traverse(&dts);
+}
+
+// Add a definition of a variable.
+
+void
+Dataflow::add_def(Named_object* var, Expression* val, Statement* statement,
+                 bool is_init)
+{
+  Defs* defnull = NULL;
+  std::pair<Defmap::iterator, bool> ins =
+    this->defs_.insert(std::make_pair(var, defnull));
+  if (ins.second)
+    ins.first->second = new Defs;
+  Def def;
+  def.statement = statement;
+  def.val = val;
+  def.is_init = is_init;
+  ins.first->second->push_back(def);
+}
+
+// Add a reference to a variable.
+
+void
+Dataflow::add_ref(Named_object* var, Statement* statement)
+{
+  Refs* refnull = NULL;
+  std::pair<Refmap::iterator, bool> ins =
+    this->refs_.insert(std::make_pair(var, refnull));
+  if (ins.second)
+    ins.first->second = new Refs;
+  Ref ref;
+  ref.statement = statement;
+  ins.first->second->push_back(ref);
+}
+
+// Return the definitions of a variable.
+
+const Dataflow::Defs*
+Dataflow::find_defs(Named_object* var) const
+{
+  Defmap::const_iterator p = this->defs_.find(var);
+  if (p == this->defs_.end())
+    return NULL;
+  else
+    return p->second;
+}
+
+// Return the references of a variable.
+
+const Dataflow::Refs*
+Dataflow::find_refs(Named_object* var) const
+{
+  Refmap::const_iterator p = this->refs_.find(var);
+  if (p == this->refs_.end())
+    return NULL;
+  else
+    return p->second;
+}
diff --git a/gcc/go/gofrontend/dataflow.h b/gcc/go/gofrontend/dataflow.h
new file mode 100644 (file)
index 0000000..a75c8e6
--- /dev/null
@@ -0,0 +1,91 @@
+// dataflow.h -- Go frontend dataflow.    -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_DATAFLOW_H
+#define GO_DATAFLOW_H
+
+class Expression;
+class Named_object;
+class Statement;
+
+// Dataflow information about the Go program.
+
+class Dataflow
+{
+ public:
+  // A variable definition.
+  struct Def
+  {
+    // The statement where the variable is defined.
+    Statement* statement;
+    // The value to which the variable is set.  This may be NULL.
+    Expression* val;
+    // Whether this is an initialization of the variable.
+    bool is_init;
+  };
+
+  // A variable reference.
+  struct Ref
+  {
+    // The statement where the variable is referenced.
+    Statement* statement;
+  };
+
+  // A list of defs.
+  typedef std::vector<Def> Defs;
+
+  // A list of refs.
+  typedef std::vector<Ref> Refs;
+
+  Dataflow();
+
+  // Initialize the dataflow information.
+  void
+  initialize(Gogo*);
+
+  // Add a definition of a variable.  STATEMENT assigns a value to
+  // VAR.  VAL is the value if it is known, NULL otherwise.
+  void
+  add_def(Named_object* var, Expression* val, Statement* statement,
+         bool is_init);
+
+  // Add a reference to a variable.  VAR is the variable, and
+  // STATEMENT is the statement which refers to it.
+  void
+  add_ref(Named_object* var, Statement* statement);
+
+  // Return the definitions of VAR--the places where it is set.
+  const Defs*
+  find_defs(Named_object* var) const;
+
+  // Return the references to VAR--the places where it is used.
+  const Refs*
+  find_refs(Named_object* var) const;
+
+ private:
+  // Order variables in the map.
+  struct Compare_vars
+  {
+    bool
+    operator()(const Named_object*, const Named_object*) const;
+  };
+
+  // Map from variables to a list of defs of the variable.  We use a
+  // map rather than a hash table because the order in which we
+  // process variables may affect the resulting code.
+  typedef std::map<Named_object*, Defs*, Compare_vars> Defmap;
+
+  // Map from variables to a list of refs to the vairable.
+  typedef std::map<Named_object*, Refs*, Compare_vars> Refmap;
+
+  // Variable defs.
+  Defmap defs_;
+  // Variable refs;
+  Refmap refs_;
+};
+
+
+#endif // !defined(GO_DATAFLOW_H)
diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc
new file mode 100644 (file)
index 0000000..6b42d0c
--- /dev/null
@@ -0,0 +1,441 @@
+// export.cc -- Export declarations in Go frontend.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+#include "sha1.h"
+
+#ifndef ENABLE_BUILD_WITH_CXX
+extern "C"
+{
+#endif
+
+#include "machmode.h"
+#include "output.h"
+#include "target.h"
+
+#ifndef ENABLE_BUILD_WITH_CXX
+}
+#endif
+
+#include "gogo.h"
+#include "types.h"
+#include "statements.h"
+#include "export.h"
+
+// This file handles exporting global declarations.
+
+// Class Export.
+
+// Version 1 magic number.
+
+const int Export::v1_magic_len;
+
+const char Export::v1_magic[Export::v1_magic_len] =
+  {
+    'v', '1', ';', '\n'
+  };
+
+const int Export::v1_checksum_len;
+
+// Constructor.
+
+Export::Export(Stream* stream)
+  : stream_(stream), type_refs_(), type_index_(1)
+{
+}
+
+// A functor to sort Named_object pointers by name.
+
+struct Sort_bindings
+{
+  bool
+  operator()(const Named_object* n1, const Named_object* n2) const
+  { return n1->name() < n2->name(); }
+};
+
+// Return true if we should export NO.
+
+static bool
+should_export(Named_object* no)
+{
+  // We only export objects which are locally defined.
+  if (no->package() != NULL)
+    return false;
+
+  // We don't export packages.
+  if (no->is_package())
+    return false;
+
+  // We don't export hidden names.
+  if (Gogo::is_hidden_name(no->name()))
+    return false;
+
+  // We don't export nested functions.
+  if (no->is_function() && no->func_value()->enclosing() != NULL)
+    return false;
+
+  // We don't export thunks.
+  if (no->is_function() && Gogo::is_thunk(no))
+    return false;
+
+  // Methods are exported with the type, not here.
+  if (no->is_function()
+      && no->func_value()->type()->is_method())
+    return false;
+  if (no->is_function_declaration()
+      && no->func_declaration_value()->type()->is_method())
+    return false;
+
+  // Don't export dummy global variables created for initializers when
+  // used with sinks.
+  if (no->is_variable() && no->name()[0] == '_' && no->name()[1] == '.')
+    return false;
+
+  return true;
+}
+
+// Export those identifiers marked for exporting.
+
+void
+Export::export_globals(const std::string& package_name,
+                      const std::string& unique_prefix,
+                      int package_priority,
+                      const std::string& import_init_fn,
+                      const std::set<Import_init>& imported_init_fns,
+                      const Bindings* bindings)
+{
+  // If there have been any errors so far, don't try to export
+  // anything.  That way the export code doesn't have to worry about
+  // mismatched types or other confusions.
+  if (saw_errors())
+    return;
+
+  // Export the symbols in sorted order.  That will reduce cases where
+  // irrelevant changes to the source code affect the exported
+  // interface.
+  std::vector<Named_object*> exports;
+  exports.reserve(bindings->size_definitions());
+
+  for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
+       p != bindings->end_definitions();
+       ++p)
+    if (should_export(*p))
+      exports.push_back(*p);
+
+  for (Bindings::const_declarations_iterator p =
+        bindings->begin_declarations();
+       p != bindings->end_declarations();
+       ++p)
+    {
+      // We export a function declaration as it may be implemented in
+      // supporting C code.  We do not export type declarations.
+      if (p->second->is_function_declaration()
+         && should_export(p->second))
+       exports.push_back(p->second);
+    }
+
+  std::sort(exports.begin(), exports.end(), Sort_bindings());
+
+  // Although the export data is readable, at least this version is,
+  // it is conceptually a binary format.  Start with a four byte
+  // verison number.
+  this->write_bytes(Export::v1_magic, Export::v1_magic_len);
+
+  // The package name.
+  this->write_c_string("package ");
+  this->write_string(package_name);
+  this->write_c_string(";\n");
+
+  // The unique prefix.  This prefix is used for all global symbols.
+  this->write_c_string("prefix ");
+  this->write_string(unique_prefix);
+  this->write_c_string(";\n");
+
+  // The package priority.
+  char buf[100];
+  snprintf(buf, sizeof buf, "priority %d;\n", package_priority);
+  this->write_c_string(buf);
+
+  this->write_imported_init_fns(package_name, package_priority, import_init_fn,
+                               imported_init_fns);
+
+  // FIXME: It might be clever to add something about the processor
+  // and ABI being used, although ideally any problems in that area
+  // would be caught by the linker.
+
+  for (std::vector<Named_object*>::const_iterator p = exports.begin();
+       p != exports.end();
+       ++p)
+    (*p)->export_named_object(this);
+
+  std::string checksum = this->stream_->checksum();
+  std::string s = "checksum ";
+  for (std::string::const_iterator p = checksum.begin();
+       p != checksum.end();
+       ++p)
+    {
+      unsigned char c = *p;
+      unsigned int dig = c >> 4;
+      s += dig < 10 ? '0' + dig : 'A' + dig - 10;
+      dig = c & 0xf;
+      s += dig < 10 ? '0' + dig : 'A' + dig - 10;
+    }
+  s += ";\n";
+  this->stream_->write_checksum(s);
+}
+
+// Write out the import control variables for this package.
+
+void
+Export::write_imported_init_fns(
+    const std::string& package_name,
+    int priority,
+    const std::string& import_init_fn,
+    const std::set<Import_init>& imported_init_fns)
+{
+  if (import_init_fn.empty() && imported_init_fns.empty())
+    return;
+
+  this->write_c_string("import");
+
+  if (!import_init_fn.empty())
+    {
+      this->write_c_string(" ");
+      this->write_string(package_name);
+      this->write_c_string(" ");
+      this->write_string(import_init_fn);
+      char buf[100];
+      snprintf(buf, sizeof buf, " %d", priority);
+      this->write_c_string(buf);
+    }
+
+  if (!imported_init_fns.empty())
+    {
+      // Sort the list of functions for more consistent output.
+      std::vector<Import_init> v;
+      for (std::set<Import_init>::const_iterator p = imported_init_fns.begin();
+          p != imported_init_fns.end();
+          ++p)
+       v.push_back(*p);
+      std::sort(v.begin(), v.end());
+
+      for (std::vector<Import_init>::const_iterator p = v.begin();
+          p != v.end();
+          ++p)
+       {
+         this->write_c_string(" ");
+         this->write_string(p->package_name());
+         this->write_c_string(" ");
+         this->write_string(p->init_name());
+         char buf[100];
+         snprintf(buf, sizeof buf, " %d", p->priority());
+         this->write_c_string(buf);
+       }
+    }
+
+  this->write_c_string(";\n");
+}
+
+// Export a type.  We have to ensure that on import we create a single
+// Named_type node for each named type.  We do this by keeping a hash
+// table mapping named types to reference numbers.  The first time we
+// see a named type we assign it a reference number by making an entry
+// in the hash table.  If we see it again, we just refer to the
+// reference number.
+
+// Named types are, of course, associated with packages.  Note that we
+// may see a named type when importing one package, and then later see
+// the same named type when importing a different package.  The home
+// package may or may not be imported during this compilation.  The
+// reference number scheme has to get this all right.  Basic approach
+// taken from "On the Linearization of Graphs and Writing Symbol
+// Files" by Robert Griesemer.
+
+void
+Export::write_type(const Type* type)
+{
+  // We don't want to assign a reference number to a forward
+  // declaration to a type which was defined later.
+  type = type->forwarded();
+
+  Type_refs::const_iterator p = this->type_refs_.find(type);
+  if (p != this->type_refs_.end())
+    {
+      // This type was already in the table.
+      int index = p->second;
+      gcc_assert(index != 0);
+      char buf[30];
+      snprintf(buf, sizeof buf, "<type %d>", index);
+      this->write_c_string(buf);
+      return;
+    }
+
+  const Named_type* named_type = type->named_type();
+  const Forward_declaration_type* forward = type->forward_declaration_type();
+
+  int index = this->type_index_;
+  ++this->type_index_;
+
+  char buf[30];
+  snprintf(buf, sizeof buf, "<type %d ", index);
+  this->write_c_string(buf);
+
+  if (named_type != NULL || forward != NULL)
+    {
+      const Named_object* named_object;
+      if (named_type != NULL)
+       {
+         // The builtin types should have been predefined.
+         gcc_assert(named_type->location() != BUILTINS_LOCATION
+                    || (named_type->named_object()->package()->name()
+                        == "unsafe"));
+         named_object = named_type->named_object();
+       }
+      else
+       named_object = forward->named_object();
+
+      const Package* package = named_object->package();
+
+      std::string s = "\"";
+      if (package != NULL && !Gogo::is_hidden_name(named_object->name()))
+       {
+         s += package->unique_prefix();
+         s += '.';
+         s += package->name();
+         s += '.';
+       }
+      s += named_object->name();
+      s += "\" ";
+      this->write_string(s);
+
+      // We must add a named type to the table now, since the
+      // definition of the type may refer to the named type via a
+      // pointer.
+      this->type_refs_[type] = index;
+    }
+
+  type->export_type(this);
+
+  this->write_c_string(">");
+
+  if (named_type == NULL)
+    this->type_refs_[type] = index;
+}
+
+// Add the builtin types to the export table.
+
+void
+Export::register_builtin_types(Gogo* gogo)
+{
+  this->register_builtin_type(gogo, "int8", BUILTIN_INT8);
+  this->register_builtin_type(gogo, "int16", BUILTIN_INT16);
+  this->register_builtin_type(gogo, "int32", BUILTIN_INT32);
+  this->register_builtin_type(gogo, "int64", BUILTIN_INT64);
+  this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8);
+  this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16);
+  this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32);
+  this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
+  this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
+  this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
+  this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
+  this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
+  this->register_builtin_type(gogo, "int", BUILTIN_INT);
+  this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
+  this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
+  this->register_builtin_type(gogo, "float", BUILTIN_FLOAT);
+  this->register_builtin_type(gogo, "complex", BUILTIN_COMPLEX);
+  this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
+  this->register_builtin_type(gogo, "string", BUILTIN_STRING);
+}
+
+// Register one builtin type in the export table.
+
+void
+Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
+{
+  Named_object* named_object = gogo->lookup_global(name);
+  gcc_assert(named_object != NULL && named_object->is_type());
+  std::pair<Type_refs::iterator, bool> ins =
+    this->type_refs_.insert(std::make_pair(named_object->type_value(), code));
+  gcc_assert(ins.second);
+
+  // We also insert the underlying type.  We can see the underlying
+  // type at least for string and bool.
+  Type* real_type = named_object->type_value()->real_type();
+  ins = this->type_refs_.insert(std::make_pair(real_type, code));
+  gcc_assert(ins.second);
+}
+
+// Class Export::Stream.
+
+Export::Stream::Stream()
+{
+  this->checksum_ = new sha1_ctx;
+  memset(this->checksum_, 0, sizeof(sha1_ctx));
+  sha1_init_ctx(this->checksum_);
+}
+
+Export::Stream::~Stream()
+{
+}
+
+// Write bytes to the stream.  This keeps a checksum of bytes as they
+// go by.
+
+void
+Export::Stream::write_and_sum_bytes(const char* bytes, size_t length)
+{
+  sha1_process_bytes(bytes, length, this->checksum_);
+  this->do_write(bytes, length);
+}
+
+// Get the checksum.
+
+std::string
+Export::Stream::checksum()
+{
+  // Use a union to provide the required alignment.
+  union
+  {
+    char checksum[Export::v1_checksum_len];
+    long align;
+  } u;
+  sha1_finish_ctx(this->checksum_, u.checksum);
+  return std::string(u.checksum, Export::v1_checksum_len);
+}
+
+// Write the checksum string to the export data.
+
+void
+Export::Stream::write_checksum(const std::string& s)
+{
+  this->do_write(s.data(), s.length());
+}
+
+// Class Stream_to_section.
+
+Stream_to_section::Stream_to_section()
+  : section_(NULL)
+{
+}
+
+// Write data to a section.
+
+void
+Stream_to_section::do_write(const char* bytes, size_t length)
+{
+  section* sec = (section*) this->section_;
+  if (sec == NULL)
+    {
+      gcc_assert(targetm.have_named_sections);
+
+      sec = get_section(".go_export", SECTION_DEBUG, NULL);
+      this->section_ = (void*) sec;
+    }
+
+  switch_to_section(sec);
+  assemble_string(bytes, length);
+}
diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h
new file mode 100644 (file)
index 0000000..90c2465
--- /dev/null
@@ -0,0 +1,191 @@
+// export.h -- Export declarations in Go frontend.     -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_EXPORT_H
+#define GO_EXPORT_H
+
+struct sha1_ctx;
+class Gogo;
+class Import_init;
+class Bindings;
+class Type;
+
+// Codes used for the builtin types.  These are all negative to make
+// them easily distinct from the codes assigned by Export::write_type.
+// Note that these codes may not be changed!  Changing them would
+// break existing export data.
+
+enum Builtin_code
+{
+  BUILTIN_INT8 = -1,
+  BUILTIN_INT16 = -2,
+  BUILTIN_INT32 = -3,
+  BUILTIN_INT64 = -4,
+  BUILTIN_UINT8 = -5,
+  BUILTIN_UINT16 = -6,
+  BUILTIN_UINT32 = -7,
+  BUILTIN_UINT64 = -8,
+  BUILTIN_FLOAT32 = -9,
+  BUILTIN_FLOAT64 = -10,
+  BUILTIN_INT = -11,
+  BUILTIN_UINT = -12,
+  BUILTIN_UINTPTR = -13,
+  BUILTIN_FLOAT = -14,
+  BUILTIN_BOOL = -15,
+  BUILTIN_STRING = -16,
+  BUILTIN_COMPLEX64 = -17,
+  BUILTIN_COMPLEX128 = -18,
+  BUILTIN_COMPLEX = -19,
+
+  SMALLEST_BUILTIN_CODE = -19
+};
+
+// This class manages exporting Go declarations.  It handles the main
+// loop of exporting.  A pointer to this class is also passed to the
+// various specific export implementations.
+
+class Export
+{
+ public:
+  // The Stream class is an interface used to output the exported
+  // information.  The caller should instantiate a child of this
+  // class.
+  class Stream
+  {
+   public:
+    Stream();
+    virtual ~Stream();
+
+    // Write a string.
+    void
+    write_string(const std::string& s)
+    { this->write_and_sum_bytes(s.data(), s.length()); }
+
+    // Write a nul terminated string.
+    void
+    write_c_string(const char* s)
+    { this->write_and_sum_bytes(s, strlen(s)); }
+
+    // Write some bytes.
+    void
+    write_bytes(const char* bytes, size_t length)
+    { this->write_and_sum_bytes(bytes, length); }
+
+    // Return the raw bytes of the checksum data.
+    std::string
+    checksum();
+
+    // Write a checksum string to the stream.  This will be called at
+    // the end of the other output.
+    void
+    write_checksum(const std::string&);
+
+   protected:
+    // This function is called with data to export.  This data must be
+    // made available as a contiguous stream for the importer.
+    virtual void
+    do_write(const char* bytes, size_t length) = 0;
+
+  private:
+    void
+    write_and_sum_bytes(const char*, size_t);
+
+    // The checksum.
+    sha1_ctx* checksum_;
+  };
+
+  Export(Stream*);
+
+  // The magic code for version 1 export data.
+  static const int v1_magic_len = 4;
+  static const char v1_magic[v1_magic_len];
+
+  // The length of the v1 checksum string.
+  static const int v1_checksum_len = 20;
+
+  // Register the builtin types.
+  void
+  register_builtin_types(Gogo*);
+
+  // Export the identifiers in BINDINGS which are marked for export.
+  // The exporting is done via a series of calls to THIS->STREAM_.  If
+  // is nothing to export, this->stream_->write will not be called.
+  // UNIQUE_PREFIX is a prefix for all global symbols.
+  // PACKAGE_PRIORITY is the priority to use for this package.
+  // IMPORT_INIT_FN is the name of the import initialization function
+  // for this package; it will be empty if none is needed.
+  // IMPORTED_INIT_FNS is the list of initialization functions for
+  // imported packages.
+  void
+  export_globals(const std::string& package_name,
+                const std::string& unique_prefix,
+                int package_priority,
+                const std::string& import_init_fn,
+                const std::set<Import_init>& imported_init_fns,
+                const Bindings* bindings);
+
+  // Write a string to the export stream.
+  void
+  write_string(const std::string& s)
+  { this->stream_->write_string(s); }
+
+  // Write a nul terminated string to the export stream.
+  void
+  write_c_string(const char* s)
+  { this->stream_->write_c_string(s); }
+
+  // Write some bytes to the export stream.
+  void
+  write_bytes(const char* bytes, size_t length)
+  { this->stream_->write_bytes(bytes, length); }
+
+  // Write out a type.  This handles references back to previous
+  // definitions.
+  void
+  write_type(const Type*);
+
+ private:
+  Export(const Export&);
+  Export& operator=(const Export&);
+
+  // Write out the imported initialization functions.
+  void
+  write_imported_init_fns(const std::string& package_name, int priority,
+                         const std::string&, const std::set<Import_init>&);
+
+  // Register one builtin type.
+  void
+  register_builtin_type(Gogo*, const char* name, Builtin_code);
+
+  // Mapping from Type objects to a constant index.
+  typedef Unordered_map(const Type*, int) Type_refs;
+
+  // The stream to which we are writing data.
+  Stream* stream_;
+  // Type mappings.
+  Type_refs type_refs_;
+  // Index number of next type.
+  int type_index_;
+};
+
+// An export streamer which puts the export stream in a named section.
+
+class Stream_to_section : public Export::Stream
+{
+ public:
+  Stream_to_section();
+
+ protected:
+  void
+  do_write(const char*, size_t);
+
+ private:
+  // The section we are writing to; this is really union section
+  // defined in output.h.
+  void* section_;
+};
+
+#endif // !defined(GO_EXPORT_H)
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
new file mode 100644 (file)
index 0000000..f35b363
--- /dev/null
@@ -0,0 +1,12264 @@
+// expressions.cc -- Go frontend expression handling.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include <gmp.h>
+
+#ifndef ENABLE_BUILD_WITH_CXX
+extern "C"
+{
+#endif
+
+#include "toplev.h"
+#include "intl.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-iterator.h"
+#include "convert.h"
+#include "real.h"
+#include "realmpfr.h"
+#include "tm.h"
+#include "tm_p.h"
+
+#ifndef ENABLE_BUILD_WITH_CXX
+}
+#endif
+
+#include "go-c.h"
+#include "gogo.h"
+#include "types.h"
+#include "export.h"
+#include "import.h"
+#include "statements.h"
+#include "lex.h"
+#include "expressions.h"
+
+// Class Expression.
+
+Expression::Expression(Expression_classification classification,
+                      source_location location)
+  : classification_(classification), location_(location)
+{
+}
+
+Expression::~Expression()
+{
+}
+
+// If this expression has a constant integer value, return it.
+
+bool
+Expression::integer_constant_value(bool iota_is_constant, mpz_t val,
+                                  Type** ptype) const
+{
+  *ptype = NULL;
+  return this->do_integer_constant_value(iota_is_constant, val, ptype);
+}
+
+// If this expression has a constant floating point value, return it.
+
+bool
+Expression::float_constant_value(mpfr_t val, Type** ptype) const
+{
+  *ptype = NULL;
+  if (this->do_float_constant_value(val, ptype))
+    return true;
+  mpz_t ival;
+  mpz_init(ival);
+  Type* t;
+  bool ret;
+  if (!this->do_integer_constant_value(false, ival, &t))
+    ret = false;
+  else
+    {
+      mpfr_set_z(val, ival, GMP_RNDN);
+      ret = true;
+    }
+  mpz_clear(ival);
+  return ret;
+}
+
+// If this expression has a constant complex value, return it.
+
+bool
+Expression::complex_constant_value(mpfr_t real, mpfr_t imag,
+                                  Type** ptype) const
+{
+  *ptype = NULL;
+  if (this->do_complex_constant_value(real, imag, ptype))
+    return true;
+  Type *t;
+  if (this->float_constant_value(real, &t))
+    {
+      mpfr_set_ui(imag, 0, GMP_RNDN);
+      return true;
+    }
+  return false;
+}
+
+// Traverse the expressions.
+
+int
+Expression::traverse(Expression** pexpr, Traverse* traverse)
+{
+  Expression* expr = *pexpr;
+  if ((traverse->traverse_mask() & Traverse::traverse_expressions) != 0)
+    {
+      int t = traverse->expression(pexpr);
+      if (t == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+      else if (t == TRAVERSE_SKIP_COMPONENTS)
+       return TRAVERSE_CONTINUE;
+    }
+  return expr->do_traverse(traverse);
+}
+
+// Traverse subexpressions of this expression.
+
+int
+Expression::traverse_subexpressions(Traverse* traverse)
+{
+  return this->do_traverse(traverse);
+}
+
+// Default implementation for do_traverse for child classes.
+
+int
+Expression::do_traverse(Traverse*)
+{
+  return TRAVERSE_CONTINUE;
+}
+
+// This virtual function is called by the parser if the value of this
+// expression is being discarded.  By default, we warn.  Expressions
+// with side effects override.
+
+void
+Expression::do_discarding_value()
+{
+  this->warn_about_unused_value();
+}
+
+// This virtual function is called to export expressions.  This will
+// only be used by expressions which may be constant.
+
+void
+Expression::do_export(Export*) const
+{
+  gcc_unreachable();
+}
+
+// Warn that the value of the expression is not used.
+
+void
+Expression::warn_about_unused_value()
+{
+  warning_at(this->location(), OPT_Wunused_value, "value computed is not used");
+}
+
+// Note that this expression is an error.  This is called by children
+// when they discover an error.
+
+void
+Expression::set_is_error()
+{
+  this->classification_ = EXPRESSION_ERROR;
+}
+
+// For children to call to report an error conveniently.
+
+void
+Expression::report_error(const char* msg)
+{
+  error_at(this->location_, "%s", msg);
+  this->set_is_error();
+}
+
+// Set types of variables and constants.  This is implemented by the
+// child class.
+
+void
+Expression::determine_type(const Type_context* context)
+{
+  this->do_determine_type(context);
+}
+
+// Set types when there is no context.
+
+void
+Expression::determine_type_no_context()
+{
+  Type_context context;
+  this->do_determine_type(&context);
+}
+
+// Return a tree handling any conversions which must be done during
+// assignment.
+
+tree
+Expression::convert_for_assignment(Translate_context* context, Type* lhs_type,
+                                  Type* rhs_type, tree rhs_tree,
+                                  source_location location)
+{
+  if (lhs_type == rhs_type)
+    return rhs_tree;
+
+  if (lhs_type->is_error_type() || rhs_type->is_error_type())
+    return error_mark_node;
+
+  if (lhs_type->is_undefined() || rhs_type->is_undefined())
+    {
+      // Make sure we report the error.
+      lhs_type->base();
+      rhs_type->base();
+      return error_mark_node;
+    }
+
+  if (rhs_tree == error_mark_node || TREE_TYPE(rhs_tree) == error_mark_node)
+    return error_mark_node;
+
+  Gogo* gogo = context->gogo();
+
+  tree lhs_type_tree = lhs_type->get_tree(gogo);
+  if (lhs_type_tree == error_mark_node)
+    return error_mark_node;
+
+  if (lhs_type->interface_type() != NULL)
+    {
+      if (rhs_type->interface_type() == NULL)
+       return Expression::convert_type_to_interface(context, lhs_type,
+                                                    rhs_type, rhs_tree,
+                                                    location);
+      else
+       return Expression::convert_interface_to_interface(context, lhs_type,
+                                                         rhs_type, rhs_tree,
+                                                         false, location);
+    }
+  else if (rhs_type->interface_type() != NULL)
+    return Expression::convert_interface_to_type(context, lhs_type, rhs_type,
+                                                rhs_tree, location);
+  else if (lhs_type->is_open_array_type()
+          && rhs_type->is_nil_type())
+    {
+      // Assigning nil to an open array.
+      gcc_assert(TREE_CODE(lhs_type_tree) == RECORD_TYPE);
+
+      VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 3);
+
+      constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+      tree field = TYPE_FIELDS(lhs_type_tree);
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
+                       "__values") == 0);
+      elt->index = field;
+      elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
+
+      elt = VEC_quick_push(constructor_elt, init, NULL);
+      field = DECL_CHAIN(field);
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
+                       "__count") == 0);
+      elt->index = field;
+      elt->value = fold_convert(TREE_TYPE(field), integer_zero_node);
+
+      elt = VEC_quick_push(constructor_elt, init, NULL);
+      field = DECL_CHAIN(field);
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
+                       "__capacity") == 0);
+      elt->index = field;
+      elt->value = fold_convert(TREE_TYPE(field), integer_zero_node);
+
+      tree val = build_constructor(lhs_type_tree, init);
+      TREE_CONSTANT(val) = 1;
+
+      return val;
+    }
+  else if (rhs_type->is_nil_type())
+    {
+      // The left hand side should be a pointer type at the tree
+      // level.
+      gcc_assert(POINTER_TYPE_P(lhs_type_tree));
+      return fold_convert(lhs_type_tree, null_pointer_node);
+    }
+  else if (lhs_type_tree == TREE_TYPE(rhs_tree))
+    {
+      // No conversion is needed.
+      return rhs_tree;
+    }
+  else if (POINTER_TYPE_P(lhs_type_tree)
+          || INTEGRAL_TYPE_P(lhs_type_tree)
+          || SCALAR_FLOAT_TYPE_P(lhs_type_tree)
+          || COMPLEX_FLOAT_TYPE_P(lhs_type_tree))
+    return fold_convert_loc(location, lhs_type_tree, rhs_tree);
+  else if (TREE_CODE(lhs_type_tree) == RECORD_TYPE
+          && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE)
+    {
+      // This conversion must be permitted by Go, or we wouldn't have
+      // gotten here.
+      gcc_assert(int_size_in_bytes(lhs_type_tree)
+                == int_size_in_bytes(TREE_TYPE(rhs_tree)));
+      return fold_build1_loc(location, VIEW_CONVERT_EXPR, lhs_type_tree,
+                            rhs_tree);
+    }
+  else
+    {
+      gcc_assert(useless_type_conversion_p(lhs_type_tree, TREE_TYPE(rhs_tree)));
+      return rhs_tree;
+    }
+}
+
+// Return a tree for a conversion from a non-interface type to an
+// interface type.
+
+tree
+Expression::convert_type_to_interface(Translate_context* context,
+                                     Type* lhs_type, Type* rhs_type,
+                                     tree rhs_tree, source_location location)
+{
+  Gogo* gogo = context->gogo();
+  Interface_type* lhs_interface_type = lhs_type->interface_type();
+  bool lhs_is_empty = lhs_interface_type->is_empty();
+
+  // Since RHS_TYPE is a static type, we can create the interface
+  // method table at compile time.
+
+  // When setting an interface to nil, we just set both fields to
+  // NULL.
+  if (rhs_type->is_nil_type())
+    return lhs_type->get_init_tree(gogo, false);
+
+  // This should have been checked already.
+  gcc_assert(lhs_interface_type->implements_interface(rhs_type, NULL));
+
+  tree lhs_type_tree = lhs_type->get_tree(gogo);
+  if (lhs_type_tree == error_mark_node)
+    return error_mark_node;
+
+  // An interface is a tuple.  If LHS_TYPE is an empty interface type,
+  // then the first field is the type descriptor for RHS_TYPE.
+  // Otherwise it is the interface method table for RHS_TYPE.
+  tree first_field_value;
+  if (lhs_is_empty)
+    first_field_value = rhs_type->type_descriptor_pointer(gogo);
+  else
+    {
+      // Build the interface method table for this interface and this
+      // object type: a list of function pointers for each interface
+      // method.
+      Named_type* rhs_named_type = rhs_type->named_type();
+      bool is_pointer = false;
+      if (rhs_named_type == NULL)
+       {
+         rhs_named_type = rhs_type->deref()->named_type();
+         is_pointer = true;
+       }
+      tree method_table;
+      if (rhs_named_type == NULL)
+       method_table = null_pointer_node;
+      else
+       method_table =
+         rhs_named_type->interface_method_table(gogo, lhs_interface_type,
+                                                is_pointer);
+      first_field_value = fold_convert_loc(location, const_ptr_type_node,
+                                          method_table);
+    }
+
+  // Start building a constructor for the value we will return.
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
+
+  constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+  tree field = TYPE_FIELDS(lhs_type_tree);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
+                   (lhs_is_empty ? "__type_descriptor" : "__methods")) == 0);
+  elt->index = field;
+  elt->value = fold_convert_loc(location, TREE_TYPE(field), first_field_value);
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = DECL_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
+  elt->index = field;
+
+  if (rhs_type->points_to() != NULL)
+    {
+      //  We are assigning a pointer to the interface; the interface
+      // holds the pointer itself.
+      elt->value = rhs_tree;
+      return build_constructor(lhs_type_tree, init);
+    }
+
+  // We are assigning a non-pointer value to the interface; the
+  // interface gets a copy of the value in the heap.
+
+  tree object_size = TYPE_SIZE_UNIT(TREE_TYPE(rhs_tree));
+
+  tree space = gogo->allocate_memory(rhs_type, object_size, location);
+  space = fold_convert_loc(location, build_pointer_type(TREE_TYPE(rhs_tree)),
+                          space);
+  space = save_expr(space);
+
+  tree ref = build_fold_indirect_ref_loc(location, space);
+  TREE_THIS_NOTRAP(ref) = 1;
+  tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
+                            ref, rhs_tree);
+
+  elt->value = fold_convert_loc(location, TREE_TYPE(field), space);
+
+  return build2(COMPOUND_EXPR, lhs_type_tree, set,
+               build_constructor(lhs_type_tree, init));
+}
+
+// Return a tree for the type descriptor of RHS_TREE, which has
+// interface type RHS_TYPE.  If RHS_TREE is nil the result will be
+// NULL.
+
+tree
+Expression::get_interface_type_descriptor(Translate_context*,
+                                         Type* rhs_type, tree rhs_tree,
+                                         source_location location)
+{
+  tree rhs_type_tree = TREE_TYPE(rhs_tree);
+  gcc_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
+  tree rhs_field = TYPE_FIELDS(rhs_type_tree);
+  tree v = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
+                 NULL_TREE);
+  if (rhs_type->interface_type()->is_empty())
+    {
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)),
+                       "__type_descriptor") == 0);
+      return v;
+    }
+
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__methods")
+            == 0);
+  gcc_assert(POINTER_TYPE_P(TREE_TYPE(v)));
+  v = save_expr(v);
+  tree v1 = build_fold_indirect_ref_loc(location, v);
+  gcc_assert(TREE_CODE(TREE_TYPE(v1)) == RECORD_TYPE);
+  tree f = TYPE_FIELDS(TREE_TYPE(v1));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(f)), "__type_descriptor")
+            == 0);
+  v1 = build3(COMPONENT_REF, TREE_TYPE(f), v1, f, NULL_TREE);
+
+  tree eq = fold_build2_loc(location, EQ_EXPR, boolean_type_node, v,
+                           fold_convert_loc(location, TREE_TYPE(v),
+                                            null_pointer_node));
+  tree n = fold_convert_loc(location, TREE_TYPE(v1), null_pointer_node);
+  return fold_build3_loc(location, COND_EXPR, TREE_TYPE(v1),
+                        eq, n, v1);
+}
+
+// Return a tree for the conversion of an interface type to an
+// interface type.
+
+tree
+Expression::convert_interface_to_interface(Translate_context* context,
+                                          Type *lhs_type, Type *rhs_type,
+                                          tree rhs_tree, bool for_type_guard,
+                                          source_location location)
+{
+  Gogo* gogo = context->gogo();
+  Interface_type* lhs_interface_type = lhs_type->interface_type();
+  bool lhs_is_empty = lhs_interface_type->is_empty();
+
+  tree lhs_type_tree = lhs_type->get_tree(gogo);
+  if (lhs_type_tree == error_mark_node)
+    return error_mark_node;
+
+  // In the general case this requires runtime examination of the type
+  // method table to match it up with the interface methods.
+
+  // FIXME: If all of the methods in the right hand side interface
+  // also appear in the left hand side interface, then we don't need
+  // to do a runtime check, although we still need to build a new
+  // method table.
+
+  // Get the type descriptor for the right hand side.  This will be
+  // NULL for a nil interface.
+
+  if (!DECL_P(rhs_tree))
+    rhs_tree = save_expr(rhs_tree);
+
+  tree rhs_type_descriptor =
+    Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
+                                             location);
+
+  // The result is going to be a two element constructor.
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
+
+  constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+  tree field = TYPE_FIELDS(lhs_type_tree);
+  elt->index = field;
+
+  if (for_type_guard)
+    {
+      // A type assertion fails when converting a nil interface.
+      tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo);
+      static tree assert_interface_decl;
+      tree call = Gogo::call_builtin(&assert_interface_decl,
+                                    location,
+                                    "__go_assert_interface",
+                                    2,
+                                    ptr_type_node,
+                                    TREE_TYPE(lhs_type_descriptor),
+                                    lhs_type_descriptor,
+                                    TREE_TYPE(rhs_type_descriptor),
+                                    rhs_type_descriptor);
+      // This will panic if the interface conversion fails.
+      TREE_NOTHROW(assert_interface_decl) = 0;
+      elt->value = fold_convert_loc(location, TREE_TYPE(field), call);
+    }
+  else if (lhs_is_empty)
+    {
+      // A convertion to an empty interface always succeeds, and the
+      // first field is just the type descriptor of the object.
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
+                       "__type_descriptor") == 0);
+      gcc_assert(TREE_TYPE(field) == TREE_TYPE(rhs_type_descriptor));
+      elt->value = rhs_type_descriptor;
+    }
+  else
+    {
+      // A conversion to a non-empty interface may fail, but unlike a
+      // type assertion converting nil will always succeed.
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods")
+                == 0);
+      tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo);
+      static tree convert_interface_decl;
+      tree call = Gogo::call_builtin(&convert_interface_decl,
+                                    location,
+                                    "__go_convert_interface",
+                                    2,
+                                    ptr_type_node,
+                                    TREE_TYPE(lhs_type_descriptor),
+                                    lhs_type_descriptor,
+                                    TREE_TYPE(rhs_type_descriptor),
+                                    rhs_type_descriptor);
+      // This will panic if the interface conversion fails.
+      TREE_NOTHROW(convert_interface_decl) = 0;
+      elt->value = fold_convert_loc(location, TREE_TYPE(field), call);
+    }
+
+  // The second field is simply the object pointer.
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = DECL_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
+  elt->index = field;
+
+  tree rhs_type_tree = TREE_TYPE(rhs_tree);
+  gcc_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
+  tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
+  elt->value = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
+                     NULL_TREE);
+
+  return build_constructor(lhs_type_tree, init);
+}
+
+// Return a tree for the conversion of an interface type to a
+// non-interface type.
+
+tree
+Expression::convert_interface_to_type(Translate_context* context,
+                                     Type *lhs_type, Type* rhs_type,
+                                     tree rhs_tree, source_location location)
+{
+  Gogo* gogo = context->gogo();
+  tree rhs_type_tree = TREE_TYPE(rhs_tree);
+
+  tree lhs_type_tree = lhs_type->get_tree(gogo);
+  if (lhs_type_tree == error_mark_node)
+    return error_mark_node;
+
+  // Call a function to check that the type is valid.  The function
+  // will panic with an appropriate runtime type error if the type is
+  // not valid.
+
+  tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo);
+
+  if (!DECL_P(rhs_tree))
+    rhs_tree = save_expr(rhs_tree);
+
+  tree rhs_type_descriptor =
+    Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
+                                             location);
+
+  tree rhs_inter_descriptor = rhs_type->type_descriptor_pointer(gogo);
+
+  static tree check_interface_type_decl;
+  tree call = Gogo::call_builtin(&check_interface_type_decl,
+                                location,
+                                "__go_check_interface_type",
+                                3,
+                                void_type_node,
+                                TREE_TYPE(lhs_type_descriptor),
+                                lhs_type_descriptor,
+                                TREE_TYPE(rhs_type_descriptor),
+                                rhs_type_descriptor,
+                                TREE_TYPE(rhs_inter_descriptor),
+                                rhs_inter_descriptor);
+  // This call will panic if the conversion is invalid.
+  TREE_NOTHROW(check_interface_type_decl) = 0;
+
+  // If the call succeeds, pull out the value.
+  gcc_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
+  tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
+  tree val = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
+                   NULL_TREE);
+
+  // If the value is a pointer, then it is the value we want.
+  // Otherwise it points to the value.
+  if (lhs_type->points_to() == NULL)
+    {
+      val = fold_convert_loc(location, build_pointer_type(lhs_type_tree), val);
+      val = build_fold_indirect_ref_loc(location, val);
+    }
+
+  return build2(COMPOUND_EXPR, lhs_type_tree, call,
+               fold_convert_loc(location, lhs_type_tree, val));
+}
+
+// Convert an expression to a tree.  This is implemented by the child
+// class.  Not that it is not in general safe to call this multiple
+// times for a single expression, but that we don't catch such errors.
+
+tree
+Expression::get_tree(Translate_context* context)
+{
+  // The child may have marked this expression as having an error.
+  if (this->classification_ == EXPRESSION_ERROR)
+    return error_mark_node;
+
+  return this->do_get_tree(context);
+}
+
+// Return a tree for VAL in TYPE.
+
+tree
+Expression::integer_constant_tree(mpz_t val, tree type)
+{
+  if (type == error_mark_node)
+    return error_mark_node;
+  else if (TREE_CODE(type) == INTEGER_TYPE)
+    return double_int_to_tree(type,
+                             mpz_get_double_int(type, val, true));
+  else if (TREE_CODE(type) == REAL_TYPE)
+    {
+      mpfr_t fval;
+      mpfr_init_set_z(fval, val, GMP_RNDN);
+      tree ret = Expression::float_constant_tree(fval, type);
+      mpfr_clear(fval);
+      return ret;
+    }
+  else if (TREE_CODE(type) == COMPLEX_TYPE)
+    {
+      mpfr_t fval;
+      mpfr_init_set_z(fval, val, GMP_RNDN);
+      tree real = Expression::float_constant_tree(fval, TREE_TYPE(type));
+      mpfr_clear(fval);
+      tree imag = build_real_from_int_cst(TREE_TYPE(type),
+                                         integer_zero_node);
+      return build_complex(type, real, imag);
+    }
+  else
+    gcc_unreachable();
+}
+
+// Return a tree for VAL in TYPE.
+
+tree
+Expression::float_constant_tree(mpfr_t val, tree type)
+{
+  if (type == error_mark_node)
+    return error_mark_node;
+  else if (TREE_CODE(type) == INTEGER_TYPE)
+    {
+      mpz_t ival;
+      mpz_init(ival);
+      mpfr_get_z(ival, val, GMP_RNDN);
+      tree ret = Expression::integer_constant_tree(ival, type);
+      mpz_clear(ival);
+      return ret;
+    }
+  else if (TREE_CODE(type) == REAL_TYPE)
+    {
+      REAL_VALUE_TYPE r1;
+      real_from_mpfr(&r1, val, type, GMP_RNDN);
+      REAL_VALUE_TYPE r2;
+      real_convert(&r2, TYPE_MODE(type), &r1);
+      return build_real(type, r2);
+    }
+  else if (TREE_CODE(type) == COMPLEX_TYPE)
+    {
+      REAL_VALUE_TYPE r1;
+      real_from_mpfr(&r1, val, TREE_TYPE(type), GMP_RNDN);
+      REAL_VALUE_TYPE r2;
+      real_convert(&r2, TYPE_MODE(TREE_TYPE(type)), &r1);
+      tree imag = build_real_from_int_cst(TREE_TYPE(type),
+                                         integer_zero_node);
+      return build_complex(type, build_real(TREE_TYPE(type), r2), imag);
+    }
+  else
+    gcc_unreachable();
+}
+
+// Return a tree for REAL/IMAG in TYPE.
+
+tree
+Expression::complex_constant_tree(mpfr_t real, mpfr_t imag, tree type)
+{
+  if (TREE_CODE(type) == COMPLEX_TYPE)
+    {
+      REAL_VALUE_TYPE r1;
+      real_from_mpfr(&r1, real, TREE_TYPE(type), GMP_RNDN);
+      REAL_VALUE_TYPE r2;
+      real_convert(&r2, TYPE_MODE(TREE_TYPE(type)), &r1);
+
+      REAL_VALUE_TYPE r3;
+      real_from_mpfr(&r3, imag, TREE_TYPE(type), GMP_RNDN);
+      REAL_VALUE_TYPE r4;
+      real_convert(&r4, TYPE_MODE(TREE_TYPE(type)), &r3);
+
+      return build_complex(type, build_real(TREE_TYPE(type), r2),
+                          build_real(TREE_TYPE(type), r4));
+    }
+  else
+    gcc_unreachable();
+}
+
+// Return a tree which evaluates to true if VAL, of arbitrary integer
+// type, is negative or is more than the maximum value of BOUND_TYPE.
+// If SOFAR is not NULL, it is or'red into the result.  The return
+// value may be NULL if SOFAR is NULL.
+
+tree
+Expression::check_bounds(tree val, tree bound_type, tree sofar,
+                        source_location loc)
+{
+  tree val_type = TREE_TYPE(val);
+  tree ret = NULL_TREE;
+
+  if (!TYPE_UNSIGNED(val_type))
+    {
+      ret = fold_build2_loc(loc, LT_EXPR, boolean_type_node, val,
+                           build_int_cst(val_type, 0));
+      if (ret == boolean_false_node)
+       ret = NULL_TREE;
+    }
+
+  if ((TYPE_UNSIGNED(val_type) && !TYPE_UNSIGNED(bound_type))
+      || TYPE_SIZE(val_type) > TYPE_SIZE(bound_type))
+    {
+      tree max = TYPE_MAX_VALUE(bound_type);
+      tree big = fold_build2_loc(loc, GT_EXPR, boolean_type_node, val,
+                                fold_convert_loc(loc, val_type, max));
+      if (big == boolean_false_node)
+       ;
+      else if (ret == NULL_TREE)
+       ret = big;
+      else
+       ret = fold_build2_loc(loc, TRUTH_OR_EXPR, boolean_type_node,
+                             ret, big);
+    }
+
+  if (ret == NULL_TREE)
+    return sofar;
+  else if (sofar == NULL_TREE)
+    return ret;
+  else
+    return fold_build2_loc(loc, TRUTH_OR_EXPR, boolean_type_node,
+                          sofar, ret);
+}
+
+// Error expressions.  This are used to avoid cascading errors.
+
+class Error_expression : public Expression
+{
+ public:
+  Error_expression(source_location location)
+    : Expression(EXPRESSION_ERROR, location)
+  { }
+
+ protected:
+  bool
+  do_is_constant() const
+  { return true; }
+
+  bool
+  do_integer_constant_value(bool, mpz_t val, Type**) const
+  {
+    mpz_set_ui(val, 0);
+    return true;
+  }
+
+  bool
+  do_float_constant_value(mpfr_t val, Type**) const
+  {
+    mpfr_set_ui(val, 0, GMP_RNDN);
+    return true;
+  }
+
+  bool
+  do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const
+  {
+    mpfr_set_ui(real, 0, GMP_RNDN);
+    mpfr_set_ui(imag, 0, GMP_RNDN);
+    return true;
+  }
+
+  void
+  do_discarding_value()
+  { }
+
+  Type*
+  do_type()
+  { return Type::make_error_type(); }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  bool
+  do_is_addressable() const
+  { return true; }
+
+  tree
+  do_get_tree(Translate_context*)
+  { return error_mark_node; }
+};
+
+Expression*
+Expression::make_error(source_location location)
+{
+  return new Error_expression(location);
+}
+
+// An expression which is really a type.  This is used during parsing.
+// It is an error if these survive after lowering.
+
+class
+Type_expression : public Expression
+{
+ public:
+  Type_expression(Type* type, source_location location)
+    : Expression(EXPRESSION_TYPE, location),
+      type_(type)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Type::traverse(this->type_, traverse); }
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  void
+  do_check_types(Gogo*)
+  { this->report_error(_("invalid use of type")); }
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // The type which we are representing as an expression.
+  Type* type_;
+};
+
+Expression*
+Expression::make_type(Type* type, source_location location)
+{
+  return new Type_expression(type, location);
+}
+
+// Class Var_expression.
+
+// Lower a variable expression.  Here we just make sure that the
+// initialization expression of the variable has been lowered.  This
+// ensures that we will be able to determine the type of the variable
+// if necessary.
+
+Expression*
+Var_expression::do_lower(Gogo* gogo, Named_object* function, int)
+{
+  if (this->variable_->is_variable())
+    {
+      Variable* var = this->variable_->var_value();
+      // This is either a local variable or a global variable.  A
+      // reference to a variable which is local to an enclosing
+      // function will be a reference to a field in a closure.
+      if (var->is_global())
+       function = NULL;
+      var->lower_init_expression(gogo, function);
+    }
+  return this;
+}
+
+// Return the name of the variable.
+
+const std::string&
+Var_expression::name() const
+{
+  return this->variable_->name();
+}
+
+// Return the type of a reference to a variable.
+
+Type*
+Var_expression::do_type()
+{
+  if (this->variable_->is_variable())
+    return this->variable_->var_value()->type();
+  else if (this->variable_->is_result_variable())
+    return this->variable_->result_var_value()->type();
+  else
+    gcc_unreachable();
+}
+
+// Something takes the address of this variable.  This means that we
+// may want to move the variable onto the heap.
+
+void
+Var_expression::do_address_taken(bool escapes)
+{
+  if (!escapes)
+    ;
+  else if (this->variable_->is_variable())
+    this->variable_->var_value()->set_address_taken();
+  else if (this->variable_->is_result_variable())
+    this->variable_->result_var_value()->set_address_taken();
+  else
+    gcc_unreachable();
+}
+
+// Get the tree for a reference to a variable.
+
+tree
+Var_expression::do_get_tree(Translate_context* context)
+{
+  return this->variable_->get_tree(context->gogo(), context->function());
+}
+
+// Make a reference to a variable in an expression.
+
+Expression*
+Expression::make_var_reference(Named_object* var, source_location location)
+{
+  if (var->is_sink())
+    return Expression::make_sink(location);
+
+  // FIXME: Creating a new object for each reference to a variable is
+  // wasteful.
+  return new Var_expression(var, location);
+}
+
+// Class Temporary_reference_expression.
+
+// The type.
+
+Type*
+Temporary_reference_expression::do_type()
+{
+  return this->statement_->type();
+}
+
+// Called if something takes the address of this temporary variable.
+// We never have to move temporary variables to the heap, but we do
+// need to know that they must live in the stack rather than in a
+// register.
+
+void
+Temporary_reference_expression::do_address_taken(bool)
+{
+  this->statement_->set_is_address_taken();
+}
+
+// Get a tree referring to the variable.
+
+tree
+Temporary_reference_expression::do_get_tree(Translate_context*)
+{
+  return this->statement_->get_decl();
+}
+
+// Make a reference to a temporary variable.
+
+Expression*
+Expression::make_temporary_reference(Temporary_statement* statement,
+                                    source_location location)
+{
+  return new Temporary_reference_expression(statement, location);
+}
+
+// A sink expression--a use of the blank identifier _.
+
+class Sink_expression : public Expression
+{
+ public:
+  Sink_expression(source_location location)
+    : Expression(EXPRESSION_SINK, location),
+      type_(NULL), var_(NULL_TREE)
+  { }
+
+ protected:
+  void
+  do_discarding_value()
+  { }
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  Expression*
+  do_copy()
+  { return new Sink_expression(this->location()); }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The type of this sink variable.
+  Type* type_;
+  // The temporary variable we generate.
+  tree var_;
+};
+
+// Return the type of a sink expression.
+
+Type*
+Sink_expression::do_type()
+{
+  if (this->type_ == NULL)
+    return Type::make_sink_type();
+  return this->type_;
+}
+
+// Determine the type of a sink expression.
+
+void
+Sink_expression::do_determine_type(const Type_context* context)
+{
+  if (context->type != NULL)
+    this->type_ = context->type;
+}
+
+// Return a temporary variable for a sink expression.  This will
+// presumably be a write-only variable which the middle-end will drop.
+
+tree
+Sink_expression::do_get_tree(Translate_context* context)
+{
+  if (this->var_ == NULL_TREE)
+    {
+      gcc_assert(this->type_ != NULL && !this->type_->is_sink_type());
+      this->var_ = create_tmp_var(this->type_->get_tree(context->gogo()),
+                                 "blank");
+    }
+  return this->var_;
+}
+
+// Make a sink expression.
+
+Expression*
+Expression::make_sink(source_location location)
+{
+  return new Sink_expression(location);
+}
+
+// Class Func_expression.
+
+// FIXME: Can a function expression appear in a constant expression?
+// The value is unchanging.  Initializing a constant to the address of
+// a function seems like it could work, though there might be little
+// point to it.
+
+// Return the name of the function.
+
+const std::string&
+Func_expression::name() const
+{
+  return this->function_->name();
+}
+
+// Traversal.
+
+int
+Func_expression::do_traverse(Traverse* traverse)
+{
+  return (this->closure_ == NULL
+         ? TRAVERSE_CONTINUE
+         : Expression::traverse(&this->closure_, traverse));
+}
+
+// Return the type of a function expression.
+
+Type*
+Func_expression::do_type()
+{
+  if (this->function_->is_function())
+    return this->function_->func_value()->type();
+  else if (this->function_->is_function_declaration())
+    return this->function_->func_declaration_value()->type();
+  else
+    gcc_unreachable();
+}
+
+// Get the tree for a function expression without evaluating the
+// closure.
+
+tree
+Func_expression::get_tree_without_closure(Gogo* gogo)
+{
+  Function_type* fntype;
+  if (this->function_->is_function())
+    fntype = this->function_->func_value()->type();
+  else if (this->function_->is_function_declaration())
+    fntype = this->function_->func_declaration_value()->type();
+  else
+    gcc_unreachable();
+
+  // Builtin functions are handled specially by Call_expression.  We
+  // can't take their address.
+  if (fntype->is_builtin())
+    {
+      error_at(this->location(), "invalid use of special builtin function %qs",
+              this->function_->name().c_str());
+      return error_mark_node;
+    }
+
+  Named_object* no = this->function_;
+  tree id = this->function_->get_id(gogo);
+  tree fndecl;
+  if (no->is_function())
+    fndecl = no->func_value()->get_or_make_decl(gogo, no, id);
+  else if (no->is_function_declaration())
+    fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no, id);
+  else
+    gcc_unreachable();
+
+  return build_fold_addr_expr_loc(this->location(), fndecl);
+}
+
+// Get the tree for a function expression.  This is used when we take
+// the address of a function rather than simply calling it.  If the
+// function has a closure, we must use a trampoline.
+
+tree
+Func_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+
+  tree fnaddr = this->get_tree_without_closure(gogo);
+  if (fnaddr == error_mark_node)
+    return error_mark_node;
+
+  gcc_assert(TREE_CODE(fnaddr) == ADDR_EXPR
+            && TREE_CODE(TREE_OPERAND(fnaddr, 0)) == FUNCTION_DECL);
+  TREE_ADDRESSABLE(TREE_OPERAND(fnaddr, 0)) = 1;
+
+  // For a normal non-nested function call, that is all we have to do.
+  if (!this->function_->is_function()
+      || this->function_->func_value()->enclosing() == NULL)
+    {
+      gcc_assert(this->closure_ == NULL);
+      return fnaddr;
+    }
+
+  // For a nested function call, we have to always allocate a
+  // trampoline.  If we don't always allocate, then closures will not
+  // be reliably distinct.
+  Expression* closure = this->closure_;
+  tree closure_tree;
+  if (closure == NULL)
+    closure_tree = null_pointer_node;
+  else
+    {
+      // Get the value of the closure.  This will be a pointer to
+      // space allocated on the heap.
+      closure_tree = closure->get_tree(context);
+      if (closure_tree == error_mark_node)
+       return error_mark_node;
+      gcc_assert(POINTER_TYPE_P(TREE_TYPE(closure_tree)));
+    }
+
+  // Now we need to build some code on the heap.  This code will load
+  // the static chain pointer with the closure and then jump to the
+  // body of the function.  The normal gcc approach is to build the
+  // code on the stack.  Unfortunately we can not do that, as Go
+  // permits us to return the function pointer.
+
+  return gogo->make_trampoline(fnaddr, closure_tree, this->location());
+}
+
+// Make a reference to a function in an expression.
+
+Expression*
+Expression::make_func_reference(Named_object* function, Expression* closure,
+                               source_location location)
+{
+  return new Func_expression(function, closure, location);
+}
+
+// Class Unknown_expression.
+
+// Return the name of an unknown expression.
+
+const std::string&
+Unknown_expression::name() const
+{
+  return this->named_object_->name();
+}
+
+// Lower a reference to an unknown name.
+
+Expression*
+Unknown_expression::do_lower(Gogo*, Named_object*, int)
+{
+  source_location location = this->location();
+  Named_object* no = this->named_object_;
+  Named_object* real = no->unknown_value()->real_named_object();
+  if (real == NULL)
+    {
+      if (this->is_composite_literal_key_)
+       return this;
+      error_at(location, "reference to undefined name %qs",
+              this->named_object_->message_name().c_str());
+      return Expression::make_error(location);
+    }
+  switch (real->classification())
+    {
+    case Named_object::NAMED_OBJECT_CONST:
+      return Expression::make_const_reference(real, location);
+    case Named_object::NAMED_OBJECT_TYPE:
+      return Expression::make_type(real->type_value(), location);
+    case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
+      if (this->is_composite_literal_key_)
+       return this;
+      error_at(location, "reference to undefined type %qs",
+              real->message_name().c_str());
+      return Expression::make_error(location);
+    case Named_object::NAMED_OBJECT_VAR:
+      return Expression::make_var_reference(real, location);
+    case Named_object::NAMED_OBJECT_FUNC:
+    case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
+      return Expression::make_func_reference(real, NULL, location);
+    case Named_object::NAMED_OBJECT_PACKAGE:
+      if (this->is_composite_literal_key_)
+       return this;
+      error_at(location, "unexpected reference to package");
+      return Expression::make_error(location);
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Make a reference to an unknown name.
+
+Expression*
+Expression::make_unknown_reference(Named_object* no, source_location location)
+{
+  gcc_assert(no->resolve()->is_unknown());
+  return new Unknown_expression(no, location);
+}
+
+// A boolean expression.
+
+class Boolean_expression : public Expression
+{
+ public:
+  Boolean_expression(bool val, source_location location)
+    : Expression(EXPRESSION_BOOLEAN, location),
+      val_(val), type_(NULL)
+  { }
+
+  static Expression*
+  do_import(Import*);
+
+ protected:
+  bool
+  do_is_constant() const
+  { return true; }
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  tree
+  do_get_tree(Translate_context*)
+  { return this->val_ ? boolean_true_node : boolean_false_node; }
+
+  void
+  do_export(Export* exp) const
+  { exp->write_c_string(this->val_ ? "true" : "false"); }
+
+ private:
+  // The constant.
+  bool val_;
+  // The type as determined by context.
+  Type* type_;
+};
+
+// Get the type.
+
+Type*
+Boolean_expression::do_type()
+{
+  if (this->type_ == NULL)
+    this->type_ = Type::make_boolean_type();
+  return this->type_;
+}
+
+// Set the type from the context.
+
+void
+Boolean_expression::do_determine_type(const Type_context* context)
+{
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    ;
+  else if (context->type != NULL && context->type->is_boolean_type())
+    this->type_ = context->type;
+  else if (!context->may_be_abstract)
+    this->type_ = Type::lookup_bool_type();
+}
+
+// Import a boolean constant.
+
+Expression*
+Boolean_expression::do_import(Import* imp)
+{
+  if (imp->peek_char() == 't')
+    {
+      imp->require_c_string("true");
+      return Expression::make_boolean(true, imp->location());
+    }
+  else
+    {
+      imp->require_c_string("false");
+      return Expression::make_boolean(false, imp->location());
+    }
+}
+
+// Make a boolean expression.
+
+Expression*
+Expression::make_boolean(bool val, source_location location)
+{
+  return new Boolean_expression(val, location);
+}
+
+// Class String_expression.
+
+// Get the type.
+
+Type*
+String_expression::do_type()
+{
+  if (this->type_ == NULL)
+    this->type_ = Type::make_string_type();
+  return this->type_;
+}
+
+// Set the type from the context.
+
+void
+String_expression::do_determine_type(const Type_context* context)
+{
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    ;
+  else if (context->type != NULL && context->type->is_string_type())
+    this->type_ = context->type;
+  else if (!context->may_be_abstract)
+    this->type_ = Type::lookup_string_type();
+}
+
+// Build a string constant.
+
+tree
+String_expression::do_get_tree(Translate_context* context)
+{
+  return context->gogo()->go_string_constant_tree(this->val_);
+}
+
+// Export a string expression.
+
+void
+String_expression::do_export(Export* exp) const
+{
+  std::string s;
+  s.reserve(this->val_.length() * 4 + 2);
+  s += '"';
+  for (std::string::const_iterator p = this->val_.begin();
+       p != this->val_.end();
+       ++p)
+    {
+      if (*p == '\\' || *p == '"')
+       {
+         s += '\\';
+         s += *p;
+       }
+      else if (*p >= 0x20 && *p < 0x7f)
+       s += *p;
+      else if (*p == '\n')
+       s += "\\n";
+      else if (*p == '\t')
+       s += "\\t";
+      else
+       {
+         s += "\\x";
+         unsigned char c = *p;
+         unsigned int dig = c >> 4;
+         s += dig < 10 ? '0' + dig : 'A' + dig - 10;
+         dig = c & 0xf;
+         s += dig < 10 ? '0' + dig : 'A' + dig - 10;
+       }
+    }
+  s += '"';
+  exp->write_string(s);
+}
+
+// Import a string expression.
+
+Expression*
+String_expression::do_import(Import* imp)
+{
+  imp->require_c_string("\"");
+  std::string val;
+  while (true)
+    {
+      int c = imp->get_char();
+      if (c == '"' || c == -1)
+       break;
+      if (c != '\\')
+       val += static_cast<char>(c);
+      else
+       {
+         c = imp->get_char();
+         if (c == '\\' || c == '"')
+           val += static_cast<char>(c);
+         else if (c == 'n')
+           val += '\n';
+         else if (c == 't')
+           val += '\t';
+         else if (c == 'x')
+           {
+             c = imp->get_char();
+             unsigned int vh = c >= '0' && c <= '9' ? c - '0' : c - 'A' + 10;
+             c = imp->get_char();
+             unsigned int vl = c >= '0' && c <= '9' ? c - '0' : c - 'A' + 10;
+             char v = (vh << 4) | vl;
+             val += v;
+           }
+         else
+           {
+             error_at(imp->location(), "bad string constant");
+             return Expression::make_error(imp->location());
+           }
+       }
+    }
+  return Expression::make_string(val, imp->location());
+}
+
+// Make a string expression.
+
+Expression*
+Expression::make_string(const std::string& val, source_location location)
+{
+  return new String_expression(val, location);
+}
+
+// Make an integer expression.
+
+class Integer_expression : public Expression
+{
+ public:
+  Integer_expression(const mpz_t* val, Type* type, source_location location)
+    : Expression(EXPRESSION_INTEGER, location),
+      type_(type)
+  { mpz_init_set(this->val_, *val); }
+
+  static Expression*
+  do_import(Import*);
+
+  // Return whether VAL fits in the type.
+  static bool
+  check_constant(mpz_t val, Type*, source_location);
+
+  // Write VAL to export data.
+  static void
+  export_integer(Export* exp, const mpz_t val);
+
+ protected:
+  bool
+  do_is_constant() const
+  { return true; }
+
+  bool
+  do_integer_constant_value(bool, mpz_t val, Type** ptype) const;
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context* context);
+
+  void
+  do_check_types(Gogo*);
+
+  tree
+  do_get_tree(Translate_context*);
+
+  Expression*
+  do_copy()
+  { return Expression::make_integer(&this->val_, this->type_,
+                                   this->location()); }
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // The integer value.
+  mpz_t val_;
+  // The type so far.
+  Type* type_;
+};
+
+// Return an integer constant value.
+
+bool
+Integer_expression::do_integer_constant_value(bool, mpz_t val,
+                                             Type** ptype) const
+{
+  if (this->type_ != NULL)
+    *ptype = this->type_;
+  mpz_set(val, this->val_);
+  return true;
+}
+
+// Return the current type.  If we haven't set the type yet, we return
+// an abstract integer type.
+
+Type*
+Integer_expression::do_type()
+{
+  if (this->type_ == NULL)
+    this->type_ = Type::make_abstract_integer_type();
+  return this->type_;
+}
+
+// Set the type of the integer value.  Here we may switch from an
+// abstract type to a real type.
+
+void
+Integer_expression::do_determine_type(const Type_context* context)
+{
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    ;
+  else if (context->type != NULL
+          && (context->type->integer_type() != NULL
+              || context->type->float_type() != NULL
+              || context->type->complex_type() != NULL))
+    this->type_ = context->type;
+  else if (!context->may_be_abstract)
+    this->type_ = Type::lookup_integer_type("int");
+}
+
+// Return true if the integer VAL fits in the range of the type TYPE.
+// Otherwise give an error and return false.  TYPE may be NULL.
+
+bool
+Integer_expression::check_constant(mpz_t val, Type* type,
+                                  source_location location)
+{
+  if (type == NULL)
+    return true;
+  Integer_type* itype = type->integer_type();
+  if (itype == NULL || itype->is_abstract())
+    return true;
+
+  int bits = mpz_sizeinbase(val, 2);
+
+  if (itype->is_unsigned())
+    {
+      // For an unsigned type we can only accept a nonnegative number,
+      // and we must be able to represent at least BITS.
+      if (mpz_sgn(val) >= 0
+         && bits <= itype->bits())
+       return true;
+    }
+  else
+    {
+      // For a signed type we need an extra bit to indicate the sign.
+      // We have to handle the most negative integer specially.
+      if (bits + 1 <= itype->bits()
+         || (bits <= itype->bits()
+             && mpz_sgn(val) < 0
+             && (mpz_scan1(val, 0)
+                 == static_cast<unsigned long>(itype->bits() - 1))
+             && mpz_scan0(val, itype->bits()) == ULONG_MAX))
+       return true;
+    }
+
+  error_at(location, "integer constant overflow");
+  return false;
+}
+
+// Check the type of an integer constant.
+
+void
+Integer_expression::do_check_types(Gogo*)
+{
+  if (this->type_ == NULL)
+    return;
+  if (!Integer_expression::check_constant(this->val_, this->type_,
+                                         this->location()))
+    this->set_is_error();
+}
+
+// Get a tree for an integer constant.
+
+tree
+Integer_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  tree type;
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    type = this->type_->get_tree(gogo);
+  else if (this->type_ != NULL && this->type_->float_type() != NULL)
+    {
+      // We are converting to an abstract floating point type.
+      type = Type::lookup_float_type("float64")->get_tree(gogo);
+    }
+  else if (this->type_ != NULL && this->type_->complex_type() != NULL)
+    {
+      // We are converting to an abstract complex type.
+      type = Type::lookup_complex_type("complex128")->get_tree(gogo);
+    }
+  else
+    {
+      // If we still have an abstract type here, then this is being
+      // used in a constant expression which didn't get reduced for
+      // some reason.  Use a type which will fit the value.  We use <,
+      // not <=, because we need an extra bit for the sign bit.
+      int bits = mpz_sizeinbase(this->val_, 2);
+      if (bits < INT_TYPE_SIZE)
+       type = Type::lookup_integer_type("int")->get_tree(gogo);
+      else if (bits < 64)
+       type = Type::lookup_integer_type("int64")->get_tree(gogo);
+      else
+       type = long_long_integer_type_node;
+    }
+  return Expression::integer_constant_tree(this->val_, type);
+}
+
+// Write VAL to export data.
+
+void
+Integer_expression::export_integer(Export* exp, const mpz_t val)
+{
+  char* s = mpz_get_str(NULL, 10, val);
+  exp->write_c_string(s);
+  free(s);
+}
+
+// Export an integer in a constant expression.
+
+void
+Integer_expression::do_export(Export* exp) const
+{
+  Integer_expression::export_integer(exp, this->val_);
+  // A trailing space lets us reliably identify the end of the number.
+  exp->write_c_string(" ");
+}
+
+// Import an integer, floating point, or complex value.  This handles
+// all these types because they all start with digits.
+
+Expression*
+Integer_expression::do_import(Import* imp)
+{
+  std::string num = imp->read_identifier();
+  imp->require_c_string(" ");
+  if (!num.empty() && num[num.length() - 1] == 'i')
+    {
+      mpfr_t real;
+      size_t plus_pos = num.find('+', 1);
+      size_t minus_pos = num.find('-', 1);
+      size_t pos;
+      if (plus_pos == std::string::npos)
+       pos = minus_pos;
+      else if (minus_pos == std::string::npos)
+       pos = plus_pos;
+      else
+       {
+         error_at(imp->location(), "bad number in import data: %qs",
+                  num.c_str());
+         return Expression::make_error(imp->location());
+       }
+      if (pos == std::string::npos)
+       mpfr_set_ui(real, 0, GMP_RNDN);
+      else
+       {
+         std::string real_str = num.substr(0, pos);
+         if (mpfr_init_set_str(real, real_str.c_str(), 10, GMP_RNDN) != 0)
+           {
+             error_at(imp->location(), "bad number in import data: %qs",
+                      real_str.c_str());
+             return Expression::make_error(imp->location());
+           }
+       }
+
+      std::string imag_str;
+      if (pos == std::string::npos)
+       imag_str = num;
+      else
+       imag_str = num.substr(pos);
+      imag_str = imag_str.substr(0, imag_str.size() - 1);
+      mpfr_t imag;
+      if (mpfr_init_set_str(imag, imag_str.c_str(), 10, GMP_RNDN) != 0)
+       {
+         error_at(imp->location(), "bad number in import data: %qs",
+                  imag_str.c_str());
+         return Expression::make_error(imp->location());
+       }
+      Expression* ret = Expression::make_complex(&real, &imag, NULL,
+                                                imp->location());
+      mpfr_clear(real);
+      mpfr_clear(imag);
+      return ret;
+    }
+  else if (num.find('.') == std::string::npos
+          && num.find('E') == std::string::npos)
+    {
+      mpz_t val;
+      if (mpz_init_set_str(val, num.c_str(), 10) != 0)
+       {
+         error_at(imp->location(), "bad number in import data: %qs",
+                  num.c_str());
+         return Expression::make_error(imp->location());
+       }
+      Expression* ret = Expression::make_integer(&val, NULL, imp->location());
+      mpz_clear(val);
+      return ret;
+    }
+  else
+    {
+      mpfr_t val;
+      if (mpfr_init_set_str(val, num.c_str(), 10, GMP_RNDN) != 0)
+       {
+         error_at(imp->location(), "bad number in import data: %qs",
+                  num.c_str());
+         return Expression::make_error(imp->location());
+       }
+      Expression* ret = Expression::make_float(&val, NULL, imp->location());
+      mpfr_clear(val);
+      return ret;
+    }
+}
+
+// Build a new integer value.
+
+Expression*
+Expression::make_integer(const mpz_t* val, Type* type,
+                        source_location location)
+{
+  return new Integer_expression(val, type, location);
+}
+
+// Floats.
+
+class Float_expression : public Expression
+{
+ public:
+  Float_expression(const mpfr_t* val, Type* type, source_location location)
+    : Expression(EXPRESSION_FLOAT, location),
+      type_(type)
+  {
+    mpfr_init_set(this->val_, *val, GMP_RNDN);
+  }
+
+  // Constrain VAL to fit into TYPE.
+  static void
+  constrain_float(mpfr_t val, Type* type);
+
+  // Return whether VAL fits in the type.
+  static bool
+  check_constant(mpfr_t val, Type*, source_location);
+
+  // Write VAL to export data.
+  static void
+  export_float(Export* exp, const mpfr_t val);
+
+ protected:
+  bool
+  do_is_constant() const
+  { return true; }
+
+  bool
+  do_float_constant_value(mpfr_t val, Type**) const;
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  { return Expression::make_float(&this->val_, this->type_,
+                                 this->location()); }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // The floating point value.
+  mpfr_t val_;
+  // The type so far.
+  Type* type_;
+};
+
+// Constrain VAL to fit into TYPE.
+
+void
+Float_expression::constrain_float(mpfr_t val, Type* type)
+{
+  Float_type* ftype = type->float_type();
+  if (ftype != NULL && !ftype->is_abstract())
+    {
+      tree type_tree = ftype->type_tree();
+      REAL_VALUE_TYPE rvt;
+      real_from_mpfr(&rvt, val, type_tree, GMP_RNDN);
+      real_convert(&rvt, TYPE_MODE(type_tree), &rvt);
+      mpfr_from_real(val, &rvt, GMP_RNDN);
+    }
+}
+
+// Return a floating point constant value.
+
+bool
+Float_expression::do_float_constant_value(mpfr_t val, Type** ptype) const
+{
+  if (this->type_ != NULL)
+    *ptype = this->type_;
+  mpfr_set(val, this->val_, GMP_RNDN);
+  return true;
+}
+
+// Return the current type.  If we haven't set the type yet, we return
+// an abstract float type.
+
+Type*
+Float_expression::do_type()
+{
+  if (this->type_ == NULL)
+    this->type_ = Type::make_abstract_float_type();
+  return this->type_;
+}
+
+// Set the type of the float value.  Here we may switch from an
+// abstract type to a real type.
+
+void
+Float_expression::do_determine_type(const Type_context* context)
+{
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    ;
+  else if (context->type != NULL
+          && (context->type->integer_type() != NULL
+              || context->type->float_type() != NULL
+              || context->type->complex_type() != NULL))
+    this->type_ = context->type;
+  else if (!context->may_be_abstract)
+    this->type_ = Type::lookup_float_type("float");
+}
+
+// Return true if the floating point value VAL fits in the range of
+// the type TYPE.  Otherwise give an error and return false.  TYPE may
+// be NULL.
+
+bool
+Float_expression::check_constant(mpfr_t val, Type* type,
+                                source_location location)
+{
+  if (type == NULL)
+    return true;
+  Float_type* ftype = type->float_type();
+  if (ftype == NULL || ftype->is_abstract())
+    return true;
+
+  // A NaN or Infinity always fits in the range of the type.
+  if (mpfr_nan_p(val) || mpfr_inf_p(val) || mpfr_zero_p(val))
+    return true;
+
+  mp_exp_t exp = mpfr_get_exp(val);
+  mp_exp_t max_exp;
+  switch (ftype->bits())
+    {
+    case 32:
+      max_exp = 128;
+      break;
+    case 64:
+      max_exp = 1024;
+      break;
+    default:
+      gcc_unreachable();
+    }
+  if (exp > max_exp)
+    {
+      error_at(location, "floating point constant overflow");
+      return false;
+    }
+  return true;
+}
+
+// Check the type of a float value.
+
+void
+Float_expression::do_check_types(Gogo*)
+{
+  if (this->type_ == NULL)
+    return;
+
+  if (!Float_expression::check_constant(this->val_, this->type_,
+                                       this->location()))
+    this->set_is_error();
+
+  Integer_type* integer_type = this->type_->integer_type();
+  if (integer_type != NULL)
+    {
+      if (!mpfr_integer_p(this->val_))
+       this->report_error(_("floating point constant truncated to integer"));
+      else
+       {
+         gcc_assert(!integer_type->is_abstract());
+         mpz_t ival;
+         mpz_init(ival);
+         mpfr_get_z(ival, this->val_, GMP_RNDN);
+         Integer_expression::check_constant(ival, integer_type,
+                                            this->location());
+         mpz_clear(ival);
+       }
+    }
+}
+
+// Get a tree for a float constant.
+
+tree
+Float_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  tree type;
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    type = this->type_->get_tree(gogo);
+  else if (this->type_ != NULL && this->type_->integer_type() != NULL)
+    {
+      // We have an abstract integer type.  We just hope for the best.
+      type = Type::lookup_integer_type("int")->get_tree(gogo);
+    }
+  else
+    {
+      // If we still have an abstract type here, then this is being
+      // used in a constant expression which didn't get reduced.  We
+      // just use float64 and hope for the best.
+      type = Type::lookup_float_type("float64")->get_tree(gogo);
+    }
+  return Expression::float_constant_tree(this->val_, type);
+}
+
+// Write a floating point number to export data.
+
+void
+Float_expression::export_float(Export *exp, const mpfr_t val)
+{
+  mp_exp_t exponent;
+  char* s = mpfr_get_str(NULL, &exponent, 10, 0, val, GMP_RNDN);
+  if (*s == '-')
+    exp->write_c_string("-");
+  exp->write_c_string("0.");
+  exp->write_c_string(*s == '-' ? s + 1 : s);
+  mpfr_free_str(s);
+  char buf[30];
+  snprintf(buf, sizeof buf, "E%ld", exponent);
+  exp->write_c_string(buf);
+}
+
+// Export a floating point number in a constant expression.
+
+void
+Float_expression::do_export(Export* exp) const
+{
+  Float_expression::export_float(exp, this->val_);
+  // A trailing space lets us reliably identify the end of the number.
+  exp->write_c_string(" ");
+}
+
+// Make a float expression.
+
+Expression*
+Expression::make_float(const mpfr_t* val, Type* type, source_location location)
+{
+  return new Float_expression(val, type, location);
+}
+
+// Complex numbers.
+
+class Complex_expression : public Expression
+{
+ public:
+  Complex_expression(const mpfr_t* real, const mpfr_t* imag, Type* type,
+                    source_location location)
+    : Expression(EXPRESSION_COMPLEX, location),
+      type_(type)
+  {
+    mpfr_init_set(this->real_, *real, GMP_RNDN);
+    mpfr_init_set(this->imag_, *imag, GMP_RNDN);
+  }
+
+  // Constrain REAL/IMAG to fit into TYPE.
+  static void
+  constrain_complex(mpfr_t real, mpfr_t imag, Type* type);
+
+  // Return whether REAL/IMAG fits in the type.
+  static bool
+  check_constant(mpfr_t real, mpfr_t imag, Type*, source_location);
+
+  // Write REAL/IMAG to export data.
+  static void
+  export_complex(Export* exp, const mpfr_t real, const mpfr_t val);
+
+ protected:
+  bool
+  do_is_constant() const
+  { return true; }
+
+  bool
+  do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const;
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_complex(&this->real_, &this->imag_, this->type_,
+                                   this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // The real part.
+  mpfr_t real_;
+  // The imaginary part;
+  mpfr_t imag_;
+  // The type if known.
+  Type* type_;
+};
+
+// Constrain REAL/IMAG to fit into TYPE.
+
+void
+Complex_expression::constrain_complex(mpfr_t real, mpfr_t imag, Type* type)
+{
+  Complex_type* ctype = type->complex_type();
+  if (ctype != NULL && !ctype->is_abstract())
+    {
+      tree type_tree = ctype->type_tree();
+
+      REAL_VALUE_TYPE rvt;
+      real_from_mpfr(&rvt, real, TREE_TYPE(type_tree), GMP_RNDN);
+      real_convert(&rvt, TYPE_MODE(TREE_TYPE(type_tree)), &rvt);
+      mpfr_from_real(real, &rvt, GMP_RNDN);
+
+      real_from_mpfr(&rvt, imag, TREE_TYPE(type_tree), GMP_RNDN);
+      real_convert(&rvt, TYPE_MODE(TREE_TYPE(type_tree)), &rvt);
+      mpfr_from_real(imag, &rvt, GMP_RNDN);
+    }
+}
+
+// Return a complex constant value.
+
+bool
+Complex_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+                                             Type** ptype) const
+{
+  if (this->type_ != NULL)
+    *ptype = this->type_;
+  mpfr_set(real, this->real_, GMP_RNDN);
+  mpfr_set(imag, this->imag_, GMP_RNDN);
+  return true;
+}
+
+// Return the current type.  If we haven't set the type yet, we return
+// an abstract complex type.
+
+Type*
+Complex_expression::do_type()
+{
+  if (this->type_ == NULL)
+    this->type_ = Type::make_abstract_complex_type();
+  return this->type_;
+}
+
+// Set the type of the complex value.  Here we may switch from an
+// abstract type to a real type.
+
+void
+Complex_expression::do_determine_type(const Type_context* context)
+{
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    ;
+  else if (context->type != NULL
+          && context->type->complex_type() != NULL)
+    this->type_ = context->type;
+  else if (!context->may_be_abstract)
+    this->type_ = Type::lookup_complex_type("complex");
+}
+
+// Return true if the complex value REAL/IMAG fits in the range of the
+// type TYPE.  Otherwise give an error and return false.  TYPE may be
+// NULL.
+
+bool
+Complex_expression::check_constant(mpfr_t real, mpfr_t imag, Type* type,
+                                  source_location location)
+{
+  if (type == NULL)
+    return true;
+  Complex_type* ctype = type->complex_type();
+  if (ctype == NULL || ctype->is_abstract())
+    return true;
+
+  mp_exp_t max_exp;
+  switch (ctype->bits())
+    {
+    case 64:
+      max_exp = 128;
+      break;
+    case 128:
+      max_exp = 1024;
+      break;
+    default:
+      gcc_unreachable();
+    }
+
+  // A NaN or Infinity always fits in the range of the type.
+  if (!mpfr_nan_p(real) && !mpfr_inf_p(real) && !mpfr_zero_p(real))
+    {
+      if (mpfr_get_exp(real) > max_exp)
+       {
+         error_at(location, "complex real part constant overflow");
+         return false;
+       }
+    }
+
+  if (!mpfr_nan_p(imag) && !mpfr_inf_p(imag) && !mpfr_zero_p(imag))
+    {
+      if (mpfr_get_exp(imag) > max_exp)
+       {
+         error_at(location, "complex imaginary part constant overflow");
+         return false;
+       }
+    }
+
+  return true;
+}
+
+// Check the type of a complex value.
+
+void
+Complex_expression::do_check_types(Gogo*)
+{
+  if (this->type_ == NULL)
+    return;
+
+  if (!Complex_expression::check_constant(this->real_, this->imag_,
+                                         this->type_, this->location()))
+    this->set_is_error();
+}
+
+// Get a tree for a complex constant.
+
+tree
+Complex_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  tree type;
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    type = this->type_->get_tree(gogo);
+  else
+    {
+      // If we still have an abstract type here, this this is being
+      // used in a constant expression which didn't get reduced.  We
+      // just use complex128 and hope for the best.
+      type = Type::lookup_complex_type("complex128")->get_tree(gogo);
+    }
+  return Expression::complex_constant_tree(this->real_, this->imag_, type);
+}
+
+// Write REAL/IMAG to export data.
+
+void
+Complex_expression::export_complex(Export* exp, const mpfr_t real,
+                                  const mpfr_t imag)
+{
+  if (!mpfr_zero_p(real))
+    {
+      Float_expression::export_float(exp, real);
+      if (mpfr_sgn(imag) > 0)
+       exp->write_c_string("+");
+    }
+  Float_expression::export_float(exp, imag);
+  exp->write_c_string("i");
+}
+
+// Export a complex number in a constant expression.
+
+void
+Complex_expression::do_export(Export* exp) const
+{
+  Complex_expression::export_complex(exp, this->real_, this->imag_);
+  // A trailing space lets us reliably identify the end of the number.
+  exp->write_c_string(" ");
+}
+
+// Make a complex expression.
+
+Expression*
+Expression::make_complex(const mpfr_t* real, const mpfr_t* imag, Type* type,
+                        source_location location)
+{
+  return new Complex_expression(real, imag, type, location);
+}
+
+// A reference to a const in an expression.
+
+class Const_expression : public Expression
+{
+ public:
+  Const_expression(Named_object* constant, source_location location)
+    : Expression(EXPRESSION_CONST_REFERENCE, location),
+      constant_(constant), type_(NULL)
+  { }
+
+  const std::string&
+  name() const
+  { return this->constant_->name(); }
+
+ protected:
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  bool
+  do_is_constant() const
+  { return true; }
+
+  bool
+  do_integer_constant_value(bool, mpz_t val, Type**) const;
+
+  bool
+  do_float_constant_value(mpfr_t val, Type**) const;
+
+  bool
+  do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const;
+
+  bool
+  do_string_constant_value(std::string* val) const
+  { return this->constant_->const_value()->expr()->string_constant_value(val); }
+
+  Type*
+  do_type();
+
+  // The type of a const is set by the declaration, not the use.
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+  // When exporting a reference to a const as part of a const
+  // expression, we export the value.  We ignore the fact that it has
+  // a name.
+  void
+  do_export(Export* exp) const
+  { this->constant_->const_value()->expr()->export_expression(exp); }
+
+ private:
+  // The constant.
+  Named_object* constant_;
+  // The type of this reference.  This is used if the constant has an
+  // abstract type.
+  Type* type_;
+};
+
+// Lower a constant expression.  This is where we convert the
+// predeclared constant iota into an integer value.
+
+Expression*
+Const_expression::do_lower(Gogo* gogo, Named_object*, int iota_value)
+{
+  if (this->constant_->const_value()->expr()->classification()
+      == EXPRESSION_IOTA)
+    {
+      if (iota_value == -1)
+       {
+         error_at(this->location(),
+                  "iota is only defined in const declarations");
+         iota_value = 0;
+       }
+      mpz_t val;
+      mpz_init_set_ui(val, static_cast<unsigned long>(iota_value));
+      Expression* ret = Expression::make_integer(&val, NULL,
+                                                this->location());
+      mpz_clear(val);
+      return ret;
+    }
+
+  // Make sure that the constant itself has been lowered.
+  gogo->lower_constant(this->constant_);
+
+  return this;
+}
+
+// Return an integer constant value.
+
+bool
+Const_expression::do_integer_constant_value(bool iota_is_constant, mpz_t val,
+                                           Type** ptype) const
+{
+  Type* ctype;
+  if (this->type_ != NULL)
+    ctype = this->type_;
+  else
+    ctype = this->constant_->const_value()->type();
+  if (ctype != NULL && ctype->integer_type() == NULL)
+    return false;
+
+  Expression* e = this->constant_->const_value()->expr();
+  Type* t;
+  bool r = e->integer_constant_value(iota_is_constant, val, &t);
+
+  if (r
+      && ctype != NULL
+      && !Integer_expression::check_constant(val, ctype, this->location()))
+    return false;
+
+  *ptype = ctype != NULL ? ctype : t;
+  return r;
+}
+
+// Return a floating point constant value.
+
+bool
+Const_expression::do_float_constant_value(mpfr_t val, Type** ptype) const
+{
+  Type* ctype;
+  if (this->type_ != NULL)
+    ctype = this->type_;
+  else
+    ctype = this->constant_->const_value()->type();
+  if (ctype != NULL && ctype->float_type() == NULL)
+    return false;
+
+  Type* t;
+  bool r = this->constant_->const_value()->expr()->float_constant_value(val,
+                                                                       &t);
+  if (r && ctype != NULL)
+    {
+      if (!Float_expression::check_constant(val, ctype, this->location()))
+       return false;
+      Float_expression::constrain_float(val, ctype);
+    }
+  *ptype = ctype != NULL ? ctype : t;
+  return r;
+}
+
+// Return a complex constant value.
+
+bool
+Const_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+                                           Type **ptype) const
+{
+  Type* ctype;
+  if (this->type_ != NULL)
+    ctype = this->type_;
+  else
+    ctype = this->constant_->const_value()->type();
+  if (ctype != NULL && ctype->complex_type() == NULL)
+    return false;
+
+  Type *t;
+  bool r = this->constant_->const_value()->expr()->complex_constant_value(real,
+                                                                         imag,
+                                                                         &t);
+  if (r && ctype != NULL)
+    {
+      if (!Complex_expression::check_constant(real, imag, ctype,
+                                             this->location()))
+       return false;
+      Complex_expression::constrain_complex(real, imag, ctype);
+    }
+  *ptype = ctype != NULL ? ctype : t;
+  return r;
+}
+
+// Return the type of the const reference.
+
+Type*
+Const_expression::do_type()
+{
+  if (this->type_ != NULL)
+    return this->type_;
+  Named_constant* nc = this->constant_->const_value();
+  Type* ret = nc->type();
+  if (ret != NULL)
+    return ret;
+  // During parsing, a named constant may have a NULL type, but we
+  // must not return a NULL type here.
+  return nc->expr()->type();
+}
+
+// Set the type of the const reference.
+
+void
+Const_expression::do_determine_type(const Type_context* context)
+{
+  Type* ctype = this->constant_->const_value()->type();
+  Type* cetype = (ctype != NULL
+                 ? ctype
+                 : this->constant_->const_value()->expr()->type());
+  if (ctype != NULL && !ctype->is_abstract())
+    ;
+  else if (context->type != NULL
+          && (context->type->integer_type() != NULL
+              || context->type->float_type() != NULL
+              || context->type->complex_type() != NULL)
+          && (cetype->integer_type() != NULL
+              || cetype->float_type() != NULL
+              || cetype->complex_type() != NULL))
+    this->type_ = context->type;
+  else if (context->type != NULL
+          && context->type->is_string_type()
+          && cetype->is_string_type())
+    this->type_ = context->type;
+  else if (context->type != NULL
+          && context->type->is_boolean_type()
+          && cetype->is_boolean_type())
+    this->type_ = context->type;
+  else if (!context->may_be_abstract)
+    {
+      if (cetype->is_abstract())
+       cetype = cetype->make_non_abstract_type();
+      this->type_ = cetype;
+    }
+}
+
+// Check types of a const reference.
+
+void
+Const_expression::do_check_types(Gogo*)
+{
+  if (this->type_ == NULL || this->type_->is_abstract())
+    return;
+
+  // Check for integer overflow.
+  if (this->type_->integer_type() != NULL)
+    {
+      mpz_t ival;
+      mpz_init(ival);
+      Type* dummy;
+      if (!this->integer_constant_value(true, ival, &dummy))
+       {
+         mpfr_t fval;
+         mpfr_init(fval);
+         Expression* cexpr = this->constant_->const_value()->expr();
+         if (cexpr->float_constant_value(fval, &dummy))
+           {
+             if (!mpfr_integer_p(fval))
+               this->report_error(_("floating point constant "
+                                    "truncated to integer"));
+             else
+               {
+                 mpfr_get_z(ival, fval, GMP_RNDN);
+                 Integer_expression::check_constant(ival, this->type_,
+                                                    this->location());
+               }
+           }
+         mpfr_clear(fval);
+       }
+      mpz_clear(ival);
+    }
+}
+
+// Return a tree for the const reference.
+
+tree
+Const_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  tree type_tree;
+  if (this->type_ == NULL)
+    type_tree = NULL_TREE;
+  else
+    {
+      type_tree = this->type_->get_tree(gogo);
+      if (type_tree == error_mark_node)
+       return error_mark_node;
+    }
+
+  // If the type has been set for this expression, but the underlying
+  // object is an abstract int or float, we try to get the abstract
+  // value.  Otherwise we may lose something in the conversion.
+  if (this->type_ != NULL
+      && this->constant_->const_value()->type()->is_abstract())
+    {
+      Expression* expr = this->constant_->const_value()->expr();
+      mpz_t ival;
+      mpz_init(ival);
+      Type* t;
+      if (expr->integer_constant_value(true, ival, &t))
+       {
+         tree ret = Expression::integer_constant_tree(ival, type_tree);
+         mpz_clear(ival);
+         return ret;
+       }
+      mpz_clear(ival);
+
+      mpfr_t fval;
+      mpfr_init(fval);
+      if (expr->float_constant_value(fval, &t))
+       {
+         tree ret = Expression::float_constant_tree(fval, type_tree);
+         mpfr_clear(fval);
+         return ret;
+       }
+
+      mpfr_t imag;
+      mpfr_init(imag);
+      if (expr->complex_constant_value(fval, imag, &t))
+       {
+         tree ret = Expression::complex_constant_tree(fval, imag, type_tree);
+         mpfr_clear(fval);
+         mpfr_clear(imag);
+         return ret;
+       }
+      mpfr_clear(imag);
+      mpfr_clear(fval);
+    }
+
+  tree const_tree = this->constant_->get_tree(gogo, context->function());
+  if (this->type_ == NULL
+      || const_tree == error_mark_node
+      || TREE_TYPE(const_tree) == error_mark_node)
+    return const_tree;
+
+  tree ret;
+  if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(const_tree)))
+    ret = fold_convert(type_tree, const_tree);
+  else if (TREE_CODE(type_tree) == INTEGER_TYPE)
+    ret = fold(convert_to_integer(type_tree, const_tree));
+  else if (TREE_CODE(type_tree) == REAL_TYPE)
+    ret = fold(convert_to_real(type_tree, const_tree));
+  else if (TREE_CODE(type_tree) == COMPLEX_TYPE)
+    ret = fold(convert_to_complex(type_tree, const_tree));
+  else
+    gcc_unreachable();
+  return ret;
+}
+
+// Make a reference to a constant in an expression.
+
+Expression*
+Expression::make_const_reference(Named_object* constant,
+                                source_location location)
+{
+  return new Const_expression(constant, location);
+}
+
+// The nil value.
+
+class Nil_expression : public Expression
+{
+ public:
+  Nil_expression(source_location location)
+    : Expression(EXPRESSION_NIL, location)
+  { }
+
+  static Expression*
+  do_import(Import*);
+
+ protected:
+  bool
+  do_is_constant() const
+  { return true; }
+
+  Type*
+  do_type()
+  { return Type::make_nil_type(); }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  tree
+  do_get_tree(Translate_context*)
+  { return null_pointer_node; }
+
+  void
+  do_export(Export* exp) const
+  { exp->write_c_string("nil"); }
+};
+
+// Import a nil expression.
+
+Expression*
+Nil_expression::do_import(Import* imp)
+{
+  imp->require_c_string("nil");
+  return Expression::make_nil(imp->location());
+}
+
+// Make a nil expression.
+
+Expression*
+Expression::make_nil(source_location location)
+{
+  return new Nil_expression(location);
+}
+
+// The value of the predeclared constant iota.  This is little more
+// than a marker.  This will be lowered to an integer in
+// Const_expression::do_lower, which is where we know the value that
+// it should have.
+
+class Iota_expression : public Parser_expression
+{
+ public:
+  Iota_expression(source_location location)
+    : Parser_expression(EXPRESSION_IOTA, location)
+  { }
+
+ protected:
+  Expression*
+  do_lower(Gogo*, Named_object*, int)
+  { gcc_unreachable(); }
+
+  // There should only ever be one of these.
+  Expression*
+  do_copy()
+  { gcc_unreachable(); }
+};
+
+// Make an iota expression.  This is only called for one case: the
+// value of the predeclared constant iota.
+
+Expression*
+Expression::make_iota()
+{
+  static Iota_expression iota_expression(UNKNOWN_LOCATION);
+  return &iota_expression;
+}
+
+// A type conversion expression.
+
+class Type_conversion_expression : public Expression
+{
+ public:
+  Type_conversion_expression(Type* type, Expression* expr,
+                            source_location location)
+    : Expression(EXPRESSION_CONVERSION, location),
+      type_(type), expr_(expr), may_convert_function_types_(false)
+  { }
+
+  // Return the type to which we are converting.
+  Type*
+  type() const
+  { return this->type_; }
+
+  // Return the expression which we are converting.
+  Expression*
+  expr() const
+  { return this->expr_; }
+
+  // Permit converting from one function type to another.  This is
+  // used internally for method expressions.
+  void
+  set_may_convert_function_types()
+  {
+    this->may_convert_function_types_ = true;
+  }
+
+  // Import a type conversion expression.
+  static Expression*
+  do_import(Import*);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  bool
+  do_is_constant() const
+  { return this->expr_->is_constant(); }
+
+  bool
+  do_integer_constant_value(bool, mpz_t, Type**) const;
+
+  bool
+  do_float_constant_value(mpfr_t, Type**) const;
+
+  bool
+  do_complex_constant_value(mpfr_t, mpfr_t, Type**) const;
+
+  bool
+  do_string_constant_value(std::string*) const;
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*)
+  {
+    Type_context subcontext(this->type_, false);
+    this->expr_->determine_type(&subcontext);
+  }
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return new Type_conversion_expression(this->type_, this->expr_->copy(),
+                                         this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // The type to convert to.
+  Type* type_;
+  // The expression to convert.
+  Expression* expr_;
+  // True if this is permitted to convert function types.  This is
+  // used internally for method expressions.
+  bool may_convert_function_types_;
+};
+
+// Traversal.
+
+int
+Type_conversion_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT
+      || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Convert to a constant at lowering time.
+
+Expression*
+Type_conversion_expression::do_lower(Gogo*, Named_object*, int)
+{
+  Type* type = this->type_;
+  Expression* val = this->expr_;
+  source_location location = this->location();
+
+  if (type->integer_type() != NULL)
+    {
+      mpz_t ival;
+      mpz_init(ival);
+      Type* dummy;
+      if (val->integer_constant_value(false, ival, &dummy))
+       {
+         if (!Integer_expression::check_constant(ival, type, location))
+           mpz_set_ui(ival, 0);
+         Expression* ret = Expression::make_integer(&ival, type, location);
+         mpz_clear(ival);
+         return ret;
+       }
+
+      mpfr_t fval;
+      mpfr_init(fval);
+      if (val->float_constant_value(fval, &dummy))
+       {
+         if (!mpfr_integer_p(fval))
+           {
+             error_at(location,
+                      "floating point constant truncated to integer");
+             return Expression::make_error(location);
+           }
+         mpfr_get_z(ival, fval, GMP_RNDN);
+         if (!Integer_expression::check_constant(ival, type, location))
+           mpz_set_ui(ival, 0);
+         Expression* ret = Expression::make_integer(&ival, type, location);
+         mpfr_clear(fval);
+         mpz_clear(ival);
+         return ret;
+       }
+      mpfr_clear(fval);
+      mpz_clear(ival);
+    }
+
+  if (type->float_type() != NULL)
+    {
+      mpfr_t fval;
+      mpfr_init(fval);
+      Type* dummy;
+      if (val->float_constant_value(fval, &dummy))
+       {
+         if (!Float_expression::check_constant(fval, type, location))
+           mpfr_set_ui(fval, 0, GMP_RNDN);
+         Float_expression::constrain_float(fval, type);
+         Expression *ret = Expression::make_float(&fval, type, location);
+         mpfr_clear(fval);
+         return ret;
+       }
+      mpfr_clear(fval);
+    }
+
+  if (type->complex_type() != NULL)
+    {
+      mpfr_t real;
+      mpfr_t imag;
+      mpfr_init(real);
+      mpfr_init(imag);
+      Type* dummy;
+      if (val->complex_constant_value(real, imag, &dummy))
+       {
+         if (!Complex_expression::check_constant(real, imag, type, location))
+           {
+             mpfr_set_ui(real, 0, GMP_RNDN);
+             mpfr_set_ui(imag, 0, GMP_RNDN);
+           }
+         Complex_expression::constrain_complex(real, imag, type);
+         Expression* ret = Expression::make_complex(&real, &imag, type,
+                                                    location);
+         mpfr_clear(real);
+         mpfr_clear(imag);
+         return ret;
+       }
+      mpfr_clear(real);
+      mpfr_clear(imag);
+    }
+
+  if (type->is_open_array_type() && type->named_type() == NULL)
+    {
+      Type* element_type = type->array_type()->element_type()->forwarded();
+      bool is_byte = element_type == Type::lookup_integer_type("uint8");
+      bool is_int = element_type == Type::lookup_integer_type("int");
+      if (is_byte || is_int)
+       {
+         std::string s;
+         if (val->string_constant_value(&s))
+           {
+             Expression_list* vals = new Expression_list();
+             if (is_byte)
+               {
+                 for (std::string::const_iterator p = s.begin();
+                      p != s.end();
+                      p++)
+                   {
+                     mpz_t val;
+                     mpz_init_set_ui(val, static_cast<unsigned char>(*p));
+                     Expression* v = Expression::make_integer(&val,
+                                                              element_type,
+                                                              location);
+                     vals->push_back(v);
+                     mpz_clear(val);
+                   }
+               }
+             else
+               {
+                 const char *p = s.data();
+                 const char *pend = s.data() + s.length();
+                 while (p < pend)
+                   {
+                     unsigned int c;
+                     int adv = Lex::fetch_char(p, &c);
+                     if (adv == 0)
+                       {
+                         warning_at(this->location(), 0,
+                                    "invalid UTF-8 encoding");
+                         adv = 1;
+                       }
+                     p += adv;
+                     mpz_t val;
+                     mpz_init_set_ui(val, c);
+                     Expression* v = Expression::make_integer(&val,
+                                                              element_type,
+                                                              location);
+                     vals->push_back(v);
+                     mpz_clear(val);
+                   }
+               }
+
+             return Expression::make_slice_composite_literal(type, vals,
+                                                             location);
+           }
+       }
+    }
+
+  return this;
+}
+
+// Return the constant integer value if there is one.
+
+bool
+Type_conversion_expression::do_integer_constant_value(bool iota_is_constant,
+                                                     mpz_t val,
+                                                     Type** ptype) const
+{
+  if (this->type_->integer_type() == NULL)
+    return false;
+
+  mpz_t ival;
+  mpz_init(ival);
+  Type* dummy;
+  if (this->expr_->integer_constant_value(iota_is_constant, ival, &dummy))
+    {
+      if (!Integer_expression::check_constant(ival, this->type_,
+                                             this->location()))
+       {
+         mpz_clear(ival);
+         return false;
+       }
+      mpz_set(val, ival);
+      mpz_clear(ival);
+      *ptype = this->type_;
+      return true;
+    }
+  mpz_clear(ival);
+
+  mpfr_t fval;
+  mpfr_init(fval);
+  if (this->expr_->float_constant_value(fval, &dummy))
+    {
+      mpfr_get_z(val, fval, GMP_RNDN);
+      mpfr_clear(fval);
+      if (!Integer_expression::check_constant(val, this->type_,
+                                             this->location()))
+       return false;
+      *ptype = this->type_;
+      return true;
+    }
+  mpfr_clear(fval);
+
+  return false;
+}
+
+// Return the constant floating point value if there is one.
+
+bool
+Type_conversion_expression::do_float_constant_value(mpfr_t val,
+                                                   Type** ptype) const
+{
+  if (this->type_->float_type() == NULL)
+    return false;
+
+  mpfr_t fval;
+  mpfr_init(fval);
+  Type* dummy;
+  if (this->expr_->float_constant_value(fval, &dummy))
+    {
+      if (!Float_expression::check_constant(fval, this->type_,
+                                           this->location()))
+       {
+         mpfr_clear(fval);
+         return false;
+       }
+      mpfr_set(val, fval, GMP_RNDN);
+      mpfr_clear(fval);
+      Float_expression::constrain_float(val, this->type_);
+      *ptype = this->type_;
+      return true;
+    }
+  mpfr_clear(fval);
+
+  return false;
+}
+
+// Return the constant complex value if there is one.
+
+bool
+Type_conversion_expression::do_complex_constant_value(mpfr_t real,
+                                                     mpfr_t imag,
+                                                     Type **ptype) const
+{
+  if (this->type_->complex_type() == NULL)
+    return false;
+
+  mpfr_t rval;
+  mpfr_t ival;
+  mpfr_init(rval);
+  mpfr_init(ival);
+  Type* dummy;
+  if (this->expr_->complex_constant_value(rval, ival, &dummy))
+    {
+      if (!Complex_expression::check_constant(rval, ival, this->type_,
+                                             this->location()))
+       {
+         mpfr_clear(rval);
+         mpfr_clear(ival);
+         return false;
+       }
+      mpfr_set(real, rval, GMP_RNDN);
+      mpfr_set(imag, ival, GMP_RNDN);
+      mpfr_clear(rval);
+      mpfr_clear(ival);
+      Complex_expression::constrain_complex(real, imag, this->type_);
+      *ptype = this->type_;
+      return true;
+    }
+  mpfr_clear(rval);
+  mpfr_clear(ival);
+
+  return false;  
+}
+
+// Return the constant string value if there is one.
+
+bool
+Type_conversion_expression::do_string_constant_value(std::string* val) const
+{
+  if (this->type_->is_string_type()
+      && this->expr_->type()->integer_type() != NULL)
+    {
+      mpz_t ival;
+      mpz_init(ival);
+      Type* dummy;
+      if (this->expr_->integer_constant_value(false, ival, &dummy))
+       {
+         unsigned long ulval = mpz_get_ui(ival);
+         if (mpz_cmp_ui(ival, ulval) == 0)
+           {
+             Lex::append_char(ulval, true, val, this->location());
+             mpz_clear(ival);
+             return true;
+           }
+       }
+      mpz_clear(ival);
+    }
+
+  // FIXME: Could handle conversion from const []int here.
+
+  return false;
+}
+
+// Check that types are convertible.
+
+void
+Type_conversion_expression::do_check_types(Gogo*)
+{
+  Type* type = this->type_;
+  Type* expr_type = this->expr_->type();
+  std::string reason;
+
+  if (this->may_convert_function_types_
+      && type->function_type() != NULL
+      && expr_type->function_type() != NULL)
+    return;
+
+  if (Type::are_convertible(type, expr_type, &reason))
+    return;
+
+  error_at(this->location(), "%s", reason.c_str());
+  this->set_is_error();
+}
+
+// Get a tree for a type conversion.
+
+tree
+Type_conversion_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  tree type_tree = this->type_->get_tree(gogo);
+  tree expr_tree = this->expr_->get_tree(context);
+
+  if (type_tree == error_mark_node
+      || expr_tree == error_mark_node
+      || TREE_TYPE(expr_tree) == error_mark_node)
+    return error_mark_node;
+
+  if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(expr_tree)))
+    return fold_convert(type_tree, expr_tree);
+
+  Type* type = this->type_;
+  Type* expr_type = this->expr_->type();
+  tree ret;
+  if (type->interface_type() != NULL || expr_type->interface_type() != NULL)
+    ret = Expression::convert_for_assignment(context, type, expr_type,
+                                            expr_tree, this->location());
+  else if (type->integer_type() != NULL)
+    {
+      if (expr_type->integer_type() != NULL
+         || expr_type->float_type() != NULL
+         || expr_type->is_unsafe_pointer_type())
+       ret = fold(convert_to_integer(type_tree, expr_tree));
+      else
+       gcc_unreachable();
+    }
+  else if (type->float_type() != NULL)
+    {
+      if (expr_type->integer_type() != NULL
+         || expr_type->float_type() != NULL)
+       ret = fold(convert_to_real(type_tree, expr_tree));
+      else
+       gcc_unreachable();
+    }
+  else if (type->complex_type() != NULL)
+    {
+      if (expr_type->complex_type() != NULL)
+       ret = fold(convert_to_complex(type_tree, expr_tree));
+      else
+       gcc_unreachable();
+    }
+  else if (type->is_string_type()
+          && expr_type->integer_type() != NULL)
+    {
+      expr_tree = fold_convert(integer_type_node, expr_tree);
+      if (host_integerp(expr_tree, 0))
+       {
+         HOST_WIDE_INT intval = tree_low_cst(expr_tree, 0);
+         std::string s;
+         Lex::append_char(intval, true, &s, this->location());
+         Expression* se = Expression::make_string(s, this->location());
+         return se->get_tree(context);
+       }
+
+      static tree int_to_string_fndecl;
+      ret = Gogo::call_builtin(&int_to_string_fndecl,
+                              this->location(),
+                              "__go_int_to_string",
+                              1,
+                              type_tree,
+                              integer_type_node,
+                              fold_convert(integer_type_node, expr_tree));
+    }
+  else if (type->is_string_type()
+          && (expr_type->array_type() != NULL
+              || (expr_type->points_to() != NULL
+                  && expr_type->points_to()->array_type() != NULL)))
+    {
+      Type* t = expr_type;
+      if (t->points_to() != NULL)
+       {
+         t = t->points_to();
+         expr_tree = build_fold_indirect_ref(expr_tree);
+       }
+      if (!DECL_P(expr_tree))
+       expr_tree = save_expr(expr_tree);
+      Array_type* a = t->array_type();
+      Type* e = a->element_type()->forwarded();
+      gcc_assert(e->integer_type() != NULL);
+      tree valptr = fold_convert(const_ptr_type_node,
+                                a->value_pointer_tree(gogo, expr_tree));
+      tree len = a->length_tree(gogo, expr_tree);
+      len = fold_convert_loc(this->location(), size_type_node, len);
+      if (e->integer_type()->is_unsigned()
+         && e->integer_type()->bits() == 8)
+       {
+         static tree byte_array_to_string_fndecl;
+         ret = Gogo::call_builtin(&byte_array_to_string_fndecl,
+                                  this->location(),
+                                  "__go_byte_array_to_string",
+                                  2,
+                                  type_tree,
+                                  const_ptr_type_node,
+                                  valptr,
+                                  size_type_node,
+                                  len);
+       }
+      else
+       {
+         gcc_assert(e == Type::lookup_integer_type("int"));
+         static tree int_array_to_string_fndecl;
+         ret = Gogo::call_builtin(&int_array_to_string_fndecl,
+                                  this->location(),
+                                  "__go_int_array_to_string",
+                                  2,
+                                  type_tree,
+                                  const_ptr_type_node,
+                                  valptr,
+                                  size_type_node,
+                                  len);
+       }
+    }
+  else if (type->is_open_array_type() && expr_type->is_string_type())
+    {
+      Type* e = type->array_type()->element_type()->forwarded();
+      gcc_assert(e->integer_type() != NULL);
+      if (e->integer_type()->is_unsigned()
+         && e->integer_type()->bits() == 8)
+       {
+         static tree string_to_byte_array_fndecl;
+         ret = Gogo::call_builtin(&string_to_byte_array_fndecl,
+                                  this->location(),
+                                  "__go_string_to_byte_array",
+                                  1,
+                                  type_tree,
+                                  TREE_TYPE(expr_tree),
+                                  expr_tree);
+       }
+      else
+       {
+         gcc_assert(e == Type::lookup_integer_type("int"));
+         static tree string_to_int_array_fndecl;
+         ret = Gogo::call_builtin(&string_to_int_array_fndecl,
+                                  this->location(),
+                                  "__go_string_to_int_array",
+                                  1,
+                                  type_tree,
+                                  TREE_TYPE(expr_tree),
+                                  expr_tree);
+       }
+    }
+  else if ((type->is_unsafe_pointer_type()
+           && expr_type->points_to() != NULL)
+          || (expr_type->is_unsafe_pointer_type()
+              && type->points_to() != NULL))
+    ret = fold_convert(type_tree, expr_tree);
+  else if (type->is_unsafe_pointer_type()
+          && expr_type->integer_type() != NULL)
+    ret = convert_to_pointer(type_tree, expr_tree);
+  else if (this->may_convert_function_types_
+          && type->function_type() != NULL
+          && expr_type->function_type() != NULL)
+    ret = fold_convert_loc(this->location(), type_tree, expr_tree);
+  else
+    ret = Expression::convert_for_assignment(context, type, expr_type,
+                                            expr_tree, this->location());
+
+  return ret;
+}
+
+// Output a type conversion in a constant expression.
+
+void
+Type_conversion_expression::do_export(Export* exp) const
+{
+  exp->write_c_string("convert(");
+  exp->write_type(this->type_);
+  exp->write_c_string(", ");
+  this->expr_->export_expression(exp);
+  exp->write_c_string(")");
+}
+
+// Import a type conversion or a struct construction.
+
+Expression*
+Type_conversion_expression::do_import(Import* imp)
+{
+  imp->require_c_string("convert(");
+  Type* type = imp->read_type();
+  imp->require_c_string(", ");
+  Expression* val = Expression::import_expression(imp);
+  imp->require_c_string(")");
+  return Expression::make_cast(type, val, imp->location());
+}
+
+// Make a type cast expression.
+
+Expression*
+Expression::make_cast(Type* type, Expression* val, source_location location)
+{
+  if (type->is_error_type() || val->is_error_expression())
+    return Expression::make_error(location);
+  return new Type_conversion_expression(type, val, location);
+}
+
+// Unary expressions.
+
+class Unary_expression : public Expression
+{
+ public:
+  Unary_expression(Operator op, Expression* expr, source_location location)
+    : Expression(EXPRESSION_UNARY, location),
+      op_(op), escapes_(true), expr_(expr)
+  { }
+
+  // Return the operator.
+  Operator
+  op() const
+  { return this->op_; }
+
+  // Return the operand.
+  Expression*
+  operand() const
+  { return this->expr_; }
+
+  // Record that an address expression does not escape.
+  void
+  set_does_not_escape()
+  {
+    gcc_assert(this->op_ == OPERATOR_AND);
+    this->escapes_ = false;
+  }
+
+  // Apply unary opcode OP to UVAL, setting VAL.  Return true if this
+  // could be done, false if not.
+  static bool
+  eval_integer(Operator op, Type* utype, mpz_t uval, mpz_t val,
+              source_location);
+
+  // Apply unary opcode OP to UVAL, setting VAL.  Return true if this
+  // could be done, false if not.
+  static bool
+  eval_float(Operator op, mpfr_t uval, mpfr_t val);
+
+  // Apply unary opcode OP to UREAL/UIMAG, setting REAL/IMAG.  Return
+  // true if this could be done, false if not.
+  static bool
+  eval_complex(Operator op, mpfr_t ureal, mpfr_t uimag, mpfr_t real,
+              mpfr_t imag);
+
+  static Expression*
+  do_import(Import*);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Expression::traverse(&this->expr_, traverse); }
+
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  bool
+  do_is_constant() const;
+
+  bool
+  do_integer_constant_value(bool, mpz_t, Type**) const;
+
+  bool
+  do_float_constant_value(mpfr_t, Type**) const;
+
+  bool
+  do_complex_constant_value(mpfr_t, mpfr_t, Type**) const;
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_unary(this->op_, this->expr_->copy(),
+                                 this->location());
+  }
+
+  bool
+  do_is_addressable() const
+  { return this->op_ == OPERATOR_MULT; }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // The unary operator to apply.
+  Operator op_;
+  // Normally true.  False if this is an address expression which does
+  // not escape the current function.
+  bool escapes_;
+  // The operand.
+  Expression* expr_;
+};
+
+// If we are taking the address of a composite literal, and the
+// contents are not constant, then we want to make a heap composite
+// instead.
+
+Expression*
+Unary_expression::do_lower(Gogo*, Named_object*, int)
+{
+  source_location loc = this->location();
+  Operator op = this->op_;
+  Expression* expr = this->expr_;
+
+  if (op == OPERATOR_MULT && expr->is_type_expression())
+    return Expression::make_type(Type::make_pointer_type(expr->type()), loc);
+
+  // *&x simplifies to x.  *(*T)(unsafe.Pointer)(&x) does not require
+  // moving x to the heap.  FIXME: Is it worth doing a real escape
+  // analysis here?  This case is found in math/unsafe.go and is
+  // therefore worth special casing.
+  if (op == OPERATOR_MULT)
+    {
+      Expression* e = expr;
+      while (e->classification() == EXPRESSION_CONVERSION)
+       {
+         Type_conversion_expression* te
+           = static_cast<Type_conversion_expression*>(e);
+         e = te->expr();
+       }
+
+      if (e->classification() == EXPRESSION_UNARY)
+       {
+         Unary_expression* ue = static_cast<Unary_expression*>(e);
+         if (ue->op_ == OPERATOR_AND)
+           {
+             if (e == expr)
+               {
+                 // *&x == x.
+                 return ue->expr_;
+               }
+             ue->set_does_not_escape();
+           }
+       }
+    }
+
+  if (op == OPERATOR_PLUS || op == OPERATOR_MINUS
+      || op == OPERATOR_NOT || op == OPERATOR_XOR)
+    {
+      Expression* ret = NULL;
+
+      mpz_t eval;
+      mpz_init(eval);
+      Type* etype;
+      if (expr->integer_constant_value(false, eval, &etype))
+       {
+         mpz_t val;
+         mpz_init(val);
+         if (Unary_expression::eval_integer(op, etype, eval, val, loc))
+           ret = Expression::make_integer(&val, etype, loc);
+         mpz_clear(val);
+       }
+      mpz_clear(eval);
+      if (ret != NULL)
+       return ret;
+
+      if (op == OPERATOR_PLUS || op == OPERATOR_MINUS)
+       {
+         mpfr_t fval;
+         mpfr_init(fval);
+         Type* ftype;
+         if (expr->float_constant_value(fval, &ftype))
+           {
+             mpfr_t val;
+             mpfr_init(val);
+             if (Unary_expression::eval_float(op, fval, val))
+               ret = Expression::make_float(&val, ftype, loc);
+             mpfr_clear(val);
+           }
+         if (ret != NULL)
+           {
+             mpfr_clear(fval);
+             return ret;
+           }
+
+         mpfr_t ival;
+         mpfr_init(ival);
+         if (expr->complex_constant_value(fval, ival, &ftype))
+           {
+             mpfr_t real;
+             mpfr_t imag;
+             mpfr_init(real);
+             mpfr_init(imag);
+             if (Unary_expression::eval_complex(op, fval, ival, real, imag))
+               ret = Expression::make_complex(&real, &imag, ftype, loc);
+             mpfr_clear(real);
+             mpfr_clear(imag);
+           }
+         mpfr_clear(ival);
+         mpfr_clear(fval);
+         if (ret != NULL)
+           return ret;
+       }
+    }
+
+  return this;
+}
+
+// Return whether a unary expression is a constant.
+
+bool
+Unary_expression::do_is_constant() const
+{
+  if (this->op_ == OPERATOR_MULT)
+    {
+      // Indirecting through a pointer is only constant if the object
+      // to which the expression points is constant, but we currently
+      // have no way to determine that.
+      return false;
+    }
+  else if (this->op_ == OPERATOR_AND)
+    {
+      // Taking the address of a variable is constant if it is a
+      // global variable, not constant otherwise.  In other cases
+      // taking the address is probably not a constant.
+      Var_expression* ve = this->expr_->var_expression();
+      if (ve != NULL)
+       {
+         Named_object* no = ve->named_object();
+         return no->is_variable() && no->var_value()->is_global();
+       }
+      return false;
+    }
+  else
+    return this->expr_->is_constant();
+}
+
+// Apply unary opcode OP to UVAL, setting VAL.  UTYPE is the type of
+// UVAL, if known; it may be NULL.  Return true if this could be done,
+// false if not.
+
+bool
+Unary_expression::eval_integer(Operator op, Type* utype, mpz_t uval, mpz_t val,
+                              source_location location)
+{
+  switch (op)
+    {
+    case OPERATOR_PLUS:
+      mpz_set(val, uval);
+      return true;
+    case OPERATOR_MINUS:
+      mpz_neg(val, uval);
+      return Integer_expression::check_constant(val, utype, location);
+    case OPERATOR_NOT:
+      mpz_set_ui(val, mpz_cmp_si(uval, 0) == 0 ? 1 : 0);
+      return true;
+    case OPERATOR_XOR:
+      if (utype == NULL
+         || utype->integer_type() == NULL
+         || utype->integer_type()->is_abstract())
+       mpz_com(val, uval);
+      else
+       {
+         // The number of HOST_WIDE_INTs that it takes to represent
+         // UVAL.
+         size_t count = ((mpz_sizeinbase(uval, 2)
+                          + HOST_BITS_PER_WIDE_INT
+                          - 1)
+                         / HOST_BITS_PER_WIDE_INT);
+
+         unsigned HOST_WIDE_INT* phwi = new unsigned HOST_WIDE_INT[count];
+         memset(phwi, 0, count * sizeof(HOST_WIDE_INT));
+
+         size_t ecount;
+         mpz_export(phwi, &ecount, -1, sizeof(HOST_WIDE_INT), 0, 0, uval);
+         gcc_assert(ecount <= count);
+
+         // Trim down to the number of words required by the type.
+         size_t obits = utype->integer_type()->bits();
+         if (!utype->integer_type()->is_unsigned())
+           ++obits;
+         size_t ocount = ((obits + HOST_BITS_PER_WIDE_INT - 1)
+                          / HOST_BITS_PER_WIDE_INT);
+         gcc_assert(ocount <= ocount);
+
+         for (size_t i = 0; i < ocount; ++i)
+           phwi[i] = ~phwi[i];
+
+         size_t clearbits = ocount * HOST_BITS_PER_WIDE_INT - obits;
+         if (clearbits != 0)
+           phwi[ocount - 1] &= (((unsigned HOST_WIDE_INT) (HOST_WIDE_INT) -1)
+                                >> clearbits);
+
+         mpz_import(val, ocount, -1, sizeof(HOST_WIDE_INT), 0, 0, phwi);
+
+         delete[] phwi;
+       }
+      return Integer_expression::check_constant(val, utype, location);
+    case OPERATOR_AND:
+    case OPERATOR_MULT:
+      return false;
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Apply unary opcode OP to UVAL, setting VAL.  Return true if this
+// could be done, false if not.
+
+bool
+Unary_expression::eval_float(Operator op, mpfr_t uval, mpfr_t val)
+{
+  switch (op)
+    {
+    case OPERATOR_PLUS:
+      mpfr_set(val, uval, GMP_RNDN);
+      return true;
+    case OPERATOR_MINUS:
+      mpfr_neg(val, uval, GMP_RNDN);
+      return true;
+    case OPERATOR_NOT:
+    case OPERATOR_XOR:
+    case OPERATOR_AND:
+    case OPERATOR_MULT:
+      return false;
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Apply unary opcode OP to RVAL/IVAL, setting REAL/IMAG.  Return true
+// if this could be done, false if not.
+
+bool
+Unary_expression::eval_complex(Operator op, mpfr_t rval, mpfr_t ival,
+                              mpfr_t real, mpfr_t imag)
+{
+  switch (op)
+    {
+    case OPERATOR_PLUS:
+      mpfr_set(real, rval, GMP_RNDN);
+      mpfr_set(imag, ival, GMP_RNDN);
+      return true;
+    case OPERATOR_MINUS:
+      mpfr_neg(real, rval, GMP_RNDN);
+      mpfr_neg(imag, ival, GMP_RNDN);
+      return true;
+    case OPERATOR_NOT:
+    case OPERATOR_XOR:
+    case OPERATOR_AND:
+    case OPERATOR_MULT:
+      return false;
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Return the integral constant value of a unary expression, if it has one.
+
+bool
+Unary_expression::do_integer_constant_value(bool iota_is_constant, mpz_t val,
+                                           Type** ptype) const
+{
+  mpz_t uval;
+  mpz_init(uval);
+  bool ret;
+  if (!this->expr_->integer_constant_value(iota_is_constant, uval, ptype))
+    ret = false;
+  else
+    ret = Unary_expression::eval_integer(this->op_, *ptype, uval, val,
+                                        this->location());
+  mpz_clear(uval);
+  return ret;
+}
+
+// Return the floating point constant value of a unary expression, if
+// it has one.
+
+bool
+Unary_expression::do_float_constant_value(mpfr_t val, Type** ptype) const
+{
+  mpfr_t uval;
+  mpfr_init(uval);
+  bool ret;
+  if (!this->expr_->float_constant_value(uval, ptype))
+    ret = false;
+  else
+    ret = Unary_expression::eval_float(this->op_, uval, val);
+  mpfr_clear(uval);
+  return ret;
+}
+
+// Return the complex constant value of a unary expression, if it has
+// one.
+
+bool
+Unary_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+                                           Type** ptype) const
+{
+  mpfr_t rval;
+  mpfr_t ival;
+  mpfr_init(rval);
+  mpfr_init(ival);
+  bool ret;
+  if (!this->expr_->complex_constant_value(rval, ival, ptype))
+    ret = false;
+  else
+    ret = Unary_expression::eval_complex(this->op_, rval, ival, real, imag);
+  mpfr_clear(rval);
+  mpfr_clear(ival);
+  return ret;
+}
+
+// Return the type of a unary expression.
+
+Type*
+Unary_expression::do_type()
+{
+  switch (this->op_)
+    {
+    case OPERATOR_PLUS:
+    case OPERATOR_MINUS:
+    case OPERATOR_NOT:
+    case OPERATOR_XOR:
+      return this->expr_->type();
+
+    case OPERATOR_AND:
+      return Type::make_pointer_type(this->expr_->type());
+
+    case OPERATOR_MULT:
+      {
+       Type* subtype = this->expr_->type();
+       Type* points_to = subtype->points_to();
+       if (points_to == NULL)
+         return Type::make_error_type();
+       return points_to;
+      }
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Determine abstract types for a unary expression.
+
+void
+Unary_expression::do_determine_type(const Type_context* context)
+{
+  switch (this->op_)
+    {
+    case OPERATOR_PLUS:
+    case OPERATOR_MINUS:
+    case OPERATOR_NOT:
+    case OPERATOR_XOR:
+      this->expr_->determine_type(context);
+      break;
+
+    case OPERATOR_AND:
+      // Taking the address of something.
+      {
+       Type* subtype = (context->type == NULL
+                        ? NULL
+                        : context->type->points_to());
+       Type_context subcontext(subtype, false);
+       this->expr_->determine_type(&subcontext);
+      }
+      break;
+
+    case OPERATOR_MULT:
+      // Indirecting through a pointer.
+      {
+       Type* subtype = (context->type == NULL
+                        ? NULL
+                        : Type::make_pointer_type(context->type));
+       Type_context subcontext(subtype, false);
+       this->expr_->determine_type(&subcontext);
+      }
+      break;
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Check types for a unary expression.
+
+void
+Unary_expression::do_check_types(Gogo*)
+{
+  switch (this->op_)
+    {
+    case OPERATOR_PLUS:
+    case OPERATOR_MINUS:
+      {
+       Type* type = this->expr_->type();
+       if (type->integer_type() == NULL
+           && type->float_type() == NULL
+           && type->complex_type() == NULL
+           && !type->is_error_type())
+         this->report_error(_("expected numeric type"));
+      }
+      break;
+
+    case OPERATOR_NOT:
+    case OPERATOR_XOR:
+      {
+       Type* type = this->expr_->type();
+       if (type->integer_type() == NULL
+           && !type->is_boolean_type()
+           && !type->is_error_type())
+         this->report_error(_("expected integer or boolean type"));
+      }
+      break;
+
+    case OPERATOR_AND:
+      if (!this->expr_->is_addressable())
+       this->report_error(_("invalid operand for unary %<&%>"));
+      else
+       this->expr_->address_taken(this->escapes_);
+      break;
+
+    case OPERATOR_MULT:
+      // Indirecting through a pointer.
+      {
+       Type* type = this->expr_->type();
+       if (type->points_to() == NULL
+           && !type->is_error_type())
+         this->report_error(_("expected pointer"));
+      }
+      break;
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Get a tree for a unary expression.
+
+tree
+Unary_expression::do_get_tree(Translate_context* context)
+{
+  tree expr = this->expr_->get_tree(context);
+  if (expr == error_mark_node)
+    return error_mark_node;
+
+  source_location loc = this->location();
+  switch (this->op_)
+    {
+    case OPERATOR_PLUS:
+      return expr;
+
+    case OPERATOR_MINUS:
+      {
+       tree type = TREE_TYPE(expr);
+       tree compute_type = excess_precision_type(type);
+       if (compute_type != NULL_TREE)
+         expr = ::convert(compute_type, expr);
+       tree ret = fold_build1_loc(loc, NEGATE_EXPR,
+                                  (compute_type != NULL_TREE
+                                   ? compute_type
+                                   : type),
+                                  expr);
+       if (compute_type != NULL_TREE)
+         ret = ::convert(type, ret);
+       return ret;
+      }
+
+    case OPERATOR_NOT:
+      if (TREE_CODE(TREE_TYPE(expr)) == BOOLEAN_TYPE)
+       return fold_build1_loc(loc, TRUTH_NOT_EXPR, TREE_TYPE(expr), expr);
+      else
+       return fold_build2_loc(loc, NE_EXPR, boolean_type_node, expr,
+                              build_int_cst(TREE_TYPE(expr), 0));
+
+    case OPERATOR_XOR:
+      return fold_build1_loc(loc, BIT_NOT_EXPR, TREE_TYPE(expr), expr);
+
+    case OPERATOR_AND:
+      // We should not see a non-constant constructor here; cases
+      // where we would see one should have been moved onto the heap
+      // at parse time.  Taking the address of a nonconstant
+      // constructor will not do what the programmer expects.
+      gcc_assert(TREE_CODE(expr) != CONSTRUCTOR || TREE_CONSTANT(expr));
+      gcc_assert(TREE_CODE(expr) != ADDR_EXPR);
+
+      // Build a decl for a constant constructor.
+      if (TREE_CODE(expr) == CONSTRUCTOR && TREE_CONSTANT(expr))
+       {
+         tree decl = build_decl(this->location(), VAR_DECL,
+                                create_tmp_var_name("C"), TREE_TYPE(expr));
+         DECL_EXTERNAL(decl) = 0;
+         TREE_PUBLIC(decl) = 0;
+         TREE_READONLY(decl) = 1;
+         TREE_CONSTANT(decl) = 1;
+         TREE_STATIC(decl) = 1;
+         TREE_ADDRESSABLE(decl) = 1;
+         DECL_ARTIFICIAL(decl) = 1;
+         DECL_INITIAL(decl) = expr;
+         rest_of_decl_compilation(decl, 1, 0);
+         expr = decl;
+       }
+
+      return build_fold_addr_expr_loc(loc, expr);
+
+    case OPERATOR_MULT:
+      {
+       gcc_assert(POINTER_TYPE_P(TREE_TYPE(expr)));
+
+       // If we are dereferencing the pointer to a large struct, we
+       // need to check for nil.  We don't bother to check for small
+       // structs because we expect the system to crash on a nil
+       // pointer dereference.
+       HOST_WIDE_INT s = int_size_in_bytes(TREE_TYPE(TREE_TYPE(expr)));
+       if (s == -1 || s >= 4096)
+         {
+           if (!DECL_P(expr))
+             expr = save_expr(expr);
+           tree compare = fold_build2_loc(loc, EQ_EXPR, boolean_type_node,
+                                          expr,
+                                          fold_convert(TREE_TYPE(expr),
+                                                       null_pointer_node));
+           tree crash = Gogo::runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
+                                            loc);
+           expr = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(expr),
+                                  build3(COND_EXPR, void_type_node,
+                                         compare, crash, NULL_TREE),
+                                  expr);
+         }
+
+       // If the type of EXPR is a recursive pointer type, then we
+       // need to insert a cast before indirecting.
+       if (TREE_TYPE(TREE_TYPE(expr)) == ptr_type_node)
+         {
+           Type* pt = this->expr_->type()->points_to();
+           tree ind = pt->get_tree(context->gogo());
+           expr = fold_convert_loc(loc, build_pointer_type(ind), expr);
+         }
+
+       return build_fold_indirect_ref_loc(loc, expr);
+      }
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Export a unary expression.
+
+void
+Unary_expression::do_export(Export* exp) const
+{
+  switch (this->op_)
+    {
+    case OPERATOR_PLUS:
+      exp->write_c_string("+ ");
+      break;
+    case OPERATOR_MINUS:
+      exp->write_c_string("- ");
+      break;
+    case OPERATOR_NOT:
+      exp->write_c_string("! ");
+      break;
+    case OPERATOR_XOR:
+      exp->write_c_string("^ ");
+      break;
+    case OPERATOR_AND:
+    case OPERATOR_MULT:
+    default:
+      gcc_unreachable();
+    }
+  this->expr_->export_expression(exp);
+}
+
+// Import a unary expression.
+
+Expression*
+Unary_expression::do_import(Import* imp)
+{
+  Operator op;
+  switch (imp->get_char())
+    {
+    case '+':
+      op = OPERATOR_PLUS;
+      break;
+    case '-':
+      op = OPERATOR_MINUS;
+      break;
+    case '!':
+      op = OPERATOR_NOT;
+      break;
+    case '^':
+      op = OPERATOR_XOR;
+      break;
+    default:
+      gcc_unreachable();
+    }
+  imp->require_c_string(" ");
+  Expression* expr = Expression::import_expression(imp);
+  return Expression::make_unary(op, expr, imp->location());
+}
+
+// Make a unary expression.
+
+Expression*
+Expression::make_unary(Operator op, Expression* expr, source_location location)
+{
+  return new Unary_expression(op, expr, location);
+}
+
+// If this is an indirection through a pointer, return the expression
+// being pointed through.  Otherwise return this.
+
+Expression*
+Expression::deref()
+{
+  if (this->classification_ == EXPRESSION_UNARY)
+    {
+      Unary_expression* ue = static_cast<Unary_expression*>(this);
+      if (ue->op() == OPERATOR_MULT)
+       return ue->operand();
+    }
+  return this;
+}
+
+// Class Binary_expression.
+
+// Traversal.
+
+int
+Binary_expression::do_traverse(Traverse* traverse)
+{
+  int t = Expression::traverse(&this->left_, traverse);
+  if (t == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return Expression::traverse(&this->right_, traverse);
+}
+
+// Compare integer constants according to OP.
+
+bool
+Binary_expression::compare_integer(Operator op, mpz_t left_val,
+                                  mpz_t right_val)
+{
+  int i = mpz_cmp(left_val, right_val);
+  switch (op)
+    {
+    case OPERATOR_EQEQ:
+      return i == 0;
+    case OPERATOR_NOTEQ:
+      return i != 0;
+    case OPERATOR_LT:
+      return i < 0;
+    case OPERATOR_LE:
+      return i <= 0;
+    case OPERATOR_GT:
+      return i > 0;
+    case OPERATOR_GE:
+      return i >= 0;
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Compare floating point constants according to OP.
+
+bool
+Binary_expression::compare_float(Operator op, Type* type, mpfr_t left_val,
+                                mpfr_t right_val)
+{
+  int i;
+  if (type == NULL)
+    i = mpfr_cmp(left_val, right_val);
+  else
+    {
+      mpfr_t lv;
+      mpfr_init_set(lv, left_val, GMP_RNDN);
+      mpfr_t rv;
+      mpfr_init_set(rv, right_val, GMP_RNDN);
+      Float_expression::constrain_float(lv, type);
+      Float_expression::constrain_float(rv, type);
+      i = mpfr_cmp(lv, rv);
+      mpfr_clear(lv);
+      mpfr_clear(rv);
+    }
+  switch (op)
+    {
+    case OPERATOR_EQEQ:
+      return i == 0;
+    case OPERATOR_NOTEQ:
+      return i != 0;
+    case OPERATOR_LT:
+      return i < 0;
+    case OPERATOR_LE:
+      return i <= 0;
+    case OPERATOR_GT:
+      return i > 0;
+    case OPERATOR_GE:
+      return i >= 0;
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Compare complex constants according to OP.  Complex numbers may
+// only be compared for equality.
+
+bool
+Binary_expression::compare_complex(Operator op, Type* type,
+                                  mpfr_t left_real, mpfr_t left_imag,
+                                  mpfr_t right_real, mpfr_t right_imag)
+{
+  bool is_equal;
+  if (type == NULL)
+    is_equal = (mpfr_cmp(left_real, right_real) == 0
+               && mpfr_cmp(left_imag, right_imag) == 0);
+  else
+    {
+      mpfr_t lr;
+      mpfr_t li;
+      mpfr_init_set(lr, left_real, GMP_RNDN);
+      mpfr_init_set(li, left_imag, GMP_RNDN);
+      mpfr_t rr;
+      mpfr_t ri;
+      mpfr_init_set(rr, right_real, GMP_RNDN);
+      mpfr_init_set(ri, right_imag, GMP_RNDN);
+      Complex_expression::constrain_complex(lr, li, type);
+      Complex_expression::constrain_complex(rr, ri, type);
+      is_equal = mpfr_cmp(lr, rr) == 0 && mpfr_cmp(li, ri) == 0;
+      mpfr_clear(lr);
+      mpfr_clear(li);
+      mpfr_clear(rr);
+      mpfr_clear(ri);
+    }
+  switch (op)
+    {
+    case OPERATOR_EQEQ:
+      return is_equal;
+    case OPERATOR_NOTEQ:
+      return !is_equal;
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Apply binary opcode OP to LEFT_VAL and RIGHT_VAL, setting VAL.
+// LEFT_TYPE is the type of LEFT_VAL, RIGHT_TYPE is the type of
+// RIGHT_VAL; LEFT_TYPE and/or RIGHT_TYPE may be NULL.  Return true if
+// this could be done, false if not.
+
+bool
+Binary_expression::eval_integer(Operator op, Type* left_type, mpz_t left_val,
+                               Type* right_type, mpz_t right_val,
+                               source_location location, mpz_t val)
+{
+  bool is_shift_op = false;
+  switch (op)
+    {
+    case OPERATOR_OROR:
+    case OPERATOR_ANDAND:
+    case OPERATOR_EQEQ:
+    case OPERATOR_NOTEQ:
+    case OPERATOR_LT:
+    case OPERATOR_LE:
+    case OPERATOR_GT:
+    case OPERATOR_GE:
+      // These return boolean values.  We should probably handle them
+      // anyhow in case a type conversion is used on the result.
+      return false;
+    case OPERATOR_PLUS:
+      mpz_add(val, left_val, right_val);
+      break;
+    case OPERATOR_MINUS:
+      mpz_sub(val, left_val, right_val);
+      break;
+    case OPERATOR_OR:
+      mpz_ior(val, left_val, right_val);
+      break;
+    case OPERATOR_XOR:
+      mpz_xor(val, left_val, right_val);
+      break;
+    case OPERATOR_MULT:
+      mpz_mul(val, left_val, right_val);
+      break;
+    case OPERATOR_DIV:
+      if (mpz_sgn(right_val) != 0)
+       mpz_tdiv_q(val, left_val, right_val);
+      else
+       {
+         error_at(location, "division by zero");
+         mpz_set_ui(val, 0);
+         return true;
+       }
+      break;
+    case OPERATOR_MOD:
+      if (mpz_sgn(right_val) != 0)
+       mpz_tdiv_r(val, left_val, right_val);
+      else
+       {
+         error_at(location, "division by zero");
+         mpz_set_ui(val, 0);
+         return true;
+       }
+      break;
+    case OPERATOR_LSHIFT:
+      {
+       unsigned long shift = mpz_get_ui(right_val);
+       if (mpz_cmp_ui(right_val, shift) != 0)
+         {
+           error_at(location, "shift count overflow");
+           mpz_set_ui(val, 0);
+           return true;
+         }
+       mpz_mul_2exp(val, left_val, shift);
+       is_shift_op = true;
+       break;
+      }
+      break;
+    case OPERATOR_RSHIFT:
+      {
+       unsigned long shift = mpz_get_ui(right_val);
+       if (mpz_cmp_ui(right_val, shift) != 0)
+         {
+           error_at(location, "shift count overflow");
+           mpz_set_ui(val, 0);
+           return true;
+         }
+       if (mpz_cmp_ui(left_val, 0) >= 0)
+         mpz_tdiv_q_2exp(val, left_val, shift);
+       else
+         mpz_fdiv_q_2exp(val, left_val, shift);
+       is_shift_op = true;
+       break;
+      }
+      break;
+    case OPERATOR_AND:
+      mpz_and(val, left_val, right_val);
+      break;
+    case OPERATOR_BITCLEAR:
+      {
+       mpz_t tval;
+       mpz_init(tval);
+       mpz_com(tval, right_val);
+       mpz_and(val, left_val, tval);
+       mpz_clear(tval);
+      }
+      break;
+    default:
+      gcc_unreachable();
+    }
+
+  Type* type = left_type;
+  if (!is_shift_op)
+    {
+      if (type == NULL)
+       type = right_type;
+      else if (type != right_type && right_type != NULL)
+       {
+         if (type->is_abstract())
+           type = right_type;
+         else if (!right_type->is_abstract())
+           {
+             // This look like a type error which should be diagnosed
+             // elsewhere.  Don't do anything here, to avoid an
+             // unhelpful chain of error messages.
+             return true;
+           }
+       }
+    }
+
+  if (type != NULL && !type->is_abstract())
+    {
+      // We have to check the operands too, as we have implicitly
+      // coerced them to TYPE.
+      if ((type != left_type
+          && !Integer_expression::check_constant(left_val, type, location))
+         || (!is_shift_op
+             && type != right_type
+             && !Integer_expression::check_constant(right_val, type,
+                                                    location))
+         || !Integer_expression::check_constant(val, type, location))
+       mpz_set_ui(val, 0);
+    }
+
+  return true;
+}
+
+// Apply binary opcode OP to LEFT_VAL and RIGHT_VAL, setting VAL.
+// Return true if this could be done, false if not.
+
+bool
+Binary_expression::eval_float(Operator op, Type* left_type, mpfr_t left_val,
+                             Type* right_type, mpfr_t right_val,
+                             mpfr_t val, source_location location)
+{
+  switch (op)
+    {
+    case OPERATOR_OROR:
+    case OPERATOR_ANDAND:
+    case OPERATOR_EQEQ:
+    case OPERATOR_NOTEQ:
+    case OPERATOR_LT:
+    case OPERATOR_LE:
+    case OPERATOR_GT:
+    case OPERATOR_GE:
+      // These return boolean values.  We should probably handle them
+      // anyhow in case a type conversion is used on the result.
+      return false;
+    case OPERATOR_PLUS:
+      mpfr_add(val, left_val, right_val, GMP_RNDN);
+      break;
+    case OPERATOR_MINUS:
+      mpfr_sub(val, left_val, right_val, GMP_RNDN);
+      break;
+    case OPERATOR_OR:
+    case OPERATOR_XOR:
+    case OPERATOR_AND:
+    case OPERATOR_BITCLEAR:
+      return false;
+    case OPERATOR_MULT:
+      mpfr_mul(val, left_val, right_val, GMP_RNDN);
+      break;
+    case OPERATOR_DIV:
+      if (mpfr_zero_p(right_val))
+       error_at(location, "division by zero");
+      mpfr_div(val, left_val, right_val, GMP_RNDN);
+      break;
+    case OPERATOR_MOD:
+      return false;
+    case OPERATOR_LSHIFT:
+    case OPERATOR_RSHIFT:
+      return false;
+    default:
+      gcc_unreachable();
+    }
+
+  Type* type = left_type;
+  if (type == NULL)
+    type = right_type;
+  else if (type != right_type && right_type != NULL)
+    {
+      if (type->is_abstract())
+       type = right_type;
+      else if (!right_type->is_abstract())
+       {
+         // This looks like a type error which should be diagnosed
+         // elsewhere.  Don't do anything here, to avoid an unhelpful
+         // chain of error messages.
+         return true;
+       }
+    }
+
+  if (type != NULL && !type->is_abstract())
+    {
+      if ((type != left_type
+          && !Float_expression::check_constant(left_val, type, location))
+         || (type != right_type
+             && !Float_expression::check_constant(right_val, type,
+                                                  location))
+         || !Float_expression::check_constant(val, type, location))
+       mpfr_set_ui(val, 0, GMP_RNDN);
+    }
+
+  return true;
+}
+
+// Apply binary opcode OP to LEFT_REAL/LEFT_IMAG and
+// RIGHT_REAL/RIGHT_IMAG, setting REAL/IMAG.  Return true if this
+// could be done, false if not.
+
+bool
+Binary_expression::eval_complex(Operator op, Type* left_type,
+                               mpfr_t left_real, mpfr_t left_imag,
+                               Type *right_type,
+                               mpfr_t right_real, mpfr_t right_imag,
+                               mpfr_t real, mpfr_t imag,
+                               source_location location)
+{
+  switch (op)
+    {
+    case OPERATOR_OROR:
+    case OPERATOR_ANDAND:
+    case OPERATOR_EQEQ:
+    case OPERATOR_NOTEQ:
+    case OPERATOR_LT:
+    case OPERATOR_LE:
+    case OPERATOR_GT:
+    case OPERATOR_GE:
+      // These return boolean values and must be handled differently.
+      return false;
+    case OPERATOR_PLUS:
+      mpfr_add(real, left_real, right_real, GMP_RNDN);
+      mpfr_add(imag, left_imag, right_imag, GMP_RNDN);
+      break;
+    case OPERATOR_MINUS:
+      mpfr_sub(real, left_real, right_real, GMP_RNDN);
+      mpfr_sub(imag, left_imag, right_imag, GMP_RNDN);
+      break;
+    case OPERATOR_OR:
+    case OPERATOR_XOR:
+    case OPERATOR_AND:
+    case OPERATOR_BITCLEAR:
+      return false;
+    case OPERATOR_MULT:
+      {
+       // You might think that multiplying two complex numbers would
+       // be simple, and you would be right, until you start to think
+       // about getting the right answer for infinity.  If one
+       // operand here is infinity and the other is anything other
+       // than zero or NaN, then we are going to wind up subtracting
+       // two infinity values.  That will give us a NaN, but the
+       // correct answer is infinity.
+
+       mpfr_t lrrr;
+       mpfr_init(lrrr);
+       mpfr_mul(lrrr, left_real, right_real, GMP_RNDN);
+
+       mpfr_t lrri;
+       mpfr_init(lrri);
+       mpfr_mul(lrri, left_real, right_imag, GMP_RNDN);
+
+       mpfr_t lirr;
+       mpfr_init(lirr);
+       mpfr_mul(lirr, left_imag, right_real, GMP_RNDN);
+
+       mpfr_t liri;
+       mpfr_init(liri);
+       mpfr_mul(liri, left_imag, right_imag, GMP_RNDN);
+
+       mpfr_sub(real, lrrr, liri, GMP_RNDN);
+       mpfr_add(imag, lrri, lirr, GMP_RNDN);
+
+       // If we get NaN on both sides, check whether it should really
+       // be infinity.  The rule is that if either side of the
+       // complex number is infinity, then the whole value is
+       // infinity, even if the other side is NaN.  So the only case
+       // we have to fix is the one in which both sides are NaN.
+       if (mpfr_nan_p(real) && mpfr_nan_p(imag)
+           && (!mpfr_nan_p(left_real) || !mpfr_nan_p(left_imag))
+           && (!mpfr_nan_p(right_real) || !mpfr_nan_p(right_imag)))
+         {
+           bool is_infinity = false;
+
+           mpfr_t lr;
+           mpfr_t li;
+           mpfr_init_set(lr, left_real, GMP_RNDN);
+           mpfr_init_set(li, left_imag, GMP_RNDN);
+
+           mpfr_t rr;
+           mpfr_t ri;
+           mpfr_init_set(rr, right_real, GMP_RNDN);
+           mpfr_init_set(ri, right_imag, GMP_RNDN);
+
+           // If the left side is infinity, then the result is
+           // infinity.
+           if (mpfr_inf_p(lr) || mpfr_inf_p(li))
+             {
+               mpfr_set_ui(lr, mpfr_inf_p(lr) ? 1 : 0, GMP_RNDN);
+               mpfr_copysign(lr, lr, left_real, GMP_RNDN);
+               mpfr_set_ui(li, mpfr_inf_p(li) ? 1 : 0, GMP_RNDN);
+               mpfr_copysign(li, li, left_imag, GMP_RNDN);
+               if (mpfr_nan_p(rr))
+                 {
+                   mpfr_set_ui(rr, 0, GMP_RNDN);
+                   mpfr_copysign(rr, rr, right_real, GMP_RNDN);
+                 }
+               if (mpfr_nan_p(ri))
+                 {
+                   mpfr_set_ui(ri, 0, GMP_RNDN);
+                   mpfr_copysign(ri, ri, right_imag, GMP_RNDN);
+                 }
+               is_infinity = true;
+             }
+
+           // If the right side is infinity, then the result is
+           // infinity.
+           if (mpfr_inf_p(rr) || mpfr_inf_p(ri))
+             {
+               mpfr_set_ui(rr, mpfr_inf_p(rr) ? 1 : 0, GMP_RNDN);
+               mpfr_copysign(rr, rr, right_real, GMP_RNDN);
+               mpfr_set_ui(ri, mpfr_inf_p(ri) ? 1 : 0, GMP_RNDN);
+               mpfr_copysign(ri, ri, right_imag, GMP_RNDN);
+               if (mpfr_nan_p(lr))
+                 {
+                   mpfr_set_ui(lr, 0, GMP_RNDN);
+                   mpfr_copysign(lr, lr, left_real, GMP_RNDN);
+                 }
+               if (mpfr_nan_p(li))
+                 {
+                   mpfr_set_ui(li, 0, GMP_RNDN);
+                   mpfr_copysign(li, li, left_imag, GMP_RNDN);
+                 }
+               is_infinity = true;
+             }
+
+           // If we got an overflow in the intermediate computations,
+           // then the result is infinity.
+           if (!is_infinity
+               && (mpfr_inf_p(lrrr) || mpfr_inf_p(lrri)
+                   || mpfr_inf_p(lirr) || mpfr_inf_p(liri)))
+             {
+               if (mpfr_nan_p(lr))
+                 {
+                   mpfr_set_ui(lr, 0, GMP_RNDN);
+                   mpfr_copysign(lr, lr, left_real, GMP_RNDN);
+                 }
+               if (mpfr_nan_p(li))
+                 {
+                   mpfr_set_ui(li, 0, GMP_RNDN);
+                   mpfr_copysign(li, li, left_imag, GMP_RNDN);
+                 }
+               if (mpfr_nan_p(rr))
+                 {
+                   mpfr_set_ui(rr, 0, GMP_RNDN);
+                   mpfr_copysign(rr, rr, right_real, GMP_RNDN);
+                 }
+               if (mpfr_nan_p(ri))
+                 {
+                   mpfr_set_ui(ri, 0, GMP_RNDN);
+                   mpfr_copysign(ri, ri, right_imag, GMP_RNDN);
+                 }
+               is_infinity = true;
+             }
+
+           if (is_infinity)
+             {
+               mpfr_mul(lrrr, lr, rr, GMP_RNDN);
+               mpfr_mul(lrri, lr, ri, GMP_RNDN);
+               mpfr_mul(lirr, li, rr, GMP_RNDN);
+               mpfr_mul(liri, li, ri, GMP_RNDN);
+               mpfr_sub(real, lrrr, liri, GMP_RNDN);
+               mpfr_add(imag, lrri, lirr, GMP_RNDN);
+               mpfr_set_inf(real, mpfr_sgn(real));
+               mpfr_set_inf(imag, mpfr_sgn(imag));
+             }
+
+           mpfr_clear(lr);
+           mpfr_clear(li);
+           mpfr_clear(rr);
+           mpfr_clear(ri);
+         }
+
+       mpfr_clear(lrrr);
+       mpfr_clear(lrri);
+       mpfr_clear(lirr);
+       mpfr_clear(liri);                                 
+      }
+      break;
+    case OPERATOR_DIV:
+      {
+       // For complex division we want to avoid having an
+       // intermediate overflow turn the whole result in a NaN.  We
+       // scale the values to try to avoid this.
+
+       if (mpfr_zero_p(right_real) && mpfr_zero_p(right_imag))
+         error_at(location, "division by zero");
+
+       mpfr_t rra;
+       mpfr_t ria;
+       mpfr_init(rra);
+       mpfr_init(ria);
+       mpfr_abs(rra, right_real, GMP_RNDN);
+       mpfr_abs(ria, right_imag, GMP_RNDN);
+       mpfr_t t;
+       mpfr_init(t);
+       mpfr_max(t, rra, ria, GMP_RNDN);
+
+       mpfr_t rr;
+       mpfr_t ri;
+       mpfr_init_set(rr, right_real, GMP_RNDN);
+       mpfr_init_set(ri, right_imag, GMP_RNDN);
+       long ilogbw = 0;
+       if (!mpfr_inf_p(t) && !mpfr_nan_p(t) && !mpfr_zero_p(t))
+         {
+           ilogbw = mpfr_get_exp(t);
+           mpfr_mul_2si(rr, rr, - ilogbw, GMP_RNDN);
+           mpfr_mul_2si(ri, ri, - ilogbw, GMP_RNDN);
+         }
+
+       mpfr_t denom;
+       mpfr_init(denom);
+       mpfr_mul(denom, rr, rr, GMP_RNDN);
+       mpfr_mul(t, ri, ri, GMP_RNDN);
+       mpfr_add(denom, denom, t, GMP_RNDN);
+
+       mpfr_mul(real, left_real, rr, GMP_RNDN);
+       mpfr_mul(t, left_imag, ri, GMP_RNDN);
+       mpfr_add(real, real, t, GMP_RNDN);
+       mpfr_div(real, real, denom, GMP_RNDN);
+       mpfr_mul_2si(real, real, - ilogbw, GMP_RNDN);
+
+       mpfr_mul(imag, left_imag, rr, GMP_RNDN);
+       mpfr_mul(t, left_real, ri, GMP_RNDN);
+       mpfr_sub(imag, imag, t, GMP_RNDN);
+       mpfr_div(imag, imag, denom, GMP_RNDN);
+       mpfr_mul_2si(imag, imag, - ilogbw, GMP_RNDN);
+
+       // If we wind up with NaN on both sides, check whether we
+       // should really have infinity.  The rule is that if either
+       // side of the complex number is infinity, then the whole
+       // value is infinity, even if the other side is NaN.  So the
+       // only case we have to fix is the one in which both sides are
+       // NaN.
+       if (mpfr_nan_p(real) && mpfr_nan_p(imag)
+           && (!mpfr_nan_p(left_real) || !mpfr_nan_p(left_imag))
+           && (!mpfr_nan_p(right_real) || !mpfr_nan_p(right_imag)))
+         {
+           if (mpfr_zero_p(denom))
+             {
+               mpfr_set_inf(real, mpfr_sgn(rr));
+               mpfr_mul(real, real, left_real, GMP_RNDN);
+               mpfr_set_inf(imag, mpfr_sgn(rr));
+               mpfr_mul(imag, imag, left_imag, GMP_RNDN);
+             }
+           else if ((mpfr_inf_p(left_real) || mpfr_inf_p(left_imag))
+                    && mpfr_number_p(rr) && mpfr_number_p(ri))
+             {
+               mpfr_set_ui(t, mpfr_inf_p(left_real) ? 1 : 0, GMP_RNDN);
+               mpfr_copysign(t, t, left_real, GMP_RNDN);
+
+               mpfr_t t2;
+               mpfr_init_set_ui(t2, mpfr_inf_p(left_imag) ? 1 : 0, GMP_RNDN);
+               mpfr_copysign(t2, t2, left_imag, GMP_RNDN);
+
+               mpfr_t t3;
+               mpfr_init(t3);
+               mpfr_mul(t3, t, rr, GMP_RNDN);
+
+               mpfr_t t4;
+               mpfr_init(t4);
+               mpfr_mul(t4, t2, ri, GMP_RNDN);
+
+               mpfr_add(t3, t3, t4, GMP_RNDN);
+               mpfr_set_inf(real, mpfr_sgn(t3));
+
+               mpfr_mul(t3, t2, rr, GMP_RNDN);
+               mpfr_mul(t4, t, ri, GMP_RNDN);
+               mpfr_sub(t3, t3, t4, GMP_RNDN);
+               mpfr_set_inf(imag, mpfr_sgn(t3));
+
+               mpfr_clear(t2);
+               mpfr_clear(t3);
+               mpfr_clear(t4);
+             }
+           else if ((mpfr_inf_p(right_real) || mpfr_inf_p(right_imag))
+                    && mpfr_number_p(left_real) && mpfr_number_p(left_imag))
+             {
+               mpfr_set_ui(t, mpfr_inf_p(rr) ? 1 : 0, GMP_RNDN);
+               mpfr_copysign(t, t, rr, GMP_RNDN);
+
+               mpfr_t t2;
+               mpfr_init_set_ui(t2, mpfr_inf_p(ri) ? 1 : 0, GMP_RNDN);
+               mpfr_copysign(t2, t2, ri, GMP_RNDN);
+
+               mpfr_t t3;
+               mpfr_init(t3);
+               mpfr_mul(t3, left_real, t, GMP_RNDN);
+
+               mpfr_t t4;
+               mpfr_init(t4);
+               mpfr_mul(t4, left_imag, t2, GMP_RNDN);
+
+               mpfr_add(t3, t3, t4, GMP_RNDN);
+               mpfr_set_ui(real, 0, GMP_RNDN);
+               mpfr_mul(real, real, t3, GMP_RNDN);
+
+               mpfr_mul(t3, left_imag, t, GMP_RNDN);
+               mpfr_mul(t4, left_real, t2, GMP_RNDN);
+               mpfr_sub(t3, t3, t4, GMP_RNDN);
+               mpfr_set_ui(imag, 0, GMP_RNDN);
+               mpfr_mul(imag, imag, t3, GMP_RNDN);
+
+               mpfr_clear(t2);
+               mpfr_clear(t3);
+               mpfr_clear(t4);
+             }
+         }
+
+       mpfr_clear(denom);
+       mpfr_clear(rr);
+       mpfr_clear(ri);
+       mpfr_clear(t);
+       mpfr_clear(rra);
+       mpfr_clear(ria);
+      }
+      break;
+    case OPERATOR_MOD:
+      return false;
+    case OPERATOR_LSHIFT:
+    case OPERATOR_RSHIFT:
+      return false;
+    default:
+      gcc_unreachable();
+    }
+
+  Type* type = left_type;
+  if (type == NULL)
+    type = right_type;
+  else if (type != right_type && right_type != NULL)
+    {
+      if (type->is_abstract())
+       type = right_type;
+      else if (!right_type->is_abstract())
+       {
+         // This looks like a type error which should be diagnosed
+         // elsewhere.  Don't do anything here, to avoid an unhelpful
+         // chain of error messages.
+         return true;
+       }
+    }
+
+  if (type != NULL && !type->is_abstract())
+    {
+      if ((type != left_type
+          && !Complex_expression::check_constant(left_real, left_imag,
+                                                 type, location))
+         || (type != right_type
+             && !Complex_expression::check_constant(right_real, right_imag,
+                                                    type, location))
+         || !Complex_expression::check_constant(real, imag, type,
+                                                location))
+       {
+         mpfr_set_ui(real, 0, GMP_RNDN);
+         mpfr_set_ui(imag, 0, GMP_RNDN);
+       }
+    }
+
+  return true;
+}
+
+// Lower a binary expression.  We have to evaluate constant
+// expressions now, in order to implement Go's unlimited precision
+// constants.
+
+Expression*
+Binary_expression::do_lower(Gogo*, Named_object*, int)
+{
+  source_location location = this->location();
+  Operator op = this->op_;
+  Expression* left = this->left_;
+  Expression* right = this->right_;
+
+  const bool is_comparison = (op == OPERATOR_EQEQ
+                             || op == OPERATOR_NOTEQ
+                             || op == OPERATOR_LT
+                             || op == OPERATOR_LE
+                             || op == OPERATOR_GT
+                             || op == OPERATOR_GE);
+
+  // Integer constant expressions.
+  {
+    mpz_t left_val;
+    mpz_init(left_val);
+    Type* left_type;
+    mpz_t right_val;
+    mpz_init(right_val);
+    Type* right_type;
+    if (left->integer_constant_value(false, left_val, &left_type)
+       && right->integer_constant_value(false, right_val, &right_type))
+      {
+       Expression* ret = NULL;
+       if (left_type != right_type
+           && left_type != NULL
+           && right_type != NULL
+           && left_type->base() != right_type->base()
+           && op != OPERATOR_LSHIFT
+           && op != OPERATOR_RSHIFT)
+         {
+           // May be a type error--let it be diagnosed later.
+         }
+       else if (is_comparison)
+         {
+           bool b = Binary_expression::compare_integer(op, left_val,
+                                                       right_val);
+           ret = Expression::make_cast(Type::lookup_bool_type(),
+                                       Expression::make_boolean(b, location),
+                                       location);
+         }
+       else
+         {
+           mpz_t val;
+           mpz_init(val);
+
+           if (Binary_expression::eval_integer(op, left_type, left_val,
+                                               right_type, right_val,
+                                               location, val))
+             {
+               gcc_assert(op != OPERATOR_OROR && op != OPERATOR_ANDAND);
+               Type* type;
+               if (op == OPERATOR_LSHIFT || op == OPERATOR_RSHIFT)
+                 type = left_type;
+               else if (left_type == NULL)
+                 type = right_type;
+               else if (right_type == NULL)
+                 type = left_type;
+               else if (!left_type->is_abstract()
+                        && left_type->named_type() != NULL)
+                 type = left_type;
+               else if (!right_type->is_abstract()
+                        && right_type->named_type() != NULL)
+                 type = right_type;
+               else if (!left_type->is_abstract())
+                 type = left_type;
+               else if (!right_type->is_abstract())
+                 type = right_type;
+               else if (left_type->float_type() != NULL)
+                 type = left_type;
+               else if (right_type->float_type() != NULL)
+                 type = right_type;
+               else if (left_type->complex_type() != NULL)
+                 type = left_type;
+               else if (right_type->complex_type() != NULL)
+                 type = right_type;
+               else
+                 type = left_type;
+               ret = Expression::make_integer(&val, type, location);
+             }
+
+           mpz_clear(val);
+         }
+
+       if (ret != NULL)
+         {
+           mpz_clear(right_val);
+           mpz_clear(left_val);
+           return ret;
+         }
+      }
+    mpz_clear(right_val);
+    mpz_clear(left_val);
+  }
+
+  // Floating point constant expressions.
+  {
+    mpfr_t left_val;
+    mpfr_init(left_val);
+    Type* left_type;
+    mpfr_t right_val;
+    mpfr_init(right_val);
+    Type* right_type;
+    if (left->float_constant_value(left_val, &left_type)
+       && right->float_constant_value(right_val, &right_type))
+      {
+       Expression* ret = NULL;
+       if (left_type != right_type
+           && left_type != NULL
+           && right_type != NULL
+           && left_type->base() != right_type->base()
+           && op != OPERATOR_LSHIFT
+           && op != OPERATOR_RSHIFT)
+         {
+           // May be a type error--let it be diagnosed later.
+         }
+       else if (is_comparison)
+         {
+           bool b = Binary_expression::compare_float(op,
+                                                     (left_type != NULL
+                                                      ? left_type
+                                                      : right_type),
+                                                     left_val, right_val);
+           ret = Expression::make_boolean(b, location);
+         }
+       else
+         {
+           mpfr_t val;
+           mpfr_init(val);
+
+           if (Binary_expression::eval_float(op, left_type, left_val,
+                                             right_type, right_val, val,
+                                             location))
+             {
+               gcc_assert(op != OPERATOR_OROR && op != OPERATOR_ANDAND
+                          && op != OPERATOR_LSHIFT && op != OPERATOR_RSHIFT);
+               Type* type;
+               if (left_type == NULL)
+                 type = right_type;
+               else if (right_type == NULL)
+                 type = left_type;
+               else if (!left_type->is_abstract()
+                        && left_type->named_type() != NULL)
+                 type = left_type;
+               else if (!right_type->is_abstract()
+                        && right_type->named_type() != NULL)
+                 type = right_type;
+               else if (!left_type->is_abstract())
+                 type = left_type;
+               else if (!right_type->is_abstract())
+                 type = right_type;
+               else if (left_type->float_type() != NULL)
+                 type = left_type;
+               else if (right_type->float_type() != NULL)
+                 type = right_type;
+               else
+                 type = left_type;
+               ret = Expression::make_float(&val, type, location);
+             }
+
+           mpfr_clear(val);
+         }
+
+       if (ret != NULL)
+         {
+           mpfr_clear(right_val);
+           mpfr_clear(left_val);
+           return ret;
+         }
+      }
+    mpfr_clear(right_val);
+    mpfr_clear(left_val);
+  }
+
+  // Complex constant expressions.
+  {
+    mpfr_t left_real;
+    mpfr_t left_imag;
+    mpfr_init(left_real);
+    mpfr_init(left_imag);
+    Type* left_type;
+
+    mpfr_t right_real;
+    mpfr_t right_imag;
+    mpfr_init(right_real);
+    mpfr_init(right_imag);
+    Type* right_type;
+
+    if (left->complex_constant_value(left_real, left_imag, &left_type)
+       && right->complex_constant_value(right_real, right_imag, &right_type))
+      {
+       Expression* ret = NULL;
+       if (left_type != right_type
+           && left_type != NULL
+           && right_type != NULL
+           && left_type->base() != right_type->base())
+         {
+           // May be a type error--let it be diagnosed later.
+         }
+       else if (is_comparison)
+         {
+           bool b = Binary_expression::compare_complex(op,
+                                                       (left_type != NULL
+                                                        ? left_type
+                                                        : right_type),
+                                                       left_real,
+                                                       left_imag,
+                                                       right_real,
+                                                       right_imag);
+           ret = Expression::make_boolean(b, location);
+         }
+       else
+         {
+           mpfr_t real;
+           mpfr_t imag;
+           mpfr_init(real);
+           mpfr_init(imag);
+
+           if (Binary_expression::eval_complex(op, left_type,
+                                               left_real, left_imag,
+                                               right_type,
+                                               right_real, right_imag,
+                                               real, imag,
+                                               location))
+             {
+               gcc_assert(op != OPERATOR_OROR && op != OPERATOR_ANDAND
+                          && op != OPERATOR_LSHIFT && op != OPERATOR_RSHIFT);
+               Type* type;
+               if (left_type == NULL)
+                 type = right_type;
+               else if (right_type == NULL)
+                 type = left_type;
+               else if (!left_type->is_abstract()
+                        && left_type->named_type() != NULL)
+                 type = left_type;
+               else if (!right_type->is_abstract()
+                        && right_type->named_type() != NULL)
+                 type = right_type;
+               else if (!left_type->is_abstract())
+                 type = left_type;
+               else if (!right_type->is_abstract())
+                 type = right_type;
+               else if (left_type->complex_type() != NULL)
+                 type = left_type;
+               else if (right_type->complex_type() != NULL)
+                 type = right_type;
+               else
+                 type = left_type;
+               ret = Expression::make_complex(&real, &imag, type,
+                                              location);
+             }
+           mpfr_clear(real);
+           mpfr_clear(imag);
+         }
+
+       if (ret != NULL)
+         {
+           mpfr_clear(left_real);
+           mpfr_clear(left_imag);
+           mpfr_clear(right_real);
+           mpfr_clear(right_imag);
+           return ret;
+         }
+      }
+
+    mpfr_clear(left_real);
+    mpfr_clear(left_imag);
+    mpfr_clear(right_real);
+    mpfr_clear(right_imag);
+  }
+
+  // String constant expressions.
+  if (op == OPERATOR_PLUS
+      && left->type()->is_string_type()
+      && right->type()->is_string_type())
+    {
+      std::string left_string;
+      std::string right_string;
+      if (left->string_constant_value(&left_string)
+         && right->string_constant_value(&right_string))
+       return Expression::make_string(left_string + right_string, location);
+    }
+
+  return this;
+}
+
+// Return the integer constant value, if it has one.
+
+bool
+Binary_expression::do_integer_constant_value(bool iota_is_constant, mpz_t val,
+                                            Type** ptype) const
+{
+  mpz_t left_val;
+  mpz_init(left_val);
+  Type* left_type;
+  if (!this->left_->integer_constant_value(iota_is_constant, left_val,
+                                          &left_type))
+    {
+      mpz_clear(left_val);
+      return false;
+    }
+
+  mpz_t right_val;
+  mpz_init(right_val);
+  Type* right_type;
+  if (!this->right_->integer_constant_value(iota_is_constant, right_val,
+                                           &right_type))
+    {
+      mpz_clear(right_val);
+      mpz_clear(left_val);
+      return false;
+    }
+
+  bool ret;
+  if (left_type != right_type
+      && left_type != NULL
+      && right_type != NULL
+      && left_type->base() != right_type->base()
+      && this->op_ != OPERATOR_RSHIFT
+      && this->op_ != OPERATOR_LSHIFT)
+    ret = false;
+  else
+    ret = Binary_expression::eval_integer(this->op_, left_type, left_val,
+                                         right_type, right_val,
+                                         this->location(), val);
+
+  mpz_clear(right_val);
+  mpz_clear(left_val);
+
+  if (ret)
+    *ptype = left_type;
+
+  return ret;
+}
+
+// Return the floating point constant value, if it has one.
+
+bool
+Binary_expression::do_float_constant_value(mpfr_t val, Type** ptype) const
+{
+  mpfr_t left_val;
+  mpfr_init(left_val);
+  Type* left_type;
+  if (!this->left_->float_constant_value(left_val, &left_type))
+    {
+      mpfr_clear(left_val);
+      return false;
+    }
+
+  mpfr_t right_val;
+  mpfr_init(right_val);
+  Type* right_type;
+  if (!this->right_->float_constant_value(right_val, &right_type))
+    {
+      mpfr_clear(right_val);
+      mpfr_clear(left_val);
+      return false;
+    }
+
+  bool ret;
+  if (left_type != right_type
+      && left_type != NULL
+      && right_type != NULL
+      && left_type->base() != right_type->base())
+    ret = false;
+  else
+    ret = Binary_expression::eval_float(this->op_, left_type, left_val,
+                                       right_type, right_val,
+                                       val, this->location());
+
+  mpfr_clear(left_val);
+  mpfr_clear(right_val);
+
+  if (ret)
+    *ptype = left_type;
+
+  return ret;
+}
+
+// Return the complex constant value, if it has one.
+
+bool
+Binary_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+                                            Type** ptype) const
+{
+  mpfr_t left_real;
+  mpfr_t left_imag;
+  mpfr_init(left_real);
+  mpfr_init(left_imag);
+  Type* left_type;
+  if (!this->left_->complex_constant_value(left_real, left_imag, &left_type))
+    {
+      mpfr_clear(left_real);
+      mpfr_clear(left_imag);
+      return false;
+    }
+
+  mpfr_t right_real;
+  mpfr_t right_imag;
+  mpfr_init(right_real);
+  mpfr_init(right_imag);
+  Type* right_type;
+  if (!this->right_->complex_constant_value(right_real, right_imag,
+                                           &right_type))
+    {
+      mpfr_clear(left_real);
+      mpfr_clear(left_imag);
+      mpfr_clear(right_real);
+      mpfr_clear(right_imag);
+      return false;
+    }
+
+  bool ret;
+  if (left_type != right_type
+      && left_type != NULL
+      && right_type != NULL
+      && left_type->base() != right_type->base())
+    ret = false;
+  else
+    ret = Binary_expression::eval_complex(this->op_, left_type,
+                                         left_real, left_imag,
+                                         right_type,
+                                         right_real, right_imag,
+                                         real, imag,
+                                         this->location());
+  mpfr_clear(left_real);
+  mpfr_clear(left_imag);
+  mpfr_clear(right_real);
+  mpfr_clear(right_imag);
+
+  if (ret)
+    *ptype = left_type;
+
+  return ret;
+}
+
+// Note that the value is being discarded.
+
+void
+Binary_expression::do_discarding_value()
+{
+  if (this->op_ == OPERATOR_OROR || this->op_ == OPERATOR_ANDAND)
+    this->right_->discarding_value();
+  else
+    this->warn_about_unused_value();
+}
+
+// Get type.
+
+Type*
+Binary_expression::do_type()
+{
+  switch (this->op_)
+    {
+    case OPERATOR_OROR:
+    case OPERATOR_ANDAND:
+    case OPERATOR_EQEQ:
+    case OPERATOR_NOTEQ:
+    case OPERATOR_LT:
+    case OPERATOR_LE:
+    case OPERATOR_GT:
+    case OPERATOR_GE:
+      return Type::lookup_bool_type();
+
+    case OPERATOR_PLUS:
+    case OPERATOR_MINUS:
+    case OPERATOR_OR:
+    case OPERATOR_XOR:
+    case OPERATOR_MULT:
+    case OPERATOR_DIV:
+    case OPERATOR_MOD:
+    case OPERATOR_AND:
+    case OPERATOR_BITCLEAR:
+      {
+       Type* left_type = this->left_->type();
+       Type* right_type = this->right_->type();
+       if (!left_type->is_abstract() && left_type->named_type() != NULL)
+         return left_type;
+       else if (!right_type->is_abstract() && right_type->named_type() != NULL)
+         return right_type;
+       else if (!left_type->is_abstract())
+         return left_type;
+       else if (!right_type->is_abstract())
+         return right_type;
+       else if (left_type->complex_type() != NULL)
+         return left_type;
+       else if (right_type->complex_type() != NULL)
+         return right_type;
+       else if (left_type->float_type() != NULL)
+         return left_type;
+       else if (right_type->float_type() != NULL)
+         return right_type;
+       else
+         return left_type;
+      }
+
+    case OPERATOR_LSHIFT:
+    case OPERATOR_RSHIFT:
+      return this->left_->type();
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Set type for a binary expression.
+
+void
+Binary_expression::do_determine_type(const Type_context* context)
+{
+  Type* tleft = this->left_->type();
+  Type* tright = this->right_->type();
+
+  // Both sides should have the same type, except for the shift
+  // operations.  For a comparison, we should ignore the incoming
+  // type.
+
+  bool is_shift_op = (this->op_ == OPERATOR_LSHIFT
+                     || this->op_ == OPERATOR_RSHIFT);
+
+  bool is_comparison = (this->op_ == OPERATOR_EQEQ
+                       || this->op_ == OPERATOR_NOTEQ
+                       || this->op_ == OPERATOR_LT
+                       || this->op_ == OPERATOR_LE
+                       || this->op_ == OPERATOR_GT
+                       || this->op_ == OPERATOR_GE);
+
+  Type_context subcontext(*context);
+
+  if (is_comparison)
+    {
+      // In a comparison, the context does not determine the types of
+      // the operands.
+      subcontext.type = NULL;
+    }
+
+  // Set the context for the left hand operand.
+  if (is_shift_op)
+    {
+      // The right hand operand plays no role in determining the type
+      // of the left hand operand.  A shift of an abstract integer in
+      // a string context gets special treatment, which may be a
+      // language bug.
+      if (subcontext.type != NULL
+         && subcontext.type->is_string_type()
+         && tleft->is_abstract())
+       error_at(this->location(), "shift of non-integer operand");
+    }
+  else if (!tleft->is_abstract())
+    subcontext.type = tleft;
+  else if (!tright->is_abstract())
+    subcontext.type = tright;
+  else if (subcontext.type == NULL)
+    {
+      if ((tleft->integer_type() != NULL && tright->integer_type() != NULL)
+         || (tleft->float_type() != NULL && tright->float_type() != NULL)
+         || (tleft->complex_type() != NULL && tright->complex_type() != NULL))
+       {
+         // Both sides have an abstract integer, abstract float, or
+         // abstract complex type.  Just let CONTEXT determine
+         // whether they may remain abstract or not.
+       }
+      else if (tleft->complex_type() != NULL)
+       subcontext.type = tleft;
+      else if (tright->complex_type() != NULL)
+       subcontext.type = tright;
+      else if (tleft->float_type() != NULL)
+       subcontext.type = tleft;
+      else if (tright->float_type() != NULL)
+       subcontext.type = tright;
+      else
+       subcontext.type = tleft;
+    }
+
+  this->left_->determine_type(&subcontext);
+
+  // The context for the right hand operand is the same as for the
+  // left hand operand, except for a shift operator.
+  if (is_shift_op)
+    {
+      subcontext.type = Type::lookup_integer_type("uint");
+      subcontext.may_be_abstract = false;
+    }
+
+  this->right_->determine_type(&subcontext);
+}
+
+// Report an error if the binary operator OP does not support TYPE.
+// Return whether the operation is OK.  This should not be used for
+// shift.
+
+bool
+Binary_expression::check_operator_type(Operator op, Type* type,
+                                      source_location location)
+{
+  switch (op)
+    {
+    case OPERATOR_OROR:
+    case OPERATOR_ANDAND:
+      if (!type->is_boolean_type())
+       {
+         error_at(location, "expected boolean type");
+         return false;
+       }
+      break;
+
+    case OPERATOR_EQEQ:
+    case OPERATOR_NOTEQ:
+      if (type->integer_type() == NULL
+         && type->float_type() == NULL
+         && type->complex_type() == NULL
+         && !type->is_string_type()
+         && type->points_to() == NULL
+         && !type->is_nil_type()
+         && !type->is_boolean_type()
+         && type->interface_type() == NULL
+         && (type->array_type() == NULL
+             || type->array_type()->length() != NULL)
+         && type->map_type() == NULL
+         && type->channel_type() == NULL
+         && type->function_type() == NULL)
+       {
+         error_at(location,
+                  ("expected integer, floating, complex, string, pointer, "
+                   "boolean, interface, slice, map, channel, "
+                   "or function type"));
+         return false;
+       }
+      break;
+
+    case OPERATOR_LT:
+    case OPERATOR_LE:
+    case OPERATOR_GT:
+    case OPERATOR_GE:
+      if (type->integer_type() == NULL
+         && type->float_type() == NULL
+         && !type->is_string_type())
+       {
+         error_at(location, "expected integer, floating, or string type");
+         return false;
+       }
+      break;
+
+    case OPERATOR_PLUS:
+    case OPERATOR_PLUSEQ:
+      if (type->integer_type() == NULL
+         && type->float_type() == NULL
+         && type->complex_type() == NULL
+         && !type->is_string_type())
+       {
+         error_at(location,
+                  "expected integer, floating, complex, or string type");
+         return false;
+       }
+      break;
+
+    case OPERATOR_MINUS:
+    case OPERATOR_MINUSEQ:
+    case OPERATOR_MULT:
+    case OPERATOR_MULTEQ:
+    case OPERATOR_DIV:
+    case OPERATOR_DIVEQ:
+      if (type->integer_type() == NULL
+         && type->float_type() == NULL
+         && type->complex_type() == NULL)
+       {
+         error_at(location, "expected integer, floating, or complex type");
+         return false;
+       }
+      break;
+
+    case OPERATOR_MOD:
+    case OPERATOR_MODEQ:
+    case OPERATOR_OR:
+    case OPERATOR_OREQ:
+    case OPERATOR_AND:
+    case OPERATOR_ANDEQ:
+    case OPERATOR_XOR:
+    case OPERATOR_XOREQ:
+    case OPERATOR_BITCLEAR:
+    case OPERATOR_BITCLEAREQ:
+      if (type->integer_type() == NULL)
+       {
+         error_at(location, "expected integer type");
+         return false;
+       }
+      break;
+
+    default:
+      gcc_unreachable();
+    }
+
+  return true;
+}
+
+// Check types.
+
+void
+Binary_expression::do_check_types(Gogo*)
+{
+  Type* left_type = this->left_->type();
+  Type* right_type = this->right_->type();
+  if (left_type->is_error_type() || right_type->is_error_type())
+    return;
+
+  if (this->op_ == OPERATOR_EQEQ
+      || this->op_ == OPERATOR_NOTEQ
+      || this->op_ == OPERATOR_LT
+      || this->op_ == OPERATOR_LE
+      || this->op_ == OPERATOR_GT
+      || this->op_ == OPERATOR_GE)
+    {
+      if (!Type::are_assignable(left_type, right_type, NULL)
+         && !Type::are_assignable(right_type, left_type, NULL))
+       {
+         this->report_error(_("incompatible types in binary expression"));
+         return;
+       }
+      if (!Binary_expression::check_operator_type(this->op_, left_type,
+                                                 this->location())
+         || !Binary_expression::check_operator_type(this->op_, right_type,
+                                                    this->location()))
+       {
+         this->set_is_error();
+         return;
+       }
+    }
+  else if (this->op_ != OPERATOR_LSHIFT && this->op_ != OPERATOR_RSHIFT)
+    {
+      if (!Type::are_compatible_for_binop(left_type, right_type))
+       {
+         this->report_error(_("incompatible types in binary expression"));
+         return;
+       }
+      if (!Binary_expression::check_operator_type(this->op_, left_type,
+                                                 this->location()))
+       {
+         this->set_is_error();
+         return;
+       }
+    }
+  else
+    {
+      if (left_type->integer_type() == NULL)
+       this->report_error(_("shift of non-integer operand"));
+
+      if (!right_type->is_abstract()
+         && (right_type->integer_type() == NULL
+             || !right_type->integer_type()->is_unsigned()))
+       this->report_error(_("shift count not unsigned integer"));
+      else
+       {
+         mpz_t val;
+         mpz_init(val);
+         Type* type;
+         if (this->right_->integer_constant_value(true, val, &type))
+           {
+             if (mpz_sgn(val) < 0)
+               this->report_error(_("negative shift count"));
+           }
+         mpz_clear(val);
+       }
+    }
+}
+
+// Get a tree for a binary expression.
+
+tree
+Binary_expression::do_get_tree(Translate_context* context)
+{
+  tree left = this->left_->get_tree(context);
+  tree right = this->right_->get_tree(context);
+
+  if (left == error_mark_node || right == error_mark_node)
+    return error_mark_node;
+
+  enum tree_code code;
+  bool use_left_type = true;
+  bool is_shift_op = false;
+  switch (this->op_)
+    {
+    case OPERATOR_EQEQ:
+    case OPERATOR_NOTEQ:
+    case OPERATOR_LT:
+    case OPERATOR_LE:
+    case OPERATOR_GT:
+    case OPERATOR_GE:
+      return Expression::comparison_tree(context, this->op_,
+                                        this->left_->type(), left,
+                                        this->right_->type(), right,
+                                        this->location());
+
+    case OPERATOR_OROR:
+      code = TRUTH_ORIF_EXPR;
+      use_left_type = false;
+      break;
+    case OPERATOR_ANDAND:
+      code = TRUTH_ANDIF_EXPR;
+      use_left_type = false;
+      break;
+    case OPERATOR_PLUS:
+      code = PLUS_EXPR;
+      break;
+    case OPERATOR_MINUS:
+      code = MINUS_EXPR;
+      break;
+    case OPERATOR_OR:
+      code = BIT_IOR_EXPR;
+      break;
+    case OPERATOR_XOR:
+      code = BIT_XOR_EXPR;
+      break;
+    case OPERATOR_MULT:
+      code = MULT_EXPR;
+      break;
+    case OPERATOR_DIV:
+      {
+       Type *t = this->left_->type();
+       if (t->float_type() != NULL || t->complex_type() != NULL)
+         code = RDIV_EXPR;
+       else
+         code = TRUNC_DIV_EXPR;
+      }
+      break;
+    case OPERATOR_MOD:
+      code = TRUNC_MOD_EXPR;
+      break;
+    case OPERATOR_LSHIFT:
+      code = LSHIFT_EXPR;
+      is_shift_op = true;
+      break;
+    case OPERATOR_RSHIFT:
+      code = RSHIFT_EXPR;
+      is_shift_op = true;
+      break;
+    case OPERATOR_AND:
+      code = BIT_AND_EXPR;
+      break;
+    case OPERATOR_BITCLEAR:
+      right = fold_build1(BIT_NOT_EXPR, TREE_TYPE(right), right);
+      code = BIT_AND_EXPR;
+      break;
+    default:
+      gcc_unreachable();
+    }
+
+  tree type = use_left_type ? TREE_TYPE(left) : TREE_TYPE(right);
+
+  if (this->left_->type()->is_string_type())
+    {
+      gcc_assert(this->op_ == OPERATOR_PLUS);
+      tree string_type = Type::make_string_type()->get_tree(context->gogo());
+      static tree string_plus_decl;
+      return Gogo::call_builtin(&string_plus_decl,
+                               this->location(),
+                               "__go_string_plus",
+                               2,
+                               string_type,
+                               string_type,
+                               left,
+                               string_type,
+                               right);
+    }
+
+  tree compute_type = excess_precision_type(type);
+  if (compute_type != NULL_TREE)
+    {
+      left = ::convert(compute_type, left);
+      right = ::convert(compute_type, right);
+    }
+
+  tree eval_saved = NULL_TREE;
+  if (is_shift_op)
+    {
+      if (!DECL_P(left))
+       left = save_expr(left);
+      if (!DECL_P(right))
+       right = save_expr(right);
+      // Make sure the values are evaluated.
+      eval_saved = fold_build2_loc(this->location(), COMPOUND_EXPR,
+                                  void_type_node, left, right);
+    }
+
+  tree ret = fold_build2_loc(this->location(),
+                            code,
+                            compute_type != NULL_TREE ? compute_type : type,
+                            left, right);
+
+  if (compute_type != NULL_TREE)
+    ret = ::convert(type, ret);
+
+  // In Go, a shift larger than the size of the type is well-defined.
+  // This is not true in GENERIC, so we need to insert a conditional.
+  if (is_shift_op)
+    {
+      gcc_assert(INTEGRAL_TYPE_P(TREE_TYPE(left)));
+      gcc_assert(this->left_->type()->integer_type() != NULL);
+      int bits = TYPE_PRECISION(TREE_TYPE(left));
+
+      tree compare = fold_build2(LT_EXPR, boolean_type_node, right,
+                                build_int_cst_type(TREE_TYPE(right), bits));
+
+      tree overflow_result = fold_convert_loc(this->location(),
+                                             TREE_TYPE(left),
+                                             integer_zero_node);
+      if (this->op_ == OPERATOR_RSHIFT
+         && !this->left_->type()->integer_type()->is_unsigned())
+       {
+         tree neg = fold_build2_loc(this->location(), LT_EXPR,
+                                    boolean_type_node, left,
+                                    fold_convert_loc(this->location(),
+                                                     TREE_TYPE(left),
+                                                     integer_zero_node));
+         tree neg_one = fold_build2_loc(this->location(),
+                                        MINUS_EXPR, TREE_TYPE(left),
+                                        fold_convert_loc(this->location(),
+                                                         TREE_TYPE(left),
+                                                         integer_zero_node),
+                                        fold_convert_loc(this->location(),
+                                                         TREE_TYPE(left),
+                                                         integer_one_node));
+         overflow_result = fold_build3_loc(this->location(), COND_EXPR,
+                                           TREE_TYPE(left), neg, neg_one,
+                                           overflow_result);
+       }
+
+      ret = fold_build3_loc(this->location(), COND_EXPR, TREE_TYPE(left),
+                           compare, ret, overflow_result);
+
+      ret = fold_build2_loc(this->location(), COMPOUND_EXPR,
+                           TREE_TYPE(ret), eval_saved, ret);
+    }
+
+  return ret;
+}
+
+// Export a binary expression.
+
+void
+Binary_expression::do_export(Export* exp) const
+{
+  exp->write_c_string("(");
+  this->left_->export_expression(exp);
+  switch (this->op_)
+    {
+    case OPERATOR_OROR:
+      exp->write_c_string(" || ");
+      break;
+    case OPERATOR_ANDAND:
+      exp->write_c_string(" && ");
+      break;
+    case OPERATOR_EQEQ:
+      exp->write_c_string(" == ");
+      break;
+    case OPERATOR_NOTEQ:
+      exp->write_c_string(" != ");
+      break;
+    case OPERATOR_LT:
+      exp->write_c_string(" < ");
+      break;
+    case OPERATOR_LE:
+      exp->write_c_string(" <= ");
+      break;
+    case OPERATOR_GT:
+      exp->write_c_string(" > ");
+      break;
+    case OPERATOR_GE:
+      exp->write_c_string(" >= ");
+      break;
+    case OPERATOR_PLUS:
+      exp->write_c_string(" + ");
+      break;
+    case OPERATOR_MINUS:
+      exp->write_c_string(" - ");
+      break;
+    case OPERATOR_OR:
+      exp->write_c_string(" | ");
+      break;
+    case OPERATOR_XOR:
+      exp->write_c_string(" ^ ");
+      break;
+    case OPERATOR_MULT:
+      exp->write_c_string(" * ");
+      break;
+    case OPERATOR_DIV:
+      exp->write_c_string(" / ");
+      break;
+    case OPERATOR_MOD:
+      exp->write_c_string(" % ");
+      break;
+    case OPERATOR_LSHIFT:
+      exp->write_c_string(" << ");
+      break;
+    case OPERATOR_RSHIFT:
+      exp->write_c_string(" >> ");
+      break;
+    case OPERATOR_AND:
+      exp->write_c_string(" & ");
+      break;
+    case OPERATOR_BITCLEAR:
+      exp->write_c_string(" &^ ");
+      break;
+    default:
+      gcc_unreachable();
+    }
+  this->right_->export_expression(exp);
+  exp->write_c_string(")");
+}
+
+// Import a binary expression.
+
+Expression*
+Binary_expression::do_import(Import* imp)
+{
+  imp->require_c_string("(");
+
+  Expression* left = Expression::import_expression(imp);
+
+  Operator op;
+  if (imp->match_c_string(" || "))
+    {
+      op = OPERATOR_OROR;
+      imp->advance(4);
+    }
+  else if (imp->match_c_string(" && "))
+    {
+      op = OPERATOR_ANDAND;
+      imp->advance(4);
+    }
+  else if (imp->match_c_string(" == "))
+    {
+      op = OPERATOR_EQEQ;
+      imp->advance(4);
+    }
+  else if (imp->match_c_string(" != "))
+    {
+      op = OPERATOR_NOTEQ;
+      imp->advance(4);
+    }
+  else if (imp->match_c_string(" < "))
+    {
+      op = OPERATOR_LT;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" <= "))
+    {
+      op = OPERATOR_LE;
+      imp->advance(4);
+    }
+  else if (imp->match_c_string(" > "))
+    {
+      op = OPERATOR_GT;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" >= "))
+    {
+      op = OPERATOR_GE;
+      imp->advance(4);
+    }
+  else if (imp->match_c_string(" + "))
+    {
+      op = OPERATOR_PLUS;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" - "))
+    {
+      op = OPERATOR_MINUS;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" | "))
+    {
+      op = OPERATOR_OR;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" ^ "))
+    {
+      op = OPERATOR_XOR;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" * "))
+    {
+      op = OPERATOR_MULT;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" / "))
+    {
+      op = OPERATOR_DIV;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" % "))
+    {
+      op = OPERATOR_MOD;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" << "))
+    {
+      op = OPERATOR_LSHIFT;
+      imp->advance(4);
+    }
+  else if (imp->match_c_string(" >> "))
+    {
+      op = OPERATOR_RSHIFT;
+      imp->advance(4);
+    }
+  else if (imp->match_c_string(" & "))
+    {
+      op = OPERATOR_AND;
+      imp->advance(3);
+    }
+  else if (imp->match_c_string(" &^ "))
+    {
+      op = OPERATOR_BITCLEAR;
+      imp->advance(4);
+    }
+  else
+    {
+      error_at(imp->location(), "unrecognized binary operator");
+      return Expression::make_error(imp->location());
+    }
+
+  Expression* right = Expression::import_expression(imp);
+
+  imp->require_c_string(")");
+
+  return Expression::make_binary(op, left, right, imp->location());
+}
+
+// Make a binary expression.
+
+Expression*
+Expression::make_binary(Operator op, Expression* left, Expression* right,
+                       source_location location)
+{
+  return new Binary_expression(op, left, right, location);
+}
+
+// Implement a comparison.
+
+tree
+Expression::comparison_tree(Translate_context* context, Operator op,
+                           Type* left_type, tree left_tree,
+                           Type* right_type, tree right_tree,
+                           source_location location)
+{
+  enum tree_code code;
+  switch (op)
+    {
+    case OPERATOR_EQEQ:
+      code = EQ_EXPR;
+      break;
+    case OPERATOR_NOTEQ:
+      code = NE_EXPR;
+      break;
+    case OPERATOR_LT:
+      code = LT_EXPR;
+      break;
+    case OPERATOR_LE:
+      code = LE_EXPR;
+      break;
+    case OPERATOR_GT:
+      code = GT_EXPR;
+      break;
+    case OPERATOR_GE:
+      code = GE_EXPR;
+      break;
+    default:
+      gcc_unreachable();
+    }
+
+  if (left_type->is_string_type())
+    {
+      gcc_assert(right_type->is_string_type());
+      tree string_type = Type::make_string_type()->get_tree(context->gogo());
+      static tree string_compare_decl;
+      left_tree = Gogo::call_builtin(&string_compare_decl,
+                                    location,
+                                    "__go_strcmp",
+                                    2,
+                                    integer_type_node,
+                                    string_type,
+                                    left_tree,
+                                    string_type,
+                                    right_tree);
+      right_tree = build_int_cst_type(integer_type_node, 0);
+    }
+
+  if ((left_type->interface_type() != NULL
+       && right_type->interface_type() == NULL
+       && !right_type->is_nil_type())
+      || (left_type->interface_type() == NULL
+         && !left_type->is_nil_type()
+         && right_type->interface_type() != NULL))
+    {
+      // Comparing an interface value to a non-interface value.
+      if (left_type->interface_type() == NULL)
+       {
+         std::swap(left_type, right_type);
+         std::swap(left_tree, right_tree);
+       }
+
+      // The right operand is not an interface.  We need to take its
+      // address if it is not a pointer.
+      tree make_tmp;
+      tree arg;
+      if (right_type->points_to() != NULL)
+       {
+         make_tmp = NULL_TREE;
+         arg = right_tree;
+       }
+      else if (TREE_ADDRESSABLE(TREE_TYPE(right_tree)) || DECL_P(right_tree))
+       {
+         make_tmp = NULL_TREE;
+         arg = build_fold_addr_expr_loc(location, right_tree);
+         if (DECL_P(right_tree))
+           TREE_ADDRESSABLE(right_tree) = 1;
+       }
+      else
+       {
+         tree tmp = create_tmp_var(TREE_TYPE(right_tree),
+                                   get_name(right_tree));
+         DECL_IGNORED_P(tmp) = 0;
+         DECL_INITIAL(tmp) = right_tree;
+         TREE_ADDRESSABLE(tmp) = 1;
+         make_tmp = build1(DECL_EXPR, void_type_node, tmp);
+         SET_EXPR_LOCATION(make_tmp, location);
+         arg = build_fold_addr_expr_loc(location, tmp);
+       }
+      arg = fold_convert_loc(location, ptr_type_node, arg);
+
+      tree descriptor = right_type->type_descriptor_pointer(context->gogo());
+
+      if (left_type->interface_type()->is_empty())
+       {
+         static tree empty_interface_value_compare_decl;
+         left_tree = Gogo::call_builtin(&empty_interface_value_compare_decl,
+                                        location,
+                                        "__go_empty_interface_value_compare",
+                                        3,
+                                        integer_type_node,
+                                        TREE_TYPE(left_tree),
+                                        left_tree,
+                                        TREE_TYPE(descriptor),
+                                        descriptor,
+                                        ptr_type_node,
+                                        arg);
+         // This can panic if the type is not comparable.
+         TREE_NOTHROW(empty_interface_value_compare_decl) = 0;
+       }
+      else
+       {
+         static tree interface_value_compare_decl;
+         left_tree = Gogo::call_builtin(&interface_value_compare_decl,
+                                        location,
+                                        "__go_interface_value_compare",
+                                        3,
+                                        integer_type_node,
+                                        TREE_TYPE(left_tree),
+                                        left_tree,
+                                        TREE_TYPE(descriptor),
+                                        descriptor,
+                                        ptr_type_node,
+                                        arg);
+         // This can panic if the type is not comparable.
+         TREE_NOTHROW(interface_value_compare_decl) = 0;
+       }
+      right_tree = build_int_cst_type(integer_type_node, 0);
+
+      if (make_tmp != NULL_TREE)
+       left_tree = build2(COMPOUND_EXPR, TREE_TYPE(left_tree), make_tmp,
+                          left_tree);
+    }
+  else if (left_type->interface_type() != NULL
+          && right_type->interface_type() != NULL)
+    {
+      if (left_type->interface_type()->is_empty())
+       {
+         gcc_assert(right_type->interface_type()->is_empty());
+         static tree empty_interface_compare_decl;
+         left_tree = Gogo::call_builtin(&empty_interface_compare_decl,
+                                        location,
+                                        "__go_empty_interface_compare",
+                                        2,
+                                        integer_type_node,
+                                        TREE_TYPE(left_tree),
+                                        left_tree,
+                                        TREE_TYPE(right_tree),
+                                        right_tree);
+         // This can panic if the type is uncomparable.
+         TREE_NOTHROW(empty_interface_compare_decl) = 0;
+       }
+      else
+       {
+         gcc_assert(!right_type->interface_type()->is_empty());
+         static tree interface_compare_decl;
+         left_tree = Gogo::call_builtin(&interface_compare_decl,
+                                        location,
+                                        "__go_interface_compare",
+                                        2,
+                                        integer_type_node,
+                                        TREE_TYPE(left_tree),
+                                        left_tree,
+                                        TREE_TYPE(right_tree),
+                                        right_tree);
+         // This can panic if the type is uncomparable.
+         TREE_NOTHROW(interface_compare_decl) = 0;
+       }
+      right_tree = build_int_cst_type(integer_type_node, 0);
+    }
+
+  if (left_type->is_nil_type()
+      && (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ))
+    {
+      std::swap(left_type, right_type);
+      std::swap(left_tree, right_tree);
+    }
+
+  if (right_type->is_nil_type())
+    {
+      if (left_type->array_type() != NULL
+         && left_type->array_type()->length() == NULL)
+       {
+         Array_type* at = left_type->array_type();
+         left_tree = at->value_pointer_tree(context->gogo(), left_tree);
+         right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+       }
+      else if (left_type->interface_type() != NULL)
+       {
+         // An interface is nil if the first field is nil.
+         tree left_type_tree = TREE_TYPE(left_tree);
+         gcc_assert(TREE_CODE(left_type_tree) == RECORD_TYPE);
+         tree field = TYPE_FIELDS(left_type_tree);
+         left_tree = build3(COMPONENT_REF, TREE_TYPE(field), left_tree,
+                            field, NULL_TREE);
+         right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+       }
+      else
+       {
+         gcc_assert(POINTER_TYPE_P(TREE_TYPE(left_tree)));
+         right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+       }
+    }
+
+  tree ret = fold_build2(code, boolean_type_node, left_tree, right_tree);
+  if (CAN_HAVE_LOCATION_P(ret))
+    SET_EXPR_LOCATION(ret, location);
+  return ret;
+}
+
+// Class Bound_method_expression.
+
+// Traversal.
+
+int
+Bound_method_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return Expression::traverse(&this->method_, traverse);
+}
+
+// Return the type of a bound method expression.  The type of this
+// object is really the type of the method with no receiver.  We
+// should be able to get away with just returning the type of the
+// method.
+
+Type*
+Bound_method_expression::do_type()
+{
+  return this->method_->type();
+}
+
+// Determine the types of a method expression.
+
+void
+Bound_method_expression::do_determine_type(const Type_context*)
+{
+  this->method_->determine_type_no_context();
+  Type* mtype = this->method_->type();
+  Function_type* fntype = mtype == NULL ? NULL : mtype->function_type();
+  if (fntype == NULL || !fntype->is_method())
+    this->expr_->determine_type_no_context();
+  else
+    {
+      Type_context subcontext(fntype->receiver()->type(), false);
+      this->expr_->determine_type(&subcontext);
+    }
+}
+
+// Check the types of a method expression.
+
+void
+Bound_method_expression::do_check_types(Gogo*)
+{
+  Type* type = this->method_->type()->deref();
+  if (type == NULL
+      || type->function_type() == NULL
+      || !type->function_type()->is_method())
+    this->report_error(_("object is not a method"));
+  else
+    {
+      Type* rtype = type->function_type()->receiver()->type()->deref();
+      Type* etype = (this->expr_type_ != NULL
+                    ? this->expr_type_
+                    : this->expr_->type());
+      etype = etype->deref();
+      if (!Type::are_identical(rtype, etype, NULL))
+       this->report_error(_("method type does not match object type"));
+    }
+}
+
+// Get the tree for a method expression.  There is no standard tree
+// representation for this.  The only places it may currently be used
+// are in a Call_expression or a Go_statement, which will take it
+// apart directly.  So this has nothing to do at present.
+
+tree
+Bound_method_expression::do_get_tree(Translate_context*)
+{
+  gcc_unreachable();
+}
+
+// Make a method expression.
+
+Bound_method_expression*
+Expression::make_bound_method(Expression* expr, Expression* method,
+                             source_location location)
+{
+  return new Bound_method_expression(expr, method, location);
+}
+
+// Class Builtin_call_expression.  This is used for a call to a
+// builtin function.
+
+class Builtin_call_expression : public Call_expression
+{
+ public:
+  Builtin_call_expression(Gogo* gogo, Expression* fn, Expression_list* args,
+                         bool is_varargs, source_location location);
+
+ protected:
+  // This overrides Call_expression::do_lower.
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  bool
+  do_is_constant() const;
+
+  bool
+  do_integer_constant_value(bool, mpz_t, Type**) const;
+
+  bool
+  do_float_constant_value(mpfr_t, Type**) const;
+
+  bool
+  do_complex_constant_value(mpfr_t, mpfr_t, Type**) const;
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return new Builtin_call_expression(this->gogo_, this->fn()->copy(),
+                                      this->args()->copy(),
+                                      this->is_varargs(),
+                                      this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  void
+  do_export(Export*) const;
+
+  virtual bool
+  do_is_recover_call() const;
+
+  virtual void
+  do_set_recover_arg(Expression*);
+
+ private:
+  // The builtin functions.
+  enum Builtin_function_code
+    {
+      BUILTIN_INVALID,
+
+      // Predeclared builtin functions.
+      BUILTIN_APPEND,
+      BUILTIN_CAP,
+      BUILTIN_CLOSE,
+      BUILTIN_CLOSED,
+      BUILTIN_CMPLX,
+      BUILTIN_COPY,
+      BUILTIN_IMAG,
+      BUILTIN_LEN,
+      BUILTIN_MAKE,
+      BUILTIN_NEW,
+      BUILTIN_PANIC,
+      BUILTIN_PRINT,
+      BUILTIN_PRINTLN,
+      BUILTIN_REAL,
+      BUILTIN_RECOVER,
+
+      // Builtin functions from the unsafe package.
+      BUILTIN_ALIGNOF,
+      BUILTIN_OFFSETOF,
+      BUILTIN_SIZEOF
+    };
+
+  Expression*
+  one_arg() const;
+
+  bool
+  check_one_arg();
+
+  static Type*
+  real_imag_type(Type*);
+
+  static Type*
+  cmplx_type(Type*);
+
+  // A pointer back to the general IR structure.  This avoids a global
+  // variable, or passing it around everywhere.
+  Gogo* gogo_;
+  // The builtin function being called.
+  Builtin_function_code code_;
+};
+
+Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
+                                                Expression* fn,
+                                                Expression_list* args,
+                                                bool is_varargs,
+                                                source_location location)
+  : Call_expression(fn, args, is_varargs, location),
+    gogo_(gogo), code_(BUILTIN_INVALID)
+{
+  Func_expression* fnexp = this->fn()->func_expression();
+  gcc_assert(fnexp != NULL);
+  const std::string& name(fnexp->named_object()->name());
+  if (name == "append")
+    this->code_ = BUILTIN_APPEND;
+  else if (name == "cap")
+    this->code_ = BUILTIN_CAP;
+  else if (name == "close")
+    this->code_ = BUILTIN_CLOSE;
+  else if (name == "closed")
+    this->code_ = BUILTIN_CLOSED;
+  else if (name == "cmplx")
+    this->code_ = BUILTIN_CMPLX;
+  else if (name == "copy")
+    this->code_ = BUILTIN_COPY;
+  else if (name == "imag")
+    this->code_ = BUILTIN_IMAG;
+  else if (name == "len")
+    this->code_ = BUILTIN_LEN;
+  else if (name == "make")
+    this->code_ = BUILTIN_MAKE;
+  else if (name == "new")
+    this->code_ = BUILTIN_NEW;
+  else if (name == "panic")
+    this->code_ = BUILTIN_PANIC;
+  else if (name == "print")
+    this->code_ = BUILTIN_PRINT;
+  else if (name == "println")
+    this->code_ = BUILTIN_PRINTLN;
+  else if (name == "real")
+    this->code_ = BUILTIN_REAL;
+  else if (name == "recover")
+    this->code_ = BUILTIN_RECOVER;
+  else if (name == "Alignof")
+    this->code_ = BUILTIN_ALIGNOF;
+  else if (name == "Offsetof")
+    this->code_ = BUILTIN_OFFSETOF;
+  else if (name == "Sizeof")
+    this->code_ = BUILTIN_SIZEOF;
+  else
+    gcc_unreachable();
+}
+
+// Return whether this is a call to recover.  This is a virtual
+// function called from the parent class.
+
+bool
+Builtin_call_expression::do_is_recover_call() const
+{
+  if (this->classification() == EXPRESSION_ERROR)
+    return false;
+  return this->code_ == BUILTIN_RECOVER;
+}
+
+// Set the argument for a call to recover.
+
+void
+Builtin_call_expression::do_set_recover_arg(Expression* arg)
+{
+  const Expression_list* args = this->args();
+  gcc_assert(args == NULL || args->empty());
+  Expression_list* new_args = new Expression_list();
+  new_args->push_back(arg);
+  this->set_args(new_args);
+}
+
+// A traversal class which looks for a call expression.
+
+class Find_call_expression : public Traverse
+{
+ public:
+  Find_call_expression()
+    : Traverse(traverse_expressions),
+      found_(false)
+  { }
+
+  int
+  expression(Expression**);
+
+  bool
+  found()
+  { return this->found_; }
+
+ private:
+  bool found_;
+};
+
+int
+Find_call_expression::expression(Expression** pexpr)
+{
+  if ((*pexpr)->call_expression() != NULL)
+    {
+      this->found_ = true;
+      return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Lower a builtin call expression.  This turns new and make into
+// specific expressions.  We also convert to a constant if we can.
+
+Expression*
+Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, int)
+{
+  if (this->code_ == BUILTIN_NEW)
+    {
+      const Expression_list* args = this->args();
+      if (args == NULL || args->size() < 1)
+       this->report_error(_("not enough arguments"));
+      else if (args->size() > 1)
+       this->report_error(_("too many arguments"));
+      else
+       {
+         Expression* arg = args->front();
+         if (!arg->is_type_expression())
+           {
+             error_at(arg->location(), "expected type");
+             this->set_is_error();
+           }
+         else
+           return Expression::make_allocation(arg->type(), this->location());
+       }
+    }
+  else if (this->code_ == BUILTIN_MAKE)
+    {
+      const Expression_list* args = this->args();
+      if (args == NULL || args->size() < 1)
+       this->report_error(_("not enough arguments"));
+      else
+       {
+         Expression* arg = args->front();
+         if (!arg->is_type_expression())
+           {
+             error_at(arg->location(), "expected type");
+             this->set_is_error();
+           }
+         else
+           {
+             Expression_list* newargs;
+             if (args->size() == 1)
+               newargs = NULL;
+             else
+               {
+                 newargs = new Expression_list();
+                 Expression_list::const_iterator p = args->begin();
+                 ++p;
+                 for (; p != args->end(); ++p)
+                   newargs->push_back(*p);
+               }
+             return Expression::make_make(arg->type(), newargs,
+                                          this->location());
+           }
+       }
+    }
+  else if (this->is_constant())
+    {
+      // We can only lower len and cap if there are no function calls
+      // in the arguments.  Otherwise we have to make the call.
+      if (this->code_ == BUILTIN_LEN || this->code_ == BUILTIN_CAP)
+       {
+         Expression* arg = this->one_arg();
+         if (!arg->is_constant())
+           {
+             Find_call_expression find_call;
+             Expression::traverse(&arg, &find_call);
+             if (find_call.found())
+               return this;
+           }
+       }
+
+      mpz_t ival;
+      mpz_init(ival);
+      Type* type;
+      if (this->integer_constant_value(true, ival, &type))
+       {
+         Expression* ret = Expression::make_integer(&ival, type,
+                                                    this->location());
+         mpz_clear(ival);
+         return ret;
+       }
+      mpz_clear(ival);
+
+      mpfr_t rval;
+      mpfr_init(rval);
+      if (this->float_constant_value(rval, &type))
+       {
+         Expression* ret = Expression::make_float(&rval, type,
+                                                  this->location());
+         mpfr_clear(rval);
+         return ret;
+       }
+
+      mpfr_t imag;
+      mpfr_init(imag);
+      if (this->complex_constant_value(rval, imag, &type))
+       {
+         Expression* ret = Expression::make_complex(&rval, &imag, type,
+                                                    this->location());
+         mpfr_clear(rval);
+         mpfr_clear(imag);
+         return ret;
+       }
+      mpfr_clear(rval);
+      mpfr_clear(imag);
+    }
+  else if (this->code_ == BUILTIN_RECOVER)
+    {
+      if (function != NULL)
+       function->func_value()->set_calls_recover();
+      else
+       {
+         // Calling recover outside of a function always returns the
+         // nil empty interface.
+         Type* eface = Type::make_interface_type(NULL, this->location());
+         return Expression::make_cast(eface,
+                                      Expression::make_nil(this->location()),
+                                      this->location());
+       }
+    }
+  else if (this->code_ == BUILTIN_APPEND)
+    {
+      // Lower the varargs.
+      const Expression_list* args = this->args();
+      if (args == NULL || args->empty())
+       return this;
+      Type* slice_type = args->front()->type();
+      if (!slice_type->is_open_array_type())
+       {
+         error_at(args->front()->location(), "argument 1 must be a slice");
+         this->set_is_error();
+         return this;
+       }
+      return this->lower_varargs(gogo, function, slice_type, 2);
+    }
+
+  return this;
+}
+
+// Return the type of the real or imag functions, given the type of
+// the argument.  We need to map complex to float, complex64 to
+// float32, and complex128 to float64, so it has to be done by name.
+// This returns NULL if it can't figure out the type.
+
+Type*
+Builtin_call_expression::real_imag_type(Type* arg_type)
+{
+  if (arg_type == NULL || arg_type->is_abstract())
+    return NULL;
+  Named_type* nt = arg_type->named_type();
+  if (nt == NULL)
+    return NULL;
+  while (nt->real_type()->named_type() != NULL)
+    nt = nt->real_type()->named_type();
+  if (nt->name() == "complex")
+    return Type::lookup_float_type("float");
+  else if (nt->name() == "complex64")
+    return Type::lookup_float_type("float32");
+  else if (nt->name() == "complex128")
+    return Type::lookup_float_type("float64");
+  else
+    return NULL;
+}
+
+// Return the type of the cmplx function, given the type of one of the
+// argments.  Like real_imag_type, we have to map by name.
+
+Type*
+Builtin_call_expression::cmplx_type(Type* arg_type)
+{
+  if (arg_type == NULL || arg_type->is_abstract())
+    return NULL;
+  Named_type* nt = arg_type->named_type();
+  if (nt == NULL)
+    return NULL;
+  while (nt->real_type()->named_type() != NULL)
+    nt = nt->real_type()->named_type();
+  if (nt->name() == "float")
+    return Type::lookup_complex_type("complex");
+  else if (nt->name() == "float32")
+    return Type::lookup_complex_type("complex64");
+  else if (nt->name() == "float64")
+    return Type::lookup_complex_type("complex128");
+  else
+    return NULL;
+}
+
+// Return a single argument, or NULL if there isn't one.
+
+Expression*
+Builtin_call_expression::one_arg() const
+{
+  const Expression_list* args = this->args();
+  if (args->size() != 1)
+    return NULL;
+  return args->front();
+}
+
+// Return whether this is constant: len of a string, or len or cap of
+// a fixed array, or unsafe.Sizeof, unsafe.Offsetof, unsafe.Alignof.
+
+bool
+Builtin_call_expression::do_is_constant() const
+{
+  switch (this->code_)
+    {
+    case BUILTIN_LEN:
+    case BUILTIN_CAP:
+      {
+       Expression* arg = this->one_arg();
+       if (arg == NULL)
+         return false;
+       Type* arg_type = arg->type();
+
+       if (arg_type->points_to() != NULL
+           && arg_type->points_to()->array_type() != NULL
+           && !arg_type->points_to()->is_open_array_type())
+         arg_type = arg_type->points_to();
+
+       if (arg_type->array_type() != NULL
+           && arg_type->array_type()->length() != NULL)
+         return arg_type->array_type()->length()->is_constant();
+
+       if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
+         return arg->is_constant();
+      }
+      break;
+
+    case BUILTIN_SIZEOF:
+    case BUILTIN_ALIGNOF:
+      return this->one_arg() != NULL;
+
+    case BUILTIN_OFFSETOF:
+      {
+       Expression* arg = this->one_arg();
+       if (arg == NULL)
+         return false;
+       return arg->field_reference_expression() != NULL;
+      }
+
+    case BUILTIN_CMPLX:
+      {
+       const Expression_list* args = this->args();
+       if (args != NULL && args->size() == 2)
+         return args->front()->is_constant() && args->back()->is_constant();
+      }
+      break;
+
+    case BUILTIN_REAL:
+    case BUILTIN_IMAG:
+      {
+       Expression* arg = this->one_arg();
+       return arg != NULL && arg->is_constant();
+      }
+
+    default:
+      break;
+    }
+
+  return false;
+}
+
+// Return an integer constant value if possible.
+
+bool
+Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
+                                                  mpz_t val,
+                                                  Type** ptype) const
+{
+  if (this->code_ == BUILTIN_LEN
+      || this->code_ == BUILTIN_CAP)
+    {
+      Expression* arg = this->one_arg();
+      if (arg == NULL)
+       return false;
+      Type* arg_type = arg->type();
+
+      if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
+       {
+         std::string sval;
+         if (arg->string_constant_value(&sval))
+           {
+             mpz_set_ui(val, sval.length());
+             *ptype = Type::lookup_integer_type("int");
+             return true;
+           }
+       }
+
+      if (arg_type->points_to() != NULL
+         && arg_type->points_to()->array_type() != NULL
+         && !arg_type->points_to()->is_open_array_type())
+       arg_type = arg_type->points_to();
+
+      if (arg_type->array_type() != NULL
+         && arg_type->array_type()->length() != NULL)
+       {
+         Expression* e = arg_type->array_type()->length();
+         if (e->integer_constant_value(iota_is_constant, val, ptype))
+           {
+             *ptype = Type::lookup_integer_type("int");
+             return true;
+           }
+       }
+    }
+  else if (this->code_ == BUILTIN_SIZEOF
+          || this->code_ == BUILTIN_ALIGNOF)
+    {
+      Expression* arg = this->one_arg();
+      if (arg == NULL)
+       return false;
+      Type* arg_type = arg->type();
+      if (arg_type->is_error_type())
+       return false;
+      if (arg_type->is_abstract())
+       return false;
+      tree arg_type_tree = arg_type->get_tree(this->gogo_);
+      unsigned long val_long;
+      if (this->code_ == BUILTIN_SIZEOF)
+       {
+         tree type_size = TYPE_SIZE_UNIT(arg_type_tree);
+         gcc_assert(TREE_CODE(type_size) == INTEGER_CST);
+         if (TREE_INT_CST_HIGH(type_size) != 0)
+           return false;
+         unsigned HOST_WIDE_INT val_wide = TREE_INT_CST_LOW(type_size);
+         val_long = static_cast<unsigned long>(val_wide);
+         if (val_long != val_wide)
+           return false;
+       }
+      else if (this->code_ == BUILTIN_ALIGNOF)
+       {
+         val_long = TYPE_ALIGN(arg_type_tree);
+         if (arg->field_reference_expression() != NULL)
+           {
+             // Calling unsafe.Alignof(s.f) returns the alignment of
+             // the type of f when it is used as a field in a struct.
+#ifdef BIGGEST_FIELD_ALIGNMENT
+             if (val_long > BIGGEST_FIELD_ALIGNMENT)
+               val_long = BIGGEST_FIELD_ALIGNMENT;
+#endif
+#ifdef ADJUST_FIELD_ALIGN
+             // A separate declaration avoids a warning promoted to
+             // an error if ADJUST_FIELD_ALIGN ignores FIELD.
+             tree field;
+             field = build_decl(UNKNOWN_LOCATION, FIELD_DECL, NULL,
+                                     arg_type_tree);
+             val_long = ADJUST_FIELD_ALIGN(field, val_long);
+#endif
+           }
+         val_long /= BITS_PER_UNIT;
+       }
+      else
+       gcc_unreachable();
+      mpz_set_ui(val, val_long);
+      *ptype = NULL;
+      return true;
+    }
+  else if (this->code_ == BUILTIN_OFFSETOF)
+    {
+      Expression* arg = this->one_arg();
+      if (arg == NULL)
+       return false;
+      Field_reference_expression* farg = arg->field_reference_expression();
+      if (farg == NULL)
+       return false;
+      Expression* struct_expr = farg->expr();
+      Type* st = struct_expr->type();
+      if (st->struct_type() == NULL)
+       return false;
+      tree struct_tree = st->get_tree(this->gogo_);
+      gcc_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
+      tree field = TYPE_FIELDS(struct_tree);
+      for (unsigned int index = farg->field_index(); index > 0; --index)
+       {
+         field = DECL_CHAIN(field);
+         gcc_assert(field != NULL_TREE);
+       }
+      HOST_WIDE_INT offset_wide = int_byte_position (field);
+      if (offset_wide < 0)
+       return false;
+      unsigned long offset_long = static_cast<unsigned long>(offset_wide);
+      if (offset_long != static_cast<unsigned HOST_WIDE_INT>(offset_wide))
+       return false;
+      mpz_set_ui(val, offset_long);
+      return true;
+    }
+  return false;
+}
+
+// Return a floating point constant value if possible.
+
+bool
+Builtin_call_expression::do_float_constant_value(mpfr_t val,
+                                                Type** ptype) const
+{
+  if (this->code_ == BUILTIN_REAL || this->code_ == BUILTIN_IMAG)
+    {
+      Expression* arg = this->one_arg();
+      if (arg == NULL)
+       return false;
+
+      mpfr_t real;
+      mpfr_t imag;
+      mpfr_init(real);
+      mpfr_init(imag);
+
+      bool ret = false;
+      Type* type;
+      if (arg->complex_constant_value(real, imag, &type))
+       {
+         if (this->code_ == BUILTIN_REAL)
+           mpfr_set(val, real, GMP_RNDN);
+         else
+           mpfr_set(val, imag, GMP_RNDN);
+         *ptype = Builtin_call_expression::real_imag_type(type);
+         ret = true;
+       }
+
+      mpfr_clear(real);
+      mpfr_clear(imag);
+      return ret;
+    }
+
+  return false;
+}
+
+// Return a complex constant value if possible.
+
+bool
+Builtin_call_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+                                                  Type** ptype) const
+{
+  if (this->code_ == BUILTIN_CMPLX)
+    {
+      const Expression_list* args = this->args();
+      if (args == NULL || args->size() != 2)
+       return false;
+
+      mpfr_t r;
+      mpfr_init(r);
+      Type* rtype;
+      if (!args->front()->float_constant_value(r, &rtype))
+       {
+         mpfr_clear(r);
+         return false;
+       }
+
+      mpfr_t i;
+      mpfr_init(i);
+
+      bool ret = false;
+      Type* itype;
+      if (args->back()->float_constant_value(i, &itype)
+         && Type::are_identical(rtype, itype, NULL))
+       {
+         mpfr_set(real, r, GMP_RNDN);
+         mpfr_set(imag, i, GMP_RNDN);
+         *ptype = Builtin_call_expression::cmplx_type(rtype);
+         ret = true;
+       }
+
+      mpfr_clear(r);
+      mpfr_clear(i);
+
+      return ret;
+    }
+
+  return false;
+}
+
+// Return the type.
+
+Type*
+Builtin_call_expression::do_type()
+{
+  switch (this->code_)
+    {
+    case BUILTIN_INVALID:
+    default:
+      gcc_unreachable();
+
+    case BUILTIN_NEW:
+    case BUILTIN_MAKE:
+      {
+       const Expression_list* args = this->args();
+       if (args == NULL || args->empty())
+         return Type::make_error_type();
+       return Type::make_pointer_type(args->front()->type());
+      }
+
+    case BUILTIN_CAP:
+    case BUILTIN_COPY:
+    case BUILTIN_LEN:
+    case BUILTIN_ALIGNOF:
+    case BUILTIN_OFFSETOF:
+    case BUILTIN_SIZEOF:
+      return Type::lookup_integer_type("int");
+
+    case BUILTIN_CLOSE:
+    case BUILTIN_PANIC:
+    case BUILTIN_PRINT:
+    case BUILTIN_PRINTLN:
+      return Type::make_void_type();
+
+    case BUILTIN_CLOSED:
+      return Type::lookup_bool_type();
+
+    case BUILTIN_RECOVER:
+      return Type::make_interface_type(NULL, BUILTINS_LOCATION);
+
+    case BUILTIN_APPEND:
+      {
+       const Expression_list* args = this->args();
+       if (args == NULL || args->empty())
+         return Type::make_error_type();
+       return args->front()->type();
+      }
+
+    case BUILTIN_REAL:
+    case BUILTIN_IMAG:
+      {
+       Expression* arg = this->one_arg();
+       if (arg == NULL)
+         return Type::make_error_type();
+       Type* t = arg->type();
+       if (t->is_abstract())
+         t = t->make_non_abstract_type();
+       t = Builtin_call_expression::real_imag_type(t);
+       if (t == NULL)
+         t = Type::make_error_type();
+       return t;
+      }
+
+    case BUILTIN_CMPLX:
+      {
+       const Expression_list* args = this->args();
+       if (args == NULL || args->size() != 2)
+         return Type::make_error_type();
+       Type* t = args->front()->type();
+       if (t->is_abstract())
+         {
+           t = args->back()->type();
+           if (t->is_abstract())
+             t = t->make_non_abstract_type();
+         }
+       t = Builtin_call_expression::cmplx_type(t);
+       if (t == NULL)
+         t = Type::make_error_type();
+       return t;
+      }
+    }
+}
+
+// Determine the type.
+
+void
+Builtin_call_expression::do_determine_type(const Type_context* context)
+{
+  this->fn()->determine_type_no_context();
+
+  const Expression_list* args = this->args();
+
+  bool is_print;
+  Type* arg_type = NULL;
+  switch (this->code_)
+    {
+    case BUILTIN_PRINT:
+    case BUILTIN_PRINTLN:
+      // Do not force a large integer constant to "int".
+      is_print = true;
+      break;
+
+    case BUILTIN_REAL:
+    case BUILTIN_IMAG:
+      arg_type = Builtin_call_expression::cmplx_type(context->type);
+      is_print = false;
+      break;
+
+    case BUILTIN_CMPLX:
+      {
+       // For the cmplx function the type of one operand can
+       // determine the type of the other, as in a binary expression.
+       arg_type = Builtin_call_expression::real_imag_type(context->type);
+       if (args != NULL && args->size() == 2)
+         {
+           Type* t1 = args->front()->type();
+           Type* t2 = args->front()->type();
+           if (!t1->is_abstract())
+             arg_type = t1;
+           else if (!t2->is_abstract())
+             arg_type = t2;
+         }
+       is_print = false;
+      }
+      break;
+
+    default:
+      is_print = false;
+      break;
+    }
+
+  if (args != NULL)
+    {
+      for (Expression_list::const_iterator pa = args->begin();
+          pa != args->end();
+          ++pa)
+       {
+         Type_context subcontext;
+         subcontext.type = arg_type;
+
+         if (is_print)
+           {
+             // We want to print large constants, we so can't just
+             // use the appropriate nonabstract type.  Use uint64 for
+             // an integer if we know it is nonnegative, otherwise
+             // use int64 for a integer, otherwise use float64 for a
+             // float or complex128 for a complex.
+             Type* want_type = NULL;
+             Type* atype = (*pa)->type();
+             if (atype->is_abstract())
+               {
+                 if (atype->integer_type() != NULL)
+                   {
+                     mpz_t val;
+                     mpz_init(val);
+                     Type* dummy;
+                     if (this->integer_constant_value(true, val, &dummy)
+                         && mpz_sgn(val) >= 0)
+                       want_type = Type::lookup_integer_type("uint64");
+                     else
+                       want_type = Type::lookup_integer_type("int64");
+                     mpz_clear(val);
+                   }
+                 else if (atype->float_type() != NULL)
+                   want_type = Type::lookup_float_type("float64");
+                 else if (atype->complex_type() != NULL)
+                   want_type = Type::lookup_complex_type("complex128");
+                 else if (atype->is_abstract_string_type())
+                   want_type = Type::lookup_string_type();
+                 else if (atype->is_abstract_boolean_type())
+                   want_type = Type::lookup_bool_type();
+                 else
+                   gcc_unreachable();
+                 subcontext.type = want_type;
+               }
+           }
+
+         (*pa)->determine_type(&subcontext);
+       }
+    }
+}
+
+// If there is exactly one argument, return true.  Otherwise give an
+// error message and return false.
+
+bool
+Builtin_call_expression::check_one_arg()
+{
+  const Expression_list* args = this->args();
+  if (args == NULL || args->size() < 1)
+    {
+      this->report_error(_("not enough arguments"));
+      return false;
+    }
+  else if (args->size() > 1)
+    {
+      this->report_error(_("too many arguments"));
+      return false;
+    }
+  if (args->front()->is_error_expression()
+      || args->front()->type()->is_error_type())
+    {
+      this->set_is_error();
+      return false;
+    }
+  return true;
+}
+
+// Check argument types for a builtin function.
+
+void
+Builtin_call_expression::do_check_types(Gogo*)
+{
+  switch (this->code_)
+    {
+    case BUILTIN_INVALID:
+    case BUILTIN_NEW:
+    case BUILTIN_MAKE:
+      return;
+
+    case BUILTIN_LEN:
+    case BUILTIN_CAP:
+      {
+       // The single argument may be either a string or an array or a
+       // map or a channel, or a pointer to a closed array.
+       if (this->check_one_arg())
+         {
+           Type* arg_type = this->one_arg()->type();
+           if (arg_type->points_to() != NULL
+               && arg_type->points_to()->array_type() != NULL
+               && !arg_type->points_to()->is_open_array_type())
+             arg_type = arg_type->points_to();
+           if (this->code_ == BUILTIN_CAP)
+             {
+               if (!arg_type->is_error_type()
+                   && arg_type->array_type() == NULL
+                   && arg_type->channel_type() == NULL)
+                 this->report_error(_("argument must be array or slice "
+                                      "or channel"));
+             }
+           else
+             {
+               if (!arg_type->is_error_type()
+                   && !arg_type->is_string_type()
+                   && arg_type->array_type() == NULL
+                   && arg_type->map_type() == NULL
+                   && arg_type->channel_type() == NULL)
+                 this->report_error(_("argument must be string or "
+                                      "array or slice or map or channel"));
+             }
+         }
+      }
+      break;
+
+    case BUILTIN_PRINT:
+    case BUILTIN_PRINTLN:
+      {
+       const Expression_list* args = this->args();
+       if (args == NULL)
+         {
+           if (this->code_ == BUILTIN_PRINT)
+             warning_at(this->location(), 0,
+                        "no arguments for builtin function %<%s%>",
+                        (this->code_ == BUILTIN_PRINT
+                         ? "print"
+                         : "println"));
+         }
+       else
+         {
+           for (Expression_list::const_iterator p = args->begin();
+                p != args->end();
+                ++p)
+             {
+               Type* type = (*p)->type();
+               if (type->is_error_type()
+                   || type->is_string_type()
+                   || type->integer_type() != NULL
+                   || type->float_type() != NULL
+                   || type->complex_type() != NULL
+                   || type->is_boolean_type()
+                   || type->points_to() != NULL
+                   || type->interface_type() != NULL
+                   || type->channel_type() != NULL
+                   || type->map_type() != NULL
+                   || type->function_type() != NULL
+                   || type->is_open_array_type())
+                 ;
+               else
+                 this->report_error(_("unsupported argument type to "
+                                      "builtin function"));
+             }
+         }
+      }
+      break;
+
+    case BUILTIN_CLOSE:
+    case BUILTIN_CLOSED:
+      if (this->check_one_arg())
+       {
+         if (this->one_arg()->type()->channel_type() == NULL)
+           this->report_error(_("argument must be channel"));
+       }
+      break;
+
+    case BUILTIN_PANIC:
+    case BUILTIN_SIZEOF:
+    case BUILTIN_ALIGNOF:
+      this->check_one_arg();
+      break;
+
+    case BUILTIN_RECOVER:
+      if (this->args() != NULL && !this->args()->empty())
+       this->report_error(_("too many arguments"));
+      break;
+
+    case BUILTIN_OFFSETOF:
+      if (this->check_one_arg())
+       {
+         Expression* arg = this->one_arg();
+         if (arg->field_reference_expression() == NULL)
+           this->report_error(_("argument must be a field reference"));
+       }
+      break;
+
+    case BUILTIN_COPY:
+      {
+       const Expression_list* args = this->args();
+       if (args == NULL || args->size() < 2)
+         {
+           this->report_error(_("not enough arguments"));
+           break;
+         }
+       else if (args->size() > 2)
+         {
+           this->report_error(_("too many arguments"));
+           break;
+         }
+       Type* arg1_type = args->front()->type();
+       Type* arg2_type = args->back()->type();
+       if (arg1_type->is_error_type() || arg2_type->is_error_type())
+         break;
+
+       Type* e1;
+       if (arg1_type->is_open_array_type())
+         e1 = arg1_type->array_type()->element_type();
+       else
+         {
+           this->report_error(_("left argument must be a slice"));
+           break;
+         }
+
+       Type* e2;
+       if (arg2_type->is_open_array_type())
+         e2 = arg2_type->array_type()->element_type();
+       else if (arg2_type->is_string_type())
+         e2 = Type::lookup_integer_type("uint8");
+       else
+         {
+           this->report_error(_("right argument must be a slice or a string"));
+           break;
+         }
+
+       if (!Type::are_identical(e1, e2, NULL))
+         this->report_error(_("element types must be the same"));
+      }
+      break;
+
+    case BUILTIN_APPEND:
+      {
+       const Expression_list* args = this->args();
+       if (args == NULL || args->empty())
+         {
+           this->report_error(_("not enough arguments"));
+           break;
+         }
+       /* Lowering varargs should have left us with 2 arguments.  */
+       gcc_assert(args->size() == 2);
+       std::string reason;
+       if (!Type::are_assignable(args->front()->type(), args->back()->type(),
+                                 &reason))
+         {
+           if (reason.empty())
+             this->report_error(_("arguments 1 and 2 have different types"));
+           else
+             {
+               error_at(this->location(),
+                        "arguments 1 and 2 have different types (%s)",
+                        reason.c_str());
+               this->set_is_error();
+             }
+         }
+       break;
+      }
+
+    case BUILTIN_REAL:
+    case BUILTIN_IMAG:
+      if (this->check_one_arg())
+       {
+         if (this->one_arg()->type()->complex_type() == NULL)
+           this->report_error(_("argument must have complex type"));
+       }
+      break;
+
+    case BUILTIN_CMPLX:
+      {
+       const Expression_list* args = this->args();
+       if (args == NULL || args->size() < 2)
+         this->report_error(_("not enough arguments"));
+       else if (args->size() > 2)
+         this->report_error(_("too many arguments"));
+       else if (args->front()->is_error_expression()
+                || args->front()->type()->is_error_type()
+                || args->back()->is_error_expression()
+                || args->back()->type()->is_error_type())
+         this->set_is_error();
+       else if (!Type::are_identical(args->front()->type(),
+                                     args->back()->type(), NULL))
+         this->report_error(_("cmplx arguments must have identical types"));
+       else if (args->front()->type()->float_type() == NULL)
+         this->report_error(_("cmplx arguments must have "
+                              "floating-point type"));
+      }
+      break;
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Return the tree for a builtin function.
+
+tree
+Builtin_call_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  source_location location = this->location();
+  switch (this->code_)
+    {
+    case BUILTIN_INVALID:
+    case BUILTIN_NEW:
+    case BUILTIN_MAKE:
+      gcc_unreachable();
+
+    case BUILTIN_LEN:
+    case BUILTIN_CAP:
+      {
+       const Expression_list* args = this->args();
+       gcc_assert(args != NULL && args->size() == 1);
+       Expression* arg = *args->begin();
+       Type* arg_type = arg->type();
+       tree arg_tree = arg->get_tree(context);
+       if (arg_tree == error_mark_node)
+         return error_mark_node;
+
+       if (arg_type->points_to() != NULL)
+         {
+           arg_type = arg_type->points_to();
+           gcc_assert(arg_type->array_type() != NULL
+                      && !arg_type->is_open_array_type());
+           gcc_assert(POINTER_TYPE_P(TREE_TYPE(arg_tree)));
+           arg_tree = build_fold_indirect_ref(arg_tree);
+         }
+
+       tree val_tree;
+       if (this->code_ == BUILTIN_LEN)
+         {
+           if (arg_type->is_string_type())
+             val_tree = String_type::length_tree(gogo, arg_tree);
+           else if (arg_type->array_type() != NULL)
+             val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
+           else if (arg_type->map_type() != NULL)
+             {
+               static tree map_len_fndecl;
+               val_tree = Gogo::call_builtin(&map_len_fndecl,
+                                             location,
+                                             "__go_map_len",
+                                             1,
+                                             sizetype,
+                                             arg_type->get_tree(gogo),
+                                             arg_tree);
+             }
+           else if (arg_type->channel_type() != NULL)
+             {
+               static tree chan_len_fndecl;
+               val_tree = Gogo::call_builtin(&chan_len_fndecl,
+                                             location,
+                                             "__go_chan_len",
+                                             1,
+                                             sizetype,
+                                             arg_type->get_tree(gogo),
+                                             arg_tree);
+             }
+           else
+             gcc_unreachable();
+         }
+       else
+         {
+           if (arg_type->array_type() != NULL)
+             val_tree = arg_type->array_type()->capacity_tree(gogo, arg_tree);
+           else if (arg_type->channel_type() != NULL)
+             {
+               static tree chan_cap_fndecl;
+               val_tree = Gogo::call_builtin(&chan_cap_fndecl,
+                                             location,
+                                             "__go_chan_cap",
+                                             1,
+                                             sizetype,
+                                             arg_type->get_tree(gogo),
+                                             arg_tree);
+             }
+           else
+             gcc_unreachable();
+         }
+
+       tree type_tree = Type::lookup_integer_type("int")->get_tree(gogo);
+       if (type_tree == TREE_TYPE(val_tree))
+         return val_tree;
+       else
+         return fold(convert_to_integer(type_tree, val_tree));
+      }
+
+    case BUILTIN_PRINT:
+    case BUILTIN_PRINTLN:
+      {
+       const bool is_ln = this->code_ == BUILTIN_PRINTLN;
+       tree stmt_list = NULL_TREE;
+
+       const Expression_list* call_args = this->args();
+       if (call_args != NULL)
+         {
+           for (Expression_list::const_iterator p = call_args->begin();
+                p != call_args->end();
+                ++p)
+             {
+               if (is_ln && p != call_args->begin())
+                 {
+                   static tree print_space_fndecl;
+                   tree call = Gogo::call_builtin(&print_space_fndecl,
+                                                  location,
+                                                  "__go_print_space",
+                                                  0,
+                                                  void_type_node);
+                   append_to_statement_list(call, &stmt_list);
+                 }
+
+               Type* type = (*p)->type();
+
+               tree arg = (*p)->get_tree(context);
+               if (arg == error_mark_node)
+                 return error_mark_node;
+
+               tree* pfndecl;
+               const char* fnname;
+               if (type->is_string_type())
+                 {
+                   static tree print_string_fndecl;
+                   pfndecl = &print_string_fndecl;
+                   fnname = "__go_print_string";
+                 }
+               else if (type->integer_type() != NULL
+                        && type->integer_type()->is_unsigned())
+                 {
+                   static tree print_uint64_fndecl;
+                   pfndecl = &print_uint64_fndecl;
+                   fnname = "__go_print_uint64";
+                   Type* itype = Type::lookup_integer_type("uint64");
+                   arg = fold_convert_loc(location, itype->get_tree(gogo),
+                                          arg);
+                 }
+               else if (type->integer_type() != NULL)
+                 {
+                   static tree print_int64_fndecl;
+                   pfndecl = &print_int64_fndecl;
+                   fnname = "__go_print_int64";
+                   Type* itype = Type::lookup_integer_type("int64");
+                   arg = fold_convert_loc(location, itype->get_tree(gogo),
+                                          arg);
+                 }
+               else if (type->float_type() != NULL)
+                 {
+                   static tree print_double_fndecl;
+                   pfndecl = &print_double_fndecl;
+                   fnname = "__go_print_double";
+                   arg = fold_convert_loc(location, double_type_node, arg);
+                 }
+               else if (type->complex_type() != NULL)
+                 {
+                   static tree print_complex_fndecl;
+                   pfndecl = &print_complex_fndecl;
+                   fnname = "__go_print_complex";
+                   arg = fold_convert_loc(location, complex_double_type_node,
+                                          arg);
+                 }
+               else if (type->is_boolean_type())
+                 {
+                   static tree print_bool_fndecl;
+                   pfndecl = &print_bool_fndecl;
+                   fnname = "__go_print_bool";
+                 }
+               else if (type->points_to() != NULL
+                        || type->channel_type() != NULL
+                        || type->map_type() != NULL
+                        || type->function_type() != NULL)
+                 {
+                   static tree print_pointer_fndecl;
+                   pfndecl = &print_pointer_fndecl;
+                   fnname = "__go_print_pointer";
+                   arg = fold_convert_loc(location, ptr_type_node, arg);
+                 }
+               else if (type->interface_type() != NULL)
+                 {
+                   if (type->interface_type()->is_empty())
+                     {
+                       static tree print_empty_interface_fndecl;
+                       pfndecl = &print_empty_interface_fndecl;
+                       fnname = "__go_print_empty_interface";
+                     }
+                   else
+                     {
+                       static tree print_interface_fndecl;
+                       pfndecl = &print_interface_fndecl;
+                       fnname = "__go_print_interface";
+                     }
+                 }
+               else if (type->is_open_array_type())
+                 {
+                   static tree print_slice_fndecl;
+                   pfndecl = &print_slice_fndecl;
+                   fnname = "__go_print_slice";
+                 }
+               else
+                 gcc_unreachable();
+
+               tree call = Gogo::call_builtin(pfndecl,
+                                              location,
+                                              fnname,
+                                              1,
+                                              void_type_node,
+                                              TREE_TYPE(arg),
+                                              arg);
+               append_to_statement_list(call, &stmt_list);
+             }
+         }
+
+       if (is_ln)
+         {
+           static tree print_nl_fndecl;
+           tree call = Gogo::call_builtin(&print_nl_fndecl,
+                                          location,
+                                          "__go_print_nl",
+                                          0,
+                                          void_type_node);
+           append_to_statement_list(call, &stmt_list);
+         }
+
+       return stmt_list;
+      }
+
+    case BUILTIN_PANIC:
+      {
+       const Expression_list* args = this->args();
+       gcc_assert(args != NULL && args->size() == 1);
+       Expression* arg = args->front();
+       tree arg_tree = arg->get_tree(context);
+       if (arg_tree == error_mark_node)
+         return error_mark_node;
+       Type *empty = Type::make_interface_type(NULL, BUILTINS_LOCATION);
+       arg_tree = Expression::convert_for_assignment(context, empty,
+                                                     arg->type(),
+                                                     arg_tree, location);
+       static tree panic_fndecl;
+       tree call = Gogo::call_builtin(&panic_fndecl,
+                                      location,
+                                      "__go_panic",
+                                      1,
+                                      void_type_node,
+                                      TREE_TYPE(arg_tree),
+                                      arg_tree);
+       // This function will throw an exception.
+       TREE_NOTHROW(panic_fndecl) = 0;
+       // This function will not return.
+       TREE_THIS_VOLATILE(panic_fndecl) = 1;
+       return call;
+      }
+
+    case BUILTIN_RECOVER:
+      {
+       // The argument is set when building recover thunks.  It's a
+       // boolean value which is true if we can recover a value now.
+       const Expression_list* args = this->args();
+       gcc_assert(args != NULL && args->size() == 1);
+       Expression* arg = args->front();
+       tree arg_tree = arg->get_tree(context);
+       if (arg_tree == error_mark_node)
+         return error_mark_node;
+
+       Type *empty = Type::make_interface_type(NULL, BUILTINS_LOCATION);
+       tree empty_tree = empty->get_tree(context->gogo());
+
+       Type* nil_type = Type::make_nil_type();
+       Expression* nil = Expression::make_nil(location);
+       tree nil_tree = nil->get_tree(context);
+       tree empty_nil_tree = Expression::convert_for_assignment(context,
+                                                                empty,
+                                                                nil_type,
+                                                                nil_tree,
+                                                                location);
+
+       // We need to handle a deferred call to recover specially,
+       // because it changes whether it can recover a panic or not.
+       // See test7 in test/recover1.go.
+       tree call;
+       if (this->is_deferred())
+         {
+           static tree deferred_recover_fndecl;
+           call = Gogo::call_builtin(&deferred_recover_fndecl,
+                                     location,
+                                     "__go_deferred_recover",
+                                     0,
+                                     empty_tree);
+         }
+       else
+         {
+           static tree recover_fndecl;
+           call = Gogo::call_builtin(&recover_fndecl,
+                                     location,
+                                     "__go_recover",
+                                     0,
+                                     empty_tree);
+         }
+       return fold_build3_loc(location, COND_EXPR, empty_tree, arg_tree,
+                              call, empty_nil_tree);
+      }
+
+    case BUILTIN_CLOSE:
+    case BUILTIN_CLOSED:
+      {
+       const Expression_list* args = this->args();
+       gcc_assert(args != NULL && args->size() == 1);
+       Expression* arg = args->front();
+       tree arg_tree = arg->get_tree(context);
+       if (arg_tree == error_mark_node)
+         return error_mark_node;
+       if (this->code_ == BUILTIN_CLOSE)
+         {
+           static tree close_fndecl;
+           return Gogo::call_builtin(&close_fndecl,
+                                     location,
+                                     "__go_builtin_close",
+                                     1,
+                                     void_type_node,
+                                     TREE_TYPE(arg_tree),
+                                     arg_tree);
+         }
+       else
+         {
+           static tree closed_fndecl;
+           return Gogo::call_builtin(&closed_fndecl,
+                                     location,
+                                     "__go_builtin_closed",
+                                     1,
+                                     boolean_type_node,
+                                     TREE_TYPE(arg_tree),
+                                     arg_tree);
+         }
+      }
+
+    case BUILTIN_SIZEOF:
+    case BUILTIN_OFFSETOF:
+    case BUILTIN_ALIGNOF:
+      {
+       mpz_t val;
+       mpz_init(val);
+       Type* dummy;
+       bool b = this->integer_constant_value(true, val, &dummy);
+       gcc_assert(b);
+       tree type = Type::lookup_integer_type("int")->get_tree(gogo);
+       tree ret = Expression::integer_constant_tree(val, type);
+       mpz_clear(val);
+       return ret;
+      }
+
+    case BUILTIN_COPY:
+      {
+       const Expression_list* args = this->args();
+       gcc_assert(args != NULL && args->size() == 2);
+       Expression* arg1 = args->front();
+       Expression* arg2 = args->back();
+
+       tree arg1_tree = arg1->get_tree(context);
+       tree arg2_tree = arg2->get_tree(context);
+       if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
+         return error_mark_node;
+
+       Type* arg1_type = arg1->type();
+       Array_type* at = arg1_type->array_type();
+       arg1_tree = save_expr(arg1_tree);
+       tree arg1_val = at->value_pointer_tree(gogo, arg1_tree);
+       tree arg1_len = at->length_tree(gogo, arg1_tree);
+
+       Type* arg2_type = arg2->type();
+       tree arg2_val;
+       tree arg2_len;
+       if (arg2_type->is_open_array_type())
+         {
+           at = arg2_type->array_type();
+           arg2_tree = save_expr(arg2_tree);
+           arg2_val = at->value_pointer_tree(gogo, arg2_tree);
+           arg2_len = at->length_tree(gogo, arg2_tree);
+         }
+       else
+         {
+           arg2_tree = save_expr(arg2_tree);
+           arg2_val = String_type::bytes_tree(gogo, arg2_tree);
+           arg2_len = String_type::length_tree(gogo, arg2_tree);
+         }
+
+       arg1_len = save_expr(arg1_len);
+       arg2_len = save_expr(arg2_len);
+       tree len = fold_build3_loc(location, COND_EXPR, TREE_TYPE(arg1_len),
+                                  fold_build2_loc(location, LT_EXPR,
+                                                  boolean_type_node,
+                                                  arg1_len, arg2_len),
+                                  arg1_len, arg2_len);
+       len = save_expr(len);
+
+       Type* element_type = at->element_type();
+       tree element_type_tree = element_type->get_tree(gogo);
+       tree element_size = TYPE_SIZE_UNIT(element_type_tree);
+       tree bytecount = fold_convert_loc(location, TREE_TYPE(element_size),
+                                         len);
+       bytecount = fold_build2_loc(location, MULT_EXPR,
+                                   TREE_TYPE(element_size),
+                                   bytecount, element_size);
+       bytecount = fold_convert_loc(location, size_type_node, bytecount);
+
+       tree call = build_call_expr_loc(location,
+                                       built_in_decls[BUILT_IN_MEMMOVE],
+                                       3, arg1_val, arg2_val, bytecount);
+
+       return fold_build2_loc(location, COMPOUND_EXPR, TREE_TYPE(len),
+                              call, len);
+      }
+
+    case BUILTIN_APPEND:
+      {
+       const Expression_list* args = this->args();
+       gcc_assert(args != NULL && args->size() == 2);
+       Expression* arg1 = args->front();
+       Expression* arg2 = args->back();
+
+       tree arg1_tree = arg1->get_tree(context);
+       tree arg2_tree = arg2->get_tree(context);
+       if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
+         return error_mark_node;
+
+       tree descriptor_tree = arg1->type()->type_descriptor_pointer(gogo);
+
+       // We rebuild the decl each time since the slice types may
+       // change.
+       tree append_fndecl = NULL_TREE;
+       return Gogo::call_builtin(&append_fndecl,
+                                 location,
+                                 "__go_append",
+                                 3,
+                                 TREE_TYPE(arg1_tree),
+                                 TREE_TYPE(descriptor_tree),
+                                 descriptor_tree,
+                                 TREE_TYPE(arg1_tree),
+                                 arg1_tree,
+                                 TREE_TYPE(arg2_tree),
+                                 arg2_tree);
+      }
+
+    case BUILTIN_REAL:
+    case BUILTIN_IMAG:
+      {
+       const Expression_list* args = this->args();
+       gcc_assert(args != NULL && args->size() == 1);
+       Expression* arg = args->front();
+       tree arg_tree = arg->get_tree(context);
+       if (arg_tree == error_mark_node)
+         return error_mark_node;
+       gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(arg_tree)));
+       if (this->code_ == BUILTIN_REAL)
+         return fold_build1_loc(location, REALPART_EXPR,
+                                TREE_TYPE(TREE_TYPE(arg_tree)),
+                                arg_tree);
+       else
+         return fold_build1_loc(location, IMAGPART_EXPR,
+                                TREE_TYPE(TREE_TYPE(arg_tree)),
+                                arg_tree);
+      }
+
+    case BUILTIN_CMPLX:
+      {
+       const Expression_list* args = this->args();
+       gcc_assert(args != NULL && args->size() == 2);
+       tree r = args->front()->get_tree(context);
+       tree i = args->back()->get_tree(context);
+       if (r == error_mark_node || i == error_mark_node)
+         return error_mark_node;
+       gcc_assert(TYPE_MAIN_VARIANT(TREE_TYPE(r))
+                  == TYPE_MAIN_VARIANT(TREE_TYPE(i)));
+       gcc_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(r)));
+       return fold_build2_loc(location, COMPLEX_EXPR,
+                              build_complex_type(TREE_TYPE(r)),
+                              r, i);
+      }
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// We have to support exporting a builtin call expression, because
+// code can set a constant to the result of a builtin expression.
+
+void
+Builtin_call_expression::do_export(Export* exp) const
+{
+  bool ok = false;
+
+  mpz_t val;
+  mpz_init(val);
+  Type* dummy;
+  if (this->integer_constant_value(true, val, &dummy))
+    {
+      Integer_expression::export_integer(exp, val);
+      ok = true;
+    }
+  mpz_clear(val);
+
+  if (!ok)
+    {
+      mpfr_t fval;
+      mpfr_init(fval);
+      if (this->float_constant_value(fval, &dummy))
+       {
+         Float_expression::export_float(exp, fval);
+         ok = true;
+       }
+      mpfr_clear(fval);
+    }
+
+  if (!ok)
+    {
+      mpfr_t real;
+      mpfr_t imag;
+      mpfr_init(real);
+      mpfr_init(imag);
+      if (this->complex_constant_value(real, imag, &dummy))
+       {
+         Complex_expression::export_complex(exp, real, imag);
+         ok = true;
+       }
+      mpfr_clear(real);
+      mpfr_clear(imag);
+    }
+
+  if (!ok)
+    {
+      error_at(this->location(), "value is not constant");
+      return;
+    }
+
+  // A trailing space lets us reliably identify the end of the number.
+  exp->write_c_string(" ");
+}
+
+// Class Call_expression.
+
+// Traversal.
+
+int
+Call_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->fn_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (this->args_ != NULL)
+    {
+      if (this->args_->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Lower a call statement.
+
+Expression*
+Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
+{
+  // A type case can look like a function call.
+  if (this->fn_->is_type_expression()
+      && this->args_ != NULL
+      && this->args_->size() == 1)
+    return Expression::make_cast(this->fn_->type(), this->args_->front(),
+                                this->location());
+
+  // Recognize a call to a builtin function.
+  Func_expression* fne = this->fn_->func_expression();
+  if (fne != NULL
+      && fne->named_object()->is_function_declaration()
+      && fne->named_object()->func_declaration_value()->type()->is_builtin())
+    return new Builtin_call_expression(gogo, this->fn_, this->args_,
+                                      this->is_varargs_, this->location());
+
+  // Handle an argument which is a call to a function which returns
+  // multiple results.
+  if (this->args_ != NULL
+      && this->args_->size() == 1
+      && this->args_->front()->call_expression() != NULL
+      && this->fn_->type()->function_type() != NULL)
+    {
+      Function_type* fntype = this->fn_->type()->function_type();
+      size_t rc = this->args_->front()->call_expression()->result_count();
+      if (rc > 1
+         && fntype->parameters() != NULL
+         && (fntype->parameters()->size() == rc
+             || (fntype->is_varargs()
+                 && fntype->parameters()->size() - 1 <= rc)))
+       {
+         Call_expression* call = this->args_->front()->call_expression();
+         Expression_list* args = new Expression_list;
+         for (size_t i = 0; i < rc; ++i)
+           args->push_back(Expression::make_call_result(call, i));
+         // We can't return a new call expression here, because this
+         // one may be referenced by Call_result expressions.  FIXME.
+         delete this->args_;
+         this->args_ = args;
+       }
+    }
+
+  // Handle a call to a varargs function by packaging up the extra
+  // parameters.
+  if (this->fn_->type()->function_type() != NULL
+      && this->fn_->type()->function_type()->is_varargs())
+    {
+      Function_type* fntype = this->fn_->type()->function_type();
+      const Typed_identifier_list* parameters = fntype->parameters();
+      gcc_assert(parameters != NULL && !parameters->empty());
+      Type* varargs_type = parameters->back().type();
+      return this->lower_varargs(gogo, function, varargs_type,
+                                parameters->size());
+    }
+
+  return this;
+}
+
+// Lower a call to a varargs function.  FUNCTION is the function in
+// which the call occurs--it's not the function we are calling.
+// VARARGS_TYPE is the type of the varargs parameter, a slice type.
+// PARAM_COUNT is the number of parameters of the function we are
+// calling; the last of these parameters will be the varargs
+// parameter.
+
+Expression*
+Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
+                              Type* varargs_type, size_t param_count)
+{
+  if (this->varargs_are_lowered_)
+    return this;
+
+  source_location loc = this->location();
+
+  gcc_assert(param_count > 0);
+  gcc_assert(varargs_type->is_open_array_type());
+
+  size_t arg_count = this->args_ == NULL ? 0 : this->args_->size();
+  if (arg_count < param_count - 1)
+    {
+      // Not enough arguments; will be caught in check_types.
+      return this;
+    }
+
+  Expression_list* old_args = this->args_;
+  Expression_list* new_args = new Expression_list();
+  bool push_empty_arg = false;
+  if (old_args == NULL || old_args->empty())
+    {
+      gcc_assert(param_count == 1);
+      push_empty_arg = true;
+    }
+  else
+    {
+      Expression_list::const_iterator pa;
+      int i = 1;
+      for (pa = old_args->begin(); pa != old_args->end(); ++pa, ++i)
+       {
+         if (static_cast<size_t>(i) == param_count)
+           break;
+         new_args->push_back(*pa);
+       }
+
+      // We have reached the varargs parameter.
+
+      bool issued_error = false;
+      if (pa == old_args->end())
+       push_empty_arg = true;
+      else if (pa + 1 == old_args->end() && this->is_varargs_)
+       new_args->push_back(*pa);
+      else if (this->is_varargs_)
+       {
+         this->report_error(_("too many arguments"));
+         return this;
+       }
+      else if (pa + 1 == old_args->end()
+              && this->is_compatible_varargs_argument(function, *pa,
+                                                      varargs_type,
+                                                      &issued_error))
+       new_args->push_back(*pa);
+      else
+       {
+         Type* element_type = varargs_type->array_type()->element_type();
+         Expression_list* vals = new Expression_list;
+         for (; pa != old_args->end(); ++pa, ++i)
+           {
+             // Check types here so that we get a better message.
+             Type* patype = (*pa)->type();
+             source_location paloc = (*pa)->location();
+             if (!this->check_argument_type(i, element_type, patype,
+                                            paloc, issued_error))
+               continue;
+             vals->push_back(*pa);
+           }
+         Expression* val =
+           Expression::make_slice_composite_literal(varargs_type, vals, loc);
+         new_args->push_back(val);
+       }
+    }
+
+  if (push_empty_arg)
+    new_args->push_back(Expression::make_nil(loc));
+
+  // We can't return a new call expression here, because this one may
+  // be referenced by Call_result expressions.  FIXME.
+  if (old_args != NULL)
+    delete old_args;
+  this->args_ = new_args;
+  this->varargs_are_lowered_ = true;
+
+  // Lower all the new subexpressions.
+  Expression* ret = this;
+  gogo->lower_expression(function, &ret);
+  gcc_assert(ret == this);
+  return ret;
+}
+
+// Return true if ARG is a varargs argment which should be passed to
+// the varargs parameter of type PARAM_TYPE without wrapping.  ARG
+// will be the last argument passed in the call, and PARAM_TYPE will
+// be the type of the last parameter of the varargs function being
+// called.
+
+bool
+Call_expression::is_compatible_varargs_argument(Named_object* function,
+                                               Expression* arg,
+                                               Type* param_type,
+                                               bool* issued_error)
+{
+  *issued_error = false;
+
+  Type* var_type = NULL;
+
+  // The simple case is passing the varargs parameter of the caller.
+  Var_expression* ve = arg->var_expression();
+  if (ve != NULL && ve->named_object()->is_variable())
+    {
+      Variable* var = ve->named_object()->var_value();
+      if (var->is_varargs_parameter())
+       var_type = var->type();
+    }
+
+  // The complex case is passing the varargs parameter of some
+  // enclosing function.  This will look like passing down *c.f where
+  // c is the closure variable and f is a field in the closure.
+  if (function != NULL
+      && function->func_value()->needs_closure()
+      && arg->classification() == EXPRESSION_UNARY)
+    {
+      Unary_expression* ue = static_cast<Unary_expression*>(arg);
+      if (ue->op() == OPERATOR_MULT)
+       {
+         Field_reference_expression* fre =
+           ue->operand()->deref()->field_reference_expression();
+         if (fre != NULL)
+           {
+             Var_expression* ve = fre->expr()->deref()->var_expression();
+             if (ve != NULL)
+               {
+                 Named_object* no = ve->named_object();
+                 Function* f = function->func_value();
+                 if (no == f->closure_var())
+                   {
+                     // At this point we know that this indeed a
+                     // reference to some enclosing variable.  Now we
+                     // need to figure out whether that variable is a
+                     // varargs parameter.
+                     Named_object* enclosing =
+                       f->enclosing_var(fre->field_index());
+                     Variable* var = enclosing->var_value();
+                     if (var->is_varargs_parameter())
+                       var_type = var->type();
+                   }
+               }
+           }
+       }
+    }
+
+  if (var_type == NULL)
+    return false;
+
+  // We only match if the parameter is the same, with an identical
+  // type.
+  Array_type* var_at = var_type->array_type();
+  gcc_assert(var_at != NULL);
+  Array_type* param_at = param_type->array_type();
+  if (param_at != NULL
+      && Type::are_identical(var_at->element_type(),
+                            param_at->element_type(), NULL))
+    return true;
+  error_at(arg->location(), "... mismatch: passing ...T as ...");
+  *issued_error = true;
+  return false;
+}
+
+// Get the function type.  Returns NULL if we don't know the type.  If
+// this returns NULL, and if_ERROR is true, issues an error.
+
+Function_type*
+Call_expression::get_function_type() const
+{
+  return this->fn_->type()->function_type();
+}
+
+// Return the number of values which this call will return.
+
+size_t
+Call_expression::result_count() const
+{
+  const Function_type* fntype = this->get_function_type();
+  if (fntype == NULL)
+    return 0;
+  if (fntype->results() == NULL)
+    return 0;
+  return fntype->results()->size();
+}
+
+// Return whether this is a call to the predeclared function recover.
+
+bool
+Call_expression::is_recover_call() const
+{
+  return this->do_is_recover_call();
+}
+
+// Set the argument to the recover function.
+
+void
+Call_expression::set_recover_arg(Expression* arg)
+{
+  this->do_set_recover_arg(arg);
+}
+
+// Virtual functions also implemented by Builtin_call_expression.
+
+bool
+Call_expression::do_is_recover_call() const
+{
+  return false;
+}
+
+void
+Call_expression::do_set_recover_arg(Expression*)
+{
+  gcc_unreachable();
+}
+
+// Get the type.
+
+Type*
+Call_expression::do_type()
+{
+  if (this->type_ != NULL)
+    return this->type_;
+
+  Type* ret;
+  Function_type* fntype = this->get_function_type();
+  if (fntype == NULL)
+    return Type::make_error_type();
+
+  const Typed_identifier_list* results = fntype->results();
+  if (results == NULL)
+    ret = Type::make_void_type();
+  else if (results->size() == 1)
+    ret = results->begin()->type();
+  else
+    ret = Type::make_call_multiple_result_type(this);
+
+  this->type_ = ret;
+
+  return this->type_;
+}
+
+// Determine types for a call expression.  We can use the function
+// parameter types to set the types of the arguments.
+
+void
+Call_expression::do_determine_type(const Type_context*)
+{
+  this->fn_->determine_type_no_context();
+  Function_type* fntype = this->get_function_type();
+  const Typed_identifier_list* parameters = NULL;
+  if (fntype != NULL)
+    parameters = fntype->parameters();
+  if (this->args_ != NULL)
+    {
+      Typed_identifier_list::const_iterator pt;
+      if (parameters != NULL)
+       pt = parameters->begin();
+      for (Expression_list::const_iterator pa = this->args_->begin();
+          pa != this->args_->end();
+          ++pa)
+       {
+         if (parameters != NULL && pt != parameters->end())
+           {
+             Type_context subcontext(pt->type(), false);
+             (*pa)->determine_type(&subcontext);
+             ++pt;
+           }
+         else
+           (*pa)->determine_type_no_context();
+       }
+    }
+}
+
+// Check types for parameter I.
+
+bool
+Call_expression::check_argument_type(int i, const Type* parameter_type,
+                                    const Type* argument_type,
+                                    source_location argument_location,
+                                    bool issued_error)
+{
+  std::string reason;
+  if (!Type::are_assignable(parameter_type, argument_type, &reason))
+    {
+      if (!issued_error)
+       {
+         if (reason.empty())
+           error_at(argument_location, "argument %d has incompatible type", i);
+         else
+           error_at(argument_location,
+                    "argument %d has incompatible type (%s)",
+                    i, reason.c_str());
+       }
+      this->set_is_error();
+      return false;
+    }
+  return true;
+}
+
+// Check types.
+
+void
+Call_expression::do_check_types(Gogo*)
+{
+  Function_type* fntype = this->get_function_type();
+  if (fntype == NULL)
+    {
+      if (!this->fn_->type()->is_error_type())
+       this->report_error(_("expected function"));
+      return;
+    }
+
+  if (fntype->is_method())
+    {
+      // We don't support pointers to methods, so the function has to
+      // be a bound method expression.
+      Bound_method_expression* bme = this->fn_->bound_method_expression();
+      if (bme == NULL)
+       {
+         this->report_error(_("method call without object"));
+         return;
+       }
+      Type* first_arg_type = bme->first_argument()->type();
+      if (first_arg_type->points_to() == NULL)
+       {
+         // When passing a value, we need to check that we are
+         // permitted to copy it.
+         std::string reason;
+         if (!Type::are_assignable(fntype->receiver()->type(),
+                                   first_arg_type, &reason))
+           {
+             if (reason.empty())
+               this->report_error(_("incompatible type for receiver"));
+             else
+               {
+                 error_at(this->location(),
+                          "incompatible type for receiver (%s)",
+                          reason.c_str());
+                 this->set_is_error();
+               }
+           }
+       }
+    }
+
+  // Note that varargs was handled by the lower_varargs() method, so
+  // we don't have to worry about it here.
+
+  const Typed_identifier_list* parameters = fntype->parameters();
+  if (this->args_ == NULL)
+    {
+      if (parameters != NULL && !parameters->empty())
+       this->report_error(_("not enough arguments"));
+    }
+  else if (parameters == NULL)
+    this->report_error(_("too many arguments"));
+  else
+    {
+      int i = 0;
+      Typed_identifier_list::const_iterator pt = parameters->begin();
+      for (Expression_list::const_iterator pa = this->args_->begin();
+          pa != this->args_->end();
+          ++pa, ++pt, ++i)
+       {
+         if (pt == parameters->end())
+           {
+             this->report_error(_("too many arguments"));
+             return;
+           }
+         this->check_argument_type(i + 1, pt->type(), (*pa)->type(),
+                                   (*pa)->location(), false);
+       }
+      if (pt != parameters->end())
+       this->report_error(_("not enough arguments"));
+    }
+}
+
+// Return whether we have to use a temporary variable to ensure that
+// we evaluate this call expression in order.  If the call returns no
+// results then it will inevitably be executed last.  If the call
+// returns more than one result then it will be used with Call_result
+// expressions.  So we only have to use a temporary variable if the
+// call returns exactly one result.
+
+bool
+Call_expression::do_must_eval_in_order() const
+{
+  return this->result_count() == 1;
+}
+
+// Get the function and the first argument to use when calling a bound
+// method.
+
+tree
+Call_expression::bound_method_function(Translate_context* context,
+                                      Bound_method_expression* bound_method,
+                                      tree* first_arg_ptr)
+{
+  Expression* first_argument = bound_method->first_argument();
+  tree first_arg = first_argument->get_tree(context);
+  if (first_arg == error_mark_node)
+    return error_mark_node;
+
+  // We always pass a pointer to the first argument when calling a
+  // method.
+  if (first_argument->type()->points_to() == NULL)
+    {
+      tree pointer_to_arg_type = build_pointer_type(TREE_TYPE(first_arg));
+      if (TREE_ADDRESSABLE(TREE_TYPE(first_arg))
+         || DECL_P(first_arg)
+         || TREE_CODE(first_arg) == INDIRECT_REF
+         || TREE_CODE(first_arg) == COMPONENT_REF)
+       {
+         first_arg = build_fold_addr_expr(first_arg);
+         if (DECL_P(first_arg))
+           TREE_ADDRESSABLE(first_arg) = 1;
+       }
+      else
+       {
+         tree tmp = create_tmp_var(TREE_TYPE(first_arg),
+                                   get_name(first_arg));
+         DECL_IGNORED_P(tmp) = 0;
+         DECL_INITIAL(tmp) = first_arg;
+         first_arg = build2(COMPOUND_EXPR, pointer_to_arg_type,
+                            build1(DECL_EXPR, void_type_node, tmp),
+                            build_fold_addr_expr(tmp));
+         TREE_ADDRESSABLE(tmp) = 1;
+       }
+      if (first_arg == error_mark_node)
+       return error_mark_node;
+    }
+
+  Type* fatype = bound_method->first_argument_type();
+  if (fatype != NULL)
+    {
+      if (fatype->points_to() == NULL)
+       fatype = Type::make_pointer_type(fatype);
+      first_arg = fold_convert(fatype->get_tree(context->gogo()), first_arg);
+      if (first_arg == error_mark_node
+         || TREE_TYPE(first_arg) == error_mark_node)
+       return error_mark_node;
+    }
+
+  *first_arg_ptr = first_arg;
+
+  return bound_method->method()->get_tree(context);
+}
+
+// Get the function and the first argument to use when calling an
+// interface method.
+
+tree
+Call_expression::interface_method_function(
+    Translate_context* context,
+    Interface_field_reference_expression* interface_method,
+    tree* first_arg_ptr)
+{
+  tree expr = interface_method->expr()->get_tree(context);
+  if (expr == error_mark_node)
+    return error_mark_node;
+  expr = save_expr(expr);
+  tree first_arg = interface_method->get_underlying_object_tree(context, expr);
+  if (first_arg == error_mark_node)
+    return error_mark_node;
+  *first_arg_ptr = first_arg;
+  return interface_method->get_function_tree(context, expr);
+}
+
+// Build the call expression.
+
+tree
+Call_expression::do_get_tree(Translate_context* context)
+{
+  if (this->tree_ != NULL_TREE)
+    return this->tree_;
+
+  Function_type* fntype = this->get_function_type();
+  if (fntype == NULL)
+    return error_mark_node;
+
+  if (this->fn_->is_error_expression())
+    return error_mark_node;
+
+  Gogo* gogo = context->gogo();
+  source_location location = this->location();
+
+  Func_expression* func = this->fn_->func_expression();
+  Bound_method_expression* bound_method = this->fn_->bound_method_expression();
+  Interface_field_reference_expression* interface_method =
+    this->fn_->interface_field_reference_expression();
+  const bool has_closure = func != NULL && func->closure() != NULL;
+  const bool is_method = bound_method != NULL || interface_method != NULL;
+  gcc_assert(!fntype->is_method() || is_method);
+
+  int nargs;
+  tree* args;
+  if (this->args_ == NULL || this->args_->empty())
+    {
+      nargs = is_method ? 1 : 0;
+      args = nargs == 0 ? NULL : new tree[nargs];
+    }
+  else
+    {
+      const Typed_identifier_list* params = fntype->parameters();
+      gcc_assert(params != NULL);
+
+      nargs = this->args_->size();
+      int i = is_method ? 1 : 0;
+      nargs += i;
+      args = new tree[nargs];
+
+      Typed_identifier_list::const_iterator pp = params->begin();
+      Expression_list::const_iterator pe;
+      for (pe = this->args_->begin();
+          pe != this->args_->end();
+          ++pe, ++pp, ++i)
+       {
+         tree arg_val = (*pe)->get_tree(context);
+         args[i] = Expression::convert_for_assignment(context,
+                                                      pp->type(),
+                                                      (*pe)->type(),
+                                                      arg_val,
+                                                      location);
+         if (args[i] == error_mark_node)
+           return error_mark_node;
+       }
+      gcc_assert(pp == params->end());
+      gcc_assert(i == nargs);
+    }
+
+  tree rettype = TREE_TYPE(TREE_TYPE(fntype->get_tree(gogo)));
+  if (rettype == error_mark_node)
+    return error_mark_node;
+
+  tree fn;
+  if (has_closure)
+    fn = func->get_tree_without_closure(gogo);
+  else if (!is_method)
+    fn = this->fn_->get_tree(context);
+  else if (bound_method != NULL)
+    fn = this->bound_method_function(context, bound_method, &args[0]);
+  else if (interface_method != NULL)
+    fn = this->interface_method_function(context, interface_method, &args[0]);
+  else
+    gcc_unreachable();
+
+  if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
+    return error_mark_node;
+
+  // This is to support builtin math functions when using 80387 math.
+  tree fndecl = fn;
+  if (TREE_CODE(fndecl) == ADDR_EXPR)
+    fndecl = TREE_OPERAND(fndecl, 0);
+  tree excess_type = NULL_TREE;
+  if (DECL_P(fndecl)
+      && DECL_IS_BUILTIN(fndecl)
+      && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
+      && nargs > 0
+      && ((SCALAR_FLOAT_TYPE_P(rettype)
+          && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0])))
+         || (COMPLEX_FLOAT_TYPE_P(rettype)
+             && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0])))))
+    {
+      excess_type = excess_precision_type(TREE_TYPE(args[0]));
+      if (excess_type != NULL_TREE)
+       {
+         tree excess_fndecl = mathfn_built_in(excess_type,
+                                              DECL_FUNCTION_CODE(fndecl));
+         if (excess_fndecl == NULL_TREE)
+           excess_type = NULL_TREE;
+         else
+           {
+             fn = build_fold_addr_expr_loc(location, excess_fndecl);
+             for (int i = 0; i < nargs; ++i)
+               args[i] = ::convert(excess_type, args[i]);
+           }
+       }
+    }
+
+  tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype,
+                             fn, nargs, args);
+  delete[] args;
+
+  SET_EXPR_LOCATION(ret, location);
+
+  if (has_closure)
+    {
+      tree closure_tree = func->closure()->get_tree(context);
+      if (closure_tree != error_mark_node)
+       CALL_EXPR_STATIC_CHAIN(ret) = closure_tree;
+    }
+
+  // If this is a recursive function type which returns itself, as in
+  //   type F func() F
+  // we have used ptr_type_node for the return type.  Add a cast here
+  // to the correct type.
+  if (TREE_TYPE(ret) == ptr_type_node)
+    {
+      tree t = this->type()->get_tree(gogo);
+      ret = fold_convert_loc(location, t, ret);
+    }
+
+  if (excess_type != NULL_TREE)
+    {
+      // Calling convert here can undo our excess precision change.
+      // That may or may not be a bug in convert_to_real.
+      ret = build1(NOP_EXPR, rettype, ret);
+    }
+
+  // If there is more than one result, we will refer to the call
+  // multiple times.
+  if (fntype->results() != NULL && fntype->results()->size() > 1)
+    ret = save_expr(ret);
+
+  this->tree_ = ret;
+
+  return ret;
+}
+
+// Make a call expression.
+
+Call_expression*
+Expression::make_call(Expression* fn, Expression_list* args, bool is_varargs,
+                     source_location location)
+{
+  return new Call_expression(fn, args, is_varargs, location);
+}
+
+// A single result from a call which returns multiple results.
+
+class Call_result_expression : public Expression
+{
+ public:
+  Call_result_expression(Call_expression* call, unsigned int index)
+    : Expression(EXPRESSION_CALL_RESULT, call->location()),
+      call_(call), index_(index)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return new Call_result_expression(this->call_->call_expression(),
+                                     this->index_);
+  }
+
+  bool
+  do_must_eval_in_order() const
+  { return true; }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The underlying call expression.
+  Expression* call_;
+  // Which result we want.
+  unsigned int index_;
+};
+
+// Traverse a call result.
+
+int
+Call_result_expression::do_traverse(Traverse* traverse)
+{
+  if (traverse->remember_expression(this->call_))
+    {
+      // We have already traversed the call expression.
+      return TRAVERSE_CONTINUE;
+    }
+  return Expression::traverse(&this->call_, traverse);
+}
+
+// Get the type.
+
+Type*
+Call_result_expression::do_type()
+{
+  // THIS->CALL_ can be replaced with a temporary reference due to
+  // Call_expression::do_must_eval_in_order when there is an error.
+  Call_expression* ce = this->call_->call_expression();
+  if (ce == NULL)
+    return Type::make_error_type();
+  Function_type* fntype = ce->get_function_type();
+  if (fntype == NULL)
+    return Type::make_error_type();
+  const Typed_identifier_list* results = fntype->results();
+  Typed_identifier_list::const_iterator pr = results->begin();
+  for (unsigned int i = 0; i < this->index_; ++i)
+    {
+      if (pr == results->end())
+       return Type::make_error_type();
+      ++pr;
+    }
+  if (pr == results->end())
+    return Type::make_error_type();
+  return pr->type();
+}
+
+// Check the type.  This is where we give an error if we're trying to
+// extract too many values from a call.
+
+void
+Call_result_expression::do_check_types(Gogo*)
+{
+  bool ok = true;
+  Call_expression* ce = this->call_->call_expression();
+  if (ce != NULL)
+    ok = this->index_ < ce->result_count();
+  else
+    {
+      // This can happen when the call returns a single value but we
+      // are asking for the second result.
+      if (this->call_->is_error_expression())
+       return;
+      ok = false;
+    }
+  if (!ok)
+    error_at(this->location(),
+            "number of results does not match number of values");
+}
+
+// Determine the type.  We have nothing to do here, but the 0 result
+// needs to pass down to the caller.
+
+void
+Call_result_expression::do_determine_type(const Type_context*)
+{
+  if (this->index_ == 0)
+    this->call_->determine_type_no_context();
+}
+
+// Return the tree.
+
+tree
+Call_result_expression::do_get_tree(Translate_context* context)
+{
+  tree call_tree = this->call_->get_tree(context);
+  if (call_tree == error_mark_node)
+    return error_mark_node;
+  gcc_assert(TREE_CODE(TREE_TYPE(call_tree)) == RECORD_TYPE);
+  tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
+  for (unsigned int i = 0; i < this->index_; ++i)
+    {
+      gcc_assert(field != NULL_TREE);
+      field = DECL_CHAIN(field);
+    }
+  gcc_assert(field != NULL_TREE);
+  return build3(COMPONENT_REF, TREE_TYPE(field), call_tree, field, NULL_TREE);
+}
+
+// Make a reference to a single result of a call which returns
+// multiple results.
+
+Expression*
+Expression::make_call_result(Call_expression* call, unsigned int index)
+{
+  return new Call_result_expression(call, index);
+}
+
+// Class Index_expression.
+
+// Traversal.
+
+int
+Index_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->left_, traverse) == TRAVERSE_EXIT
+      || Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT
+      || (this->end_ != NULL
+         && Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT))
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Lower an index expression.  This converts the generic index
+// expression into an array index, a string index, or a map index.
+
+Expression*
+Index_expression::do_lower(Gogo*, Named_object*, int)
+{
+  source_location location = this->location();
+  Expression* left = this->left_;
+  Expression* start = this->start_;
+  Expression* end = this->end_;
+
+  Type* type = left->type();
+  if (type->is_error_type())
+    return Expression::make_error(location);
+  else if (type->array_type() != NULL)
+    return Expression::make_array_index(left, start, end, location);
+  else if (type->points_to() != NULL
+          && type->points_to()->array_type() != NULL
+          && !type->points_to()->is_open_array_type())
+    {
+      Expression* deref = Expression::make_unary(OPERATOR_MULT, left,
+                                                location);
+      return Expression::make_array_index(deref, start, end, location);
+    }
+  else if (type->is_string_type())
+    return Expression::make_string_index(left, start, end, location);
+  else if (type->map_type() != NULL)
+    {
+      if (end != NULL)
+       {
+         error_at(location, "invalid slice of map");
+         return Expression::make_error(location);
+       }
+      Map_index_expression* ret= Expression::make_map_index(left, start,
+                                                           location);
+      if (this->is_lvalue_)
+       ret->set_is_lvalue();
+      return ret;
+    }
+  else
+    {
+      error_at(location,
+              "attempt to index object which is not array, string, or map");
+      return Expression::make_error(location);
+    }
+}
+
+// Make an index expression.
+
+Expression*
+Expression::make_index(Expression* left, Expression* start, Expression* end,
+                      source_location location)
+{
+  return new Index_expression(left, start, end, location);
+}
+
+// An array index.  This is used for both indexing and slicing.
+
+class Array_index_expression : public Expression
+{
+ public:
+  Array_index_expression(Expression* array, Expression* start,
+                        Expression* end, source_location location)
+    : Expression(EXPRESSION_ARRAY_INDEX, location),
+      array_(array), start_(start), end_(end), type_(NULL)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_array_index(this->array_->copy(),
+                                       this->start_->copy(),
+                                       (this->end_ == NULL
+                                        ? NULL
+                                        : this->end_->copy()),
+                                       this->location());
+  }
+
+  bool
+  do_is_addressable() const;
+
+  void
+  do_address_taken(bool escapes)
+  { this->array_->address_taken(escapes); }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The array we are getting a value from.
+  Expression* array_;
+  // The start or only index.
+  Expression* start_;
+  // The end index of a slice.  This may be NULL for a simple array
+  // index, or it may be a nil expression for the length of the array.
+  Expression* end_;
+  // The type of the expression.
+  Type* type_;
+};
+
+// Array index traversal.
+
+int
+Array_index_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->array_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (this->end_ != NULL)
+    {
+      if (Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Return the type of an array index.
+
+Type*
+Array_index_expression::do_type()
+{
+  if (this->type_ == NULL)
+    {
+     Array_type* type = this->array_->type()->array_type();
+      if (type == NULL)
+       this->type_ = Type::make_error_type();
+      else if (this->end_ == NULL)
+       this->type_ = type->element_type();
+      else if (type->is_open_array_type())
+       {
+         // A slice of a slice has the same type as the original
+         // slice.
+         this->type_ = this->array_->type()->deref();
+       }
+      else
+       {
+         // A slice of an array is a slice.
+         this->type_ = Type::make_array_type(type->element_type(), NULL);
+       }
+    }
+  return this->type_;
+}
+
+// Set the type of an array index.
+
+void
+Array_index_expression::do_determine_type(const Type_context*)
+{
+  this->array_->determine_type_no_context();
+  Type_context subcontext(NULL, true);
+  this->start_->determine_type(&subcontext);
+  if (this->end_ != NULL)
+    this->end_->determine_type(&subcontext);
+}
+
+// Check types of an array index.
+
+void
+Array_index_expression::do_check_types(Gogo*)
+{
+  if (this->start_->type()->integer_type() == NULL)
+    this->report_error(_("index must be integer"));
+  if (this->end_ != NULL
+      && this->end_->type()->integer_type() == NULL
+      && !this->end_->is_nil_expression())
+    this->report_error(_("slice end must be integer"));
+
+  Array_type* array_type = this->array_->type()->array_type();
+  gcc_assert(array_type != NULL);
+
+  unsigned int int_bits =
+    Type::lookup_integer_type("int")->integer_type()->bits();
+
+  Type* dummy;
+  mpz_t lval;
+  mpz_init(lval);
+  bool lval_valid = (array_type->length() != NULL
+                    && array_type->length()->integer_constant_value(true,
+                                                                    lval,
+                                                                    &dummy));
+  mpz_t ival;
+  mpz_init(ival);
+  if (this->start_->integer_constant_value(true, ival, &dummy))
+    {
+      if (mpz_sgn(ival) < 0
+         || mpz_sizeinbase(ival, 2) >= int_bits
+         || (lval_valid
+             && (this->end_ == NULL
+                 ? mpz_cmp(ival, lval) >= 0
+                 : mpz_cmp(ival, lval) > 0)))
+       {
+         error_at(this->start_->location(), "array index out of bounds");
+         this->set_is_error();
+       }
+    }
+  if (this->end_ != NULL && !this->end_->is_nil_expression())
+    {
+      if (this->end_->integer_constant_value(true, ival, &dummy))
+       {
+         if (mpz_sgn(ival) < 0
+             || mpz_sizeinbase(ival, 2) >= int_bits
+             || (lval_valid && mpz_cmp(ival, lval) > 0))
+           {
+             error_at(this->end_->location(), "array index out of bounds");
+             this->set_is_error();
+           }
+       }
+    }
+  mpz_clear(ival);
+  mpz_clear(lval);
+
+  // A slice of an array requires an addressable array.  A slice of a
+  // slice is always possible.
+  if (this->end_ != NULL
+      && !array_type->is_open_array_type()
+      && !this->array_->is_addressable())
+    this->report_error(_("array is not addressable"));
+}
+
+// Return whether this expression is addressable.
+
+bool
+Array_index_expression::do_is_addressable() const
+{
+  // A slice expression is not addressable.
+  if (this->end_ != NULL)
+    return false;
+
+  // An index into a slice is addressable.
+  if (this->array_->type()->is_open_array_type())
+    return true;
+
+  // An index into an array is addressable if the array is
+  // addressable.
+  return this->array_->is_addressable();
+}
+
+// Get a tree for an array index.
+
+tree
+Array_index_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  source_location loc = this->location();
+
+  Array_type* array_type = this->array_->type()->array_type();
+  gcc_assert(array_type != NULL);
+
+  tree type_tree = array_type->get_tree(gogo);
+
+  tree array_tree = this->array_->get_tree(context);
+  if (array_tree == error_mark_node)
+    return error_mark_node;
+
+  if (array_type->length() == NULL && !DECL_P(array_tree))
+    array_tree = save_expr(array_tree);
+  tree length_tree = array_type->length_tree(gogo, array_tree);
+  length_tree = save_expr(length_tree);
+  tree length_type = TREE_TYPE(length_tree);
+
+  tree bad_index = boolean_false_node;
+
+  tree start_tree = this->start_->get_tree(context);
+  if (start_tree == error_mark_node)
+    return error_mark_node;
+  if (!DECL_P(start_tree))
+    start_tree = save_expr(start_tree);
+  if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree)))
+    start_tree = convert_to_integer(length_type, start_tree);
+
+  bad_index = Expression::check_bounds(start_tree, length_type, bad_index,
+                                      loc);
+
+  start_tree = fold_convert_loc(loc, length_type, start_tree);
+  bad_index = fold_build2_loc(loc, TRUTH_OR_EXPR, boolean_type_node, bad_index,
+                             fold_build2_loc(loc,
+                                             (this->end_ == NULL
+                                              ? GE_EXPR
+                                              : GT_EXPR),
+                                             boolean_type_node, start_tree,
+                                             length_tree));
+
+  int code = (array_type->length() != NULL
+             ? (this->end_ == NULL
+                ? RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS
+                : RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS)
+             : (this->end_ == NULL
+                ? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS
+                : RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS));
+  tree crash = Gogo::runtime_error(code, loc);
+
+  if (this->end_ == NULL)
+    {
+      // Simple array indexing.  This has to return an l-value, so
+      // wrap the index check into START_TREE.
+      start_tree = build2(COMPOUND_EXPR, TREE_TYPE(start_tree),
+                         build3(COND_EXPR, void_type_node,
+                                bad_index, crash, NULL_TREE),
+                         start_tree);
+      start_tree = fold_convert_loc(loc, sizetype, start_tree);
+
+      if (array_type->length() != NULL)
+       {
+         // Fixed array.
+         return build4(ARRAY_REF, TREE_TYPE(type_tree), array_tree,
+                       start_tree, NULL_TREE, NULL_TREE);
+       }
+      else
+       {
+         // Open array.
+         tree values = array_type->value_pointer_tree(gogo, array_tree);
+         tree element_type_tree = array_type->element_type()->get_tree(gogo);
+         tree element_size = TYPE_SIZE_UNIT(element_type_tree);
+         tree offset = fold_build2_loc(loc, MULT_EXPR, sizetype,
+                                       start_tree, element_size);
+         tree ptr = fold_build2_loc(loc, POINTER_PLUS_EXPR,
+                                    TREE_TYPE(values), values, offset);
+         return build_fold_indirect_ref(ptr);
+       }
+    }
+
+  // Array slice.
+
+  tree capacity_tree = array_type->capacity_tree(gogo, array_tree);
+  capacity_tree = fold_convert_loc(loc, length_type, capacity_tree);
+
+  tree end_tree;
+  if (this->end_->is_nil_expression())
+    end_tree = length_tree;
+  else
+    {
+      end_tree = this->end_->get_tree(context);
+      if (end_tree == error_mark_node)
+       return error_mark_node;
+      if (!DECL_P(end_tree))
+       end_tree = save_expr(end_tree);
+      if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree)))
+       end_tree = convert_to_integer(length_type, end_tree);
+
+      bad_index = Expression::check_bounds(end_tree, length_type, bad_index,
+                                          loc);
+
+      end_tree = fold_convert_loc(loc, length_type, end_tree);
+
+      capacity_tree = save_expr(capacity_tree);
+      tree bad_end = fold_build2_loc(loc, TRUTH_OR_EXPR, boolean_type_node,
+                                    fold_build2_loc(loc, LT_EXPR,
+                                                    boolean_type_node,
+                                                    end_tree, start_tree),
+                                    fold_build2_loc(loc, GT_EXPR,
+                                                    boolean_type_node,
+                                                    end_tree, capacity_tree));
+      bad_index = fold_build2_loc(loc, TRUTH_OR_EXPR, boolean_type_node,
+                                 bad_index, bad_end);
+    }
+
+  tree element_type_tree = array_type->element_type()->get_tree(gogo);
+  tree element_size = TYPE_SIZE_UNIT(element_type_tree);
+
+  tree offset = fold_build2_loc(loc, MULT_EXPR, sizetype,
+                               fold_convert_loc(loc, sizetype, start_tree),
+                               element_size);
+
+  tree value_pointer = array_type->value_pointer_tree(gogo, array_tree);
+
+  value_pointer = fold_build2_loc(loc, POINTER_PLUS_EXPR,
+                                 TREE_TYPE(value_pointer),
+                                 value_pointer, offset);
+
+  tree result_length_tree = fold_build2_loc(loc, MINUS_EXPR, length_type,
+                                           end_tree, start_tree);
+
+  tree result_capacity_tree = fold_build2_loc(loc, MINUS_EXPR, length_type,
+                                             capacity_tree, start_tree);
+
+  tree struct_tree = this->type()->get_tree(gogo);
+  gcc_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 3);
+
+  constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+  tree field = TYPE_FIELDS(struct_tree);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
+  elt->index = field;
+  elt->value = value_pointer;
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = DECL_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
+  elt->index = field;
+  elt->value = fold_convert_loc(loc, TREE_TYPE(field), result_length_tree);
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = DECL_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
+  elt->index = field;
+  elt->value = fold_convert_loc(loc, TREE_TYPE(field), result_capacity_tree);
+
+  tree constructor = build_constructor(struct_tree, init);
+
+  if (TREE_CONSTANT(value_pointer)
+      && TREE_CONSTANT(result_length_tree)
+      && TREE_CONSTANT(result_capacity_tree))
+    TREE_CONSTANT(constructor) = 1;
+
+  return fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(constructor),
+                        build3(COND_EXPR, void_type_node,
+                               bad_index, crash, NULL_TREE),
+                        constructor);
+}
+
+// Make an array index expression.  END may be NULL.
+
+Expression*
+Expression::make_array_index(Expression* array, Expression* start,
+                            Expression* end, source_location location)
+{
+  // Taking a slice of a composite literal requires moving the literal
+  // onto the heap.
+  if (end != NULL && array->is_composite_literal())
+    {
+      array = Expression::make_heap_composite(array, location);
+      array = Expression::make_unary(OPERATOR_MULT, array, location);
+    }
+  return new Array_index_expression(array, start, end, location);
+}
+
+// A string index.  This is used for both indexing and slicing.
+
+class String_index_expression : public Expression
+{
+ public:
+  String_index_expression(Expression* string, Expression* start,
+                         Expression* end, source_location location)
+    : Expression(EXPRESSION_STRING_INDEX, location),
+      string_(string), start_(start), end_(end)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_string_index(this->string_->copy(),
+                                        this->start_->copy(),
+                                        (this->end_ == NULL
+                                         ? NULL
+                                         : this->end_->copy()),
+                                        this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The string we are getting a value from.
+  Expression* string_;
+  // The start or only index.
+  Expression* start_;
+  // The end index of a slice.  This may be NULL for a single index,
+  // or it may be a nil expression for the length of the string.
+  Expression* end_;
+};
+
+// String index traversal.
+
+int
+String_index_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->string_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (this->end_ != NULL)
+    {
+      if (Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Return the type of a string index.
+
+Type*
+String_index_expression::do_type()
+{
+  if (this->end_ == NULL)
+    return Type::lookup_integer_type("uint8");
+  else
+    return Type::make_string_type();
+}
+
+// Determine the type of a string index.
+
+void
+String_index_expression::do_determine_type(const Type_context*)
+{
+  this->string_->determine_type_no_context();
+  Type_context subcontext(NULL, true);
+  this->start_->determine_type(&subcontext);
+  if (this->end_ != NULL)
+    this->end_->determine_type(&subcontext);
+}
+
+// Check types of a string index.
+
+void
+String_index_expression::do_check_types(Gogo*)
+{
+  if (this->start_->type()->integer_type() == NULL)
+    this->report_error(_("index must be integer"));
+  if (this->end_ != NULL
+      && this->end_->type()->integer_type() == NULL
+      && !this->end_->is_nil_expression())
+    this->report_error(_("slice end must be integer"));
+
+  std::string sval;
+  bool sval_valid = this->string_->string_constant_value(&sval);
+
+  mpz_t ival;
+  mpz_init(ival);
+  Type* dummy;
+  if (this->start_->integer_constant_value(true, ival, &dummy))
+    {
+      if (mpz_sgn(ival) < 0
+         || (sval_valid && mpz_cmp_ui(ival, sval.length()) >= 0))
+       {
+         error_at(this->start_->location(), "string index out of bounds");
+         this->set_is_error();
+       }
+    }
+  if (this->end_ != NULL && !this->end_->is_nil_expression())
+    {
+      if (this->end_->integer_constant_value(true, ival, &dummy))
+       {
+         if (mpz_sgn(ival) < 0
+             || (sval_valid && mpz_cmp_ui(ival, sval.length()) > 0))
+           {
+             error_at(this->end_->location(), "string index out of bounds");
+             this->set_is_error();
+           }
+       }
+    }
+  mpz_clear(ival);
+}
+
+// Get a tree for a string index.
+
+tree
+String_index_expression::do_get_tree(Translate_context* context)
+{
+  source_location loc = this->location();
+
+  tree string_tree = this->string_->get_tree(context);
+  if (string_tree == error_mark_node)
+    return error_mark_node;
+
+  if (this->string_->type()->points_to() != NULL)
+    string_tree = build_fold_indirect_ref(string_tree);
+  if (!DECL_P(string_tree))
+    string_tree = save_expr(string_tree);
+  tree string_type = TREE_TYPE(string_tree);
+
+  tree length_tree = String_type::length_tree(context->gogo(), string_tree);
+  length_tree = save_expr(length_tree);
+  tree length_type = TREE_TYPE(length_tree);
+
+  tree bad_index = boolean_false_node;
+
+  tree start_tree = this->start_->get_tree(context);
+  if (start_tree == error_mark_node)
+    return error_mark_node;
+  if (!DECL_P(start_tree))
+    start_tree = save_expr(start_tree);
+  if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree)))
+    start_tree = convert_to_integer(length_type, start_tree);
+
+  bad_index = Expression::check_bounds(start_tree, length_type, bad_index,
+                                      loc);
+
+  start_tree = fold_convert_loc(loc, length_type, start_tree);
+
+  int code = (this->end_ == NULL
+             ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS
+             : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS);
+  tree crash = Gogo::runtime_error(code, loc);
+
+  if (this->end_ == NULL)
+    {
+      bad_index = fold_build2_loc(loc, TRUTH_OR_EXPR, boolean_type_node,
+                                 bad_index,
+                                 fold_build2_loc(loc, GE_EXPR,
+                                                 boolean_type_node,
+                                                 start_tree, length_tree));
+
+      tree bytes_tree = String_type::bytes_tree(context->gogo(), string_tree);
+      tree ptr = fold_build2_loc(loc, POINTER_PLUS_EXPR, TREE_TYPE(bytes_tree),
+                                bytes_tree,
+                                fold_convert_loc(loc, sizetype, start_tree));
+      tree index = build_fold_indirect_ref_loc(loc, ptr);
+
+      return build2(COMPOUND_EXPR, TREE_TYPE(index),
+                   build3(COND_EXPR, void_type_node,
+                          bad_index, crash, NULL_TREE),
+                   index);
+    }
+  else
+    {
+      tree end_tree;
+      if (this->end_->is_nil_expression())
+       end_tree = build_int_cst(length_type, -1);
+      else
+       {
+         end_tree = this->end_->get_tree(context);
+         if (end_tree == error_mark_node)
+           return error_mark_node;
+         if (!DECL_P(end_tree))
+           end_tree = save_expr(end_tree);
+         if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree)))
+           end_tree = convert_to_integer(length_type, end_tree);
+
+         bad_index = Expression::check_bounds(end_tree, length_type,
+                                              bad_index, loc);
+
+         end_tree = fold_convert_loc(loc, length_type, end_tree);
+       }
+
+      static tree strslice_fndecl;
+      tree ret = Gogo::call_builtin(&strslice_fndecl,
+                                   loc,
+                                   "__go_string_slice",
+                                   3,
+                                   string_type,
+                                   string_type,
+                                   string_tree,
+                                   length_type,
+                                   start_tree,
+                                   length_type,
+                                   end_tree);
+      // This will panic if the bounds are out of range for the
+      // string.
+      TREE_NOTHROW(strslice_fndecl) = 0;
+
+      if (bad_index == boolean_false_node)
+       return ret;
+      else
+       return build2(COMPOUND_EXPR, TREE_TYPE(ret),
+                     build3(COND_EXPR, void_type_node,
+                            bad_index, crash, NULL_TREE),
+                     ret);
+    }
+}
+
+// Make a string index expression.  END may be NULL.
+
+Expression*
+Expression::make_string_index(Expression* string, Expression* start,
+                             Expression* end, source_location location)
+{
+  return new String_index_expression(string, start, end, location);
+}
+
+// Class Map_index.
+
+// Get the type of the map.
+
+Map_type*
+Map_index_expression::get_map_type() const
+{
+  Map_type* mt = this->map_->type()->deref()->map_type();
+  gcc_assert(mt != NULL);
+  return mt;
+}
+
+// Map index traversal.
+
+int
+Map_index_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->map_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return Expression::traverse(&this->index_, traverse);
+}
+
+// Return the type of a map index.
+
+Type*
+Map_index_expression::do_type()
+{
+  Type* type = this->get_map_type()->val_type();
+  // If this map index is in a tuple assignment, we actually return a
+  // pointer to the value type.  Tuple_map_assignment_statement is
+  // responsible for handling this correctly.  We need to get the type
+  // right in case this gets assigned to a temporary variable.
+  if (this->is_in_tuple_assignment_)
+    type = Type::make_pointer_type(type);
+  return type;
+}
+
+// Fix the type of a map index.
+
+void
+Map_index_expression::do_determine_type(const Type_context*)
+{
+  this->map_->determine_type_no_context();
+  Type_context subcontext(this->get_map_type()->key_type(), false);
+  this->index_->determine_type(&subcontext);
+}
+
+// Check types of a map index.
+
+void
+Map_index_expression::do_check_types(Gogo*)
+{
+  std::string reason;
+  if (!Type::are_assignable(this->get_map_type()->key_type(),
+                           this->index_->type(), &reason))
+    {
+      if (reason.empty())
+       this->report_error(_("incompatible type for map index"));
+      else
+       {
+         error_at(this->location(), "incompatible type for map index (%s)",
+                  reason.c_str());
+         this->set_is_error();
+       }
+    }
+}
+
+// Get a tree for a map index.
+
+tree
+Map_index_expression::do_get_tree(Translate_context* context)
+{
+  Map_type* type = this->get_map_type();
+
+  tree valptr = this->get_value_pointer(context, this->is_lvalue_);
+  if (valptr == error_mark_node)
+    return error_mark_node;
+  valptr = save_expr(valptr);
+
+  tree val_type_tree = TREE_TYPE(TREE_TYPE(valptr));
+
+  if (this->is_lvalue_)
+    return build_fold_indirect_ref(valptr);
+  else if (this->is_in_tuple_assignment_)
+    {
+      // Tuple_map_assignment_statement is responsible for using this
+      // appropriately.
+      return valptr;
+    }
+  else
+    {
+      return fold_build3(COND_EXPR, val_type_tree,
+                        fold_build2(EQ_EXPR, boolean_type_node, valptr,
+                                    fold_convert(TREE_TYPE(valptr),
+                                                 null_pointer_node)),
+                        type->val_type()->get_init_tree(context->gogo(),
+                                                        false),
+                        build_fold_indirect_ref(valptr));
+    }
+}
+
+// Get a tree for the map index.  This returns a tree which evaluates
+// to a pointer to a value.  The pointer will be NULL if the key is
+// not in the map.
+
+tree
+Map_index_expression::get_value_pointer(Translate_context* context,
+                                       bool insert)
+{
+  Map_type* type = this->get_map_type();
+
+  tree map_tree = this->map_->get_tree(context);
+  tree index_tree = this->index_->get_tree(context);
+  index_tree = Expression::convert_for_assignment(context, type->key_type(),
+                                                 this->index_->type(),
+                                                 index_tree,
+                                                 this->location());
+  if (map_tree == error_mark_node || index_tree == error_mark_node)
+    return error_mark_node;
+
+  if (this->map_->type()->points_to() != NULL)
+    map_tree = build_fold_indirect_ref(map_tree);
+
+  // We need to pass in a pointer to the key, so stuff it into a
+  // variable.
+  tree tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree));
+  DECL_IGNORED_P(tmp) = 0;
+  DECL_INITIAL(tmp) = index_tree;
+  tree make_tmp = build1(DECL_EXPR, void_type_node, tmp);
+  tree tmpref = fold_convert(const_ptr_type_node, build_fold_addr_expr(tmp));
+  TREE_ADDRESSABLE(tmp) = 1;
+
+  static tree map_index_fndecl;
+  tree call = Gogo::call_builtin(&map_index_fndecl,
+                                this->location(),
+                                "__go_map_index",
+                                3,
+                                const_ptr_type_node,
+                                TREE_TYPE(map_tree),
+                                map_tree,
+                                const_ptr_type_node,
+                                tmpref,
+                                boolean_type_node,
+                                (insert
+                                 ? boolean_true_node
+                                 : boolean_false_node));
+  // This can panic on a map of interface type if the interface holds
+  // an uncomparable or unhashable type.
+  TREE_NOTHROW(map_index_fndecl) = 0;
+
+  tree val_type_tree = type->val_type()->get_tree(context->gogo());
+  if (val_type_tree == error_mark_node)
+    return error_mark_node;
+  tree ptr_val_type_tree = build_pointer_type(val_type_tree);
+
+  return build2(COMPOUND_EXPR, ptr_val_type_tree,
+               make_tmp,
+               fold_convert(ptr_val_type_tree, call));
+}
+
+// Make a map index expression.
+
+Map_index_expression*
+Expression::make_map_index(Expression* map, Expression* index,
+                          source_location location)
+{
+  return new Map_index_expression(map, index, location);
+}
+
+// Class Field_reference_expression.
+
+// Return the type of a field reference.
+
+Type*
+Field_reference_expression::do_type()
+{
+  Struct_type* struct_type = this->expr_->type()->struct_type();
+  gcc_assert(struct_type != NULL);
+  return struct_type->field(this->field_index_)->type();
+}
+
+// Check the types for a field reference.
+
+void
+Field_reference_expression::do_check_types(Gogo*)
+{
+  Struct_type* struct_type = this->expr_->type()->struct_type();
+  gcc_assert(struct_type != NULL);
+  gcc_assert(struct_type->field(this->field_index_) != NULL);
+}
+
+// Get a tree for a field reference.
+
+tree
+Field_reference_expression::do_get_tree(Translate_context* context)
+{
+  tree struct_tree = this->expr_->get_tree(context);
+  if (struct_tree == error_mark_node
+      || TREE_TYPE(struct_tree) == error_mark_node)
+    return error_mark_node;
+  gcc_assert(TREE_CODE(TREE_TYPE(struct_tree)) == RECORD_TYPE);
+  tree field = TYPE_FIELDS(TREE_TYPE(struct_tree));
+  gcc_assert(field != NULL_TREE);
+  for (unsigned int i = this->field_index_; i > 0; --i)
+    {
+      field = DECL_CHAIN(field);
+      gcc_assert(field != NULL_TREE);
+    }
+  return build3(COMPONENT_REF, TREE_TYPE(field), struct_tree, field,
+               NULL_TREE);
+}
+
+// Make a reference to a qualified identifier in an expression.
+
+Field_reference_expression*
+Expression::make_field_reference(Expression* expr, unsigned int field_index,
+                                source_location location)
+{
+  return new Field_reference_expression(expr, field_index, location);
+}
+
+// Class Interface_field_reference_expression.
+
+// Return a tree for the pointer to the function to call.
+
+tree
+Interface_field_reference_expression::get_function_tree(Translate_context*,
+                                                       tree expr)
+{
+  if (this->expr_->type()->points_to() != NULL)
+    expr = build_fold_indirect_ref(expr);
+
+  tree expr_type = TREE_TYPE(expr);
+  gcc_assert(TREE_CODE(expr_type) == RECORD_TYPE);
+
+  tree field = TYPE_FIELDS(expr_type);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0);
+
+  tree table = build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
+  gcc_assert(POINTER_TYPE_P(TREE_TYPE(table)));
+
+  table = build_fold_indirect_ref(table);
+  gcc_assert(TREE_CODE(TREE_TYPE(table)) == RECORD_TYPE);
+
+  std::string name = Gogo::unpack_hidden_name(this->name_);
+  for (field = DECL_CHAIN(TYPE_FIELDS(TREE_TYPE(table)));
+       field != NULL_TREE;
+       field = DECL_CHAIN(field))
+    {
+      if (name == IDENTIFIER_POINTER(DECL_NAME(field)))
+       break;
+    }
+  gcc_assert(field != NULL_TREE);
+
+  return build3(COMPONENT_REF, TREE_TYPE(field), table, field, NULL_TREE);
+}
+
+// Return a tree for the first argument to pass to the interface
+// function.
+
+tree
+Interface_field_reference_expression::get_underlying_object_tree(
+    Translate_context*,
+    tree expr)
+{
+  if (this->expr_->type()->points_to() != NULL)
+    expr = build_fold_indirect_ref(expr);
+
+  tree expr_type = TREE_TYPE(expr);
+  gcc_assert(TREE_CODE(expr_type) == RECORD_TYPE);
+
+  tree field = DECL_CHAIN(TYPE_FIELDS(expr_type));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
+
+  return build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
+}
+
+// Traversal.
+
+int
+Interface_field_reference_expression::do_traverse(Traverse* traverse)
+{
+  return Expression::traverse(&this->expr_, traverse);
+}
+
+// Return the type of an interface field reference.
+
+Type*
+Interface_field_reference_expression::do_type()
+{
+  Type* expr_type = this->expr_->type();
+
+  Type* points_to = expr_type->points_to();
+  if (points_to != NULL)
+    expr_type = points_to;
+
+  Interface_type* interface_type = expr_type->interface_type();
+  if (interface_type == NULL)
+    return Type::make_error_type();
+
+  const Typed_identifier* method = interface_type->find_method(this->name_);
+  if (method == NULL)
+    return Type::make_error_type();
+
+  return method->type();
+}
+
+// Determine types.
+
+void
+Interface_field_reference_expression::do_determine_type(const Type_context*)
+{
+  this->expr_->determine_type_no_context();
+}
+
+// Check the types for an interface field reference.
+
+void
+Interface_field_reference_expression::do_check_types(Gogo*)
+{
+  Type* type = this->expr_->type();
+
+  Type* points_to = type->points_to();
+  if (points_to != NULL)
+    type = points_to;
+
+  Interface_type* interface_type = type->interface_type();
+  if (interface_type == NULL)
+    this->report_error(_("expected interface or pointer to interface"));
+  else
+    {
+      const Typed_identifier* method =
+       interface_type->find_method(this->name_);
+      if (method == NULL)
+       {
+         error_at(this->location(), "method %qs not in interface",
+                  Gogo::message_name(this->name_).c_str());
+         this->set_is_error();
+       }
+    }
+}
+
+// Get a tree for a reference to a field in an interface.  There is no
+// standard tree type representation for this: it's a function
+// attached to its first argument, like a Bound_method_expression.
+// The only places it may currently be used are in a Call_expression
+// or a Go_statement, which will take it apart directly.  So this has
+// nothing to do at present.
+
+tree
+Interface_field_reference_expression::do_get_tree(Translate_context*)
+{
+  gcc_unreachable();
+}
+
+// Make a reference to a field in an interface.
+
+Expression*
+Expression::make_interface_field_reference(Expression* expr,
+                                          const std::string& field,
+                                          source_location location)
+{
+  return new Interface_field_reference_expression(expr, field, location);
+}
+
+// A general selector.  This is a Parser_expression for LEFT.NAME.  It
+// is lowered after we know the type of the left hand side.
+
+class Selector_expression : public Parser_expression
+{
+ public:
+  Selector_expression(Expression* left, const std::string& name,
+                     source_location location)
+    : Parser_expression(EXPRESSION_SELECTOR, location),
+      left_(left), name_(name)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Expression::traverse(&this->left_, traverse); }
+
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  Expression*
+  do_copy()
+  {
+    return new Selector_expression(this->left_->copy(), this->name_,
+                                  this->location());
+  }
+
+ private:
+  Expression*
+  lower_method_expression(Gogo*);
+
+  // The expression on the left hand side.
+  Expression* left_;
+  // The name on the right hand side.
+  std::string name_;
+};
+
+// Lower a selector expression once we know the real type of the left
+// hand side.
+
+Expression*
+Selector_expression::do_lower(Gogo* gogo, Named_object*, int)
+{
+  Expression* left = this->left_;
+  if (left->is_type_expression())
+    return this->lower_method_expression(gogo);
+  return Type::bind_field_or_method(gogo, left->type(), left, this->name_,
+                                   this->location());
+}
+
+// Lower a method expression T.M or (*T).M.  We turn this into a
+// function literal.
+
+Expression*
+Selector_expression::lower_method_expression(Gogo* gogo)
+{
+  source_location location = this->location();
+  Type* type = this->left_->type();
+  const std::string& name(this->name_);
+
+  bool is_pointer;
+  if (type->points_to() == NULL)
+    is_pointer = false;
+  else
+    {
+      is_pointer = true;
+      type = type->points_to();
+    }
+  Named_type* nt = type->named_type();
+  if (nt == NULL)
+    {
+      error_at(location,
+              ("method expression requires named type or "
+               "pointer to named type"));
+      return Expression::make_error(location);
+    }
+
+  bool is_ambiguous;
+  Method* method = nt->method_function(name, &is_ambiguous);
+  if (method == NULL)
+    {
+      if (!is_ambiguous)
+       error_at(location, "type %<%s%> has no method %<%s%>",
+                nt->message_name().c_str(),
+                Gogo::message_name(name).c_str());
+      else
+       error_at(location, "method %<%s%> is ambiguous in type %<%s%>",
+                Gogo::message_name(name).c_str(),
+                nt->message_name().c_str());
+      return Expression::make_error(location);
+    }
+
+  if (!is_pointer && !method->is_value_method())
+    {
+      error_at(location, "method requires pointer (use %<(*%s).%s)%>",
+              nt->message_name().c_str(),
+              Gogo::message_name(name).c_str());
+      return Expression::make_error(location);
+    }
+
+  // Build a new function type in which the receiver becomes the first
+  // argument.
+  Function_type* method_type = method->type();
+  gcc_assert(method_type->is_method());
+
+  const char* const receiver_name = "$this";
+  Typed_identifier_list* parameters = new Typed_identifier_list();
+  parameters->push_back(Typed_identifier(receiver_name, this->left_->type(),
+                                        location));
+
+  const Typed_identifier_list* method_parameters = method_type->parameters();
+  if (method_parameters != NULL)
+    {
+      for (Typed_identifier_list::const_iterator p = method_parameters->begin();
+          p != method_parameters->end();
+          ++p)
+       parameters->push_back(*p);
+    }
+
+  const Typed_identifier_list* method_results = method_type->results();
+  Typed_identifier_list* results;
+  if (method_results == NULL)
+    results = NULL;
+  else
+    {
+      results = new Typed_identifier_list();
+      for (Typed_identifier_list::const_iterator p = method_results->begin();
+          p != method_results->end();
+          ++p)
+       results->push_back(*p);
+    }
+  
+  Function_type* fntype = Type::make_function_type(NULL, parameters, results,
+                                                  location);
+  if (method_type->is_varargs())
+    fntype->set_is_varargs();
+
+  // We generate methods which always takes a pointer to the receiver
+  // as their first argument.  If this is for a pointer type, we can
+  // simply reuse the existing function.  We use an internal hack to
+  // get the right type.
+
+  if (is_pointer)
+    {
+      Named_object* mno = (method->needs_stub_method()
+                          ? method->stub_object()
+                          : method->named_object());
+      Expression* f = Expression::make_func_reference(mno, NULL, location);
+      f = Expression::make_cast(fntype, f, location);
+      Type_conversion_expression* tce =
+       static_cast<Type_conversion_expression*>(f);
+      tce->set_may_convert_function_types();
+      return f;
+    }
+
+  Named_object* no = gogo->start_function(Gogo::thunk_name(), fntype, false,
+                                         location);
+
+  Named_object* vno = gogo->lookup(receiver_name, NULL);
+  gcc_assert(vno != NULL);
+  Expression* ve = Expression::make_var_reference(vno, location);
+  Expression* bm = Type::bind_field_or_method(gogo, nt, ve, name, location);
+  gcc_assert(bm != NULL && !bm->is_error_expression());
+
+  Expression_list* args;
+  if (method_parameters == NULL)
+    args = NULL;
+  else
+    {
+      args = new Expression_list();
+      for (Typed_identifier_list::const_iterator p = method_parameters->begin();
+          p != method_parameters->end();
+          ++p)
+       {
+         vno = gogo->lookup(p->name(), NULL);
+         gcc_assert(vno != NULL);
+         args->push_back(Expression::make_var_reference(vno, location));
+       }
+    }
+
+  Call_expression* call = Expression::make_call(bm, args,
+                                               method_type->is_varargs(),
+                                               location);
+
+  size_t count = call->result_count();
+  Statement* s;
+  if (count == 0)
+    s = Statement::make_statement(call);
+  else
+    {
+      Expression_list* retvals = new Expression_list();
+      if (count <= 1)
+       retvals->push_back(call);
+      else
+       {
+         for (size_t i = 0; i < count; ++i)
+           retvals->push_back(Expression::make_call_result(call, i));
+       }
+      s = Statement::make_return_statement(no->func_value()->type()->results(),
+                                          retvals, location);
+    }
+  gogo->add_statement(s);
+
+  gogo->finish_function(location);
+
+  return Expression::make_func_reference(no, NULL, location);
+}
+
+// Make a selector expression.
+
+Expression*
+Expression::make_selector(Expression* left, const std::string& name,
+                         source_location location)
+{
+  return new Selector_expression(left, name, location);
+}
+
+// Implement the builtin function new.
+
+class Allocation_expression : public Expression
+{
+ public:
+  Allocation_expression(Type* type, source_location location)
+    : Expression(EXPRESSION_ALLOCATION, location),
+      type_(type)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Type::traverse(this->type_, traverse); }
+
+  Type*
+  do_type()
+  { return Type::make_pointer_type(this->type_); }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  { return new Allocation_expression(this->type_, this->location()); }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The type we are allocating.
+  Type* type_;
+};
+
+// Check the type of an allocation expression.
+
+void
+Allocation_expression::do_check_types(Gogo*)
+{
+  if (this->type_->function_type() != NULL)
+    this->report_error(_("invalid new of function type"));
+}
+
+// Return a tree for an allocation expression.
+
+tree
+Allocation_expression::do_get_tree(Translate_context* context)
+{
+  tree type_tree = this->type_->get_tree(context->gogo());
+  tree size_tree = TYPE_SIZE_UNIT(type_tree);
+  tree space = context->gogo()->allocate_memory(this->type_, size_tree,
+                                               this->location());
+  return fold_convert(build_pointer_type(type_tree), space);
+}
+
+// Make an allocation expression.
+
+Expression*
+Expression::make_allocation(Type* type, source_location location)
+{
+  return new Allocation_expression(type, location);
+}
+
+// Implement the builtin function make.
+
+class Make_expression : public Expression
+{
+ public:
+  Make_expression(Type* type, Expression_list* args, source_location location)
+    : Expression(EXPRESSION_MAKE, location),
+      type_(type), args_(args)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return new Make_expression(this->type_, this->args_->copy(),
+                              this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The type we are making.
+  Type* type_;
+  // The arguments to pass to the make routine.
+  Expression_list* args_;
+};
+
+// Traversal.
+
+int
+Make_expression::do_traverse(Traverse* traverse)
+{
+  if (this->args_ != NULL
+      && this->args_->traverse(traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Set types of arguments.
+
+void
+Make_expression::do_determine_type(const Type_context*)
+{
+  if (this->args_ != NULL)
+    {
+      Type_context context(Type::lookup_integer_type("int"), false);
+      for (Expression_list::const_iterator pe = this->args_->begin();
+          pe != this->args_->end();
+          ++pe)
+       (*pe)->determine_type(&context);
+    }
+}
+
+// Check types for a make expression.
+
+void
+Make_expression::do_check_types(Gogo*)
+{
+  if (this->type_->channel_type() == NULL
+      && this->type_->map_type() == NULL
+      && (this->type_->array_type() == NULL
+         || this->type_->array_type()->length() != NULL))
+    this->report_error(_("invalid type for make function"));
+  else if (!this->type_->check_make_expression(this->args_, this->location()))
+    this->set_is_error();
+}
+
+// Return a tree for a make expression.
+
+tree
+Make_expression::do_get_tree(Translate_context* context)
+{
+  return this->type_->make_expression_tree(context, this->args_,
+                                          this->location());
+}
+
+// Make a make expression.
+
+Expression*
+Expression::make_make(Type* type, Expression_list* args,
+                     source_location location)
+{
+  return new Make_expression(type, args, location);
+}
+
+// Construct a struct.
+
+class Struct_construction_expression : public Expression
+{
+ public:
+  Struct_construction_expression(Type* type, Expression_list* vals,
+                                source_location location)
+    : Expression(EXPRESSION_STRUCT_CONSTRUCTION, location),
+      type_(type), vals_(vals)
+  { }
+
+  // Return whether this is a constant initializer.
+  bool
+  is_constant_struct() const;
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return new Struct_construction_expression(this->type_, this->vals_->copy(),
+                                             this->location());
+  }
+
+  bool
+  do_is_addressable() const
+  { return true; }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // The type of the struct to construct.
+  Type* type_;
+  // The list of values, in order of the fields in the struct.  A NULL
+  // entry means that the field should be zero-initialized.
+  Expression_list* vals_;
+};
+
+// Traversal.
+
+int
+Struct_construction_expression::do_traverse(Traverse* traverse)
+{
+  if (this->vals_ != NULL
+      && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Return whether this is a constant initializer.
+
+bool
+Struct_construction_expression::is_constant_struct() const
+{
+  if (this->vals_ == NULL)
+    return true;
+  for (Expression_list::const_iterator pv = this->vals_->begin();
+       pv != this->vals_->end();
+       ++pv)
+    {
+      if (*pv != NULL
+         && !(*pv)->is_constant()
+         && (!(*pv)->is_composite_literal()
+             || (*pv)->is_nonconstant_composite_literal()))
+       return false;
+    }
+
+  const Struct_field_list* fields = this->type_->struct_type()->fields();
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf)
+    {
+      // There are no constant constructors for interfaces.
+      if (pf->type()->interface_type() != NULL)
+       return false;
+    }
+
+  return true;
+}
+
+// Final type determination.
+
+void
+Struct_construction_expression::do_determine_type(const Type_context*)
+{
+  if (this->vals_ == NULL)
+    return;
+  const Struct_field_list* fields = this->type_->struct_type()->fields();
+  Expression_list::const_iterator pv = this->vals_->begin();
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf, ++pv)
+    {
+      if (pv == this->vals_->end())
+       return;
+      if (*pv != NULL)
+       {
+         Type_context subcontext(pf->type(), false);
+         (*pv)->determine_type(&subcontext);
+       }
+    }
+}
+
+// Check types.
+
+void
+Struct_construction_expression::do_check_types(Gogo*)
+{
+  if (this->vals_ == NULL)
+    return;
+
+  Struct_type* st = this->type_->struct_type();
+  if (this->vals_->size() > st->field_count())
+    {
+      this->report_error(_("too many expressions for struct"));
+      return;
+    }
+
+  const Struct_field_list* fields = st->fields();
+  Expression_list::const_iterator pv = this->vals_->begin();
+  int i = 0;
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf, ++pv, ++i)
+    {
+      if (pv == this->vals_->end())
+       {
+         this->report_error(_("too few expressions for struct"));
+         break;
+       }
+
+      if (*pv == NULL)
+       continue;
+
+      std::string reason;
+      if (!Type::are_assignable(pf->type(), (*pv)->type(), &reason))
+       {
+         if (reason.empty())
+           error_at((*pv)->location(),
+                    "incompatible type for field %d in struct construction",
+                    i + 1);
+         else
+           error_at((*pv)->location(),
+                    ("incompatible type for field %d in "
+                     "struct construction (%s)"),
+                    i + 1, reason.c_str());
+         this->set_is_error();
+       }
+    }
+  gcc_assert(pv == this->vals_->end());
+}
+
+// Return a tree for constructing a struct.
+
+tree
+Struct_construction_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+
+  if (this->vals_ == NULL)
+    return this->type_->get_init_tree(gogo, false);
+
+  tree type_tree = this->type_->get_tree(gogo);
+  if (type_tree == error_mark_node)
+    return error_mark_node;
+  gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE);
+
+  bool is_constant = true;
+  const Struct_field_list* fields = this->type_->struct_type()->fields();
+  VEC(constructor_elt,gc)* elts = VEC_alloc(constructor_elt, gc,
+                                           fields->size());
+  Struct_field_list::const_iterator pf = fields->begin();
+  Expression_list::const_iterator pv = this->vals_->begin();
+  for (tree field = TYPE_FIELDS(type_tree);
+       field != NULL_TREE;
+       field = DECL_CHAIN(field), ++pf)
+    {
+      gcc_assert(pf != fields->end());
+
+      tree val;
+      if (pv == this->vals_->end())
+       val = pf->type()->get_init_tree(gogo, false);
+      else if (*pv == NULL)
+       {
+         val = pf->type()->get_init_tree(gogo, false);
+         ++pv;
+       }
+      else
+       {
+         val = Expression::convert_for_assignment(context, pf->type(),
+                                                  (*pv)->type(),
+                                                  (*pv)->get_tree(context),
+                                                  this->location());
+         ++pv;
+       }
+
+      if (val == error_mark_node || TREE_TYPE(val) == error_mark_node)
+       return error_mark_node;
+
+      constructor_elt* elt = VEC_quick_push(constructor_elt, elts, NULL);
+      elt->index = field;
+      elt->value = val;
+      if (!TREE_CONSTANT(val))
+       is_constant = false;
+    }
+  gcc_assert(pf == fields->end());
+
+  tree ret = build_constructor(type_tree, elts);
+  if (is_constant)
+    TREE_CONSTANT(ret) = 1;
+  return ret;
+}
+
+// Export a struct construction.
+
+void
+Struct_construction_expression::do_export(Export* exp) const
+{
+  exp->write_c_string("convert(");
+  exp->write_type(this->type_);
+  for (Expression_list::const_iterator pv = this->vals_->begin();
+       pv != this->vals_->end();
+       ++pv)
+    {
+      exp->write_c_string(", ");
+      if (*pv != NULL)
+       (*pv)->export_expression(exp);
+    }
+  exp->write_c_string(")");
+}
+
+// Make a struct composite literal.  This used by the thunk code.
+
+Expression*
+Expression::make_struct_composite_literal(Type* type, Expression_list* vals,
+                                         source_location location)
+{
+  gcc_assert(type->struct_type() != NULL);
+  return new Struct_construction_expression(type, vals, location);
+}
+
+// Construct an array.  This class is not used directly; instead we
+// use the child classes, Fixed_array_construction_expression and
+// Open_array_construction_expression.
+
+class Array_construction_expression : public Expression
+{
+ protected:
+  Array_construction_expression(Expression_classification classification,
+                               Type* type, Expression_list* vals,
+                               source_location location)
+    : Expression(classification, location),
+      type_(type), vals_(vals)
+  { }
+
+ public:
+  // Return whether this is a constant initializer.
+  bool
+  is_constant_array() const;
+
+  // Return the number of elements.
+  size_t
+  element_count() const
+  { return this->vals_ == NULL ? 0 : this->vals_->size(); }
+
+protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  bool
+  do_is_addressable() const
+  { return true; }
+
+  void
+  do_export(Export*) const;
+
+  // The list of values.
+  Expression_list*
+  vals()
+  { return this->vals_; }
+
+  // Get a constructor tree for the array values.
+  tree
+  get_constructor_tree(Translate_context* context, tree type_tree);
+
+ private:
+  // The type of the array to construct.
+  Type* type_;
+  // The list of values.
+  Expression_list* vals_;
+};
+
+// Traversal.
+
+int
+Array_construction_expression::do_traverse(Traverse* traverse)
+{
+  if (this->vals_ != NULL
+      && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Return whether this is a constant initializer.
+
+bool
+Array_construction_expression::is_constant_array() const
+{
+  if (this->vals_ == NULL)
+    return true;
+
+  // There are no constant constructors for interfaces.
+  if (this->type_->array_type()->element_type()->interface_type() != NULL)
+    return false;
+
+  for (Expression_list::const_iterator pv = this->vals_->begin();
+       pv != this->vals_->end();
+       ++pv)
+    {
+      if (*pv != NULL
+         && !(*pv)->is_constant()
+         && (!(*pv)->is_composite_literal()
+             || (*pv)->is_nonconstant_composite_literal()))
+       return false;
+    }
+  return true;
+}
+
+// Final type determination.
+
+void
+Array_construction_expression::do_determine_type(const Type_context*)
+{
+  if (this->vals_ == NULL)
+    return;
+  Type_context subcontext(this->type_->array_type()->element_type(), false);
+  for (Expression_list::const_iterator pv = this->vals_->begin();
+       pv != this->vals_->end();
+       ++pv)
+    {
+      if (*pv != NULL)
+       (*pv)->determine_type(&subcontext);
+    }
+}
+
+// Check types.
+
+void
+Array_construction_expression::do_check_types(Gogo*)
+{
+  if (this->vals_ == NULL)
+    return;
+
+  Array_type* at = this->type_->array_type();
+  int i = 0;
+  Type* element_type = at->element_type();
+  for (Expression_list::const_iterator pv = this->vals_->begin();
+       pv != this->vals_->end();
+       ++pv, ++i)
+    {
+      if (*pv != NULL
+         && !Type::are_assignable(element_type, (*pv)->type(), NULL))
+       {
+         error_at((*pv)->location(),
+                  "incompatible type for element %d in composite literal",
+                  i + 1);
+         this->set_is_error();
+       }
+    }
+
+  Expression* length = at->length();
+  if (length != NULL)
+    {
+      mpz_t val;
+      mpz_init(val);
+      Type* type;
+      if (at->length()->integer_constant_value(true, val, &type))
+       {
+         if (this->vals_->size() > mpz_get_ui(val))
+           this->report_error(_("too many elements in composite literal"));
+       }
+      mpz_clear(val);
+    }
+}
+
+// Get a constructor tree for the array values.
+
+tree
+Array_construction_expression::get_constructor_tree(Translate_context* context,
+                                                   tree type_tree)
+{
+  VEC(constructor_elt,gc)* values = VEC_alloc(constructor_elt, gc,
+                                             (this->vals_ == NULL
+                                              ? 0
+                                              : this->vals_->size()));
+  Type* element_type = this->type_->array_type()->element_type();
+  bool is_constant = true;
+  if (this->vals_ != NULL)
+    {
+      size_t i = 0;
+      for (Expression_list::const_iterator pv = this->vals_->begin();
+          pv != this->vals_->end();
+          ++pv, ++i)
+       {
+         constructor_elt* elt = VEC_quick_push(constructor_elt, values, NULL);
+         elt->index = size_int(i);
+         if (*pv == NULL)
+           elt->value = element_type->get_init_tree(context->gogo(), false);
+         else
+           {
+             tree value_tree = (*pv)->get_tree(context);
+             elt->value = Expression::convert_for_assignment(context,
+                                                             element_type,
+                                                             (*pv)->type(),
+                                                             value_tree,
+                                                             this->location());
+           }
+         if (elt->value == error_mark_node)
+           return error_mark_node;
+         if (!TREE_CONSTANT(elt->value))
+           is_constant = false;
+       }
+    }
+
+  tree ret = build_constructor(type_tree, values);
+  if (is_constant)
+    TREE_CONSTANT(ret) = 1;
+  return ret;
+}
+
+// Export an array construction.
+
+void
+Array_construction_expression::do_export(Export* exp) const
+{
+  exp->write_c_string("convert(");
+  exp->write_type(this->type_);
+  if (this->vals_ != NULL)
+    {
+      for (Expression_list::const_iterator pv = this->vals_->begin();
+          pv != this->vals_->end();
+          ++pv)
+       {
+         exp->write_c_string(", ");
+         if (*pv != NULL)
+           (*pv)->export_expression(exp);
+       }
+    }
+  exp->write_c_string(")");
+}
+
+// Construct a fixed array.
+
+class Fixed_array_construction_expression :
+  public Array_construction_expression
+{
+ public:
+  Fixed_array_construction_expression(Type* type, Expression_list* vals,
+                                     source_location location)
+    : Array_construction_expression(EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
+                                   type, vals, location)
+  {
+    gcc_assert(type->array_type() != NULL
+              && type->array_type()->length() != NULL);
+  }
+
+ protected:
+  Expression*
+  do_copy()
+  {
+    return new Fixed_array_construction_expression(this->type(),
+                                                  (this->vals() == NULL
+                                                   ? NULL
+                                                   : this->vals()->copy()),
+                                                  this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+};
+
+// Return a tree for constructing a fixed array.
+
+tree
+Fixed_array_construction_expression::do_get_tree(Translate_context* context)
+{
+  return this->get_constructor_tree(context,
+                                   this->type()->get_tree(context->gogo()));
+}
+
+// Construct an open array.
+
+class Open_array_construction_expression : public Array_construction_expression
+{
+ public:
+  Open_array_construction_expression(Type* type, Expression_list* vals,
+                                    source_location location)
+    : Array_construction_expression(EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
+                                   type, vals, location)
+  {
+    gcc_assert(type->array_type() != NULL
+              && type->array_type()->length() == NULL);
+  }
+
+ protected:
+  // Note that taking the address of an open array literal is invalid.
+
+  Expression*
+  do_copy()
+  {
+    return new Open_array_construction_expression(this->type(),
+                                                 (this->vals() == NULL
+                                                  ? NULL
+                                                  : this->vals()->copy()),
+                                                 this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+};
+
+// Return a tree for constructing an open array.
+
+tree
+Open_array_construction_expression::do_get_tree(Translate_context* context)
+{
+  Type* element_type = this->type()->array_type()->element_type();
+  tree element_type_tree = element_type->get_tree(context->gogo());
+  tree values;
+  tree length_tree;
+  if (this->vals() == NULL || this->vals()->empty())
+    {
+      // We need to create a unique value.
+      tree max = size_int(0);
+      tree constructor_type = build_array_type(element_type_tree,
+                                              build_index_type(max));
+      if (constructor_type == error_mark_node)
+       return error_mark_node;
+      VEC(constructor_elt,gc)* vec = VEC_alloc(constructor_elt, gc, 1);
+      constructor_elt* elt = VEC_quick_push(constructor_elt, vec, NULL);
+      elt->index = size_int(0);
+      elt->value = element_type->get_init_tree(context->gogo(), false);
+      values = build_constructor(constructor_type, vec);
+      if (TREE_CONSTANT(elt->value))
+       TREE_CONSTANT(values) = 1;
+      length_tree = size_int(0);
+    }
+  else
+    {
+      tree max = size_int(this->vals()->size() - 1);
+      tree constructor_type = build_array_type(element_type_tree,
+                                              build_index_type(max));
+      if (constructor_type == error_mark_node)
+       return error_mark_node;
+      values = this->get_constructor_tree(context, constructor_type);
+      length_tree = size_int(this->vals()->size());
+    }
+
+  if (values == error_mark_node)
+    return error_mark_node;
+
+  bool is_constant_initializer = TREE_CONSTANT(values);
+  bool is_in_function = context->function() != NULL;
+
+  if (is_constant_initializer)
+    {
+      tree tmp = build_decl(this->location(), VAR_DECL,
+                           create_tmp_var_name("C"), TREE_TYPE(values));
+      DECL_EXTERNAL(tmp) = 0;
+      TREE_PUBLIC(tmp) = 0;
+      TREE_STATIC(tmp) = 1;
+      DECL_ARTIFICIAL(tmp) = 1;
+      if (is_in_function)
+       {
+         // If this is not a function, we will only initialize the
+         // value once, so we can use this directly rather than
+         // copying it.  In that case we can't make it read-only,
+         // because the program is permitted to change it.
+         TREE_READONLY(tmp) = 1;
+         TREE_CONSTANT(tmp) = 1;
+       }
+      DECL_INITIAL(tmp) = values;
+      rest_of_decl_compilation(tmp, 1, 0);
+      values = tmp;
+    }
+
+  tree space;
+  tree set;
+  if (!is_in_function && is_constant_initializer)
+    {
+      // Outside of a function, we know the initializer will only run
+      // once.
+      space = build_fold_addr_expr(values);
+      set = NULL_TREE;
+    }
+  else
+    {
+      tree memsize = TYPE_SIZE_UNIT(TREE_TYPE(values));
+      space = context->gogo()->allocate_memory(element_type, memsize,
+                                              this->location());
+      space = save_expr(space);
+
+      tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
+      tree ref = build_fold_indirect_ref_loc(this->location(), s);
+      TREE_THIS_NOTRAP(ref) = 1;
+      set = build2(MODIFY_EXPR, void_type_node, ref, values);
+    }
+
+  // Build a constructor for the open array.
+
+  tree type_tree = this->type()->get_tree(context->gogo());
+  gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE);
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 3);
+
+  constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+  tree field = TYPE_FIELDS(type_tree);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
+  elt->index = field;
+  elt->value = fold_convert(TREE_TYPE(field), space);
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = DECL_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
+  elt->index = field;
+  elt->value = fold_convert(TREE_TYPE(field), length_tree);
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = DECL_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),"__capacity") == 0);
+  elt->index = field;
+  elt->value = fold_convert(TREE_TYPE(field), length_tree);
+
+  tree constructor = build_constructor(type_tree, init);
+  if (!is_in_function && is_constant_initializer)
+    TREE_CONSTANT(constructor) = 1;
+
+  if (set == NULL_TREE)
+    return constructor;
+  else
+    return build2(COMPOUND_EXPR, type_tree, set, constructor);
+}
+
+// Make a slice composite literal.  This is used by the type
+// descriptor code.
+
+Expression*
+Expression::make_slice_composite_literal(Type* type, Expression_list* vals,
+                                        source_location location)
+{
+  gcc_assert(type->is_open_array_type());
+  return new Open_array_construction_expression(type, vals, location);
+}
+
+// Construct a map.
+
+class Map_construction_expression : public Expression
+{
+ public:
+  Map_construction_expression(Type* type, Expression_list* vals,
+                             source_location location)
+    : Expression(EXPRESSION_MAP_CONSTRUCTION, location),
+      type_(type), vals_(vals)
+  { gcc_assert(vals == NULL || vals->size() % 2 == 0); }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return new Map_construction_expression(this->type_, this->vals_->copy(),
+                                          this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // The type of the map to construct.
+  Type* type_;
+  // The list of values.
+  Expression_list* vals_;
+};
+
+// Traversal.
+
+int
+Map_construction_expression::do_traverse(Traverse* traverse)
+{
+  if (this->vals_ != NULL
+      && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Final type determination.
+
+void
+Map_construction_expression::do_determine_type(const Type_context*)
+{
+  if (this->vals_ == NULL)
+    return;
+
+  Map_type* mt = this->type_->map_type();
+  Type_context key_context(mt->key_type(), false);
+  Type_context val_context(mt->val_type(), false);
+  for (Expression_list::const_iterator pv = this->vals_->begin();
+       pv != this->vals_->end();
+       ++pv)
+    {
+      (*pv)->determine_type(&key_context);
+      ++pv;
+      (*pv)->determine_type(&val_context);
+    }
+}
+
+// Check types.
+
+void
+Map_construction_expression::do_check_types(Gogo*)
+{
+  if (this->vals_ == NULL)
+    return;
+
+  Map_type* mt = this->type_->map_type();
+  int i = 0;
+  Type* key_type = mt->key_type();
+  Type* val_type = mt->val_type();
+  for (Expression_list::const_iterator pv = this->vals_->begin();
+       pv != this->vals_->end();
+       ++pv, ++i)
+    {
+      if (!Type::are_assignable(key_type, (*pv)->type(), NULL))
+       {
+         error_at((*pv)->location(),
+                  "incompatible type for element %d key in map construction",
+                  i + 1);
+         this->set_is_error();
+       }
+      ++pv;
+      if (!Type::are_assignable(val_type, (*pv)->type(), NULL))
+       {
+         error_at((*pv)->location(),
+                  ("incompatible type for element %d value "
+                   "in map construction"),
+                  i + 1);
+         this->set_is_error();
+       }
+    }
+}
+
+// Return a tree for constructing a map.
+
+tree
+Map_construction_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  source_location loc = this->location();
+
+  Map_type* mt = this->type_->map_type();
+
+  // Build a struct to hold the key and value.
+  tree struct_type = make_node(RECORD_TYPE);
+
+  Type* key_type = mt->key_type();
+  tree id = get_identifier("__key");
+  tree key_field = build_decl(loc, FIELD_DECL, id, key_type->get_tree(gogo));
+  DECL_CONTEXT(key_field) = struct_type;
+  TYPE_FIELDS(struct_type) = key_field;
+
+  Type* val_type = mt->val_type();
+  id = get_identifier("__val");
+  tree val_field = build_decl(loc, FIELD_DECL, id, val_type->get_tree(gogo));
+  DECL_CONTEXT(val_field) = struct_type;
+  DECL_CHAIN(key_field) = val_field;
+
+  layout_type(struct_type);
+
+  bool is_constant = true;
+  size_t i = 0;
+  tree valaddr;
+  tree make_tmp;
+
+  if (this->vals_ == NULL || this->vals_->empty())
+    {
+      valaddr = null_pointer_node;
+      make_tmp = NULL_TREE;
+    }
+  else
+    {
+      VEC(constructor_elt,gc)* values = VEC_alloc(constructor_elt, gc,
+                                                 this->vals_->size() / 2);
+
+      for (Expression_list::const_iterator pv = this->vals_->begin();
+          pv != this->vals_->end();
+          ++pv, ++i)
+       {
+         bool one_is_constant = true;
+
+         VEC(constructor_elt,gc)* one = VEC_alloc(constructor_elt, gc, 2);
+
+         constructor_elt* elt = VEC_quick_push(constructor_elt, one, NULL);
+         elt->index = key_field;
+         tree val_tree = (*pv)->get_tree(context);
+         elt->value = Expression::convert_for_assignment(context, key_type,
+                                                         (*pv)->type(),
+                                                         val_tree, loc);
+         if (elt->value == error_mark_node)
+           return error_mark_node;
+         if (!TREE_CONSTANT(elt->value))
+           one_is_constant = false;
+
+         ++pv;
+
+         elt = VEC_quick_push(constructor_elt, one, NULL);
+         elt->index = val_field;
+         val_tree = (*pv)->get_tree(context);
+         elt->value = Expression::convert_for_assignment(context, val_type,
+                                                         (*pv)->type(),
+                                                         val_tree, loc);
+         if (elt->value == error_mark_node)
+           return error_mark_node;
+         if (!TREE_CONSTANT(elt->value))
+           one_is_constant = false;
+
+         elt = VEC_quick_push(constructor_elt, values, NULL);
+         elt->index = size_int(i);
+         elt->value = build_constructor(struct_type, one);
+         if (one_is_constant)
+           TREE_CONSTANT(elt->value) = 1;
+         else
+           is_constant = false;
+       }
+
+      tree index_type = build_index_type(size_int(i - 1));
+      tree array_type = build_array_type(struct_type, index_type);
+      tree init = build_constructor(array_type, values);
+      if (is_constant)
+       TREE_CONSTANT(init) = 1;
+      tree tmp;
+      if (current_function_decl != NULL)
+       {
+         tmp = create_tmp_var(array_type, get_name(array_type));
+         DECL_INITIAL(tmp) = init;
+         make_tmp = fold_build1_loc(loc, DECL_EXPR, void_type_node, tmp);
+         TREE_ADDRESSABLE(tmp) = 1;
+       }
+      else
+       {
+         tmp = build_decl(loc, VAR_DECL, create_tmp_var_name("M"), array_type);
+         DECL_EXTERNAL(tmp) = 0;
+         TREE_PUBLIC(tmp) = 0;
+         TREE_STATIC(tmp) = 1;
+         DECL_ARTIFICIAL(tmp) = 1;
+         if (!TREE_CONSTANT(init))
+           make_tmp = fold_build2_loc(loc, INIT_EXPR, void_type_node, tmp,
+                                      init);
+         else
+           {
+             TREE_READONLY(tmp) = 1;
+             TREE_CONSTANT(tmp) = 1;
+             DECL_INITIAL(tmp) = init;
+             make_tmp = NULL_TREE;
+           }
+         rest_of_decl_compilation(tmp, 1, 0);
+       }
+
+      valaddr = build_fold_addr_expr(tmp);
+    }
+
+  tree descriptor = gogo->map_descriptor(mt);
+
+  tree type_tree = this->type_->get_tree(gogo);
+
+  static tree construct_map_fndecl;
+  tree call = Gogo::call_builtin(&construct_map_fndecl,
+                                loc,
+                                "__go_construct_map",
+                                6,
+                                type_tree,
+                                TREE_TYPE(descriptor),
+                                descriptor,
+                                sizetype,
+                                size_int(i),
+                                sizetype,
+                                TYPE_SIZE_UNIT(struct_type),
+                                sizetype,
+                                byte_position(val_field),
+                                sizetype,
+                                TYPE_SIZE_UNIT(TREE_TYPE(val_field)),
+                                const_ptr_type_node,
+                                fold_convert(const_ptr_type_node, valaddr));
+
+  tree ret;
+  if (make_tmp == NULL)
+    ret = call;
+  else
+    ret = fold_build2_loc(loc, COMPOUND_EXPR, type_tree, make_tmp, call);
+  return ret;
+}
+
+// Export an array construction.
+
+void
+Map_construction_expression::do_export(Export* exp) const
+{
+  exp->write_c_string("convert(");
+  exp->write_type(this->type_);
+  for (Expression_list::const_iterator pv = this->vals_->begin();
+       pv != this->vals_->end();
+       ++pv)
+    {
+      exp->write_c_string(", ");
+      (*pv)->export_expression(exp);
+    }
+  exp->write_c_string(")");
+}
+
+// A general composite literal.  This is lowered to a type specific
+// version.
+
+class Composite_literal_expression : public Parser_expression
+{
+ public:
+  Composite_literal_expression(Type* type, int depth, bool has_keys,
+                              Expression_list* vals, source_location location)
+    : Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location),
+      type_(type), depth_(depth), vals_(vals), has_keys_(has_keys)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  Expression*
+  do_copy()
+  {
+    return new Composite_literal_expression(this->type_, this->depth_,
+                                           this->has_keys_,
+                                           (this->vals_ == NULL
+                                            ? NULL
+                                            : this->vals_->copy()),
+                                           this->location());
+  }
+
+ private:
+  Expression*
+  lower_struct(Type*);
+
+  Expression*
+  lower_array(Type*);
+
+  Expression*
+  make_array(Type*, Expression_list*);
+
+  Expression*
+  lower_map(Type*);
+
+  // The type of the composite literal.
+  Type* type_;
+  // The depth within a list of composite literals within a composite
+  // literal, when the type is omitted.
+  int depth_;
+  // The values to put in the composite literal.
+  Expression_list* vals_;
+  // If this is true, then VALS_ is a list of pairs: a key and a
+  // value.  In an array initializer, a missing key will be NULL.
+  bool has_keys_;
+};
+
+// Traversal.
+
+int
+Composite_literal_expression::do_traverse(Traverse* traverse)
+{
+  if (this->vals_ != NULL
+      && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return Type::traverse(this->type_, traverse);
+}
+
+// Lower a generic composite literal into a specific version based on
+// the type.
+
+Expression*
+Composite_literal_expression::do_lower(Gogo*, Named_object*, int)
+{
+  Type* type = this->type_;
+
+  for (int depth = this->depth_; depth > 0; --depth)
+    {
+      if (type->array_type() != NULL)
+       type = type->array_type()->element_type();
+      else if (type->map_type() != NULL)
+       type = type->map_type()->val_type();
+      else
+       {
+         if (!type->is_error_type())
+           error_at(this->location(),
+                    ("may only omit types within composite literals "
+                     "of slice, array, or map type"));
+         return Expression::make_error(this->location());
+       }
+    }
+
+  if (type->is_error_type())
+    return Expression::make_error(this->location());
+  else if (type->struct_type() != NULL)
+    return this->lower_struct(type);
+  else if (type->array_type() != NULL)
+    return this->lower_array(type);
+  else if (type->map_type() != NULL)
+    return this->lower_map(type);
+  else
+    {
+      error_at(this->location(),
+              ("expected struct, slice, array, or map type "
+               "for composite literal"));
+      return Expression::make_error(this->location());
+    }
+}
+
+// Lower a struct composite literal.
+
+Expression*
+Composite_literal_expression::lower_struct(Type* type)
+{
+  source_location location = this->location();
+  Struct_type* st = type->struct_type();
+  if (this->vals_ == NULL || !this->has_keys_)
+    return new Struct_construction_expression(type, this->vals_, location);
+
+  size_t field_count = st->field_count();
+  std::vector<Expression*> vals(field_count);
+  Expression_list::const_iterator p = this->vals_->begin();
+  while (p != this->vals_->end())
+    {
+      Expression* name_expr = *p;
+
+      ++p;
+      gcc_assert(p != this->vals_->end());
+      Expression* val = *p;
+
+      ++p;
+
+      if (name_expr == NULL)
+       {
+         error_at(val->location(), "mixture of field and value initializers");
+         return Expression::make_error(location);
+       }
+
+      bool bad_key = false;
+      std::string name;
+      switch (name_expr->classification())
+       {
+       case EXPRESSION_UNKNOWN_REFERENCE:
+         name = name_expr->unknown_expression()->name();
+         break;
+
+       case EXPRESSION_CONST_REFERENCE:
+         name = static_cast<Const_expression*>(name_expr)->name();
+         break;
+
+       case EXPRESSION_TYPE:
+         {
+           Type* t = name_expr->type();
+           Named_type* nt = t->named_type();
+           if (nt == NULL)
+             bad_key = true;
+           else
+             name = nt->name();
+         }
+         break;
+
+       case EXPRESSION_VAR_REFERENCE:
+         name = name_expr->var_expression()->name();
+         break;
+
+       case EXPRESSION_FUNC_REFERENCE:
+         name = name_expr->func_expression()->name();
+         break;
+
+       case EXPRESSION_UNARY:
+         // If there is a local variable around with the same name as
+         // the field, and this occurs in the closure, then the
+         // parser may turn the field reference into an indirection
+         // through the closure.  FIXME: This is a mess.
+         {
+           bad_key = true;
+           Unary_expression* ue = static_cast<Unary_expression*>(name_expr);
+           if (ue->op() == OPERATOR_MULT)
+             {
+               Field_reference_expression* fre =
+                 ue->operand()->field_reference_expression();
+               if (fre != NULL)
+                 {
+                   Struct_type* st =
+                     fre->expr()->type()->deref()->struct_type();
+                   if (st != NULL)
+                     {
+                       const Struct_field* sf = st->field(fre->field_index());
+                       name = sf->field_name();
+                       char buf[20];
+                       snprintf(buf, sizeof buf, "%u", fre->field_index());
+                       size_t buflen = strlen(buf);
+                       if (name.compare(name.length() - buflen, buflen, buf)
+                           == 0)
+                         {
+                           name = name.substr(0, name.length() - buflen);
+                           bad_key = false;
+                         }
+                     }
+                 }
+             }
+         }
+         break;
+
+       default:
+         bad_key = true;
+         break;
+       }
+      if (bad_key)
+       {
+         error_at(name_expr->location(), "expected struct field name");
+         return Expression::make_error(location);
+       }
+
+      unsigned int index;
+      const Struct_field* sf = st->find_local_field(name, &index);
+      if (sf == NULL)
+       {
+         error_at(name_expr->location(), "unknown field %qs in %qs",
+                  Gogo::message_name(name).c_str(),
+                  (type->named_type() != NULL
+                   ? type->named_type()->message_name().c_str()
+                   : "unnamed struct"));
+         return Expression::make_error(location);
+       }
+      if (vals[index] != NULL)
+       {
+         error_at(name_expr->location(),
+                  "duplicate value for field %qs in %qs",
+                  Gogo::message_name(name).c_str(),
+                  (type->named_type() != NULL
+                   ? type->named_type()->message_name().c_str()
+                   : "unnamed struct"));
+         return Expression::make_error(location);
+       }
+
+      vals[index] = val;
+    }
+
+  Expression_list* list = new Expression_list;
+  list->reserve(field_count);
+  for (size_t i = 0; i < field_count; ++i)
+    list->push_back(vals[i]);
+
+  return new Struct_construction_expression(type, list, location);
+}
+
+// Lower an array composite literal.
+
+Expression*
+Composite_literal_expression::lower_array(Type* type)
+{
+  source_location location = this->location();
+  if (this->vals_ == NULL || !this->has_keys_)
+    return this->make_array(type, this->vals_);
+
+  std::vector<Expression*> vals;
+  vals.reserve(this->vals_->size());
+  unsigned long index = 0;
+  Expression_list::const_iterator p = this->vals_->begin();
+  while (p != this->vals_->end())
+    {
+      Expression* index_expr = *p;
+
+      ++p;
+      gcc_assert(p != this->vals_->end());
+      Expression* val = *p;
+
+      ++p;
+
+      if (index_expr != NULL)
+       {
+         mpz_t ival;
+         mpz_init(ival);
+         Type* dummy;
+         if (!index_expr->integer_constant_value(true, ival, &dummy))
+           {
+             mpz_clear(ival);
+             error_at(index_expr->location(),
+                      "index expression is not integer constant");
+             return Expression::make_error(location);
+           }
+         if (mpz_sgn(ival) < 0)
+           {
+             mpz_clear(ival);
+             error_at(index_expr->location(), "index expression is negative");
+             return Expression::make_error(location);
+           }
+         index = mpz_get_ui(ival);
+         if (mpz_cmp_ui(ival, index) != 0)
+           {
+             mpz_clear(ival);
+             error_at(index_expr->location(), "index value overflow");
+             return Expression::make_error(location);
+           }
+         mpz_clear(ival);
+       }
+
+      if (index == vals.size())
+       vals.push_back(val);
+      else
+       {
+         if (index > vals.size())
+           {
+             vals.reserve(index + 32);
+             vals.resize(index + 1, static_cast<Expression*>(NULL));
+           }
+         if (vals[index] != NULL)
+           {
+             error_at((index_expr != NULL
+                       ? index_expr->location()
+                       : val->location()),
+                      "duplicate value for index %lu",
+                      index);
+             return Expression::make_error(location);
+           }
+         vals[index] = val;
+       }
+
+      ++index;
+    }
+
+  size_t size = vals.size();
+  Expression_list* list = new Expression_list;
+  list->reserve(size);
+  for (size_t i = 0; i < size; ++i)
+    list->push_back(vals[i]);
+
+  return this->make_array(type, list);
+}
+
+// Actually build the array composite literal. This handles
+// [...]{...}.
+
+Expression*
+Composite_literal_expression::make_array(Type* type, Expression_list* vals)
+{
+  source_location location = this->location();
+  Array_type* at = type->array_type();
+  if (at->length() != NULL && at->length()->is_nil_expression())
+    {
+      size_t size = vals == NULL ? 0 : vals->size();
+      mpz_t vlen;
+      mpz_init_set_ui(vlen, size);
+      Expression* elen = Expression::make_integer(&vlen, NULL, location);
+      mpz_clear(vlen);
+      at = Type::make_array_type(at->element_type(), elen);
+      type = at;
+    }
+  if (at->length() != NULL)
+    return new Fixed_array_construction_expression(type, vals, location);
+  else
+    return new Open_array_construction_expression(type, vals, location);
+}
+
+// Lower a map composite literal.
+
+Expression*
+Composite_literal_expression::lower_map(Type* type)
+{
+  source_location location = this->location();
+  if (this->vals_ != NULL)
+    {
+      if (!this->has_keys_)
+       {
+         error_at(location, "map composite literal must have keys");
+         return Expression::make_error(location);
+       }
+
+      for (Expression_list::const_iterator p = this->vals_->begin();
+          p != this->vals_->end();
+          p += 2)
+       {
+         if (*p == NULL)
+           {
+             ++p;
+             error_at((*p)->location(),
+                      "map composite literal must have keys for every value");
+             return Expression::make_error(location);
+           }
+       }
+    }
+
+  return new Map_construction_expression(type, this->vals_, location);
+}
+
+// Make a composite literal expression.
+
+Expression*
+Expression::make_composite_literal(Type* type, int depth, bool has_keys,
+                                  Expression_list* vals,
+                                  source_location location)
+{
+  return new Composite_literal_expression(type, depth, has_keys, vals,
+                                         location);
+}
+
+// Return whether this expression is a composite literal.
+
+bool
+Expression::is_composite_literal() const
+{
+  switch (this->classification_)
+    {
+    case EXPRESSION_COMPOSITE_LITERAL:
+    case EXPRESSION_STRUCT_CONSTRUCTION:
+    case EXPRESSION_FIXED_ARRAY_CONSTRUCTION:
+    case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
+    case EXPRESSION_MAP_CONSTRUCTION:
+      return true;
+    default:
+      return false;
+    }
+}
+
+// Return whether this expression is a composite literal which is not
+// constant.
+
+bool
+Expression::is_nonconstant_composite_literal() const
+{
+  switch (this->classification_)
+    {
+    case EXPRESSION_STRUCT_CONSTRUCTION:
+      {
+       const Struct_construction_expression *psce =
+         static_cast<const Struct_construction_expression*>(this);
+       return !psce->is_constant_struct();
+      }
+    case EXPRESSION_FIXED_ARRAY_CONSTRUCTION:
+      {
+       const Fixed_array_construction_expression *pace =
+         static_cast<const Fixed_array_construction_expression*>(this);
+       return !pace->is_constant_array();
+      }
+    case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
+      {
+       const Open_array_construction_expression *pace =
+         static_cast<const Open_array_construction_expression*>(this);
+       return !pace->is_constant_array();
+      }
+    case EXPRESSION_MAP_CONSTRUCTION:
+      return true;
+    default:
+      return false;
+    }
+}
+
+// Return true if this is a reference to a local variable.
+
+bool
+Expression::is_local_variable() const
+{
+  const Var_expression* ve = this->var_expression();
+  if (ve == NULL)
+    return false;
+  const Named_object* no = ve->named_object();
+  return (no->is_result_variable()
+         || (no->is_variable() && !no->var_value()->is_global()));
+}
+
+// Class Type_guard_expression.
+
+// Traversal.
+
+int
+Type_guard_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT
+      || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Check types of a type guard expression.  The expression must have
+// an interface type, but the actual type conversion is checked at run
+// time.
+
+void
+Type_guard_expression::do_check_types(Gogo*)
+{
+  // 6g permits using a type guard with unsafe.pointer; we are
+  // compatible.
+  Type* expr_type = this->expr_->type();
+  if (expr_type->is_unsafe_pointer_type())
+    {
+      if (this->type_->points_to() == NULL
+         && (this->type_->integer_type() == NULL
+             || (this->type_->forwarded()
+                 != Type::lookup_integer_type("uintptr"))))
+       this->report_error(_("invalid unsafe.Pointer conversion"));
+    }
+  else if (this->type_->is_unsafe_pointer_type())
+    {
+      if (expr_type->points_to() == NULL
+         && (expr_type->integer_type() == NULL
+             || (expr_type->forwarded()
+                 != Type::lookup_integer_type("uintptr"))))
+       this->report_error(_("invalid unsafe.Pointer conversion"));
+    }
+  else if (expr_type->interface_type() == NULL)
+    this->report_error(_("type assertion only valid for interface types"));
+  else if (this->type_->interface_type() == NULL)
+    {
+      std::string reason;
+      if (!expr_type->interface_type()->implements_interface(this->type_,
+                                                            &reason))
+       {
+         if (reason.empty())
+           this->report_error(_("impossible type assertion: "
+                                "type does not implement interface"));
+         else
+           {
+             error_at(this->location(),
+                      ("impossible type assertion: "
+                       "type does not implement interface (%s)"),
+                      reason.c_str());
+             this->set_is_error();
+           }
+       }
+    }
+}
+
+// Return a tree for a type guard expression.
+
+tree
+Type_guard_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  tree expr_tree = this->expr_->get_tree(context);
+  if (expr_tree == error_mark_node)
+    return error_mark_node;
+  Type* expr_type = this->expr_->type();
+  if ((this->type_->is_unsafe_pointer_type()
+       && (expr_type->points_to() != NULL
+          || expr_type->integer_type() != NULL))
+      || (expr_type->is_unsafe_pointer_type()
+         && this->type_->points_to() != NULL))
+    return convert_to_pointer(this->type_->get_tree(gogo), expr_tree);
+  else if (expr_type->is_unsafe_pointer_type()
+          && this->type_->integer_type() != NULL)
+    return convert_to_integer(this->type_->get_tree(gogo), expr_tree);
+  else if (this->type_->interface_type() != NULL)
+    return Expression::convert_interface_to_interface(context, this->type_,
+                                                     this->expr_->type(),
+                                                     expr_tree, true,
+                                                     this->location());
+  else
+    return Expression::convert_for_assignment(context, this->type_,
+                                             this->expr_->type(), expr_tree,
+                                             this->location());
+}
+
+// Make a type guard expression.
+
+Expression*
+Expression::make_type_guard(Expression* expr, Type* type,
+                           source_location location)
+{
+  return new Type_guard_expression(expr, type, location);
+}
+
+// Class Heap_composite_expression.
+
+// When you take the address of a composite literal, it is allocated
+// on the heap.  This class implements that.
+
+class Heap_composite_expression : public Expression
+{
+ public:
+  Heap_composite_expression(Expression* expr, source_location location)
+    : Expression(EXPRESSION_HEAP_COMPOSITE, location),
+      expr_(expr)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Expression::traverse(&this->expr_, traverse); }
+
+  Type*
+  do_type()
+  { return Type::make_pointer_type(this->expr_->type()); }
+
+  void
+  do_determine_type(const Type_context*)
+  { this->expr_->determine_type_no_context(); }
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_heap_composite(this->expr_->copy(),
+                                          this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  // We only export global objects, and the parser does not generate
+  // this in global scope.
+  void
+  do_export(Export*) const
+  { gcc_unreachable(); }
+
+ private:
+  // The composite literal which is being put on the heap.
+  Expression* expr_;
+};
+
+// Return a tree which allocates a composite literal on the heap.
+
+tree
+Heap_composite_expression::do_get_tree(Translate_context* context)
+{
+  tree expr_tree = this->expr_->get_tree(context);
+  if (expr_tree == error_mark_node)
+    return error_mark_node;
+  tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree));
+  gcc_assert(TREE_CODE(expr_size) == INTEGER_CST);
+  tree space = context->gogo()->allocate_memory(this->expr_->type(),
+                                               expr_size, this->location());
+  space = fold_convert(build_pointer_type(TREE_TYPE(expr_tree)), space);
+  space = save_expr(space);
+  tree ref = build_fold_indirect_ref_loc(this->location(), space);
+  TREE_THIS_NOTRAP(ref) = 1;
+  tree ret = build2(COMPOUND_EXPR, TREE_TYPE(space),
+                   build2(MODIFY_EXPR, void_type_node, ref, expr_tree),
+                   space);
+  SET_EXPR_LOCATION(ret, this->location());
+  return ret;
+}
+
+// Allocate a composite literal on the heap.
+
+Expression*
+Expression::make_heap_composite(Expression* expr, source_location location)
+{
+  return new Heap_composite_expression(expr, location);
+}
+
+// Class Receive_expression.
+
+// Return the type of a receive expression.
+
+Type*
+Receive_expression::do_type()
+{
+  Channel_type* channel_type = this->channel_->type()->channel_type();
+  if (channel_type == NULL)
+    return Type::make_error_type();
+  return channel_type->element_type();
+}
+
+// Check types for a receive expression.
+
+void
+Receive_expression::do_check_types(Gogo*)
+{
+  Type* type = this->channel_->type();
+  if (type->is_error_type())
+    {
+      this->set_is_error();
+      return;
+    }
+  if (type->channel_type() == NULL)
+    {
+      this->report_error(_("expected channel"));
+      return;
+    }
+  if (!type->channel_type()->may_receive())
+    {
+      this->report_error(_("invalid receive on send-only channel"));
+      return;
+    }
+}
+
+// Get a tree for a receive expression.
+
+tree
+Receive_expression::do_get_tree(Translate_context* context)
+{
+  Channel_type* channel_type = this->channel_->type()->channel_type();
+  gcc_assert(channel_type != NULL);
+  Type* element_type = channel_type->element_type();
+  tree element_type_tree = element_type->get_tree(context->gogo());
+
+  tree channel = this->channel_->get_tree(context);
+  if (element_type_tree == error_mark_node || channel == error_mark_node)
+    return error_mark_node;
+
+  return Gogo::receive_from_channel(element_type_tree, channel,
+                                   this->for_select_, this->location());
+}
+
+// Make a receive expression.
+
+Receive_expression*
+Expression::make_receive(Expression* channel, source_location location)
+{
+  return new Receive_expression(channel, location);
+}
+
+// Class Send_expression.
+
+// Traversal.
+
+int
+Send_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return Expression::traverse(&this->val_, traverse);
+}
+
+// Get the type.
+
+Type*
+Send_expression::do_type()
+{
+  return Type::lookup_bool_type();
+}
+
+// Set types.
+
+void
+Send_expression::do_determine_type(const Type_context*)
+{
+  this->channel_->determine_type_no_context();
+
+  Type* type = this->channel_->type();
+  Type_context subcontext;
+  if (type->channel_type() != NULL)
+    subcontext.type = type->channel_type()->element_type();
+  this->val_->determine_type(&subcontext);
+}
+
+// Check types.
+
+void
+Send_expression::do_check_types(Gogo*)
+{
+  Type* type = this->channel_->type();
+  if (type->is_error_type())
+    {
+      this->set_is_error();
+      return;
+    }
+  Channel_type* channel_type = type->channel_type();
+  if (channel_type == NULL)
+    {
+      error_at(this->location(), "left operand of %<<-%> must be channel");
+      this->set_is_error();
+      return;
+    }
+  Type* element_type = channel_type->element_type();
+  if (element_type != NULL
+      && !Type::are_assignable(element_type, this->val_->type(), NULL))
+    {
+      this->report_error(_("incompatible types in send"));
+      return;
+    }
+  if (!channel_type->may_send())
+    {
+      this->report_error(_("invalid send on receive-only channel"));
+      return;
+    }
+}
+
+// Get a tree for a send expression.
+
+tree
+Send_expression::do_get_tree(Translate_context* context)
+{
+  tree channel = this->channel_->get_tree(context);
+  tree val = this->val_->get_tree(context);
+  if (channel == error_mark_node || val == error_mark_node)
+    return error_mark_node;
+  Channel_type* channel_type = this->channel_->type()->channel_type();
+  val = Expression::convert_for_assignment(context,
+                                          channel_type->element_type(),
+                                          this->val_->type(),
+                                          val,
+                                          this->location());
+  return Gogo::send_on_channel(channel, val, this->is_value_discarded_,
+                              this->for_select_, this->location());
+}
+
+// Make a send expression
+
+Send_expression*
+Expression::make_send(Expression* channel, Expression* val,
+                     source_location location)
+{
+  return new Send_expression(channel, val, location);
+}
+
+// An expression which evaluates to a pointer to the type descriptor
+// of a type.
+
+class Type_descriptor_expression : public Expression
+{
+ public:
+  Type_descriptor_expression(Type* type, source_location location)
+    : Expression(EXPRESSION_TYPE_DESCRIPTOR, location),
+      type_(type)
+  { }
+
+ protected:
+  Type*
+  do_type()
+  { return Type::make_type_descriptor_ptr_type(); }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  tree
+  do_get_tree(Translate_context* context)
+  { return this->type_->type_descriptor_pointer(context->gogo()); }
+
+ private:
+  // The type for which this is the descriptor.
+  Type* type_;
+};
+
+// Make a type descriptor expression.
+
+Expression*
+Expression::make_type_descriptor(Type* type, source_location location)
+{
+  return new Type_descriptor_expression(type, location);
+}
+
+// An expression which evaluates to some characteristic of a type.
+// This is only used to initialize fields of a type descriptor.  Using
+// a new expression class is slightly inefficient but gives us a good
+// separation between the frontend and the middle-end with regard to
+// how types are laid out.
+
+class Type_info_expression : public Expression
+{
+ public:
+  Type_info_expression(Type* type, Type_info type_info)
+    : Expression(EXPRESSION_TYPE_INFO, BUILTINS_LOCATION),
+      type_(type), type_info_(type_info)
+  { }
+
+ protected:
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+ private:
+  // The type for which we are getting information.
+  Type* type_;
+  // What information we want.
+  Type_info type_info_;
+};
+
+// The type is chosen to match what the type descriptor struct
+// expects.
+
+Type*
+Type_info_expression::do_type()
+{
+  switch (this->type_info_)
+    {
+    case TYPE_INFO_SIZE:
+      return Type::lookup_integer_type("uintptr");
+    case TYPE_INFO_ALIGNMENT:
+    case TYPE_INFO_FIELD_ALIGNMENT:
+      return Type::lookup_integer_type("uint8");
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Return type information in GENERIC.
+
+tree
+Type_info_expression::do_get_tree(Translate_context* context)
+{
+  tree type_tree = this->type_->get_tree(context->gogo());
+  if (type_tree == error_mark_node)
+    return error_mark_node;
+
+  tree val_type_tree = this->type()->get_tree(context->gogo());
+  gcc_assert(val_type_tree != error_mark_node);
+
+  if (this->type_info_ == TYPE_INFO_SIZE)
+    return fold_convert_loc(BUILTINS_LOCATION, val_type_tree,
+                           TYPE_SIZE_UNIT(type_tree));
+  else
+    {
+      unsigned HOST_WIDE_INT val;
+      if (this->type_info_ == TYPE_INFO_ALIGNMENT)
+       val = TYPE_ALIGN_UNIT(type_tree);
+      else
+       {
+         gcc_assert(this->type_info_ == TYPE_INFO_FIELD_ALIGNMENT);
+         val = TYPE_ALIGN(type_tree);
+#ifdef BIGGEST_FIELD_ALIGMENT
+         if (val > BIGGEST_FIELD_ALIGNMENT)
+           val = BIGGEST_FIELD_ALIGNMENT;
+#endif
+#ifdef ADJUST_FIELD_ALIGN
+         {
+           tree f = build_decl(UNKNOWN_LOCATION, FIELD_DECL, NULL, type_tree);
+           val = ADJUST_FIELD_ALIGN(f, val);
+         }
+#endif
+         val /= BITS_PER_UNIT;
+       }
+
+      return build_int_cstu(val_type_tree, val);
+    }
+}
+
+// Make a type info expression.
+
+Expression*
+Expression::make_type_info(Type* type, Type_info type_info)
+{
+  return new Type_info_expression(type, type_info);
+}
+
+// An expression which evaluates to the offset of a field within a
+// struct.  This, like Type_info_expression, q.v., is only used to
+// initialize fields of a type descriptor.
+
+class Struct_field_offset_expression : public Expression
+{
+ public:
+  Struct_field_offset_expression(Struct_type* type, const Struct_field* field)
+    : Expression(EXPRESSION_STRUCT_FIELD_OFFSET, BUILTINS_LOCATION),
+      type_(type), field_(field)
+  { }
+
+ protected:
+  Type*
+  do_type()
+  { return Type::lookup_integer_type("uintptr"); }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+ private:
+  // The type of the struct.
+  Struct_type* type_;
+  // The field.
+  const Struct_field* field_;
+};
+
+// Return a struct field offset in GENERIC.
+
+tree
+Struct_field_offset_expression::do_get_tree(Translate_context* context)
+{
+  tree type_tree = this->type_->get_tree(context->gogo());
+  if (type_tree == error_mark_node)
+    return error_mark_node;
+
+  tree val_type_tree = this->type()->get_tree(context->gogo());
+  gcc_assert(val_type_tree != error_mark_node);
+
+  const Struct_field_list* fields = this->type_->fields();
+  tree struct_field_tree = TYPE_FIELDS(type_tree);
+  Struct_field_list::const_iterator p;
+  for (p = fields->begin();
+       p != fields->end();
+       ++p, struct_field_tree = DECL_CHAIN(struct_field_tree))
+    {
+      gcc_assert(struct_field_tree != NULL_TREE);
+      if (&*p == this->field_)
+       break;
+    }
+  gcc_assert(&*p == this->field_);
+
+  return fold_convert_loc(BUILTINS_LOCATION, val_type_tree,
+                         byte_position(struct_field_tree));
+}
+
+// Make an expression for a struct field offset.
+
+Expression*
+Expression::make_struct_field_offset(Struct_type* type,
+                                    const Struct_field* field)
+{
+  return new Struct_field_offset_expression(type, field);
+}
+
+// An expression which evaluates to the address of an unnamed label.
+
+class Label_addr_expression : public Expression
+{
+ public:
+  Label_addr_expression(Label* label, source_location location)
+    : Expression(EXPRESSION_LABEL_ADDR, location),
+      label_(label)
+  { }
+
+ protected:
+  Type*
+  do_type()
+  { return Type::make_pointer_type(Type::make_void_type()); }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return new Label_addr_expression(this->label_, this->location()); }
+
+  tree
+  do_get_tree(Translate_context*)
+  { return this->label_->get_addr(this->location()); }
+
+ private:
+  // The label whose address we are taking.
+  Label* label_;
+};
+
+// Make an expression for the address of an unnamed label.
+
+Expression*
+Expression::make_label_addr(Label* label, source_location location)
+{
+  return new Label_addr_expression(label, location);
+}
+
+// Import an expression.  This comes at the end in order to see the
+// various class definitions.
+
+Expression*
+Expression::import_expression(Import* imp)
+{
+  int c = imp->peek_char();
+  if (imp->match_c_string("- ")
+      || imp->match_c_string("! ")
+      || imp->match_c_string("^ "))
+    return Unary_expression::do_import(imp);
+  else if (c == '(')
+    return Binary_expression::do_import(imp);
+  else if (imp->match_c_string("true")
+          || imp->match_c_string("false"))
+    return Boolean_expression::do_import(imp);
+  else if (c == '"')
+    return String_expression::do_import(imp);
+  else if (c == '-' || (c >= '0' && c <= '9'))
+    {
+      // This handles integers, floats and complex constants.
+      return Integer_expression::do_import(imp);
+    }
+  else if (imp->match_c_string("nil"))
+    return Nil_expression::do_import(imp);
+  else if (imp->match_c_string("convert"))
+    return Type_conversion_expression::do_import(imp);
+  else
+    {
+      error_at(imp->location(), "import error: expected expression");
+      return Expression::make_error(imp->location());
+    }
+}
+
+// Class Expression_list.
+
+// Traverse the list.
+
+int
+Expression_list::traverse(Traverse* traverse)
+{
+  for (Expression_list::iterator p = this->begin();
+       p != this->end();
+       ++p)
+    {
+      if (*p != NULL)
+       {
+         if (Expression::traverse(&*p, traverse) == TRAVERSE_EXIT)
+           return TRAVERSE_EXIT;
+       }
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Copy the list.
+
+Expression_list*
+Expression_list::copy()
+{
+  Expression_list* ret = new Expression_list();
+  for (Expression_list::iterator p = this->begin();
+       p != this->end();
+       ++p)
+    {
+      if (*p == NULL)
+       ret->push_back(NULL);
+      else
+       ret->push_back((*p)->copy());
+    }
+  return ret;
+}
+
+// Return whether an expression list has an error expression.
+
+bool
+Expression_list::contains_error() const
+{
+  for (Expression_list::const_iterator p = this->begin();
+       p != this->end();
+       ++p)
+    if (*p != NULL && (*p)->is_error_expression())
+      return true;
+  return false;
+}
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
new file mode 100644 (file)
index 0000000..4d539d4
--- /dev/null
@@ -0,0 +1,1920 @@
+// expressions.h -- Go frontend expression handling.     -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_EXPRESSIONS_H
+#define GO_EXPRESSIONS_H
+
+#include <gmp.h>
+#include <mpfr.h>
+
+#include "operator.h"
+
+class Gogo;
+class Translate_context;
+class Traverse;
+class Type;
+struct Type_context;
+class Function_type;
+class Map_type;
+class Struct_type;
+class Struct_field;
+class Expression_list;
+class Var_expression;
+class Temporary_reference_expression;
+class String_expression;
+class Binary_expression;
+class Call_expression;
+class Func_expression;
+class Unknown_expression;
+class Index_expression;
+class Map_index_expression;
+class Bound_method_expression;
+class Field_reference_expression;
+class Interface_field_reference_expression;
+class Type_guard_expression;
+class Receive_expression;
+class Send_expression;
+class Named_object;
+class Export;
+class Import;
+class Temporary_statement;
+class Label;
+
+// The base class for all expressions.
+
+class Expression
+{
+ public:
+  // The types of expressions.
+  enum Expression_classification
+  {
+    EXPRESSION_ERROR,
+    EXPRESSION_TYPE,
+    EXPRESSION_UNARY,
+    EXPRESSION_BINARY,
+    EXPRESSION_CONST_REFERENCE,
+    EXPRESSION_VAR_REFERENCE,
+    EXPRESSION_TEMPORARY_REFERENCE,
+    EXPRESSION_SINK,
+    EXPRESSION_FUNC_REFERENCE,
+    EXPRESSION_UNKNOWN_REFERENCE,
+    EXPRESSION_BOOLEAN,
+    EXPRESSION_STRING,
+    EXPRESSION_INTEGER,
+    EXPRESSION_FLOAT,
+    EXPRESSION_COMPLEX,
+    EXPRESSION_NIL,
+    EXPRESSION_IOTA,
+    EXPRESSION_CALL,
+    EXPRESSION_CALL_RESULT,
+    EXPRESSION_BOUND_METHOD,
+    EXPRESSION_INDEX,
+    EXPRESSION_ARRAY_INDEX,
+    EXPRESSION_STRING_INDEX,
+    EXPRESSION_MAP_INDEX,
+    EXPRESSION_SELECTOR,
+    EXPRESSION_FIELD_REFERENCE,
+    EXPRESSION_INTERFACE_FIELD_REFERENCE,
+    EXPRESSION_ALLOCATION,
+    EXPRESSION_MAKE,
+    EXPRESSION_TYPE_GUARD,
+    EXPRESSION_CONVERSION,
+    EXPRESSION_STRUCT_CONSTRUCTION,
+    EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
+    EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
+    EXPRESSION_MAP_CONSTRUCTION,
+    EXPRESSION_COMPOSITE_LITERAL,
+    EXPRESSION_HEAP_COMPOSITE,
+    EXPRESSION_RECEIVE,
+    EXPRESSION_SEND,
+    EXPRESSION_TYPE_DESCRIPTOR,
+    EXPRESSION_TYPE_INFO,
+    EXPRESSION_STRUCT_FIELD_OFFSET,
+    EXPRESSION_LABEL_ADDR
+  };
+
+  Expression(Expression_classification, source_location);
+
+  virtual ~Expression();
+
+  // Make an error expression.  This is used when a parse error occurs
+  // to prevent cascading errors.
+  static Expression*
+  make_error(source_location);
+
+  // Make an expression which is really a type.  This is used during
+  // parsing.
+  static Expression*
+  make_type(Type*, source_location);
+
+  // Make a unary expression.
+  static Expression*
+  make_unary(Operator, Expression*, source_location);
+
+  // Make a binary expression.
+  static Expression*
+  make_binary(Operator, Expression*, Expression*, source_location);
+
+  // Make a reference to a constant in an expression.
+  static Expression*
+  make_const_reference(Named_object*, source_location);
+
+  // Make a reference to a variable in an expression.
+  static Expression*
+  make_var_reference(Named_object*, source_location);
+
+  // Make a reference to a temporary variable.  Temporary variables
+  // are always created by a single statement, which is what we use to
+  // refer to them.
+  static Expression*
+  make_temporary_reference(Temporary_statement*, source_location);
+
+  // Make a sink expression--a reference to the blank identifier _.
+  static Expression*
+  make_sink(source_location);
+
+  // Make a reference to a function in an expression.
+  static Expression*
+  make_func_reference(Named_object*, Expression* closure, source_location);
+
+  // Make a reference to an unknown name.  In a correct program this
+  // will always be lowered to a real const/var/func reference.
+  static Expression*
+  make_unknown_reference(Named_object*, source_location);
+
+  // Make a constant bool expression.
+  static Expression*
+  make_boolean(bool val, source_location);
+
+  // Make a constant string expression.
+  static Expression*
+  make_string(const std::string&, source_location);
+
+  // Make a constant integer expression.  TYPE should be NULL for an
+  // abstract type.
+  static Expression*
+  make_integer(const mpz_t*, Type*, source_location);
+
+  // Make a constant float expression.  TYPE should be NULL for an
+  // abstract type.
+  static Expression*
+  make_float(const mpfr_t*, Type*, source_location);
+
+  // Make a constant complex expression.  TYPE should be NULL for an
+  // abstract type.
+  static Expression*
+  make_complex(const mpfr_t* real, const mpfr_t* imag, Type*, source_location);
+
+  // Make a nil expression.
+  static Expression*
+  make_nil(source_location);
+
+  // Make an iota expression.  This is used for the predeclared
+  // constant iota.
+  static Expression*
+  make_iota();
+
+  // Make a call expression.
+  static Call_expression*
+  make_call(Expression* func, Expression_list* args, bool is_varargs,
+           source_location);
+
+  // Make a reference to a specific result of a call expression which
+  // returns a tuple.
+  static Expression*
+  make_call_result(Call_expression*, unsigned int index);
+
+  // Make an expression which is a method bound to its first
+  // parameter.
+  static Bound_method_expression*
+  make_bound_method(Expression* object, Expression* method, source_location);
+
+  // Make an index or slice expression.  This is a parser expression
+  // which represents LEFT[START:END].  END may be NULL, meaning an
+  // index rather than a slice.  At parse time we may not know the
+  // type of LEFT.  After parsing this is lowered to an array index, a
+  // string index, or a map index.
+  static Expression*
+  make_index(Expression* left, Expression* start, Expression* end,
+            source_location);
+
+  // Make an array index expression.  END may be NULL, in which case
+  // this is an lvalue.
+  static Expression*
+  make_array_index(Expression* array, Expression* start, Expression* end,
+                  source_location);
+
+  // Make a string index expression.  END may be NULL.  This is never
+  // an lvalue.
+  static Expression*
+  make_string_index(Expression* string, Expression* start, Expression* end,
+                   source_location);
+
+  // Make a map index expression.  This is an lvalue.
+  static Map_index_expression*
+  make_map_index(Expression* map, Expression* val, source_location);
+
+  // Make a selector.  This is a parser expression which represents
+  // LEFT.NAME.  At parse time we may not know the type of the left
+  // hand side.
+  static Expression*
+  make_selector(Expression* left, const std::string& name, source_location);
+
+  // Make a reference to a field in a struct.
+  static Field_reference_expression*
+  make_field_reference(Expression*, unsigned int field_index, source_location);
+
+  // Make a reference to a field of an interface, with an associated
+  // object.
+  static Expression*
+  make_interface_field_reference(Expression*, const std::string&,
+                                source_location);
+
+  // Make an allocation expression.
+  static Expression*
+  make_allocation(Type*, source_location);
+
+  // Make a call to the builtin function make.
+  static Expression*
+  make_make(Type*, Expression_list*, source_location);
+
+  // Make a type guard expression.
+  static Expression*
+  make_type_guard(Expression*, Type*, source_location);
+
+  // Make a type cast expression.
+  static Expression*
+  make_cast(Type*, Expression*, source_location);
+
+  // Make a composite literal.  The DEPTH parameter is how far down we
+  // are in a list of composite literals with omitted types.
+  static Expression*
+  make_composite_literal(Type*, int depth, bool has_keys, Expression_list*,
+                        source_location);
+
+  // Make a struct composite literal.
+  static Expression*
+  make_struct_composite_literal(Type*, Expression_list*, source_location);
+
+  // Make a slice composite literal.
+  static Expression*
+  make_slice_composite_literal(Type*, Expression_list*, source_location);
+
+  // Take a composite literal and allocate it on the heap.
+  static Expression*
+  make_heap_composite(Expression*, source_location);
+
+  // Make a receive expression.  VAL is NULL for a unary receive.
+  static Receive_expression*
+  make_receive(Expression* channel, source_location);
+
+  // Make a send expression.
+  static Send_expression*
+  make_send(Expression* channel, Expression* val, source_location);
+
+  // Make an expression which evaluates to the type descriptor of a
+  // type.
+  static Expression*
+  make_type_descriptor(Type* type, source_location);
+
+  // Make an expression which evaluates to some characteristic of a
+  // type.  These are only used for type descriptors, so there is no
+  // location parameter.
+  enum Type_info
+    {
+      // The size of a value of the type.
+      TYPE_INFO_SIZE,
+      // The required alignment of a value of the type.
+      TYPE_INFO_ALIGNMENT,
+      // The required alignment of a value of the type when used as a
+      // field in a struct.
+      TYPE_INFO_FIELD_ALIGNMENT
+    };
+
+  static Expression*
+  make_type_info(Type* type, Type_info);
+
+  // Make an expression which evaluates to the offset of a field in a
+  // struct.  This is only used for type descriptors, so there is no
+  // location parameter.
+  static Expression*
+  make_struct_field_offset(Struct_type*, const Struct_field*);
+
+  // Make an expression which evaluates to the address of an unnamed
+  // label.
+  static Expression*
+  make_label_addr(Label*, source_location);
+
+  // Return the expression classification.
+  Expression_classification
+  classification() const
+  { return this->classification_; }
+
+  // Return the location of the expression.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Return whether this is a constant expression.
+  bool
+  is_constant() const
+  { return this->do_is_constant(); }
+
+  // If this is not a constant expression with integral type, return
+  // false.  If it is one, return true, and set VAL to the value.  VAL
+  // should already be initialized.  If this returns true, it sets
+  // *PTYPE to the type of the value, or NULL for an abstract type.
+  // If IOTA_IS_CONSTANT is true, then an iota expression is assumed
+  // to have its final value.
+  bool
+  integer_constant_value(bool iota_is_constant, mpz_t val, Type** ptype) const;
+
+  // If this is not a constant expression with floating point type,
+  // return false.  If it is one, return true, and set VAL to the
+  // value.  VAL should already be initialized.  If this returns true,
+  // it sets *PTYPE to the type of the value, or NULL for an abstract
+  // type.
+  bool
+  float_constant_value(mpfr_t val, Type** ptype) const;
+
+  // If this is not a constant expression with complex type, return
+  // false.  If it is one, return true, and set REAL and IMAG to the
+  // value.  REAL and IMAG should already be initialized.  If this
+  // return strue, it sets *PTYPE to the type of the value, or NULL
+  // for an abstract type.
+  bool
+  complex_constant_value(mpfr_t real, mpfr_t imag, Type** ptype) const;
+
+  // If this is not a constant expression with string type, return
+  // false.  If it is one, return true, and set VAL to the value.
+  bool
+  string_constant_value(std::string* val) const
+  { return this->do_string_constant_value(val); }
+
+  // This is called by the parser if the value of this expression is
+  // being discarded.  This issues warnings about computed values
+  // being unused, and handles send expressions which act differently
+  // depending upon whether the value is used.
+  void
+  discarding_value()
+  { this->do_discarding_value(); }
+
+  // Return whether this is an error expression.
+  bool
+  is_error_expression() const
+  { return this->classification_ == EXPRESSION_ERROR; }
+
+  // Return whether this expression really represents a type.
+  bool
+  is_type_expression() const
+  { return this->classification_ == EXPRESSION_TYPE; }
+
+  // If this is a variable reference, return the Var_expression
+  // structure.  Otherwise, return NULL.  This is a controlled dynamic
+  // cast.
+  Var_expression*
+  var_expression()
+  { return this->convert<Var_expression, EXPRESSION_VAR_REFERENCE>(); }
+
+  const Var_expression*
+  var_expression() const
+  { return this->convert<const Var_expression, EXPRESSION_VAR_REFERENCE>(); }
+
+  // If this is a reference to a temporary variable, return the
+  // Temporary_reference_expression.  Otherwise, return NULL.
+  Temporary_reference_expression*
+  temporary_reference_expression()
+  {
+    return this->convert<Temporary_reference_expression,
+                        EXPRESSION_TEMPORARY_REFERENCE>();
+  }
+
+  // Return whether this is a sink expression.
+  bool
+  is_sink_expression() const
+  { return this->classification_ == EXPRESSION_SINK; }
+
+  // If this is a string expression, return the String_expression
+  // structure.  Otherwise, return NULL.
+  String_expression*
+  string_expression()
+  { return this->convert<String_expression, EXPRESSION_STRING>(); }
+
+  // Return whether this is the expression nil.
+  bool
+  is_nil_expression() const
+  { return this->classification_ == EXPRESSION_NIL; }
+
+  // If this is an indirection through a pointer, return the
+  // expression being pointed through.  Otherwise return this.
+  Expression*
+  deref();
+
+  // If this is a binary expression, return the Binary_expression
+  // structure.  Otherwise return NULL.
+  Binary_expression*
+  binary_expression()
+  { return this->convert<Binary_expression, EXPRESSION_BINARY>(); }
+
+  // If this is a call expression, return the Call_expression
+  // structure.  Otherwise, return NULL.  This is a controlled dynamic
+  // cast.
+  Call_expression*
+  call_expression()
+  { return this->convert<Call_expression, EXPRESSION_CALL>(); }
+
+  // If this is an expression which refers to a function, return the
+  // Func_expression structure.  Otherwise, return NULL.
+  Func_expression*
+  func_expression()
+  { return this->convert<Func_expression, EXPRESSION_FUNC_REFERENCE>(); }
+
+  const Func_expression*
+  func_expression() const
+  { return this->convert<const Func_expression, EXPRESSION_FUNC_REFERENCE>(); }
+
+  // If this is an expression which refers to an unknown name, return
+  // the Unknown_expression structure.  Otherwise, return NULL.
+  Unknown_expression*
+  unknown_expression()
+  { return this->convert<Unknown_expression, EXPRESSION_UNKNOWN_REFERENCE>(); }
+
+  const Unknown_expression*
+  unknown_expression() const
+  {
+    return this->convert<const Unknown_expression,
+                        EXPRESSION_UNKNOWN_REFERENCE>();
+  }
+
+  // If this is an index expression, return the Index_expression
+  // structure.  Otherwise, return NULL.
+  Index_expression*
+  index_expression()
+  { return this->convert<Index_expression, EXPRESSION_INDEX>(); }
+
+  // If this is an expression which refers to indexing in a map,
+  // return the Map_index_expression structure.  Otherwise, return
+  // NULL.
+  Map_index_expression*
+  map_index_expression()
+  { return this->convert<Map_index_expression, EXPRESSION_MAP_INDEX>(); }
+
+  // If this is a bound method expression, return the
+  // Bound_method_expression structure.  Otherwise, return NULL.
+  Bound_method_expression*
+  bound_method_expression()
+  { return this->convert<Bound_method_expression, EXPRESSION_BOUND_METHOD>(); }
+
+  // If this is a reference to a field in a struct, return the
+  // Field_reference_expression structure.  Otherwise, return NULL.
+  Field_reference_expression*
+  field_reference_expression()
+  {
+    return this->convert<Field_reference_expression,
+                        EXPRESSION_FIELD_REFERENCE>();
+  }
+
+  // If this is a reference to a field in an interface, return the
+  // Interface_field_reference_expression structure.  Otherwise,
+  // return NULL.
+  Interface_field_reference_expression*
+  interface_field_reference_expression()
+  {
+    return this->convert<Interface_field_reference_expression,
+                        EXPRESSION_INTERFACE_FIELD_REFERENCE>();
+  }
+
+  // If this is a type guard expression, return the
+  // Type_guard_expression structure.  Otherwise, return NULL.
+  Type_guard_expression*
+  type_guard_expression()
+  { return this->convert<Type_guard_expression, EXPRESSION_TYPE_GUARD>(); }
+
+  // If this is a receive expression, return the Receive_expression
+  // structure.  Otherwise, return NULL.
+  Receive_expression*
+  receive_expression()
+  { return this->convert<Receive_expression, EXPRESSION_RECEIVE>(); }
+
+  // Return true if this is a composite literal.
+  bool
+  is_composite_literal() const;
+
+  // Return true if this is a composite literal which is not constant.
+  bool
+  is_nonconstant_composite_literal() const;
+
+  // Return true if this is a reference to a local variable.
+  bool
+  is_local_variable() const;
+
+  // Traverse an expression.
+  static int
+  traverse(Expression**, Traverse*);
+
+  // Traverse subexpressions of this expression.
+  int
+  traverse_subexpressions(Traverse*);
+
+  // Lower an expression.  This is called immediately after parsing.
+  // IOTA_VALUE is the value that we should give to any iota
+  // expressions.  This function must resolve expressions which could
+  // not be fully parsed into their final form.  It returns the same
+  // Expression or a new one.
+  Expression*
+  lower(Gogo* gogo, Named_object* function, int iota_value)
+  { return this->do_lower(gogo, function, iota_value); }
+
+  // Determine the real type of an expression with abstract integer,
+  // floating point, or complex type.  TYPE_CONTEXT describes the
+  // expected type.
+  void
+  determine_type(const Type_context*);
+
+  // Check types in an expression.
+  void
+  check_types(Gogo* gogo)
+  { this->do_check_types(gogo); }
+
+  // Determine the type when there is no context.
+  void
+  determine_type_no_context();
+
+  // Return the current type of the expression.  This may be changed
+  // by determine_type.
+  Type*
+  type()
+  { return this->do_type(); }
+
+  // Return a copy of an expression.
+  Expression*
+  copy()
+  { return this->do_copy(); }
+
+  // Return whether the expression is addressable--something which may
+  // be used as the operand of the unary & operator.
+  bool
+  is_addressable() const
+  { return this->do_is_addressable(); }
+
+  // Note that we are taking the address of this expression.  ESCAPES
+  // is true if this address escapes the current function.
+  void
+  address_taken(bool escapes)
+  { this->do_address_taken(escapes); }
+
+  // Return whether this expression must be evaluated in order
+  // according to the order of evaluation rules.  This is basically
+  // true of all expressions with side-effects.
+  bool
+  must_eval_in_order() const
+  { return this->do_must_eval_in_order(); }
+
+  // Return the tree for this expression.
+  tree
+  get_tree(Translate_context*);
+
+  // Return a tree handling any conversions which must be done during
+  // assignment.
+  static tree
+  convert_for_assignment(Translate_context*, Type* lhs_type, Type* rhs_type,
+                        tree rhs_tree, source_location location);
+
+  // Return a tree converting a value of one interface type to another
+  // interface type.  If FOR_TYPE_GUARD is true this is for a type
+  // assertion.
+  static tree
+  convert_interface_to_interface(Translate_context*, Type* lhs_type,
+                                Type* rhs_type, tree rhs_tree,
+                                bool for_type_guard, source_location);
+
+  // Return a tree implementing the comparison LHS_TREE OP RHS_TREE.
+  // TYPE is the type of both sides.
+  static tree
+  comparison_tree(Translate_context*, Operator op, Type* left_type,
+                 tree left_tree, Type* right_type, tree right_tree,
+                 source_location);
+
+  // Return a tree for the multi-precision integer VAL in TYPE.
+  static tree
+  integer_constant_tree(mpz_t val, tree type);
+
+  // Return a tree for the floating point value VAL in TYPE.
+  static tree
+  float_constant_tree(mpfr_t val, tree type);
+
+  // Return a tree for the complex value REAL/IMAG in TYPE.
+  static tree
+  complex_constant_tree(mpfr_t real, mpfr_t imag, tree type);
+
+  // Export the expression.  This is only used for constants.  It will
+  // be used for things like values of named constants and sizes of
+  // arrays.
+  void
+  export_expression(Export* exp) const
+  { this->do_export(exp); }
+
+  // Import an expression.
+  static Expression*
+  import_expression(Import*);
+
+  // Return a tree which checks that VAL, of arbitrary integer type,
+  // is non-negative and is not more than the maximum value of
+  // BOUND_TYPE.  If SOFAR is not NULL, it is or'red into the result.
+  // The return value may be NULL if SOFAR is NULL.
+  static tree
+  check_bounds(tree val, tree bound_type, tree sofar, source_location);
+
+ protected:
+  // May be implemented by child class: traverse the expressions.
+  virtual int
+  do_traverse(Traverse*);
+
+  // Return a lowered expression.
+  virtual Expression*
+  do_lower(Gogo*, Named_object*, int)
+  { return this; }
+
+  // Return whether this is a constant expression.
+  virtual bool
+  do_is_constant() const
+  { return false; }
+
+  // Return whether this is a constant expression of integral type,
+  // and set VAL to the value.
+  virtual bool
+  do_integer_constant_value(bool, mpz_t, Type**) const
+  { return false; }
+
+  // Return whether this is a constant expression of floating point
+  // type, and set VAL to the value.
+  virtual bool
+  do_float_constant_value(mpfr_t, Type**) const
+  { return false; }
+
+  // Return whether this is a constant expression of complex type, and
+  // set REAL and IMAGE to the value.
+  virtual bool
+  do_complex_constant_value(mpfr_t, mpfr_t, Type**) const
+  { return false; }
+
+  // Return whether this is a constant expression of string type, and
+  // set VAL to the value.
+  virtual bool
+  do_string_constant_value(std::string*) const
+  { return false; }
+
+  // Called by the parser if the value is being discarded.
+  virtual void
+  do_discarding_value();
+
+  // Child class holds type.
+  virtual Type*
+  do_type() = 0;
+
+  // Child class implements determining type information.
+  virtual void
+  do_determine_type(const Type_context*) = 0;
+
+  // Child class implements type checking if needed.
+  virtual void
+  do_check_types(Gogo*)
+  { }
+
+  // Child class implements copying.
+  virtual Expression*
+  do_copy() = 0;
+
+  // Child class implements whether the expression is addressable.
+  virtual bool
+  do_is_addressable() const
+  { return false; }
+
+  // Child class implements taking the address of an expression.
+  virtual void
+  do_address_taken(bool)
+  { }
+
+  // Child class implements whether this expression must be evaluated
+  // in order.
+  virtual bool
+  do_must_eval_in_order() const
+  { return false; }
+
+  // Child class implements conversion to tree.
+  virtual tree
+  do_get_tree(Translate_context*) = 0;
+
+  // Child class implements export.
+  virtual void
+  do_export(Export*) const;
+
+  // For children to call to warn about an unused value.
+  void
+  warn_about_unused_value();
+
+  // For children to call when they detect that they are in error.
+  void
+  set_is_error();
+
+  // For children to call to report an error conveniently.
+  void
+  report_error(const char*);
+
+ private:
+  // Convert to the desired statement classification, or return NULL.
+  // This is a controlled dynamic cast.
+  template<typename Expression_class,
+          Expression_classification expr_classification>
+  Expression_class*
+  convert()
+  {
+    return (this->classification_ == expr_classification
+           ? static_cast<Expression_class*>(this)
+           : NULL);
+  }
+
+  template<typename Expression_class,
+          Expression_classification expr_classification>
+  const Expression_class*
+  convert() const
+  {
+    return (this->classification_ == expr_classification
+           ? static_cast<const Expression_class*>(this)
+           : NULL);
+  }
+
+  static tree
+  convert_type_to_interface(Translate_context*, Type*, Type*, tree,
+                           source_location);
+
+  static tree
+  get_interface_type_descriptor(Translate_context*, Type*, tree,
+                               source_location);
+
+  static tree
+  convert_interface_to_type(Translate_context*, Type*, Type*, tree,
+                           source_location);
+
+  // The expression classification.
+  Expression_classification classification_;
+  // The location in the input file.
+  source_location location_;
+};
+
+// A list of Expressions.
+
+class Expression_list
+{
+ public:
+  Expression_list()
+    : entries_()
+  { }
+
+  // Return whether the list is empty.
+  bool
+  empty() const
+  { return this->entries_.empty(); }
+
+  // Return the number of entries in the list.
+  size_t
+  size() const
+  { return this->entries_.size(); }
+
+  // Add an entry to the end of the list.
+  void
+  push_back(Expression* expr)
+  { this->entries_.push_back(expr); }
+
+  void
+  append(Expression_list* add)
+  { this->entries_.insert(this->entries_.end(), add->begin(), add->end()); }
+
+  // Reserve space in the list.
+  void
+  reserve(size_t size)
+  { this->entries_.reserve(size); }
+
+  // Traverse the expressions in the list.
+  int
+  traverse(Traverse*);
+
+  // Copy the list.
+  Expression_list*
+  copy();
+
+  // Return true if the list contains an error expression.
+  bool
+  contains_error() const;
+
+  // Return the first and last elements.
+  Expression*&
+  front()
+  { return this->entries_.front(); }
+
+  Expression*
+  front() const
+  { return this->entries_.front(); }
+
+  Expression*&
+  back()
+  { return this->entries_.back(); }
+
+  Expression*
+  back() const
+  { return this->entries_.back(); }
+
+  // Iterators.
+
+  typedef std::vector<Expression*>::iterator iterator;
+  typedef std::vector<Expression*>::const_iterator const_iterator;
+
+  iterator
+  begin()
+  { return this->entries_.begin(); }
+
+  const_iterator
+  begin() const
+  { return this->entries_.begin(); }
+
+  iterator
+  end()
+  { return this->entries_.end(); }
+
+  const_iterator
+  end() const
+  { return this->entries_.end(); }
+
+  // Erase an entry.
+  void
+  erase(iterator p)
+  { this->entries_.erase(p); }
+
+ private:
+  std::vector<Expression*> entries_;
+};
+
+// An abstract base class for an expression which is only used by the
+// parser, and is lowered in the lowering pass.
+
+class Parser_expression : public Expression
+{
+ public:
+  Parser_expression(Expression_classification classification,
+                   source_location location)
+    : Expression(classification, location)
+  { }
+
+ protected:
+  virtual Expression*
+  do_lower(Gogo*, Named_object*, int) = 0;
+
+  Type*
+  do_type()
+  { gcc_unreachable(); }
+
+  void
+  do_determine_type(const Type_context*)
+  { gcc_unreachable(); }
+
+  void
+  do_check_types(Gogo*)
+  { gcc_unreachable(); }
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+};
+
+// An expression which is simply a variable.
+
+class Var_expression : public Expression
+{
+ public:
+  Var_expression(Named_object* variable, source_location location)
+    : Expression(EXPRESSION_VAR_REFERENCE, location),
+      variable_(variable)
+  { }
+
+  // Return the variable.
+  Named_object*
+  named_object() const
+  { return this->variable_; }
+
+  // Return the name of the variable.
+  const std::string&
+  name() const;
+
+ protected:
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  bool
+  do_is_addressable() const
+  { return true; }
+
+  void
+  do_address_taken(bool);
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The variable we are referencing.
+  Named_object* variable_;
+};
+
+// A reference to a temporary variable.
+
+class Temporary_reference_expression : public Expression
+{
+ public:
+  Temporary_reference_expression(Temporary_statement* statement,
+                                source_location location)
+    : Expression(EXPRESSION_TEMPORARY_REFERENCE, location),
+      statement_(statement)
+  { }
+
+ protected:
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return make_temporary_reference(this->statement_, this->location()); }
+
+  bool
+  do_is_addressable() const
+  { return true; }
+
+  void
+  do_address_taken(bool);
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The statement where the temporary variable is defined.
+  Temporary_statement* statement_;
+};
+
+// A string expression.
+
+class String_expression : public Expression
+{
+ public:
+  String_expression(const std::string& val, source_location location)
+    : Expression(EXPRESSION_STRING, location),
+      val_(val), type_(NULL)
+  { }
+
+  const std::string&
+  val() const
+  { return this->val_; }
+
+  static Expression*
+  do_import(Import*);
+
+ protected:
+  bool
+  do_is_constant() const
+  { return true; }
+
+  bool
+  do_string_constant_value(std::string* val) const
+  {
+    *val = this->val_;
+    return true;
+  }
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // The string value.  This is immutable.
+  const std::string val_;
+  // The type as determined by context.
+  Type* type_;
+};
+
+// A binary expression.
+
+class Binary_expression : public Expression
+{
+ public:
+  Binary_expression(Operator op, Expression* left, Expression* right,
+                   source_location location)
+    : Expression(EXPRESSION_BINARY, location),
+      op_(op), left_(left), right_(right)
+  { }
+
+  // Return the operator.
+  Operator
+  op()
+  { return this->op_; }
+
+  // Return the left hand expression.
+  Expression*
+  left()
+  { return this->left_; }
+
+  // Return the right hand expression.
+  Expression*
+  right()
+  { return this->right_; }
+
+  // Apply binary opcode OP to LEFT_VAL and RIGHT_VAL, setting VAL.
+  // LEFT_TYPE is the type of LEFT_VAL, RIGHT_TYPE is the type of
+  // RIGHT_VAL; LEFT_TYPE and/or RIGHT_TYPE may be NULL.  Return true
+  // if this could be done, false if not.
+  static bool
+  eval_integer(Operator op, Type* left_type, mpz_t left_val,
+              Type* right_type, mpz_t right_val, source_location,
+              mpz_t val);
+
+  // Apply binary opcode OP to LEFT_VAL and RIGHT_VAL, setting VAL.
+  // Return true if this could be done, false if not.
+  static bool
+  eval_float(Operator op, Type* left_type, mpfr_t left_val,
+            Type* right_type, mpfr_t right_val, mpfr_t val,
+            source_location);
+
+  // Apply binary opcode OP to LEFT_REAL/LEFT_IMAG and
+  // RIGHT_REAL/RIGHT_IMAG, setting REAL/IMAG.  Return true if this
+  // could be done, false if not.
+  static bool
+  eval_complex(Operator op, Type* left_type, mpfr_t left_real,
+              mpfr_t left_imag, Type* right_type, mpfr_t right_real,
+              mpfr_t right_imag, mpfr_t real, mpfr_t imag, source_location);
+
+  // Compare integer constants according to OP.
+  static bool
+  compare_integer(Operator op, mpz_t left_val, mpz_t right_val);
+
+  // Compare floating point constants according to OP.
+  static bool
+  compare_float(Operator op, Type* type, mpfr_t left_val, mpfr_t right_val);
+
+  // Compare complex constants according to OP.
+  static bool
+  compare_complex(Operator op, Type* type, mpfr_t left_real, mpfr_t left_imag,
+                 mpfr_t right_val, mpfr_t right_imag);
+
+  static Expression*
+  do_import(Import*);
+
+  // Report an error if OP can not be applied to TYPE.  Return whether
+  // it can.
+  static bool
+  check_operator_type(Operator op, Type* type, source_location);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  bool
+  do_is_constant() const
+  { return this->left_->is_constant() && this->right_->is_constant(); }
+
+  bool
+  do_integer_constant_value(bool, mpz_t val, Type**) const;
+
+  bool
+  do_float_constant_value(mpfr_t val, Type**) const;
+
+  bool
+  do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const;
+
+  void
+  do_discarding_value();
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_binary(this->op_, this->left_->copy(),
+                                  this->right_->copy(), this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // The binary operator to apply.
+  Operator op_;
+  // The left hand side operand.
+  Expression* left_;
+  // The right hand side operand.
+  Expression* right_;
+};
+
+// A call expression.  The go statement needs to dig inside this.
+
+class Call_expression : public Expression
+{
+ public:
+  Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
+                 source_location location)
+    : Expression(EXPRESSION_CALL, location),
+      fn_(fn), args_(args), type_(NULL), tree_(NULL), is_varargs_(is_varargs),
+      is_value_discarded_(false), varargs_are_lowered_(false),
+      is_deferred_(false)
+  { }
+
+  // The function to call.
+  Expression*
+  fn() const
+  { return this->fn_; }
+
+  // The arguments.
+  Expression_list*
+  args()
+  { return this->args_; }
+
+  const Expression_list*
+  args() const
+  { return this->args_; }
+
+  // Get the function type.
+  Function_type*
+  get_function_type() const;
+
+  // Return the number of values this call will return.
+  size_t
+  result_count() const;
+
+  // Return whether this is a call to the predeclared function
+  // recover.
+  bool
+  is_recover_call() const;
+
+  // Set the argument for a call to recover.
+  void
+  set_recover_arg(Expression*);
+
+  // Whether the last argument is a varargs argument (f(a...)).
+  bool
+  is_varargs() const
+  { return this->is_varargs_; }
+
+  // Whether this call is being deferred.
+  bool
+  is_deferred() const
+  { return this->is_deferred_; }
+
+  // Note that the call is being deferred.
+  void
+  set_is_deferred()
+  { this->is_deferred_ = true; }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  virtual Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  void
+  do_discarding_value()
+  { this->is_value_discarded_ = true; }
+
+  virtual Type*
+  do_type();
+
+  virtual void
+  do_determine_type(const Type_context*);
+
+  virtual void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_call(this->fn_->copy(), this->args_->copy(),
+                                this->is_varargs_, this->location());
+  }
+
+  bool
+  do_must_eval_in_order() const;
+
+  virtual tree
+  do_get_tree(Translate_context*);
+
+  virtual bool
+  do_is_recover_call() const;
+
+  virtual void
+  do_set_recover_arg(Expression*);
+
+  // Let a builtin expression change the argument list.
+  void
+  set_args(Expression_list* args)
+  { this->args_ = args; }
+
+  // Let a builtin expression lower varargs.
+  Expression*
+  lower_varargs(Gogo*, Named_object* function, Type* varargs_type,
+               size_t param_count);
+
+ private:
+  bool
+  is_compatible_varargs_argument(Named_object*, Expression*, Type*, bool*);
+
+  bool
+  check_argument_type(int, const Type*, const Type*, source_location, bool);
+
+  tree
+  bound_method_function(Translate_context*, Bound_method_expression*, tree*);
+
+  tree
+  interface_method_function(Translate_context*,
+                           Interface_field_reference_expression*,
+                           tree*);
+
+  // The function to call.
+  Expression* fn_;
+  // The arguments to pass.  This may be NULL if there are no
+  // arguments.
+  Expression_list* args_;
+  // The type of the expression, to avoid recomputing it.
+  Type* type_;
+  // The tree for the call, used for a call which returns a tuple.
+  tree tree_;
+  // True if the last argument is a varargs argument (f(a...)).
+  bool is_varargs_;
+  // True if the value is being discarded.
+  bool is_value_discarded_;
+  // True if varargs have already been lowered.
+  bool varargs_are_lowered_;
+  // True if the call is an argument to a defer statement.
+  bool is_deferred_;
+};
+
+// An expression which represents a pointer to a function.
+
+class Func_expression : public Expression
+{
+ public:
+  Func_expression(Named_object* function, Expression* closure,
+                 source_location location)
+    : Expression(EXPRESSION_FUNC_REFERENCE, location),
+      function_(function), closure_(closure)
+  { }
+
+  // Return the object associated with the function.
+  const Named_object*
+  named_object() const
+  { return this->function_; }
+
+  // Return the name of the function.
+  const std::string&
+  name() const;
+
+  // Return the closure for this function.  This will return NULL if
+  // the function has no closure, which is the normal case.
+  Expression*
+  closure()
+  { return this->closure_; }
+
+  // Return a tree for this function without evaluating the closure.
+  tree
+  get_tree_without_closure(Gogo*);
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*)
+  {
+    if (this->closure_ != NULL)
+      this->closure_->determine_type_no_context();
+  }
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_func_reference(this->function_,
+                                          this->closure_->copy(),
+                                          this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The function itself.
+  Named_object* function_;
+  // A closure.  This is normally NULL.  For a nested function, it may
+  // be a heap-allocated struct holding pointers to all the variables
+  // referenced by this function and defined in enclosing functions.
+  Expression* closure_;
+};
+
+// A reference to an unknown name.
+
+class Unknown_expression : public Parser_expression
+{
+ public:
+  Unknown_expression(Named_object* named_object, source_location location)
+    : Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location),
+      named_object_(named_object), is_composite_literal_key_(false)
+  { }
+
+  // The associated named object.
+  Named_object*
+  named_object() const
+  { return this->named_object_; }
+
+  // The name of the identifier which was unknown.
+  const std::string&
+  name() const;
+
+  // Note that this expression is being used as the key in a composite
+  // literal, so it may be OK if it is not resolved.
+  void
+  set_is_composite_literal_key()
+  { this->is_composite_literal_key_ = true; }
+
+ protected:
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  Expression*
+  do_copy()
+  { return new Unknown_expression(this->named_object_, this->location()); }
+
+ private:
+  // The unknown name.
+  Named_object* named_object_;
+  // True if this is the key in a composite literal.
+  bool is_composite_literal_key_;
+};
+
+// An index expression.  This is lowered to an array index, a string
+// index, or a map index.
+
+class Index_expression : public Parser_expression
+{
+ public:
+  Index_expression(Expression* left, Expression* start, Expression* end,
+                  source_location location)
+    : Parser_expression(EXPRESSION_INDEX, location),
+      left_(left), start_(start), end_(end), is_lvalue_(false)
+  { }
+
+  // Record that this expression is an lvalue.
+  void
+  set_is_lvalue()
+  { this->is_lvalue_ = true; }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Expression*
+  do_lower(Gogo*, Named_object*, int);
+
+  Expression*
+  do_copy()
+  {
+    return new Index_expression(this->left_->copy(), this->start_->copy(),
+                               (this->end_ == NULL
+                                ? NULL
+                                : this->end_->copy()),
+                               this->location());
+  }
+
+ private:
+  // The expression being indexed.
+  Expression* left_;
+  // The first index.
+  Expression* start_;
+  // The second index.  This is NULL for an index, non-NULL for a
+  // slice.
+  Expression* end_;
+  // Whether this is being used as an l-value.  We set this during the
+  // parse because map index expressions need to know.
+  bool is_lvalue_;
+};
+
+// An index into a map.
+
+class Map_index_expression : public Expression
+{
+ public:
+  Map_index_expression(Expression* map, Expression* index,
+                      source_location location)
+    : Expression(EXPRESSION_MAP_INDEX, location),
+      map_(map), index_(index), is_lvalue_(false),
+      is_in_tuple_assignment_(false)
+  { }
+
+  // Return the map.
+  Expression*
+  map()
+  { return this->map_; }
+
+  const Expression*
+  map() const
+  { return this->map_; }
+
+  // Return the index.
+  Expression*
+  index()
+  { return this->index_; }
+
+  const Expression*
+  index() const
+  { return this->index_; }
+
+  // Get the type of the map being indexed.
+  Map_type*
+  get_map_type() const;
+
+  // Record that this map expression is an lvalue.  The difference is
+  // that an lvalue always inserts the key.
+  void
+  set_is_lvalue()
+  { this->is_lvalue_ = true; }
+
+  // Return whether this map expression occurs in an assignment to a
+  // pair of values.
+  bool
+  is_in_tuple_assignment() const
+  { return this->is_in_tuple_assignment_; }
+
+  // Record that this map expression occurs in an assignment to a pair
+  // of values.
+  void
+  set_is_in_tuple_assignment()
+  { this->is_in_tuple_assignment_ = true; }
+
+  // Return a tree for the map index.  This returns a tree which
+  // evaluates to a pointer to a value in the map.  If INSERT is true,
+  // the key will be inserted if not present, and the value pointer
+  // will be zero initialized.  If INSERT is false, and the key is not
+  // present in the map, the pointer will be NULL.
+  tree
+  get_value_pointer(Translate_context*, bool insert);
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_map_index(this->map_->copy(),
+                                     this->index_->copy(),
+                                     this->location());
+  }
+
+  // A map index expression is an lvalue but it is not addressable.
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The map we are looking into.
+  Expression* map_;
+  // The index.
+  Expression* index_;
+  // Whether this is an lvalue.
+  bool is_lvalue_;
+  // Whether this is in a tuple assignment to a pair of values.
+  bool is_in_tuple_assignment_;
+};
+
+// An expression which represents a method bound to its first
+// argument.
+
+class Bound_method_expression : public Expression
+{
+ public:
+  Bound_method_expression(Expression* expr, Expression* method,
+                         source_location location)
+    : Expression(EXPRESSION_BOUND_METHOD, location),
+      expr_(expr), expr_type_(NULL), method_(method)
+  { }
+
+  // Return the object which is the first argument.
+  Expression*
+  first_argument()
+  { return this->expr_; }
+
+  // Return the implicit type of the first argument.  This will be
+  // non-NULL when using a method from an anonymous field without
+  // using an explicit stub.
+  Type*
+  first_argument_type() const
+  { return this->expr_type_; }
+
+  // Return the reference to the method function.
+  Expression*
+  method()
+  { return this->method_; }
+
+  // Set the implicit type of the expression.
+  void
+  set_first_argument_type(Type* type)
+  { this->expr_type_ = type; }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return new Bound_method_expression(this->expr_->copy(),
+                                      this->method_->copy(),
+                                      this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The object used to find the method.  This is passed to the method
+  // as the first argument.
+  Expression* expr_;
+  // The implicit type of the object to pass to the method.  This is
+  // NULL in the normal case, non-NULL when using a method from an
+  // anonymous field which does not require a stub.
+  Type* expr_type_;
+  // The method itself.  This is a Func_expression.
+  Expression* method_;
+};
+
+// A reference to a field in a struct.
+
+class Field_reference_expression : public Expression
+{
+ public:
+  Field_reference_expression(Expression* expr, unsigned int field_index,
+                            source_location location)
+    : Expression(EXPRESSION_FIELD_REFERENCE, location),
+      expr_(expr), field_index_(field_index)
+  { }
+
+  // Return the struct expression.
+  Expression*
+  expr() const
+  { return this->expr_; }
+
+  // Return the field index.
+  unsigned int
+  field_index() const
+  { return this->field_index_; }
+
+  // Set the struct expression.  This is used when parsing.
+  void
+  set_struct_expression(Expression* expr)
+  {
+    gcc_assert(this->expr_ == NULL);
+    this->expr_ = expr;
+  }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Expression::traverse(&this->expr_, traverse); }
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*)
+  { this->expr_->determine_type_no_context(); }
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_field_reference(this->expr_->copy(),
+                                           this->field_index_,
+                                           this->location());
+  }
+
+  bool
+  do_is_addressable() const
+  { return this->expr_->is_addressable(); }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The expression we are looking into.  This should have a type of
+  // struct.
+  Expression* expr_;
+  // The zero-based index of the field we are retrieving.
+  unsigned int field_index_;
+};
+
+// A reference to a field of an interface.
+
+class Interface_field_reference_expression : public Expression
+{
+ public:
+  Interface_field_reference_expression(Expression* expr,
+                                      const std::string& name,
+                                      source_location location)
+    : Expression(EXPRESSION_INTERFACE_FIELD_REFERENCE, location),
+      expr_(expr), name_(name)
+  { }
+
+  // Return the expression for the interface object.
+  Expression*
+  expr()
+  { return this->expr_; }
+
+  // Return the name of the method to call.
+  const std::string&
+  name() const
+  { return this->name_; }
+
+  // Return a tree for the pointer to the function to call, given a
+  // tree for the expression.
+  tree
+  get_function_tree(Translate_context*, tree);
+
+  // Return a tree for the first argument to pass to the interface
+  // function, given a tree for the expression.  This is the real
+  // object associated with the interface object.
+  tree
+  get_underlying_object_tree(Translate_context*, tree);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_interface_field_reference(this->expr_->copy(),
+                                                     this->name_,
+                                                     this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The expression for the interface object.  This should have a type
+  // of interface or pointer to interface.
+  Expression* expr_;
+  // The field we are retrieving--the name of the method.
+  std::string name_;
+};
+
+// A type guard expression.
+
+class Type_guard_expression : public Expression
+{
+ public:
+  Type_guard_expression(Expression* expr, Type* type, source_location location)
+    : Expression(EXPRESSION_TYPE_GUARD, location),
+      expr_(expr), type_(type)
+  { }
+
+  // Return the expression to convert.
+  Expression*
+  expr()
+  { return this->expr_; }
+
+  // Return the type to which to convert.
+  Type*
+  type()
+  { return this->type_; }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*)
+  { this->expr_->determine_type_no_context(); }
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return new Type_guard_expression(this->expr_->copy(), this->type_,
+                                    this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The expression to convert.
+  Expression* expr_;
+  // The type to which to convert.
+  Type* type_;
+};
+
+// A receive expression.
+
+class Receive_expression : public Expression
+{
+ public:
+  Receive_expression(Expression* channel, source_location location)
+    : Expression(EXPRESSION_RECEIVE, location),
+      channel_(channel), is_value_discarded_(false), for_select_(false)
+  { }
+
+  // Return the channel.
+  Expression*
+  channel()
+  { return this->channel_; }
+
+  // Note that this is for a select statement.
+  void
+  set_for_select()
+  { this->for_select_ = true; }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Expression::traverse(&this->channel_, traverse); }
+
+  void
+  do_discarding_value()
+  { this->is_value_discarded_ = true; }
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*)
+  { this->channel_->determine_type_no_context(); }
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_receive(this->channel_->copy(), this->location());
+  }
+
+  bool
+  do_must_eval_in_order() const
+  { return true; }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The channel from which we are receiving.
+  Expression* channel_;
+  // Whether the value is being discarded.
+  bool is_value_discarded_;
+  // Whether this is for a select statement.
+  bool for_select_;
+};
+
+// A send expression.
+
+class Send_expression : public Expression
+{
+ public:
+  Send_expression(Expression* channel, Expression* val,
+                 source_location location)
+    : Expression(EXPRESSION_SEND, location),
+      channel_(channel), val_(val), is_value_discarded_(false),
+      for_select_(false)
+  { }
+
+  // Note that this is for a select statement.
+  void
+  set_for_select()
+  { this->for_select_ = true; }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  void
+  do_discarding_value()
+  { this->is_value_discarded_ = true; }
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  void
+  do_check_types(Gogo*);
+
+  Expression*
+  do_copy()
+  {
+    return Expression::make_send(this->channel_->copy(), this->val_->copy(),
+                                this->location());
+  }
+
+  bool
+  do_must_eval_in_order() const
+  { return true; }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The channel on which to send the value.
+  Expression* channel_;
+  // The value to send.
+  Expression* val_;
+  // Whether the value is being discarded.
+  bool is_value_discarded_;
+  // Whether this is for a select statement.
+  bool for_select_;
+};
+
+#endif // !defined(GO_EXPRESSIONS_H)
diff --git a/gcc/go/gofrontend/go-dump.cc b/gcc/go/gofrontend/go-dump.cc
new file mode 100644 (file)
index 0000000..dd5a4c3
--- /dev/null
@@ -0,0 +1,53 @@
+// go-dump.cc -- Go frontend debug dumps.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "go-c.h"
+#include "go-dump.h"
+
+namespace {
+
+// The list of dumps.
+
+Go_dump* dumps;
+
+} // End empty namespace.
+
+// Create a new dump.
+
+Go_dump::Go_dump(const char* name)
+  : next_(dumps), name_(name), is_enabled_(false)
+{
+  dumps = this;
+}
+
+// Enable a dump by name.
+
+bool
+Go_dump::enable_by_name(const char* name)
+{
+  bool is_all = strcmp(name, "all") == 0;
+  bool found = false;
+  for (Go_dump* p = dumps; p != NULL; p = p->next_)
+    {
+      if (is_all || strcmp(name, p->name_) == 0)
+       {
+         p->is_enabled_ = true;
+         found = true;
+       }
+    }
+  return found;
+}
+
+// Enable a dump.  Return 1 if this is a real name, 0 if not.
+
+GO_EXTERN_C
+int
+go_enable_dump(const char* name)
+{
+  return Go_dump::enable_by_name(name) ? 1 : 0;
+}
diff --git a/gcc/go/gofrontend/go-dump.h b/gcc/go/gofrontend/go-dump.h
new file mode 100644 (file)
index 0000000..13639bc
--- /dev/null
@@ -0,0 +1,38 @@
+// go-dump.h -- Go frontend debug dumps.    -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_DUMP_H
+#define GO_DUMP_H
+
+// This class manages different arguments to -fgo-dump-XXX.  If you
+// want to create a new dump, create a variable of this type with the
+// name to use for XXX.  You can then use is_enabled to see whether
+// the -fgo-dump-XXX option was used on the command line.
+
+class Go_dump
+{
+ public:
+  Go_dump(const char* name);
+
+  // Whether this dump was enabled.
+  bool
+  is_enabled() const
+  { return this->is_enabled_; }
+
+  // Enable a dump by name.  Return true if the dump was found.
+  static bool
+  enable_by_name(const char*);
+
+ private:
+  // The next dump.  These are not in any order.
+  Go_dump* next_;
+  // The name of this dump.
+  const char* name_;
+  // Whether this dump was enabled.
+  bool is_enabled_;
+};
+
+#endif // !defined(GO_DUMP_H)
diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc
new file mode 100644 (file)
index 0000000..c756084
--- /dev/null
@@ -0,0 +1,153 @@
+// go.cc -- Go frontend main file for gcc.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "go-c.h"
+
+#include "lex.h"
+#include "parse.h"
+#include "gogo.h"
+
+// The unique prefix to use for exported symbols.  This is set during
+// option processing.
+
+static std::string unique_prefix;
+
+// The data structures we build to represent the file.
+static Gogo* gogo;
+
+// Create the main IR data structure.
+
+GO_EXTERN_C
+void
+go_create_gogo(int int_type_size, int float_type_size, int pointer_size)
+{
+  gcc_assert(::gogo == NULL);
+  ::gogo = new Gogo(int_type_size, float_type_size, pointer_size);
+  if (!unique_prefix.empty())
+    ::gogo->set_unique_prefix(unique_prefix);
+}
+
+// Set the unique prefix we use for exported symbols.
+
+GO_EXTERN_C
+void
+go_set_prefix(const char* arg)
+{
+  unique_prefix = arg;
+  for (size_t i = 0; i < unique_prefix.length(); ++i)
+    {
+      char c = unique_prefix[i];
+      if ((c >= 'a' && c <= 'z')
+         || (c >= 'A' && c <= 'Z')
+         || (c >= '0' && c <= '9')
+         || c == '_')
+       ;
+      else
+       unique_prefix[i] = '_';
+    }
+}
+
+// Parse the input files.
+
+GO_EXTERN_C
+void
+go_parse_input_files(const char** filenames, unsigned int filename_count,
+                    bool only_check_syntax, bool require_return_statement)
+{
+  gcc_assert(filename_count > 0);
+  for (unsigned int i = 0; i < filename_count; ++i)
+    {
+      if (i > 0)
+       ::gogo->clear_file_scope();
+
+      const char* filename = filenames[i];
+      FILE* file;
+      if (strcmp(filename, "-") == 0)
+       file = stdin;
+      else
+       {
+         file = fopen(filename, "r");
+         if (file == NULL)
+           fatal_error("cannot open %s: %m", filename);
+       }
+
+      Lex lexer(filename, file);
+
+      Parse parse(&lexer, ::gogo);
+      parse.program();
+
+      if (strcmp(filename, "-") != 0)
+       fclose(file);
+    }
+
+  ::gogo->clear_file_scope();
+
+  // If the global predeclared names are referenced but not defined,
+  // define them now.
+  ::gogo->define_global_names();
+
+  // Finalize method lists and build stub methods for named types.
+  ::gogo->finalize_methods();
+
+  // Now that we have seen all the names, lower the parse tree into a
+  // form which is easier to use.
+  ::gogo->lower_parse_tree();
+
+  // Now that we have seen all the names, verify that types are
+  // correct.
+  ::gogo->verify_types();
+
+  // Work out types of unspecified constants and variables.
+  ::gogo->determine_types();
+
+  // Check types and issue errors as appropriate.
+  ::gogo->check_types();
+
+  if (only_check_syntax)
+    return;
+
+  // Check that functions have return statements.
+  if (require_return_statement)
+    ::gogo->check_return_statements();
+
+  // Export global identifiers as appropriate.
+  ::gogo->do_exports();
+
+  // Build required interface method tables.
+  ::gogo->build_interface_method_tables();
+
+  // Turn short-cut operators (&&, ||) into explicit if statements.
+  ::gogo->remove_shortcuts();
+
+  // Use temporary variables to force order of evaluation.
+  ::gogo->order_evaluations();
+
+  // Build thunks for functions which call recover.
+  ::gogo->build_recover_thunks();
+
+  // Convert complicated go and defer statements into simpler ones.
+  ::gogo->simplify_thunk_statements();
+}
+
+// Write out globals.
+
+GO_EXTERN_C
+void
+go_write_globals()
+{
+  return ::gogo->write_globals();
+}
+
+// Return the global IR structure.  This is used by some of the
+// langhooks to pass to other code.
+
+Gogo*
+go_get_gogo()
+{
+  return ::gogo;
+}
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
new file mode 100644 (file)
index 0000000..755a0e9
--- /dev/null
@@ -0,0 +1,3105 @@
+// gogo-tree.cc -- convert Go frontend Gogo IR to gcc trees.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include <gmp.h>
+
+#ifndef ENABLE_BUILD_WITH_CXX
+extern "C"
+{
+#endif
+
+#include "tm.h"
+#include "toplev.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-iterator.h"
+#include "cgraph.h"
+#include "langhooks.h"
+#include "convert.h"
+#include "output.h"
+#include "diagnostic.h"
+#include "rtl.h"
+
+#ifndef ENABLE_BUILD_WITH_CXX
+}
+#endif
+
+#include "go-c.h"
+#include "types.h"
+#include "expressions.h"
+#include "statements.h"
+#include "gogo.h"
+
+// Whether we have seen any errors.
+
+bool
+saw_errors()
+{
+  return errorcount != 0 || sorrycount != 0;
+}
+
+// A helper function.
+
+static inline tree
+get_identifier_from_string(const std::string& str)
+{
+  return get_identifier_with_length(str.data(), str.length());
+}
+
+// Builtin functions.
+
+static std::map<std::string, tree> builtin_functions;
+
+// Define a builtin function.  BCODE is the builtin function code
+// defined by builtins.def.  NAME is the name of the builtin function.
+// LIBNAME is the name of the corresponding library function, and is
+// NULL if there isn't one.  FNTYPE is the type of the function.
+// CONST_P is true if the function has the const attribute.
+
+static void
+define_builtin(built_in_function bcode, const char* name, const char* libname,
+              tree fntype, bool const_p)
+{
+  tree decl = add_builtin_function(name, fntype, bcode, BUILT_IN_NORMAL,
+                                  libname, NULL_TREE);
+  if (const_p)
+    TREE_READONLY(decl) = 1;
+  built_in_decls[bcode] = decl;
+  implicit_built_in_decls[bcode] = decl;
+  builtin_functions[name] = decl;
+  if (libname != NULL)
+    {
+      decl = add_builtin_function(libname, fntype, bcode, BUILT_IN_NORMAL,
+                                 NULL, NULL_TREE);
+      if (const_p)
+       TREE_READONLY(decl) = 1;
+      builtin_functions[libname] = decl;
+    }
+}
+
+// Create trees for implicit builtin functions.
+
+void
+Gogo::define_builtin_function_trees()
+{
+  /* We need to define the fetch_and_add functions, since we use them
+     for ++ and --.  */
+  tree t = go_type_for_size(BITS_PER_UNIT, 1);
+  tree p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
+  define_builtin(BUILT_IN_ADD_AND_FETCH_1, "__sync_fetch_and_add_1", NULL,
+                build_function_type_list(t, p, t, NULL_TREE), false);
+
+  t = go_type_for_size(BITS_PER_UNIT * 2, 1);
+  p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
+  define_builtin (BUILT_IN_ADD_AND_FETCH_2, "__sync_fetch_and_add_2", NULL,
+                 build_function_type_list(t, p, t, NULL_TREE), false);
+
+  t = go_type_for_size(BITS_PER_UNIT * 4, 1);
+  p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
+  define_builtin(BUILT_IN_ADD_AND_FETCH_4, "__sync_fetch_and_add_4", NULL,
+                build_function_type_list(t, p, t, NULL_TREE), false);
+
+  t = go_type_for_size(BITS_PER_UNIT * 8, 1);
+  p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
+  define_builtin(BUILT_IN_ADD_AND_FETCH_8, "__sync_fetch_and_add_8", NULL,
+                build_function_type_list(t, p, t, NULL_TREE), false);
+
+  // We use __builtin_expect for magic import functions.
+  define_builtin(BUILT_IN_EXPECT, "__builtin_expect", NULL,
+                build_function_type_list(long_integer_type_node,
+                                         long_integer_type_node,
+                                         long_integer_type_node,
+                                         NULL_TREE),
+                true);
+
+  // We use __builtin_memmove for the predeclared copy function.
+  define_builtin(BUILT_IN_MEMMOVE, "__builtin_memmove", "memmove",
+                build_function_type_list(ptr_type_node,
+                                         ptr_type_node,
+                                         const_ptr_type_node,
+                                         size_type_node,
+                                         NULL_TREE),
+                false);
+
+  // We provide sqrt for the math library.
+  define_builtin(BUILT_IN_SQRT, "__builtin_sqrt", "sqrt",
+                build_function_type_list(double_type_node,
+                                         double_type_node,
+                                         NULL_TREE),
+                true);
+  define_builtin(BUILT_IN_SQRTL, "__builtin_sqrtl", "sqrtl",
+                build_function_type_list(long_double_type_node,
+                                         long_double_type_node,
+                                         NULL_TREE),
+                true);
+
+  // We use __builtin_return_address in the thunk we build for
+  // functions which call recover.
+  define_builtin(BUILT_IN_RETURN_ADDRESS, "__builtin_return_address", NULL,
+                build_function_type_list(ptr_type_node,
+                                         unsigned_type_node,
+                                         NULL_TREE),
+                false);
+
+  // The compiler uses __builtin_trap for some exception handling
+  // cases.
+  define_builtin(BUILT_IN_TRAP, "__builtin_trap", NULL,
+                build_function_type(void_type_node, void_list_node),
+                false);
+}
+
+// Get the name to use for the import control function.  If there is a
+// global function or variable, then we know that that name must be
+// unique in the link, and we use it as the basis for our name.
+
+const std::string&
+Gogo::get_init_fn_name()
+{
+  if (this->init_fn_name_.empty())
+    {
+      gcc_assert(this->package_ != NULL);
+      if (this->package_name() == "main")
+       {
+         // Use a name which the runtime knows.
+         this->init_fn_name_ = "__go_init_main";
+       }
+      else
+       {
+         std::string s = this->unique_prefix();
+         s.append(1, '.');
+         s.append(this->package_name());
+         s.append("..import");
+         this->init_fn_name_ = s;
+       }
+    }
+
+  return this->init_fn_name_;
+}
+
+// Add statements to INIT_STMT_LIST which run the initialization
+// functions for imported packages.  This is only used for the "main"
+// package.
+
+void
+Gogo::init_imports(tree* init_stmt_list)
+{
+  gcc_assert(this->package_name() == "main");
+
+  if (this->imported_init_fns_.empty())
+    return;
+
+  tree fntype = build_function_type(void_type_node, void_list_node);
+
+  // We must call them in increasing priority order.
+  std::vector<Import_init> v;
+  for (std::set<Import_init>::const_iterator p =
+        this->imported_init_fns_.begin();
+       p != this->imported_init_fns_.end();
+       ++p)
+    v.push_back(*p);
+  std::sort(v.begin(), v.end());
+
+  for (std::vector<Import_init>::const_iterator p = v.begin();
+       p != v.end();
+       ++p)
+    {
+      std::string user_name = p->package_name() + ".init";
+      tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL,
+                            get_identifier_from_string(user_name),
+                            fntype);
+      const std::string& init_name(p->init_name());
+      SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(init_name));
+      TREE_PUBLIC(decl) = 1;
+      DECL_EXTERNAL(decl) = 1;
+      append_to_statement_list(build_call_expr(decl, 0), init_stmt_list);
+    }
+}
+
+// Register global variables with the garbage collector.  We need to
+// register all variables which can hold a pointer value.  They become
+// roots during the mark phase.  We build a struct that is easy to
+// hook into a list of roots.
+
+// struct __go_gc_root_list
+// {
+//   struct __go_gc_root_list* __next;
+//   struct __go_gc_root
+//   {
+//     void* __decl;
+//     size_t __size;
+//   } __roots[];
+// };
+
+// The last entry in the roots array has a NULL decl field.
+
+void
+Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
+                      tree* init_stmt_list)
+{
+  if (var_gc.empty())
+    return;
+
+  size_t count = var_gc.size();
+
+  tree root_type = Gogo::builtin_struct(NULL, "__go_gc_root", NULL_TREE, 2,
+                                       "__next",
+                                       ptr_type_node,
+                                       "__size",
+                                       sizetype);
+
+  tree index_type = build_index_type(size_int(count));
+  tree array_type = build_array_type(root_type, index_type);
+
+  tree root_list_type = make_node(RECORD_TYPE);
+  root_list_type = Gogo::builtin_struct(NULL, "__go_gc_root_list",
+                                       root_list_type, 2,
+                                       "__next",
+                                       build_pointer_type(root_list_type),
+                                       "__roots",
+                                       array_type);
+
+  // Build an initialier for the __roots array.
+
+  VEC(constructor_elt,gc)* roots_init = VEC_alloc(constructor_elt, gc,
+                                                 count + 1);
+
+  size_t i = 0;
+  for (std::vector<Named_object*>::const_iterator p = var_gc.begin();
+       p != var_gc.end();
+       ++p, ++i)
+    {
+      VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
+
+      constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+      tree field = TYPE_FIELDS(root_type);
+      elt->index = field;
+      tree decl = (*p)->get_tree(this, NULL);
+      gcc_assert(TREE_CODE(decl) == VAR_DECL);
+      elt->value = build_fold_addr_expr(decl);
+
+      elt = VEC_quick_push(constructor_elt, init, NULL);
+      field = DECL_CHAIN(field);
+      elt->index = field;
+      elt->value = DECL_SIZE_UNIT(decl);
+
+      elt = VEC_quick_push(constructor_elt, roots_init, NULL);
+      elt->index = size_int(i);
+      elt->value = build_constructor(root_type, init);
+    }
+
+  // The list ends with a NULL entry.
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
+
+  constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+  tree field = TYPE_FIELDS(root_type);
+  elt->index = field;
+  elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = DECL_CHAIN(field);
+  elt->index = field;
+  elt->value = size_zero_node;
+
+  elt = VEC_quick_push(constructor_elt, roots_init, NULL);
+  elt->index = size_int(i);
+  elt->value = build_constructor(root_type, init);
+
+  // Build a constructor for the struct.
+
+  VEC(constructor_elt,gc*) root_list_init = VEC_alloc(constructor_elt, gc, 2);
+
+  elt = VEC_quick_push(constructor_elt, root_list_init, NULL);
+  field = TYPE_FIELDS(root_list_type);
+  elt->index = field;
+  elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
+
+  elt = VEC_quick_push(constructor_elt, root_list_init, NULL);
+  field = DECL_CHAIN(field);
+  elt->index = field;
+  elt->value = build_constructor(array_type, roots_init);
+
+  // Build a decl to register.
+
+  tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
+                        create_tmp_var_name("gc"), root_list_type);
+  DECL_EXTERNAL(decl) = 0;
+  TREE_PUBLIC(decl) = 0;
+  TREE_STATIC(decl) = 1;
+  DECL_ARTIFICIAL(decl) = 1;
+  DECL_INITIAL(decl) = build_constructor(root_list_type, root_list_init);
+  rest_of_decl_compilation(decl, 1, 0);
+
+  static tree register_gc_fndecl;
+  tree call = Gogo::call_builtin(&register_gc_fndecl, BUILTINS_LOCATION,
+                                "__go_register_gc_roots",
+                                1,
+                                void_type_node,
+                                build_pointer_type(root_list_type),
+                                build_fold_addr_expr(decl));
+  append_to_statement_list(call, init_stmt_list);
+}
+
+// Build the decl for the initialization function.
+
+tree
+Gogo::initialization_function_decl()
+{
+  // The tedious details of building your own function.  There doesn't
+  // seem to be a helper function for this.
+  std::string name = this->package_name() + ".init";
+  tree fndecl = build_decl(BUILTINS_LOCATION, FUNCTION_DECL,
+                          get_identifier_from_string(name),
+                          build_function_type(void_type_node,
+                                              void_list_node));
+  const std::string& asm_name(this->get_init_fn_name());
+  SET_DECL_ASSEMBLER_NAME(fndecl, get_identifier_from_string(asm_name));
+
+  tree resdecl = build_decl(BUILTINS_LOCATION, RESULT_DECL, NULL_TREE,
+                           void_type_node);
+  DECL_ARTIFICIAL(resdecl) = 1;
+  DECL_CONTEXT(resdecl) = fndecl;
+  DECL_RESULT(fndecl) = resdecl;
+
+  TREE_STATIC(fndecl) = 1;
+  TREE_USED(fndecl) = 1;
+  DECL_ARTIFICIAL(fndecl) = 1;
+  TREE_PUBLIC(fndecl) = 1;
+
+  DECL_INITIAL(fndecl) = make_node(BLOCK);
+  TREE_USED(DECL_INITIAL(fndecl)) = 1;
+
+  return fndecl;
+}
+
+// Create the magic initialization function.  INIT_STMT_LIST is the
+// code that it needs to run.
+
+void
+Gogo::write_initialization_function(tree fndecl, tree init_stmt_list)
+{
+  // Make sure that we thought we needed an initialization function,
+  // as otherwise we will not have reported it in the export data.
+  gcc_assert(this->package_name() == "main" || this->need_init_fn_);
+
+  if (fndecl == NULL_TREE)
+    fndecl = this->initialization_function_decl();
+
+  DECL_SAVED_TREE(fndecl) = init_stmt_list;
+
+  current_function_decl = fndecl;
+  if (DECL_STRUCT_FUNCTION(fndecl) == NULL)
+    push_struct_function(fndecl);
+  else
+    push_cfun(DECL_STRUCT_FUNCTION(fndecl));
+  cfun->function_end_locus = BUILTINS_LOCATION;
+
+  gimplify_function_tree(fndecl);
+
+  cgraph_add_new_function(fndecl, false);
+  cgraph_mark_needed_node(cgraph_node(fndecl));
+
+  current_function_decl = NULL_TREE;
+  pop_cfun();
+}
+
+// Search for references to VAR in any statements or called functions.
+
+class Find_var : public Traverse
+{
+ public:
+  // A hash table we use to avoid looping.  The index is the name of a
+  // named object.  We only look through objects defined in this
+  // package.
+  typedef Unordered_set(std::string) Seen_objects;
+
+  Find_var(Named_object* var, Seen_objects* seen_objects)
+    : Traverse(traverse_expressions),
+      var_(var), seen_objects_(seen_objects), found_(false)
+  { }
+
+  // Whether the variable was found.
+  bool
+  found() const
+  { return this->found_; }
+
+  int
+  expression(Expression**);
+
+ private:
+  // The variable we are looking for.
+  Named_object* var_;
+  // Names of objects we have already seen.
+  Seen_objects* seen_objects_;
+  // True if the variable was found.
+  bool found_;
+};
+
+// See if EXPR refers to VAR, looking through function calls and
+// variable initializations.
+
+int
+Find_var::expression(Expression** pexpr)
+{
+  Expression* e = *pexpr;
+
+  Var_expression* ve = e->var_expression();
+  if (ve != NULL)
+    {
+      Named_object* v = ve->named_object();
+      if (v == this->var_)
+       {
+         this->found_ = true;
+         return TRAVERSE_EXIT;
+       }
+
+      if (v->is_variable() && v->package() == NULL)
+       {
+         Expression* init = v->var_value()->init();
+         if (init != NULL)
+           {
+             std::pair<Seen_objects::iterator, bool> ins =
+               this->seen_objects_->insert(v->name());
+             if (ins.second)
+               {
+                 // This is the first time we have seen this name.
+                 if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
+                   return TRAVERSE_EXIT;
+               }
+           }
+       }
+    }
+
+  // We traverse the code of any function we see.  Note that this
+  // means that we will traverse the code of a function whose address
+  // is taken even if it is not called.
+  Func_expression* fe = e->func_expression();
+  if (fe != NULL)
+    {
+      const Named_object* f = fe->named_object();
+      if (f->is_function() && f->package() == NULL)
+       {
+         std::pair<Seen_objects::iterator, bool> ins =
+           this->seen_objects_->insert(f->name());
+         if (ins.second)
+           {
+             // This is the first time we have seen this name.
+             if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+       }
+    }
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Return true if EXPR refers to VAR.
+
+static bool
+expression_requires(Expression* expr, Block* preinit, Named_object* var)
+{
+  Find_var::Seen_objects seen_objects;
+  Find_var find_var(var, &seen_objects);
+  if (expr != NULL)
+    Expression::traverse(&expr, &find_var);
+  if (preinit != NULL)
+    preinit->traverse(&find_var);
+  
+  return find_var.found();
+}
+
+// Sort variable initializations.  If the initialization expression
+// for variable A refers directly or indirectly to the initialization
+// expression for variable B, then we must initialize B before A.
+
+class Var_init
+{
+ public:
+  Var_init()
+    : var_(NULL), init_(NULL_TREE), waiting_(0)
+  { }
+
+  Var_init(Named_object* var, tree init)
+    : var_(var), init_(init), waiting_(0)
+  { }
+
+  // Return the variable.
+  Named_object*
+  var() const
+  { return this->var_; }
+
+  // Return the initialization expression.
+  tree
+  init() const
+  { return this->init_; }
+
+  // Return the number of variables waiting for this one to be
+  // initialized.
+  size_t
+  waiting() const
+  { return this->waiting_; }
+
+  // Increment the number waiting.
+  void
+  increment_waiting()
+  { ++this->waiting_; }
+
+ private:
+  // The variable being initialized.
+  Named_object* var_;
+  // The initialization expression to run.
+  tree init_;
+  // The number of variables which are waiting for this one.
+  size_t waiting_;
+};
+
+typedef std::list<Var_init> Var_inits;
+
+// Sort the variable initializations.  The rule we follow is that we
+// emit them in the order they appear in the array, except that if the
+// initialization expression for a variable V1 depends upon another
+// variable V2 then we initialize V1 after V2.
+
+static void
+sort_var_inits(Var_inits* var_inits)
+{
+  Var_inits ready;
+  while (!var_inits->empty())
+    {
+      Var_inits::iterator p1 = var_inits->begin();
+      Named_object* var = p1->var();
+      Expression* init = var->var_value()->init();
+      Block* preinit = var->var_value()->preinit();
+
+      // Start walking through the list to see which variables VAR
+      // needs to wait for.  We can skip P1->WAITING variables--that
+      // is the number we've already checked.
+      Var_inits::iterator p2 = p1;
+      ++p2;
+      for (size_t i = p1->waiting(); i > 0; --i)
+       ++p2;
+
+      for (; p2 != var_inits->end(); ++p2)
+       {
+         if (expression_requires(init, preinit, p2->var()))
+           {
+             // Check for cycles.
+             if (expression_requires(p2->var()->var_value()->init(),
+                                     p2->var()->var_value()->preinit(),
+                                     var))
+               {
+                 error_at(var->location(),
+                          ("initialization expressions for %qs and "
+                           "%qs depend upon each other"),
+                          var->message_name().c_str(),
+                          p2->var()->message_name().c_str());
+                 inform(p2->var()->location(), "%qs defined here",
+                        p2->var()->message_name().c_str());
+                 p2 = var_inits->end();
+               }
+             else
+               {
+                 // We can't emit P1 until P2 is emitted.  Move P1.
+                 // Note that the WAITING loop always executes at
+                 // least once, which is what we want.
+                 p2->increment_waiting();
+                 Var_inits::iterator p3 = p2;
+                 for (size_t i = p2->waiting(); i > 0; --i)
+                   ++p3;
+                 var_inits->splice(p3, *var_inits, p1);
+               }
+             break;
+           }
+       }
+
+      if (p2 == var_inits->end())
+       {
+         // VAR does not depends upon any other initialization expressions.
+
+         // Check for a loop of VAR on itself.  We only do this if
+         // INIT is not NULL; when INIT is NULL, it means that
+         // PREINIT sets VAR, which we will interpret as a loop.
+         if (init != NULL && expression_requires(init, preinit, var))
+           error_at(var->location(),
+                    "initialization expression for %qs depends upon itself",
+                    var->message_name().c_str());
+         ready.splice(ready.end(), *var_inits, p1);
+       }
+    }
+
+  // Now READY is the list in the desired initialization order.
+  var_inits->swap(ready);
+}
+
+// Write out the global definitions.
+
+void
+Gogo::write_globals()
+{
+  Bindings* bindings = this->current_bindings();
+  size_t count = bindings->size_definitions();
+
+  tree* vec = new tree[count];
+
+  tree init_fndecl = NULL_TREE;
+  tree init_stmt_list = NULL_TREE;
+
+  if (this->package_name() == "main")
+    this->init_imports(&init_stmt_list);
+
+  // A list of variable initializations.
+  Var_inits var_inits;
+
+  // A list of variables which need to be registered with the garbage
+  // collector.
+  std::vector<Named_object*> var_gc;
+  var_gc.reserve(count);
+
+  tree var_init_stmt_list = NULL_TREE;
+  size_t i = 0;
+  for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
+       p != bindings->end_definitions();
+       ++p, ++i)
+    {
+      Named_object* no = *p;
+
+      gcc_assert(!no->is_type_declaration() && !no->is_function_declaration());
+      // There is nothing to do for a package.
+      if (no->is_package())
+       {
+         --i;
+         --count;
+         continue;
+       }
+
+      // There is nothing to do for an object which was imported from
+      // a different package into the global scope.
+      if (no->package() != NULL)
+       {
+         --i;
+         --count;
+         continue;
+       }
+
+      // There is nothing useful we can output for constants which
+      // have ideal or non-integeral type.
+      if (no->is_const())
+       {
+         Type* type = no->const_value()->type();
+         if (type == NULL)
+           type = no->const_value()->expr()->type();
+         if (type->is_abstract() || type->integer_type() == NULL)
+           {
+             --i;
+             --count;
+             continue;
+           }
+       }
+
+      vec[i] = no->get_tree(this, NULL);
+
+      if (vec[i] == error_mark_node)
+       {
+         gcc_assert(saw_errors());
+         --i;
+         --count;
+         continue;
+       }
+
+      // If a variable is initialized to a non-constant value, do the
+      // initialization in an initialization function.
+      if (TREE_CODE(vec[i]) == VAR_DECL)
+       {
+         gcc_assert(no->is_variable());
+
+         // Check for a sink variable, which may be used to run
+         // an initializer purely for its side effects.
+         bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
+
+         tree var_init_tree = NULL_TREE;
+         if (!no->var_value()->has_pre_init())
+           {
+             tree init = no->var_value()->get_init_tree(this, NULL);
+             if (init == error_mark_node)
+               gcc_assert(saw_errors());
+             else if (init == NULL_TREE)
+               ;
+             else if (TREE_CONSTANT(init))
+               DECL_INITIAL(vec[i]) = init;
+             else if (is_sink)
+               var_init_tree = init;
+             else
+               var_init_tree = fold_build2_loc(no->location(), MODIFY_EXPR,
+                                               void_type_node, vec[i], init);
+           }
+         else
+           {
+             // We are going to create temporary variables which
+             // means that we need an fndecl.
+             if (init_fndecl == NULL_TREE)
+               init_fndecl = this->initialization_function_decl();
+             current_function_decl = init_fndecl;
+             if (DECL_STRUCT_FUNCTION(init_fndecl) == NULL)
+               push_struct_function(init_fndecl);
+             else
+               push_cfun(DECL_STRUCT_FUNCTION(init_fndecl));
+
+             tree var_decl = is_sink ? NULL_TREE : vec[i];
+             var_init_tree = no->var_value()->get_init_block(this, NULL,
+                                                             var_decl);
+
+             current_function_decl = NULL_TREE;
+             pop_cfun();
+           }
+
+         if (var_init_tree != NULL_TREE)
+           {
+             if (no->var_value()->init() == NULL
+                 && !no->var_value()->has_pre_init())
+               append_to_statement_list(var_init_tree, &var_init_stmt_list);
+             else
+               var_inits.push_back(Var_init(no, var_init_tree));
+           }
+
+         if (!is_sink && no->var_value()->type()->has_pointer())
+           var_gc.push_back(no);
+       }
+    }
+
+  // Register global variables with the garbage collector.
+  this->register_gc_vars(var_gc, &init_stmt_list);
+
+  // Simple variable initializations, after all variables are
+  // registered.
+  append_to_statement_list(var_init_stmt_list, &init_stmt_list);
+
+  // Complex variable initializations, first sorting them into a
+  // workable order.
+  if (!var_inits.empty())
+    {
+      sort_var_inits(&var_inits);
+      for (Var_inits::const_iterator p = var_inits.begin();
+          p != var_inits.end();
+          ++p)
+       append_to_statement_list(p->init(), &init_stmt_list);
+    }
+
+  // After all the variables are initialized, call the "init"
+  // functions if there are any.
+  for (std::vector<Named_object*>::const_iterator p =
+        this->init_functions_.begin();
+       p != this->init_functions_.end();
+       ++p)
+    {
+      tree decl = (*p)->get_tree(this, NULL);
+      tree call = build_call_expr(decl, 0);
+      append_to_statement_list(call, &init_stmt_list);
+    }
+
+  // Set up a magic function to do all the initialization actions.
+  // This will be called if this package is imported.
+  if (init_stmt_list != NULL_TREE
+      || this->need_init_fn_
+      || this->package_name() == "main")
+    this->write_initialization_function(init_fndecl, init_stmt_list);
+
+  // Pass everything back to the middle-end.
+
+  if (this->imported_unsafe_)
+    {
+      // Importing the "unsafe" package automatically disables TBAA.
+      flag_strict_aliasing = false;
+
+      // This is a real hack.  init_varasm_once has already grabbed an
+      // alias set, which we don't want when we aren't going strict
+      // aliasing.  We reinitialize to make it do it again.  FIXME.
+      init_varasm_once();
+    }
+
+  wrapup_global_declarations(vec, count);
+
+  cgraph_finalize_compilation_unit();
+
+  check_global_declarations(vec, count);
+  emit_debug_global_declarations(vec, count);
+
+  delete[] vec;
+}
+
+// Get a tree for the identifier for a named object.
+
+tree
+Named_object::get_id(Gogo* gogo)
+{
+  std::string decl_name;
+  if (this->is_function_declaration()
+      && !this->func_declaration_value()->asm_name().empty())
+    decl_name = this->func_declaration_value()->asm_name();
+  else if ((this->is_variable() && !this->var_value()->is_global())
+          || (this->is_type()
+              && this->type_value()->location() == BUILTINS_LOCATION))
+    {
+      // We don't need the package name for local variables or builtin
+      // types.
+      decl_name = Gogo::unpack_hidden_name(this->name_);
+    }
+  else if (this->is_function()
+          && !this->func_value()->is_method()
+          && this->package_ == NULL
+          && Gogo::unpack_hidden_name(this->name_) == "init")
+    {
+      // A single package can have multiple "init" functions, which
+      // means that we need to give them different names.
+      static int init_index;
+      char buf[20];
+      snprintf(buf, sizeof buf, "%d", init_index);
+      ++init_index;
+      decl_name = gogo->package_name() + ".init." + buf;
+    }
+  else
+    {
+      std::string package_name;
+      if (this->package_ == NULL)
+       package_name = gogo->package_name();
+      else
+       package_name = this->package_->name();
+
+      decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_);
+
+      Function_type* fntype;
+      if (this->is_function())
+       fntype = this->func_value()->type();
+      else if (this->is_function_declaration())
+       fntype = this->func_declaration_value()->type();
+      else
+       fntype = NULL;
+      if (fntype != NULL && fntype->is_method())
+       {
+         decl_name.push_back('.');
+         decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
+       }
+    }
+  if (this->is_type())
+    {
+      const Named_object* in_function = this->type_value()->in_function();
+      if (in_function != NULL)
+       decl_name += '$' + in_function->name();
+    }
+  return get_identifier_from_string(decl_name);
+}
+
+// Get a tree for a named object.
+
+tree
+Named_object::get_tree(Gogo* gogo, Named_object* function)
+{
+  if (this->tree_ != NULL_TREE)
+    {
+      // If this is a variable whose address is taken, we must rebuild
+      // the INDIRECT_REF each time to avoid invalid sharing.
+      tree ret = this->tree_;
+      if (((this->classification_ == NAMED_OBJECT_VAR
+           && this->var_value()->is_in_heap())
+          || (this->classification_ == NAMED_OBJECT_RESULT_VAR
+              && this->result_var_value()->is_in_heap()))
+         && ret != error_mark_node)
+       {
+         gcc_assert(TREE_CODE(ret) == INDIRECT_REF);
+         ret = build_fold_indirect_ref(TREE_OPERAND(ret, 0));
+         TREE_THIS_NOTRAP(ret) = 1;
+       }
+      return ret;
+    }
+
+  tree name;
+  if (this->classification_ == NAMED_OBJECT_TYPE)
+    name = NULL_TREE;
+  else
+    name = this->get_id(gogo);
+  tree decl;
+  switch (this->classification_)
+    {
+    case NAMED_OBJECT_CONST:
+      {
+       Named_constant* named_constant = this->u_.const_value;
+       Translate_context subcontext(gogo, function, NULL, NULL_TREE);
+       tree expr_tree = named_constant->expr()->get_tree(&subcontext);
+       if (expr_tree == error_mark_node)
+         decl = error_mark_node;
+       else
+         {
+           Type* type = named_constant->type();
+           if (type != NULL && !type->is_abstract())
+             expr_tree = fold_convert(type->get_tree(gogo), expr_tree);
+           if (expr_tree == error_mark_node)
+             decl = error_mark_node;
+           else if (INTEGRAL_TYPE_P(TREE_TYPE(expr_tree)))
+             {
+               decl = build_decl(named_constant->location(), CONST_DECL,
+                                 name, TREE_TYPE(expr_tree));
+               DECL_INITIAL(decl) = expr_tree;
+               TREE_CONSTANT(decl) = 1;
+               TREE_READONLY(decl) = 1;
+             }
+           else
+             {
+               // A CONST_DECL is only for an enum constant, so we
+               // shouldn't use for non-integral types.  Instead we
+               // just return the constant itself, rather than a
+               // decl.
+               decl = expr_tree;
+             }
+         }
+      }
+      break;
+
+    case NAMED_OBJECT_TYPE:
+      {
+       Named_type* named_type = this->u_.type_value;
+       tree type_tree = named_type->get_tree(gogo);
+       if (type_tree == error_mark_node)
+         decl = error_mark_node;
+       else
+         {
+           decl = TYPE_NAME(type_tree);
+           gcc_assert(decl != NULL_TREE);
+
+           // We need to produce a type descriptor for every named
+           // type, and for a pointer to every named type, since
+           // other files or packages might refer to them.  We need
+           // to do this even for hidden types, because they might
+           // still be returned by some function.  Simply calling the
+           // type_descriptor method is enough to create the type
+           // descriptor, even though we don't do anything with it.
+           if (this->package_ == NULL)
+             {
+               named_type->type_descriptor_pointer(gogo);
+               Type* pn = Type::make_pointer_type(named_type);
+               pn->type_descriptor_pointer(gogo);
+             }
+         }
+      }
+      break;
+
+    case NAMED_OBJECT_TYPE_DECLARATION:
+      error("reference to undefined type %qs",
+           this->message_name().c_str());
+      return error_mark_node;
+
+    case NAMED_OBJECT_VAR:
+      {
+       Variable* var = this->u_.var_value;
+       Type* type = var->type();
+       if (type->is_error_type()
+           || (type->is_undefined()
+               && (!var->is_global() || this->package() == NULL)))
+         {
+           // Force the error for an undefined type, just in case.
+           type->base();
+           decl = error_mark_node;
+         }
+       else
+         {
+           tree var_type = type->get_tree(gogo);
+           bool is_parameter = var->is_parameter();
+           if (var->is_receiver() && type->points_to() == NULL)
+             is_parameter = false;
+           if (var->is_in_heap())
+             {
+               is_parameter = false;
+               var_type = build_pointer_type(var_type);
+             }
+           decl = build_decl(var->location(),
+                             is_parameter ? PARM_DECL : VAR_DECL,
+                             name, var_type);
+           if (!var->is_global())
+             {
+               tree fnid = function->get_id(gogo);
+               tree fndecl = function->func_value()->get_or_make_decl(gogo,
+                                                                      function,
+                                                                      fnid);
+               DECL_CONTEXT(decl) = fndecl;
+             }
+           if (is_parameter)
+             DECL_ARG_TYPE(decl) = TREE_TYPE(decl);
+
+           if (var->is_global())
+             {
+               const Package* package = this->package();
+               if (package == NULL)
+                 TREE_STATIC(decl) = 1;
+               else
+                 DECL_EXTERNAL(decl) = 1;
+               if (!Gogo::is_hidden_name(this->name_))
+                 {
+                   TREE_PUBLIC(decl) = 1;
+                   std::string asm_name = (package == NULL
+                                           ? gogo->unique_prefix()
+                                           : package->unique_prefix());
+                   asm_name.append(1, '.');
+                   asm_name.append(IDENTIFIER_POINTER(name),
+                                   IDENTIFIER_LENGTH(name));
+                   tree asm_id = get_identifier_from_string(asm_name);
+                   SET_DECL_ASSEMBLER_NAME(decl, asm_id);
+                 }
+             }
+
+           // FIXME: We should only set this for variables which are
+           // actually used somewhere.
+           TREE_USED(decl) = 1;
+         }
+      }
+      break;
+
+    case NAMED_OBJECT_RESULT_VAR:
+      {
+       Result_variable* result = this->u_.result_var_value;
+       Type* type = result->type();
+       if (type->is_error_type() || type->is_undefined())
+         {
+           // Force the error.
+           type->base();
+           decl = error_mark_node;
+         }
+       else
+         {
+           gcc_assert(result->function() == function->func_value());
+           source_location loc = function->location();
+           tree result_type = type->get_tree(gogo);
+           tree init;
+           if (!result->is_in_heap())
+             init = type->get_init_tree(gogo, false);
+           else
+             {
+               tree space = gogo->allocate_memory(type,
+                                                  TYPE_SIZE_UNIT(result_type),
+                                                  loc);
+               result_type = build_pointer_type(result_type);
+               tree subinit = type->get_init_tree(gogo, true);
+               if (subinit == NULL_TREE)
+                 init = fold_convert_loc(loc, result_type, space);
+               else
+                 {
+                   space = save_expr(space);
+                   space = fold_convert_loc(loc, result_type, space);
+                   tree spaceref = build_fold_indirect_ref_loc(loc, space);
+                   TREE_THIS_NOTRAP(spaceref) = 1;
+                   tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node,
+                                              spaceref, subinit);
+                   init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space),
+                                          set, space);
+                 }
+             }
+           decl = build_decl(loc, VAR_DECL, name, result_type);
+           tree fnid = function->get_id(gogo);
+           tree fndecl = function->func_value()->get_or_make_decl(gogo,
+                                                                  function,
+                                                                  fnid);
+           DECL_CONTEXT(decl) = fndecl;
+           DECL_INITIAL(decl) = init;
+           TREE_USED(decl) = 1;
+         }
+      }
+      break;
+
+    case NAMED_OBJECT_SINK:
+      gcc_unreachable();
+
+    case NAMED_OBJECT_FUNC:
+      {
+       Function* func = this->u_.func_value;
+       decl = func->get_or_make_decl(gogo, this, name);
+       if (decl != error_mark_node)
+         {
+           if (func->block() != NULL)
+             {
+               if (DECL_STRUCT_FUNCTION(decl) == NULL)
+                 push_struct_function(decl);
+               else
+                 push_cfun(DECL_STRUCT_FUNCTION(decl));
+
+               cfun->function_end_locus = func->block()->end_location();
+
+               current_function_decl = decl;
+
+               func->build_tree(gogo, this);
+
+               gimplify_function_tree(decl);
+
+               cgraph_finalize_function(decl, true);
+
+               current_function_decl = NULL_TREE;
+               pop_cfun();
+             }
+         }
+      }
+      break;
+
+    default:
+      gcc_unreachable();
+    }
+
+  if (TREE_TYPE(decl) == error_mark_node)
+    decl = error_mark_node;
+
+  tree ret = decl;
+
+  // If this is a local variable whose address is taken, then we
+  // actually store it in the heap.  For uses of the variable we need
+  // to return a reference to that heap location.
+  if (((this->classification_ == NAMED_OBJECT_VAR
+       && this->var_value()->is_in_heap())
+       || (this->classification_ == NAMED_OBJECT_RESULT_VAR
+          && this->result_var_value()->is_in_heap()))
+      && ret != error_mark_node)
+    {
+      gcc_assert(POINTER_TYPE_P(TREE_TYPE(ret)));
+      ret = build_fold_indirect_ref(ret);
+      TREE_THIS_NOTRAP(ret) = 1;
+    }
+
+  this->tree_ = ret;
+
+  if (ret != error_mark_node)
+    go_preserve_from_gc(ret);
+
+  return ret;
+}
+
+// Get the initial value of a variable as a tree.  This does not
+// consider whether the variable is in the heap--it returns the
+// initial value as though it were always stored in the stack.
+
+tree
+Variable::get_init_tree(Gogo* gogo, Named_object* function)
+{
+  gcc_assert(this->preinit_ == NULL);
+  if (this->init_ == NULL)
+    {
+      gcc_assert(!this->is_parameter_);
+      return this->type_->get_init_tree(gogo, this->is_global_);
+    }
+  else
+    {
+      Translate_context context(gogo, function, NULL, NULL_TREE);
+      tree rhs_tree = this->init_->get_tree(&context);
+      return Expression::convert_for_assignment(&context, this->type(),
+                                               this->init_->type(),
+                                               rhs_tree, this->location());
+    }
+}
+
+// Get the initial value of a variable when a block is required.
+// VAR_DECL is the decl to set; it may be NULL for a sink variable.
+
+tree
+Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
+{
+  gcc_assert(this->preinit_ != NULL);
+
+  // We want to add the variable assignment to the end of the preinit
+  // block.  The preinit block may have a TRY_FINALLY_EXPR and a
+  // TRY_CATCH_EXPR; if it does, we want to add to the end of the
+  // regular statements.
+
+  Translate_context context(gogo, function, NULL, NULL_TREE);
+  tree block_tree = this->preinit_->get_tree(&context);
+  gcc_assert(TREE_CODE(block_tree) == BIND_EXPR);
+  tree statements = BIND_EXPR_BODY(block_tree);
+  while (TREE_CODE(statements) == TRY_FINALLY_EXPR
+        || TREE_CODE(statements) == TRY_CATCH_EXPR)
+    statements = TREE_OPERAND(statements, 0);
+
+  // It's possible to have pre-init statements without an initializer
+  // if the pre-init statements set the variable.
+  if (this->init_ != NULL)
+    {
+      tree rhs_tree = this->init_->get_tree(&context);
+      if (var_decl == NULL_TREE)
+       append_to_statement_list(rhs_tree, &statements);
+      else
+       {
+         tree val = Expression::convert_for_assignment(&context, this->type(),
+                                                       this->init_->type(),
+                                                       rhs_tree,
+                                                       this->location());
+         tree set = fold_build2_loc(this->location(), MODIFY_EXPR,
+                                    void_type_node, var_decl, val);
+         append_to_statement_list(set, &statements);
+       }
+    }
+
+  return block_tree;
+}
+
+// Get a tree for a function decl.
+
+tree
+Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
+{
+  if (this->fndecl_ == NULL_TREE)
+    {
+      tree functype = this->type_->get_tree(gogo);
+      if (functype == error_mark_node)
+       this->fndecl_ = error_mark_node;
+      else
+       {
+         // The type of a function comes back as a pointer, but we
+         // want the real function type for a function declaration.
+         gcc_assert(POINTER_TYPE_P(functype));
+         functype = TREE_TYPE(functype);
+         tree decl = build_decl(this->location(), FUNCTION_DECL, id, functype);
+
+         this->fndecl_ = decl;
+
+         gcc_assert(no->package() == NULL);
+         if (this->enclosing_ != NULL || Gogo::is_thunk(no))
+           ;
+         else if (Gogo::unpack_hidden_name(no->name()) == "init"
+                  && !this->type_->is_method())
+           ;
+         else if (Gogo::unpack_hidden_name(no->name()) == "main"
+                  && gogo->package_name() == "main")
+           TREE_PUBLIC(decl) = 1;
+         // Methods have to be public even if they are hidden because
+         // they can be pulled into type descriptors when using
+         // anonymous fields.
+         else if (!Gogo::is_hidden_name(no->name())
+                  || this->type_->is_method())
+           {
+             TREE_PUBLIC(decl) = 1;
+             std::string asm_name = gogo->unique_prefix();
+             asm_name.append(1, '.');
+             asm_name.append(IDENTIFIER_POINTER(id), IDENTIFIER_LENGTH(id));
+             SET_DECL_ASSEMBLER_NAME(decl,
+                                     get_identifier_from_string(asm_name));
+           }
+
+         // Why do we have to do this in the frontend?
+         tree restype = TREE_TYPE(functype);
+         tree resdecl = build_decl(this->location(), RESULT_DECL, NULL_TREE,
+                                   restype);
+         DECL_ARTIFICIAL(resdecl) = 1;
+         DECL_IGNORED_P(resdecl) = 1;
+         DECL_CONTEXT(resdecl) = decl;
+         DECL_RESULT(decl) = resdecl;
+
+         if (this->enclosing_ != NULL)
+           DECL_STATIC_CHAIN(decl) = 1;
+
+         // If a function calls the predeclared recover function, we
+         // can't inline it, because recover behaves differently in a
+         // function passed directly to defer.
+         if (this->calls_recover_ && !this->is_recover_thunk_)
+           DECL_UNINLINABLE(decl) = 1;
+
+         // If this is a thunk created to call a function which calls
+         // the predeclared recover function, we need to disable
+         // stack splitting for the thunk.
+         if (this->is_recover_thunk_)
+           {
+             tree attr = get_identifier("__no_split_stack__");
+             DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
+           }
+
+         go_preserve_from_gc(decl);
+
+         if (this->closure_var_ != NULL)
+           {
+             push_struct_function(decl);
+
+             tree closure_decl = this->closure_var_->get_tree(gogo, no);
+
+             DECL_ARTIFICIAL(closure_decl) = 1;
+             DECL_IGNORED_P(closure_decl) = 1;
+             TREE_USED(closure_decl) = 1;
+             DECL_ARG_TYPE(closure_decl) = TREE_TYPE(closure_decl);
+             TREE_READONLY(closure_decl) = 1;
+
+             DECL_STRUCT_FUNCTION(decl)->static_chain_decl = closure_decl;
+             pop_cfun();
+           }
+       }
+    }
+  return this->fndecl_;
+}
+
+// Get a tree for a function declaration.
+
+tree
+Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
+{
+  if (this->fndecl_ == NULL_TREE)
+    {
+      // Let Go code use an asm declaration to pick up a builtin
+      // function.
+      if (!this->asm_name_.empty())
+       {
+         std::map<std::string, tree>::const_iterator p =
+           builtin_functions.find(this->asm_name_);
+         if (p != builtin_functions.end())
+           {
+             this->fndecl_ = p->second;
+             return this->fndecl_;
+           }
+       }
+
+      tree functype = this->fntype_->get_tree(gogo);
+      tree decl;
+      if (functype == error_mark_node)
+       decl = error_mark_node;
+      else
+       {
+         // The type of a function comes back as a pointer, but we
+         // want the real function type for a function declaration.
+         gcc_assert(POINTER_TYPE_P(functype));
+         functype = TREE_TYPE(functype);
+         decl = build_decl(this->location(), FUNCTION_DECL, id, functype);
+         TREE_PUBLIC(decl) = 1;
+         DECL_EXTERNAL(decl) = 1;
+
+         if (this->asm_name_.empty())
+           {
+             std::string asm_name = (no->package() == NULL
+                                     ? gogo->unique_prefix()
+                                     : no->package()->unique_prefix());
+             asm_name.append(1, '.');
+             asm_name.append(IDENTIFIER_POINTER(id), IDENTIFIER_LENGTH(id));
+             SET_DECL_ASSEMBLER_NAME(decl,
+                                     get_identifier_from_string(asm_name));
+           }
+       }
+      this->fndecl_ = decl;
+      go_preserve_from_gc(decl);
+    }
+  return this->fndecl_;
+}
+
+// We always pass the receiver to a method as a pointer.  If the
+// receiver is actually declared as a non-pointer type, then we copy
+// the value into a local variable, so that it has the right type.  In
+// this function we create the real PARM_DECL to use, and set
+// DEC_INITIAL of the var_decl to be the value passed in.
+
+tree
+Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl)
+{
+  // If the function takes the address of a receiver which is passed
+  // by value, then we will have an INDIRECT_REF here.  We need to get
+  // the real variable.
+  bool is_in_heap = no->var_value()->is_in_heap();
+  tree val_type;
+  if (TREE_CODE(var_decl) != INDIRECT_REF)
+    {
+      gcc_assert(!is_in_heap);
+      val_type = TREE_TYPE(var_decl);
+    }
+  else
+    {
+      gcc_assert(is_in_heap);
+      var_decl = TREE_OPERAND(var_decl, 0);
+      gcc_assert(POINTER_TYPE_P(TREE_TYPE(var_decl)));
+      val_type = TREE_TYPE(TREE_TYPE(var_decl));
+    }
+  gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+  source_location loc = DECL_SOURCE_LOCATION(var_decl);
+  std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
+  name += ".pointer";
+  tree id = get_identifier_from_string(name);
+  tree parm_decl = build_decl(loc, PARM_DECL, id, build_pointer_type(val_type));
+  DECL_CONTEXT(parm_decl) = current_function_decl;
+  DECL_ARG_TYPE(parm_decl) = TREE_TYPE(parm_decl);
+
+  gcc_assert(DECL_INITIAL(var_decl) == NULL_TREE);
+  // The receiver might be passed as a null pointer.
+  tree check = fold_build2_loc(loc, NE_EXPR, boolean_type_node, parm_decl,
+                              fold_convert_loc(loc, TREE_TYPE(parm_decl),
+                                               null_pointer_node));
+  tree ind = build_fold_indirect_ref_loc(loc, parm_decl);
+  TREE_THIS_NOTRAP(ind) = 1;
+  tree zero_init = no->var_value()->type()->get_init_tree(gogo, false);
+  tree init = fold_build3_loc(loc, COND_EXPR, TREE_TYPE(ind),
+                             check, ind, zero_init);
+
+  if (is_in_heap)
+    {
+      tree size = TYPE_SIZE_UNIT(val_type);
+      tree space = gogo->allocate_memory(no->var_value()->type(), size,
+                                        no->location());
+      space = save_expr(space);
+      space = fold_convert(build_pointer_type(val_type), space);
+      tree spaceref = build_fold_indirect_ref_loc(no->location(), space);
+      TREE_THIS_NOTRAP(spaceref) = 1;
+      tree check = fold_build2_loc(loc, NE_EXPR, boolean_type_node,
+                                  parm_decl,
+                                  fold_convert_loc(loc, TREE_TYPE(parm_decl),
+                                                   null_pointer_node));
+      tree parmref = build_fold_indirect_ref_loc(no->location(), parm_decl);
+      TREE_THIS_NOTRAP(parmref) = 1;
+      tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node,
+                                spaceref, parmref);
+      init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space),
+                            build3(COND_EXPR, void_type_node,
+                                   check, set, NULL_TREE),
+                            space);
+    }
+
+  DECL_INITIAL(var_decl) = init;
+
+  return parm_decl;
+}
+
+// If we take the address of a parameter, then we need to copy it into
+// the heap.  We will access it as a local variable via an
+// indirection.
+
+tree
+Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree ref)
+{
+  gcc_assert(TREE_CODE(ref) == INDIRECT_REF);
+
+  tree var_decl = TREE_OPERAND(ref, 0);
+  gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+  source_location loc = DECL_SOURCE_LOCATION(var_decl);
+
+  std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
+  name += ".param";
+  tree id = get_identifier_from_string(name);
+
+  tree type = TREE_TYPE(var_decl);
+  gcc_assert(POINTER_TYPE_P(type));
+  type = TREE_TYPE(type);
+
+  tree parm_decl = build_decl(loc, PARM_DECL, id, type);
+  DECL_CONTEXT(parm_decl) = current_function_decl;
+  DECL_ARG_TYPE(parm_decl) = type;
+
+  tree size = TYPE_SIZE_UNIT(type);
+  tree space = gogo->allocate_memory(no->var_value()->type(), size, loc);
+  space = save_expr(space);
+  space = fold_convert(TREE_TYPE(var_decl), space);
+  tree spaceref = build_fold_indirect_ref_loc(loc, space);
+  TREE_THIS_NOTRAP(spaceref) = 1;
+  tree init = build2(COMPOUND_EXPR, TREE_TYPE(space),
+                    build2(MODIFY_EXPR, void_type_node, spaceref, parm_decl),
+                    space);
+  DECL_INITIAL(var_decl) = init;
+
+  return parm_decl;
+}
+
+// Get a tree for function code.
+
+void
+Function::build_tree(Gogo* gogo, Named_object* named_function)
+{
+  tree fndecl = this->fndecl_;
+  gcc_assert(fndecl != NULL_TREE);
+
+  tree params = NULL_TREE;
+  tree* pp = &params;
+
+  tree declare_vars = NULL_TREE;
+  for (Bindings::const_definitions_iterator p =
+        this->block_->bindings()->begin_definitions();
+       p != this->block_->bindings()->end_definitions();
+       ++p)
+    {
+      if ((*p)->is_variable() && (*p)->var_value()->is_parameter())
+       {
+         *pp = (*p)->get_tree(gogo, named_function);
+
+         // We always pass the receiver to a method as a pointer.  If
+         // the receiver is declared as a non-pointer type, then we
+         // copy the value into a local variable.
+         if ((*p)->var_value()->is_receiver()
+             && (*p)->var_value()->type()->points_to() == NULL)
+           {
+             tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp);
+             tree var = *pp;
+             if (TREE_CODE(var) == INDIRECT_REF)
+               var = TREE_OPERAND(var, 0);
+             gcc_assert(TREE_CODE(var) == VAR_DECL);
+             DECL_CHAIN(var) = declare_vars;
+             declare_vars = var;
+             *pp = parm_decl;
+           }
+         else if ((*p)->var_value()->is_in_heap())
+           {
+             // If we take the address of a parameter, then we need
+             // to copy it into the heap.
+             tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp);
+             gcc_assert(TREE_CODE(*pp) == INDIRECT_REF);
+             tree var_decl = TREE_OPERAND(*pp, 0);
+             gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+             DECL_CHAIN(var_decl) = declare_vars;
+             declare_vars = var_decl;
+             *pp = parm_decl;
+           }
+
+         if (*pp != error_mark_node)
+           {
+             gcc_assert(TREE_CODE(*pp) == PARM_DECL);
+             pp = &DECL_CHAIN(*pp);
+           }
+       }
+      else if ((*p)->is_result_variable())
+       {
+         tree var_decl = (*p)->get_tree(gogo, named_function);
+         if ((*p)->result_var_value()->is_in_heap())
+           {
+             gcc_assert(TREE_CODE(var_decl) == INDIRECT_REF);
+             var_decl = TREE_OPERAND(var_decl, 0);
+           }
+         gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+         DECL_CHAIN(var_decl) = declare_vars;
+         declare_vars = var_decl;
+       }
+    }
+  *pp = NULL_TREE;
+
+  DECL_ARGUMENTS(fndecl) = params;
+
+  if (this->block_ != NULL)
+    {
+      gcc_assert(DECL_INITIAL(fndecl) == NULL_TREE);
+
+      // Declare variables if necessary.
+      tree bind = NULL_TREE;
+      if (declare_vars != NULL_TREE)
+       {
+         tree block = make_node(BLOCK);
+         BLOCK_SUPERCONTEXT(block) = fndecl;
+         DECL_INITIAL(fndecl) = block;
+         BLOCK_VARS(block) = declare_vars;
+         TREE_USED(block) = 1;
+         bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block),
+                       NULL_TREE, block);
+         TREE_SIDE_EFFECTS(bind) = 1;
+       }
+
+      // Build the trees for all the statements in the function.
+      Translate_context context(gogo, named_function, NULL, NULL_TREE);
+      tree code = this->block_->get_tree(&context);
+
+      tree init = NULL_TREE;
+      tree except = NULL_TREE;
+      tree fini = NULL_TREE;
+
+      // Initialize variables if necessary.
+      for (tree v = declare_vars; v != NULL_TREE; v = DECL_CHAIN(v))
+       {
+         tree dv = build1(DECL_EXPR, void_type_node, v);
+         SET_EXPR_LOCATION(dv, DECL_SOURCE_LOCATION(v));
+         append_to_statement_list(dv, &init);
+       }
+
+      // If we have a defer stack, initialize it at the start of a
+      // function.
+      if (this->defer_stack_ != NULL_TREE)
+       {
+         tree defer_init = build1(DECL_EXPR, void_type_node,
+                                  this->defer_stack_);
+         SET_EXPR_LOCATION(defer_init, this->block_->start_location());
+         append_to_statement_list(defer_init, &init);
+
+         // Clean up the defer stack when we leave the function.
+         this->build_defer_wrapper(gogo, named_function, &except, &fini);
+       }
+
+      if (code != NULL_TREE && code != error_mark_node)
+       {
+         if (init != NULL_TREE)
+           code = build2(COMPOUND_EXPR, void_type_node, init, code);
+         if (except != NULL_TREE)
+           code = build2(TRY_CATCH_EXPR, void_type_node, code,
+                         build2(CATCH_EXPR, void_type_node, NULL, except));
+         if (fini != NULL_TREE)
+           code = build2(TRY_FINALLY_EXPR, void_type_node, code, fini);
+       }
+
+      // Stick the code into the block we built for the receiver, if
+      // we built on.
+      if (bind != NULL_TREE && code != NULL_TREE && code != error_mark_node)
+       {
+         BIND_EXPR_BODY(bind) = code;
+         code = bind;
+       }
+
+      DECL_SAVED_TREE(fndecl) = code;
+    }
+}
+
+// Build the wrappers around function code needed if the function has
+// any defer statements.  This sets *EXCEPT to an exception handler
+// and *FINI to a finally handler.
+
+void
+Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
+                             tree *except, tree *fini)
+{
+  source_location end_loc = this->block_->end_location();
+
+  // Add an exception handler.  This is used if a panic occurs.  Its
+  // purpose is to stop the stack unwinding if a deferred function
+  // calls recover.  There are more details in
+  // libgo/runtime/go-unwind.c.
+  tree stmt_list = NULL_TREE;
+  static tree check_fndecl;
+  tree call = Gogo::call_builtin(&check_fndecl,
+                                end_loc,
+                                "__go_check_defer",
+                                1,
+                                void_type_node,
+                                ptr_type_node,
+                                this->defer_stack(end_loc));
+  append_to_statement_list(call, &stmt_list);
+
+  tree retval = this->return_value(gogo, named_function, end_loc, &stmt_list);
+  tree set;
+  if (retval == NULL_TREE)
+    set = NULL_TREE;
+  else
+    set = fold_build2_loc(end_loc, MODIFY_EXPR, void_type_node,
+                         DECL_RESULT(this->fndecl_), retval);
+  tree ret_stmt = fold_build1_loc(end_loc, RETURN_EXPR, void_type_node, set);
+  append_to_statement_list(ret_stmt, &stmt_list);
+
+  gcc_assert(*except == NULL_TREE);
+  *except = stmt_list;
+
+  // Add some finally code to run the defer functions.  This is used
+  // both in the normal case, when no panic occurs, and also if a
+  // panic occurs to run any further defer functions.  Of course, it
+  // is possible for a defer function to call panic which should be
+  // caught by another defer function.  To handle that we use a loop.
+  //  finish:
+  //   try { __go_undefer(); } catch { __go_check_defer(); goto finish; }
+  //   if (return values are named) return named_vals;
+
+  stmt_list = NULL;
+
+  tree label = create_artificial_label(end_loc);
+  tree define_label = fold_build1_loc(end_loc, LABEL_EXPR, void_type_node,
+                                     label);
+  append_to_statement_list(define_label, &stmt_list);
+
+  static tree undefer_fndecl;
+  tree undefer = Gogo::call_builtin(&undefer_fndecl,
+                                   end_loc,
+                                   "__go_undefer",
+                                   1,
+                                   void_type_node,
+                                   ptr_type_node,
+                                   this->defer_stack(end_loc));
+  TREE_NOTHROW(undefer_fndecl) = 0;
+
+  tree defer = Gogo::call_builtin(&check_fndecl,
+                                 end_loc,
+                                 "__go_check_defer",
+                                 1,
+                                 void_type_node,
+                                 ptr_type_node,
+                                 this->defer_stack(end_loc));
+  tree jump = fold_build1_loc(end_loc, GOTO_EXPR, void_type_node, label);
+  tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer, jump);
+  catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
+  tree try_catch = build2(TRY_CATCH_EXPR, void_type_node, undefer, catch_body);
+
+  append_to_statement_list(try_catch, &stmt_list);
+
+  if (this->type_->results() != NULL
+      && !this->type_->results()->empty()
+      && !this->type_->results()->front().name().empty())
+    {
+      // If the result variables are named, we need to return them
+      // again, because they might have been changed by a defer
+      // function.
+      retval = this->return_value(gogo, named_function, end_loc,
+                                 &stmt_list);
+      set = fold_build2_loc(end_loc, MODIFY_EXPR, void_type_node,
+                           DECL_RESULT(this->fndecl_), retval);
+      ret_stmt = fold_build1_loc(end_loc, RETURN_EXPR, void_type_node, set);
+      append_to_statement_list(ret_stmt, &stmt_list);
+    }
+  
+  gcc_assert(*fini == NULL_TREE);
+  *fini = stmt_list;
+}
+
+// Return the value to assign to DECL_RESULT(this->fndecl_).  This may
+// also add statements to STMT_LIST, which need to be executed before
+// the assignment.  This is used for a return statement with no
+// explicit values.
+
+tree
+Function::return_value(Gogo* gogo, Named_object* named_function,
+                      source_location location, tree* stmt_list) const
+{
+  const Typed_identifier_list* results = this->type_->results();
+  if (results == NULL || results->empty())
+    return NULL_TREE;
+
+  // In the case of an exception handler created for functions with
+  // defer statements, the result variables may be unnamed.
+  bool is_named = !results->front().name().empty();
+  if (is_named)
+    gcc_assert(this->named_results_ != NULL
+              && this->named_results_->size() == results->size());
+
+  tree retval;
+  if (results->size() == 1)
+    {
+      if (is_named)
+       return this->named_results_->front()->get_tree(gogo, named_function);
+      else
+       return results->front().type()->get_init_tree(gogo, false);
+    }
+  else
+    {
+      tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_));
+      retval = create_tmp_var(rettype, "RESULT");
+      tree field = TYPE_FIELDS(rettype);
+      int index = 0;
+      for (Typed_identifier_list::const_iterator pr = results->begin();
+          pr != results->end();
+          ++pr, ++index, field = DECL_CHAIN(field))
+       {
+         gcc_assert(field != NULL);
+         tree val;
+         if (is_named)
+           val = (*this->named_results_)[index]->get_tree(gogo,
+                                                          named_function);
+         else
+           val = pr->type()->get_init_tree(gogo, false);
+         tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
+                                    build3(COMPONENT_REF, TREE_TYPE(field),
+                                           retval, field, NULL_TREE),
+                                    val);
+         append_to_statement_list(set, stmt_list);
+       }
+      return retval;
+    }
+}
+
+// Get the tree for the variable holding the defer stack for this
+// function.  At least at present, the value of this variable is not
+// used.  However, a pointer to this variable is used as a marker for
+// the functions on the defer stack associated with this function.
+// Doing things this way permits inlining a function which uses defer.
+
+tree
+Function::defer_stack(source_location location)
+{
+  if (this->defer_stack_ == NULL_TREE)
+    {
+      tree var = create_tmp_var(ptr_type_node, "DEFER");
+      DECL_INITIAL(var) = null_pointer_node;
+      DECL_SOURCE_LOCATION(var) = location;
+      TREE_ADDRESSABLE(var) = 1;
+      this->defer_stack_ = var;
+    }
+  return fold_convert_loc(location, ptr_type_node,
+                         build_fold_addr_expr_loc(location,
+                                                  this->defer_stack_));
+}
+
+// Get a tree for the statements in a block.
+
+tree
+Block::get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+
+  tree block = make_node(BLOCK);
+
+  // Put the new block into the block tree.
+
+  if (context->block() == NULL)
+    {
+      tree fndecl;
+      if (context->function() != NULL)
+       fndecl = context->function()->func_value()->get_decl();
+      else
+       fndecl = current_function_decl;
+      gcc_assert(fndecl != NULL_TREE);
+
+      // We may have already created a block for the receiver.
+      if (DECL_INITIAL(fndecl) == NULL_TREE)
+       {
+         BLOCK_SUPERCONTEXT(block) = fndecl;
+         DECL_INITIAL(fndecl) = block;
+       }
+      else
+       {
+         tree superblock_tree = DECL_INITIAL(fndecl);
+         BLOCK_SUPERCONTEXT(block) = superblock_tree;
+         gcc_assert(BLOCK_CHAIN(block) == NULL_TREE);
+         BLOCK_CHAIN(block) = block;
+       }
+    }
+  else
+    {
+      tree superblock_tree = context->block_tree();
+      BLOCK_SUPERCONTEXT(block) = superblock_tree;
+      tree* pp;
+      for (pp = &BLOCK_SUBBLOCKS(superblock_tree);
+          *pp != NULL_TREE;
+          pp = &BLOCK_CHAIN(*pp))
+       ;
+      *pp = block;
+    }
+
+  // Expand local variables in the block.
+
+  tree* pp = &BLOCK_VARS(block);
+  for (Bindings::const_definitions_iterator pv =
+        this->bindings_->begin_definitions();
+       pv != this->bindings_->end_definitions();
+       ++pv)
+    {
+      if ((!(*pv)->is_variable() || !(*pv)->var_value()->is_parameter())
+         && !(*pv)->is_result_variable()
+         && !(*pv)->is_const())
+       {
+         tree var = (*pv)->get_tree(gogo, context->function());
+         if (var != error_mark_node && TREE_TYPE(var) != error_mark_node)
+           {
+             if ((*pv)->is_variable() && (*pv)->var_value()->is_in_heap())
+               {
+                 gcc_assert(TREE_CODE(var) == INDIRECT_REF);
+                 var = TREE_OPERAND(var, 0);
+                 gcc_assert(TREE_CODE(var) == VAR_DECL);
+               }
+             *pp = var;
+             pp = &DECL_CHAIN(*pp);
+           }
+       }
+    }
+  *pp = NULL_TREE;
+
+  Translate_context subcontext(context->gogo(), context->function(),
+                              this, block);
+
+  tree statements = NULL_TREE;
+
+  // Expand the statements.
+
+  for (std::vector<Statement*>::const_iterator p = this->statements_.begin();
+       p != this->statements_.end();
+       ++p)
+    {
+      tree statement = (*p)->get_tree(&subcontext);
+      if (statement != error_mark_node)
+       append_to_statement_list(statement, &statements);
+    }
+
+  TREE_USED(block) = 1;
+
+  tree bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block), statements,
+                    block);
+  TREE_SIDE_EFFECTS(bind) = 1;
+
+  return bind;
+}
+
+// Get the LABEL_DECL for a label.
+
+tree
+Label::get_decl()
+{
+  if (this->decl_ == NULL)
+    {
+      tree id = get_identifier_from_string(this->name_);
+      this->decl_ = build_decl(this->location_, LABEL_DECL, id, void_type_node);
+      DECL_CONTEXT(this->decl_) = current_function_decl;
+    }
+  return this->decl_;
+}
+
+// Return an expression for the address of this label.
+
+tree
+Label::get_addr(source_location location)
+{
+  tree decl = this->get_decl();
+  TREE_USED(decl) = 1;
+  TREE_ADDRESSABLE(decl) = 1;
+  return fold_convert_loc(location, ptr_type_node,
+                         build_fold_addr_expr_loc(location, decl));
+}
+
+// Get the LABEL_DECL for an unnamed label.
+
+tree
+Unnamed_label::get_decl()
+{
+  if (this->decl_ == NULL)
+    this->decl_ = create_artificial_label(this->location_);
+  return this->decl_;
+}
+
+// Get the LABEL_EXPR for an unnamed label.
+
+tree
+Unnamed_label::get_definition()
+{
+  tree t = build1(LABEL_EXPR, void_type_node, this->get_decl());
+  SET_EXPR_LOCATION(t, this->location_);
+  return t;
+}
+
+// Return a goto to this label.
+
+tree
+Unnamed_label::get_goto(source_location location)
+{
+  tree t = build1(GOTO_EXPR, void_type_node, this->get_decl());
+  SET_EXPR_LOCATION(t, location);
+  return t;
+}
+
+// Return the integer type to use for a size.
+
+GO_EXTERN_C
+tree
+go_type_for_size(unsigned int bits, int unsignedp)
+{
+  const char* name;
+  switch (bits)
+    {
+    case 8:
+      name = unsignedp ? "uint8" : "int8";
+      break;
+    case 16:
+      name = unsignedp ? "uint16" : "int16";
+      break;
+    case 32:
+      name = unsignedp ? "uint32" : "int32";
+      break;
+    case 64:
+      name = unsignedp ? "uint64" : "int64";
+      break;
+    default:
+      if (bits == POINTER_SIZE && unsignedp)
+       name = "uintptr";
+      else
+       return NULL_TREE;
+    }
+  Type* type = Type::lookup_integer_type(name);
+  return type->get_tree(go_get_gogo());
+}
+
+// Return the type to use for a mode.
+
+GO_EXTERN_C
+tree
+go_type_for_mode(enum machine_mode mode, int unsignedp)
+{
+  // FIXME: This static_cast should be in machmode.h.
+  enum mode_class mc = static_cast<enum mode_class>(GET_MODE_CLASS(mode));
+  if (mc == MODE_INT)
+    return go_type_for_size(GET_MODE_BITSIZE(mode), unsignedp);
+  else if (mc == MODE_FLOAT)
+    {
+      Type* type;
+      switch (GET_MODE_BITSIZE (mode))
+       {
+       case 32:
+         type = Type::lookup_float_type("float32");
+         break;
+       case 64:
+         type = Type::lookup_float_type("float64");
+         break;
+       default:
+         // We have to check for long double in order to support
+         // i386 excess precision.
+         if (mode == TYPE_MODE(long_double_type_node))
+           return long_double_type_node;
+         return NULL_TREE;
+       }
+      return type->float_type()->type_tree();
+    }
+  else if (mc == MODE_COMPLEX_FLOAT)
+    {
+      Type *type;
+      switch (GET_MODE_BITSIZE (mode))
+       {
+       case 64:
+         type = Type::lookup_complex_type("complex64");
+         break;
+       case 128:
+         type = Type::lookup_complex_type("complex128");
+         break;
+       default:
+         // We have to check for long double in order to support
+         // i386 excess precision.
+         if (mode == TYPE_MODE(complex_long_double_type_node))
+           return complex_long_double_type_node;
+         return NULL_TREE;
+       }
+      return type->complex_type()->type_tree();
+    }
+  else
+    return NULL_TREE;
+}
+
+// Return a tree which allocates SIZE bytes which will holds value of
+// type TYPE.
+
+tree
+Gogo::allocate_memory(Type* type, tree size, source_location location)
+{
+  // If the package imports unsafe, then it may play games with
+  // pointers that look like integers.
+  if (this->imported_unsafe_ || type->has_pointer())
+    {
+      static tree new_fndecl;
+      return Gogo::call_builtin(&new_fndecl,
+                               location,
+                               "__go_new",
+                               1,
+                               ptr_type_node,
+                               sizetype,
+                               size);
+    }
+  else
+    {
+      static tree new_nopointers_fndecl;
+      return Gogo::call_builtin(&new_nopointers_fndecl,
+                               location,
+                               "__go_new_nopointers",
+                               1,
+                               ptr_type_node,
+                               sizetype,
+                               size);
+    }
+}
+
+// Build a builtin struct with a list of fields.  The name is
+// STRUCT_NAME.  STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE
+// node; this exists so that the struct can have fields which point to
+// itself.  If PTYPE is not NULL, store the result in *PTYPE.  There
+// are NFIELDS fields.  Each field is a name (a const char*) followed
+// by a type (a tree).
+
+tree
+Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type,
+                    int nfields, ...)
+{
+  if (ptype != NULL && *ptype != NULL_TREE)
+    return *ptype;
+
+  va_list ap;
+  va_start(ap, nfields);
+
+  tree fields = NULL_TREE;
+  for (int i = 0; i < nfields; ++i)
+    {
+      const char* field_name = va_arg(ap, const char*);
+      tree type = va_arg(ap, tree);
+      if (type == error_mark_node)
+       {
+         if (ptype != NULL)
+           *ptype = error_mark_node;
+         return error_mark_node;
+       }
+      tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL,
+                             get_identifier(field_name), type);
+      DECL_CHAIN(field) = fields;
+      fields = field;
+    }
+
+  va_end(ap);
+
+  if (struct_type == NULL_TREE)
+    struct_type = make_node(RECORD_TYPE);
+  finish_builtin_struct(struct_type, struct_name, fields, NULL_TREE);
+
+  if (ptype != NULL)
+    {
+      go_preserve_from_gc(struct_type);
+      *ptype = struct_type;
+    }
+
+  return struct_type;
+}
+
+// Return a type to use for pointer to const char for a string.
+
+tree
+Gogo::const_char_pointer_type_tree()
+{
+  static tree type;
+  if (type == NULL_TREE)
+    {
+      tree const_char_type = build_qualified_type(unsigned_char_type_node,
+                                                 TYPE_QUAL_CONST);
+      type = build_pointer_type(const_char_type);
+      go_preserve_from_gc(type);
+    }
+  return type;
+}
+
+// Return a tree for a string constant.
+
+tree
+Gogo::string_constant_tree(const std::string& val)
+{
+  tree index_type = build_index_type(size_int(val.length()));
+  tree const_char_type = build_qualified_type(unsigned_char_type_node,
+                                             TYPE_QUAL_CONST);
+  tree string_type = build_array_type(const_char_type, index_type);
+  string_type = build_variant_type_copy(string_type);
+  TYPE_STRING_FLAG(string_type) = 1;
+  tree string_val = build_string(val.length(), val.data());
+  TREE_TYPE(string_val) = string_type;
+  return string_val;
+}
+
+// Return a tree for a Go string constant.
+
+tree
+Gogo::go_string_constant_tree(const std::string& val)
+{
+  tree string_type = Type::make_string_type()->get_tree(this);
+
+  VEC(constructor_elt, gc)* init = VEC_alloc(constructor_elt, gc, 2);
+
+  constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+  tree field = TYPE_FIELDS(string_type);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__data") == 0);
+  elt->index = field;
+  tree str = Gogo::string_constant_tree(val);
+  elt->value = fold_convert(TREE_TYPE(field),
+                           build_fold_addr_expr(str));
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = DECL_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__length") == 0);
+  elt->index = field;
+  elt->value = build_int_cst_type(TREE_TYPE(field), val.length());
+
+  tree constructor = build_constructor(string_type, init);
+  TREE_READONLY(constructor) = 1;
+  TREE_CONSTANT(constructor) = 1;
+
+  return constructor;
+}
+
+// Return a tree for a pointer to a Go string constant.  This is only
+// used for type descriptors, so we return a pointer to a constant
+// decl.
+
+tree
+Gogo::ptr_go_string_constant_tree(const std::string& val)
+{
+  tree pval = this->go_string_constant_tree(val);
+
+  tree decl = build_decl(UNKNOWN_LOCATION, VAR_DECL,
+                        create_tmp_var_name("SP"), TREE_TYPE(pval));
+  DECL_EXTERNAL(decl) = 0;
+  TREE_PUBLIC(decl) = 0;
+  TREE_USED(decl) = 1;
+  TREE_READONLY(decl) = 1;
+  TREE_CONSTANT(decl) = 1;
+  TREE_STATIC(decl) = 1;
+  DECL_ARTIFICIAL(decl) = 1;
+  DECL_INITIAL(decl) = pval;
+  rest_of_decl_compilation(decl, 1, 0);
+
+  return build_fold_addr_expr(decl);
+}
+
+// Build the type of the struct that holds a slice for the given
+// element type.
+
+tree
+Gogo::slice_type_tree(tree element_type_tree)
+{
+  // We use int for the count and capacity fields in a slice header.
+  // This matches 6g.  The language definition guarantees that we
+  // can't allocate space of a size which does not fit in int
+  // anyhow. FIXME: integer_type_node is the the C type "int" but is
+  // not necessarily the Go type "int".  They will differ when the C
+  // type "int" has fewer than 32 bits.
+  return Gogo::builtin_struct(NULL, "__go_slice", NULL_TREE, 3,
+                             "__values",
+                             build_pointer_type(element_type_tree),
+                             "__count",
+                             integer_type_node,
+                             "__capacity",
+                             integer_type_node);
+}
+
+// Given the tree for a slice type, return the tree for the type of
+// the elements of the slice.
+
+tree
+Gogo::slice_element_type_tree(tree slice_type_tree)
+{
+  gcc_assert(TREE_CODE(slice_type_tree) == RECORD_TYPE
+            && POINTER_TYPE_P(TREE_TYPE(TYPE_FIELDS(slice_type_tree))));
+  return TREE_TYPE(TREE_TYPE(TYPE_FIELDS(slice_type_tree)));
+}
+
+// Build a constructor for a slice.  SLICE_TYPE_TREE is the type of
+// the slice.  VALUES is the value pointer and COUNT is the number of
+// entries.  If CAPACITY is not NULL, it is the capacity; otherwise
+// the capacity and the count are the same.
+
+tree
+Gogo::slice_constructor(tree slice_type_tree, tree values, tree count,
+                       tree capacity)
+{
+  gcc_assert(TREE_CODE(slice_type_tree) == RECORD_TYPE);
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 3);
+
+  tree field = TYPE_FIELDS(slice_type_tree);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
+  constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+  elt->index = field;
+  gcc_assert(TYPE_MAIN_VARIANT(TREE_TYPE(field))
+            == TYPE_MAIN_VARIANT(TREE_TYPE(values)));
+  elt->value = values;
+
+  count = fold_convert(sizetype, count);
+  if (capacity == NULL_TREE)
+    {
+      count = save_expr(count);
+      capacity = count;
+    }
+
+  field = DECL_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  elt->index = field;
+  elt->value = fold_convert(TREE_TYPE(field), count);
+
+  field = DECL_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  elt->index = field;
+  elt->value = fold_convert(TREE_TYPE(field), capacity);
+
+  return build_constructor(slice_type_tree, init);
+}
+
+// Build a constructor for an empty slice.
+
+tree
+Gogo::empty_slice_constructor(tree slice_type_tree)
+{
+  tree element_field = TYPE_FIELDS(slice_type_tree);
+  tree ret = Gogo::slice_constructor(slice_type_tree,
+                                    fold_convert(TREE_TYPE(element_field),
+                                                 null_pointer_node),
+                                    size_zero_node,
+                                    size_zero_node);
+  TREE_CONSTANT(ret) = 1;
+  return ret;
+}
+
+// Build a map descriptor for a map of type MAPTYPE.
+
+tree
+Gogo::map_descriptor(Map_type* maptype)
+{
+  if (this->map_descriptors_ == NULL)
+    this->map_descriptors_ = new Map_descriptors(10);
+
+  std::pair<const Map_type*, tree> val(maptype, NULL);
+  std::pair<Map_descriptors::iterator, bool> ins =
+    this->map_descriptors_->insert(val);
+  Map_descriptors::iterator p = ins.first;
+  if (!ins.second)
+    {
+      gcc_assert(p->second != NULL_TREE && DECL_P(p->second));
+      return build_fold_addr_expr(p->second);
+    }
+
+  Type* keytype = maptype->key_type();
+  Type* valtype = maptype->val_type();
+
+  std::string mangled_name = ("__go_map_" + maptype->mangled_name(this));
+
+  tree id = get_identifier_from_string(mangled_name);
+
+  // Get the type of the map descriptor.  This is __go_map_descriptor
+  // in libgo/map.h.
+
+  tree struct_type = this->map_descriptor_type();
+
+  // The map entry type is a struct with three fields.  This struct is
+  // specific to MAPTYPE.  Build it.
+
+  tree map_entry_type = make_node(RECORD_TYPE);
+
+  map_entry_type = Gogo::builtin_struct(NULL, "__map", map_entry_type, 3,
+                                       "__next",
+                                       build_pointer_type(map_entry_type),
+                                       "__key",
+                                       keytype->get_tree(this),
+                                       "__val",
+                                       valtype->get_tree(this));
+  if (map_entry_type == error_mark_node)
+    return error_mark_node;
+
+  tree map_entry_key_field = DECL_CHAIN(TYPE_FIELDS(map_entry_type));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_key_field)),
+                   "__key") == 0);
+
+  tree map_entry_val_field = DECL_CHAIN(map_entry_key_field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_val_field)),
+                   "__val") == 0);
+
+  // Initialize the entries.
+
+  tree map_descriptor_field = TYPE_FIELDS(struct_type);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_descriptor_field)),
+                   "__map_descriptor") == 0);
+  tree entry_size_field = DECL_CHAIN(map_descriptor_field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(entry_size_field)),
+                   "__entry_size") == 0);
+  tree key_offset_field = DECL_CHAIN(entry_size_field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(key_offset_field)),
+                   "__key_offset") == 0);
+  tree val_offset_field = DECL_CHAIN(key_offset_field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(val_offset_field)),
+                   "__val_offset") == 0);
+
+  VEC(constructor_elt, gc)* descriptor = VEC_alloc(constructor_elt, gc, 6);
+
+  constructor_elt* elt = VEC_quick_push(constructor_elt, descriptor, NULL);
+  elt->index = map_descriptor_field;
+  elt->value = maptype->type_descriptor_pointer(this);
+
+  elt = VEC_quick_push(constructor_elt, descriptor, NULL);
+  elt->index = entry_size_field;
+  elt->value = TYPE_SIZE_UNIT(map_entry_type);
+
+  elt = VEC_quick_push(constructor_elt, descriptor, NULL);
+  elt->index = key_offset_field;
+  elt->value = byte_position(map_entry_key_field);
+
+  elt = VEC_quick_push(constructor_elt, descriptor, NULL);
+  elt->index = val_offset_field;
+  elt->value = byte_position(map_entry_val_field);
+
+  tree constructor = build_constructor(struct_type, descriptor);
+
+  tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, struct_type);
+  TREE_STATIC(decl) = 1;
+  TREE_USED(decl) = 1;
+  TREE_READONLY(decl) = 1;
+  TREE_CONSTANT(decl) = 1;
+  DECL_INITIAL(decl) = constructor;
+  make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
+  resolve_unique_section(decl, 1, 0);
+
+  rest_of_decl_compilation(decl, 1, 0);
+
+  go_preserve_from_gc(decl);
+  p->second = decl;
+
+  return build_fold_addr_expr(decl);
+}
+
+// Return a tree for the type of a map descriptor.  This is struct
+// __go_map_descriptor in libgo/runtime/map.h.  This is the same for
+// all map types.
+
+tree
+Gogo::map_descriptor_type()
+{
+  static tree struct_type;
+  tree dtype = Type::make_type_descriptor_type()->get_tree(this);
+  dtype = build_qualified_type(dtype, TYPE_QUAL_CONST);
+  return Gogo::builtin_struct(&struct_type, "__go_map_descriptor", NULL_TREE,
+                             4,
+                             "__map_descriptor",
+                             build_pointer_type(dtype),
+                             "__entry_size",
+                             sizetype,
+                             "__key_offset",
+                             sizetype,
+                             "__val_offset",
+                             sizetype);
+}
+
+// Return the name to use for a type descriptor decl for TYPE.  This
+// is used when TYPE does not have a name.
+
+std::string
+Gogo::unnamed_type_descriptor_decl_name(const Type* type)
+{
+  return "__go_td_" + type->mangled_name(this);
+}
+
+// Return the name to use for a type descriptor decl for a type named
+// NAME, defined in the function IN_FUNCTION.  IN_FUNCTION will
+// normally be NULL.
+
+std::string
+Gogo::type_descriptor_decl_name(const Named_object* no,
+                               const Named_object* in_function)
+{
+  std::string ret = "__go_tdn_";
+  if (no->type_value()->is_builtin())
+    gcc_assert(in_function == NULL);
+  else
+    {
+      const std::string& unique_prefix(no->package() == NULL
+                                      ? this->unique_prefix()
+                                      : no->package()->unique_prefix());
+      const std::string& package_name(no->package() == NULL
+                                     ? this->package_name()
+                                     : no->package()->name());
+      ret.append(unique_prefix);
+      ret.append(1, '.');
+      ret.append(package_name);
+      ret.append(1, '.');
+      if (in_function != NULL)
+       {
+         ret.append(Gogo::unpack_hidden_name(in_function->name()));
+         ret.append(1, '.');
+       }
+    }
+  ret.append(no->name());
+  return ret;
+}
+
+// Where a type descriptor decl should be defined.
+
+Gogo::Type_descriptor_location
+Gogo::type_descriptor_location(const Type* type)
+{
+  const Named_type* name = type->named_type();
+  if (name != NULL)
+    {
+      if (name->named_object()->package() != NULL)
+       {
+         // This is a named type defined in a different package.  The
+         // descriptor should be defined in that package.
+         return TYPE_DESCRIPTOR_UNDEFINED;
+       }
+      else if (name->is_builtin())
+       {
+         // We create the descriptor for a builtin type whenever we
+         // need it.
+         return TYPE_DESCRIPTOR_COMMON;
+       }
+      else
+       {
+         // This is a named type defined in this package.  The
+         // descriptor should be defined here.
+         return TYPE_DESCRIPTOR_DEFINED;
+       }
+    }
+  else
+    {
+      if (type->points_to() != NULL
+         && type->points_to()->named_type() != NULL
+         && type->points_to()->named_type()->named_object()->package() != NULL)
+       {
+         // This is an unnamed pointer to a named type defined in a
+         // different package.  The descriptor should be defined in
+         // that package.
+         return TYPE_DESCRIPTOR_UNDEFINED;
+       }
+      else
+       {
+         // This is an unnamed type.  The descriptor could be defined
+         // in any package where it is needed, and the linker will
+         // pick one descriptor to keep.
+         return TYPE_DESCRIPTOR_COMMON;
+       }
+    }
+}
+
+// Build a type descriptor decl for TYPE.  INITIALIZER is a struct
+// composite literal which initializers the type descriptor.
+
+void
+Gogo::build_type_descriptor_decl(const Type* type, Expression* initializer,
+                                tree* pdecl)
+{
+  const Named_type* name = type->named_type();
+
+  // We can have multiple instances of unnamed types, but we only want
+  // to emit the type descriptor once.  We use a hash table to handle
+  // this.  This is not necessary for named types, as they are unique,
+  // and we store the type descriptor decl in the type itself.
+  tree* phash = NULL;
+  if (name == NULL)
+    {
+      if (this->type_descriptor_decls_ == NULL)
+       this->type_descriptor_decls_ = new Type_descriptor_decls(10);
+
+      std::pair<Type_descriptor_decls::iterator, bool> ins =
+       this->type_descriptor_decls_->insert(std::make_pair(type, NULL_TREE));
+      if (!ins.second)
+       {
+         // We've already built a type descriptor for this type.
+         *pdecl = ins.first->second;
+         return;
+       }
+      phash = &ins.first->second;
+    }
+
+  std::string decl_name;
+  if (name == NULL)
+    decl_name = this->unnamed_type_descriptor_decl_name(type);
+  else
+    decl_name = this->type_descriptor_decl_name(name->named_object(),
+                                               name->in_function());
+  tree id = get_identifier_from_string(decl_name);
+  tree descriptor_type_tree = initializer->type()->get_tree(this);
+  if (descriptor_type_tree == error_mark_node)
+    {
+      *pdecl = error_mark_node;
+      return;
+    }
+  tree decl = build_decl(name == NULL ? BUILTINS_LOCATION : name->location(),
+                        VAR_DECL, id,
+                        build_qualified_type(descriptor_type_tree,
+                                             TYPE_QUAL_CONST));
+  TREE_READONLY(decl) = 1;
+  TREE_CONSTANT(decl) = 1;
+  DECL_ARTIFICIAL(decl) = 1;
+
+  go_preserve_from_gc(decl);
+  if (phash != NULL)
+    *phash = decl;
+
+  // We store the new DECL now because we may need to refer to it when
+  // expanding INITIALIZER.
+  *pdecl = decl;
+
+  // If appropriate, just refer to the exported type identifier.
+  Gogo::Type_descriptor_location type_descriptor_location =
+    this->type_descriptor_location(type);
+  if (type_descriptor_location == TYPE_DESCRIPTOR_UNDEFINED)
+    {
+      TREE_PUBLIC(decl) = 1;
+      DECL_EXTERNAL(decl) = 1;
+      return;
+    }
+
+  TREE_STATIC(decl) = 1;
+  TREE_USED(decl) = 1;
+
+  Translate_context context(this, NULL, NULL, NULL);
+  context.set_is_const();
+  tree constructor = initializer->get_tree(&context);
+
+  if (constructor == error_mark_node)
+    gcc_assert(saw_errors());
+
+  DECL_INITIAL(decl) = constructor;
+
+  if (type_descriptor_location == TYPE_DESCRIPTOR_COMMON)
+    {
+      make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
+      resolve_unique_section(decl, 1, 0);
+    }
+  else
+    {
+#ifdef OBJECT_FORMAT_ELF
+      // Give the decl protected visibility.  This avoids out-of-range
+      // references with shared libraries with the x86_64 small model
+      // when the type descriptor gets a COPY reloc into the main
+      // executable.  There is no need to have unique pointers to type
+      // descriptors, as the runtime code compares reflection strings
+      // if necessary.
+      DECL_VISIBILITY(decl) = VISIBILITY_PROTECTED;
+      DECL_VISIBILITY_SPECIFIED(decl) = 1;
+#endif
+
+      TREE_PUBLIC(decl) = 1;
+    }
+
+  rest_of_decl_compilation(decl, 1, 0);
+}
+
+// Build an interface method table for a type: a list of function
+// pointers, one for each interface method.  This is used for
+// interfaces.
+
+tree
+Gogo::interface_method_table_for_type(const Interface_type* interface,
+                                     Named_type* type,
+                                     bool is_pointer)
+{
+  const Typed_identifier_list* interface_methods = interface->methods();
+  gcc_assert(!interface_methods->empty());
+
+  std::string mangled_name = ((is_pointer ? "__go_pimt__" : "__go_imt_")
+                             + interface->mangled_name(this)
+                             + "__"
+                             + type->mangled_name(this));
+
+  tree id = get_identifier_from_string(mangled_name);
+
+  // See whether this interface has any hidden methods.
+  bool has_hidden_methods = false;
+  for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+       p != interface_methods->end();
+       ++p)
+    {
+      if (Gogo::is_hidden_name(p->name()))
+       {
+         has_hidden_methods = true;
+         break;
+       }
+    }
+
+  // We already know that the named type is convertible to the
+  // interface.  If the interface has hidden methods, and the named
+  // type is defined in a different package, then the interface
+  // conversion table will be defined by that other package.
+  if (has_hidden_methods && type->named_object()->package() != NULL)
+    {
+      tree array_type = build_array_type(const_ptr_type_node, NULL);
+      tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
+      TREE_READONLY(decl) = 1;
+      TREE_CONSTANT(decl) = 1;
+      TREE_PUBLIC(decl) = 1;
+      DECL_EXTERNAL(decl) = 1;
+      go_preserve_from_gc(decl);
+      return decl;
+    }
+
+  size_t count = interface_methods->size();
+  VEC(constructor_elt, gc)* pointers = VEC_alloc(constructor_elt, gc,
+                                                count + 1);
+
+  // The first element is the type descriptor.
+  constructor_elt* elt = VEC_quick_push(constructor_elt, pointers, NULL);
+  elt->index = size_zero_node;
+  Type* td_type;
+  if (!is_pointer)
+    td_type = type;
+  else
+    td_type = Type::make_pointer_type(type);
+  elt->value = fold_convert(const_ptr_type_node,
+                           td_type->type_descriptor_pointer(this));
+
+  size_t i = 1;
+  for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+       p != interface_methods->end();
+       ++p, ++i)
+    {
+      bool is_ambiguous;
+      Method* m = type->method_function(p->name(), &is_ambiguous);
+      gcc_assert(m != NULL);
+
+      Named_object* no = m->named_object();
+
+      tree fnid = no->get_id(this);
+
+      tree fndecl;
+      if (no->is_function())
+       fndecl = no->func_value()->get_or_make_decl(this, no, fnid);
+      else if (no->is_function_declaration())
+       fndecl = no->func_declaration_value()->get_or_make_decl(this, no,
+                                                               fnid);
+      else
+       gcc_unreachable();
+      fndecl = build_fold_addr_expr(fndecl);
+
+      elt = VEC_quick_push(constructor_elt, pointers, NULL);
+      elt->index = size_int(i);
+      elt->value = fold_convert(const_ptr_type_node, fndecl);
+    }
+  gcc_assert(i == count + 1);
+
+  tree array_type = build_array_type(const_ptr_type_node,
+                                    build_index_type(size_int(count)));
+  tree constructor = build_constructor(array_type, pointers);
+
+  tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
+  TREE_STATIC(decl) = 1;
+  TREE_USED(decl) = 1;
+  TREE_READONLY(decl) = 1;
+  TREE_CONSTANT(decl) = 1;
+  DECL_INITIAL(decl) = constructor;
+
+  // If the interface type has hidden methods, then this is the only
+  // definition of the table.  Otherwise it is a comdat table which
+  // may be defined in multiple packages.
+  if (has_hidden_methods)
+    {
+#ifdef OBJECT_FORMAT_ELF
+      // Give the decl protected visibility.  This avoids out-of-range
+      // references with shared libraries with the x86_64 small model
+      // when the table gets a COPY reloc into the main executable.
+      DECL_VISIBILITY(decl) = VISIBILITY_PROTECTED;
+      DECL_VISIBILITY_SPECIFIED(decl) = 1;
+#endif
+
+      TREE_PUBLIC(decl) = 1;
+    }
+  else
+    {
+      make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
+      resolve_unique_section(decl, 1, 0);
+    }
+
+  rest_of_decl_compilation(decl, 1, 0);
+
+  go_preserve_from_gc(decl);
+
+  return decl;
+}
+
+// Mark a function as a builtin library function.
+
+void
+Gogo::mark_fndecl_as_builtin_library(tree fndecl)
+{
+  DECL_EXTERNAL(fndecl) = 1;
+  TREE_PUBLIC(fndecl) = 1;
+  DECL_ARTIFICIAL(fndecl) = 1;
+  TREE_NOTHROW(fndecl) = 1;
+  DECL_VISIBILITY(fndecl) = VISIBILITY_DEFAULT;
+  DECL_VISIBILITY_SPECIFIED(fndecl) = 1;
+}
+
+// Build a call to a builtin function.
+
+tree
+Gogo::call_builtin(tree* pdecl, source_location location, const char* name,
+                  int nargs, tree rettype, ...)
+{
+  if (rettype == error_mark_node)
+    return error_mark_node;
+
+  tree* types = new tree[nargs];
+  tree* args = new tree[nargs];
+
+  va_list ap;
+  va_start(ap, rettype);
+  for (int i = 0; i < nargs; ++i)
+    {
+      types[i] = va_arg(ap, tree);
+      args[i] = va_arg(ap, tree);
+      if (types[i] == error_mark_node || args[i] == error_mark_node)
+       return error_mark_node;
+    }
+  va_end(ap);
+
+  if (*pdecl == NULL_TREE)
+    {
+      tree fnid = get_identifier(name);
+
+      tree argtypes = NULL_TREE;
+      tree* pp = &argtypes;
+      for (int i = 0; i < nargs; ++i)
+       {
+         *pp = tree_cons(NULL_TREE, types[i], NULL_TREE);
+         pp = &TREE_CHAIN(*pp);
+       }
+      *pp = void_list_node;
+
+      tree fntype = build_function_type(rettype, argtypes);
+
+      *pdecl = build_decl(BUILTINS_LOCATION, FUNCTION_DECL, fnid, fntype);
+      Gogo::mark_fndecl_as_builtin_library(*pdecl);
+      go_preserve_from_gc(*pdecl);
+    }
+
+  tree fnptr = build_fold_addr_expr(*pdecl);
+  if (CAN_HAVE_LOCATION_P(fnptr))
+    SET_EXPR_LOCATION(fnptr, location);
+
+  tree ret = build_call_array(rettype, fnptr, nargs, args);
+  SET_EXPR_LOCATION(ret, location);
+
+  delete[] types;
+  delete[] args;
+
+  return ret;
+}
+
+// Build a call to the runtime error function.
+
+tree
+Gogo::runtime_error(int code, source_location location)
+{
+  static tree runtime_error_fndecl;
+  tree ret = Gogo::call_builtin(&runtime_error_fndecl,
+                               location,
+                               "__go_runtime_error",
+                               1,
+                               void_type_node,
+                               integer_type_node,
+                               build_int_cst(integer_type_node, code));
+  // The runtime error function panics and does not return.
+  TREE_NOTHROW(runtime_error_fndecl) = 0;
+  TREE_THIS_VOLATILE(runtime_error_fndecl) = 1;
+  return ret;
+}
+
+// Send VAL on CHANNEL.  If BLOCKING is true, the resulting tree has a
+// void type.  If BLOCKING is false, the resulting tree has a boolean
+// type, and it will evaluate as true if the value was sent.  If
+// FOR_SELECT is true, this is being done because it was chosen in a
+// select statement.
+
+tree
+Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
+                     source_location location)
+{
+  if (int_size_in_bytes(TREE_TYPE(val)) <= 8
+      && !AGGREGATE_TYPE_P(TREE_TYPE(val))
+      && !FLOAT_TYPE_P(TREE_TYPE(val)))
+    {
+      val = convert_to_integer(uint64_type_node, val);
+      if (blocking)
+       {
+         static tree send_small_fndecl;
+         tree ret = Gogo::call_builtin(&send_small_fndecl,
+                                       location,
+                                       "__go_send_small",
+                                       3,
+                                       void_type_node,
+                                       ptr_type_node,
+                                       channel,
+                                       uint64_type_node,
+                                       val,
+                                       boolean_type_node,
+                                       (for_select
+                                        ? boolean_true_node
+                                        : boolean_false_node));
+         // This can panic if there are too many operations on a
+         // closed channel.
+         TREE_NOTHROW(send_small_fndecl) = 0;
+         return ret;
+       }
+      else
+       {
+         gcc_assert(!for_select);
+         static tree send_nonblocking_small_fndecl;
+         tree ret = Gogo::call_builtin(&send_nonblocking_small_fndecl,
+                                       location,
+                                       "__go_send_nonblocking_small",
+                                       2,
+                                       boolean_type_node,
+                                       ptr_type_node,
+                                       channel,
+                                       uint64_type_node,
+                                       val);
+         // This can panic if there are too many operations on a
+         // closed channel.
+         TREE_NOTHROW(send_nonblocking_small_fndecl) = 0;
+         return ret;
+       }
+    }
+  else
+    {
+      tree make_tmp;
+      if (TREE_ADDRESSABLE(TREE_TYPE(val)) || TREE_CODE(val) == VAR_DECL)
+       {
+         make_tmp = NULL_TREE;
+         val = build_fold_addr_expr(val);
+         if (DECL_P(val))
+           TREE_ADDRESSABLE(val) = 1;
+       }
+      else
+       {
+         tree tmp = create_tmp_var(TREE_TYPE(val), get_name(val));
+         DECL_IGNORED_P(tmp) = 0;
+         DECL_INITIAL(tmp) = val;
+         TREE_ADDRESSABLE(tmp) = 1;
+         make_tmp = build1(DECL_EXPR, void_type_node, tmp);
+         SET_EXPR_LOCATION(make_tmp, location);
+         val = build_fold_addr_expr(tmp);
+       }
+      val = fold_convert(ptr_type_node, val);
+
+      tree call;
+      if (blocking)
+       {
+         static tree send_big_fndecl;
+         call = Gogo::call_builtin(&send_big_fndecl,
+                                   location,
+                                   "__go_send_big",
+                                   3,
+                                   void_type_node,
+                                   ptr_type_node,
+                                   channel,
+                                   ptr_type_node,
+                                   val,
+                                   boolean_type_node,
+                                   (for_select
+                                    ? boolean_true_node
+                                    : boolean_false_node));
+         // This can panic if there are too many operations on a
+         // closed channel.
+         TREE_NOTHROW(send_big_fndecl) = 0;
+       }
+      else
+       {
+         gcc_assert(!for_select);
+         static tree send_nonblocking_big_fndecl;
+         call = Gogo::call_builtin(&send_nonblocking_big_fndecl,
+                                   location,
+                                   "__go_send_nonblocking_big",
+                                   2,
+                                   boolean_type_node,
+                                   ptr_type_node,
+                                   channel,
+                                   ptr_type_node,
+                                   val);
+         // This can panic if there are too many operations on a
+         // closed channel.
+         TREE_NOTHROW(send_nonblocking_big_fndecl) = 0;
+       }
+
+      if (make_tmp == NULL_TREE)
+       return call;
+      else
+       {
+         tree ret = build2(COMPOUND_EXPR, TREE_TYPE(call), make_tmp, call);
+         SET_EXPR_LOCATION(ret, location);
+         return ret;
+       }
+    }
+}
+
+// Return a tree for receiving a value of type TYPE_TREE on CHANNEL.
+// This does a blocking receive and returns the value read from the
+// channel.  If FOR_SELECT is true, this is being done because it was
+// chosen in a select statement.
+
+tree
+Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
+                          source_location location)
+{
+  if (int_size_in_bytes(type_tree) <= 8
+      && !AGGREGATE_TYPE_P(type_tree)
+      && !FLOAT_TYPE_P(type_tree))
+    {
+      static tree receive_small_fndecl;
+      tree call = Gogo::call_builtin(&receive_small_fndecl,
+                                    location,
+                                    "__go_receive_small",
+                                    2,
+                                    uint64_type_node,
+                                    ptr_type_node,
+                                    channel,
+                                    boolean_type_node,
+                                    (for_select
+                                     ? boolean_true_node
+                                     : boolean_false_node));
+      // This can panic if there are too many operations on a closed
+      // channel.
+      TREE_NOTHROW(receive_small_fndecl) = 0;
+      int bitsize = GET_MODE_BITSIZE(TYPE_MODE(type_tree));
+      tree int_type_tree = go_type_for_size(bitsize, 1);
+      return fold_convert_loc(location, type_tree,
+                             fold_convert_loc(location, int_type_tree,
+                                              call));
+    }
+  else
+    {
+      tree tmp = create_tmp_var(type_tree, get_name(type_tree));
+      DECL_IGNORED_P(tmp) = 0;
+      TREE_ADDRESSABLE(tmp) = 1;
+      tree make_tmp = build1(DECL_EXPR, void_type_node, tmp);
+      SET_EXPR_LOCATION(make_tmp, location);
+      tree tmpaddr = build_fold_addr_expr(tmp);
+      tmpaddr = fold_convert(ptr_type_node, tmpaddr);
+      static tree receive_big_fndecl;
+      tree call = Gogo::call_builtin(&receive_big_fndecl,
+                                    location,
+                                    "__go_receive_big",
+                                    3,
+                                    void_type_node,
+                                    ptr_type_node,
+                                    channel,
+                                    ptr_type_node,
+                                    tmpaddr,
+                                    boolean_type_node,
+                                    (for_select
+                                     ? boolean_true_node
+                                     : boolean_false_node));
+      // This can panic if there are too many operations on a closed
+      // channel.
+      TREE_NOTHROW(receive_big_fndecl) = 0;
+      return build2(COMPOUND_EXPR, type_tree, make_tmp,
+                   build2(COMPOUND_EXPR, type_tree, call, tmp));
+    }
+}
+
+// Return the type of a function trampoline.  This is like
+// get_trampoline_type in tree-nested.c.
+
+tree
+Gogo::trampoline_type_tree()
+{
+  static tree type_tree;
+  if (type_tree == NULL_TREE)
+    {
+      unsigned int align = TRAMPOLINE_ALIGNMENT;
+      unsigned int size = TRAMPOLINE_SIZE;
+      tree t = build_index_type(build_int_cst(integer_type_node, size - 1));
+      t = build_array_type(char_type_node, t);
+
+      type_tree = Gogo::builtin_struct(NULL, "__go_trampoline", NULL_TREE, 1,
+                                      "__data", t);
+      t = TYPE_FIELDS(type_tree);
+      DECL_ALIGN(t) = align;
+      DECL_USER_ALIGN(t) = 1;
+
+      go_preserve_from_gc(type_tree);
+    }
+  return type_tree;
+}
+
+// Make a trampoline which calls FNADDR passing CLOSURE.
+
+tree
+Gogo::make_trampoline(tree fnaddr, tree closure, source_location location)
+{
+  tree trampoline_type = Gogo::trampoline_type_tree();
+  tree trampoline_size = TYPE_SIZE_UNIT(trampoline_type);
+
+  closure = save_expr(closure);
+
+  // We allocate the trampoline using a special function which will
+  // mark it as executable.
+  static tree trampoline_fndecl;
+  tree x = Gogo::call_builtin(&trampoline_fndecl,
+                             location,
+                             "__go_allocate_trampoline",
+                             2,
+                             ptr_type_node,
+                             size_type_node,
+                             trampoline_size,
+                             ptr_type_node,
+                             fold_convert_loc(location, ptr_type_node,
+                                              closure));
+
+  x = save_expr(x);
+
+  // Initialize the trampoline.
+  tree ini = build_call_expr(implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE],
+                            3, x, fnaddr, closure);
+
+  // On some targets the trampoline address needs to be adjusted.  For
+  // example, when compiling in Thumb mode on the ARM, the address
+  // needs to have the low bit set.
+  x = build_call_expr(implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE],
+                     1, x);
+  x = fold_convert(TREE_TYPE(fnaddr), x);
+
+  return build2(COMPOUND_EXPR, TREE_TYPE(x), ini, x);
+}
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
new file mode 100644 (file)
index 0000000..0216d6c
--- /dev/null
@@ -0,0 +1,4274 @@
+// gogo.cc -- Go frontend parsed representation.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "go-c.h"
+#include "go-dump.h"
+#include "lex.h"
+#include "types.h"
+#include "statements.h"
+#include "expressions.h"
+#include "dataflow.h"
+#include "import.h"
+#include "export.h"
+#include "gogo.h"
+
+// Class Gogo.
+
+Gogo::Gogo(int int_type_size, int float_type_size, int pointer_size)
+  : package_(NULL),
+    functions_(),
+    globals_(new Bindings(NULL)),
+    imports_(),
+    imported_unsafe_(false),
+    packages_(),
+    map_descriptors_(NULL),
+    type_descriptor_decls_(NULL),
+    init_functions_(),
+    need_init_fn_(false),
+    init_fn_name_(),
+    imported_init_fns_(),
+    unique_prefix_(),
+    interface_types_()
+{
+  const source_location loc = BUILTINS_LOCATION;
+
+  Named_type* uint8_type = Type::make_integer_type("uint8", true, 8,
+                                                  RUNTIME_TYPE_KIND_UINT8);
+  this->add_named_type(uint8_type);
+  this->add_named_type(Type::make_integer_type("uint16", true,  16,
+                                              RUNTIME_TYPE_KIND_UINT16));
+  this->add_named_type(Type::make_integer_type("uint32", true,  32,
+                                              RUNTIME_TYPE_KIND_UINT32));
+  this->add_named_type(Type::make_integer_type("uint64", true,  64,
+                                              RUNTIME_TYPE_KIND_UINT64));
+
+  this->add_named_type(Type::make_integer_type("int8",  false,   8,
+                                              RUNTIME_TYPE_KIND_INT8));
+  this->add_named_type(Type::make_integer_type("int16", false,  16,
+                                              RUNTIME_TYPE_KIND_INT16));
+  this->add_named_type(Type::make_integer_type("int32", false,  32,
+                                              RUNTIME_TYPE_KIND_INT32));
+  this->add_named_type(Type::make_integer_type("int64", false,  64,
+                                              RUNTIME_TYPE_KIND_INT64));
+
+  this->add_named_type(Type::make_float_type("float32", 32,
+                                            RUNTIME_TYPE_KIND_FLOAT32));
+  this->add_named_type(Type::make_float_type("float64", 64,
+                                            RUNTIME_TYPE_KIND_FLOAT64));
+
+  this->add_named_type(Type::make_complex_type("complex64", 64,
+                                              RUNTIME_TYPE_KIND_COMPLEX64));
+  this->add_named_type(Type::make_complex_type("complex128", 128,
+                                              RUNTIME_TYPE_KIND_COMPLEX128));
+
+  if (int_type_size < 32)
+    int_type_size = 32;
+  this->add_named_type(Type::make_integer_type("uint", true,
+                                              int_type_size,
+                                              RUNTIME_TYPE_KIND_UINT));
+  Named_type* int_type = Type::make_integer_type("int", false, int_type_size,
+                                                RUNTIME_TYPE_KIND_INT);
+  this->add_named_type(int_type);
+
+  // "byte" is an alias for "uint8".  Construct a Named_object which
+  // points to UINT8_TYPE.  Note that this breaks the normal pairing
+  // in which a Named_object points to a Named_type which points back
+  // to the same Named_object.
+  Named_object* byte_type = this->declare_type("byte", loc);
+  byte_type->set_type_value(uint8_type);
+
+  this->add_named_type(Type::make_integer_type("uintptr", true,
+                                              pointer_size,
+                                              RUNTIME_TYPE_KIND_UINTPTR));
+
+  this->add_named_type(Type::make_float_type("float", float_type_size,
+                                            RUNTIME_TYPE_KIND_FLOAT));
+
+  this->add_named_type(Type::make_complex_type("complex", float_type_size * 2,
+                                              RUNTIME_TYPE_KIND_COMPLEX));
+
+  this->add_named_type(Type::make_named_bool_type());
+
+  this->add_named_type(Type::make_named_string_type());
+
+  this->globals_->add_constant(Typed_identifier("true",
+                                               Type::make_boolean_type(),
+                                               loc),
+                              NULL,
+                              Expression::make_boolean(true, loc),
+                              0);
+  this->globals_->add_constant(Typed_identifier("false",
+                                               Type::make_boolean_type(),
+                                               loc),
+                              NULL,
+                              Expression::make_boolean(false, loc),
+                              0);
+
+  this->globals_->add_constant(Typed_identifier("nil", Type::make_nil_type(),
+                                               loc),
+                              NULL,
+                              Expression::make_nil(loc),
+                              0);
+
+  Type* abstract_int_type = Type::make_abstract_integer_type();
+  this->globals_->add_constant(Typed_identifier("iota", abstract_int_type,
+                                               loc),
+                              NULL,
+                              Expression::make_iota(),
+                              0);
+
+  Function_type* new_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  new_type->set_is_varargs();
+  new_type->set_is_builtin();
+  this->globals_->add_function_declaration("new", NULL, new_type, loc);
+
+  Function_type* make_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  make_type->set_is_varargs();
+  make_type->set_is_builtin();
+  this->globals_->add_function_declaration("make", NULL, make_type, loc);
+
+  Typed_identifier_list* len_result = new Typed_identifier_list();
+  len_result->push_back(Typed_identifier("", int_type, loc));
+  Function_type* len_type = Type::make_function_type(NULL, NULL, len_result,
+                                                    loc);
+  len_type->set_is_builtin();
+  this->globals_->add_function_declaration("len", NULL, len_type, loc);
+
+  Typed_identifier_list* cap_result = new Typed_identifier_list();
+  cap_result->push_back(Typed_identifier("", int_type, loc));
+  Function_type* cap_type = Type::make_function_type(NULL, NULL, len_result,
+                                                    loc);
+  cap_type->set_is_builtin();
+  this->globals_->add_function_declaration("cap", NULL, cap_type, loc);
+
+  Function_type* print_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  print_type->set_is_varargs();
+  print_type->set_is_builtin();
+  this->globals_->add_function_declaration("print", NULL, print_type, loc);
+
+  print_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  print_type->set_is_varargs();
+  print_type->set_is_builtin();
+  this->globals_->add_function_declaration("println", NULL, print_type, loc);
+
+  Type *empty = Type::make_interface_type(NULL, loc);
+  Typed_identifier_list* panic_parms = new Typed_identifier_list();
+  panic_parms->push_back(Typed_identifier("e", empty, loc));
+  Function_type *panic_type = Type::make_function_type(NULL, panic_parms,
+                                                      NULL, loc);
+  panic_type->set_is_builtin();
+  this->globals_->add_function_declaration("panic", NULL, panic_type, loc);
+
+  Typed_identifier_list* recover_result = new Typed_identifier_list();
+  recover_result->push_back(Typed_identifier("", empty, loc));
+  Function_type* recover_type = Type::make_function_type(NULL, NULL,
+                                                        recover_result,
+                                                        loc);
+  recover_type->set_is_builtin();
+  this->globals_->add_function_declaration("recover", NULL, recover_type, loc);
+
+  Function_type* close_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  close_type->set_is_varargs();
+  close_type->set_is_builtin();
+  this->globals_->add_function_declaration("close", NULL, close_type, loc);
+
+  Typed_identifier_list* closed_result = new Typed_identifier_list();
+  closed_result->push_back(Typed_identifier("", Type::lookup_bool_type(),
+                                           loc));
+  Function_type* closed_type = Type::make_function_type(NULL, NULL,
+                                                       closed_result, loc);
+  closed_type->set_is_varargs();
+  closed_type->set_is_builtin();
+  this->globals_->add_function_declaration("closed", NULL, closed_type, loc);
+
+  Typed_identifier_list* copy_result = new Typed_identifier_list();
+  copy_result->push_back(Typed_identifier("", int_type, loc));
+  Function_type* copy_type = Type::make_function_type(NULL, NULL,
+                                                     copy_result, loc);
+  copy_type->set_is_varargs();
+  copy_type->set_is_builtin();
+  this->globals_->add_function_declaration("copy", NULL, copy_type, loc);
+
+  Function_type* append_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  append_type->set_is_varargs();
+  append_type->set_is_builtin();
+  this->globals_->add_function_declaration("append", NULL, append_type, loc);
+
+  Function_type* cmplx_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  cmplx_type->set_is_varargs();
+  cmplx_type->set_is_builtin();
+  this->globals_->add_function_declaration("cmplx", NULL, cmplx_type, loc);
+
+  Function_type* real_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  real_type->set_is_varargs();
+  real_type->set_is_builtin();
+  this->globals_->add_function_declaration("real", NULL, real_type, loc);
+
+  Function_type* imag_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  imag_type->set_is_varargs();
+  imag_type->set_is_builtin();
+  this->globals_->add_function_declaration("imag", NULL, cmplx_type, loc);
+
+  this->define_builtin_function_trees();
+
+  // Declare "init", to ensure that it is not defined with parameters
+  // or return values.
+  this->declare_function("init",
+                        Type::make_function_type(NULL, NULL, NULL, loc),
+                        loc);
+}
+
+// Munge name for use in an error message.
+
+std::string
+Gogo::message_name(const std::string& name)
+{
+  return go_localize_identifier(Gogo::unpack_hidden_name(name).c_str());
+}
+
+// Get the package name.
+
+const std::string&
+Gogo::package_name() const
+{
+  gcc_assert(this->package_ != NULL);
+  return this->package_->name();
+}
+
+// Set the package name.
+
+void
+Gogo::set_package_name(const std::string& package_name,
+                      source_location location)
+{
+  if (this->package_ != NULL && this->package_->name() != package_name)
+    {
+      error_at(location, "expected package %<%s%>",
+              Gogo::message_name(this->package_->name()).c_str());
+      return;
+    }
+
+  // If the user did not specify a unique prefix, we always use "go".
+  // This in effect requires that the package name be unique.
+  if (this->unique_prefix_.empty())
+    this->unique_prefix_ = "go";
+
+  this->package_ = this->register_package(package_name, this->unique_prefix_,
+                                         location);
+
+  // We used to permit people to qualify symbols with the current
+  // package name (e.g., P.x), but we no longer do.
+  // this->globals_->add_package(package_name, this->package_);
+
+  if (package_name == "main")
+    {
+      // Declare "main" as a function which takes no parameters and
+      // returns no value.
+      this->declare_function("main",
+                            Type::make_function_type(NULL, NULL, NULL,
+                                                     BUILTINS_LOCATION),
+                            BUILTINS_LOCATION);
+    }
+}
+
+// Import a package.
+
+void
+Gogo::import_package(const std::string& filename,
+                    const std::string& local_name,
+                    bool is_local_name_exported,
+                    source_location location)
+{
+  if (filename == "unsafe")
+    {
+      this->import_unsafe(local_name, is_local_name_exported, location);
+      return;
+    }
+
+  Imports::const_iterator p = this->imports_.find(filename);
+  if (p != this->imports_.end())
+    {
+      Package* package = p->second;
+      package->set_location(location);
+      package->set_is_imported();
+      std::string ln = local_name;
+      bool is_ln_exported = is_local_name_exported;
+      if (ln.empty())
+       {
+         ln = package->name();
+         is_ln_exported = Lex::is_exported_name(ln);
+       }
+      if (ln != ".")
+       {
+         ln = this->pack_hidden_name(ln, is_ln_exported);
+         this->package_->bindings()->add_package(ln, package);
+       }
+      else
+       {
+         Bindings* bindings = package->bindings();
+         for (Bindings::const_declarations_iterator p =
+                bindings->begin_declarations();
+              p != bindings->end_declarations();
+              ++p)
+           this->add_named_object(p->second);
+       }
+      return;
+    }
+
+  Import::Stream* stream = Import::open_package(filename, location);
+  if (stream == NULL)
+    {
+      error_at(location, "import file %qs not found", filename.c_str());
+      return;
+    }
+
+  Import imp(stream, location);
+  imp.register_builtin_types(this);
+  Package* package = imp.import(this, local_name, is_local_name_exported);
+  this->imports_.insert(std::make_pair(filename, package));
+  package->set_is_imported();
+
+  delete stream;
+}
+
+// Add an import control function for an imported package to the list.
+
+void
+Gogo::add_import_init_fn(const std::string& package_name,
+                        const std::string& init_name, int prio)
+{
+  for (std::set<Import_init>::const_iterator p =
+        this->imported_init_fns_.begin();
+       p != this->imported_init_fns_.end();
+       ++p)
+    {
+      if (p->init_name() == init_name
+         && (p->package_name() != package_name || p->priority() != prio))
+       {
+         error("duplicate package initialization name %qs",
+               Gogo::message_name(init_name).c_str());
+         inform(UNKNOWN_LOCATION, "used by package %qs at priority %d",
+                Gogo::message_name(p->package_name()).c_str(),
+                p->priority());
+         inform(UNKNOWN_LOCATION, " and by package %qs at priority %d",
+                Gogo::message_name(package_name).c_str(), prio);
+         return;
+       }
+    }
+
+  this->imported_init_fns_.insert(Import_init(package_name, init_name,
+                                             prio));
+}
+
+// Return whether we are at the global binding level.
+
+bool
+Gogo::in_global_scope() const
+{
+  return this->functions_.empty();
+}
+
+// Return the current binding contour.
+
+Bindings*
+Gogo::current_bindings()
+{
+  if (!this->functions_.empty())
+    return this->functions_.back().blocks.back()->bindings();
+  else if (this->package_ != NULL)
+    return this->package_->bindings();
+  else
+    return this->globals_;
+}
+
+const Bindings*
+Gogo::current_bindings() const
+{
+  if (!this->functions_.empty())
+    return this->functions_.back().blocks.back()->bindings();
+  else if (this->package_ != NULL)
+    return this->package_->bindings();
+  else
+    return this->globals_;
+}
+
+// Return the current block.
+
+Block*
+Gogo::current_block()
+{
+  if (this->functions_.empty())
+    return NULL;
+  else
+    return this->functions_.back().blocks.back();
+}
+
+// Look up a name in the current binding contour.  If PFUNCTION is not
+// NULL, set it to the function in which the name is defined, or NULL
+// if the name is defined in global scope.
+
+Named_object*
+Gogo::lookup(const std::string& name, Named_object** pfunction) const
+{
+  if (Gogo::is_sink_name(name))
+    return Named_object::make_sink();
+
+  for (Open_functions::const_reverse_iterator p = this->functions_.rbegin();
+       p != this->functions_.rend();
+       ++p)
+    {
+      Named_object* ret = p->blocks.back()->bindings()->lookup(name);
+      if (ret != NULL)
+       {
+         if (pfunction != NULL)
+           *pfunction = p->function;
+         return ret;
+       }
+    }
+
+  if (pfunction != NULL)
+    *pfunction = NULL;
+
+  if (this->package_ != NULL)
+    {
+      Named_object* ret = this->package_->bindings()->lookup(name);
+      if (ret != NULL)
+       {
+         if (ret->package() != NULL)
+           ret->package()->set_used();
+         return ret;
+       }
+    }
+
+  // We do not look in the global namespace.  If we did, the global
+  // namespace would effectively hide names which were defined in
+  // package scope which we have not yet seen.  Instead,
+  // define_global_names is called after parsing is over to connect
+  // undefined names at package scope with names defined at global
+  // scope.
+
+  return NULL;
+}
+
+// Look up a name in the current block, without searching enclosing
+// blocks.
+
+Named_object*
+Gogo::lookup_in_block(const std::string& name) const
+{
+  gcc_assert(!this->functions_.empty());
+  gcc_assert(!this->functions_.back().blocks.empty());
+  return this->functions_.back().blocks.back()->bindings()->lookup_local(name);
+}
+
+// Look up a name in the global namespace.
+
+Named_object*
+Gogo::lookup_global(const char* name) const
+{
+  return this->globals_->lookup(name);
+}
+
+// Add an imported package.
+
+Package*
+Gogo::add_imported_package(const std::string& real_name,
+                          const std::string& alias_arg,
+                          bool is_alias_exported,
+                          const std::string& unique_prefix,
+                          source_location location,
+                          bool* padd_to_globals)
+{
+  // FIXME: Now that we compile packages as a whole, should we permit
+  // importing the current package?
+  if (this->package_name() == real_name
+      && this->unique_prefix() == unique_prefix)
+    {
+      *padd_to_globals = false;
+      if (!alias_arg.empty() && alias_arg != ".")
+       {
+         std::string alias = this->pack_hidden_name(alias_arg,
+                                                    is_alias_exported);
+         this->package_->bindings()->add_package(alias, this->package_);
+       }
+      return this->package_;
+    }
+  else if (alias_arg == ".")
+    {
+      *padd_to_globals = true;
+      return this->register_package(real_name, unique_prefix, location);
+    }
+  else if (alias_arg == "_")
+    {
+      Package* ret = this->register_package(real_name, unique_prefix, location);
+      ret->set_uses_sink_alias();
+      return ret;
+    }
+  else
+    {
+      *padd_to_globals = false;
+      std::string alias = alias_arg;
+      if (alias.empty())
+       {
+         alias = real_name;
+         is_alias_exported = Lex::is_exported_name(alias);
+       }
+      alias = this->pack_hidden_name(alias, is_alias_exported);
+      Named_object* no = this->add_package(real_name, alias, unique_prefix,
+                                          location);
+      if (!no->is_package())
+       return NULL;
+      return no->package_value();
+    }
+}
+
+// Add a package.
+
+Named_object*
+Gogo::add_package(const std::string& real_name, const std::string& alias,
+                 const std::string& unique_prefix, source_location location)
+{
+  gcc_assert(this->in_global_scope());
+
+  // Register the package.  Note that we might have already seen it in
+  // an earlier import.
+  Package* package = this->register_package(real_name, unique_prefix, location);
+
+  return this->package_->bindings()->add_package(alias, package);
+}
+
+// Register a package.  This package may or may not be imported.  This
+// returns the Package structure for the package, creating if it
+// necessary.
+
+Package*
+Gogo::register_package(const std::string& package_name,
+                      const std::string& unique_prefix,
+                      source_location location)
+{
+  gcc_assert(!unique_prefix.empty() && !package_name.empty());
+  std::string name = unique_prefix + '.' + package_name;
+  Package* package = NULL;
+  std::pair<Packages::iterator, bool> ins =
+    this->packages_.insert(std::make_pair(name, package));
+  if (!ins.second)
+    {
+      // We have seen this package name before.
+      package = ins.first->second;
+      gcc_assert(package != NULL);
+      gcc_assert(package->name() == package_name
+                && package->unique_prefix() == unique_prefix);
+      if (package->location() == UNKNOWN_LOCATION)
+       package->set_location(location);
+    }
+  else
+    {
+      // First time we have seen this package name.
+      package = new Package(package_name, unique_prefix, location);
+      gcc_assert(ins.first->second == NULL);
+      ins.first->second = package;
+    }
+
+  return package;
+}
+
+// Start compiling a function.
+
+Named_object*
+Gogo::start_function(const std::string& name, Function_type* type,
+                    bool add_method_to_type, source_location location)
+{
+  bool at_top_level = this->functions_.empty();
+
+  Block* block = new Block(NULL, location);
+
+  Function* enclosing = (at_top_level
+                        ? NULL
+                        : this->functions_.back().function->func_value());
+
+  Function* function = new Function(type, enclosing, block, location);
+
+  if (type->is_method())
+    {
+      const Typed_identifier* receiver = type->receiver();
+      Variable* this_param = new Variable(receiver->type(), NULL, false,
+                                         true, true, location);
+      std::string name = receiver->name();
+      if (name.empty())
+       {
+         // We need to give receivers a name since they wind up in
+         // DECL_ARGUMENTS.  FIXME.
+         static unsigned int count;
+         char buf[50];
+         snprintf(buf, sizeof buf, "r.%u", count);
+         ++count;
+         name = buf;
+       }
+      block->bindings()->add_variable(name, NULL, this_param);
+    }
+
+  const Typed_identifier_list* parameters = type->parameters();
+  bool is_varargs = type->is_varargs();
+  if (parameters != NULL)
+    {
+      for (Typed_identifier_list::const_iterator p = parameters->begin();
+          p != parameters->end();
+          ++p)
+       {
+         Variable* param = new Variable(p->type(), NULL, false, true, false,
+                                        location);
+         if (is_varargs && p + 1 == parameters->end())
+           param->set_is_varargs_parameter();
+
+         std::string name = p->name();
+         if (name.empty() || Gogo::is_sink_name(name))
+           {
+             // We need to give parameters a name since they wind up
+             // in DECL_ARGUMENTS.  FIXME.
+             static unsigned int count;
+             char buf[50];
+             snprintf(buf, sizeof buf, "p.%u", count);
+             ++count;
+             name = buf;
+           }
+         block->bindings()->add_variable(name, NULL, param);
+       }
+    }
+
+  function->create_named_result_variables();
+
+  const std::string* pname;
+  std::string nested_name;
+  if (!name.empty())
+    pname = &name;
+  else
+    {
+      // Invent a name for a nested function.
+      static int nested_count;
+      char buf[30];
+      snprintf(buf, sizeof buf, ".$nested%d", nested_count);
+      ++nested_count;
+      nested_name = buf;
+      pname = &nested_name;
+    }
+
+  Named_object* ret;
+  if (Gogo::is_sink_name(*pname))
+    ret = Named_object::make_sink();
+  else if (!type->is_method())
+    {
+      ret = this->package_->bindings()->add_function(*pname, NULL, function);
+      if (!ret->is_function())
+       {
+         // Redefinition error.
+         ret = Named_object::make_function(name, NULL, function);
+       }
+    }
+  else
+    {
+      if (!add_method_to_type)
+       ret = Named_object::make_function(name, NULL, function);
+      else
+       {
+         gcc_assert(at_top_level);
+         Type* rtype = type->receiver()->type();
+
+         // We want to look through the pointer created by the
+         // parser, without getting an error if the type is not yet
+         // defined.
+         if (rtype->classification() == Type::TYPE_POINTER)
+           rtype = rtype->points_to();
+
+         if (rtype->is_error_type())
+           ret = Named_object::make_function(name, NULL, function);
+         else if (rtype->named_type() != NULL)
+           {
+             ret = rtype->named_type()->add_method(name, function);
+             if (!ret->is_function())
+               {
+                 // Redefinition error.
+                 ret = Named_object::make_function(name, NULL, function);
+               }
+           }
+         else if (rtype->forward_declaration_type() != NULL)
+           {
+             Named_object* type_no =
+               rtype->forward_declaration_type()->named_object();
+             if (type_no->is_unknown())
+               {
+                 // If we are seeing methods it really must be a
+                 // type.  Declare it as such.  An alternative would
+                 // be to support lists of methods for unknown
+                 // expressions.  Either way the error messages if
+                 // this is not a type are going to get confusing.
+                 Named_object* declared =
+                   this->declare_package_type(type_no->name(),
+                                              type_no->location());
+                 gcc_assert(declared
+                            == type_no->unknown_value()->real_named_object());
+               }
+             ret = rtype->forward_declaration_type()->add_method(name,
+                                                                 function);
+           }
+         else
+           gcc_unreachable();
+       }
+      this->package_->bindings()->add_method(ret);
+    }
+
+  this->functions_.resize(this->functions_.size() + 1);
+  Open_function& of(this->functions_.back());
+  of.function = ret;
+  of.blocks.push_back(block);
+
+  if (!type->is_method() && Gogo::unpack_hidden_name(name) == "init")
+    {
+      this->init_functions_.push_back(ret);
+      this->need_init_fn_ = true;
+    }
+
+  return ret;
+}
+
+// Finish compiling a function.
+
+void
+Gogo::finish_function(source_location location)
+{
+  this->finish_block(location);
+  gcc_assert(this->functions_.back().blocks.empty());
+  this->functions_.pop_back();
+}
+
+// Return the current function.
+
+Named_object*
+Gogo::current_function() const
+{
+  gcc_assert(!this->functions_.empty());
+  return this->functions_.back().function;
+}
+
+// Start a new block.
+
+void
+Gogo::start_block(source_location location)
+{
+  gcc_assert(!this->functions_.empty());
+  Block* block = new Block(this->current_block(), location);
+  this->functions_.back().blocks.push_back(block);
+}
+
+// Finish a block.
+
+Block*
+Gogo::finish_block(source_location location)
+{
+  gcc_assert(!this->functions_.empty());
+  gcc_assert(!this->functions_.back().blocks.empty());
+  Block* block = this->functions_.back().blocks.back();
+  this->functions_.back().blocks.pop_back();
+  block->set_end_location(location);
+  return block;
+}
+
+// Add an unknown name.
+
+Named_object*
+Gogo::add_unknown_name(const std::string& name, source_location location)
+{
+  return this->package_->bindings()->add_unknown_name(name, location);
+}
+
+// Declare a function.
+
+Named_object*
+Gogo::declare_function(const std::string& name, Function_type* type,
+                      source_location location)
+{
+  if (!type->is_method())
+    return this->current_bindings()->add_function_declaration(name, NULL, type,
+                                                             location);
+  else
+    {
+      // We don't bother to add this to the list of global
+      // declarations.
+      Type* rtype = type->receiver()->type();
+
+      // We want to look through the pointer created by the
+      // parser, without getting an error if the type is not yet
+      // defined.
+      if (rtype->classification() == Type::TYPE_POINTER)
+       rtype = rtype->points_to();
+
+      if (rtype->is_error_type())
+       return NULL;
+      else if (rtype->named_type() != NULL)
+       return rtype->named_type()->add_method_declaration(name, NULL, type,
+                                                          location);
+      else if (rtype->forward_declaration_type() != NULL)
+       {
+         Forward_declaration_type* ftype = rtype->forward_declaration_type();
+         return ftype->add_method_declaration(name, type, location);
+       }
+      else
+       gcc_unreachable();
+    }
+}
+
+// Add a label definition.
+
+Label*
+Gogo::add_label_definition(const std::string& label_name,
+                          source_location location)
+{
+  gcc_assert(!this->functions_.empty());
+  Function* func = this->functions_.back().function->func_value();
+  Label* label = func->add_label_definition(label_name, location);
+  this->add_statement(Statement::make_label_statement(label, location));
+  return label;
+}
+
+// Add a label reference.
+
+Label*
+Gogo::add_label_reference(const std::string& label_name)
+{
+  gcc_assert(!this->functions_.empty());
+  Function* func = this->functions_.back().function->func_value();
+  return func->add_label_reference(label_name);
+}
+
+// Add a statement.
+
+void
+Gogo::add_statement(Statement* statement)
+{
+  gcc_assert(!this->functions_.empty()
+            && !this->functions_.back().blocks.empty());
+  this->functions_.back().blocks.back()->add_statement(statement);
+}
+
+// Add a block.
+
+void
+Gogo::add_block(Block* block, source_location location)
+{
+  gcc_assert(!this->functions_.empty()
+            && !this->functions_.back().blocks.empty());
+  Statement* statement = Statement::make_block_statement(block, location);
+  this->functions_.back().blocks.back()->add_statement(statement);
+}
+
+// Add a constant.
+
+Named_object*
+Gogo::add_constant(const Typed_identifier& tid, Expression* expr,
+                  int iota_value)
+{
+  return this->current_bindings()->add_constant(tid, NULL, expr, iota_value);
+}
+
+// Add a type.
+
+void
+Gogo::add_type(const std::string& name, Type* type, source_location location)
+{
+  Named_object* no = this->current_bindings()->add_type(name, NULL, type,
+                                                       location);
+  if (!this->in_global_scope())
+    no->type_value()->set_in_function(this->functions_.back().function);
+}
+
+// Add a named type.
+
+void
+Gogo::add_named_type(Named_type* type)
+{
+  gcc_assert(this->in_global_scope());
+  this->current_bindings()->add_named_type(type);
+}
+
+// Declare a type.
+
+Named_object*
+Gogo::declare_type(const std::string& name, source_location location)
+{
+  Bindings* bindings = this->current_bindings();
+  Named_object* no = bindings->add_type_declaration(name, NULL, location);
+  if (!this->in_global_scope())
+    {
+      Named_object* f = this->functions_.back().function;
+      no->type_declaration_value()->set_in_function(f);
+    }
+  return no;
+}
+
+// Declare a type at the package level.
+
+Named_object*
+Gogo::declare_package_type(const std::string& name, source_location location)
+{
+  return this->package_->bindings()->add_type_declaration(name, NULL, location);
+}
+
+// Define a type which was already declared.
+
+void
+Gogo::define_type(Named_object* no, Named_type* type)
+{
+  this->current_bindings()->define_type(no, type);
+}
+
+// Add a variable.
+
+Named_object*
+Gogo::add_variable(const std::string& name, Variable* variable)
+{
+  Named_object* no = this->current_bindings()->add_variable(name, NULL,
+                                                           variable);
+
+  // In a function the middle-end wants to see a DECL_EXPR node.
+  if (no != NULL
+      && no->is_variable()
+      && !no->var_value()->is_parameter()
+      && !this->functions_.empty())
+    this->add_statement(Statement::make_variable_declaration(no));
+
+  return no;
+}
+
+// Add a sink--a reference to the blank identifier _.
+
+Named_object*
+Gogo::add_sink()
+{
+  return Named_object::make_sink();
+}
+
+// Add a named object.
+
+void
+Gogo::add_named_object(Named_object* no)
+{
+  this->current_bindings()->add_named_object(no);
+}
+
+// Record that we've seen an interface type.
+
+void
+Gogo::record_interface_type(Interface_type* itype)
+{
+  this->interface_types_.push_back(itype);
+}
+
+// Return a name for a thunk object.
+
+std::string
+Gogo::thunk_name()
+{
+  static int thunk_count;
+  char thunk_name[50];
+  snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count);
+  ++thunk_count;
+  return thunk_name;
+}
+
+// Return whether a function is a thunk.
+
+bool
+Gogo::is_thunk(const Named_object* no)
+{
+  return no->name().compare(0, 6, "$thunk") == 0;
+}
+
+// Define the global names.  We do this only after parsing all the
+// input files, because the program might define the global names
+// itself.
+
+void
+Gogo::define_global_names()
+{
+  for (Bindings::const_declarations_iterator p =
+        this->globals_->begin_declarations();
+       p != this->globals_->end_declarations();
+       ++p)
+    {
+      Named_object* global_no = p->second;
+      std::string name(Gogo::pack_hidden_name(global_no->name(), false));
+      Named_object* no = this->package_->bindings()->lookup(name);
+      if (no == NULL)
+       continue;
+      no = no->resolve();
+      if (no->is_type_declaration())
+       {
+         if (global_no->is_type())
+           {
+             if (no->type_declaration_value()->has_methods())
+               error_at(no->location(),
+                        "may not define methods for global type");
+             no->set_type_value(global_no->type_value());
+           }
+         else
+           {
+             error_at(no->location(), "expected type");
+             Type* errtype = Type::make_error_type();
+             Named_object* err = Named_object::make_type("error", NULL,
+                                                         errtype,
+                                                         BUILTINS_LOCATION);
+             no->set_type_value(err->type_value());
+           }
+       }
+      else if (no->is_unknown())
+       no->unknown_value()->set_real_named_object(global_no);
+    }
+}
+
+// Clear out names in file scope.
+
+void
+Gogo::clear_file_scope()
+{
+  this->package_->bindings()->clear_file_scope();
+
+  // Warn about packages which were imported but not used.
+  for (Packages::iterator p = this->packages_.begin();
+       p != this->packages_.end();
+       ++p)
+    {
+      Package* package = p->second;
+      if (package != this->package_
+         && package->is_imported()
+         && !package->used()
+         && !package->uses_sink_alias()
+         && !saw_errors())
+       error_at(package->location(), "imported and not used: %s",
+                Gogo::message_name(package->name()).c_str());
+      package->clear_is_imported();
+      package->clear_uses_sink_alias();
+      package->clear_used();
+    }
+}
+
+// Traverse the tree.
+
+void
+Gogo::traverse(Traverse* traverse)
+{
+  // Traverse the current package first for consistency.  The other
+  // packages will only contain imported types, constants, and
+  // declarations.
+  if (this->package_->bindings()->traverse(traverse, true) == TRAVERSE_EXIT)
+    return;
+  for (Packages::const_iterator p = this->packages_.begin();
+       p != this->packages_.end();
+       ++p)
+    {
+      if (p->second != this->package_)
+       {
+         if (p->second->bindings()->traverse(traverse, true) == TRAVERSE_EXIT)
+           break;
+       }
+    }
+}
+
+// Traversal class used to verify types.
+
+class Verify_types : public Traverse
+{
+ public:
+  Verify_types()
+    : Traverse(traverse_types)
+  { }
+
+  int
+  type(Type*);
+};
+
+// Verify that a type is correct.
+
+int
+Verify_types::type(Type* t)
+{
+  // Don't verify types defined in other packages.
+  Named_type* nt = t->named_type();
+  if (nt != NULL && nt->named_object()->package() != NULL)
+    return TRAVERSE_SKIP_COMPONENTS;
+
+  if (!t->verify())
+    return TRAVERSE_SKIP_COMPONENTS;
+  return TRAVERSE_CONTINUE;
+}
+
+// Verify that all types are correct.
+
+void
+Gogo::verify_types()
+{
+  Verify_types traverse;
+  this->traverse(&traverse);
+}
+
+// Traversal class used to lower parse tree.
+
+class Lower_parse_tree : public Traverse
+{
+ public:
+  Lower_parse_tree(Gogo* gogo, Named_object* function)
+    : Traverse(traverse_constants
+              | traverse_functions
+              | traverse_statements
+              | traverse_expressions),
+      gogo_(gogo), function_(function), iota_value_(-1)
+  { }
+
+  int
+  constant(Named_object*, bool);
+
+  int
+  function(Named_object*);
+
+  int
+  statement(Block*, size_t* pindex, Statement*);
+
+  int
+  expression(Expression**);
+
+ private:
+  // General IR.
+  Gogo* gogo_;
+  // The function we are traversing.
+  Named_object* function_;
+  // Value to use for the predeclared constant iota.
+  int iota_value_;
+};
+
+// Lower constants.  We handle constants specially so that we can set
+// the right value for the predeclared constant iota.  This works in
+// conjunction with the way we lower Const_expression objects.
+
+int
+Lower_parse_tree::constant(Named_object* no, bool)
+{
+  Named_constant* nc = no->const_value();
+
+  // We can recursively a constant if the initializer expression
+  // manages to refer to itself.
+  if (nc->lowering())
+    return TRAVERSE_CONTINUE;
+  nc->set_lowering();
+
+  gcc_assert(this->iota_value_ == -1);
+  this->iota_value_ = nc->iota_value();
+  nc->traverse_expression(this);
+  this->iota_value_ = -1;
+
+  nc->clear_lowering();
+
+  // We will traverse the expression a second time, but that will be
+  // fast.
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Lower function closure types.  Record the function while lowering
+// it, so that we can pass it down when lowering an expression.
+
+int
+Lower_parse_tree::function(Named_object* no)
+{
+  no->func_value()->set_closure_type();
+
+  gcc_assert(this->function_ == NULL);
+  this->function_ = no;
+  int t = no->func_value()->traverse(this);
+  this->function_ = NULL;
+
+  if (t == TRAVERSE_EXIT)
+    return t;
+  return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// Lower statement parse trees.
+
+int
+Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig)
+{
+  // Lower the expressions first.
+  int t = sorig->traverse_contents(this);
+  if (t == TRAVERSE_EXIT)
+    return t;
+
+  // Keep lowering until nothing changes.
+  Statement* s = sorig;
+  while (true)
+    {
+      Statement* snew = s->lower(this->gogo_, block);
+      if (snew == s)
+       break;
+      s = snew;
+      t = s->traverse_contents(this);
+      if (t == TRAVERSE_EXIT)
+       return t;
+    }
+
+  if (s != sorig)
+    block->replace_statement(*pindex, s);
+
+  return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// Lower expression parse trees.
+
+int
+Lower_parse_tree::expression(Expression** pexpr)
+{
+  // We have to lower all subexpressions first, so that we can get
+  // their type if necessary.  This is awkward, because we don't have
+  // a postorder traversal pass.
+  if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  // Keep lowering until nothing changes.
+  while (true)
+    {
+      Expression* e = *pexpr;
+      Expression* enew = e->lower(this->gogo_, this->function_,
+                                 this->iota_value_);
+      if (enew == e)
+       break;
+      *pexpr = enew;
+    }
+  return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// Lower the parse tree.  This is called after the parse is complete,
+// when all names should be resolved.
+
+void
+Gogo::lower_parse_tree()
+{
+  Lower_parse_tree lower_parse_tree(this, NULL);
+  this->traverse(&lower_parse_tree);
+}
+
+// Lower an expression.
+
+void
+Gogo::lower_expression(Named_object* function, Expression** pexpr)
+{
+  Lower_parse_tree lower_parse_tree(this, function);
+  lower_parse_tree.expression(pexpr);
+}
+
+// Lower a constant.  This is called when lowering a reference to a
+// constant.  We have to make sure that the constant has already been
+// lowered.
+
+void
+Gogo::lower_constant(Named_object* no)
+{
+  gcc_assert(no->is_const());
+  Lower_parse_tree lower(this, NULL);
+  lower.constant(no, false);
+}
+
+// Look for interface types to finalize methods of inherited
+// interfaces.
+
+class Finalize_methods : public Traverse
+{
+ public:
+  Finalize_methods(Gogo* gogo)
+    : Traverse(traverse_types),
+      gogo_(gogo)
+  { }
+
+  int
+  type(Type*);
+
+ private:
+  Gogo* gogo_;
+};
+
+// Finalize the methods of an interface type.
+
+int
+Finalize_methods::type(Type* t)
+{
+  // Check the classification so that we don't finalize the methods
+  // twice for a named interface type.
+  switch (t->classification())
+    {
+    case Type::TYPE_INTERFACE:
+      t->interface_type()->finalize_methods();
+      break;
+
+    case Type::TYPE_NAMED:
+      {
+       // We have to finalize the methods of the real type first.
+       // But if the real type is a struct type, then we only want to
+       // finalize the methods of the field types, not of the struct
+       // type itself.  We don't want to add methods to the struct,
+       // since it has a name.
+       Type* rt = t->named_type()->real_type();
+       if (rt->classification() != Type::TYPE_STRUCT)
+         {
+           if (Type::traverse(rt, this) == TRAVERSE_EXIT)
+             return TRAVERSE_EXIT;
+         }
+       else
+         {
+           if (rt->struct_type()->traverse_field_types(this) == TRAVERSE_EXIT)
+             return TRAVERSE_EXIT;
+         }
+
+       t->named_type()->finalize_methods(this->gogo_);
+
+       return TRAVERSE_SKIP_COMPONENTS;
+      }
+
+    case Type::TYPE_STRUCT:
+      t->struct_type()->finalize_methods(this->gogo_);
+      break;
+
+    default:
+      break;
+    }
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Finalize method lists and build stub methods for types.
+
+void
+Gogo::finalize_methods()
+{
+  Finalize_methods finalize(this);
+  this->traverse(&finalize);
+}
+
+// Set types for unspecified variables and constants.
+
+void
+Gogo::determine_types()
+{
+  Bindings* bindings = this->current_bindings();
+  for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
+       p != bindings->end_definitions();
+       ++p)
+    {
+      if ((*p)->is_function())
+       (*p)->func_value()->determine_types();
+      else if ((*p)->is_variable())
+       (*p)->var_value()->determine_type();
+      else if ((*p)->is_const())
+       (*p)->const_value()->determine_type();
+
+      // See if a variable requires us to build an initialization
+      // function.  We know that we will see all global variables
+      // here.
+      if (!this->need_init_fn_ && (*p)->is_variable())
+       {
+         Variable* variable = (*p)->var_value();
+
+         // If this is a global variable which requires runtime
+         // initialization, we need an initialization function.
+         if (!variable->is_global() || variable->init() == NULL)
+           ;
+         else if (variable->type()->interface_type() != NULL)
+           this->need_init_fn_ = true;
+         else if (variable->init()->is_constant())
+           ;
+         else if (!variable->init()->is_composite_literal())
+           this->need_init_fn_ = true;
+         else if (variable->init()->is_nonconstant_composite_literal())
+           this->need_init_fn_ = true;
+
+         // If this is a global variable which holds a pointer value,
+         // then we need an initialization function to register it as a
+         // GC root.
+         if (variable->is_global() && variable->type()->has_pointer())
+           this->need_init_fn_ = true;
+       }
+    }
+
+  // Determine the types of constants in packages.
+  for (Packages::const_iterator p = this->packages_.begin();
+       p != this->packages_.end();
+       ++p)
+    p->second->determine_types();
+}
+
+// Traversal class used for type checking.
+
+class Check_types_traverse : public Traverse
+{
+ public:
+  Check_types_traverse(Gogo* gogo)
+    : Traverse(traverse_variables
+              | traverse_constants
+              | traverse_statements
+              | traverse_expressions),
+      gogo_(gogo)
+  { }
+
+  int
+  variable(Named_object*);
+
+  int
+  constant(Named_object*, bool);
+
+  int
+  statement(Block*, size_t* pindex, Statement*);
+
+  int
+  expression(Expression**);
+
+ private:
+  // General IR.
+  Gogo* gogo_;
+};
+
+// Check that a variable initializer has the right type.
+
+int
+Check_types_traverse::variable(Named_object* named_object)
+{
+  if (named_object->is_variable())
+    {
+      Variable* var = named_object->var_value();
+      Expression* init = var->init();
+      std::string reason;
+      if (init != NULL
+         && !Type::are_assignable(var->type(), init->type(), &reason))
+       {
+         if (reason.empty())
+           error_at(var->location(), "incompatible type in initialization");
+         else
+           error_at(var->location(),
+                    "incompatible type in initialization (%s)",
+                    reason.c_str());
+         var->clear_init();
+       }
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Check that a constant initializer has the right type.
+
+int
+Check_types_traverse::constant(Named_object* named_object, bool)
+{
+  Named_constant* constant = named_object->const_value();
+  Type* ctype = constant->type();
+  if (ctype->integer_type() == NULL
+      && ctype->float_type() == NULL
+      && ctype->complex_type() == NULL
+      && !ctype->is_boolean_type()
+      && !ctype->is_string_type())
+    {
+      error_at(constant->location(), "invalid constant type");
+      constant->set_error();
+    }
+  else if (!constant->expr()->is_constant())
+    {
+      error_at(constant->expr()->location(), "expression is not constant");
+      constant->set_error();
+    }
+  else if (!Type::are_assignable(constant->type(), constant->expr()->type(),
+                                NULL))
+    {
+      error_at(constant->location(),
+              "initialization expression has wrong type");
+      constant->set_error();
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Check that types are valid in a statement.
+
+int
+Check_types_traverse::statement(Block*, size_t*, Statement* s)
+{
+  s->check_types(this->gogo_);
+  return TRAVERSE_CONTINUE;
+}
+
+// Check that types are valid in an expression.
+
+int
+Check_types_traverse::expression(Expression** expr)
+{
+  (*expr)->check_types(this->gogo_);
+  return TRAVERSE_CONTINUE;
+}
+
+// Check that types are valid.
+
+void
+Gogo::check_types()
+{
+  Check_types_traverse traverse(this);
+  this->traverse(&traverse);
+}
+
+// Check the types in a single block.
+
+void
+Gogo::check_types_in_block(Block* block)
+{
+  Check_types_traverse traverse(this);
+  block->traverse(&traverse);
+}
+
+// A traversal class used to find a single shortcut operator within an
+// expression.
+
+class Find_shortcut : public Traverse
+{
+ public:
+  Find_shortcut()
+    : Traverse(traverse_blocks
+              | traverse_statements
+              | traverse_expressions),
+      found_(NULL)
+  { }
+
+  // A pointer to the expression which was found, or NULL if none was
+  // found.
+  Expression**
+  found() const
+  { return this->found_; }
+
+ protected:
+  int
+  block(Block*)
+  { return TRAVERSE_SKIP_COMPONENTS; }
+
+  int
+  statement(Block*, size_t*, Statement*)
+  { return TRAVERSE_SKIP_COMPONENTS; }
+
+  int
+  expression(Expression**);
+
+ private:
+  Expression** found_;
+};
+
+// Find a shortcut expression.
+
+int
+Find_shortcut::expression(Expression** pexpr)
+{
+  Expression* expr = *pexpr;
+  Binary_expression* be = expr->binary_expression();
+  if (be == NULL)
+    return TRAVERSE_CONTINUE;
+  Operator op = be->op();
+  if (op != OPERATOR_OROR && op != OPERATOR_ANDAND)
+    return TRAVERSE_CONTINUE;
+  gcc_assert(this->found_ == NULL);
+  this->found_ = pexpr;
+  return TRAVERSE_EXIT;
+}
+
+// A traversal class used to turn shortcut operators into explicit if
+// statements.
+
+class Shortcuts : public Traverse
+{
+ public:
+  Shortcuts()
+    : Traverse(traverse_variables
+              | traverse_statements)
+  { }
+
+ protected:
+  int
+  variable(Named_object*);
+
+  int
+  statement(Block*, size_t*, Statement*);
+
+ private:
+  // Convert a shortcut operator.
+  Statement*
+  convert_shortcut(Block* enclosing, Expression** pshortcut);
+};
+
+// Remove shortcut operators in a single statement.
+
+int
+Shortcuts::statement(Block* block, size_t* pindex, Statement* s)
+{
+  // FIXME: This approach doesn't work for switch statements, because
+  // we add the new statements before the whole switch when we need to
+  // instead add them just before the switch expression.  The right
+  // fix is probably to lower switch statements with nonconstant cases
+  // to a series of conditionals.
+  if (s->switch_statement() != NULL)
+    return TRAVERSE_CONTINUE;
+
+  while (true)
+    {
+      Find_shortcut find_shortcut;
+
+      // If S is a variable declaration, then ordinary traversal won't
+      // do anything.  We want to explicitly traverse the
+      // initialization expression if there is one.
+      Variable_declaration_statement* vds = s->variable_declaration_statement();
+      Expression* init = NULL;
+      if (vds == NULL)
+       s->traverse_contents(&find_shortcut);
+      else
+       {
+         init = vds->var()->var_value()->init();
+         if (init == NULL)
+           return TRAVERSE_CONTINUE;
+         init->traverse(&init, &find_shortcut);
+       }
+      Expression** pshortcut = find_shortcut.found();
+      if (pshortcut == NULL)
+       return TRAVERSE_CONTINUE;
+
+      Statement* snew = this->convert_shortcut(block, pshortcut);
+      block->insert_statement_before(*pindex, snew);
+      ++*pindex;
+
+      if (pshortcut == &init)
+       vds->var()->var_value()->set_init(init);
+    }
+}
+
+// Remove shortcut operators in the initializer of a global variable.
+
+int
+Shortcuts::variable(Named_object* no)
+{
+  if (no->is_result_variable())
+    return TRAVERSE_CONTINUE;
+  Variable* var = no->var_value();
+  Expression* init = var->init();
+  if (!var->is_global() || init == NULL)
+    return TRAVERSE_CONTINUE;
+
+  while (true)
+    {
+      Find_shortcut find_shortcut;
+      init->traverse(&init, &find_shortcut);
+      Expression** pshortcut = find_shortcut.found();
+      if (pshortcut == NULL)
+       return TRAVERSE_CONTINUE;
+
+      Statement* snew = this->convert_shortcut(NULL, pshortcut);
+      var->add_preinit_statement(snew);
+      if (pshortcut == &init)
+       var->set_init(init);
+    }
+}
+
+// Given an expression which uses a shortcut operator, return a
+// statement which implements it, and update *PSHORTCUT accordingly.
+
+Statement*
+Shortcuts::convert_shortcut(Block* enclosing, Expression** pshortcut)
+{
+  Binary_expression* shortcut = (*pshortcut)->binary_expression();
+  Expression* left = shortcut->left();
+  Expression* right = shortcut->right();
+  source_location loc = shortcut->location();
+
+  Block* retblock = new Block(enclosing, loc);
+  retblock->set_end_location(loc);
+
+  Temporary_statement* ts = Statement::make_temporary(Type::make_boolean_type(),
+                                                     left, loc);
+  retblock->add_statement(ts);
+
+  Block* block = new Block(retblock, loc);
+  block->set_end_location(loc);
+  Expression* tmpref = Expression::make_temporary_reference(ts, loc);
+  Statement* assign = Statement::make_assignment(tmpref, right, loc);
+  block->add_statement(assign);
+
+  Expression* cond = Expression::make_temporary_reference(ts, loc);
+  if (shortcut->binary_expression()->op() == OPERATOR_OROR)
+    cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
+
+  Statement* if_statement = Statement::make_if_statement(cond, block, NULL,
+                                                        loc);
+  retblock->add_statement(if_statement);
+
+  *pshortcut = Expression::make_temporary_reference(ts, loc);
+
+  delete shortcut;
+
+  // Now convert any shortcut operators in LEFT and RIGHT.
+  Shortcuts shortcuts;
+  retblock->traverse(&shortcuts);
+
+  return Statement::make_block_statement(retblock, loc);
+}
+
+// Turn shortcut operators into explicit if statements.  Doing this
+// considerably simplifies the order of evaluation rules.
+
+void
+Gogo::remove_shortcuts()
+{
+  Shortcuts shortcuts;
+  this->traverse(&shortcuts);
+}
+
+// A traversal class which finds all the expressions which must be
+// evaluated in order within a statement or larger expression.  This
+// is used to implement the rules about order of evaluation.
+
+class Find_eval_ordering : public Traverse
+{
+ private:
+  typedef std::vector<Expression**> Expression_pointers;
+
+ public:
+  Find_eval_ordering()
+    : Traverse(traverse_blocks
+              | traverse_statements
+              | traverse_expressions),
+      exprs_()
+  { }
+
+  size_t
+  size() const
+  { return this->exprs_.size(); }
+
+  typedef Expression_pointers::const_iterator const_iterator;
+
+  const_iterator
+  begin() const
+  { return this->exprs_.begin(); }
+
+  const_iterator
+  end() const
+  { return this->exprs_.end(); }
+
+ protected:
+  int
+  block(Block*)
+  { return TRAVERSE_SKIP_COMPONENTS; }
+
+  int
+  statement(Block*, size_t*, Statement*)
+  { return TRAVERSE_SKIP_COMPONENTS; }
+
+  int
+  expression(Expression**);
+
+ private:
+  // A list of pointers to expressions with side-effects.
+  Expression_pointers exprs_;
+};
+
+// If an expression must be evaluated in order, put it on the list.
+
+int
+Find_eval_ordering::expression(Expression** expression_pointer)
+{
+  // We have to look at subexpressions before this one.
+  if ((*expression_pointer)->traverse_subexpressions(this) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if ((*expression_pointer)->must_eval_in_order())
+    this->exprs_.push_back(expression_pointer);
+  return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// A traversal class for ordering evaluations.
+
+class Order_eval : public Traverse
+{
+ public:
+  Order_eval()
+    : Traverse(traverse_variables
+              | traverse_statements)
+  { }
+
+  int
+  variable(Named_object*);
+
+  int
+  statement(Block*, size_t*, Statement*);
+};
+
+// Implement the order of evaluation rules for a statement.
+
+int
+Order_eval::statement(Block* block, size_t* pindex, Statement* s)
+{
+  // FIXME: This approach doesn't work for switch statements, because
+  // we add the new statements before the whole switch when we need to
+  // instead add them just before the switch expression.  The right
+  // fix is probably to lower switch statements with nonconstant cases
+  // to a series of conditionals.
+  if (s->switch_statement() != NULL)
+    return TRAVERSE_CONTINUE;
+
+  Find_eval_ordering find_eval_ordering;
+
+  // If S is a variable declaration, then ordinary traversal won't do
+  // anything.  We want to explicitly traverse the initialization
+  // expression if there is one.
+  Variable_declaration_statement* vds = s->variable_declaration_statement();
+  Expression* init = NULL;
+  Expression* orig_init = NULL;
+  if (vds == NULL)
+    s->traverse_contents(&find_eval_ordering);
+  else
+    {
+      init = vds->var()->var_value()->init();
+      if (init == NULL)
+       return TRAVERSE_CONTINUE;
+      orig_init = init;
+
+      // It might seem that this could be
+      // init->traverse_subexpressions.  Unfortunately that can fail
+      // in a case like
+      //   var err os.Error
+      //   newvar, err := call(arg())
+      // Here newvar will have an init of call result 0 of
+      // call(arg()).  If we only traverse subexpressions, we will
+      // only find arg(), and we won't bother to move anything out.
+      // Then we get to the assignment to err, we will traverse the
+      // whole statement, and this time we will find both call() and
+      // arg(), and so we will move them out.  This will cause them to
+      // be put into temporary variables before the assignment to err
+      // but after the declaration of newvar.  To avoid that problem,
+      // we traverse the entire expression here.
+      Expression::traverse(&init, &find_eval_ordering);
+    }
+
+  if (find_eval_ordering.size() <= 1)
+    {
+      // If there is only one expression with a side-effect, we can
+      // leave it in place.
+      return TRAVERSE_CONTINUE;
+    }
+
+  bool is_thunk = s->thunk_statement() != NULL;
+  for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin();
+       p != find_eval_ordering.end();
+       ++p)
+    {
+      Expression** pexpr = *p;
+
+      // If the last expression is a send or receive expression, we
+      // may be ignoring the value; we don't want to evaluate it
+      // early.
+      if (p + 1 == find_eval_ordering.end()
+         && ((*pexpr)->classification() == Expression::EXPRESSION_SEND
+             || (*pexpr)->classification() == Expression::EXPRESSION_RECEIVE))
+       break;
+
+      // The last expression in a thunk will be the call passed to go
+      // or defer, which we must not evaluate early.
+      if (is_thunk && p + 1 == find_eval_ordering.end())
+       break;
+
+      source_location loc = (*pexpr)->location();
+      Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr, loc);
+      block->insert_statement_before(*pindex, ts);
+      ++*pindex;
+
+      *pexpr = Expression::make_temporary_reference(ts, loc);
+    }
+
+  if (init != orig_init)
+    vds->var()->var_value()->set_init(init);
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Implement the order of evaluation rules for the initializer of a
+// global variable.
+
+int
+Order_eval::variable(Named_object* no)
+{
+  if (no->is_result_variable())
+    return TRAVERSE_CONTINUE;
+  Variable* var = no->var_value();
+  Expression* init = var->init();
+  if (!var->is_global() || init == NULL)
+    return TRAVERSE_CONTINUE;
+
+  Find_eval_ordering find_eval_ordering;
+  init->traverse_subexpressions(&find_eval_ordering);
+
+  if (find_eval_ordering.size() <= 1)
+    {
+      // If there is only one expression with a side-effect, we can
+      // leave it in place.
+      return TRAVERSE_SKIP_COMPONENTS;
+    }
+
+  for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin();
+       p != find_eval_ordering.end();
+       ++p)
+    {
+      Expression** pexpr = *p;
+      source_location loc = (*pexpr)->location();
+      Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr, loc);
+      var->add_preinit_statement(ts);
+      *pexpr = Expression::make_temporary_reference(ts, loc);
+    }
+
+  return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// Use temporary variables to implement the order of evaluation rules.
+
+void
+Gogo::order_evaluations()
+{
+  Order_eval order_eval;
+  this->traverse(&order_eval);
+}
+
+// Traversal to convert calls to the predeclared recover function to
+// pass in an argument indicating whether it can recover from a panic
+// or not.
+
+class Convert_recover : public Traverse
+{
+ public:
+  Convert_recover(Named_object* arg)
+    : Traverse(traverse_expressions),
+      arg_(arg)
+  { }
+
+ protected:
+  int
+  expression(Expression**);
+
+ private:
+  // The argument to pass to the function.
+  Named_object* arg_;
+};
+
+// Convert calls to recover.
+
+int
+Convert_recover::expression(Expression** pp)
+{
+  Call_expression* ce = (*pp)->call_expression();
+  if (ce != NULL && ce->is_recover_call())
+    ce->set_recover_arg(Expression::make_var_reference(this->arg_,
+                                                      ce->location()));
+  return TRAVERSE_CONTINUE;
+}
+
+// Traversal for build_recover_thunks.
+
+class Build_recover_thunks : public Traverse
+{
+ public:
+  Build_recover_thunks(Gogo* gogo)
+    : Traverse(traverse_functions),
+      gogo_(gogo)
+  { }
+
+  int
+  function(Named_object*);
+
+ private:
+  Expression*
+  can_recover_arg(source_location);
+
+  // General IR.
+  Gogo* gogo_;
+};
+
+// If this function calls recover, turn it into a thunk.
+
+int
+Build_recover_thunks::function(Named_object* orig_no)
+{
+  Function* orig_func = orig_no->func_value();
+  if (!orig_func->calls_recover()
+      || orig_func->is_recover_thunk()
+      || orig_func->has_recover_thunk())
+    return TRAVERSE_CONTINUE;
+
+  Gogo* gogo = this->gogo_;
+  source_location location = orig_func->location();
+
+  static int count;
+  char buf[50];
+
+  Function_type* orig_fntype = orig_func->type();
+  Typed_identifier_list* new_params = new Typed_identifier_list();
+  std::string receiver_name;
+  if (orig_fntype->is_method())
+    {
+      const Typed_identifier* receiver = orig_fntype->receiver();
+      snprintf(buf, sizeof buf, "rt.%u", count);
+      ++count;
+      receiver_name = buf;
+      new_params->push_back(Typed_identifier(receiver_name, receiver->type(),
+                                            receiver->location()));
+    }
+  const Typed_identifier_list* orig_params = orig_fntype->parameters();
+  if (orig_params != NULL && !orig_params->empty())
+    {
+      for (Typed_identifier_list::const_iterator p = orig_params->begin();
+          p != orig_params->end();
+          ++p)
+       {
+         snprintf(buf, sizeof buf, "pt.%u", count);
+         ++count;
+         new_params->push_back(Typed_identifier(buf, p->type(),
+                                                p->location()));
+       }
+    }
+  snprintf(buf, sizeof buf, "pr.%u", count);
+  ++count;
+  std::string can_recover_name = buf;
+  new_params->push_back(Typed_identifier(can_recover_name,
+                                        Type::make_boolean_type(),
+                                        orig_fntype->location()));
+
+  const Typed_identifier_list* orig_results = orig_fntype->results();
+  Typed_identifier_list* new_results;
+  if (orig_results == NULL || orig_results->empty())
+    new_results = NULL;
+  else
+    {
+      new_results = new Typed_identifier_list();
+      for (Typed_identifier_list::const_iterator p = orig_results->begin();
+          p != orig_results->end();
+          ++p)
+       new_results->push_back(*p);
+    }
+
+  Function_type *new_fntype = Type::make_function_type(NULL, new_params,
+                                                      new_results,
+                                                      orig_fntype->location());
+  if (orig_fntype->is_varargs())
+    new_fntype->set_is_varargs();
+
+  std::string name = orig_no->name() + "$recover";
+  Named_object *new_no = gogo->start_function(name, new_fntype, false,
+                                             location);
+  Function *new_func = new_no->func_value();
+  if (orig_func->enclosing() != NULL)
+    new_func->set_enclosing(orig_func->enclosing());
+
+  // We build the code for the original function attached to the new
+  // function, and then swap the original and new function bodies.
+  // This means that existing references to the original function will
+  // then refer to the new function.  That makes this code a little
+  // confusing, in that the reference to NEW_NO really refers to the
+  // other function, not the one we are building.
+
+  Expression* closure = NULL;
+  if (orig_func->needs_closure())
+    {
+      Named_object* orig_closure_no = orig_func->closure_var();
+      Variable* orig_closure_var = orig_closure_no->var_value();
+      Variable* new_var = new Variable(orig_closure_var->type(), NULL, false,
+                                      true, false, location);
+      snprintf(buf, sizeof buf, "closure.%u", count);
+      ++count;
+      Named_object* new_closure_no = Named_object::make_variable(buf, NULL,
+                                                                new_var);
+      new_func->set_closure_var(new_closure_no);
+      closure = Expression::make_var_reference(new_closure_no, location);
+    }
+
+  Expression* fn = Expression::make_func_reference(new_no, closure, location);
+
+  Expression_list* args = new Expression_list();
+  if (orig_fntype->is_method())
+    {
+      Named_object* rec_no = gogo->lookup(receiver_name, NULL);
+      gcc_assert(rec_no != NULL
+                && rec_no->is_variable()
+                && rec_no->var_value()->is_parameter());
+      args->push_back(Expression::make_var_reference(rec_no, location));
+    }
+  if (new_params != NULL)
+    {
+      // Note that we skip the last parameter, which is the boolean
+      // indicating whether recover can succed.
+      for (Typed_identifier_list::const_iterator p = new_params->begin();
+          p + 1 != new_params->end();
+          ++p)
+       {
+         Named_object* p_no = gogo->lookup(p->name(), NULL);
+         gcc_assert(p_no != NULL
+                    && p_no->is_variable()
+                    && p_no->var_value()->is_parameter());
+         args->push_back(Expression::make_var_reference(p_no, location));
+       }
+    }
+  args->push_back(this->can_recover_arg(location));
+
+  Expression* call = Expression::make_call(fn, args, false, location);
+
+  Statement* s;
+  if (orig_fntype->results() == NULL || orig_fntype->results()->empty())
+    s = Statement::make_statement(call);
+  else
+    {
+      Expression_list* vals = new Expression_list();
+      vals->push_back(call);
+      s = Statement::make_return_statement(new_func->type()->results(),
+                                          vals, location);
+    }
+  s->determine_types();
+  gogo->add_statement(s);
+
+  gogo->finish_function(location);
+
+  // Swap the function bodies and types.
+  new_func->swap_for_recover(orig_func);
+  orig_func->set_is_recover_thunk();
+  new_func->set_calls_recover();
+  new_func->set_has_recover_thunk();
+
+  Bindings* orig_bindings = orig_func->block()->bindings();
+  Bindings* new_bindings = new_func->block()->bindings();
+  if (orig_fntype->is_method())
+    {
+      // We changed the receiver to be a regular parameter.  We have
+      // to update the binding accordingly in both functions.
+      Named_object* orig_rec_no = orig_bindings->lookup_local(receiver_name);
+      gcc_assert(orig_rec_no != NULL
+                && orig_rec_no->is_variable()
+                && !orig_rec_no->var_value()->is_receiver());
+      orig_rec_no->var_value()->set_is_receiver();
+
+      Named_object* new_rec_no = new_bindings->lookup_local(receiver_name);
+      gcc_assert(new_rec_no != NULL
+                && new_rec_no->is_variable()
+                && !new_rec_no->var_value()->is_receiver());
+      new_rec_no->var_value()->set_is_not_receiver();
+    }
+
+  // Because we flipped blocks but not types, the can_recover
+  // parameter appears in the (now) old bindings as a parameter.
+  // Change it to a local variable, whereupon it will be discarded.
+  Named_object* can_recover_no = orig_bindings->lookup_local(can_recover_name);
+  gcc_assert(can_recover_no != NULL
+            && can_recover_no->is_variable()
+            && can_recover_no->var_value()->is_parameter());
+  orig_bindings->remove_binding(can_recover_no);
+
+  // Add the can_recover argument to the (now) new bindings, and
+  // attach it to any recover statements.
+  Variable* can_recover_var = new Variable(Type::make_boolean_type(), NULL,
+                                          false, true, false, location);
+  can_recover_no = new_bindings->add_variable(can_recover_name, NULL,
+                                             can_recover_var);
+  Convert_recover convert_recover(can_recover_no);
+  new_func->traverse(&convert_recover);
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Return the expression to pass for the .can_recover parameter to the
+// new function.  This indicates whether a call to recover may return
+// non-nil.  The expression is
+// __go_can_recover(__builtin_return_address()).
+
+Expression*
+Build_recover_thunks::can_recover_arg(source_location location)
+{
+  static Named_object* builtin_return_address;
+  if (builtin_return_address == NULL)
+    {
+      const source_location bloc = BUILTINS_LOCATION;
+
+      Typed_identifier_list* param_types = new Typed_identifier_list();
+      Type* uint_type = Type::lookup_integer_type("uint");
+      param_types->push_back(Typed_identifier("l", uint_type, bloc));
+
+      Typed_identifier_list* return_types = new Typed_identifier_list();
+      Type* voidptr_type = Type::make_pointer_type(Type::make_void_type());
+      return_types->push_back(Typed_identifier("", voidptr_type, bloc));
+
+      Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                      return_types, bloc);
+      builtin_return_address =
+       Named_object::make_function_declaration("__builtin_return_address",
+                                               NULL, fntype, bloc);
+      const char* n = "__builtin_return_address";
+      builtin_return_address->func_declaration_value()->set_asm_name(n);
+    }
+
+  static Named_object* can_recover;
+  if (can_recover == NULL)
+    {
+      const source_location bloc = BUILTINS_LOCATION;
+      Typed_identifier_list* param_types = new Typed_identifier_list();
+      Type* voidptr_type = Type::make_pointer_type(Type::make_void_type());
+      param_types->push_back(Typed_identifier("a", voidptr_type, bloc));
+      Type* boolean_type = Type::make_boolean_type();
+      Typed_identifier_list* results = new Typed_identifier_list();
+      results->push_back(Typed_identifier("", boolean_type, bloc));
+      Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                      results, bloc);
+      can_recover = Named_object::make_function_declaration("__go_can_recover",
+                                                           NULL, fntype,
+                                                           bloc);
+      can_recover->func_declaration_value()->set_asm_name("__go_can_recover");
+    }
+
+  Expression* fn = Expression::make_func_reference(builtin_return_address,
+                                                  NULL, location);
+
+  mpz_t zval;
+  mpz_init_set_ui(zval, 0UL);
+  Expression* zexpr = Expression::make_integer(&zval, NULL, location);
+  mpz_clear(zval);
+  Expression_list *args = new Expression_list();
+  args->push_back(zexpr);
+
+  Expression* call = Expression::make_call(fn, args, false, location);
+
+  args = new Expression_list();
+  args->push_back(call);
+
+  fn = Expression::make_func_reference(can_recover, NULL, location);
+  return Expression::make_call(fn, args, false, location);
+}
+
+// Build thunks for functions which call recover.  We build a new
+// function with an extra parameter, which is whether a call to
+// recover can succeed.  We then move the body of this function to
+// that one.  We then turn this function into a thunk which calls the
+// new one, passing the value of
+// __go_can_recover(__builtin_return_address()).  The function will be
+// marked as not splitting the stack.  This will cooperate with the
+// implementation of defer to make recover do the right thing.
+
+void
+Gogo::build_recover_thunks()
+{
+  Build_recover_thunks build_recover_thunks(this);
+  this->traverse(&build_recover_thunks);
+}
+
+// Look for named types to see whether we need to create an interface
+// method table.
+
+class Build_method_tables : public Traverse
+{
+ public:
+  Build_method_tables(Gogo* gogo,
+                     const std::vector<Interface_type*>& interfaces)
+    : Traverse(traverse_types),
+      gogo_(gogo), interfaces_(interfaces)
+  { }
+
+  int
+  type(Type*);
+
+ private:
+  // The IR.
+  Gogo* gogo_;
+  // A list of locally defined interfaces which have hidden methods.
+  const std::vector<Interface_type*>& interfaces_;
+};
+
+// Build all required interface method tables for types.  We need to
+// ensure that we have an interface method table for every interface
+// which has a hidden method, for every named type which implements
+// that interface.  Normally we can just build interface method tables
+// as we need them.  However, in some cases we can require an
+// interface method table for an interface defined in a different
+// package for a type defined in that package.  If that interface and
+// type both use a hidden method, that is OK.  However, we will not be
+// able to build that interface method table when we need it, because
+// the type's hidden method will be static.  So we have to build it
+// here, and just refer it from other packages as needed.
+
+void
+Gogo::build_interface_method_tables()
+{
+  std::vector<Interface_type*> hidden_interfaces;
+  hidden_interfaces.reserve(this->interface_types_.size());
+  for (std::vector<Interface_type*>::const_iterator pi =
+        this->interface_types_.begin();
+       pi != this->interface_types_.end();
+       ++pi)
+    {
+      const Typed_identifier_list* methods = (*pi)->methods();
+      if (methods == NULL)
+       continue;
+      for (Typed_identifier_list::const_iterator pm = methods->begin();
+          pm != methods->end();
+          ++pm)
+       {
+         if (Gogo::is_hidden_name(pm->name()))
+           {
+             hidden_interfaces.push_back(*pi);
+             break;
+           }
+       }
+    }
+
+  if (!hidden_interfaces.empty())
+    {
+      // Now traverse the tree looking for all named types.
+      Build_method_tables bmt(this, hidden_interfaces);
+      this->traverse(&bmt);
+    }
+
+  // We no longer need the list of interfaces.
+
+  this->interface_types_.clear();
+}
+
+// This is called for each type.  For a named type, for each of the
+// interfaces with hidden methods that it implements, create the
+// method table.
+
+int
+Build_method_tables::type(Type* type)
+{
+  Named_type* nt = type->named_type();
+  if (nt != NULL)
+    {
+      for (std::vector<Interface_type*>::const_iterator p =
+            this->interfaces_.begin();
+          p != this->interfaces_.end();
+          ++p)
+       {
+         // We ask whether a pointer to the named type implements the
+         // interface, because a pointer can implement more methods
+         // than a value.
+         if ((*p)->implements_interface(Type::make_pointer_type(nt), NULL))
+           {
+             nt->interface_method_table(this->gogo_, *p, false);
+             nt->interface_method_table(this->gogo_, *p, true);
+           }
+       }
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Traversal class used to check for return statements.
+
+class Check_return_statements_traverse : public Traverse
+{
+ public:
+  Check_return_statements_traverse()
+    : Traverse(traverse_functions)
+  { }
+
+  int
+  function(Named_object*);
+};
+
+// Check that a function has a return statement if it needs one.
+
+int
+Check_return_statements_traverse::function(Named_object* no)
+{
+  Function* func = no->func_value();
+  const Function_type* fntype = func->type();
+  const Typed_identifier_list* results = fntype->results();
+
+  // We only need a return statement if there is a return value.
+  if (results == NULL || results->empty())
+    return TRAVERSE_CONTINUE;
+
+  if (func->block()->may_fall_through())
+    error_at(func->location(), "control reaches end of non-void function");
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Check return statements.
+
+void
+Gogo::check_return_statements()
+{
+  Check_return_statements_traverse traverse;
+  this->traverse(&traverse);
+}
+
+// Get the unique prefix to use before all exported symbols.  This
+// must be unique across the entire link.
+
+const std::string&
+Gogo::unique_prefix() const
+{
+  gcc_assert(!this->unique_prefix_.empty());
+  return this->unique_prefix_;
+}
+
+// Set the unique prefix to use before all exported symbols.  This
+// comes from the command line option -fgo-prefix=XXX.
+
+void
+Gogo::set_unique_prefix(const std::string& arg)
+{
+  gcc_assert(this->unique_prefix_.empty());
+  this->unique_prefix_ = arg;
+}
+
+// Work out the package priority.  It is one more than the maximum
+// priority of an imported package.
+
+int
+Gogo::package_priority() const
+{
+  int priority = 0;
+  for (Packages::const_iterator p = this->packages_.begin();
+       p != this->packages_.end();
+       ++p)
+    if (p->second->priority() > priority)
+      priority = p->second->priority();
+  return priority + 1;
+}
+
+// Export identifiers as requested.
+
+void
+Gogo::do_exports()
+{
+  // For now we always stream to a section.  Later we may want to
+  // support streaming to a separate file.
+  Stream_to_section stream;
+
+  Export exp(&stream);
+  exp.register_builtin_types(this);
+  exp.export_globals(this->package_name(),
+                    this->unique_prefix(),
+                    this->package_priority(),
+                    (this->need_init_fn_ && this->package_name() != "main"
+                     ? this->get_init_fn_name()
+                     : ""),
+                    this->imported_init_fns_,
+                    this->package_->bindings());
+}
+
+// Class Function.
+
+Function::Function(Function_type* type, Function* enclosing, Block* block,
+                  source_location location)
+  : type_(type), enclosing_(enclosing), named_results_(NULL),
+    closure_var_(NULL), block_(block), location_(location), fndecl_(NULL),
+    defer_stack_(NULL), calls_recover_(false), is_recover_thunk_(false),
+    has_recover_thunk_(false)
+{
+}
+
+// Create the named result variables.
+
+void
+Function::create_named_result_variables()
+{
+  const Typed_identifier_list* results = this->type_->results();
+  if (results == NULL
+      || results->empty()
+      || results->front().name().empty())
+    return;
+
+  this->named_results_ = new Named_results();
+  this->named_results_->reserve(results->size());
+
+  Block* block = this->block_;
+  int index = 0;
+  for (Typed_identifier_list::const_iterator p = results->begin();
+       p != results->end();
+       ++p, ++index)
+    {
+      Result_variable* result = new Result_variable(p->type(), this,
+                                                   index);
+      Named_object* no = block->bindings()->add_result_variable(p->name(),
+                                                               result);
+      this->named_results_->push_back(no);
+    }
+}
+
+// Return the closure variable, creating it if necessary.
+
+Named_object*
+Function::closure_var()
+{
+  if (this->closure_var_ == NULL)
+    {
+      // We don't know the type of the variable yet.  We add fields as
+      // we find them.
+      source_location loc = this->type_->location();
+      Struct_field_list* sfl = new Struct_field_list;
+      Type* struct_type = Type::make_struct_type(sfl, loc);
+      Variable* var = new Variable(Type::make_pointer_type(struct_type),
+                                  NULL, false, true, false, loc);
+      this->closure_var_ = Named_object::make_variable("closure", NULL, var);
+      // Note that the new variable is not in any binding contour.
+    }
+  return this->closure_var_;
+}
+
+// Set the type of the closure variable.
+
+void
+Function::set_closure_type()
+{
+  if (this->closure_var_ == NULL)
+    return;
+  Named_object* closure = this->closure_var_;
+  Struct_type* st = closure->var_value()->type()->deref()->struct_type();
+  unsigned int index = 0;
+  for (Closure_fields::const_iterator p = this->closure_fields_.begin();
+       p != this->closure_fields_.end();
+       ++p, ++index)
+    {
+      Named_object* no = p->first;
+      char buf[20];
+      snprintf(buf, sizeof buf, "%u", index);
+      std::string n = no->name() + buf;
+      Type* var_type;
+      if (no->is_variable())
+       var_type = no->var_value()->type();
+      else
+       var_type = no->result_var_value()->type();
+      Type* field_type = Type::make_pointer_type(var_type);
+      st->push_field(Struct_field(Typed_identifier(n, field_type, p->second)));
+    }
+}
+
+// Return whether this function is a method.
+
+bool
+Function::is_method() const
+{
+  return this->type_->is_method();
+}
+
+// Add a label definition.
+
+Label*
+Function::add_label_definition(const std::string& label_name,
+                              source_location location)
+{
+  Label* lnull = NULL;
+  std::pair<Labels::iterator, bool> ins =
+    this->labels_.insert(std::make_pair(label_name, lnull));
+  if (ins.second)
+    {
+      // This is a new label.
+      Label* label = new Label(label_name);
+      label->define(location);
+      ins.first->second = label;
+      return label;
+    }
+  else
+    {
+      // The label was already in the hash table.
+      Label* label = ins.first->second;
+      if (!label->is_defined())
+       {
+         label->define(location);
+         return label;
+       }
+      else
+       {
+         error_at(location, "redefinition of label %qs",
+                  Gogo::message_name(label_name).c_str());
+         inform(label->location(), "previous definition of %qs was here",
+                Gogo::message_name(label_name).c_str());
+         return new Label(label_name);
+       }
+    }
+}
+
+// Add a reference to a label.
+
+Label*
+Function::add_label_reference(const std::string& label_name)
+{
+  Label* lnull = NULL;
+  std::pair<Labels::iterator, bool> ins =
+    this->labels_.insert(std::make_pair(label_name, lnull));
+  if (!ins.second)
+    {
+      // The label was already in the hash table.
+      return ins.first->second;
+    }
+  else
+    {
+      gcc_assert(ins.first->second == NULL);
+      Label* label = new Label(label_name);
+      ins.first->second = label;
+      return label;
+    }
+}
+
+// Swap one function with another.  This is used when building the
+// thunk we use to call a function which calls recover.  It may not
+// work for any other case.
+
+void
+Function::swap_for_recover(Function *x)
+{
+  gcc_assert(this->enclosing_ == x->enclosing_);
+  gcc_assert(this->named_results_ == x->named_results_);
+  std::swap(this->closure_var_, x->closure_var_);
+  std::swap(this->block_, x->block_);
+  gcc_assert(this->location_ == x->location_);
+  gcc_assert(this->fndecl_ == NULL && x->fndecl_ == NULL);
+  gcc_assert(this->defer_stack_ == NULL && x->defer_stack_ == NULL);
+}
+
+// Traverse the tree.
+
+int
+Function::traverse(Traverse* traverse)
+{
+  unsigned int traverse_mask = traverse->traverse_mask();
+
+  // FIXME: We should check traverse_functions here if nested
+  // functions are stored in block bindings.
+  if (this->block_ != NULL
+      && (traverse_mask
+         & (Traverse::traverse_variables
+            | Traverse::traverse_constants
+            | Traverse::traverse_blocks
+            | Traverse::traverse_statements
+            | Traverse::traverse_expressions
+            | Traverse::traverse_types)) != 0)
+    {
+      if (this->block_->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Work out types for unspecified variables and constants.
+
+void
+Function::determine_types()
+{
+  if (this->block_ != NULL)
+    this->block_->determine_types();
+}
+
+// Export the function.
+
+void
+Function::export_func(Export* exp, const std::string& name) const
+{
+  Function::export_func_with_type(exp, name, this->type_);
+}
+
+// Export a function with a type.
+
+void
+Function::export_func_with_type(Export* exp, const std::string& name,
+                               const Function_type* fntype)
+{
+  exp->write_c_string("func ");
+
+  if (fntype->is_method())
+    {
+      exp->write_c_string("(");
+      exp->write_type(fntype->receiver()->type());
+      exp->write_c_string(") ");
+    }
+
+  exp->write_string(name);
+
+  exp->write_c_string(" (");
+  const Typed_identifier_list* parameters = fntype->parameters();
+  if (parameters != NULL)
+    {
+      bool is_varargs = fntype->is_varargs();
+      bool first = true;
+      for (Typed_identifier_list::const_iterator p = parameters->begin();
+          p != parameters->end();
+          ++p)
+       {
+         if (first)
+           first = false;
+         else
+           exp->write_c_string(", ");
+         if (!is_varargs || p + 1 != parameters->end())
+           exp->write_type(p->type());
+         else
+           {
+             exp->write_c_string("...");
+             exp->write_type(p->type()->array_type()->element_type());
+           }
+       }
+    }
+  exp->write_c_string(")");
+
+  const Typed_identifier_list* results = fntype->results();
+  if (results != NULL)
+    {
+      if (results->size() == 1)
+       {
+         exp->write_c_string(" ");
+         exp->write_type(results->begin()->type());
+       }
+      else
+       {
+         exp->write_c_string(" (");
+         bool first = true;
+         for (Typed_identifier_list::const_iterator p = results->begin();
+              p != results->end();
+              ++p)
+           {
+             if (first)
+               first = false;
+             else
+               exp->write_c_string(", ");
+             exp->write_type(p->type());
+           }
+         exp->write_c_string(")");
+       }
+    }
+  exp->write_c_string(";\n");
+}
+
+// Import a function.
+
+void
+Function::import_func(Import* imp, std::string* pname,
+                     Typed_identifier** preceiver,
+                     Typed_identifier_list** pparameters,
+                     Typed_identifier_list** presults,
+                     bool* is_varargs)
+{
+  imp->require_c_string("func ");
+
+  *preceiver = NULL;
+  if (imp->peek_char() == '(')
+    {
+      imp->require_c_string("(");
+      Type* rtype = imp->read_type();
+      *preceiver = new Typed_identifier(Import::import_marker, rtype,
+                                       imp->location());
+      imp->require_c_string(") ");
+    }
+
+  *pname = imp->read_identifier();
+
+  Typed_identifier_list* parameters;
+  *is_varargs = false;
+  imp->require_c_string(" (");
+  if (imp->peek_char() == ')')
+    parameters = NULL;
+  else
+    {
+      parameters = new Typed_identifier_list();
+      while (true)
+       {
+         if (imp->match_c_string("..."))
+           {
+             imp->advance(3);
+             *is_varargs = true;
+           }
+
+         Type* ptype = imp->read_type();
+         if (*is_varargs)
+           ptype = Type::make_array_type(ptype, NULL);
+         parameters->push_back(Typed_identifier(Import::import_marker,
+                                                ptype, imp->location()));
+         if (imp->peek_char() != ',')
+           break;
+         gcc_assert(!*is_varargs);
+         imp->require_c_string(", ");
+       }
+    }
+  imp->require_c_string(")");
+  *pparameters = parameters;
+
+  Typed_identifier_list* results;
+  if (imp->peek_char() != ' ')
+    results = NULL;
+  else
+    {
+      results = new Typed_identifier_list();
+      imp->require_c_string(" ");
+      if (imp->peek_char() != '(')
+       {
+         Type* rtype = imp->read_type();
+         results->push_back(Typed_identifier(Import::import_marker, rtype,
+                                             imp->location()));
+       }
+      else
+       {
+         imp->require_c_string("(");
+         while (true)
+           {
+             Type* rtype = imp->read_type();
+             results->push_back(Typed_identifier(Import::import_marker,
+                                                 rtype, imp->location()));
+             if (imp->peek_char() != ',')
+               break;
+             imp->require_c_string(", ");
+           }
+         imp->require_c_string(")");
+       }
+    }
+  imp->require_c_string(";\n");
+  *presults = results;
+}
+
+// Class Block.
+
+Block::Block(Block* enclosing, source_location location)
+  : enclosing_(enclosing), statements_(),
+    bindings_(new Bindings(enclosing == NULL
+                          ? NULL
+                          : enclosing->bindings())),
+    start_location_(location),
+    end_location_(UNKNOWN_LOCATION)
+{
+}
+
+// Add a statement to a block.
+
+void
+Block::add_statement(Statement* statement)
+{
+  this->statements_.push_back(statement);
+}
+
+// Add a statement to the front of a block.  This is slow but is only
+// used for reference counts of parameters.
+
+void
+Block::add_statement_at_front(Statement* statement)
+{
+  this->statements_.insert(this->statements_.begin(), statement);
+}
+
+// Replace a statement in a block.
+
+void
+Block::replace_statement(size_t index, Statement* s)
+{
+  gcc_assert(index < this->statements_.size());
+  this->statements_[index] = s;
+}
+
+// Add a statement before another statement.
+
+void
+Block::insert_statement_before(size_t index, Statement* s)
+{
+  gcc_assert(index < this->statements_.size());
+  this->statements_.insert(this->statements_.begin() + index, s);
+}
+
+// Add a statement after another statement.
+
+void
+Block::insert_statement_after(size_t index, Statement* s)
+{
+  gcc_assert(index < this->statements_.size());
+  this->statements_.insert(this->statements_.begin() + index + 1, s);
+}
+
+// Traverse the tree.
+
+int
+Block::traverse(Traverse* traverse)
+{
+  unsigned int traverse_mask = traverse->traverse_mask();
+
+  if ((traverse_mask & Traverse::traverse_blocks) != 0)
+    {
+      int t = traverse->block(this);
+      if (t == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+      else if (t == TRAVERSE_SKIP_COMPONENTS)
+       return TRAVERSE_CONTINUE;
+    }
+
+  if ((traverse_mask
+       & (Traverse::traverse_variables
+         | Traverse::traverse_constants
+         | Traverse::traverse_expressions
+         | Traverse::traverse_types)) != 0)
+    {
+      for (Bindings::const_definitions_iterator pb =
+            this->bindings_->begin_definitions();
+          pb != this->bindings_->end_definitions();
+          ++pb)
+       {
+         switch ((*pb)->classification())
+           {
+           case Named_object::NAMED_OBJECT_CONST:
+             if ((traverse_mask & Traverse::traverse_constants) != 0)
+               {
+                 if (traverse->constant(*pb, false) == TRAVERSE_EXIT)
+                   return TRAVERSE_EXIT;
+               }
+             if ((traverse_mask & Traverse::traverse_types) != 0
+                 || (traverse_mask & Traverse::traverse_expressions) != 0)
+               {
+                 Type* t = (*pb)->const_value()->type();
+                 if (t != NULL
+                     && Type::traverse(t, traverse) == TRAVERSE_EXIT)
+                   return TRAVERSE_EXIT;
+               }
+             if ((traverse_mask & Traverse::traverse_expressions) != 0
+                 || (traverse_mask & Traverse::traverse_types) != 0)
+               {
+                 if ((*pb)->const_value()->traverse_expression(traverse)
+                     == TRAVERSE_EXIT)
+                   return TRAVERSE_EXIT;
+               }
+             break;
+
+           case Named_object::NAMED_OBJECT_VAR:
+           case Named_object::NAMED_OBJECT_RESULT_VAR:
+             if ((traverse_mask & Traverse::traverse_variables) != 0)
+               {
+                 if (traverse->variable(*pb) == TRAVERSE_EXIT)
+                   return TRAVERSE_EXIT;
+               }
+             if (((traverse_mask & Traverse::traverse_types) != 0
+                  || (traverse_mask & Traverse::traverse_expressions) != 0)
+                 && ((*pb)->is_result_variable()
+                     || (*pb)->var_value()->has_type()))
+               {
+                 Type* t = ((*pb)->is_variable()
+                            ? (*pb)->var_value()->type()
+                            : (*pb)->result_var_value()->type());
+                 if (t != NULL
+                     && Type::traverse(t, traverse) == TRAVERSE_EXIT)
+                   return TRAVERSE_EXIT;
+               }
+             if ((*pb)->is_variable()
+                 && ((traverse_mask & Traverse::traverse_expressions) != 0
+                     || (traverse_mask & Traverse::traverse_types) != 0))
+               {
+                 if ((*pb)->var_value()->traverse_expression(traverse)
+                     == TRAVERSE_EXIT)
+                   return TRAVERSE_EXIT;
+               }
+             break;
+
+           case Named_object::NAMED_OBJECT_FUNC:
+           case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
+             // FIXME: Where will nested functions be found?
+             gcc_unreachable();
+
+           case Named_object::NAMED_OBJECT_TYPE:
+             if ((traverse_mask & Traverse::traverse_types) != 0
+                 || (traverse_mask & Traverse::traverse_expressions) != 0)
+               {
+                 if (Type::traverse((*pb)->type_value(), traverse)
+                     == TRAVERSE_EXIT)
+                   return TRAVERSE_EXIT;
+               }
+             break;
+
+           case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
+           case Named_object::NAMED_OBJECT_UNKNOWN:
+             break;
+
+           case Named_object::NAMED_OBJECT_PACKAGE:
+           case Named_object::NAMED_OBJECT_SINK:
+             gcc_unreachable();
+
+           default:
+             gcc_unreachable();
+           }
+       }
+    }
+
+  // No point in checking traverse_mask here--if we got here we always
+  // want to walk the statements.  The traversal can insert new
+  // statements before or after the current statement.  Inserting
+  // statements before the current statement requires updating I via
+  // the pointer; those statements will not be traversed.  Any new
+  // statements inserted after the current statement will be traversed
+  // in their turn.
+  for (size_t i = 0; i < this->statements_.size(); ++i)
+    {
+      if (this->statements_[i]->traverse(this, &i, traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Work out types for unspecified variables and constants.
+
+void
+Block::determine_types()
+{
+  for (Bindings::const_definitions_iterator pb =
+        this->bindings_->begin_definitions();
+       pb != this->bindings_->end_definitions();
+       ++pb)
+    {
+      if ((*pb)->is_variable())
+       (*pb)->var_value()->determine_type();
+      else if ((*pb)->is_const())
+       (*pb)->const_value()->determine_type();
+    }
+
+  for (std::vector<Statement*>::const_iterator ps = this->statements_.begin();
+       ps != this->statements_.end();
+       ++ps)
+    (*ps)->determine_types();
+}
+
+// Return true if the statements in this block may fall through.
+
+bool
+Block::may_fall_through() const
+{
+  if (this->statements_.empty())
+    return true;
+  return this->statements_.back()->may_fall_through();
+}
+
+// Class Variable.
+
+Variable::Variable(Type* type, Expression* init, bool is_global,
+                  bool is_parameter, bool is_receiver,
+                  source_location location)
+  : type_(type), init_(init), preinit_(NULL), location_(location),
+    is_global_(is_global), is_parameter_(is_parameter),
+    is_receiver_(is_receiver), is_varargs_parameter_(false),
+    is_address_taken_(false), init_is_lowered_(false),
+    type_from_init_tuple_(false), type_from_range_index_(false),
+    type_from_range_value_(false), type_from_chan_element_(false),
+    is_type_switch_var_(false)
+{
+  gcc_assert(type != NULL || init != NULL);
+  gcc_assert(!is_parameter || init == NULL);
+}
+
+// Traverse the initializer expression.
+
+int
+Variable::traverse_expression(Traverse* traverse)
+{
+  if (this->preinit_ != NULL)
+    {
+      if (this->preinit_->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  if (this->init_ != NULL)
+    {
+      if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Lower the initialization expression after parsing is complete.
+
+void
+Variable::lower_init_expression(Gogo* gogo, Named_object* function)
+{
+  if (this->init_ != NULL && !this->init_is_lowered_)
+    {
+      gogo->lower_expression(function, &this->init_);
+      this->init_is_lowered_ = true;
+    }
+}
+
+// Get the preinit block.
+
+Block*
+Variable::preinit_block()
+{
+  gcc_assert(this->is_global_);
+  if (this->preinit_ == NULL)
+    this->preinit_ = new Block(NULL, this->location());
+  return this->preinit_;
+}
+
+// Add a statement to be run before the initialization expression.
+
+void
+Variable::add_preinit_statement(Statement* s)
+{
+  Block* b = this->preinit_block();
+  b->add_statement(s);
+  b->set_end_location(s->location());
+}
+
+// In an assignment which sets a variable to a tuple of EXPR, return
+// the type of the first element of the tuple.
+
+Type*
+Variable::type_from_tuple(Expression* expr, bool report_error) const
+{
+  if (expr->map_index_expression() != NULL)
+    return expr->map_index_expression()->get_map_type()->val_type();
+  else if (expr->receive_expression() != NULL)
+    {
+      Expression* channel = expr->receive_expression()->channel();
+      return channel->type()->channel_type()->element_type();
+    }
+  else
+    {
+      if (report_error)
+       error_at(this->location(), "invalid tuple definition");
+      return Type::make_error_type();
+    }
+}
+
+// Given EXPR used in a range clause, return either the index type or
+// the value type of the range, depending upon GET_INDEX_TYPE.
+
+Type*
+Variable::type_from_range(Expression* expr, bool get_index_type,
+                         bool report_error) const
+{
+  Type* t = expr->type();
+  if (t->array_type() != NULL
+      || (t->points_to() != NULL
+         && t->points_to()->array_type() != NULL
+         && !t->points_to()->is_open_array_type()))
+    {
+      if (get_index_type)
+       return Type::lookup_integer_type("int");
+      else
+       return t->deref()->array_type()->element_type();
+    }
+  else if (t->is_string_type())
+    return Type::lookup_integer_type("int");
+  else if (t->map_type() != NULL)
+    {
+      if (get_index_type)
+       return t->map_type()->key_type();
+      else
+       return t->map_type()->val_type();
+    }
+  else if (t->channel_type() != NULL)
+    {
+      if (get_index_type)
+       return t->channel_type()->element_type();
+      else
+       {
+         if (report_error)
+           error_at(this->location(),
+                    "invalid definition of value variable for channel range");
+         return Type::make_error_type();
+       }
+    }
+  else
+    {
+      if (report_error)
+       error_at(this->location(), "invalid type for range clause");
+      return Type::make_error_type();
+    }
+}
+
+// EXPR should be a channel.  Return the channel's element type.
+
+Type*
+Variable::type_from_chan_element(Expression* expr, bool report_error) const
+{
+  Type* t = expr->type();
+  if (t->channel_type() != NULL)
+    return t->channel_type()->element_type();
+  else
+    {
+      if (report_error)
+       error_at(this->location(), "expected channel");
+      return Type::make_error_type();
+    }
+}
+
+// Return the type of the Variable.  This may be called before
+// Variable::determine_type is called, which means that we may need to
+// get the type from the initializer.  FIXME: If we combine lowering
+// with type determination, then this should be unnecessary.
+
+Type*
+Variable::type() const
+{
+  // A variable in a type switch with a nil case will have the wrong
+  // type here.  This gets fixed up in determine_type, below.
+  Type* type = this->type_;
+  Expression* init = this->init_;
+  if (this->is_type_switch_var_
+      && this->type_->is_nil_constant_as_type())
+    {
+      Type_guard_expression* tge = this->init_->type_guard_expression();
+      gcc_assert(tge != NULL);
+      init = tge->expr();
+      type = NULL;
+    }
+
+  if (type != NULL)
+    return type;
+  else if (this->type_from_init_tuple_)
+    return this->type_from_tuple(init, false);
+  else if (this->type_from_range_index_ || this->type_from_range_value_)
+    return this->type_from_range(init, this->type_from_range_index_, false);
+  else if (this->type_from_chan_element_)
+    return this->type_from_chan_element(init, false);
+  else
+    {
+      gcc_assert(init != NULL);
+      type = init->type();
+      gcc_assert(type != NULL);
+
+      // Variables should not have abstract types.
+      if (type->is_abstract())
+       type = type->make_non_abstract_type();
+
+      if (type->is_void_type())
+       type = Type::make_error_type();
+
+      return type;
+    }
+}
+
+// Set the type if necessary.
+
+void
+Variable::determine_type()
+{
+  // A variable in a type switch with a nil case will have the wrong
+  // type here.  It will have an initializer which is a type guard.
+  // We want to initialize it to the value without the type guard, and
+  // use the type of that value as well.
+  if (this->is_type_switch_var_ && this->type_->is_nil_constant_as_type())
+    {
+      Type_guard_expression* tge = this->init_->type_guard_expression();
+      gcc_assert(tge != NULL);
+      this->type_ = NULL;
+      this->init_ = tge->expr();
+    }
+
+  if (this->init_ == NULL)
+    gcc_assert(this->type_ != NULL && !this->type_->is_abstract());
+  else if (this->type_from_init_tuple_)
+    {
+      Expression *init = this->init_;
+      init->determine_type_no_context();
+      this->type_ = this->type_from_tuple(init, true);
+      this->init_ = NULL;
+    }
+  else if (this->type_from_range_index_ || this->type_from_range_value_)
+    {
+      Expression* init = this->init_;
+      init->determine_type_no_context();
+      this->type_ = this->type_from_range(init, this->type_from_range_index_,
+                                         true);
+      this->init_ = NULL;
+    }
+  else
+    {
+      // type_from_chan_element_ should have been cleared during
+      // lowering.
+      gcc_assert(!this->type_from_chan_element_);
+
+      Type_context context(this->type_, false);
+      this->init_->determine_type(&context);
+      if (this->type_ == NULL)
+       {
+         Type* type = this->init_->type();
+         gcc_assert(type != NULL);
+         if (type->is_abstract())
+           type = type->make_non_abstract_type();
+
+         if (type->is_void_type())
+           {
+             error_at(this->location_, "variable has no type");
+             type = Type::make_error_type();
+           }
+         else if (type->is_nil_type())
+           {
+             error_at(this->location_, "variable defined to nil type");
+             type = Type::make_error_type();
+           }
+         else if (type->is_call_multiple_result_type())
+           {
+             error_at(this->location_,
+                      "single variable set to multiple value function call");
+             type = Type::make_error_type();
+           }
+
+         this->type_ = type;
+       }
+    }
+}
+
+// Export the variable
+
+void
+Variable::export_var(Export* exp, const std::string& name) const
+{
+  gcc_assert(this->is_global_);
+  exp->write_c_string("var ");
+  exp->write_string(name);
+  exp->write_c_string(" ");
+  exp->write_type(this->type());
+  exp->write_c_string(";\n");
+}
+
+// Import a variable.
+
+void
+Variable::import_var(Import* imp, std::string* pname, Type** ptype)
+{
+  imp->require_c_string("var ");
+  *pname = imp->read_identifier();
+  imp->require_c_string(" ");
+  *ptype = imp->read_type();
+  imp->require_c_string(";\n");
+}
+
+// Class Named_constant.
+
+// Traverse the initializer expression.
+
+int
+Named_constant::traverse_expression(Traverse* traverse)
+{
+  return Expression::traverse(&this->expr_, traverse);
+}
+
+// Determine the type of the constant.
+
+void
+Named_constant::determine_type()
+{
+  if (this->type_ != NULL)
+    {
+      Type_context context(this->type_, false);
+      this->expr_->determine_type(&context);
+    }
+  else
+    {
+      // A constant may have an abstract type.
+      Type_context context(NULL, true);
+      this->expr_->determine_type(&context);
+      this->type_ = this->expr_->type();
+      gcc_assert(this->type_ != NULL);
+    }
+}
+
+// Indicate that we found and reported an error for this constant.
+
+void
+Named_constant::set_error()
+{
+  this->type_ = Type::make_error_type();
+  this->expr_ = Expression::make_error(this->location_);
+}
+
+// Export a constant.
+
+void
+Named_constant::export_const(Export* exp, const std::string& name) const
+{
+  exp->write_c_string("const ");
+  exp->write_string(name);
+  exp->write_c_string(" ");
+  if (!this->type_->is_abstract())
+    {
+      exp->write_type(this->type_);
+      exp->write_c_string(" ");
+    }
+  exp->write_c_string("= ");
+  this->expr()->export_expression(exp);
+  exp->write_c_string(";\n");
+}
+
+// Import a constant.
+
+void
+Named_constant::import_const(Import* imp, std::string* pname, Type** ptype,
+                            Expression** pexpr)
+{
+  imp->require_c_string("const ");
+  *pname = imp->read_identifier();
+  imp->require_c_string(" ");
+  if (imp->peek_char() == '=')
+    *ptype = NULL;
+  else
+    {
+      *ptype = imp->read_type();
+      imp->require_c_string(" ");
+    }
+  imp->require_c_string("= ");
+  *pexpr = Expression::import_expression(imp);
+  imp->require_c_string(";\n");
+}
+
+// Add a method.
+
+Named_object*
+Type_declaration::add_method(const std::string& name, Function* function)
+{
+  Named_object* ret = Named_object::make_function(name, NULL, function);
+  this->methods_.push_back(ret);
+  return ret;
+}
+
+// Add a method declaration.
+
+Named_object*
+Type_declaration::add_method_declaration(const std::string&  name,
+                                        Function_type* type,
+                                        source_location location)
+{
+  Named_object* ret = Named_object::make_function_declaration(name, NULL, type,
+                                                             location);
+  this->methods_.push_back(ret);
+  return ret;
+}
+
+// Return whether any methods ere defined.
+
+bool
+Type_declaration::has_methods() const
+{
+  return !this->methods_.empty();
+}
+
+// Define methods for the real type.
+
+void
+Type_declaration::define_methods(Named_type* nt)
+{
+  for (Methods::const_iterator p = this->methods_.begin();
+       p != this->methods_.end();
+       ++p)
+    nt->add_existing_method(*p);
+}
+
+// We are using the type.  Return true if we should issue a warning.
+
+bool
+Type_declaration::using_type()
+{
+  bool ret = !this->issued_warning_;
+  this->issued_warning_ = true;
+  return ret;
+}
+
+// Class Unknown_name.
+
+// Set the real named object.
+
+void
+Unknown_name::set_real_named_object(Named_object* no)
+{
+  gcc_assert(this->real_named_object_ == NULL);
+  gcc_assert(!no->is_unknown());
+  this->real_named_object_ = no;
+}
+
+// Class Named_object.
+
+Named_object::Named_object(const std::string& name,
+                          const Package* package,
+                          Classification classification)
+  : name_(name), package_(package), classification_(classification),
+    tree_(NULL)
+{
+  if (Gogo::is_sink_name(name))
+    gcc_assert(classification == NAMED_OBJECT_SINK);
+}
+
+// Make an unknown name.  This is used by the parser.  The name must
+// be resolved later.  Unknown names are only added in the current
+// package.
+
+Named_object*
+Named_object::make_unknown_name(const std::string& name,
+                               source_location location)
+{
+  Named_object* named_object = new Named_object(name, NULL,
+                                               NAMED_OBJECT_UNKNOWN);
+  Unknown_name* value = new Unknown_name(location);
+  named_object->u_.unknown_value = value;
+  return named_object;
+}
+
+// Make a constant.
+
+Named_object*
+Named_object::make_constant(const Typed_identifier& tid,
+                           const Package* package, Expression* expr,
+                           int iota_value)
+{
+  Named_object* named_object = new Named_object(tid.name(), package,
+                                               NAMED_OBJECT_CONST);
+  Named_constant* named_constant = new Named_constant(tid.type(), expr,
+                                                     iota_value,
+                                                     tid.location());
+  named_object->u_.const_value = named_constant;
+  return named_object;
+}
+
+// Make a named type.
+
+Named_object*
+Named_object::make_type(const std::string& name, const Package* package,
+                       Type* type, source_location location)
+{
+  Named_object* named_object = new Named_object(name, package,
+                                               NAMED_OBJECT_TYPE);
+  Named_type* named_type = Type::make_named_type(named_object, type, location);
+  named_object->u_.type_value = named_type;
+  return named_object;
+}
+
+// Make a type declaration.
+
+Named_object*
+Named_object::make_type_declaration(const std::string& name,
+                                   const Package* package,
+                                   source_location location)
+{
+  Named_object* named_object = new Named_object(name, package,
+                                               NAMED_OBJECT_TYPE_DECLARATION);
+  Type_declaration* type_declaration = new Type_declaration(location);
+  named_object->u_.type_declaration = type_declaration;
+  return named_object;
+}
+
+// Make a variable.
+
+Named_object*
+Named_object::make_variable(const std::string& name, const Package* package,
+                           Variable* variable)
+{
+  Named_object* named_object = new Named_object(name, package,
+                                               NAMED_OBJECT_VAR);
+  named_object->u_.var_value = variable;
+  return named_object;
+}
+
+// Make a result variable.
+
+Named_object*
+Named_object::make_result_variable(const std::string& name,
+                                  Result_variable* result)
+{
+  Named_object* named_object = new Named_object(name, NULL,
+                                               NAMED_OBJECT_RESULT_VAR);
+  named_object->u_.result_var_value = result;
+  return named_object;
+}
+
+// Make a sink.  This is used for the special blank identifier _.
+
+Named_object*
+Named_object::make_sink()
+{
+  return new Named_object("_", NULL, NAMED_OBJECT_SINK);
+}
+
+// Make a named function.
+
+Named_object*
+Named_object::make_function(const std::string& name, const Package* package,
+                           Function* function)
+{
+  Named_object* named_object = new Named_object(name, package,
+                                               NAMED_OBJECT_FUNC);
+  named_object->u_.func_value = function;
+  return named_object;
+}
+
+// Make a function declaration.
+
+Named_object*
+Named_object::make_function_declaration(const std::string& name,
+                                       const Package* package,
+                                       Function_type* fntype,
+                                       source_location location)
+{
+  Named_object* named_object = new Named_object(name, package,
+                                               NAMED_OBJECT_FUNC_DECLARATION);
+  Function_declaration *func_decl = new Function_declaration(fntype, location);
+  named_object->u_.func_declaration_value = func_decl;
+  return named_object;
+}
+
+// Make a package.
+
+Named_object*
+Named_object::make_package(const std::string& alias, Package* package)
+{
+  Named_object* named_object = new Named_object(alias, NULL,
+                                               NAMED_OBJECT_PACKAGE);
+  named_object->u_.package_value = package;
+  return named_object;
+}
+
+// Return the name to use in an error message.
+
+std::string
+Named_object::message_name() const
+{
+  if (this->package_ == NULL)
+    return Gogo::message_name(this->name_);
+  std::string ret = Gogo::message_name(this->package_->name());
+  ret += '.';
+  ret += Gogo::message_name(this->name_);
+  return ret;
+}
+
+// Set the type when a declaration is defined.
+
+void
+Named_object::set_type_value(Named_type* named_type)
+{
+  gcc_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
+  Type_declaration* td = this->u_.type_declaration;
+  td->define_methods(named_type);
+  Named_object* in_function = td->in_function();
+  if (in_function != NULL)
+    named_type->set_in_function(in_function);
+  delete td;
+  this->classification_ = NAMED_OBJECT_TYPE;
+  this->u_.type_value = named_type;
+}
+
+// Define a function which was previously declared.
+
+void
+Named_object::set_function_value(Function* function)
+{
+  gcc_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
+  this->classification_ = NAMED_OBJECT_FUNC;
+  // FIXME: We should free the old value.
+  this->u_.func_value = function;
+}
+
+// Return the location of a named object.
+
+source_location
+Named_object::location() const
+{
+  switch (this->classification_)
+    {
+    default:
+    case NAMED_OBJECT_UNINITIALIZED:
+      gcc_unreachable();
+
+    case NAMED_OBJECT_UNKNOWN:
+      return this->unknown_value()->location();
+
+    case NAMED_OBJECT_CONST:
+      return this->const_value()->location();
+
+    case NAMED_OBJECT_TYPE:
+      return this->type_value()->location();
+
+    case NAMED_OBJECT_TYPE_DECLARATION:
+      return this->type_declaration_value()->location();
+
+    case NAMED_OBJECT_VAR:
+      return this->var_value()->location();
+
+    case NAMED_OBJECT_RESULT_VAR:
+      return this->result_var_value()->function()->location();
+
+    case NAMED_OBJECT_SINK:
+      gcc_unreachable();
+
+    case NAMED_OBJECT_FUNC:
+      return this->func_value()->location();
+
+    case NAMED_OBJECT_FUNC_DECLARATION:
+      return this->func_declaration_value()->location();
+
+    case NAMED_OBJECT_PACKAGE:
+      return this->package_value()->location();
+    }
+}
+
+// Export a named object.
+
+void
+Named_object::export_named_object(Export* exp) const
+{
+  switch (this->classification_)
+    {
+    default:
+    case NAMED_OBJECT_UNINITIALIZED:
+    case NAMED_OBJECT_UNKNOWN:
+      gcc_unreachable();
+
+    case NAMED_OBJECT_CONST:
+      this->const_value()->export_const(exp, this->name_);
+      break;
+
+    case NAMED_OBJECT_TYPE:
+      this->type_value()->export_named_type(exp, this->name_);
+      break;
+
+    case NAMED_OBJECT_TYPE_DECLARATION:
+      error_at(this->type_declaration_value()->location(),
+              "attempt to export %<%s%> which was declared but not defined",
+              this->message_name().c_str());
+      break;
+
+    case NAMED_OBJECT_FUNC_DECLARATION:
+      this->func_declaration_value()->export_func(exp, this->name_);
+      break;
+
+    case NAMED_OBJECT_VAR:
+      this->var_value()->export_var(exp, this->name_);
+      break;
+
+    case NAMED_OBJECT_RESULT_VAR:
+    case NAMED_OBJECT_SINK:
+      gcc_unreachable();
+
+    case NAMED_OBJECT_FUNC:
+      this->func_value()->export_func(exp, this->name_);
+      break;
+    }
+}
+
+// Class Bindings.
+
+Bindings::Bindings(Bindings* enclosing)
+  : enclosing_(enclosing), named_objects_(), bindings_()
+{
+}
+
+// Clear imports.
+
+void
+Bindings::clear_file_scope()
+{
+  Contour::iterator p = this->bindings_.begin();
+  while (p != this->bindings_.end())
+    {
+      bool keep;
+      if (p->second->package() != NULL)
+       keep = false;
+      else if (p->second->is_package())
+       keep = false;
+      else if (p->second->is_function()
+              && !p->second->func_value()->type()->is_method()
+              && Gogo::unpack_hidden_name(p->second->name()) == "init")
+       keep = false;
+      else
+       keep = true;
+
+      if (keep)
+       ++p;
+      else
+       p = this->bindings_.erase(p);
+    }
+}
+
+// Look up a symbol.
+
+Named_object*
+Bindings::lookup(const std::string& name) const
+{
+  Contour::const_iterator p = this->bindings_.find(name);
+  if (p != this->bindings_.end())
+    return p->second->resolve();
+  else if (this->enclosing_ != NULL)
+    return this->enclosing_->lookup(name);
+  else
+    return NULL;
+}
+
+// Look up a symbol locally.
+
+Named_object*
+Bindings::lookup_local(const std::string& name) const
+{
+  Contour::const_iterator p = this->bindings_.find(name);
+  if (p == this->bindings_.end())
+    return NULL;
+  return p->second;
+}
+
+// Remove an object from a set of bindings.  This is used for a
+// special case in thunks for functions which call recover.
+
+void
+Bindings::remove_binding(Named_object* no)
+{
+  Contour::iterator pb = this->bindings_.find(no->name());
+  gcc_assert(pb != this->bindings_.end());
+  this->bindings_.erase(pb);
+  for (std::vector<Named_object*>::iterator pn = this->named_objects_.begin();
+       pn != this->named_objects_.end();
+       ++pn)
+    {
+      if (*pn == no)
+       {
+         this->named_objects_.erase(pn);
+         return;
+       }
+    }
+  gcc_unreachable();
+}
+
+// Add a method to the list of objects.  This is not added to the
+// lookup table.  This is so that we have a single list of objects
+// declared at the top level, which we walk through when it's time to
+// convert to trees.
+
+void
+Bindings::add_method(Named_object* method)
+{
+  this->named_objects_.push_back(method);
+}
+
+// Add a generic Named_object to a Contour.
+
+Named_object*
+Bindings::add_named_object_to_contour(Contour* contour,
+                                     Named_object* named_object)
+{
+  gcc_assert(named_object == named_object->resolve());
+  const std::string& name(named_object->name());
+  gcc_assert(!Gogo::is_sink_name(name));
+
+  std::pair<Contour::iterator, bool> ins =
+    contour->insert(std::make_pair(name, named_object));
+  if (!ins.second)
+    {
+      // The name was already there.
+      if (named_object->package() != NULL
+         && ins.first->second->package() == named_object->package()
+         && (ins.first->second->classification()
+             == named_object->classification()))
+       {
+         // This is a second import of the same object.
+         return ins.first->second;
+       }
+      ins.first->second = this->new_definition(ins.first->second,
+                                              named_object);
+      return ins.first->second;
+    }
+  else
+    {
+      // Don't push declarations on the list.  We push them on when
+      // and if we find the definitions.  That way we genericize the
+      // functions in order.
+      if (!named_object->is_type_declaration()
+         && !named_object->is_function_declaration()
+         && !named_object->is_unknown())
+       this->named_objects_.push_back(named_object);
+      return named_object;
+    }
+}
+
+// We had an existing named object OLD_OBJECT, and we've seen a new
+// one NEW_OBJECT with the same name.  FIXME: This does not free the
+// new object when we don't need it.
+
+Named_object*
+Bindings::new_definition(Named_object* old_object, Named_object* new_object)
+{
+  std::string reason;
+  switch (old_object->classification())
+    {
+    default:
+    case Named_object::NAMED_OBJECT_UNINITIALIZED:
+      gcc_unreachable();
+
+    case Named_object::NAMED_OBJECT_UNKNOWN:
+      {
+       Named_object* real = old_object->unknown_value()->real_named_object();
+       if (real != NULL)
+         return this->new_definition(real, new_object);
+       gcc_assert(!new_object->is_unknown());
+       old_object->unknown_value()->set_real_named_object(new_object);
+       if (!new_object->is_type_declaration()
+           && !new_object->is_function_declaration())
+         this->named_objects_.push_back(new_object);
+       return new_object;
+      }
+
+    case Named_object::NAMED_OBJECT_CONST:
+      break;
+
+    case Named_object::NAMED_OBJECT_TYPE:
+      if (new_object->is_type_declaration())
+       return old_object;
+      break;
+
+    case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
+      if (new_object->is_type_declaration())
+       return old_object;
+      if (new_object->is_type())
+       {
+         old_object->set_type_value(new_object->type_value());
+         new_object->type_value()->set_named_object(old_object);
+         this->named_objects_.push_back(old_object);
+         return old_object;
+       }
+      break;
+
+    case Named_object::NAMED_OBJECT_VAR:
+    case Named_object::NAMED_OBJECT_RESULT_VAR:
+      break;
+
+    case Named_object::NAMED_OBJECT_SINK:
+      gcc_unreachable();
+
+    case Named_object::NAMED_OBJECT_FUNC:
+      if (new_object->is_function_declaration())
+       {
+         if (!new_object->func_declaration_value()->asm_name().empty())
+           sorry("__asm__ for function definitions");
+         Function_type* old_type = old_object->func_value()->type();
+         Function_type* new_type =
+           new_object->func_declaration_value()->type();
+         if (old_type->is_valid_redeclaration(new_type, &reason))
+           return old_object;
+       }
+      break;
+
+    case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
+      {
+       Function_type* old_type = old_object->func_declaration_value()->type();
+       if (new_object->is_function_declaration())
+         {
+           Function_type* new_type =
+             new_object->func_declaration_value()->type();
+           if (old_type->is_valid_redeclaration(new_type, &reason))
+             return old_object;
+         }
+       if (new_object->is_function())
+         {
+           Function_type* new_type = new_object->func_value()->type();
+           if (old_type->is_valid_redeclaration(new_type, &reason))
+             {
+               if (!old_object->func_declaration_value()->asm_name().empty())
+                 sorry("__asm__ for function definitions");
+               old_object->set_function_value(new_object->func_value());
+               this->named_objects_.push_back(old_object);
+               return old_object;
+             }
+         }
+      }
+      break;
+
+    case Named_object::NAMED_OBJECT_PACKAGE:
+      if (new_object->is_package()
+         && (old_object->package_value()->name()
+             == new_object->package_value()->name()))
+       return old_object;
+
+      break;
+    }
+
+  std::string n = old_object->message_name();
+  if (reason.empty())
+    error_at(new_object->location(), "redefinition of %qs", n.c_str());
+  else
+    error_at(new_object->location(), "redefinition of %qs: %s", n.c_str(),
+            reason.c_str());
+
+  inform(old_object->location(), "previous definition of %qs was here",
+        n.c_str());
+
+  return old_object;
+}
+
+// Add a named type.
+
+Named_object*
+Bindings::add_named_type(Named_type* named_type)
+{
+  return this->add_named_object(named_type->named_object());
+}
+
+// Add a function.
+
+Named_object*
+Bindings::add_function(const std::string& name, const Package* package,
+                      Function* function)
+{
+  return this->add_named_object(Named_object::make_function(name, package,
+                                                           function));
+}
+
+// Add a function declaration.
+
+Named_object*
+Bindings::add_function_declaration(const std::string& name,
+                                  const Package* package,
+                                  Function_type* type,
+                                  source_location location)
+{
+  Named_object* no = Named_object::make_function_declaration(name, package,
+                                                            type, location);
+  return this->add_named_object(no);
+}
+
+// Define a type which was previously declared.
+
+void
+Bindings::define_type(Named_object* no, Named_type* type)
+{
+  no->set_type_value(type);
+  this->named_objects_.push_back(no);
+}
+
+// Traverse bindings.
+
+int
+Bindings::traverse(Traverse* traverse, bool is_global)
+{
+  unsigned int traverse_mask = traverse->traverse_mask();
+
+  // We don't use an iterator because we permit the traversal to add
+  // new global objects.
+  for (size_t i = 0; i < this->named_objects_.size(); ++i)
+    {
+      Named_object* p = this->named_objects_[i];
+      switch (p->classification())
+       {
+       case Named_object::NAMED_OBJECT_CONST:
+         if ((traverse_mask & Traverse::traverse_constants) != 0)
+           {
+             if (traverse->constant(p, is_global) == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+         if ((traverse_mask & Traverse::traverse_types) != 0
+             || (traverse_mask & Traverse::traverse_expressions) != 0)
+           {
+             Type* t = p->const_value()->type();
+             if (t != NULL
+                 && Type::traverse(t, traverse) == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+         if ((traverse_mask & Traverse::traverse_expressions) != 0)
+           {
+             if (p->const_value()->traverse_expression(traverse)
+                 == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+         break;
+
+       case Named_object::NAMED_OBJECT_VAR:
+       case Named_object::NAMED_OBJECT_RESULT_VAR:
+         if ((traverse_mask & Traverse::traverse_variables) != 0)
+           {
+             if (traverse->variable(p) == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+         if (((traverse_mask & Traverse::traverse_types) != 0
+              || (traverse_mask & Traverse::traverse_expressions) != 0)
+             && (p->is_result_variable()
+                 || p->var_value()->has_type()))
+           {
+             Type* t = (p->is_variable()
+                        ? p->var_value()->type()
+                        : p->result_var_value()->type());
+             if (t != NULL
+                 && Type::traverse(t, traverse) == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+         if (p->is_variable()
+             && (traverse_mask & Traverse::traverse_expressions) != 0)
+           {
+             if (p->var_value()->traverse_expression(traverse)
+                 == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+         break;
+
+       case Named_object::NAMED_OBJECT_FUNC:
+         if ((traverse_mask & Traverse::traverse_functions) != 0)
+           {
+             int t = traverse->function(p);
+             if (t == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+             else if (t == TRAVERSE_SKIP_COMPONENTS)
+               break;
+           }
+
+         if ((traverse_mask
+              & (Traverse::traverse_variables
+                 | Traverse::traverse_constants
+                 | Traverse::traverse_functions
+                 | Traverse::traverse_blocks
+                 | Traverse::traverse_statements
+                 | Traverse::traverse_expressions
+                 | Traverse::traverse_types)) != 0)
+           {
+             if (p->func_value()->traverse(traverse) == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+         break;
+
+       case Named_object::NAMED_OBJECT_PACKAGE:
+         // These are traversed in Gogo::traverse.
+         gcc_assert(is_global);
+         break;
+
+       case Named_object::NAMED_OBJECT_TYPE:
+         if ((traverse_mask & Traverse::traverse_types) != 0
+             || (traverse_mask & Traverse::traverse_expressions) != 0)
+           {
+             if (Type::traverse(p->type_value(), traverse) == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+         break;
+
+       case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
+       case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
+       case Named_object::NAMED_OBJECT_UNKNOWN:
+         break;
+
+       case Named_object::NAMED_OBJECT_SINK:
+       default:
+         gcc_unreachable();
+       }
+    }
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Class Package.
+
+Package::Package(const std::string& name, const std::string& unique_prefix,
+                source_location location)
+  : name_(name), unique_prefix_(unique_prefix), bindings_(new Bindings(NULL)),
+    priority_(0), location_(location), used_(false), is_imported_(false),
+    uses_sink_alias_(false)
+{
+  gcc_assert(!name.empty() && !unique_prefix.empty());
+}
+
+// Set the priority.  We may see multiple priorities for an imported
+// package; we want to use the largest one.
+
+void
+Package::set_priority(int priority)
+{
+  if (priority > this->priority_)
+    this->priority_ = priority;
+}
+
+// Determine types of constants.  Everything else in a package
+// (variables, function declarations) should already have a fixed
+// type.  Constants may have abstract types.
+
+void
+Package::determine_types()
+{
+  Bindings* bindings = this->bindings_;
+  for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
+       p != bindings->end_definitions();
+       ++p)
+    {
+      if ((*p)->is_const())
+       (*p)->const_value()->determine_type();
+    }
+}
+
+// Class Traverse.
+
+// Destructor.
+
+Traverse::~Traverse()
+{
+  if (this->types_seen_ != NULL)
+    delete this->types_seen_;
+  if (this->expressions_seen_ != NULL)
+    delete this->expressions_seen_;
+}
+
+// Record that we are looking at a type, and return true if we have
+// already seen it.
+
+bool
+Traverse::remember_type(const Type* type)
+{
+  gcc_assert((this->traverse_mask() & traverse_types) != 0
+            || (this->traverse_mask() & traverse_expressions) != 0);
+  // We only have to remember named types, as they are the only ones
+  // we can see multiple times in a traversal.
+  if (type->classification() != Type::TYPE_NAMED)
+    return false;
+  if (this->types_seen_ == NULL)
+    this->types_seen_ = new Types_seen();
+  std::pair<Types_seen::iterator, bool> ins = this->types_seen_->insert(type);
+  return !ins.second;
+}
+
+// Record that we are looking at an expression, and return true if we
+// have already seen it.
+
+bool
+Traverse::remember_expression(const Expression* expression)
+{
+  gcc_assert((this->traverse_mask() & traverse_types) != 0
+            || (this->traverse_mask() & traverse_expressions) != 0);
+  if (this->expressions_seen_ == NULL)
+    this->expressions_seen_ = new Expressions_seen();
+  std::pair<Expressions_seen::iterator, bool> ins =
+    this->expressions_seen_->insert(expression);
+  return !ins.second;
+}
+
+// The default versions of these functions should never be called: the
+// traversal mask indicates which functions may be called.
+
+int
+Traverse::variable(Named_object*)
+{
+  gcc_unreachable();
+}
+
+int
+Traverse::constant(Named_object*, bool)
+{
+  gcc_unreachable();
+}
+
+int
+Traverse::function(Named_object*)
+{
+  gcc_unreachable();
+}
+
+int
+Traverse::block(Block*)
+{
+  gcc_unreachable();
+}
+
+int
+Traverse::statement(Block*, size_t*, Statement*)
+{
+  gcc_unreachable();
+}
+
+int
+Traverse::expression(Expression**)
+{
+  gcc_unreachable();
+}
+
+int
+Traverse::type(Type*)
+{
+  gcc_unreachable();
+}
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
new file mode 100644 (file)
index 0000000..d0cfa1e
--- /dev/null
@@ -0,0 +1,2484 @@
+// gogo.h -- Go frontend parsed representation.     -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_GOGO_H
+#define GO_GOGO_H
+
+class Traverse;
+class Type;
+class Type_hash_identical;
+class Type_equal;
+class Type_identical;
+class Typed_identifier;
+class Typed_identifier_list;
+class Function_type;
+class Expression;
+class Statement;
+class Block;
+class Function;
+class Bindings;
+class Package;
+class Variable;
+class Pointer_type;
+class Struct_type;
+class Struct_field;
+class Struct_field_list;
+class Array_type;
+class Map_type;
+class Channel_type;
+class Interface_type;
+class Named_type;
+class Forward_declaration_type;
+class Method;
+class Methods;
+class Named_object;
+class Label;
+class Translate_context;
+class Export;
+class Import;
+
+// This file declares the basic classes used to hold the internal
+// representation of Go which is built by the parser.
+
+// An initialization function for an imported package.  This is a
+// magic function which initializes variables and runs the "init"
+// function.
+
+class Import_init
+{
+ public:
+  Import_init(const std::string& package_name, const std::string& init_name,
+             int priority)
+    : package_name_(package_name), init_name_(init_name), priority_(priority)
+  { }
+
+  // The name of the package being imported.
+  const std::string&
+  package_name() const
+  { return this->package_name_; }
+
+  // The name of the package's init function.
+  const std::string&
+  init_name() const
+  { return this->init_name_; }
+
+  // The priority of the initialization function.  Functions with a
+  // lower priority number must be run first.
+  int
+  priority() const
+  { return this->priority_; }
+
+ private:
+  // The name of the package being imported.
+  std::string package_name_;
+  // The name of the package's init function.
+  std::string init_name_;
+  // The priority.
+  int priority_;
+};
+
+// For sorting purposes.
+
+inline bool
+operator<(const Import_init& i1, const Import_init& i2)
+{
+  if (i1.priority() < i2.priority())
+    return true;
+  if (i1.priority() > i2.priority())
+    return false;
+  if (i1.package_name() != i2.package_name())
+    return i1.package_name() < i2.package_name();
+  return i1.init_name() < i2.init_name();
+}
+
+// The holder for the internal representation of the entire
+// compilation unit.
+
+class Gogo
+{
+ public:
+  // Create the IR, passing in the sizes of the types "int", "float",
+  // and "uintptr" in bits.
+  Gogo(int int_type_size, int float_type_size, int pointer_size);
+
+  // Get the package name.
+  const std::string&
+  package_name() const;
+
+  // Set the package name.
+  void
+  set_package_name(const std::string&, source_location);
+
+  // If necessary, adjust the name to use for a hidden symbol.  We add
+  // a prefix of the package name, so that hidden symbols in different
+  // packages do not collide.
+  std::string
+  pack_hidden_name(const std::string& name, bool is_exported) const
+  {
+    return (is_exported
+           ? name
+           : ('.' + this->unique_prefix()
+              + '.' + this->package_name()
+              + '.' + name));
+  }
+
+  // Unpack a name which may have been hidden.  Returns the
+  // user-visible name of the object.
+  static std::string
+  unpack_hidden_name(const std::string& name)
+  { return name[0] != '.' ? name : name.substr(name.rfind('.') + 1); }
+
+  // Return whether a possibly packed name is hidden.
+  static bool
+  is_hidden_name(const std::string& name)
+  { return name[0] == '.'; }
+
+  // Return the package prefix of a hidden name.
+  static std::string
+  hidden_name_prefix(const std::string& name)
+  {
+    gcc_assert(Gogo::is_hidden_name(name));
+    return name.substr(1, name.rfind('.') - 1);
+  }
+
+  // Given a name which may or may not have been hidden, return the
+  // name to use in an error message.
+  static std::string
+  message_name(const std::string& name);
+
+  // Return whether a name is the blank identifier _.
+  static bool
+  is_sink_name(const std::string& name)
+  {
+    return (name[0] == '.'
+           && name[name.length() - 1] == '_'
+           && name[name.length() - 2] == '.');
+  }
+
+  // Return the unique prefix to use for all exported symbols.
+  const std::string&
+  unique_prefix() const;
+
+  // Set the unique prefix.
+  void
+  set_unique_prefix(const std::string&);
+
+  // Return the priority to use for the package we are compiling.
+  // This is two more than the largest priority of any package we
+  // import.
+  int
+  package_priority() const;
+
+  // Import a package.  FILENAME is the file name argument, LOCAL_NAME
+  // is the local name to give to the package.  If LOCAL_NAME is empty
+  // the declarations are added to the global scope.
+  void
+  import_package(const std::string& filename, const std::string& local_name,
+                bool is_local_name_exported, source_location);
+
+  // Whether we are the global binding level.
+  bool
+  in_global_scope() const;
+
+  // Look up a name in the current binding contours.
+  Named_object*
+  lookup(const std::string&, Named_object** pfunction) const;
+
+  // Look up a name in the current block.
+  Named_object*
+  lookup_in_block(const std::string&) const;
+
+  // Look up a name in the global namespace--the universal scope.
+  Named_object*
+  lookup_global(const char*) const;
+
+  // Add a new imported package.  REAL_NAME is the real name of the
+  // package.  ALIAS is the alias of the package; this may be the same
+  // as REAL_NAME.  This sets *PADD_TO_GLOBALS if symbols added to
+  // this package should be added to the global namespace; this is
+  // true if the alias is ".".  LOCATION is the location of the import
+  // statement.  This returns the new package, or NULL on error.
+  Package*
+  add_imported_package(const std::string& real_name, const std::string& alias,
+                      bool is_alias_exported,
+                      const std::string& unique_prefix,
+                      source_location location,
+                      bool* padd_to_globals);
+
+  // Register a package.  This package may or may not be imported.
+  // This returns the Package structure for the package, creating if
+  // it necessary.
+  Package*
+  register_package(const std::string& name, const std::string& unique_prefix,
+                  source_location);
+
+  // Start compiling a function.  ADD_METHOD_TO_TYPE is true if a
+  // method function should be added to the type of its receiver.
+  Named_object*
+  start_function(const std::string& name, Function_type* type,
+                bool add_method_to_type, source_location);
+
+  // Finish compiling a function.
+  void
+  finish_function(source_location);
+
+  // Return the current function.
+  Named_object*
+  current_function() const;
+
+  // Start a new block.  This is not initially associated with a
+  // function.
+  void
+  start_block(source_location);
+
+  // Finish the current block and return it.
+  Block*
+  finish_block(source_location);
+
+  // Declare an unknown name.  This is used while parsing.  The name
+  // must be resolved by the end of the parse.  Unknown names are
+  // always added at the package level.
+  Named_object*
+  add_unknown_name(const std::string& name, source_location);
+
+  // Declare a function.
+  Named_object*
+  declare_function(const std::string&, Function_type*, source_location);
+
+  // Add a label.
+  Label*
+  add_label_definition(const std::string&, source_location);
+
+  // Add a label reference.
+  Label*
+  add_label_reference(const std::string&);
+
+  // Add a statement to the current block.
+  void
+  add_statement(Statement*);
+
+  // Add a block to the current block.
+  void
+  add_block(Block*, source_location);
+
+  // Add a constant.
+  Named_object*
+  add_constant(const Typed_identifier&, Expression*, int iota_value);
+
+  // Add a type.
+  void
+  add_type(const std::string&, Type*, source_location);
+
+  // Add a named type.  This is used for builtin types, and to add an
+  // imported type to the global scope.
+  void
+  add_named_type(Named_type*);
+
+  // Declare a type.
+  Named_object*
+  declare_type(const std::string&, source_location);
+
+  // Declare a type at the package level.  This is used when the
+  // parser sees an unknown name where a type name is required.
+  Named_object*
+  declare_package_type(const std::string&, source_location);
+
+  // Define a type which was already declared.
+  void
+  define_type(Named_object*, Named_type*);
+
+  // Add a variable.
+  Named_object*
+  add_variable(const std::string&, Variable*);
+
+  // Add a sink--a reference to the blank identifier _.
+  Named_object*
+  add_sink();
+
+  // Add a named object to the current namespace.  This is used for
+  // import . "package".
+  void
+  add_named_object(Named_object*);
+
+  // Return a name to use for a thunk function.  A thunk function is
+  // one we create during the compilation, for a go statement or a
+  // defer statement or a method expression.
+  static std::string
+  thunk_name();
+
+  // Return whether an object is a thunk.
+  static bool
+  is_thunk(const Named_object*);
+
+  // Note that we've seen an interface type.  This is used to build
+  // all required interface method tables.
+  void
+  record_interface_type(Interface_type*);
+
+  // Clear out all names in file scope.  This is called when we start
+  // parsing a new file.
+  void
+  clear_file_scope();
+
+  // Traverse the tree.  See the Traverse class.
+  void
+  traverse(Traverse*);
+
+  // Define the predeclared global names.
+  void
+  define_global_names();
+
+  // Verify and complete all types.
+  void
+  verify_types();
+
+  // Lower the parse tree.
+  void
+  lower_parse_tree();
+
+  // Lower an expression.
+  void
+  lower_expression(Named_object* function, Expression**);
+
+  // Lower a constant.
+  void
+  lower_constant(Named_object*);
+
+  // Finalize the method lists and build stub methods for named types.
+  void
+  finalize_methods();
+
+  // Work out the types to use for unspecified variables and
+  // constants.
+  void
+  determine_types();
+
+  // Type check the program.
+  void
+  check_types();
+
+  // Check the types in a single block.  This is used for complicated
+  // go statements.
+  void
+  check_types_in_block(Block*);
+
+  // Check for return statements.
+  void
+  check_return_statements();
+
+  // Do all exports.
+  void
+  do_exports();
+
+  // Add an import control function for an imported package to the
+  // list.
+  void
+  add_import_init_fn(const std::string& package_name,
+                    const std::string& init_name, int prio);
+
+  // Turn short-cut operators (&&, ||) into explicit if statements.
+  void
+  remove_shortcuts();
+
+  // Use temporary variables to force order of evaluation.
+  void
+  order_evaluations();
+
+  // Build thunks for functions which call recover.
+  void
+  build_recover_thunks();
+
+  // Simplify statements which might use thunks: go and defer
+  // statements.
+  void
+  simplify_thunk_statements();
+
+  // Write out the global values.
+  void
+  write_globals();
+
+  // Build a call to a builtin function.  PDECL should point to a NULL
+  // initialized static pointer which will hold the fndecl.  NAME is
+  // the name of the function.  NARGS is the number of arguments.
+  // RETTYPE is the return type.  It is followed by NARGS pairs of
+  // type and argument (both trees).
+  static tree
+  call_builtin(tree* pdecl, source_location, const char* name, int nargs,
+              tree rettype, ...);
+
+  // Build a call to the runtime error function.
+  static tree
+  runtime_error(int code, source_location);
+
+  // Build a builtin struct with a list of fields.
+  static tree
+  builtin_struct(tree* ptype, const char* struct_name, tree struct_type,
+                int nfields, ...);
+
+  // Mark a function declaration as a builtin library function.
+  static void
+  mark_fndecl_as_builtin_library(tree fndecl);
+
+  // Build the type of the struct that holds a slice for the given
+  // element type.
+  tree
+  slice_type_tree(tree element_type_tree);
+
+  // Given a tree for a slice type, return the tree for the element
+  // type.
+  static tree
+  slice_element_type_tree(tree slice_type_tree);
+
+  // Build a constructor for a slice.  SLICE_TYPE_TREE is the type of
+  // the slice.  VALUES points to the values.  COUNT is the size,
+  // CAPACITY is the capacity.  If CAPACITY is NULL, it is set to
+  // COUNT.
+  static tree
+  slice_constructor(tree slice_type_tree, tree values, tree count,
+                   tree capacity);
+
+  // Build a constructor for an empty slice.  SLICE_TYPE_TREE is the
+  // type of the slice.
+  static tree
+  empty_slice_constructor(tree slice_type_tree);
+
+  // Build a map descriptor.
+  tree
+  map_descriptor(Map_type*);
+
+  // Return a tree for the type of a map descriptor.  This is struct
+  // __go_map_descriptor in libgo/runtime/map.h.  This is the same for
+  // all map types.
+  tree
+  map_descriptor_type();
+
+  // Build a type descriptor for TYPE using INITIALIZER as the type
+  // descriptor.  This builds a new decl stored in *PDECL.
+  void
+  build_type_descriptor_decl(const Type*, Expression* initializer,
+                            tree* pdecl);
+
+  // Build required interface method tables.
+  void
+  build_interface_method_tables();
+
+  // Build an interface method table for a type: a list of function
+  // pointers, one for each interface method.  This returns a decl.
+  tree
+  interface_method_table_for_type(const Interface_type*, Named_type*,
+                                 bool is_pointer);
+
+  // Return a tree which allocate SIZE bytes to hold values of type
+  // TYPE.
+  tree
+  allocate_memory(Type *type, tree size, source_location);
+
+  // Return a type to use for pointer to const char.
+  static tree
+  const_char_pointer_type_tree();
+
+  // Build a string constant with the right type.
+  static tree
+  string_constant_tree(const std::string&);
+
+  // Build a Go string constant.  This returns a pointer to the
+  // constant.
+  tree
+  go_string_constant_tree(const std::string&);
+
+  // Send a value on a channel.
+  static tree
+  send_on_channel(tree channel, tree val, bool blocking, bool for_select,
+                 source_location);
+
+  // Receive a value from a channel.
+  static tree
+  receive_from_channel(tree type_tree, tree channel, bool for_select,
+                      source_location);
+
+  // Return a tree for receiving an integer on a channel.
+  static tree
+  receive_as_64bit_integer(tree type, tree channel, bool blocking,
+                          bool for_select);
+
+
+  // Make a trampoline which calls FNADDR passing CLOSURE.
+  tree
+  make_trampoline(tree fnaddr, tree closure, source_location);
+
+ private:
+  // During parsing, we keep a stack of functions.  Each function on
+  // the stack is one that we are currently parsing.  For each
+  // function, we keep track of the current stack of blocks.
+  struct Open_function
+  {
+    // The function.
+    Named_object* function;
+    // The stack of active blocks in the function.
+    std::vector<Block*> blocks;
+  };
+
+  // The stack of functions.
+  typedef std::vector<Open_function> Open_functions;
+
+  // Create trees for implicit builtin functions.
+  void
+  define_builtin_function_trees();
+
+  // Set up the built-in unsafe package.
+  void
+  import_unsafe(const std::string&, bool is_exported, source_location);
+
+  // Add a new imported package.
+  Named_object*
+  add_package(const std::string& real_name, const std::string& alias,
+             const std::string& unique_prefix, source_location location);
+
+  // Return the current binding contour.
+  Bindings*
+  current_bindings();
+
+  const Bindings*
+  current_bindings() const;
+
+  // Return the current block.
+  Block*
+  current_block();
+
+  // Get the name of the magic initialization function.
+  const std::string&
+  get_init_fn_name();
+
+  // Get the decl for the magic initialization function.
+  tree
+  initialization_function_decl();
+
+  // Write the magic initialization function.
+  void
+  write_initialization_function(tree fndecl, tree init_stmt_list);
+
+  // Initialize imported packages.
+  void
+  init_imports(tree*);
+
+  // Register variables with the garbage collector.
+  void
+  register_gc_vars(const std::vector<Named_object*>&, tree*);
+
+  // Build a pointer to a Go string constant.  This returns a pointer
+  // to the pointer.
+  tree
+  ptr_go_string_constant_tree(const std::string&);
+
+  // Return the name to use for a type descriptor decl for an unnamed
+  // type.
+  std::string
+  unnamed_type_descriptor_decl_name(const Type* type);
+
+  // Return the name to use for a type descriptor decl for a type
+  // named NO, defined in IN_FUNCTION.
+  std::string
+  type_descriptor_decl_name(const Named_object* no,
+                           const Named_object* in_function);
+
+  // Where a type descriptor should be defined.
+  enum Type_descriptor_location
+    {
+      // Defined in this file.
+      TYPE_DESCRIPTOR_DEFINED,
+      // Defined in some other file.
+      TYPE_DESCRIPTOR_UNDEFINED,
+      // Common definition which may occur in multiple files.
+      TYPE_DESCRIPTOR_COMMON
+    };
+
+  // Return where the decl for TYPE should be defined.
+  Type_descriptor_location
+  type_descriptor_location(const Type* type);
+
+  // Return the type of a trampoline.
+  static tree
+  trampoline_type_tree();
+
+  // Type used to map import names to packages.
+  typedef std::map<std::string, Package*> Imports;
+
+  // Type used to map package names to packages.
+  typedef std::map<std::string, Package*> Packages;
+
+  // Type used to map special names in the sys package.
+  typedef std::map<std::string, std::string> Sys_names;
+
+  // Hash table mapping map types to map descriptor decls.
+  typedef Unordered_map_hash(const Map_type*, tree, Type_hash_identical,
+                            Type_identical) Map_descriptors;
+
+  // Map unnamed types to type descriptor decls.
+  typedef Unordered_map_hash(const Type*, tree, Type_hash_identical,
+                            Type_identical) Type_descriptor_decls;
+
+  // The package we are compiling.
+  Package* package_;
+  // The list of currently open functions during parsing.
+  Open_functions functions_;
+  // The global binding contour.  This includes the builtin functions
+  // and the package we are compiling.
+  Bindings* globals_;
+  // Mapping from import file names to packages.
+  Imports imports_;
+  // Whether the magic unsafe package was imported.
+  bool imported_unsafe_;
+  // Mapping from package names we have seen to packages.  This does
+  // not include the package we are compiling.
+  Packages packages_;
+  // Mapping from map types to map descriptors.
+  Map_descriptors* map_descriptors_;
+  // Mapping from unnamed types to type descriptor decls.
+  Type_descriptor_decls* type_descriptor_decls_;
+  // The functions named "init", if there are any.
+  std::vector<Named_object*> init_functions_;
+  // Whether we need a magic initialization function.
+  bool need_init_fn_;
+  // The name of the magic initialization function.
+  std::string init_fn_name_;
+  // A list of import control variables for packages that we import.
+  std::set<Import_init> imported_init_fns_;
+  // The unique prefix used for all global symbols.
+  std::string unique_prefix_;
+  // A list of interface types defined while parsing.
+  std::vector<Interface_type*> interface_types_;
+};
+
+// A block of statements.
+
+class Block
+{
+ public:
+  Block(Block* enclosing, source_location);
+
+  // Return the enclosing block.
+  const Block*
+  enclosing() const
+  { return this->enclosing_; }
+
+  // Return the bindings of the block.
+  Bindings*
+  bindings()
+  { return this->bindings_; }
+
+  const Bindings*
+  bindings() const
+  { return this->bindings_; }
+
+  // Look at the block's statements.
+  const std::vector<Statement*>*
+  statements() const
+  { return &this->statements_; }
+
+  // Return the start location.  This is normally the location of the
+  // left curly brace which starts the block.
+  source_location
+  start_location() const
+  { return this->start_location_; }
+
+  // Return the end location.  This is normally the location of the
+  // right curly brace which ends the block.
+  source_location
+  end_location() const
+  { return this->end_location_; }
+
+  // Add a statement to the block.
+  void
+  add_statement(Statement*);
+
+  // Add a statement to the front of the block.
+  void
+  add_statement_at_front(Statement*);
+
+  // Replace a statement in a block.
+  void
+  replace_statement(size_t index, Statement*);
+
+  // Add a Statement before statement number INDEX.
+  void
+  insert_statement_before(size_t index, Statement*);
+
+  // Add a Statement after statement number INDEX.
+  void
+  insert_statement_after(size_t index, Statement*);
+
+  // Set the end location of the block.
+  void
+  set_end_location(source_location location)
+  { this->end_location_ = location; }
+
+  // Traverse the tree.
+  int
+  traverse(Traverse*);
+
+  // Set final types for unspecified variables and constants.
+  void
+  determine_types();
+
+  // Return true if execution of this block may fall through to the
+  // next block.
+  bool
+  may_fall_through() const;
+
+  // Return a tree of the code in this block.
+  tree
+  get_tree(Translate_context*);
+
+  // Iterate over statements.
+
+  typedef std::vector<Statement*>::iterator iterator;
+
+  iterator
+  begin()
+  { return this->statements_.begin(); }
+
+  iterator
+  end()
+  { return this->statements_.end(); }
+
+ private:
+  // Enclosing block.
+  Block* enclosing_;
+  // Statements in the block.
+  std::vector<Statement*> statements_;
+  // Binding contour.
+  Bindings* bindings_;
+  // Location of start of block.
+  source_location start_location_;
+  // Location of end of block.
+  source_location end_location_;
+};
+
+// A function.
+
+class Function
+{
+ public:
+  Function(Function_type* type, Function*, Block*, source_location);
+
+  // Return the function's type.
+  Function_type*
+  type() const
+  { return this->type_; }
+
+  // Return the enclosing function if there is one.
+  Function*
+  enclosing()
+  { return this->enclosing_; }
+
+  // Set the enclosing function.  This is used when building thunks
+  // for functions which call recover.
+  void
+  set_enclosing(Function* enclosing)
+  {
+    gcc_assert(this->enclosing_ == NULL);
+    this->enclosing_ = enclosing;
+  }
+
+  // Create the named result variables in the outer block.
+  void
+  create_named_result_variables();
+
+  // Add a new field to the closure variable.
+  void
+  add_closure_field(Named_object* var, source_location loc)
+  { this->closure_fields_.push_back(std::make_pair(var, loc)); }
+
+  // Whether this function needs a closure.
+  bool
+  needs_closure() const
+  { return !this->closure_fields_.empty(); }
+
+  // Return the closure variable, creating it if necessary.  This is
+  // passed to the function as a static chain parameter.
+  Named_object*
+  closure_var();
+
+  // Set the closure variable.  This is used when building thunks for
+  // functions which call recover.
+  void
+  set_closure_var(Named_object* v)
+  {
+    gcc_assert(this->closure_var_ == NULL);
+    this->closure_var_ = v;
+  }
+
+  // Return the variable for a reference to field INDEX in the closure
+  // variable.
+  Named_object*
+  enclosing_var(unsigned int index)
+  {
+    gcc_assert(index < this->closure_fields_.size());
+    return closure_fields_[index].first;
+  }
+
+  // Set the type of the closure variable if there is one.
+  void
+  set_closure_type();
+
+  // Get the block of statements associated with the function.
+  Block*
+  block() const
+  { return this->block_; }
+
+  // Get the location of the start of the function.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Return whether this function is actually a method.
+  bool
+  is_method() const;
+
+  // Add a label definition to the function.
+  Label*
+  add_label_definition(const std::string& label_name, source_location);
+
+  // Add a label reference to a function.
+  Label*
+  add_label_reference(const std::string& label_name);
+
+  // Whether this function calls the predeclared recover function.
+  bool
+  calls_recover() const
+  { return this->calls_recover_; }
+
+  // Record that this function calls the predeclared recover function.
+  // This is set during the lowering pass.
+  void
+  set_calls_recover()
+  { this->calls_recover_ = true; }
+
+  // Whether this is a recover thunk function.
+  bool
+  is_recover_thunk() const
+  { return this->is_recover_thunk_; }
+
+  // Record that this is a thunk built for a function which calls
+  // recover.
+  void
+  set_is_recover_thunk()
+  { this->is_recover_thunk_ = true; }
+
+  // Whether this function already has a recover thunk.
+  bool
+  has_recover_thunk() const
+  { return this->has_recover_thunk_; }
+
+  // Record that this function already has a recover thunk.
+  void
+  set_has_recover_thunk()
+  { this->has_recover_thunk_ = true; }
+
+  // Swap with another function.  Used only for the thunk which calls
+  // recover.
+  void
+  swap_for_recover(Function *);
+
+  // Traverse the tree.
+  int
+  traverse(Traverse*);
+
+  // Determine types in the function.
+  void
+  determine_types();
+
+  // Return the function's decl given an identifier.
+  tree
+  get_or_make_decl(Gogo*, Named_object*, tree id);
+
+  // Return the function's decl after it has been built.
+  tree
+  get_decl() const
+  {
+    gcc_assert(this->fndecl_ != NULL);
+    return this->fndecl_;
+  }
+
+  // Set the function decl to hold a tree of the function code.
+  void
+  build_tree(Gogo*, Named_object*);
+
+  // Get the value to return when not explicitly specified.  May also
+  // add statements to execute first to STMT_LIST.
+  tree
+  return_value(Gogo*, Named_object*, source_location, tree* stmt_list) const;
+
+  // Get a tree for the variable holding the defer stack.
+  tree
+  defer_stack(source_location);
+
+  // Export the function.
+  void
+  export_func(Export*, const std::string& name) const;
+
+  // Export a function with a type.
+  static void
+  export_func_with_type(Export*, const std::string& name,
+                       const Function_type*);
+
+  // Import a function.
+  static void
+  import_func(Import*, std::string* pname, Typed_identifier** receiver,
+             Typed_identifier_list** pparameters,
+             Typed_identifier_list** presults, bool* is_varargs);
+
+ private:
+  // Type for mapping from label names to Label objects.
+  typedef Unordered_map(std::string, Label*) Labels;
+
+  tree
+  make_receiver_parm_decl(Gogo*, Named_object*, tree);
+
+  tree
+  copy_parm_to_heap(Gogo*, Named_object*, tree);
+
+  void
+  build_defer_wrapper(Gogo*, Named_object*, tree*, tree*);
+
+  typedef std::vector<Named_object*> Named_results;
+
+  typedef std::vector<std::pair<Named_object*,
+                               source_location> > Closure_fields;
+
+  // The function's type.
+  Function_type* type_;
+  // The enclosing function.  This is NULL when there isn't one, which
+  // is the normal case.
+  Function* enclosing_;
+  // The named result variables, if any.
+  Named_results* named_results_;
+  // If there is a closure, this is the list of variables which appear
+  // in the closure.  This is created by the parser, and then resolved
+  // to a real type when we lower parse trees.
+  Closure_fields closure_fields_;
+  // The closure variable, passed as a parameter using the static
+  // chain parameter.  Normally NULL.
+  Named_object* closure_var_;
+  // The outer block of statements in the function.
+  Block* block_;
+  // The source location of the start of the function.
+  source_location location_;
+  // Labels defined or referenced in the function.
+  Labels labels_;
+  // The function decl.
+  tree fndecl_;
+  // A variable holding the defer stack variable.  This is NULL unless
+  // we actually need a defer stack.
+  tree defer_stack_;
+  // True if this function calls the predeclared recover function.
+  bool calls_recover_;
+  // True if this a thunk built for a function which calls recover.
+  bool is_recover_thunk_;
+  // True if this function already has a recover thunk.
+  bool has_recover_thunk_;
+};
+
+// A function declaration.
+
+class Function_declaration
+{
+ public:
+  Function_declaration(Function_type* fntype, source_location location)
+    : fntype_(fntype), location_(location), asm_name_(), fndecl_(NULL)
+  { }
+
+  Function_type*
+  type() const
+  { return this->fntype_; }
+
+  source_location
+  location() const
+  { return this->location_; }
+
+  const std::string&
+  asm_name() const
+  { return this->asm_name_; }
+
+  // Set the assembler name.
+  void
+  set_asm_name(const std::string& asm_name)
+  { this->asm_name_ = asm_name; }
+
+  // Return a decl for the function given an identifier.
+  tree
+  get_or_make_decl(Gogo*, Named_object*, tree id);
+
+  // Export a function declaration.
+  void
+  export_func(Export* exp, const std::string& name) const
+  { Function::export_func_with_type(exp, name, this->fntype_); }
+
+ private:
+  // The type of the function.
+  Function_type* fntype_;
+  // The location of the declaration.
+  source_location location_;
+  // The assembler name: this is the name to use in references to the
+  // function.  This is normally empty.
+  std::string asm_name_;
+  // The function decl if needed.
+  tree fndecl_;
+};
+
+// A variable.
+
+class Variable
+{
+ public:
+  Variable(Type*, Expression*, bool is_global, bool is_parameter,
+          bool is_receiver, source_location);
+
+  // Get the type of the variable.
+  Type*
+  type() const;
+
+  // Return whether the type is defined yet.
+  bool
+  has_type() const
+  { return this->type_ != NULL; }
+
+  // Get the initial value.
+  Expression*
+  init() const
+  { return this->init_; }
+
+  // Return whether there are any preinit statements.
+  bool
+  has_pre_init() const
+  { return this->preinit_ != NULL; }
+
+  // Return the preinit statements if any.
+  Block*
+  preinit() const
+  { return this->preinit_; }
+
+  // Return whether this is a global variable.
+  bool
+  is_global() const
+  { return this->is_global_; }
+
+  // Return whether this is a function parameter.
+  bool
+  is_parameter() const
+  { return this->is_parameter_; }
+
+  // Return whether this is the receiver parameter of a method.
+  bool
+  is_receiver() const
+  { return this->is_receiver_; }
+
+  // Change this parameter to be a receiver.  This is used when
+  // creating the thunks created for functions which call recover.
+  void
+  set_is_receiver()
+  {
+    gcc_assert(this->is_parameter_);
+    this->is_receiver_ = true;
+  }
+
+  // Change this parameter to not be a receiver.  This is used when
+  // creating the thunks created for functions which call recover.
+  void
+  set_is_not_receiver()
+  {
+    gcc_assert(this->is_parameter_);
+    this->is_receiver_ = false;
+  }
+
+  // Return whether this is the varargs parameter of a function.
+  bool
+  is_varargs_parameter() const
+  { return this->is_varargs_parameter_; }
+
+  // Whether this variable's address is taken.
+  bool
+  is_address_taken() const
+  { return this->is_address_taken_; }
+
+  // Whether this variable should live in the heap.
+  bool
+  is_in_heap() const
+  { return this->is_address_taken_ && !this->is_global_; }
+
+  // Get the source location of the variable's declaration.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Record that this is the varargs parameter of a function.
+  void
+  set_is_varargs_parameter()
+  {
+    gcc_assert(this->is_parameter_);
+    this->is_varargs_parameter_ = true;
+  }
+
+  // Clear the initial value; used for error handling.
+  void
+  clear_init()
+  { this->init_ = NULL; }
+
+  // Set the initial value; used for converting shortcuts.
+  void
+  set_init(Expression* init)
+  { this->init_ = init; }
+
+  // Get the preinit block, a block of statements to be run before the
+  // initialization expression.
+  Block*
+  preinit_block();
+
+  // Add a statement to be run before the initialization expression.
+  // This is only used for global variables.
+  void
+  add_preinit_statement(Statement*);
+
+  // Lower the initialization expression after parsing is complete.
+  void
+  lower_init_expression(Gogo*, Named_object*);
+
+  // A special case: the init value is used only to determine the
+  // type.  This is used if the variable is defined using := with the
+  // comma-ok form of a map index or a receive expression.  The init
+  // value is actually the map index expression or receive expression.
+  // We use this because we may not know the right type at parse time.
+  void
+  set_type_from_init_tuple()
+  { this->type_from_init_tuple_ = true; }
+
+  // Another special case: the init value is used only to determine
+  // the type.  This is used if the variable is defined using := with
+  // a range clause.  The init value is the range expression.  The
+  // type of the variable is the index type of the range expression
+  // (i.e., the first value returned by a range).
+  void
+  set_type_from_range_index()
+  { this->type_from_range_index_ = true; }
+
+  // Another special case: like set_type_from_range_index, but the
+  // type is the value type of the range expression (i.e., the second
+  // value returned by a range).
+  void
+  set_type_from_range_value()
+  { this->type_from_range_value_ = true; }
+
+  // Another special case: the init value is used only to determine
+  // the type.  This is used if the variable is defined using := with
+  // a case in a select statement.  The init value is the channel.
+  // The type of the variable is the channel's element type.
+  void
+  set_type_from_chan_element()
+  { this->type_from_chan_element_ = true; }
+
+  // After we lower the select statement, we once again set the type
+  // from the initialization expression.
+  void
+  clear_type_from_chan_element()
+  {
+    gcc_assert(this->type_from_chan_element_);
+    this->type_from_chan_element_ = false;
+  }
+
+  // Note that this variable was created for a type switch clause.
+  void
+  set_is_type_switch_var()
+  { this->is_type_switch_var_ = true; }
+
+  // Traverse the initializer expression.
+  int
+  traverse_expression(Traverse*);
+
+  // Determine the type of the variable if necessary.
+  void
+  determine_type();
+
+  // Note that something takes the address of this variable.
+  void
+  set_address_taken()
+  { this->is_address_taken_ = true; }
+
+  // Get the initial value of the variable as a tree.  This may only
+  // be called if has_pre_init() returns false.
+  tree
+  get_init_tree(Gogo*, Named_object* function);
+
+  // Return a series of statements which sets the value of the
+  // variable in DECL.  This should only be called is has_pre_init()
+  // returns true.  DECL may be NULL for a sink variable.
+  tree
+  get_init_block(Gogo*, Named_object* function, tree decl);
+
+  // Export the variable.
+  void
+  export_var(Export*, const std::string& name) const;
+
+  // Import a variable.
+  static void
+  import_var(Import*, std::string* pname, Type** ptype);
+
+ private:
+  // The type of a tuple.
+  Type*
+  type_from_tuple(Expression*, bool) const;
+
+  // The type of a range.
+  Type*
+  type_from_range(Expression*, bool, bool) const;
+
+  // The element type of a channel.
+  Type*
+  type_from_chan_element(Expression*, bool) const;
+
+  // The variable's type.  This may be NULL if the type is set from
+  // the expression.
+  Type* type_;
+  // The initial value.  This may be NULL if the variable should be
+  // initialized to the default value for the type.
+  Expression* init_;
+  // Statements to run before the init statement.
+  Block* preinit_;
+  // Location of variable definition.
+  source_location location_;
+  // Whether this is a global variable.
+  bool is_global_ : 1;
+  // Whether this is a function parameter.
+  bool is_parameter_ : 1;
+  // Whether this is the receiver parameter of a method.
+  bool is_receiver_ : 1;
+  // Whether this is the varargs parameter of a function.
+  bool is_varargs_parameter_ : 1;
+  // Whether something takes the address of this variable.
+  bool is_address_taken_ : 1;
+  // True if we have lowered the initialization expression.
+  bool init_is_lowered_ : 1;
+  // True if init is a tuple used to set the type.
+  bool type_from_init_tuple_ : 1;
+  // True if init is a range clause and the type is the index type.
+  bool type_from_range_index_ : 1;
+  // True if init is a range clause and the type is the value type.
+  bool type_from_range_value_ : 1;
+  // True if init is a channel and the type is the channel's element type.
+  bool type_from_chan_element_ : 1;
+  // True if this is a variable created for a type switch case.
+  bool is_type_switch_var_ : 1;
+};
+
+// A variable which is really the name for a function return value, or
+// part of one.
+
+class Result_variable
+{
+ public:
+  Result_variable(Type* type, Function* function, int index)
+    : type_(type), function_(function), index_(index),
+      is_address_taken_(false)
+  { }
+
+  // Get the type of the result variable.
+  Type*
+  type() const
+  { return this->type_; }
+
+  // Get the function that this is associated with.
+  Function*
+  function() const
+  { return this->function_; }
+
+  // Index in the list of function results.
+  int
+  index() const
+  { return this->index_; }
+
+  // Whether this variable's address is taken.
+  bool
+  is_address_taken() const
+  { return this->is_address_taken_; }
+
+  // Note that something takes the address of this variable.
+  void
+  set_address_taken()
+  { this->is_address_taken_ = true; }
+
+  // Whether this variable should live in the heap.
+  bool
+  is_in_heap() const
+  { return this->is_address_taken_; }
+
+ private:
+  // Type of result variable.
+  Type* type_;
+  // Function with which this is associated.
+  Function* function_;
+  // Index in list of results.
+  int index_;
+  // Whether something takes the address of this variable.
+  bool is_address_taken_;
+};
+
+// The value we keep for a named constant.  This lets us hold a type
+// and an expression.
+
+class Named_constant
+{
+ public:
+  Named_constant(Type* type, Expression* expr, int iota_value,
+                source_location location)
+    : type_(type), expr_(expr), iota_value_(iota_value), location_(location),
+      lowering_(false)
+  { }
+
+  Type*
+  type() const
+  { return this->type_; }
+
+  Expression*
+  expr() const
+  { return this->expr_; }
+
+  int
+  iota_value() const
+  { return this->iota_value_; }
+
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Whether we are lowering.
+  bool
+  lowering() const
+  { return this->lowering_; }
+
+  // Set that we are lowering.
+  void
+  set_lowering()
+  { this->lowering_ = true; }
+
+  // We are no longer lowering.
+  void
+  clear_lowering()
+  { this->lowering_ = false; }
+
+  // Traverse the expression.
+  int
+  traverse_expression(Traverse*);
+
+  // Determine the type of the constant if necessary.
+  void
+  determine_type();
+
+  // Indicate that we found and reported an error for this constant.
+  void
+  set_error();
+
+  // Export the constant.
+  void
+  export_const(Export*, const std::string& name) const;
+
+  // Import a constant.
+  static void
+  import_const(Import*, std::string*, Type**, Expression**);
+
+ private:
+  // The type of the constant.
+  Type* type_;
+  // The expression for the constant.
+  Expression* expr_;
+  // If the predeclared constant iota is used in EXPR_, this is the
+  // value it will have.  We do this because at parse time we don't
+  // know whether the name "iota" will refer to the predeclared
+  // constant or to something else.  We put in the right value in when
+  // we lower.
+  int iota_value_;
+  // The location of the definition.
+  source_location location_;
+  // Whether we are currently lowering this constant.
+  bool lowering_;
+};
+
+// A type declaration.
+
+class Type_declaration
+{
+ public:
+  Type_declaration(source_location location)
+    : location_(location), in_function_(NULL), methods_(),
+      issued_warning_(false)
+  { }
+
+  // Return the location.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Return the function in which this type is declared.  This will
+  // return NULL for a type declared in global scope.
+  Named_object*
+  in_function()
+  { return this->in_function_; }
+
+  // Set the function in which this type is declared.
+  void
+  set_in_function(Named_object* f)
+  { this->in_function_ = f; }
+
+  // Add a method to this type.  This is used when methods are defined
+  // before the type.
+  Named_object*
+  add_method(const std::string& name, Function* function);
+
+  // Add a method declaration to this type.
+  Named_object*
+  add_method_declaration(const std::string& name, Function_type* type,
+                        source_location location);
+
+  // Return whether any methods were defined.
+  bool
+  has_methods() const;
+
+  // Define methods when the real type is known.
+  void
+  define_methods(Named_type*);
+
+  // This is called if we are trying to use this type.  It returns
+  // true if we should issue a warning.
+  bool
+  using_type();
+
+ private:
+  typedef std::vector<Named_object*> Methods;
+
+  // The location of the type declaration.
+  source_location location_;
+  // If this type is declared in a function, a pointer back to the
+  // function in which it is defined.
+  Named_object* in_function_;
+  // Methods defined before the type is defined.
+  Methods methods_;
+  // True if we have issued a warning about a use of this type
+  // declaration when it is undefined.
+  bool issued_warning_;
+};
+
+// An unknown object.  These are created by the parser for forward
+// references to names which have not been seen before.  In a correct
+// program, these will always point to a real definition by the end of
+// the parse.  Because they point to another Named_object, these may
+// only be referenced by Unknown_expression objects.
+
+class Unknown_name
+{
+ public:
+  Unknown_name(source_location location)
+    : location_(location), real_named_object_(NULL)
+  { }
+
+  // Return the location where this name was first seen.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Return the real named object that this points to, or NULL if it
+  // was never resolved.
+  Named_object*
+  real_named_object() const
+  { return this->real_named_object_; }
+
+  // Set the real named object that this points to.
+  void
+  set_real_named_object(Named_object* no);
+
+ private:
+  // The location where this name was first seen.
+  source_location location_;
+  // The real named object when it is known.
+  Named_object*
+  real_named_object_;
+};
+
+// A named object named.  This is the result of a declaration.  We
+// don't use a superclass because they all have to be handled
+// differently.
+
+class Named_object
+{
+ public:
+  enum Classification
+  {
+    // An uninitialized Named_object.  We should never see this.
+    NAMED_OBJECT_UNINITIALIZED,
+    // An unknown name.  This is used for forward references.  In a
+    // correct program, these will all be resolved by the end of the
+    // parse.
+    NAMED_OBJECT_UNKNOWN,
+    // A const.
+    NAMED_OBJECT_CONST,
+    // A type.
+    NAMED_OBJECT_TYPE,
+    // A forward type declaration.
+    NAMED_OBJECT_TYPE_DECLARATION,
+    // A var.
+    NAMED_OBJECT_VAR,
+    // A result variable in a function.
+    NAMED_OBJECT_RESULT_VAR,
+    // The blank identifier--the special variable named _.
+    NAMED_OBJECT_SINK,
+    // A func.
+    NAMED_OBJECT_FUNC,
+    // A forward func declaration.
+    NAMED_OBJECT_FUNC_DECLARATION,
+    // A package.
+    NAMED_OBJECT_PACKAGE
+  };
+
+  // Return the classification.
+  Classification
+  classification() const
+  { return this->classification_; }
+
+  // Classifiers.
+
+  bool
+  is_unknown() const
+  { return this->classification_ == NAMED_OBJECT_UNKNOWN; }
+
+  bool
+  is_const() const
+  { return this->classification_ == NAMED_OBJECT_CONST; }
+
+  bool
+  is_type() const
+  { return this->classification_ == NAMED_OBJECT_TYPE; }
+
+  bool
+  is_type_declaration() const
+  { return this->classification_ == NAMED_OBJECT_TYPE_DECLARATION; }
+
+  bool
+  is_variable() const
+  { return this->classification_ == NAMED_OBJECT_VAR; }
+
+  bool
+  is_result_variable() const
+  { return this->classification_ == NAMED_OBJECT_RESULT_VAR; }
+
+  bool
+  is_sink() const
+  { return this->classification_ == NAMED_OBJECT_SINK; }
+
+  bool
+  is_function() const
+  { return this->classification_ == NAMED_OBJECT_FUNC; }
+
+  bool
+  is_function_declaration() const
+  { return this->classification_ == NAMED_OBJECT_FUNC_DECLARATION; }
+
+  bool
+  is_package() const
+  { return this->classification_ == NAMED_OBJECT_PACKAGE; }
+
+  // Creators.
+
+  static Named_object*
+  make_unknown_name(const std::string& name, source_location);
+
+  static Named_object*
+  make_constant(const Typed_identifier&, const Package*, Expression*,
+               int iota_value);
+
+  static Named_object*
+  make_type(const std::string&, const Package*, Type*, source_location);
+
+  static Named_object*
+  make_type_declaration(const std::string&, const Package*, source_location);
+
+  static Named_object*
+  make_variable(const std::string&, const Package*, Variable*);
+
+  static Named_object*
+  make_result_variable(const std::string&, Result_variable*);
+
+  static Named_object*
+  make_sink();
+
+  static Named_object*
+  make_function(const std::string&, const Package*, Function*);
+
+  static Named_object*
+  make_function_declaration(const std::string&, const Package*, Function_type*,
+                           source_location);
+
+  static Named_object*
+  make_package(const std::string& alias, Package* package);
+
+  // Getters.
+
+  Unknown_name*
+  unknown_value()
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
+    return this->u_.unknown_value;
+  }
+
+  const Unknown_name*
+  unknown_value() const
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
+    return this->u_.unknown_value;
+  }
+
+  Named_constant*
+  const_value()
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_CONST);
+    return this->u_.const_value;
+  }
+
+  const Named_constant*
+  const_value() const
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_CONST);
+    return this->u_.const_value;
+  }
+
+  Named_type*
+  type_value()
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_TYPE);
+    return this->u_.type_value;
+  }
+
+  const Named_type*
+  type_value() const
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_TYPE);
+    return this->u_.type_value;
+  }
+
+  Type_declaration*
+  type_declaration_value()
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
+    return this->u_.type_declaration;
+  }
+
+  const Type_declaration*
+  type_declaration_value() const
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
+    return this->u_.type_declaration;
+  }
+
+  Variable*
+  var_value()
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_VAR);
+    return this->u_.var_value;
+  }
+
+  const Variable*
+  var_value() const
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_VAR);
+    return this->u_.var_value;
+  }
+
+  Result_variable*
+  result_var_value()
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR);
+    return this->u_.result_var_value;
+  }
+
+  const Result_variable*
+  result_var_value() const
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR);
+    return this->u_.result_var_value;
+  }
+
+  Function*
+  func_value()
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_FUNC);
+    return this->u_.func_value;
+  }
+
+  const Function*
+  func_value() const
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_FUNC);
+    return this->u_.func_value;
+  }
+
+  Function_declaration*
+  func_declaration_value()
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
+    return this->u_.func_declaration_value;
+  }
+
+  const Function_declaration*
+  func_declaration_value() const
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
+    return this->u_.func_declaration_value;
+  }
+
+  Package*
+  package_value()
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_PACKAGE);
+    return this->u_.package_value;
+  }
+
+  const Package*
+  package_value() const
+  {
+    gcc_assert(this->classification_ == NAMED_OBJECT_PACKAGE);
+    return this->u_.package_value;
+  }
+
+  const std::string&
+  name() const
+  { return this->name_; }
+
+  // Return the name to use in an error message.  The difference is
+  // that if this Named_object is defined in a different package, this
+  // will return PACKAGE.NAME.
+  std::string
+  message_name() const;
+
+  const Package*
+  package() const
+  { return this->package_; }
+
+  // Resolve an unknown value if possible.  This returns the same
+  // Named_object or a new one.
+  Named_object*
+  resolve()
+  {
+    Named_object* ret = this;
+    if (this->is_unknown())
+      {
+       Named_object* r = this->unknown_value()->real_named_object();
+       if (r != NULL)
+         ret = r;
+      }
+    return ret;
+  }
+
+  const Named_object*
+  resolve() const
+  {
+    const Named_object* ret = this;
+    if (this->is_unknown())
+      {
+       const Named_object* r = this->unknown_value()->real_named_object();
+       if (r != NULL)
+         ret = r;
+      }
+    return ret;
+  }
+
+  // The location where this object was defined or referenced.
+  source_location
+  location() const;
+
+  // Return a tree for the external identifier for this object.
+  tree
+  get_id(Gogo*);
+
+  // Return a tree representing this object.
+  tree
+  get_tree(Gogo*, Named_object* function);
+
+  // Define a type declaration.
+  void
+  set_type_value(Named_type*);
+
+  // Define a function declaration.
+  void
+  set_function_value(Function*);
+
+  // Export this object.
+  void
+  export_named_object(Export*) const;
+
+ private:
+  Named_object(const std::string&, const Package*, Classification);
+
+  // The name of the object.
+  std::string name_;
+  // The package that this object is in.  This is NULL if it is in the
+  // file we are compiling.
+  const Package* package_;
+  // The type of object this is.
+  Classification classification_;
+  // The real data.
+  union
+  {
+    Unknown_name* unknown_value;
+    Named_constant* const_value;
+    Named_type* type_value;
+    Type_declaration* type_declaration;
+    Variable* var_value;
+    Result_variable* result_var_value;
+    Function* func_value;
+    Function_declaration* func_declaration_value;
+    Package* package_value;
+  } u_;
+  // The DECL tree for this object if we have already converted it.
+  tree tree_;
+};
+
+// A binding contour.  This binds names to objects.
+
+class Bindings
+{
+ public:
+  // Type for mapping from names to objects.
+  typedef Unordered_map(std::string, Named_object*) Contour;
+
+  Bindings(Bindings* enclosing);
+
+  // Add an unknown name.
+  Named_object*
+  add_unknown_name(const std::string& name, source_location location)
+  {
+    return this->add_named_object(Named_object::make_unknown_name(name,
+                                                                 location));
+  }
+
+  // Add a constant.
+  Named_object*
+  add_constant(const Typed_identifier& tid, const Package* package,
+              Expression* expr, int iota_value)
+  {
+    return this->add_named_object(Named_object::make_constant(tid, package,
+                                                             expr,
+                                                             iota_value));
+  }
+
+  // Add a type.
+  Named_object*
+  add_type(const std::string& name, const Package* package, Type* type,
+          source_location location)
+  {
+    return this->add_named_object(Named_object::make_type(name, package, type,
+                                                         location));
+  }
+
+  // Add a named type.  This is used for builtin types, and to add an
+  // imported type to the global scope.
+  Named_object*
+  add_named_type(Named_type* named_type);
+
+  // Add a type declaration.
+  Named_object*
+  add_type_declaration(const std::string& name, const Package* package,
+                      source_location location)
+  {
+    Named_object* no = Named_object::make_type_declaration(name, package,
+                                                          location);
+    return this->add_named_object(no);
+  }
+
+  // Add a variable.
+  Named_object*
+  add_variable(const std::string& name, const Package* package,
+              Variable* variable)
+  {
+    return this->add_named_object(Named_object::make_variable(name, package,
+                                                             variable));
+  }
+
+  // Add a result variable.
+  Named_object*
+  add_result_variable(const std::string& name, Result_variable* result)
+  {
+    return this->add_named_object(Named_object::make_result_variable(name,
+                                                                    result));
+  }
+
+  // Add a function.
+  Named_object*
+  add_function(const std::string& name, const Package*, Function* function);
+
+  // Add a function declaration.
+  Named_object*
+  add_function_declaration(const std::string& name, const Package* package,
+                          Function_type* type, source_location location);
+
+  // Add a package.  The location is the location of the import
+  // statement.
+  Named_object*
+  add_package(const std::string& alias, Package* package)
+  {
+    Named_object* no = Named_object::make_package(alias, package);
+    return this->add_named_object(no);
+  }
+
+  // Define a type which was already declared.
+  void
+  define_type(Named_object*, Named_type*);
+
+  // Add a method to the list of objects.  This is not added to the
+  // lookup table.
+  void
+  add_method(Named_object*);
+
+  // Add a named object to this binding.
+  Named_object*
+  add_named_object(Named_object* no)
+  { return this->add_named_object_to_contour(&this->bindings_, no); }
+
+  // Clear all names in file scope from the bindings.
+  void
+  clear_file_scope();
+
+  // Look up a name in this binding contour and in any enclosing
+  // binding contours.  This returns NULL if the name is not found.
+  Named_object*
+  lookup(const std::string&) const;
+
+  // Look up a name in this binding contour without looking in any
+  // enclosing binding contours.  Returns NULL if the name is not found.
+  Named_object*
+  lookup_local(const std::string&) const;
+
+  // Remove a name.
+  void
+  remove_binding(Named_object*);
+
+  // Traverse the tree.  See the Traverse class.
+  int
+  traverse(Traverse*, bool is_global);
+
+  // Iterate over definitions.  This does not include things which
+  // were only declared.
+
+  typedef std::vector<Named_object*>::const_iterator
+    const_definitions_iterator;
+
+  const_definitions_iterator
+  begin_definitions() const
+  { return this->named_objects_.begin(); }
+
+  const_definitions_iterator
+  end_definitions() const
+  { return this->named_objects_.end(); }
+
+  // Return the number of definitions.
+  size_t
+  size_definitions() const
+  { return this->named_objects_.size(); }
+
+  // Return whether there are no definitions.
+  bool
+  empty_definitions() const
+  { return this->named_objects_.empty(); }
+
+  // Iterate over declarations.  This is everything that has been
+  // declared, which includes everything which has been defined.
+
+  typedef Contour::const_iterator const_declarations_iterator;
+
+  const_declarations_iterator
+  begin_declarations() const
+  { return this->bindings_.begin(); }
+
+  const_declarations_iterator
+  end_declarations() const
+  { return this->bindings_.end(); }
+
+  // Return the number of declarations.
+  size_t
+  size_declarations() const
+  { return this->bindings_.size(); }
+
+  // Return whether there are no declarations.
+  bool
+  empty_declarations() const
+  { return this->bindings_.empty(); }
+
+  // Return the first declaration.
+  Named_object*
+  first_declaration()
+  { return this->bindings_.empty() ? NULL : this->bindings_.begin()->second; }
+
+ private:
+  Named_object*
+  add_named_object_to_contour(Contour*, Named_object*);
+
+  Named_object*
+  new_definition(Named_object*, Named_object*);
+
+  // Enclosing bindings.
+  Bindings* enclosing_;
+  // The list of objects.
+  std::vector<Named_object*> named_objects_;
+  // The mapping from names to objects.
+  Contour bindings_;
+};
+
+// A label.
+
+class Label
+{
+ public:
+  Label(const std::string& name)
+    : name_(name), location_(0), decl_(NULL)
+  { }
+
+  // Return the label's name.
+  const std::string&
+  name() const
+  { return this->name_; }
+
+  // Return whether the label has been defined.
+  bool
+  is_defined() const
+  { return this->location_ != 0; }
+
+  // Return the location of the definition.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Define the label at LOCATION.
+  void
+  define(source_location location)
+  {
+    gcc_assert(this->location_ == 0);
+    this->location_ = location;
+  }
+
+  // Return the LABEL_DECL for this decl.
+  tree
+  get_decl();
+
+  // Return an expression for the address of this label.
+  tree
+  get_addr(source_location location);
+
+ private:
+  // The name of the label.
+  std::string name_;
+  // The location of the definition.  This is 0 if the label has not
+  // yet been defined.
+  source_location location_;
+  // The LABEL_DECL.
+  tree decl_;
+};
+
+// An unnamed label.  These are used when lowering loops.
+
+class Unnamed_label
+{
+ public:
+  Unnamed_label(source_location location)
+    : location_(location), decl_(NULL)
+  { }
+
+  // Get the location where the label is defined.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Set the location where the label is defined.
+  void
+  set_location(source_location location)
+  { this->location_ = location; }
+
+  // Return a statement which defines this label.
+  tree
+  get_definition();
+
+  // Return a goto to this label from LOCATION.
+  tree
+  get_goto(source_location location);
+
+ private:
+  // Return the LABEL_DECL to use with GOTO_EXPR.
+  tree
+  get_decl();
+
+  // The location where the label is defined.
+  source_location location_;
+  // The LABEL_DECL.
+  tree decl_;
+};
+
+// An imported package.
+
+class Package
+{
+ public:
+  Package(const std::string& name, const std::string& unique_prefix,
+         source_location location);
+
+  // The real name of this package.  This may be different from the
+  // name in the associated Named_object if the import statement used
+  // an alias.
+  const std::string&
+  name() const
+  { return this->name_; }
+
+  // Return the location of the import statement.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Get the unique prefix used for all symbols exported from this
+  // package.
+  const std::string&
+  unique_prefix() const
+  {
+    gcc_assert(!this->unique_prefix_.empty());
+    return this->unique_prefix_;
+  }
+
+  // The priority of this package.  The init function of packages with
+  // lower priority must be run before the init function of packages
+  // with higher priority.
+  int
+  priority() const
+  { return this->priority_; }
+
+  // Set the priority.
+  void
+  set_priority(int priority);
+
+  // Return the bindings.
+  Bindings*
+  bindings()
+  { return this->bindings_; }
+
+  // Whether some symbol from the package was used.
+  bool
+  used() const
+  { return this->used_; }
+
+  // Note that some symbol from this package was used.
+  void
+  set_used() const
+  { this->used_ = true; }
+
+  // Clear the used field for the next file.
+  void
+  clear_used()
+  { this->used_ = false; }
+
+  // Whether this package was imported in the current file.
+  bool
+  is_imported() const
+  { return this->is_imported_; }
+
+  // Note that this package was imported in the current file.
+  void
+  set_is_imported()
+  { this->is_imported_ = true; }
+
+  // Clear the imported field for the next file.
+  void
+  clear_is_imported()
+  { this->is_imported_ = false; }
+
+  // Whether this package was imported with a name of "_".
+  bool
+  uses_sink_alias() const
+  { return this->uses_sink_alias_; }
+
+  // Note that this package was imported with a name of "_".
+  void
+  set_uses_sink_alias()
+  { this->uses_sink_alias_ = true; }
+
+  // Clear the sink alias field for the next file.
+  void
+  clear_uses_sink_alias()
+  { this->uses_sink_alias_ = false; }
+
+  // Look up a name in the package.  Returns NULL if the name is not
+  // found.
+  Named_object*
+  lookup(const std::string& name) const
+  { return this->bindings_->lookup(name); }
+
+  // Set the location of the package.  This is used if it is seen in a
+  // different import before it is really imported.
+  void
+  set_location(source_location location)
+  { this->location_ = location; }
+
+  // Add a constant to the package.
+  Named_object*
+  add_constant(const Typed_identifier& tid, Expression* expr)
+  { return this->bindings_->add_constant(tid, this, expr, 0); }
+
+  // Add a type to the package.
+  Named_object*
+  add_type(const std::string& name, Type* type, source_location location)
+  { return this->bindings_->add_type(name, this, type, location); }
+
+  // Add a type declaration to the package.
+  Named_object*
+  add_type_declaration(const std::string& name, source_location location)
+  { return this->bindings_->add_type_declaration(name, this, location); }
+
+  // Add a variable to the package.
+  Named_object*
+  add_variable(const std::string& name, Variable* variable)
+  { return this->bindings_->add_variable(name, this, variable); }
+
+  // Add a function declaration to the package.
+  Named_object*
+  add_function_declaration(const std::string& name, Function_type* type,
+                          source_location loc)
+  { return this->bindings_->add_function_declaration(name, this, type, loc); }
+
+  // Determine types of constants.
+  void
+  determine_types();
+
+ private:
+  // The real name of this package.
+  std::string name_;
+  // The unique prefix for all exported global symbols.
+  std::string unique_prefix_;
+  // The names in this package.
+  Bindings* bindings_;
+  // The priority of this package.  A package has a priority higher
+  // than the priority of all of the packages that it imports.  This
+  // is used to run init functions in the right order.
+  int priority_;
+  // The location of the import statement.
+  source_location location_;
+  // True if some name from this package was used.  This is mutable
+  // because we can use a package even if we have a const pointer to
+  // it.
+  mutable bool used_;
+  // True if this package was imported in the current file.
+  bool is_imported_;
+  // True if this package was imported with a name of "_".
+  bool uses_sink_alias_;
+};
+
+// Return codes for the traversal functions.  This is not an enum
+// because we want to be able to declare traversal functions in other
+// header files without including this one.
+
+// Continue traversal as usual.
+const int TRAVERSE_CONTINUE = -1;
+
+// Exit traversal.
+const int TRAVERSE_EXIT = 0;
+
+// Continue traversal, but skip components of the current object.
+// E.g., if this is returned by Traverse::statement, we do not
+// traverse the expressions in the statement even if
+// traverse_expressions is set in the traverse_mask.
+const int TRAVERSE_SKIP_COMPONENTS = 1;
+
+// This class is used when traversing the parse tree.  The caller uses
+// a subclass which overrides functions as desired.
+
+class Traverse
+{
+ public:
+  // These bitmasks say what to traverse.
+  static const unsigned int traverse_variables =    0x1;
+  static const unsigned int traverse_constants =    0x2;
+  static const unsigned int traverse_functions =    0x4;
+  static const unsigned int traverse_blocks =       0x8;
+  static const unsigned int traverse_statements =  0x10;
+  static const unsigned int traverse_expressions = 0x20;
+  static const unsigned int traverse_types =       0x40;
+
+  Traverse(unsigned int traverse_mask)
+    : traverse_mask_(traverse_mask), types_seen_(NULL), expressions_seen_(NULL)
+  { }
+
+  virtual ~Traverse();
+
+  // The bitmask of what to traverse.
+  unsigned int
+  traverse_mask() const
+  { return this->traverse_mask_; }
+
+  // Record that we are going to traverse a type.  This returns true
+  // if the type has already been seen in this traversal.  This is
+  // required because types, unlike expressions, can form a circular
+  // graph.
+  bool
+  remember_type(const Type*);
+
+  // Record that we are going to see an expression.  This returns true
+  // if the expression has already been seen in this traversal.  This
+  // is only needed for cases where multiple expressions can point to
+  // a single one.
+  bool
+  remember_expression(const Expression*);
+
+  // These functions return one of the TRAVERSE codes defined above.
+
+  // If traverse_variables is set in the mask, this is called for
+  // every variable in the tree.
+  virtual int
+  variable(Named_object*);
+
+  // If traverse_constants is set in the mask, this is called for
+  // every named constant in the tree.  The bool parameter is true for
+  // a global constant.
+  virtual int
+  constant(Named_object*, bool);
+
+  // If traverse_functions is set in the mask, this is called for
+  // every function in the tree.
+  virtual int
+  function(Named_object*);
+
+  // If traverse_blocks is set in the mask, this is called for every
+  // block in the tree.
+  virtual int
+  block(Block*);
+
+  // If traverse_statements is set in the mask, this is called for
+  // every statement in the tree.
+  virtual int
+  statement(Block*, size_t* index, Statement*);
+
+  // If traverse_expressions is set in the mask, this is called for
+  // every expression in the tree.
+  virtual int
+  expression(Expression**);
+
+  // If traverse_types is set in the mask, this is called for every
+  // type in the tree.
+  virtual int
+  type(Type*);
+
+ private:
+  typedef Unordered_set_hash(const Type*, Type_hash_identical,
+                            Type_identical) Types_seen;
+
+  typedef Unordered_set(const Expression*) Expressions_seen;
+
+  // Bitmask of what sort of objects to traverse.
+  unsigned int traverse_mask_;
+  // Types which have been seen in this traversal.
+  Types_seen* types_seen_;
+  // Expressions which have been seen in this traversal.
+  Expressions_seen* expressions_seen_;
+};
+
+// When translating the gogo IR into trees, this is the context we
+// pass down the blocks and statements.
+
+class Translate_context
+{
+ public:
+  Translate_context(Gogo* gogo, Named_object* function, Block* block,
+                   tree block_tree)
+    : gogo_(gogo), function_(function), block_(block), block_tree_(block_tree),
+      is_const_(false)
+  { }
+
+  // Accessors.
+
+  Gogo*
+  gogo()
+  { return this->gogo_; }
+
+  Named_object*
+  function()
+  { return this->function_; }
+
+  Block*
+  block()
+  { return this->block_; }
+
+  tree
+  block_tree()
+  { return this->block_tree_; }
+
+  bool
+  is_const()
+  { return this->is_const_; }
+
+  // Make a constant context.
+  void
+  set_is_const()
+  { this->is_const_ = true; }
+
+ private:
+  // The IR for the entire compilation unit.
+  Gogo* gogo_;
+  // The function we are currently translating.
+  Named_object* function_;
+  // The block we are currently translating.
+  Block *block_;
+  // The BLOCK node for the current block.
+  tree block_tree_;
+  // Whether this is being evaluated in a constant context.  This is
+  // used for type descriptor initializers.
+  bool is_const_;
+};
+
+// Runtime error codes.  These must match the values in
+// libgo/runtime/go-runtime-error.c.
+
+// Slice index out of bounds: negative or larger than the length of
+// the slice.
+static const int RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS = 0;
+
+// Array index out of bounds.
+static const int RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS = 1;
+
+// String index out of bounds.
+static const int RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS = 2;
+
+// Slice slice out of bounds: negative or larger than the length of
+// the slice or high bound less than low bound.
+static const int RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS = 3;
+
+// Array slice out of bounds.
+static const int RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS = 4;
+
+// String slice out of bounds.
+static const int RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS = 5;
+
+// Dereference of nil pointer.  This is used when there is a
+// dereference of a pointer to a very large struct or array, to ensure
+// that a gigantic array is not used a proxy to access random memory
+// locations.
+static const int RUNTIME_ERROR_NIL_DEREFERENCE = 6;
+
+// Slice length or capacity out of bounds in make: negative or
+// overflow or length greater than capacity.
+static const int RUNTIME_ERROR_MAKE_SLICE_OUT_OF_BOUNDS = 7;
+
+// Map capacity out of bounds in make: negative or overflow.
+static const int RUNTIME_ERROR_MAKE_MAP_OUT_OF_BOUNDS = 8;
+
+// Channel capacity out of bounds in make: negative or overflow.
+static const int RUNTIME_ERROR_MAKE_CHAN_OUT_OF_BOUNDS = 9;
+
+// This is used by some of the langhooks.
+extern Gogo* go_get_gogo();
+
+// Whether we have seen any errors.  FIXME: Replace with a backend
+// interface.
+extern bool saw_errors();
+
+#endif // !defined(GO_GOGO_H)
diff --git a/gcc/go/gofrontend/import-archive.cc b/gcc/go/gofrontend/import-archive.cc
new file mode 100644 (file)
index 0000000..4356d82
--- /dev/null
@@ -0,0 +1,661 @@
+// import-archive.cc -- Go frontend read import data from an archive file.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "import.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+// Archive magic numbers.
+
+static const char armag[] =
+{
+  '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
+};
+
+static const char armagt[] =
+{
+  '!', '<', 't', 'h', 'i', 'n', '>', '\n'
+};
+
+static const char arfmag[2] = { '`', '\n' };
+
+// The header of an entry in an archive.  This is all readable text,
+// padded with spaces where necesary.
+
+struct Archive_header
+{
+  // The entry name.
+  char ar_name[16];
+  // The file modification time.
+  char ar_date[12];
+  // The user's UID in decimal.
+  char ar_uid[6];
+  // The user's GID in decimal.
+  char ar_gid[6];
+  // The file mode in octal.
+  char ar_mode[8];
+  // The file size in decimal.
+  char ar_size[10];
+  // The final magic code.
+  char ar_fmag[2];
+};
+
+// The functions in this file extract Go export data from an archive.
+
+const int Import::archive_magic_len;
+
+// Return true if BYTES, which are from the start of the file, are an
+// archive magic number.
+
+bool
+Import::is_archive_magic(const char* bytes)
+{
+  return (memcmp(bytes, armag, Import::archive_magic_len) == 0
+         || memcmp(bytes, armagt, Import::archive_magic_len) == 0);
+}
+
+// An object used to read an archive file.
+
+class Archive_file
+{
+ public:
+  Archive_file(const std::string& filename, int fd, source_location location)
+    : filename_(filename), fd_(fd), filesize_(-1), extended_names_(),
+      is_thin_archive_(false), location_(location), nested_archives_()
+  { }
+
+  // Initialize.
+  bool
+  initialize();
+
+  // Return the file name.
+  const std::string&
+  filename() const
+  { return this->filename_; }
+
+  // Get the file size.
+  off_t
+  filesize() const
+  { return this->filesize_; }
+
+  // Return whether this is a thin archive.
+  bool
+  is_thin_archive() const
+  { return this->is_thin_archive_; }
+
+  // Return the location of the import statement.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Read bytes.
+  bool
+  read(off_t offset, off_t size, char*);
+
+  // Read the archive header at OFF, setting *PNAME, *SIZE, and
+  // *NESTED_OFF.
+  bool
+  read_header(off_t off, std::string* pname, off_t* size, off_t* nested_off);
+
+  // Interpret the header of HDR, the header of the archive member at
+  // file offset OFF.  Return whether it succeeded.  Set *SIZE to the
+  // size of the member.  Set *PNAME to the name of the member.  Set
+  // *NESTED_OFF to the offset in a nested archive.
+  bool
+  interpret_header(const Archive_header* hdr, off_t off,
+                  std::string* pname, off_t* size, off_t* nested_off) const;
+
+  // Get the file and offset for an archive member.
+  bool
+  get_file_and_offset(off_t off, const std::string& hdrname,
+                     off_t nested_off, int* memfd, off_t* memoff,
+                     std::string* memname);
+
+ private:
+  // For keeping track of open nested archives in a thin archive file.
+  typedef std::map<std::string, Archive_file*> Nested_archive_table;
+
+  // The name of the file.
+  std::string filename_;
+  // The file descriptor.
+  int fd_;
+  // The file size;
+  off_t filesize_;
+  // The extended name table.
+  std::string extended_names_;
+  // Whether this is a thin archive.
+  bool is_thin_archive_;
+  // The location of the import statements.
+  source_location location_;
+  // Table of nested archives.
+  Nested_archive_table nested_archives_;
+};
+
+bool
+Archive_file::initialize()
+{
+  struct stat st;
+  if (fstat(this->fd_, &st) < 0)
+    {
+      error_at(this->location_, "%s: %m", this->filename_.c_str());
+      return false;
+    }
+  this->filesize_ = st.st_size;
+
+  char buf[sizeof(armagt)];
+  if (::lseek(this->fd_, 0, SEEK_SET) < 0
+      || ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt))
+    {
+      error_at(this->location_, "%s: %m", this->filename_.c_str());
+      return false;
+    }
+  this->is_thin_archive_ = memcmp(buf, armagt, sizeof(armagt)) == 0;
+
+  if (this->filesize_ == sizeof(armag))
+    {
+      // Empty archive.
+      return true;
+    }
+
+  // Look for the extended name table.
+  std::string filename;
+  off_t size;
+  if (!this->read_header(sizeof(armagt), &filename, &size, NULL))
+    return false;
+  if (filename.empty())
+    {
+      // We found the symbol table.
+      off_t off = sizeof(armagt) + sizeof(Archive_header) + size;
+      if ((off & 1) != 0)
+       ++off;
+      if (!this->read_header(off, &filename, &size, NULL))
+       filename.clear();
+    }
+  if (filename == "/")
+    {
+      char* buf = new char[size];
+      if (::read(this->fd_, buf, size) != size)
+       {
+         error_at(this->location_, "%s: could not read extended names",
+                  filename.c_str());
+         delete buf;
+         return false;
+       }
+      this->extended_names_.assign(buf, size);
+      delete buf;
+    }
+
+  return true;
+}
+
+// Read bytes from the file.
+
+bool
+Archive_file::read(off_t offset, off_t size, char* buf)
+{
+  if (::lseek(this->fd_, offset, SEEK_SET) < 0
+      || ::read(this->fd_, buf, size) != size)
+    {
+      error_at(this->location_, "%s: %m", this->filename_.c_str());
+      return false;
+    }
+  return true;
+}
+
+// Read the header at OFF.  Set *PNAME to the name, *SIZE to the size,
+// and *NESTED_OFF to the nested offset.
+
+bool
+Archive_file::read_header(off_t off, std::string* pname, off_t* size,
+                         off_t* nested_off)
+{
+  Archive_header hdr;
+  if (::lseek(this->fd_, off, SEEK_SET) < 0)
+    {
+      error_at(this->location_, "%s: %m", this->filename_.c_str());
+      return false;
+    }
+  ssize_t got = ::read(this->fd_, &hdr, sizeof hdr);
+  if (got != sizeof hdr)
+    {
+      if (got < 0)
+       error_at(this->location_, "%s: %m", this->filename_.c_str());
+      else if (got > 0)
+       error_at(this->location_, "%s: short archive header at %ld",
+                this->filename_.c_str(), static_cast<long>(off));
+      else
+       error_at(this->location_, "%s: unexpected EOF at %ld",
+                this->filename_.c_str(), static_cast<long>(off));
+    }
+  off_t local_nested_off;
+  if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off))
+    return false;
+  if (nested_off != NULL)
+    *nested_off = local_nested_off;
+  return true;
+}
+
+// Interpret the header of HDR, the header of the archive member at
+// file offset OFF.
+
+bool
+Archive_file::interpret_header(const Archive_header* hdr, off_t off,
+                              std::string* pname, off_t* size,
+                              off_t* nested_off) const
+{
+  if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
+    {
+      error_at(this->location_, "%s: malformed archive header at %lu",
+              this->filename_.c_str(), static_cast<unsigned long>(off));
+      return false;
+    }
+
+  const int size_string_size = sizeof hdr->ar_size;
+  char size_string[size_string_size + 1];
+  memcpy(size_string, hdr->ar_size, size_string_size);
+  char* ps = size_string + size_string_size;
+  while (ps[-1] == ' ')
+    --ps;
+  *ps = '\0';
+
+  errno = 0;
+  char* end;
+  *size = strtol(size_string, &end, 10);
+  if (*end != '\0'
+      || *size < 0
+      || (*size == LONG_MAX && errno == ERANGE))
+    {
+      error_at(this->location_, "%s: malformed archive header size at %lu",
+              this->filename_.c_str(), static_cast<unsigned long>(off));
+      return false;
+    }
+
+  if (hdr->ar_name[0] != '/')
+    {
+      const char* name_end = strchr(hdr->ar_name, '/');
+      if (name_end == NULL
+         || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
+       {
+         error_at(this->location_, "%s: malformed archive header name at %lu",
+                  this->filename_.c_str(), static_cast<unsigned long>(off));
+         return false;
+       }
+      pname->assign(hdr->ar_name, name_end - hdr->ar_name);
+      *nested_off = 0;
+    }
+  else if (hdr->ar_name[1] == ' ')
+    {
+      // This is the symbol table.
+      pname->clear();
+    }
+  else if (hdr->ar_name[1] == '/')
+    {
+      // This is the extended name table.
+      pname->assign(1, '/');
+    }
+  else
+    {
+      errno = 0;
+      long x = strtol(hdr->ar_name + 1, &end, 10);
+      long y = 0;
+      if (*end == ':')
+        y = strtol(end + 1, &end, 10);
+      if (*end != ' '
+         || x < 0
+         || (x == LONG_MAX && errno == ERANGE)
+         || static_cast<size_t>(x) >= this->extended_names_.size())
+       {
+         error_at(this->location_, "%s: bad extended name index at %lu",
+                  this->filename_.c_str(), static_cast<unsigned long>(off));
+         return false;
+       }
+
+      const char* name = this->extended_names_.data() + x;
+      const char* name_end = strchr(name, '\n');
+      if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
+         || name_end[-1] != '/')
+       {
+         error_at(this->location_, "%s: bad extended name entry at header %lu",
+                  this->filename_.c_str(), static_cast<unsigned long>(off));
+         return false;
+       }
+      pname->assign(name, name_end - 1 - name);
+      if (nested_off != NULL)
+        *nested_off = y;
+    }
+
+  return true;
+}
+
+// Get the file and offset for an archive member.
+
+bool
+Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
+                                 off_t nested_off, int* memfd, off_t* memoff,
+                                 std::string* memname)
+{
+  if (!this->is_thin_archive_)
+    {
+      *memfd = this->fd_;
+      *memoff = off + sizeof(Archive_header);
+      *memname = this->filename_ + '(' + hdrname + ')';
+      return true;
+    }
+
+  std::string filename = hdrname;
+  if (!IS_ABSOLUTE_PATH(filename.c_str()))
+    {
+      const char* archive_path = this->filename_.c_str();
+      const char* basename = lbasename(archive_path);
+      if (basename > archive_path)
+       filename.replace(0, 0,
+                        this->filename_.substr(0, basename - archive_path));
+    }
+
+  if (nested_off > 0)
+    {
+      // This is a member of a nested archive.
+      Archive_file* nfile;
+      Nested_archive_table::const_iterator p =
+       this->nested_archives_.find(filename);
+      if (p != this->nested_archives_.end())
+       nfile = p->second;
+      else
+       {
+         int nfd = open(filename.c_str(), O_RDONLY | O_BINARY);
+         if (nfd < 0)
+           {
+             error_at(this->location_, "%s: can't open nested archive %s",
+                      this->filename_.c_str(), filename.c_str());
+             return false;
+           }
+         nfile = new Archive_file(filename, nfd, this->location_);
+         if (!nfile->initialize())
+           {
+             delete nfile;
+             return false;
+           }
+         this->nested_archives_[filename] = nfile;
+       }
+
+      std::string nname;
+      off_t nsize;
+      off_t nnested_off;
+      if (!nfile->read_header(nested_off, &nname, &nsize, &nnested_off))
+       return false;
+      return nfile->get_file_and_offset(nested_off, nname, nnested_off,
+                                       memfd, memoff, memname);
+    }
+
+  // An external member of a thin archive.
+  *memfd = open(filename.c_str(), O_RDONLY | O_BINARY);
+  if (*memfd < 0)
+    {
+      error_at(this->location_, "%s: %m", filename.c_str());
+      return false;
+    }
+  *memoff = 0;
+  *memname = filename;
+  return true;
+}
+
+// An archive member iterator.  This is more-or-less copied from gold.
+
+class Archive_iterator
+{
+ public:
+  // The header of an archive member.  This is what this iterator
+  // points to.
+  struct Header
+  {
+    // The name of the member.
+    std::string name;
+    // The file offset of the member.
+    off_t off;
+    // The file offset of a nested archive member.
+    off_t nested_off;
+    // The size of the member.
+    off_t size;
+  };
+
+  Archive_iterator(Archive_file* afile, off_t off)
+    : afile_(afile), off_(off)
+  { this->read_next_header(); }
+
+  const Header&
+  operator*() const
+  { return this->header_; }
+
+  const Header*
+  operator->() const
+  { return &this->header_; }
+
+  Archive_iterator&
+  operator++()
+  {
+    if (this->off_ == this->afile_->filesize())
+      return *this;
+    this->off_ += sizeof(Archive_header);
+    if (!this->afile_->is_thin_archive())
+      this->off_ += this->header_.size;
+    if ((this->off_ & 1) != 0)
+      ++this->off_;
+    this->read_next_header();
+    return *this;
+  }
+
+  Archive_iterator
+  operator++(int)
+  {
+    Archive_iterator ret = *this;
+    ++*this;
+    return ret;
+  }
+
+  bool
+  operator==(const Archive_iterator p) const
+  { return this->off_ == p->off; }
+
+  bool
+  operator!=(const Archive_iterator p) const
+  { return this->off_ != p->off; }
+
+ private:
+  void
+  read_next_header();
+
+  // The underlying archive file.
+  Archive_file* afile_;
+  // The current offset in the file.
+  off_t off_;
+  // The current archive header.
+  Header header_;
+};
+
+// Read the next archive header.
+
+void
+Archive_iterator::read_next_header()
+{
+  off_t filesize = this->afile_->filesize();
+  while (true)
+    {
+      if (filesize - this->off_ < static_cast<off_t>(sizeof(Archive_header)))
+       {
+         if (filesize != this->off_)
+           {
+             error_at(this->afile_->location(),
+                      "%s: short archive header at %lu",
+                      this->afile_->filename().c_str(),
+                      static_cast<unsigned long>(this->off_));
+             this->off_ = filesize;
+           }
+         this->header_.off = filesize;
+         return;
+       }
+
+      char buf[sizeof(Archive_header)];
+      if (!this->afile_->read(this->off_, sizeof(Archive_header), buf))
+       {
+         this->header_.off = filesize;
+         return;
+       }
+
+      const Archive_header* hdr = reinterpret_cast<const Archive_header*>(buf);
+      if (!this->afile_->interpret_header(hdr, this->off_, &this->header_.name,
+                                         &this->header_.size,
+                                         &this->header_.nested_off))
+       {
+         this->header_.off = filesize;
+         return;
+       }
+      this->header_.off = this->off_;
+
+      // Skip special members.
+      if (!this->header_.name.empty() && this->header_.name != "/")
+       return;
+
+      this->off_ += sizeof(Archive_header) + this->header_.size;
+      if ((this->off_ & 1) != 0)
+       ++this->off_;
+    }
+}
+
+// Initial iterator.
+
+Archive_iterator
+archive_begin(Archive_file* afile)
+{
+  return Archive_iterator(afile, sizeof(armag));
+}
+
+// Final iterator.
+
+Archive_iterator
+archive_end(Archive_file* afile)
+{
+  return Archive_iterator(afile, afile->filesize());
+}
+
+// A type of Import_stream which concatenates other Import_streams
+// together.
+
+class Stream_concatenate : public Import::Stream
+{
+ public:
+  Stream_concatenate()
+    : inputs_()
+  { }
+
+  // Add a new stream.
+  void
+  add(Import::Stream* is)
+  { this->inputs_.push_back(is); }
+
+ protected:
+  bool
+  do_peek(size_t, const char**);
+
+  void
+  do_advance(size_t);
+
+ private:
+  std::list<Import::Stream*> inputs_;
+};
+
+// Peek ahead.
+
+bool
+Stream_concatenate::do_peek(size_t length, const char** bytes)
+{
+  while (true)
+    {
+      if (this->inputs_.empty())
+       return false;
+      if (this->inputs_.front()->peek(length, bytes))
+       return true;
+      delete this->inputs_.front();
+      this->inputs_.pop_front();
+    }
+}
+
+// Advance.
+
+void
+Stream_concatenate::do_advance(size_t skip)
+{
+  while (true)
+    {
+      if (this->inputs_.empty())
+       return;
+      if (!this->inputs_.front()->at_eof())
+       {
+         // We just assume that this will do the right thing.  It
+         // should be OK since we should never want to skip past
+         // multiple streams.
+         this->inputs_.front()->advance(skip);
+         return;
+       }
+      delete this->inputs_.front();
+      this->inputs_.pop_front();
+    }
+}
+
+// Import data from an archive.  We walk through the archive and
+// import data from each member.
+
+Import::Stream*
+Import::find_archive_export_data(const std::string& filename, int fd,
+                                source_location location)
+{
+  Archive_file afile(filename, fd, location);
+  if (!afile.initialize())
+    return NULL;
+
+  Stream_concatenate* ret = new Stream_concatenate;
+
+  bool any_data = false;
+  bool any_members = false;
+  Archive_iterator pend = archive_end(&afile);
+  for (Archive_iterator p = archive_begin(&afile); p != pend; p++)
+    {
+      any_members = true;
+      int member_fd;
+      off_t member_off;
+      std::string member_name;
+      if (!afile.get_file_and_offset(p->off, p->name, p->nested_off,
+                                    &member_fd, &member_off, &member_name))
+       return NULL;
+
+      Import::Stream* is = Import::find_object_export_data(member_name,
+                                                          member_fd,
+                                                          member_off,
+                                                          location);
+      if (is != NULL)
+       {
+         ret->add(is);
+         any_data = true;
+       }
+    }
+
+  if (!any_members)
+    {
+      // It's normal to have an empty archive file when using gobuild.
+      return new Stream_from_string("");
+    }
+
+  if (!any_data)
+    {
+      delete ret;
+      return NULL;
+    }
+
+  return ret;
+}
diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc
new file mode 100644 (file)
index 0000000..0f0da89
--- /dev/null
@@ -0,0 +1,892 @@
+// import.cc -- Go frontend import declarations.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "filenames.h"
+#include "simple-object.h"
+
+#include "go-c.h"
+#include "gogo.h"
+#include "types.h"
+#include "export.h"
+#include "import.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+// The list of paths we search for import files.
+
+static std::vector<std::string> search_path;
+
+// Add a directory to the search path.  This is called from the option
+// handling language hook.
+
+GO_EXTERN_C
+void
+go_add_search_path(const char* path)
+{
+  search_path.push_back(std::string(path));
+}
+
+// The name used for parameters, receivers, and results in imported
+// function types.
+
+const char* const Import::import_marker = "*imported*";
+
+// Find import data.  This searches the file system for FILENAME and
+// returns a pointer to a Stream object to read the data that it
+// exports.  If the file is not found, it returns NULL.
+
+// When FILENAME is not an absolute path, we use the search path
+// provided by -I and -L options.
+
+// When FILENAME does not exist, we try modifying FILENAME to find the
+// file.  We use the first of these which exists:
+//   * We append ".gox".
+//   * We turn the base of FILENAME into libFILENAME.so.
+//   * We turn the base of FILENAME into libFILENAME.a.
+//   * We append ".o".
+
+// When using a search path, we apply each of these transformations at
+// each entry on the search path before moving on to the next entry.
+// If the file exists, but does not contain any Go export data, we
+// stop; we do not keep looking for another file with the same name
+// later in the search path.
+
+Import::Stream*
+Import::open_package(const std::string& filename, source_location location)
+{
+  if (!IS_ABSOLUTE_PATH(filename))
+    {
+      for (std::vector<std::string>::const_iterator p = search_path.begin();
+          p != search_path.end();
+          ++p)
+       {
+         std::string indir = *p;
+         if (!indir.empty() && indir[indir.size() - 1] != '/')
+           indir += '/';
+         indir += filename;
+         Stream* s = Import::try_package_in_directory(indir, location);
+         if (s != NULL)
+           return s;
+       }
+    }
+
+  Stream* s = Import::try_package_in_directory(filename, location);
+  if (s != NULL)
+    return s;
+
+  return NULL;
+}
+
+// Try to find the export data for FILENAME.
+
+Import::Stream*
+Import::try_package_in_directory(const std::string& filename,
+                                source_location location)
+{
+  std::string found_filename = filename;
+  int fd = open(found_filename.c_str(), O_RDONLY | O_BINARY);
+
+  if (fd >= 0)
+    {
+      struct stat s;
+      if (fstat(fd, &s) >= 0 && S_ISDIR(s.st_mode))
+       {
+         close(fd);
+         fd = -1;
+         errno = EISDIR;
+       }
+    }
+
+  if (fd < 0)
+    {
+      if (errno != ENOENT && errno != EISDIR)
+       warning_at(location, 0, "%s: %m", filename.c_str());
+
+      fd = Import::try_suffixes(&found_filename);
+      if (fd < 0)
+       return NULL;
+    }
+
+  // The export data may not be in this file.
+  Stream* s = Import::find_export_data(found_filename, fd, location);
+  if (s != NULL)
+    return s;
+
+  close(fd);
+
+  error_at(location, "%s exists but does not contain any Go export data",
+          found_filename.c_str());
+
+  return NULL;
+}
+
+// Given import "*PFILENAME", where *PFILENAME does not exist, try
+// various suffixes.  If we find one, set *PFILENAME to the one we
+// found.  Return the open file descriptor.
+
+int
+Import::try_suffixes(std::string* pfilename)
+{
+  std::string filename = *pfilename + ".gox";
+  int fd = open(filename.c_str(), O_RDONLY | O_BINARY);
+  if (fd >= 0)
+    {
+      *pfilename = filename;
+      return fd;
+    }
+
+  const char* basename = lbasename(pfilename->c_str());
+  size_t basename_pos = basename - pfilename->c_str();
+  filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".so";
+  fd = open(filename.c_str(), O_RDONLY | O_BINARY);
+  if (fd >= 0)
+    {
+      *pfilename = filename;
+      return fd;
+    }
+
+  filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".a";
+  fd = open(filename.c_str(), O_RDONLY | O_BINARY);
+  if (fd >= 0)
+    {
+      *pfilename = filename;
+      return fd;
+    }
+
+  filename = *pfilename + ".o";
+  fd = open(filename.c_str(), O_RDONLY | O_BINARY);
+  if (fd >= 0)
+    {
+      *pfilename = filename;
+      return fd;
+    }
+
+  return -1;
+}
+
+// Look for export data in the file descriptor FD.
+
+Import::Stream*
+Import::find_export_data(const std::string& filename, int fd,
+                        source_location location)
+{
+  // See if we can read this as an object file.
+  Import::Stream* stream = Import::find_object_export_data(filename, fd, 0,
+                                                          location);
+  if (stream != NULL)
+    return stream;
+
+  const int len = MAX(Export::v1_magic_len, Import::archive_magic_len);
+
+  if (lseek(fd, 0, SEEK_SET) < 0)
+    {
+      error_at(location, "lseek %s failed: %m", filename.c_str());
+      return NULL;
+    }
+
+  char buf[len];
+  ssize_t c = read(fd, buf, len);
+  if (c < len)
+    return NULL;
+
+  // Check for a file containing nothing but Go export data.
+  if (memcmp(buf, Export::v1_magic, Export::v1_magic_len) == 0)
+    return new Stream_from_file(fd);
+
+  // See if we can read this as an archive.
+  if (Import::is_archive_magic(buf))
+    return Import::find_archive_export_data(filename, fd, location);
+
+  return NULL;
+}
+
+// Look for export data in a simple_object.
+
+Import::Stream*
+Import::find_object_export_data(const std::string& filename,
+                               int fd,
+                               off_t offset,
+                               source_location location)
+{
+  const char* errmsg;
+  int err;
+  simple_object_read* sobj = simple_object_start_read(fd, offset,
+                                                     "__GNU_GO",
+                                                     &errmsg, &err);
+  if (sobj == NULL)
+    return NULL;
+
+  off_t sec_offset;
+  off_t sec_length;
+  int found = simple_object_find_section(sobj, ".go_export", &sec_offset,
+                                        &sec_length, &errmsg, &err);
+
+  simple_object_release_read(sobj);
+
+  if (!found)
+    return NULL;
+
+  if (lseek(fd, offset + sec_offset, SEEK_SET) < 0)
+    {
+      error_at(location, "lseek %s failed: %m", filename.c_str());
+      return NULL;
+    }
+
+  char* buf = new char[sec_length];
+  ssize_t c = read(fd, buf, sec_length);
+  if (c < 0)
+    {
+      error_at(location, "read %s failed: %m", filename.c_str());
+      return NULL;
+    }
+  if (c < sec_length)
+    {
+      error_at(location, "%s: short read", filename.c_str());
+      return NULL;
+    }
+
+  return new Stream_from_buffer(buf, sec_length);
+}
+
+// Class Import.
+
+// Construct an Import object.  We make the builtin_types_ vector
+// large enough to hold all the builtin types.
+
+Import::Import(Stream* stream, source_location location)
+  : gogo_(NULL), stream_(stream), location_(location), package_(NULL),
+    add_to_globals_(false),
+    builtin_types_((- SMALLEST_BUILTIN_CODE) + 1),
+    types_()
+{
+}
+
+// Import the data in the associated stream.
+
+Package*
+Import::import(Gogo* gogo, const std::string& local_name,
+              bool is_local_name_exported)
+{
+  // Hold on to the Gogo structure.  Otherwise we need to pass it
+  // through all the import functions, because we need it when reading
+  // a type.
+  this->gogo_ = gogo;
+
+  // A stream of export data can include data from more than one input
+  // file.  Here we loop over each input file.
+  Stream* stream = this->stream_;
+  while (!stream->at_eof() && !stream->saw_error())
+    {
+      // The vector of types is package specific.
+      this->types_.clear();
+
+      stream->require_bytes(this->location_, Export::v1_magic,
+                           Export::v1_magic_len);
+
+      this->require_c_string("package ");
+      std::string package_name = this->read_identifier();
+      this->require_c_string(";\n");
+
+      this->require_c_string("prefix ");
+      std::string unique_prefix = this->read_identifier();
+      this->require_c_string(";\n");
+
+      this->package_ = gogo->add_imported_package(package_name, local_name,
+                                                 is_local_name_exported,
+                                                 unique_prefix,
+                                                 this->location_,
+                                                 &this->add_to_globals_);
+      if (this->package_ == NULL)
+       {
+         stream->set_saw_error();
+         return NULL;
+       }
+
+      this->require_c_string("priority ");
+      std::string priority_string = this->read_identifier();
+      int prio;
+      if (!this->string_to_int(priority_string, false, &prio))
+       return NULL;
+      this->package_->set_priority(prio);
+      this->require_c_string(";\n");
+
+      if (stream->match_c_string("import "))
+       this->read_import_init_fns(gogo);
+
+      // Loop over all the input data for this package.
+      while (!stream->saw_error())
+       {
+         if (stream->match_c_string("const "))
+           this->import_const();
+         else if (stream->match_c_string("type "))
+           this->import_type();
+         else if (stream->match_c_string("var "))
+           this->import_var();
+         else if (stream->match_c_string("func "))
+           this->import_func(this->package_);
+         else if (stream->match_c_string("checksum "))
+           break;
+         else
+           {
+             error_at(this->location_,
+                      ("error in import data at %d: "
+                       "expected %<const%>, %<type%>, %<var%>, "
+                       "%<func%>, or %<checksum%>"),
+                      stream->pos());
+             stream->set_saw_error();
+             return NULL;
+           }
+       }
+
+      // We currently ignore the checksum.  In the future we could
+      // store the checksum somewhere in the generated object and then
+      // verify that the checksum matches at link time or at dynamic
+      // load time.
+      this->require_c_string("checksum ");
+      stream->advance(Export::v1_checksum_len * 2);
+      this->require_c_string(";\n");
+    }
+
+  return this->package_;
+}
+
+// Read the list of import control functions.
+
+void
+Import::read_import_init_fns(Gogo* gogo)
+{
+  this->require_c_string("import");
+  while (!this->match_c_string(";"))
+    {
+      this->require_c_string(" ");
+      std::string package_name = this->read_identifier();
+      this->require_c_string(" ");
+      std::string init_name = this->read_identifier();
+      this->require_c_string(" ");
+      std::string prio_string = this->read_identifier();
+      int prio;
+      if (!this->string_to_int(prio_string, false, &prio))
+       return;
+      gogo->add_import_init_fn(package_name, init_name, prio);
+    }
+  this->require_c_string(";\n");
+}
+
+// Import a constant.
+
+void
+Import::import_const()
+{
+  std::string name;
+  Type* type;
+  Expression* expr;
+  Named_constant::import_const(this, &name, &type, &expr);
+  Typed_identifier tid(name, type, this->location_);
+  Named_object* no = this->package_->add_constant(tid, expr);
+  if (this->add_to_globals_)
+    this->gogo_->add_named_object(no);
+}
+
+// Import a type.
+
+void
+Import::import_type()
+{
+  Named_type* type;
+  Named_type::import_named_type(this, &type);
+
+  // The named type has been added to the package by the type import
+  // process.  Here we need to make it visible to the parser, and it
+  // to the global bindings if necessary.
+  type->set_is_visible();
+
+  if (this->add_to_globals_)
+    this->gogo_->add_named_type(type);
+}
+
+// Import a variable.
+
+void
+Import::import_var()
+{
+  std::string name;
+  Type* type;
+  Variable::import_var(this, &name, &type);
+  Variable* var = new Variable(type, NULL, true, false, false,
+                              this->location_);
+  Named_object* no;
+  no = this->package_->add_variable(name, var);
+  if (this->add_to_globals_)
+    this->gogo_->add_named_object(no);
+}
+
+// Import a function into PACKAGE.  PACKAGE is normally
+// THIS->PACKAGE_, but it will be different for a method associated
+// with a type defined in a different package.
+
+Named_object*
+Import::import_func(Package* package)
+{
+  std::string name;
+  Typed_identifier* receiver;
+  Typed_identifier_list* parameters;
+  Typed_identifier_list* results;
+  bool is_varargs;
+  Function::import_func(this, &name, &receiver, &parameters, &results,
+                       &is_varargs);
+  Function_type *fntype = Type::make_function_type(receiver, parameters,
+                                                  results, this->location_);
+  if (is_varargs)
+    fntype->set_is_varargs();
+
+  source_location loc = this->location_;
+  Named_object* no;
+  if (fntype->is_method())
+    {
+      Type* rtype = receiver->type()->deref();
+      if (rtype->is_error_type())
+       return NULL;
+      Named_type* named_rtype = rtype->named_type();
+      gcc_assert(named_rtype != NULL);
+      no = named_rtype->add_method_declaration(name, package, fntype, loc);
+    }
+  else
+    {
+      no = package->add_function_declaration(name, fntype, loc);
+      if (this->add_to_globals_)
+       this->gogo_->add_named_object(no);
+    }
+  return no;
+}
+
+// Read a type in the import stream.  This records the type by the
+// type index.  If the type is named, it registers the name, but marks
+// it as invisible.
+
+Type*
+Import::read_type()
+{
+  Stream* stream = this->stream_;
+  this->require_c_string("<type ");
+
+  std::string number;
+  int c;
+  while (true)
+    {
+      c = stream->get_char();
+      if (c != '-' && (c < '0' || c > '9'))
+       break;
+      number += c;
+    }
+
+  int index;
+  if (!this->string_to_int(number, true, &index))
+    return Type::make_error_type();
+
+  if (c == '>')
+    {
+      // This type was already defined.
+      if (index < 0
+         ? (static_cast<size_t>(- index) >= this->builtin_types_.size()
+            || this->builtin_types_[- index] == NULL)
+         : (static_cast<size_t>(index) >= this->types_.size()
+            || this->types_[index] == NULL))
+       {
+         error_at(this->location_,
+                  "error in import data at %d: bad type index %d",
+                  stream->pos(), index);
+         stream->set_saw_error();
+         return Type::make_error_type();
+       }
+
+      return index < 0 ? this->builtin_types_[- index] : this->types_[index];
+    }
+
+  if (c != ' ')
+    {
+      if (!stream->saw_error())
+       error_at(this->location_,
+                "error in import data at %d: expect %< %> or %<>%>'",
+                stream->pos());
+      stream->set_saw_error();
+      stream->advance(1);
+      return Type::make_error_type();
+    }
+
+  if (index <= 0
+      || (static_cast<size_t>(index) < this->types_.size()
+         && this->types_[index] != NULL))
+    {
+      error_at(this->location_,
+              "error in import data at %d: type index already defined",
+              stream->pos());
+      stream->set_saw_error();
+      return Type::make_error_type();
+    }
+
+  if (static_cast<size_t>(index) >= this->types_.size())
+    {
+      int newsize = std::max(static_cast<size_t>(index) + 1,
+                            this->types_.size() * 2);
+      this->types_.resize(newsize, NULL);
+    }
+
+  if (stream->peek_char() != '"')
+    {
+      Type* type = Type::import_type(this);
+      this->require_c_string(">");
+      this->types_[index] = type;
+      return type;
+    }
+
+  // This type has a name.
+
+  stream->advance(1);
+  std::string type_name;
+  while ((c = stream->get_char()) != '"')
+    type_name += c;
+
+  // If this type is in the current package, the name will be
+  // .PREFIX.PACKAGE.NAME or simply NAME with no dots.  Otherwise, a
+  // non-hidden symbol will be PREFIX.PACKAGE.NAME and a hidden symbol
+  // will be .PREFIX.PACKAGE.NAME.
+  std::string package_name;
+  std::string unique_prefix;
+  if (type_name.find('.') != std::string::npos)
+    {
+      bool is_hidden = false;
+      size_t start = 0;
+      if (type_name[0] == '.')
+       {
+         ++start;
+         is_hidden = true;
+       }
+      size_t dot1 = type_name.find('.', start);
+      size_t dot2;
+      if (dot1 == std::string::npos)
+       dot2 = std::string::npos;
+      else
+       dot2 = type_name.find('.', dot1 + 1);
+      if (dot1 == std::string::npos || dot2 == std::string::npos)
+       {
+         error_at(this->location_,
+                  ("error at import data at %d: missing dot in type name"),
+                  stream->pos());
+         stream->set_saw_error();
+       }
+      else
+       {
+         unique_prefix = type_name.substr(start, dot1 - start);
+         package_name = type_name.substr(dot1 + 1, dot2 - (dot1 + 1));
+       }
+      if (!is_hidden)
+       type_name.erase(0, dot2 + 1);
+    }
+
+  this->require_c_string(" ");
+
+  // Declare the type in the appropriate package.  If we haven't seen
+  // it before, mark it as invisible.  We declare it before we read
+  // the actual definition of the type, since the definition may refer
+  // to the type itself.
+  Package* package;
+  if (package_name.empty())
+    package = this->package_;
+  else
+    package = this->gogo_->register_package(package_name, unique_prefix,
+                                           UNKNOWN_LOCATION);
+
+  Named_object* no = package->bindings()->lookup(type_name);
+  if (no == NULL)
+    no = package->add_type_declaration(type_name, this->location_);
+  else if (!no->is_type_declaration() && !no->is_type())
+    {
+      error_at(this->location_, "imported %<%s.%s%> both type and non-type",
+              Gogo::message_name(package->name()).c_str(),
+              Gogo::message_name(type_name).c_str());
+      stream->set_saw_error();
+      return Type::make_error_type();
+    }
+  else
+    gcc_assert(no->package() == package);
+
+  if (this->types_[index] == NULL)
+    {
+      if (no->is_type_declaration())
+       {
+         // FIXME: It's silly to make a forward declaration every time.
+         this->types_[index] = Type::make_forward_declaration(no);
+       }
+      else
+       {
+         gcc_assert(no->is_type());
+         this->types_[index] = no->type_value();
+       }
+    }
+
+  // If there is no type definition, then this is just a forward
+  // declaration of a type defined in some other file.
+  Type* type;
+  if (this->match_c_string(">"))
+    type = this->types_[index];
+  else
+    {
+      type = this->read_type();
+
+      if (no->is_type_declaration())
+       {
+         // We can define the type now.
+
+         no = package->add_type(type_name, type, this->location_);
+         Named_type* ntype = no->type_value();
+
+         // This type has not yet been imported.
+         ntype->clear_is_visible();
+
+         type = ntype;
+       }
+      else if (no->is_type())
+       {
+         // We have seen this type before.  FIXME: it would be a good
+         // idea to check that the two imported types are identical,
+         // but we have not finalized the methds yet, which means
+         // that we can nt reliably compare interface types.
+         type = no->type_value();
+
+         // Don't change the visibility of the existing type.
+       }
+
+      this->types_[index] = type;
+
+      // Read the type methods.
+      if (this->match_c_string("\n"))
+       {
+         this->advance(1);
+         while (this->match_c_string(" func"))
+           {
+             this->advance(1);
+             this->import_func(package);
+           }
+       }
+    }
+
+  this->require_c_string(">");
+
+  return type;
+}
+
+// Register the builtin types.
+
+void
+Import::register_builtin_types(Gogo* gogo)
+{
+  this->register_builtin_type(gogo, "int8", BUILTIN_INT8);
+  this->register_builtin_type(gogo, "int16", BUILTIN_INT16);
+  this->register_builtin_type(gogo, "int32", BUILTIN_INT32);
+  this->register_builtin_type(gogo, "int64", BUILTIN_INT64);
+  this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8);
+  this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16);
+  this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32);
+  this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
+  this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
+  this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
+  this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
+  this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
+  this->register_builtin_type(gogo, "int", BUILTIN_INT);
+  this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
+  this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
+  this->register_builtin_type(gogo, "float", BUILTIN_FLOAT);
+  this->register_builtin_type(gogo, "complex", BUILTIN_COMPLEX);
+  this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
+  this->register_builtin_type(gogo, "string", BUILTIN_STRING);
+}
+
+// Register a single builtin type.
+
+void
+Import::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
+{
+  Named_object* named_object = gogo->lookup_global(name);
+  gcc_assert(named_object != NULL && named_object->is_type());
+  int index = - static_cast<int>(code);
+  gcc_assert(index > 0
+            && static_cast<size_t>(index) < this->builtin_types_.size());
+  this->builtin_types_[index] = named_object->type_value();
+}
+
+// Read an identifier from the stream.
+
+std::string
+Import::read_identifier()
+{
+  std::string ret;
+  Stream* stream = this->stream_;
+  int c;
+  while (true)
+    {
+      c = stream->peek_char();
+      if (c == -1 || c == ' ' || c == ';')
+       break;
+      ret += c;
+      stream->advance(1);
+    }
+  return ret;
+}
+
+// Turn a string into a integer with appropriate error handling.
+
+bool
+Import::string_to_int(const std::string &s, bool is_neg_ok, int* ret)
+{
+  char* end;
+  long prio = strtol(s.c_str(), &end, 10);
+  if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok))
+    {
+      error_at(this->location_, "invalid integer in import data at %d",
+              this->stream_->pos());
+      this->stream_->set_saw_error();
+      return false;
+    }
+  *ret = prio;
+  return true;
+}
+
+// Class Import::Stream.
+
+Import::Stream::Stream()
+  : pos_(0), saw_error_(false)
+{
+}
+
+Import::Stream::~Stream()
+{
+}
+
+// Return the next character to come from the stream.
+
+int
+Import::Stream::peek_char()
+{
+  const char* read;
+  if (!this->do_peek(1, &read))
+    return -1;
+  // Make sure we return an unsigned char, so that we don't get
+  // confused by \xff.
+  unsigned char ret = *read;
+  return ret;
+}
+
+// Return true if the next LENGTH characters from the stream match
+// BYTES
+
+bool
+Import::Stream::match_bytes(const char* bytes, size_t length)
+{
+  const char* read;
+  if (!this->do_peek(length, &read))
+    return false;
+  return memcmp(bytes, read, length) == 0;
+}
+
+// Require that the next LENGTH bytes from the stream match BYTES.
+
+void
+Import::Stream::require_bytes(source_location location, const char* bytes,
+                             size_t length)
+{
+  const char* read;
+  if (!this->do_peek(length, &read)
+      || memcmp(bytes, read, length) != 0)
+    {
+      if (!this->saw_error_)
+       error_at(location, "import error at %d: expected %<%.*s%>",
+                this->pos(), static_cast<int>(length), bytes);
+      this->saw_error_ = true;
+      return;
+    }
+  this->advance(length);
+}
+
+// Class Stream_from_file.
+
+Stream_from_file::Stream_from_file(int fd)
+  : fd_(fd), data_()
+{
+  if (lseek(fd, 0, SEEK_SET) != 0)
+    {
+      error("lseek failed: %m");
+      this->set_saw_error();
+    }
+}
+
+Stream_from_file::~Stream_from_file()
+{
+  close(this->fd_);
+}
+
+// Read next bytes.
+
+bool
+Stream_from_file::do_peek(size_t length, const char** bytes)
+{
+  if (this->data_.length() <= length)
+    {
+      *bytes = this->data_.data();
+      return true;
+    }
+  // Don't bother to handle the general case, since we don't need it.
+  gcc_assert(length < 64);
+  char buf[64];
+  ssize_t got = read(this->fd_, buf, length);
+
+  if (got < 0)
+    {
+      if (!this->saw_error())
+       error("read failed: %m");
+      this->set_saw_error();
+      return false;
+    }
+
+  if (lseek(this->fd_, - got, SEEK_CUR) != 0)
+    {
+      if (!this->saw_error())
+       error("lseek failed: %m");
+      this->set_saw_error();
+      return false;
+    }
+
+  if (static_cast<size_t>(got) < length)
+    return false;
+
+  this->data_.assign(buf, got);
+
+  *bytes = this->data_.data();
+  return true;
+}
+
+// Advance.
+
+void
+Stream_from_file::do_advance(size_t skip)
+{
+  if (lseek(this->fd_, skip, SEEK_CUR) != 0)
+    {
+      if (!this->saw_error())
+       error("lseek failed: %m");
+      this->set_saw_error();
+    }
+  if (!this->data_.empty())
+    {
+      if (this->data_.length() < skip)
+       this->data_.erase(0, skip);
+      else
+       this->data_.clear();
+    }
+}
diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h
new file mode 100644 (file)
index 0000000..0101a40
--- /dev/null
@@ -0,0 +1,351 @@
+// import.h -- Go frontend import declarations.     -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_IMPORT_H
+#define GO_IMPORT_H
+
+#include "export.h"
+
+class Gogo;
+class Package;
+class Type;
+class Named_object;
+class Named_type;
+class Expression;
+
+// This class manages importing Go declarations.
+
+class Import
+{
+ public:
+  // The Stream class is an interface used to read the data.  The
+  // caller should instantiate a child of this class.
+  class Stream
+  {
+   public:
+    Stream();
+    virtual ~Stream();
+
+    // Return whether we have seen an error.
+    bool
+    saw_error() const
+    { return this->saw_error_; }
+
+    // Record that we've seen an error.
+    void
+    set_saw_error()
+    { this->saw_error_ = true; }
+
+    // Return the next character (a value from 0 to 0xff) without
+    // advancing.  Returns -1 at end of stream.
+    int
+    peek_char();
+
+    // Look for LENGTH characters, setting *BYTES to point to them.
+    // Returns false if the bytes are not available.  Does not
+    // advance.
+    bool
+    peek(size_t length, const char** bytes)
+    { return this->do_peek(length, bytes); }
+
+    // Return the next character (a value from 0 to 0xff) and advance
+    // the read position by 1.  Returns -1 at end of stream.
+    int
+    get_char()
+    {
+      int c = this->peek_char();
+      this->advance(1);
+      return c;
+    }
+
+    // Return true if at the end of the stream.
+    bool
+    at_eof()
+    { return this->peek_char() == -1; }
+
+    // Return true if the next bytes match STR.
+    bool
+    match_c_string(const char* str)
+    { return this->match_bytes(str, strlen(str)); }
+
+    // Return true if the next LENGTH bytes match BYTES.
+    bool
+    match_bytes(const char* bytes, size_t length);
+
+    // Give an error if the next bytes do not match STR.  Advance the
+    // read position by the length of STR.
+    void
+    require_c_string(source_location location, const char* str)
+    { this->require_bytes(location, str, strlen(str)); }
+
+    // Given an error if the next LENGTH bytes do not match BYTES.
+    // Advance the read position by LENGTH.
+    void
+    require_bytes(source_location, const char* bytes, size_t length);
+
+    // Advance the read position by SKIP bytes.
+    void
+    advance(size_t skip)
+    {
+      this->do_advance(skip);
+      this->pos_ += skip;
+    }
+
+    // Return the current read position.  This returns int because it
+    // is more convenient in error reporting.  FIXME.
+    int
+    pos()
+    { return static_cast<int>(this->pos_); }
+
+   protected:
+    // This function should set *BYTES to point to a buffer holding
+    // the LENGTH bytes at the current read position.  It should
+    // return false if the bytes are not available.  This should not
+    // change the current read position.
+    virtual bool
+    do_peek(size_t length, const char** bytes) = 0;
+
+    // This function should advance the current read position LENGTH
+    // bytes.
+    virtual void
+    do_advance(size_t skip) = 0;
+
+   private:
+    // The current read position.
+    size_t pos_;
+    // True if we've seen an error reading from this stream.
+    bool saw_error_;
+  };
+
+  // Find import data.  This searches the file system for FILENAME and
+  // returns a pointer to a Stream object to read the data that it
+  // exports.  LOCATION is the location of the import statement.
+  static Stream*
+  open_package(const std::string& filename, source_location location);
+
+  // Constructor.
+  Import(Stream*, source_location);
+
+  // Register the builtin types.
+  void
+  register_builtin_types(Gogo*);
+
+  // Import everything defined in the stream.  LOCAL_NAME is the local
+  // name to be used for bindings; if it is the string "." then
+  // bindings should be inserted in the global scope.  If LOCAL_NAME
+  // is the empty string then the name of the package itself is the
+  // local name.  This returns the imported package, or NULL on error.
+  Package*
+  import(Gogo*, const std::string& local_name, bool is_local_name_exported);
+
+  // The location of the import statement.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Return the next character.
+  int
+  peek_char()
+  { return this->stream_->peek_char(); }
+
+  // Return the next character and advance.
+  int
+  get_char()
+  { return this->stream_->get_char(); }
+
+  // Return true at the end of the stream.
+  bool
+  at_eof()
+  { return this->stream_->at_eof(); }
+
+  // Return whether the next bytes match STR.
+  bool
+  match_c_string(const char* str)
+  { return this->stream_->match_c_string(str); }
+
+  // Require that the next bytes match STR.
+  void
+  require_c_string(const char* str)
+  { this->stream_->require_c_string(this->location_, str); }
+
+  // Advance the stream SKIP bytes.
+  void
+  advance(size_t skip)
+  { this->stream_->advance(skip); }
+
+  // Read an identifier.
+  std::string
+  read_identifier();
+
+  // Read a type.
+  Type*
+  read_type();
+
+  // The name used for parameters, receivers, and results in imported
+  // function types.
+  static const char* const import_marker;
+
+ private:
+  static Stream*
+  try_package_in_directory(const std::string&, source_location);
+
+  static int
+  try_suffixes(std::string*);
+
+  static Stream*
+  find_export_data(const std::string& filename, int fd, source_location);
+
+  static Stream*
+  find_object_export_data(const std::string& filename, int fd,
+                         off_t offset, source_location);
+
+  static const int archive_magic_len = 8;
+
+  static bool
+  is_archive_magic(const char*);
+
+  static Stream*
+  find_archive_export_data(const std::string& filename, int fd,
+                          source_location);
+
+  // Read the import control functions.
+  void
+  read_import_init_fns(Gogo*);
+
+  // Import a constant.
+  void
+  import_const();
+
+  // Import a type.
+  void
+  import_type();
+
+  // Import a variable.
+  void
+  import_var();
+
+  // Import a function.
+  Named_object*
+  import_func(Package*);
+
+  // Register a single builtin type.
+  void
+  register_builtin_type(Gogo*, const char* name, Builtin_code);
+
+  // Get an integer from a string.
+  bool
+  string_to_int(const std::string&, bool is_neg_ok, int* ret);
+
+  // The general IR.
+  Gogo* gogo_;
+  // The stream from which to read import data.
+  Stream* stream_;
+  // The location of the import statement we are processing.
+  source_location location_;
+  // The package we are importing.
+  Package* package_;
+  // Whether to add new objects to the global scope, rather than to a
+  // package scope.
+  bool add_to_globals_;
+  // Mapping from negated builtin type codes to Type structures.
+  std::vector<Named_type*> builtin_types_;
+  // Mapping from exported type codes to Type structures.
+  std::vector<Type*> types_;
+};
+
+// Read import data from a string.
+
+class Stream_from_string : public Import::Stream
+{
+ public:
+  Stream_from_string(const std::string& str)
+    : str_(str), pos_(0)
+  { }
+
+ protected:
+  bool
+  do_peek(size_t length, const char** bytes)
+  {
+    if (this->pos_ + length > this->str_.length())
+      return false;
+    *bytes = this->str_.data() + this->pos_;
+    return true;
+  }
+
+  void
+  do_advance(size_t len)
+  { this->pos_ += len; }
+
+ private:
+  // The string of data we are reading.
+  std::string str_;
+  // The current position within the string.
+  size_t pos_;
+};
+
+// Read import data from an allocated buffer.
+
+class Stream_from_buffer : public Import::Stream
+{
+ public:
+  Stream_from_buffer(char* buf, size_t length)
+    : buf_(buf), length_(length), pos_(0)
+  { }
+
+  ~Stream_from_buffer()
+  { delete[] this->buf_; }
+
+ protected:
+  bool
+  do_peek(size_t length, const char** bytes)
+  {
+    if (this->pos_ + length > this->length_)
+      return false;
+    *bytes = this->buf_ + this->pos_;
+    return true;
+  }
+
+  void
+  do_advance(size_t len)
+  { this->pos_ += len; }
+
+ private:
+  // The data we are reading.
+  char* buf_;
+  // The length of the buffer.
+  size_t length_;
+  // The current position within the buffer.
+  size_t pos_;
+};
+
+// Read import data from an open file descriptor.
+
+class Stream_from_file : public Import::Stream
+{
+ public:
+  Stream_from_file(int fd);
+
+  ~Stream_from_file();
+
+ protected:
+  bool
+  do_peek(size_t, const char**);
+
+  void
+  do_advance(size_t);
+
+ private:
+  // No copying.
+  Stream_from_file(const Stream_from_file&);
+  Stream_from_file& operator=(const Stream_from_file&);
+
+  // The file descriptor.
+  int fd_;
+  // Data read from the file.
+  std::string data_;
+};
+
+#endif // !defined(GO_IMPORT_H)
diff --git a/gcc/go/gofrontend/lex.cc b/gcc/go/gofrontend/lex.cc
new file mode 100644 (file)
index 0000000..bc2531e
--- /dev/null
@@ -0,0 +1,2287 @@
+// lex.cc -- Go frontend lexer.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "lex.h"
+
+// Manage mapping from keywords to the Keyword codes.
+
+class Keywords
+{
+ public:
+  // The structure which maps keywords to codes.
+  struct Mapping
+  {
+    // Keyword string.
+    const char* keystring;
+    // Keyword code.
+    Keyword keycode;
+  };
+
+  // Return the parsecode corresponding to KEYSTRING, or
+  // KEYWORD_INVALID if it is not a keyword.
+  Keyword
+  keyword_to_code(const char* keyword, size_t len) const;
+
+  // Return the string for a keyword.
+  const char*
+  keyword_to_string(Keyword) const;
+
+ private:
+  static const Mapping mapping_[];
+  static const int count_;
+};
+
+// Mapping from keyword string to keyword code.  This array must be
+// kept in sorted order, and the order must match the Keyword enum.
+// Strings are looked up using bsearch.
+
+const Keywords::Mapping
+Keywords::mapping_[] =
+{
+  { NULL,         KEYWORD_INVALID },
+  { "__asm__",    KEYWORD_ASM },
+  { "break",      KEYWORD_BREAK },
+  { "case",       KEYWORD_CASE },
+  { "chan",       KEYWORD_CHAN },
+  { "const",      KEYWORD_CONST },
+  { "continue",           KEYWORD_CONTINUE },
+  { "default",    KEYWORD_DEFAULT },
+  { "defer",      KEYWORD_DEFER },
+  { "else",       KEYWORD_ELSE },
+  { "fallthrough", KEYWORD_FALLTHROUGH },
+  { "for",        KEYWORD_FOR },
+  { "func",       KEYWORD_FUNC },
+  { "go",         KEYWORD_GO },
+  { "goto",       KEYWORD_GOTO },
+  { "if",         KEYWORD_IF },
+  { "import",     KEYWORD_IMPORT },
+  { "interface",   KEYWORD_INTERFACE },
+  { "map",        KEYWORD_MAP },
+  { "package",    KEYWORD_PACKAGE },
+  { "range",      KEYWORD_RANGE },
+  { "return",     KEYWORD_RETURN },
+  { "select",     KEYWORD_SELECT },
+  { "struct",     KEYWORD_STRUCT },
+  { "switch",     KEYWORD_SWITCH },
+  { "type",       KEYWORD_TYPE },
+  { "var",        KEYWORD_VAR }
+};
+
+// Number of entries in the map.
+
+const int Keywords::count_ =
+  sizeof(Keywords::mapping_) / sizeof(Keywords::mapping_[0]);
+
+// Comparison function passed to bsearch.
+
+extern "C"
+{
+
+struct Keywords_search_key
+{
+  const char* str;
+  size_t len;
+};
+
+static int
+keyword_compare(const void* keyv, const void* mapv)
+{
+  const Keywords_search_key* key =
+    static_cast<const Keywords_search_key*>(keyv);
+  const Keywords::Mapping* map =
+    static_cast<const Keywords::Mapping*>(mapv);
+  if (map->keystring == NULL)
+    return 1;
+  int i = strncmp(key->str, map->keystring, key->len);
+  if (i != 0)
+    return i;
+  if (map->keystring[key->len] != '\0')
+    return -1;
+  return 0;
+}
+
+} // End extern "C".
+
+// Convert a string to a keyword code.  Return KEYWORD_INVALID if the
+// string is not a keyword.
+
+Keyword
+Keywords::keyword_to_code(const char* keyword, size_t len) const
+{
+  Keywords_search_key key;
+  key.str = keyword;
+  key.len = len;
+  void* mapv = bsearch(&key,
+                       this->mapping_,
+                       this->count_,
+                       sizeof(this->mapping_[0]),
+                       keyword_compare);
+  if (mapv == NULL)
+    return KEYWORD_INVALID;
+  Mapping* map = static_cast<Mapping*>(mapv);
+  return map->keycode;
+}
+
+// Convert a keyword code to a string.
+
+const char*
+Keywords::keyword_to_string(Keyword code) const
+{
+  gcc_assert(code > KEYWORD_INVALID && code < this->count_);
+  const Mapping* map = &this->mapping_[code];
+  gcc_assert(map->keycode == code);
+  return map->keystring;
+}
+
+// There is one instance of the Keywords class.
+
+static Keywords keywords;
+
+// Class Token.
+
+// Make a general token.
+
+Token::Token(Classification classification, source_location location)
+  : classification_(classification), location_(location)
+{
+}
+
+// Destroy a token.
+
+Token::~Token()
+{
+  this->clear();
+}
+
+// Clear a token--release memory.
+
+void
+Token::clear()
+{
+  if (this->classification_ == TOKEN_INTEGER)
+    mpz_clear(this->u_.integer_value);
+  else if (this->classification_ == TOKEN_FLOAT
+          || this->classification_ == TOKEN_IMAGINARY)
+    mpfr_clear(this->u_.float_value);
+}
+
+// Construct a token.
+
+Token::Token(const Token& tok)
+  : classification_(tok.classification_), location_(tok.location_)
+{
+  switch (this->classification_)
+    {
+    case TOKEN_INVALID:
+    case TOKEN_EOF:
+      break;
+    case TOKEN_KEYWORD:
+      this->u_.keyword = tok.u_.keyword;
+      break;
+    case TOKEN_IDENTIFIER:
+    case TOKEN_STRING:
+      this->u_.string_value = tok.u_.string_value;
+      break;
+    case TOKEN_OPERATOR:
+      this->u_.op = tok.u_.op;
+      break;
+    case TOKEN_INTEGER:
+      mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
+      break;
+    case TOKEN_FLOAT:
+    case TOKEN_IMAGINARY:
+      mpfr_init_set(this->u_.float_value, tok.u_.float_value, GMP_RNDN);
+      break;
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Assign to a token.
+
+Token&
+Token::operator=(const Token& tok)
+{
+  this->clear();
+  this->classification_ = tok.classification_;
+  this->location_ = tok.location_;
+  switch (tok.classification_)
+    {
+    case TOKEN_INVALID:
+    case TOKEN_EOF:
+      break;
+    case TOKEN_KEYWORD:
+      this->u_.keyword = tok.u_.keyword;
+      break;
+    case TOKEN_IDENTIFIER:
+      this->u_.identifier_value.name = tok.u_.identifier_value.name;
+      this->u_.identifier_value.is_exported =
+       tok.u_.identifier_value.is_exported;
+      break;
+    case TOKEN_STRING:
+      this->u_.string_value = tok.u_.string_value;
+      break;
+    case TOKEN_OPERATOR:
+      this->u_.op = tok.u_.op;
+      break;
+    case TOKEN_INTEGER:
+      mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
+      break;
+    case TOKEN_FLOAT:
+    case TOKEN_IMAGINARY:
+      mpfr_init_set(this->u_.float_value, tok.u_.float_value, GMP_RNDN);
+      break;
+    default:
+      gcc_unreachable();
+    }
+  return *this;
+}
+
+// Print the token for debugging.
+
+void
+Token::print(FILE* file) const
+{
+  switch (this->classification_)
+    {
+    case TOKEN_INVALID:
+      fprintf(file, "invalid");
+      break;
+    case TOKEN_EOF:
+      fprintf(file, "EOF");
+      break;
+    case TOKEN_KEYWORD:
+      fprintf(file, "keyword %s", keywords.keyword_to_string(this->u_.keyword));
+      break;
+    case TOKEN_IDENTIFIER:
+      fprintf(file, "identifier \"%s\"", this->u_.string_value->c_str());
+      break;
+    case TOKEN_STRING:
+      fprintf(file, "quoted string \"%s\"", this->u_.string_value->c_str());
+      break;
+    case TOKEN_INTEGER:
+      fprintf(file, "integer ");
+      mpz_out_str(file, 10, this->u_.integer_value);
+      break;
+    case TOKEN_FLOAT:
+      fprintf(file, "float ");
+      mpfr_out_str(file, 10, 0, this->u_.float_value, GMP_RNDN);
+      break;
+    case TOKEN_IMAGINARY:
+      fprintf(file, "imaginary ");
+      mpfr_out_str(file, 10, 0, this->u_.float_value, GMP_RNDN);
+      break;
+    case TOKEN_OPERATOR:
+      fprintf(file, "operator ");
+      switch (this->u_.op)
+       {
+       case OPERATOR_INVALID:
+         fprintf(file, "invalid");
+         break;
+       case OPERATOR_OROR:
+         fprintf(file, "||");
+         break;
+       case OPERATOR_ANDAND:
+         fprintf(file, "&&");
+         break;
+       case OPERATOR_EQEQ:
+         fprintf(file, "==");
+         break;
+       case OPERATOR_NOTEQ:
+         fprintf(file, "!=");
+         break;
+       case OPERATOR_LT:
+         fprintf(file, "<");
+         break;
+       case OPERATOR_LE:
+         fprintf(file, "<=");
+         break;
+       case OPERATOR_GT:
+         fprintf(file, ">");
+         break;
+       case OPERATOR_GE:
+         fprintf(file, ">=");
+         break;
+       case OPERATOR_PLUS:
+         fprintf(file, "+");
+         break;
+       case OPERATOR_MINUS:
+         fprintf(file, "-");
+         break;
+       case OPERATOR_OR:
+         fprintf(file, "|");
+         break;
+       case OPERATOR_XOR:
+         fprintf(file, "^");
+         break;
+       case OPERATOR_MULT:
+         fprintf(file, "*");
+         break;
+       case OPERATOR_DIV:
+         fprintf(file, "/");
+         break;
+       case OPERATOR_MOD:
+         fprintf(file, "%%");
+         break;
+       case OPERATOR_LSHIFT:
+         fprintf(file, "<<");
+         break;
+       case OPERATOR_RSHIFT:
+         fprintf(file, ">>");
+         break;
+       case OPERATOR_AND:
+         fprintf(file, "&");
+         break;
+       case OPERATOR_BITCLEAR:
+         fprintf(file, "&^");
+         break;
+       case OPERATOR_NOT:
+         fprintf(file, "!");
+         break;
+       case OPERATOR_CHANOP:
+         fprintf(file, "<-");
+         break;
+       case OPERATOR_EQ:
+         fprintf(file, "=");
+         break;
+       case OPERATOR_PLUSEQ:
+         fprintf(file, "+=");
+         break;
+       case OPERATOR_MINUSEQ:
+         fprintf(file, "-=");
+         break;
+       case OPERATOR_OREQ:
+         fprintf(file, "|=");
+         break;
+       case OPERATOR_XOREQ:
+         fprintf(file, "^=");
+         break;
+       case OPERATOR_MULTEQ:
+         fprintf(file, "*=");
+         break;
+       case OPERATOR_DIVEQ:
+         fprintf(file, "/=");
+         break;
+       case OPERATOR_MODEQ:
+         fprintf(file, "%%=");
+         break;
+       case OPERATOR_LSHIFTEQ:
+         fprintf(file, "<<=");
+         break;
+       case OPERATOR_RSHIFTEQ:
+         fprintf(file, ">>=");
+         break;
+       case OPERATOR_ANDEQ:
+         fprintf(file, "&=");
+         break;
+       case OPERATOR_BITCLEAREQ:
+         fprintf(file, "&^=");
+         break;
+       case OPERATOR_PLUSPLUS:
+         fprintf(file, "++");
+         break;
+       case OPERATOR_MINUSMINUS:
+         fprintf(file, "--");
+         break;
+       case OPERATOR_COLON:
+         fprintf(file, ":");
+         break;
+       case OPERATOR_COLONEQ:
+         fprintf(file, ":=");
+         break;
+       case OPERATOR_SEMICOLON:
+         fprintf(file, ";");
+         break;
+       case OPERATOR_DOT:
+         fprintf(file, ".");
+         break;
+       case OPERATOR_COMMA:
+         fprintf(file, ",");
+         break;
+       case OPERATOR_LPAREN:
+         fprintf(file, "(");
+         break;
+       case OPERATOR_RPAREN:
+         fprintf(file, ")");
+         break;
+       case OPERATOR_LCURLY:
+         fprintf(file, "{");
+         break;
+       case OPERATOR_RCURLY:
+         fprintf(file, "}");
+         break;
+       case OPERATOR_LSQUARE:
+         fprintf(file, "[");
+         break;
+       case OPERATOR_RSQUARE:
+         fprintf(file, "]");
+         break;
+       default:
+         gcc_unreachable();
+       }
+      break;
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Class Lex.
+
+Lex::Lex(const char* input_file_name, FILE* input_file)
+  : input_file_name_(input_file_name), input_file_(input_file),
+    linebuf_(NULL), linebufsize_(120), linesize_(0), lineno_(0),
+    add_semi_at_eol_(false)
+{
+  this->linebuf_ = new char[this->linebufsize_];
+  linemap_add(line_table, LC_ENTER, 0, input_file_name, 1);
+}
+
+Lex::~Lex()
+{
+  delete[] this->linebuf_;
+  linemap_add(line_table, LC_LEAVE, 0, NULL, 0);
+}
+
+// Read a new line from the file.
+
+ssize_t
+Lex::get_line()
+{
+  char* buf = this->linebuf_;
+  size_t size = this->linebufsize_;
+
+  FILE* file = this->input_file_;
+  size_t cur = 0;
+  while (true)
+    {
+      int c = getc(file);
+      if (c == EOF)
+       {
+         if (cur == 0)
+           return -1;
+         break;
+       }
+      if (cur + 1 >= size)
+       {
+         size_t ns = 2 * size + 1;
+         if (ns < size || static_cast<ssize_t>(ns) < 0)
+           error_at(this->location(), "out of memory");
+         char* nb = new char[ns];
+         memcpy(nb, buf, cur);
+         delete[] buf;
+         buf = nb;
+         size = ns;
+       }
+      buf[cur] = c;
+      ++cur;
+
+      if (c == '\n')
+       break;
+    }
+
+  buf[cur] = '\0';
+
+  this->linebuf_ = buf;
+  this->linebufsize_ = size;
+
+  return cur;
+}
+
+// See if we need to read a new line.  Return true if there is a new
+// line, false if we are at EOF.
+
+bool
+Lex::require_line()
+{
+  if (this->lineoff_ < this->linesize_)
+    return true;
+
+  ssize_t got = this->get_line();
+  if (got < 0)
+    return false;
+  ++this->lineno_;
+  this->linesize_= got;
+  this->lineoff_ = 0;
+
+  linemap_line_start(line_table, this->lineno_, this->linesize_);
+
+  return true;
+}
+
+// Get the current location.
+
+source_location
+Lex::location() const
+{
+  source_location location;
+  LINEMAP_POSITION_FOR_COLUMN(location, line_table, this->lineoff_ + 1);
+  return location;
+}
+
+// Get a location slightly before the current one.  This is used for
+// slightly more efficient handling of operator tokens.
+
+source_location
+Lex::earlier_location(int chars) const
+{
+  source_location location;
+  LINEMAP_POSITION_FOR_COLUMN(location, line_table, this->lineoff_ + 1 - chars);
+  return location;
+}
+
+// Get the next token.
+
+Token
+Lex::next_token()
+{
+  while (true)
+    {
+      if (!this->require_line())
+       return this->make_eof_token();
+
+      const char* p = this->linebuf_ + this->lineoff_;
+      const char* pend = this->linebuf_ + this->linesize_;
+
+      while (p < pend)
+       {
+         unsigned char cc = *p;
+         switch (cc)
+           {
+           case ' ': case '\t': case '\r':
+             ++p;
+             // Skip whitespace quickly.
+             while (*p == ' ' || *p == '\t' || *p == '\r')
+               ++p;
+             break;
+
+           case '\n':
+             {
+               ++p;
+               bool add_semi_at_eol = this->add_semi_at_eol_;
+               this->add_semi_at_eol_ = false;
+               if (add_semi_at_eol)
+                 {
+                   this->lineoff_ = p - this->linebuf_;
+                   return this->make_operator(OPERATOR_SEMICOLON, 1);
+                 }
+             }
+             break;
+
+           case '/':
+             if (p[1] == '/')
+               {
+                 this->lineoff_ = p + 2 - this->linebuf_;
+                 this->skip_cpp_comment();
+                 p = pend;
+                 if (p[-1] == '\n' && this->add_semi_at_eol_)
+                   --p;
+               }
+             else if (p[1] == '*')
+               {
+                 this->lineoff_ = p - this->linebuf_;
+                 source_location location = this->location();
+                 if (!this->skip_c_comment())
+                   return Token::make_invalid_token(location);
+                 p = this->linebuf_ + this->lineoff_;
+                 pend = this->linebuf_ + this->linesize_;
+               }
+             else if (p[1] == '=')
+               {
+                 this->add_semi_at_eol_ = false;
+                 this->lineoff_ = p + 2 - this->linebuf_;
+                 return this->make_operator(OPERATOR_DIVEQ, 2);
+               }
+             else
+               {
+                 this->add_semi_at_eol_ = false;
+                 this->lineoff_ = p + 1 - this->linebuf_;
+                 return this->make_operator(OPERATOR_DIV, 1);
+               }
+             break;
+
+           case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+           case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+           case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+           case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+           case 'Y': case 'Z':
+           case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+           case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+           case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+           case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+           case 'y': case 'z':
+           case '_':
+             this->lineoff_ = p - this->linebuf_;
+             return this->gather_identifier();
+
+           case '0': case '1': case '2': case '3': case '4':
+           case '5': case '6': case '7': case '8': case '9':
+             this->add_semi_at_eol_ = true;
+             this->lineoff_ = p - this->linebuf_;
+             return this->gather_number();
+
+           case '\'':
+             this->add_semi_at_eol_ = true;
+             this->lineoff_ = p - this->linebuf_;
+             return this->gather_character();
+
+           case '"':
+             this->add_semi_at_eol_ = true;
+             this->lineoff_ = p - this->linebuf_;
+             return this->gather_string();
+
+           case '`':
+             this->add_semi_at_eol_ = true;
+             this->lineoff_ = p - this->linebuf_;
+             return this->gather_raw_string();
+
+           case '<':
+           case '>':
+           case '&':
+             if (p + 2 < pend)
+               {
+                 this->add_semi_at_eol_ = false;
+                 Operator op = this->three_character_operator(cc, p[1], p[2]);
+                 if (op != OPERATOR_INVALID)
+                   {
+                     this->lineoff_ = p + 3 - this->linebuf_;
+                     return this->make_operator(op, 3);
+                   }
+               }
+             // Fall through.
+           case '|':
+           case '=':
+           case '!':
+           case '+':
+           case '-':
+           case '^':
+           case '*':
+             // '/' handled above.
+           case '%':
+           case ':':
+           case ';':
+           case ',':
+           case '(': case ')':
+           case '{': case '}':
+           case '[': case ']':
+             {
+               this->add_semi_at_eol_ = false;
+               Operator op = this->two_character_operator(cc, p[1]);
+               int chars;
+               if (op != OPERATOR_INVALID)
+                 {
+                   ++p;
+                   chars = 2;
+                 }
+               else
+                 {
+                   op = this->one_character_operator(cc);
+                   chars = 1;
+                 }
+               this->lineoff_ = p + 1 - this->linebuf_;
+               return this->make_operator(op, chars);
+             }
+
+           case '.':
+             if (p[1] >= '0' && p[1] <= '9')
+               {
+                 this->add_semi_at_eol_ = true;
+                 this->lineoff_ = p - this->linebuf_;
+                 return this->gather_number();
+               }
+             if (p[1] == '.' && p[2] == '.')
+               {
+                 this->add_semi_at_eol_ = false;
+                 this->lineoff_ = p + 3 - this->linebuf_;
+                 return this->make_operator(OPERATOR_ELLIPSIS, 3);
+               }
+             this->add_semi_at_eol_ = false;
+             this->lineoff_ = p + 1 - this->linebuf_;
+             return this->make_operator(OPERATOR_DOT, 1);
+
+           default:
+             {
+               unsigned int ci;
+               bool issued_error;
+               this->lineoff_ = p - this->linebuf_;
+               this->advance_one_utf8_char(p, &ci, &issued_error);
+               if (Lex::is_unicode_letter(ci))
+                 return this->gather_identifier();
+
+               if (!issued_error)
+                 error_at(this->location(),
+                          "invalid character 0x%x in input file",
+                          ci);
+
+               p = pend;
+
+               break;
+             }
+           }
+       }
+
+      this->lineoff_ = p - this->linebuf_;
+    }
+}
+
+// Fetch one UTF-8 character from a string.  Set *VALUE to the value.
+// Return the number of bytes read from the string.  Returns 0 if the
+// string does not point to a valid UTF-8 character.
+
+int
+Lex::fetch_char(const char* p, unsigned int* value)
+{
+  unsigned char c = *p;
+  if (c == 0)
+    {    
+      *value = 0xfffd;
+      return 0;
+    }
+  else if (c <= 0x7f)
+    {
+      *value = c;
+      return 1;
+    }
+  else if ((c & 0xe0) == 0xc0
+          && (p[1] & 0xc0) == 0x80)
+    {
+      *value = (((c & 0x1f) << 6)
+               + (p[1] & 0x3f));
+      if (*value <= 0x7f)
+       {
+         *value = 0xfffd;
+         return 0;
+       }
+      return 2;
+    }
+  else if ((c & 0xf0) == 0xe0
+          && (p[1] & 0xc0) == 0x80
+          && (p[2] & 0xc0) == 0x80)
+    {
+      *value = (((c & 0xf) << 12)
+               + ((p[1] & 0x3f) << 6)
+               + (p[2] & 0x3f));
+      if (*value <= 0x7ff)
+       {
+         *value = 0xfffd;
+         return 0;
+       }
+      return 3;
+    }
+  else if ((c & 0xf8) == 0xf0
+          && (p[1] & 0xc0) == 0x80
+          && (p[2] & 0xc0) == 0x80
+          && (p[3] & 0xc0) == 0x80)
+    {
+      *value = (((c & 0x7) << 18)
+               + ((p[1] & 0x3f) << 12)
+               + ((p[2] & 0x3f) << 6)
+               + (p[3] & 0x3f));
+      if (*value <= 0xffff)
+       {
+         *value = 0xfffd;
+         return 0;
+       }
+      return 4;
+    }
+  else
+    {
+      /* Invalid encoding. Return the Unicode replacement
+        character.  */
+      *value = 0xfffd;
+      return 0;
+    }
+}
+
+// Advance one UTF-8 character.  Return the pointer beyond the
+// character.  Set *VALUE to the value.  Set *ISSUED_ERROR if an error
+// was issued.
+
+const char*
+Lex::advance_one_utf8_char(const char* p, unsigned int* value,
+                          bool* issued_error)
+{
+  *issued_error = false;
+  int adv = Lex::fetch_char(p, value);
+  if (adv == 0)
+    {
+      if (*p == '\0')
+       error_at(this->location(), "invalid NUL byte");
+      else
+       error_at(this->location(), "invalid UTF-8 encoding");
+      *issued_error = true;
+      return p + 1;
+    }
+  return p + adv;
+}
+
+// Pick up an identifier.
+
+Token
+Lex::gather_identifier()
+{
+  const char* pstart = this->linebuf_ + this->lineoff_;
+  const char* p = pstart;
+  const char* pend = this->linebuf_ + this->linesize_;
+  bool is_first = true;
+  bool is_exported = false;
+  bool has_non_ascii_char = false;
+  std::string buf;
+  while (p < pend)
+    {
+      unsigned char cc = *p;
+      if (cc <= 0x7f)
+       {
+         if ((cc < 'A' || cc > 'Z')
+             && (cc < 'a' || cc > 'z')
+             && cc != '_'
+             && (cc < '0' || cc > '9'))
+           break;
+         ++p;
+         if (is_first)
+           {
+             is_exported = cc >= 'A' && cc <= 'Z';
+             is_first = false;
+           }
+         if (has_non_ascii_char)
+           buf.push_back(cc);
+       }
+      else
+       {
+         unsigned int ci;
+         bool issued_error;
+         this->lineoff_ = p - this->linebuf_;
+         const char* pnext = this->advance_one_utf8_char(p, &ci,
+                                                         &issued_error);
+         if (!Lex::is_unicode_letter(ci) && !Lex::is_unicode_digit(ci))
+           {
+             // There is no valid place for a non-ASCII character
+             // other than an identifier, so we get better error
+             // handling behaviour if we swallow this character after
+             // giving an error.
+             if (!issued_error)
+               error_at(this->location(),
+                        "invalid character 0x%x in identifier",
+                        ci);
+           }
+         if (is_first)
+           {
+             is_exported = Lex::is_unicode_uppercase(ci);
+             is_first = false;
+           }
+         if (!has_non_ascii_char)
+           {
+             buf.assign(pstart, p - pstart);
+             has_non_ascii_char = true;
+           }
+         p = pnext;
+         char ubuf[50];
+         // This assumes that all assemblers can handle an identifier
+         // with a '$' character.
+         snprintf(ubuf, sizeof ubuf, "$U%x$", ci);
+         buf.append(ubuf);
+       }
+    }
+  source_location location = this->location();
+  this->add_semi_at_eol_ = true;
+  this->lineoff_ = p - this->linebuf_;
+  if (has_non_ascii_char)
+    return Token::make_identifier_token(buf, is_exported, location);
+  else
+    {
+      Keyword code = keywords.keyword_to_code(pstart, p - pstart);
+      if (code == KEYWORD_INVALID)
+       return Token::make_identifier_token(std::string(pstart, p - pstart),
+                                           is_exported, location);
+      else
+       {
+         switch (code)
+           {
+           case KEYWORD_BREAK:
+           case KEYWORD_CONTINUE:
+           case KEYWORD_FALLTHROUGH:
+           case KEYWORD_RETURN:
+             break;
+           default:
+             this->add_semi_at_eol_ = false;
+             break;
+           }
+         return Token::make_keyword_token(code, location);
+       }
+    }
+}
+
+// Return whether C is a hex digit.
+
+bool
+Lex::is_hex_digit(char c)
+{
+  return ((c >= '0' && c <= '9')
+         || (c >= 'A' && c <= 'F')
+         || (c >= 'a' && c <= 'f'));
+}
+
+// Pick up a number.
+
+Token
+Lex::gather_number()
+{
+  const char* pstart = this->linebuf_ + this->lineoff_;
+  const char* p = pstart;
+  const char* pend = this->linebuf_ + this->linesize_;
+
+  source_location location = this->location();
+
+  bool neg = false;
+  if (*p == '+')
+    ++p;
+  else if (*p == '-')
+    {
+      ++p;
+      neg = true;
+    }
+
+  const char* pnum = p;
+  if (*p == '0')
+    {
+      int base;
+      if ((p[1] == 'x' || p[1] == 'X')
+         && Lex::is_hex_digit(p[2]))
+       {
+         base = 16;
+         p += 2;
+         pnum = p;
+         while (p < pend)
+           {
+             if (!Lex::is_hex_digit(*p))
+               break;
+             ++p;
+           }
+       }
+      else
+       {
+         base = 8;
+         pnum = p;
+         while (p < pend)
+           {
+             if (*p < '0' || *p > '7')
+               break;
+             ++p;
+           }
+       }
+
+      if (*p != '.' && *p != 'e' && *p != 'E' && *p != 'i')
+       {
+         std::string s(pnum, p - pnum);
+         mpz_t val;
+         int r = mpz_init_set_str(val, s.c_str(), base);
+         gcc_assert(r == 0);
+
+         if (neg)
+           mpz_neg(val, val);
+
+         this->lineoff_ = p - this->linebuf_;
+         Token ret = Token::make_integer_token(val, location);
+         mpz_clear(val);
+         return ret;
+       }
+    }
+
+  while (p < pend)
+    {
+      if (*p < '0' || *p > '9')
+       break;
+      ++p;
+    }
+
+  if (*p != '.' && *p != 'E' && *p != 'e' && *p != 'i')
+    {
+      std::string s(pnum, p - pnum);
+      mpz_t val;
+      int r = mpz_init_set_str(val, s.c_str(), 10);
+      gcc_assert(r == 0);
+
+      if (neg)
+       mpz_neg(val, val);
+
+      this->lineoff_ = p - this->linebuf_;
+      Token ret = Token::make_integer_token(val, location);
+      mpz_clear(val);
+      return ret;
+    }
+
+  if (*p != 'i')
+    {
+      bool dot = *p == '.';
+
+      ++p;
+
+      if (!dot)
+       {
+         if (*p == '+' || *p == '-')
+           ++p;
+       }
+
+      while (p < pend)
+       {
+         if (*p < '0' || *p > '9')
+           break;
+         ++p;
+       }
+
+      if (dot && (*p == 'E' || *p == 'e'))
+       {
+         ++p;
+         if (*p == '+' || *p == '-')
+           ++p;
+         while (p < pend)
+           {
+             if (*p < '0' || *p > '9')
+               break;
+             ++p;
+           }
+       }
+    }
+
+  std::string s(pnum, p - pnum);
+  mpfr_t val;
+  int r = mpfr_init_set_str(val, s.c_str(), 10, GMP_RNDN);
+  gcc_assert(r == 0);
+
+  if (neg)
+    mpfr_neg(val, val, GMP_RNDN);
+
+  bool is_imaginary = *p == 'i';
+  if (is_imaginary)
+    ++p;
+
+  this->lineoff_ = p - this->linebuf_;
+  if (is_imaginary)
+    {
+      Token ret = Token::make_imaginary_token(val, location);
+      mpfr_clear(val);
+      return ret;
+    }
+  else
+    {
+      Token ret = Token::make_float_token(val, location);
+      mpfr_clear(val);
+      return ret;
+    }
+}
+
+// Advance one character, possibly escaped.  Return the pointer beyond
+// the character.  Set *VALUE to the character.  Set *IS_CHARACTER if
+// this is a character (e.g., 'a' or '\u1234') rather than a byte
+// value (e.g., '\001').
+
+const char*
+Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
+                     bool* is_character)
+{
+  *value = 0;
+  *is_character = true;
+  if (*p != '\\')
+    {
+      bool issued_error;
+      const char* ret = this->advance_one_utf8_char(p, value, &issued_error);
+      if (is_single_quote
+         && (*value == '\'' || *value == '\n')
+         && !issued_error)
+       error_at(this->location(), "invalid character literal");
+      return ret;
+    }
+  else
+    {
+      ++p;
+      switch (*p)
+       {
+       case '0': case '1': case '2': case '3':
+       case '4': case '5': case '6': case '7':
+         *is_character = false;
+         if (p[1] >= '0' && p[1] <= '7'
+             && p[2] >= '0' && p[2] <= '7')
+           {
+             *value = ((Lex::octal_value(p[0]) << 6)
+                       + (Lex::octal_value(p[1]) << 3)
+                       + Lex::octal_value(p[2]));
+             if (*value > 255)
+               {
+                 error_at(this->location(), "invalid octal constant");
+                 *value = 255;
+               }
+             return p + 3;
+           }
+             error_at(this->location(), "invalid octal character");
+         return (p[1] >= '0' && p[1] <= '7'
+                 ? p + 2
+                 : p + 1);
+
+       case 'x':
+       case 'X':
+         *is_character = false;
+         if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2]))
+           {
+             *value = (hex_value(p[1]) << 4) + hex_value(p[2]);
+             return p + 3;
+           }
+         error_at(this->location(), "invalid hex character");
+         return (Lex::is_hex_digit(p[1])
+                 ? p + 2
+                 : p + 1);
+
+       case 'a':
+         *value = '\a';
+         return p + 1;
+       case 'b':
+         *value = '\b';
+         return p + 1;
+       case 'f':
+         *value = '\f';
+         return p + 1;
+       case 'n':
+         *value = '\n';
+         return p + 1;
+       case 'r':
+         *value = '\r';
+         return p + 1;
+       case 't':
+         *value = '\t';
+         return p + 1;
+       case 'v':
+         *value = '\v';
+         return p + 1;
+       case '\\':
+         *value = '\\';
+         return p + 1;
+       case '\'':
+         if (!is_single_quote)
+           error_at(this->location(), "invalid quoted character");
+         *value = '\'';
+         return p + 1;
+       case '"':
+         if (is_single_quote)
+           error_at(this->location(), "invalid quoted character");
+         *value = '"';
+         return p + 1;
+
+       case 'u':
+         if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2])
+             && Lex::is_hex_digit(p[3]) && Lex::is_hex_digit(p[4]))
+           {
+             *value = ((hex_value(p[1]) << 12)
+                       + (hex_value(p[2]) << 8)
+                       + (hex_value(p[3]) << 4)
+                       + hex_value(p[4]));
+             if (*value >= 0xd800 && *value < 0xe000)
+               {
+                 error_at(this->location(),
+                          "invalid unicode code point 0x%x",
+                          *value);
+                 // Use the replacement character.
+                 *value = 0xfffd;
+               }
+             return p + 5;
+           }
+         error_at(this->location(), "invalid little unicode code point");
+         return p + 1;
+
+       case 'U':
+         if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2])
+             && Lex::is_hex_digit(p[3]) && Lex::is_hex_digit(p[4])
+             && Lex::is_hex_digit(p[5]) && Lex::is_hex_digit(p[6])
+             && Lex::is_hex_digit(p[7]) && Lex::is_hex_digit(p[8]))
+           {
+             *value = ((hex_value(p[1]) << 28)
+                       + (hex_value(p[2]) << 24)
+                       + (hex_value(p[3]) << 20)
+                       + (hex_value(p[4]) << 16)
+                       + (hex_value(p[5]) << 12)
+                       + (hex_value(p[6]) << 8)
+                       + (hex_value(p[7]) << 4)
+                       + hex_value(p[8]));
+             if (*value > 0x10ffff
+                 || (*value >= 0xd800 && *value < 0xe000))
+               {
+                 error_at(this->location(), "invalid unicode code point 0x%x",
+                          *value);
+                 // Use the replacement character.
+                 *value = 0xfffd;
+               }
+             return p + 9;
+           }
+         error_at(this->location(), "invalid big unicode code point");
+         return p + 1;
+
+       default:
+         error_at(this->location(), "invalid character after %<\\%>");
+         *value = *p;
+         return p + 1;
+       }
+    }
+}
+
+// Append V to STR.  IS_CHARACTER is true for a character which should
+// be stored in UTF-8, false for a general byte value which should be
+// stored directly.
+
+void
+Lex::append_char(unsigned int v, bool is_character, std::string* str,
+                source_location location)
+{
+  char buf[4];
+  size_t len;
+  if (v <= 0x7f || !is_character)
+    {
+      buf[0] = v;
+      len = 1;
+    }
+  else if (v <= 0x7ff)
+    {
+      buf[0] = 0xc0 + (v >> 6);
+      buf[1] = 0x80 + (v & 0x3f);
+      len = 2;
+    }
+  else
+    {
+      if (v > 0x10ffff)
+       {
+         warning_at(location, 0,
+                    "unicode code point 0x%x out of range in string", v);
+         // Turn it into the "replacement character".
+         v = 0xfffd;
+       }
+      if (v <= 0xffff)
+       {
+         buf[0] = 0xe0 + (v >> 12);
+         buf[1] = 0x80 + ((v >> 6) & 0x3f);
+         buf[2] = 0x80 + (v & 0x3f);
+         len = 3;
+       }
+      else
+       {
+         buf[0] = 0xf0 + (v >> 18);
+         buf[1] = 0x80 + ((v >> 12) & 0x3f);
+         buf[2] = 0x80 + ((v >> 6) & 0x3f);
+         buf[3] = 0x80 + (v & 0x3f);
+         len = 4;
+       }
+    }
+  str->append(buf, len);
+}
+
+// Pick up a character literal.
+
+Token
+Lex::gather_character()
+{
+  ++this->lineoff_;
+  const char* pstart = this->linebuf_ + this->lineoff_;
+  const char* p = pstart;
+
+  unsigned int value;
+  bool is_character;
+  p = this->advance_one_char(p, true, &value, &is_character);
+
+  if (*p != '\'')
+    {
+      error_at(this->location(), "unterminated character constant");
+      this->lineoff_ = p - this->linebuf_;
+      return this->make_invalid_token();
+    }
+
+  mpz_t val;
+  mpz_init_set_ui(val, value);
+
+  source_location location = this->location();
+  this->lineoff_ = p + 1 - this->linebuf_;
+  Token ret = Token::make_integer_token(val, location);
+  mpz_clear(val);
+  return ret;
+}
+
+// Pick up a quoted string.
+
+Token
+Lex::gather_string()
+{
+  const char* pstart = this->linebuf_ + this->lineoff_ + 1;
+  const char* p = pstart;
+  const char* pend = this->linebuf_ + this->linesize_;
+
+  std::string value;
+  while (*p != '"')
+    {
+      source_location loc = this->location();
+      unsigned int c;
+      bool is_character;
+      this->lineoff_ = p - this->linebuf_;
+      p = this->advance_one_char(p, false, &c, &is_character);
+      if (p >= pend)
+       {
+         error_at(this->location(), "unterminated string");
+         --p;
+         break;
+       }
+      Lex::append_char(c, is_character, &value, loc);
+    }
+
+  source_location location = this->location();
+  this->lineoff_ = p + 1 - this->linebuf_;
+  return Token::make_string_token(value, location);
+}
+
+// Pick up a raw string.
+
+Token
+Lex::gather_raw_string()
+{
+  const char* p = this->linebuf_ + this->lineoff_ + 1;
+  const char* pend = this->linebuf_ + this->linesize_;
+  source_location location = this->location();
+
+  std::string value;
+  while (true)
+    {
+      while (p < pend)
+       {
+         if (*p == '`')
+           {
+             this->lineoff_ = p + 1 - this->linebuf_;
+             return Token::make_string_token(value, location);
+           }
+         source_location loc = this->location();
+         unsigned int c;
+         bool issued_error;
+         this->lineoff_ = p - this->linebuf_;
+         p = this->advance_one_utf8_char(p, &c, &issued_error);
+         Lex::append_char(c, true, &value, loc);
+       }
+      this->lineoff_ = p - this->linebuf_;
+      if (!this->require_line())
+       {
+         error_at(location, "unterminated raw string");
+         return Token::make_string_token(value, location);
+       }
+      p = this->linebuf_ + this->lineoff_;
+      pend = this->linebuf_ + this->linesize_;
+    }
+}
+
+// If C1 C2 C3 are a three character operator, return the code.
+
+Operator
+Lex::three_character_operator(char c1, char c2, char c3)
+{
+  if (c3 == '=')
+    {
+      if (c1 == '<' && c2 == '<')
+       return OPERATOR_LSHIFTEQ;
+      else if (c1 == '>' && c2 == '>')
+       return OPERATOR_RSHIFTEQ;
+      else if (c1 == '&' && c2 == '^')
+       return OPERATOR_BITCLEAREQ;
+    }
+  return OPERATOR_INVALID;
+}
+
+// If C1 C2 are a two character operator, return the code.
+
+Operator
+Lex::two_character_operator(char c1, char c2)
+{
+  switch (c1)
+    {
+    case '|':
+      if (c2 == '|')
+       return OPERATOR_OROR;
+      else if (c2 == '=')
+       return OPERATOR_OREQ;
+      break;
+    case '&':
+      if (c2 == '&')
+       return OPERATOR_ANDAND;
+      else if (c2 == '^')
+       return OPERATOR_BITCLEAR;
+      else if (c2 == '=')
+       return OPERATOR_ANDEQ;
+      break;
+    case '^':
+      if (c2 == '=')
+       return OPERATOR_XOREQ;
+      break;
+    case '=':
+      if (c2 == '=')
+       return OPERATOR_EQEQ;
+      break;
+    case '!':
+      if (c2 == '=')
+       return OPERATOR_NOTEQ;
+      break;
+    case '<':
+      if (c2 == '=')
+       return OPERATOR_LE;
+      else if (c2 == '<')
+       return OPERATOR_LSHIFT;
+      else if (c2 == '-')
+       return OPERATOR_CHANOP;
+      break;
+    case '>':
+      if (c2 == '=')
+       return OPERATOR_GE;
+      else if (c2 == '>')
+       return OPERATOR_RSHIFT;
+      break;
+    case '*':
+      if (c2 == '=')
+       return OPERATOR_MULTEQ;
+      break;
+    case '/':
+      if (c2 == '=')
+       return OPERATOR_DIVEQ;
+      break;
+    case '%':
+      if (c2 == '=')
+       return OPERATOR_MODEQ;
+      break;
+    case '+':
+      if (c2 == '+')
+       {
+         this->add_semi_at_eol_ = true;
+         return OPERATOR_PLUSPLUS;
+       }
+      else if (c2 == '=')
+       return OPERATOR_PLUSEQ;
+      break;
+    case '-':
+      if (c2 == '-')
+       {
+         this->add_semi_at_eol_ = true;
+         return OPERATOR_MINUSMINUS;
+       }
+      else if (c2 == '=')
+       return OPERATOR_MINUSEQ;
+      break;
+    case ':':
+      if (c2 == '=')
+       return OPERATOR_COLONEQ;
+      break;
+    default:
+      break;
+    }
+  return OPERATOR_INVALID;
+}
+
+// If character C is an operator, return the code.
+
+Operator
+Lex::one_character_operator(char c)
+{
+  switch (c)
+    {
+    case '<':
+      return OPERATOR_LT;
+    case '>':
+      return OPERATOR_GT;
+    case '+':
+      return OPERATOR_PLUS;
+    case '-':
+      return OPERATOR_MINUS;
+    case '|':
+      return OPERATOR_OR;
+    case '^':
+      return OPERATOR_XOR;
+    case '*':
+      return OPERATOR_MULT;
+    case '/':
+      return OPERATOR_DIV;
+    case '%':
+      return OPERATOR_MOD;
+    case '&':
+      return OPERATOR_AND;
+    case '!':
+      return OPERATOR_NOT;
+    case '=':
+      return OPERATOR_EQ;
+    case ':':
+      return OPERATOR_COLON;
+    case ';':
+      return OPERATOR_SEMICOLON;
+    case '.':
+      return OPERATOR_DOT;
+    case ',':
+      return OPERATOR_COMMA;
+    case '(':
+      return OPERATOR_LPAREN;
+    case ')':
+      this->add_semi_at_eol_ = true;
+      return OPERATOR_RPAREN;
+    case '{':
+      return OPERATOR_LCURLY;
+    case '}':
+      this->add_semi_at_eol_ = true;
+      return OPERATOR_RCURLY;
+    case '[':
+      return OPERATOR_LSQUARE;
+    case ']':
+      this->add_semi_at_eol_ = true;
+      return OPERATOR_RSQUARE;
+    default:
+      return OPERATOR_INVALID;
+    }
+}
+
+// Skip a C-style comment.
+
+bool
+Lex::skip_c_comment()
+{
+  while (true)
+    {
+      if (!this->require_line())
+       {
+         error_at(this->location(), "unterminated comment");
+         return false;
+       }
+
+      const char* p = this->linebuf_ + this->lineoff_;
+      const char* pend = this->linebuf_ + this->linesize_;
+
+      while (p < pend)
+       {
+         if (p[0] == '*' && p + 1 < pend && p[1] == '/')
+           {
+             this->lineoff_ = p + 2 - this->linebuf_;
+             return true;
+           }
+
+         this->lineoff_ = p - this->linebuf_;
+         unsigned int c;
+         bool issued_error;
+         p = this->advance_one_utf8_char(p, &c, &issued_error);
+       }
+
+      this->lineoff_ = p - this->linebuf_;
+    }
+}
+
+// Skip a C++-style comment.
+
+void
+Lex::skip_cpp_comment()
+{
+  const char* p = this->linebuf_ + this->lineoff_;
+  const char* pend = this->linebuf_ + this->linesize_;
+
+  // By convention, a C++ comment at the start of the line of the form
+  //   //line FILE:LINENO
+  // is interpreted as setting the file name and line number of the
+  // next source line.
+
+  if (this->lineoff_ == 2
+      && pend - p > 5
+      && memcmp(p, "line ", 5) == 0)
+    {
+      p += 5;
+      while (p < pend && *p == ' ')
+       ++p;
+      const char* pcolon = static_cast<const char*>(memchr(p, ':', pend - p));
+      if (pcolon != NULL
+         && pcolon[1] >= '0'
+         && pcolon[1] <= '9')
+       {
+         char* plend;
+         long lineno = strtol(pcolon + 1, &plend, 10);
+         if (plend > pcolon + 1
+             && (plend == pend
+                 || *plend < '0'
+                 || *plend > '9')
+             && lineno > 0
+             && lineno < 0x7fffffff)
+           {
+             unsigned int filelen = pcolon - p;
+             char* file = new char[filelen + 1];
+             memcpy(file, p, filelen);
+             file[filelen] = '\0';
+
+             linemap_add(line_table, LC_LEAVE, 0, NULL, 0);
+             linemap_add(line_table, LC_ENTER, 0, file, lineno);
+             this->lineno_ = lineno - 1;
+
+             p = plend;
+           }
+       }
+    }
+
+  while (p < pend)
+    {
+      this->lineoff_ = p - this->linebuf_;
+      unsigned int c;
+      bool issued_error;
+      p = this->advance_one_utf8_char(p, &c, &issued_error);
+    }
+}
+
+// The Unicode tables use this struct.
+
+struct Unicode_range
+{
+  // The low end of the range.
+  unsigned int low;
+  // The high end of the range.
+  unsigned int high;
+  // The stride.  This entries represents low, low + stride, low + 2 *
+  // stride, etc., up to high.
+  unsigned int stride;
+};
+
+// A table of Unicode digits--Unicode code points classified as
+// "Digit".
+
+static const Unicode_range unicode_digits[] =
+{
+  { 0x0030, 0x0039, 1},
+  { 0x0660, 0x0669, 1},
+  { 0x06f0, 0x06f9, 1},
+  { 0x07c0, 0x07c9, 1},
+  { 0x0966, 0x096f, 1},
+  { 0x09e6, 0x09ef, 1},
+  { 0x0a66, 0x0a6f, 1},
+  { 0x0ae6, 0x0aef, 1},
+  { 0x0b66, 0x0b6f, 1},
+  { 0x0be6, 0x0bef, 1},
+  { 0x0c66, 0x0c6f, 1},
+  { 0x0ce6, 0x0cef, 1},
+  { 0x0d66, 0x0d6f, 1},
+  { 0x0e50, 0x0e59, 1},
+  { 0x0ed0, 0x0ed9, 1},
+  { 0x0f20, 0x0f29, 1},
+  { 0x1040, 0x1049, 1},
+  { 0x17e0, 0x17e9, 1},
+  { 0x1810, 0x1819, 1},
+  { 0x1946, 0x194f, 1},
+  { 0x19d0, 0x19d9, 1},
+  { 0x1b50, 0x1b59, 1},
+  { 0xff10, 0xff19, 1},
+  { 0x104a0, 0x104a9, 1},
+  { 0x1d7ce, 0x1d7ff, 1},
+};
+
+// A table of Unicode letters--Unicode code points classified as
+// "Letter".
+
+static const Unicode_range unicode_letters[] =
+{
+  { 0x0041, 0x005a, 1},
+  { 0x0061, 0x007a, 1},
+  { 0x00aa, 0x00b5, 11},
+  { 0x00ba, 0x00ba, 1},
+  { 0x00c0, 0x00d6, 1},
+  { 0x00d8, 0x00f6, 1},
+  { 0x00f8, 0x02c1, 1},
+  { 0x02c6, 0x02d1, 1},
+  { 0x02e0, 0x02e4, 1},
+  { 0x02ec, 0x02ee, 2},
+  { 0x0370, 0x0374, 1},
+  { 0x0376, 0x0377, 1},
+  { 0x037a, 0x037d, 1},
+  { 0x0386, 0x0386, 1},
+  { 0x0388, 0x038a, 1},
+  { 0x038c, 0x038c, 1},
+  { 0x038e, 0x03a1, 1},
+  { 0x03a3, 0x03f5, 1},
+  { 0x03f7, 0x0481, 1},
+  { 0x048a, 0x0523, 1},
+  { 0x0531, 0x0556, 1},
+  { 0x0559, 0x0559, 1},
+  { 0x0561, 0x0587, 1},
+  { 0x05d0, 0x05ea, 1},
+  { 0x05f0, 0x05f2, 1},
+  { 0x0621, 0x064a, 1},
+  { 0x066e, 0x066f, 1},
+  { 0x0671, 0x06d3, 1},
+  { 0x06d5, 0x06d5, 1},
+  { 0x06e5, 0x06e6, 1},
+  { 0x06ee, 0x06ef, 1},
+  { 0x06fa, 0x06fc, 1},
+  { 0x06ff, 0x0710, 17},
+  { 0x0712, 0x072f, 1},
+  { 0x074d, 0x07a5, 1},
+  { 0x07b1, 0x07b1, 1},
+  { 0x07ca, 0x07ea, 1},
+  { 0x07f4, 0x07f5, 1},
+  { 0x07fa, 0x07fa, 1},
+  { 0x0904, 0x0939, 1},
+  { 0x093d, 0x0950, 19},
+  { 0x0958, 0x0961, 1},
+  { 0x0971, 0x0972, 1},
+  { 0x097b, 0x097f, 1},
+  { 0x0985, 0x098c, 1},
+  { 0x098f, 0x0990, 1},
+  { 0x0993, 0x09a8, 1},
+  { 0x09aa, 0x09b0, 1},
+  { 0x09b2, 0x09b2, 1},
+  { 0x09b6, 0x09b9, 1},
+  { 0x09bd, 0x09ce, 17},
+  { 0x09dc, 0x09dd, 1},
+  { 0x09df, 0x09e1, 1},
+  { 0x09f0, 0x09f1, 1},
+  { 0x0a05, 0x0a0a, 1},
+  { 0x0a0f, 0x0a10, 1},
+  { 0x0a13, 0x0a28, 1},
+  { 0x0a2a, 0x0a30, 1},
+  { 0x0a32, 0x0a33, 1},
+  { 0x0a35, 0x0a36, 1},
+  { 0x0a38, 0x0a39, 1},
+  { 0x0a59, 0x0a5c, 1},
+  { 0x0a5e, 0x0a5e, 1},
+  { 0x0a72, 0x0a74, 1},
+  { 0x0a85, 0x0a8d, 1},
+  { 0x0a8f, 0x0a91, 1},
+  { 0x0a93, 0x0aa8, 1},
+  { 0x0aaa, 0x0ab0, 1},
+  { 0x0ab2, 0x0ab3, 1},
+  { 0x0ab5, 0x0ab9, 1},
+  { 0x0abd, 0x0ad0, 19},
+  { 0x0ae0, 0x0ae1, 1},
+  { 0x0b05, 0x0b0c, 1},
+  { 0x0b0f, 0x0b10, 1},
+  { 0x0b13, 0x0b28, 1},
+  { 0x0b2a, 0x0b30, 1},
+  { 0x0b32, 0x0b33, 1},
+  { 0x0b35, 0x0b39, 1},
+  { 0x0b3d, 0x0b3d, 1},
+  { 0x0b5c, 0x0b5d, 1},
+  { 0x0b5f, 0x0b61, 1},
+  { 0x0b71, 0x0b83, 18},
+  { 0x0b85, 0x0b8a, 1},
+  { 0x0b8e, 0x0b90, 1},
+  { 0x0b92, 0x0b95, 1},
+  { 0x0b99, 0x0b9a, 1},
+  { 0x0b9c, 0x0b9c, 1},
+  { 0x0b9e, 0x0b9f, 1},
+  { 0x0ba3, 0x0ba4, 1},
+  { 0x0ba8, 0x0baa, 1},
+  { 0x0bae, 0x0bb9, 1},
+  { 0x0bd0, 0x0bd0, 1},
+  { 0x0c05, 0x0c0c, 1},
+  { 0x0c0e, 0x0c10, 1},
+  { 0x0c12, 0x0c28, 1},
+  { 0x0c2a, 0x0c33, 1},
+  { 0x0c35, 0x0c39, 1},
+  { 0x0c3d, 0x0c3d, 1},
+  { 0x0c58, 0x0c59, 1},
+  { 0x0c60, 0x0c61, 1},
+  { 0x0c85, 0x0c8c, 1},
+  { 0x0c8e, 0x0c90, 1},
+  { 0x0c92, 0x0ca8, 1},
+  { 0x0caa, 0x0cb3, 1},
+  { 0x0cb5, 0x0cb9, 1},
+  { 0x0cbd, 0x0cde, 33},
+  { 0x0ce0, 0x0ce1, 1},
+  { 0x0d05, 0x0d0c, 1},
+  { 0x0d0e, 0x0d10, 1},
+  { 0x0d12, 0x0d28, 1},
+  { 0x0d2a, 0x0d39, 1},
+  { 0x0d3d, 0x0d3d, 1},
+  { 0x0d60, 0x0d61, 1},
+  { 0x0d7a, 0x0d7f, 1},
+  { 0x0d85, 0x0d96, 1},
+  { 0x0d9a, 0x0db1, 1},
+  { 0x0db3, 0x0dbb, 1},
+  { 0x0dbd, 0x0dbd, 1},
+  { 0x0dc0, 0x0dc6, 1},
+  { 0x0e01, 0x0e30, 1},
+  { 0x0e32, 0x0e33, 1},
+  { 0x0e40, 0x0e46, 1},
+  { 0x0e81, 0x0e82, 1},
+  { 0x0e84, 0x0e84, 1},
+  { 0x0e87, 0x0e88, 1},
+  { 0x0e8a, 0x0e8d, 3},
+  { 0x0e94, 0x0e97, 1},
+  { 0x0e99, 0x0e9f, 1},
+  { 0x0ea1, 0x0ea3, 1},
+  { 0x0ea5, 0x0ea7, 2},
+  { 0x0eaa, 0x0eab, 1},
+  { 0x0ead, 0x0eb0, 1},
+  { 0x0eb2, 0x0eb3, 1},
+  { 0x0ebd, 0x0ebd, 1},
+  { 0x0ec0, 0x0ec4, 1},
+  { 0x0ec6, 0x0ec6, 1},
+  { 0x0edc, 0x0edd, 1},
+  { 0x0f00, 0x0f00, 1},
+  { 0x0f40, 0x0f47, 1},
+  { 0x0f49, 0x0f6c, 1},
+  { 0x0f88, 0x0f8b, 1},
+  { 0x1000, 0x102a, 1},
+  { 0x103f, 0x103f, 1},
+  { 0x1050, 0x1055, 1},
+  { 0x105a, 0x105d, 1},
+  { 0x1061, 0x1061, 1},
+  { 0x1065, 0x1066, 1},
+  { 0x106e, 0x1070, 1},
+  { 0x1075, 0x1081, 1},
+  { 0x108e, 0x108e, 1},
+  { 0x10a0, 0x10c5, 1},
+  { 0x10d0, 0x10fa, 1},
+  { 0x10fc, 0x10fc, 1},
+  { 0x1100, 0x1159, 1},
+  { 0x115f, 0x11a2, 1},
+  { 0x11a8, 0x11f9, 1},
+  { 0x1200, 0x1248, 1},
+  { 0x124a, 0x124d, 1},
+  { 0x1250, 0x1256, 1},
+  { 0x1258, 0x1258, 1},
+  { 0x125a, 0x125d, 1},
+  { 0x1260, 0x1288, 1},
+  { 0x128a, 0x128d, 1},
+  { 0x1290, 0x12b0, 1},
+  { 0x12b2, 0x12b5, 1},
+  { 0x12b8, 0x12be, 1},
+  { 0x12c0, 0x12c0, 1},
+  { 0x12c2, 0x12c5, 1},
+  { 0x12c8, 0x12d6, 1},
+  { 0x12d8, 0x1310, 1},
+  { 0x1312, 0x1315, 1},
+  { 0x1318, 0x135a, 1},
+  { 0x1380, 0x138f, 1},
+  { 0x13a0, 0x13f4, 1},
+  { 0x1401, 0x166c, 1},
+  { 0x166f, 0x1676, 1},
+  { 0x1681, 0x169a, 1},
+  { 0x16a0, 0x16ea, 1},
+  { 0x1700, 0x170c, 1},
+  { 0x170e, 0x1711, 1},
+  { 0x1720, 0x1731, 1},
+  { 0x1740, 0x1751, 1},
+  { 0x1760, 0x176c, 1},
+  { 0x176e, 0x1770, 1},
+  { 0x1780, 0x17b3, 1},
+  { 0x17d7, 0x17dc, 5},
+  { 0x1820, 0x1877, 1},
+  { 0x1880, 0x18a8, 1},
+  { 0x18aa, 0x18aa, 1},
+  { 0x1900, 0x191c, 1},
+  { 0x1950, 0x196d, 1},
+  { 0x1970, 0x1974, 1},
+  { 0x1980, 0x19a9, 1},
+  { 0x19c1, 0x19c7, 1},
+  { 0x1a00, 0x1a16, 1},
+  { 0x1b05, 0x1b33, 1},
+  { 0x1b45, 0x1b4b, 1},
+  { 0x1b83, 0x1ba0, 1},
+  { 0x1bae, 0x1baf, 1},
+  { 0x1c00, 0x1c23, 1},
+  { 0x1c4d, 0x1c4f, 1},
+  { 0x1c5a, 0x1c7d, 1},
+  { 0x1d00, 0x1dbf, 1},
+  { 0x1e00, 0x1f15, 1},
+  { 0x1f18, 0x1f1d, 1},
+  { 0x1f20, 0x1f45, 1},
+  { 0x1f48, 0x1f4d, 1},
+  { 0x1f50, 0x1f57, 1},
+  { 0x1f59, 0x1f5d, 2},
+  { 0x1f5f, 0x1f7d, 1},
+  { 0x1f80, 0x1fb4, 1},
+  { 0x1fb6, 0x1fbc, 1},
+  { 0x1fbe, 0x1fbe, 1},
+  { 0x1fc2, 0x1fc4, 1},
+  { 0x1fc6, 0x1fcc, 1},
+  { 0x1fd0, 0x1fd3, 1},
+  { 0x1fd6, 0x1fdb, 1},
+  { 0x1fe0, 0x1fec, 1},
+  { 0x1ff2, 0x1ff4, 1},
+  { 0x1ff6, 0x1ffc, 1},
+  { 0x2071, 0x207f, 14},
+  { 0x2090, 0x2094, 1},
+  { 0x2102, 0x2107, 5},
+  { 0x210a, 0x2113, 1},
+  { 0x2115, 0x2115, 1},
+  { 0x2119, 0x211d, 1},
+  { 0x2124, 0x2128, 2},
+  { 0x212a, 0x212d, 1},
+  { 0x212f, 0x2139, 1},
+  { 0x213c, 0x213f, 1},
+  { 0x2145, 0x2149, 1},
+  { 0x214e, 0x214e, 1},
+  { 0x2183, 0x2184, 1},
+  { 0x2c00, 0x2c2e, 1},
+  { 0x2c30, 0x2c5e, 1},
+  { 0x2c60, 0x2c6f, 1},
+  { 0x2c71, 0x2c7d, 1},
+  { 0x2c80, 0x2ce4, 1},
+  { 0x2d00, 0x2d25, 1},
+  { 0x2d30, 0x2d65, 1},
+  { 0x2d6f, 0x2d6f, 1},
+  { 0x2d80, 0x2d96, 1},
+  { 0x2da0, 0x2da6, 1},
+  { 0x2da8, 0x2dae, 1},
+  { 0x2db0, 0x2db6, 1},
+  { 0x2db8, 0x2dbe, 1},
+  { 0x2dc0, 0x2dc6, 1},
+  { 0x2dc8, 0x2dce, 1},
+  { 0x2dd0, 0x2dd6, 1},
+  { 0x2dd8, 0x2dde, 1},
+  { 0x2e2f, 0x2e2f, 1},
+  { 0x3005, 0x3006, 1},
+  { 0x3031, 0x3035, 1},
+  { 0x303b, 0x303c, 1},
+  { 0x3041, 0x3096, 1},
+  { 0x309d, 0x309f, 1},
+  { 0x30a1, 0x30fa, 1},
+  { 0x30fc, 0x30ff, 1},
+  { 0x3105, 0x312d, 1},
+  { 0x3131, 0x318e, 1},
+  { 0x31a0, 0x31b7, 1},
+  { 0x31f0, 0x31ff, 1},
+  { 0x3400, 0x4db5, 1},
+  { 0x4e00, 0x9fc3, 1},
+  { 0xa000, 0xa48c, 1},
+  { 0xa500, 0xa60c, 1},
+  { 0xa610, 0xa61f, 1},
+  { 0xa62a, 0xa62b, 1},
+  { 0xa640, 0xa65f, 1},
+  { 0xa662, 0xa66e, 1},
+  { 0xa67f, 0xa697, 1},
+  { 0xa717, 0xa71f, 1},
+  { 0xa722, 0xa788, 1},
+  { 0xa78b, 0xa78c, 1},
+  { 0xa7fb, 0xa801, 1},
+  { 0xa803, 0xa805, 1},
+  { 0xa807, 0xa80a, 1},
+  { 0xa80c, 0xa822, 1},
+  { 0xa840, 0xa873, 1},
+  { 0xa882, 0xa8b3, 1},
+  { 0xa90a, 0xa925, 1},
+  { 0xa930, 0xa946, 1},
+  { 0xaa00, 0xaa28, 1},
+  { 0xaa40, 0xaa42, 1},
+  { 0xaa44, 0xaa4b, 1},
+  { 0xac00, 0xd7a3, 1},
+  { 0xf900, 0xfa2d, 1},
+  { 0xfa30, 0xfa6a, 1},
+  { 0xfa70, 0xfad9, 1},
+  { 0xfb00, 0xfb06, 1},
+  { 0xfb13, 0xfb17, 1},
+  { 0xfb1d, 0xfb1d, 1},
+  { 0xfb1f, 0xfb28, 1},
+  { 0xfb2a, 0xfb36, 1},
+  { 0xfb38, 0xfb3c, 1},
+  { 0xfb3e, 0xfb3e, 1},
+  { 0xfb40, 0xfb41, 1},
+  { 0xfb43, 0xfb44, 1},
+  { 0xfb46, 0xfbb1, 1},
+  { 0xfbd3, 0xfd3d, 1},
+  { 0xfd50, 0xfd8f, 1},
+  { 0xfd92, 0xfdc7, 1},
+  { 0xfdf0, 0xfdfb, 1},
+  { 0xfe70, 0xfe74, 1},
+  { 0xfe76, 0xfefc, 1},
+  { 0xff21, 0xff3a, 1},
+  { 0xff41, 0xff5a, 1},
+  { 0xff66, 0xffbe, 1},
+  { 0xffc2, 0xffc7, 1},
+  { 0xffca, 0xffcf, 1},
+  { 0xffd2, 0xffd7, 1},
+  { 0xffda, 0xffdc, 1},
+  { 0x10000, 0x1000b, 1},
+  { 0x1000d, 0x10026, 1},
+  { 0x10028, 0x1003a, 1},
+  { 0x1003c, 0x1003d, 1},
+  { 0x1003f, 0x1004d, 1},
+  { 0x10050, 0x1005d, 1},
+  { 0x10080, 0x100fa, 1},
+  { 0x10280, 0x1029c, 1},
+  { 0x102a0, 0x102d0, 1},
+  { 0x10300, 0x1031e, 1},
+  { 0x10330, 0x10340, 1},
+  { 0x10342, 0x10349, 1},
+  { 0x10380, 0x1039d, 1},
+  { 0x103a0, 0x103c3, 1},
+  { 0x103c8, 0x103cf, 1},
+  { 0x10400, 0x1049d, 1},
+  { 0x10800, 0x10805, 1},
+  { 0x10808, 0x10808, 1},
+  { 0x1080a, 0x10835, 1},
+  { 0x10837, 0x10838, 1},
+  { 0x1083c, 0x1083f, 3},
+  { 0x10900, 0x10915, 1},
+  { 0x10920, 0x10939, 1},
+  { 0x10a00, 0x10a00, 1},
+  { 0x10a10, 0x10a13, 1},
+  { 0x10a15, 0x10a17, 1},
+  { 0x10a19, 0x10a33, 1},
+  { 0x12000, 0x1236e, 1},
+  { 0x1d400, 0x1d454, 1},
+  { 0x1d456, 0x1d49c, 1},
+  { 0x1d49e, 0x1d49f, 1},
+  { 0x1d4a2, 0x1d4a2, 1},
+  { 0x1d4a5, 0x1d4a6, 1},
+  { 0x1d4a9, 0x1d4ac, 1},
+  { 0x1d4ae, 0x1d4b9, 1},
+  { 0x1d4bb, 0x1d4bb, 1},
+  { 0x1d4bd, 0x1d4c3, 1},
+  { 0x1d4c5, 0x1d505, 1},
+  { 0x1d507, 0x1d50a, 1},
+  { 0x1d50d, 0x1d514, 1},
+  { 0x1d516, 0x1d51c, 1},
+  { 0x1d51e, 0x1d539, 1},
+  { 0x1d53b, 0x1d53e, 1},
+  { 0x1d540, 0x1d544, 1},
+  { 0x1d546, 0x1d546, 1},
+  { 0x1d54a, 0x1d550, 1},
+  { 0x1d552, 0x1d6a5, 1},
+  { 0x1d6a8, 0x1d6c0, 1},
+  { 0x1d6c2, 0x1d6da, 1},
+  { 0x1d6dc, 0x1d6fa, 1},
+  { 0x1d6fc, 0x1d714, 1},
+  { 0x1d716, 0x1d734, 1},
+  { 0x1d736, 0x1d74e, 1},
+  { 0x1d750, 0x1d76e, 1},
+  { 0x1d770, 0x1d788, 1},
+  { 0x1d78a, 0x1d7a8, 1},
+  { 0x1d7aa, 0x1d7c2, 1},
+  { 0x1d7c4, 0x1d7cb, 1},
+  { 0x20000, 0x2a6d6, 1},
+  { 0x2f800, 0x2fa1d, 1},
+};
+
+// A table of Unicode uppercase letters--Unicode code points
+// classified as "Letter, uppercase".
+
+static const Unicode_range unicode_uppercase_letters[] =
+{
+  { 0x0041, 0x005a, 1},
+  { 0x00c0, 0x00d6, 1},
+  { 0x00d8, 0x00de, 1},
+  { 0x0100, 0x0136, 2},
+  { 0x0139, 0x0147, 2},
+  { 0x014a, 0x0176, 2},
+  { 0x0178, 0x0179, 1},
+  { 0x017b, 0x017d, 2},
+  { 0x0181, 0x0182, 1},
+  { 0x0184, 0x0184, 1},
+  { 0x0186, 0x0187, 1},
+  { 0x0189, 0x018b, 1},
+  { 0x018e, 0x0191, 1},
+  { 0x0193, 0x0194, 1},
+  { 0x0196, 0x0198, 1},
+  { 0x019c, 0x019d, 1},
+  { 0x019f, 0x01a0, 1},
+  { 0x01a2, 0x01a4, 2},
+  { 0x01a6, 0x01a7, 1},
+  { 0x01a9, 0x01ac, 3},
+  { 0x01ae, 0x01af, 1},
+  { 0x01b1, 0x01b3, 1},
+  { 0x01b5, 0x01b5, 1},
+  { 0x01b7, 0x01b8, 1},
+  { 0x01bc, 0x01c4, 8},
+  { 0x01c7, 0x01cd, 3},
+  { 0x01cf, 0x01db, 2},
+  { 0x01de, 0x01ee, 2},
+  { 0x01f1, 0x01f4, 3},
+  { 0x01f6, 0x01f8, 1},
+  { 0x01fa, 0x0232, 2},
+  { 0x023a, 0x023b, 1},
+  { 0x023d, 0x023e, 1},
+  { 0x0241, 0x0241, 1},
+  { 0x0243, 0x0246, 1},
+  { 0x0248, 0x024e, 2},
+  { 0x0370, 0x0372, 2},
+  { 0x0376, 0x0386, 16},
+  { 0x0388, 0x038a, 1},
+  { 0x038c, 0x038c, 1},
+  { 0x038e, 0x038f, 1},
+  { 0x0391, 0x03a1, 1},
+  { 0x03a3, 0x03ab, 1},
+  { 0x03cf, 0x03cf, 1},
+  { 0x03d2, 0x03d4, 1},
+  { 0x03d8, 0x03ee, 2},
+  { 0x03f4, 0x03f7, 3},
+  { 0x03f9, 0x03fa, 1},
+  { 0x03fd, 0x042f, 1},
+  { 0x0460, 0x0480, 2},
+  { 0x048a, 0x04be, 2},
+  { 0x04c0, 0x04c1, 1},
+  { 0x04c3, 0x04cd, 2},
+  { 0x04d0, 0x0522, 2},
+  { 0x0531, 0x0556, 1},
+  { 0x10a0, 0x10c5, 1},
+  { 0x1e00, 0x1e94, 2},
+  { 0x1e9e, 0x1efe, 2},
+  { 0x1f08, 0x1f0f, 1},
+  { 0x1f18, 0x1f1d, 1},
+  { 0x1f28, 0x1f2f, 1},
+  { 0x1f38, 0x1f3f, 1},
+  { 0x1f48, 0x1f4d, 1},
+  { 0x1f59, 0x1f5f, 2},
+  { 0x1f68, 0x1f6f, 1},
+  { 0x1fb8, 0x1fbb, 1},
+  { 0x1fc8, 0x1fcb, 1},
+  { 0x1fd8, 0x1fdb, 1},
+  { 0x1fe8, 0x1fec, 1},
+  { 0x1ff8, 0x1ffb, 1},
+  { 0x2102, 0x2107, 5},
+  { 0x210b, 0x210d, 1},
+  { 0x2110, 0x2112, 1},
+  { 0x2115, 0x2115, 1},
+  { 0x2119, 0x211d, 1},
+  { 0x2124, 0x2128, 2},
+  { 0x212a, 0x212d, 1},
+  { 0x2130, 0x2133, 1},
+  { 0x213e, 0x213f, 1},
+  { 0x2145, 0x2183, 62},
+  { 0x2c00, 0x2c2e, 1},
+  { 0x2c60, 0x2c60, 1},
+  { 0x2c62, 0x2c64, 1},
+  { 0x2c67, 0x2c6b, 2},
+  { 0x2c6d, 0x2c6f, 1},
+  { 0x2c72, 0x2c75, 3},
+  { 0x2c80, 0x2ce2, 2},
+  { 0xa640, 0xa65e, 2},
+  { 0xa662, 0xa66c, 2},
+  { 0xa680, 0xa696, 2},
+  { 0xa722, 0xa72e, 2},
+  { 0xa732, 0xa76e, 2},
+  { 0xa779, 0xa77b, 2},
+  { 0xa77d, 0xa77e, 1},
+  { 0xa780, 0xa786, 2},
+  { 0xa78b, 0xa78b, 1},
+  { 0xff21, 0xff3a, 1},
+  { 0x10400, 0x10427, 1},
+  { 0x1d400, 0x1d419, 1},
+  { 0x1d434, 0x1d44d, 1},
+  { 0x1d468, 0x1d481, 1},
+  { 0x1d49c, 0x1d49c, 1},
+  { 0x1d49e, 0x1d49f, 1},
+  { 0x1d4a2, 0x1d4a2, 1},
+  { 0x1d4a5, 0x1d4a6, 1},
+  { 0x1d4a9, 0x1d4ac, 1},
+  { 0x1d4ae, 0x1d4b5, 1},
+  { 0x1d4d0, 0x1d4e9, 1},
+  { 0x1d504, 0x1d505, 1},
+  { 0x1d507, 0x1d50a, 1},
+  { 0x1d50d, 0x1d514, 1},
+  { 0x1d516, 0x1d51c, 1},
+  { 0x1d538, 0x1d539, 1},
+  { 0x1d53b, 0x1d53e, 1},
+  { 0x1d540, 0x1d544, 1},
+  { 0x1d546, 0x1d546, 1},
+  { 0x1d54a, 0x1d550, 1},
+  { 0x1d56c, 0x1d585, 1},
+  { 0x1d5a0, 0x1d5b9, 1},
+  { 0x1d5d4, 0x1d5ed, 1},
+  { 0x1d608, 0x1d621, 1},
+  { 0x1d63c, 0x1d655, 1},
+  { 0x1d670, 0x1d689, 1},
+  { 0x1d6a8, 0x1d6c0, 1},
+  { 0x1d6e2, 0x1d6fa, 1},
+  { 0x1d71c, 0x1d734, 1},
+  { 0x1d756, 0x1d76e, 1},
+  { 0x1d790, 0x1d7a8, 1},
+  { 0x1d7ca, 0x1d7ca, 1},
+};
+
+// Return true if C is in RANGES.
+
+bool
+Lex::is_in_unicode_range(unsigned int c, const Unicode_range* ranges,
+                        size_t range_size)
+{
+  if (c < 0x100)
+    {
+      // The common case is a small value, and we know that it will be
+      // in the first few entries of the table.  Do a linear scan
+      // rather than a binary search.
+      for (size_t i = 0; i < range_size; ++i)
+       {
+         const Unicode_range* p = &ranges[i];
+         if (c <= p->high)
+           {
+             if (c < p->low)
+               return false;
+             return (c - p->low) % p->stride == 0;
+           }
+       }
+      return false;
+    }
+  else
+    {
+      size_t lo = 0;
+      size_t hi = range_size;
+      while (lo < hi)
+       {
+         size_t mid = lo + (hi - lo) / 2;
+         const Unicode_range* p = &ranges[mid];
+         if (c < p->low)
+           hi = mid;
+         else if (c > p->high)
+           lo = mid + 1;
+         else
+           return (c - p->low) % p->stride == 0;
+       }
+      return false;
+    }
+}
+
+// Return whether C is a Unicode digit--a Unicode code point
+// classified as "Digit".
+
+bool
+Lex::is_unicode_digit(unsigned int c)
+{
+  return Lex::is_in_unicode_range(c, unicode_digits,
+                                 ARRAY_SIZE(unicode_digits));
+}
+
+// Return whether C is a Unicode letter--a Unicode code point
+// classified as "Letter".
+
+bool
+Lex::is_unicode_letter(unsigned int c)
+{
+  return Lex::is_in_unicode_range(c, unicode_letters,
+                                 ARRAY_SIZE(unicode_letters));
+}
+
+// Return whether C is a Unicode uppercase letter.  a Unicode code
+// point classified as "Letter, uppercase".
+
+bool
+Lex::is_unicode_uppercase(unsigned int c)
+{
+  return Lex::is_in_unicode_range(c, unicode_uppercase_letters,
+                                 ARRAY_SIZE(unicode_uppercase_letters));
+}
+
+// Return whether the identifier NAME should be exported.  NAME is a
+// mangled name which includes only ASCII characters.
+
+bool
+Lex::is_exported_name(const std::string& name)
+{
+  unsigned char c = name[0];
+  if (c != '$')
+    return c >= 'A' && c <= 'Z';
+  else
+    {
+      const char* p = name.data();
+      size_t len = name.length();
+      if (len < 2 || p[1] != 'U')
+       return false;
+      unsigned int ci = 0;
+      for (size_t i = 2; i < len && p[i] != '$'; ++i)
+       {
+         c = p[i];
+         if (!hex_p(c))
+           return false;
+         ci <<= 4;
+         ci |= hex_value(c);
+       }
+      return Lex::is_unicode_uppercase(ci);
+    }
+}
diff --git a/gcc/go/gofrontend/lex.h b/gcc/go/gofrontend/lex.h
new file mode 100644 (file)
index 0000000..c8def2b
--- /dev/null
@@ -0,0 +1,446 @@
+// lex.h -- Go frontend lexer.     -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_LEX_H
+#define GO_LEX_H
+
+#include <gmp.h>
+#include <mpfr.h>
+
+#include "operator.h"
+
+struct Unicode_range;
+
+// The keywords.  These must be in sorted order, other than
+// KEYWORD_INVALID.  They must match the Keywords::mapping_ array in
+// lex.cc.
+
+enum Keyword
+{
+  KEYWORD_INVALID,     // Not a keyword.
+  KEYWORD_ASM,
+  KEYWORD_BREAK,
+  KEYWORD_CASE,
+  KEYWORD_CHAN,
+  KEYWORD_CONST,
+  KEYWORD_CONTINUE,
+  KEYWORD_DEFAULT,
+  KEYWORD_DEFER,
+  KEYWORD_ELSE,
+  KEYWORD_FALLTHROUGH,
+  KEYWORD_FOR,
+  KEYWORD_FUNC,
+  KEYWORD_GO,
+  KEYWORD_GOTO,
+  KEYWORD_IF,
+  KEYWORD_IMPORT,
+  KEYWORD_INTERFACE,
+  KEYWORD_MAP,
+  KEYWORD_PACKAGE,
+  KEYWORD_RANGE,
+  KEYWORD_RETURN,
+  KEYWORD_SELECT,
+  KEYWORD_STRUCT,
+  KEYWORD_SWITCH,
+  KEYWORD_TYPE,
+  KEYWORD_VAR
+};
+
+// A token returned from the lexer.
+
+class Token
+{
+ public:
+  // Token classification.
+  enum Classification
+  {
+    // Token is invalid.
+    TOKEN_INVALID,
+    // Token indicates end of input.
+    TOKEN_EOF,
+    // Token is a keyword.
+    TOKEN_KEYWORD,
+    // Token is an identifier.
+    TOKEN_IDENTIFIER,
+    // Token is a string of characters.
+    TOKEN_STRING,
+    // Token is an operator.
+    TOKEN_OPERATOR,
+    // Token is an integer.
+    TOKEN_INTEGER,
+    // Token is a floating point number.
+    TOKEN_FLOAT,
+    // Token is an imaginary number.
+    TOKEN_IMAGINARY
+  };
+
+  ~Token();
+  Token(const Token&);
+  Token& operator=(const Token&);
+
+  // Get token classification.
+  Classification
+  classification() const
+  { return this->classification_; }
+
+  // Make a token for an invalid value.
+  static Token
+  make_invalid_token(source_location location)
+  { return Token(TOKEN_INVALID, location); }
+
+  // Make a token representing end of file.
+  static Token
+  make_eof_token(source_location location)
+  { return Token(TOKEN_EOF, location); }
+
+  // Make a keyword token.
+  static Token
+  make_keyword_token(Keyword keyword, source_location location)
+  {
+    Token tok(TOKEN_KEYWORD, location);
+    tok.u_.keyword = keyword;
+    return tok;
+  }
+
+  // Make an identifier token.
+  static Token
+  make_identifier_token(const std::string& value, bool is_exported,
+                       source_location location)
+  {
+    Token tok(TOKEN_IDENTIFIER, location);
+    tok.u_.identifier_value.name = new std::string(value);
+    tok.u_.identifier_value.is_exported = is_exported;
+    return tok;
+  }
+
+  // Make a quoted string token.
+  static Token
+  make_string_token(const std::string& value, source_location location)
+  {
+    Token tok(TOKEN_STRING, location);
+    tok.u_.string_value = new std::string(value);
+    return tok;
+  }
+
+  // Make an operator token.
+  static Token
+  make_operator_token(Operator op, source_location location)
+  {
+    Token tok(TOKEN_OPERATOR, location);
+    tok.u_.op = op;
+    return tok;
+  }
+
+  // Make an integer token.
+  static Token
+  make_integer_token(mpz_t val, source_location location)
+  {
+    Token tok(TOKEN_INTEGER, location);
+    mpz_init(tok.u_.integer_value);
+    mpz_swap(tok.u_.integer_value, val);
+    return tok;
+  }
+
+  // Make a float token.
+  static Token
+  make_float_token(mpfr_t val, source_location location)
+  {
+    Token tok(TOKEN_FLOAT, location);
+    mpfr_init(tok.u_.float_value);
+    mpfr_swap(tok.u_.float_value, val);
+    return tok;
+  }
+
+  // Make a token for an imaginary number.
+  static Token
+  make_imaginary_token(mpfr_t val, source_location location)
+  {
+    Token tok(TOKEN_IMAGINARY, location);
+    mpfr_init(tok.u_.float_value);
+    mpfr_swap(tok.u_.float_value, val);
+    return tok;
+  }
+
+  // Get the location of the token.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Return whether this is an invalid token.
+  bool
+  is_invalid() const
+  { return this->classification_ == TOKEN_INVALID; }
+
+  // Return whether this is the EOF token.
+  bool
+  is_eof() const
+  { return this->classification_ == TOKEN_EOF; }
+
+  // Return the keyword value for a keyword token.
+  Keyword
+  keyword() const
+  {
+    gcc_assert(this->classification_ == TOKEN_KEYWORD);
+    return this->u_.keyword;
+  }
+
+  // Return whether this is an identifier.
+  bool
+  is_identifier() const
+  { return this->classification_ == TOKEN_IDENTIFIER; }
+
+  // Return the identifier.
+  const std::string&
+  identifier() const
+  {
+    gcc_assert(this->classification_ == TOKEN_IDENTIFIER);
+    return *this->u_.identifier_value.name;
+  }
+
+  // Return whether the identifier is exported.
+  bool
+  is_identifier_exported() const
+  {
+    gcc_assert(this->classification_ == TOKEN_IDENTIFIER);
+    return this->u_.identifier_value.is_exported;
+  }
+
+  // Return whether this is a string.
+  bool
+  is_string() const
+  {
+    return this->classification_ == TOKEN_STRING;
+  }
+
+  // Return the value of a string.  The returned value is a string of
+  // UTF-8 characters.
+  std::string
+  string_value() const
+  {
+    gcc_assert(this->classification_ == TOKEN_STRING);
+    return *this->u_.string_value;
+  }
+
+  // Return the value of an integer.
+  const mpz_t*
+  integer_value() const
+  {
+    gcc_assert(this->classification_ == TOKEN_INTEGER);
+    return &this->u_.integer_value;
+  }
+
+  // Return the value of a float.
+  const mpfr_t*
+  float_value() const
+  {
+    gcc_assert(this->classification_ == TOKEN_FLOAT);
+    return &this->u_.float_value;
+  }
+
+  // Return the value of an imaginary number.
+  const mpfr_t*
+  imaginary_value() const
+  {
+    gcc_assert(this->classification_ == TOKEN_IMAGINARY);
+    return &this->u_.float_value;
+  }
+
+  // Return the operator value for an operator token.
+  Operator
+  op() const
+  {
+    gcc_assert(this->classification_ == TOKEN_OPERATOR);
+    return this->u_.op;
+  }
+
+  // Return whether this token is KEYWORD.
+  bool
+  is_keyword(Keyword keyword) const
+  {
+    return (this->classification_ == TOKEN_KEYWORD
+           && this->u_.keyword == keyword);
+  }
+
+  // Return whether this token is OP.
+  bool
+  is_op(Operator op) const
+  { return this->classification_ == TOKEN_OPERATOR && this->u_.op == op; }
+
+  // Print the token for debugging.
+  void
+  print(FILE*) const;
+
+ private:
+  // Private constructor used by make_..._token functions above.
+  Token(Classification, source_location);
+
+  // Clear the token.
+  void
+  clear();
+
+  // The token classification.
+  Classification classification_;
+  union
+  {
+    // The keyword value for TOKEN_KEYWORD.
+    Keyword keyword;
+    // The token value for TOKEN_IDENTIFIER.
+    struct
+    {
+      // The name of the identifier.  This has been mangled to only
+      // include ASCII characters.
+      std::string* name;
+      // Whether this name should be exported.  This is true if the
+      // first letter in the name is upper case.
+      bool is_exported;
+    } identifier_value;
+    // The string value for TOKEN_STRING.
+    std::string* string_value;
+    // The token value for TOKEN_INTEGER.
+    mpz_t integer_value;
+    // The token value for TOKEN_FLOAT or TOKEN_IMAGINARY.
+    mpfr_t float_value;
+    // The token value for TOKEN_OPERATOR or the keyword value
+    Operator op;
+  } u_;
+  // The source location.
+  source_location location_;
+};
+
+// The lexer itself.
+
+class Lex
+{
+ public:
+  Lex(const char* input_file_name, FILE* input_file);
+
+  ~Lex();
+
+  // Return the next token.
+  Token
+  next_token();
+
+  // Return whether the identifier NAME should be exported.  NAME is a
+  // mangled name which includes only ASCII characters.
+  static bool
+  is_exported_name(const std::string& name);
+
+  // A helper function.  Append V to STR.  IS_CHARACTER is true if V
+  // is a Unicode character which should be converted into UTF-8,
+  // false if it is a byte value to be appended directly.  The
+  // location is used to warn about an out of range character.
+  static void
+  append_char(unsigned int v, bool is_charater, std::string* str,
+             source_location);
+
+  // A helper function.  Fetch a UTF-8 character from STR and store it
+  // in *VALUE.  Return the number of bytes read from STR.  Return 0
+  // if STR does not point to a valid UTF-8 character.
+  static int
+  fetch_char(const char* str, unsigned int *value);
+
+ private:
+  ssize_t
+  get_line();
+
+  bool
+  require_line();
+
+  // The current location.
+  source_location
+  location() const;
+
+  // A position CHARS column positions before the current location.
+  source_location
+  earlier_location(int chars) const;
+
+  static bool
+  is_hex_digit(char);
+
+  static unsigned char
+  octal_value(char c)
+  { return c - '0'; }
+
+  Token
+  make_invalid_token()
+  { return Token::make_invalid_token(this->location()); }
+
+  Token
+  make_eof_token()
+  { return Token::make_eof_token(this->location()); }
+
+  Token
+  make_operator(Operator op, int chars)
+  { return Token::make_operator_token(op, this->earlier_location(chars)); }
+
+  Token
+  gather_identifier();
+
+  Token
+  gather_number();
+
+  Token
+  gather_character();
+
+  Token
+  gather_string();
+
+  Token
+  gather_raw_string();
+
+  const char*
+  advance_one_utf8_char(const char*, unsigned int*, bool*);
+
+  const char*
+  advance_one_char(const char*, bool, unsigned int*, bool*);
+
+  static bool
+  is_unicode_digit(unsigned int c);
+
+  static bool
+  is_unicode_letter(unsigned int c);
+
+  static bool
+  is_unicode_uppercase(unsigned int c);
+
+  static bool
+  is_in_unicode_range(unsigned int C, const Unicode_range* ranges,
+                     size_t range_size);
+
+  Operator
+  three_character_operator(char, char, char);
+
+  Operator
+  two_character_operator(char, char);
+
+  Operator
+  one_character_operator(char);
+
+  bool
+  skip_c_comment();
+
+  void
+  skip_cpp_comment();
+
+  // The input file name.
+  const char* input_file_name_;
+  // The input file.
+  FILE* input_file_;
+  // The line buffer.  This holds the current line.
+  char* linebuf_;
+  // The size of the line buffer.
+  size_t linebufsize_;
+  // The nmber of characters in the current line.
+  size_t linesize_;
+  // The current offset in linebuf_.
+  size_t lineoff_;
+  // The current line number.
+  size_t lineno_;
+  // Whether to add a semicolon if we see a newline now.
+  bool add_semi_at_eol_;
+};
+
+#endif // !defined(GO_LEX_H)
diff --git a/gcc/go/gofrontend/operator.h b/gcc/go/gofrontend/operator.h
new file mode 100644 (file)
index 0000000..f3e0fd0
--- /dev/null
@@ -0,0 +1,66 @@
+// operator.h -- Go frontend operators.     -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_OPERATOR_H
+#define GO_OPERATOR_H
+
+// The operators.
+
+enum Operator
+{
+  OPERATOR_INVALID,
+  OPERATOR_OROR,       // ||
+  OPERATOR_ANDAND,     // &&
+  OPERATOR_EQEQ,       // ==
+  OPERATOR_NOTEQ,      // !=
+  OPERATOR_LT,         // <
+  OPERATOR_LE,         // <=
+  OPERATOR_GT,         // >
+  OPERATOR_GE,         // >=
+  OPERATOR_PLUS,       // +
+  OPERATOR_MINUS,      // -
+  OPERATOR_OR,         // |
+  OPERATOR_XOR,                // ^
+  OPERATOR_MULT,       // *
+  OPERATOR_DIV,                // /
+  OPERATOR_MOD,                // %
+  OPERATOR_LSHIFT,     // <<
+  OPERATOR_RSHIFT,     // >>
+  OPERATOR_AND,                // &
+  OPERATOR_NOT,                // !
+  OPERATOR_BITCLEAR,   // &^
+  OPERATOR_CHANOP,     // <-
+
+  OPERATOR_EQ,         // =
+  OPERATOR_PLUSEQ,     // +=
+  OPERATOR_MINUSEQ,    // -=
+  OPERATOR_OREQ,       // |=
+  OPERATOR_XOREQ,      // ^=
+  OPERATOR_MULTEQ,     // *=
+  OPERATOR_DIVEQ,      // /=
+  OPERATOR_MODEQ,      // %=
+  OPERATOR_LSHIFTEQ,   // <<=
+  OPERATOR_RSHIFTEQ,   // >>=
+  OPERATOR_ANDEQ,      // &=
+  OPERATOR_BITCLEAREQ, // &^=
+  OPERATOR_PLUSPLUS,   // ++
+  OPERATOR_MINUSMINUS, // --
+
+  OPERATOR_COLON,      // :
+  OPERATOR_COLONEQ,    // :=
+  OPERATOR_SEMICOLON,  // ;
+  OPERATOR_DOT,                // .
+  OPERATOR_ELLIPSIS,   // ...
+  OPERATOR_COMMA,      // ,
+  OPERATOR_LPAREN,     // (
+  OPERATOR_RPAREN,     // )
+  OPERATOR_LCURLY,     // {
+  OPERATOR_RCURLY,     // }
+  OPERATOR_LSQUARE,    // [
+  OPERATOR_RSQUARE     // ]
+};
+
+#endif // !defined(GO_OPERATOR_H)
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
new file mode 100644 (file)
index 0000000..c8b55c5
--- /dev/null
@@ -0,0 +1,4730 @@
+// parse.cc -- Go frontend parser.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "lex.h"
+#include "gogo.h"
+#include "types.h"
+#include "statements.h"
+#include "expressions.h"
+#include "parse.h"
+
+// Struct Parse::Enclosing_var_comparison.
+
+// Return true if v1 should be considered to be less than v2.
+
+bool
+Parse::Enclosing_var_comparison::operator()(const Enclosing_var& v1,
+                                           const Enclosing_var& v2)
+{
+  if (v1.var() == v2.var())
+    return false;
+
+  const std::string& n1(v1.var()->name());
+  const std::string& n2(v2.var()->name());
+  int i = n1.compare(n2);
+  if (i < 0)
+    return true;
+  else if (i > 0)
+    return false;
+
+  // If we get here it means that a single nested function refers to
+  // two different variables defined in enclosing functions, and both
+  // variables have the same name.  I think this is impossible.
+  gcc_unreachable();
+}
+
+// Class Parse.
+
+Parse::Parse(Lex* lex, Gogo* gogo)
+  : lex_(lex),
+    token_(Token::make_invalid_token(0)),
+    unget_token_(Token::make_invalid_token(0)),
+    unget_token_valid_(false),
+    gogo_(gogo),
+    break_stack_(),
+    continue_stack_(),
+    iota_(0),
+    enclosing_vars_()
+{
+}
+
+// Return the current token.
+
+const Token*
+Parse::peek_token()
+{
+  if (this->unget_token_valid_)
+    return &this->unget_token_;
+  if (this->token_.is_invalid())
+    this->token_ = this->lex_->next_token();
+  return &this->token_;
+}
+
+// Advance to the next token and return it.
+
+const Token*
+Parse::advance_token()
+{
+  if (this->unget_token_valid_)
+    {
+      this->unget_token_valid_ = false;
+      if (!this->token_.is_invalid())
+       return &this->token_;
+    }
+  this->token_ = this->lex_->next_token();
+  return &this->token_;
+}
+
+// Push a token back on the input stream.
+
+void
+Parse::unget_token(const Token& token)
+{
+  gcc_assert(!this->unget_token_valid_);
+  this->unget_token_ = token;
+  this->unget_token_valid_ = true;
+}
+
+// The location of the current token.
+
+source_location
+Parse::location()
+{
+  return this->peek_token()->location();
+}
+
+// IdentifierList = identifier { "," identifier } .
+
+void
+Parse::identifier_list(Typed_identifier_list* til)
+{
+  const Token* token = this->peek_token();
+  while (true)
+    {
+      if (!token->is_identifier())
+       {
+         error_at(this->location(), "expected identifier");
+         return;
+       }
+      std::string name =
+       this->gogo_->pack_hidden_name(token->identifier(),
+                                     token->is_identifier_exported());
+      til->push_back(Typed_identifier(name, NULL, token->location()));
+      token = this->advance_token();
+      if (!token->is_op(OPERATOR_COMMA))
+       return;
+      token = this->advance_token();
+    }
+}
+
+// ExpressionList = Expression { "," Expression } .
+
+// If MAY_BE_SINK is true, the expressions in the list may be "_".
+
+Expression_list*
+Parse::expression_list(Expression* first, bool may_be_sink)
+{
+  Expression_list* ret = new Expression_list();
+  if (first != NULL)
+    ret->push_back(first);
+  while (true)
+    {
+      ret->push_back(this->expression(PRECEDENCE_NORMAL, may_be_sink, true,
+                                     NULL));
+
+      const Token* token = this->peek_token();
+      if (!token->is_op(OPERATOR_COMMA))
+       return ret;
+
+      // Most expression lists permit a trailing comma.
+      source_location location = token->location();
+      this->advance_token();
+      if (!this->expression_may_start_here())
+       {
+         this->unget_token(Token::make_operator_token(OPERATOR_COMMA,
+                                                      location));
+         return ret;
+       }
+    }
+}
+
+// QualifiedIdent = [ PackageName "." ] identifier .
+// PackageName = identifier .
+
+// This sets *PNAME to the identifier and sets *PPACKAGE to the
+// package or NULL if there isn't one.  This returns true on success,
+// false on failure in which case it will have emitted an error
+// message.
+
+bool
+Parse::qualified_ident(std::string* pname, Named_object** ppackage)
+{
+  const Token* token = this->peek_token();
+  if (!token->is_identifier())
+    {
+      error_at(this->location(), "expected identifier");
+      return false;
+    }
+
+  std::string name = token->identifier();
+  bool is_exported = token->is_identifier_exported();
+  name = this->gogo_->pack_hidden_name(name, is_exported);
+
+  token = this->advance_token();
+  if (!token->is_op(OPERATOR_DOT))
+    {
+      *pname = name;
+      *ppackage = NULL;
+      return true;
+    }
+
+  Named_object* package = this->gogo_->lookup(name, NULL);
+  if (package == NULL || !package->is_package())
+    {
+      error_at(this->location(), "expected package");
+      // We expect . IDENTIFIER; skip both.
+      if (this->advance_token()->is_identifier())
+       this->advance_token();
+      return false;
+    }
+
+  package->package_value()->set_used();
+
+  token = this->advance_token();
+  if (!token->is_identifier())
+    {
+      error_at(this->location(), "expected identifier");
+      return false;
+    }
+
+  name = token->identifier();
+
+  if (name == "_")
+    {
+      error_at(this->location(), "invalid use of %<_%>");
+      name = "blank";
+    }
+
+  if (package->name() == this->gogo_->package_name())
+    name = this->gogo_->pack_hidden_name(name,
+                                        token->is_identifier_exported());
+
+  *pname = name;
+  *ppackage = package;
+
+  this->advance_token();
+
+  return true;
+}
+
+// Type = TypeName | TypeLit | "(" Type ")" .
+// TypeLit =
+//     ArrayType | StructType | PointerType | FunctionType | InterfaceType |
+//     SliceType | MapType | ChannelType .
+
+Type*
+Parse::type()
+{
+  const Token* token = this->peek_token();
+  if (token->is_identifier())
+    return this->type_name(true);
+  else if (token->is_op(OPERATOR_LSQUARE))
+    return this->array_type(false);
+  else if (token->is_keyword(KEYWORD_CHAN)
+          || token->is_op(OPERATOR_CHANOP))
+    return this->channel_type();
+  else if (token->is_keyword(KEYWORD_INTERFACE))
+    return this->interface_type();
+  else if (token->is_keyword(KEYWORD_FUNC))
+    {
+      source_location location = token->location();
+      this->advance_token();
+      return this->signature(NULL, location);
+    }
+  else if (token->is_keyword(KEYWORD_MAP))
+    return this->map_type();
+  else if (token->is_keyword(KEYWORD_STRUCT))
+    return this->struct_type();
+  else if (token->is_op(OPERATOR_MULT))
+    return this->pointer_type();
+  else if (token->is_op(OPERATOR_LPAREN))
+    {
+      this->advance_token();
+      Type* ret = this->type();
+      if (this->peek_token()->is_op(OPERATOR_RPAREN))
+       this->advance_token();
+      else
+       {
+         if (!ret->is_error_type())
+           error_at(this->location(), "expected %<)%>");
+       }
+      return ret;
+    }
+  else
+    {
+      error_at(token->location(), "expected type");
+      return Type::make_error_type();
+    }
+}
+
+bool
+Parse::type_may_start_here()
+{
+  const Token* token = this->peek_token();
+  return (token->is_identifier()
+         || token->is_op(OPERATOR_LSQUARE)
+         || token->is_op(OPERATOR_CHANOP)
+         || token->is_keyword(KEYWORD_CHAN)
+         || token->is_keyword(KEYWORD_INTERFACE)
+         || token->is_keyword(KEYWORD_FUNC)
+         || token->is_keyword(KEYWORD_MAP)
+         || token->is_keyword(KEYWORD_STRUCT)
+         || token->is_op(OPERATOR_MULT)
+         || token->is_op(OPERATOR_LPAREN));
+}
+
+// TypeName = QualifiedIdent .
+
+// If MAY_BE_NIL is true, then an identifier with the value of the
+// predefined constant nil is accepted, returning the nil type.
+
+Type*
+Parse::type_name(bool issue_error)
+{
+  source_location location = this->location();
+
+  std::string name;
+  Named_object* package;
+  if (!this->qualified_ident(&name, &package))
+    return Type::make_error_type();
+
+  Named_object* named_object;
+  if (package == NULL)
+    named_object = this->gogo_->lookup(name, NULL);
+  else
+    {
+      named_object = package->package_value()->lookup(name);
+      if (named_object == NULL
+         && issue_error
+         && package->name() != this->gogo_->package_name())
+       {
+         // Check whether the name is there but hidden.
+         std::string s = ('.' + package->package_value()->unique_prefix()
+                          + '.' + package->package_value()->name()
+                          + '.' + name);
+         named_object = package->package_value()->lookup(s);
+         if (named_object != NULL)
+           {
+             const std::string& packname(package->package_value()->name());
+             error_at(location, "invalid reference to hidden type %<%s.%s%>",
+                      Gogo::message_name(packname).c_str(),
+                      Gogo::message_name(name).c_str());
+             issue_error = false;
+           }
+       }
+    }
+
+  bool ok = true;
+  if (named_object == NULL)
+    {
+      if (package != NULL)
+       ok = false;
+      else
+       named_object = this->gogo_->add_unknown_name(name, location);
+    }
+  else if (named_object->is_type())
+    {
+      if (!named_object->type_value()->is_visible())
+       ok = false;
+    }
+  else if (named_object->is_unknown() || named_object->is_type_declaration())
+    ;
+  else
+    ok = false;
+
+  if (!ok)
+    {
+      if (issue_error)
+       error_at(location, "expected type");
+      return Type::make_error_type();
+    }
+
+  if (named_object->is_type())
+    return named_object->type_value();
+  else if (named_object->is_unknown() || named_object->is_type_declaration())
+    return Type::make_forward_declaration(named_object);
+  else
+    gcc_unreachable();
+}
+
+// ArrayType = "[" [ ArrayLength ] "]" ElementType .
+// ArrayLength = Expression .
+// ElementType = CompleteType .
+
+Type*
+Parse::array_type(bool may_use_ellipsis)
+{
+  gcc_assert(this->peek_token()->is_op(OPERATOR_LSQUARE));
+  const Token* token = this->advance_token();
+
+  Expression* length = NULL;
+  if (token->is_op(OPERATOR_RSQUARE))
+    this->advance_token();
+  else
+    {
+      if (!token->is_op(OPERATOR_ELLIPSIS))
+       length = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+      else if (may_use_ellipsis)
+       {
+         // An ellipsis is used in composite literals to represent a
+         // fixed array of the size of the number of elements.  We
+         // use a length of nil to represent this, and change the
+         // length when parsing the composite literal.
+         length = Expression::make_nil(this->location());
+         this->advance_token();
+       }
+      else
+       {
+         error_at(this->location(),
+                  "use of %<[...]%> outside of array literal");
+         length = Expression::make_error(this->location());
+         this->advance_token();
+       }
+      if (!this->peek_token()->is_op(OPERATOR_RSQUARE))
+       {
+         error_at(this->location(), "expected %<]%>");
+         return Type::make_error_type();
+       }
+      this->advance_token();
+    }
+
+  Type* element_type = this->type();
+
+  return Type::make_array_type(element_type, length);
+}
+
+// MapType = "map" "[" KeyType "]" ValueType .
+// KeyType = CompleteType .
+// ValueType = CompleteType .
+
+Type*
+Parse::map_type()
+{
+  source_location location = this->location();
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_MAP));
+  if (!this->advance_token()->is_op(OPERATOR_LSQUARE))
+    {
+      error_at(this->location(), "expected %<[%>");
+      return Type::make_error_type();
+    }
+  this->advance_token();
+
+  Type* key_type = this->type();
+
+  if (!this->peek_token()->is_op(OPERATOR_RSQUARE))
+    {
+      error_at(this->location(), "expected %<]%>");
+      return Type::make_error_type();
+    }
+  this->advance_token();
+
+  Type* value_type = this->type();
+
+  if (key_type->is_error_type() || value_type->is_error_type())
+    return Type::make_error_type();
+
+  return Type::make_map_type(key_type, value_type, location);
+}
+
+// StructType     = "struct" "{" { FieldDecl ";" } "}" .
+
+Type*
+Parse::struct_type()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_STRUCT));
+  source_location location = this->location();
+  if (!this->advance_token()->is_op(OPERATOR_LCURLY))
+    {
+      source_location token_loc = this->location();
+      if (this->peek_token()->is_op(OPERATOR_SEMICOLON)
+         && this->advance_token()->is_op(OPERATOR_LCURLY))
+       error_at(token_loc, "unexpected semicolon or newline before %<{%>");
+      else
+       {
+         error_at(this->location(), "expected %<{%>");
+         return Type::make_error_type();
+       }
+    }
+  this->advance_token();
+
+  Struct_field_list* sfl = new Struct_field_list;
+  while (!this->peek_token()->is_op(OPERATOR_RCURLY))
+    {
+      this->field_decl(sfl);
+      if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+       this->advance_token();
+      else if (!this->peek_token()->is_op(OPERATOR_RCURLY))
+       {
+         error_at(this->location(), "expected %<;%> or %<}%> or newline");
+         if (!this->skip_past_error(OPERATOR_RCURLY))
+           return Type::make_error_type();
+       }
+    }
+  this->advance_token();
+
+  for (Struct_field_list::const_iterator pi = sfl->begin();
+       pi != sfl->end();
+       ++pi)
+    {
+      if (pi->type()->is_error_type())
+       return pi->type();
+      for (Struct_field_list::const_iterator pj = pi + 1;
+          pj != sfl->end();
+          ++pj)
+       {
+         if (pi->field_name() == pj->field_name()
+             && !Gogo::is_sink_name(pi->field_name()))
+           error_at(pi->location(), "duplicate field name %<%s%>",
+                    Gogo::message_name(pi->field_name()).c_str());
+       }
+    }
+
+  return Type::make_struct_type(sfl, location);
+}
+
+// FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] .
+// Tag = string_lit .
+
+void
+Parse::field_decl(Struct_field_list* sfl)
+{
+  const Token* token = this->peek_token();
+  source_location location = token->location();
+  bool is_anonymous;
+  bool is_anonymous_pointer;
+  if (token->is_op(OPERATOR_MULT))
+    {
+      is_anonymous = true;
+      is_anonymous_pointer = true;
+    }
+  else if (token->is_identifier())
+    {
+      std::string id = token->identifier();
+      bool is_id_exported = token->is_identifier_exported();
+      source_location id_location = token->location();
+      token = this->advance_token();
+      is_anonymous = (token->is_op(OPERATOR_SEMICOLON)
+                     || token->is_op(OPERATOR_RCURLY)
+                     || token->is_op(OPERATOR_DOT)
+                     || token->is_string());
+      is_anonymous_pointer = false;
+      this->unget_token(Token::make_identifier_token(id, is_id_exported,
+                                                    id_location));
+    }
+  else
+    {
+      error_at(this->location(), "expected field name");
+      while (!token->is_op(OPERATOR_SEMICOLON)
+            && !token->is_op(OPERATOR_RCURLY)
+            && !token->is_eof())
+       token = this->advance_token();
+      return;
+    }
+
+  if (is_anonymous)
+    {
+      if (is_anonymous_pointer)
+       {
+         this->advance_token();
+         if (!this->peek_token()->is_identifier())
+           {
+             error_at(this->location(), "expected field name");
+             while (!token->is_op(OPERATOR_SEMICOLON)
+                    && !token->is_op(OPERATOR_RCURLY)
+                    && !token->is_eof())
+               token = this->advance_token();
+             return;
+           }
+       }
+      Type* type = this->type_name(true);
+
+      std::string tag;
+      if (this->peek_token()->is_string())
+       {
+         tag = this->peek_token()->string_value();
+         this->advance_token();
+       }
+
+      if (!type->is_error_type())
+       {
+         if (is_anonymous_pointer)
+           type = Type::make_pointer_type(type);
+         sfl->push_back(Struct_field(Typed_identifier("", type, location)));
+         if (!tag.empty())
+           sfl->back().set_tag(tag);
+       }
+    }
+  else
+    {
+      Typed_identifier_list til;
+      while (true)
+       {
+         token = this->peek_token();
+         if (!token->is_identifier())
+           {
+             error_at(this->location(), "expected identifier");
+             return;
+           }
+         std::string name =
+           this->gogo_->pack_hidden_name(token->identifier(),
+                                         token->is_identifier_exported());
+         til.push_back(Typed_identifier(name, NULL, token->location()));
+         if (!this->advance_token()->is_op(OPERATOR_COMMA))
+           break;
+         this->advance_token();
+       }
+
+      Type* type = this->type();
+
+      std::string tag;
+      if (this->peek_token()->is_string())
+       {
+         tag = this->peek_token()->string_value();
+         this->advance_token();
+       }
+
+      for (Typed_identifier_list::iterator p = til.begin();
+          p != til.end();
+          ++p)
+       {
+         p->set_type(type);
+         sfl->push_back(Struct_field(*p));
+         if (!tag.empty())
+           sfl->back().set_tag(tag);
+       }
+    }
+}
+
+// PointerType = "*" Type .
+
+Type*
+Parse::pointer_type()
+{
+  gcc_assert(this->peek_token()->is_op(OPERATOR_MULT));
+  this->advance_token();
+  Type* type = this->type();
+  if (type->is_error_type())
+    return type;
+  return Type::make_pointer_type(type);
+}
+
+// ChannelType   = Channel | SendChannel | RecvChannel .
+// Channel       = "chan" ElementType .
+// SendChannel   = "chan" "<-" ElementType .
+// RecvChannel   = "<-" "chan" ElementType .
+
+Type*
+Parse::channel_type()
+{
+  const Token* token = this->peek_token();
+  bool send = true;
+  bool receive = true;
+  if (token->is_op(OPERATOR_CHANOP))
+    {
+      if (!this->advance_token()->is_keyword(KEYWORD_CHAN))
+       {
+         error_at(this->location(), "expected %<chan%>");
+         return Type::make_error_type();
+       }
+      send = false;
+      this->advance_token();
+    }
+  else
+    {
+      gcc_assert(token->is_keyword(KEYWORD_CHAN));
+      if (this->advance_token()->is_op(OPERATOR_CHANOP))
+       {
+         receive = false;
+         this->advance_token();
+       }
+    }
+  Type* element_type = this->type();
+  return Type::make_channel_type(send, receive, element_type);
+}
+
+// Signature      = Parameters [ Result ] .
+
+// RECEIVER is the receiver if there is one, or NULL.  LOCATION is the
+// location of the start of the type.
+
+Function_type*
+Parse::signature(Typed_identifier* receiver, source_location location)
+{
+  bool is_varargs = false;
+  Typed_identifier_list* params = this->parameters(&is_varargs);
+
+  Typed_identifier_list* result = NULL;
+  if (this->peek_token()->is_op(OPERATOR_LPAREN)
+      || this->type_may_start_here())
+    result = this->result();
+
+  Function_type* ret = Type::make_function_type(receiver, params, result,
+                                               location);
+  if (is_varargs)
+    ret->set_is_varargs();
+  return ret;
+}
+
+// Parameters     = "(" [ ParameterList [ "," ] ] ")" .
+
+Typed_identifier_list*
+Parse::parameters(bool* is_varargs)
+{
+  if (!this->peek_token()->is_op(OPERATOR_LPAREN))
+    {
+      error_at(this->location(), "expected %<(%>");
+      return NULL;
+    }
+
+  Typed_identifier_list* params = NULL;
+
+  const Token* token = this->advance_token();
+  if (!token->is_op(OPERATOR_RPAREN))
+    {
+      params = this->parameter_list(is_varargs);
+      token = this->peek_token();
+    }
+
+  // The optional trailing comma is picked up in parameter_list.
+
+  if (!token->is_op(OPERATOR_RPAREN))
+    error_at(this->location(), "expected %<)%>");
+  else
+    this->advance_token();
+
+  return params;
+}
+
+// ParameterList  = ParameterDecl { "," ParameterDecl } .
+
+// This sets *IS_VARARGS if the list ends with an ellipsis.
+// IS_VARARGS will be NULL if varargs are not permitted.
+
+// We pick up an optional trailing comma.
+
+Typed_identifier_list*
+Parse::parameter_list(bool* is_varargs)
+{
+  source_location location = this->location();
+  Typed_identifier_list* ret = new Typed_identifier_list();
+
+  // If we see an identifier and then a comma, then we don't know
+  // whether we are looking at a list of identifiers followed by a
+  // type, or a list of types given by name.  We have to do an
+  // arbitrary lookahead to figure it out.
+
+  bool parameters_have_names;
+  const Token* token = this->peek_token();
+  if (!token->is_identifier())
+    {
+      // This must be a type which starts with something like '*'.
+      parameters_have_names = false;
+    }
+  else
+    {
+      std::string name = token->identifier();
+      bool is_exported = token->is_identifier_exported();
+      source_location location = token->location();
+      token = this->advance_token();
+      if (!token->is_op(OPERATOR_COMMA))
+       {
+         if (token->is_op(OPERATOR_DOT))
+           {
+             // This is a qualified identifier, which must turn out
+             // to be a type.
+             parameters_have_names = false;
+           }
+         else if (token->is_op(OPERATOR_RPAREN))
+           {
+             // A single identifier followed by a parenthesis must be
+             // a type name.
+             parameters_have_names = false;
+           }
+         else
+           {
+             // An identifier followed by something other than a
+             // comma or a dot or a right parenthesis must be a
+             // parameter name followed by a type.
+             parameters_have_names = true;
+           }
+
+         this->unget_token(Token::make_identifier_token(name, is_exported,
+                                                        location));
+       }
+      else
+       {
+         // An identifier followed by a comma may be the first in a
+         // list of parameter names followed by a type, or it may be
+         // the first in a list of types without parameter names.  To
+         // find out we gather as many identifiers separated by
+         // commas as we can.
+         std::string id_name = this->gogo_->pack_hidden_name(name,
+                                                             is_exported);
+         ret->push_back(Typed_identifier(id_name, NULL, location));
+         bool just_saw_comma = true;
+         while (this->advance_token()->is_identifier())
+           {
+             name = this->peek_token()->identifier();
+             is_exported = this->peek_token()->is_identifier_exported();
+             location = this->peek_token()->location();
+             id_name = this->gogo_->pack_hidden_name(name, is_exported);
+             ret->push_back(Typed_identifier(id_name, NULL, location));
+             if (!this->advance_token()->is_op(OPERATOR_COMMA))
+               {
+                 just_saw_comma = false;
+                 break;
+               }
+           }
+
+         if (just_saw_comma)
+           {
+             // We saw ID1 "," ID2 "," followed by something which
+             // was not an identifier.  We must be seeing the start
+             // of a type, and ID1 and ID2 must be types, and the
+             // parameters don't have names.
+             parameters_have_names = false;
+           }
+         else if (this->peek_token()->is_op(OPERATOR_RPAREN))
+           {
+             // We saw ID1 "," ID2 ")".  ID1 and ID2 must be types,
+             // and the parameters don't have names.
+             parameters_have_names = false;
+           }
+         else if (this->peek_token()->is_op(OPERATOR_DOT))
+           {
+             // We saw ID1 "," ID2 ".".  ID2 must be a package name,
+             // ID1 must be a type, and the parameters don't have
+             // names.
+             parameters_have_names = false;
+             this->unget_token(Token::make_identifier_token(name, is_exported,
+                                                            location));
+             ret->pop_back();
+             just_saw_comma = true;
+           }
+         else
+           {
+             // We saw ID1 "," ID2 followed by something other than
+             // ",", ".", or ")".  We must be looking at the start of
+             // a type, and ID1 and ID2 must be parameter names.
+             parameters_have_names = true;
+           }
+
+         if (parameters_have_names)
+           {
+             gcc_assert(!just_saw_comma);
+             // We have just seen ID1, ID2 xxx.
+             Type* type;
+             if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS))
+               type = this->type();
+             else
+               {
+                 error_at(this->location(), "%<...%> only permits one name");
+                 this->advance_token();
+                 type = this->type();
+               }
+             for (size_t i = 0; i < ret->size(); ++i)
+               ret->set_type(i, type);
+             if (!this->peek_token()->is_op(OPERATOR_COMMA))
+               return ret;
+             if (this->advance_token()->is_op(OPERATOR_RPAREN))
+               return ret;
+           }
+         else
+           {
+             Typed_identifier_list* tret = new Typed_identifier_list();
+             for (Typed_identifier_list::const_iterator p = ret->begin();
+                  p != ret->end();
+                  ++p)
+               {
+                 Named_object* no = this->gogo_->lookup(p->name(), NULL);
+                 Type* type;
+                 if (no == NULL)
+                   no = this->gogo_->add_unknown_name(p->name(),
+                                                      p->location());
+
+                 if (no->is_type())
+                   type = no->type_value();
+                 else if (no->is_unknown() || no->is_type_declaration())
+                   type = Type::make_forward_declaration(no);
+                 else
+                   {
+                     error_at(p->location(), "expected %<%s%> to be a type",
+                              Gogo::message_name(p->name()).c_str());
+                     type = Type::make_error_type();
+                   }
+                 tret->push_back(Typed_identifier("", type, p->location()));
+               }
+             delete ret;
+             ret = tret;
+             if (!just_saw_comma
+                 || this->peek_token()->is_op(OPERATOR_RPAREN))
+               return ret;
+           }
+       }
+    }
+
+  bool mix_error = false;
+  this->parameter_decl(parameters_have_names, ret, is_varargs, &mix_error);
+  while (this->peek_token()->is_op(OPERATOR_COMMA))
+    {
+      if (is_varargs != NULL && *is_varargs)
+       error_at(this->location(), "%<...%> must be last parameter");
+      if (this->advance_token()->is_op(OPERATOR_RPAREN))
+       break;
+      this->parameter_decl(parameters_have_names, ret, is_varargs, &mix_error);
+    }
+  if (mix_error)
+    error_at(location, "invalid named/anonymous mix");
+  return ret;
+}
+
+// ParameterDecl  = [ IdentifierList ] [ "..." ] Type .
+
+void
+Parse::parameter_decl(bool parameters_have_names,
+                     Typed_identifier_list* til,
+                     bool* is_varargs,
+                     bool* mix_error)
+{
+  if (!parameters_have_names)
+    {
+      Type* type;
+      source_location location = this->location();
+      if (!this->peek_token()->is_identifier())
+       {
+         if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS))
+           type = this->type();
+         else
+           {
+             if (is_varargs == NULL)
+               error_at(this->location(), "invalid use of %<...%>");
+             else
+               *is_varargs = true;
+             this->advance_token();
+             if (is_varargs == NULL
+                 && this->peek_token()->is_op(OPERATOR_RPAREN))
+               type = Type::make_error_type();
+             else
+               {
+                 Type* element_type = this->type();
+                 type = Type::make_array_type(element_type, NULL);
+               }
+           }
+       }
+      else
+       {
+         type = this->type_name(false);
+         if (type->is_error_type()
+             || (!this->peek_token()->is_op(OPERATOR_COMMA)
+                 && !this->peek_token()->is_op(OPERATOR_RPAREN)))
+           {
+             *mix_error = true;
+             while (!this->peek_token()->is_op(OPERATOR_COMMA)
+                    && !this->peek_token()->is_op(OPERATOR_RPAREN))
+               this->advance_token();
+           }
+       }
+      if (!type->is_error_type())
+       til->push_back(Typed_identifier("", type, location));
+    }
+  else
+    {
+      size_t orig_count = til->size();
+      if (this->peek_token()->is_identifier())
+       this->identifier_list(til);
+      else
+       *mix_error = true;
+      size_t new_count = til->size();
+
+      Type* type;
+      if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS))
+       type = this->type();
+      else
+       {
+         if (is_varargs == NULL)
+           error_at(this->location(), "invalid use of %<...%>");
+         else if (new_count > orig_count + 1)
+           error_at(this->location(), "%<...%> only permits one name");
+         else
+           *is_varargs = true;
+         this->advance_token();
+         Type* element_type = this->type();
+         type = Type::make_array_type(element_type, NULL);
+       }
+      for (size_t i = orig_count; i < new_count; ++i)
+       til->set_type(i, type);
+    }
+}
+
+// Result         = Parameters | Type .
+
+Typed_identifier_list*
+Parse::result()
+{
+  if (this->peek_token()->is_op(OPERATOR_LPAREN))
+    return this->parameters(NULL);
+  else
+    {
+      source_location location = this->location();
+      Typed_identifier_list* til = new Typed_identifier_list();
+      Type* type = this->type();
+      til->push_back(Typed_identifier("", type, location));
+      return til;
+    }
+}
+
+// Block = "{" [ StatementList ] "}" .
+
+// Returns the location of the closing brace.
+
+source_location
+Parse::block()
+{
+  if (!this->peek_token()->is_op(OPERATOR_LCURLY))
+    {
+      source_location loc = this->location();
+      if (this->peek_token()->is_op(OPERATOR_SEMICOLON)
+         && this->advance_token()->is_op(OPERATOR_LCURLY))
+       error_at(loc, "unexpected semicolon or newline before %<{%>");
+      else
+       {
+         error_at(this->location(), "expected %<{%>");
+         return UNKNOWN_LOCATION;
+       }
+    }
+
+  const Token* token = this->advance_token();
+
+  if (!token->is_op(OPERATOR_RCURLY))
+    {
+      this->statement_list();
+      token = this->peek_token();
+      if (!token->is_op(OPERATOR_RCURLY))
+       {
+         if (!token->is_eof() || !saw_errors())
+           error_at(this->location(), "expected %<}%>");
+
+         // Skip ahead to the end of the block, in hopes of avoiding
+         // lots of meaningless errors.
+         source_location ret = token->location();
+         int nest = 0;
+         while (!token->is_eof())
+           {
+             if (token->is_op(OPERATOR_LCURLY))
+               ++nest;
+             else if (token->is_op(OPERATOR_RCURLY))
+               {
+                 --nest;
+                 if (nest < 0)
+                   {
+                     this->advance_token();
+                     break;
+                   }
+               }
+             token = this->advance_token();
+             ret = token->location();
+           }
+         return ret;
+       }
+    }
+
+  source_location ret = token->location();
+  this->advance_token();
+  return ret;
+}
+
+// InterfaceType      = "interface" "{" [ MethodSpecList ] "}" .
+// MethodSpecList     = MethodSpec { ";" MethodSpec } [ ";" ] .
+
+Type*
+Parse::interface_type()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_INTERFACE));
+  source_location location = this->location();
+
+  if (!this->advance_token()->is_op(OPERATOR_LCURLY))
+    {
+      source_location token_loc = this->location();
+      if (this->peek_token()->is_op(OPERATOR_SEMICOLON)
+         && this->advance_token()->is_op(OPERATOR_LCURLY))
+       error_at(token_loc, "unexpected semicolon or newline before %<{%>");
+      else
+       {
+         error_at(this->location(), "expected %<{%>");
+         return Type::make_error_type();
+       }
+    }
+  this->advance_token();
+
+  Typed_identifier_list* methods = new Typed_identifier_list();
+  if (!this->peek_token()->is_op(OPERATOR_RCURLY))
+    {
+      this->method_spec(methods);
+      while (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+       {
+         if (this->advance_token()->is_op(OPERATOR_RCURLY))
+           break;
+         this->method_spec(methods);
+       }
+      if (!this->peek_token()->is_op(OPERATOR_RCURLY))
+       {
+         error_at(this->location(), "expected %<}%>");
+         while (!this->advance_token()->is_op(OPERATOR_RCURLY))
+           {
+             if (this->peek_token()->is_eof())
+               return Type::make_error_type();
+           }
+       }
+    }
+  this->advance_token();
+
+  if (methods->empty())
+    {
+      delete methods;
+      methods = NULL;
+    }
+
+  Interface_type* ret = Type::make_interface_type(methods, location);
+  this->gogo_->record_interface_type(ret);
+  return ret;
+}
+
+// MethodSpec         = MethodName Signature | InterfaceTypeName .
+// MethodName         = identifier .
+// InterfaceTypeName  = TypeName .
+
+bool
+Parse::method_spec(Typed_identifier_list* methods)
+{
+  const Token* token = this->peek_token();
+  if (!token->is_identifier())
+    {
+      error_at(this->location(), "expected identifier");
+      return false;
+    }
+
+  std::string name = token->identifier();
+  bool is_exported = token->is_identifier_exported();
+  source_location location = token->location();
+
+  if (this->advance_token()->is_op(OPERATOR_LPAREN))
+    {
+      // This is a MethodName.
+      name = this->gogo_->pack_hidden_name(name, is_exported);
+      Function_type* type = this->signature(NULL, location);
+      methods->push_back(Typed_identifier(name, type, location));
+    }
+  else
+    {
+      this->unget_token(Token::make_identifier_token(name, is_exported,
+                                                    location));
+      Type* type = this->type_name(false);
+      if (type->is_error_type()
+         || (!this->peek_token()->is_op(OPERATOR_SEMICOLON)
+             && !this->peek_token()->is_op(OPERATOR_RCURLY)))
+       {
+         if (this->peek_token()->is_op(OPERATOR_COMMA))
+           error_at(this->location(),
+                    "name list not allowed in interface type");
+         else
+           error_at(location, "expected signature or type name");
+         token = this->peek_token();
+         while (!token->is_eof()
+                && !token->is_op(OPERATOR_SEMICOLON)
+                && !token->is_op(OPERATOR_RCURLY))
+           token = this->advance_token();
+         return false;
+       }
+      // This must be an interface type, but we can't check that now.
+      // We check it and pull out the methods in
+      // Interface_type::do_verify.
+      methods->push_back(Typed_identifier("", type, location));
+    }
+
+  return false;
+}
+
+// Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl .
+
+void
+Parse::declaration()
+{
+  const Token* token = this->peek_token();
+  if (token->is_keyword(KEYWORD_CONST))
+    this->const_decl();
+  else if (token->is_keyword(KEYWORD_TYPE))
+    this->type_decl();
+  else if (token->is_keyword(KEYWORD_VAR))
+    this->var_decl();
+  else if (token->is_keyword(KEYWORD_FUNC))
+    this->function_decl();
+  else
+    {
+      error_at(this->location(), "expected declaration");
+      this->advance_token();
+    }
+}
+
+bool
+Parse::declaration_may_start_here()
+{
+  const Token* token = this->peek_token();
+  return (token->is_keyword(KEYWORD_CONST)
+         || token->is_keyword(KEYWORD_TYPE)
+         || token->is_keyword(KEYWORD_VAR)
+         || token->is_keyword(KEYWORD_FUNC));
+}
+
+// Decl<P> = P | "(" [ List<P> ] ")" .
+
+void
+Parse::decl(void (Parse::*pfn)(void*), void* varg)
+{
+  if (!this->peek_token()->is_op(OPERATOR_LPAREN))
+    (this->*pfn)(varg);
+  else
+    {
+      if (!this->advance_token()->is_op(OPERATOR_RPAREN))
+       {
+         this->list(pfn, varg, true);
+         if (!this->peek_token()->is_op(OPERATOR_RPAREN))
+           {
+             error_at(this->location(), "missing %<)%>");
+             while (!this->advance_token()->is_op(OPERATOR_RPAREN))
+               {
+                 if (this->peek_token()->is_eof())
+                   return;
+               }
+           }
+       }
+      this->advance_token();
+    }
+}
+
+// List<P> = P { ";" P } [ ";" ] .
+
+// In order to pick up the trailing semicolon we need to know what
+// might follow.  This is either a '}' or a ')'.
+
+void
+Parse::list(void (Parse::*pfn)(void*), void* varg, bool follow_is_paren)
+{
+  (this->*pfn)(varg);
+  Operator follow = follow_is_paren ? OPERATOR_RPAREN : OPERATOR_RCURLY;
+  while (this->peek_token()->is_op(OPERATOR_SEMICOLON)
+        || this->peek_token()->is_op(OPERATOR_COMMA))
+    {
+      if (this->peek_token()->is_op(OPERATOR_COMMA))
+       error_at(this->location(), "unexpected comma");
+      if (this->advance_token()->is_op(follow))
+       break;
+      (this->*pfn)(varg);
+    }
+}
+
+// ConstDecl      = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
+
+void
+Parse::const_decl()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_CONST));
+  this->advance_token();
+  this->reset_iota();
+
+  Type* last_type = NULL;
+  Expression_list* last_expr_list = NULL;
+
+  if (!this->peek_token()->is_op(OPERATOR_LPAREN))
+    this->const_spec(&last_type, &last_expr_list);
+  else
+    {
+      this->advance_token();
+      while (!this->peek_token()->is_op(OPERATOR_RPAREN))
+       {
+         this->const_spec(&last_type, &last_expr_list);
+         if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+           this->advance_token();
+         else if (!this->peek_token()->is_op(OPERATOR_RPAREN))
+           {
+             error_at(this->location(), "expected %<;%> or %<)%> or newline");
+             if (!this->skip_past_error(OPERATOR_RPAREN))
+               return;
+           }
+       }
+      this->advance_token();
+    }
+
+  if (last_expr_list != NULL)
+    delete last_expr_list;
+}
+
+// ConstSpec = IdentifierList [ [ CompleteType ] "=" ExpressionList ] .
+
+void
+Parse::const_spec(Type** last_type, Expression_list** last_expr_list)
+{
+  Typed_identifier_list til;
+  this->identifier_list(&til);
+
+  Type* type = NULL;
+  if (this->type_may_start_here())
+    {
+      type = this->type();
+      *last_type = NULL;
+      *last_expr_list = NULL;
+    }
+
+  Expression_list *expr_list;
+  if (!this->peek_token()->is_op(OPERATOR_EQ))
+    {
+      if (*last_expr_list == NULL)
+       {
+         error_at(this->location(), "expected %<=%>");
+         return;
+       }
+      type = *last_type;
+      expr_list = new Expression_list;
+      for (Expression_list::const_iterator p = (*last_expr_list)->begin();
+          p != (*last_expr_list)->end();
+          ++p)
+       expr_list->push_back((*p)->copy());
+    }
+  else
+    {
+      this->advance_token();
+      expr_list = this->expression_list(NULL, false);
+      *last_type = type;
+      if (*last_expr_list != NULL)
+       delete *last_expr_list;
+      *last_expr_list = expr_list;
+    }
+
+  Expression_list::const_iterator pe = expr_list->begin();
+  for (Typed_identifier_list::iterator pi = til.begin();
+       pi != til.end();
+       ++pi, ++pe)
+    {
+      if (pe == expr_list->end())
+       {
+         error_at(this->location(), "not enough initializers");
+         return;
+       }
+      if (type != NULL)
+       pi->set_type(type);
+
+      if (!Gogo::is_sink_name(pi->name()))
+       this->gogo_->add_constant(*pi, *pe, this->iota_value());
+    }
+  if (pe != expr_list->end())
+    error_at(this->location(), "too many initializers");
+
+  this->increment_iota();
+
+  return;
+}
+
+// TypeDecl = "type" Decl<TypeSpec> .
+
+void
+Parse::type_decl()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_TYPE));
+  this->advance_token();
+  this->decl(&Parse::type_spec, NULL);
+}
+
+// TypeSpec = identifier Type .
+
+void
+Parse::type_spec(void*)
+{
+  const Token* token = this->peek_token();
+  if (!token->is_identifier())
+    {
+      error_at(this->location(), "expected identifier");
+      return;
+    }
+  std::string name = token->identifier();
+  bool is_exported = token->is_identifier_exported();
+  source_location location = token->location();
+  token = this->advance_token();
+
+  // The scope of the type name starts at the point where the
+  // identifier appears in the source code.  We implement this by
+  // declaring the type before we read the type definition.
+  Named_object* named_type = NULL;
+  if (name != "_")
+    {
+      name = this->gogo_->pack_hidden_name(name, is_exported);
+      named_type = this->gogo_->declare_type(name, location);
+    }
+
+  Type* type;
+  if (!this->peek_token()->is_op(OPERATOR_SEMICOLON))
+    type = this->type();
+  else
+    {
+      error_at(this->location(),
+              "unexpected semicolon or newline in type declaration");
+      type = Type::make_error_type();
+      this->advance_token();
+    }
+
+  if (type->is_error_type())
+    {
+      while (!this->peek_token()->is_op(OPERATOR_SEMICOLON)
+            && !this->peek_token()->is_eof())
+       this->advance_token();
+    }
+
+  if (name != "_")
+    {
+      if (named_type->is_type_declaration())
+       {
+         Type* ftype = type->forwarded();
+         if (ftype->forward_declaration_type() != NULL
+             && (ftype->forward_declaration_type()->named_object()
+                 == named_type))
+           {
+             error_at(location, "invalid recursive type");
+             type = Type::make_error_type();
+           }
+
+         this->gogo_->define_type(named_type,
+                                  Type::make_named_type(named_type, type,
+                                                        location));
+         gcc_assert(named_type->package() == NULL);
+       }
+      else
+       {
+         // This will probably give a redefinition error.
+         this->gogo_->add_type(name, type, location);
+       }
+    }
+}
+
+// VarDecl = "var" Decl<VarSpec> .
+
+void
+Parse::var_decl()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_VAR));
+  this->advance_token();
+  this->decl(&Parse::var_spec, NULL);
+}
+
+// VarSpec = IdentifierList
+//             ( CompleteType [ "=" ExpressionList ] | "=" ExpressionList ) .
+
+void
+Parse::var_spec(void*)
+{
+  // Get the variable names.
+  Typed_identifier_list til;
+  this->identifier_list(&til);
+
+  source_location location = this->location();
+
+  Type* type = NULL;
+  Expression_list* init = NULL;
+  if (!this->peek_token()->is_op(OPERATOR_EQ))
+    {
+      type = this->type();
+      if (type->is_error_type())
+       {
+         while (!this->peek_token()->is_op(OPERATOR_EQ)
+                && !this->peek_token()->is_op(OPERATOR_SEMICOLON)
+                && !this->peek_token()->is_eof())
+           this->advance_token();
+       }
+      if (this->peek_token()->is_op(OPERATOR_EQ))
+       {
+         this->advance_token();
+         init = this->expression_list(NULL, false);
+       }
+    }
+  else
+    {
+      this->advance_token();
+      init = this->expression_list(NULL, false);
+    }
+
+  this->init_vars(&til, type, init, false, location);
+
+  if (init != NULL)
+    delete init;
+}
+
+// Create variables.  TIL is a list of variable names.  If TYPE is not
+// NULL, it is the type of all the variables.  If INIT is not NULL, it
+// is an initializer list for the variables.
+
+void
+Parse::init_vars(const Typed_identifier_list* til, Type* type,
+                Expression_list* init, bool is_coloneq,
+                source_location location)
+{
+  // Check for an initialization which can yield multiple values.
+  if (init != NULL && init->size() == 1 && til->size() > 1)
+    {
+      if (this->init_vars_from_call(til, type, *init->begin(), is_coloneq,
+                                   location))
+       return;
+      if (this->init_vars_from_map(til, type, *init->begin(), is_coloneq,
+                                  location))
+       return;
+      if (this->init_vars_from_receive(til, type, *init->begin(), is_coloneq,
+                                      location))
+       return;
+      if (this->init_vars_from_type_guard(til, type, *init->begin(),
+                                         is_coloneq, location))
+       return;
+    }
+
+  if (init != NULL && init->size() != til->size())
+    {
+      if (init->empty() || !init->front()->is_error_expression())
+       error_at(location, "wrong number of initializations");
+      init = NULL;
+      if (type == NULL)
+       type = Type::make_error_type();
+    }
+
+  // Note that INIT was already parsed with the old name bindings, so
+  // we don't have to worry that it will accidentally refer to the
+  // newly declared variables.
+
+  Expression_list::const_iterator pexpr;
+  if (init != NULL)
+    pexpr = init->begin();
+  bool any_new = false;
+  for (Typed_identifier_list::const_iterator p = til->begin();
+       p != til->end();
+       ++p)
+    {
+      if (init != NULL)
+       gcc_assert(pexpr != init->end());
+      this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq,
+                    false, &any_new);
+      if (init != NULL)
+       ++pexpr;
+    }
+  if (init != NULL)
+    gcc_assert(pexpr == init->end());
+  if (is_coloneq && !any_new)
+    error_at(location, "variables redeclared but no variable is new");
+}
+
+// See if we need to initialize a list of variables from a function
+// call.  This returns true if we have set up the variables and the
+// initialization.
+
+bool
+Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
+                          Expression* expr, bool is_coloneq,
+                          source_location location)
+{
+  Call_expression* call = expr->call_expression();
+  if (call == NULL)
+    return false;
+
+  // This is a function call.  We can't check here whether it returns
+  // the right number of values, but it might.  Declare the variables,
+  // and then assign the results of the call to them.
+
+  unsigned int index = 0;
+  bool any_new = false;
+  for (Typed_identifier_list::const_iterator pv = vars->begin();
+       pv != vars->end();
+       ++pv, ++index)
+    {
+      Expression* init = Expression::make_call_result(call, index);
+      this->init_var(*pv, type, init, is_coloneq, false, &any_new);
+    }
+
+  if (is_coloneq && !any_new)
+    error_at(location, "variables redeclared but no variable is new");
+
+  return true;
+}
+
+// See if we need to initialize a pair of values from a map index
+// expression.  This returns true if we have set up the variables and
+// the initialization.
+
+bool
+Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
+                         Expression* expr, bool is_coloneq,
+                         source_location location)
+{
+  Index_expression* index = expr->index_expression();
+  if (index == NULL)
+    return false;
+  if (vars->size() != 2)
+    return false;
+
+  // This is an index which is being assigned to two variables.  It
+  // must be a map index.  Declare the variables, and then assign the
+  // results of the map index.
+  bool any_new = false;
+  Typed_identifier_list::const_iterator p = vars->begin();
+  Expression* init = type == NULL ? index : NULL;
+  Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
+                                       type == NULL, &any_new);
+  if (type == NULL && any_new && val_no->is_variable())
+    val_no->var_value()->set_type_from_init_tuple();
+  Expression* val_var = Expression::make_var_reference(val_no, location);
+
+  ++p;
+  Type* var_type = type;
+  if (var_type == NULL)
+    var_type = Type::lookup_bool_type();
+  Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
+                                   &any_new);
+  Expression* present_var = Expression::make_var_reference(no, location);
+
+  if (is_coloneq && !any_new)
+    error_at(location, "variables redeclared but no variable is new");
+
+  Statement* s = Statement::make_tuple_map_assignment(val_var, present_var,
+                                                     index, location);
+
+  if (!this->gogo_->in_global_scope())
+    this->gogo_->add_statement(s);
+  else
+    val_no->var_value()->add_preinit_statement(s);
+
+  return true;
+}
+
+// See if we need to initialize a pair of values from a receive
+// expression.  This returns true if we have set up the variables and
+// the initialization.
+
+bool
+Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
+                             Expression* expr, bool is_coloneq,
+                             source_location location)
+{
+  Receive_expression* receive = expr->receive_expression();
+  if (receive == NULL)
+    return false;
+  if (vars->size() != 2)
+    return false;
+
+  // This is a receive expression which is being assigned to two
+  // variables.  Declare the variables, and then assign the results of
+  // the receive.
+  bool any_new = false;
+  Typed_identifier_list::const_iterator p = vars->begin();
+  Expression* init = type == NULL ? receive : NULL;
+  Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
+                                       type == NULL, &any_new);
+  if (type == NULL && any_new && val_no->is_variable())
+    val_no->var_value()->set_type_from_init_tuple();
+  Expression* val_var = Expression::make_var_reference(val_no, location);
+
+  ++p;
+  Type* var_type = type;
+  if (var_type == NULL)
+    var_type = Type::lookup_bool_type();
+  Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
+                                   &any_new);
+  Expression* received_var = Expression::make_var_reference(no, location);
+
+  if (is_coloneq && !any_new)
+    error_at(location, "variables redeclared but no variable is new");
+
+  Statement* s = Statement::make_tuple_receive_assignment(val_var,
+                                                         received_var,
+                                                         receive->channel(),
+                                                         location);
+
+  if (!this->gogo_->in_global_scope())
+    this->gogo_->add_statement(s);
+  else
+    val_no->var_value()->add_preinit_statement(s);
+
+  return true;
+}
+
+// See if we need to initialize a pair of values from a type guard
+// expression.  This returns true if we have set up the variables and
+// the initialization.
+
+bool
+Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
+                                Type* type, Expression* expr,
+                                bool is_coloneq, source_location location)
+{
+  Type_guard_expression* type_guard = expr->type_guard_expression();
+  if (type_guard == NULL)
+    return false;
+  if (vars->size() != 2)
+    return false;
+
+  // This is a type guard expression which is being assigned to two
+  // variables.  Declare the variables, and then assign the results of
+  // the type guard.
+  bool any_new = false;
+  Typed_identifier_list::const_iterator p = vars->begin();
+  Type* var_type = type;
+  if (var_type == NULL)
+    var_type = type_guard->type();
+  Named_object* val_no = this->init_var(*p, var_type, NULL, is_coloneq, false,
+                                       &any_new);
+  Expression* val_var = Expression::make_var_reference(val_no, location);
+
+  ++p;
+  var_type = type;
+  if (var_type == NULL)
+    var_type = Type::lookup_bool_type();
+  Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
+                                   &any_new);
+  Expression* ok_var = Expression::make_var_reference(no, location);
+
+  Expression* texpr = type_guard->expr();
+  Type* t = type_guard->type();
+  Statement* s = Statement::make_tuple_type_guard_assignment(val_var, ok_var,
+                                                            texpr, t,
+                                                            location);
+
+  if (is_coloneq && !any_new)
+    error_at(location, "variables redeclared but no variable is new");
+
+  if (!this->gogo_->in_global_scope())
+    this->gogo_->add_statement(s);
+  else
+    val_no->var_value()->add_preinit_statement(s);
+
+  return true;
+}
+
+// Create a single variable.  If IS_COLONEQ is true, we permit
+// redeclarations in the same block, and we set *IS_NEW when we find a
+// new variable which is not a redeclaration.
+
+Named_object*
+Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
+               bool is_coloneq, bool type_from_init, bool* is_new)
+{
+  source_location location = tid.location();
+
+  if (Gogo::is_sink_name(tid.name()))
+    {
+      if (!type_from_init && init != NULL)
+       {
+         if (!this->gogo_->in_global_scope())
+           this->gogo_->add_statement(Statement::make_statement(init));
+         else
+           {
+             // Create a dummy global variable to force the
+             // initializer to be run in the right place.
+             Variable* var = new Variable(type, init, true, false, false,
+                                          location);
+             static int count;
+             char buf[30];
+             snprintf(buf, sizeof buf, "_.%d", count);
+             ++count;
+             return this->gogo_->add_variable(buf, var);
+           }
+       }
+      return this->gogo_->add_sink();
+    }
+
+  if (is_coloneq)
+    {
+      Named_object* no = this->gogo_->lookup_in_block(tid.name());
+      if (no != NULL
+         && (no->is_variable() || no->is_result_variable()))
+       {
+         // INIT may be NULL even when IS_COLONEQ is true for cases
+         // like v, ok := x.(int).
+         if (!type_from_init && init != NULL)
+           {
+             Expression *v = Expression::make_var_reference(no, location);
+             Statement *s = Statement::make_assignment(v, init, location);
+             this->gogo_->add_statement(s);
+           }
+         return no;
+       }
+    }
+  *is_new = true;
+  Variable* var = new Variable(type, init, this->gogo_->in_global_scope(),
+                              false, false, location);
+  return this->gogo_->add_variable(tid.name(), var);
+}
+
+// SimpleVarDecl = identifier ":=" Expression .
+
+// We've already seen the identifier.
+
+// FIXME: We also have to implement
+//  IdentifierList ":=" ExpressionList
+// In order to support both "a, b := 1, 0" and "a, b = 1, 0" we accept
+// tuple assignments here as well.
+
+// If P_RANGE_CLAUSE is not NULL, then this will recognize a
+// RangeClause.
+
+// If P_TYPE_SWITCH is not NULL, this will recognize a type switch
+// guard (var := expr.("type") using the literal keyword "type").
+
+void
+Parse::simple_var_decl_or_assignment(const std::string& name,
+                                    source_location location,
+                                    Range_clause* p_range_clause,
+                                    Type_switch* p_type_switch)
+{
+  Typed_identifier_list til;
+  til.push_back(Typed_identifier(name, NULL, location));
+
+  // We've seen one identifier.  If we see a comma now, this could be
+  // "a, *p = 1, 2".
+  if (this->peek_token()->is_op(OPERATOR_COMMA))
+    {
+      gcc_assert(p_type_switch == NULL);
+      while (true)
+       {
+         const Token* token = this->advance_token();
+         if (!token->is_identifier())
+           break;
+
+         std::string id = token->identifier();
+         bool is_id_exported = token->is_identifier_exported();
+         source_location id_location = token->location();
+
+         token = this->advance_token();
+         if (!token->is_op(OPERATOR_COMMA))
+           {
+             if (token->is_op(OPERATOR_COLONEQ))
+               {
+                 id = this->gogo_->pack_hidden_name(id, is_id_exported);
+                 til.push_back(Typed_identifier(id, NULL, location));
+               }
+             else
+               this->unget_token(Token::make_identifier_token(id,
+                                                              is_id_exported,
+                                                              id_location));
+             break;
+           }
+
+         id = this->gogo_->pack_hidden_name(id, is_id_exported);
+         til.push_back(Typed_identifier(id, NULL, location));
+       }
+
+      // We have a comma separated list of identifiers in TIL.  If the
+      // next token is COLONEQ, then this is a simple var decl, and we
+      // have the complete list of identifiers.  If the next token is
+      // not COLONEQ, then the only valid parse is a tuple assignment.
+      // The list of identifiers we have so far is really a list of
+      // expressions.  There are more expressions following.
+
+      if (!this->peek_token()->is_op(OPERATOR_COLONEQ))
+       {
+         Expression_list* exprs = new Expression_list;
+         for (Typed_identifier_list::const_iterator p = til.begin();
+              p != til.end();
+              ++p)
+           exprs->push_back(this->id_to_expression(p->name(),
+                                                   p->location()));
+
+         Expression_list* more_exprs = this->expression_list(NULL, true);
+         for (Expression_list::const_iterator p = more_exprs->begin();
+              p != more_exprs->end();
+              ++p)
+           exprs->push_back(*p);
+         delete more_exprs;
+
+         this->tuple_assignment(exprs, p_range_clause);
+         return;
+       }
+    }
+
+  gcc_assert(this->peek_token()->is_op(OPERATOR_COLONEQ));
+  const Token* token = this->advance_token();
+
+  if (p_range_clause != NULL && token->is_keyword(KEYWORD_RANGE))
+    {
+      this->range_clause_decl(&til, p_range_clause);
+      return;
+    }
+
+  Expression_list* init;
+  if (p_type_switch == NULL)
+    init = this->expression_list(NULL, false);
+  else
+    {
+      bool is_type_switch = false;
+      Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true,
+                                         &is_type_switch);
+      if (is_type_switch)
+       {
+         p_type_switch->found = true;
+         p_type_switch->name = name;
+         p_type_switch->location = location;
+         p_type_switch->expr = expr;
+         return;
+       }
+
+      if (!this->peek_token()->is_op(OPERATOR_COMMA))
+       {
+         init = new Expression_list();
+         init->push_back(expr);
+       }
+      else
+       {
+         this->advance_token();
+         init = this->expression_list(expr, false);
+       }
+    }
+
+  this->init_vars(&til, NULL, init, true, location);
+}
+
+// FunctionDecl = "func" identifier Signature [ Block ] .
+// MethodDecl = "func" Receiver identifier Signature [ Block ] .
+
+// gcc extension:
+//   FunctionDecl = "func" identifier Signature
+//                    __asm__ "(" string_lit ")" .
+// This extension means a function whose real name is the identifier
+// inside the asm.
+
+void
+Parse::function_decl()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
+  source_location location = this->location();
+  const Token* token = this->advance_token();
+
+  Typed_identifier* rec = NULL;
+  if (token->is_op(OPERATOR_LPAREN))
+    {
+      rec = this->receiver();
+      token = this->peek_token();
+    }
+
+  if (!token->is_identifier())
+    {
+      error_at(this->location(), "expected function name");
+      return;
+    }
+
+  std::string name =
+    this->gogo_->pack_hidden_name(token->identifier(),
+                                 token->is_identifier_exported());
+
+  this->advance_token();
+
+  Function_type* fntype = this->signature(rec, this->location());
+
+  Named_object* named_object = NULL;
+
+  if (this->peek_token()->is_keyword(KEYWORD_ASM))
+    {
+      if (!this->advance_token()->is_op(OPERATOR_LPAREN))
+       {
+         error_at(this->location(), "expected %<(%>");
+         return;
+       }
+      token = this->advance_token();
+      if (!token->is_string())
+       {
+         error_at(this->location(), "expected string");
+         return;
+       }
+      std::string asm_name = token->string_value();
+      if (!this->advance_token()->is_op(OPERATOR_RPAREN))
+       {
+         error_at(this->location(), "expected %<)%>");
+         return;
+       }
+      this->advance_token();
+      named_object = this->gogo_->declare_function(name, fntype, location);
+      if (named_object->is_function_declaration())
+       named_object->func_declaration_value()->set_asm_name(asm_name);
+    }
+
+  // Check for the easy error of a newline before the opening brace.
+  if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+    {
+      source_location semi_loc = this->location();
+      if (this->advance_token()->is_op(OPERATOR_LCURLY))
+       error_at(this->location(),
+                "unexpected semicolon or newline before %<{%>");
+      else
+       this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
+                                                    semi_loc));
+    }
+
+  if (!this->peek_token()->is_op(OPERATOR_LCURLY))
+    {
+      if (named_object == NULL)
+       named_object = this->gogo_->declare_function(name, fntype, location);
+    }
+  else
+    {
+      this->gogo_->start_function(name, fntype, true, location);
+      source_location end_loc = this->block();
+      this->gogo_->finish_function(end_loc);
+    }
+}
+
+// Receiver     = "(" [ identifier ] [ "*" ] BaseTypeName ")" .
+// BaseTypeName = identifier .
+
+Typed_identifier*
+Parse::receiver()
+{
+  gcc_assert(this->peek_token()->is_op(OPERATOR_LPAREN));
+
+  std::string name;
+  const Token* token = this->advance_token();
+  source_location location = token->location();
+  if (!token->is_op(OPERATOR_MULT))
+    {
+      if (!token->is_identifier())
+       {
+         error_at(this->location(), "method has no receiver");
+         while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN))
+           token = this->advance_token();
+         if (!token->is_eof())
+           this->advance_token();
+         return NULL;
+       }
+      name = token->identifier();
+      bool is_exported = token->is_identifier_exported();
+      token = this->advance_token();
+      if (!token->is_op(OPERATOR_DOT) && !token->is_op(OPERATOR_RPAREN))
+       {
+         // An identifier followed by something other than a dot or a
+         // right parenthesis must be a receiver name followed by a
+         // type.
+         name = this->gogo_->pack_hidden_name(name, is_exported);
+       }
+      else
+       {
+         // This must be a type name.
+         this->unget_token(Token::make_identifier_token(name, is_exported,
+                                                        location));
+         token = this->peek_token();
+         name.clear();
+       }
+    }
+
+  // Here the receiver name is in NAME (it is empty if the receiver is
+  // unnamed) and TOKEN is the first token in the type.
+
+  bool is_pointer = false;
+  if (token->is_op(OPERATOR_MULT))
+    {
+      is_pointer = true;
+      token = this->advance_token();
+    }
+
+  if (!token->is_identifier())
+    {
+      error_at(this->location(), "expected receiver name or type");
+      int c = token->is_op(OPERATOR_LPAREN) ? 1 : 0;
+      while (!token->is_eof())
+       {
+         token = this->advance_token();
+         if (token->is_op(OPERATOR_LPAREN))
+           ++c;
+         else if (token->is_op(OPERATOR_RPAREN))
+           {
+             if (c == 0)
+               break;
+             --c;
+           }
+       }
+      if (!token->is_eof())
+       this->advance_token();
+      return NULL;
+    }
+
+  Type* type = this->type_name(true);
+
+  if (is_pointer && !type->is_error_type())
+    type = Type::make_pointer_type(type);
+
+  if (this->peek_token()->is_op(OPERATOR_RPAREN))
+    this->advance_token();
+  else
+    {
+      if (this->peek_token()->is_op(OPERATOR_COMMA))
+       error_at(this->location(), "method has multiple receivers");
+      else
+       error_at(this->location(), "expected %<)%>");
+      while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN))
+       token = this->advance_token();
+      if (!token->is_eof())
+       this->advance_token();
+      return NULL;
+    }
+
+  return new Typed_identifier(name, type, location);
+}
+
+// Operand    = Literal | QualifiedIdent | MethodExpr | "(" Expression ")" .
+// Literal    = BasicLit | CompositeLit | FunctionLit .
+// BasicLit   = int_lit | float_lit | imaginary_lit | char_lit | string_lit .
+
+// If MAY_BE_SINK is true, this operand may be "_".
+
+Expression*
+Parse::operand(bool may_be_sink)
+{
+  const Token* token = this->peek_token();
+  Expression* ret;
+  switch (token->classification())
+    {
+    case Token::TOKEN_IDENTIFIER:
+      {
+       source_location location = token->location();
+       std::string id = token->identifier();
+       bool is_exported = token->is_identifier_exported();
+       std::string packed = this->gogo_->pack_hidden_name(id, is_exported);
+
+       Named_object* in_function;
+       Named_object* named_object = this->gogo_->lookup(packed, &in_function);
+
+       Package* package = NULL;
+       if (named_object != NULL && named_object->is_package())
+         {
+           if (!this->advance_token()->is_op(OPERATOR_DOT)
+               || !this->advance_token()->is_identifier())
+             {
+               error_at(location, "unexpected reference to package");
+               return Expression::make_error(location);
+             }
+           package = named_object->package_value();
+           package->set_used();
+           id = this->peek_token()->identifier();
+           is_exported = this->peek_token()->is_identifier_exported();
+           packed = this->gogo_->pack_hidden_name(id, is_exported);
+           named_object = package->lookup(packed);
+           location = this->location();
+           gcc_assert(in_function == NULL);
+         }
+
+       this->advance_token();
+
+       if (named_object != NULL
+           && named_object->is_type()
+           && !named_object->type_value()->is_visible())
+         {
+           gcc_assert(package != NULL);
+           error_at(location, "invalid reference to hidden type %<%s.%s%>",
+                    Gogo::message_name(package->name()).c_str(),
+                    Gogo::message_name(id).c_str());
+           return Expression::make_error(location);
+         }
+
+
+       if (named_object == NULL)
+         {
+           if (package != NULL)
+             {
+               std::string n1 = Gogo::message_name(package->name());
+               std::string n2 = Gogo::message_name(id);
+               if (!is_exported)
+                 error_at(location,
+                          ("invalid reference to unexported identifier "
+                           "%<%s.%s%>"),
+                          n1.c_str(), n2.c_str());
+               else
+                 error_at(location,
+                          "reference to undefined identifier %<%s.%s%>",
+                          n1.c_str(), n2.c_str());
+               return Expression::make_error(location);
+             }
+
+           named_object = this->gogo_->add_unknown_name(packed, location);
+         }
+
+       if (in_function != NULL
+           && in_function != this->gogo_->current_function()
+           && (named_object->is_variable()
+               || named_object->is_result_variable()))
+         return this->enclosing_var_reference(in_function, named_object,
+                                              location);
+
+       switch (named_object->classification())
+         {
+         case Named_object::NAMED_OBJECT_CONST:
+           return Expression::make_const_reference(named_object, location);
+         case Named_object::NAMED_OBJECT_TYPE:
+           return Expression::make_type(named_object->type_value(), location);
+         case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
+           {
+             Type* t = Type::make_forward_declaration(named_object);
+             return Expression::make_type(t, location);
+           }
+         case Named_object::NAMED_OBJECT_VAR:
+         case Named_object::NAMED_OBJECT_RESULT_VAR:
+           return Expression::make_var_reference(named_object, location);
+         case Named_object::NAMED_OBJECT_SINK:
+           if (may_be_sink)
+             return Expression::make_sink(location);
+           else
+             {
+               error_at(location, "cannot use _ as value");
+               return Expression::make_error(location);
+             }
+         case Named_object::NAMED_OBJECT_FUNC:
+         case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
+           return Expression::make_func_reference(named_object, NULL,
+                                                  location);
+         case Named_object::NAMED_OBJECT_UNKNOWN:
+           return Expression::make_unknown_reference(named_object, location);
+         default:
+           gcc_unreachable();
+         }
+      }
+      gcc_unreachable();
+
+    case Token::TOKEN_STRING:
+      ret = Expression::make_string(token->string_value(), token->location());
+      this->advance_token();
+      return ret;
+
+    case Token::TOKEN_INTEGER:
+      ret = Expression::make_integer(token->integer_value(), NULL,
+                                    token->location());
+      this->advance_token();
+      return ret;
+
+    case Token::TOKEN_FLOAT:
+      ret = Expression::make_float(token->float_value(), NULL,
+                                  token->location());
+      this->advance_token();
+      return ret;
+
+    case Token::TOKEN_IMAGINARY:
+      {
+       mpfr_t zero;
+       mpfr_init_set_ui(zero, 0, GMP_RNDN);
+       ret = Expression::make_complex(&zero, token->imaginary_value(),
+                                      NULL, token->location());
+       mpfr_clear(zero);
+       this->advance_token();
+       return ret;
+      }
+
+    case Token::TOKEN_KEYWORD:
+      switch (token->keyword())
+       {
+       case KEYWORD_FUNC:
+         return this->function_lit();
+       case KEYWORD_CHAN:
+       case KEYWORD_INTERFACE:
+       case KEYWORD_MAP:
+       case KEYWORD_STRUCT:
+         {
+           source_location location = token->location();
+           return Expression::make_type(this->type(), location);
+         }
+       default:
+         break;
+       }
+      break;
+
+    case Token::TOKEN_OPERATOR:
+      if (token->is_op(OPERATOR_LPAREN))
+       {
+         this->advance_token();
+         ret = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+         if (!this->peek_token()->is_op(OPERATOR_RPAREN))
+           error_at(this->location(), "missing %<)%>");
+         else
+           this->advance_token();
+         return ret;
+       }
+      else if (token->is_op(OPERATOR_LSQUARE))
+       {
+         // Here we call array_type directly, as this is the only
+         // case where an ellipsis is permitted for an array type.
+         source_location location = token->location();
+         return Expression::make_type(this->array_type(true), location);
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  error_at(this->location(), "expected operand");
+  return Expression::make_error(this->location());
+}
+
+// Handle a reference to a variable in an enclosing function.  We add
+// it to a list of such variables.  We return a reference to a field
+// in a struct which will be passed on the static chain when calling
+// the current function.
+
+Expression*
+Parse::enclosing_var_reference(Named_object* in_function, Named_object* var,
+                              source_location location)
+{
+  gcc_assert(var->is_variable() || var->is_result_variable());
+
+  Named_object* this_function = this->gogo_->current_function();
+  Named_object* closure = this_function->func_value()->closure_var();
+
+  Enclosing_var ev(var, in_function, this->enclosing_vars_.size());
+  std::pair<Enclosing_vars::iterator, bool> ins =
+    this->enclosing_vars_.insert(ev);
+  if (ins.second)
+    {
+      // This is a variable we have not seen before.  Add a new field
+      // to the closure type.
+      this_function->func_value()->add_closure_field(var, location);
+    }
+
+  Expression* closure_ref = Expression::make_var_reference(closure,
+                                                          location);
+  closure_ref = Expression::make_unary(OPERATOR_MULT, closure_ref, location);
+
+  // The closure structure holds pointers to the variables, so we need
+  // to introduce an indirection.
+  Expression* e = Expression::make_field_reference(closure_ref,
+                                                  ins.first->index(),
+                                                  location);
+  e = Expression::make_unary(OPERATOR_MULT, e, location);
+  return e;
+}
+
+// CompositeLit  = LiteralType LiteralValue .
+// LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
+//                 SliceType | MapType | TypeName .
+// LiteralValue  = "{" [ ElementList [ "," ] ] "}" .
+// ElementList   = Element { "," Element } .
+// Element       = [ Key ":" ] Value .
+// Key           = Expression .
+// Value         = Expression | LiteralValue .
+
+// We have already seen the type if there is one, and we are now
+// looking at the LiteralValue.  The case "[" "..."  "]" ElementType
+// will be seen here as an array type whose length is "nil".  The
+// DEPTH parameter is non-zero if this is an embedded composite
+// literal and the type was omitted.  It gives the number of steps up
+// to the type which was provided.  E.g., in [][]int{{1}} it will be
+// 1.  In [][][]int{{{1}}} it will be 2.
+
+Expression*
+Parse::composite_lit(Type* type, int depth, source_location location)
+{
+  gcc_assert(this->peek_token()->is_op(OPERATOR_LCURLY));
+  this->advance_token();
+
+  if (this->peek_token()->is_op(OPERATOR_RCURLY))
+    {
+      this->advance_token();
+      return Expression::make_composite_literal(type, depth, false, NULL,
+                                               location);
+    }
+
+  bool has_keys = false;
+  Expression_list* vals = new Expression_list;
+  while (true)
+    {
+      Expression* val;
+      bool is_type_omitted = false;
+
+      const Token* token = this->peek_token();
+
+      if (!token->is_op(OPERATOR_LCURLY))
+       val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+      else
+       {
+         // This must be a composite literal inside another composite
+         // literal, with the type omitted for the inner one.
+         val = this->composite_lit(type, depth + 1, token->location());
+         is_type_omitted = true;
+       }
+
+      token = this->peek_token();
+      if (!token->is_op(OPERATOR_COLON))
+       {
+         if (has_keys)
+           vals->push_back(NULL);
+       }
+      else
+       {
+         if (is_type_omitted && !val->is_error_expression())
+           {
+             error_at(this->location(), "unexpected %<:%>");
+             val = Expression::make_error(this->location());
+           }
+
+         this->advance_token();
+
+         if (!has_keys && !vals->empty())
+           {
+             Expression_list* newvals = new Expression_list;
+             for (Expression_list::const_iterator p = vals->begin();
+                  p != vals->end();
+                  ++p)
+               {
+                 newvals->push_back(NULL);
+                 newvals->push_back(*p);
+               }
+             delete vals;
+             vals = newvals;
+           }
+         has_keys = true;
+
+         if (val->unknown_expression() != NULL)
+           val->unknown_expression()->set_is_composite_literal_key();
+
+         vals->push_back(val);
+
+         if (!token->is_op(OPERATOR_LCURLY))
+           val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+         else
+           {
+             // This must be a composite literal inside another
+             // composite literal, with the type omitted for the
+             // inner one.
+             val = this->composite_lit(type, depth + 1, token->location());
+           }
+
+         token = this->peek_token();
+       }
+
+      vals->push_back(val);
+
+      if (token->is_op(OPERATOR_COMMA))
+       {
+         if (this->advance_token()->is_op(OPERATOR_RCURLY))
+           {
+             this->advance_token();
+             break;
+           }
+       }
+      else if (token->is_op(OPERATOR_RCURLY))
+       {
+         this->advance_token();
+         break;
+       }
+      else
+       {
+         error_at(this->location(), "expected %<,%> or %<}%>");
+
+         int depth = 0;
+         while (!token->is_eof()
+                && (depth > 0 || !token->is_op(OPERATOR_RCURLY)))
+           {
+             if (token->is_op(OPERATOR_LCURLY))
+               ++depth;
+             else if (token->is_op(OPERATOR_RCURLY))
+               --depth;
+             token = this->advance_token();
+           }
+         if (token->is_op(OPERATOR_RCURLY))
+           this->advance_token();
+
+         return Expression::make_error(location);
+       }
+    }
+
+  return Expression::make_composite_literal(type, depth, has_keys, vals,
+                                           location);
+}
+
+// FunctionLit = "func" Signature Block .
+
+Expression*
+Parse::function_lit()
+{
+  source_location location = this->location();
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
+  this->advance_token();
+
+  Enclosing_vars hold_enclosing_vars;
+  hold_enclosing_vars.swap(this->enclosing_vars_);
+
+  Function_type* type = this->signature(NULL, location);
+
+  // For a function literal, the next token must be a '{'.  If we
+  // don't see that, then we may have a type expression.
+  if (!this->peek_token()->is_op(OPERATOR_LCURLY))
+    return Expression::make_type(type, location);
+
+  Named_object* no = this->gogo_->start_function("", type, true, location);
+
+  source_location end_loc = this->block();
+
+  this->gogo_->finish_function(end_loc);
+
+  hold_enclosing_vars.swap(this->enclosing_vars_);
+
+  Expression* closure = this->create_closure(no, &hold_enclosing_vars,
+                                            location);
+
+  return Expression::make_func_reference(no, closure, location);
+}
+
+// Create a closure for the nested function FUNCTION.  This is based
+// on ENCLOSING_VARS, which is a list of all variables defined in
+// enclosing functions and referenced from FUNCTION.  A closure is the
+// address of a struct which contains the addresses of all the
+// referenced variables.  This returns NULL if no closure is required.
+
+Expression*
+Parse::create_closure(Named_object* function, Enclosing_vars* enclosing_vars,
+                     source_location location)
+{
+  if (enclosing_vars->empty())
+    return NULL;
+
+  // Get the variables in order by their field index.
+
+  size_t enclosing_var_count = enclosing_vars->size();
+  std::vector<Enclosing_var> ev(enclosing_var_count);
+  for (Enclosing_vars::const_iterator p = enclosing_vars->begin();
+       p != enclosing_vars->end();
+       ++p)
+    ev[p->index()] = *p;
+
+  // Build an initializer for a composite literal of the closure's
+  // type.
+
+  Named_object* enclosing_function = this->gogo_->current_function();
+  Expression_list* initializer = new Expression_list;
+  for (size_t i = 0; i < enclosing_var_count; ++i)
+    {
+      gcc_assert(ev[i].index() == i);
+      Named_object* var = ev[i].var();
+      Expression* ref;
+      if (ev[i].in_function() == enclosing_function)
+       ref = Expression::make_var_reference(var, location);
+      else
+       ref = this->enclosing_var_reference(ev[i].in_function(), var,
+                                           location);
+      Expression* refaddr = Expression::make_unary(OPERATOR_AND, ref,
+                                                  location);
+      initializer->push_back(refaddr);
+    }
+
+  Named_object* closure_var = function->func_value()->closure_var();
+  Struct_type* st = closure_var->var_value()->type()->deref()->struct_type();
+  Expression* cv = Expression::make_struct_composite_literal(st, initializer,
+                                                            location);
+  return Expression::make_heap_composite(cv, location);
+}
+
+// PrimaryExpr = Operand { Selector | Index | Slice | TypeGuard | Call } .
+
+// If MAY_BE_SINK is true, this expression may be "_".
+
+// If MAY_BE_COMPOSITE_LIT is true, this expression may be a composite
+// literal.
+
+// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
+// guard (var := expr.("type") using the literal keyword "type").
+
+Expression*
+Parse::primary_expr(bool may_be_sink, bool may_be_composite_lit,
+                   bool* is_type_switch)
+{
+  source_location start_loc = this->location();
+  bool is_parenthesized = this->peek_token()->is_op(OPERATOR_LPAREN);
+
+  Expression* ret = this->operand(may_be_sink);
+
+  // An unknown name followed by a curly brace must be a composite
+  // literal, and the unknown name must be a type.
+  if (may_be_composite_lit
+      && !is_parenthesized
+      && ret->unknown_expression() != NULL
+      && this->peek_token()->is_op(OPERATOR_LCURLY))
+    {
+      Named_object* no = ret->unknown_expression()->named_object();
+      Type* type = Type::make_forward_declaration(no);
+      ret = Expression::make_type(type, ret->location());
+    }
+
+  // We handle composite literals and type casts here, as it is the
+  // easiest way to handle types which are in parentheses, as in
+  // "((uint))(1)".
+  if (ret->is_type_expression())
+    {
+      if (this->peek_token()->is_op(OPERATOR_LCURLY))
+       {
+         if (is_parenthesized)
+           error_at(start_loc,
+                    "cannot parenthesize type in composite literal");
+         ret = this->composite_lit(ret->type(), 0, ret->location());
+       }
+      else if (this->peek_token()->is_op(OPERATOR_LPAREN))
+       {
+         source_location loc = this->location();
+         this->advance_token();
+         Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true,
+                                             NULL);
+         if (!this->peek_token()->is_op(OPERATOR_RPAREN))
+           error_at(this->location(), "expected %<)%>");
+         else
+           this->advance_token();
+         if (expr->is_error_expression())
+           return expr;
+         ret = Expression::make_cast(ret->type(), expr, loc);
+       }
+    }
+
+  while (true)
+    {
+      const Token* token = this->peek_token();
+      if (token->is_op(OPERATOR_LPAREN))
+       ret = this->call(this->verify_not_sink(ret));
+      else if (token->is_op(OPERATOR_DOT))
+       {
+         ret = this->selector(this->verify_not_sink(ret), is_type_switch);
+         if (is_type_switch != NULL && *is_type_switch)
+           break;
+       }
+      else if (token->is_op(OPERATOR_LSQUARE))
+       ret = this->index(this->verify_not_sink(ret));
+      else
+       break;
+    }
+
+  return ret;
+}
+
+// Selector = "." identifier .
+// TypeGuard = "." "(" QualifiedIdent ")" .
+
+// Note that Operand can expand to QualifiedIdent, which contains a
+// ".".  That is handled directly in operand when it sees a package
+// name.
+
+// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
+// guard (var := expr.("type") using the literal keyword "type").
+
+Expression*
+Parse::selector(Expression* left, bool* is_type_switch)
+{
+  gcc_assert(this->peek_token()->is_op(OPERATOR_DOT));
+  source_location location = this->location();
+
+  const Token* token = this->advance_token();
+  if (token->is_identifier())
+    {
+      // This could be a field in a struct, or a method in an
+      // interface, or a method associated with a type.  We can't know
+      // which until we have seen all the types.
+      std::string name =
+       this->gogo_->pack_hidden_name(token->identifier(),
+                                     token->is_identifier_exported());
+      if (token->identifier() == "_")
+       {
+         error_at(this->location(), "invalid use of %<_%>");
+         name = this->gogo_->pack_hidden_name("blank", false);
+       }
+      this->advance_token();
+      return Expression::make_selector(left, name, location);
+    }
+  else if (token->is_op(OPERATOR_LPAREN))
+    {
+      this->advance_token();
+      Type* type = NULL;
+      if (is_type_switch == NULL
+         || !this->peek_token()->is_keyword(KEYWORD_TYPE))
+       type = this->type();
+      else
+       {
+         *is_type_switch = true;
+         this->advance_token();
+       }
+      if (!this->peek_token()->is_op(OPERATOR_RPAREN))
+       error_at(this->location(), "missing %<)%>");
+      else
+       this->advance_token();
+      if (is_type_switch != NULL && *is_type_switch)
+       return left;
+      return Expression::make_type_guard(left, type, location);
+    }
+  else
+    {
+      error_at(this->location(), "expected identifier or %<(%>");
+      return left;
+    }
+}
+
+// Index          = "[" Expression "]" .
+// Slice          = "[" Expression ":" [ Expression ] "]" .
+
+Expression*
+Parse::index(Expression* expr)
+{
+  source_location location = this->location();
+  gcc_assert(this->peek_token()->is_op(OPERATOR_LSQUARE));
+  this->advance_token();
+
+  Expression* start;
+  if (!this->peek_token()->is_op(OPERATOR_COLON))
+    start = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+  else
+    {
+      mpz_t zero;
+      mpz_init_set_ui(zero, 0);
+      start = Expression::make_integer(&zero, NULL, location);
+      mpz_clear(zero);
+    }
+
+  Expression* end = NULL;
+  if (this->peek_token()->is_op(OPERATOR_COLON))
+    {
+      // We use nil to indicate a missing high expression.
+      if (this->advance_token()->is_op(OPERATOR_RSQUARE))
+       end = Expression::make_nil(this->location());
+      else
+       end = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+    }
+  if (!this->peek_token()->is_op(OPERATOR_RSQUARE))
+    error_at(this->location(), "missing %<]%>");
+  else
+    this->advance_token();
+  return Expression::make_index(expr, start, end, location);
+}
+
+// Call           = "(" [ ArgumentList [ "," ] ] ")" .
+// ArgumentList   = ExpressionList [ "..." ] .
+
+Expression*
+Parse::call(Expression* func)
+{
+  gcc_assert(this->peek_token()->is_op(OPERATOR_LPAREN));
+  Expression_list* args = NULL;
+  bool is_varargs = false;
+  const Token* token = this->advance_token();
+  if (!token->is_op(OPERATOR_RPAREN))
+    {
+      args = this->expression_list(NULL, false);
+      token = this->peek_token();
+      if (token->is_op(OPERATOR_ELLIPSIS))
+       {
+         is_varargs = true;
+         token = this->advance_token();
+       }
+    }
+  if (token->is_op(OPERATOR_COMMA))
+    token = this->advance_token();
+  if (!token->is_op(OPERATOR_RPAREN))
+    error_at(this->location(), "missing %<)%>");
+  else
+    this->advance_token();
+  if (func->is_error_expression())
+    return func;
+  return Expression::make_call(func, args, is_varargs, func->location());
+}
+
+// Return an expression for a single unqualified identifier.
+
+Expression*
+Parse::id_to_expression(const std::string& name, source_location location)
+{
+  Named_object* in_function;
+  Named_object* named_object = this->gogo_->lookup(name, &in_function);
+  if (named_object == NULL)
+    named_object = this->gogo_->add_unknown_name(name, location);
+
+  if (in_function != NULL
+      && in_function != this->gogo_->current_function()
+      && (named_object->is_variable() || named_object->is_result_variable()))
+    return this->enclosing_var_reference(in_function, named_object,
+                                        location);
+
+  switch (named_object->classification())
+    {
+    case Named_object::NAMED_OBJECT_CONST:
+      return Expression::make_const_reference(named_object, location);
+    case Named_object::NAMED_OBJECT_VAR:
+    case Named_object::NAMED_OBJECT_RESULT_VAR:
+      return Expression::make_var_reference(named_object, location);
+    case Named_object::NAMED_OBJECT_SINK:
+      return Expression::make_sink(location);
+    case Named_object::NAMED_OBJECT_FUNC:
+    case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
+      return Expression::make_func_reference(named_object, NULL, location);
+    case Named_object::NAMED_OBJECT_UNKNOWN:
+      return Expression::make_unknown_reference(named_object, location);
+    default:
+      error_at(this->location(), "unexpected type of identifier");
+      return Expression::make_error(location);
+    }
+}
+
+// Expression = UnaryExpr { binary_op Expression } .
+
+// PRECEDENCE is the precedence of the current operator.
+
+// If MAY_BE_SINK is true, this expression may be "_".
+
+// If MAY_BE_COMPOSITE_LIT is true, this expression may be a composite
+// literal.
+
+// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
+// guard (var := expr.("type") using the literal keyword "type").
+
+Expression*
+Parse::expression(Precedence precedence, bool may_be_sink,
+                 bool may_be_composite_lit, bool* is_type_switch)
+{
+  Expression* left = this->unary_expr(may_be_sink, may_be_composite_lit,
+                                     is_type_switch);
+
+  while (true)
+    {
+      if (is_type_switch != NULL && *is_type_switch)
+       return left;
+
+      const Token* token = this->peek_token();
+      if (token->classification() != Token::TOKEN_OPERATOR)
+       {
+         // Not a binary_op.
+         return left;
+       }
+
+      Precedence right_precedence;
+      switch (token->op())
+       {
+       case OPERATOR_OROR:
+         right_precedence = PRECEDENCE_OROR;
+         break;
+       case OPERATOR_ANDAND:
+         right_precedence = PRECEDENCE_ANDAND;
+         break;
+       case OPERATOR_CHANOP:
+         right_precedence = PRECEDENCE_CHANOP;
+         break;
+       case OPERATOR_EQEQ:
+       case OPERATOR_NOTEQ:
+       case OPERATOR_LT:
+       case OPERATOR_LE:
+       case OPERATOR_GT:
+       case OPERATOR_GE:
+         right_precedence = PRECEDENCE_RELOP;
+         break;
+       case OPERATOR_PLUS:
+       case OPERATOR_MINUS:
+       case OPERATOR_OR:
+       case OPERATOR_XOR:
+         right_precedence = PRECEDENCE_ADDOP;
+         break;
+       case OPERATOR_MULT:
+       case OPERATOR_DIV:
+       case OPERATOR_MOD:
+       case OPERATOR_LSHIFT:
+       case OPERATOR_RSHIFT:
+       case OPERATOR_AND:
+       case OPERATOR_BITCLEAR:
+         right_precedence = PRECEDENCE_MULOP;
+         break;
+       default:
+         right_precedence = PRECEDENCE_INVALID;
+         break;
+       }
+
+      if (right_precedence == PRECEDENCE_INVALID)
+       {
+         // Not a binary_op.
+         return left;
+       }
+
+      Operator op = token->op();
+      source_location binop_location = token->location();
+
+      if (precedence >= right_precedence)
+       {
+         // We've already seen A * B, and we see + C.  We want to
+         // return so that A * B becomes a group.
+         return left;
+       }
+
+      this->advance_token();
+
+      left = this->verify_not_sink(left);
+      Expression* right = this->expression(right_precedence, false,
+                                          may_be_composite_lit,
+                                          is_type_switch);
+      if (op == OPERATOR_CHANOP)
+       left = Expression::make_send(left, right, binop_location);
+      else
+       left = Expression::make_binary(op, left, right, binop_location);
+    }
+}
+
+bool
+Parse::expression_may_start_here()
+{
+  const Token* token = this->peek_token();
+  switch (token->classification())
+    {
+    case Token::TOKEN_INVALID:
+    case Token::TOKEN_EOF:
+      return false;
+    case Token::TOKEN_KEYWORD:
+      switch (token->keyword())
+       {
+       case KEYWORD_CHAN:
+       case KEYWORD_FUNC:
+       case KEYWORD_MAP:
+       case KEYWORD_STRUCT:
+       case KEYWORD_INTERFACE:
+         return true;
+       default:
+         return false;
+       }
+    case Token::TOKEN_IDENTIFIER:
+      return true;
+    case Token::TOKEN_STRING:
+      return true;
+    case Token::TOKEN_OPERATOR:
+      switch (token->op())
+       {
+       case OPERATOR_PLUS:
+       case OPERATOR_MINUS:
+       case OPERATOR_NOT:
+       case OPERATOR_XOR:
+       case OPERATOR_MULT:
+       case OPERATOR_CHANOP:
+       case OPERATOR_AND:
+       case OPERATOR_LPAREN:
+       case OPERATOR_LSQUARE:
+         return true;
+       default:
+         return false;
+       }
+    case Token::TOKEN_INTEGER:
+    case Token::TOKEN_FLOAT:
+    case Token::TOKEN_IMAGINARY:
+      return true;
+    default:
+      gcc_unreachable();
+    }
+}
+
+// UnaryExpr = unary_op UnaryExpr | PrimaryExpr .
+
+// If MAY_BE_SINK is true, this expression may be "_".
+
+// If MAY_BE_COMPOSITE_LIT is true, this expression may be a composite
+// literal.
+
+// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
+// guard (var := expr.("type") using the literal keyword "type").
+
+Expression*
+Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
+                 bool* is_type_switch)
+{
+  const Token* token = this->peek_token();
+  if (token->is_op(OPERATOR_PLUS)
+      || token->is_op(OPERATOR_MINUS)
+      || token->is_op(OPERATOR_NOT)
+      || token->is_op(OPERATOR_XOR)
+      || token->is_op(OPERATOR_CHANOP)
+      || token->is_op(OPERATOR_MULT)
+      || token->is_op(OPERATOR_AND))
+    {
+      source_location location = token->location();
+      Operator op = token->op();
+      this->advance_token();
+
+      if (op == OPERATOR_CHANOP
+         && this->peek_token()->is_keyword(KEYWORD_CHAN))
+       {
+         // This is "<- chan" which must be the start of a type.
+         this->unget_token(Token::make_operator_token(op, location));
+         return Expression::make_type(this->type(), location);
+       }
+
+      Expression* expr = this->unary_expr(false, may_be_composite_lit,
+                                         is_type_switch);
+      if (expr->is_error_expression())
+       ;
+      else if (op == OPERATOR_MULT && expr->is_type_expression())
+       expr = Expression::make_type(Type::make_pointer_type(expr->type()),
+                                    location);
+      else if (op == OPERATOR_AND && expr->is_composite_literal())
+       expr = Expression::make_heap_composite(expr, location);
+      else if (op != OPERATOR_CHANOP)
+       expr = Expression::make_unary(op, expr, location);
+      else
+       expr = Expression::make_receive(expr, location);
+      return expr;
+    }
+  else
+    return this->primary_expr(may_be_sink, may_be_composite_lit,
+                             is_type_switch);
+}
+
+// Statement =
+//     Declaration | LabeledStmt | SimpleStmt |
+//     GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
+//     FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
+//     DeferStmt .
+
+// LABEL is the label of this statement if it has one.
+
+void
+Parse::statement(const Label* label)
+{
+  const Token* token = this->peek_token();
+  switch (token->classification())
+    {
+    case Token::TOKEN_KEYWORD:
+      {
+       switch (token->keyword())
+         {
+         case KEYWORD_CONST:
+         case KEYWORD_TYPE:
+         case KEYWORD_VAR:
+           this->declaration();
+           break;
+         case KEYWORD_FUNC:
+         case KEYWORD_MAP:
+         case KEYWORD_STRUCT:
+         case KEYWORD_INTERFACE:
+           this->simple_stat(true, false, NULL, NULL);
+           break;
+         case KEYWORD_GO:
+         case KEYWORD_DEFER:
+           this->go_or_defer_stat();
+           break;
+         case KEYWORD_RETURN:
+           this->return_stat();
+           break;
+         case KEYWORD_BREAK:
+           this->break_stat();
+           break;
+         case KEYWORD_CONTINUE:
+           this->continue_stat();
+           break;
+         case KEYWORD_GOTO:
+           this->goto_stat();
+           break;
+         case KEYWORD_IF:
+           this->if_stat();
+           break;
+         case KEYWORD_SWITCH:
+           this->switch_stat(label);
+           break;
+         case KEYWORD_SELECT:
+           this->select_stat(label);
+           break;
+         case KEYWORD_FOR:
+           this->for_stat(label);
+           break;
+         default:
+           error_at(this->location(), "expected statement");
+           this->advance_token();
+           break;
+         }
+      }
+      break;
+
+    case Token::TOKEN_IDENTIFIER:
+      {
+       std::string identifier = token->identifier();
+       bool is_exported = token->is_identifier_exported();
+       source_location location = token->location();
+       if (this->advance_token()->is_op(OPERATOR_COLON))
+         {
+           this->advance_token();
+           this->labeled_stmt(identifier, location);
+         }
+       else
+         {
+           this->unget_token(Token::make_identifier_token(identifier,
+                                                          is_exported,
+                                                          location));
+           this->simple_stat(true, false, NULL, NULL);
+         }
+      }
+      break;
+
+    case Token::TOKEN_OPERATOR:
+      if (token->is_op(OPERATOR_LCURLY))
+       {
+         source_location location = token->location();
+         this->gogo_->start_block(location);
+         source_location end_loc = this->block();
+         this->gogo_->add_block(this->gogo_->finish_block(end_loc),
+                                location);
+       }
+      else if (!token->is_op(OPERATOR_SEMICOLON))
+       this->simple_stat(true, false, NULL, NULL);
+      break;
+
+    case Token::TOKEN_STRING:
+    case Token::TOKEN_INTEGER:
+    case Token::TOKEN_FLOAT:
+    case Token::TOKEN_IMAGINARY:
+      this->simple_stat(true, false, NULL, NULL);
+      break;
+
+    default:
+      error_at(this->location(), "expected statement");
+      this->advance_token();
+      break;
+    }
+}
+
+bool
+Parse::statement_may_start_here()
+{
+  const Token* token = this->peek_token();
+  switch (token->classification())
+    {
+    case Token::TOKEN_KEYWORD:
+      {
+       switch (token->keyword())
+         {
+         case KEYWORD_CONST:
+         case KEYWORD_TYPE:
+         case KEYWORD_VAR:
+         case KEYWORD_FUNC:
+         case KEYWORD_MAP:
+         case KEYWORD_STRUCT:
+         case KEYWORD_INTERFACE:
+         case KEYWORD_GO:
+         case KEYWORD_DEFER:
+         case KEYWORD_RETURN:
+         case KEYWORD_BREAK:
+         case KEYWORD_CONTINUE:
+         case KEYWORD_GOTO:
+         case KEYWORD_IF:
+         case KEYWORD_SWITCH:
+         case KEYWORD_SELECT:
+         case KEYWORD_FOR:
+           return true;
+
+         default:
+           return false;
+         }
+      }
+      break;
+
+    case Token::TOKEN_IDENTIFIER:
+      return true;
+
+    case Token::TOKEN_OPERATOR:
+      if (token->is_op(OPERATOR_LCURLY)
+         || token->is_op(OPERATOR_SEMICOLON))
+       return true;
+      else
+       return this->expression_may_start_here();
+
+    case Token::TOKEN_STRING:
+    case Token::TOKEN_INTEGER:
+    case Token::TOKEN_FLOAT:
+    case Token::TOKEN_IMAGINARY:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+// LabeledStmt = Label ":" Statement .
+// Label       = identifier .
+
+void
+Parse::labeled_stmt(const std::string& label_name, source_location location)
+{
+  Label* label = this->gogo_->add_label_definition(label_name, location);
+
+  if (this->peek_token()->is_op(OPERATOR_RCURLY))
+    {
+      // This is a label at the end of a block.  A program is
+      // permitted to omit a semicolon here.
+      return;
+    }
+
+  if (!this->statement_may_start_here())
+    {
+      error_at(location, "missing statement after label");
+      this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
+                                                  location));
+      return;
+    }
+
+  this->statement(label);
+}
+
+// SimpleStat =
+//   ExpressionStat | IncDecStat | Assignment | SimpleVarDecl .
+
+// In order to make this work for if and switch statements, if
+// RETURN_EXP is true, and we see an ExpressionStat, we return the
+// expression rather than adding an expression statement to the
+// current block.  If we see something other than an ExpressionStat,
+// we add the statement and return NULL.
+
+// If P_RANGE_CLAUSE is not NULL, then this will recognize a
+// RangeClause.
+
+// If P_TYPE_SWITCH is not NULL, this will recognize a type switch
+// guard (var := expr.("type") using the literal keyword "type").
+
+Expression*
+Parse::simple_stat(bool may_be_composite_lit, bool return_exp,
+                  Range_clause* p_range_clause, Type_switch* p_type_switch)
+{
+  const Token* token = this->peek_token();
+
+  // An identifier follow by := is a SimpleVarDecl.
+  if (token->is_identifier())
+    {
+      std::string identifier = token->identifier();
+      bool is_exported = token->is_identifier_exported();
+      source_location location = token->location();
+
+      token = this->advance_token();
+      if (token->is_op(OPERATOR_COLONEQ)
+         || token->is_op(OPERATOR_COMMA))
+       {
+         identifier = this->gogo_->pack_hidden_name(identifier, is_exported);
+         this->simple_var_decl_or_assignment(identifier, location,
+                                             p_range_clause,
+                                             (token->is_op(OPERATOR_COLONEQ)
+                                              ? p_type_switch
+                                              : NULL));
+         return NULL;
+       }
+
+      this->unget_token(Token::make_identifier_token(identifier, is_exported,
+                                                    location));
+    }
+
+  Expression* exp = this->expression(PRECEDENCE_NORMAL, true,
+                                    may_be_composite_lit,
+                                    (p_type_switch == NULL
+                                     ? NULL
+                                     : &p_type_switch->found));
+  if (p_type_switch != NULL && p_type_switch->found)
+    {
+      p_type_switch->name.clear();
+      p_type_switch->location = exp->location();
+      p_type_switch->expr = this->verify_not_sink(exp);
+      return NULL;
+    }
+  token = this->peek_token();
+  if (token->is_op(OPERATOR_PLUSPLUS) || token->is_op(OPERATOR_MINUSMINUS))
+    this->inc_dec_stat(this->verify_not_sink(exp));
+  else if (token->is_op(OPERATOR_COMMA)
+          || token->is_op(OPERATOR_EQ))
+    this->assignment(exp, p_range_clause);
+  else if (token->is_op(OPERATOR_PLUSEQ)
+          || token->is_op(OPERATOR_MINUSEQ)
+          || token->is_op(OPERATOR_OREQ)
+          || token->is_op(OPERATOR_XOREQ)
+          || token->is_op(OPERATOR_MULTEQ)
+          || token->is_op(OPERATOR_DIVEQ)
+          || token->is_op(OPERATOR_MODEQ)
+          || token->is_op(OPERATOR_LSHIFTEQ)
+          || token->is_op(OPERATOR_RSHIFTEQ)
+          || token->is_op(OPERATOR_ANDEQ)
+          || token->is_op(OPERATOR_BITCLEAREQ))
+    this->assignment(this->verify_not_sink(exp), p_range_clause);
+  else if (return_exp)
+    return this->verify_not_sink(exp);
+  else
+    this->expression_stat(this->verify_not_sink(exp));
+
+  return NULL;
+}
+
+bool
+Parse::simple_stat_may_start_here()
+{
+  return this->expression_may_start_here();
+}
+
+// Parse { Statement ";" } which is used in a few places.  The list of
+// statements may end with a right curly brace, in which case the
+// semicolon may be omitted.
+
+void
+Parse::statement_list()
+{
+  while (this->statement_may_start_here())
+    {
+      this->statement(NULL);
+      if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+       this->advance_token();
+      else if (this->peek_token()->is_op(OPERATOR_RCURLY))
+       break;
+      else
+       {
+         if (!this->peek_token()->is_eof() || !saw_errors())
+           error_at(this->location(), "expected %<;%> or %<}%> or newline");
+         if (!this->skip_past_error(OPERATOR_RCURLY))
+           return;
+       }
+    }
+}
+
+bool
+Parse::statement_list_may_start_here()
+{
+  return this->statement_may_start_here();
+}
+
+// ExpressionStat = Expression .
+
+void
+Parse::expression_stat(Expression* exp)
+{
+  exp->discarding_value();
+  this->gogo_->add_statement(Statement::make_statement(exp));
+}
+
+// IncDecStat = Expression ( "++" | "--" ) .
+
+void
+Parse::inc_dec_stat(Expression* exp)
+{
+  const Token* token = this->peek_token();
+
+  // Lvalue maps require special handling.
+  if (exp->index_expression() != NULL)
+    exp->index_expression()->set_is_lvalue();
+
+  if (token->is_op(OPERATOR_PLUSPLUS))
+    this->gogo_->add_statement(Statement::make_inc_statement(exp));
+  else if (token->is_op(OPERATOR_MINUSMINUS))
+    this->gogo_->add_statement(Statement::make_dec_statement(exp));
+  else
+    gcc_unreachable();
+  this->advance_token();
+}
+
+// Assignment = ExpressionList assign_op ExpressionList .
+
+// EXP is an expression that we have already parsed.
+
+// If RANGE_CLAUSE is not NULL, then this will recognize a
+// RangeClause.
+
+void
+Parse::assignment(Expression* expr, Range_clause* p_range_clause)
+{
+  Expression_list* vars;
+  if (!this->peek_token()->is_op(OPERATOR_COMMA))
+    {
+      vars = new Expression_list();
+      vars->push_back(expr);
+    }
+  else
+    {
+      this->advance_token();
+      vars = this->expression_list(expr, true);
+    }
+
+  this->tuple_assignment(vars, p_range_clause);
+}
+
+// An assignment statement.  LHS is the list of expressions which
+// appear on the left hand side.
+
+// If RANGE_CLAUSE is not NULL, then this will recognize a
+// RangeClause.
+
+void
+Parse::tuple_assignment(Expression_list* lhs, Range_clause* p_range_clause)
+{
+  const Token* token = this->peek_token();
+  if (!token->is_op(OPERATOR_EQ)
+      && !token->is_op(OPERATOR_PLUSEQ)
+      && !token->is_op(OPERATOR_MINUSEQ)
+      && !token->is_op(OPERATOR_OREQ)
+      && !token->is_op(OPERATOR_XOREQ)
+      && !token->is_op(OPERATOR_MULTEQ)
+      && !token->is_op(OPERATOR_DIVEQ)
+      && !token->is_op(OPERATOR_MODEQ)
+      && !token->is_op(OPERATOR_LSHIFTEQ)
+      && !token->is_op(OPERATOR_RSHIFTEQ)
+      && !token->is_op(OPERATOR_ANDEQ)
+      && !token->is_op(OPERATOR_BITCLEAREQ))
+    {
+      error_at(this->location(), "expected assignment operator");
+      return;
+    }
+  Operator op = token->op();
+  source_location location = token->location();
+
+  token = this->advance_token();
+
+  if (p_range_clause != NULL && token->is_keyword(KEYWORD_RANGE))
+    {
+      if (op != OPERATOR_EQ)
+       error_at(this->location(), "range clause requires %<=%>");
+      this->range_clause_expr(lhs, p_range_clause);
+      return;
+    }
+
+  Expression_list* vals = this->expression_list(NULL, false);
+
+  // We've parsed everything; check for errors.
+  if (lhs == NULL || vals == NULL)
+    return;
+  for (Expression_list::const_iterator pe = lhs->begin();
+       pe != lhs->end();
+       ++pe)
+    {
+      if ((*pe)->is_error_expression())
+       return;
+      if (op != OPERATOR_EQ && (*pe)->is_sink_expression())
+       error_at((*pe)->location(), "cannot use _ as value");
+    }
+  for (Expression_list::const_iterator pe = vals->begin();
+       pe != vals->end();
+       ++pe)
+    {
+      if ((*pe)->is_error_expression())
+       return;
+    }
+
+  // Map expressions act differently when they are lvalues.
+  for (Expression_list::iterator plv = lhs->begin();
+       plv != lhs->end();
+       ++plv)
+    if ((*plv)->index_expression() != NULL)
+      (*plv)->index_expression()->set_is_lvalue();
+
+  Call_expression* call;
+  Index_expression* map_index;
+  Receive_expression* receive;
+  Type_guard_expression* type_guard;
+  if (lhs->size() == vals->size())
+    {
+      Statement* s;
+      if (lhs->size() > 1)
+       {
+         if (op != OPERATOR_EQ)
+           error_at(location, "multiple values only permitted with %<=%>");
+         s = Statement::make_tuple_assignment(lhs, vals, location);
+       }
+      else
+       {
+         if (op == OPERATOR_EQ)
+           s = Statement::make_assignment(lhs->front(), vals->front(),
+                                          location);
+         else
+           s = Statement::make_assignment_operation(op, lhs->front(),
+                                                    vals->front(), location);
+         delete lhs;
+         delete vals;
+       }
+      this->gogo_->add_statement(s);
+    }
+  else if (vals->size() == 1
+          && (call = (*vals->begin())->call_expression()) != NULL)
+    {
+      if (op != OPERATOR_EQ)
+       error_at(location, "multiple results only permitted with %<=%>");
+      delete vals;
+      vals = new Expression_list;
+      for (unsigned int i = 0; i < lhs->size(); ++i)
+       vals->push_back(Expression::make_call_result(call, i));
+      Statement* s = Statement::make_tuple_assignment(lhs, vals, location);
+      this->gogo_->add_statement(s);
+    }
+  else if (lhs->size() == 2
+          && vals->size() == 1
+          && (map_index = (*vals->begin())->index_expression()) != NULL)
+    {
+      if (op != OPERATOR_EQ)
+       error_at(location, "two values from map requires %<=%>");
+      Expression* val = lhs->front();
+      Expression* present = lhs->back();
+      Statement* s = Statement::make_tuple_map_assignment(val, present,
+                                                         map_index, location);
+      this->gogo_->add_statement(s);
+    }
+  else if (lhs->size() == 1
+          && vals->size() == 2
+          && (map_index = lhs->front()->index_expression()) != NULL)
+    {
+      if (op != OPERATOR_EQ)
+       error_at(location, "assigning tuple to map index requires %<=%>");
+      Expression* val = vals->front();
+      Expression* should_set = vals->back();
+      Statement* s = Statement::make_map_assignment(map_index, val, should_set,
+                                                   location);
+      this->gogo_->add_statement(s);
+    }
+  else if (lhs->size() == 2
+          && vals->size() == 1
+          && (receive = (*vals->begin())->receive_expression()) != NULL)
+    {
+      if (op != OPERATOR_EQ)
+       error_at(location, "two values from receive requires %<=%>");
+      Expression* val = lhs->front();
+      Expression* success = lhs->back();
+      Expression* channel = receive->channel();
+      Statement* s = Statement::make_tuple_receive_assignment(val, success,
+                                                             channel,
+                                                             location);
+      this->gogo_->add_statement(s);
+    }
+  else if (lhs->size() == 2
+          && vals->size() == 1
+          && (type_guard = (*vals->begin())->type_guard_expression()) != NULL)
+    {
+      if (op != OPERATOR_EQ)
+       error_at(location, "two values from type guard requires %<=%>");
+      Expression* val = lhs->front();
+      Expression* ok = lhs->back();
+      Expression* expr = type_guard->expr();
+      Type* type = type_guard->type();
+      Statement* s = Statement::make_tuple_type_guard_assignment(val, ok,
+                                                                expr, type,
+                                                                location);
+      this->gogo_->add_statement(s);
+    }
+  else
+    {
+      error_at(location, "number of variables does not match number of values");
+    }
+}
+
+// GoStat = "go" Expression .
+// DeferStat = "defer" Expression .
+
+void
+Parse::go_or_defer_stat()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_GO)
+            || this->peek_token()->is_keyword(KEYWORD_DEFER));
+  bool is_go = this->peek_token()->is_keyword(KEYWORD_GO);
+  source_location stat_location = this->location();
+  this->advance_token();
+  source_location expr_location = this->location();
+  Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+  Call_expression* call_expr = expr->call_expression();
+  if (call_expr == NULL)
+    {
+      error_at(expr_location, "expected call expression");
+      return;
+    }
+
+  // Make it easier to simplify go/defer statements by putting every
+  // statement in its own block.
+  this->gogo_->start_block(stat_location);
+  Statement* stat;
+  if (is_go)
+    stat = Statement::make_go_statement(call_expr, stat_location);
+  else
+    stat = Statement::make_defer_statement(call_expr, stat_location);
+  this->gogo_->add_statement(stat);
+  this->gogo_->add_block(this->gogo_->finish_block(stat_location),
+                        stat_location);
+}
+
+// ReturnStat = "return" [ ExpressionList ] .
+
+void
+Parse::return_stat()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_RETURN));
+  source_location location = this->location();
+  this->advance_token();
+  Expression_list* vals = NULL;
+  if (this->expression_may_start_here())
+    vals = this->expression_list(NULL, false);
+  const Function* function = this->gogo_->current_function()->func_value();
+  const Typed_identifier_list* results = function->type()->results();
+  this->gogo_->add_statement(Statement::make_return_statement(results, vals,
+                                                             location));
+}
+
+// IfStat = "if" [ [ SimpleStat ] ";" ] [ Condition ]
+//             Block [ "else" Statement ] .
+
+void
+Parse::if_stat()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_IF));
+  source_location location = this->location();
+  this->advance_token();
+
+  this->gogo_->start_block(location);
+
+  Expression* cond = NULL;
+  if (this->simple_stat_may_start_here())
+    cond = this->simple_stat(false, true, NULL, NULL);
+  if (cond != NULL && this->peek_token()->is_op(OPERATOR_SEMICOLON))
+    {
+      // The SimpleStat is an expression statement.
+      this->expression_stat(cond);
+      cond = NULL;
+    }
+  if (cond == NULL)
+    {
+      if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+       this->advance_token();
+      if (!this->peek_token()->is_op(OPERATOR_LCURLY))
+       cond = this->expression(PRECEDENCE_NORMAL, false, false, NULL);
+    }
+
+  this->gogo_->start_block(this->location());
+  source_location end_loc = this->block();
+  Block* then_block = this->gogo_->finish_block(end_loc);
+
+  // Check for the easy error of a newline before "else".
+  if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+    {
+      source_location semi_loc = this->location();
+      if (this->advance_token()->is_keyword(KEYWORD_ELSE))
+       error_at(this->location(),
+                "unexpected semicolon or newline before %<else%>");
+      else
+       this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
+                                                    semi_loc));
+    }
+
+  Block* else_block = NULL;
+  if (this->peek_token()->is_keyword(KEYWORD_ELSE))
+    {
+      this->advance_token();
+      // We create a block to gather the statement.
+      this->gogo_->start_block(this->location());
+      this->statement(NULL);
+      else_block = this->gogo_->finish_block(this->location());
+    }
+
+  this->gogo_->add_statement(Statement::make_if_statement(cond, then_block,
+                                                         else_block,
+                                                         location));
+
+  this->gogo_->add_block(this->gogo_->finish_block(this->location()),
+                        location);
+}
+
+// SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
+// ExprSwitchStmt = "switch" [ [ SimpleStat ] ";" ] [ Expression ]
+//                     "{" { ExprCaseClause } "}" .
+// TypeSwitchStmt  = "switch" [ [ SimpleStat ] ";" ] TypeSwitchGuard
+//                     "{" { TypeCaseClause } "}" .
+// TypeSwitchGuard = [ identifier ":=" ] Expression "." "(" "type" ")" .
+
+void
+Parse::switch_stat(const Label* label)
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_SWITCH));
+  source_location location = this->location();
+  this->advance_token();
+
+  this->gogo_->start_block(location);
+
+  Expression* switch_val = NULL;
+  Type_switch type_switch;
+  if (this->simple_stat_may_start_here())
+    switch_val = this->simple_stat(false, true, NULL, &type_switch);
+  if (switch_val != NULL && this->peek_token()->is_op(OPERATOR_SEMICOLON))
+    {
+      // The SimpleStat is an expression statement.
+      this->expression_stat(switch_val);
+      switch_val = NULL;
+    }
+  if (switch_val == NULL && !type_switch.found)
+    {
+      if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+       this->advance_token();
+      if (!this->peek_token()->is_op(OPERATOR_LCURLY))
+       {
+         if (this->peek_token()->is_identifier())
+           {
+             const Token* token = this->peek_token();
+             std::string identifier = token->identifier();
+             bool is_exported = token->is_identifier_exported();
+             source_location id_loc = token->location();
+
+             token = this->advance_token();
+             bool is_coloneq = token->is_op(OPERATOR_COLONEQ);
+             this->unget_token(Token::make_identifier_token(identifier,
+                                                            is_exported,
+                                                            id_loc));
+             if (is_coloneq)
+               {
+                 // This must be a TypeSwitchGuard.
+                 switch_val = this->simple_stat(false, true, NULL,
+                                                &type_switch);
+                 if (!type_switch.found
+                     && !switch_val->is_error_expression())
+                   {
+                     error_at(id_loc, "expected type switch assignment");
+                     switch_val = Expression::make_error(id_loc);
+                   }
+               }
+           }
+         if (switch_val == NULL && !type_switch.found)
+           {
+             switch_val = this->expression(PRECEDENCE_NORMAL, false, false,
+                                           &type_switch.found);
+             if (type_switch.found)
+               {
+                 type_switch.name.clear();
+                 type_switch.expr = switch_val;
+                 type_switch.location = switch_val->location();
+               }
+           }
+       }
+    }
+
+  if (!this->peek_token()->is_op(OPERATOR_LCURLY))
+    {
+      source_location token_loc = this->location();
+      if (this->peek_token()->is_op(OPERATOR_SEMICOLON)
+         && this->advance_token()->is_op(OPERATOR_LCURLY))
+       error_at(token_loc, "unexpected semicolon or newline before %<{%>");
+      else
+       {
+         error_at(this->location(), "expected %<{%>");
+         this->gogo_->add_block(this->gogo_->finish_block(this->location()),
+                                location);
+         return;
+       }
+    }
+  this->advance_token();
+
+  Statement* statement;
+  if (type_switch.found)
+    statement = this->type_switch_body(label, type_switch, location);
+  else
+    statement = this->expr_switch_body(label, switch_val, location);
+
+  if (statement != NULL)
+    this->gogo_->add_statement(statement);
+
+  this->gogo_->add_block(this->gogo_->finish_block(this->location()),
+                        location);
+}
+
+// The body of an expression switch.
+//   "{" { ExprCaseClause } "}"
+
+Statement*
+Parse::expr_switch_body(const Label* label, Expression* switch_val,
+                       source_location location)
+{
+  Switch_statement* statement = Statement::make_switch_statement(switch_val,
+                                                                location);
+
+  this->push_break_statement(statement, label);
+
+  Case_clauses* case_clauses = new Case_clauses();
+  while (!this->peek_token()->is_op(OPERATOR_RCURLY))
+    {
+      if (this->peek_token()->is_eof())
+       {
+         if (!saw_errors())
+           error_at(this->location(), "missing %<}%>");
+         return NULL;
+       }
+      this->expr_case_clause(case_clauses);
+    }
+  this->advance_token();
+
+  statement->add_clauses(case_clauses);
+
+  this->pop_break_statement();
+
+  return statement;
+}
+
+// ExprCaseClause = ExprSwitchCase ":" [ StatementList ] .
+// FallthroughStat = "fallthrough" .
+
+void
+Parse::expr_case_clause(Case_clauses* clauses)
+{
+  source_location location = this->location();
+
+  bool is_default = false;
+  Expression_list* vals = this->expr_switch_case(&is_default);
+
+  if (!this->peek_token()->is_op(OPERATOR_COLON))
+    {
+      if (!saw_errors())
+       error_at(this->location(), "expected %<:%>");
+      return;
+    }
+  else
+    this->advance_token();
+
+  Block* statements = NULL;
+  if (this->statement_list_may_start_here())
+    {
+      this->gogo_->start_block(this->location());
+      this->statement_list();
+      statements = this->gogo_->finish_block(this->location());
+    }
+
+  bool is_fallthrough = false;
+  if (this->peek_token()->is_keyword(KEYWORD_FALLTHROUGH))
+    {
+      is_fallthrough = true;
+      if (this->advance_token()->is_op(OPERATOR_SEMICOLON))
+       this->advance_token();
+    }
+
+  if (is_default || vals != NULL)
+    clauses->add(vals, is_default, statements, is_fallthrough, location);
+}
+
+// ExprSwitchCase = "case" ExpressionList | "default" .
+
+Expression_list*
+Parse::expr_switch_case(bool* is_default)
+{
+  const Token* token = this->peek_token();
+  if (token->is_keyword(KEYWORD_CASE))
+    {
+      this->advance_token();
+      return this->expression_list(NULL, false);
+    }
+  else if (token->is_keyword(KEYWORD_DEFAULT))
+    {
+      this->advance_token();
+      *is_default = true;
+      return NULL;
+    }
+  else
+    {
+      if (!saw_errors())
+       error_at(this->location(), "expected %<case%> or %<default%>");
+      if (!token->is_op(OPERATOR_RCURLY))
+       this->advance_token();
+      return NULL;
+    }
+}
+
+// The body of a type switch.
+//   "{" { TypeCaseClause } "}" .
+
+Statement*
+Parse::type_switch_body(const Label* label, const Type_switch& type_switch,
+                       source_location location)
+{
+  Named_object* switch_no = NULL;
+  if (!type_switch.name.empty())
+    {
+      Variable* switch_var = new Variable(NULL, type_switch.expr, false, false,
+                                         false, type_switch.location);
+      switch_no = this->gogo_->add_variable(type_switch.name, switch_var);
+    }
+
+  Type_switch_statement* statement =
+    Statement::make_type_switch_statement(switch_no,
+                                         (switch_no == NULL
+                                          ? type_switch.expr
+                                          : NULL),
+                                         location);
+
+  this->push_break_statement(statement, label);
+
+  Type_case_clauses* case_clauses = new Type_case_clauses();
+  while (!this->peek_token()->is_op(OPERATOR_RCURLY))
+    {
+      if (this->peek_token()->is_eof())
+       {
+         error_at(this->location(), "missing %<}%>");
+         return NULL;
+       }
+      this->type_case_clause(switch_no, case_clauses);
+    }
+  this->advance_token();
+
+  statement->add_clauses(case_clauses);
+
+  this->pop_break_statement();
+
+  return statement;
+}
+
+// TypeCaseClause  = TypeSwitchCase ":" [ StatementList ] .
+
+void
+Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses)
+{
+  source_location location = this->location();
+
+  std::vector<Type*> types;
+  bool is_default = false;
+  this->type_switch_case(&types, &is_default);
+
+  if (!this->peek_token()->is_op(OPERATOR_COLON))
+    error_at(this->location(), "expected %<:%>");
+  else
+    this->advance_token();
+
+  Block* statements = NULL;
+  if (this->statement_list_may_start_here())
+    {
+      this->gogo_->start_block(this->location());
+      if (switch_no != NULL && types.size() == 1)
+       {
+         Type* type = types.front();
+         Expression* init = Expression::make_var_reference(switch_no,
+                                                           location);
+         init = Expression::make_type_guard(init, type, location);
+         Variable* v = new Variable(type, init, false, false, false,
+                                    location);
+         v->set_is_type_switch_var();
+         this->gogo_->add_variable(switch_no->name(), v);
+       }
+      this->statement_list();
+      statements = this->gogo_->finish_block(this->location());
+    }
+
+  if (this->peek_token()->is_keyword(KEYWORD_FALLTHROUGH))
+    {
+      error_at(this->location(),
+              "fallthrough is not permitted in a type switch");
+      if (this->advance_token()->is_op(OPERATOR_SEMICOLON))
+       this->advance_token();
+    }
+
+  if (is_default)
+    {
+      gcc_assert(types.empty());
+      clauses->add(NULL, false, true, statements, location);
+    }
+  else if (!types.empty())
+    {
+      for (std::vector<Type*>::const_iterator p = types.begin();
+          p + 1 != types.end();
+          ++p)
+       clauses->add(*p, true, false, NULL, location);
+      clauses->add(types.back(), false, false, statements, location);
+    }
+}
+
+// TypeSwitchCase  = "case" type | "default"
+
+// We accept a comma separated list of types.
+
+void
+Parse::type_switch_case(std::vector<Type*>* types, bool* is_default)
+{
+  const Token* token = this->peek_token();
+  if (token->is_keyword(KEYWORD_CASE))
+    {
+      this->advance_token();
+      while (true)
+       {
+         Type* t = this->type();
+         if (!t->is_error_type())
+           types->push_back(t);
+         if (!this->peek_token()->is_op(OPERATOR_COMMA))
+           break;
+         this->advance_token();
+       }
+    }
+  else if (token->is_keyword(KEYWORD_DEFAULT))
+    {
+      this->advance_token();
+      *is_default = true;
+    }
+  else
+    {
+      error_at(this->location(), "expected %<case%> or %<default%>");
+      if (!token->is_op(OPERATOR_RCURLY))
+       this->advance_token();
+    }
+}
+
+// SelectStat = "select" "{" { CommClause } "}" .
+
+void
+Parse::select_stat(const Label* label)
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_SELECT));
+  source_location location = this->location();
+  const Token* token = this->advance_token();
+
+  if (!token->is_op(OPERATOR_LCURLY))
+    {
+      source_location token_loc = token->location();
+      if (token->is_op(OPERATOR_SEMICOLON)
+         && this->advance_token()->is_op(OPERATOR_LCURLY))
+       error_at(token_loc, "unexpected semicolon or newline before %<{%>");
+      else
+       {
+         error_at(this->location(), "expected %<{%>");
+         return;
+       }
+    }
+  this->advance_token();
+
+  Select_statement* statement = Statement::make_select_statement(location);
+
+  this->push_break_statement(statement, label);
+
+  Select_clauses* select_clauses = new Select_clauses();
+  while (!this->peek_token()->is_op(OPERATOR_RCURLY))
+    {
+      if (this->peek_token()->is_eof())
+       {
+         error_at(this->location(), "expected %<}%>");
+         return;
+       }
+      this->comm_clause(select_clauses);
+    }
+
+  this->advance_token();
+
+  statement->add_clauses(select_clauses);
+
+  this->pop_break_statement();
+
+  this->gogo_->add_statement(statement);
+}
+
+// CommClause = CommCase [ StatementList ] .
+
+void
+Parse::comm_clause(Select_clauses* clauses)
+{
+  source_location location = this->location();
+  bool is_send = false;
+  Expression* channel = NULL;
+  Expression* val = NULL;
+  std::string varname;
+  bool is_default = false;
+  bool got_case = this->comm_case(&is_send, &channel, &val, &varname,
+                                 &is_default);
+
+  Block* statements = NULL;
+  Named_object* var = NULL;
+  if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+    this->advance_token();
+  else if (this->statement_list_may_start_here())
+    {
+      this->gogo_->start_block(this->location());
+
+      if (!varname.empty())
+       {
+         // FIXME: LOCATION is slightly wrong here.
+         Variable* v = new Variable(NULL, channel, false, false, false,
+                                    location);
+         v->set_type_from_chan_element();
+         var = this->gogo_->add_variable(varname, v);
+       }
+
+      this->statement_list();
+      statements = this->gogo_->finish_block(this->location());
+    }
+
+  if (got_case)
+    clauses->add(is_send, channel, val, var, is_default, statements, location);
+}
+
+// CommCase = ( "default" | ( "case" ( SendExpr | RecvExpr) ) ) ":" .
+
+bool
+Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
+                std::string* varname, bool* is_default)
+{
+  const Token* token = this->peek_token();
+  if (token->is_keyword(KEYWORD_DEFAULT))
+    {
+      this->advance_token();
+      *is_default = true;
+    }
+  else if (token->is_keyword(KEYWORD_CASE))
+    {
+      this->advance_token();
+      if (!this->send_or_recv_expr(is_send, channel, val, varname))
+       return false;
+    }
+  else
+    {
+      error_at(this->location(), "expected %<case%> or %<default%>");
+      if (!token->is_op(OPERATOR_RCURLY))
+       this->advance_token();
+      return false;
+    }
+
+  if (!this->peek_token()->is_op(OPERATOR_COLON))
+    {
+      error_at(this->location(), "expected colon");
+      return false;
+    }
+
+  this->advance_token();
+
+  return true;
+}
+
+// SendExpr = Expression "<-" Expression .
+// RecvExpr =  [ Expression ( "=" | ":=" ) ] "<-" Expression .
+
+bool
+Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val,
+                        std::string* varname)
+{
+  const Token* token = this->peek_token();
+  source_location location = token->location();
+  if (token->is_identifier())
+    {
+      std::string recv_var = token->identifier();
+      bool is_var_exported = token->is_identifier_exported();
+      if (!this->advance_token()->is_op(OPERATOR_COLONEQ))
+       this->unget_token(Token::make_identifier_token(recv_var,
+                                                      is_var_exported,
+                                                      location));
+      else
+       {
+         if (!this->advance_token()->is_op(OPERATOR_CHANOP))
+           {
+             error_at(this->location(), "expected %<<-%>");
+             return false;
+           }
+         *is_send = false;
+         *varname = this->gogo_->pack_hidden_name(recv_var, is_var_exported);
+         this->advance_token();
+         *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+         return true;
+       }
+    }
+
+  if (this->peek_token()->is_op(OPERATOR_CHANOP))
+    {
+      *is_send = false;
+      this->advance_token();
+      *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+    }
+  else
+    {
+      Expression* left = this->expression(PRECEDENCE_CHANOP, true, true, NULL);
+
+      if (this->peek_token()->is_op(OPERATOR_EQ))
+       {
+         if (!this->advance_token()->is_op(OPERATOR_CHANOP))
+           {
+             error_at(this->location(), "missing %<<-%>");
+             return false;
+           }
+         *is_send = false;
+         *val = left;
+         this->advance_token();
+         *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+       }
+      else if (this->peek_token()->is_op(OPERATOR_CHANOP))
+       {
+         *is_send = true;
+         *channel = this->verify_not_sink(left);
+         this->advance_token();
+         *val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+       }
+      else
+       {
+         error_at(this->location(), "expected %<<-%> or %<=%>");
+         return false;
+       }
+    }
+
+  return true;
+}
+
+// ForStat = "for" [ Condition | ForClause | RangeClause ] Block .
+// Condition = Expression .
+
+void
+Parse::for_stat(const Label* label)
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_FOR));
+  source_location location = this->location();
+  const Token* token = this->advance_token();
+
+  // Open a block to hold any variables defined in the init statement
+  // of the for statement.
+  this->gogo_->start_block(location);
+
+  Block* init = NULL;
+  Expression* cond = NULL;
+  Block* post = NULL;
+  Range_clause range_clause;
+
+  if (!token->is_op(OPERATOR_LCURLY))
+    {
+      if (token->is_keyword(KEYWORD_VAR))
+       {
+         error_at(this->location(),
+                  "var declaration not allowed in for initializer");
+         this->var_decl();
+       }
+
+      if (token->is_op(OPERATOR_SEMICOLON))
+       this->for_clause(&cond, &post);
+      else
+       {
+         // We might be looking at a Condition, an InitStat, or a
+         // RangeClause.
+         cond = this->simple_stat(false, true, &range_clause, NULL);
+         if (!this->peek_token()->is_op(OPERATOR_SEMICOLON))
+           {
+             if (cond == NULL && !range_clause.found)
+               error_at(this->location(), "parse error in for statement");
+           }
+         else
+           {
+             if (range_clause.found)
+               error_at(this->location(), "parse error after range clause");
+
+             if (cond != NULL)
+               {
+                 // COND is actually an expression statement for
+                 // InitStat at the start of a ForClause.
+                 this->expression_stat(cond);
+                 cond = NULL;
+               }
+
+             this->for_clause(&cond, &post);
+           }
+       }
+    }
+
+  // Build the For_statement and note that it is the current target
+  // for break and continue statements.
+
+  For_statement* sfor;
+  For_range_statement* srange;
+  Statement* s;
+  if (!range_clause.found)
+    {
+      sfor = Statement::make_for_statement(init, cond, post, location);
+      s = sfor;
+      srange = NULL;
+    }
+  else
+    {
+      srange = Statement::make_for_range_statement(range_clause.index,
+                                                  range_clause.value,
+                                                  range_clause.range,
+                                                  location);
+      s = srange;
+      sfor = NULL;
+    }
+
+  this->push_break_statement(s, label);
+  this->push_continue_statement(s, label);
+
+  // Gather the block of statements in the loop and add them to the
+  // For_statement.
+
+  this->gogo_->start_block(this->location());
+  source_location end_loc = this->block();
+  Block* statements = this->gogo_->finish_block(end_loc);
+
+  if (sfor != NULL)
+    sfor->add_statements(statements);
+  else
+    srange->add_statements(statements);
+
+  // This is no longer the break/continue target.
+  this->pop_break_statement();
+  this->pop_continue_statement();
+
+  // Add the For_statement to the list of statements, and close out
+  // the block we started to hold any variables defined in the for
+  // statement.
+
+  this->gogo_->add_statement(s);
+
+  this->gogo_->add_block(this->gogo_->finish_block(this->location()),
+                        location);
+}
+
+// ForClause = [ InitStat ] ";" [ Condition ] ";" [ PostStat ] .
+// InitStat = SimpleStat .
+// PostStat = SimpleStat .
+
+// We have already read InitStat at this point.
+
+void
+Parse::for_clause(Expression** cond, Block** post)
+{
+  gcc_assert(this->peek_token()->is_op(OPERATOR_SEMICOLON));
+  this->advance_token();
+  if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+    *cond = NULL;
+  else if (this->peek_token()->is_op(OPERATOR_LCURLY))
+    {
+      error_at(this->location(),
+              "unexpected semicolon or newline before %<{%>");
+      *cond = NULL;
+      *post = NULL;
+      return;
+    }
+  else
+    *cond = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+  if (!this->peek_token()->is_op(OPERATOR_SEMICOLON))
+    error_at(this->location(), "expected semicolon");
+  else
+    this->advance_token();
+
+  if (this->peek_token()->is_op(OPERATOR_LCURLY))
+    *post = NULL;
+  else
+    {
+      this->gogo_->start_block(this->location());
+      this->simple_stat(false, false, NULL, NULL);
+      *post = this->gogo_->finish_block(this->location());
+    }
+}
+
+// RangeClause = IdentifierList ( "=" | ":=" ) "range" Expression .
+
+// This is the := version.  It is called with a list of identifiers.
+
+void
+Parse::range_clause_decl(const Typed_identifier_list* til,
+                        Range_clause* p_range_clause)
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_RANGE));
+  source_location location = this->location();
+
+  p_range_clause->found = true;
+
+  gcc_assert(til->size() >= 1);
+  if (til->size() > 2)
+    error_at(this->location(), "too many variables for range clause");
+
+  this->advance_token();
+  Expression* expr = this->expression(PRECEDENCE_NORMAL, false, false, NULL);
+  p_range_clause->range = expr;
+
+  bool any_new = false;
+
+  const Typed_identifier* pti = &til->front();
+  Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new);
+  if (any_new && no->is_variable())
+    no->var_value()->set_type_from_range_index();
+  p_range_clause->index = Expression::make_var_reference(no, location);
+
+  if (til->size() == 1)
+    p_range_clause->value = NULL;
+  else
+    {
+      pti = &til->back();
+      bool is_new = false;
+      no = this->init_var(*pti, NULL, expr, true, true, &is_new);
+      if (is_new && no->is_variable())
+       no->var_value()->set_type_from_range_value();
+      if (is_new)
+       any_new = true;
+      p_range_clause->value = Expression::make_var_reference(no, location);
+    }
+
+  if (!any_new)
+    error_at(location, "variables redeclared but no variable is new");
+}
+
+// The = version of RangeClause.  This is called with a list of
+// expressions.
+
+void
+Parse::range_clause_expr(const Expression_list* vals,
+                        Range_clause* p_range_clause)
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_RANGE));
+
+  p_range_clause->found = true;
+
+  gcc_assert(vals->size() >= 1);
+  if (vals->size() > 2)
+    error_at(this->location(), "too many variables for range clause");
+
+  this->advance_token();
+  p_range_clause->range = this->expression(PRECEDENCE_NORMAL, false, false,
+                                          NULL);
+
+  p_range_clause->index = vals->front();
+  if (vals->size() == 1)
+    p_range_clause->value = NULL;
+  else
+    p_range_clause->value = vals->back();
+}
+
+// Push a statement on the break stack.
+
+void
+Parse::push_break_statement(Statement* enclosing, const Label* label)
+{
+  this->break_stack_.push_back(std::make_pair(enclosing, label));
+}
+
+// Push a statement on the continue stack.
+
+void
+Parse::push_continue_statement(Statement* enclosing, const Label* label)
+{
+  this->continue_stack_.push_back(std::make_pair(enclosing, label));
+}
+
+// Pop the break stack.
+
+void
+Parse::pop_break_statement()
+{
+  this->break_stack_.pop_back();
+}
+
+// Pop the continue stack.
+
+void
+Parse::pop_continue_statement()
+{
+  this->continue_stack_.pop_back();
+}
+
+// Find a break or continue statement given a label name.
+
+Statement*
+Parse::find_bc_statement(const Bc_stack* bc_stack, const std::string& label)
+{
+  for (Bc_stack::const_reverse_iterator p = bc_stack->rbegin();
+       p != bc_stack->rend();
+       ++p)
+    if (p->second != NULL && p->second->name() == label)
+      return p->first;
+  return NULL;
+}
+
+// BreakStat = "break" [ identifier ] .
+
+void
+Parse::break_stat()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_BREAK));
+  source_location location = this->location();
+
+  const Token* token = this->advance_token();
+  Statement* enclosing;
+  if (!token->is_identifier())
+    {
+      if (this->break_stack_.empty())
+       {
+         error_at(this->location(),
+                  "break statement not within for or switch or select");
+         return;
+       }
+      enclosing = this->break_stack_.back().first;
+    }
+  else
+    {
+      enclosing = this->find_bc_statement(&this->break_stack_,
+                                         token->identifier());
+      if (enclosing == NULL)
+       {
+         error_at(token->location(),
+                  ("break label %qs not associated with "
+                   "for or switch or select"),
+                  Gogo::message_name(token->identifier()).c_str());
+         this->advance_token();
+         return;
+       }
+      this->advance_token();
+    }
+
+  Unnamed_label* label;
+  if (enclosing->classification() == Statement::STATEMENT_FOR)
+    label = enclosing->for_statement()->break_label();
+  else if (enclosing->classification() == Statement::STATEMENT_FOR_RANGE)
+    label = enclosing->for_range_statement()->break_label();
+  else if (enclosing->classification() == Statement::STATEMENT_SWITCH)
+    label = enclosing->switch_statement()->break_label();
+  else if (enclosing->classification() == Statement::STATEMENT_TYPE_SWITCH)
+    label = enclosing->type_switch_statement()->break_label();
+  else if (enclosing->classification() == Statement::STATEMENT_SELECT)
+    label = enclosing->select_statement()->break_label();
+  else
+    gcc_unreachable();
+
+  this->gogo_->add_statement(Statement::make_break_statement(label,
+                                                            location));
+}
+
+// ContinueStat = "continue" [ identifier ] .
+
+void
+Parse::continue_stat()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_CONTINUE));
+  source_location location = this->location();
+
+  const Token* token = this->advance_token();
+  Statement* enclosing;
+  if (!token->is_identifier())
+    {
+      if (this->continue_stack_.empty())
+       {
+         error_at(this->location(), "continue statement not within for");
+         return;
+       }
+      enclosing = this->continue_stack_.back().first;
+    }
+  else
+    {
+      enclosing = this->find_bc_statement(&this->continue_stack_,
+                                         token->identifier());
+      if (enclosing == NULL)
+       {
+         error_at(token->location(),
+                  "continue label %qs not associated with for",
+                  Gogo::message_name(token->identifier()).c_str());
+         this->advance_token();
+         return;
+       }
+      this->advance_token();
+    }
+
+  Unnamed_label* label;
+  if (enclosing->classification() == Statement::STATEMENT_FOR)
+    label = enclosing->for_statement()->continue_label();
+  else if (enclosing->classification() == Statement::STATEMENT_FOR_RANGE)
+    label = enclosing->for_range_statement()->continue_label();
+  else
+    gcc_unreachable();
+
+  this->gogo_->add_statement(Statement::make_continue_statement(label,
+                                                               location));
+}
+
+// GotoStat = "goto" identifier .
+
+void
+Parse::goto_stat()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_GOTO));
+  source_location location = this->location();
+  const Token* token = this->advance_token();
+  if (!token->is_identifier())
+    error_at(this->location(), "expected label for goto");
+  else
+    {
+      Label* label = this->gogo_->add_label_reference(token->identifier());
+      Statement* s = Statement::make_goto_statement(label, location);
+      this->gogo_->add_statement(s);
+      this->advance_token();
+    }
+}
+
+// PackageClause = "package" PackageName .
+
+void
+Parse::package_clause()
+{
+  const Token* token = this->peek_token();
+  source_location location = token->location();
+  std::string name;
+  if (!token->is_keyword(KEYWORD_PACKAGE))
+    {
+      error_at(this->location(), "program must start with package clause");
+      name = "ERROR";
+    }
+  else
+    {
+      token = this->advance_token();
+      if (token->is_identifier())
+       {
+         name = token->identifier();
+         if (name == "_")
+           {
+             error_at(this->location(), "invalid package name _");
+             name = "blank";
+           }
+         this->advance_token();
+       }
+      else
+       {
+         error_at(this->location(), "package name must be an identifier");
+         name = "ERROR";
+       }
+    }
+  this->gogo_->set_package_name(name, location);
+}
+
+// ImportDecl = "import" Decl<ImportSpec> .
+
+void
+Parse::import_decl()
+{
+  gcc_assert(this->peek_token()->is_keyword(KEYWORD_IMPORT));
+  this->advance_token();
+  this->decl(&Parse::import_spec, NULL);
+}
+
+// ImportSpec = [ "." | PackageName ] PackageFileName .
+
+void
+Parse::import_spec(void*)
+{
+  const Token* token = this->peek_token();
+  source_location location = token->location();
+
+  std::string local_name;
+  bool is_local_name_exported = false;
+  if (token->is_op(OPERATOR_DOT))
+    {
+      local_name = ".";
+      token = this->advance_token();
+    }
+  else if (token->is_identifier())
+    {
+      local_name = token->identifier();
+      is_local_name_exported = token->is_identifier_exported();
+      token = this->advance_token();
+    }
+
+  if (!token->is_string())
+    {
+      error_at(this->location(), "missing import package name");
+      return;
+    }
+
+  this->gogo_->import_package(token->string_value(), local_name,
+                             is_local_name_exported, location);
+
+  this->advance_token();
+}
+
+// SourceFile       = PackageClause ";" { ImportDecl ";" }
+//                     { TopLevelDecl ";" } .
+
+void
+Parse::program()
+{
+  this->package_clause();
+
+  const Token* token = this->peek_token();
+  if (token->is_op(OPERATOR_SEMICOLON))
+    token = this->advance_token();
+  else
+    error_at(this->location(),
+            "expected %<;%> or newline after package clause");
+
+  while (token->is_keyword(KEYWORD_IMPORT))
+    {
+      this->import_decl();
+      token = this->peek_token();
+      if (token->is_op(OPERATOR_SEMICOLON))
+       token = this->advance_token();
+      else
+       error_at(this->location(),
+                "expected %<;%> or newline after import declaration");
+    }
+
+  while (!token->is_eof())
+    {
+      if (this->declaration_may_start_here())
+       this->declaration();
+      else
+       {
+         error_at(this->location(), "expected declaration");
+         do
+           this->advance_token();
+         while (!this->peek_token()->is_eof()
+                && !this->peek_token()->is_op(OPERATOR_SEMICOLON)
+                && !this->peek_token()->is_op(OPERATOR_RCURLY));
+         if (!this->peek_token()->is_eof()
+             && !this->peek_token()->is_op(OPERATOR_SEMICOLON))
+           this->advance_token();
+       }
+      token = this->peek_token();
+      if (token->is_op(OPERATOR_SEMICOLON))
+       token = this->advance_token();
+      else if (!token->is_eof() || !saw_errors())
+       {
+         error_at(this->location(),
+                  "expected %<;%> or newline after top level declaration");
+         this->skip_past_error(OPERATOR_INVALID);
+       }
+    }
+}
+
+// Reset the current iota value.
+
+void
+Parse::reset_iota()
+{
+  this->iota_ = 0;
+}
+
+// Return the current iota value.
+
+int
+Parse::iota_value()
+{
+  return this->iota_;
+}
+
+// Increment the current iota value.
+
+void
+Parse::increment_iota()
+{
+  ++this->iota_;
+}
+
+// Skip forward to a semicolon or OP.  OP will normally be
+// OPERATOR_RPAREN or OPERATOR_RCURLY.  If we find a semicolon, move
+// past it and return.  If we find OP, it will be the next token to
+// read.  Return true if we are OK, false if we found EOF.
+
+bool
+Parse::skip_past_error(Operator op)
+{
+  const Token* token = this->peek_token();
+  while (!token->is_op(op))
+    {
+      if (token->is_eof())
+       return false;
+      if (token->is_op(OPERATOR_SEMICOLON))
+       {
+         this->advance_token();
+         return true;
+       }
+      token = this->advance_token();
+    }
+  return true;
+}
+
+// Check that an expression is not a sink.
+
+Expression*
+Parse::verify_not_sink(Expression* expr)
+{
+  if (expr->is_sink_expression())
+    {
+      error_at(expr->location(), "cannot use _ as value");
+      expr = Expression::make_error(expr->location());
+    }
+  return expr;
+}
diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h
new file mode 100644 (file)
index 0000000..fc2eb12
--- /dev/null
@@ -0,0 +1,307 @@
+// parse.h -- Go frontend parser.     -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_PARSE_H
+#define GO_PARSE_H
+
+class Set_iota_traverse;
+class Lex;
+class Gogo;
+class Named_object;
+class Type;
+class Typed_identifier;
+class Typed_identifier_list;
+class Function_type;
+class Block;
+class Expression;
+class Expression_list;
+class Struct_field_list;
+class Case_clauses;
+class Type_case_clauses;
+class Select_clauses;
+class Statement;
+class Label;
+
+// Parse the program.
+
+class Parse
+{
+ public:
+  Parse(Lex*, Gogo*);
+
+  // Parse a program.
+  void
+  program();
+
+ private:
+  // Precedence values.
+  enum Precedence
+  {
+    PRECEDENCE_INVALID = -1,
+    PRECEDENCE_NORMAL = 0,
+    PRECEDENCE_OROR,
+    PRECEDENCE_ANDAND,
+    PRECEDENCE_CHANOP,
+    PRECEDENCE_RELOP,
+    PRECEDENCE_ADDOP,
+    PRECEDENCE_MULOP
+  };
+
+  // We use this when parsing the range clause of a for statement.
+  struct Range_clause
+  {
+    // Set to true if we found a range clause.
+    bool found;
+    // The index expression.
+    Expression* index;
+    // The value expression.
+    Expression* value;
+    // The range expression.
+    Expression* range;
+
+    Range_clause()
+      : found(false), index(NULL), value(NULL), range(NULL)
+    { }
+  };
+
+  // We use this when parsing the statement at the start of a switch,
+  // in order to recognize type switches.
+  struct Type_switch
+  {
+    // Set to true if we find a type switch.
+    bool found;
+    // The variable name.
+    std::string name;
+    // The location of the variable.
+    source_location location;
+    // The expression.
+    Expression* expr;
+
+    Type_switch()
+      : found(false), name(), location(UNKNOWN_LOCATION), expr(NULL)
+    { }
+  };
+
+  // A variable defined in an enclosing function referenced by the
+  // current function.
+  class Enclosing_var
+  {
+   public:
+    Enclosing_var(Named_object* var, Named_object* in_function,
+                 unsigned int index)
+      : var_(var), in_function_(in_function), index_(index)
+    { }
+
+    // We put these in a vector, so we need a default constructor.
+    Enclosing_var()
+      : var_(NULL), in_function_(NULL), index_(-1U)
+    { }
+
+    Named_object*
+    var() const
+    { return this->var_; }
+
+    Named_object*
+    in_function() const
+    { return this->in_function_; }
+
+    unsigned int
+    index() const
+    { return this->index_; }
+
+   private:
+    // The variable which is being referred to.
+    Named_object* var_;
+    // The function where the variable is defined.
+    Named_object* in_function_;
+    // The index of the field in this function's closure struct for
+    // this variable.
+    unsigned int index_;
+  };
+
+  // We store Enclosing_var entries in a set, so we need a comparator.
+  struct Enclosing_var_comparison
+  {
+    bool
+    operator()(const Enclosing_var&, const Enclosing_var&);
+  };
+
+  // A set of Enclosing_var entries.
+  typedef std::set<Enclosing_var, Enclosing_var_comparison> Enclosing_vars;
+
+  // Peek at the current token from the lexer.
+  const Token*
+  peek_token();
+
+  // Consume the current token, return the next one.
+  const Token*
+  advance_token();
+
+  // Push a token back on the input stream.
+  void
+  unget_token(const Token&);
+
+  // The location of the current token.
+  source_location
+  location();
+
+  // For break and continue we keep a stack of statements with
+  // associated labels (if any).  The top of the stack is used for a
+  // break or continue statement with no label.
+  typedef std::vector<std::pair<Statement*, const Label*> > Bc_stack;
+
+  // Parser nonterminals.
+  void identifier_list(Typed_identifier_list*);
+  Expression_list* expression_list(Expression*, bool may_be_sink);
+  bool qualified_ident(std::string*, Named_object**);
+  Type* type();
+  bool type_may_start_here();
+  Type* type_name(bool issue_error);
+  Type* array_type(bool may_use_ellipsis);
+  Type* map_type();
+  Type* struct_type();
+  void field_decl(Struct_field_list*);
+  Type* pointer_type();
+  Type* channel_type();
+  Function_type* signature(Typed_identifier*, source_location);
+  Typed_identifier_list* parameters(bool* is_varargs);
+  Typed_identifier_list* parameter_list(bool* is_varargs);
+  void parameter_decl(bool, Typed_identifier_list*, bool*, bool*);
+  Typed_identifier_list* result();
+  source_location block();
+  Type* interface_type();
+  bool method_spec(Typed_identifier_list*);
+  void declaration();
+  bool declaration_may_start_here();
+  void decl(void (Parse::*)(void*), void*);
+  void list(void (Parse::*)(void*), void*, bool);
+  void const_decl();
+  void const_spec(Type**, Expression_list**);
+  void type_decl();
+  void type_spec(void*);
+  void var_decl();
+  void var_spec(void*);
+  void init_vars(const Typed_identifier_list*, Type*, Expression_list*,
+                bool is_coloneq, source_location);
+  bool init_vars_from_call(const Typed_identifier_list*, Type*, Expression*,
+                          bool is_coloneq, source_location);
+  bool init_vars_from_map(const Typed_identifier_list*, Type*, Expression*,
+                         bool is_coloneq, source_location);
+  bool init_vars_from_receive(const Typed_identifier_list*, Type*,
+                             Expression*, bool is_coloneq, source_location);
+  bool init_vars_from_type_guard(const Typed_identifier_list*, Type*,
+                                Expression*, bool is_coloneq,
+                                source_location);
+  Named_object* init_var(const Typed_identifier&, Type*, Expression*,
+                        bool is_coloneq, bool type_from_init, bool* is_new);
+  void simple_var_decl_or_assignment(const std::string&, source_location,
+                                    Range_clause*, Type_switch*);
+  void function_decl();
+  Typed_identifier* receiver();
+  Expression* operand(bool may_be_sink);
+  Expression* enclosing_var_reference(Named_object*, Named_object*,
+                                     source_location);
+  Expression* composite_lit(Type*, int depth, source_location);
+  Expression* function_lit();
+  Expression* create_closure(Named_object* function, Enclosing_vars*,
+                            source_location);
+  Expression* primary_expr(bool may_be_sink, bool may_be_composite_lit,
+                          bool* is_type_switch);
+  Expression* selector(Expression*, bool* is_type_switch);
+  Expression* index(Expression*);
+  Expression* call(Expression*);
+  Expression* expression(Precedence, bool may_be_sink,
+                        bool may_be_composite_lit, bool* is_type_switch);
+  bool expression_may_start_here();
+  Expression* unary_expr(bool may_be_sink, bool may_be_composite_lit,
+                        bool* is_type_switch);
+  Expression* qualified_expr(Expression*, source_location);
+  Expression* id_to_expression(const std::string&, source_location);
+  void statement(const Label*);
+  bool statement_may_start_here();
+  void labeled_stmt(const std::string&, source_location);
+  Expression* simple_stat(bool, bool, Range_clause*, Type_switch*);
+  bool simple_stat_may_start_here();
+  void statement_list();
+  bool statement_list_may_start_here();
+  void expression_stat(Expression*);
+  void inc_dec_stat(Expression*);
+  void assignment(Expression*, Range_clause*);
+  void tuple_assignment(Expression_list*, Range_clause*);
+  void send();
+  void go_or_defer_stat();
+  void return_stat();
+  void if_stat();
+  void switch_stat(const Label*);
+  Statement* expr_switch_body(const Label*, Expression*, source_location);
+  void expr_case_clause(Case_clauses*);
+  Expression_list* expr_switch_case(bool*);
+  Statement* type_switch_body(const Label*, const Type_switch&,
+                             source_location);
+  void type_case_clause(Named_object*, Type_case_clauses*);
+  void type_switch_case(std::vector<Type*>*, bool*);
+  void select_stat(const Label*);
+  void comm_clause(Select_clauses*);
+  bool comm_case(bool*, Expression**, Expression**, std::string*, bool*);
+  bool send_or_recv_expr(bool*, Expression**, Expression**, std::string*);
+  void for_stat(const Label*);
+  void for_clause(Expression**, Block**);
+  void range_clause_decl(const Typed_identifier_list*, Range_clause*);
+  void range_clause_expr(const Expression_list*, Range_clause*);
+  void push_break_statement(Statement*, const Label*);
+  void push_continue_statement(Statement*, const Label*);
+  void pop_break_statement();
+  void pop_continue_statement();
+  Statement* find_bc_statement(const Bc_stack*, const std::string&);
+  void break_stat();
+  void continue_stat();
+  void goto_stat();
+  void package_clause();
+  void import_decl();
+  void import_spec(void*);
+
+  void reset_iota();
+  int iota_value();
+  void increment_iota();
+
+  // Skip past an error looking for a semicolon or OP.  Return true if
+  // all is well, false if we found EOF.
+  bool
+  skip_past_error(Operator op);
+
+  // Verify that an expression is not a sink, and return either the
+  // expression or an error.
+  Expression*
+  verify_not_sink(Expression*);
+
+  // Return the statement associated with a label in a Bc_stack, or
+  // NULL.
+  Statement*
+  find_bc_statement(const Bc_stack*, const std::string&) const;
+
+  // The lexer output we are parsing.
+  Lex* lex_;
+  // The current token.
+  Token token_;
+  // A token pushed back on the input stream.
+  Token unget_token_;
+  // Whether unget_token_ is valid.
+  bool unget_token_valid_;
+  // The code we are generating.
+  Gogo* gogo_;
+  // A stack of statements for which break may be used.
+  Bc_stack break_stack_;
+  // A stack of statements for which continue may be used.
+  Bc_stack continue_stack_;
+  // The current iota value.
+  int iota_;
+  // References from the local function to variables defined in
+  // enclosing functions.
+  Enclosing_vars enclosing_vars_;
+};
+
+
+#endif // !defined(GO_PARSE_H)
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
new file mode 100644 (file)
index 0000000..10fe7e4
--- /dev/null
@@ -0,0 +1,5146 @@
+// statements.cc -- Go frontend statements.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include <gmp.h>
+
+#ifndef ENABLE_BUILD_WITH_CXX
+extern "C"
+{
+#endif
+
+#include "intl.h"
+#include "tree.h"
+#include "gimple.h"
+#include "convert.h"
+#include "tree-iterator.h"
+#include "tree-flow.h"
+#include "real.h"
+
+#ifndef ENABLE_BUILD_WITH_CXX
+}
+#endif
+
+#include "go-c.h"
+#include "types.h"
+#include "expressions.h"
+#include "gogo.h"
+#include "statements.h"
+
+// Class Statement.
+
+Statement::Statement(Statement_classification classification,
+                    source_location location)
+  : classification_(classification), location_(location)
+{
+}
+
+Statement::~Statement()
+{
+}
+
+// Traverse the tree.  The work of walking the components is handled
+// by the subclasses.
+
+int
+Statement::traverse(Block* block, size_t* pindex, Traverse* traverse)
+{
+  if (this->classification_ == STATEMENT_ERROR)
+    return TRAVERSE_CONTINUE;
+
+  unsigned int traverse_mask = traverse->traverse_mask();
+
+  if ((traverse_mask & Traverse::traverse_statements) != 0)
+    {
+      int t = traverse->statement(block, pindex, this);
+      if (t == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+      else if (t == TRAVERSE_SKIP_COMPONENTS)
+       return TRAVERSE_CONTINUE;
+    }
+
+  // No point in checking traverse_mask here--a statement may contain
+  // other blocks or statements, and if we got here we always want to
+  // walk them.
+  return this->do_traverse(traverse);
+}
+
+// Traverse the contents of a statement.
+
+int
+Statement::traverse_contents(Traverse* traverse)
+{
+  return this->do_traverse(traverse);
+}
+
+// Traverse assignments.
+
+bool
+Statement::traverse_assignments(Traverse_assignments* tassign)
+{
+  if (this->classification_ == STATEMENT_ERROR)
+    return false;
+  return this->do_traverse_assignments(tassign);
+}
+
+// Traverse an expression in a statement.  This is a helper function
+// for child classes.
+
+int
+Statement::traverse_expression(Traverse* traverse, Expression** expr)
+{
+  if ((traverse->traverse_mask()
+       & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
+    return TRAVERSE_CONTINUE;
+  return Expression::traverse(expr, traverse);
+}
+
+// Traverse an expression list in a statement.  This is a helper
+// function for child classes.
+
+int
+Statement::traverse_expression_list(Traverse* traverse,
+                                   Expression_list* expr_list)
+{
+  if (expr_list == NULL)
+    return TRAVERSE_CONTINUE;
+  if ((traverse->traverse_mask() & Traverse::traverse_expressions) == 0)
+    return TRAVERSE_CONTINUE;
+  return expr_list->traverse(traverse);
+}
+
+// Traverse a type in a statement.  This is a helper function for
+// child classes.
+
+int
+Statement::traverse_type(Traverse* traverse, Type* type)
+{
+  if ((traverse->traverse_mask()
+       & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
+    return TRAVERSE_CONTINUE;
+  return Type::traverse(type, traverse);
+}
+
+// Set type information for unnamed constants.  This is really done by
+// the child class.
+
+void
+Statement::determine_types()
+{
+  this->do_determine_types();
+}
+
+// If this is a thunk statement, return it.
+
+Thunk_statement*
+Statement::thunk_statement()
+{
+  Thunk_statement* ret = this->convert<Thunk_statement, STATEMENT_GO>();
+  if (ret == NULL)
+    ret = this->convert<Thunk_statement, STATEMENT_DEFER>();
+  return ret;
+}
+
+// Get a tree for a Statement.  This is really done by the child
+// class.
+
+tree
+Statement::get_tree(Translate_context* context)
+{
+  if (this->classification_ == STATEMENT_ERROR)
+    return error_mark_node;
+
+  return this->do_get_tree(context);
+}
+
+// Build tree nodes and set locations.
+
+tree
+Statement::build_stmt_1(int tree_code_value, tree node)
+{
+  tree ret = build1(static_cast<tree_code>(tree_code_value),
+                   void_type_node, node);
+  SET_EXPR_LOCATION(ret, this->location_);
+  return ret;
+}
+
+// Note that this statement is erroneous.  This is called by children
+// when they discover an error.
+
+void
+Statement::set_is_error()
+{
+  this->classification_ = STATEMENT_ERROR;
+}
+
+// For children to call to report an error conveniently.
+
+void
+Statement::report_error(const char* msg)
+{
+  error_at(this->location_, "%s", msg);
+  this->set_is_error();
+}
+
+// An error statement, used to avoid crashing after we report an
+// error.
+
+class Error_statement : public Statement
+{
+ public:
+  Error_statement(source_location location)
+    : Statement(STATEMENT_ERROR, location)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*)
+  { return TRAVERSE_CONTINUE; }
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+};
+
+// Make an error statement.
+
+Statement*
+Statement::make_error_statement(source_location location)
+{
+  return new Error_statement(location);
+}
+
+// Class Variable_declaration_statement.
+
+Variable_declaration_statement::Variable_declaration_statement(
+    Named_object* var)
+  : Statement(STATEMENT_VARIABLE_DECLARATION, var->var_value()->location()),
+    var_(var)
+{
+}
+
+// We don't actually traverse the variable here; it was traversed
+// while traversing the Block.
+
+int
+Variable_declaration_statement::do_traverse(Traverse*)
+{
+  return TRAVERSE_CONTINUE;
+}
+
+// Traverse the assignments in a variable declaration.  Note that this
+// traversal is different from the usual traversal.
+
+bool
+Variable_declaration_statement::do_traverse_assignments(
+    Traverse_assignments* tassign)
+{
+  tassign->initialize_variable(this->var_);
+  return true;
+}
+
+// Return the tree for a variable declaration.
+
+tree
+Variable_declaration_statement::do_get_tree(Translate_context* context)
+{
+  tree val = this->var_->get_tree(context->gogo(), context->function());
+  if (val == error_mark_node || TREE_TYPE(val) == error_mark_node)
+    return error_mark_node;
+  Variable* variable = this->var_->var_value();
+
+  tree init = variable->get_init_tree(context->gogo(), context->function());
+  if (init == error_mark_node)
+    return error_mark_node;
+
+  // If this variable lives on the heap, we need to allocate it now.
+  if (!variable->is_in_heap())
+    {
+      DECL_INITIAL(val) = init;
+      return this->build_stmt_1(DECL_EXPR, val);
+    }
+  else
+    {
+      gcc_assert(TREE_CODE(val) == INDIRECT_REF);
+      tree decl = TREE_OPERAND(val, 0);
+      gcc_assert(TREE_CODE(decl) == VAR_DECL);
+      tree type = TREE_TYPE(decl);
+      gcc_assert(POINTER_TYPE_P(type));
+      tree size = TYPE_SIZE_UNIT(TREE_TYPE(type));
+      tree space = context->gogo()->allocate_memory(variable->type(), size,
+                                                   this->location());
+      space = fold_convert(TREE_TYPE(decl), space);
+      DECL_INITIAL(decl) = space;
+      return build2(COMPOUND_EXPR, void_type_node,
+                   this->build_stmt_1(DECL_EXPR, decl),
+                   build2(MODIFY_EXPR, void_type_node, val, init));
+    }
+}
+
+// Make a variable declaration.
+
+Statement*
+Statement::make_variable_declaration(Named_object* var)
+{
+  return new Variable_declaration_statement(var);
+}
+
+// Class Temporary_statement.
+
+// Return the type of the temporary variable.
+
+Type*
+Temporary_statement::type() const
+{
+  return this->type_ != NULL ? this->type_ : this->init_->type();
+}
+
+// Traversal.
+
+int
+Temporary_statement::do_traverse(Traverse* traverse)
+{
+  if (this->init_ == NULL)
+    return TRAVERSE_CONTINUE;
+  else
+    return this->traverse_expression(traverse, &this->init_);
+}
+
+// Traverse assignments.
+
+bool
+Temporary_statement::do_traverse_assignments(Traverse_assignments* tassign)
+{
+  if (this->init_ == NULL)
+    return false;
+  tassign->value(&this->init_, true, true);
+  return true;
+}
+
+// Determine types.
+
+void
+Temporary_statement::do_determine_types()
+{
+  if (this->init_ != NULL)
+    {
+      if (this->type_ == NULL)
+       this->init_->determine_type_no_context();
+      else
+       {
+         Type_context context(this->type_, false);
+         this->init_->determine_type(&context);
+       }
+    }
+
+  if (this->type_ == NULL)
+    this->type_ = this->init_->type();
+
+  if (this->type_->is_abstract())
+    this->type_ = this->type_->make_non_abstract_type();
+}
+
+// Check types.
+
+void
+Temporary_statement::do_check_types(Gogo*)
+{
+  if (this->type_ != NULL && this->init_ != NULL)
+    gcc_assert(Type::are_assignable(this->type_, this->init_->type(), NULL));
+}
+
+// Return a tree.
+
+tree
+Temporary_statement::do_get_tree(Translate_context* context)
+{
+  gcc_assert(this->decl_ == NULL_TREE);
+  tree type_tree = this->type()->get_tree(context->gogo());
+  if (type_tree == error_mark_node)
+    {
+      this->decl_ = error_mark_node;
+      return error_mark_node;
+    }
+  // We can only use create_tmp_var if the type is not addressable.
+  if (!TREE_ADDRESSABLE(type_tree))
+    {
+      this->decl_ = create_tmp_var(type_tree, "GOTMP");
+      DECL_SOURCE_LOCATION(this->decl_) = this->location();
+    }
+  else
+    {
+      gcc_assert(context->function() != NULL && context->block() != NULL);
+      tree decl = build_decl(this->location(), VAR_DECL,
+                            create_tmp_var_name("GOTMP"),
+                            type_tree);
+      DECL_ARTIFICIAL(decl) = 1;
+      DECL_IGNORED_P(decl) = 1;
+      TREE_USED(decl) = 1;
+      gcc_assert(current_function_decl != NULL_TREE);
+      DECL_CONTEXT(decl) = current_function_decl;
+
+      // We have to add this variable to the block so that it winds up
+      // in a BIND_EXPR.
+      tree block_tree = context->block_tree();
+      gcc_assert(block_tree != NULL_TREE);
+      DECL_CHAIN(decl) = BLOCK_VARS(block_tree);
+      BLOCK_VARS(block_tree) = decl;
+
+      this->decl_ = decl;
+    }
+  if (this->init_ != NULL)
+    DECL_INITIAL(this->decl_) =
+      Expression::convert_for_assignment(context, this->type(),
+                                        this->init_->type(),
+                                        this->init_->get_tree(context),
+                                        this->location());
+  if (this->is_address_taken_)
+    TREE_ADDRESSABLE(this->decl_) = 1;
+  return this->build_stmt_1(DECL_EXPR, this->decl_);
+}
+
+// Make and initialize a temporary variable in BLOCK.
+
+Temporary_statement*
+Statement::make_temporary(Type* type, Expression* init,
+                         source_location location)
+{
+  return new Temporary_statement(type, init, location);
+}
+
+// An assignment statement.
+
+class Assignment_statement : public Statement
+{
+ public:
+  Assignment_statement(Expression* lhs, Expression* rhs,
+                      source_location location)
+    : Statement(STATEMENT_ASSIGNMENT, location),
+      lhs_(lhs), rhs_(rhs)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*);
+
+  void
+  do_determine_types();
+
+  void
+  do_check_types(Gogo*);
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // Left hand side--the lvalue.
+  Expression* lhs_;
+  // Right hand side--the rvalue.
+  Expression* rhs_;
+};
+
+// Traversal.
+
+int
+Assignment_statement::do_traverse(Traverse* traverse)
+{
+  if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return this->traverse_expression(traverse, &this->rhs_);
+}
+
+bool
+Assignment_statement::do_traverse_assignments(Traverse_assignments* tassign)
+{
+  tassign->assignment(&this->lhs_, &this->rhs_);
+  return true;
+}
+
+// Set types for the assignment.
+
+void
+Assignment_statement::do_determine_types()
+{
+  this->lhs_->determine_type_no_context();
+  Type_context context(this->lhs_->type(), false);
+  this->rhs_->determine_type(&context);
+}
+
+// Check types for an assignment.
+
+void
+Assignment_statement::do_check_types(Gogo*)
+{
+  // The left hand side must be either addressable, a map index
+  // expression, or the blank identifier.
+  if (!this->lhs_->is_addressable()
+      && this->lhs_->map_index_expression() == NULL
+      && !this->lhs_->is_sink_expression())
+    {
+      if (!this->lhs_->type()->is_error_type())
+       this->report_error(_("invalid left hand side of assignment"));
+      return;
+    }
+
+  Type* lhs_type = this->lhs_->type();
+  Type* rhs_type = this->rhs_->type();
+  std::string reason;
+  if (!Type::are_assignable(lhs_type, rhs_type, &reason))
+    {
+      if (reason.empty())
+       error_at(this->location(), "incompatible types in assignment");
+      else
+       error_at(this->location(), "incompatible types in assignment (%s)",
+                reason.c_str());
+      this->set_is_error();
+    }
+
+  if (lhs_type->is_error_type()
+      || rhs_type->is_error_type()
+      || lhs_type->is_undefined()
+      || rhs_type->is_undefined())
+    {
+      // Make sure we get the error for an undefined type.
+      lhs_type->base();
+      rhs_type->base();
+      this->set_is_error();
+    }
+}
+
+// Build a tree for an assignment statement.
+
+tree
+Assignment_statement::do_get_tree(Translate_context* context)
+{
+  tree rhs_tree = this->rhs_->get_tree(context);
+
+  if (this->lhs_->is_sink_expression())
+    return rhs_tree;
+
+  tree lhs_tree = this->lhs_->get_tree(context);
+
+  if (lhs_tree == error_mark_node || rhs_tree == error_mark_node)
+    return error_mark_node;
+
+  rhs_tree = Expression::convert_for_assignment(context, this->lhs_->type(),
+                                               this->rhs_->type(), rhs_tree,
+                                               this->location());
+  if (rhs_tree == error_mark_node)
+    return error_mark_node;
+
+  return fold_build2_loc(this->location(), MODIFY_EXPR, void_type_node,
+                        lhs_tree, rhs_tree);
+}
+
+// Make an assignment statement.
+
+Statement*
+Statement::make_assignment(Expression* lhs, Expression* rhs,
+                          source_location location)
+{
+  return new Assignment_statement(lhs, rhs, location);
+}
+
+// The Move_ordered_evals class is used to find any subexpressions of
+// an expression that have an evaluation order dependency.  It creates
+// temporary variables to hold them.
+
+class Move_ordered_evals : public Traverse
+{
+ public:
+  Move_ordered_evals(Block* block)
+    : Traverse(traverse_expressions),
+      block_(block)
+  { }
+
+ protected:
+  int
+  expression(Expression**);
+
+ private:
+  // The block where new temporary variables should be added.
+  Block* block_;
+};
+
+int
+Move_ordered_evals::expression(Expression** pexpr)
+{
+  // We have to look at subexpressions first.
+  if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if ((*pexpr)->must_eval_in_order())
+    {
+      source_location loc = (*pexpr)->location();
+      Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
+      this->block_->add_statement(temp);
+      *pexpr = Expression::make_temporary_reference(temp, loc);
+    }
+  return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// An assignment operation statement.
+
+class Assignment_operation_statement : public Statement
+{
+ public:
+  Assignment_operation_statement(Operator op, Expression* lhs, Expression* rhs,
+                                source_location location)
+    : Statement(STATEMENT_ASSIGNMENT_OPERATION, location),
+      op_(op), lhs_(lhs), rhs_(rhs)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // The operator (OPERATOR_PLUSEQ, etc.).
+  Operator op_;
+  // Left hand side.
+  Expression* lhs_;
+  // Right hand side.
+  Expression* rhs_;
+};
+
+// Traversal.
+
+int
+Assignment_operation_statement::do_traverse(Traverse* traverse)
+{
+  if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return this->traverse_expression(traverse, &this->rhs_);
+}
+
+// Lower an assignment operation statement to a regular assignment
+// statement.
+
+Statement*
+Assignment_operation_statement::do_lower(Gogo*, Block* enclosing)
+{
+  source_location loc = this->location();
+
+  // We have to evaluate the left hand side expression only once.  We
+  // do this by moving out any expression with side effects.
+  Block* b = new Block(enclosing, loc);
+  Move_ordered_evals moe(b);
+  this->lhs_->traverse_subexpressions(&moe);
+
+  Expression* lval = this->lhs_->copy();
+
+  Operator op;
+  switch (this->op_)
+    {
+    case OPERATOR_PLUSEQ:
+      op = OPERATOR_PLUS;
+      break;
+    case OPERATOR_MINUSEQ:
+      op = OPERATOR_MINUS;
+      break;
+    case OPERATOR_OREQ:
+      op = OPERATOR_OR;
+      break;
+    case OPERATOR_XOREQ:
+      op = OPERATOR_XOR;
+      break;
+    case OPERATOR_MULTEQ:
+      op = OPERATOR_MULT;
+      break;
+    case OPERATOR_DIVEQ:
+      op = OPERATOR_DIV;
+      break;
+    case OPERATOR_MODEQ:
+      op = OPERATOR_MOD;
+      break;
+    case OPERATOR_LSHIFTEQ:
+      op = OPERATOR_LSHIFT;
+      break;
+    case OPERATOR_RSHIFTEQ:
+      op = OPERATOR_RSHIFT;
+      break;
+    case OPERATOR_ANDEQ:
+      op = OPERATOR_AND;
+      break;
+    case OPERATOR_BITCLEAREQ:
+      op = OPERATOR_BITCLEAR;
+      break;
+    default:
+      gcc_unreachable();
+    }
+
+  Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc);
+  Statement* s = Statement::make_assignment(this->lhs_, binop, loc);
+  if (b->statements()->empty())
+    {
+      delete b;
+      return s;
+    }
+  else
+    {
+      b->add_statement(s);
+      return Statement::make_block_statement(b, loc);
+    }
+}
+
+// Make an assignment operation statement.
+
+Statement*
+Statement::make_assignment_operation(Operator op, Expression* lhs,
+                                    Expression* rhs, source_location location)
+{
+  return new Assignment_operation_statement(op, lhs, rhs, location);
+}
+
+// A tuple assignment statement.  This differs from an assignment
+// statement in that the right-hand-side expressions are evaluated in
+// parallel.
+
+class Tuple_assignment_statement : public Statement
+{
+ public:
+  Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
+                            source_location location)
+    : Statement(STATEMENT_TUPLE_ASSIGNMENT, location),
+      lhs_(lhs), rhs_(rhs)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // Left hand side--a list of lvalues.
+  Expression_list* lhs_;
+  // Right hand side--a list of rvalues.
+  Expression_list* rhs_;
+};
+
+// Traversal.
+
+int
+Tuple_assignment_statement::do_traverse(Traverse* traverse)
+{
+  if (this->traverse_expression_list(traverse, this->lhs_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return this->traverse_expression_list(traverse, this->rhs_);
+}
+
+// Lower a tuple assignment.  We use temporary variables to split it
+// up into a set of single assignments.
+
+Statement*
+Tuple_assignment_statement::do_lower(Gogo*, Block* enclosing)
+{
+  source_location loc = this->location();
+
+  Block* b = new Block(enclosing, loc);
+  
+  // First move out any subexpressions on the left hand side.  The
+  // right hand side will be evaluated in the required order anyhow.
+  Move_ordered_evals moe(b);
+  for (Expression_list::const_iterator plhs = this->lhs_->begin();
+       plhs != this->lhs_->end();
+       ++plhs)
+    (*plhs)->traverse_subexpressions(&moe);
+
+  std::vector<Temporary_statement*> temps;
+  temps.reserve(this->lhs_->size());
+
+  Expression_list::const_iterator prhs = this->rhs_->begin();
+  for (Expression_list::const_iterator plhs = this->lhs_->begin();
+       plhs != this->lhs_->end();
+       ++plhs, ++prhs)
+    {
+      gcc_assert(prhs != this->rhs_->end());
+
+      if ((*plhs)->is_sink_expression())
+       {
+         b->add_statement(Statement::make_statement(*prhs));
+         continue;
+       }
+
+      Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
+                                                           *prhs, loc);
+      b->add_statement(temp);
+      temps.push_back(temp);
+
+    }
+  gcc_assert(prhs == this->rhs_->end());
+
+  prhs = this->rhs_->begin();
+  std::vector<Temporary_statement*>::const_iterator ptemp = temps.begin();
+  for (Expression_list::const_iterator plhs = this->lhs_->begin();
+       plhs != this->lhs_->end();
+       ++plhs, ++prhs)
+    {
+      if ((*plhs)->is_sink_expression())
+       continue;
+
+      Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
+      Statement* s = Statement::make_assignment(*plhs, ref, loc);
+      b->add_statement(s);
+      ++ptemp;
+    }
+  gcc_assert(ptemp == temps.end());
+
+  return Statement::make_block_statement(b, loc);
+}
+
+// Make a tuple assignment statement.
+
+Statement*
+Statement::make_tuple_assignment(Expression_list* lhs, Expression_list* rhs,
+                                source_location location)
+{
+  return new Tuple_assignment_statement(lhs, rhs, location);
+}
+
+// A tuple assignment from a map index expression.
+//   v, ok = m[k]
+
+class Tuple_map_assignment_statement : public Statement
+{
+public:
+  Tuple_map_assignment_statement(Expression* val, Expression* present,
+                                Expression* map_index,
+                                source_location location)
+    : Statement(STATEMENT_TUPLE_MAP_ASSIGNMENT, location),
+      val_(val), present_(present), map_index_(map_index)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // Lvalue which receives the value from the map.
+  Expression* val_;
+  // Lvalue which receives whether the key value was present.
+  Expression* present_;
+  // The map index expression.
+  Expression* map_index_;
+};
+
+// Traversal.
+
+int
+Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
+{
+  if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
+      || this->traverse_expression(traverse, &this->present_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return this->traverse_expression(traverse, &this->map_index_);
+}
+
+// Lower a tuple map assignment.
+
+Statement*
+Tuple_map_assignment_statement::do_lower(Gogo*, Block* enclosing)
+{
+  source_location loc = this->location();
+
+  Map_index_expression* map_index = this->map_index_->map_index_expression();
+  if (map_index == NULL)
+    {
+      this->report_error(_("expected map index on right hand side"));
+      return Statement::make_error_statement(loc);
+    }
+  Map_type* map_type = map_index->get_map_type();
+
+  Block* b = new Block(enclosing, loc);
+
+  // Move out any subexpressions to make sure that functions are
+  // called in the required order.
+  Move_ordered_evals moe(b);
+  this->val_->traverse_subexpressions(&moe);
+  this->present_->traverse_subexpressions(&moe);
+
+  // Copy the key value into a temporary so that we can take its
+  // address without pushing the value onto the heap.
+
+  // var key_temp KEY_TYPE = MAP_INDEX
+  Temporary_statement* key_temp =
+    Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
+  b->add_statement(key_temp);
+
+  // var val_temp VAL_TYPE
+  Temporary_statement* val_temp =
+    Statement::make_temporary(map_type->val_type(), NULL, loc);
+  b->add_statement(val_temp);
+
+  // var present_temp bool
+  Temporary_statement* present_temp =
+    Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
+  b->add_statement(present_temp);
+
+  // func mapaccess2(hmap map[k]v, key *k, val *v) bool
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("hmap", map_type, bloc));
+  Type* pkey_type = Type::make_pointer_type(map_type->key_type());
+  param_types->push_back(Typed_identifier("key", pkey_type, bloc));
+  Type* pval_type = Type::make_pointer_type(map_type->val_type());
+  param_types->push_back(Typed_identifier("val", pval_type, bloc));
+
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("", Type::make_boolean_type(), bloc));
+
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                  ret_types, bloc);
+  Named_object* mapaccess2 =
+    Named_object::make_function_declaration("mapaccess2", NULL, fntype, bloc);
+  mapaccess2->func_declaration_value()->set_asm_name("runtime.mapaccess2");
+
+  // present_temp = mapaccess2(MAP, &key_temp, &val_temp)
+  Expression* func = Expression::make_func_reference(mapaccess2, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(map_index->map());
+  Expression* ref = Expression::make_temporary_reference(key_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  ref = Expression::make_temporary_reference(val_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  Expression* call = Expression::make_call(func, params, false, loc);
+
+  ref = Expression::make_temporary_reference(present_temp, loc);
+  Statement* s = Statement::make_assignment(ref, call, loc);
+  b->add_statement(s);
+
+  // val = val_temp
+  ref = Expression::make_temporary_reference(val_temp, loc);
+  s = Statement::make_assignment(this->val_, ref, loc);
+  b->add_statement(s);
+
+  // present = present_temp
+  ref = Expression::make_temporary_reference(present_temp, loc);
+  s = Statement::make_assignment(this->present_, ref, loc);
+  b->add_statement(s);
+
+  return Statement::make_block_statement(b, loc);
+}
+
+// Make a map assignment statement which returns a pair of values.
+
+Statement*
+Statement::make_tuple_map_assignment(Expression* val, Expression* present,
+                                    Expression* map_index,
+                                    source_location location)
+{
+  return new Tuple_map_assignment_statement(val, present, map_index, location);
+}
+
+// Assign a pair of entries to a map.
+//   m[k] = v, p
+
+class Map_assignment_statement : public Statement
+{
+ public:
+  Map_assignment_statement(Expression* map_index,
+                          Expression* val, Expression* should_set,
+                          source_location location)
+    : Statement(STATEMENT_MAP_ASSIGNMENT, location),
+      map_index_(map_index), val_(val), should_set_(should_set)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // A reference to the map index which should be set or deleted.
+  Expression* map_index_;
+  // The value to add to the map.
+  Expression* val_;
+  // Whether or not to add the value.
+  Expression* should_set_;
+};
+
+// Traverse a map assignment.
+
+int
+Map_assignment_statement::do_traverse(Traverse* traverse)
+{
+  if (this->traverse_expression(traverse, &this->map_index_) == TRAVERSE_EXIT
+      || this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return this->traverse_expression(traverse, &this->should_set_);
+}
+
+// Lower a map assignment to a function call.
+
+Statement*
+Map_assignment_statement::do_lower(Gogo*, Block* enclosing)
+{
+  source_location loc = this->location();
+
+  Map_index_expression* map_index = this->map_index_->map_index_expression();
+  if (map_index == NULL)
+    {
+      this->report_error(_("expected map index on left hand side"));
+      return Statement::make_error_statement(loc);
+    }
+  Map_type* map_type = map_index->get_map_type();
+
+  Block* b = new Block(enclosing, loc);
+
+  // Evaluate the map first to get order of evaluation right.
+  // map_temp := m // we are evaluating m[k] = v, p
+  Temporary_statement* map_temp = Statement::make_temporary(map_type,
+                                                           map_index->map(),
+                                                           loc);
+  b->add_statement(map_temp);
+
+  // var key_temp MAP_KEY_TYPE = k
+  Temporary_statement* key_temp =
+    Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
+  b->add_statement(key_temp);
+
+  // var val_temp MAP_VAL_TYPE = v
+  Temporary_statement* val_temp =
+    Statement::make_temporary(map_type->val_type(), this->val_, loc);
+  b->add_statement(val_temp);
+
+  // func mapassign2(hmap map[k]v, key *k, val *v, p)
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("hmap", map_type, bloc));
+  Type* pkey_type = Type::make_pointer_type(map_type->key_type());
+  param_types->push_back(Typed_identifier("key", pkey_type, bloc));
+  Type* pval_type = Type::make_pointer_type(map_type->val_type());
+  param_types->push_back(Typed_identifier("val", pval_type, bloc));
+  param_types->push_back(Typed_identifier("p", Type::lookup_bool_type(), bloc));
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                  NULL, bloc);
+  Named_object* mapassign2 =
+    Named_object::make_function_declaration("mapassign2", NULL, fntype, bloc);
+  mapassign2->func_declaration_value()->set_asm_name("runtime.mapassign2");
+
+  // mapassign2(map_temp, &key_temp, &val_temp, p)
+  Expression* func = Expression::make_func_reference(mapassign2, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(Expression::make_temporary_reference(map_temp, loc));
+  Expression* ref = Expression::make_temporary_reference(key_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  ref = Expression::make_temporary_reference(val_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  params->push_back(this->should_set_);
+  Expression* call = Expression::make_call(func, params, false, loc);
+  Statement* s = Statement::make_statement(call);
+  b->add_statement(s);
+
+  return Statement::make_block_statement(b, loc);
+}
+
+// Make a statement which assigns a pair of entries to a map.
+
+Statement*
+Statement::make_map_assignment(Expression* map_index,
+                              Expression* val, Expression* should_set,
+                              source_location location)
+{
+  return new Map_assignment_statement(map_index, val, should_set, location);
+}
+
+// A tuple assignment from a receive statement.
+
+class Tuple_receive_assignment_statement : public Statement
+{
+ public:
+  Tuple_receive_assignment_statement(Expression* val, Expression* success,
+                                    Expression* channel,
+                                    source_location location)
+    : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
+      val_(val), success_(success), channel_(channel)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // Lvalue which receives the value from the channel.
+  Expression* val_;
+  // Lvalue which receives whether the read succeeded or failed.
+  Expression* success_;
+  // The channel on which we receive the value.
+  Expression* channel_;
+};
+
+// Traversal.
+
+int
+Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
+{
+  if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
+      || this->traverse_expression(traverse, &this->success_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return this->traverse_expression(traverse, &this->channel_);
+}
+
+// Lower to a function call.
+
+Statement*
+Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing)
+{
+  source_location loc = this->location();
+
+  Channel_type* channel_type = this->channel_->type()->channel_type();
+  if (channel_type == NULL)
+    {
+      this->report_error(_("expected channel"));
+      return Statement::make_error_statement(loc);
+    }
+  if (!channel_type->may_receive())
+    {
+      this->report_error(_("invalid receive on send-only channel"));
+      return Statement::make_error_statement(loc);
+    }
+
+  Block* b = new Block(enclosing, loc);
+
+  // Make sure that any subexpressions on the left hand side are
+  // evaluated in the right order.
+  Move_ordered_evals moe(b);
+  this->val_->traverse_subexpressions(&moe);
+  this->success_->traverse_subexpressions(&moe);
+
+  // var val_temp ELEMENT_TYPE
+  Temporary_statement* val_temp =
+    Statement::make_temporary(channel_type->element_type(), NULL, loc);
+  b->add_statement(val_temp);
+
+  // var success_temp bool
+  Temporary_statement* success_temp =
+    Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
+  b->add_statement(success_temp);
+
+  // func chanrecv2(c chan T, val *T) bool
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("c", channel_type, bloc));
+  Type* pelement_type = Type::make_pointer_type(channel_type->element_type());
+  param_types->push_back(Typed_identifier("val", pelement_type, bloc));
+
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc));
+
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                  ret_types, bloc);
+  Named_object* chanrecv2 =
+    Named_object::make_function_declaration("chanrecv2", NULL, fntype, bloc);
+  chanrecv2->func_declaration_value()->set_asm_name("runtime.chanrecv2");
+
+  // success_temp = chanrecv2(channel, &val_temp)
+  Expression* func = Expression::make_func_reference(chanrecv2, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(this->channel_);
+  Expression* ref = Expression::make_temporary_reference(val_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  Expression* call = Expression::make_call(func, params, false, loc);
+  ref = Expression::make_temporary_reference(success_temp, loc);
+  Statement* s = Statement::make_assignment(ref, call, loc);
+  b->add_statement(s);
+
+  // val = val_temp
+  ref = Expression::make_temporary_reference(val_temp, loc);
+  s = Statement::make_assignment(this->val_, ref, loc);
+  b->add_statement(s);
+
+  // success = success_temp
+  ref = Expression::make_temporary_reference(success_temp, loc);
+  s = Statement::make_assignment(this->success_, ref, loc);
+  b->add_statement(s);
+
+  return Statement::make_block_statement(b, loc);
+}
+
+// Make a nonblocking receive statement.
+
+Statement*
+Statement::make_tuple_receive_assignment(Expression* val, Expression* success,
+                                        Expression* channel,
+                                        source_location location)
+{
+  return new Tuple_receive_assignment_statement(val, success, channel,
+                                               location);
+}
+
+// An assignment to a pair of values from a type guard.  This is a
+// conditional type guard.  v, ok = i.(type).
+
+class Tuple_type_guard_assignment_statement : public Statement
+{
+ public:
+  Tuple_type_guard_assignment_statement(Expression* val, Expression* ok,
+                                       Expression* expr, Type* type,
+                                       source_location location)
+    : Statement(STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT, location),
+      val_(val), ok_(ok), expr_(expr), type_(type)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  Call_expression*
+  lower_to_empty_interface(const char*);
+
+  Call_expression*
+  lower_to_type(const char*);
+
+  void
+  lower_to_object_type(Block*, const char*);
+
+  // The variable which recieves the converted value.
+  Expression* val_;
+  // The variable which receives the indication of success.
+  Expression* ok_;
+  // The expression being converted.
+  Expression* expr_;
+  // The type to which the expression is being converted.
+  Type* type_;
+};
+
+// Traverse a type guard tuple assignment.
+
+int
+Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
+{
+  if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
+      || this->traverse_expression(traverse, &this->ok_) == TRAVERSE_EXIT
+      || this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return this->traverse_expression(traverse, &this->expr_);
+}
+
+// Lower to a function call.
+
+Statement*
+Tuple_type_guard_assignment_statement::do_lower(Gogo*, Block* enclosing)
+{
+  source_location loc = this->location();
+
+  Type* expr_type = this->expr_->type();
+  if (expr_type->interface_type() == NULL)
+    {
+      this->report_error(_("type assertion only valid for interface types"));
+      return Statement::make_error_statement(loc);
+    }
+
+  Block* b = new Block(enclosing, loc);
+
+  // Make sure that any subexpressions on the left hand side are
+  // evaluated in the right order.
+  Move_ordered_evals moe(b);
+  this->val_->traverse_subexpressions(&moe);
+  this->ok_->traverse_subexpressions(&moe);
+
+  bool expr_is_empty = expr_type->interface_type()->is_empty();
+  Call_expression* call;
+  if (this->type_->interface_type() != NULL)
+    {
+      if (this->type_->interface_type()->is_empty())
+       call = this->lower_to_empty_interface(expr_is_empty
+                                             ? "ifaceE2E2"
+                                             : "ifaceI2E2");
+      else
+       call = this->lower_to_type(expr_is_empty ? "ifaceE2I2" : "ifaceI2I2");
+    }
+  else if (this->type_->points_to() != NULL)
+    call = this->lower_to_type(expr_is_empty ? "ifaceE2T2P" : "ifaceI2T2P");
+  else
+    {
+      this->lower_to_object_type(b, expr_is_empty ? "ifaceE2T2" : "ifaceI2T2");
+      call = NULL;
+    }
+
+  if (call != NULL)
+    {
+      Expression* res = Expression::make_call_result(call, 0);
+      Statement* s = Statement::make_assignment(this->val_, res, loc);
+      b->add_statement(s);
+
+      res = Expression::make_call_result(call, 1);
+      s = Statement::make_assignment(this->ok_, res, loc);
+      b->add_statement(s);
+    }
+
+  return Statement::make_block_statement(b, loc);
+}
+
+// Lower a conversion to an empty interface type.
+
+Call_expression*
+Tuple_type_guard_assignment_statement::lower_to_empty_interface(
+    const char *fnname)
+{
+  source_location loc = this->location();
+
+  // func FNNAME(interface) (empty, bool)
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("ret", this->type_, bloc));
+  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                  ret_types, bloc);
+  Named_object* fn =
+    Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
+  std::string asm_name = "runtime.";
+  asm_name += fnname;
+  fn->func_declaration_value()->set_asm_name(asm_name);
+
+  // val, ok = FNNAME(expr)
+  Expression* func = Expression::make_func_reference(fn, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(this->expr_);
+  return Expression::make_call(func, params, false, loc);
+}
+
+// Lower a conversion to a non-empty interface type or a pointer type.
+
+Call_expression*
+Tuple_type_guard_assignment_statement::lower_to_type(const char* fnname)
+{
+  source_location loc = this->location();
+
+  // func FNNAME(*descriptor, interface) (interface, bool)
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("inter",
+                                         Type::make_type_descriptor_ptr_type(),
+                                         bloc));
+  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("ret", this->type_, bloc));
+  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                  ret_types, bloc);
+  Named_object* fn =
+    Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
+  std::string asm_name = "runtime.";
+  asm_name += fnname;
+  fn->func_declaration_value()->set_asm_name(asm_name);
+
+  // val, ok = FNNAME(type_descriptor, expr)
+  Expression* func = Expression::make_func_reference(fn, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(Expression::make_type_descriptor(this->type_, loc));
+  params->push_back(this->expr_);
+  return Expression::make_call(func, params, false, loc);
+}
+
+// Lower a conversion to a non-interface non-pointer type.
+
+void
+Tuple_type_guard_assignment_statement::lower_to_object_type(Block* b,
+                                                           const char *fnname)
+{
+  source_location loc = this->location();
+
+  // var val_temp TYPE
+  Temporary_statement* val_temp = Statement::make_temporary(this->type_,
+                                                           NULL, loc);
+  b->add_statement(val_temp);
+
+  // func FNNAME(*descriptor, interface, *T) bool
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("inter",
+                                         Type::make_type_descriptor_ptr_type(),
+                                         bloc));
+  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
+  Type* ptype = Type::make_pointer_type(this->type_);
+  param_types->push_back(Typed_identifier("v", ptype, bloc));
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                  ret_types, bloc);
+  Named_object* fn =
+    Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
+  std::string asm_name = "runtime.";
+  asm_name += fnname;
+  fn->func_declaration_value()->set_asm_name(asm_name);
+
+  // ok = FNNAME(type_descriptor, expr, &val_temp)
+  Expression* func = Expression::make_func_reference(fn, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(Expression::make_type_descriptor(this->type_, loc));
+  params->push_back(this->expr_);
+  Expression* ref = Expression::make_temporary_reference(val_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  Expression* call = Expression::make_call(func, params, false, loc);
+  Statement* s = Statement::make_assignment(this->ok_, call, loc);
+  b->add_statement(s);
+
+  // val = val_temp
+  ref = Expression::make_temporary_reference(val_temp, loc);
+  s = Statement::make_assignment(this->val_, ref, loc);
+  b->add_statement(s);
+}
+
+// Make an assignment from a type guard to a pair of variables.
+
+Statement*
+Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
+                                           Expression* expr, Type* type,
+                                           source_location location)
+{
+  return new Tuple_type_guard_assignment_statement(val, ok, expr, type,
+                                                  location);
+}
+
+// An expression statement.
+
+class Expression_statement : public Statement
+{
+ public:
+  Expression_statement(Expression* expr)
+    : Statement(STATEMENT_EXPRESSION, expr->location()),
+      expr_(expr)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return this->traverse_expression(traverse, &this->expr_); }
+
+  void
+  do_determine_types()
+  { this->expr_->determine_type_no_context(); }
+
+  bool
+  do_may_fall_through() const;
+
+  tree
+  do_get_tree(Translate_context* context)
+  { return this->expr_->get_tree(context); }
+
+ private:
+  Expression* expr_;
+};
+
+// An expression statement may fall through unless it is a call to a
+// function which does not return.
+
+bool
+Expression_statement::do_may_fall_through() const
+{
+  const Call_expression* call = this->expr_->call_expression();
+  if (call != NULL)
+    {
+      const Expression* fn = call->fn();
+      const Func_expression* fe = fn->func_expression();
+      if (fe != NULL)
+       {
+         const Named_object* no = fe->named_object();
+
+         Function_type* fntype;
+         if (no->is_function())
+           fntype = no->func_value()->type();
+         else if (no->is_function_declaration())
+           fntype = no->func_declaration_value()->type();
+         else
+           fntype = NULL;
+
+         // The builtin function panic does not return.
+         if (fntype != NULL && fntype->is_builtin() && no->name() == "panic")
+           return false;
+       }
+    }
+  return true;
+}
+
+// Make an expression statement from an Expression.
+
+Statement*
+Statement::make_statement(Expression* expr)
+{
+  return new Expression_statement(expr);
+}
+
+// A block statement--a list of statements which may include variable
+// definitions.
+
+class Block_statement : public Statement
+{
+ public:
+  Block_statement(Block* block, source_location location)
+    : Statement(STATEMENT_BLOCK, location),
+      block_(block)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return this->block_->traverse(traverse); }
+
+  void
+  do_determine_types()
+  { this->block_->determine_types(); }
+
+  bool
+  do_may_fall_through() const
+  { return this->block_->may_fall_through(); }
+
+  tree
+  do_get_tree(Translate_context* context)
+  { return this->block_->get_tree(context); }
+
+ private:
+  Block* block_;
+};
+
+// Make a block statement.
+
+Statement*
+Statement::make_block_statement(Block* block, source_location location)
+{
+  return new Block_statement(block, location);
+}
+
+// An increment or decrement statement.
+
+class Inc_dec_statement : public Statement
+{
+ public:
+  Inc_dec_statement(bool is_inc, Expression* expr)
+    : Statement(STATEMENT_INCDEC, expr->location()),
+      expr_(expr), is_inc_(is_inc)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return this->traverse_expression(traverse, &this->expr_); }
+
+  bool
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // The l-value to increment or decrement.
+  Expression* expr_;
+  // Whether to increment or decrement.
+  bool is_inc_;
+};
+
+// Lower to += or -=.
+
+Statement*
+Inc_dec_statement::do_lower(Gogo*, Block*)
+{
+  source_location loc = this->location();
+
+  mpz_t oval;
+  mpz_init_set_ui(oval, 1UL);
+  Expression* oexpr = Expression::make_integer(&oval, NULL, loc);
+  mpz_clear(oval);
+
+  Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ;
+  return Statement::make_assignment_operation(op, this->expr_, oexpr, loc);
+}
+
+// Make an increment statement.
+
+Statement*
+Statement::make_inc_statement(Expression* expr)
+{
+  return new Inc_dec_statement(true, expr);
+}
+
+// Make a decrement statement.
+
+Statement*
+Statement::make_dec_statement(Expression* expr)
+{
+  return new Inc_dec_statement(false, expr);
+}
+
+// Class Thunk_statement.  This is the base class for go and defer
+// statements.
+
+const char* const Thunk_statement::thunk_field_fn = "fn";
+
+const char* const Thunk_statement::thunk_field_receiver = "receiver";
+
+// Constructor.
+
+Thunk_statement::Thunk_statement(Statement_classification classification,
+                                Call_expression* call,
+                                source_location location)
+    : Statement(classification, location),
+      call_(call), struct_type_(NULL)
+{
+}
+
+// Return whether this is a simple statement which does not require a
+// thunk.
+
+bool
+Thunk_statement::is_simple(Function_type* fntype) const
+{
+  // We need a thunk to call a method, or to pass a variable number of
+  // arguments.
+  if (fntype->is_method() || fntype->is_varargs())
+    return false;
+
+  // A defer statement requires a thunk to set up for whether the
+  // function can call recover.
+  if (this->classification() == STATEMENT_DEFER)
+    return false;
+
+  // We can only permit a single parameter of pointer type.
+  const Typed_identifier_list* parameters = fntype->parameters();
+  if (parameters != NULL
+      && (parameters->size() > 1
+         || (parameters->size() == 1
+             && parameters->begin()->type()->points_to() == NULL)))
+    return false;
+
+  // If the function returns multiple values, or returns a type other
+  // than integer, floating point, or pointer, then it may get a
+  // hidden first parameter, in which case we need the more
+  // complicated approach.  This is true even though we are going to
+  // ignore the return value.
+  const Typed_identifier_list* results = fntype->results();
+  if (results != NULL
+      && (results->size() > 1
+         || (results->size() == 1
+             && !results->begin()->type()->is_basic_type()
+             && results->begin()->type()->points_to() == NULL)))
+    return false;
+
+  // If this calls something which is not a simple function, then we
+  // need a thunk.
+  Expression* fn = this->call_->call_expression()->fn();
+  if (fn->bound_method_expression() != NULL
+      || fn->interface_field_reference_expression() != NULL)
+    return false;
+
+  return true;
+}
+
+// Traverse a thunk statement.
+
+int
+Thunk_statement::do_traverse(Traverse* traverse)
+{
+  return this->traverse_expression(traverse, &this->call_);
+}
+
+// We implement traverse_assignment for a thunk statement because it
+// effectively copies the function call.
+
+bool
+Thunk_statement::do_traverse_assignments(Traverse_assignments* tassign)
+{
+  Expression* fn = this->call_->call_expression()->fn();
+  Expression* fn2 = fn;
+  tassign->value(&fn2, true, false);
+  return true;
+}
+
+// Determine types in a thunk statement.
+
+void
+Thunk_statement::do_determine_types()
+{
+  this->call_->determine_type_no_context();
+
+  // Now that we know the types of the call, build the struct used to
+  // pass parameters.
+  Function_type* fntype =
+    this->call_->call_expression()->get_function_type();
+  if (fntype != NULL && !this->is_simple(fntype))
+    this->struct_type_ = this->build_struct(fntype);
+}
+
+// Check types in a thunk statement.
+
+void
+Thunk_statement::do_check_types(Gogo*)
+{
+  Call_expression* ce = this->call_->call_expression();
+  Function_type* fntype = ce->get_function_type();
+  if (fntype != NULL && fntype->is_method())
+    {
+      Expression* fn = ce->fn();
+      if (fn->bound_method_expression() == NULL
+         && fn->interface_field_reference_expression() == NULL)
+       this->report_error(_("no object for method call"));
+    }
+}
+
+// The Traverse class used to find and simplify thunk statements.
+
+class Simplify_thunk_traverse : public Traverse
+{
+ public:
+  Simplify_thunk_traverse(Gogo* gogo)
+    : Traverse(traverse_blocks),
+      gogo_(gogo)
+  { }
+
+  int
+  block(Block*);
+
+ private:
+  Gogo* gogo_;
+};
+
+int
+Simplify_thunk_traverse::block(Block* b)
+{
+  // The parser ensures that thunk statements always appear at the end
+  // of a block.
+  if (b->statements()->size() < 1)
+    return TRAVERSE_CONTINUE;
+  Thunk_statement* stat = b->statements()->back()->thunk_statement();
+  if (stat == NULL)
+    return TRAVERSE_CONTINUE;
+  if (stat->simplify_statement(this->gogo_, b))
+    return TRAVERSE_SKIP_COMPONENTS;
+  return TRAVERSE_CONTINUE;
+}
+
+// Simplify all thunk statements.
+
+void
+Gogo::simplify_thunk_statements()
+{
+  Simplify_thunk_traverse thunk_traverse(this);
+  this->traverse(&thunk_traverse);
+}
+
+// Simplify complex thunk statements into simple ones.  A complicated
+// thunk statement is one which takes anything other than zero
+// parameters or a single pointer parameter.  We rewrite it into code
+// which allocates a struct, stores the parameter values into the
+// struct, and does a simple go or defer statement which passes the
+// struct to a thunk.  The thunk does the real call.
+
+bool
+Thunk_statement::simplify_statement(Gogo* gogo, Block* block)
+{
+  if (this->classification() == STATEMENT_ERROR)
+    return false;
+  if (this->call_->is_error_expression())
+    return false;
+
+  Call_expression* ce = this->call_->call_expression();
+  Function_type* fntype = ce->get_function_type();
+  if (fntype == NULL || this->is_simple(fntype))
+    return false;
+
+  Expression* fn = ce->fn();
+  Bound_method_expression* bound_method = fn->bound_method_expression();
+  Interface_field_reference_expression* interface_method =
+    fn->interface_field_reference_expression();
+  const bool is_method = bound_method != NULL || interface_method != NULL;
+
+  source_location location = this->location();
+
+  std::string thunk_name = Gogo::thunk_name();
+
+  // Build the thunk.
+  this->build_thunk(gogo, thunk_name, fntype);
+
+  // Generate code to call the thunk.
+
+  // Get the values to store into the struct which is the single
+  // argument to the thunk.
+
+  Expression_list* vals = new Expression_list();
+  if (fntype->is_builtin())
+    ;
+  else if (!is_method)
+    vals->push_back(fn);
+  else if (interface_method != NULL)
+    vals->push_back(interface_method->expr());
+  else if (bound_method != NULL)
+    {
+      vals->push_back(bound_method->method());
+      Expression* first_arg = bound_method->first_argument();
+
+      // We always pass a pointer when calling a method.
+      if (first_arg->type()->points_to() == NULL)
+       first_arg = Expression::make_unary(OPERATOR_AND, first_arg, location);
+
+      // If we are calling a method which was inherited from an
+      // embedded struct, and the method did not get a stub, then the
+      // first type may be wrong.
+      Type* fatype = bound_method->first_argument_type();
+      if (fatype != NULL)
+       {
+         if (fatype->points_to() == NULL)
+           fatype = Type::make_pointer_type(fatype);
+         Type* unsafe = Type::make_pointer_type(Type::make_void_type());
+         first_arg = Expression::make_cast(unsafe, first_arg, location);
+         first_arg = Expression::make_cast(fatype, first_arg, location);
+       }
+
+      vals->push_back(first_arg);
+    }
+  else
+    gcc_unreachable();
+
+  if (ce->args() != NULL)
+    {
+      for (Expression_list::const_iterator p = ce->args()->begin();
+          p != ce->args()->end();
+          ++p)
+       vals->push_back(*p);
+    }
+
+  // Build the struct.
+  Expression* constructor =
+    Expression::make_struct_composite_literal(this->struct_type_, vals,
+                                             location);
+
+  // Allocate the initialized struct on the heap.
+  constructor = Expression::make_heap_composite(constructor, location);
+
+  // Look up the thunk.
+  Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
+  gcc_assert(named_thunk != NULL && named_thunk->is_function());
+
+  // Build the call.
+  Expression* func = Expression::make_func_reference(named_thunk, NULL,
+                                                    location);
+  Expression_list* params = new Expression_list();
+  params->push_back(constructor);
+  Call_expression* call = Expression::make_call(func, params, false, location);
+
+  // Build the simple go or defer statement.
+  Statement* s;
+  if (this->classification() == STATEMENT_GO)
+    s = Statement::make_go_statement(call, location);
+  else if (this->classification() == STATEMENT_DEFER)
+    s = Statement::make_defer_statement(call, location);
+  else
+    gcc_unreachable();
+
+  // The current block should end with the go statement.
+  gcc_assert(block->statements()->size() >= 1);
+  gcc_assert(block->statements()->back() == this);
+  block->replace_statement(block->statements()->size() - 1, s);
+
+  // We already ran the determine_types pass, so we need to run it now
+  // for the new statement.
+  s->determine_types();
+
+  // Sanity check.
+  gogo->check_types_in_block(block);
+
+  // Return true to tell the block not to keep looking at statements.
+  return true;
+}
+
+// Set the name to use for thunk parameter N.
+
+void
+Thunk_statement::thunk_field_param(int n, char* buf, size_t buflen)
+{
+  snprintf(buf, buflen, "a%d", n);
+}
+
+// Build a new struct type to hold the parameters for a complicated
+// thunk statement.  FNTYPE is the type of the function call.
+
+Struct_type*
+Thunk_statement::build_struct(Function_type* fntype)
+{
+  source_location location = this->location();
+
+  Struct_field_list* fields = new Struct_field_list();
+
+  Call_expression* ce = this->call_->call_expression();
+  Expression* fn = ce->fn();
+
+  Interface_field_reference_expression* interface_method =
+    fn->interface_field_reference_expression();
+  if (interface_method != NULL)
+    {
+      // If this thunk statement calls a method on an interface, we
+      // pass the interface object to the thunk.
+      Typed_identifier tid(Thunk_statement::thunk_field_fn,
+                          interface_method->expr()->type(),
+                          location);
+      fields->push_back(Struct_field(tid));
+    }
+  else if (!fntype->is_builtin())
+    {
+      // The function to call.
+      Typed_identifier tid(Go_statement::thunk_field_fn, fntype, location);
+      fields->push_back(Struct_field(tid));
+    }
+  else if (ce->is_recover_call())
+    {
+      // The predeclared recover function has no argument.  However,
+      // we add an argument when building recover thunks.  Handle that
+      // here.
+      fields->push_back(Struct_field(Typed_identifier("can_recover",
+                                                     Type::make_boolean_type(),
+                                                     location)));
+    }
+
+  if (fn->bound_method_expression() != NULL)
+    {
+      gcc_assert(fntype->is_method());
+      Type* rtype = fntype->receiver()->type();
+      // We always pass the receiver as a pointer.
+      if (rtype->points_to() == NULL)
+       rtype = Type::make_pointer_type(rtype);
+      Typed_identifier tid(Thunk_statement::thunk_field_receiver, rtype,
+                          location);
+      fields->push_back(Struct_field(tid));
+    }
+
+  const Expression_list* args = ce->args();
+  if (args != NULL)
+    {
+      int i = 0;
+      for (Expression_list::const_iterator p = args->begin();
+          p != args->end();
+          ++p, ++i)
+       {
+         char buf[50];
+         this->thunk_field_param(i, buf, sizeof buf);
+         fields->push_back(Struct_field(Typed_identifier(buf, (*p)->type(),
+                                                         location)));
+       }
+    }
+
+  return Type::make_struct_type(fields, location);
+}
+
+// Build the thunk we are going to call.  This is a brand new, albeit
+// artificial, function.
+
+void
+Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
+                            Function_type* fntype)
+{
+  source_location location = this->location();
+
+  Call_expression* ce = this->call_->call_expression();
+
+  bool may_call_recover = false;
+  if (this->classification() == STATEMENT_DEFER)
+    {
+      Func_expression* fn = ce->fn()->func_expression();
+      if (fn == NULL)
+       may_call_recover = true;
+      else
+       {
+         const Named_object* no = fn->named_object();
+         if (!no->is_function())
+           may_call_recover = true;
+         else
+           may_call_recover = no->func_value()->calls_recover();
+       }
+    }
+
+  // Build the type of the thunk.  The thunk takes a single parameter,
+  // which is a pointer to the special structure we build.
+  const char* const parameter_name = "__go_thunk_parameter";
+  Typed_identifier_list* thunk_parameters = new Typed_identifier_list();
+  Type* pointer_to_struct_type = Type::make_pointer_type(this->struct_type_);
+  thunk_parameters->push_back(Typed_identifier(parameter_name,
+                                              pointer_to_struct_type,
+                                              location));
+
+  Typed_identifier_list* thunk_results = NULL;
+  if (may_call_recover)
+    {
+      // When deferring a function which may call recover, add a
+      // return value, to disable tail call optimizations which will
+      // break the way we check whether recover is permitted.
+      thunk_results = new Typed_identifier_list();
+      thunk_results->push_back(Typed_identifier("", Type::make_boolean_type(),
+                                               location));
+    }
+
+  Function_type* thunk_type = Type::make_function_type(NULL, thunk_parameters,
+                                                      thunk_results,
+                                                      location);
+
+  // Start building the thunk.
+  Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
+                                               location);
+
+  // For a defer statement, start with a call to
+  // __go_set_defer_retaddr.  */
+  Label* retaddr_label = NULL; 
+  if (may_call_recover)
+    {
+      retaddr_label = gogo->add_label_reference("retaddr");
+      Expression* arg = Expression::make_label_addr(retaddr_label, location);
+      Expression_list* args = new Expression_list();
+      args->push_back(arg);
+
+      static Named_object* set_defer_retaddr;
+      if (set_defer_retaddr == NULL)
+       {
+         const source_location bloc = BUILTINS_LOCATION;
+         Typed_identifier_list* param_types = new Typed_identifier_list();
+         Type *voidptr_type = Type::make_pointer_type(Type::make_void_type());
+         param_types->push_back(Typed_identifier("r", voidptr_type, bloc));
+
+         Typed_identifier_list* result_types = new Typed_identifier_list();
+         result_types->push_back(Typed_identifier("",
+                                                  Type::make_boolean_type(),
+                                                  bloc));
+
+         Function_type* t = Type::make_function_type(NULL, param_types,
+                                                     result_types, bloc);
+         set_defer_retaddr =
+           Named_object::make_function_declaration("__go_set_defer_retaddr",
+                                                   NULL, t, bloc);
+         const char* n = "__go_set_defer_retaddr";
+         set_defer_retaddr->func_declaration_value()->set_asm_name(n);
+       }
+
+      Expression* fn = Expression::make_func_reference(set_defer_retaddr,
+                                                      NULL, location);
+      Expression* call = Expression::make_call(fn, args, false, location);
+
+      // This is a hack to prevent the middle-end from deleting the
+      // label.
+      gogo->start_block(location);
+      gogo->add_statement(Statement::make_goto_statement(retaddr_label,
+                                                        location));
+      Block* then_block = gogo->finish_block(location);
+      then_block->determine_types();
+
+      Statement* s = Statement::make_if_statement(call, then_block, NULL,
+                                                 location);
+      s->determine_types();
+      gogo->add_statement(s);
+    }
+
+  // Get a reference to the parameter.
+  Named_object* named_parameter = gogo->lookup(parameter_name, NULL);
+  gcc_assert(named_parameter != NULL && named_parameter->is_variable());
+
+  // Build the call.  Note that the field names are the same as the
+  // ones used in build_struct.
+  Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
+                                                              location);
+  thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
+                                          location);
+
+  Bound_method_expression* bound_method = ce->fn()->bound_method_expression();
+  Interface_field_reference_expression* interface_method =
+    ce->fn()->interface_field_reference_expression();
+
+  Expression* func_to_call;
+  unsigned int next_index;
+  if (!fntype->is_builtin())
+    {
+      func_to_call = Expression::make_field_reference(thunk_parameter,
+                                                     0, location);
+      next_index = 1;
+    }
+  else
+    {
+      gcc_assert(bound_method == NULL && interface_method == NULL);
+      func_to_call = ce->fn();
+      next_index = 0;
+    }
+
+  if (bound_method != NULL)
+    {
+      Expression* r = Expression::make_field_reference(thunk_parameter, 1,
+                                                      location);
+      // The main program passes in a function pointer from the
+      // interface expression, so here we can make a bound method in
+      // all cases.
+      func_to_call = Expression::make_bound_method(r, func_to_call,
+                                                  location);
+      next_index = 2;
+    }
+  else if (interface_method != NULL)
+    {
+      // The main program passes the interface object.
+      const std::string& name(interface_method->name());
+      func_to_call = Expression::make_interface_field_reference(func_to_call,
+                                                               name,
+                                                               location);
+    }
+
+  Expression_list* call_params = new Expression_list();
+  const Struct_field_list* fields = this->struct_type_->fields();
+  Struct_field_list::const_iterator p = fields->begin();
+  for (unsigned int i = 0; i < next_index; ++i)
+    ++p;
+  for (; p != fields->end(); ++p, ++next_index)
+    {
+      Expression* thunk_param = Expression::make_var_reference(named_parameter,
+                                                              location);
+      thunk_param = Expression::make_unary(OPERATOR_MULT, thunk_param,
+                                          location);
+      Expression* param = Expression::make_field_reference(thunk_param,
+                                                          next_index,
+                                                          location);
+      call_params->push_back(param);
+    }
+
+  Expression* call = Expression::make_call(func_to_call, call_params, false,
+                                          location);
+  // We need to lower in case this is a builtin function.
+  call = call->lower(gogo, function, -1);
+  if (may_call_recover)
+    {
+      Call_expression* ce = call->call_expression();
+      if (ce != NULL)
+       ce->set_is_deferred();
+    }
+
+  Statement* call_statement = Statement::make_statement(call);
+
+  // We already ran the determine_types pass, so we need to run it
+  // just for this statement now.
+  call_statement->determine_types();
+
+  gogo->add_statement(call_statement);
+
+  // If this is a defer statement, the label comes immediately after
+  // the call.
+  if (may_call_recover)
+    {
+      gogo->add_label_definition("retaddr", location);
+
+      Expression_list* vals = new Expression_list();
+      vals->push_back(Expression::make_boolean(false, location));
+      const Typed_identifier_list* results =
+       function->func_value()->type()->results();
+      gogo->add_statement(Statement::make_return_statement(results, vals,
+                                                         location));
+    }
+
+  // That is all the thunk has to do.
+  gogo->finish_function(location);
+}
+
+// Get the function and argument trees.
+
+void
+Thunk_statement::get_fn_and_arg(Translate_context* context, tree* pfn,
+                               tree* parg)
+{
+  if (this->call_->is_error_expression())
+    {
+      *pfn = error_mark_node;
+      *parg = error_mark_node;
+      return;
+    }
+
+  Call_expression* ce = this->call_->call_expression();
+
+  Expression* fn = ce->fn();
+  *pfn = fn->get_tree(context);
+
+  const Expression_list* args = ce->args();
+  if (args == NULL || args->empty())
+    *parg = null_pointer_node;
+  else
+    {
+      gcc_assert(args->size() == 1);
+      *parg = args->front()->get_tree(context);
+    }
+}
+
+// Class Go_statement.
+
+tree
+Go_statement::do_get_tree(Translate_context* context)
+{
+  tree fn_tree;
+  tree arg_tree;
+  this->get_fn_and_arg(context, &fn_tree, &arg_tree);
+
+  static tree go_fndecl;
+
+  tree fn_arg_type = NULL_TREE;
+  if (go_fndecl == NULL_TREE)
+    {
+      // Only build FN_ARG_TYPE if we need it.
+      tree subargtypes = tree_cons(NULL_TREE, ptr_type_node, void_list_node);
+      tree subfntype = build_function_type(ptr_type_node, subargtypes);
+      fn_arg_type = build_pointer_type(subfntype);
+    }
+
+  return Gogo::call_builtin(&go_fndecl,
+                           this->location(),
+                           "__go_go",
+                           2,
+                           void_type_node,
+                           fn_arg_type,
+                           fn_tree,
+                           ptr_type_node,
+                           arg_tree);
+}
+
+// Make a go statement.
+
+Statement*
+Statement::make_go_statement(Call_expression* call, source_location location)
+{
+  return new Go_statement(call, location);
+}
+
+// Class Defer_statement.
+
+tree
+Defer_statement::do_get_tree(Translate_context* context)
+{
+  source_location loc = this->location();
+
+  tree fn_tree;
+  tree arg_tree;
+  this->get_fn_and_arg(context, &fn_tree, &arg_tree);
+  if (fn_tree == error_mark_node || arg_tree == error_mark_node)
+    return error_mark_node;
+
+  static tree defer_fndecl;
+
+  tree fn_arg_type = NULL_TREE;
+  if (defer_fndecl == NULL_TREE)
+    {
+      // Only build FN_ARG_TYPE if we need it.
+      tree subargtypes = tree_cons(NULL_TREE, ptr_type_node, void_list_node);
+      tree subfntype = build_function_type(ptr_type_node, subargtypes);
+      fn_arg_type = build_pointer_type(subfntype);
+    }
+
+  tree defer_stack = context->function()->func_value()->defer_stack(loc);
+
+  return Gogo::call_builtin(&defer_fndecl,
+                           loc,
+                           "__go_defer",
+                           3,
+                           void_type_node,
+                           ptr_type_node,
+                           defer_stack,
+                           fn_arg_type,
+                           fn_tree,
+                           ptr_type_node,
+                           arg_tree);
+}
+
+// Make a defer statement.
+
+Statement*
+Statement::make_defer_statement(Call_expression* call,
+                               source_location location)
+{
+  return new Defer_statement(call, location);
+}
+
+// Class Return_statement.
+
+// Traverse assignments.  We treat each return value as a top level
+// RHS in an expression.
+
+bool
+Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
+{
+  Expression_list* vals = this->vals_;
+  if (vals != NULL)
+    {
+      for (Expression_list::iterator p = vals->begin();
+          p != vals->end();
+          ++p)
+       tassign->value(&*p, true, true);
+    }
+  return true;
+}
+
+// Lower a return statement.  If we are returning a function call
+// which returns multiple values which match the current function,
+// split up the call's results.  If the function has named result
+// variables, and the return statement lists explicit values, then
+// implement it by assigning the values to the result variables and
+// changing the statement to not list any values.  This lets
+// panic/recover work correctly.
+
+Statement*
+Return_statement::do_lower(Gogo*, Block* enclosing)
+{
+  if (this->vals_ == NULL)
+    return this;
+
+  const Typed_identifier_list* results = this->results_;
+  if (results == NULL || results->empty())
+    return this;
+
+  // If the current function has multiple return values, and we are
+  // returning a single call expression, split up the call expression.
+  size_t results_count = results->size();
+  if (results_count > 1
+      && this->vals_->size() == 1
+      && this->vals_->front()->call_expression() != NULL)
+    {
+      Call_expression* call = this->vals_->front()->call_expression();
+      size_t count = results->size();
+      Expression_list* vals = new Expression_list;
+      for (size_t i = 0; i < count; ++i)
+       vals->push_back(Expression::make_call_result(call, i));
+      delete this->vals_;
+      this->vals_ = vals;
+    }
+
+  if (results->front().name().empty())
+    return this;
+
+  if (results_count != this->vals_->size())
+    {
+      // Presumably an error which will be reported in check_types.
+      return this;
+    }
+
+  // Assign to named return values and then return them.
+
+  source_location loc = this->location();
+  const Block* top = enclosing;
+  while (top->enclosing() != NULL)
+    top = top->enclosing();
+
+  const Bindings *bindings = top->bindings();
+  Block* b = new Block(enclosing, loc);
+
+  Expression_list* lhs = new Expression_list();
+  Expression_list* rhs = new Expression_list();
+
+  Expression_list::const_iterator pe = this->vals_->begin();
+  int i = 1;
+  for (Typed_identifier_list::const_iterator pr = results->begin();
+       pr != results->end();
+       ++pr, ++pe, ++i)
+    {
+      Named_object* rv = bindings->lookup_local(pr->name());
+      if (rv == NULL || !rv->is_result_variable())
+       {
+         // Presumably an error.
+         delete b;
+         delete lhs;
+         delete rhs;
+         return this;
+       }
+
+      Expression* e = *pe;
+
+      // Check types now so that we give a good error message.  The
+      // result type is known.  We determine the expression type
+      // early.
+
+      Type *rvtype = rv->result_var_value()->type();
+      Type_context type_context(rvtype, false);
+      e->determine_type(&type_context);
+
+      std::string reason;
+      if (Type::are_assignable(rvtype, e->type(), &reason))
+       {
+         Expression* ve = Expression::make_var_reference(rv, e->location());
+         lhs->push_back(ve);
+         rhs->push_back(e);
+       }
+      else
+       {
+         if (reason.empty())
+           error_at(e->location(), "incompatible type for return value %d", i);
+         else
+           error_at(e->location(),
+                    "incompatible type for return value %d (%s)",
+                    i, reason.c_str());
+       }
+    }
+  gcc_assert(lhs->size() == rhs->size());
+
+  if (lhs->empty())
+    ;
+  else if (lhs->size() == 1)
+    {
+      b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(),
+                                                 loc));
+      delete lhs;
+      delete rhs;
+    }
+  else
+    b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc));
+
+  b->add_statement(Statement::make_return_statement(this->results_, NULL,
+                                                   loc));
+
+  return Statement::make_block_statement(b, loc);
+}
+
+// Determine types.
+
+void
+Return_statement::do_determine_types()
+{
+  if (this->vals_ == NULL)
+    return;
+  const Typed_identifier_list* results = this->results_;
+
+  Typed_identifier_list::const_iterator pt;
+  if (results != NULL)
+    pt = results->begin();
+  for (Expression_list::iterator pe = this->vals_->begin();
+       pe != this->vals_->end();
+       ++pe)
+    {
+      if (results == NULL || pt == results->end())
+       (*pe)->determine_type_no_context();
+      else
+       {
+         Type_context context(pt->type(), false);
+         (*pe)->determine_type(&context);
+         ++pt;
+       }
+    }
+}
+
+// Check types.
+
+void
+Return_statement::do_check_types(Gogo*)
+{
+  if (this->vals_ == NULL)
+    return;
+
+  const Typed_identifier_list* results = this->results_;
+  if (results == NULL)
+    {
+      this->report_error(_("return with value in function "
+                          "with no return type"));
+      return;
+    }
+
+  int i = 1;
+  Typed_identifier_list::const_iterator pt = results->begin();
+  for (Expression_list::const_iterator pe = this->vals_->begin();
+       pe != this->vals_->end();
+       ++pe, ++pt, ++i)
+    {
+      if (pt == results->end())
+       {
+         this->report_error(_("too many values in return statement"));
+         return;
+       }
+      std::string reason;
+      if (!Type::are_assignable(pt->type(), (*pe)->type(), &reason))
+       {
+         if (reason.empty())
+           error_at(this->location(),
+                    "incompatible type for return value %d",
+                    i);
+         else
+           error_at(this->location(),
+                    "incompatible type for return value %d (%s)",
+                    i, reason.c_str());
+         this->set_is_error();
+       }
+      else if (pt->type()->is_error_type()
+              || (*pe)->type()->is_error_type()
+              || pt->type()->is_undefined()
+              || (*pe)->type()->is_undefined())
+       {
+         // Make sure we get the error for an undefined type.
+         pt->type()->base();
+         (*pe)->type()->base();
+         this->set_is_error();
+       }
+    }
+
+  if (pt != results->end())
+    this->report_error(_("not enough values in return statement"));
+}
+
+// Build a RETURN_EXPR tree.
+
+tree
+Return_statement::do_get_tree(Translate_context* context)
+{
+  Function* function = context->function()->func_value();
+  tree fndecl = function->get_decl();
+
+  const Typed_identifier_list* results = this->results_;
+
+  if (this->vals_ == NULL)
+    {
+      tree stmt_list = NULL_TREE;
+      tree retval = function->return_value(context->gogo(),
+                                          context->function(),
+                                          this->location(),
+                                          &stmt_list);
+      tree set;
+      if (retval == NULL_TREE)
+       set = NULL_TREE;
+      else
+       set = fold_build2_loc(this->location(), MODIFY_EXPR, void_type_node,
+                             DECL_RESULT(fndecl), retval);
+      append_to_statement_list(this->build_stmt_1(RETURN_EXPR, set),
+                              &stmt_list);
+      return stmt_list;
+    }
+  else if (this->vals_->size() == 1)
+    {
+      gcc_assert(!VOID_TYPE_P(TREE_TYPE(TREE_TYPE(fndecl))));
+      tree val = (*this->vals_->begin())->get_tree(context);
+      if (val == error_mark_node)
+       return error_mark_node;
+      gcc_assert(results != NULL && results->size() == 1);
+      val = Expression::convert_for_assignment(context,
+                                              results->begin()->type(),
+                                              (*this->vals_->begin())->type(),
+                                              val, this->location());
+      tree set = build2(MODIFY_EXPR, void_type_node,
+                       DECL_RESULT(fndecl), val);
+      SET_EXPR_LOCATION(set, this->location());
+      return this->build_stmt_1(RETURN_EXPR, set);
+    }
+  else
+    {
+      gcc_assert(!VOID_TYPE_P(TREE_TYPE(TREE_TYPE(fndecl))));
+      tree stmt_list = NULL_TREE;
+      tree rettype = TREE_TYPE(DECL_RESULT(fndecl));
+      tree retvar = create_tmp_var(rettype, "RESULT");
+      gcc_assert(results != NULL && results->size() == this->vals_->size());
+      Expression_list::const_iterator pv = this->vals_->begin();
+      Typed_identifier_list::const_iterator pr = results->begin();
+      for (tree field = TYPE_FIELDS(rettype);
+          field != NULL_TREE;
+          ++pv, ++pr, field = DECL_CHAIN(field))
+       {
+         gcc_assert(pv != this->vals_->end());
+         tree val = (*pv)->get_tree(context);
+         if (val == error_mark_node)
+           return error_mark_node;
+         val = Expression::convert_for_assignment(context, pr->type(),
+                                                  (*pv)->type(), val,
+                                                  this->location());
+         tree set = build2(MODIFY_EXPR, void_type_node,
+                           build3(COMPONENT_REF, TREE_TYPE(field),
+                                  retvar, field, NULL_TREE),
+                           val);
+         SET_EXPR_LOCATION(set, this->location());
+         append_to_statement_list(set, &stmt_list);
+       }
+      tree set = build2(MODIFY_EXPR, void_type_node, DECL_RESULT(fndecl),
+                       retvar);
+      append_to_statement_list(this->build_stmt_1(RETURN_EXPR, set),
+                              &stmt_list);
+      return stmt_list;
+    }
+}
+
+// Make a return statement.
+
+Statement*
+Statement::make_return_statement(const Typed_identifier_list* results,
+                                Expression_list* vals,
+                                source_location location)
+{
+  return new Return_statement(results, vals, location);
+}
+
+// A break or continue statement.
+
+class Bc_statement : public Statement
+{
+ public:
+  Bc_statement(bool is_break, Unnamed_label* label, source_location location)
+    : Statement(STATEMENT_BREAK_OR_CONTINUE, location),
+      label_(label), is_break_(is_break)
+  { }
+
+  bool
+  is_break() const
+  { return this->is_break_; }
+
+ protected:
+  int
+  do_traverse(Traverse*)
+  { return TRAVERSE_CONTINUE; }
+
+  bool
+  do_may_fall_through() const
+  { return false; }
+
+  tree
+  do_get_tree(Translate_context*)
+  { return this->label_->get_goto(this->location()); }
+
+ private:
+  // The label that this branches to.
+  Unnamed_label* label_;
+  // True if this is "break", false if it is "continue".
+  bool is_break_;
+};
+
+// Make a break statement.
+
+Statement*
+Statement::make_break_statement(Unnamed_label* label, source_location location)
+{
+  return new Bc_statement(true, label, location);
+}
+
+// Make a continue statement.
+
+Statement*
+Statement::make_continue_statement(Unnamed_label* label,
+                                  source_location location)
+{
+  return new Bc_statement(false, label, location);
+}
+
+// A goto statement.
+
+class Goto_statement : public Statement
+{
+ public:
+  Goto_statement(Label* label, source_location location)
+    : Statement(STATEMENT_GOTO, location),
+      label_(label)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*)
+  { return TRAVERSE_CONTINUE; }
+
+  void
+  do_check_types(Gogo*);
+
+  bool
+  do_may_fall_through() const
+  { return false; }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  Label* label_;
+};
+
+// Check types for a label.  There aren't any types per se, but we use
+// this to give an error if the label was never defined.
+
+void
+Goto_statement::do_check_types(Gogo*)
+{
+  if (!this->label_->is_defined())
+    {
+      error_at(this->location(), "reference to undefined label %qs",
+              Gogo::message_name(this->label_->name()).c_str());
+      this->set_is_error();
+    }
+}
+
+// Return the tree for the goto statement.
+
+tree
+Goto_statement::do_get_tree(Translate_context*)
+{
+  return this->build_stmt_1(GOTO_EXPR, this->label_->get_decl());
+}
+
+// Make a goto statement.
+
+Statement*
+Statement::make_goto_statement(Label* label, source_location location)
+{
+  return new Goto_statement(label, location);
+}
+
+// A goto statement to an unnamed label.
+
+class Goto_unnamed_statement : public Statement
+{
+ public:
+  Goto_unnamed_statement(Unnamed_label* label, source_location location)
+    : Statement(STATEMENT_GOTO_UNNAMED, location),
+      label_(label)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*)
+  { return TRAVERSE_CONTINUE; }
+
+  bool
+  do_may_fall_through() const
+  { return false; }
+
+  tree
+  do_get_tree(Translate_context*)
+  { return this->label_->get_goto(this->location()); }
+
+ private:
+  Unnamed_label* label_;
+};
+
+// Make a goto statement to an unnamed label.
+
+Statement*
+Statement::make_goto_unnamed_statement(Unnamed_label* label,
+                                      source_location location)
+{
+  return new Goto_unnamed_statement(label, location);
+}
+
+// Class Label_statement.
+
+// Traversal.
+
+int
+Label_statement::do_traverse(Traverse*)
+{
+  return TRAVERSE_CONTINUE;
+}
+
+// Return a tree defining this label.
+
+tree
+Label_statement::do_get_tree(Translate_context*)
+{
+  return this->build_stmt_1(LABEL_EXPR, this->label_->get_decl());
+}
+
+// Make a label statement.
+
+Statement*
+Statement::make_label_statement(Label* label, source_location location)
+{
+  return new Label_statement(label, location);
+}
+
+// An unnamed label statement.
+
+class Unnamed_label_statement : public Statement
+{
+ public:
+  Unnamed_label_statement(Unnamed_label* label)
+    : Statement(STATEMENT_UNNAMED_LABEL, label->location()),
+      label_(label)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*)
+  { return TRAVERSE_CONTINUE; }
+
+  tree
+  do_get_tree(Translate_context*)
+  { return this->label_->get_definition(); }
+
+ private:
+  // The label.
+  Unnamed_label* label_;
+};
+
+// Make an unnamed label statement.
+
+Statement*
+Statement::make_unnamed_label_statement(Unnamed_label* label)
+{
+  return new Unnamed_label_statement(label);
+}
+
+// An if statement.
+
+class If_statement : public Statement
+{
+ public:
+  If_statement(Expression* cond, Block* then_block, Block* else_block,
+              source_location location)
+    : Statement(STATEMENT_IF, location),
+      cond_(cond), then_block_(then_block), else_block_(else_block)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  void
+  do_determine_types();
+
+  void
+  do_check_types(Gogo*);
+
+  bool
+  do_may_fall_through() const;
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  Expression* cond_;
+  Block* then_block_;
+  Block* else_block_;
+};
+
+// Traversal.
+
+int
+If_statement::do_traverse(Traverse* traverse)
+{
+  if (this->cond_ != NULL)
+    {
+      if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  if (this->then_block_->traverse(traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (this->else_block_ != NULL)
+    {
+      if (this->else_block_->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+void
+If_statement::do_determine_types()
+{
+  if (this->cond_ != NULL)
+    {
+      Type_context context(Type::lookup_bool_type(), false);
+      this->cond_->determine_type(&context);
+    }
+  this->then_block_->determine_types();
+  if (this->else_block_ != NULL)
+    this->else_block_->determine_types();
+}
+
+// Check types.
+
+void
+If_statement::do_check_types(Gogo*)
+{
+  if (this->cond_ != NULL)
+    {
+      Type* type = this->cond_->type();
+      if (type->is_error_type())
+       this->set_is_error();
+      else if (!type->is_boolean_type())
+       this->report_error(_("expected boolean expression"));
+    }
+}
+
+// Whether the overall statement may fall through.
+
+bool
+If_statement::do_may_fall_through() const
+{
+  return (this->else_block_ == NULL
+         || this->then_block_->may_fall_through()
+         || this->else_block_->may_fall_through());
+}
+
+// Get tree.
+
+tree
+If_statement::do_get_tree(Translate_context* context)
+{
+  gcc_assert(this->cond_ == NULL || this->cond_->type()->is_boolean_type());
+  tree ret = build3(COND_EXPR, void_type_node,
+                   (this->cond_ == NULL
+                    ? boolean_true_node
+                    : this->cond_->get_tree(context)),
+                   this->then_block_->get_tree(context),
+                   (this->else_block_ == NULL
+                    ? NULL_TREE
+                    : this->else_block_->get_tree(context)));
+  SET_EXPR_LOCATION(ret, this->location());
+  return ret;
+}
+
+// Make an if statement.
+
+Statement*
+Statement::make_if_statement(Expression* cond, Block* then_block,
+                            Block* else_block, source_location location)
+{
+  return new If_statement(cond, then_block, else_block, location);
+}
+
+// Class Case_clauses::Case_clause.
+
+// Traversal.
+
+int
+Case_clauses::Case_clause::traverse(Traverse* traverse)
+{
+  if (this->cases_ != NULL
+      && (traverse->traverse_mask() & Traverse::traverse_expressions) != 0)
+    {
+      if (this->cases_->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  if (this->statements_ != NULL)
+    {
+      if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Check whether all the case expressions are integer constants.
+
+bool
+Case_clauses::Case_clause::is_constant() const
+{
+  if (this->cases_ != NULL)
+    {
+      for (Expression_list::const_iterator p = this->cases_->begin();
+          p != this->cases_->end();
+          ++p)
+       if (!(*p)->is_constant() || (*p)->type()->integer_type() == NULL)
+         return false;
+    }
+  return true;
+}
+
+// Lower a case clause for a nonconstant switch.  VAL_TEMP is the
+// value we are switching on; it may be NULL.  If START_LABEL is not
+// NULL, it goes at the start of the statements, after the condition
+// test.  We branch to FINISH_LABEL at the end of the statements.
+
+void
+Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
+                                Unnamed_label* start_label,
+                                Unnamed_label* finish_label) const
+{
+  source_location loc = this->location_;
+  Unnamed_label* next_case_label;
+  if (this->cases_ == NULL || this->cases_->empty())
+    {
+      gcc_assert(this->is_default_);
+      next_case_label = NULL;
+    }
+  else
+    {
+      Expression* cond = NULL;
+
+      for (Expression_list::const_iterator p = this->cases_->begin();
+          p != this->cases_->end();
+          ++p)
+       {
+         Expression* this_cond;
+         if (val_temp == NULL)
+           this_cond = *p;
+         else
+           {
+             Expression* ref = Expression::make_temporary_reference(val_temp,
+                                                                    loc);
+             this_cond = Expression::make_binary(OPERATOR_EQEQ, ref, *p, loc);
+           }
+
+         if (cond == NULL)
+           cond = this_cond;
+         else
+           cond = Expression::make_binary(OPERATOR_OROR, cond, this_cond, loc);
+       }
+
+      Block* then_block = new Block(b, loc);
+      next_case_label = new Unnamed_label(UNKNOWN_LOCATION);
+      Statement* s = Statement::make_goto_unnamed_statement(next_case_label,
+                                                           loc);
+      then_block->add_statement(s);
+
+      // if !COND { goto NEXT_CASE_LABEL }
+      cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
+      s = Statement::make_if_statement(cond, then_block, NULL, loc);
+      b->add_statement(s);
+    }
+
+  if (start_label != NULL)
+    b->add_statement(Statement::make_unnamed_label_statement(start_label));
+
+  if (this->statements_ != NULL)
+    b->add_statement(Statement::make_block_statement(this->statements_, loc));
+
+  Statement* s = Statement::make_goto_unnamed_statement(finish_label, loc);
+  b->add_statement(s);
+
+  if (next_case_label != NULL)
+    b->add_statement(Statement::make_unnamed_label_statement(next_case_label));
+}
+
+// Determine types.
+
+void
+Case_clauses::Case_clause::determine_types(Type* type)
+{
+  if (this->cases_ != NULL)
+    {
+      Type_context case_context(type, false);
+      for (Expression_list::iterator p = this->cases_->begin();
+          p != this->cases_->end();
+          ++p)
+       (*p)->determine_type(&case_context);
+    }
+  if (this->statements_ != NULL)
+    this->statements_->determine_types();
+}
+
+// Check types.  Returns false if there was an error.
+
+bool
+Case_clauses::Case_clause::check_types(Type* type)
+{
+  if (this->cases_ != NULL)
+    {
+      for (Expression_list::iterator p = this->cases_->begin();
+          p != this->cases_->end();
+          ++p)
+       {
+         if (!Type::are_assignable(type, (*p)->type(), NULL)
+             && !Type::are_assignable((*p)->type(), type, NULL))
+           {
+             error_at((*p)->location(),
+                      "type mismatch between switch value and case clause");
+             return false;
+           }
+       }
+    }
+  return true;
+}
+
+// Return true if this clause may fall through to the following
+// statements.  Note that this is not the same as whether the case
+// uses the "fallthrough" keyword.
+
+bool
+Case_clauses::Case_clause::may_fall_through() const
+{
+  if (this->statements_ == NULL)
+    return true;
+  return this->statements_->may_fall_through();
+}
+
+// Build up the body of a SWITCH_EXPR.
+
+void
+Case_clauses::Case_clause::get_constant_tree(Translate_context* context,
+                                            Unnamed_label* break_label,
+                                            Case_constants* case_constants,
+                                            tree* stmt_list) const
+{
+  if (this->cases_ != NULL)
+    {
+      for (Expression_list::const_iterator p = this->cases_->begin();
+          p != this->cases_->end();
+          ++p)
+       {
+         Type* itype;
+         mpz_t ival;
+         mpz_init(ival);
+         if (!(*p)->integer_constant_value(true, ival, &itype))
+           gcc_unreachable();
+         gcc_assert(itype != NULL);
+         tree type_tree = itype->get_tree(context->gogo());
+         tree val = Expression::integer_constant_tree(ival, type_tree);
+         mpz_clear(ival);
+
+         if (val != error_mark_node)
+           {
+             gcc_assert(TREE_CODE(val) == INTEGER_CST);
+
+             std::pair<Case_constants::iterator, bool> ins =
+               case_constants->insert(val);
+             if (!ins.second)
+               {
+                 // Value was already present.
+                 warning_at(this->location_, 0,
+                            "duplicate case value will never match");
+                 continue;
+               }
+
+             tree label = create_artificial_label(this->location_);
+             append_to_statement_list(build3(CASE_LABEL_EXPR, void_type_node,
+                                             val, NULL_TREE, label),
+                                      stmt_list);
+           }
+       }
+    }
+
+  if (this->is_default_)
+    {
+      tree label = create_artificial_label(this->location_);
+      append_to_statement_list(build3(CASE_LABEL_EXPR, void_type_node,
+                                     NULL_TREE, NULL_TREE, label),
+                              stmt_list);
+    }
+
+  if (this->statements_ != NULL)
+    {
+      tree block_tree = this->statements_->get_tree(context);
+      if (block_tree != error_mark_node)
+       append_to_statement_list(block_tree, stmt_list);
+    }
+
+  if (!this->is_fallthrough_)
+    append_to_statement_list(break_label->get_goto(this->location_), stmt_list);
+}
+
+// Class Case_clauses.
+
+// Traversal.
+
+int
+Case_clauses::traverse(Traverse* traverse)
+{
+  for (Clauses::iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      if (p->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Check whether all the case expressions are constant.
+
+bool
+Case_clauses::is_constant() const
+{
+  for (Clauses::const_iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    if (!p->is_constant())
+      return false;
+  return true;
+}
+
+// Lower case clauses for a nonconstant switch.
+
+void
+Case_clauses::lower(Block* b, Temporary_statement* val_temp,
+                   Unnamed_label* break_label) const
+{
+  // The default case.
+  const Case_clause* default_case = NULL;
+
+  // The label for the fallthrough of the previous case.
+  Unnamed_label* last_fallthrough_label = NULL;
+
+  // The label for the start of the default case.  This is used if the
+  // case before the default case falls through.
+  Unnamed_label* default_start_label = NULL;
+
+  // The label for the end of the default case.  This normally winds
+  // up as BREAK_LABEL, but it will be different if the default case
+  // falls through.
+  Unnamed_label* default_finish_label = NULL;
+
+  for (Clauses::const_iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      // The label to use for the start of the statements for this
+      // case.  This is NULL unless the previous case falls through.
+      Unnamed_label* start_label = last_fallthrough_label;
+
+      // The label to jump to after the end of the statements for this
+      // case.
+      Unnamed_label* finish_label = break_label;
+
+      last_fallthrough_label = NULL;
+      if (p->is_fallthrough() && p + 1 != this->clauses_.end())
+       {
+         finish_label = new Unnamed_label(p->location());
+         last_fallthrough_label = finish_label;
+       }
+
+      if (!p->is_default())
+       p->lower(b, val_temp, start_label, finish_label);
+      else
+       {
+         // We have to move the default case to the end, so that we
+         // only use it if all the other tests fail.
+         default_case = &*p;
+         default_start_label = start_label;
+         default_finish_label = finish_label;
+       }
+    }
+
+  if (default_case != NULL)
+    default_case->lower(b, val_temp, default_start_label,
+                       default_finish_label);
+      
+}
+
+// Determine types.
+
+void
+Case_clauses::determine_types(Type* type)
+{
+  for (Clauses::iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    p->determine_types(type);
+}
+
+// Check types.  Returns false if there was an error.
+
+bool
+Case_clauses::check_types(Type* type)
+{
+  bool ret = true;
+  for (Clauses::iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      if (!p->check_types(type))
+       ret = false;
+    }
+  return ret;
+}
+
+// Return true if these clauses may fall through to the statements
+// following the switch statement.
+
+bool
+Case_clauses::may_fall_through() const
+{
+  bool found_default = false;
+  for (Clauses::const_iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      if (p->may_fall_through() && !p->is_fallthrough())
+       return true;
+      if (p->is_default())
+       found_default = true;
+    }
+  return !found_default;
+}
+
+// Return a tree when all case expressions are constants.
+
+tree
+Case_clauses::get_constant_tree(Translate_context* context,
+                               Unnamed_label* break_label) const
+{
+  Case_constants case_constants;
+  tree stmt_list = NULL_TREE;
+  for (Clauses::const_iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    p->get_constant_tree(context, break_label, &case_constants,
+                        &stmt_list);
+  return stmt_list;
+}
+
+// A constant switch statement.  A Switch_statement is lowered to this
+// when all the cases are constants.
+
+class Constant_switch_statement : public Statement
+{
+ public:
+  Constant_switch_statement(Expression* val, Case_clauses* clauses,
+                           Unnamed_label* break_label,
+                           source_location location)
+    : Statement(STATEMENT_CONSTANT_SWITCH, location),
+      val_(val), clauses_(clauses), break_label_(break_label)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  void
+  do_determine_types();
+
+  void
+  do_check_types(Gogo*);
+
+  bool
+  do_may_fall_through() const;
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The value to switch on.
+  Expression* val_;
+  // The case clauses.
+  Case_clauses* clauses_;
+  // The break label, if needed.
+  Unnamed_label* break_label_;
+};
+
+// Traversal.
+
+int
+Constant_switch_statement::do_traverse(Traverse* traverse)
+{
+  if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return this->clauses_->traverse(traverse);
+}
+
+// Determine types.
+
+void
+Constant_switch_statement::do_determine_types()
+{
+  this->val_->determine_type_no_context();
+  this->clauses_->determine_types(this->val_->type());
+}
+
+// Check types.
+
+void
+Constant_switch_statement::do_check_types(Gogo*)
+{
+  if (!this->clauses_->check_types(this->val_->type()))
+    this->set_is_error();
+}
+
+// Return whether this switch may fall through.
+
+bool
+Constant_switch_statement::do_may_fall_through() const
+{
+  if (this->clauses_ == NULL)
+    return true;
+
+  // If we have a break label, then some case needed it.  That implies
+  // that the switch statement as a whole can fall through.
+  if (this->break_label_ != NULL)
+    return true;
+
+  return this->clauses_->may_fall_through();
+}
+
+// Convert to GENERIC.
+
+tree
+Constant_switch_statement::do_get_tree(Translate_context* context)
+{
+  tree switch_val_tree = this->val_->get_tree(context);
+
+  Unnamed_label* break_label = this->break_label_;
+  if (break_label == NULL)
+    break_label = new Unnamed_label(this->location());
+
+  tree stmt_list = NULL_TREE;
+  tree s = build3(SWITCH_EXPR, void_type_node, switch_val_tree,
+                 this->clauses_->get_constant_tree(context, break_label),
+                 NULL_TREE);
+  SET_EXPR_LOCATION(s, this->location());
+  append_to_statement_list(s, &stmt_list);
+
+  append_to_statement_list(break_label->get_definition(), &stmt_list);
+
+  return stmt_list;
+}
+
+// Class Switch_statement.
+
+// Traversal.
+
+int
+Switch_statement::do_traverse(Traverse* traverse)
+{
+  if (this->val_ != NULL)
+    {
+      if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return this->clauses_->traverse(traverse);
+}
+
+// Lower a Switch_statement to a Constant_switch_statement or a series
+// of if statements.
+
+Statement*
+Switch_statement::do_lower(Gogo*, Block* enclosing)
+{
+  source_location loc = this->location();
+
+  if (this->val_ != NULL
+      && (this->val_->is_error_expression()
+         || this->val_->type()->is_error_type()))
+    return Statement::make_error_statement(loc);
+
+  if (this->val_ != NULL
+      && this->val_->type()->integer_type() != NULL
+      && !this->clauses_->empty()
+      && this->clauses_->is_constant())
+    return new Constant_switch_statement(this->val_, this->clauses_,
+                                        this->break_label_, loc);
+
+  Block* b = new Block(enclosing, loc);
+
+  if (this->clauses_->empty())
+    {
+      Expression* val = this->val_;
+      if (val == NULL)
+       val = Expression::make_boolean(true, loc);
+      return Statement::make_statement(val);
+    }
+
+  Temporary_statement* val_temp;
+  if (this->val_ == NULL)
+    val_temp = NULL;
+  else
+    {
+      // var val_temp VAL_TYPE = VAL
+      val_temp = Statement::make_temporary(NULL, this->val_, loc);
+      b->add_statement(val_temp);
+    }
+
+  this->clauses_->lower(b, val_temp, this->break_label());
+
+  Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
+  b->add_statement(s);
+
+  return Statement::make_block_statement(b, loc);
+}
+
+// Return the break label for this switch statement, creating it if
+// necessary.
+
+Unnamed_label*
+Switch_statement::break_label()
+{
+  if (this->break_label_ == NULL)
+    this->break_label_ = new Unnamed_label(this->location());
+  return this->break_label_;
+}
+
+// Make a switch statement.
+
+Switch_statement*
+Statement::make_switch_statement(Expression* val, source_location location)
+{
+  return new Switch_statement(val, location);
+}
+
+// Class Type_case_clauses::Type_case_clause.
+
+// Traversal.
+
+int
+Type_case_clauses::Type_case_clause::traverse(Traverse* traverse)
+{
+  if (!this->is_default_
+      && ((traverse->traverse_mask()
+          & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
+      && Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (this->statements_ != NULL)
+    return this->statements_->traverse(traverse);
+  return TRAVERSE_CONTINUE;
+}
+
+// Lower one clause in a type switch.  Add statements to the block B.
+// The type descriptor we are switching on is in DESCRIPTOR_TEMP.
+// BREAK_LABEL is the label at the end of the type switch.
+// *STMTS_LABEL, if not NULL, is a label to put at the start of the
+// statements.
+
+void
+Type_case_clauses::Type_case_clause::lower(Block* b,
+                                          Temporary_statement* descriptor_temp,
+                                          Unnamed_label* break_label,
+                                          Unnamed_label** stmts_label) const
+{
+  source_location loc = this->location_;
+
+  Unnamed_label* next_case_label = NULL;
+  if (!this->is_default_)
+    {
+      Type* type = this->type_;
+
+      Expression* cond;
+      // The language permits case nil, which is of course a constant
+      // rather than a type.  It will appear here as an invalid
+      // forwarding type.
+      if (type->is_nil_constant_as_type())
+       {
+         Expression* ref =
+           Expression::make_temporary_reference(descriptor_temp, loc);
+         cond = Expression::make_binary(OPERATOR_EQEQ, ref,
+                                        Expression::make_nil(loc),
+                                        loc);
+       }
+      else
+       {
+         Expression* func;
+         if (type->interface_type() == NULL)
+           {
+             // func ifacetypeeq(*descriptor, *descriptor) bool
+             static Named_object* ifacetypeeq;
+             if (ifacetypeeq == NULL)
+               {
+                 const source_location bloc = BUILTINS_LOCATION;
+                 Typed_identifier_list* param_types =
+                   new Typed_identifier_list();
+                 Type* descriptor_type = Type::make_type_descriptor_ptr_type();
+                 param_types->push_back(Typed_identifier("a", descriptor_type,
+                                                         bloc));
+                 param_types->push_back(Typed_identifier("b", descriptor_type,
+                                                         bloc));
+                 Typed_identifier_list* ret_types =
+                   new Typed_identifier_list();
+                 Type* bool_type = Type::lookup_bool_type();
+                 ret_types->push_back(Typed_identifier("", bool_type, bloc));
+                 Function_type* fntype = Type::make_function_type(NULL,
+                                                                  param_types,
+                                                                  ret_types,
+                                                                  bloc);
+                 ifacetypeeq =
+                   Named_object::make_function_declaration("ifacetypeeq", NULL,
+                                                           fntype, bloc);
+                 const char* n = "runtime.ifacetypeeq";
+                 ifacetypeeq->func_declaration_value()->set_asm_name(n);
+               }
+
+             // ifacetypeeq(descriptor_temp, DESCRIPTOR)
+             func = Expression::make_func_reference(ifacetypeeq, NULL, loc);
+           }
+         else
+           {
+             // func ifaceI2Tp(*descriptor, *descriptor) bool
+             static Named_object* ifaceI2Tp;
+             if (ifaceI2Tp == NULL)
+               {
+                 const source_location bloc = BUILTINS_LOCATION;
+                 Typed_identifier_list* param_types =
+                   new Typed_identifier_list();
+                 Type* descriptor_type = Type::make_type_descriptor_ptr_type();
+                 param_types->push_back(Typed_identifier("a", descriptor_type,
+                                                         bloc));
+                 param_types->push_back(Typed_identifier("b", descriptor_type,
+                                                         bloc));
+                 Typed_identifier_list* ret_types =
+                   new Typed_identifier_list();
+                 Type* bool_type = Type::lookup_bool_type();
+                 ret_types->push_back(Typed_identifier("", bool_type, bloc));
+                 Function_type* fntype = Type::make_function_type(NULL,
+                                                                  param_types,
+                                                                  ret_types,
+                                                                  bloc);
+                 ifaceI2Tp =
+                   Named_object::make_function_declaration("ifaceI2Tp", NULL,
+                                                           fntype, bloc);
+                 const char* n = "runtime.ifaceI2Tp";
+                 ifaceI2Tp->func_declaration_value()->set_asm_name(n);
+               }
+
+             // ifaceI2Tp(descriptor_temp, DESCRIPTOR)
+             func = Expression::make_func_reference(ifaceI2Tp, NULL, loc);
+           }
+         Expression_list* params = new Expression_list();
+         params->push_back(Expression::make_type_descriptor(type, loc));
+         Expression* ref =
+           Expression::make_temporary_reference(descriptor_temp, loc);
+         params->push_back(ref);
+         cond = Expression::make_call(func, params, false, loc);
+       }
+
+      Unnamed_label* dest;
+      if (!this->is_fallthrough_)
+       {
+         // if !COND { goto NEXT_CASE_LABEL }
+         next_case_label = new Unnamed_label(UNKNOWN_LOCATION);
+         dest = next_case_label;
+         cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
+       }
+      else
+       {
+         // if COND { goto STMTS_LABEL }
+         gcc_assert(stmts_label != NULL);
+         if (*stmts_label == NULL)
+           *stmts_label = new Unnamed_label(UNKNOWN_LOCATION);
+         dest = *stmts_label;
+       }
+      Block* then_block = new Block(b, loc);
+      Statement* s = Statement::make_goto_unnamed_statement(dest, loc);
+      then_block->add_statement(s);
+      s = Statement::make_if_statement(cond, then_block, NULL, loc);
+      b->add_statement(s);
+    }
+
+  if (this->statements_ != NULL
+      || (!this->is_fallthrough_
+         && stmts_label != NULL
+         && *stmts_label != NULL))
+    {
+      gcc_assert(!this->is_fallthrough_);
+      if (stmts_label != NULL && *stmts_label != NULL)
+       {
+         gcc_assert(!this->is_default_);
+         if (this->statements_ != NULL)
+           (*stmts_label)->set_location(this->statements_->start_location());
+         Statement* s = Statement::make_unnamed_label_statement(*stmts_label);
+         b->add_statement(s);
+         *stmts_label = NULL;
+       }
+      if (this->statements_ != NULL)
+       b->add_statement(Statement::make_block_statement(this->statements_,
+                                                        loc));
+    }
+
+  if (this->is_fallthrough_)
+    gcc_assert(next_case_label == NULL);
+  else
+    {
+      source_location gloc = (this->statements_ == NULL
+                             ? loc
+                             : this->statements_->end_location());
+      b->add_statement(Statement::make_goto_unnamed_statement(break_label,
+                                                             gloc));
+      if (next_case_label != NULL)
+       {
+         Statement* s =
+           Statement::make_unnamed_label_statement(next_case_label);
+         b->add_statement(s);
+       }
+    }
+}
+
+// Class Type_case_clauses.
+
+// Traversal.
+
+int
+Type_case_clauses::traverse(Traverse* traverse)
+{
+  for (Type_clauses::iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      if (p->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Check for duplicate types.
+
+void
+Type_case_clauses::check_duplicates() const
+{
+  typedef Unordered_set_hash(const Type*, Type_hash_identical,
+                            Type_identical) Types_seen;
+  Types_seen types_seen;
+  for (Type_clauses::const_iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      Type* t = p->type();
+      if (t == NULL)
+       continue;
+      if (t->is_nil_constant_as_type())
+       t = Type::make_nil_type();
+      std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t);
+      if (!ins.second)
+       error_at(p->location(), "duplicate type in switch");
+    }
+}
+
+// Lower the clauses in a type switch.  Add statements to the block B.
+// The type descriptor we are switching on is in DESCRIPTOR_TEMP.
+// BREAK_LABEL is the label at the end of the type switch.
+
+void
+Type_case_clauses::lower(Block* b, Temporary_statement* descriptor_temp,
+                        Unnamed_label* break_label) const
+{
+  const Type_case_clause* default_case = NULL;
+
+  Unnamed_label* stmts_label = NULL;
+  for (Type_clauses::const_iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      if (!p->is_default())
+       p->lower(b, descriptor_temp, break_label, &stmts_label);
+      else
+       {
+         // We are generating a series of tests, which means that we
+         // need to move the default case to the end.
+         default_case = &*p;
+       }
+    }
+  gcc_assert(stmts_label == NULL);
+
+  if (default_case != NULL)
+    default_case->lower(b, descriptor_temp, break_label, NULL);
+}
+
+// Class Type_switch_statement.
+
+// Traversal.
+
+int
+Type_switch_statement::do_traverse(Traverse* traverse)
+{
+  if (this->var_ == NULL)
+    {
+      if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  if (this->clauses_ != NULL)
+    return this->clauses_->traverse(traverse);
+  return TRAVERSE_CONTINUE;
+}
+
+// Lower a type switch statement to a series of if statements.  The gc
+// compiler is able to generate a table in some cases.  However, that
+// does not work for us because we may have type descriptors in
+// different shared libraries, so we can't compare them with simple
+// equality testing.
+
+Statement*
+Type_switch_statement::do_lower(Gogo*, Block* enclosing)
+{
+  const source_location loc = this->location();
+
+  if (this->clauses_ != NULL)
+    this->clauses_->check_duplicates();
+
+  Block* b = new Block(enclosing, loc);
+
+  Type* val_type = (this->var_ != NULL
+                   ? this->var_->var_value()->type()
+                   : this->expr_->type());
+
+  // var descriptor_temp DESCRIPTOR_TYPE
+  Type* descriptor_type = Type::make_type_descriptor_ptr_type();
+  Temporary_statement* descriptor_temp =
+    Statement::make_temporary(descriptor_type, NULL, loc);
+  b->add_statement(descriptor_temp);
+
+  if (val_type->interface_type() == NULL)
+    {
+      // Doing a type switch on a non-interface type.  Should we issue
+      // a warning for this case?
+      // descriptor_temp = DESCRIPTOR
+      Expression* lhs = Expression::make_temporary_reference(descriptor_temp,
+                                                            loc);
+      Expression* rhs = Expression::make_type_descriptor(val_type, loc);
+      Statement* s = Statement::make_assignment(lhs, rhs, loc);
+      b->add_statement(s);
+    }
+  else
+    {
+      const source_location bloc = BUILTINS_LOCATION;
+
+      // func {efacetype,ifacetype}(*interface) *descriptor
+      // FIXME: This should be inlined.
+      Typed_identifier_list* param_types = new Typed_identifier_list();
+      param_types->push_back(Typed_identifier("i", val_type, bloc));
+      Typed_identifier_list* ret_types = new Typed_identifier_list();
+      ret_types->push_back(Typed_identifier("", descriptor_type, bloc));
+      Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                      ret_types, bloc);
+      bool is_empty = val_type->interface_type()->is_empty();
+      const char* fnname = is_empty ? "efacetype" : "ifacetype";
+      Named_object* fn =
+       Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
+      const char* asm_name = (is_empty
+                             ? "runtime.efacetype"
+                             : "runtime.ifacetype");
+      fn->func_declaration_value()->set_asm_name(asm_name);
+
+      // descriptor_temp = ifacetype(val_temp)
+      Expression* func = Expression::make_func_reference(fn, NULL, loc);
+      Expression_list* params = new Expression_list();
+      Expression* ref;
+      if (this->var_ == NULL)
+       ref = this->expr_;
+      else
+       ref = Expression::make_var_reference(this->var_, loc);
+      params->push_back(ref);
+      Expression* call = Expression::make_call(func, params, false, loc);
+      Expression* lhs = Expression::make_temporary_reference(descriptor_temp,
+                                                            loc);
+      Statement* s = Statement::make_assignment(lhs, call, loc);
+      b->add_statement(s);
+    }
+
+  if (this->clauses_ != NULL)
+    this->clauses_->lower(b, descriptor_temp, this->break_label());
+
+  Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
+  b->add_statement(s);
+
+  return Statement::make_block_statement(b, loc);
+}
+
+// Return the break label for this type switch statement, creating it
+// if necessary.
+
+Unnamed_label*
+Type_switch_statement::break_label()
+{
+  if (this->break_label_ == NULL)
+    this->break_label_ = new Unnamed_label(this->location());
+  return this->break_label_;
+}
+
+// Make a type switch statement.
+
+Type_switch_statement*
+Statement::make_type_switch_statement(Named_object* var, Expression* expr,
+                                     source_location location)
+{
+  return new Type_switch_statement(var, expr, location);
+}
+
+// Class Select_clauses::Select_clause.
+
+// Traversal.
+
+int
+Select_clauses::Select_clause::traverse(Traverse* traverse)
+{
+  if (!this->is_lowered_
+      && (traverse->traverse_mask() & Traverse::traverse_expressions) != 0)
+    {
+      if (this->channel_ != NULL)
+       {
+         if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
+           return TRAVERSE_EXIT;
+       }
+      if (this->val_ != NULL)
+       {
+         if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
+           return TRAVERSE_EXIT;
+       }
+    }
+  if (this->statements_ != NULL)
+    {
+      if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Lowering.  Here we pull out the channel and the send values, to
+// enforce the order of evaluation.  We also add explicit send and
+// receive statements to the clauses.
+
+void
+Select_clauses::Select_clause::lower(Block* b)
+{
+  if (this->is_default_)
+    {
+      gcc_assert(this->channel_ == NULL && this->val_ == NULL);
+      this->is_lowered_ = true;
+      return;
+    }
+
+  source_location loc = this->location_;
+
+  // Evaluate the channel before the select statement.
+  Temporary_statement* channel_temp = Statement::make_temporary(NULL,
+                                                               this->channel_,
+                                                               loc);
+  b->add_statement(channel_temp);
+  this->channel_ = Expression::make_temporary_reference(channel_temp, loc);
+
+  // If this is a send clause, evaluate the value to send before the
+  // select statement.
+  Temporary_statement* val_temp = NULL;
+  if (this->is_send_)
+    {
+      val_temp = Statement::make_temporary(NULL, this->val_, loc);
+      b->add_statement(val_temp);
+    }
+
+  // Add the send or receive before the rest of the statements if any.
+  Block *init = new Block(b, loc);
+  Expression* ref = Expression::make_temporary_reference(channel_temp, loc);
+  if (this->is_send_)
+    {
+      Expression* ref2 = Expression::make_temporary_reference(val_temp, loc);
+      Send_expression* send = Expression::make_send(ref, ref2, loc);
+      send->discarding_value();
+      send->set_for_select();
+      init->add_statement(Statement::make_statement(send));
+    }
+  else
+    {
+      Receive_expression* recv = Expression::make_receive(ref, loc);
+      recv->set_for_select();
+      if (this->val_ != NULL)
+       {
+         gcc_assert(this->var_ == NULL);
+         init->add_statement(Statement::make_assignment(this->val_, recv,
+                                                        loc));
+       }
+      else if (this->var_ != NULL)
+       {
+         this->var_->var_value()->set_init(recv);
+         this->var_->var_value()->clear_type_from_chan_element();
+       }
+      else
+       {
+         recv->discarding_value();
+         init->add_statement(Statement::make_statement(recv));
+       }
+    }
+
+  if (this->statements_ != NULL)
+    init->add_statement(Statement::make_block_statement(this->statements_,
+                                                       loc));
+
+  this->statements_ = init;
+
+  // Now all references should be handled through the statements, not
+  // through here.
+  this->is_lowered_ = true;
+  this->val_ = NULL;
+  this->var_ = NULL;
+}
+
+// Determine types.
+
+void
+Select_clauses::Select_clause::determine_types()
+{
+  gcc_assert(this->is_lowered_);
+  if (this->statements_ != NULL)
+    this->statements_->determine_types();
+}
+
+// Whether this clause may fall through to the statement which follows
+// the overall select statement.
+
+bool
+Select_clauses::Select_clause::may_fall_through() const
+{
+  if (this->statements_ == NULL)
+    return true;
+  return this->statements_->may_fall_through();
+}
+
+// Return a tree for the statements to execute.
+
+tree
+Select_clauses::Select_clause::get_statements_tree(Translate_context* context)
+{
+  if (this->statements_ == NULL)
+    return NULL_TREE;
+  return this->statements_->get_tree(context);
+}
+
+// Class Select_clauses.
+
+// Traversal.
+
+int
+Select_clauses::traverse(Traverse* traverse)
+{
+  for (Clauses::iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      if (p->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Lowering.  Here we pull out the channel and the send values, to
+// enforce the order of evaluation.  We also add explicit send and
+// receive statements to the clauses.
+
+void
+Select_clauses::lower(Block* b)
+{
+  for (Clauses::iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    p->lower(b);
+}
+
+// Determine types.
+
+void
+Select_clauses::determine_types()
+{
+  for (Clauses::iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    p->determine_types();
+}
+
+// Return whether these select clauses fall through to the statement
+// following the overall select statement.
+
+bool
+Select_clauses::may_fall_through() const
+{
+  for (Clauses::const_iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    if (p->may_fall_through())
+      return true;
+  return false;
+}
+
+// Return a tree.  We build a call to
+//   size_t __go_select(size_t count, _Bool has_default,
+//                      channel* channels, _Bool* is_send)
+//
+// There are COUNT entries in the CHANNELS and IS_SEND arrays.  The
+// value in the IS_SEND array is true for send, false for receive.
+// __go_select returns an integer from 0 to COUNT, inclusive.  A
+// return of 0 means that the default case should be run; this only
+// happens if HAS_DEFAULT is non-zero.  Otherwise the number indicates
+// the case to run.
+
+// FIXME: This doesn't handle channels which send interface types
+// where the receiver has a static type which matches that interface.
+
+tree
+Select_clauses::get_tree(Translate_context* context,
+                        Unnamed_label *break_label,
+                        source_location location)
+{
+  size_t count = this->clauses_.size();
+  VEC(constructor_elt, gc)* chan_init = VEC_alloc(constructor_elt, gc, count);
+  VEC(constructor_elt, gc)* is_send_init = VEC_alloc(constructor_elt, gc,
+                                                    count);
+  Select_clause* default_clause = NULL;
+  tree final_stmt_list = NULL_TREE;
+  tree channel_type_tree = NULL_TREE;
+
+  size_t i = 0;
+  for (Clauses::iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      if (p->is_default())
+       {
+         default_clause = &*p;
+         --count;
+         continue;
+       }
+
+      tree channel_tree = p->channel()->get_tree(context);
+      if (channel_tree == error_mark_node)
+       return error_mark_node;
+      channel_type_tree = TREE_TYPE(channel_tree);
+
+      constructor_elt* elt = VEC_quick_push(constructor_elt, chan_init, NULL);
+      elt->index = build_int_cstu(sizetype, i);
+      elt->value = channel_tree;
+
+      elt = VEC_quick_push(constructor_elt, is_send_init, NULL);
+      elt->index = build_int_cstu(sizetype, i);
+      elt->value = p->is_send() ? boolean_true_node : boolean_false_node;
+
+      ++i;
+    }
+  gcc_assert(i == count);
+
+  if (i == 0 && default_clause != NULL)
+    {
+      // There is only a default clause.
+      gcc_assert(final_stmt_list == NULL_TREE);
+      tree stmt_list = NULL_TREE;
+      append_to_statement_list(default_clause->get_statements_tree(context),
+                              &stmt_list);
+      append_to_statement_list(break_label->get_definition(), &stmt_list);
+      return stmt_list;
+    }
+
+  tree pointer_chan_type_tree = (channel_type_tree == NULL_TREE
+                                ? ptr_type_node
+                                : build_pointer_type(channel_type_tree));
+  tree chans_arg;
+  tree pointer_boolean_type_tree = build_pointer_type(boolean_type_node);
+  tree is_sends_arg;
+
+  if (i == 0)
+    {
+      chans_arg = fold_convert_loc(location, pointer_chan_type_tree,
+                                  null_pointer_node);
+      is_sends_arg = fold_convert_loc(location, pointer_boolean_type_tree,
+                                     null_pointer_node);
+    }
+  else
+    {
+      tree index_type_tree = build_index_type(size_int(count - 1));
+      tree chan_array_type_tree = build_array_type(channel_type_tree,
+                                                  index_type_tree);
+      tree chan_constructor = build_constructor(chan_array_type_tree,
+                                               chan_init);
+      tree chan_var = create_tmp_var(chan_array_type_tree, "CHAN");
+      DECL_IGNORED_P(chan_var) = 0;
+      DECL_INITIAL(chan_var) = chan_constructor;
+      DECL_SOURCE_LOCATION(chan_var) = location;
+      TREE_ADDRESSABLE(chan_var) = 1;
+      tree decl_expr = build1(DECL_EXPR, void_type_node, chan_var);
+      SET_EXPR_LOCATION(decl_expr, location);
+      append_to_statement_list(decl_expr, &final_stmt_list);
+
+      tree is_send_array_type_tree = build_array_type(boolean_type_node,
+                                                     index_type_tree);
+      tree is_send_constructor = build_constructor(is_send_array_type_tree,
+                                                  is_send_init);
+      tree is_send_var = create_tmp_var(is_send_array_type_tree, "ISSEND");
+      DECL_IGNORED_P(is_send_var) = 0;
+      DECL_INITIAL(is_send_var) = is_send_constructor;
+      DECL_SOURCE_LOCATION(is_send_var) = location;
+      TREE_ADDRESSABLE(is_send_var) = 1;
+      decl_expr = build1(DECL_EXPR, void_type_node, is_send_var);
+      SET_EXPR_LOCATION(decl_expr, location);
+      append_to_statement_list(decl_expr, &final_stmt_list);
+
+      chans_arg = fold_convert_loc(location, pointer_chan_type_tree,
+                                  build_fold_addr_expr_loc(location,
+                                                           chan_var));
+      is_sends_arg = fold_convert_loc(location, pointer_boolean_type_tree,
+                                     build_fold_addr_expr_loc(location,
+                                                              is_send_var));
+    }
+
+  static tree select_fndecl;
+  tree call = Gogo::call_builtin(&select_fndecl,
+                                location,
+                                "__go_select",
+                                4,
+                                sizetype,
+                                sizetype,
+                                size_int(count),
+                                boolean_type_node,
+                                (default_clause == NULL
+                                 ? boolean_false_node
+                                 : boolean_true_node),
+                                pointer_chan_type_tree,
+                                chans_arg,
+                                pointer_boolean_type_tree,
+                                is_sends_arg);
+
+  tree stmt_list = NULL_TREE;
+
+  if (default_clause != NULL)
+    this->add_clause_tree(context, 0, default_clause, break_label, &stmt_list);
+
+  i = 1;
+  for (Clauses::iterator p = this->clauses_.begin();
+       p != this->clauses_.end();
+       ++p)
+    {
+      if (!p->is_default())
+       {
+         this->add_clause_tree(context, i, &*p, break_label, &stmt_list);
+         ++i;
+       }
+    }
+
+  append_to_statement_list(break_label->get_definition(), &stmt_list);
+
+  tree switch_stmt = build3(SWITCH_EXPR, sizetype, call, stmt_list, NULL_TREE);
+  SET_EXPR_LOCATION(switch_stmt, location);
+  append_to_statement_list(switch_stmt, &final_stmt_list);
+
+  return final_stmt_list;
+}
+
+// Add the tree for CLAUSE to STMT_LIST.
+
+void
+Select_clauses::add_clause_tree(Translate_context* context, int case_index,
+                               Select_clause* clause,
+                               Unnamed_label* bottom_label, tree* stmt_list)
+{
+  tree label = create_artificial_label(clause->location());
+  append_to_statement_list(build3(CASE_LABEL_EXPR, void_type_node,
+                                 build_int_cst(sizetype, case_index),
+                                 NULL_TREE, label),
+                          stmt_list);
+  append_to_statement_list(clause->get_statements_tree(context), stmt_list);
+  tree g = bottom_label->get_goto(clause->statements() == NULL
+                                 ? clause->location()
+                                 : clause->statements()->end_location());
+  append_to_statement_list(g, stmt_list);
+}
+
+// Class Select_statement.
+
+// Return the break label for this switch statement, creating it if
+// necessary.
+
+Unnamed_label*
+Select_statement::break_label()
+{
+  if (this->break_label_ == NULL)
+    this->break_label_ = new Unnamed_label(this->location());
+  return this->break_label_;
+}
+
+// Lower a select statement.  This will still return a select
+// statement, but it will be modified to implement the order of
+// evaluation rules, and to include the send and receive statements as
+// explicit statements in the clauses.
+
+Statement*
+Select_statement::do_lower(Gogo*, Block* enclosing)
+{
+  if (this->is_lowered_)
+    return this;
+  Block* b = new Block(enclosing, this->location());
+  this->clauses_->lower(b);
+  this->is_lowered_ = true;
+  b->add_statement(this);
+  return Statement::make_block_statement(b, this->location());
+}
+
+// Return the tree for a select statement.
+
+tree
+Select_statement::do_get_tree(Translate_context* context)
+{
+  return this->clauses_->get_tree(context, this->break_label(),
+                                 this->location());
+}
+
+// Make a select statement.
+
+Select_statement*
+Statement::make_select_statement(source_location location)
+{
+  return new Select_statement(location);
+}
+
+// Class For_statement.
+
+// Traversal.
+
+int
+For_statement::do_traverse(Traverse* traverse)
+{
+  if (this->init_ != NULL)
+    {
+      if (this->init_->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  if (this->cond_ != NULL)
+    {
+      if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  if (this->post_ != NULL)
+    {
+      if (this->post_->traverse(traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return this->statements_->traverse(traverse);
+}
+
+// Lower a For_statement into if statements and gotos.  Getting rid of
+// complex statements make it easier to handle garbage collection.
+
+Statement*
+For_statement::do_lower(Gogo*, Block* enclosing)
+{
+  Statement* s;
+  source_location loc = this->location();
+
+  Block* b = new Block(enclosing, this->location());
+  if (this->init_ != NULL)
+    {
+      s = Statement::make_block_statement(this->init_,
+                                         this->init_->start_location());
+      b->add_statement(s);
+    }
+
+  Unnamed_label* entry = NULL;
+  if (this->cond_ != NULL)
+    {
+      entry = new Unnamed_label(this->location());
+      b->add_statement(Statement::make_goto_unnamed_statement(entry, loc));
+    }
+
+  Unnamed_label* top = new Unnamed_label(this->location());
+  b->add_statement(Statement::make_unnamed_label_statement(top));
+
+  s = Statement::make_block_statement(this->statements_,
+                                     this->statements_->start_location());
+  b->add_statement(s);
+
+  source_location end_loc = this->statements_->end_location();
+
+  Unnamed_label* cont = this->continue_label_;
+  if (cont != NULL)
+    b->add_statement(Statement::make_unnamed_label_statement(cont));
+
+  if (this->post_ != NULL)
+    {
+      s = Statement::make_block_statement(this->post_,
+                                         this->post_->start_location());
+      b->add_statement(s);
+      end_loc = this->post_->end_location();
+    }
+
+  if (this->cond_ == NULL)
+    b->add_statement(Statement::make_goto_unnamed_statement(top, end_loc));
+  else
+    {
+      b->add_statement(Statement::make_unnamed_label_statement(entry));
+
+      source_location cond_loc = this->cond_->location();
+      Block* then_block = new Block(b, cond_loc);
+      s = Statement::make_goto_unnamed_statement(top, cond_loc);
+      then_block->add_statement(s);
+
+      s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc);
+      b->add_statement(s);
+    }
+
+  Unnamed_label* brk = this->break_label_;
+  if (brk != NULL)
+    b->add_statement(Statement::make_unnamed_label_statement(brk));
+
+  b->set_end_location(end_loc);
+
+  return Statement::make_block_statement(b, loc);
+}
+
+// Return the break label, creating it if necessary.
+
+Unnamed_label*
+For_statement::break_label()
+{
+  if (this->break_label_ == NULL)
+    this->break_label_ = new Unnamed_label(this->location());
+  return this->break_label_;
+}
+
+// Return the continue LABEL_EXPR.
+
+Unnamed_label*
+For_statement::continue_label()
+{
+  if (this->continue_label_ == NULL)
+    this->continue_label_ = new Unnamed_label(this->location());
+  return this->continue_label_;
+}
+
+// Set the break and continue labels a for statement.  This is used
+// when lowering a for range statement.
+
+void
+For_statement::set_break_continue_labels(Unnamed_label* break_label,
+                                        Unnamed_label* continue_label)
+{
+  gcc_assert(this->break_label_ == NULL && this->continue_label_ == NULL);
+  this->break_label_ = break_label;
+  this->continue_label_ = continue_label;
+}
+
+// Make a for statement.
+
+For_statement*
+Statement::make_for_statement(Block* init, Expression* cond, Block* post,
+                             source_location location)
+{
+  return new For_statement(init, cond, post, location);
+}
+
+// Class For_range_statement.
+
+// Traversal.
+
+int
+For_range_statement::do_traverse(Traverse* traverse)
+{
+  if (this->traverse_expression(traverse, &this->index_var_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (this->value_var_ != NULL)
+    {
+      if (this->traverse_expression(traverse, &this->value_var_)
+         == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  if (this->traverse_expression(traverse, &this->range_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return this->statements_->traverse(traverse);
+}
+
+// Lower a for range statement.  For simplicity we lower this into a
+// for statement, which will then be lowered in turn to goto
+// statements.
+
+Statement*
+For_range_statement::do_lower(Gogo* gogo, Block* enclosing)
+{
+  Type* range_type = this->range_->type();
+  if (range_type->points_to() != NULL
+      && range_type->points_to()->array_type() != NULL
+      && !range_type->points_to()->is_open_array_type())
+    range_type = range_type->points_to();
+
+  Type* index_type;
+  Type* value_type = NULL;
+  if (range_type->array_type() != NULL)
+    {
+      index_type = Type::lookup_integer_type("int");
+      value_type = range_type->array_type()->element_type();
+    }
+  else if (range_type->is_string_type())
+    {
+      index_type = Type::lookup_integer_type("int");
+      value_type = index_type;
+    }
+  else if (range_type->map_type() != NULL)
+    {
+      index_type = range_type->map_type()->key_type();
+      value_type = range_type->map_type()->val_type();
+    }
+  else if (range_type->channel_type() != NULL)
+    {
+      index_type = range_type->channel_type()->element_type();
+      if (this->value_var_ != NULL)
+       {
+         if (!this->value_var_->type()->is_error_type())
+           this->report_error(_("too many variables for range clause "
+                                "with channel"));
+         return Statement::make_error_statement(this->location());
+       }
+    }
+  else
+    {
+      this->report_error(_("range clause must have "
+                          "array, slice, setring, map, or channel type"));
+      return Statement::make_error_statement(this->location());
+    }
+
+  source_location loc = this->location();
+  Block* temp_block = new Block(enclosing, loc);
+
+  Named_object* range_object = NULL;
+  Temporary_statement* range_temp = NULL;
+  Var_expression* ve = this->range_->var_expression();
+  if (ve != NULL)
+    range_object = ve->named_object();
+  else
+    {
+      range_temp = Statement::make_temporary(NULL, this->range_, loc);
+      temp_block->add_statement(range_temp);
+    }
+
+  Temporary_statement* index_temp = Statement::make_temporary(index_type,
+                                                             NULL, loc);
+  temp_block->add_statement(index_temp);
+
+  Temporary_statement* value_temp = NULL;
+  if (this->value_var_ != NULL)
+    {
+      value_temp = Statement::make_temporary(value_type, NULL, loc);
+      temp_block->add_statement(value_temp);
+    }
+
+  Block* body = new Block(temp_block, loc);
+
+  Block* init;
+  Expression* cond;
+  Block* iter_init;
+  Block* post;
+
+  // Arrange to do a loop appropriate for the type.  We will produce
+  //   for INIT ; COND ; POST {
+  //           ITER_INIT
+  //           INDEX = INDEX_TEMP
+  //           VALUE = VALUE_TEMP // If there is a value
+  //           original statements
+  //   }
+
+  if (range_type->array_type() != NULL)
+    this->lower_range_array(gogo, temp_block, body, range_object, range_temp,
+                           index_temp, value_temp, &init, &cond, &iter_init,
+                           &post);
+  else if (range_type->is_string_type())
+    this->lower_range_string(gogo, temp_block, body, range_object, range_temp,
+                            index_temp, value_temp, &init, &cond, &iter_init,
+                            &post);
+  else if (range_type->map_type() != NULL)
+    this->lower_range_map(gogo, temp_block, body, range_object, range_temp,
+                         index_temp, value_temp, &init, &cond, &iter_init,
+                         &post);
+  else if (range_type->channel_type() != NULL)
+    this->lower_range_channel(gogo, temp_block, body, range_object, range_temp,
+                             index_temp, value_temp, &init, &cond, &iter_init,
+                             &post);
+  else
+    gcc_unreachable();
+
+  if (iter_init != NULL)
+    body->add_statement(Statement::make_block_statement(iter_init, loc));
+
+  Statement* assign;
+  Expression* index_ref = Expression::make_temporary_reference(index_temp, loc);
+  if (this->value_var_ == NULL)
+    {
+      assign = Statement::make_assignment(this->index_var_, index_ref, loc);
+    }
+  else
+    {
+      Expression_list* lhs = new Expression_list();
+      lhs->push_back(this->index_var_);
+      lhs->push_back(this->value_var_);
+
+      Expression_list* rhs = new Expression_list();
+      rhs->push_back(index_ref);
+      rhs->push_back(Expression::make_temporary_reference(value_temp, loc));
+
+      assign = Statement::make_tuple_assignment(lhs, rhs, loc);
+    }
+  body->add_statement(assign);
+
+  body->add_statement(Statement::make_block_statement(this->statements_, loc));
+
+  body->set_end_location(this->statements_->end_location());
+
+  For_statement* loop = Statement::make_for_statement(init, cond, post,
+                                                     this->location());
+  loop->add_statements(body);
+  loop->set_break_continue_labels(this->break_label_, this->continue_label_);
+
+  temp_block->add_statement(loop);
+
+  return Statement::make_block_statement(temp_block, loc);
+}
+
+// Return a reference to the range, which may be in RANGE_OBJECT or in
+// RANGE_TEMP.
+
+Expression*
+For_range_statement::make_range_ref(Named_object* range_object,
+                                   Temporary_statement* range_temp,
+                                   source_location loc)
+{
+  if (range_object != NULL)
+    return Expression::make_var_reference(range_object, loc);
+  else
+    return Expression::make_temporary_reference(range_temp, loc);
+}
+
+// Return a call to the predeclared function FUNCNAME passing a
+// reference to the temporary variable ARG.
+
+Expression*
+For_range_statement::call_builtin(Gogo* gogo, const char* funcname,
+                                 Expression* arg,
+                                 source_location loc)
+{
+  Named_object* no = gogo->lookup_global(funcname);
+  gcc_assert(no != NULL && no->is_function_declaration());
+  Expression* func = Expression::make_func_reference(no, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(arg);
+  return Expression::make_call(func, params, false, loc);
+}
+
+// Lower a for range over an array or slice.
+
+void
+For_range_statement::lower_range_array(Gogo* gogo,
+                                      Block* enclosing,
+                                      Block* body_block,
+                                      Named_object* range_object,
+                                      Temporary_statement* range_temp,
+                                      Temporary_statement* index_temp,
+                                      Temporary_statement* value_temp,
+                                      Block** pinit,
+                                      Expression** pcond,
+                                      Block** piter_init,
+                                      Block** ppost)
+{
+  source_location loc = this->location();
+
+  // The loop we generate:
+  //   len_temp := len(range)
+  //   for index_temp = 0; index_temp < len_temp; index_temp++ {
+  //           value_temp = range[index_temp]
+  //           index = index_temp
+  //           value = value_temp
+  //           original body
+  //   }
+
+  // Set *PINIT to
+  //   var len_temp int
+  //   len_temp = len(range)
+  //   index_temp = 0
+
+  Block* init = new Block(enclosing, loc);
+
+  Expression* ref = this->make_range_ref(range_object, range_temp, loc);
+  Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
+  Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
+                                                           len_call, loc);
+  init->add_statement(len_temp);
+
+  mpz_t zval;
+  mpz_init_set_ui(zval, 0UL);
+  Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
+  mpz_clear(zval);
+
+  ref = Expression::make_temporary_reference(index_temp, loc);
+  Statement* s = Statement::make_assignment(ref, zexpr, loc);
+  init->add_statement(s);
+
+  *pinit = init;
+
+  // Set *PCOND to
+  //   index_temp < len_temp
+
+  ref = Expression::make_temporary_reference(index_temp, loc);
+  Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
+  Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
+
+  *pcond = lt;
+
+  // Set *PITER_INIT to
+  //   value_temp = range[index_temp]
+
+  Block* iter_init = NULL;
+  if (value_temp != NULL)
+    {
+      iter_init = new Block(body_block, loc);
+
+      ref = this->make_range_ref(range_object, range_temp, loc);
+      Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
+      Expression* index = Expression::make_index(ref, ref2, NULL, loc);
+
+      ref = Expression::make_temporary_reference(value_temp, loc);
+      s = Statement::make_assignment(ref, index, loc);
+
+      iter_init->add_statement(s);
+    }
+  *piter_init = iter_init;
+
+  // Set *PPOST to
+  //   index_temp++
+
+  Block* post = new Block(enclosing, loc);
+  ref = Expression::make_temporary_reference(index_temp, loc);
+  s = Statement::make_inc_statement(ref);
+  post->add_statement(s);
+  *ppost = post;
+}
+
+// Lower a for range over a string.
+
+void
+For_range_statement::lower_range_string(Gogo* gogo,
+                                       Block* enclosing,
+                                       Block* body_block,
+                                       Named_object* range_object,
+                                       Temporary_statement* range_temp,
+                                       Temporary_statement* index_temp,
+                                       Temporary_statement* value_temp,
+                                       Block** pinit,
+                                       Expression** pcond,
+                                       Block** piter_init,
+                                       Block** ppost)
+{
+  source_location loc = this->location();
+
+  // The loop we generate:
+  //   var next_index_temp int
+  //   for index_temp = 0; ; index_temp = next_index_temp {
+  //           next_index_temp, value_temp = stringiter2(range, index_temp)
+  //           if next_index_temp == 0 {
+  //                   break
+  //           }
+  //           index = index_temp
+  //           value = value_temp
+  //           original body
+  //   }
+
+  // Set *PINIT to
+  //   var next_index_temp int
+  //   index_temp = 0
+
+  Block* init = new Block(enclosing, loc);
+
+  Temporary_statement* next_index_temp =
+    Statement::make_temporary(index_temp->type(), NULL, loc);
+  init->add_statement(next_index_temp);
+
+  mpz_t zval;
+  mpz_init_set_ui(zval, 0UL);
+  Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
+
+  Expression* ref = Expression::make_temporary_reference(index_temp, loc);
+  Statement* s = Statement::make_assignment(ref, zexpr, loc);
+
+  init->add_statement(s);
+  *pinit = init;
+
+  // The loop has no condition.
+
+  *pcond = NULL;
+
+  // Set *PITER_INIT to
+  //   next_index_temp = runtime.stringiter(range, index_temp)
+  // or
+  //   next_index_temp, value_temp = runtime.stringiter2(range, index_temp)
+  // followed by
+  //   if next_index_temp == 0 {
+  //           break
+  //   }
+
+  Block* iter_init = new Block(body_block, loc);
+
+  Named_object* no;
+  if (value_temp == NULL)
+    {
+      static Named_object* stringiter;
+      if (stringiter == NULL)
+       {
+         source_location bloc = BUILTINS_LOCATION;
+         Type* int_type = gogo->lookup_global("int")->type_value();
+
+         Typed_identifier_list* params = new Typed_identifier_list();
+         params->push_back(Typed_identifier("s", Type::make_string_type(),
+                                            bloc));
+         params->push_back(Typed_identifier("k", int_type, bloc));
+
+         Typed_identifier_list* results = new Typed_identifier_list();
+         results->push_back(Typed_identifier("", int_type, bloc));
+
+         Function_type* fntype = Type::make_function_type(NULL, params,
+                                                          results, bloc);
+         stringiter = Named_object::make_function_declaration("stringiter",
+                                                              NULL, fntype,
+                                                              bloc);
+         const char* n = "runtime.stringiter";
+         stringiter->func_declaration_value()->set_asm_name(n);
+       }
+      no = stringiter;
+    }
+  else
+    {
+      static Named_object* stringiter2;
+      if (stringiter2 == NULL)
+       {
+         source_location bloc = BUILTINS_LOCATION;
+         Type* int_type = gogo->lookup_global("int")->type_value();
+
+         Typed_identifier_list* params = new Typed_identifier_list();
+         params->push_back(Typed_identifier("s", Type::make_string_type(),
+                                            bloc));
+         params->push_back(Typed_identifier("k", int_type, bloc));
+
+         Typed_identifier_list* results = new Typed_identifier_list();
+         results->push_back(Typed_identifier("", int_type, bloc));
+         results->push_back(Typed_identifier("", int_type, bloc));
+
+         Function_type* fntype = Type::make_function_type(NULL, params,
+                                                          results, bloc);
+         stringiter2 = Named_object::make_function_declaration("stringiter",
+                                                               NULL, fntype,
+                                                               bloc);
+         const char* n = "runtime.stringiter2";
+         stringiter2->func_declaration_value()->set_asm_name(n);
+       }
+      no = stringiter2;
+    }
+
+  Expression* func = Expression::make_func_reference(no, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(this->make_range_ref(range_object, range_temp, loc));
+  params->push_back(Expression::make_temporary_reference(index_temp, loc));
+  Call_expression* call = Expression::make_call(func, params, false, loc);
+
+  if (value_temp == NULL)
+    {
+      ref = Expression::make_temporary_reference(next_index_temp, loc);
+      s = Statement::make_assignment(ref, call, loc);
+    }
+  else
+    {
+      Expression_list* lhs = new Expression_list();
+      lhs->push_back(Expression::make_temporary_reference(next_index_temp,
+                                                         loc));
+      lhs->push_back(Expression::make_temporary_reference(value_temp, loc));
+
+      Expression_list* rhs = new Expression_list();
+      rhs->push_back(Expression::make_call_result(call, 0));
+      rhs->push_back(Expression::make_call_result(call, 1));
+
+      s = Statement::make_tuple_assignment(lhs, rhs, loc);
+    }
+  iter_init->add_statement(s);
+
+  ref = Expression::make_temporary_reference(next_index_temp, loc);
+  zexpr = Expression::make_integer(&zval, NULL, loc);
+  mpz_clear(zval);
+  Expression* equals = Expression::make_binary(OPERATOR_EQEQ, ref, zexpr, loc);
+
+  Block* then_block = new Block(iter_init, loc);
+  s = Statement::make_break_statement(this->break_label(), loc);
+  then_block->add_statement(s);
+
+  s = Statement::make_if_statement(equals, then_block, NULL, loc);
+  iter_init->add_statement(s);
+
+  *piter_init = iter_init;
+
+  // Set *PPOST to
+  //   index_temp = next_index_temp
+
+  Block* post = new Block(enclosing, loc);
+
+  Expression* lhs = Expression::make_temporary_reference(index_temp, loc);
+  Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
+  s = Statement::make_assignment(lhs, rhs, loc);
+
+  post->add_statement(s);
+  *ppost = post;
+}
+
+// Lower a for range over a map.
+
+void
+For_range_statement::lower_range_map(Gogo* gogo,
+                                    Block* enclosing,
+                                    Block* body_block,
+                                    Named_object* range_object,
+                                    Temporary_statement* range_temp,
+                                    Temporary_statement* index_temp,
+                                    Temporary_statement* value_temp,
+                                    Block** pinit,
+                                    Expression** pcond,
+                                    Block** piter_init,
+                                    Block** ppost)
+{
+  source_location loc = this->location();
+
+  // The runtime uses a struct to handle ranges over a map.  The
+  // struct is four pointers long.  The first pointer is NULL when we
+  // have completed the iteration.
+
+  // The loop we generate:
+  //   var hiter map_iteration_struct
+  //   for mapiterinit(range, &hiter); hiter[0] != nil; mapiternext(&hiter) {
+  //           mapiter2(hiter, &index_temp, &value_temp)
+  //           index = index_temp
+  //           value = value_temp
+  //           original body
+  //   }
+
+  // Set *PINIT to
+  //   var hiter map_iteration_struct
+  //   runtime.mapiterinit(range, &hiter)
+
+  Block* init = new Block(enclosing, loc);
+
+  const unsigned long map_iteration_size = 4;
+
+  mpz_t ival;
+  mpz_init_set_ui(ival, map_iteration_size);
+  Expression* iexpr = Expression::make_integer(&ival, NULL, loc);
+  mpz_clear(ival);
+
+  Type* byte_type = gogo->lookup_global("byte")->type_value();
+  Type* ptr_type = Type::make_pointer_type(byte_type);
+
+  Type* map_iteration_type = Type::make_array_type(ptr_type, iexpr);
+  Type* map_iteration_ptr = Type::make_pointer_type(map_iteration_type);
+
+  Temporary_statement* hiter = Statement::make_temporary(map_iteration_type,
+                                                        NULL, loc);
+  init->add_statement(hiter);
+
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("map", this->range_->type(), bloc));
+  param_types->push_back(Typed_identifier("it", map_iteration_ptr, bloc));
+  Function_type* fntype = Type::make_function_type(NULL, param_types, NULL,
+                                                  bloc);
+
+  Named_object* mapiterinit =
+    Named_object::make_function_declaration("mapiterinit", NULL, fntype, bloc);
+  const char* n = "runtime.mapiterinit";
+  mapiterinit->func_declaration_value()->set_asm_name(n);
+
+  Expression* func = Expression::make_func_reference(mapiterinit, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(this->make_range_ref(range_object, range_temp, loc));
+  Expression* ref = Expression::make_temporary_reference(hiter, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  Expression* call = Expression::make_call(func, params, false, loc);
+  init->add_statement(Statement::make_statement(call));
+
+  *pinit = init;
+
+  // Set *PCOND to
+  //   hiter[0] != nil
+
+  ref = Expression::make_temporary_reference(hiter, loc);
+
+  mpz_t zval;
+  mpz_init_set_ui(zval, 0UL);
+  Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
+  mpz_clear(zval);
+
+  Expression* index = Expression::make_index(ref, zexpr, NULL, loc);
+
+  Expression* ne = Expression::make_binary(OPERATOR_NOTEQ, index,
+                                          Expression::make_nil(loc),
+                                          loc);
+
+  *pcond = ne;
+
+  // Set *PITER_INIT to
+  //   mapiter1(hiter, &index_temp)
+  // or
+  //   mapiter2(hiter, &index_temp, &value_temp)
+
+  Block* iter_init = new Block(body_block, loc);
+
+  param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("hiter", map_iteration_ptr, bloc));
+  Type* pkey_type = Type::make_pointer_type(index_temp->type());
+  param_types->push_back(Typed_identifier("key", pkey_type, bloc));
+  if (value_temp != NULL)
+    {
+      Type* pval_type = Type::make_pointer_type(value_temp->type());
+      param_types->push_back(Typed_identifier("val", pval_type, bloc));
+    }
+  fntype = Type::make_function_type(NULL, param_types, NULL, bloc);
+  n = value_temp == NULL ? "mapiter1" : "mapiter2";
+  Named_object* mapiter = Named_object::make_function_declaration(n, NULL,
+                                                                 fntype, bloc);
+  n = value_temp == NULL ? "runtime.mapiter1" : "runtime.mapiter2";
+  mapiter->func_declaration_value()->set_asm_name(n);
+
+  func = Expression::make_func_reference(mapiter, NULL, loc);
+  params = new Expression_list();
+  ref = Expression::make_temporary_reference(hiter, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  ref = Expression::make_temporary_reference(index_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  if (value_temp != NULL)
+    {
+      ref = Expression::make_temporary_reference(value_temp, loc);
+      params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+    }
+  call = Expression::make_call(func, params, false, loc);
+  iter_init->add_statement(Statement::make_statement(call));
+
+  *piter_init = iter_init;
+
+  // Set *PPOST to
+  //   mapiternext(&hiter)
+
+  Block* post = new Block(enclosing, loc);
+
+  static Named_object* mapiternext;
+  if (mapiternext == NULL)
+    {
+      param_types = new Typed_identifier_list();
+      param_types->push_back(Typed_identifier("it", map_iteration_ptr, bloc));
+      fntype = Type::make_function_type(NULL, param_types, NULL, bloc);
+      mapiternext = Named_object::make_function_declaration("mapiternext",
+                                                           NULL, fntype,
+                                                           bloc);
+      const char* n = "runtime.mapiternext";
+      mapiternext->func_declaration_value()->set_asm_name(n);
+    }
+
+  func = Expression::make_func_reference(mapiternext, NULL, loc);
+  params = new Expression_list();
+  ref = Expression::make_temporary_reference(hiter, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  call = Expression::make_call(func, params, false, loc);
+  post->add_statement(Statement::make_statement(call));
+
+  *ppost = post;
+}
+
+// Lower a for range over a channel.
+
+void
+For_range_statement::lower_range_channel(Gogo* gogo,
+                                        Block*,
+                                        Block* body_block,
+                                        Named_object* range_object,
+                                        Temporary_statement* range_temp,
+                                        Temporary_statement* index_temp,
+                                        Temporary_statement* value_temp,
+                                        Block** pinit,
+                                        Expression** pcond,
+                                        Block** piter_init,
+                                        Block** ppost)
+{
+  gcc_assert(value_temp == NULL);
+
+  source_location loc = this->location();
+
+  // The loop we generate:
+  //   for {
+  //           index_temp = <-range
+  //           if closed(range) {
+  //                   break
+  //           }
+  //           index = index_temp
+  //           value = value_temp
+  //           original body
+  //   }
+
+  // We have no initialization code, no condition, and no post code.
+
+  *pinit = NULL;
+  *pcond = NULL;
+  *ppost = NULL;
+
+  // Set *PITER_INIT to
+  //   index_temp = <-range
+  //   if closed(range) {
+  //           break
+  //   }
+
+  Block* iter_init = new Block(body_block, loc);
+
+  Expression* ref = this->make_range_ref(range_object, range_temp, loc);
+  Expression* cond = this->call_builtin(gogo, "closed", ref, loc);
+
+  ref = this->make_range_ref(range_object, range_temp, loc);
+  Expression* recv = Expression::make_receive(ref, loc);
+  ref = Expression::make_temporary_reference(index_temp, loc);
+  Statement* s = Statement::make_assignment(ref, recv, loc);
+  iter_init->add_statement(s);
+
+  Block* then_block = new Block(iter_init, loc);
+  s = Statement::make_break_statement(this->break_label(), loc);
+  then_block->add_statement(s);
+
+  s = Statement::make_if_statement(cond, then_block, NULL, loc);
+  iter_init->add_statement(s);
+
+  *piter_init = iter_init;
+}
+
+// Return the break LABEL_EXPR.
+
+Unnamed_label*
+For_range_statement::break_label()
+{
+  if (this->break_label_ == NULL)
+    this->break_label_ = new Unnamed_label(this->location());
+  return this->break_label_;
+}
+
+// Return the continue LABEL_EXPR.
+
+Unnamed_label*
+For_range_statement::continue_label()
+{
+  if (this->continue_label_ == NULL)
+    this->continue_label_ = new Unnamed_label(this->location());
+  return this->continue_label_;
+}
+
+// Make a for statement with a range clause.
+
+For_range_statement*
+Statement::make_for_range_statement(Expression* index_var,
+                                   Expression* value_var,
+                                   Expression* range,
+                                   source_location location)
+{
+  return new For_range_statement(index_var, value_var, range, location);
+}
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
new file mode 100644 (file)
index 0000000..6ca586f
--- /dev/null
@@ -0,0 +1,1420 @@
+// statements.h -- Go frontend statements.     -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_STATEMENTS_H
+#define GO_STATEMENTS_H
+
+#include "operator.h"
+
+class Gogo;
+class Traverse;
+class Block;
+class Function;
+class Unnamed_label;
+class Temporary_statement;
+class Variable_declaration_statement;
+class Return_statement;
+class Thunk_statement;
+class Label_statement;
+class For_statement;
+class For_range_statement;
+class Switch_statement;
+class Type_switch_statement;
+class Select_statement;
+class Variable;
+class Named_object;
+class Label;
+class Translate_context;
+class Expression;
+class Expression_list;
+class Struct_type;
+class Call_expression;
+class Map_index_expression;
+class Receive_expression;
+class Case_clauses;
+class Type_case_clauses;
+class Select_clauses;
+class Typed_identifier_list;
+
+// This class is used to traverse assignments made by a statement
+// which makes assignments.
+
+class Traverse_assignments
+{
+ public:
+  Traverse_assignments()
+  { }
+
+  virtual ~Traverse_assignments()
+  { }
+
+  // This is called for a variable initialization.
+  virtual void
+  initialize_variable(Named_object*) = 0;
+
+  // This is called for each assignment made by the statement.  PLHS
+  // points to the left hand side, and PRHS points to the right hand
+  // side.  PRHS may be NULL if there is no associated expression, as
+  // in the bool set by a non-blocking receive.
+  virtual void
+  assignment(Expression** plhs, Expression** prhs) = 0;
+
+  // This is called for each expression which is not passed to the
+  // assignment function.  This is used for some of the statements
+  // which assign two values, for which there is no expression which
+  // describes the value.  For ++ and -- the value is passed to both
+  // the assignment method and the rhs method.  IS_STORED is true if
+  // this value is being stored directly.  It is false if the value is
+  // computed but not stored.  IS_LOCAL is true if the value is being
+  // stored in a local variable or this is being called by a return
+  // statement.
+  virtual void
+  value(Expression**, bool is_stored, bool is_local) = 0;
+};
+
+// A single statement.
+
+class Statement
+{
+ public:
+  // The types of statements.
+  enum Statement_classification
+  {
+    STATEMENT_ERROR,
+    STATEMENT_VARIABLE_DECLARATION,
+    STATEMENT_TEMPORARY,
+    STATEMENT_ASSIGNMENT,
+    STATEMENT_EXPRESSION,
+    STATEMENT_BLOCK,
+    STATEMENT_GO,
+    STATEMENT_DEFER,
+    STATEMENT_RETURN,
+    STATEMENT_BREAK_OR_CONTINUE,
+    STATEMENT_GOTO,
+    STATEMENT_GOTO_UNNAMED,
+    STATEMENT_LABEL,
+    STATEMENT_UNNAMED_LABEL,
+    STATEMENT_IF,
+    STATEMENT_CONSTANT_SWITCH,
+    STATEMENT_SELECT,
+
+    // These statements types are created by the parser, but they
+    // disappear during the lowering pass.
+    STATEMENT_ASSIGNMENT_OPERATION,
+    STATEMENT_TUPLE_ASSIGNMENT,
+    STATEMENT_TUPLE_MAP_ASSIGNMENT,
+    STATEMENT_MAP_ASSIGNMENT,
+    STATEMENT_TUPLE_RECEIVE_ASSIGNMENT,
+    STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT,
+    STATEMENT_INCDEC,
+    STATEMENT_FOR,
+    STATEMENT_FOR_RANGE,
+    STATEMENT_SWITCH,
+    STATEMENT_TYPE_SWITCH
+  };
+
+  Statement(Statement_classification, source_location);
+
+  virtual ~Statement();
+
+  // Make a variable declaration.
+  static Statement*
+  make_variable_declaration(Named_object*);
+
+  // Make a statement which creates a temporary variable and
+  // initializes it to an expression.  The block is used if the
+  // temporary variable has to be explicitly destroyed; the variable
+  // must still be added to the block.  References to the temporary
+  // variable may be constructed using make_temporary_reference.
+  // Either the type or the initialization expression may be NULL, but
+  // not both.
+  static Temporary_statement*
+  make_temporary(Type*, Expression*, source_location);
+
+  // Make an assignment statement.
+  static Statement*
+  make_assignment(Expression*, Expression*, source_location);
+
+  // Make an assignment operation (+=, etc.).
+  static Statement*
+  make_assignment_operation(Operator, Expression*, Expression*,
+                           source_location);
+
+  // Make a tuple assignment statement.
+  static Statement*
+  make_tuple_assignment(Expression_list*, Expression_list*, source_location);
+
+  // Make an assignment from a map index to a pair of variables.
+  static Statement*
+  make_tuple_map_assignment(Expression* val, Expression* present,
+                           Expression*, source_location);
+
+  // Make a statement which assigns a pair of values to a map.
+  static Statement*
+  make_map_assignment(Expression*, Expression* val,
+                     Expression* should_set, source_location);
+
+  // Make an assignment from a nonblocking receive to a pair of
+  // variables.
+  static Statement*
+  make_tuple_receive_assignment(Expression* val, Expression* success,
+                               Expression* channel, source_location);
+
+  // Make an assignment from a type guard to a pair of variables.
+  static Statement*
+  make_tuple_type_guard_assignment(Expression* val, Expression* ok,
+                                  Expression* expr, Type* type,
+                                  source_location);
+
+  // Make an expression statement from an Expression.
+  static Statement*
+  make_statement(Expression*);
+
+  // Make a block statement from a Block.  This is an embedded list of
+  // statements which may also include variable definitions.
+  static Statement*
+  make_block_statement(Block*, source_location);
+
+  // Make an increment statement.
+  static Statement*
+  make_inc_statement(Expression*);
+
+  // Make a decrement statement.
+  static Statement*
+  make_dec_statement(Expression*);
+
+  // Make a go statement.
+  static Statement*
+  make_go_statement(Call_expression* call, source_location);
+
+  // Make a defer statement.
+  static Statement*
+  make_defer_statement(Call_expression* call, source_location);
+
+  // Make a return statement.
+  static Statement*
+  make_return_statement(const Typed_identifier_list*, Expression_list*,
+                       source_location);
+
+  // Make a break statement.
+  static Statement*
+  make_break_statement(Unnamed_label* label, source_location);
+
+  // Make a continue statement.
+  static Statement*
+  make_continue_statement(Unnamed_label* label, source_location);
+
+  // Make a goto statement.
+  static Statement*
+  make_goto_statement(Label* label, source_location);
+
+  // Make a goto statement to an unnamed label.
+  static Statement*
+  make_goto_unnamed_statement(Unnamed_label* label, source_location);
+
+  // Make a label statement--where the label is defined.
+  static Statement*
+  make_label_statement(Label* label, source_location);
+
+  // Make an unnamed label statement--where the label is defined.
+  static Statement*
+  make_unnamed_label_statement(Unnamed_label* label);
+
+  // Make an if statement.
+  static Statement*
+  make_if_statement(Expression* cond, Block* then_block, Block* else_block,
+                   source_location);
+
+  // Make a switch statement.
+  static Switch_statement*
+  make_switch_statement(Expression* switch_val, source_location);
+
+  // Make a type switch statement.
+  static Type_switch_statement*
+  make_type_switch_statement(Named_object* var, Expression*, source_location);
+
+  // Make a select statement.
+  static Select_statement*
+  make_select_statement(source_location);
+
+  // Make a for statement.
+  static For_statement*
+  make_for_statement(Block* init, Expression* cond, Block* post,
+                    source_location location);
+
+  // Make a for statement with a range clause.
+  static For_range_statement*
+  make_for_range_statement(Expression* index_var, Expression* value_var,
+                          Expression* range, source_location);
+
+  // Return the statement classification.
+  Statement_classification
+  classification() const
+  { return this->classification_; }
+
+  // Get the statement location.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Traverse the tree.
+  int
+  traverse(Block*, size_t* index, Traverse*);
+
+  // Traverse the contents of this statement--the expressions and
+  // statements which it contains.
+  int
+  traverse_contents(Traverse*);
+
+  // If this statement assigns some values, it calls a function for
+  // each value to which this statement assigns a value, and returns
+  // true.  If this statement does not assign any values, it returns
+  // false.
+  bool
+  traverse_assignments(Traverse_assignments* tassign);
+
+  // Lower a statement.  This is called immediately after parsing to
+  // simplify statements for further processing.  It returns the same
+  // Statement or a new one.  BLOCK is the block containing this
+  // statement.
+  Statement*
+  lower(Gogo* gogo, Block* block)
+  { return this->do_lower(gogo, block); }
+
+  // Set type information for unnamed constants.
+  void
+  determine_types();
+
+  // Check types in a statement.  This simply checks that any
+  // expressions used by the statement have the right type.
+  void
+  check_types(Gogo* gogo)
+  { this->do_check_types(gogo); }
+
+  // Return whether this is a block statement.
+  bool
+  is_block_statement() const
+  { return this->classification_ == STATEMENT_BLOCK; }
+
+  // If this is a variable declaration statement, return it.
+  // Otherwise return NULL.
+  Variable_declaration_statement*
+  variable_declaration_statement()
+  {
+    return this->convert<Variable_declaration_statement,
+                        STATEMENT_VARIABLE_DECLARATION>();
+  }
+
+  // If this is a return statement, return it.  Otherwise return NULL.
+  Return_statement*
+  return_statement()
+  { return this->convert<Return_statement, STATEMENT_RETURN>(); }
+
+  // If this is a thunk statement (a go or defer statement), return
+  // it.  Otherwise return NULL.
+  Thunk_statement*
+  thunk_statement();
+
+  // If this is a label statement, return it.  Otherwise return NULL.
+  Label_statement*
+  label_statement()
+  { return this->convert<Label_statement, STATEMENT_LABEL>(); }
+
+  // If this is a for statement, return it.  Otherwise return NULL.
+  For_statement*
+  for_statement()
+  { return this->convert<For_statement, STATEMENT_FOR>(); }
+
+  // If this is a for statement over a range clause, return it.
+  // Otherwise return NULL.
+  For_range_statement*
+  for_range_statement()
+  { return this->convert<For_range_statement, STATEMENT_FOR_RANGE>(); }
+
+  // If this is a switch statement, return it.  Otherwise return NULL.
+  Switch_statement*
+  switch_statement()
+  { return this->convert<Switch_statement, STATEMENT_SWITCH>(); }
+
+  // If this is a type switch statement, return it.  Otherwise return
+  // NULL.
+  Type_switch_statement*
+  type_switch_statement()
+  { return this->convert<Type_switch_statement, STATEMENT_TYPE_SWITCH>(); }
+
+  // If this is a select statement, return it.  Otherwise return NULL.
+  Select_statement*
+  select_statement()
+  { return this->convert<Select_statement, STATEMENT_SELECT>(); }
+
+  // Return true if this statement may fall through--if after
+  // executing this statement we may go on to execute the following
+  // statement, if any.
+  bool
+  may_fall_through() const
+  { return this->do_may_fall_through(); }
+
+  // Return the tree for a statement.  BLOCK is the enclosing block.
+  tree
+  get_tree(Translate_context*);
+
+ protected:
+  // Implemented by child class: traverse the tree.
+  virtual int
+  do_traverse(Traverse*) = 0;
+
+  // Implemented by child class: traverse assignments.  Any statement
+  // which includes an assignment should implement this.
+  virtual bool
+  do_traverse_assignments(Traverse_assignments*)
+  { return false; }
+
+  // Implemented by the child class: lower this statement to a simpler
+  // one.
+  virtual Statement*
+  do_lower(Gogo*, Block*)
+  { return this; }
+
+  // Implemented by child class: set type information for unnamed
+  // constants.  Any statement which includes an expression needs to
+  // implement this.
+  virtual void
+  do_determine_types()
+  { }
+
+  // Implemented by child class: check types of expressions used in a
+  // statement.
+  virtual void
+  do_check_types(Gogo*)
+  { }
+
+  // Implemented by child class: return true if this statement may
+  // fall through.
+  virtual bool
+  do_may_fall_through() const
+  { return true; }
+
+  // Implemented by child class: return a tree.
+  virtual tree
+  do_get_tree(Translate_context*) = 0;
+
+  // Traverse an expression in a statement.
+  int
+  traverse_expression(Traverse*, Expression**);
+
+  // Traverse an expression list in a statement.  The Expression_list
+  // may be NULL.
+  int
+  traverse_expression_list(Traverse*, Expression_list*);
+
+  // Traverse a type in a statement.
+  int
+  traverse_type(Traverse*, Type*);
+
+  // Build a tree node with one operand, setting the location.  The
+  // first operand really has type "enum tree_code", but that enum is
+  // not defined here.
+  tree
+  build_stmt_1(int tree_code_value, tree);
+
+  // For children to call when they detect that they are in error.
+  void
+  set_is_error();
+
+  // For children to call to report an error conveniently.
+  void
+  report_error(const char*);
+
+  // For children to return an error statement from lower().
+  static Statement*
+  make_error_statement(source_location);
+
+ private:
+  // Convert to the desired statement classification, or return NULL.
+  // This is a controlled dynamic cast.
+  template<typename Statement_class, Statement_classification sc>
+  Statement_class*
+  convert()
+  {
+    return (this->classification_ == sc
+           ? static_cast<Statement_class*>(this)
+           : NULL);
+  }
+
+  template<typename Statement_class, Statement_classification sc>
+  const Statement_class*
+  convert() const
+  {
+    return (this->classification_ == sc
+           ? static_cast<const Statement_class*>(this)
+           : NULL);
+  }
+
+  // The statement classification.
+  Statement_classification classification_;
+  // The location in the input file of the start of this statement.
+  source_location location_;
+};
+
+// A statement which creates and initializes a temporary variable.
+
+class Temporary_statement : public Statement
+{
+ public:
+  Temporary_statement(Type* type, Expression* init, source_location location)
+    : Statement(STATEMENT_TEMPORARY, location),
+      type_(type), init_(init), decl_(NULL), is_address_taken_(false)
+  { }
+
+  // Return the type of the temporary variable.
+  Type*
+  type() const;
+
+  // Return the initialization expression.
+  Expression*
+  init() const
+  { return this->init_; }
+
+  // Record that something takes the address of this temporary
+  // variable.
+  void
+  set_is_address_taken()
+  { this->is_address_taken_ = true; }
+
+  // Return the tree for the temporary variable itself.  This should
+  // not be called until after the statement itself has been expanded.
+  tree
+  get_decl() const
+  {
+    gcc_assert(this->decl_ != NULL);
+    return this->decl_;
+  }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*);
+
+  void
+  do_determine_types();
+
+  void
+  do_check_types(Gogo*);
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The type of the temporary variable.
+  Type* type_;
+  // The initial value of the temporary variable.  This may be NULL.
+  Expression* init_;
+  // The DECL for the temporary variable.
+  tree decl_;
+  // True if something takes the address of this temporary variable.
+  bool is_address_taken_;
+};
+
+// A variable declaration.  This marks the point in the code where a
+// variable is declared.  The Variable is also attached to a Block.
+
+class Variable_declaration_statement : public Statement
+{
+ public:
+  Variable_declaration_statement(Named_object* var);
+
+  // The variable being declared.
+  Named_object*
+  var()
+  { return this->var_; }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*);
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  Named_object* var_;
+};
+
+// A return statement.
+
+class Return_statement : public Statement
+{
+ public:
+  Return_statement(const Typed_identifier_list* results, Expression_list* vals,
+                  source_location location)
+    : Statement(STATEMENT_RETURN, location),
+      results_(results), vals_(vals)
+  { }
+
+  // The list of values being returned.  This may be NULL.
+  const Expression_list*
+  vals() const
+  { return this->vals_; }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return this->traverse_expression_list(traverse, this->vals_); }
+
+  bool
+  do_traverse_assignments(Traverse_assignments*);
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  void
+  do_determine_types();
+
+  void
+  do_check_types(Gogo*);
+
+  bool
+  do_may_fall_through() const
+  { return false; }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The result types of the function we are returning from.  This is
+  // here because in some of the traversals it is inconvenient to get
+  // it.
+  const Typed_identifier_list* results_;
+  // Return values.  This may be NULL.
+  Expression_list* vals_;
+};
+
+// Select_clauses holds the clauses of a select statement.  This is
+// built by the parser.
+
+class Select_clauses
+{
+ public:
+  Select_clauses()
+    : clauses_()
+  { }
+
+  // Add a new clause.  IS_SEND is true if this is a send clause,
+  // false for a receive clause.  For a send clause CHANNEL is the
+  // channel and VAL is the value to send.  For a receive clause
+  // CHANNEL is the channel and VAL is either NULL or a Var_expression
+  // for the variable to set; if VAL is NULL, VAR may be a variable
+  // which is initialized with the received value.  IS_DEFAULT is true
+  // if this is the default clause.  STATEMENTS is the list of
+  // statements to execute.
+  void
+  add(bool is_send, Expression* channel, Expression* val, Named_object* var,
+      bool is_default, Block* statements, source_location location)
+  {
+    this->clauses_.push_back(Select_clause(is_send, channel, val, var,
+                                          is_default, statements, location));
+  }
+
+  // Traverse the select clauses.
+  int
+  traverse(Traverse*);
+
+  // Lower statements.
+  void
+  lower(Block*);
+
+  // Determine types.
+  void
+  determine_types();
+
+  // Whether the select clauses may fall through to the statement
+  // which follows the overall select statement.
+  bool
+  may_fall_through() const;
+
+  // Return a tree implementing the select statement.
+  tree
+  get_tree(Translate_context*, Unnamed_label* break_label, source_location);
+
+ private:
+  // A single clause.
+  class Select_clause
+  {
+   public:
+    Select_clause()
+      : channel_(NULL), val_(NULL), var_(NULL), statements_(NULL),
+       is_send_(false), is_default_(false)
+    { }
+
+    Select_clause(bool is_send, Expression* channel, Expression* val,
+                 Named_object* var, bool is_default, Block* statements,
+                 source_location location)
+      : channel_(channel), val_(val), var_(var), statements_(statements),
+       location_(location), is_send_(is_send), is_default_(is_default),
+       is_lowered_(false)
+    { gcc_assert(is_default ? channel == NULL : channel != NULL); }
+
+    // Traverse the select clause.
+    int
+    traverse(Traverse*);
+
+    // Lower statements.
+    void
+    lower(Block*);
+
+    // Determine types.
+    void
+    determine_types();
+
+    // Return true if this is the default clause.
+    bool
+    is_default() const
+    { return this->is_default_; }
+
+    // Return the channel.  This will return NULL for the default
+    // clause.
+    Expression*
+    channel() const
+    { return this->channel_; }
+
+    // Return the value.  This will return NULL for the default
+    // clause, or for a receive clause for which no value was given.
+    Expression*
+    val() const
+    { return this->val_; }
+
+    // Return the variable to set when a receive clause is also a
+    // variable definition (v := <- ch).  This will return NULL for
+    // the default case, or for a send clause, or for a receive clause
+    // which does not define a variable.
+    Named_object*
+    var() const
+    { return this->var_; }
+
+    // Return true for a send, false for a receive.
+    bool
+    is_send() const
+    {
+      gcc_assert(!this->is_default_);
+      return this->is_send_;
+    }
+
+    // Return the statements.
+    const Block*
+    statements() const
+    { return this->statements_; }
+
+    // Return the location.
+    source_location
+    location() const
+    { return this->location_; }
+
+    // Whether this clause may fall through to the statement which
+    // follows the overall select statement.
+    bool
+    may_fall_through() const;
+
+    // Return a tree for the statements to execute.
+    tree
+    get_statements_tree(Translate_context*);
+
+   private:
+    // The channel.
+    Expression* channel_;
+    // The value to send or the variable to set.
+    Expression* val_;
+    // The variable to initialize, for "case a := <- ch".
+    Named_object* var_;
+    // The statements to execute.
+    Block* statements_;
+    // The location of this clause.
+    source_location location_;
+    // Whether this is a send or a receive.
+    bool is_send_;
+    // Whether this is the default.
+    bool is_default_;
+    // Whether this has been lowered.
+    bool is_lowered_;
+  };
+
+  void
+  add_clause_tree(Translate_context*, int, Select_clause*, Unnamed_label*,
+                 tree*);
+
+  typedef std::vector<Select_clause> Clauses;
+
+  Clauses clauses_;
+};
+
+// A select statement.
+
+class Select_statement : public Statement
+{
+ public:
+  Select_statement(source_location location)
+    : Statement(STATEMENT_SELECT, location),
+      clauses_(NULL), break_label_(NULL), is_lowered_(false)
+  { }
+
+  // Add the clauses.
+  void
+  add_clauses(Select_clauses* clauses)
+  {
+    gcc_assert(this->clauses_ == NULL);
+    this->clauses_ = clauses;
+  }
+
+  // Return the break label for this select statement.
+  Unnamed_label*
+  break_label();
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return this->clauses_->traverse(traverse); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  void
+  do_determine_types()
+  { this->clauses_->determine_types(); }
+
+  bool
+  do_may_fall_through() const
+  { return this->clauses_->may_fall_through(); }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The select clauses.
+  Select_clauses* clauses_;
+  // The break label.
+  Unnamed_label* break_label_;
+  // Whether this statement has been lowered.
+  bool is_lowered_;
+};
+
+// A statement which requires a thunk: go or defer.
+
+class Thunk_statement : public Statement
+{
+ public:
+  Thunk_statement(Statement_classification, Call_expression*,
+                 source_location);
+
+  // Return the call expression.
+  Expression*
+  call()
+  { return this->call_; }
+
+  // Simplify a go or defer statement so that it only uses a single
+  // parameter.
+  bool
+  simplify_statement(Gogo*, Block*);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*);
+
+  void
+  do_determine_types();
+
+  void
+  do_check_types(Gogo*);
+
+  // Return the function and argument trees for the call.
+  void
+  get_fn_and_arg(Translate_context*, tree* pfn, tree* parg);
+
+ private:
+  // Return whether this is a simple go statement.
+  bool
+  is_simple(Function_type*) const;
+
+  // Build the struct to use for a complex case.
+  Struct_type*
+  build_struct(Function_type* fntype);
+
+  // Build the thunk.
+  void
+  build_thunk(Gogo*, const std::string&, Function_type* fntype);
+
+  // The field name used in the thunk structure for the function
+  // pointer.
+  static const char* const thunk_field_fn;
+
+  // The field name used in the thunk structure for the receiver, if
+  // there is one.
+  static const char* const thunk_field_receiver;
+
+  // Set the name to use for thunk field N.
+  void
+  thunk_field_param(int n, char* buf, size_t buflen);
+
+  // The function call to be executed in a separate thread (go) or
+  // later (defer).
+  Expression* call_;
+  // The type used for a struct to pass to a thunk, if this is not a
+  // simple call.
+  Struct_type* struct_type_;
+};
+
+// A go statement.
+
+class Go_statement : public Thunk_statement
+{
+ public:
+  Go_statement(Call_expression* call, source_location location)
+    : Thunk_statement(STATEMENT_GO, call, location)
+  { }
+
+ protected:
+  tree
+  do_get_tree(Translate_context*);
+};
+
+// A defer statement.
+
+class Defer_statement : public Thunk_statement
+{
+ public:
+  Defer_statement(Call_expression* call, source_location location)
+    : Thunk_statement(STATEMENT_DEFER, call, location)
+  { }
+
+ protected:
+  tree
+  do_get_tree(Translate_context*);
+};
+
+// A label statement.
+
+class Label_statement : public Statement
+{
+ public:
+  Label_statement(Label* label, source_location location)
+    : Statement(STATEMENT_LABEL, location),
+      label_(label)
+  { }
+
+  // Return the label itself.
+  const Label*
+  label() const
+  { return this->label_; }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The label.
+  Label* label_;
+};
+
+// A for statement.
+
+class For_statement : public Statement
+{
+ public:
+  For_statement(Block* init, Expression* cond, Block* post,
+               source_location location)
+    : Statement(STATEMENT_FOR, location),
+      init_(init), cond_(cond), post_(post), statements_(NULL),
+      break_label_(NULL), continue_label_(NULL)
+  { }
+
+  // Add the statements.
+  void
+  add_statements(Block* statements)
+  {
+    gcc_assert(this->statements_ == NULL);
+    this->statements_ = statements;
+  }
+
+  // Return the break label for this for statement.
+  Unnamed_label*
+  break_label();
+
+  // Return the continue label for this for statement.
+  Unnamed_label*
+  continue_label();
+
+  // Set the break and continue labels for this statement.
+  void
+  set_break_continue_labels(Unnamed_label* break_label,
+                           Unnamed_label* continue_label);
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // The initialization statements.  This may be NULL.
+  Block* init_;
+  // The condition.  This may be NULL.
+  Expression* cond_;
+  // The statements to run after each iteration.  This may be NULL.
+  Block* post_;
+  // The statements in the loop itself.
+  Block* statements_;
+  // The break label, if needed.
+  Unnamed_label* break_label_;
+  // The continue label, if needed.
+  Unnamed_label* continue_label_;
+};
+
+// A for statement over a range clause.
+
+class For_range_statement : public Statement
+{
+ public:
+  For_range_statement(Expression* index_var, Expression* value_var,
+                     Expression* range, source_location location)
+    : Statement(STATEMENT_FOR_RANGE, location),
+      index_var_(index_var), value_var_(value_var), range_(range),
+      statements_(NULL), break_label_(NULL), continue_label_(NULL)
+  { }
+
+  // Add the statements.
+  void
+  add_statements(Block* statements)
+  {
+    gcc_assert(this->statements_ == NULL);
+    this->statements_ = statements;
+  }
+
+  // Return the break label for this for statement.
+  Unnamed_label*
+  break_label();
+
+  // Return the continue label for this for statement.
+  Unnamed_label*
+  continue_label();
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  Expression*
+  make_range_ref(Named_object*, Temporary_statement*, source_location);
+
+  Expression*
+  call_builtin(Gogo*, const char* funcname, Expression* arg, source_location);
+
+  void
+  lower_range_array(Gogo*, Block*, Block*, Named_object*, Temporary_statement*,
+                   Temporary_statement*, Temporary_statement*,
+                   Block**, Expression**, Block**, Block**);
+
+  void
+  lower_range_string(Gogo*, Block*, Block*, Named_object*, Temporary_statement*,
+                    Temporary_statement*, Temporary_statement*,
+                    Block**, Expression**, Block**, Block**);
+
+  void
+  lower_range_map(Gogo*, Block*, Block*, Named_object*, Temporary_statement*,
+                 Temporary_statement*, Temporary_statement*,
+                 Block**, Expression**, Block**, Block**);
+
+  void
+  lower_range_channel(Gogo*, Block*, Block*, Named_object*,
+                     Temporary_statement*, Temporary_statement*,
+                     Temporary_statement*, Block**, Expression**, Block**,
+                     Block**);
+
+  // The variable which is set to the index value.
+  Expression* index_var_;
+  // The variable which is set to the element value.  This may be
+  // NULL.
+  Expression* value_var_;
+  // The expression we are ranging over.
+  Expression* range_;
+  // The statements in the block.
+  Block* statements_;
+  // The break label, if needed.
+  Unnamed_label* break_label_;
+  // The continue label, if needed.
+  Unnamed_label* continue_label_;
+};
+
+// Class Case_clauses holds the clauses of a switch statement.  This
+// is built by the parser.
+
+class Case_clauses
+{
+ public:
+  Case_clauses()
+    : clauses_()
+  { }
+
+  // Add a new clause.  CASES is a list of case expressions; it may be
+  // NULL.  IS_DEFAULT is true if this is the default case.
+  // STATEMENTS is a block of statements.  IS_FALLTHROUGH is true if
+  // after the statements the case clause should fall through to the
+  // next clause.
+  void
+  add(Expression_list* cases, bool is_default, Block* statements,
+      bool is_fallthrough, source_location location)
+  {
+    this->clauses_.push_back(Case_clause(cases, is_default, statements,
+                                        is_fallthrough, location));
+  }
+
+  // Return whether there are no clauses.
+  bool
+  empty() const
+  { return this->clauses_.empty(); }
+
+  // Traverse the case clauses.
+  int
+  traverse(Traverse*);
+
+  // Lower for a nonconstant switch.
+  void
+  lower(Block*, Temporary_statement*, Unnamed_label*) const;
+
+  // Determine types of expressions.  The Type parameter is the type
+  // of the switch value.
+  void
+  determine_types(Type*);
+
+  // Check types.  The Type parameter is the type of the switch value.
+  bool
+  check_types(Type*);
+
+  // Return true if all the clauses are constant values.
+  bool
+  is_constant() const;
+
+  // Return true if these clauses may fall through to the statements
+  // following the switch statement.
+  bool
+  may_fall_through() const;
+
+  // Return the body of a SWITCH_EXPR when all the clauses are
+  // constants.
+  tree
+  get_constant_tree(Translate_context*, Unnamed_label* break_label) const;
+
+ private:
+  // For a constant tree we need to keep a record of constants we have
+  // already seen.  Note that INTEGER_CST trees are interned.
+  typedef Unordered_set(tree) Case_constants;
+
+  // One case clause.
+  class Case_clause
+  {
+   public:
+    Case_clause()
+      : cases_(NULL), statements_(NULL), is_default_(false),
+       is_fallthrough_(false), location_(UNKNOWN_LOCATION)
+    { }
+
+    Case_clause(Expression_list* cases, bool is_default, Block* statements,
+               bool is_fallthrough, source_location location)
+      : cases_(cases), statements_(statements), is_default_(is_default),
+       is_fallthrough_(is_fallthrough), location_(location)
+    { }
+
+    // Whether this clause falls through to the next clause.
+    bool
+    is_fallthrough() const
+    { return this->is_fallthrough_; }
+
+    // Whether this is the default.
+    bool
+    is_default() const
+    { return this->is_default_; }
+
+    // The location of this clause.
+    source_location
+    location() const
+    { return this->location_; }
+
+    // Traversal.
+    int
+    traverse(Traverse*);
+
+    // Lower for a nonconstant switch.
+    void
+    lower(Block*, Temporary_statement*, Unnamed_label*, Unnamed_label*) const;
+
+    // Determine types.
+    void
+    determine_types(Type*);
+
+    // Check types.
+    bool
+    check_types(Type*);
+
+    // Return true if all the case expressions are constant.
+    bool
+    is_constant() const;
+
+    // Return true if this clause may fall through to execute the
+    // statements following the switch statement.  This is not the
+    // same as whether this clause falls through to the next clause.
+    bool
+    may_fall_through() const;
+
+    // Build up the body of a SWITCH_EXPR when the case expressions
+    // are constant.
+    void
+    get_constant_tree(Translate_context*, Unnamed_label* break_label,
+                     Case_constants* case_constants, tree* stmt_list) const;
+
+   private:
+    // The list of case expressions.
+    Expression_list* cases_;
+    // The statements to execute.
+    Block* statements_;
+    // Whether this is the default case.
+    bool is_default_;
+    // Whether this falls through after the statements.
+    bool is_fallthrough_;
+    // The location of this case clause.
+    source_location location_;
+  };
+
+  friend class Case_clause;
+
+  // The type of the list of clauses.
+  typedef std::vector<Case_clause> Clauses;
+
+  // All the case clauses.
+  Clauses clauses_;
+};
+
+// A switch statement.
+
+class Switch_statement : public Statement
+{
+ public:
+  Switch_statement(Expression* val, source_location location)
+    : Statement(STATEMENT_SWITCH, location),
+      val_(val), clauses_(NULL), break_label_(NULL)
+  { }
+
+  // Add the clauses.
+  void
+  add_clauses(Case_clauses* clauses)
+  {
+    gcc_assert(this->clauses_ == NULL);
+    this->clauses_ = clauses;
+  }
+
+  // Return the break label for this switch statement.
+  Unnamed_label*
+  break_label();
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // The value to switch on.  This may be NULL.
+  Expression* val_;
+  // The case clauses.
+  Case_clauses* clauses_;
+  // The break label, if needed.
+  Unnamed_label* break_label_;
+};
+
+// Class Type_case_clauses holds the clauses of a type switch
+// statement.  This is built by the parser.
+
+class Type_case_clauses
+{
+ public:
+  Type_case_clauses()
+    : clauses_()
+  { }
+
+  // Add a new clause.  TYPE is the type for this clause; it may be
+  // NULL.  IS_FALLTHROUGH is true if this falls through to the next
+  // clause; in this case STATEMENTS will be NULL.  IS_DEFAULT is true
+  // if this is the default case.  STATEMENTS is a block of
+  // statements; it may be NULL.
+  void
+  add(Type* type, bool is_fallthrough, bool is_default, Block* statements,
+      source_location location)
+  {
+    this->clauses_.push_back(Type_case_clause(type, is_fallthrough, is_default,
+                                             statements, location));
+  }
+
+  // Return whether there are no clauses.
+  bool
+  empty() const
+  { return this->clauses_.empty(); }
+
+  // Traverse the type case clauses.
+  int
+  traverse(Traverse*);
+
+  // Check for duplicates.
+  void
+  check_duplicates() const;
+
+  // Lower to if and goto statements.
+  void
+  lower(Block*, Temporary_statement* descriptor_temp,
+       Unnamed_label* break_label) const;
+
+ private:
+  // One type case clause.
+  class Type_case_clause
+  {
+   public:
+    Type_case_clause()
+      : type_(NULL), statements_(NULL), is_default_(false),
+       location_(UNKNOWN_LOCATION)
+    { }
+
+    Type_case_clause(Type* type, bool is_fallthrough, bool is_default,
+                    Block* statements, source_location location)
+      : type_(type), statements_(statements), is_fallthrough_(is_fallthrough),
+       is_default_(is_default), location_(location)
+    { }
+
+    // The type.
+    Type*
+    type() const
+    { return this->type_; }
+
+    // Whether this is the default.
+    bool
+    is_default() const
+    { return this->is_default_; }
+
+    // The location of this type clause.
+    source_location
+    location() const
+    { return this->location_; }
+
+    // Traversal.
+    int
+    traverse(Traverse*);
+
+    // Lower to if and goto statements.
+    void
+    lower(Block*, Temporary_statement* descriptor_temp,
+         Unnamed_label* break_label, Unnamed_label** stmts_label) const;
+
+   private:
+    // The type for this type clause.
+    Type* type_;
+    // The statements to execute.
+    Block* statements_;
+    // Whether this falls through--this is true for "case T1, T2".
+    bool is_fallthrough_;
+    // Whether this is the default case.
+    bool is_default_;
+    // The location of this type case clause.
+    source_location location_;
+  };
+
+  friend class Type_case_clause;
+
+  // The type of the list of type clauses.
+  typedef std::vector<Type_case_clause> Type_clauses;
+
+  // All the type case clauses.
+  Type_clauses clauses_;
+};
+
+// A type switch statement.
+
+class Type_switch_statement : public Statement
+{
+ public:
+  Type_switch_statement(Named_object* var, Expression* expr,
+                       source_location location)
+    : Statement(STATEMENT_TYPE_SWITCH, location),
+      var_(var), expr_(expr), clauses_(NULL), break_label_(NULL)
+  { gcc_assert(var == NULL || expr == NULL); }
+
+  // Add the clauses.
+  void
+  add_clauses(Type_case_clauses* clauses)
+  {
+    gcc_assert(this->clauses_ == NULL);
+    this->clauses_ = clauses;
+  }
+
+  // Return the break label for this type switch statement.
+  Unnamed_label*
+  break_label();
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
+
+ private:
+  // Get the type descriptor.
+  tree
+  get_type_descriptor(Translate_context*, Type*, tree);
+
+  // The variable holding the value we are switching on.
+  Named_object* var_;
+  // The expression we are switching on if there is no variable.
+  Expression* expr_;
+  // The type case clauses.
+  Type_case_clauses* clauses_;
+  // The break label, if needed.
+  Unnamed_label* break_label_;
+};
+
+#endif // !defined(GO_STATEMENTS_H)
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
new file mode 100644 (file)
index 0000000..b030a42
--- /dev/null
@@ -0,0 +1,8078 @@
+// types.cc -- Go frontend types.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include <gmp.h>
+
+#ifndef ENABLE_BUILD_WITH_CXX
+extern "C"
+{
+#endif
+
+#include "toplev.h"
+#include "intl.h"
+#include "tree.h"
+#include "gimple.h"
+#include "real.h"
+#include "convert.h"
+
+#ifndef ENABLE_BUILD_WITH_CXX
+}
+#endif
+
+#include "go-c.h"
+#include "gogo.h"
+#include "operator.h"
+#include "expressions.h"
+#include "statements.h"
+#include "export.h"
+#include "import.h"
+#include "types.h"
+
+// Class Type.
+
+Type::Type(Type_classification classification)
+  : classification_(classification), tree_(NULL_TREE),
+    type_descriptor_decl_(NULL_TREE)
+{
+}
+
+Type::~Type()
+{
+}
+
+// Get the base type for a type--skip names and forward declarations.
+
+Type*
+Type::base()
+{
+  switch (this->classification_)
+    {
+    case TYPE_NAMED:
+      return static_cast<Named_type*>(this)->real_type()->base();
+    case TYPE_FORWARD:
+      return static_cast<Forward_declaration_type*>(this)->real_type()->base();
+    default:
+      return this;
+    }
+}
+
+const Type*
+Type::base() const
+{
+  switch (this->classification_)
+    {
+    case TYPE_NAMED:
+      return static_cast<const Named_type*>(this)->real_type()->base();
+    case TYPE_FORWARD:
+      {
+       const Forward_declaration_type* ftype =
+         static_cast<const Forward_declaration_type*>(this);
+       return ftype->real_type()->base();
+      }
+    default:
+      return this;
+    }
+}
+
+// Skip defined forward declarations.
+
+Type*
+Type::forwarded()
+{
+  Type* t = this;
+  Forward_declaration_type* ftype = t->forward_declaration_type();
+  while (ftype != NULL && ftype->is_defined())
+    {
+      t = ftype->real_type();
+      ftype = t->forward_declaration_type();
+    }
+  return t;
+}
+
+const Type*
+Type::forwarded() const
+{
+  const Type* t = this;
+  const Forward_declaration_type* ftype = t->forward_declaration_type();
+  while (ftype != NULL && ftype->is_defined())
+    {
+      t = ftype->real_type();
+      ftype = t->forward_declaration_type();
+    }
+  return t;
+}
+
+// If this is a named type, return it.  Otherwise, return NULL.
+
+Named_type*
+Type::named_type()
+{
+  return this->forwarded()->convert_no_base<Named_type, TYPE_NAMED>();
+}
+
+const Named_type*
+Type::named_type() const
+{
+  return this->forwarded()->convert_no_base<const Named_type, TYPE_NAMED>();
+}
+
+// Return true if this type is not defined.
+
+bool
+Type::is_undefined() const
+{
+  return this->forwarded()->forward_declaration_type() != NULL;
+}
+
+// Return true if this is a basic type: a type which is not composed
+// of other types, and is not void.
+
+bool
+Type::is_basic_type() const
+{
+  switch (this->classification_)
+    {
+    case TYPE_INTEGER:
+    case TYPE_FLOAT:
+    case TYPE_COMPLEX:
+    case TYPE_BOOLEAN:
+    case TYPE_STRING:
+    case TYPE_NIL:
+      return true;
+
+    case TYPE_ERROR:
+    case TYPE_VOID:
+    case TYPE_FUNCTION:
+    case TYPE_POINTER:
+    case TYPE_STRUCT:
+    case TYPE_ARRAY:
+    case TYPE_MAP:
+    case TYPE_CHANNEL:
+    case TYPE_INTERFACE:
+      return false;
+
+    case TYPE_NAMED:
+    case TYPE_FORWARD:
+      return this->base()->is_basic_type();
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Return true if this is an abstract type.
+
+bool
+Type::is_abstract() const
+{
+  switch (this->classification())
+    {
+    case TYPE_INTEGER:
+      return this->integer_type()->is_abstract();
+    case TYPE_FLOAT:
+      return this->float_type()->is_abstract();
+    case TYPE_COMPLEX:
+      return this->complex_type()->is_abstract();
+    case TYPE_STRING:
+      return this->is_abstract_string_type();
+    case TYPE_BOOLEAN:
+      return this->is_abstract_boolean_type();
+    default:
+      return false;
+    }
+}
+
+// Return a non-abstract version of an abstract type.
+
+Type*
+Type::make_non_abstract_type()
+{
+  gcc_assert(this->is_abstract());
+  switch (this->classification())
+    {
+    case TYPE_INTEGER:
+      return Type::lookup_integer_type("int");
+    case TYPE_FLOAT:
+      return Type::lookup_float_type("float");
+    case TYPE_COMPLEX:
+      return Type::lookup_complex_type("complex");
+    case TYPE_STRING:
+      return Type::lookup_string_type();
+    case TYPE_BOOLEAN:
+      return Type::lookup_bool_type();
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Return true if this is an error type.  Don't give an error if we
+// try to dereference an undefined forwarding type, as this is called
+// in the parser when the type may legitimately be undefined.
+
+bool
+Type::is_error_type() const
+{
+  const Type* t = this->forwarded();
+  // Note that we return false for an undefined forward type.
+  switch (t->classification_)
+    {
+    case TYPE_ERROR:
+      return true;
+    case TYPE_NAMED:
+      return t->named_type()->real_type()->is_error_type();
+    default:
+      return false;
+    }
+}
+
+// If this is a pointer type, return the type to which it points.
+// Otherwise, return NULL.
+
+Type*
+Type::points_to() const
+{
+  const Pointer_type* ptype = this->convert<const Pointer_type,
+                                           TYPE_POINTER>();
+  return ptype == NULL ? NULL : ptype->points_to();
+}
+
+// Return whether this is an open array type.
+
+bool
+Type::is_open_array_type() const
+{
+  return this->array_type() != NULL && this->array_type()->length() == NULL;
+}
+
+// Return whether this is the predeclared constant nil being used as a
+// type.
+
+bool
+Type::is_nil_constant_as_type() const
+{
+  const Type* t = this->forwarded();
+  if (t->forward_declaration_type() != NULL)
+    {
+      const Named_object* no = t->forward_declaration_type()->named_object();
+      if (no->is_unknown())
+       no = no->unknown_value()->real_named_object();
+      if (no != NULL
+         && no->is_const()
+         && no->const_value()->expr()->is_nil_expression())
+       return true;
+    }
+  return false;
+}
+
+// Traverse a type.
+
+int
+Type::traverse(Type* type, Traverse* traverse)
+{
+  gcc_assert((traverse->traverse_mask() & Traverse::traverse_types) != 0
+            || (traverse->traverse_mask()
+                & Traverse::traverse_expressions) != 0);
+  if (traverse->remember_type(type))
+    {
+      // We have already traversed this type.
+      return TRAVERSE_CONTINUE;
+    }
+  if ((traverse->traverse_mask() & Traverse::traverse_types) != 0)
+    {
+      int t = traverse->type(type);
+      if (t == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+      else if (t == TRAVERSE_SKIP_COMPONENTS)
+       return TRAVERSE_CONTINUE;
+    }
+  // An array type has an expression which we need to traverse if
+  // traverse_expressions is set.
+  if (type->do_traverse(traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Default implementation for do_traverse for child class.
+
+int
+Type::do_traverse(Traverse*)
+{
+  return TRAVERSE_CONTINUE;
+}
+
+// Return whether two types are identical.  If REASON is not NULL,
+// optionally set *REASON to the reason the types are not identical.
+
+bool
+Type::are_identical(const Type* t1, const Type* t2, std::string* reason)
+{
+  if (t1 == NULL || t2 == NULL)
+    {
+      // Something is wrong.  Return true to avoid cascading errors.
+      return true;
+    }
+
+  // Skip defined forward declarations.
+  t1 = t1->forwarded();
+  t2 = t2->forwarded();
+
+  if (t1 == t2)
+    return true;
+
+  // An undefined forward declaration is an error, so we return true
+  // to avoid cascading errors.
+  if (t1->forward_declaration_type() != NULL
+      || t2->forward_declaration_type() != NULL)
+    return true;
+
+  // Avoid cascading errors with error types.
+  if (t1->is_error_type() || t2->is_error_type())
+    return true;
+
+  // Get a good reason for the sink type.  Note that the sink type on
+  // the left hand side of an assignment is handled in are_assignable.
+  if (t1->is_sink_type() || t2->is_sink_type())
+    {
+      if (reason != NULL)
+       *reason = "invalid use of _";
+      return false;
+    }
+
+  // A named type is only identical to itself.
+  if (t1->named_type() != NULL || t2->named_type() != NULL)
+    return false;
+
+  // Check type shapes.
+  if (t1->classification() != t2->classification())
+    return false;
+
+  switch (t1->classification())
+    {
+    case TYPE_VOID:
+    case TYPE_BOOLEAN:
+    case TYPE_STRING:
+    case TYPE_NIL:
+      // These types are always identical.
+      return true;
+
+    case TYPE_INTEGER:
+      return t1->integer_type()->is_identical(t2->integer_type());
+
+    case TYPE_FLOAT:
+      return t1->float_type()->is_identical(t2->float_type());
+
+    case TYPE_COMPLEX:
+      return t1->complex_type()->is_identical(t2->complex_type());
+
+    case TYPE_FUNCTION:
+      return t1->function_type()->is_identical(t2->function_type(),
+                                              false,
+                                              reason);
+
+    case TYPE_POINTER:
+      return Type::are_identical(t1->points_to(), t2->points_to(), reason);
+
+    case TYPE_STRUCT:
+      return t1->struct_type()->is_identical(t2->struct_type());
+
+    case TYPE_ARRAY:
+      return t1->array_type()->is_identical(t2->array_type());
+
+    case TYPE_MAP:
+      return t1->map_type()->is_identical(t2->map_type());
+
+    case TYPE_CHANNEL:
+      return t1->channel_type()->is_identical(t2->channel_type());
+
+    case TYPE_INTERFACE:
+      return t1->interface_type()->is_identical(t2->interface_type());
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Return true if it's OK to have a binary operation with types LHS
+// and RHS.  This is not used for shifts or comparisons.
+
+bool
+Type::are_compatible_for_binop(const Type* lhs, const Type* rhs)
+{
+  if (Type::are_identical(lhs, rhs, NULL))
+    return true;
+
+  // A constant of abstract bool type may be mixed with any bool type.
+  if ((rhs->is_abstract_boolean_type() && lhs->is_boolean_type())
+      || (lhs->is_abstract_boolean_type() && rhs->is_boolean_type()))
+    return true;
+
+  // A constant of abstract string type may be mixed with any string
+  // type.
+  if ((rhs->is_abstract_string_type() && lhs->is_string_type())
+      || (lhs->is_abstract_string_type() && rhs->is_string_type()))
+    return true;
+
+  lhs = lhs->base();
+  rhs = rhs->base();
+
+  // A constant of abstract integer, float, or complex type may be
+  // mixed with an integer, float, or complex type.
+  if ((rhs->is_abstract()
+       && (rhs->integer_type() != NULL
+          || rhs->float_type() != NULL
+          || rhs->complex_type() != NULL)
+       && (lhs->integer_type() != NULL
+          || lhs->float_type() != NULL
+          || lhs->complex_type() != NULL))
+      || (lhs->is_abstract()
+         && (lhs->integer_type() != NULL
+             || lhs->float_type() != NULL
+             || lhs->complex_type() != NULL)
+         && (rhs->integer_type() != NULL
+             || rhs->float_type() != NULL
+             || rhs->complex_type() != NULL)))
+    return true;
+
+  // The nil type may be compared to a pointer, an interface type, a
+  // slice type, a channel type, a map type, or a function type.
+  if (lhs->is_nil_type()
+      && (rhs->points_to() != NULL
+         || rhs->interface_type() != NULL
+         || rhs->is_open_array_type()
+         || rhs->map_type() != NULL
+         || rhs->channel_type() != NULL
+         || rhs->function_type() != NULL))
+    return true;
+  if (rhs->is_nil_type()
+      && (lhs->points_to() != NULL
+         || lhs->interface_type() != NULL
+         || lhs->is_open_array_type()
+         || lhs->map_type() != NULL
+         || lhs->channel_type() != NULL
+         || lhs->function_type() != NULL))
+    return true;
+
+  return false;
+}
+
+// Return true if a value with type RHS may be assigned to a variable
+// with type LHS.  If REASON is not NULL, set *REASON to the reason
+// the types are not assignable.
+
+bool
+Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
+{
+  // Do some checks first.  Make sure the types are defined.
+  if (lhs != NULL && lhs->forwarded()->forward_declaration_type() == NULL)
+    {
+      // Any value may be assigned to the blank identifier.
+      if (lhs->is_sink_type())
+       return true;
+
+      // All fields of a struct must be exported, or the assignment
+      // must be in the same package.
+      if (rhs != NULL && rhs->forwarded()->forward_declaration_type() == NULL)
+       {
+         if (lhs->has_hidden_fields(NULL, reason)
+             || rhs->has_hidden_fields(NULL, reason))
+           return false;
+       }
+    }
+
+  // Identical types are assignable.
+  if (Type::are_identical(lhs, rhs, reason))
+    return true;
+
+  // The types are assignable if they have identical underlying types
+  // and either LHS or RHS is not a named type.
+  if (((lhs->named_type() != NULL && rhs->named_type() == NULL)
+       || (rhs->named_type() != NULL && lhs->named_type() == NULL))
+      && Type::are_identical(lhs->base(), rhs->base(), reason))
+    return true;
+
+  // The types are assignable if LHS is an interface type and RHS
+  // implements the required methods.
+  const Interface_type* lhs_interface_type = lhs->interface_type();
+  if (lhs_interface_type != NULL)
+    {
+      if (lhs_interface_type->implements_interface(rhs, reason))
+       return true;
+      const Interface_type* rhs_interface_type = rhs->interface_type();
+      if (rhs_interface_type != NULL
+         && lhs_interface_type->is_compatible_for_assign(rhs_interface_type,
+                                                         reason))
+       return true;
+    }
+
+  // The type are assignable if RHS is a bidirectional channel type,
+  // LHS is a channel type, they have identical element types, and
+  // either LHS or RHS is not a named type.
+  if (lhs->channel_type() != NULL
+      && rhs->channel_type() != NULL
+      && rhs->channel_type()->may_send()
+      && rhs->channel_type()->may_receive()
+      && (lhs->named_type() == NULL || rhs->named_type() == NULL)
+      && Type::are_identical(lhs->channel_type()->element_type(),
+                            rhs->channel_type()->element_type(),
+                            reason))
+    return true;
+
+  // The nil type may be assigned to a pointer, function, slice, map,
+  // channel, or interface type.
+  if (rhs->is_nil_type()
+      && (lhs->points_to() != NULL
+         || lhs->function_type() != NULL
+         || lhs->is_open_array_type()
+         || lhs->map_type() != NULL
+         || lhs->channel_type() != NULL
+         || lhs->interface_type() != NULL))
+    return true;
+
+  // An untyped constant may be assigned to a numeric type if it is
+  // representable in that type.
+  if (rhs->is_abstract()
+      && (lhs->integer_type() != NULL
+         || lhs->float_type() != NULL
+         || lhs->complex_type() != NULL))
+    return true;
+
+
+  // Give some better error messages.
+  if (reason != NULL && reason->empty())
+    {
+      if (rhs->interface_type() != NULL)
+       reason->assign(_("need explicit conversion"));
+      else if (rhs->is_call_multiple_result_type())
+       reason->assign(_("multiple value function call in "
+                        "single value context"));
+      else if (lhs->named_type() != NULL && rhs->named_type() != NULL)
+       {
+         size_t len = (lhs->named_type()->name().length()
+                       + rhs->named_type()->name().length()
+                       + 100);
+         char* buf = new char[len];
+         snprintf(buf, len, _("cannot use type %s as type %s"),
+                  rhs->named_type()->message_name().c_str(),
+                  lhs->named_type()->message_name().c_str());
+         reason->assign(buf);
+         delete[] buf;
+       }
+    }
+
+  return false;
+}
+
+// Return true if a value with type RHS may be converted to type LHS.
+// If REASON is not NULL, set *REASON to the reason the types are not
+// convertible.
+
+bool
+Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason)
+{
+  // The types are convertible if they are assignable.
+  if (Type::are_assignable(lhs, rhs, reason))
+    return true;
+
+  // The types are convertible if they have identical underlying
+  // types.
+  if ((lhs->named_type() != NULL || rhs->named_type() != NULL)
+      && Type::are_identical(lhs->base(), rhs->base(), reason))
+    return true;
+
+  // The types are convertible if they are both unnamed pointer types
+  // and their pointer base types have identical underlying types.
+  if (lhs->named_type() == NULL
+      && rhs->named_type() == NULL
+      && lhs->points_to() != NULL
+      && rhs->points_to() != NULL
+      && (lhs->points_to()->named_type() != NULL
+         || rhs->points_to()->named_type() != NULL)
+      && Type::are_identical(lhs->points_to()->base(),
+                            rhs->points_to()->base(),
+                            reason))
+    return true;
+
+  // Integer and floating point types are convertible to each other.
+  if ((lhs->integer_type() != NULL || lhs->float_type() != NULL)
+      && (rhs->integer_type() != NULL || rhs->float_type() != NULL))
+    return true;
+
+  // Complex types are convertible to each other.
+  if (lhs->complex_type() != NULL && rhs->complex_type() != NULL)
+    return true;
+
+  // An integer, or []byte, or []int, may be converted to a string.
+  if (lhs->is_string_type())
+    {
+      if (rhs->integer_type() != NULL)
+       return true;
+      if (rhs->is_open_array_type() && rhs->named_type() == NULL)
+       {
+         const Type* e = rhs->array_type()->element_type()->forwarded();
+         if (e->integer_type() != NULL
+             && (e == Type::lookup_integer_type("uint8")
+                 || e == Type::lookup_integer_type("int")))
+           return true;
+       }
+    }
+
+  // A string may be converted to []byte or []int.
+  if (rhs->is_string_type()
+      && lhs->is_open_array_type()
+      && lhs->named_type() == NULL)
+    {
+      const Type* e = lhs->array_type()->element_type()->forwarded();
+      if (e->integer_type() != NULL
+         && (e == Type::lookup_integer_type("uint8")
+             || e == Type::lookup_integer_type("int")))
+       return true;
+    }
+
+  // An unsafe.Pointer type may be converted to any pointer type or to
+  // uintptr, and vice-versa.
+  if (lhs->is_unsafe_pointer_type()
+      && (rhs->points_to() != NULL
+         || (rhs->integer_type() != NULL
+             && rhs->forwarded() == Type::lookup_integer_type("uintptr"))))
+    return true;
+  if (rhs->is_unsafe_pointer_type()
+      && (lhs->points_to() != NULL
+         || (lhs->integer_type() != NULL
+             && lhs->forwarded() == Type::lookup_integer_type("uintptr"))))
+    return true;
+
+  // Give a better error message.
+  if (reason != NULL)
+    {
+      if (reason->empty())
+       *reason = "invalid type conversion";
+      else
+       {
+         std::string s = "invalid type conversion (";
+         s += *reason;
+         s += ')';
+         *reason = s;
+       }
+    }
+
+  return false;
+}
+
+// Return whether this type has any hidden fields.  This is only a
+// possibility for a few types.
+
+bool
+Type::has_hidden_fields(const Named_type* within, std::string* reason) const
+{
+  switch (this->forwarded()->classification_)
+    {
+    case TYPE_NAMED:
+      return this->named_type()->named_type_has_hidden_fields(reason);
+    case TYPE_STRUCT:
+      return this->struct_type()->struct_has_hidden_fields(within, reason);
+    case TYPE_ARRAY:
+      return this->array_type()->array_has_hidden_fields(within, reason);
+    default:
+      return false;
+    }
+}
+
+// Return a hash code for the type to be used for method lookup.
+
+unsigned int
+Type::hash_for_method(Gogo* gogo) const
+{
+  unsigned int ret = 0;
+  if (this->classification_ != TYPE_FORWARD)
+    ret += this->classification_;
+  return ret + this->do_hash_for_method(gogo);
+}
+
+// Default implementation of do_hash_for_method.  This is appropriate
+// for types with no subfields.
+
+unsigned int
+Type::do_hash_for_method(Gogo*) const
+{
+  return 0;
+}
+
+// Return a hash code for a string, given a starting hash.
+
+unsigned int
+Type::hash_string(const std::string& s, unsigned int h)
+{
+  const char* p = s.data();
+  size_t len = s.length();
+  for (; len > 0; --len)
+    {
+      h ^= *p++;
+      h*= 16777619;
+    }
+  return h;
+}
+
+// Default check for the expression passed to make.  Any type which
+// may be used with make implements its own version of this.
+
+bool
+Type::do_check_make_expression(Expression_list*, source_location)
+{
+  gcc_unreachable();
+}
+
+// Return whether an expression has an integer value.  Report an error
+// if not.  This is used when handling calls to the predeclared make
+// function.
+
+bool
+Type::check_int_value(Expression* e, const char* errmsg,
+                     source_location location)
+{
+  if (e->type()->integer_type() != NULL)
+    return true;
+
+  // Check for a floating point constant with integer value.
+  mpfr_t fval;
+  mpfr_init(fval);
+
+  Type* dummy;
+  if (e->float_constant_value(fval, &dummy))
+    {
+      mpz_t ival;
+      mpz_init(ival);
+
+      bool ok = false;
+
+      mpfr_clear_overflow();
+      mpfr_clear_erangeflag();
+      mpfr_get_z(ival, fval, GMP_RNDN);
+      if (!mpfr_overflow_p()
+         && !mpfr_erangeflag_p()
+         && mpz_sgn(ival) >= 0)
+       {
+         Named_type* ntype = Type::lookup_integer_type("int");
+         Integer_type* inttype = ntype->integer_type();
+         mpz_t max;
+         mpz_init_set_ui(max, 1);
+         mpz_mul_2exp(max, max, inttype->bits() - 1);
+         ok = mpz_cmp(ival, max) < 0;
+         mpz_clear(max);
+       }
+      mpz_clear(ival);
+
+      if (ok)
+       {
+         mpfr_clear(fval);
+         return true;
+       }
+    }
+
+  mpfr_clear(fval);
+
+  error_at(location, "%s", errmsg);
+  return false;
+}
+
+// A hash table mapping unnamed types to trees.
+
+Type::Type_trees Type::type_trees;
+
+// Return a tree representing this type.
+
+tree
+Type::get_tree(Gogo* gogo)
+{
+  if (this->tree_ != NULL)
+    return this->tree_;
+
+  if (this->forward_declaration_type() != NULL
+      || this->named_type() != NULL)
+    return this->get_tree_without_hash(gogo);
+
+  // To avoid confusing GIMPLE, we need to translate all identical Go
+  // types to the same GIMPLE type.  We use a hash table to do that.
+  // There is no need to use the hash table for named types, as named
+  // types are only identical to themselves.
+
+  std::pair<Type*, tree> val(this, NULL);
+  std::pair<Type_trees::iterator, bool> ins =
+    Type::type_trees.insert(val);
+  if (!ins.second && ins.first->second != NULL_TREE)
+    {
+      this->tree_ = ins.first->second;
+      return this->tree_;
+    }
+
+  tree t = this->get_tree_without_hash(gogo);
+
+  if (ins.first->second == NULL_TREE)
+    ins.first->second = t;
+  else
+    {
+      // We have already created a tree for this type.  This can
+      // happen when an unnamed type is defined using a named type
+      // which in turns uses an identical unnamed type.  Use the tree
+      // we created earlier and ignore the one we just built.
+      t = ins.first->second;
+      this->tree_ = t;
+    }
+
+  return t;
+}
+
+// Return a tree for a type without looking in the hash table for
+// identical types.  This is used for named types, since there is no
+// point to looking in the hash table for them.
+
+tree
+Type::get_tree_without_hash(Gogo* gogo)
+{
+  if (this->tree_ == NULL_TREE)
+    {
+      tree t = this->do_get_tree(gogo);
+
+      // For a recursive function or pointer type, we will temporarily
+      // return ptr_type_node during the recursion.  We don't want to
+      // record that for a forwarding type, as it may confuse us
+      // later.
+      if (t == ptr_type_node && this->forward_declaration_type() != NULL)
+       return t;
+
+      this->tree_ = t;
+      go_preserve_from_gc(t);
+    }
+
+  return this->tree_;
+}
+
+// Return a tree representing a zero initialization for this type.
+
+tree
+Type::get_init_tree(Gogo* gogo, bool is_clear)
+{
+  tree type_tree = this->get_tree(gogo);
+  if (type_tree == error_mark_node)
+    return error_mark_node;
+  return this->do_get_init_tree(gogo, type_tree, is_clear);
+}
+
+// Any type which supports the builtin make function must implement
+// this.
+
+tree
+Type::do_make_expression_tree(Translate_context*, Expression_list*,
+                             source_location)
+{
+  gcc_unreachable();
+}
+
+// Return a pointer to the type descriptor for this type.
+
+tree
+Type::type_descriptor_pointer(Gogo* gogo)
+{
+  Type* t = this->forwarded();
+  if (t->type_descriptor_decl_ == NULL_TREE)
+    {
+      Expression* e = t->do_type_descriptor(gogo, NULL);
+      gogo->build_type_descriptor_decl(t, e, &t->type_descriptor_decl_);
+      gcc_assert(t->type_descriptor_decl_ != NULL_TREE
+                && (t->type_descriptor_decl_ == error_mark_node
+                    || DECL_P(t->type_descriptor_decl_)));
+    }
+  if (t->type_descriptor_decl_ == error_mark_node)
+    return error_mark_node;
+  return build_fold_addr_expr(t->type_descriptor_decl_);
+}
+
+// Return a composite literal for a type descriptor.
+
+Expression*
+Type::type_descriptor(Gogo* gogo, Type* type)
+{
+  return type->do_type_descriptor(gogo, NULL);
+}
+
+// Return a composite literal for a type descriptor with a name.
+
+Expression*
+Type::named_type_descriptor(Gogo* gogo, Type* type, Named_type* name)
+{
+  gcc_assert(name != NULL && type->named_type() != name);
+  return type->do_type_descriptor(gogo, name);
+}
+
+// Make a builtin struct type from a list of fields.  The fields are
+// pairs of a name and a type.
+
+Struct_type*
+Type::make_builtin_struct_type(int nfields, ...)
+{
+  va_list ap;
+  va_start(ap, nfields);
+
+  source_location bloc = BUILTINS_LOCATION;
+  Struct_field_list* sfl = new Struct_field_list();
+  for (int i = 0; i < nfields; i++)
+    {
+      const char* field_name = va_arg(ap, const char *);
+      Type* type = va_arg(ap, Type*);
+      sfl->push_back(Struct_field(Typed_identifier(field_name, type, bloc)));
+    }
+
+  va_end(ap);
+
+  return Type::make_struct_type(sfl, bloc);
+}
+
+// Make a builtin named type.
+
+Named_type*
+Type::make_builtin_named_type(const char* name, Type* type)
+{
+  source_location bloc = BUILTINS_LOCATION;
+  Named_object* no = Named_object::make_type(name, NULL, type, bloc);
+  return no->type_value();
+}
+
+// Return the type of a type descriptor.  We should really tie this to
+// runtime.Type rather than copying it.  This must match commonType in
+// libgo/go/runtime/type.go.
+
+Type*
+Type::make_type_descriptor_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      source_location bloc = BUILTINS_LOCATION;
+
+      Type* uint8_type = Type::lookup_integer_type("uint8");
+      Type* uint32_type = Type::lookup_integer_type("uint32");
+      Type* uintptr_type = Type::lookup_integer_type("uintptr");
+      Type* string_type = Type::lookup_string_type();
+      Type* pointer_string_type = Type::make_pointer_type(string_type);
+
+      // This is an unnamed version of unsafe.Pointer.  Perhaps we
+      // should use the named version instead, although that would
+      // require us to create the unsafe package if it has not been
+      // imported.  It probably doesn't matter.
+      Type* void_type = Type::make_void_type();
+      Type* unsafe_pointer_type = Type::make_pointer_type(void_type);
+
+      // Forward declaration for the type descriptor type.
+      Named_object* named_type_descriptor_type =
+       Named_object::make_type_declaration("commonType", NULL, bloc);
+      Type* ft = Type::make_forward_declaration(named_type_descriptor_type);
+      Type* pointer_type_descriptor_type = Type::make_pointer_type(ft);
+
+      // The type of a method on a concrete type.
+      Struct_type* method_type =
+       Type::make_builtin_struct_type(5,
+                                      "name", pointer_string_type,
+                                      "pkgPath", pointer_string_type,
+                                      "mtyp", pointer_type_descriptor_type,
+                                      "typ", pointer_type_descriptor_type,
+                                      "tfn", unsafe_pointer_type);
+      Named_type* named_method_type =
+       Type::make_builtin_named_type("method", method_type);
+
+      // Information for types with a name or methods.
+      Type* slice_named_method_type =
+       Type::make_array_type(named_method_type, NULL);
+      Struct_type* uncommon_type =
+       Type::make_builtin_struct_type(3,
+                                      "name", pointer_string_type,
+                                      "pkgPath", pointer_string_type,
+                                      "methods", slice_named_method_type);
+      Named_type* named_uncommon_type =
+       Type::make_builtin_named_type("uncommonType", uncommon_type);
+
+      Type* pointer_uncommon_type =
+       Type::make_pointer_type(named_uncommon_type);
+
+      // The type descriptor type.
+
+      Typed_identifier_list* params = new Typed_identifier_list();
+      params->push_back(Typed_identifier("", unsafe_pointer_type, bloc));
+      params->push_back(Typed_identifier("", uintptr_type, bloc));
+
+      Typed_identifier_list* results = new Typed_identifier_list();
+      results->push_back(Typed_identifier("", uintptr_type, bloc));
+
+      Type* hashfn_type = Type::make_function_type(NULL, params, results, bloc);
+
+      params = new Typed_identifier_list();
+      params->push_back(Typed_identifier("", unsafe_pointer_type, bloc));
+      params->push_back(Typed_identifier("", unsafe_pointer_type, bloc));
+      params->push_back(Typed_identifier("", uintptr_type, bloc));
+
+      results = new Typed_identifier_list();
+      results->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc));
+
+      Type* equalfn_type = Type::make_function_type(NULL, params, results,
+                                                   bloc);
+
+      Struct_type* type_descriptor_type =
+       Type::make_builtin_struct_type(9,
+                                      "Kind", uint8_type,
+                                      "align", uint8_type,
+                                      "fieldAlign", uint8_type,
+                                      "size", uintptr_type,
+                                      "hash", uint32_type,
+                                      "hashfn", hashfn_type,
+                                      "equalfn", equalfn_type,
+                                      "string", pointer_string_type,
+                                      "", pointer_uncommon_type);
+
+      Named_type* named = Type::make_builtin_named_type("commonType",
+                                                       type_descriptor_type);
+
+      named_type_descriptor_type->set_type_value(named);
+
+      ret = named;
+    }
+
+  return ret;
+}
+
+// Make the type of a pointer to a type descriptor as represented in
+// Go.
+
+Type*
+Type::make_type_descriptor_ptr_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    ret = Type::make_pointer_type(Type::make_type_descriptor_type());
+  return ret;
+}
+
+// Return the names of runtime functions which compute a hash code for
+// this type and which compare whether two values of this type are
+// equal.
+
+void
+Type::type_functions(const char** hash_fn, const char** equal_fn) const
+{
+  switch (this->base()->classification())
+    {
+    case Type::TYPE_ERROR:
+    case Type::TYPE_VOID:
+    case Type::TYPE_NIL:
+      // These types can not be hashed or compared.
+      *hash_fn = "__go_type_hash_error";
+      *equal_fn = "__go_type_equal_error";
+      break;
+
+    case Type::TYPE_BOOLEAN:
+    case Type::TYPE_INTEGER:
+    case Type::TYPE_FLOAT:
+    case Type::TYPE_COMPLEX:
+    case Type::TYPE_POINTER:
+    case Type::TYPE_FUNCTION:
+    case Type::TYPE_MAP:
+    case Type::TYPE_CHANNEL:
+      *hash_fn = "__go_type_hash_identity";
+      *equal_fn = "__go_type_equal_identity";
+      break;
+
+    case Type::TYPE_STRING:
+      *hash_fn = "__go_type_hash_string";
+      *equal_fn = "__go_type_equal_string";
+      break;
+
+    case Type::TYPE_STRUCT:
+    case Type::TYPE_ARRAY:
+      // These types can not be hashed or compared.
+      *hash_fn = "__go_type_hash_error";
+      *equal_fn = "__go_type_equal_error";
+      break;
+
+    case Type::TYPE_INTERFACE:
+      if (this->interface_type()->is_empty())
+       {
+         *hash_fn = "__go_type_hash_empty_interface";
+         *equal_fn = "__go_type_equal_empty_interface";
+       }
+      else
+       {
+         *hash_fn = "__go_type_hash_interface";
+         *equal_fn = "__go_type_equal_interface";
+       }
+      break;
+
+    case Type::TYPE_NAMED:
+    case Type::TYPE_FORWARD:
+      gcc_unreachable();
+
+    default:
+      gcc_unreachable();
+    }
+}
+
+// Return a composite literal for the type descriptor for a plain type
+// of kind RUNTIME_TYPE_KIND named NAME.
+
+Expression*
+Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
+                                 Named_type* name, const Methods* methods,
+                                 bool only_value_methods)
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  Type* td_type = Type::make_type_descriptor_type();
+  const Struct_field_list* fields = td_type->struct_type()->fields();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(9);
+
+  Struct_field_list::const_iterator p = fields->begin();
+  gcc_assert(p->field_name() == "Kind");
+  mpz_t iv;
+  mpz_init_set_ui(iv, runtime_type_kind);
+  vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "align");
+  Expression::Type_info type_info = Expression::TYPE_INFO_ALIGNMENT;
+  vals->push_back(Expression::make_type_info(this, type_info));
+
+  ++p;
+  gcc_assert(p->field_name() == "fieldAlign");
+  type_info = Expression::TYPE_INFO_FIELD_ALIGNMENT;
+  vals->push_back(Expression::make_type_info(this, type_info));
+
+  ++p;
+  gcc_assert(p->field_name() == "size");
+  type_info = Expression::TYPE_INFO_SIZE;
+  vals->push_back(Expression::make_type_info(this, type_info));
+
+  ++p;
+  gcc_assert(p->field_name() == "hash");
+  mpz_set_ui(iv, this->hash_for_method(gogo));
+  vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
+
+  const char* hash_fn;
+  const char* equal_fn;
+  this->type_functions(&hash_fn, &equal_fn);
+
+  ++p;
+  gcc_assert(p->field_name() == "hashfn");
+  Function_type* fntype = p->type()->function_type();
+  Named_object* no = Named_object::make_function_declaration(hash_fn, NULL,
+                                                            fntype,
+                                                            bloc);
+  no->func_declaration_value()->set_asm_name(hash_fn);
+  vals->push_back(Expression::make_func_reference(no, NULL, bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "equalfn");
+  fntype = p->type()->function_type();
+  no = Named_object::make_function_declaration(equal_fn, NULL, fntype, bloc);
+  no->func_declaration_value()->set_asm_name(equal_fn);
+  vals->push_back(Expression::make_func_reference(no, NULL, bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "string");
+  Expression* s = Expression::make_string((name != NULL
+                                          ? name->reflection(gogo)
+                                          : this->reflection(gogo)),
+                                         bloc);
+  vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "uncommonType");
+  if (name == NULL && methods == NULL)
+    vals->push_back(Expression::make_nil(bloc));
+  else
+    {
+      if (methods == NULL)
+       methods = name->methods();
+      vals->push_back(this->uncommon_type_constructor(gogo,
+                                                     p->type()->deref(),
+                                                     name, methods,
+                                                     only_value_methods));
+    }
+
+  ++p;
+  gcc_assert(p == fields->end());
+
+  mpz_clear(iv);
+
+  return Expression::make_struct_composite_literal(td_type, vals, bloc);
+}
+
+// Return a composite literal for the uncommon type information for
+// this type.  UNCOMMON_STRUCT_TYPE is the type of the uncommon type
+// struct.  If name is not NULL, it is the name of the type.  If
+// METHODS is not NULL, it is the list of methods.  ONLY_VALUE_METHODS
+// is true if only value methods should be included.  At least one of
+// NAME and METHODS must not be NULL.
+
+Expression*
+Type::uncommon_type_constructor(Gogo* gogo, Type* uncommon_type,
+                               Named_type* name, const Methods* methods,
+                               bool only_value_methods) const
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  const Struct_field_list* fields = uncommon_type->struct_type()->fields();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(3);
+
+  Struct_field_list::const_iterator p = fields->begin();
+  gcc_assert(p->field_name() == "name");
+
+  ++p;
+  gcc_assert(p->field_name() == "pkgPath");
+
+  if (name == NULL)
+    {
+      vals->push_back(Expression::make_nil(bloc));
+      vals->push_back(Expression::make_nil(bloc));
+    }
+  else
+    {
+      Named_object* no = name->named_object();
+      std::string n = Gogo::unpack_hidden_name(no->name());
+      Expression* s = Expression::make_string(n, bloc);
+      vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
+
+      if (name->is_builtin())
+       vals->push_back(Expression::make_nil(bloc));
+      else
+       {
+         const Package* package = no->package();
+         const std::string& unique_prefix(package == NULL
+                                          ? gogo->unique_prefix()
+                                          : package->unique_prefix());
+         const std::string& package_name(package == NULL
+                                         ? gogo->package_name()
+                                         : package->name());
+         n.assign(unique_prefix);
+         n.append(1, '.');
+         n.append(package_name);
+         if (name->in_function() != NULL)
+           {
+             n.append(1, '.');
+             n.append(Gogo::unpack_hidden_name(name->in_function()->name()));
+           }
+         s = Expression::make_string(n, bloc);
+         vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
+       }
+    }
+
+  ++p;
+  gcc_assert(p->field_name() == "methods");
+  vals->push_back(this->methods_constructor(gogo, p->type(), methods,
+                                           only_value_methods));
+
+  ++p;
+  gcc_assert(p == fields->end());
+
+  Expression* r = Expression::make_struct_composite_literal(uncommon_type,
+                                                           vals, bloc);
+  return Expression::make_unary(OPERATOR_AND, r, bloc);
+}
+
+// Sort methods by name.
+
+class Sort_methods
+{
+ public:
+  bool
+  operator()(const std::pair<std::string, const Method*>& m1,
+            const std::pair<std::string, const Method*>& m2) const
+  { return m1.first < m2.first; }
+};
+
+// Return a composite literal for the type method table for this type.
+// METHODS_TYPE is the type of the table, and is a slice type.
+// METHODS is the list of methods.  If ONLY_VALUE_METHODS is true,
+// then only value methods are used.
+
+Expression*
+Type::methods_constructor(Gogo* gogo, Type* methods_type,
+                         const Methods* methods,
+                         bool only_value_methods) const
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  std::vector<std::pair<std::string, const Method*> > smethods;
+  if (methods != NULL)
+    {
+      smethods.reserve(methods->count());
+      for (Methods::const_iterator p = methods->begin();
+          p != methods->end();
+          ++p)
+       {
+         if (p->second->is_ambiguous())
+           continue;
+         if (only_value_methods && !p->second->is_value_method())
+           continue;
+         smethods.push_back(std::make_pair(p->first, p->second));
+       }
+    }
+
+  if (smethods.empty())
+    return Expression::make_slice_composite_literal(methods_type, NULL, bloc);
+
+  std::sort(smethods.begin(), smethods.end(), Sort_methods());
+
+  Type* method_type = methods_type->array_type()->element_type();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(smethods.size());
+  for (std::vector<std::pair<std::string, const Method*> >::const_iterator p
+        = smethods.begin();
+       p != smethods.end();
+       ++p)
+    vals->push_back(this->method_constructor(gogo, method_type, p->first,
+                                            p->second));
+
+  return Expression::make_slice_composite_literal(methods_type, vals, bloc);
+}
+
+// Return a composite literal for a single method.  METHOD_TYPE is the
+// type of the entry.  METHOD_NAME is the name of the method and M is
+// the method information.
+
+Expression*
+Type::method_constructor(Gogo*, Type* method_type,
+                        const std::string& method_name,
+                        const Method* m) const
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  const Struct_field_list* fields = method_type->struct_type()->fields();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(5);
+
+  Struct_field_list::const_iterator p = fields->begin();
+  gcc_assert(p->field_name() == "name");
+  const std::string n = Gogo::unpack_hidden_name(method_name);
+  Expression* s = Expression::make_string(n, bloc);
+  vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "pkgPath");
+  if (!Gogo::is_hidden_name(method_name))
+    vals->push_back(Expression::make_nil(bloc));
+  else
+    {
+      s = Expression::make_string(Gogo::hidden_name_prefix(method_name), bloc);
+      vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
+    }
+
+  Named_object* no = (m->needs_stub_method()
+                     ? m->stub_object()
+                     : m->named_object());
+
+  Function_type* mtype;
+  if (no->is_function())
+    mtype = no->func_value()->type();
+  else
+    mtype = no->func_declaration_value()->type();
+  gcc_assert(mtype->is_method());
+  Type* nonmethod_type = mtype->copy_without_receiver();
+
+  ++p;
+  gcc_assert(p->field_name() == "mtyp");
+  vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "typ");
+  vals->push_back(Expression::make_type_descriptor(mtype, bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "tfn");
+  vals->push_back(Expression::make_func_reference(no, NULL, bloc));
+
+  ++p;
+  gcc_assert(p == fields->end());
+
+  return Expression::make_struct_composite_literal(method_type, vals, bloc);
+}
+
+// Return a composite literal for the type descriptor of a plain type.
+// RUNTIME_TYPE_KIND is the value of the kind field.  If NAME is not
+// NULL, it is the name to use as well as the list of methods.
+
+Expression*
+Type::plain_type_descriptor(Gogo* gogo, int runtime_type_kind,
+                           Named_type* name)
+{
+  return this->type_descriptor_constructor(gogo, runtime_type_kind,
+                                          name, NULL, true);
+}
+
+// Return the type reflection string for this type.
+
+std::string
+Type::reflection(Gogo* gogo) const
+{
+  std::string ret;
+
+  // The do_reflection virtual function should set RET to the
+  // reflection string.
+  this->do_reflection(gogo, &ret);
+
+  return ret;
+}
+
+// Return a mangled name for the type.
+
+std::string
+Type::mangled_name(Gogo* gogo) const
+{
+  std::string ret;
+
+  // The do_mangled_name virtual function should set RET to the
+  // mangled name.  For a composite type it should append a code for
+  // the composition and then call do_mangled_name on the components.
+  this->do_mangled_name(gogo, &ret);
+
+  return ret;
+}
+
+// Default function to export a type.
+
+void
+Type::do_export(Export*) const
+{
+  gcc_unreachable();
+}
+
+// Import a type.
+
+Type*
+Type::import_type(Import* imp)
+{
+  if (imp->match_c_string("("))
+    return Function_type::do_import(imp);
+  else if (imp->match_c_string("*"))
+    return Pointer_type::do_import(imp);
+  else if (imp->match_c_string("struct "))
+    return Struct_type::do_import(imp);
+  else if (imp->match_c_string("["))
+    return Array_type::do_import(imp);
+  else if (imp->match_c_string("map "))
+    return Map_type::do_import(imp);
+  else if (imp->match_c_string("chan "))
+    return Channel_type::do_import(imp);
+  else if (imp->match_c_string("interface"))
+    return Interface_type::do_import(imp);
+  else
+    {
+      error_at(imp->location(), "import error: expected type");
+      return Type::make_error_type();
+    }
+}
+
+// A type used to indicate a parsing error.  This exists to simplify
+// later error detection.
+
+class Error_type : public Type
+{
+ public:
+  Error_type()
+    : Type(TYPE_ERROR)
+  { }
+
+ protected:
+  tree
+  do_get_tree(Gogo*)
+  { return error_mark_node; }
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool)
+  { return error_mark_node; }
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*)
+  { return Expression::make_error(BUILTINS_LOCATION); }
+
+  void
+  do_reflection(Gogo*, std::string*) const
+  { gcc_assert(saw_errors()); }
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const
+  { ret->push_back('E'); }
+};
+
+Type*
+Type::make_error_type()
+{
+  static Error_type singleton_error_type;
+  return &singleton_error_type;
+}
+
+// The void type.
+
+class Void_type : public Type
+{
+ public:
+  Void_type()
+    : Type(TYPE_VOID)
+  { }
+
+ protected:
+  tree
+  do_get_tree(Gogo*)
+  { return void_type_node; }
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool)
+  { gcc_unreachable(); }
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*)
+  { gcc_unreachable(); }
+
+  void
+  do_reflection(Gogo*, std::string*) const
+  { }
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const
+  { ret->push_back('v'); }
+};
+
+Type*
+Type::make_void_type()
+{
+  static Void_type singleton_void_type;
+  return &singleton_void_type;
+}
+
+// The boolean type.
+
+class Boolean_type : public Type
+{
+ public:
+  Boolean_type()
+    : Type(TYPE_BOOLEAN)
+  { }
+
+ protected:
+  tree
+  do_get_tree(Gogo*)
+  { return boolean_type_node; }
+
+  tree
+  do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+  { return is_clear ? NULL : fold_convert(type_tree, boolean_false_node); }
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type* name);
+
+  // We should not be asked for the reflection string of a basic type.
+  void
+  do_reflection(Gogo*, std::string* ret) const
+  { ret->append("bool"); }
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const
+  { ret->push_back('b'); }
+};
+
+// Make the type descriptor.
+
+Expression*
+Boolean_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  if (name != NULL)
+    return this->plain_type_descriptor(gogo, RUNTIME_TYPE_KIND_BOOL, name);
+  else
+    {
+      Named_object* no = gogo->lookup_global("bool");
+      gcc_assert(no != NULL);
+      return Type::type_descriptor(gogo, no->type_value());
+    }
+}
+
+Type*
+Type::make_boolean_type()
+{
+  static Boolean_type boolean_type;
+  return &boolean_type;
+}
+
+// The named type "bool".
+
+static Named_type* named_bool_type;
+
+// Get the named type "bool".
+
+Named_type*
+Type::lookup_bool_type()
+{
+  return named_bool_type;
+}
+
+// Make the named type "bool".
+
+Named_type*
+Type::make_named_bool_type()
+{
+  Type* bool_type = Type::make_boolean_type();
+  Named_object* named_object = Named_object::make_type("bool", NULL,
+                                                      bool_type,
+                                                      BUILTINS_LOCATION);
+  Named_type* named_type = named_object->type_value();
+  named_bool_type = named_type;
+  return named_type;
+}
+
+// Class Integer_type.
+
+Integer_type::Named_integer_types Integer_type::named_integer_types;
+
+// Create a new integer type.  Non-abstract integer types always have
+// names.
+
+Named_type*
+Integer_type::create_integer_type(const char* name, bool is_unsigned,
+                                 int bits, int runtime_type_kind)
+{
+  Integer_type* integer_type = new Integer_type(false, is_unsigned, bits,
+                                               runtime_type_kind);
+  std::string sname(name);
+  Named_object* named_object = Named_object::make_type(sname, NULL,
+                                                      integer_type,
+                                                      BUILTINS_LOCATION);
+  Named_type* named_type = named_object->type_value();
+  std::pair<Named_integer_types::iterator, bool> ins =
+    Integer_type::named_integer_types.insert(std::make_pair(sname, named_type));
+  gcc_assert(ins.second);
+  return named_type;
+}
+
+// Look up an existing integer type.
+
+Named_type*
+Integer_type::lookup_integer_type(const char* name)
+{
+  Named_integer_types::const_iterator p =
+    Integer_type::named_integer_types.find(name);
+  gcc_assert(p != Integer_type::named_integer_types.end());
+  return p->second;
+}
+
+// Create a new abstract integer type.
+
+Integer_type*
+Integer_type::create_abstract_integer_type()
+{
+  static Integer_type* abstract_type;
+  if (abstract_type == NULL)
+    abstract_type = new Integer_type(true, false, INT_TYPE_SIZE,
+                                    RUNTIME_TYPE_KIND_INT);
+  return abstract_type;
+}
+
+// Integer type compatibility.
+
+bool
+Integer_type::is_identical(const Integer_type* t) const
+{
+  if (this->is_unsigned_ != t->is_unsigned_ || this->bits_ != t->bits_)
+    return false;
+  return this->is_abstract_ == t->is_abstract_;
+}
+
+// Hash code.
+
+unsigned int
+Integer_type::do_hash_for_method(Gogo*) const
+{
+  return ((this->bits_ << 4)
+         + ((this->is_unsigned_ ? 1 : 0) << 8)
+         + ((this->is_abstract_ ? 1 : 0) << 9));
+}
+
+// Get the tree for an Integer_type.
+
+tree
+Integer_type::do_get_tree(Gogo*)
+{
+  gcc_assert(!this->is_abstract_);
+  if (this->is_unsigned_)
+    {
+      if (this->bits_ == INT_TYPE_SIZE)
+       return unsigned_type_node;
+      else if (this->bits_ == CHAR_TYPE_SIZE)
+       return unsigned_char_type_node;
+      else if (this->bits_ == SHORT_TYPE_SIZE)
+       return short_unsigned_type_node;
+      else if (this->bits_ == LONG_TYPE_SIZE)
+       return long_unsigned_type_node;
+      else if (this->bits_ == LONG_LONG_TYPE_SIZE)
+       return long_long_unsigned_type_node;
+      else
+       return make_unsigned_type(this->bits_);
+    }
+  else
+    {
+      if (this->bits_ == INT_TYPE_SIZE)
+       return integer_type_node;
+      else if (this->bits_ == CHAR_TYPE_SIZE)
+       return signed_char_type_node;
+      else if (this->bits_ == SHORT_TYPE_SIZE)
+       return short_integer_type_node;
+      else if (this->bits_ == LONG_TYPE_SIZE)
+       return long_integer_type_node;
+      else if (this->bits_ == LONG_LONG_TYPE_SIZE)
+       return long_long_integer_type_node;
+      else
+       return make_signed_type(this->bits_);
+    }
+}
+
+tree
+Integer_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  return is_clear ? NULL : build_int_cst(type_tree, 0);
+}
+
+// The type descriptor for an integer type.  Integer types are always
+// named.
+
+Expression*
+Integer_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  gcc_assert(name != NULL);
+  return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name);
+}
+
+// We should not be asked for the reflection string of a basic type.
+
+void
+Integer_type::do_reflection(Gogo*, std::string*) const
+{
+  gcc_unreachable();
+}
+
+// Mangled name.
+
+void
+Integer_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  char buf[100];
+  snprintf(buf, sizeof buf, "i%s%s%de",
+          this->is_abstract_ ? "a" : "",
+          this->is_unsigned_ ? "u" : "",
+          this->bits_);
+  ret->append(buf);
+}
+
+// Make an integer type.
+
+Named_type*
+Type::make_integer_type(const char* name, bool is_unsigned, int bits,
+                       int runtime_type_kind)
+{
+  return Integer_type::create_integer_type(name, is_unsigned, bits,
+                                          runtime_type_kind);
+}
+
+// Make an abstract integer type.
+
+Integer_type*
+Type::make_abstract_integer_type()
+{
+  return Integer_type::create_abstract_integer_type();
+}
+
+// Look up an integer type.
+
+Named_type*
+Type::lookup_integer_type(const char* name)
+{
+  return Integer_type::lookup_integer_type(name);
+}
+
+// Class Float_type.
+
+Float_type::Named_float_types Float_type::named_float_types;
+
+// Create a new float type.  Non-abstract float types always have
+// names.
+
+Named_type*
+Float_type::create_float_type(const char* name, int bits,
+                             int runtime_type_kind)
+{
+  Float_type* float_type = new Float_type(false, bits, runtime_type_kind);
+  std::string sname(name);
+  Named_object* named_object = Named_object::make_type(sname, NULL, float_type,
+                                                      BUILTINS_LOCATION);
+  Named_type* named_type = named_object->type_value();
+  std::pair<Named_float_types::iterator, bool> ins =
+    Float_type::named_float_types.insert(std::make_pair(sname, named_type));
+  gcc_assert(ins.second);
+  return named_type;
+}
+
+// Look up an existing float type.
+
+Named_type*
+Float_type::lookup_float_type(const char* name)
+{
+  Named_float_types::const_iterator p =
+    Float_type::named_float_types.find(name);
+  gcc_assert(p != Float_type::named_float_types.end());
+  return p->second;
+}
+
+// Create a new abstract float type.
+
+Float_type*
+Float_type::create_abstract_float_type()
+{
+  static Float_type* abstract_type;
+  if (abstract_type == NULL)
+    abstract_type = new Float_type(true, FLOAT_TYPE_SIZE,
+                                  RUNTIME_TYPE_KIND_FLOAT);
+  return abstract_type;
+}
+
+// Whether this type is identical with T.
+
+bool
+Float_type::is_identical(const Float_type* t) const
+{
+  if (this->bits_ != t->bits_)
+    return false;
+  return this->is_abstract_ == t->is_abstract_;
+}
+
+// Hash code.
+
+unsigned int
+Float_type::do_hash_for_method(Gogo*) const
+{
+  return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8);
+}
+
+// Get a tree without using a Gogo*.
+
+tree
+Float_type::type_tree() const
+{
+  if (this->bits_ == FLOAT_TYPE_SIZE)
+    return float_type_node;
+  else if (this->bits_ == DOUBLE_TYPE_SIZE)
+    return double_type_node;
+  else if (this->bits_ == LONG_DOUBLE_TYPE_SIZE)
+    return long_double_type_node;
+  else
+    {
+      tree ret = make_node(REAL_TYPE);
+      TYPE_PRECISION(ret) = this->bits_;
+      layout_type(ret);
+      return ret;
+    }
+}
+
+// Get a tree.
+
+tree
+Float_type::do_get_tree(Gogo*)
+{
+  return this->type_tree();
+}
+
+tree
+Float_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  if (is_clear)
+    return NULL;
+  REAL_VALUE_TYPE r;
+  real_from_integer(&r, TYPE_MODE(type_tree), 0, 0, 0);
+  return build_real(type_tree, r);
+}
+
+// The type descriptor for a float type.  Float types are always named.
+
+Expression*
+Float_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  gcc_assert(name != NULL);
+  return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name);
+}
+
+// We should not be asked for the reflection string of a basic type.
+
+void
+Float_type::do_reflection(Gogo*, std::string*) const
+{
+  gcc_unreachable();
+}
+
+// Mangled name.
+
+void
+Float_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  char buf[100];
+  snprintf(buf, sizeof buf, "f%s%de",
+          this->is_abstract_ ? "a" : "",
+          this->bits_);
+  ret->append(buf);
+}
+
+// Make a floating point type.
+
+Named_type*
+Type::make_float_type(const char* name, int bits, int runtime_type_kind)
+{
+  return Float_type::create_float_type(name, bits, runtime_type_kind);
+}
+
+// Make an abstract float type.
+
+Float_type*
+Type::make_abstract_float_type()
+{
+  return Float_type::create_abstract_float_type();
+}
+
+// Look up a float type.
+
+Named_type*
+Type::lookup_float_type(const char* name)
+{
+  return Float_type::lookup_float_type(name);
+}
+
+// Class Complex_type.
+
+Complex_type::Named_complex_types Complex_type::named_complex_types;
+
+// Create a new complex type.  Non-abstract complex types always have
+// names.
+
+Named_type*
+Complex_type::create_complex_type(const char* name, int bits,
+                                 int runtime_type_kind)
+{
+  Complex_type* complex_type = new Complex_type(false, bits,
+                                               runtime_type_kind);
+  std::string sname(name);
+  Named_object* named_object = Named_object::make_type(sname, NULL,
+                                                      complex_type,
+                                                      BUILTINS_LOCATION);
+  Named_type* named_type = named_object->type_value();
+  std::pair<Named_complex_types::iterator, bool> ins =
+    Complex_type::named_complex_types.insert(std::make_pair(sname,
+                                                           named_type));
+  gcc_assert(ins.second);
+  return named_type;
+}
+
+// Look up an existing complex type.
+
+Named_type*
+Complex_type::lookup_complex_type(const char* name)
+{
+  Named_complex_types::const_iterator p =
+    Complex_type::named_complex_types.find(name);
+  gcc_assert(p != Complex_type::named_complex_types.end());
+  return p->second;
+}
+
+// Create a new abstract complex type.
+
+Complex_type*
+Complex_type::create_abstract_complex_type()
+{
+  static Complex_type* abstract_type;
+  if (abstract_type == NULL)
+    abstract_type = new Complex_type(true, FLOAT_TYPE_SIZE * 2,
+                                    RUNTIME_TYPE_KIND_FLOAT);
+  return abstract_type;
+}
+
+// Whether this type is identical with T.
+
+bool
+Complex_type::is_identical(const Complex_type *t) const
+{
+  if (this->bits_ != t->bits_)
+    return false;
+  return this->is_abstract_ == t->is_abstract_;
+}
+
+// Hash code.
+
+unsigned int
+Complex_type::do_hash_for_method(Gogo*) const
+{
+  return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8);
+}
+
+// Get a tree without using a Gogo*.
+
+tree
+Complex_type::type_tree() const
+{
+  if (this->bits_ == FLOAT_TYPE_SIZE * 2)
+    return complex_float_type_node;
+  else if (this->bits_ == DOUBLE_TYPE_SIZE * 2)
+    return complex_double_type_node;
+  else if (this->bits_ == LONG_DOUBLE_TYPE_SIZE * 2)
+    return complex_long_double_type_node;
+  else
+    {
+      tree ret = make_node(REAL_TYPE);
+      TYPE_PRECISION(ret) = this->bits_ / 2;
+      layout_type(ret);
+      return build_complex_type(ret);
+    }
+}
+
+// Get a tree.
+
+tree
+Complex_type::do_get_tree(Gogo*)
+{
+  return this->type_tree();
+}
+
+// Zero initializer.
+
+tree
+Complex_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  if (is_clear)
+    return NULL;
+  REAL_VALUE_TYPE r;
+  real_from_integer(&r, TYPE_MODE(TREE_TYPE(type_tree)), 0, 0, 0);
+  return build_complex(type_tree, build_real(TREE_TYPE(type_tree), r),
+                      build_real(TREE_TYPE(type_tree), r));
+}
+
+// The type descriptor for a complex type.  Complex types are always
+// named.
+
+Expression*
+Complex_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  gcc_assert(name != NULL);
+  return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name);
+}
+
+// We should not be asked for the reflection string of a basic type.
+
+void
+Complex_type::do_reflection(Gogo*, std::string*) const
+{
+  gcc_unreachable();
+}
+
+// Mangled name.
+
+void
+Complex_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  char buf[100];
+  snprintf(buf, sizeof buf, "c%s%de",
+          this->is_abstract_ ? "a" : "",
+          this->bits_);
+  ret->append(buf);
+}
+
+// Make a complex type.
+
+Named_type*
+Type::make_complex_type(const char* name, int bits, int runtime_type_kind)
+{
+  return Complex_type::create_complex_type(name, bits, runtime_type_kind);
+}
+
+// Make an abstract complex type.
+
+Complex_type*
+Type::make_abstract_complex_type()
+{
+  return Complex_type::create_abstract_complex_type();
+}
+
+// Look up a complex type.
+
+Named_type*
+Type::lookup_complex_type(const char* name)
+{
+  return Complex_type::lookup_complex_type(name);
+}
+
+// Class String_type.
+
+// Return the tree for String_type.  A string is a struct with two
+// fields: a pointer to the characters and a length.
+
+tree
+String_type::do_get_tree(Gogo*)
+{
+  static tree struct_type;
+  return Gogo::builtin_struct(&struct_type, "__go_string", NULL_TREE, 2,
+                             "__data",
+                             build_pointer_type(unsigned_char_type_node),
+                             "__length",
+                             integer_type_node);
+}
+
+// Return a tree for the length of STRING.
+
+tree
+String_type::length_tree(Gogo*, tree string)
+{
+  tree string_type = TREE_TYPE(string);
+  gcc_assert(TREE_CODE(string_type) == RECORD_TYPE);
+  tree length_field = DECL_CHAIN(TYPE_FIELDS(string_type));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(length_field)),
+                   "__length") == 0);
+  return fold_build3(COMPONENT_REF, integer_type_node, string,
+                    length_field, NULL_TREE);
+}
+
+// Return a tree for a pointer to the bytes of STRING.
+
+tree
+String_type::bytes_tree(Gogo*, tree string)
+{
+  tree string_type = TREE_TYPE(string);
+  gcc_assert(TREE_CODE(string_type) == RECORD_TYPE);
+  tree bytes_field = TYPE_FIELDS(string_type);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(bytes_field)),
+                   "__data") == 0);
+  return fold_build3(COMPONENT_REF, TREE_TYPE(bytes_field), string,
+                    bytes_field, NULL_TREE);
+}
+
+// We initialize a string to { NULL, 0 }.
+
+tree
+String_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  if (is_clear)
+    return NULL_TREE;
+
+  gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE);
+
+  VEC(constructor_elt, gc)* init = VEC_alloc(constructor_elt, gc, 2);
+
+  for (tree field = TYPE_FIELDS(type_tree);
+       field != NULL_TREE;
+       field = DECL_CHAIN(field))
+    {
+      constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+      elt->index = field;
+      elt->value = fold_convert(TREE_TYPE(field), size_zero_node);
+    }
+
+  tree ret = build_constructor(type_tree, init);
+  TREE_CONSTANT(ret) = 1;
+  return ret;
+}
+
+// The type descriptor for the string type.
+
+Expression*
+String_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  if (name != NULL)
+    return this->plain_type_descriptor(gogo, RUNTIME_TYPE_KIND_STRING, name);
+  else
+    {
+      Named_object* no = gogo->lookup_global("string");
+      gcc_assert(no != NULL);
+      return Type::type_descriptor(gogo, no->type_value());
+    }
+}
+
+// We should not be asked for the reflection string of a basic type.
+
+void
+String_type::do_reflection(Gogo*, std::string* ret) const
+{
+  ret->append("string");
+}
+
+// Mangled name of a string type.
+
+void
+String_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+  ret->push_back('z');
+}
+
+// Make a string type.
+
+Type*
+Type::make_string_type()
+{
+  static String_type string_type;
+  return &string_type;
+}
+
+// The named type "string".
+
+static Named_type* named_string_type;
+
+// Get the named type "string".
+
+Named_type*
+Type::lookup_string_type()
+{
+  return named_string_type;
+}
+
+// Make the named type string.
+
+Named_type*
+Type::make_named_string_type()
+{
+  Type* string_type = Type::make_string_type();
+  Named_object* named_object = Named_object::make_type("string", NULL,
+                                                      string_type,
+                                                      BUILTINS_LOCATION);
+  Named_type* named_type = named_object->type_value();
+  named_string_type = named_type;
+  return named_type;
+}
+
+// The sink type.  This is the type of the blank identifier _.  Any
+// type may be assigned to it.
+
+class Sink_type : public Type
+{
+ public:
+  Sink_type()
+    : Type(TYPE_SINK)
+  { }
+
+ protected:
+  tree
+  do_get_tree(Gogo*)
+  { gcc_unreachable(); }
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool)
+  { gcc_unreachable(); }
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*)
+  { gcc_unreachable(); }
+
+  void
+  do_reflection(Gogo*, std::string*) const
+  { gcc_unreachable(); }
+
+  void
+  do_mangled_name(Gogo*, std::string*) const
+  { gcc_unreachable(); }
+};
+
+// Make the sink type.
+
+Type*
+Type::make_sink_type()
+{
+  static Sink_type sink_type;
+  return &sink_type;
+}
+
+// Class Function_type.
+
+// Traversal.
+
+int
+Function_type::do_traverse(Traverse* traverse)
+{
+  if (this->receiver_ != NULL
+      && Type::traverse(this->receiver_->type(), traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (this->parameters_ != NULL
+      && this->parameters_->traverse(traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (this->results_ != NULL
+      && this->results_->traverse(traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Returns whether T is a valid redeclaration of this type.  If this
+// returns false, and REASON is not NULL, *REASON may be set to a
+// brief explanation of why it returned false.
+
+bool
+Function_type::is_valid_redeclaration(const Function_type* t,
+                                     std::string* reason) const
+{
+  if (!this->is_identical(t, false, reason))
+    return false;
+
+  // A redeclaration of a function is required to use the same names
+  // for the receiver and parameters.
+  if (this->receiver() != NULL
+      && this->receiver()->name() != t->receiver()->name()
+      && this->receiver()->name() != Import::import_marker
+      && t->receiver()->name() != Import::import_marker)
+    {
+      if (reason != NULL)
+       *reason = "receiver name changed";
+      return false;
+    }
+
+  const Typed_identifier_list* parms1 = this->parameters();
+  const Typed_identifier_list* parms2 = t->parameters();
+  if (parms1 != NULL)
+    {
+      Typed_identifier_list::const_iterator p1 = parms1->begin();
+      for (Typed_identifier_list::const_iterator p2 = parms2->begin();
+          p2 != parms2->end();
+          ++p2, ++p1)
+       {
+         if (p1->name() != p2->name()
+             && p1->name() != Import::import_marker
+             && p2->name() != Import::import_marker)
+           {
+             if (reason != NULL)
+               *reason = "parameter name changed";
+             return false;
+           }
+
+         // This is called at parse time, so we may have unknown
+         // types.
+         Type* t1 = p1->type()->forwarded();
+         Type* t2 = p2->type()->forwarded();
+         if (t1 != t2
+             && t1->forward_declaration_type() != NULL
+             && (t2->forward_declaration_type() == NULL
+                 || (t1->forward_declaration_type()->named_object()
+                     != t2->forward_declaration_type()->named_object())))
+           return false;
+       }
+    }
+
+  const Typed_identifier_list* results1 = this->results();
+  const Typed_identifier_list* results2 = t->results();
+  if (results1 != NULL)
+    {
+      Typed_identifier_list::const_iterator res1 = results1->begin();
+      for (Typed_identifier_list::const_iterator res2 = results2->begin();
+          res2 != results2->end();
+          ++res2, ++res1)
+       {
+         if (res1->name() != res2->name()
+             && res1->name() != Import::import_marker
+             && res2->name() != Import::import_marker)
+           {
+             if (reason != NULL)
+               *reason = "result name changed";
+             return false;
+           }
+
+         // This is called at parse time, so we may have unknown
+         // types.
+         Type* t1 = res1->type()->forwarded();
+         Type* t2 = res2->type()->forwarded();
+         if (t1 != t2
+             && t1->forward_declaration_type() != NULL
+             && (t2->forward_declaration_type() == NULL
+                 || (t1->forward_declaration_type()->named_object()
+                     != t2->forward_declaration_type()->named_object())))
+           return false;
+       }
+    }
+
+  return true;
+}
+
+// Check whether T is the same as this type.
+
+bool
+Function_type::is_identical(const Function_type* t, bool ignore_receiver,
+                           std::string* reason) const
+{
+  if (!ignore_receiver)
+    {
+      const Typed_identifier* r1 = this->receiver();
+      const Typed_identifier* r2 = t->receiver();
+      if ((r1 != NULL) != (r2 != NULL))
+       {
+         if (reason != NULL)
+           *reason = _("different receiver types");
+         return false;
+       }
+      if (r1 != NULL)
+       {
+         if (!Type::are_identical(r1->type(), r2->type(), reason))
+           {
+             if (reason != NULL && !reason->empty())
+               *reason = "receiver: " + *reason;
+             return false;
+           }
+       }
+    }
+
+  const Typed_identifier_list* parms1 = this->parameters();
+  const Typed_identifier_list* parms2 = t->parameters();
+  if ((parms1 != NULL) != (parms2 != NULL))
+    {
+      if (reason != NULL)
+       *reason = _("different number of parameters");
+      return false;
+    }
+  if (parms1 != NULL)
+    {
+      Typed_identifier_list::const_iterator p1 = parms1->begin();
+      for (Typed_identifier_list::const_iterator p2 = parms2->begin();
+          p2 != parms2->end();
+          ++p2, ++p1)
+       {
+         if (p1 == parms1->end())
+           {
+             if (reason != NULL)
+               *reason = _("different number of parameters");
+             return false;
+           }
+
+         if (!Type::are_identical(p1->type(), p2->type(), NULL))
+           {
+             if (reason != NULL)
+               *reason = _("different parameter types");
+             return false;
+           }
+       }
+      if (p1 != parms1->end())
+       {
+         if (reason != NULL)
+           *reason = _("different number of parameters");
+       return false;
+       }
+    }
+
+  if (this->is_varargs() != t->is_varargs())
+    {
+      if (reason != NULL)
+       *reason = _("different varargs");
+      return false;
+    }
+
+  const Typed_identifier_list* results1 = this->results();
+  const Typed_identifier_list* results2 = t->results();
+  if ((results1 != NULL) != (results2 != NULL))
+    {
+      if (reason != NULL)
+       *reason = _("different number of results");
+      return false;
+    }
+  if (results1 != NULL)
+    {
+      Typed_identifier_list::const_iterator res1 = results1->begin();
+      for (Typed_identifier_list::const_iterator res2 = results2->begin();
+          res2 != results2->end();
+          ++res2, ++res1)
+       {
+         if (res1 == results1->end())
+           {
+             if (reason != NULL)
+               *reason = _("different number of results");
+             return false;
+           }
+
+         if (!Type::are_identical(res1->type(), res2->type(), NULL))
+           {
+             if (reason != NULL)
+               *reason = _("different result types");
+             return false;
+           }
+       }
+      if (res1 != results1->end())
+       {
+         if (reason != NULL)
+           *reason = _("different number of results");
+         return false;
+       }
+    }
+
+  return true;
+}
+
+// Hash code.
+
+unsigned int
+Function_type::do_hash_for_method(Gogo* gogo) const
+{
+  unsigned int ret = 0;
+  // We ignore the receiver type for hash codes, because we need to
+  // get the same hash code for a method in an interface and a method
+  // declared for a type.  The former will not have a receiver.
+  if (this->parameters_ != NULL)
+    {
+      int shift = 1;
+      for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
+          p != this->parameters_->end();
+          ++p, ++shift)
+       ret += p->type()->hash_for_method(gogo) << shift;
+    }
+  if (this->results_ != NULL)
+    {
+      int shift = 2;
+      for (Typed_identifier_list::const_iterator p = this->results_->begin();
+          p != this->results_->end();
+          ++p, ++shift)
+       ret += p->type()->hash_for_method(gogo) << shift;
+    }
+  if (this->is_varargs_)
+    ret += 1;
+  ret <<= 4;
+  return ret;
+}
+
+// Get the tree for a function type.
+
+tree
+Function_type::do_get_tree(Gogo* gogo)
+{
+  tree args = NULL_TREE;
+  tree* pp = &args;
+
+  if (this->receiver_ != NULL)
+    {
+      Type* rtype = this->receiver_->type();
+      tree ptype = rtype->get_tree(gogo);
+      if (ptype == error_mark_node)
+       return error_mark_node;
+
+      // We always pass the address of the receiver parameter, in
+      // order to make interface calls work with unknown types.
+      if (rtype->points_to() == NULL)
+       ptype = build_pointer_type(ptype);
+
+      *pp = tree_cons (NULL_TREE, ptype, NULL_TREE);
+      pp = &TREE_CHAIN (*pp);
+    }
+
+  if (this->parameters_ != NULL)
+    {
+      for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
+          p != this->parameters_->end();
+          ++p)
+       {
+         tree ptype = p->type()->get_tree(gogo);
+         if (ptype == error_mark_node)
+           return error_mark_node;
+         *pp = tree_cons (NULL_TREE, ptype, NULL_TREE);
+         pp = &TREE_CHAIN (*pp);
+       }
+    }
+
+  // Varargs is handled entirely at the Go level.  At the tree level,
+  // functions are not varargs.
+  *pp = void_list_node;
+
+  tree result;
+  if (this->results_ == NULL)
+    result = void_type_node;
+  else if (this->results_->size() == 1)
+    result = this->results_->begin()->type()->get_tree(gogo);
+  else
+    {
+      result = make_node(RECORD_TYPE);
+      tree field_trees = NULL_TREE;
+      tree* pp = &field_trees;
+      for (Typed_identifier_list::const_iterator p = this->results_->begin();
+          p != this->results_->end();
+          ++p)
+       {
+         const std::string name = (p->name().empty()
+                                   ? "UNNAMED"
+                                   : Gogo::unpack_hidden_name(p->name()));
+         tree name_tree = get_identifier_with_length(name.data(),
+                                                     name.length());
+         tree field_type_tree = p->type()->get_tree(gogo);
+         if (field_type_tree == error_mark_node)
+           return error_mark_node;
+         tree field = build_decl(this->location_, FIELD_DECL, name_tree,
+                                 field_type_tree);
+         DECL_CONTEXT(field) = result;
+         *pp = field;
+         pp = &DECL_CHAIN(field);
+       }
+      TYPE_FIELDS(result) = field_trees;
+      layout_type(result);
+    }
+
+  if (result == error_mark_node)
+    return error_mark_node;
+
+  tree fntype = build_function_type(result, args);
+  if (fntype == error_mark_node)
+    return fntype;
+
+  return build_pointer_type(fntype);
+}
+
+// Functions are initialized to NULL.
+
+tree
+Function_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  if (is_clear)
+    return NULL;
+  return fold_convert(type_tree, null_pointer_node);
+}
+
+// The type of a function type descriptor.
+
+Type*
+Function_type::make_function_type_descriptor_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      Type* tdt = Type::make_type_descriptor_type();
+      Type* ptdt = Type::make_type_descriptor_ptr_type();
+
+      Type* bool_type = Type::lookup_bool_type();
+
+      Type* slice_type = Type::make_array_type(ptdt, NULL);
+
+      Struct_type* s = Type::make_builtin_struct_type(4,
+                                                     "", tdt,
+                                                     "dotdotdot", bool_type,
+                                                     "in", slice_type,
+                                                     "out", slice_type);
+
+      ret = Type::make_builtin_named_type("FuncType", s);
+    }
+
+  return ret;
+}
+
+// The type descriptor for a function type.
+
+Expression*
+Function_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  Type* ftdt = Function_type::make_function_type_descriptor_type();
+
+  const Struct_field_list* fields = ftdt->struct_type()->fields();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(4);
+
+  Struct_field_list::const_iterator p = fields->begin();
+  gcc_assert(p->field_name() == "commonType");
+  vals->push_back(this->type_descriptor_constructor(gogo,
+                                                   RUNTIME_TYPE_KIND_FUNC,
+                                                   name, NULL, true));
+
+  ++p;
+  gcc_assert(p->field_name() == "dotdotdot");
+  vals->push_back(Expression::make_boolean(this->is_varargs(), bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "in");
+  vals->push_back(this->type_descriptor_params(p->type(), this->receiver(),
+                                              this->parameters()));
+
+  ++p;
+  gcc_assert(p->field_name() == "out");
+  vals->push_back(this->type_descriptor_params(p->type(), NULL,
+                                              this->results()));
+
+  ++p;
+  gcc_assert(p == fields->end());
+
+  return Expression::make_struct_composite_literal(ftdt, vals, bloc);
+}
+
+// Return a composite literal for the parameters or results of a type
+// descriptor.
+
+Expression*
+Function_type::type_descriptor_params(Type* params_type,
+                                     const Typed_identifier* receiver,
+                                     const Typed_identifier_list* params)
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  if (receiver == NULL && params == NULL)
+    return Expression::make_slice_composite_literal(params_type, NULL, bloc);
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve((params == NULL ? 0 : params->size())
+               + (receiver != NULL ? 1 : 0));
+
+  if (receiver != NULL)
+    {
+      Type* rtype = receiver->type();
+      // The receiver is always passed as a pointer.  FIXME: Is this
+      // right?  Should that fact affect the type descriptor?
+      if (rtype->points_to() == NULL)
+       rtype = Type::make_pointer_type(rtype);
+      vals->push_back(Expression::make_type_descriptor(rtype, bloc));
+    }
+
+  if (params != NULL)
+    {
+      for (Typed_identifier_list::const_iterator p = params->begin();
+          p != params->end();
+          ++p)
+       vals->push_back(Expression::make_type_descriptor(p->type(), bloc));
+    }
+
+  return Expression::make_slice_composite_literal(params_type, vals, bloc);
+}
+
+// The reflection string.
+
+void
+Function_type::do_reflection(Gogo* gogo, std::string* ret) const
+{
+  // FIXME: Turn this off until we straighten out the type of the
+  // struct field used in a go statement which calls a method.
+  // gcc_assert(this->receiver_ == NULL);
+
+  ret->append("func");
+
+  if (this->receiver_ != NULL)
+    {
+      ret->push_back('(');
+      this->append_reflection(this->receiver_->type(), gogo, ret);
+      ret->push_back(')');
+    }
+
+  ret->push_back('(');
+  const Typed_identifier_list* params = this->parameters();
+  if (params != NULL)
+    {
+      bool is_varargs = this->is_varargs_;
+      for (Typed_identifier_list::const_iterator p = params->begin();
+          p != params->end();
+          ++p)
+       {
+         if (p != params->begin())
+           ret->append(", ");
+         if (!is_varargs || p + 1 != params->end())
+           this->append_reflection(p->type(), gogo, ret);
+         else
+           {
+             ret->append("...");
+             this->append_reflection(p->type()->array_type()->element_type(),
+                                     gogo, ret);
+           }
+       }
+    }
+  ret->push_back(')');
+
+  const Typed_identifier_list* results = this->results();
+  if (results != NULL && !results->empty())
+    {
+      if (results->size() == 1)
+       ret->push_back(' ');
+      else
+       ret->append(" (");
+      for (Typed_identifier_list::const_iterator p = results->begin();
+          p != results->end();
+          ++p)
+       {
+         if (p != results->begin())
+           ret->append(", ");
+         this->append_reflection(p->type(), gogo, ret);
+       }
+      if (results->size() > 1)
+       ret->push_back(')');
+    }
+}
+
+// Mangled name.
+
+void
+Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('F');
+
+  if (this->receiver_ != NULL)
+    {
+      ret->push_back('m');
+      this->append_mangled_name(this->receiver_->type(), gogo, ret);
+    }
+
+  const Typed_identifier_list* params = this->parameters();
+  if (params != NULL)
+    {
+      ret->push_back('p');
+      for (Typed_identifier_list::const_iterator p = params->begin();
+          p != params->end();
+          ++p)
+       this->append_mangled_name(p->type(), gogo, ret);
+      if (this->is_varargs_)
+       ret->push_back('V');
+      ret->push_back('e');
+    }
+
+  const Typed_identifier_list* results = this->results();
+  if (results != NULL)
+    {
+      ret->push_back('r');
+      for (Typed_identifier_list::const_iterator p = results->begin();
+          p != results->end();
+          ++p)
+       this->append_mangled_name(p->type(), gogo, ret);
+      ret->push_back('e');
+    }
+
+  ret->push_back('e');
+}
+
+// Export a function type.
+
+void
+Function_type::do_export(Export* exp) const
+{
+  // We don't write out the receiver.  The only function types which
+  // should have a receiver are the ones associated with explicitly
+  // defined methods.  For those the receiver type is written out by
+  // Function::export_func.
+
+  exp->write_c_string("(");
+  bool first = true;
+  if (this->parameters_ != NULL)
+    {
+      bool is_varargs = this->is_varargs_;
+      for (Typed_identifier_list::const_iterator p =
+            this->parameters_->begin();
+          p != this->parameters_->end();
+          ++p)
+       {
+         if (first)
+           first = false;
+         else
+           exp->write_c_string(", ");
+         if (!is_varargs || p + 1 != this->parameters_->end())
+           exp->write_type(p->type());
+         else
+           {
+             exp->write_c_string("...");
+             exp->write_type(p->type()->array_type()->element_type());
+           }
+       }
+    }
+  exp->write_c_string(")");
+
+  const Typed_identifier_list* results = this->results_;
+  if (results != NULL)
+    {
+      exp->write_c_string(" ");
+      if (results->size() == 1)
+       exp->write_type(results->begin()->type());
+      else
+       {
+         first = true;
+         exp->write_c_string("(");
+         for (Typed_identifier_list::const_iterator p = results->begin();
+              p != results->end();
+              ++p)
+           {
+             if (first)
+               first = false;
+             else
+               exp->write_c_string(", ");
+             exp->write_type(p->type());
+           }
+         exp->write_c_string(")");
+       }
+    }
+}
+
+// Import a function type.
+
+Function_type*
+Function_type::do_import(Import* imp)
+{
+  imp->require_c_string("(");
+  Typed_identifier_list* parameters;
+  bool is_varargs = false;
+  if (imp->peek_char() == ')')
+    parameters = NULL;
+  else
+    {
+      parameters = new Typed_identifier_list();
+      while (true)
+       {
+         if (imp->match_c_string("..."))
+           {
+             imp->advance(3);
+             is_varargs = true;
+           }
+
+         Type* ptype = imp->read_type();
+         if (is_varargs)
+           ptype = Type::make_array_type(ptype, NULL);
+         parameters->push_back(Typed_identifier(Import::import_marker,
+                                                ptype, imp->location()));
+         if (imp->peek_char() != ',')
+           break;
+         gcc_assert(!is_varargs);
+         imp->require_c_string(", ");
+       }
+    }
+  imp->require_c_string(")");
+
+  Typed_identifier_list* results;
+  if (imp->peek_char() != ' ')
+    results = NULL;
+  else
+    {
+      imp->advance(1);
+      results = new Typed_identifier_list;
+      if (imp->peek_char() != '(')
+       {
+         Type* rtype = imp->read_type();
+         results->push_back(Typed_identifier(Import::import_marker, rtype,
+                                             imp->location()));
+       }
+      else
+       {
+         imp->advance(1);
+         while (true)
+           {
+             Type* rtype = imp->read_type();
+             results->push_back(Typed_identifier(Import::import_marker,
+                                                 rtype, imp->location()));
+             if (imp->peek_char() != ',')
+               break;
+             imp->require_c_string(", ");
+           }
+         imp->require_c_string(")");
+       }
+    }
+
+  Function_type* ret = Type::make_function_type(NULL, parameters, results,
+                                               imp->location());
+  if (is_varargs)
+    ret->set_is_varargs();
+  return ret;
+}
+
+// Make a copy of a function type without a receiver.
+
+Function_type*
+Function_type::copy_without_receiver() const
+{
+  gcc_assert(this->is_method());
+  Function_type *ret = Type::make_function_type(NULL, this->parameters_,
+                                               this->results_,
+                                               this->location_);
+  if (this->is_varargs())
+    ret->set_is_varargs();
+  if (this->is_builtin())
+    ret->set_is_builtin();
+  return ret;
+}
+
+// Make a copy of a function type with a receiver.
+
+Function_type*
+Function_type::copy_with_receiver(Type* receiver_type) const
+{
+  gcc_assert(!this->is_method());
+  Typed_identifier* receiver = new Typed_identifier("", receiver_type,
+                                                   this->location_);
+  return Type::make_function_type(receiver, this->parameters_,
+                                 this->results_, this->location_);
+}
+
+// Make a function type.
+
+Function_type*
+Type::make_function_type(Typed_identifier* receiver,
+                        Typed_identifier_list* parameters,
+                        Typed_identifier_list* results,
+                        source_location location)
+{
+  return new Function_type(receiver, parameters, results, location);
+}
+
+// Class Pointer_type.
+
+// Traversal.
+
+int
+Pointer_type::do_traverse(Traverse* traverse)
+{
+  return Type::traverse(this->to_type_, traverse);
+}
+
+// Hash code.
+
+unsigned int
+Pointer_type::do_hash_for_method(Gogo* gogo) const
+{
+  return this->to_type_->hash_for_method(gogo) << 4;
+}
+
+// The tree for a pointer type.
+
+tree
+Pointer_type::do_get_tree(Gogo* gogo)
+{
+  return build_pointer_type(this->to_type_->get_tree(gogo));
+}
+
+// Initialize a pointer type.
+
+tree
+Pointer_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  if (is_clear)
+    return NULL;
+  return fold_convert(type_tree, null_pointer_node);
+}
+
+// The type of a pointer type descriptor.
+
+Type*
+Pointer_type::make_pointer_type_descriptor_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      Type* tdt = Type::make_type_descriptor_type();
+      Type* ptdt = Type::make_type_descriptor_ptr_type();
+
+      Struct_type* s = Type::make_builtin_struct_type(2,
+                                                     "", tdt,
+                                                     "elem", ptdt);
+
+      ret = Type::make_builtin_named_type("PtrType", s);
+    }
+
+  return ret;
+}
+
+// The type descriptor for a pointer type.
+
+Expression*
+Pointer_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  if (this->is_unsafe_pointer_type())
+    {
+      gcc_assert(name != NULL);
+      return this->plain_type_descriptor(gogo,
+                                        RUNTIME_TYPE_KIND_UNSAFE_POINTER,
+                                        name);
+    }
+  else
+    {
+      source_location bloc = BUILTINS_LOCATION;
+
+      const Methods* methods;
+      Type* deref = this->points_to();
+      if (deref->named_type() != NULL)
+       methods = deref->named_type()->methods();
+      else if (deref->struct_type() != NULL)
+       methods = deref->struct_type()->methods();
+      else
+       methods = NULL;
+
+      Type* ptr_tdt = Pointer_type::make_pointer_type_descriptor_type();
+
+      const Struct_field_list* fields = ptr_tdt->struct_type()->fields();
+
+      Expression_list* vals = new Expression_list();
+      vals->reserve(2);
+
+      Struct_field_list::const_iterator p = fields->begin();
+      gcc_assert(p->field_name() == "commonType");
+      vals->push_back(this->type_descriptor_constructor(gogo,
+                                                       RUNTIME_TYPE_KIND_PTR,
+                                                       name, methods, false));
+
+      ++p;
+      gcc_assert(p->field_name() == "elem");
+      vals->push_back(Expression::make_type_descriptor(deref, bloc));
+
+      return Expression::make_struct_composite_literal(ptr_tdt, vals, bloc);
+    }
+}
+
+// Reflection string.
+
+void
+Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('*');
+  this->append_reflection(this->to_type_, gogo, ret);
+}
+
+// Mangled name.
+
+void
+Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('p');
+  this->append_mangled_name(this->to_type_, gogo, ret);
+}
+
+// Export.
+
+void
+Pointer_type::do_export(Export* exp) const
+{
+  exp->write_c_string("*");
+  if (this->is_unsafe_pointer_type())
+    exp->write_c_string("any");
+  else
+    exp->write_type(this->to_type_);
+}
+
+// Import.
+
+Pointer_type*
+Pointer_type::do_import(Import* imp)
+{
+  imp->require_c_string("*");
+  if (imp->match_c_string("any"))
+    {
+      imp->advance(3);
+      return Type::make_pointer_type(Type::make_void_type());
+    }
+  Type* to = imp->read_type();
+  return Type::make_pointer_type(to);
+}
+
+// Make a pointer type.
+
+Pointer_type*
+Type::make_pointer_type(Type* to_type)
+{
+  typedef Unordered_map(Type*, Pointer_type*) Hashtable;
+  static Hashtable pointer_types;
+  Hashtable::const_iterator p = pointer_types.find(to_type);
+  if (p != pointer_types.end())
+    return p->second;
+  Pointer_type* ret = new Pointer_type(to_type);
+  pointer_types[to_type] = ret;
+  return ret;
+}
+
+// The nil type.  We use a special type for nil because it is not the
+// same as any other type.  In C term nil has type void*, but there is
+// no such type in Go.
+
+class Nil_type : public Type
+{
+ public:
+  Nil_type()
+    : Type(TYPE_NIL)
+  { }
+
+ protected:
+  tree
+  do_get_tree(Gogo*)
+  { return ptr_type_node; }
+
+  tree
+  do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+  { return is_clear ? NULL : fold_convert(type_tree, null_pointer_node); }
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*)
+  { gcc_unreachable(); }
+
+  void
+  do_reflection(Gogo*, std::string*) const
+  { gcc_unreachable(); }
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const
+  { ret->push_back('n'); }
+};
+
+// Make the nil type.
+
+Type*
+Type::make_nil_type()
+{
+  static Nil_type singleton_nil_type;
+  return &singleton_nil_type;
+}
+
+// The type of a function call which returns multiple values.  This is
+// really a struct, but we don't want to confuse a function call which
+// returns a struct with a function call which returns multiple
+// values.
+
+class Call_multiple_result_type : public Type
+{
+ public:
+  Call_multiple_result_type(Call_expression* call)
+    : Type(TYPE_CALL_MULTIPLE_RESULT),
+      call_(call)
+  { }
+
+ protected:
+  bool
+  do_has_pointer() const
+  { gcc_unreachable(); }
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool)
+  { gcc_unreachable(); }
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*)
+  { gcc_unreachable(); }
+
+  void
+  do_reflection(Gogo*, std::string*) const
+  { gcc_unreachable(); }
+
+  void
+  do_mangled_name(Gogo*, std::string*) const
+  { gcc_unreachable(); }
+
+ private:
+  // The expression being called.
+  Call_expression* call_;
+};
+
+// Return the tree for a call result.
+
+tree
+Call_multiple_result_type::do_get_tree(Gogo* gogo)
+{
+  Function_type* fntype = this->call_->get_function_type();
+  gcc_assert(fntype != NULL);
+  const Typed_identifier_list* results = fntype->results();
+  gcc_assert(results != NULL && results->size() > 1);
+
+  Struct_field_list* sfl = new Struct_field_list;
+  for (Typed_identifier_list::const_iterator p = results->begin();
+       p != results->end();
+       ++p)
+    {
+      const std::string name = ((p->name().empty()
+                                || p->name() == Import::import_marker)
+                               ? "UNNAMED"
+                               : p->name());
+      sfl->push_back(Struct_field(Typed_identifier(name, p->type(),
+                                                  this->call_->location())));
+    }
+  return Type::make_struct_type(sfl, this->call_->location())->get_tree(gogo);
+}
+
+// Make a call result type.
+
+Type*
+Type::make_call_multiple_result_type(Call_expression* call)
+{
+  return new Call_multiple_result_type(call);
+}
+
+// Class Struct_field.
+
+// Get the name of a field.
+
+const std::string&
+Struct_field::field_name() const
+{
+  const std::string& name(this->typed_identifier_.name());
+  if (!name.empty())
+    return name;
+  else
+    {
+      // This is called during parsing, before anything is lowered, so
+      // we have to be pretty careful to avoid dereferencing an
+      // unknown type name.
+      Type* t = this->typed_identifier_.type();
+      Type* dt = t;
+      if (t->classification() == Type::TYPE_POINTER)
+       {
+         // Very ugly.
+         Pointer_type* ptype = static_cast<Pointer_type*>(t);
+         dt = ptype->points_to();
+       }
+      if (dt->forward_declaration_type() != NULL)
+       return dt->forward_declaration_type()->name();
+      else if (dt->named_type() != NULL)
+       return dt->named_type()->name();
+      else if (t->is_error_type() || dt->is_error_type())
+       {
+         static const std::string error_string = "*error*";
+         return error_string;
+       }
+      else
+       {
+         // Avoid crashing in the erroneous case where T is named but
+         // DT is not.
+         gcc_assert(t != dt);
+         if (t->forward_declaration_type() != NULL)
+           return t->forward_declaration_type()->name();
+         else if (t->named_type() != NULL)
+           return t->named_type()->name();
+         else
+           gcc_unreachable();
+       }
+    }
+}
+
+// Class Struct_type.
+
+// Traversal.
+
+int
+Struct_type::do_traverse(Traverse* traverse)
+{
+  Struct_field_list* fields = this->fields_;
+  if (fields != NULL)
+    {
+      for (Struct_field_list::iterator p = fields->begin();
+          p != fields->end();
+          ++p)
+       {
+         if (Type::traverse(p->type(), traverse) == TRAVERSE_EXIT)
+           return TRAVERSE_EXIT;
+       }
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Verify that the struct type is complete and valid.
+
+bool
+Struct_type::do_verify()
+{
+  Struct_field_list* fields = this->fields_;
+  if (fields == NULL)
+    return true;
+  for (Struct_field_list::iterator p = fields->begin();
+       p != fields->end();
+       ++p)
+    {
+      Type* t = p->type();
+      if (t->is_undefined())
+       {
+         error_at(p->location(), "struct field type is incomplete");
+         p->set_type(Type::make_error_type());
+         return false;
+       }
+      else if (p->is_anonymous())
+       {
+         if (t->named_type() != NULL && t->points_to() != NULL)
+           {
+             error_at(p->location(), "embedded type may not be a pointer");
+             p->set_type(Type::make_error_type());
+             return false;
+           }
+       }
+    }
+  return true;
+}
+
+// Whether this contains a pointer.
+
+bool
+Struct_type::do_has_pointer() const
+{
+  const Struct_field_list* fields = this->fields();
+  if (fields == NULL)
+    return false;
+  for (Struct_field_list::const_iterator p = fields->begin();
+       p != fields->end();
+       ++p)
+    {
+      if (p->type()->has_pointer())
+       return true;
+    }
+  return false;
+}
+
+// Whether this type is identical to T.
+
+bool
+Struct_type::is_identical(const Struct_type* t) const
+{
+  const Struct_field_list* fields1 = this->fields();
+  const Struct_field_list* fields2 = t->fields();
+  if (fields1 == NULL || fields2 == NULL)
+    return fields1 == fields2;
+  Struct_field_list::const_iterator pf2 = fields2->begin();
+  for (Struct_field_list::const_iterator pf1 = fields1->begin();
+       pf1 != fields1->end();
+       ++pf1, ++pf2)
+    {
+      if (pf2 == fields2->end())
+       return false;
+      if (pf1->field_name() != pf2->field_name())
+       return false;
+      if (pf1->is_anonymous() != pf2->is_anonymous()
+         || !Type::are_identical(pf1->type(), pf2->type(), NULL))
+       return false;
+      if (!pf1->has_tag())
+       {
+         if (pf2->has_tag())
+           return false;
+       }
+      else
+       {
+         if (!pf2->has_tag())
+           return false;
+         if (pf1->tag() != pf2->tag())
+           return false;
+       }
+    }
+  if (pf2 != fields2->end())
+    return false;
+  return true;
+}
+
+// Whether this struct type has any hidden fields.
+
+bool
+Struct_type::struct_has_hidden_fields(const Named_type* within,
+                                     std::string* reason) const
+{
+  const Struct_field_list* fields = this->fields();
+  if (fields == NULL)
+    return false;
+  const Package* within_package = (within == NULL
+                                  ? NULL
+                                  : within->named_object()->package());
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf)
+    {
+      if (within_package != NULL
+         && !pf->is_anonymous()
+         && Gogo::is_hidden_name(pf->field_name()))
+       {
+         if (reason != NULL)
+           {
+             std::string within_name = within->named_object()->message_name();
+             std::string name = Gogo::message_name(pf->field_name());
+             size_t bufsize = 200 + within_name.length() + name.length();
+             char* buf = new char[bufsize];
+             snprintf(buf, bufsize,
+                      _("implicit assignment of %s%s%s hidden field %s%s%s"),
+                      open_quote, within_name.c_str(), close_quote,
+                      open_quote, name.c_str(), close_quote);
+             reason->assign(buf);
+             delete[] buf;
+           }
+         return true;
+       }
+
+      if (pf->type()->has_hidden_fields(within, reason))
+       return true;
+    }
+
+  return false;
+}
+
+// Hash code.
+
+unsigned int
+Struct_type::do_hash_for_method(Gogo* gogo) const
+{
+  unsigned int ret = 0;
+  if (this->fields() != NULL)
+    {
+      for (Struct_field_list::const_iterator pf = this->fields()->begin();
+          pf != this->fields()->end();
+          ++pf)
+       ret = (ret << 1) + pf->type()->hash_for_method(gogo);
+    }
+  return ret <<= 2;
+}
+
+// Find the local field NAME.
+
+const Struct_field*
+Struct_type::find_local_field(const std::string& name,
+                             unsigned int *pindex) const
+{
+  const Struct_field_list* fields = this->fields_;
+  if (fields == NULL)
+    return NULL;
+  unsigned int i = 0;
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf, ++i)
+    {
+      if (pf->field_name() == name)
+       {
+         if (pindex != NULL)
+           *pindex = i;
+         return &*pf;
+       }
+    }
+  return NULL;
+}
+
+// Return an expression for field NAME in STRUCT_EXPR, or NULL.
+
+Field_reference_expression*
+Struct_type::field_reference(Expression* struct_expr, const std::string& name,
+                            source_location location) const
+{
+  unsigned int depth;
+  return this->field_reference_depth(struct_expr, name, location, &depth);
+}
+
+// Return an expression for a field, along with the depth at which it
+// was found.
+
+Field_reference_expression*
+Struct_type::field_reference_depth(Expression* struct_expr,
+                                  const std::string& name,
+                                  source_location location,
+                                  unsigned int* depth) const
+{
+  const Struct_field_list* fields = this->fields_;
+  if (fields == NULL)
+    return NULL;
+
+  // Look for a field with this name.
+  unsigned int i = 0;
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf, ++i)
+    {
+      if (pf->field_name() == name)
+       {
+         *depth = 0;
+         return Expression::make_field_reference(struct_expr, i, location);
+       }
+    }
+
+  // Look for an anonymous field which contains a field with this
+  // name.
+  unsigned int found_depth = 0;
+  Field_reference_expression* ret = NULL;
+  i = 0;
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf, ++i)
+    {
+      if (!pf->is_anonymous())
+       continue;
+
+      Struct_type* st = pf->type()->deref()->struct_type();
+      if (st == NULL)
+       continue;
+
+      // Look for a reference using a NULL struct expression.  If we
+      // find one, fill in the struct expression with a reference to
+      // this field.
+      unsigned int subdepth;
+      Field_reference_expression* sub = st->field_reference_depth(NULL, name,
+                                                                 location,
+                                                                 &subdepth);
+      if (sub == NULL)
+       continue;
+
+      if (ret == NULL || subdepth < found_depth)
+       {
+         if (ret != NULL)
+           delete ret;
+         ret = sub;
+         found_depth = subdepth;
+         Expression* here = Expression::make_field_reference(struct_expr, i,
+                                                             location);
+         if (pf->type()->points_to() != NULL)
+           here = Expression::make_unary(OPERATOR_MULT, here, location);
+         while (sub->expr() != NULL)
+           {
+             sub = sub->expr()->deref()->field_reference_expression();
+             gcc_assert(sub != NULL);
+           }
+         sub->set_struct_expression(here);
+       }
+      else if (subdepth > found_depth)
+       delete sub;
+      else
+       {
+         // We do not handle ambiguity here--it should be handled by
+         // Type::bind_field_or_method.
+         delete sub;
+         found_depth = 0;
+         ret = NULL;
+       }
+    }
+
+  if (ret != NULL)
+    *depth = found_depth + 1;
+
+  return ret;
+}
+
+// Return the total number of fields, including embedded fields.
+
+unsigned int
+Struct_type::total_field_count() const
+{
+  if (this->fields_ == NULL)
+    return 0;
+  unsigned int ret = 0;
+  for (Struct_field_list::const_iterator pf = this->fields_->begin();
+       pf != this->fields_->end();
+       ++pf)
+    {
+      if (!pf->is_anonymous() || pf->type()->deref()->struct_type() == NULL)
+       ++ret;
+      else
+       ret += pf->type()->struct_type()->total_field_count();
+    }
+  return ret;
+}
+
+// Return whether NAME is an unexported field, for better error reporting.
+
+bool
+Struct_type::is_unexported_local_field(Gogo* gogo,
+                                      const std::string& name) const
+{
+  const Struct_field_list* fields = this->fields_;
+  if (fields != NULL)
+    {
+      for (Struct_field_list::const_iterator pf = fields->begin();
+          pf != fields->end();
+          ++pf)
+       {
+         const std::string& field_name(pf->field_name());
+         if (Gogo::is_hidden_name(field_name)
+             && name == Gogo::unpack_hidden_name(field_name)
+             && gogo->pack_hidden_name(name, false) != field_name)
+           return true;
+       }
+    }
+  return false;
+}
+
+// Finalize the methods of an unnamed struct.
+
+void
+Struct_type::finalize_methods(Gogo* gogo)
+{
+  Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
+}
+
+// Return the method NAME, or NULL if there isn't one or if it is
+// ambiguous.  Set *IS_AMBIGUOUS if the method exists but is
+// ambiguous.
+
+Method*
+Struct_type::method_function(const std::string& name, bool* is_ambiguous) const
+{
+  return Type::method_function(this->all_methods_, name, is_ambiguous);
+}
+
+// Get the tree for a struct type.
+
+tree
+Struct_type::do_get_tree(Gogo* gogo)
+{
+  tree type = make_node(RECORD_TYPE);
+  return this->fill_in_tree(gogo, type);
+}
+
+// Fill in the fields for a struct type.
+
+tree
+Struct_type::fill_in_tree(Gogo* gogo, tree type)
+{
+  tree field_trees = NULL_TREE;
+  tree* pp = &field_trees;
+  for (Struct_field_list::const_iterator p = this->fields_->begin();
+       p != this->fields_->end();
+       ++p)
+    {
+      std::string name = Gogo::unpack_hidden_name(p->field_name());
+      tree name_tree = get_identifier_with_length(name.data(), name.length());
+      tree field_type_tree = p->type()->get_tree(gogo);
+      if (field_type_tree == error_mark_node)
+       return error_mark_node;
+      tree field = build_decl(p->location(), FIELD_DECL, name_tree,
+                             field_type_tree);
+      DECL_CONTEXT(field) = type;
+      *pp = field;
+      pp = &DECL_CHAIN(field);
+    }
+
+  TYPE_FIELDS(type) = field_trees;
+
+  layout_type(type);
+
+  return type;
+}
+
+// Initialize struct fields.
+
+tree
+Struct_type::do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+{
+  if (this->fields_ == NULL || this->fields_->empty())
+    {
+      if (is_clear)
+       return NULL;
+      else
+       {
+         tree ret = build_constructor(type_tree,
+                                      VEC_alloc(constructor_elt, gc, 0));
+         TREE_CONSTANT(ret) = 1;
+         return ret;
+       }
+    }
+
+  bool is_constant = true;
+  bool any_fields_set = false;
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc,
+                                           this->fields_->size());
+  Struct_field_list::const_iterator p = this->fields_->begin();
+  for (tree field = TYPE_FIELDS(type_tree);
+       field != NULL_TREE;
+       field = DECL_CHAIN(field), ++p)
+    {
+      gcc_assert(p != this->fields_->end());
+      tree value = p->type()->get_init_tree(gogo, is_clear);
+      if (value != NULL)
+       {
+         constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+         elt->index = field;
+         elt->value = value;
+         any_fields_set = true;
+         if (!TREE_CONSTANT(value))
+           is_constant = false;
+       }
+    }
+  gcc_assert(p == this->fields_->end());
+
+  if (!any_fields_set)
+    {
+      gcc_assert(is_clear);
+      VEC_free(constructor_elt, gc, init);
+      return NULL;
+    }
+
+  tree ret = build_constructor(type_tree, init);
+  if (is_constant)
+    TREE_CONSTANT(ret) = 1;
+  return ret;
+}
+
+// The type of a struct type descriptor.
+
+Type*
+Struct_type::make_struct_type_descriptor_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      Type* tdt = Type::make_type_descriptor_type();
+      Type* ptdt = Type::make_type_descriptor_ptr_type();
+
+      Type* uintptr_type = Type::lookup_integer_type("uintptr");
+      Type* string_type = Type::lookup_string_type();
+      Type* pointer_string_type = Type::make_pointer_type(string_type);
+
+      Struct_type* sf =
+       Type::make_builtin_struct_type(5,
+                                      "name", pointer_string_type,
+                                      "pkgPath", pointer_string_type,
+                                      "typ", ptdt,
+                                      "tag", pointer_string_type,
+                                      "offset", uintptr_type);
+      Type* nsf = Type::make_builtin_named_type("structField", sf);
+
+      Type* slice_type = Type::make_array_type(nsf, NULL);
+
+      Struct_type* s = Type::make_builtin_struct_type(2,
+                                                     "", tdt,
+                                                     "fields", slice_type);
+
+      ret = Type::make_builtin_named_type("StructType", s);
+    }
+
+  return ret;
+}
+
+// Build a type descriptor for a struct type.
+
+Expression*
+Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  Type* stdt = Struct_type::make_struct_type_descriptor_type();
+
+  const Struct_field_list* fields = stdt->struct_type()->fields();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(2);
+
+  const Methods* methods = this->methods();
+  // A named struct should not have methods--the methods should attach
+  // to the named type.
+  gcc_assert(methods == NULL || name == NULL);
+
+  Struct_field_list::const_iterator ps = fields->begin();
+  gcc_assert(ps->field_name() == "commonType");
+  vals->push_back(this->type_descriptor_constructor(gogo,
+                                                   RUNTIME_TYPE_KIND_STRUCT,
+                                                   name, methods, true));
+
+  ++ps;
+  gcc_assert(ps->field_name() == "fields");
+
+  Expression_list* elements = new Expression_list();
+  elements->reserve(this->fields_->size());
+  Type* element_type = ps->type()->array_type()->element_type();
+  for (Struct_field_list::const_iterator pf = this->fields_->begin();
+       pf != this->fields_->end();
+       ++pf)
+    {
+      const Struct_field_list* f = element_type->struct_type()->fields();
+
+      Expression_list* fvals = new Expression_list();
+      fvals->reserve(5);
+
+      Struct_field_list::const_iterator q = f->begin();
+      gcc_assert(q->field_name() == "name");
+      if (pf->is_anonymous())
+       fvals->push_back(Expression::make_nil(bloc));
+      else
+       {
+         std::string n = Gogo::unpack_hidden_name(pf->field_name());
+         Expression* s = Expression::make_string(n, bloc);
+         fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
+       }
+
+      ++q;
+      gcc_assert(q->field_name() == "pkgPath");
+      if (!Gogo::is_hidden_name(pf->field_name()))
+       fvals->push_back(Expression::make_nil(bloc));
+      else
+       {
+         std::string n = Gogo::hidden_name_prefix(pf->field_name());
+         Expression* s = Expression::make_string(n, bloc);
+         fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
+       }
+
+      ++q;
+      gcc_assert(q->field_name() == "typ");
+      fvals->push_back(Expression::make_type_descriptor(pf->type(), bloc));
+
+      ++q;
+      gcc_assert(q->field_name() == "tag");
+      if (!pf->has_tag())
+       fvals->push_back(Expression::make_nil(bloc));
+      else
+       {
+         Expression* s = Expression::make_string(pf->tag(), bloc);
+         fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
+       }
+
+      ++q;
+      gcc_assert(q->field_name() == "offset");
+      fvals->push_back(Expression::make_struct_field_offset(this, &*pf));
+
+      Expression* v = Expression::make_struct_composite_literal(element_type,
+                                                               fvals, bloc);
+      elements->push_back(v);
+    }
+
+  vals->push_back(Expression::make_slice_composite_literal(ps->type(),
+                                                          elements, bloc));
+
+  return Expression::make_struct_composite_literal(stdt, vals, bloc);
+}
+
+// Reflection string.
+
+void
+Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
+{
+  ret->append("struct { ");
+
+  for (Struct_field_list::const_iterator p = this->fields_->begin();
+       p != this->fields_->end();
+       ++p)
+    {
+      if (p != this->fields_->begin())
+       ret->append("; ");
+      if (p->is_anonymous())
+       ret->push_back('?');
+      else
+       ret->append(Gogo::unpack_hidden_name(p->field_name()));
+      ret->push_back(' ');
+      this->append_reflection(p->type(), gogo, ret);
+
+      if (p->has_tag())
+       {
+         const std::string& tag(p->tag());
+         ret->append(" \"");
+         for (std::string::const_iterator p = tag.begin();
+              p != tag.end();
+              ++p)
+           {
+             if (*p == '\0')
+               ret->append("\\x00");
+             else if (*p == '\n')
+               ret->append("\\n");
+             else if (*p == '\t')
+               ret->append("\\t");
+             else if (*p == '"')
+               ret->append("\\\"");
+             else if (*p == '\\')
+               ret->append("\\\\");
+             else
+               ret->push_back(*p);
+           }
+         ret->push_back('"');
+       }
+    }
+
+  ret->append(" }");
+}
+
+// Mangled name.
+
+void
+Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('S');
+
+  const Struct_field_list* fields = this->fields_;
+  if (fields != NULL)
+    {
+      for (Struct_field_list::const_iterator p = fields->begin();
+          p != fields->end();
+          ++p)
+       {
+         if (p->is_anonymous())
+           ret->append("0_");
+         else
+           {
+             std::string n = Gogo::unpack_hidden_name(p->field_name());
+             char buf[20];
+             snprintf(buf, sizeof buf, "%u_",
+                      static_cast<unsigned int>(n.length()));
+             ret->append(buf);
+             ret->append(n);
+           }
+         this->append_mangled_name(p->type(), gogo, ret);
+         if (p->has_tag())
+           {
+             const std::string& tag(p->tag());
+             std::string out;
+             for (std::string::const_iterator p = tag.begin();
+                  p != tag.end();
+                  ++p)
+               {
+                 if (ISALNUM(*p) || *p == '_')
+                   out.push_back(*p);
+                 else
+                   {
+                     char buf[20];
+                     snprintf(buf, sizeof buf, ".%x.",
+                              static_cast<unsigned int>(*p));
+                     out.append(buf);
+                   }
+               }
+             char buf[20];
+             snprintf(buf, sizeof buf, "T%u_",
+                      static_cast<unsigned int>(out.length()));
+             ret->append(buf);
+             ret->append(out);
+           }
+       }
+    }
+
+  ret->push_back('e');
+}
+
+// Export.
+
+void
+Struct_type::do_export(Export* exp) const
+{
+  exp->write_c_string("struct { ");
+  const Struct_field_list* fields = this->fields_;
+  gcc_assert(fields != NULL);
+  for (Struct_field_list::const_iterator p = fields->begin();
+       p != fields->end();
+       ++p)
+    {
+      if (p->is_anonymous())
+       exp->write_string("? ");
+      else
+       {
+         exp->write_string(p->field_name());
+         exp->write_c_string(" ");
+       }
+      exp->write_type(p->type());
+
+      if (p->has_tag())
+       {
+         exp->write_c_string(" ");
+         Expression* expr = Expression::make_string(p->tag(),
+                                                    BUILTINS_LOCATION);
+         expr->export_expression(exp);
+         delete expr;
+       }
+
+      exp->write_c_string("; ");
+    }
+  exp->write_c_string("}");
+}
+
+// Import.
+
+Struct_type*
+Struct_type::do_import(Import* imp)
+{
+  imp->require_c_string("struct { ");
+  Struct_field_list* fields = new Struct_field_list;
+  if (imp->peek_char() != '}')
+    {
+      while (true)
+       {
+         std::string name;
+         if (imp->match_c_string("? "))
+           imp->advance(2);
+         else
+           {
+             name = imp->read_identifier();
+             imp->require_c_string(" ");
+           }
+         Type* ftype = imp->read_type();
+
+         Struct_field sf(Typed_identifier(name, ftype, imp->location()));
+
+         if (imp->peek_char() == ' ')
+           {
+             imp->advance(1);
+             Expression* expr = Expression::import_expression(imp);
+             String_expression* sexpr = expr->string_expression();
+             gcc_assert(sexpr != NULL);
+             sf.set_tag(sexpr->val());
+             delete sexpr;
+           }
+
+         imp->require_c_string("; ");
+         fields->push_back(sf);
+         if (imp->peek_char() == '}')
+           break;
+       }
+    }
+  imp->require_c_string("}");
+
+  return Type::make_struct_type(fields, imp->location());
+}
+
+// Make a struct type.
+
+Struct_type*
+Type::make_struct_type(Struct_field_list* fields,
+                      source_location location)
+{
+  return new Struct_type(fields, location);
+}
+
+// Class Array_type.
+
+// Whether two array types are identical.
+
+bool
+Array_type::is_identical(const Array_type* t) const
+{
+  if (!Type::are_identical(this->element_type(), t->element_type(), NULL))
+    return false;
+
+  Expression* l1 = this->length();
+  Expression* l2 = t->length();
+
+  // Slices of the same element type are identical.
+  if (l1 == NULL && l2 == NULL)
+    return true;
+
+  // Arrays of the same element type are identical if they have the
+  // same length.
+  if (l1 != NULL && l2 != NULL)
+    {
+      if (l1 == l2)
+       return true;
+
+      // Try to determine the lengths.  If we can't, assume the arrays
+      // are not identical.
+      bool ret = false;
+      mpz_t v1;
+      mpz_init(v1);
+      Type* type1;
+      mpz_t v2;
+      mpz_init(v2);
+      Type* type2;
+      if (l1->integer_constant_value(true, v1, &type1)
+         && l2->integer_constant_value(true, v2, &type2))
+       ret = mpz_cmp(v1, v2) == 0;
+      mpz_clear(v1);
+      mpz_clear(v2);
+      return ret;
+    }
+
+  // Otherwise the arrays are not identical.
+  return false;
+}
+
+// Traversal.
+
+int
+Array_type::do_traverse(Traverse* traverse)
+{
+  if (Type::traverse(this->element_type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  if (this->length_ != NULL
+      && Expression::traverse(&this->length_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Check that the length is valid.
+
+bool
+Array_type::verify_length()
+{
+  if (this->length_ == NULL)
+    return true;
+  if (!this->length_->is_constant())
+    {
+      error_at(this->length_->location(), "array bound is not constant");
+      return false;
+    }
+
+  mpz_t val;
+
+  Type* t = this->length_->type();
+  if (t->integer_type() != NULL)
+    {
+      Type* vt;
+      mpz_init(val);
+      if (!this->length_->integer_constant_value(true, val, &vt))
+       {
+         error_at(this->length_->location(),
+                  "array bound is not constant");
+         mpz_clear(val);
+         return false;
+       }
+    }
+  else if (t->float_type() != NULL)
+    {
+      Type* vt;
+      mpfr_t fval;
+      mpfr_init(fval);
+      if (!this->length_->float_constant_value(fval, &vt))
+       {
+         error_at(this->length_->location(),
+                  "array bound is not constant");
+         mpfr_clear(fval);
+         return false;
+       }
+      if (!mpfr_integer_p(fval))
+       {
+         error_at(this->length_->location(),
+                  "array bound truncated to integer");
+         mpfr_clear(fval);
+         return false;
+       }
+      mpz_init(val);
+      mpfr_get_z(val, fval, GMP_RNDN);
+      mpfr_clear(fval);
+    }
+  else
+    {
+      if (!t->is_error_type())
+       error_at(this->length_->location(), "array bound is not numeric");
+      return false;
+    }
+
+  if (mpz_sgn(val) < 0)
+    {
+      error_at(this->length_->location(), "negative array bound");
+      mpz_clear(val);
+      return false;
+    }
+
+  Type* int_type = Type::lookup_integer_type("int");
+  int tbits = int_type->integer_type()->bits();
+  int vbits = mpz_sizeinbase(val, 2);
+  if (vbits + 1 > tbits)
+    {
+      error_at(this->length_->location(), "array bound overflows");
+      mpz_clear(val);
+      return false;
+    }
+
+  mpz_clear(val);
+
+  return true;
+}
+
+// Verify the type.
+
+bool
+Array_type::do_verify()
+{
+  if (!this->verify_length())
+    {
+      this->length_ = Expression::make_error(this->length_->location());
+      return false;
+    }
+  return true;
+}
+
+// Array type hash code.
+
+unsigned int
+Array_type::do_hash_for_method(Gogo* gogo) const
+{
+  // There is no very convenient way to get a hash code for the
+  // length.
+  return this->element_type_->hash_for_method(gogo) + 1;
+}
+
+// See if the expression passed to make is suitable.  The first
+// argument is required, and gives the length.  An optional second
+// argument is permitted for the capacity.
+
+bool
+Array_type::do_check_make_expression(Expression_list* args,
+                                    source_location location)
+{
+  gcc_assert(this->length_ == NULL);
+  if (args == NULL || args->empty())
+    {
+      error_at(location, "length required when allocating a slice");
+      return false;
+    }
+  else if (args->size() > 2)
+    {
+      error_at(location, "too many expressions passed to make");
+      return false;
+    }
+  else
+    {
+      if (!Type::check_int_value(args->front(),
+                                _("bad length when making slice"), location))
+       return false;
+
+      if (args->size() > 1)
+       {
+         if (!Type::check_int_value(args->back(),
+                                    _("bad capacity when making slice"),
+                                    location))
+           return false;
+       }
+
+      return true;
+    }
+}
+
+// Get a tree for the length of a fixed array.  The length may be
+// computed using a function call, so we must only evaluate it once.
+
+tree
+Array_type::get_length_tree(Gogo* gogo)
+{
+  gcc_assert(this->length_ != NULL);
+  if (this->length_tree_ == NULL_TREE)
+    {
+      mpz_t val;
+      mpz_init(val);
+      Type* t;
+      if (this->length_->integer_constant_value(true, val, &t))
+       {
+         if (t == NULL)
+           t = Type::lookup_integer_type("int");
+         else if (t->is_abstract())
+           t = t->make_non_abstract_type();
+         tree tt = t->get_tree(gogo);
+         this->length_tree_ = Expression::integer_constant_tree(val, tt);
+         mpz_clear(val);
+       }
+      else
+       {
+         mpz_clear(val);
+
+         // Make up a translation context for the array length
+         // expression.  FIXME: This won't work in general.
+         Translate_context context(gogo, NULL, NULL, NULL_TREE);
+         tree len = this->length_->get_tree(&context);
+         len = convert_to_integer(integer_type_node, len);
+         this->length_tree_ = save_expr(len);
+       }
+    }
+  return this->length_tree_;
+}
+
+// Get a tree for the type of this array.  A fixed array is simply
+// represented as ARRAY_TYPE with the appropriate index--i.e., it is
+// just like an array in C.  An open array is a struct with three
+// fields: a data pointer, the length, and the capacity.
+
+tree
+Array_type::do_get_tree(Gogo* gogo)
+{
+  if (this->length_ == NULL)
+    {
+      tree struct_type = gogo->slice_type_tree(void_type_node);
+      return this->fill_in_tree(gogo, struct_type);
+    }
+  else
+    {
+      tree element_type_tree = this->element_type_->get_tree(gogo);
+      tree length_tree = this->get_length_tree(gogo);
+      if (element_type_tree == error_mark_node
+         || length_tree == error_mark_node)
+       return error_mark_node;
+
+      length_tree = fold_convert(sizetype, length_tree);
+
+      // build_index_type takes the maximum index, which is one less
+      // than the length.
+      tree index_type = build_index_type(fold_build2(MINUS_EXPR, sizetype,
+                                                    length_tree,
+                                                    size_one_node));
+
+      return build_array_type(element_type_tree, index_type);
+    }
+}
+
+// Fill in the fields for a slice type.  This is used for named slice
+// types.
+
+tree
+Array_type::fill_in_tree(Gogo* gogo, tree struct_type)
+{
+  gcc_assert(this->length_ == NULL);
+
+  tree element_type_tree = this->element_type_->get_tree(gogo);
+  tree field = TYPE_FIELDS(struct_type);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
+  gcc_assert(POINTER_TYPE_P(TREE_TYPE(field))
+            && TREE_TYPE(TREE_TYPE(field)) == void_type_node);
+  TREE_TYPE(field) = build_pointer_type(element_type_tree);
+
+  return struct_type;
+}
+
+// Return an initializer for an array type.
+
+tree
+Array_type::do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+{
+  if (this->length_ == NULL)
+    {
+      // Open array.
+
+      if (is_clear)
+       return NULL;
+
+      gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE);
+
+      VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 3);
+
+      for (tree field = TYPE_FIELDS(type_tree);
+          field != NULL_TREE;
+          field = DECL_CHAIN(field))
+       {
+         constructor_elt* elt = VEC_quick_push(constructor_elt, init,
+                                               NULL);
+         elt->index = field;
+         elt->value = fold_convert(TREE_TYPE(field), size_zero_node);
+       }
+
+      tree ret = build_constructor(type_tree, init);
+      TREE_CONSTANT(ret) = 1;
+      return ret;
+    }
+  else
+    {
+      // Fixed array.
+
+      tree value = this->element_type_->get_init_tree(gogo, is_clear);
+      if (value == NULL)
+       return NULL;
+
+      tree length_tree = this->get_length_tree(gogo);
+      length_tree = fold_convert(sizetype, length_tree);
+      tree range = build2(RANGE_EXPR, sizetype, size_zero_node,
+                         fold_build2(MINUS_EXPR, sizetype,
+                                     length_tree, size_one_node));
+      tree ret = build_constructor_single(type_tree, range, value);
+      if (TREE_CONSTANT(value))
+       TREE_CONSTANT(ret) = 1;
+      return ret;
+    }
+}
+
+// Handle the builtin make function for a slice.
+
+tree
+Array_type::do_make_expression_tree(Translate_context* context,
+                                   Expression_list* args,
+                                   source_location location)
+{
+  gcc_assert(this->length_ == NULL);
+
+  Gogo* gogo = context->gogo();
+  tree type_tree = this->get_tree(gogo);
+  if (type_tree == error_mark_node)
+    return error_mark_node;
+
+  tree values_field = TYPE_FIELDS(type_tree);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(values_field)),
+                   "__values") == 0);
+
+  tree count_field = DECL_CHAIN(values_field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(count_field)),
+                   "__count") == 0);
+
+  tree element_type_tree = this->element_type_->get_tree(gogo);
+  if (element_type_tree == error_mark_node)
+    return error_mark_node;
+  tree element_size_tree = TYPE_SIZE_UNIT(element_type_tree);
+
+  tree value = this->element_type_->get_init_tree(gogo, true);
+
+  // The first argument is the number of elements, the optional second
+  // argument is the capacity.
+  gcc_assert(args != NULL && args->size() >= 1 && args->size() <= 2);
+
+  tree length_tree = args->front()->get_tree(context);
+  if (length_tree == error_mark_node)
+    return error_mark_node;
+  if (!DECL_P(length_tree))
+    length_tree = save_expr(length_tree);
+  if (!INTEGRAL_TYPE_P(TREE_TYPE(length_tree)))
+    length_tree = convert_to_integer(TREE_TYPE(count_field), length_tree);
+
+  tree bad_index = Expression::check_bounds(length_tree,
+                                           TREE_TYPE(count_field),
+                                           NULL_TREE, location);
+
+  length_tree = fold_convert_loc(location, TREE_TYPE(count_field), length_tree);
+  tree capacity_tree;
+  if (args->size() == 1)
+    capacity_tree = length_tree;
+  else
+    {
+      capacity_tree = args->back()->get_tree(context);
+      if (capacity_tree == error_mark_node)
+       return error_mark_node;
+      if (!DECL_P(capacity_tree))
+       capacity_tree = save_expr(capacity_tree);
+      if (!INTEGRAL_TYPE_P(TREE_TYPE(capacity_tree)))
+       capacity_tree = convert_to_integer(TREE_TYPE(count_field),
+                                          capacity_tree);
+
+      bad_index = Expression::check_bounds(capacity_tree,
+                                          TREE_TYPE(count_field),
+                                          bad_index, location);
+
+      tree chktype = (((TYPE_SIZE(TREE_TYPE(capacity_tree))
+                       > TYPE_SIZE(TREE_TYPE(length_tree)))
+                      || ((TYPE_SIZE(TREE_TYPE(capacity_tree))
+                           == TYPE_SIZE(TREE_TYPE(length_tree)))
+                          && TYPE_UNSIGNED(TREE_TYPE(capacity_tree))))
+                     ? TREE_TYPE(capacity_tree)
+                     : TREE_TYPE(length_tree));
+      tree chk = fold_build2_loc(location, LT_EXPR, boolean_type_node,
+                                fold_convert_loc(location, chktype,
+                                                 capacity_tree),
+                                fold_convert_loc(location, chktype,
+                                                 length_tree));
+      if (bad_index == NULL_TREE)
+       bad_index = chk;
+      else
+       bad_index = fold_build2_loc(location, TRUTH_OR_EXPR, boolean_type_node,
+                                   bad_index, chk);
+
+      capacity_tree = fold_convert_loc(location, TREE_TYPE(count_field),
+                                      capacity_tree);
+    }
+
+  tree size_tree = fold_build2_loc(location, MULT_EXPR, sizetype,
+                                  element_size_tree,
+                                  fold_convert_loc(location, sizetype,
+                                                   capacity_tree));
+
+  tree chk = fold_build2_loc(location, TRUTH_AND_EXPR, boolean_type_node,
+                            fold_build2_loc(location, GT_EXPR,
+                                            boolean_type_node,
+                                            fold_convert_loc(location,
+                                                             sizetype,
+                                                             capacity_tree),
+                                            size_zero_node),
+                            fold_build2_loc(location, LT_EXPR,
+                                            boolean_type_node,
+                                            size_tree, element_size_tree));
+  if (bad_index == NULL_TREE)
+    bad_index = chk;
+  else
+    bad_index = fold_build2_loc(location, TRUTH_OR_EXPR, boolean_type_node,
+                               bad_index, chk);
+
+  tree space = context->gogo()->allocate_memory(this->element_type_,
+                                               size_tree, location);
+
+  if (value != NULL_TREE)
+    space = save_expr(space);
+
+  space = fold_convert(TREE_TYPE(values_field), space);
+
+  if (bad_index != NULL_TREE && bad_index != boolean_false_node)
+    {
+      tree crash = Gogo::runtime_error(RUNTIME_ERROR_MAKE_SLICE_OUT_OF_BOUNDS,
+                                      location);
+      space = build2(COMPOUND_EXPR, TREE_TYPE(space),
+                    build3(COND_EXPR, void_type_node,
+                           bad_index, crash, NULL_TREE),
+                    space);
+    }
+
+  tree constructor = gogo->slice_constructor(type_tree, space, length_tree,
+                                            capacity_tree);
+
+  if (value == NULL_TREE)
+    {
+      // The array contents are zero initialized.
+      return constructor;
+    }
+
+  // The elements must be initialized.
+
+  tree max = fold_build2_loc(location, MINUS_EXPR, TREE_TYPE(count_field),
+                            capacity_tree,
+                            fold_convert_loc(location, TREE_TYPE(count_field),
+                                             integer_one_node));
+
+  tree array_type = build_array_type(element_type_tree,
+                                    build_index_type(max));
+
+  tree value_pointer = fold_convert_loc(location,
+                                       build_pointer_type(array_type),
+                                       space);
+
+  tree range = build2(RANGE_EXPR, sizetype, size_zero_node, max);
+  tree space_init = build_constructor_single(array_type, range, value);
+
+  return build2(COMPOUND_EXPR, TREE_TYPE(space),
+               build2(MODIFY_EXPR, void_type_node,
+                      build_fold_indirect_ref(value_pointer),
+                      space_init),
+               constructor);
+}
+
+// Return a tree for a pointer to the values in ARRAY.
+
+tree
+Array_type::value_pointer_tree(Gogo*, tree array) const
+{
+  tree ret;
+  if (this->length() != NULL)
+    {
+      // Fixed array.
+      ret = fold_convert(build_pointer_type(TREE_TYPE(TREE_TYPE(array))),
+                        build_fold_addr_expr(array));
+    }
+  else
+    {
+      // Open array.
+      tree field = TYPE_FIELDS(TREE_TYPE(array));
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
+                       "__values") == 0);
+      ret = fold_build3(COMPONENT_REF, TREE_TYPE(field), array, field,
+                       NULL_TREE);
+    }
+  if (TREE_CONSTANT(array))
+    TREE_CONSTANT(ret) = 1;
+  return ret;
+}
+
+// Return a tree for the length of the array ARRAY which has this
+// type.
+
+tree
+Array_type::length_tree(Gogo* gogo, tree array)
+{
+  if (this->length_ != NULL)
+    {
+      if (TREE_CODE(array) == SAVE_EXPR)
+       return fold_convert(integer_type_node, this->get_length_tree(gogo));
+      else
+       return omit_one_operand(integer_type_node,
+                               this->get_length_tree(gogo), array);
+    }
+
+  // This is an open array.  We need to read the length field.
+
+  tree type = TREE_TYPE(array);
+  gcc_assert(TREE_CODE(type) == RECORD_TYPE);
+
+  tree field = DECL_CHAIN(TYPE_FIELDS(type));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
+
+  tree ret = build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE);
+  if (TREE_CONSTANT(array))
+    TREE_CONSTANT(ret) = 1;
+  return ret;
+}
+
+// Return a tree for the capacity of the array ARRAY which has this
+// type.
+
+tree
+Array_type::capacity_tree(Gogo* gogo, tree array)
+{
+  if (this->length_ != NULL)
+    return omit_one_operand(sizetype, this->get_length_tree(gogo), array);
+
+  // This is an open array.  We need to read the capacity field.
+
+  tree type = TREE_TYPE(array);
+  gcc_assert(TREE_CODE(type) == RECORD_TYPE);
+
+  tree field = DECL_CHAIN(DECL_CHAIN(TYPE_FIELDS(type)));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
+
+  return build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE);
+}
+
+// Export.
+
+void
+Array_type::do_export(Export* exp) const
+{
+  exp->write_c_string("[");
+  if (this->length_ != NULL)
+    this->length_->export_expression(exp);
+  exp->write_c_string("] ");
+  exp->write_type(this->element_type_);
+}
+
+// Import.
+
+Array_type*
+Array_type::do_import(Import* imp)
+{
+  imp->require_c_string("[");
+  Expression* length;
+  if (imp->peek_char() == ']')
+    length = NULL;
+  else
+    length = Expression::import_expression(imp);
+  imp->require_c_string("] ");
+  Type* element_type = imp->read_type();
+  return Type::make_array_type(element_type, length);
+}
+
+// The type of an array type descriptor.
+
+Type*
+Array_type::make_array_type_descriptor_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      Type* tdt = Type::make_type_descriptor_type();
+      Type* ptdt = Type::make_type_descriptor_ptr_type();
+
+      Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+      Struct_type* sf =
+       Type::make_builtin_struct_type(3,
+                                      "", tdt,
+                                      "elem", ptdt,
+                                      "len", uintptr_type);
+
+      ret = Type::make_builtin_named_type("ArrayType", sf);
+    }
+
+  return ret;
+}
+
+// The type of an slice type descriptor.
+
+Type*
+Array_type::make_slice_type_descriptor_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      Type* tdt = Type::make_type_descriptor_type();
+      Type* ptdt = Type::make_type_descriptor_ptr_type();
+
+      Struct_type* sf =
+       Type::make_builtin_struct_type(2,
+                                      "", tdt,
+                                      "elem", ptdt);
+
+      ret = Type::make_builtin_named_type("SliceType", sf);
+    }
+
+  return ret;
+}
+
+// Build a type descriptor for an array/slice type.
+
+Expression*
+Array_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  if (this->length_ != NULL)
+    return this->array_type_descriptor(gogo, name);
+  else
+    return this->slice_type_descriptor(gogo, name);
+}
+
+// Build a type descriptor for an array type.
+
+Expression*
+Array_type::array_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  Type* atdt = Array_type::make_array_type_descriptor_type();
+
+  const Struct_field_list* fields = atdt->struct_type()->fields();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(3);
+
+  Struct_field_list::const_iterator p = fields->begin();
+  gcc_assert(p->field_name() == "commonType");
+  vals->push_back(this->type_descriptor_constructor(gogo,
+                                                   RUNTIME_TYPE_KIND_ARRAY,
+                                                   name, NULL, true));
+
+  ++p;
+  gcc_assert(p->field_name() == "elem");
+  vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "len");
+  vals->push_back(this->length_);
+
+  ++p;
+  gcc_assert(p == fields->end());
+
+  return Expression::make_struct_composite_literal(atdt, vals, bloc);
+}
+
+// Build a type descriptor for a slice type.
+
+Expression*
+Array_type::slice_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  Type* stdt = Array_type::make_slice_type_descriptor_type();
+
+  const Struct_field_list* fields = stdt->struct_type()->fields();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(2);
+
+  Struct_field_list::const_iterator p = fields->begin();
+  gcc_assert(p->field_name() == "commonType");
+  vals->push_back(this->type_descriptor_constructor(gogo,
+                                                   RUNTIME_TYPE_KIND_SLICE,
+                                                   name, NULL, true));
+
+  ++p;
+  gcc_assert(p->field_name() == "elem");
+  vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc));
+
+  ++p;
+  gcc_assert(p == fields->end());
+
+  return Expression::make_struct_composite_literal(stdt, vals, bloc);
+}
+
+// Reflection string.
+
+void
+Array_type::do_reflection(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('[');
+  if (this->length_ != NULL)
+    {
+      mpz_t val;
+      mpz_init(val);
+      Type* type;
+      if (!this->length_->integer_constant_value(true, val, &type))
+       error_at(this->length_->location(),
+                "array length must be integer constant expression");
+      else if (mpz_cmp_si(val, 0) < 0)
+       error_at(this->length_->location(), "array length is negative");
+      else if (mpz_cmp_ui(val, mpz_get_ui(val)) != 0)
+       error_at(this->length_->location(), "array length is too large");
+      else
+       {
+         char buf[50];
+         snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val));
+         ret->append(buf);
+       }
+      mpz_clear(val);
+    }
+  ret->push_back(']');
+
+  this->append_reflection(this->element_type_, gogo, ret);
+}
+
+// Mangled name.
+
+void
+Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('A');
+  this->append_mangled_name(this->element_type_, gogo, ret);
+  if (this->length_ != NULL)
+    {
+      mpz_t val;
+      mpz_init(val);
+      Type* type;
+      if (!this->length_->integer_constant_value(true, val, &type))
+       error_at(this->length_->location(),
+                "array length must be integer constant expression");
+      else if (mpz_cmp_si(val, 0) < 0)
+       error_at(this->length_->location(), "array length is negative");
+      else if (mpz_cmp_ui(val, mpz_get_ui(val)) != 0)
+       error_at(this->length_->location(), "array size is too large");
+      else
+       {
+         char buf[50];
+         snprintf(buf, sizeof buf, "%lu", mpz_get_ui(val));
+         ret->append(buf);
+       }
+      mpz_clear(val);
+    }
+  ret->push_back('e');
+}
+
+// Make an array type.
+
+Array_type*
+Type::make_array_type(Type* element_type, Expression* length)
+{
+  return new Array_type(element_type, length);
+}
+
+// Class Map_type.
+
+// Traversal.
+
+int
+Map_type::do_traverse(Traverse* traverse)
+{
+  if (Type::traverse(this->key_type_, traverse) == TRAVERSE_EXIT
+      || Type::traverse(this->val_type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Check that the map type is OK.
+
+bool
+Map_type::do_verify()
+{
+  if (this->key_type_->struct_type() != NULL
+      || this->key_type_->array_type() != NULL)
+    {
+      error_at(this->location_, "invalid map key type");
+      return false;
+    }
+  return true;
+}
+
+// Whether two map types are identical.
+
+bool
+Map_type::is_identical(const Map_type* t) const
+{
+  return (Type::are_identical(this->key_type(), t->key_type(), NULL)
+         && Type::are_identical(this->val_type(), t->val_type(), NULL));
+}
+
+// Hash code.
+
+unsigned int
+Map_type::do_hash_for_method(Gogo* gogo) const
+{
+  return (this->key_type_->hash_for_method(gogo)
+         + this->val_type_->hash_for_method(gogo)
+         + 2);
+}
+
+// Check that a call to the builtin make function is valid.  For a map
+// the optional argument is the number of spaces to preallocate for
+// values.
+
+bool
+Map_type::do_check_make_expression(Expression_list* args,
+                                  source_location location)
+{
+  if (args != NULL && !args->empty())
+    {
+      if (!Type::check_int_value(args->front(), _("bad size when making map"),
+                                location))
+       return false;
+      else if (args->size() > 1)
+       {
+         error_at(location, "too many arguments when making map");
+         return false;
+       }
+    }
+  return true;
+}
+
+// Get a tree for a map type.  A map type is represented as a pointer
+// to a struct.  The struct is __go_map in libgo/map.h.
+
+tree
+Map_type::do_get_tree(Gogo* gogo)
+{
+  static tree type_tree;
+  if (type_tree == NULL_TREE)
+    {
+      tree struct_type = make_node(RECORD_TYPE);
+
+      tree map_descriptor_type = gogo->map_descriptor_type();
+      tree const_map_descriptor_type =
+       build_qualified_type(map_descriptor_type, TYPE_QUAL_CONST);
+      tree name = get_identifier("__descriptor");
+      tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL, name,
+                             build_pointer_type(const_map_descriptor_type));
+      DECL_CONTEXT(field) = struct_type;
+      TYPE_FIELDS(struct_type) = field;
+      tree last_field = field;
+
+      name = get_identifier("__element_count");
+      field = build_decl(BUILTINS_LOCATION, FIELD_DECL, name, sizetype);
+      DECL_CONTEXT(field) = struct_type;
+      DECL_CHAIN(last_field) = field;
+      last_field = field;
+
+      name = get_identifier("__bucket_count");
+      field = build_decl(BUILTINS_LOCATION, FIELD_DECL, name, sizetype);
+      DECL_CONTEXT(field) = struct_type;
+      DECL_CHAIN(last_field) = field;
+      last_field = field;
+
+      name = get_identifier("__buckets");
+      field = build_decl(BUILTINS_LOCATION, FIELD_DECL, name,
+                        build_pointer_type(ptr_type_node));
+      DECL_CONTEXT(field) = struct_type;
+      DECL_CHAIN(last_field) = field;
+
+      layout_type(struct_type);
+
+      // Give the struct a name for better debugging info.
+      name = get_identifier("__go_map");
+      tree type_decl = build_decl(BUILTINS_LOCATION, TYPE_DECL, name,
+                                 struct_type);
+      DECL_ARTIFICIAL(type_decl) = 1;
+      TYPE_NAME(struct_type) = type_decl;
+      go_preserve_from_gc(type_decl);
+      rest_of_decl_compilation(type_decl, 1, 0);
+
+      type_tree = build_pointer_type(struct_type);
+      go_preserve_from_gc(type_tree);
+    }
+
+  return type_tree;
+}
+
+// Initialize a map.
+
+tree
+Map_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  if (is_clear)
+    return NULL;
+  return fold_convert(type_tree, null_pointer_node);
+}
+
+// Return an expression for a newly allocated map.
+
+tree
+Map_type::do_make_expression_tree(Translate_context* context,
+                                 Expression_list* args,
+                                 source_location location)
+{
+  tree bad_index = NULL_TREE;
+
+  tree expr_tree;
+  if (args == NULL || args->empty())
+    expr_tree = size_zero_node;
+  else
+    {
+      expr_tree = args->front()->get_tree(context);
+      if (expr_tree == error_mark_node)
+       return error_mark_node;
+      if (!DECL_P(expr_tree))
+       expr_tree = save_expr(expr_tree);
+      if (!INTEGRAL_TYPE_P(TREE_TYPE(expr_tree)))
+       expr_tree = convert_to_integer(sizetype, expr_tree);
+      bad_index = Expression::check_bounds(expr_tree, sizetype, bad_index,
+                                          location);
+    }
+
+  tree map_type = this->get_tree(context->gogo());
+
+  static tree new_map_fndecl;
+  tree ret = Gogo::call_builtin(&new_map_fndecl,
+                               location,
+                               "__go_new_map",
+                               2,
+                               map_type,
+                               TREE_TYPE(TYPE_FIELDS(TREE_TYPE(map_type))),
+                               context->gogo()->map_descriptor(this),
+                               sizetype,
+                               expr_tree);
+  // This can panic if the capacity is out of range.
+  TREE_NOTHROW(new_map_fndecl) = 0;
+
+  if (bad_index == NULL_TREE)
+    return ret;
+  else
+    {
+      tree crash = Gogo::runtime_error(RUNTIME_ERROR_MAKE_MAP_OUT_OF_BOUNDS,
+                                      location);
+      return build2(COMPOUND_EXPR, TREE_TYPE(ret),
+                   build3(COND_EXPR, void_type_node,
+                          bad_index, crash, NULL_TREE),
+                   ret);
+    }
+}
+
+// The type of a map type descriptor.
+
+Type*
+Map_type::make_map_type_descriptor_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      Type* tdt = Type::make_type_descriptor_type();
+      Type* ptdt = Type::make_type_descriptor_ptr_type();
+
+      Struct_type* sf =
+       Type::make_builtin_struct_type(3,
+                                      "", tdt,
+                                      "key", ptdt,
+                                      "elem", ptdt);
+
+      ret = Type::make_builtin_named_type("MapType", sf);
+    }
+
+  return ret;
+}
+
+// Build a type descriptor for a map type.
+
+Expression*
+Map_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  Type* mtdt = Map_type::make_map_type_descriptor_type();
+
+  const Struct_field_list* fields = mtdt->struct_type()->fields();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(3);
+
+  Struct_field_list::const_iterator p = fields->begin();
+  gcc_assert(p->field_name() == "commonType");
+  vals->push_back(this->type_descriptor_constructor(gogo,
+                                                   RUNTIME_TYPE_KIND_MAP,
+                                                   name, NULL, true));
+
+  ++p;
+  gcc_assert(p->field_name() == "key");
+  vals->push_back(Expression::make_type_descriptor(this->key_type_, bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "elem");
+  vals->push_back(Expression::make_type_descriptor(this->val_type_, bloc));
+
+  ++p;
+  gcc_assert(p == fields->end());
+
+  return Expression::make_struct_composite_literal(mtdt, vals, bloc);
+}
+
+// Reflection string for a map.
+
+void
+Map_type::do_reflection(Gogo* gogo, std::string* ret) const
+{
+  ret->append("map[");
+  this->append_reflection(this->key_type_, gogo, ret);
+  ret->append("] ");
+  this->append_reflection(this->val_type_, gogo, ret);
+}
+
+// Mangled name for a map.
+
+void
+Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('M');
+  this->append_mangled_name(this->key_type_, gogo, ret);
+  ret->append("__");
+  this->append_mangled_name(this->val_type_, gogo, ret);
+}
+
+// Export a map type.
+
+void
+Map_type::do_export(Export* exp) const
+{
+  exp->write_c_string("map [");
+  exp->write_type(this->key_type_);
+  exp->write_c_string("] ");
+  exp->write_type(this->val_type_);
+}
+
+// Import a map type.
+
+Map_type*
+Map_type::do_import(Import* imp)
+{
+  imp->require_c_string("map [");
+  Type* key_type = imp->read_type();
+  imp->require_c_string("] ");
+  Type* val_type = imp->read_type();
+  return Type::make_map_type(key_type, val_type, imp->location());
+}
+
+// Make a map type.
+
+Map_type*
+Type::make_map_type(Type* key_type, Type* val_type, source_location location)
+{
+  return new Map_type(key_type, val_type, location);
+}
+
+// Class Channel_type.
+
+// Hash code.
+
+unsigned int
+Channel_type::do_hash_for_method(Gogo* gogo) const
+{
+  unsigned int ret = 0;
+  if (this->may_send_)
+    ret += 1;
+  if (this->may_receive_)
+    ret += 2;
+  if (this->element_type_ != NULL)
+    ret += this->element_type_->hash_for_method(gogo) << 2;
+  return ret << 3;
+}
+
+// Whether this type is the same as T.
+
+bool
+Channel_type::is_identical(const Channel_type* t) const
+{
+  if (!Type::are_identical(this->element_type(), t->element_type(), NULL))
+    return false;
+  return (this->may_send_ == t->may_send_
+         && this->may_receive_ == t->may_receive_);
+}
+
+// Check whether the parameters for a call to the builtin function
+// make are OK for a channel.  A channel can take an optional single
+// parameter which is the buffer size.
+
+bool
+Channel_type::do_check_make_expression(Expression_list* args,
+                                     source_location location)
+{
+  if (args != NULL && !args->empty())
+    {
+      if (!Type::check_int_value(args->front(),
+                                _("bad buffer size when making channel"),
+                                location))
+       return false;
+      else if (args->size() > 1)
+       {
+         error_at(location, "too many arguments when making channel");
+         return false;
+       }
+    }
+  return true;
+}
+
+// Return the tree for a channel type.  A channel is a pointer to a
+// __go_channel struct.  The __go_channel struct is defined in
+// libgo/runtime/channel.h.
+
+tree
+Channel_type::do_get_tree(Gogo*)
+{
+  static tree type_tree;
+  if (type_tree == NULL_TREE)
+    {
+      tree ret = make_node(RECORD_TYPE);
+      TYPE_NAME(ret) = get_identifier("__go_channel");
+      TYPE_STUB_DECL(ret) = build_decl(BUILTINS_LOCATION, TYPE_DECL, NULL_TREE,
+                                      ret);
+      type_tree = build_pointer_type(ret);
+      go_preserve_from_gc(type_tree);
+    }
+  return type_tree;
+}
+
+// Initialize a channel variable.
+
+tree
+Channel_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  if (is_clear)
+    return NULL;
+  return fold_convert(type_tree, null_pointer_node);
+}
+
+// Handle the builtin function make for a channel.
+
+tree
+Channel_type::do_make_expression_tree(Translate_context* context,
+                                     Expression_list* args,
+                                     source_location location)
+{
+  Gogo* gogo = context->gogo();
+  tree channel_type = this->get_tree(gogo);
+
+  tree element_tree = this->element_type_->get_tree(gogo);
+  tree element_size_tree = size_in_bytes(element_tree);
+
+  tree bad_index = NULL_TREE;
+
+  tree expr_tree;
+  if (args == NULL || args->empty())
+    expr_tree = size_zero_node;
+  else
+    {
+      expr_tree = args->front()->get_tree(context);
+      if (expr_tree == error_mark_node)
+       return error_mark_node;
+      if (!DECL_P(expr_tree))
+       expr_tree = save_expr(expr_tree);
+      if (!INTEGRAL_TYPE_P(TREE_TYPE(expr_tree)))
+       expr_tree = convert_to_integer(sizetype, expr_tree);
+      bad_index = Expression::check_bounds(expr_tree, sizetype, bad_index,
+                                          location);
+    }
+
+  static tree new_channel_fndecl;
+  tree ret = Gogo::call_builtin(&new_channel_fndecl,
+                               location,
+                               "__go_new_channel",
+                               2,
+                               channel_type,
+                               sizetype,
+                               element_size_tree,
+                               sizetype,
+                               expr_tree);
+  // This can panic if the capacity is out of range.
+  TREE_NOTHROW(new_channel_fndecl) = 0;
+
+  if (bad_index == NULL_TREE)
+    return ret;
+  else
+    {
+      tree crash = Gogo::runtime_error(RUNTIME_ERROR_MAKE_CHAN_OUT_OF_BOUNDS,
+                                      location);
+      return build2(COMPOUND_EXPR, TREE_TYPE(ret),
+                   build3(COND_EXPR, void_type_node,
+                          bad_index, crash, NULL_TREE),
+                   ret);
+    }
+}
+
+// Build a type descriptor for a channel type.
+
+Type*
+Channel_type::make_chan_type_descriptor_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      Type* tdt = Type::make_type_descriptor_type();
+      Type* ptdt = Type::make_type_descriptor_ptr_type();
+
+      Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+      Struct_type* sf =
+       Type::make_builtin_struct_type(3,
+                                      "", tdt,
+                                      "elem", ptdt,
+                                      "dir", uintptr_type);
+
+      ret = Type::make_builtin_named_type("ChanType", sf);
+    }
+
+  return ret;
+}
+
+// Build a type descriptor for a map type.
+
+Expression*
+Channel_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  Type* ctdt = Channel_type::make_chan_type_descriptor_type();
+
+  const Struct_field_list* fields = ctdt->struct_type()->fields();
+
+  Expression_list* vals = new Expression_list();
+  vals->reserve(3);
+
+  Struct_field_list::const_iterator p = fields->begin();
+  gcc_assert(p->field_name() == "commonType");
+  vals->push_back(this->type_descriptor_constructor(gogo,
+                                                   RUNTIME_TYPE_KIND_CHAN,
+                                                   name, NULL, true));
+
+  ++p;
+  gcc_assert(p->field_name() == "elem");
+  vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc));
+
+  ++p;
+  gcc_assert(p->field_name() == "dir");
+  // These bits must match the ones in libgo/runtime/go-type.h.
+  int val = 0;
+  if (this->may_receive_)
+    val |= 1;
+  if (this->may_send_)
+    val |= 2;
+  mpz_t iv;
+  mpz_init_set_ui(iv, val);
+  vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
+  mpz_clear(iv);
+
+  ++p;
+  gcc_assert(p == fields->end());
+
+  return Expression::make_struct_composite_literal(ctdt, vals, bloc);
+}
+
+// Reflection string.
+
+void
+Channel_type::do_reflection(Gogo* gogo, std::string* ret) const
+{
+  if (!this->may_send_)
+    ret->append("<-");
+  ret->append("chan");
+  if (!this->may_receive_)
+    ret->append("<-");
+  ret->push_back(' ');
+  this->append_reflection(this->element_type_, gogo, ret);
+}
+
+// Mangled name.
+
+void
+Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('C');
+  this->append_mangled_name(this->element_type_, gogo, ret);
+  if (this->may_send_)
+    ret->push_back('s');
+  if (this->may_receive_)
+    ret->push_back('r');
+  ret->push_back('e');
+}
+
+// Export.
+
+void
+Channel_type::do_export(Export* exp) const
+{
+  exp->write_c_string("chan ");
+  if (this->may_send_ && !this->may_receive_)
+    exp->write_c_string("-< ");
+  else if (this->may_receive_ && !this->may_send_)
+    exp->write_c_string("<- ");
+  exp->write_type(this->element_type_);
+}
+
+// Import.
+
+Channel_type*
+Channel_type::do_import(Import* imp)
+{
+  imp->require_c_string("chan ");
+
+  bool may_send;
+  bool may_receive;
+  if (imp->match_c_string("-< "))
+    {
+      imp->advance(3);
+      may_send = true;
+      may_receive = false;
+    }
+  else if (imp->match_c_string("<- "))
+    {
+      imp->advance(3);
+      may_receive = true;
+      may_send = false;
+    }
+  else
+    {
+      may_send = true;
+      may_receive = true;
+    }
+
+  Type* element_type = imp->read_type();
+
+  return Type::make_channel_type(may_send, may_receive, element_type);
+}
+
+// Make a new channel type.
+
+Channel_type*
+Type::make_channel_type(bool send, bool receive, Type* element_type)
+{
+  return new Channel_type(send, receive, element_type);
+}
+
+// Class Interface_type.
+
+// Traversal.
+
+int
+Interface_type::do_traverse(Traverse* traverse)
+{
+  if (this->methods_ == NULL)
+    return TRAVERSE_CONTINUE;
+  return this->methods_->traverse(traverse);
+}
+
+// Finalize the methods.  This handles interface inheritance.
+
+void
+Interface_type::finalize_methods()
+{
+  if (this->methods_ == NULL)
+    return;
+  bool is_recursive = false;
+  size_t from = 0;
+  size_t to = 0;
+  while (from < this->methods_->size())
+    {
+      const Typed_identifier* p = &this->methods_->at(from);
+      if (!p->name().empty())
+       {
+         if (from != to)
+           this->methods_->set(to, *p);
+         ++from;
+         ++to;
+         continue;
+       }
+      Interface_type* it = p->type()->interface_type();
+      if (it == NULL)
+       {
+         error_at(p->location(), "interface contains embedded non-interface");
+         ++from;
+         continue;
+       }
+      if (it == this)
+       {
+         if (!is_recursive)
+           {
+             error_at(p->location(), "invalid recursive interface");
+             is_recursive = true;
+           }
+         ++from;
+         continue;
+       }
+      const Typed_identifier_list* methods = it->methods();
+      if (methods == NULL)
+       {
+         ++from;
+         continue;
+       }
+      for (Typed_identifier_list::const_iterator q = methods->begin();
+          q != methods->end();
+          ++q)
+       {
+         if (q->name().empty() || this->find_method(q->name()) == NULL)
+           this->methods_->push_back(Typed_identifier(q->name(), q->type(),
+                                                      p->location()));
+         else
+           {
+             if (!is_recursive)
+               error_at(p->location(), "inherited method %qs is ambiguous",
+                        Gogo::message_name(q->name()).c_str());
+           }
+       }
+      ++from;
+    }
+  if (to == 0)
+    {
+      delete this->methods_;
+      this->methods_ = NULL;
+    }
+  else
+    {
+      this->methods_->resize(to);
+      this->methods_->sort_by_name();
+    }
+}
+
+// Return the method NAME, or NULL.
+
+const Typed_identifier*
+Interface_type::find_method(const std::string& name) const
+{
+  if (this->methods_ == NULL)
+    return NULL;
+  for (Typed_identifier_list::const_iterator p = this->methods_->begin();
+       p != this->methods_->end();
+       ++p)
+    if (p->name() == name)
+      return &*p;
+  return NULL;
+}
+
+// Return the method index.
+
+size_t
+Interface_type::method_index(const std::string& name) const
+{
+  gcc_assert(this->methods_ != NULL);
+  size_t ret = 0;
+  for (Typed_identifier_list::const_iterator p = this->methods_->begin();
+       p != this->methods_->end();
+       ++p, ++ret)
+    if (p->name() == name)
+      return ret;
+  gcc_unreachable();
+}
+
+// Return whether NAME is an unexported method, for better error
+// reporting.
+
+bool
+Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const
+{
+  if (this->methods_ == NULL)
+    return false;
+  for (Typed_identifier_list::const_iterator p = this->methods_->begin();
+       p != this->methods_->end();
+       ++p)
+    {
+      const std::string& method_name(p->name());
+      if (Gogo::is_hidden_name(method_name)
+         && name == Gogo::unpack_hidden_name(method_name)
+         && gogo->pack_hidden_name(name, false) != method_name)
+       return true;
+    }
+  return false;
+}
+
+// Whether this type is identical with T.
+
+bool
+Interface_type::is_identical(const Interface_type* t) const
+{
+  // We require the same methods with the same types.  The methods
+  // have already been sorted.
+  if (this->methods() == NULL || t->methods() == NULL)
+    return this->methods() == t->methods();
+
+  Typed_identifier_list::const_iterator p1 = this->methods()->begin();
+  for (Typed_identifier_list::const_iterator p2 = t->methods()->begin();
+       p2 != t->methods()->end();
+       ++p1, ++p2)
+    {
+      if (p1 == this->methods()->end())
+       return false;
+      if (p1->name() != p2->name()
+         || !Type::are_identical(p1->type(), p2->type(), NULL))
+       return false;
+    }
+  if (p1 != this->methods()->end())
+    return false;
+  return true;
+}
+
+// Whether we can assign the interface type T to this type.  The types
+// are known to not be identical.  An interface assignment is only
+// permitted if T is known to implement all methods in THIS.
+// Otherwise a type guard is required.
+
+bool
+Interface_type::is_compatible_for_assign(const Interface_type* t,
+                                        std::string* reason) const
+{
+  if (this->methods() == NULL)
+    return true;
+  for (Typed_identifier_list::const_iterator p = this->methods()->begin();
+       p != this->methods()->end();
+       ++p)
+    {
+      const Typed_identifier* m = t->find_method(p->name());
+      if (m == NULL)
+       {
+         if (reason != NULL)
+           {
+             char buf[200];
+             snprintf(buf, sizeof buf,
+                      _("need explicit conversion; missing method %s%s%s"),
+                      open_quote, Gogo::message_name(p->name()).c_str(),
+                      close_quote);
+             reason->assign(buf);
+           }
+         return false;
+       }
+
+      std::string subreason;
+      if (!Type::are_identical(p->type(), m->type(), &subreason))
+       {
+         if (reason != NULL)
+           {
+             std::string n = Gogo::message_name(p->name());
+             size_t len = 100 + n.length() + subreason.length();
+             char* buf = new char[len];
+             if (subreason.empty())
+               snprintf(buf, len, _("incompatible type for method %s%s%s"),
+                        open_quote, n.c_str(), close_quote);
+             else
+               snprintf(buf, len,
+                        _("incompatible type for method %s%s%s (%s)"),
+                        open_quote, n.c_str(), close_quote,
+                        subreason.c_str());
+             reason->assign(buf);
+             delete[] buf;
+           }
+         return false;
+       }
+    }
+
+  return true;
+}
+
+// Hash code.
+
+unsigned int
+Interface_type::do_hash_for_method(Gogo* gogo) const
+{
+  unsigned int ret = 0;
+  if (this->methods_ != NULL)
+    {
+      for (Typed_identifier_list::const_iterator p = this->methods_->begin();
+          p != this->methods_->end();
+          ++p)
+       {
+         ret = Type::hash_string(p->name(), ret);
+         ret += p->type()->hash_for_method(gogo);
+         ret <<= 1;
+       }
+    }
+  return ret;
+}
+
+// Return true if T implements the interface.  If it does not, and
+// REASON is not NULL, set *REASON to a useful error message.
+
+bool
+Interface_type::implements_interface(const Type* t, std::string* reason) const
+{
+  if (this->methods_ == NULL)
+    return true;
+
+  bool is_pointer = false;
+  const Named_type* nt = t->named_type();
+  const Struct_type* st = t->struct_type();
+  // If we start with a named type, we don't dereference it to find
+  // methods.
+  if (nt == NULL)
+    {
+      const Type* pt = t->points_to();
+      if (pt != NULL)
+       {
+         // If T is a pointer to a named type, then we need to look at
+         // the type to which it points.
+         is_pointer = true;
+         nt = pt->named_type();
+         st = pt->struct_type();
+       }
+    }
+
+  // If we have a named type, get the methods from it rather than from
+  // any struct type.
+  if (nt != NULL)
+    st = NULL;
+
+  // Only named and struct types have methods.
+  if (nt == NULL && st == NULL)
+    {
+      if (reason != NULL)
+       {
+         if (t->points_to() != NULL
+             && t->points_to()->interface_type() != NULL)
+           reason->assign(_("pointer to interface type has no methods"));
+         else
+           reason->assign(_("type has no methods"));
+       }
+      return false;
+    }
+
+  if (nt != NULL ? !nt->has_any_methods() : !st->has_any_methods())
+    {
+      if (reason != NULL)
+       {
+         if (t->points_to() != NULL
+             && t->points_to()->interface_type() != NULL)
+           reason->assign(_("pointer to interface type has no methods"));
+         else
+           reason->assign(_("type has no methods"));
+       }
+      return false;
+    }
+
+  for (Typed_identifier_list::const_iterator p = this->methods_->begin();
+       p != this->methods_->end();
+       ++p)
+    {
+      bool is_ambiguous = false;
+      Method* m = (nt != NULL
+                  ? nt->method_function(p->name(), &is_ambiguous)
+                  : st->method_function(p->name(), &is_ambiguous));
+      if (m == NULL)
+       {
+         if (reason != NULL)
+           {
+             std::string n = Gogo::message_name(p->name());
+             size_t len = n.length() + 100;
+             char* buf = new char[len];
+             if (is_ambiguous)
+               snprintf(buf, len, _("ambiguous method %s%s%s"),
+                        open_quote, n.c_str(), close_quote);
+             else
+               snprintf(buf, len, _("missing method %s%s%s"),
+                        open_quote, n.c_str(), close_quote);
+             reason->assign(buf);
+             delete[] buf;
+           }
+         return false;
+       }
+
+      Function_type *p_fn_type = p->type()->function_type();
+      Function_type* m_fn_type = m->type()->function_type();
+      gcc_assert(p_fn_type != NULL && m_fn_type != NULL);
+      std::string subreason;
+      if (!p_fn_type->is_identical(m_fn_type, true, &subreason))
+       {
+         if (reason != NULL)
+           {
+             std::string n = Gogo::message_name(p->name());
+             size_t len = 100 + n.length() + subreason.length();
+             char* buf = new char[len];
+             if (subreason.empty())
+               snprintf(buf, len, _("incompatible type for method %s%s%s"),
+                        open_quote, n.c_str(), close_quote);
+             else
+               snprintf(buf, len,
+                        _("incompatible type for method %s%s%s (%s)"),
+                        open_quote, n.c_str(), close_quote,
+                        subreason.c_str());
+             reason->assign(buf);
+             delete[] buf;
+           }
+         return false;
+       }
+
+      if (!is_pointer && !m->is_value_method())
+       {
+         if (reason != NULL)
+           {
+             std::string n = Gogo::message_name(p->name());
+             size_t len = 100 + n.length();
+             char* buf = new char[len];
+             snprintf(buf, len, _("method %s%s%s requires a pointer"),
+                      open_quote, n.c_str(), close_quote);
+             reason->assign(buf);
+             delete[] buf;
+           }
+         return false;
+       }
+    }
+
+  return true;
+}
+
+// Return a tree for an interface type.  An interface is a pointer to
+// a struct.  The struct has three fields.  The first field is a
+// pointer to the type descriptor for the dynamic type of the object.
+// The second field is a pointer to a table of methods for the
+// interface to be used with the object.  The third field is the value
+// of the object itself.
+
+tree
+Interface_type::do_get_tree(Gogo* gogo)
+{
+  if (this->methods_ == NULL)
+    {
+      // At the tree level, use the same type for all empty
+      // interfaces.  This lets us assign them to each other directly
+      // without triggering GIMPLE type errors.
+      tree dtype = Type::make_type_descriptor_type()->get_tree(gogo);
+      dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST));
+      static tree empty_interface;
+      return Gogo::builtin_struct(&empty_interface, "__go_empty_interface",
+                                 NULL_TREE, 2,
+                                 "__type_descriptor",
+                                 dtype,
+                                 "__object",
+                                 ptr_type_node);
+    }
+
+  return this->fill_in_tree(gogo, make_node(RECORD_TYPE));
+}
+
+// Fill in the tree for an interface type.  This is used for named
+// interface types.
+
+tree
+Interface_type::fill_in_tree(Gogo* gogo, tree type)
+{
+  gcc_assert(this->methods_ != NULL);
+
+  // Build the type of the table of methods.
+
+  tree method_table = make_node(RECORD_TYPE);
+
+  // The first field is a pointer to the type descriptor.
+  tree name_tree = get_identifier("__type_descriptor");
+  tree dtype = Type::make_type_descriptor_type()->get_tree(gogo);
+  dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST));
+  tree field = build_decl(this->location_, FIELD_DECL, name_tree, dtype);
+  DECL_CONTEXT(field) = method_table;
+  TYPE_FIELDS(method_table) = field;
+
+  std::string last_name = "";
+  tree* pp = &DECL_CHAIN(field);
+  for (Typed_identifier_list::const_iterator p = this->methods_->begin();
+       p != this->methods_->end();
+       ++p)
+    {
+      std::string name = Gogo::unpack_hidden_name(p->name());
+      name_tree = get_identifier_with_length(name.data(), name.length());
+      tree field_type = p->type()->get_tree(gogo);
+      if (field_type == error_mark_node)
+       return error_mark_node;
+      field = build_decl(this->location_, FIELD_DECL, name_tree, field_type);
+      DECL_CONTEXT(field) = method_table;
+      *pp = field;
+      pp = &DECL_CHAIN(field);
+      // Sanity check: the names should be sorted.
+      gcc_assert(p->name() > last_name);
+      last_name = p->name();
+    }
+  layout_type(method_table);
+
+  tree mtype = build_pointer_type(method_table);
+
+  tree field_trees = NULL_TREE;
+  pp = &field_trees;
+
+  name_tree = get_identifier("__methods");
+  field = build_decl(this->location_, FIELD_DECL, name_tree, mtype);
+  DECL_CONTEXT(field) = type;
+  *pp = field;
+  pp = &DECL_CHAIN(field);
+
+  name_tree = get_identifier("__object");
+  field = build_decl(this->location_, FIELD_DECL, name_tree, ptr_type_node);
+  DECL_CONTEXT(field) = type;
+  *pp = field;
+
+  TYPE_FIELDS(type) = field_trees;
+
+  layout_type(type);
+
+  return type;
+}
+
+// Initialization value.
+
+tree
+Interface_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear)
+{
+  if (is_clear)
+    return NULL;
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
+  for (tree field = TYPE_FIELDS(type_tree);
+       field != NULL_TREE;
+       field = DECL_CHAIN(field))
+    {
+      constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+      elt->index = field;
+      elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
+    }
+
+  tree ret = build_constructor(type_tree, init);
+  TREE_CONSTANT(ret) = 1;
+  return ret;
+}
+
+// The type of an interface type descriptor.
+
+Type*
+Interface_type::make_interface_type_descriptor_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      Type* tdt = Type::make_type_descriptor_type();
+      Type* ptdt = Type::make_type_descriptor_ptr_type();
+
+      Type* string_type = Type::lookup_string_type();
+      Type* pointer_string_type = Type::make_pointer_type(string_type);
+
+      Struct_type* sm =
+       Type::make_builtin_struct_type(3,
+                                      "name", pointer_string_type,
+                                      "pkgPath", pointer_string_type,
+                                      "typ", ptdt);
+
+      Type* nsm = Type::make_builtin_named_type("imethod", sm);
+
+      Type* slice_nsm = Type::make_array_type(nsm, NULL);
+
+      Struct_type* s = Type::make_builtin_struct_type(2,
+                                                     "", tdt,
+                                                     "methods", slice_nsm);
+
+      ret = Type::make_builtin_named_type("InterfaceType", s);
+    }
+
+  return ret;
+}
+
+// Build a type descriptor for an interface type.
+
+Expression*
+Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  source_location bloc = BUILTINS_LOCATION;
+
+  Type* itdt = Interface_type::make_interface_type_descriptor_type();
+
+  const Struct_field_list* ifields = itdt->struct_type()->fields();
+
+  Expression_list* ivals = new Expression_list();
+  ivals->reserve(2);
+
+  Struct_field_list::const_iterator pif = ifields->begin();
+  gcc_assert(pif->field_name() == "commonType");
+  ivals->push_back(this->type_descriptor_constructor(gogo,
+                                                    RUNTIME_TYPE_KIND_INTERFACE,
+                                                    name, NULL, true));
+
+  ++pif;
+  gcc_assert(pif->field_name() == "methods");
+
+  Expression_list* methods = new Expression_list();
+  if (this->methods_ != NULL && !this->methods_->empty())
+    {
+      Type* elemtype = pif->type()->array_type()->element_type();
+
+      methods->reserve(this->methods_->size());
+      for (Typed_identifier_list::const_iterator pm = this->methods_->begin();
+          pm != this->methods_->end();
+          ++pm)
+       {
+         const Struct_field_list* mfields = elemtype->struct_type()->fields();
+
+         Expression_list* mvals = new Expression_list();
+         mvals->reserve(3);
+
+         Struct_field_list::const_iterator pmf = mfields->begin();
+         gcc_assert(pmf->field_name() == "name");
+         std::string s = Gogo::unpack_hidden_name(pm->name());
+         Expression* e = Expression::make_string(s, bloc);
+         mvals->push_back(Expression::make_unary(OPERATOR_AND, e, bloc));
+
+         ++pmf;
+         gcc_assert(pmf->field_name() == "pkgPath");
+         if (!Gogo::is_hidden_name(pm->name()))
+           mvals->push_back(Expression::make_nil(bloc));
+         else
+           {
+             s = Gogo::hidden_name_prefix(pm->name());
+             e = Expression::make_string(s, bloc);
+             mvals->push_back(Expression::make_unary(OPERATOR_AND, e, bloc));
+           }
+
+         ++pmf;
+         gcc_assert(pmf->field_name() == "typ");
+         mvals->push_back(Expression::make_type_descriptor(pm->type(), bloc));
+
+         ++pmf;
+         gcc_assert(pmf == mfields->end());
+
+         e = Expression::make_struct_composite_literal(elemtype, mvals,
+                                                       bloc);
+         methods->push_back(e);
+       }
+    }
+
+  ivals->push_back(Expression::make_slice_composite_literal(pif->type(),
+                                                           methods, bloc));
+
+  ++pif;
+  gcc_assert(pif == ifields->end());
+
+  return Expression::make_struct_composite_literal(itdt, ivals, bloc);
+}
+
+// Reflection string.
+
+void
+Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
+{
+  ret->append("interface {");
+  if (this->methods_ != NULL)
+    {
+      for (Typed_identifier_list::const_iterator p = this->methods_->begin();
+          p != this->methods_->end();
+          ++p)
+       {
+         if (p != this->methods_->begin())
+           ret->append(";");
+         ret->push_back(' ');
+         ret->append(Gogo::unpack_hidden_name(p->name()));
+         std::string sub = p->type()->reflection(gogo);
+         gcc_assert(sub.compare(0, 4, "func") == 0);
+         sub = sub.substr(4);
+         ret->append(sub);
+       }
+    }
+  ret->append(" }");
+}
+
+// Mangled name.
+
+void
+Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  ret->push_back('I');
+
+  const Typed_identifier_list* methods = this->methods_;
+  if (methods != NULL)
+    {
+      for (Typed_identifier_list::const_iterator p = methods->begin();
+          p != methods->end();
+          ++p)
+       {
+         std::string n = Gogo::unpack_hidden_name(p->name());
+         char buf[20];
+         snprintf(buf, sizeof buf, "%u_",
+                  static_cast<unsigned int>(n.length()));
+         ret->append(buf);
+         ret->append(n);
+         this->append_mangled_name(p->type(), gogo, ret);
+       }
+    }
+
+  ret->push_back('e');
+}
+
+// Export.
+
+void
+Interface_type::do_export(Export* exp) const
+{
+  exp->write_c_string("interface { ");
+
+  const Typed_identifier_list* methods = this->methods_;
+  if (methods != NULL)
+    {
+      for (Typed_identifier_list::const_iterator pm = methods->begin();
+          pm != methods->end();
+          ++pm)
+       {
+         exp->write_string(pm->name());
+         exp->write_c_string(" (");
+
+         const Function_type* fntype = pm->type()->function_type();
+
+         bool first = true;
+         const Typed_identifier_list* parameters = fntype->parameters();
+         if (parameters != NULL)
+           {
+             bool is_varargs = fntype->is_varargs();
+             for (Typed_identifier_list::const_iterator pp =
+                    parameters->begin();
+                  pp != parameters->end();
+                  ++pp)
+               {
+                 if (first)
+                   first = false;
+                 else
+                   exp->write_c_string(", ");
+                 if (!is_varargs || pp + 1 != parameters->end())
+                   exp->write_type(pp->type());
+                 else
+                   {
+                     exp->write_c_string("...");
+                     Type *pptype = pp->type();
+                     exp->write_type(pptype->array_type()->element_type());
+                   }
+               }
+           }
+
+         exp->write_c_string(")");
+
+         const Typed_identifier_list* results = fntype->results();
+         if (results != NULL)
+           {
+             exp->write_c_string(" ");
+             if (results->size() == 1)
+               exp->write_type(results->begin()->type());
+             else
+               {
+                 first = true;
+                 exp->write_c_string("(");
+                 for (Typed_identifier_list::const_iterator p =
+                        results->begin();
+                      p != results->end();
+                      ++p)
+                   {
+                     if (first)
+                       first = false;
+                     else
+                       exp->write_c_string(", ");
+                     exp->write_type(p->type());
+                   }
+                 exp->write_c_string(")");
+               }
+           }
+
+         exp->write_c_string("; ");
+       }
+    }
+
+  exp->write_c_string("}");
+}
+
+// Import an interface type.
+
+Interface_type*
+Interface_type::do_import(Import* imp)
+{
+  imp->require_c_string("interface { ");
+
+  Typed_identifier_list* methods = new Typed_identifier_list;
+  while (imp->peek_char() != '}')
+    {
+      std::string name = imp->read_identifier();
+      imp->require_c_string(" (");
+
+      Typed_identifier_list* parameters;
+      bool is_varargs = false;
+      if (imp->peek_char() == ')')
+       parameters = NULL;
+      else
+       {
+         parameters = new Typed_identifier_list;
+         while (true)
+           {
+             if (imp->match_c_string("..."))
+               {
+                 imp->advance(3);
+                 is_varargs = true;
+               }
+
+             Type* ptype = imp->read_type();
+             if (is_varargs)
+               ptype = Type::make_array_type(ptype, NULL);
+             parameters->push_back(Typed_identifier(Import::import_marker,
+                                                    ptype, imp->location()));
+             if (imp->peek_char() != ',')
+               break;
+             gcc_assert(!is_varargs);
+             imp->require_c_string(", ");
+           }
+       }
+      imp->require_c_string(")");
+
+      Typed_identifier_list* results;
+      if (imp->peek_char() != ' ')
+       results = NULL;
+      else
+       {
+         results = new Typed_identifier_list;
+         imp->advance(1);
+         if (imp->peek_char() != '(')
+           {
+             Type* rtype = imp->read_type();
+             results->push_back(Typed_identifier(Import::import_marker,
+                                                 rtype, imp->location()));
+           }
+         else
+           {
+             imp->advance(1);
+             while (true)
+               {
+                 Type* rtype = imp->read_type();
+                 results->push_back(Typed_identifier(Import::import_marker,
+                                                     rtype, imp->location()));
+                 if (imp->peek_char() != ',')
+                   break;
+                 imp->require_c_string(", ");
+               }
+             imp->require_c_string(")");
+           }
+       }
+
+      Function_type* fntype = Type::make_function_type(NULL, parameters,
+                                                      results,
+                                                      imp->location());
+      if (is_varargs)
+       fntype->set_is_varargs();
+      methods->push_back(Typed_identifier(name, fntype, imp->location()));
+
+      imp->require_c_string("; ");
+    }
+
+  imp->require_c_string("}");
+
+  if (methods->empty())
+    {
+      delete methods;
+      methods = NULL;
+    }
+
+  return Type::make_interface_type(methods, imp->location());
+}
+
+// Make an interface type.
+
+Interface_type*
+Type::make_interface_type(Typed_identifier_list* methods,
+                         source_location location)
+{
+  return new Interface_type(methods, location);
+}
+
+// Class Method.
+
+// Bind a method to an object.
+
+Expression*
+Method::bind_method(Expression* expr, source_location location) const
+{
+  if (this->stub_ == NULL)
+    {
+      // When there is no stub object, the binding is determined by
+      // the child class.
+      return this->do_bind_method(expr, location);
+    }
+
+  Expression* func = Expression::make_func_reference(this->stub_, NULL,
+                                                    location);
+  return Expression::make_bound_method(expr, func, location);
+}
+
+// Return the named object associated with a method.  This may only be
+// called after methods are finalized.
+
+Named_object*
+Method::named_object() const
+{
+  if (this->stub_ != NULL)
+    return this->stub_;
+  return this->do_named_object();
+}
+
+// Class Named_method.
+
+// The type of the method.
+
+Function_type*
+Named_method::do_type() const
+{
+  if (this->named_object_->is_function())
+    return this->named_object_->func_value()->type();
+  else if (this->named_object_->is_function_declaration())
+    return this->named_object_->func_declaration_value()->type();
+  else
+    gcc_unreachable();
+}
+
+// Return the location of the method receiver.
+
+source_location
+Named_method::do_receiver_location() const
+{
+  return this->do_type()->receiver()->location();
+}
+
+// Bind a method to an object.
+
+Expression*
+Named_method::do_bind_method(Expression* expr, source_location location) const
+{
+  Expression* func = Expression::make_func_reference(this->named_object_, NULL,
+                                                    location);
+  Bound_method_expression* bme = Expression::make_bound_method(expr, func,
+                                                              location);
+  // If this is not a local method, and it does not use a stub, then
+  // the real method expects a different type.  We need to cast the
+  // first argument.
+  if (this->depth() > 0 && !this->needs_stub_method())
+    {
+      Function_type* ftype = this->do_type();
+      gcc_assert(ftype->is_method());
+      Type* frtype = ftype->receiver()->type();
+      bme->set_first_argument_type(frtype);
+    }
+  return bme;
+}
+
+// Class Interface_method.
+
+// Bind a method to an object.
+
+Expression*
+Interface_method::do_bind_method(Expression* expr,
+                                source_location location) const
+{
+  return Expression::make_interface_field_reference(expr, this->name_,
+                                                   location);
+}
+
+// Class Methods.
+
+// Insert a new method.  Return true if it was inserted, false
+// otherwise.
+
+bool
+Methods::insert(const std::string& name, Method* m)
+{
+  std::pair<Method_map::iterator, bool> ins =
+    this->methods_.insert(std::make_pair(name, m));
+  if (ins.second)
+    return true;
+  else
+    {
+      Method* old_method = ins.first->second;
+      if (m->depth() < old_method->depth())
+       {
+         delete old_method;
+         ins.first->second = m;
+         return true;
+       }
+      else
+       {
+         if (m->depth() == old_method->depth())
+           old_method->set_is_ambiguous();
+         return false;
+       }
+    }
+}
+
+// Return the number of unambiguous methods.
+
+size_t
+Methods::count() const
+{
+  size_t ret = 0;
+  for (Method_map::const_iterator p = this->methods_.begin();
+       p != this->methods_.end();
+       ++p)
+    if (!p->second->is_ambiguous())
+      ++ret;
+  return ret;
+}
+
+// Class Named_type.
+
+// Return the name of the type.
+
+const std::string&
+Named_type::name() const
+{
+  return this->named_object_->name();
+}
+
+// Return the name of the type to use in an error message.
+
+std::string
+Named_type::message_name() const
+{
+  return this->named_object_->message_name();
+}
+
+// Add a method to this type.
+
+Named_object*
+Named_type::add_method(const std::string& name, Function* function)
+{
+  if (this->local_methods_ == NULL)
+    this->local_methods_ = new Bindings(NULL);
+  return this->local_methods_->add_function(name, NULL, function);
+}
+
+// Add a method declaration to this type.
+
+Named_object*
+Named_type::add_method_declaration(const std::string& name, Package* package,
+                                  Function_type* type,
+                                  source_location location)
+{
+  if (this->local_methods_ == NULL)
+    this->local_methods_ = new Bindings(NULL);
+  return this->local_methods_->add_function_declaration(name, package, type,
+                                                       location);
+}
+
+// Add an existing method to this type.
+
+void
+Named_type::add_existing_method(Named_object* no)
+{
+  if (this->local_methods_ == NULL)
+    this->local_methods_ = new Bindings(NULL);
+  this->local_methods_->add_named_object(no);
+}
+
+// Look for a local method NAME, and returns its named object, or NULL
+// if not there.
+
+Named_object*
+Named_type::find_local_method(const std::string& name) const
+{
+  if (this->local_methods_ == NULL)
+    return NULL;
+  return this->local_methods_->lookup(name);
+}
+
+// Return whether NAME is an unexported field or method, for better
+// error reporting.
+
+bool
+Named_type::is_unexported_local_method(Gogo* gogo,
+                                      const std::string& name) const
+{
+  Bindings* methods = this->local_methods_;
+  if (methods != NULL)
+    {
+      for (Bindings::const_declarations_iterator p =
+            methods->begin_declarations();
+          p != methods->end_declarations();
+          ++p)
+       {
+         if (Gogo::is_hidden_name(p->first)
+             && name == Gogo::unpack_hidden_name(p->first)
+             && gogo->pack_hidden_name(name, false) != p->first)
+           return true;
+       }
+    }
+  return false;
+}
+
+// Build the complete list of methods for this type, which means
+// recursively including all methods for anonymous fields.  Create all
+// stub methods.
+
+void
+Named_type::finalize_methods(Gogo* gogo)
+{
+  if (this->local_methods_ != NULL
+      && (this->points_to() != NULL || this->interface_type() != NULL))
+    {
+      const Bindings* lm = this->local_methods_;
+      for (Bindings::const_declarations_iterator p = lm->begin_declarations();
+          p != lm->end_declarations();
+          ++p)
+       error_at(p->second->location(),
+                "invalid pointer or interface receiver type");
+      delete this->local_methods_;
+      this->local_methods_ = NULL;
+      return;
+    }
+
+  Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
+}
+
+// Return the method NAME, or NULL if there isn't one or if it is
+// ambiguous.  Set *IS_AMBIGUOUS if the method exists but is
+// ambiguous.
+
+Method*
+Named_type::method_function(const std::string& name, bool* is_ambiguous) const
+{
+  return Type::method_function(this->all_methods_, name, is_ambiguous);
+}
+
+// Return a pointer to the interface method table for this type for
+// the interface INTERFACE.  IS_POINTER is true if this is for a
+// pointer to THIS.
+
+tree
+Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface,
+                                  bool is_pointer)
+{
+  gcc_assert(!interface->is_empty());
+
+  Interface_method_tables** pimt = (is_pointer
+                                   ? &this->interface_method_tables_
+                                   : &this->pointer_interface_method_tables_);
+
+  if (*pimt == NULL)
+    *pimt = new Interface_method_tables(5);
+
+  std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
+  std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
+
+  if (ins.second)
+    {
+      // This is a new entry in the hash table.
+      gcc_assert(ins.first->second == NULL_TREE);
+      ins.first->second = gogo->interface_method_table_for_type(interface,
+                                                               this,
+                                                               is_pointer);
+    }
+
+  tree decl = ins.first->second;
+  if (decl == error_mark_node)
+    return error_mark_node;
+  gcc_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL);
+  return build_fold_addr_expr(decl);
+}
+
+// Return whether a named type has any hidden fields.
+
+bool
+Named_type::named_type_has_hidden_fields(std::string* reason) const
+{
+  if (this->seen_)
+    return false;
+  this->seen_ = true;
+  bool ret = this->type_->has_hidden_fields(this, reason);
+  this->seen_ = false;
+  return ret;
+}
+
+// Look for a use of a complete type within another type.  This is
+// used to check that we don't try to use a type within itself.
+
+class Find_type_use : public Traverse
+{
+ public:
+  Find_type_use(Type* find_type)
+    : Traverse(traverse_types),
+      find_type_(find_type), found_(false)
+  { }
+
+  // Whether we found the type.
+  bool
+  found() const
+  { return this->found_; }
+
+ protected:
+  int
+  type(Type*);
+
+ private:
+  // The type we are looking for.
+  Type* find_type_;
+  // Whether we found the type.
+  bool found_;
+};
+
+// Check for FIND_TYPE in TYPE.
+
+int
+Find_type_use::type(Type* type)
+{
+  if (this->find_type_ == type)
+    {
+      this->found_ = true;
+      return TRAVERSE_EXIT;
+    }
+  // It's OK if we see a reference to the type in any type which is
+  // essentially a pointer: a pointer, a slice, a function, a map, or
+  // a channel.
+  if (type->points_to() != NULL
+      || type->is_open_array_type()
+      || type->function_type() != NULL
+      || type->map_type() != NULL
+      || type->channel_type() != NULL)
+    return TRAVERSE_SKIP_COMPONENTS;
+
+  // For an interface, a reference to the type in a method type should
+  // be ignored, but we have to consider direct inheritance.  When
+  // this is called, there may be cases of direct inheritance
+  // represented as a method with no name.
+  if (type->interface_type() != NULL)
+    {
+      const Typed_identifier_list* methods = type->interface_type()->methods();
+      if (methods != NULL)
+       {
+         for (Typed_identifier_list::const_iterator p = methods->begin();
+              p != methods->end();
+              ++p)
+           {
+             if (p->name().empty())
+               {
+                 if (Type::traverse(p->type(), this) == TRAVERSE_EXIT)
+                   return TRAVERSE_EXIT;
+               }
+           }
+       }
+      return TRAVERSE_SKIP_COMPONENTS;
+    }
+
+  return TRAVERSE_CONTINUE;
+}
+
+// Verify that a named type does not refer to itself.
+
+bool
+Named_type::do_verify()
+{
+  Find_type_use find(this);
+  Type::traverse(this->type_, &find);
+  if (find.found())
+    {
+      error_at(this->location_, "invalid recursive type %qs",
+              this->message_name().c_str());
+      this->is_error_ = true;
+      return false;
+    }
+
+  // Check whether any of the local methods overloads an existing
+  // struct field or interface method.  We don't need to check the
+  // list of methods against itself: that is handled by the Bindings
+  // code.
+  if (this->local_methods_ != NULL)
+    {
+      Struct_type* st = this->type_->struct_type();
+      Interface_type* it = this->type_->interface_type();
+      bool found_dup = false;
+      if (st != NULL || it != NULL)
+       {
+         for (Bindings::const_declarations_iterator p =
+                this->local_methods_->begin_declarations();
+              p != this->local_methods_->end_declarations();
+              ++p)
+           {
+             const std::string& name(p->first);
+             if (st != NULL && st->find_local_field(name, NULL) != NULL)
+               {
+                 error_at(p->second->location(),
+                          "method %qs redeclares struct field name",
+                          Gogo::message_name(name).c_str());
+                 found_dup = true;
+               }
+             if (it != NULL && it->find_method(name) != NULL)
+               {
+                 error_at(p->second->location(),
+                          "method %qs redeclares interface method name",
+                          Gogo::message_name(name).c_str());
+                 found_dup = true;
+               }
+           }
+       }
+      if (found_dup)
+       return false;
+    }
+
+  return true;
+}
+
+// Return a hash code.  This is used for method lookup.  We simply
+// hash on the name itself.
+
+unsigned int
+Named_type::do_hash_for_method(Gogo* gogo) const
+{
+  const std::string& name(this->named_object()->name());
+  unsigned int ret = Type::hash_string(name, 0);
+
+  // GOGO will be NULL here when called from Type_hash_identical.
+  // That is OK because that is only used for internal hash tables
+  // where we are going to be comparing named types for equality.  In
+  // other cases, which are cases where the runtime is going to
+  // compare hash codes to see if the types are the same, we need to
+  // include the package prefix and name in the hash.
+  if (gogo != NULL && !Gogo::is_hidden_name(name) && !this->is_builtin())
+    {
+      const Package* package = this->named_object()->package();
+      if (package == NULL)
+       {
+         ret = Type::hash_string(gogo->unique_prefix(), ret);
+         ret = Type::hash_string(gogo->package_name(), ret);
+       }
+      else
+       {
+         ret = Type::hash_string(package->unique_prefix(), ret);
+         ret = Type::hash_string(package->name(), ret);
+       }
+    }
+
+  return ret;
+}
+
+// Get a tree for a named type.
+
+tree
+Named_type::do_get_tree(Gogo* gogo)
+{
+  if (this->is_error_)
+    return error_mark_node;
+
+  // Go permits types to refer to themselves in various ways.  Break
+  // the recursion here.
+  tree t;
+  switch (this->type_->forwarded()->classification())
+    {
+    case TYPE_ERROR:
+      return error_mark_node;
+
+    case TYPE_VOID:
+    case TYPE_BOOLEAN:
+    case TYPE_INTEGER:
+    case TYPE_FLOAT:
+    case TYPE_COMPLEX:
+    case TYPE_STRING:
+    case TYPE_NIL:
+      // These types can not refer to themselves.
+    case TYPE_MAP:
+    case TYPE_CHANNEL:
+      // All maps and channels have the same type in GENERIC.
+      t = Type::get_named_type_tree(gogo, this->type_);
+      if (t == error_mark_node)
+       return error_mark_node;
+      // Build a copy to set TYPE_NAME.
+      t = build_variant_type_copy(t);
+      break;
+
+    case TYPE_FUNCTION:
+      // GENERIC can't handle a pointer to a function type whose
+      // return type is a pointer to the function type itself.  It
+      // does into infinite loops when walking the types.
+      if (this->seen_
+         && this->function_type()->results() != NULL
+         && this->function_type()->results()->size() == 1
+         && (this->function_type()->results()->front().type()->forwarded()
+             == this))
+       return ptr_type_node;
+      this->seen_ = true;
+      t = Type::get_named_type_tree(gogo, this->type_);
+      this->seen_ = false;
+      if (t == error_mark_node)
+       return error_mark_node;
+      t = build_variant_type_copy(t);
+      break;
+
+    case TYPE_POINTER:
+      // GENERIC can't handle a pointer type which points to itself.
+      // It goes into infinite loops when walking the types.
+      if (this->seen_ && this->points_to()->forwarded() == this)
+       return ptr_type_node;
+      this->seen_ = true;
+      t = Type::get_named_type_tree(gogo, this->type_);
+      this->seen_ = false;
+      if (t == error_mark_node)
+       return error_mark_node;
+      t = build_variant_type_copy(t);
+      break;
+
+    case TYPE_STRUCT:
+      if (this->named_tree_ != NULL_TREE)
+       return this->named_tree_;
+      t = make_node(RECORD_TYPE);
+      this->named_tree_ = t;
+      this->type_->struct_type()->fill_in_tree(gogo, t);
+      break;
+
+    case TYPE_ARRAY:
+      if (!this->is_open_array_type())
+       t = Type::get_named_type_tree(gogo, this->type_);
+      else
+       {
+         if (this->named_tree_ != NULL_TREE)
+           return this->named_tree_;
+         t = gogo->slice_type_tree(void_type_node);
+         this->named_tree_ = t;
+         t = this->type_->array_type()->fill_in_tree(gogo, t);
+       }
+      if (t == error_mark_node)
+       return error_mark_node;
+      t = build_variant_type_copy(t);
+      break;
+
+    case TYPE_INTERFACE:
+      if (this->type_->interface_type()->is_empty())
+       {
+         t = Type::get_named_type_tree(gogo, this->type_);
+         if (t == error_mark_node)
+           return error_mark_node;
+         t = build_variant_type_copy(t);
+       }
+      else
+       {
+         if (this->named_tree_ != NULL_TREE)
+           return this->named_tree_;
+         t = make_node(RECORD_TYPE);
+         this->named_tree_ = t;
+         t = this->type_->interface_type()->fill_in_tree(gogo, t);
+       }
+      break;
+
+    case TYPE_NAMED:
+      {
+       // When a named type T1 is defined as another named type T2,
+       // the definition must simply be "type T1 T2".  If the
+       // definition of T2 may refer to T1, then we must simply
+       // return the type for T2 here.  It's not precisely correct,
+       // but it's as close as we can get with GENERIC.
+       bool was_seen = this->seen_;
+       this->seen_ = true;
+       t = Type::get_named_type_tree(gogo, this->type_);
+       this->seen_ = was_seen;
+       if (was_seen)
+         return t;
+       if (t == error_mark_node)
+         return error_mark_node;
+       t = build_variant_type_copy(t);
+      }
+      break;
+
+    case TYPE_FORWARD:
+      // An undefined forwarding type.  Make sure the error is
+      // emitted.
+      this->type_->forward_declaration_type()->real_type();
+      return error_mark_node;
+
+    default:
+    case TYPE_SINK:
+    case TYPE_CALL_MULTIPLE_RESULT:
+      gcc_unreachable();
+    }
+
+  tree id = this->named_object_->get_id(gogo);
+  tree decl = build_decl(this->location_, TYPE_DECL, id, t);
+  TYPE_NAME(t) = decl;
+
+  return t;
+}
+
+// Build a type descriptor for a named type.
+
+Expression*
+Named_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  // If NAME is not NULL, then we don't really want the type
+  // descriptor for this type; we want the descriptor for the
+  // underlying type, giving it the name NAME.
+  return this->named_type_descriptor(gogo, this->type_,
+                                    name == NULL ? this : name);
+}
+
+// Add to the reflection string.  This is used mostly for the name of
+// the type used in a type descriptor, not for actual reflection
+// strings.
+
+void
+Named_type::do_reflection(Gogo* gogo, std::string* ret) const
+{
+  if (this->location() != BUILTINS_LOCATION)
+    {
+      const Package* package = this->named_object_->package();
+      if (package != NULL)
+       ret->append(package->name());
+      else
+       ret->append(gogo->package_name());
+      ret->push_back('.');
+    }
+  if (this->in_function_ != NULL)
+    {
+      ret->append(Gogo::unpack_hidden_name(this->in_function_->name()));
+      ret->push_back('$');
+    }
+  ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
+}
+
+// Get the mangled name.
+
+void
+Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  Named_object* no = this->named_object_;
+  std::string name;
+  if (this->location() == BUILTINS_LOCATION)
+    gcc_assert(this->in_function_ == NULL);
+  else
+    {
+      const std::string& unique_prefix(no->package() == NULL
+                                      ? gogo->unique_prefix()
+                                      : no->package()->unique_prefix());
+      const std::string& package_name(no->package() == NULL
+                                     ? gogo->package_name()
+                                     : no->package()->name());
+      name = unique_prefix;
+      name.append(1, '.');
+      name.append(package_name);
+      name.append(1, '.');
+      if (this->in_function_ != NULL)
+       {
+         name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
+         name.append(1, '$');
+       }
+    }
+  name.append(Gogo::unpack_hidden_name(no->name()));
+  char buf[20];
+  snprintf(buf, sizeof buf, "N%u_", static_cast<unsigned int>(name.length()));
+  ret->append(buf);
+  ret->append(name);
+}
+
+// Export the type.  This is called to export a global type.
+
+void
+Named_type::export_named_type(Export* exp, const std::string&) const
+{
+  // We don't need to write the name of the type here, because it will
+  // be written by Export::write_type anyhow.
+  exp->write_c_string("type ");
+  exp->write_type(this);
+  exp->write_c_string(";\n");
+}
+
+// Import a named type.
+
+void
+Named_type::import_named_type(Import* imp, Named_type** ptype)
+{
+  imp->require_c_string("type ");
+  Type *type = imp->read_type();
+  *ptype = type->named_type();
+  gcc_assert(*ptype != NULL);
+  imp->require_c_string(";\n");
+}
+
+// Export the type when it is referenced by another type.  In this
+// case Export::export_type will already have issued the name.
+
+void
+Named_type::do_export(Export* exp) const
+{
+  exp->write_type(this->type_);
+
+  // To save space, we only export the methods directly attached to
+  // this type.
+  Bindings* methods = this->local_methods_;
+  if (methods == NULL)
+    return;
+
+  exp->write_c_string("\n");
+  for (Bindings::const_definitions_iterator p = methods->begin_definitions();
+       p != methods->end_definitions();
+       ++p)
+    {
+      exp->write_c_string(" ");
+      (*p)->export_named_object(exp);
+    }
+
+  for (Bindings::const_declarations_iterator p = methods->begin_declarations();
+       p != methods->end_declarations();
+       ++p)
+    {
+      if (p->second->is_function_declaration())
+       {
+         exp->write_c_string(" ");
+         p->second->export_named_object(exp);
+       }
+    }
+}
+
+// Make a named type.
+
+Named_type*
+Type::make_named_type(Named_object* named_object, Type* type,
+                     source_location location)
+{
+  return new Named_type(named_object, type, location);
+}
+
+// Finalize the methods for TYPE.  It will be a named type or a struct
+// type.  This sets *ALL_METHODS to the list of methods, and builds
+// all required stubs.
+
+void
+Type::finalize_methods(Gogo* gogo, const Type* type, source_location location,
+                      Methods** all_methods)
+{
+  *all_methods = NULL;
+  Types_seen types_seen;
+  Type::add_methods_for_type(type, NULL, 0, false, false, &types_seen,
+                            all_methods);
+  Type::build_stub_methods(gogo, type, *all_methods, location);
+}
+
+// Add the methods for TYPE to *METHODS.  FIELD_INDEXES is used to
+// build up the struct field indexes as we go.  DEPTH is the depth of
+// the field within TYPE.  IS_EMBEDDED_POINTER is true if we are
+// adding these methods for an anonymous field with pointer type.
+// NEEDS_STUB_METHOD is true if we need to use a stub method which
+// calls the real method.  TYPES_SEEN is used to avoid infinite
+// recursion.
+
+void
+Type::add_methods_for_type(const Type* type,
+                          const Method::Field_indexes* field_indexes,
+                          unsigned int depth,
+                          bool is_embedded_pointer,
+                          bool needs_stub_method,
+                          Types_seen* types_seen,
+                          Methods** methods)
+{
+  // Pointer types may not have methods.
+  if (type->points_to() != NULL)
+    return;
+
+  const Named_type* nt = type->named_type();
+  if (nt != NULL)
+    {
+      std::pair<Types_seen::iterator, bool> ins = types_seen->insert(nt);
+      if (!ins.second)
+       return;
+    }
+
+  if (nt != NULL)
+    Type::add_local_methods_for_type(nt, field_indexes, depth,
+                                    is_embedded_pointer, needs_stub_method,
+                                    methods);
+
+  Type::add_embedded_methods_for_type(type, field_indexes, depth,
+                                     is_embedded_pointer, needs_stub_method,
+                                     types_seen, methods);
+
+  // If we are called with depth > 0, then we are looking at an
+  // anonymous field of a struct.  If such a field has interface type,
+  // then we need to add the interface methods.  We don't want to add
+  // them when depth == 0, because we will already handle them
+  // following the usual rules for an interface type.
+  if (depth > 0)
+    Type::add_interface_methods_for_type(type, field_indexes, depth, methods);
+}
+
+// Add the local methods for the named type NT to *METHODS.  The
+// parameters are as for add_methods_to_type.
+
+void
+Type::add_local_methods_for_type(const Named_type* nt,
+                                const Method::Field_indexes* field_indexes,
+                                unsigned int depth,
+                                bool is_embedded_pointer,
+                                bool needs_stub_method,
+                                Methods** methods)
+{
+  const Bindings* local_methods = nt->local_methods();
+  if (local_methods == NULL)
+    return;
+
+  if (*methods == NULL)
+    *methods = new Methods();
+
+  for (Bindings::const_declarations_iterator p =
+        local_methods->begin_declarations();
+       p != local_methods->end_declarations();
+       ++p)
+    {
+      Named_object* no = p->second;
+      bool is_value_method = (is_embedded_pointer
+                             || !Type::method_expects_pointer(no));
+      Method* m = new Named_method(no, field_indexes, depth, is_value_method,
+                                  (needs_stub_method
+                                   || (depth > 0 && is_value_method)));
+      if (!(*methods)->insert(no->name(), m))
+       delete m;
+    }
+}
+
+// Add the embedded methods for TYPE to *METHODS.  These are the
+// methods attached to anonymous fields.  The parameters are as for
+// add_methods_to_type.
+
+void
+Type::add_embedded_methods_for_type(const Type* type,
+                                   const Method::Field_indexes* field_indexes,
+                                   unsigned int depth,
+                                   bool is_embedded_pointer,
+                                   bool needs_stub_method,
+                                   Types_seen* types_seen,
+                                   Methods** methods)
+{
+  // Look for anonymous fields in TYPE.  TYPE has fields if it is a
+  // struct.
+  const Struct_type* st = type->struct_type();
+  if (st == NULL)
+    return;
+
+  const Struct_field_list* fields = st->fields();
+  if (fields == NULL)
+    return;
+
+  unsigned int i = 0;
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf, ++i)
+    {
+      if (!pf->is_anonymous())
+       continue;
+
+      Type* ftype = pf->type();
+      bool is_pointer = false;
+      if (ftype->points_to() != NULL)
+       {
+         ftype = ftype->points_to();
+         is_pointer = true;
+       }
+      Named_type* fnt = ftype->named_type();
+      if (fnt == NULL)
+       {
+         // This is an error, but it will be diagnosed elsewhere.
+         continue;
+       }
+
+      Method::Field_indexes* sub_field_indexes = new Method::Field_indexes();
+      sub_field_indexes->next = field_indexes;
+      sub_field_indexes->field_index = i;
+
+      Type::add_methods_for_type(fnt, sub_field_indexes, depth + 1,
+                                (is_embedded_pointer || is_pointer),
+                                (needs_stub_method
+                                 || is_pointer
+                                 || i > 0),
+                                types_seen,
+                                methods);
+    }
+}
+
+// If TYPE is an interface type, then add its method to *METHODS.
+// This is for interface methods attached to an anonymous field.  The
+// parameters are as for add_methods_for_type.
+
+void
+Type::add_interface_methods_for_type(const Type* type,
+                                    const Method::Field_indexes* field_indexes,
+                                    unsigned int depth,
+                                    Methods** methods)
+{
+  const Interface_type* it = type->interface_type();
+  if (it == NULL)
+    return;
+
+  const Typed_identifier_list* imethods = it->methods();
+  if (imethods == NULL)
+    return;
+
+  if (*methods == NULL)
+    *methods = new Methods();
+
+  for (Typed_identifier_list::const_iterator pm = imethods->begin();
+       pm != imethods->end();
+       ++pm)
+    {
+      Function_type* fntype = pm->type()->function_type();
+      gcc_assert(fntype != NULL && !fntype->is_method());
+      fntype = fntype->copy_with_receiver(const_cast<Type*>(type));
+      Method* m = new Interface_method(pm->name(), pm->location(), fntype,
+                                      field_indexes, depth);
+      if (!(*methods)->insert(pm->name(), m))
+       delete m;
+    }
+}
+
+// Build stub methods for TYPE as needed.  METHODS is the set of
+// methods for the type.  A stub method may be needed when a type
+// inherits a method from an anonymous field.  When we need the
+// address of the method, as in a type descriptor, we need to build a
+// little stub which does the required field dereferences and jumps to
+// the real method.  LOCATION is the location of the type definition.
+
+void
+Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods,
+                        source_location location)
+{
+  if (methods == NULL)
+    return;
+  for (Methods::const_iterator p = methods->begin();
+       p != methods->end();
+       ++p)
+    {
+      Method* m = p->second;
+      if (m->is_ambiguous() || !m->needs_stub_method())
+       continue;
+
+      const std::string& name(p->first);
+
+      // Build a stub method.
+
+      const Function_type* fntype = m->type();
+
+      static unsigned int counter;
+      char buf[100];
+      snprintf(buf, sizeof buf, "$this%u", counter);
+      ++counter;
+
+      Type* receiver_type = const_cast<Type*>(type);
+      if (!m->is_value_method())
+       receiver_type = Type::make_pointer_type(receiver_type);
+      source_location receiver_location = m->receiver_location();
+      Typed_identifier* receiver = new Typed_identifier(buf, receiver_type,
+                                                       receiver_location);
+
+      const Typed_identifier_list* fnparams = fntype->parameters();
+      Typed_identifier_list* stub_params;
+      if (fnparams == NULL || fnparams->empty())
+       stub_params = NULL;
+      else
+       {
+         // We give each stub parameter a unique name.
+         stub_params = new Typed_identifier_list();
+         for (Typed_identifier_list::const_iterator pp = fnparams->begin();
+              pp != fnparams->end();
+              ++pp)
+           {
+             char pbuf[100];
+             snprintf(pbuf, sizeof pbuf, "$p%u", counter);
+             stub_params->push_back(Typed_identifier(pbuf, pp->type(),
+                                                     pp->location()));
+             ++counter;
+           }
+       }
+
+      const Typed_identifier_list* fnresults = fntype->results();
+      Typed_identifier_list* stub_results;
+      if (fnresults == NULL || fnresults->empty())
+       stub_results = NULL;
+      else
+       {
+         // We create the result parameters without any names, since
+         // we won't refer to them.
+         stub_results = new Typed_identifier_list();
+         for (Typed_identifier_list::const_iterator pr = fnresults->begin();
+              pr != fnresults->end();
+              ++pr)
+           stub_results->push_back(Typed_identifier("", pr->type(),
+                                                    pr->location()));
+       }
+
+      Function_type* stub_type = Type::make_function_type(receiver,
+                                                         stub_params,
+                                                         stub_results,
+                                                         fntype->location());
+      if (fntype->is_varargs())
+       stub_type->set_is_varargs();
+
+      // We only create the function in the package which creates the
+      // type.
+      const Package* package;
+      if (type->named_type() == NULL)
+       package = NULL;
+      else
+       package = type->named_type()->named_object()->package();
+      Named_object* stub;
+      if (package != NULL)
+       stub = Named_object::make_function_declaration(name, package,
+                                                      stub_type, location);
+      else
+       {
+         stub = gogo->start_function(name, stub_type, false,
+                                     fntype->location());
+         Type::build_one_stub_method(gogo, m, buf, stub_params,
+                                     fntype->is_varargs(), location);
+         gogo->finish_function(fntype->location());
+       }
+
+      m->set_stub_object(stub);
+    }
+}
+
+// Build a stub method which adjusts the receiver as required to call
+// METHOD.  RECEIVER_NAME is the name we used for the receiver.
+// PARAMS is the list of function parameters.
+
+void
+Type::build_one_stub_method(Gogo* gogo, Method* method,
+                           const char* receiver_name,
+                           const Typed_identifier_list* params,
+                           bool is_varargs,
+                           source_location location)
+{
+  Named_object* receiver_object = gogo->lookup(receiver_name, NULL);
+  gcc_assert(receiver_object != NULL);
+
+  Expression* expr = Expression::make_var_reference(receiver_object, location);
+  expr = Type::apply_field_indexes(expr, method->field_indexes(), location);
+  if (expr->type()->points_to() == NULL)
+    expr = Expression::make_unary(OPERATOR_AND, expr, location);
+
+  Expression_list* arguments;
+  if (params == NULL || params->empty())
+    arguments = NULL;
+  else
+    {
+      arguments = new Expression_list();
+      for (Typed_identifier_list::const_iterator p = params->begin();
+          p != params->end();
+          ++p)
+       {
+         Named_object* param = gogo->lookup(p->name(), NULL);
+         gcc_assert(param != NULL);
+         Expression* param_ref = Expression::make_var_reference(param,
+                                                                location);
+         arguments->push_back(param_ref);
+       }
+    }
+
+  Expression* func = method->bind_method(expr, location);
+  gcc_assert(func != NULL);
+  Call_expression* call = Expression::make_call(func, arguments, is_varargs,
+                                               location);
+  size_t count = call->result_count();
+  if (count == 0)
+    gogo->add_statement(Statement::make_statement(call));
+  else
+    {
+      Expression_list* retvals = new Expression_list();
+      if (count <= 1)
+       retvals->push_back(call);
+      else
+       {
+         for (size_t i = 0; i < count; ++i)
+           retvals->push_back(Expression::make_call_result(call, i));
+       }
+      const Function* function = gogo->current_function()->func_value();
+      const Typed_identifier_list* results = function->type()->results();
+      Statement* retstat = Statement::make_return_statement(results, retvals,
+                                                           location);
+      gogo->add_statement(retstat);
+    }
+}
+
+// Apply FIELD_INDEXES to EXPR.  The field indexes have to be applied
+// in reverse order.
+
+Expression*
+Type::apply_field_indexes(Expression* expr,
+                         const Method::Field_indexes* field_indexes,
+                         source_location location)
+{
+  if (field_indexes == NULL)
+    return expr;
+  expr = Type::apply_field_indexes(expr, field_indexes->next, location);
+  Struct_type* stype = expr->type()->deref()->struct_type();
+  gcc_assert(stype != NULL
+            && field_indexes->field_index < stype->field_count());
+  if (expr->type()->struct_type() == NULL)
+    {
+      gcc_assert(expr->type()->points_to() != NULL);
+      expr = Expression::make_unary(OPERATOR_MULT, expr, location);
+      gcc_assert(expr->type()->struct_type() == stype);
+    }
+  return Expression::make_field_reference(expr, field_indexes->field_index,
+                                         location);
+}
+
+// Return whether NO is a method for which the receiver is a pointer.
+
+bool
+Type::method_expects_pointer(const Named_object* no)
+{
+  const Function_type *fntype;
+  if (no->is_function())
+    fntype = no->func_value()->type();
+  else if (no->is_function_declaration())
+    fntype = no->func_declaration_value()->type();
+  else
+    gcc_unreachable();
+  return fntype->receiver()->type()->points_to() != NULL;
+}
+
+// Given a set of methods for a type, METHODS, return the method NAME,
+// or NULL if there isn't one or if it is ambiguous.  If IS_AMBIGUOUS
+// is not NULL, then set *IS_AMBIGUOUS to true if the method exists
+// but is ambiguous (and return NULL).
+
+Method*
+Type::method_function(const Methods* methods, const std::string& name,
+                     bool* is_ambiguous)
+{
+  if (is_ambiguous != NULL)
+    *is_ambiguous = false;
+  if (methods == NULL)
+    return NULL;
+  Methods::const_iterator p = methods->find(name);
+  if (p == methods->end())
+    return NULL;
+  Method* m = p->second;
+  if (m->is_ambiguous())
+    {
+      if (is_ambiguous != NULL)
+       *is_ambiguous = true;
+      return NULL;
+    }
+  return m;
+}
+
+// Look for field or method NAME for TYPE.  Return an Expression for
+// the field or method bound to EXPR.  If there is no such field or
+// method, give an appropriate error and return an error expression.
+
+Expression*
+Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
+                          const std::string& name,
+                          source_location location)
+{
+  if (type->is_error_type())
+    return Expression::make_error(location);
+
+  const Named_type* nt = type->named_type();
+  if (nt == NULL)
+    nt = type->deref()->named_type();
+  const Struct_type* st = type->deref()->struct_type();
+  const Interface_type* it = type->deref()->interface_type();
+
+  // If this is a pointer to a pointer, then it is possible that the
+  // pointed-to type has methods.
+  if (nt == NULL
+      && st == NULL
+      && it == NULL
+      && type->points_to() != NULL
+      && type->points_to()->points_to() != NULL)
+    {
+      expr = Expression::make_unary(OPERATOR_MULT, expr, location);
+      type = type->points_to();
+      nt = type->points_to()->named_type();
+      st = type->points_to()->struct_type();
+      it = type->points_to()->interface_type();
+    }
+
+  bool receiver_can_be_pointer = (expr->type()->points_to() != NULL
+                                 || expr->is_addressable());
+  bool is_method = false;
+  bool found_pointer_method = false;
+  std::string ambig1;
+  std::string ambig2;
+  if (Type::find_field_or_method(type, name, receiver_can_be_pointer, NULL,
+                                &is_method, &found_pointer_method,
+                                &ambig1, &ambig2))
+    {
+      Expression* ret;
+      if (!is_method)
+       {
+         gcc_assert(st != NULL);
+         if (type->struct_type() == NULL)
+           {
+             gcc_assert(type->points_to() != NULL);
+             expr = Expression::make_unary(OPERATOR_MULT, expr,
+                                           location);
+             gcc_assert(expr->type()->struct_type() == st);
+           }
+         ret = st->field_reference(expr, name, location);
+       }
+      else if (it != NULL && it->find_method(name) != NULL)
+       ret = Expression::make_interface_field_reference(expr, name,
+                                                        location);
+      else
+       {
+         Method* m;
+         if (nt != NULL)
+           m = nt->method_function(name, NULL);
+         else if (st != NULL)
+           m = st->method_function(name, NULL);
+         else
+           gcc_unreachable();
+         gcc_assert(m != NULL);
+         if (!m->is_value_method() && expr->type()->points_to() == NULL)
+           expr = Expression::make_unary(OPERATOR_AND, expr, location);
+         ret = m->bind_method(expr, location);
+       }
+      gcc_assert(ret != NULL);
+      return ret;
+    }
+  else
+    {
+      if (!ambig1.empty())
+       error_at(location, "%qs is ambiguous via %qs and %qs",
+                Gogo::message_name(name).c_str(),
+                Gogo::message_name(ambig1).c_str(),
+                Gogo::message_name(ambig2).c_str());
+      else if (found_pointer_method)
+       error_at(location, "method requires a pointer");
+      else if (nt == NULL && st == NULL && it == NULL)
+       error_at(location,
+                ("reference to field %qs in object which "
+                 "has no fields or methods"),
+                Gogo::message_name(name).c_str());
+      else
+       {
+         bool is_unexported;
+         if (!Gogo::is_hidden_name(name))
+           is_unexported = false;
+         else
+           {
+             std::string unpacked = Gogo::unpack_hidden_name(name);
+             is_unexported = Type::is_unexported_field_or_method(gogo, type,
+                                                                 unpacked);
+           }
+         if (is_unexported)
+           error_at(location, "reference to unexported field or method %qs",
+                    Gogo::message_name(name).c_str());
+         else
+           error_at(location, "reference to undefined field or method %qs",
+                    Gogo::message_name(name).c_str());
+       }
+      return Expression::make_error(location);
+    }
+}
+
+// Look in TYPE for a field or method named NAME, return true if one
+// is found.  This looks through embedded anonymous fields and handles
+// ambiguity.  If a method is found, sets *IS_METHOD to true;
+// otherwise, if a field is found, set it to false.  If
+// RECEIVER_CAN_BE_POINTER is false, then the receiver is a value
+// whose address can not be taken.  When returning false, this sets
+// *FOUND_POINTER_METHOD if we found a method we couldn't use because
+// it requires a pointer.  LEVEL is used for recursive calls, and can
+// be NULL for a non-recursive call.  When this function returns false
+// because it finds that the name is ambiguous, it will store a path
+// to the ambiguous names in *AMBIG1 and *AMBIG2.  If the name is not
+// found at all, *AMBIG1 and *AMBIG2 will be unchanged.
+
+// This function just returns whether or not there is a field or
+// method, and whether it is a field or method.  It doesn't build an
+// expression to refer to it.  If it is a method, we then look in the
+// list of all methods for the type.  If it is a field, the search has
+// to be done again, looking only for fields, and building up the
+// expression as we go.
+
+bool
+Type::find_field_or_method(const Type* type,
+                          const std::string& name,
+                          bool receiver_can_be_pointer,
+                          int* level,
+                          bool* is_method,
+                          bool* found_pointer_method,
+                          std::string* ambig1,
+                          std::string* ambig2)
+{
+  // Named types can have locally defined methods.
+  const Named_type* nt = type->named_type();
+  if (nt == NULL && type->points_to() != NULL)
+    nt = type->points_to()->named_type();
+  if (nt != NULL)
+    {
+      Named_object* no = nt->find_local_method(name);
+      if (no != NULL)
+       {
+         if (receiver_can_be_pointer || !Type::method_expects_pointer(no))
+           {
+             *is_method = true;
+             return true;
+           }
+
+         // Record that we have found a pointer method in order to
+         // give a better error message if we don't find anything
+         // else.
+         *found_pointer_method = true;
+       }
+    }
+
+  // Interface types can have methods.
+  const Interface_type* it = type->deref()->interface_type();
+  if (it != NULL && it->find_method(name) != NULL)
+    {
+      *is_method = true;
+      return true;
+    }
+
+  // Struct types can have fields.  They can also inherit fields and
+  // methods from anonymous fields.
+  const Struct_type* st = type->deref()->struct_type();
+  if (st == NULL)
+    return false;
+  const Struct_field_list* fields = st->fields();
+  if (fields == NULL)
+    return false;
+
+  int found_level = 0;
+  bool found_is_method = false;
+  std::string found_ambig1;
+  std::string found_ambig2;
+  const Struct_field* found_parent = NULL;
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf)
+    {
+      if (pf->field_name() == name)
+       {
+         *is_method = false;
+         return true;
+       }
+
+      if (!pf->is_anonymous())
+       continue;
+
+      Named_type* fnt = pf->type()->deref()->named_type();
+      gcc_assert(fnt != NULL);
+
+      int sublevel = level == NULL ? 1 : *level + 1;
+      bool sub_is_method;
+      std::string subambig1;
+      std::string subambig2;
+      bool subfound = Type::find_field_or_method(fnt,
+                                                name,
+                                                receiver_can_be_pointer,
+                                                &sublevel,
+                                                &sub_is_method,
+                                                found_pointer_method,
+                                                &subambig1,
+                                                &subambig2);
+      if (!subfound)
+       {
+         if (!subambig1.empty())
+           {
+             // The name was found via this field, but is ambiguous.
+             // if the ambiguity is lower or at the same level as
+             // anything else we have already found, then we want to
+             // pass the ambiguity back to the caller.
+             if (found_level == 0 || sublevel <= found_level)
+               {
+                 found_ambig1 = pf->field_name() + '.' + subambig1;
+                 found_ambig2 = pf->field_name() + '.' + subambig2;
+                 found_level = sublevel;
+               }
+           }
+       }
+      else
+       {
+         // The name was found via this field.  Use the level to see
+         // if we want to use this one, or whether it introduces an
+         // ambiguity.
+         if (found_level == 0 || sublevel < found_level)
+           {
+             found_level = sublevel;
+             found_is_method = sub_is_method;
+             found_ambig1.clear();
+             found_ambig2.clear();
+             found_parent = &*pf;
+           }
+         else if (sublevel > found_level)
+           ;
+         else if (found_ambig1.empty())
+           {
+             // We found an ambiguity.
+             gcc_assert(found_parent != NULL);
+             found_ambig1 = found_parent->field_name();
+             found_ambig2 = pf->field_name();
+           }
+         else
+           {
+             // We found an ambiguity, but we already know of one.
+             // Just report the earlier one.
+           }
+       }
+    }
+
+  // Here if we didn't find anything FOUND_LEVEL is 0.  If we found
+  // something ambiguous, FOUND_LEVEL is not 0 and FOUND_AMBIG1 and
+  // FOUND_AMBIG2 are not empty.  If we found the field, FOUND_LEVEL
+  // is not 0 and FOUND_AMBIG1 and FOUND_AMBIG2 are empty.
+
+  if (found_level == 0)
+    return false;
+  else if (!found_ambig1.empty())
+    {
+      gcc_assert(!found_ambig1.empty());
+      ambig1->assign(found_ambig1);
+      ambig2->assign(found_ambig2);
+      if (level != NULL)
+       *level = found_level;
+      return false;
+    }
+  else
+    {
+      if (level != NULL)
+       *level = found_level;
+      *is_method = found_is_method;
+      return true;
+    }
+}
+
+// Return whether NAME is an unexported field or method for TYPE.
+
+bool
+Type::is_unexported_field_or_method(Gogo* gogo, const Type* type,
+                                   const std::string& name)
+{
+  type = type->deref();
+
+  const Named_type* nt = type->named_type();
+  if (nt != NULL && nt->is_unexported_local_method(gogo, name))
+    return true;
+
+  const Interface_type* it = type->interface_type();
+  if (it != NULL && it->is_unexported_method(gogo, name))
+    return true;
+
+  const Struct_type* st = type->struct_type();
+  if (st != NULL && st->is_unexported_local_field(gogo, name))
+    return true;
+
+  if (st == NULL)
+    return false;
+
+  const Struct_field_list* fields = st->fields();
+  if (fields == NULL)
+    return false;
+
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf)
+    {
+      if (pf->is_anonymous())
+       {
+         Named_type* subtype = pf->type()->deref()->named_type();
+         gcc_assert(subtype != NULL);
+         if (Type::is_unexported_field_or_method(gogo, subtype, name))
+           return true;
+       }
+    }
+
+  return false;
+}
+
+// Class Forward_declaration.
+
+Forward_declaration_type::Forward_declaration_type(Named_object* named_object)
+  : Type(TYPE_FORWARD),
+    named_object_(named_object->resolve()), warned_(false)
+{
+  gcc_assert(this->named_object_->is_unknown()
+            || this->named_object_->is_type_declaration());
+}
+
+// Return the named object.
+
+Named_object*
+Forward_declaration_type::named_object()
+{
+  return this->named_object_->resolve();
+}
+
+const Named_object*
+Forward_declaration_type::named_object() const
+{
+  return this->named_object_->resolve();
+}
+
+// Return the name of the forward declared type.
+
+const std::string&
+Forward_declaration_type::name() const
+{
+  return this->named_object()->name();
+}
+
+// Warn about a use of a type which has been declared but not defined.
+
+void
+Forward_declaration_type::warn() const
+{
+  Named_object* no = this->named_object_->resolve();
+  if (no->is_unknown())
+    {
+      // The name was not defined anywhere.
+      if (!this->warned_)
+       {
+         error_at(this->named_object_->location(),
+                  "use of undefined type %qs",
+                  no->message_name().c_str());
+         this->warned_ = true;
+       }
+    }
+  else if (no->is_type_declaration())
+    {
+      // The name was seen as a type, but the type was never defined.
+      if (no->type_declaration_value()->using_type())
+       {
+         error_at(this->named_object_->location(),
+                  "use of undefined type %qs",
+                  no->message_name().c_str());
+         this->warned_ = true;
+       }
+    }
+  else
+    {
+      // The name was defined, but not as a type.
+      if (!this->warned_)
+       {
+         error_at(this->named_object_->location(), "expected type");
+         this->warned_ = true;
+       }
+    }
+}
+
+// Get the base type of a declaration.  This gives an error if the
+// type has not yet been defined.
+
+Type*
+Forward_declaration_type::real_type()
+{
+  if (this->is_defined())
+    return this->named_object()->type_value();
+  else
+    {
+      this->warn();
+      return Type::make_error_type();
+    }
+}
+
+const Type*
+Forward_declaration_type::real_type() const
+{
+  if (this->is_defined())
+    return this->named_object()->type_value();
+  else
+    {
+      this->warn();
+      return Type::make_error_type();
+    }
+}
+
+// Return whether the base type is defined.
+
+bool
+Forward_declaration_type::is_defined() const
+{
+  return this->named_object()->is_type();
+}
+
+// Add a method.  This is used when methods are defined before the
+// type.
+
+Named_object*
+Forward_declaration_type::add_method(const std::string& name,
+                                    Function* function)
+{
+  Named_object* no = this->named_object();
+  gcc_assert(no->is_type_declaration());
+  return no->type_declaration_value()->add_method(name, function);
+}
+
+// Add a method declaration.  This is used when methods are declared
+// before the type.
+
+Named_object*
+Forward_declaration_type::add_method_declaration(const std::string& name,
+                                                Function_type* type,
+                                                source_location location)
+{
+  Named_object* no = this->named_object();
+  gcc_assert(no->is_type_declaration());
+  Type_declaration* td = no->type_declaration_value();
+  return td->add_method_declaration(name, type, location);
+}
+
+// Traversal.
+
+int
+Forward_declaration_type::do_traverse(Traverse* traverse)
+{
+  if (this->is_defined()
+      && Type::traverse(this->real_type(), traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Get a tree for the type.
+
+tree
+Forward_declaration_type::do_get_tree(Gogo* gogo)
+{
+  if (this->is_defined())
+    return Type::get_named_type_tree(gogo, this->real_type());
+
+  if (this->warned_)
+    return error_mark_node;
+
+  // We represent an undefined type as a struct with no fields.  That
+  // should work fine for the middle-end, since the same case can
+  // arise in C.
+  Named_object* no = this->named_object();
+  tree type_tree = make_node(RECORD_TYPE);
+  tree id = no->get_id(gogo);
+  tree decl = build_decl(no->location(), TYPE_DECL, id, type_tree);
+  TYPE_NAME(type_tree) = decl;
+  return type_tree;
+}
+
+// Build a type descriptor for a forwarded type.
+
+Expression*
+Forward_declaration_type::do_type_descriptor(Gogo* gogo, Named_type* name)
+{
+  if (!this->is_defined())
+    return Expression::make_nil(BUILTINS_LOCATION);
+  else
+    {
+      Type* t = this->real_type();
+      if (name != NULL)
+       return this->named_type_descriptor(gogo, t, name);
+      else
+       return Expression::make_type_descriptor(t, BUILTINS_LOCATION);
+    }
+}
+
+// The reflection string.
+
+void
+Forward_declaration_type::do_reflection(Gogo* gogo, std::string* ret) const
+{
+  this->append_reflection(this->real_type(), gogo, ret);
+}
+
+// The mangled name.
+
+void
+Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+  if (this->is_defined())
+    this->append_mangled_name(this->real_type(), gogo, ret);
+  else
+    {
+      const Named_object* no = this->named_object();
+      std::string name;
+      if (no->package() == NULL)
+       name = gogo->package_name();
+      else
+       name = no->package()->name();
+      name += '.';
+      name += Gogo::unpack_hidden_name(no->name());
+      char buf[20];
+      snprintf(buf, sizeof buf, "N%u_",
+              static_cast<unsigned int>(name.length()));
+      ret->append(buf);
+      ret->append(name);
+    }
+}
+
+// Export a forward declaration.  This can happen when a defined type
+// refers to a type which is only declared (and is presumably defined
+// in some other file in the same package).
+
+void
+Forward_declaration_type::do_export(Export*) const
+{
+  // If there is a base type, that should be exported instead of this.
+  gcc_assert(!this->is_defined());
+
+  // We don't output anything.
+}
+
+// Make a forward declaration.
+
+Type*
+Type::make_forward_declaration(Named_object* named_object)
+{
+  return new Forward_declaration_type(named_object);
+}
+
+// Class Typed_identifier_list.
+
+// Sort the entries by name.
+
+struct Typed_identifier_list_sort
+{
+ public:
+  bool
+  operator()(const Typed_identifier& t1, const Typed_identifier& t2) const
+  { return t1.name() < t2.name(); }
+};
+
+void
+Typed_identifier_list::sort_by_name()
+{
+  std::sort(this->entries_.begin(), this->entries_.end(),
+           Typed_identifier_list_sort());
+}
+
+// Traverse types.
+
+int
+Typed_identifier_list::traverse(Traverse* traverse)
+{
+  for (Typed_identifier_list::const_iterator p = this->begin();
+       p != this->end();
+       ++p)
+    {
+      if (Type::traverse(p->type(), traverse) == TRAVERSE_EXIT)
+       return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Copy the list.
+
+Typed_identifier_list*
+Typed_identifier_list::copy() const
+{
+  Typed_identifier_list* ret = new Typed_identifier_list();
+  for (Typed_identifier_list::const_iterator p = this->begin();
+       p != this->end();
+       ++p)
+    ret->push_back(Typed_identifier(p->name(), p->type(), p->location()));
+  return ret;
+}
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
new file mode 100644 (file)
index 0000000..025f85f
--- /dev/null
@@ -0,0 +1,2730 @@
+// types.h -- Go frontend types.     -*- C++ -*-
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_TYPES_H
+#define GO_TYPES_H
+
+class Gogo;
+class Package;
+class Traverse;
+class Typed_identifier;
+class Typed_identifier_list;
+class Integer_type;
+class Float_type;
+class Complex_type;
+class String_type;
+class Function_type;
+class Struct_field;
+class Struct_field_list;
+class Struct_type;
+class Pointer_type;
+class Array_type;
+class Map_type;
+class Channel_type;
+class Interface_type;
+class Named_type;
+class Forward_declaration_type;
+class Method;
+class Methods;
+class Type_hash_identical;
+class Type_identical;
+class Expression;
+class Expression_list;
+class Call_expression;
+class Field_reference_expression;
+class Bound_method_expression;
+class Bindings;
+class Named_object;
+class Function;
+class Translate_context;
+class Export;
+class Import;
+
+// Type codes used in type descriptors.  These must match the values
+// in libgo/runtime/go-type.h.  They also match the values in the gc
+// compiler in src/cmd/gc/reflect.c and src/pkg/runtime/type.go,
+// although this is not required.
+
+static const int RUNTIME_TYPE_KIND_BOOL = 1;
+static const int RUNTIME_TYPE_KIND_INT = 2;
+static const int RUNTIME_TYPE_KIND_INT8 = 3;
+static const int RUNTIME_TYPE_KIND_INT16 = 4;
+static const int RUNTIME_TYPE_KIND_INT32 = 5;
+static const int RUNTIME_TYPE_KIND_INT64 = 6;
+static const int RUNTIME_TYPE_KIND_UINT = 7;
+static const int RUNTIME_TYPE_KIND_UINT8 = 8;
+static const int RUNTIME_TYPE_KIND_UINT16 = 9;
+static const int RUNTIME_TYPE_KIND_UINT32 = 10;
+static const int RUNTIME_TYPE_KIND_UINT64 = 11;
+static const int RUNTIME_TYPE_KIND_UINTPTR = 12;
+static const int RUNTIME_TYPE_KIND_FLOAT = 13;
+static const int RUNTIME_TYPE_KIND_FLOAT32 = 14;
+static const int RUNTIME_TYPE_KIND_FLOAT64 = 15;
+static const int RUNTIME_TYPE_KIND_COMPLEX = 16;
+static const int RUNTIME_TYPE_KIND_COMPLEX64 = 17;
+static const int RUNTIME_TYPE_KIND_COMPLEX128 = 18;
+static const int RUNTIME_TYPE_KIND_ARRAY = 19;
+static const int RUNTIME_TYPE_KIND_CHAN = 20;
+static const int RUNTIME_TYPE_KIND_FUNC = 21;
+static const int RUNTIME_TYPE_KIND_INTERFACE = 22;
+static const int RUNTIME_TYPE_KIND_MAP = 23;
+static const int RUNTIME_TYPE_KIND_PTR = 24;
+static const int RUNTIME_TYPE_KIND_SLICE = 25;
+static const int RUNTIME_TYPE_KIND_STRING = 26;
+static const int RUNTIME_TYPE_KIND_STRUCT = 27;
+static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 28;
+
+// To build the complete list of methods for a named type we need to
+// gather all methods from anonymous fields.  Those methods may
+// require an arbitrary set of indirections and field offsets.  There
+// is also the possibility of ambiguous methods, which we could ignore
+// except that we want to give a better error message for that case.
+// This is a base class.  There are two types of methods: named
+// methods, and methods which are inherited from an anonymous field of
+// interface type.
+
+class Method
+{
+ public:
+  // For methods in anonymous types we need to know the sequence of
+  // field references used to extract the pointer to pass to the
+  // method.  Since each method for a particular anonymous field will
+  // have the sequence of field indexes, and since the indexes can be
+  // shared going down the chain, we use a manually managed linked
+  // list.  The first entry in the list is the field index for the
+  // last field, the one passed to the method.
+
+  struct Field_indexes
+  {
+    const Field_indexes* next;
+    unsigned int field_index;
+  };
+
+  virtual ~Method()
+  { }
+
+  // Get the list of field indexes.
+  const Field_indexes*
+  field_indexes() const
+  { return this->field_indexes_; }
+
+  // Get the depth.
+  unsigned int
+  depth() const
+  { return this->depth_; }
+
+  // Return whether this is a value method--a method which does not
+  // require a pointer expression.
+  bool
+  is_value_method() const
+  { return this->is_value_method_; }
+
+  // Return whether we need a stub method--this is true if we can't
+  // just pass the main object to the method.
+  bool
+  needs_stub_method() const
+  { return this->needs_stub_method_; }
+
+  // Return whether this is an ambiguous method name.
+  bool
+  is_ambiguous() const
+  { return this->is_ambiguous_; }
+
+  // Note that this method is ambiguous.
+  void
+  set_is_ambiguous()
+  { this->is_ambiguous_ = true; }
+
+  // Return the type of the method.
+  Function_type*
+  type() const
+  { return this->do_type(); }
+
+  // Return the location of the method receiver.
+  source_location
+  receiver_location() const
+  { return this->do_receiver_location(); }
+
+  // Return an expression which binds this method to EXPR.  This is
+  // something which can be used with a function call.
+  Expression*
+  bind_method(Expression* expr, source_location location) const;
+
+  // Return the named object for this method.  This may only be called
+  // after methods are finalized.
+  Named_object*
+  named_object() const;
+
+  // Get the stub object.
+  Named_object*
+  stub_object() const
+  {
+    gcc_assert(this->stub_ != NULL);
+    return this->stub_;
+  }
+
+  // Set the stub object.
+  void
+  set_stub_object(Named_object* no)
+  {
+    gcc_assert(this->stub_ == NULL);
+    this->stub_ = no;
+  }
+
+ protected:
+  // These objects are only built by the child classes.
+  Method(const Field_indexes* field_indexes, unsigned int depth,
+        bool is_value_method, bool needs_stub_method)
+    : field_indexes_(field_indexes), depth_(depth), stub_(NULL),
+      is_value_method_(is_value_method), needs_stub_method_(needs_stub_method),
+      is_ambiguous_(false)
+  { }
+
+  // The named object for this method.
+  virtual Named_object*
+  do_named_object() const = 0;
+
+  // The type of the method.
+  virtual Function_type*
+  do_type() const = 0;
+
+  // Return the location of the method receiver.
+  virtual source_location
+  do_receiver_location() const = 0;
+
+  // Bind a method to an object.
+  virtual Expression*
+  do_bind_method(Expression* expr, source_location location) const = 0;
+
+ private:
+  // The sequence of field indexes used for this method.  If this is
+  // NULL, then the method is defined for the current type.
+  const Field_indexes* field_indexes_;
+  // The depth at which this method was found.
+  unsigned int depth_;
+  // If a stub method is required, this is its object.  This is only
+  // set after stub methods are built in finalize_methods.
+  Named_object* stub_;
+  // Whether this is a value method--a method that does not require a
+  // pointer.
+  bool is_value_method_;
+  // Whether a stub method is required.
+  bool needs_stub_method_;
+  // Whether this method is ambiguous.
+  bool is_ambiguous_;
+};
+
+// A named method.  This is what you get with a method declaration,
+// either directly on the type, or inherited from some anonymous
+// embedded field.
+
+class Named_method : public Method
+{
+ public:
+  Named_method(Named_object* named_object, const Field_indexes* field_indexes,
+              unsigned int depth, bool is_value_method,
+              bool needs_stub_method)
+    : Method(field_indexes, depth, is_value_method, needs_stub_method),
+      named_object_(named_object)
+  { }
+
+ protected:
+  // Get the Named_object for the method.
+  Named_object*
+  do_named_object() const
+  { return this->named_object_; }
+
+  // The type of the method.
+  Function_type*
+  do_type() const;
+
+  // Return the location of the method receiver.
+  source_location
+  do_receiver_location() const;
+
+  // Bind a method to an object.
+  Expression*
+  do_bind_method(Expression* expr, source_location location) const;
+
+ private:
+  // The method itself.  For a method which needs a stub, this starts
+  // out as the underlying method, and is later replaced with the stub
+  // method.
+  Named_object* named_object_;
+};
+
+// An interface method.  This is used when an interface appears as an
+// anonymous field in a named struct.
+
+class Interface_method : public Method
+{
+ public:
+  Interface_method(const std::string& name, source_location location,
+                  Function_type* fntype, const Field_indexes* field_indexes,
+                  unsigned int depth)
+    : Method(field_indexes, depth, true, true),
+      name_(name), location_(location), fntype_(fntype)
+  { }
+
+ protected:
+  // Get the Named_object for the method.  This should never be
+  // called, as we always create a stub.
+  Named_object*
+  do_named_object() const
+  { gcc_unreachable(); }
+
+  // The type of the method.
+  Function_type*
+  do_type() const
+  { return this->fntype_; }
+
+  // Return the location of the method receiver.
+  source_location
+  do_receiver_location() const
+  { return this->location_; }
+
+  // Bind a method to an object.
+  Expression*
+  do_bind_method(Expression* expr, source_location location) const;
+
+ private:
+  // The name of the interface method to call.
+  std::string name_;
+  // The location of the definition of the interface method.
+  source_location location_;
+  // The type of the interface method.
+  Function_type* fntype_;
+};
+
+// A mapping from method name to Method.  This is a wrapper around a
+// hash table.
+
+class Methods
+{
+ private:
+  typedef Unordered_map(std::string, Method*) Method_map;
+
+ public:
+  typedef Method_map::const_iterator const_iterator;
+
+  Methods()
+    : methods_()
+  { }
+
+  // Insert a new method.  Returns true if it was inserted, false if
+  // it was overidden or ambiguous.
+  bool
+  insert(const std::string& name, Method* m);
+
+  // The number of (unambiguous) methods.
+  size_t
+  count() const;
+
+  // Iterate.
+  const_iterator
+  begin() const
+  { return this->methods_.begin(); }
+
+  const_iterator
+  end() const
+  { return this->methods_.end(); }
+
+  // Lookup.
+  const_iterator
+  find(const std::string& name) const
+  { return this->methods_.find(name); }
+
+ private:
+  Method_map methods_;
+};
+
+// The base class for all types.
+
+class Type
+{
+ public:
+  // The types of types.
+  enum Type_classification
+  {
+    TYPE_ERROR,
+    TYPE_VOID,
+    TYPE_BOOLEAN,
+    TYPE_INTEGER,
+    TYPE_FLOAT,
+    TYPE_COMPLEX,
+    TYPE_STRING,
+    TYPE_SINK,
+    TYPE_FUNCTION,
+    TYPE_POINTER,
+    TYPE_NIL,
+    TYPE_CALL_MULTIPLE_RESULT,
+    TYPE_STRUCT,
+    TYPE_ARRAY,
+    TYPE_MAP,
+    TYPE_CHANNEL,
+    TYPE_INTERFACE,
+    TYPE_NAMED,
+    TYPE_FORWARD
+  };
+
+  virtual ~Type();
+
+  // Creators.
+
+  static Type*
+  make_error_type();
+
+  static Type*
+  make_void_type();
+
+  // Get the unnamed bool type.
+  static Type*
+  make_boolean_type();
+
+  // Get the named type "bool".
+  static Named_type*
+  lookup_bool_type();
+
+  // Make the named type "bool".
+  static Named_type*
+  make_named_bool_type();
+
+  // Make an abstract integer type.
+  static Integer_type*
+  make_abstract_integer_type();
+
+  // Make a named integer type with a specified size.
+  // RUNTIME_TYPE_KIND is the code to use in reflection information,
+  // to distinguish int and int32.
+  static Named_type*
+  make_integer_type(const char* name, bool is_unsigned, int bits,
+                   int runtime_type_kind);
+
+  // Look up a named integer type.
+  static Named_type*
+  lookup_integer_type(const char* name);
+
+  // Make an abstract floating point type.
+  static Float_type*
+  make_abstract_float_type();
+
+  // Make a named floating point type with a specific size.
+  // RUNTIME_TYPE_KIND is the code to use in reflection information,
+  // to distinguish float and float32.
+  static Named_type*
+  make_float_type(const char* name, int bits, int runtime_type_kind);
+
+  // Look up a named float type.
+  static Named_type*
+  lookup_float_type(const char* name);
+
+  // Make an abstract complex type.
+  static Complex_type*
+  make_abstract_complex_type();
+
+  // Make a named complex type with a specific size.
+  // RUNTIME_TYPE_KIND is the code to use in reflection information,
+  // to distinguish complex and complex64.
+  static Named_type*
+  make_complex_type(const char* name, int bits, int runtime_type_kind);
+
+  // Look up a named complex type.
+  static Named_type*
+  lookup_complex_type(const char* name);
+
+  // Get the unnamed string type.
+  static Type*
+  make_string_type();
+
+  // Get the named type "string".
+  static Named_type*
+  lookup_string_type();
+
+  // Make the named type "string".
+  static Named_type*
+  make_named_string_type();
+
+  static Type*
+  make_sink_type();
+
+  static Function_type*
+  make_function_type(Typed_identifier* receiver,
+                    Typed_identifier_list* parameters,
+                    Typed_identifier_list* results,
+                    source_location);
+
+  static Pointer_type*
+  make_pointer_type(Type*);
+
+  static Type*
+  make_nil_type();
+
+  static Type*
+  make_call_multiple_result_type(Call_expression*);
+
+  static Struct_type*
+  make_struct_type(Struct_field_list* fields, source_location);
+
+  static Array_type*
+  make_array_type(Type* element_type, Expression* length);
+
+  static Map_type*
+  make_map_type(Type* key_type, Type* value_type, source_location);
+
+  static Channel_type*
+  make_channel_type(bool send, bool receive, Type*);
+
+  static Interface_type*
+  make_interface_type(Typed_identifier_list* methods, source_location);
+
+  static Type*
+  make_type_descriptor_type();
+
+  static Type*
+  make_type_descriptor_ptr_type();
+
+  static Named_type*
+  make_named_type(Named_object*, Type*, source_location);
+
+  static Type*
+  make_forward_declaration(Named_object*);
+
+  // Traverse a type.
+  static int
+  traverse(Type*, Traverse*);
+
+  // Verify the type.  This is called after parsing, and verifies that
+  // types are complete and meet the language requirements.  This
+  // returns false if the type is invalid.
+  bool
+  verify()
+  { return this->do_verify(); }
+
+  // Return true if two types are identical.  If this returns false,
+  // and REASON is not NULL, it may set *REASON.
+  static bool
+  are_identical(const Type* lhs, const Type* rhs, std::string* reason);
+
+  // Return true if two types are compatible for use in a binary
+  // operation, other than a shift, comparison, or channel send.  This
+  // is an equivalence relation.
+  static bool
+  are_compatible_for_binop(const Type* t1, const Type* t2);
+
+  // Return true if a value with type RHS is assignable to a variable
+  // with type LHS.  This is not an equivalence relation.  If this
+  // returns false, and REASON is not NULL, it sets *REASON.
+  static bool
+  are_assignable(const Type* lhs, const Type* rhs, std::string* reason);
+
+  // Return true if a value with type RHS may be converted to type
+  // LHS.  If this returns false, and REASON is not NULL, it sets
+  // *REASON.
+  static bool
+  are_convertible(const Type* lhs, const Type* rhs, std::string* reason);
+
+  // Whether this type has any hidden fields which are not visible in
+  // the current compilation, such as a field whose name begins with a
+  // lower case letter in a struct imported from a different package.
+  // WITHIN is not NULL if we are looking at fields in a named type.
+  bool
+  has_hidden_fields(const Named_type* within, std::string* reason) const;
+
+  // Return a hash code for this type for the method hash table.
+  // Types which are equivalent according to are_identical will have
+  // the same hash code.
+  unsigned int
+  hash_for_method(Gogo*) const;
+
+  // Return the type classification.
+  Type_classification
+  classification() const
+  { return this->classification_; }
+
+  // Return the base type for this type.  This looks through forward
+  // declarations and names.  Using this with a forward declaration
+  // which has not been defined will return an error type.
+  Type*
+  base();
+
+  const Type*
+  base() const;
+
+  // Return the type skipping defined forward declarations.  If this
+  // type is a forward declaration which has not been defined, it will
+  // return the Forward_declaration_type.  This differs from base() in
+  // that it will return a Named_type, and for a
+  // Forward_declaration_type which is not defined it will return that
+  // type rather than an error type.
+  Type*
+  forwarded();
+
+  const Type*
+  forwarded() const;
+
+  // Return true if this is a basic type: a type which is not composed
+  // of other types, and is not void.
+  bool
+  is_basic_type() const;
+
+  // Return true if this is an abstract type--an integer, floating
+  // point, or complex type whose size has not been determined.
+  bool
+  is_abstract() const;
+
+  // Return a non-abstract version of an abstract type.
+  Type*
+  make_non_abstract_type();
+
+  // Return true if this type is or contains a pointer.  This
+  // determines whether the garbage collector needs to look at a value
+  // of this type.
+  bool
+  has_pointer() const
+  { return this->do_has_pointer(); }
+
+  // Return true if this is an error type.  An error type indicates a
+  // parsing error.
+  bool
+  is_error_type() const;
+
+  // Return true if this is a void type.
+  bool
+  is_void_type() const
+  { return this->classification_ == TYPE_VOID; }
+
+  // If this is an integer type, return the Integer_type.  Otherwise,
+  // return NULL.  This is a controlled dynamic_cast.
+  Integer_type*
+  integer_type()
+  { return this->convert<Integer_type, TYPE_INTEGER>(); }
+
+  const Integer_type*
+  integer_type() const
+  { return this->convert<const Integer_type, TYPE_INTEGER>(); }
+
+  // If this is a floating point type, return the Float_type.
+  // Otherwise, return NULL.  This is a controlled dynamic_cast.
+  Float_type*
+  float_type()
+  { return this->convert<Float_type, TYPE_FLOAT>(); }
+
+  const Float_type*
+  float_type() const
+  { return this->convert<const Float_type, TYPE_FLOAT>(); }
+
+  // If this is a complex type, return the Complex_type.  Otherwise,
+  // return NULL.
+  Complex_type*
+  complex_type()
+  { return this->convert<Complex_type, TYPE_COMPLEX>(); }
+
+  const Complex_type*
+  complex_type() const
+  { return this->convert<const Complex_type, TYPE_COMPLEX>(); }
+
+  // Return true if this is a boolean type.
+  bool
+  is_boolean_type() const
+  { return this->base()->classification_ == TYPE_BOOLEAN; }
+
+  // Return true if this is an abstract boolean type.
+  bool
+  is_abstract_boolean_type() const
+  { return this->classification_ == TYPE_BOOLEAN; }
+
+  // Return true if this is a string type.
+  bool
+  is_string_type() const
+  { return this->base()->classification_ == TYPE_STRING; }
+
+  // Return true if this is an abstract string type.
+  bool
+  is_abstract_string_type() const
+  { return this->classification_ == TYPE_STRING; }
+
+  // Return true if this is the sink type.  This is the type of the
+  // blank identifier _.
+  bool
+  is_sink_type() const
+  { return this->base()->classification_ == TYPE_SINK; }
+
+  // If this is a function type, return it.  Otherwise, return NULL.
+  Function_type*
+  function_type()
+  { return this->convert<Function_type, TYPE_FUNCTION>(); }
+
+  const Function_type*
+  function_type() const
+  { return this->convert<const Function_type, TYPE_FUNCTION>(); }
+
+  // If this is a pointer type, return the type to which it points.
+  // Otherwise, return NULL.
+  Type*
+  points_to() const;
+
+  // If this is a pointer type, return the type to which it points.
+  // Otherwise, return the type itself.
+  Type*
+  deref()
+  {
+    Type* pt = this->points_to();
+    return pt != NULL ? pt : this;
+  }
+
+  const Type*
+  deref() const
+  {
+    const Type* pt = this->points_to();
+    return pt != NULL ? pt : this;
+  }
+
+  // Return true if this is the nil type.  We don't use base() here,
+  // because this can be called during parse, and there is no way to
+  // name the nil type anyhow.
+  bool
+  is_nil_type() const
+  { return this->classification_ == TYPE_NIL; }
+
+  // Return true if this is the predeclared constant nil being used as
+  // a type.  This is what the parser produces for type switches which
+  // use "case nil".
+  bool
+  is_nil_constant_as_type() const;
+
+  // Return true if this is the return type of a function which
+  // returns multiple values.
+  bool
+  is_call_multiple_result_type() const
+  { return this->base()->classification_ == TYPE_CALL_MULTIPLE_RESULT; }
+
+  // If this is a struct type, return it.  Otherwise, return NULL.
+  Struct_type*
+  struct_type()
+  { return this->convert<Struct_type, TYPE_STRUCT>(); }
+
+  const Struct_type*
+  struct_type() const
+  { return this->convert<const Struct_type, TYPE_STRUCT>(); }
+
+  // If this is an array type, return it.  Otherwise, return NULL.
+  Array_type*
+  array_type()
+  { return this->convert<Array_type, TYPE_ARRAY>(); }
+
+  const Array_type*
+  array_type() const
+  { return this->convert<const Array_type, TYPE_ARRAY>(); }
+
+  // Return whether if this is an open array type.
+  bool
+  is_open_array_type() const;
+
+  // If this is a map type, return it.  Otherwise, return NULL.
+  Map_type*
+  map_type()
+  { return this->convert<Map_type, TYPE_MAP>(); }
+
+  const Map_type*
+  map_type() const
+  { return this->convert<const Map_type, TYPE_MAP>(); }
+
+  // If this is a channel type, return it.  Otherwise, return NULL.
+  Channel_type*
+  channel_type()
+  { return this->convert<Channel_type, TYPE_CHANNEL>(); }
+
+  const Channel_type*
+  channel_type() const
+  { return this->convert<const Channel_type, TYPE_CHANNEL>(); }
+
+  // If this is an interface type, return it.  Otherwise, return NULL.
+  Interface_type*
+  interface_type()
+  { return this->convert<Interface_type, TYPE_INTERFACE>(); }
+
+  const Interface_type*
+  interface_type() const
+  { return this->convert<const Interface_type, TYPE_INTERFACE>(); }
+
+  // If this is a named type, return it.  Otherwise, return NULL.
+  Named_type*
+  named_type();
+
+  const Named_type*
+  named_type() const;
+
+  // If this is a forward declaration, return it.  Otherwise, return
+  // NULL.
+  Forward_declaration_type*
+  forward_declaration_type()
+  { return this->convert_no_base<Forward_declaration_type, TYPE_FORWARD>(); }
+
+  const Forward_declaration_type*
+  forward_declaration_type() const
+  {
+    return this->convert_no_base<const Forward_declaration_type,
+                                TYPE_FORWARD>();
+  }
+
+  // Return true if this type is not yet defined.
+  bool
+  is_undefined() const;
+
+  // Return true if this is the unsafe.pointer type.  We currently
+  // represent that as pointer-to-void.
+  bool
+  is_unsafe_pointer_type() const
+  { return this->points_to() != NULL && this->points_to()->is_void_type(); }
+
+  // Look for field or method NAME for TYPE.  Return an expression for
+  // it, bound to EXPR.
+  static Expression*
+  bind_field_or_method(Gogo*, const Type* type, Expression* expr,
+                      const std::string& name, source_location);
+
+  // Return true if NAME is an unexported field or method of TYPE.
+  static bool
+  is_unexported_field_or_method(Gogo*, const Type*, const std::string&);
+
+  // This type was passed to the builtin function make.  ARGS are the
+  // arguments passed to make after the type; this may be NULL if
+  // there were none.  Issue any required errors.
+  bool
+  check_make_expression(Expression_list* args, source_location location)
+  { return this->do_check_make_expression(args, location); }
+
+  // Return a tree representing this type.
+  tree
+  get_tree(Gogo*);
+
+  // Return a tree representing a zero initialization for this type.
+  // This will be something like an INTEGER_CST or a CONSTRUCTOR.  If
+  // IS_CLEAR is true, then the memory is known to be zeroed; in that
+  // case, this will return NULL if there is nothing to be done.
+  tree
+  get_init_tree(Gogo*, bool is_clear);
+
+  // Like get_init_tree, but passing in the type to use for the
+  // initializer.
+  tree
+  get_typed_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+  { return this->do_get_init_tree(gogo, type_tree, is_clear); }
+
+  // Return a tree for a make expression applied to this type.
+  tree
+  make_expression_tree(Translate_context* context, Expression_list* args,
+                      source_location location)
+  { return this->do_make_expression_tree(context, args, location); }
+
+  // Build a type descriptor entry for this type.  Return a pointer to
+  // it.
+  tree
+  type_descriptor_pointer(Gogo* gogo);
+
+  // Return the type reflection string for this type.
+  std::string
+  reflection(Gogo*) const;
+
+  // Return a mangled name for the type.  This is a name which can be
+  // used in assembler code.  Identical types should have the same
+  // manged name.
+  std::string
+  mangled_name(Gogo*) const;
+
+  // Export the type.
+  void
+  export_type(Export* exp) const
+  { this->do_export(exp); }
+
+  // Import a type.
+  static Type*
+  import_type(Import*);
+
+ protected:
+  Type(Type_classification);
+
+  // Functions implemented by the child class.
+
+  // Traverse the subtypes.
+  virtual int
+  do_traverse(Traverse*);
+
+  // Verify the type.
+  virtual bool
+  do_verify()
+  { return true; }
+
+  virtual bool
+  do_has_pointer() const
+  { return false; }
+
+  virtual unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  virtual bool
+  do_check_make_expression(Expression_list* args, source_location);
+
+
+  virtual tree
+  do_get_tree(Gogo*) = 0;
+
+  virtual tree
+  do_get_init_tree(Gogo*, tree, bool) = 0;
+
+  virtual tree
+  do_make_expression_tree(Translate_context*, Expression_list*,
+                         source_location);
+
+  virtual Expression*
+  do_type_descriptor(Gogo*, Named_type* name) = 0;
+
+  virtual void
+  do_reflection(Gogo*, std::string*) const = 0;
+
+
+  virtual void
+  do_mangled_name(Gogo*, std::string*) const = 0;
+
+  virtual void
+  do_export(Export*) const;
+
+  // Return whether an expression is an integer.
+  static bool
+  check_int_value(Expression*, const char*, source_location);
+
+  // Return whether a method expects a pointer as the receiver.
+  static bool
+  method_expects_pointer(const Named_object*);
+
+  // Finalize the methods for a type.
+  static void
+  finalize_methods(Gogo*, const Type*, source_location, Methods**);
+
+  // Return a method from a set of methods.
+  static Method*
+  method_function(const Methods*, const std::string& name,
+                 bool* is_ambiguous);
+
+  // Return a composite literal for the type descriptor entry for a
+  // type.
+  static Expression*
+  type_descriptor(Gogo*, Type*);
+
+  // Return a composite literal for the type descriptor entry for
+  // TYPE, using NAME as the name of the type.
+  static Expression*
+  named_type_descriptor(Gogo*, Type* type, Named_type* name);
+
+  // Return a composite literal for a plain type descriptor for this
+  // type with the given kind and name.
+  Expression*
+  plain_type_descriptor(Gogo*, int runtime_type_kind, Named_type* name);
+
+  // Build a composite literal for the basic type descriptor.
+  Expression*
+  type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*,
+                             const Methods*, bool only_value_methods);
+
+  // Make a builtin struct type from a list of fields.
+  static Struct_type*
+  make_builtin_struct_type(int nfields, ...);
+
+  // Make a builtin named type.
+  static Named_type*
+  make_builtin_named_type(const char* name, Type* type);
+
+  // For the benefit of child class reflection string generation.
+  void
+  append_reflection(const Type* type, Gogo* gogo, std::string* ret) const
+  { type->do_reflection(gogo, ret); }
+
+  // For the benefit of child class mangling.
+  void
+  append_mangled_name(const Type* type, Gogo* gogo, std::string* ret) const
+  { type->do_mangled_name(gogo, ret); }
+
+  // Incorporate a string into a hash code.
+  static unsigned int
+  hash_string(const std::string&, unsigned int);
+
+  // Return a tree for the underlying type of a named type.
+  static tree
+  get_named_type_tree(Gogo* gogo, Type* base_type)
+  { return base_type->get_tree_without_hash(gogo); }
+
+ private:
+  // Convert to the desired type classification, or return NULL.  This
+  // is a controlled dynamic_cast.
+  template<typename Type_class, Type_classification type_classification>
+  Type_class*
+  convert()
+  {
+    Type* base = this->base();
+    return (base->classification_ == type_classification
+           ? static_cast<Type_class*>(base)
+           : NULL);
+  }
+
+  template<typename Type_class, Type_classification type_classification>
+  const Type_class*
+  convert() const
+  {
+    const Type* base = this->base();
+    return (base->classification_ == type_classification
+           ? static_cast<Type_class*>(base)
+           : NULL);
+  }
+
+  template<typename Type_class, Type_classification type_classification>
+  Type_class*
+  convert_no_base()
+  {
+    return (this->classification_ == type_classification
+           ? static_cast<Type_class*>(this)
+           : NULL);
+  }
+
+  template<typename Type_class, Type_classification type_classification>
+  const Type_class*
+  convert_no_base() const
+  {
+    return (this->classification_ == type_classification
+           ? static_cast<Type_class*>(this)
+           : NULL);
+  }
+
+  // Get the hash and equality functions for a type.
+  void
+  type_functions(const char** hash_fn, const char** equal_fn) const;
+
+  // Build a composite literal for the uncommon type information.
+  Expression*
+  uncommon_type_constructor(Gogo*, Type* uncommon_type,
+                           Named_type*, const Methods*,
+                           bool only_value_methods) const;
+
+  // Build a composite literal for the methods.
+  Expression*
+  methods_constructor(Gogo*, Type* methods_type, const Methods*,
+                     bool only_value_methods) const;
+
+  // Build a composite literal for one method.
+  Expression*
+  method_constructor(Gogo*, Type* method_type, const std::string& name,
+                    const Method*) const;
+
+  static tree
+  build_receive_return_type(tree type);
+
+  // A hash table we use to avoid infinite recursion.
+  typedef Unordered_set_hash(const Named_type*, Type_hash_identical,
+                            Type_identical) Types_seen;
+
+  // Add all methods for TYPE to the list of methods for THIS.
+  static void
+  add_methods_for_type(const Type* type, const Method::Field_indexes*,
+                      unsigned int depth, bool, bool, Types_seen*,
+                      Methods**);
+
+  static void
+  add_local_methods_for_type(const Named_type* type,
+                            const Method::Field_indexes*,
+                            unsigned int depth, bool, bool, Methods**);
+
+  static void
+  add_embedded_methods_for_type(const Type* type,
+                               const Method::Field_indexes*,
+                               unsigned int depth, bool, bool, Types_seen*,
+                               Methods**);
+
+  static void
+  add_interface_methods_for_type(const Type* type,
+                                const Method::Field_indexes*,
+                                unsigned int depth, Methods**);
+
+  // Build stub methods for a type.
+  static void
+  build_stub_methods(Gogo*, const Type* type, const Methods* methods,
+                    source_location);
+
+  static void
+  build_one_stub_method(Gogo*, Method*, const char* receiver_name,
+                       const Typed_identifier_list*, bool is_varargs,
+                       source_location);
+
+  static Expression*
+  apply_field_indexes(Expression*, const Method::Field_indexes*,
+                     source_location);
+
+  // Look for a field or method named NAME in TYPE.
+  static bool
+  find_field_or_method(const Type* type, const std::string& name,
+                      bool receiver_can_be_pointer,
+                      int* level, bool* is_method,
+                      bool* found_pointer_method,
+                      std::string* ambig1, std::string* ambig2);
+
+  // Get a tree for a type without looking in the hash table for
+  // identical types.
+  tree
+  get_tree_without_hash(Gogo*);
+
+  // A mapping from Type to tree, used to ensure that the GIMPLE
+  // representation of identical types is identical.
+  typedef Unordered_map_hash(const Type*, tree, Type_hash_identical,
+                            Type_identical) Type_trees;
+
+  static Type_trees type_trees;
+
+  // The type classification.
+  Type_classification classification_;
+  // The tree representation of the type, once it has been determined.
+  tree tree_;
+  // The decl for the type descriptor for this type.  This starts out
+  // as NULL and is filled in as needed.
+  tree type_descriptor_decl_;
+};
+
+// Type hash table operations.
+
+class Type_hash_identical
+{
+ public:
+  unsigned int
+  operator()(const Type* type) const
+  { return type->hash_for_method(NULL); }
+};
+
+class Type_identical
+{
+ public:
+  bool
+  operator()(const Type* t1, const Type* t2) const
+  { return Type::are_identical(t1, t2, NULL); }
+};
+
+// An identifier with a type.
+
+class Typed_identifier
+{
+ public:
+  Typed_identifier(const std::string& name, Type* type,
+                  source_location location)
+    : name_(name), type_(type), location_(location)
+  { }
+
+  // Get the name.
+  const std::string&
+  name() const
+  { return this->name_; }
+
+  // Get the type.
+  Type*
+  type() const
+  { return this->type_; }
+
+  // Return the location where the name was seen.  This is not always
+  // meaningful.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Set the type--sometimes we see the identifier before the type.
+  void
+  set_type(Type* type)
+  {
+    gcc_assert(this->type_ == NULL || type->is_error_type());
+    this->type_ = type;
+  }
+
+ private:
+  // Identifier name.
+  std::string name_;
+  // Type.
+  Type* type_;
+  // The location where the name was seen.
+  source_location location_;
+};
+
+// A list of Typed_identifiers.
+
+class Typed_identifier_list
+{
+ public:
+  Typed_identifier_list()
+    : entries_()
+  { }
+
+  // Whether the list is empty.
+  bool
+  empty() const
+  { return this->entries_.empty(); }
+
+  // Return the number of entries in the list.
+  size_t
+  size() const
+  { return this->entries_.size(); }
+
+  // Add an entry to the end of the list.
+  void
+  push_back(const Typed_identifier& td)
+  { this->entries_.push_back(td); }
+
+  // Remove an entry from the end of the list.
+  void
+  pop_back()
+  { this->entries_.pop_back(); }
+
+  // Set the type of entry I to TYPE.
+  void
+  set_type(size_t i, Type* type)
+  {
+    gcc_assert(i < this->entries_.size());
+    this->entries_[i].set_type(type);
+  }
+
+  // Sort the entries by name.
+  void
+  sort_by_name();
+
+  // Traverse types.
+  int
+  traverse(Traverse*);
+
+  // Return the first and last elements.
+  Typed_identifier&
+  front()
+  { return this->entries_.front(); }
+
+  const Typed_identifier&
+  front() const
+  { return this->entries_.front(); }
+
+  Typed_identifier&
+  back()
+  { return this->entries_.back(); }
+
+  const Typed_identifier&
+  back() const
+  { return this->entries_.back(); }
+
+  const Typed_identifier&
+  at(size_t i) const
+  { return this->entries_.at(i); }
+
+  void
+  set(size_t i, const Typed_identifier& t)
+  { this->entries_.at(i) = t; }
+
+  void
+  resize(size_t c)
+  {
+    gcc_assert(c <= this->entries_.size());
+    this->entries_.resize(c, Typed_identifier("", NULL, UNKNOWN_LOCATION));
+  }
+
+  // Iterators.
+
+  typedef std::vector<Typed_identifier>::iterator iterator;
+  typedef std::vector<Typed_identifier>::const_iterator const_iterator;
+
+  iterator
+  begin()
+  { return this->entries_.begin(); }
+
+  const_iterator
+  begin() const
+  { return this->entries_.begin(); }
+
+  iterator
+  end()
+  { return this->entries_.end(); }
+
+  const_iterator
+  end() const
+  { return this->entries_.end(); }
+
+  // Return a copy of this list.  This returns an independent copy of
+  // the vector, but does not copy the types.
+  Typed_identifier_list*
+  copy() const;
+
+ private:
+  std::vector<Typed_identifier> entries_;
+};
+
+// The type of an integer.
+
+class Integer_type : public Type
+{
+ public:
+  // Create a new integer type.
+  static Named_type*
+  create_integer_type(const char* name, bool is_unsigned, int bits,
+                     int runtime_type_kind);
+
+  // Look up an existing integer type.
+  static Named_type*
+  lookup_integer_type(const char* name);
+
+  // Create an abstract integer type.
+  static Integer_type*
+  create_abstract_integer_type();
+
+  // Whether this is an abstract integer type.
+  bool
+  is_abstract() const
+  { return this->is_abstract_; }
+
+  // Whether this is an unsigned type.
+  bool
+  is_unsigned() const
+  { return this->is_unsigned_; }
+
+  // The number of bits.
+  int
+  bits() const
+  { return this->bits_; }
+
+  // Whether this type is the same as T.
+  bool
+  is_identical(const Integer_type* t) const;
+
+ protected:
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+ private:
+  Integer_type(bool is_abstract, bool is_unsigned, int bits,
+              int runtime_type_kind)
+    : Type(TYPE_INTEGER),
+      is_abstract_(is_abstract), is_unsigned_(is_unsigned), bits_(bits),
+      runtime_type_kind_(runtime_type_kind)
+  { }
+
+  // Map names of integer types to the types themselves.
+  typedef std::map<std::string, Named_type*> Named_integer_types;
+  static Named_integer_types named_integer_types;
+
+  // True if this is an abstract type.
+  bool is_abstract_;
+  // True if this is an unsigned type.
+  bool is_unsigned_;
+  // The number of bits.
+  int bits_;
+  // The runtime type code used in the type descriptor for this type.
+  int runtime_type_kind_;
+};
+
+// The type of a floating point number.
+
+class Float_type : public Type
+{
+ public:
+  // Create a new float type.
+  static Named_type*
+  create_float_type(const char* name, int bits, int runtime_type_kind);
+
+  // Look up an existing float type.
+  static Named_type*
+  lookup_float_type(const char* name);
+
+  // Create an abstract float type.
+  static Float_type*
+  create_abstract_float_type();
+
+  // Whether this is an abstract float type.
+  bool
+  is_abstract() const
+  { return this->is_abstract_; }
+
+  // The number of bits.
+  int
+  bits() const
+  { return this->bits_; }
+
+  // Whether this type is the same as T.
+  bool
+  is_identical(const Float_type* t) const;
+
+  // Return a tree for this type without using a Gogo*.
+  tree
+  type_tree() const;
+
+ protected:
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+ private:
+  Float_type(bool is_abstract, int bits, int runtime_type_kind)
+    : Type(TYPE_FLOAT),
+      is_abstract_(is_abstract), bits_(bits),
+      runtime_type_kind_(runtime_type_kind)
+  { }
+
+  // Map names of float types to the types themselves.
+  typedef std::map<std::string, Named_type*> Named_float_types;
+  static Named_float_types named_float_types;
+
+  // True if this is an abstract type.
+  bool is_abstract_;
+  // The number of bits in the floating point value.
+  int bits_;
+  // The runtime type code used in the type descriptor for this type.
+  int runtime_type_kind_;
+};
+
+// The type of a complex number.
+
+class Complex_type : public Type
+{
+ public:
+  // Create a new complex type.
+  static Named_type*
+  create_complex_type(const char* name, int bits, int runtime_type_kind);
+
+  // Look up an existing complex type.
+  static Named_type*
+  lookup_complex_type(const char* name);
+
+  // Create an abstract complex type.
+  static Complex_type*
+  create_abstract_complex_type();
+
+  // Whether this is an abstract complex type.
+  bool
+  is_abstract() const
+  { return this->is_abstract_; }
+
+  // The number of bits: 64 or 128.
+  int bits() const
+  { return this->bits_; }
+
+  // Whether this type is the same as T.
+  bool
+  is_identical(const Complex_type* t) const;
+
+  // Return a tree for this type without using a Gogo*.
+  tree
+  type_tree() const;
+
+ protected:
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+ private:
+  Complex_type(bool is_abstract, int bits, int runtime_type_kind)
+    : Type(TYPE_COMPLEX),
+      is_abstract_(is_abstract), bits_(bits),
+      runtime_type_kind_(runtime_type_kind)
+  { }
+
+  // Map names of complex types to the types themselves.
+  typedef std::map<std::string, Named_type*> Named_complex_types;
+  static Named_complex_types named_complex_types;
+
+  // True if this is an abstract type.
+  bool is_abstract_;
+  // The number of bits in the complex value--64 or 128.
+  int bits_;
+  // The runtime type code used in the type descriptor for this type.
+  int runtime_type_kind_;
+};
+
+// The type of a string.
+
+class String_type : public Type
+{
+ public:
+  String_type()
+    : Type(TYPE_STRING)
+  { }
+
+  // Return a tree for the length of STRING.
+  static tree
+  length_tree(Gogo*, tree string);
+
+  // Return a tree which points to the bytes of STRING.
+  static tree
+  bytes_tree(Gogo*, tree string);
+
+ protected:
+  bool
+  do_has_pointer() const
+  { return true; }
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo* gogo, tree, bool);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const;
+
+ private:
+  // The named string type.
+  static Named_type* string_type_;
+};
+
+// The type of a function.
+
+class Function_type : public Type
+{
+ public:
+  Function_type(Typed_identifier* receiver, Typed_identifier_list* parameters,
+               Typed_identifier_list* results, source_location location)
+    : Type(TYPE_FUNCTION),
+      receiver_(receiver), parameters_(parameters), results_(results),
+      location_(location), is_varargs_(false), is_builtin_(false)
+  { }
+
+  // Get the receiver.
+  const Typed_identifier*
+  receiver() const
+  { return this->receiver_; }
+
+  // Get the return names and types.
+  const Typed_identifier_list*
+  results() const
+  { return this->results_; }
+
+  // Get the parameter names and types.
+  const Typed_identifier_list*
+  parameters() const
+  { return this->parameters_; }
+
+  // Whether this is a varargs function.
+  bool
+  is_varargs() const
+  { return this->is_varargs_; }
+
+  // Whether this is a builtin function.
+  bool
+  is_builtin() const
+  { return this->is_builtin_; }
+
+  // The location where this type was defined.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Return whether this is a method type.
+  bool
+  is_method() const
+  { return this->receiver_ != NULL; }
+
+  // Whether T is a valid redeclaration of this type.  This is called
+  // when a function is declared more than once.
+  bool
+  is_valid_redeclaration(const Function_type* t, std::string*) const;
+
+  // Whether this type is the same as T.
+  bool
+  is_identical(const Function_type* t, bool ignore_receiver,
+              std::string*) const;
+
+  // Record that this is a varargs function.
+  void
+  set_is_varargs()
+  { this->is_varargs_ = true; }
+
+  // Record that this is a builtin function.
+  void
+  set_is_builtin()
+  { this->is_builtin_ = true; }
+
+  // Import a function type.
+  static Function_type*
+  do_import(Import*);
+
+  // Return a copy of this type without a receiver.  This is only
+  // valid for a method type.
+  Function_type*
+  copy_without_receiver() const;
+
+  // Return a copy of this type with a receiver.  This is used when an
+  // interface method is attached to a named or struct type.
+  Function_type*
+  copy_with_receiver(Type*) const;
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  // A trampoline function has a pointer which matters for GC.
+  bool
+  do_has_pointer() const
+  { return true; }
+
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+  void
+  do_export(Export*) const;
+
+ private:
+  static Type*
+  make_function_type_descriptor_type();
+
+  Expression*
+  type_descriptor_params(Type*, const Typed_identifier*,
+                        const Typed_identifier_list*);
+
+  // The receiver name and type.  This will be NULL for a normal
+  // function, non-NULL for a method.
+  Typed_identifier* receiver_;
+  // The parameter names and types.
+  Typed_identifier_list* parameters_;
+  // The result names and types.  This will be NULL if no result was
+  // specified.
+  Typed_identifier_list* results_;
+  // The location where this type was defined.  This exists solely to
+  // give a location for the fields of the struct if this function
+  // returns multiple values.
+  source_location location_;
+  // Whether this function takes a variable number of arguments.
+  bool is_varargs_;
+  // Whether this is a special builtin function which can not simply
+  // be called.  This is used for len, cap, etc.
+  bool is_builtin_;
+};
+
+// The type of a pointer.
+
+class Pointer_type : public Type
+{
+ public:
+  Pointer_type(Type* to_type)
+    : Type(TYPE_POINTER),
+      to_type_(to_type)
+  {}
+
+  Type*
+  points_to() const
+  { return this->to_type_; }
+
+  // Import a pointer type.
+  static Pointer_type*
+  do_import(Import*);
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_has_pointer() const
+  { return true; }
+
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+  void
+  do_export(Export*) const;
+
+ private:
+  static Type*
+  make_pointer_type_descriptor_type();
+
+  // The type to which this type points.
+  Type* to_type_;
+};
+
+// The type of a field in a struct.
+
+class Struct_field
+{
+ public:
+  explicit Struct_field(const Typed_identifier& typed_identifier)
+    : typed_identifier_(typed_identifier), tag_(NULL)
+  { }
+
+  // The field name.
+  const std::string&
+  field_name() const;
+
+  // The field type.
+  Type*
+  type() const
+  { return this->typed_identifier_.type(); }
+
+  // The field location.
+  source_location
+  location() const
+  { return this->typed_identifier_.location(); }
+
+  // Whether the field has a tag.
+  bool
+  has_tag() const
+  { return this->tag_ != NULL; }
+
+  // The tag.
+  const std::string&
+  tag() const
+  {
+    gcc_assert(this->tag_ != NULL);
+    return *this->tag_;
+  }
+
+  // Whether this is an anonymous field.
+  bool
+  is_anonymous() const
+  { return this->typed_identifier_.name().empty(); }
+
+  // Set the tag.  FIXME: This is never freed.
+  void
+  set_tag(const std::string& tag)
+  { this->tag_ = new std::string(tag); }
+
+  // Set the type.  This is only used in error cases.
+  void
+  set_type(Type* type)
+  { this->typed_identifier_.set_type(type); }
+
+ private:
+  // The field name, type, and location.
+  Typed_identifier typed_identifier_;
+  // The field tag.  This is NULL if the field has no tag.
+  std::string* tag_;
+};
+
+// A list of struct fields.
+
+class Struct_field_list
+{
+ public:
+  Struct_field_list()
+    : entries_()
+  { }
+
+  // Whether the list is empty.
+  bool
+  empty() const
+  { return this->entries_.empty(); }
+
+  // Return the number of entries.
+  size_t
+  size() const
+  { return this->entries_.size(); }
+
+  // Add an entry to the end of the list.
+  void
+  push_back(const Struct_field& sf)
+  { this->entries_.push_back(sf); }
+
+  // Index into the list.
+  const Struct_field&
+  at(size_t i) const
+  { return this->entries_.at(i); }
+
+  // Last entry in list.
+  Struct_field&
+  back()
+  { return this->entries_.back(); }
+
+  // Iterators.
+
+  typedef std::vector<Struct_field>::iterator iterator;
+  typedef std::vector<Struct_field>::const_iterator const_iterator;
+
+  iterator
+  begin()
+  { return this->entries_.begin(); }
+
+  const_iterator
+  begin() const
+  { return this->entries_.begin(); }
+
+  iterator
+  end()
+  { return this->entries_.end(); }
+
+  const_iterator
+  end() const
+  { return this->entries_.end(); }
+
+ private:
+  std::vector<Struct_field> entries_;
+};
+
+// The type of a struct.
+
+class Struct_type : public Type
+{
+ public:
+  Struct_type(Struct_field_list* fields, source_location location)
+    : Type(TYPE_STRUCT),
+      fields_(fields), location_(location), all_methods_(NULL)
+  { }
+
+  // Return the field NAME.  This only looks at local fields, not at
+  // embedded types.  If the field is found, and PINDEX is not NULL,
+  // this sets *PINDEX to the field index.  If the field is not found,
+  // this returns NULL.
+  const Struct_field*
+  find_local_field(const std::string& name, unsigned int *pindex) const;
+
+  // Return the field number INDEX.
+  const Struct_field*
+  field(unsigned int index) const
+  { return &this->fields_->at(index); }
+
+  // Get the struct fields.
+  const Struct_field_list*
+  fields() const
+  { return this->fields_; }
+
+  // Return the number of fields.
+  size_t
+  field_count() const
+  { return this->fields_->size(); }
+
+  // Push a new field onto the end of the struct.  This is used when
+  // building a closure variable.
+  void
+  push_field(const Struct_field& sf)
+  { this->fields_->push_back(sf); }
+
+  // Return an expression referring to field NAME in STRUCT_EXPR, or
+  // NULL if there is no field with that name.
+  Field_reference_expression*
+  field_reference(Expression* struct_expr, const std::string& name,
+                 source_location) const;
+
+  // Return the total number of fields, including embedded fields.
+  // This is the number of values which can appear in a conversion to
+  // this type.
+  unsigned int
+  total_field_count() const;
+
+  // Whether this type is identical with T.
+  bool
+  is_identical(const Struct_type* t) const;
+
+  // Whether this struct type has any hidden fields.  This returns
+  // true if any fields have hidden names, or if any non-pointer
+  // anonymous fields have types with hidden fields.
+  bool
+  struct_has_hidden_fields(const Named_type* within, std::string*) const;
+
+  // Return whether NAME is a local field which is not exported.  This
+  // is only used for better error reporting.
+  bool
+  is_unexported_local_field(Gogo*, const std::string& name) const;
+
+  // If this is an unnamed struct, build the complete list of methods,
+  // including those from anonymous fields, and build methods stubs if
+  // needed.
+  void
+  finalize_methods(Gogo*);
+
+  // Return whether this type has any methods.  This should only be
+  // called after the finalize_methods pass.
+  bool
+  has_any_methods() const
+  { return this->all_methods_ != NULL; }
+
+  // Return the methods for tihs type.  This should only be called
+  // after the finalize_methods pass.
+  const Methods*
+  methods() const
+  { return this->all_methods_; }
+
+  // Return the method to use for NAME.  This returns NULL if there is
+  // no such method or if the method is ambiguous.  When it returns
+  // NULL, this sets *IS_AMBIGUOUS if the method name is ambiguous.
+  Method*
+  method_function(const std::string& name, bool* is_ambiguous) const;
+
+  // Traverse just the field types of a struct type.
+  int
+  traverse_field_types(Traverse* traverse)
+  { return this->do_traverse(traverse); }
+
+  // Import a struct type.
+  static Struct_type*
+  do_import(Import*);
+
+  // Fill in the fields for a named struct type.
+  tree
+  fill_in_tree(Gogo*, tree);
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_verify();
+
+  bool
+  do_has_pointer() const;
+
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+  void
+  do_export(Export*) const;
+
+ private:
+  Field_reference_expression*
+  field_reference_depth(Expression* struct_expr, const std::string& name,
+                       source_location, unsigned int* depth) const;
+
+  static Type*
+  make_struct_type_descriptor_type();
+
+  // The fields of the struct.
+  Struct_field_list* fields_;
+  // The place where the struct was declared.
+  source_location location_;
+  // If this struct is unnamed, a list of methods.
+  Methods* all_methods_;
+};
+
+// The type of an array.
+
+class Array_type : public Type
+{
+ public:
+  Array_type(Type* element_type, Expression* length)
+    : Type(TYPE_ARRAY),
+      element_type_(element_type), length_(length), length_tree_(NULL)
+  { }
+
+  // Return the element type.
+  Type*
+  element_type() const
+  { return this->element_type_; }
+
+  // Return the length.  This will return NULL for an open array.
+  Expression*
+  length() const
+  { return this->length_; }
+
+  // Whether this type is identical with T.
+  bool
+  is_identical(const Array_type* t) const;
+
+  // Whether this type has any hidden fields.
+  bool
+  array_has_hidden_fields(const Named_type* within, std::string* reason) const
+  { return this->element_type_->has_hidden_fields(within, reason); }
+
+  // Return a tree for the pointer to the values in an array.
+  tree
+  value_pointer_tree(Gogo*, tree array) const;
+
+  // Return a tree for the length of an array with this type.
+  tree
+  length_tree(Gogo*, tree array);
+
+  // Return a tree for the capacity of an array with this type.
+  tree
+  capacity_tree(Gogo*, tree array);
+
+  // Import an array type.
+  static Array_type*
+  do_import(Import*);
+
+  // Fill in the fields for a named slice type.
+  tree
+  fill_in_tree(Gogo*, tree);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  bool
+  do_verify();
+
+  bool
+  do_has_pointer() const
+  {
+    return this->length_ == NULL || this->element_type_->has_pointer();
+  }
+
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  bool
+  do_check_make_expression(Expression_list*, source_location);
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool);
+
+  tree
+  do_make_expression_tree(Translate_context*, Expression_list*,
+                         source_location);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+  void
+  do_export(Export*) const;
+
+ private:
+  bool
+  verify_length();
+
+  tree
+  get_length_tree(Gogo*);
+
+  Type*
+  make_array_type_descriptor_type();
+
+  Type*
+  make_slice_type_descriptor_type();
+
+  Expression*
+  array_type_descriptor(Gogo*, Named_type*);
+
+  Expression*
+  slice_type_descriptor(Gogo*, Named_type*);
+
+  // The type of elements of the array.
+  Type* element_type_;
+  // The number of elements.  This may be NULL.
+  Expression* length_;
+  // The length as a tree.  We only want to compute this once.
+  tree length_tree_;
+};
+
+// The type of a map.
+
+class Map_type : public Type
+{
+ public:
+  Map_type(Type* key_type, Type* val_type, source_location location)
+    : Type(TYPE_MAP),
+      key_type_(key_type), val_type_(val_type), location_(location)
+  { }
+
+  // Return the key type.
+  Type*
+  key_type() const
+  { return this->key_type_; }
+
+  // Return the value type.
+  Type*
+  val_type() const
+  { return this->val_type_; }
+
+  // Whether this type is identical with T.
+  bool
+  is_identical(const Map_type* t) const;
+
+  // Import a map type.
+  static Map_type*
+  do_import(Import*);
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_verify();
+
+  bool
+  do_has_pointer() const
+  { return true; }
+
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  bool
+  do_check_make_expression(Expression_list*, source_location);
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool);
+
+  tree
+  do_make_expression_tree(Translate_context*, Expression_list*,
+                         source_location);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+  void
+  do_export(Export*) const;
+
+ private:
+  static Type*
+  make_map_type_descriptor_type();
+
+  // The key type.
+  Type* key_type_;
+  // The value type.
+  Type* val_type_;
+  // Where the type was defined.
+  source_location location_;
+};
+
+// The type of a channel.
+
+class Channel_type : public Type
+{
+ public:
+  Channel_type(bool may_send, bool may_receive, Type* element_type)
+    : Type(TYPE_CHANNEL),
+      may_send_(may_send), may_receive_(may_receive),
+      element_type_(element_type)
+  { gcc_assert(may_send || may_receive); }
+
+  // Whether this channel can send data.
+  bool
+  may_send() const
+  { return this->may_send_; }
+
+  // Whether this channel can receive data.
+  bool
+  may_receive() const
+  { return this->may_receive_; }
+
+  // The type of the values that may be sent on this channel.  This is
+  // NULL if any type may be sent.
+  Type*
+  element_type() const
+  { return this->element_type_; }
+
+  // Whether this type is identical with T.
+  bool
+  is_identical(const Channel_type* t) const;
+
+  // Import a channel type.
+  static Channel_type*
+  do_import(Import*);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Type::traverse(this->element_type_, traverse); }
+
+  bool
+  do_has_pointer() const
+  { return true; }
+
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  bool
+  do_check_make_expression(Expression_list*, source_location);
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo*, tree, bool);
+
+  tree
+  do_make_expression_tree(Translate_context*, Expression_list*,
+                         source_location);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+  void
+  do_export(Export*) const;
+
+ private:
+  static Type*
+  make_chan_type_descriptor_type();
+
+  // Whether this channel can send data.
+  bool may_send_;
+  // Whether this channel can receive data.
+  bool may_receive_;
+  // The types of elements which may be sent on this channel.  If this
+  // is NULL, it means that any type may be sent.
+  Type* element_type_;
+};
+
+// An interface type.
+
+class Interface_type : public Type
+{
+ public:
+  Interface_type(Typed_identifier_list* methods, source_location location)
+    : Type(TYPE_INTERFACE),
+      methods_(methods), location_(location)
+  { gcc_assert(methods == NULL || !methods->empty()); }
+
+  // Return whether this is an empty interface.
+  bool
+  is_empty() const
+  { return this->methods_ == NULL; }
+
+  // Return the list of methods.  This will return NULL for an empty
+  // interface.
+  const Typed_identifier_list*
+  methods() const
+  { return this->methods_; }
+
+  // Return the number of methods.
+  size_t
+  method_count() const
+  { return this->methods_ == NULL ? 0 : this->methods_->size(); }
+
+  // Return the method NAME, or NULL.
+  const Typed_identifier*
+  find_method(const std::string& name) const;
+
+  // Return the zero-based index of method NAME.
+  size_t
+  method_index(const std::string& name) const;
+
+  // Finalize the methods.  This handles interface inheritance.
+  void
+  finalize_methods();
+
+  // Return true if T implements this interface.  If this returns
+  // false, and REASON is not NULL, it sets *REASON to the reason that
+  // it fails.
+  bool
+  implements_interface(const Type* t, std::string* reason) const;
+
+  // Whether this type is identical with T.  REASON is as in
+  // implements_interface.
+  bool
+  is_identical(const Interface_type* t) const;
+
+  // Whether we can assign T to this type.  is_identical is known to
+  // be false.
+  bool
+  is_compatible_for_assign(const Interface_type*, std::string* reason) const;
+
+  // Return whether NAME is a method which is not exported.  This is
+  // only used for better error reporting.
+  bool
+  is_unexported_method(Gogo*, const std::string& name) const;
+
+  // Import an interface type.
+  static Interface_type*
+  do_import(Import*);
+
+  // Fill in the fields for a named interface type.
+  tree
+  fill_in_tree(Gogo*, tree);
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  bool
+  do_has_pointer() const
+  { return true; }
+
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo* gogo, tree, bool);
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string*) const;
+
+  void
+  do_export(Export*) const;
+
+ private:
+  static Type*
+  make_interface_type_descriptor_type();
+
+  // The list of methods associated with the interface.  This will be
+  // NULL for the empty interface.
+  Typed_identifier_list* methods_;
+  // The location where the interface was defined.
+  source_location location_;
+};
+
+// The value we keep for a named type.  This lets us get the right
+// name when we convert to trees.  Note that we don't actually keep
+// the name here; the name is in the Named_object which points to
+// this.  This object exists to hold a unique tree which represents
+// the type.
+
+class Named_type : public Type
+{
+ public:
+  Named_type(Named_object* named_object, Type* type, source_location location)
+    : Type(TYPE_NAMED),
+      named_object_(named_object), in_function_(NULL), type_(type),
+      local_methods_(NULL), all_methods_(NULL),
+      interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
+      location_(location), named_tree_(NULL), is_visible_(true),
+      is_error_(false), seen_(false)
+  { }
+
+  // Return the associated Named_object.  This holds the actual name.
+  Named_object*
+  named_object()
+  { return this->named_object_; }
+
+  const Named_object*
+  named_object() const
+  { return this->named_object_; }
+
+  // Set the Named_object.  This is used when we see a type
+  // declaration followed by a type.
+  void
+  set_named_object(Named_object* no)
+  { this->named_object_ = no; }
+
+  // Return the function in which this type is defined.  This will
+  // return NULL for a type defined in global scope.
+  const Named_object*
+  in_function() const
+  { return this->in_function_; }
+
+  // Set the function in which this type is defined.
+  void
+  set_in_function(Named_object* f)
+  { this->in_function_ = f; }
+
+  // Return the name of the type.
+  const std::string&
+  name() const;
+
+  // Return the name of the type for an error message.  The difference
+  // is that if the type is defined in a different package, this will
+  // return PACKAGE.NAME.
+  std::string
+  message_name() const;
+
+  // Return the underlying type.
+  Type*
+  real_type()
+  { return this->type_; }
+
+  const Type*
+  real_type() const
+  { return this->type_; }
+
+  // Return the location.
+  source_location
+  location() const
+  { return this->location_; }
+
+  // Whether this type is visible.  This only matters when parsing.
+  bool
+  is_visible() const
+  { return this->is_visible_; }
+
+  // Mark this type as visible.
+  void
+  set_is_visible()
+  { this->is_visible_ = true; }
+
+  // Mark this type as invisible.
+  void
+  clear_is_visible()
+  { this->is_visible_ = false; }
+
+  // Whether this is a builtin type.
+  bool
+  is_builtin() const
+  { return this->location_ == BUILTINS_LOCATION; }
+
+  // Add a method to this type.
+  Named_object*
+  add_method(const std::string& name, Function*);
+
+  // Add a method declaration to this type.
+  Named_object*
+  add_method_declaration(const std::string& name, Package* package,
+                        Function_type* type, source_location location);
+
+  // Add an existing method--one defined before the type itself was
+  // defined--to a type.
+  void
+  add_existing_method(Named_object*);
+
+  // Look up a local method.
+  Named_object*
+  find_local_method(const std::string& name) const;
+
+  // Return the list of local methods.
+  const Bindings*
+  local_methods() const
+  { return this->local_methods_; }
+
+  // Build the complete list of methods, including those from
+  // anonymous fields, and build method stubs if needed.
+  void
+  finalize_methods(Gogo*);
+
+  // Return whether this type has any methods.  This should only be
+  // called after the finalize_methods pass.
+  bool
+  has_any_methods() const
+  { return this->all_methods_ != NULL; }
+
+  // Return the methods for this type.  This should only be called
+  // after the finalized_methods pass.
+  const Methods*
+  methods() const
+  { return this->all_methods_; }
+
+  // Return the method to use for NAME.  This returns NULL if there is
+  // no such method or if the method is ambiguous.  When it returns
+  // NULL, this sets *IS_AMBIGUOUS if the method name is ambiguous.
+  Method*
+  method_function(const std::string& name, bool *is_ambiguous) const;
+
+  // Return whether NAME is a known field or method which is not
+  // exported.  This is only used for better error reporting.
+  bool
+  is_unexported_local_method(Gogo*, const std::string& name) const;
+
+  // Return a pointer to the interface method table for this type for
+  // the interface INTERFACE.  If IS_POINTER is true, set the type
+  // descriptor to a pointer to this type, otherwise set it to this
+  // type.
+  tree
+  interface_method_table(Gogo*, const Interface_type* interface,
+                        bool is_pointer);
+
+  // Whether this type has any hidden fields.
+  bool
+  named_type_has_hidden_fields(std::string* reason) const;
+
+  // Export the type.
+  void
+  export_named_type(Export*, const std::string& name) const;
+
+  // Import a named type.
+  static void
+  import_named_type(Import*, Named_type**);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse)
+  { return Type::traverse(this->type_, traverse); }
+
+  bool
+  do_verify();
+
+  bool
+  do_has_pointer() const
+  { return this->type_->has_pointer(); }
+
+  unsigned int
+  do_hash_for_method(Gogo*) const;
+
+  bool
+  do_check_make_expression(Expression_list* args, source_location location)
+  { return this->type_->check_make_expression(args, location); }
+
+  tree
+  do_get_tree(Gogo*);
+
+  tree
+  do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+  { return this->type_->get_typed_init_tree(gogo, type_tree, is_clear); }
+
+  tree
+  do_make_expression_tree(Translate_context* context, Expression_list* args,
+                         source_location location)
+  { return this->type_->make_expression_tree(context, args, location); }
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const;
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // A mapping from interfaces to the associated interface method
+  // tables for this type.  This maps to a decl.
+  typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
+                            Type_identical) Interface_method_tables;
+
+  // A pointer back to the Named_object for this type.
+  Named_object* named_object_;
+  // If this type is defined in a function, a pointer back to the
+  // function in which it is defined.
+  Named_object* in_function_;
+  // The actual type.
+  Type* type_;
+  // The list of methods defined for this type.  Any named type can
+  // have methods.
+  Bindings* local_methods_;
+  // The full list of methods for this type, including methods
+  // declared for anonymous fields.
+  Methods* all_methods_;
+  // A mapping from interfaces to the associated interface method
+  // tables for this type.
+  Interface_method_tables* interface_method_tables_;
+  // A mapping from interfaces to the associated interface method
+  // tables for pointers to this type.
+  Interface_method_tables* pointer_interface_method_tables_;
+  // The location where this type was defined.
+  source_location location_;
+  // The tree for this type while converting to GENERIC.  This is used
+  // to avoid endless recursion when a named type refers to itself.
+  tree named_tree_;
+  // Whether this type is visible.  This is false if this type was
+  // created because it was referenced by an imported object, but the
+  // type itself was not exported.  This will always be true for types
+  // created in the current package.
+  bool is_visible_;
+  // Whether this type is erroneous.
+  bool is_error_;
+  // In a recursive operation such as has_hidden_fields, this flag is
+  // used to prevent infinite recursion when a type refers to itself.
+  // This is mutable because it is always reset to false when the
+  // function exits.
+  mutable bool seen_;
+};
+
+// A forward declaration.  This handles a type which has been declared
+// but not defined.
+
+class Forward_declaration_type : public Type
+{
+ public:
+  Forward_declaration_type(Named_object* named_object);
+
+  // The named object associated with this type declaration.  This
+  // will be resolved.
+  Named_object*
+  named_object();
+
+  const Named_object*
+  named_object() const;
+
+  // Return the name of the type.
+  const std::string&
+  name() const;
+
+  // Return the type to which this points.  Give an error if the type
+  // has not yet been defined.
+  Type*
+  real_type();
+
+  const Type*
+  real_type() const;
+
+  // Whether the base type has been defined.
+  bool
+  is_defined() const;
+
+  // Add a method to this type.
+  Named_object*
+  add_method(const std::string& name, Function*);
+
+  // Add a method declaration to this type.
+  Named_object*
+  add_method_declaration(const std::string& name, Function_type*,
+                        source_location);
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  bool
+  do_has_pointer() const
+  { return this->base()->has_pointer(); }
+
+  unsigned int
+  do_hash_for_method(Gogo* gogo) const
+  { return this->real_type()->hash_for_method(gogo); }
+
+  bool
+  do_check_make_expression(Expression_list* args, source_location location)
+  { return this->base()->check_make_expression(args, location); }
+
+  tree
+  do_get_tree(Gogo* gogo);
+
+  tree
+  do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear)
+  { return this->base()->get_typed_init_tree(gogo, type_tree, is_clear); }
+
+  tree
+  do_make_expression_tree(Translate_context* context, Expression_list* args,
+                         source_location location)
+  { return this->base()->make_expression_tree(context, args, location); }
+
+  Expression*
+  do_type_descriptor(Gogo*, Named_type*);
+
+  void
+  do_reflection(Gogo*, std::string*) const;
+
+  void
+  do_mangled_name(Gogo*, std::string* ret) const;
+
+  void
+  do_export(Export*) const;
+
+ private:
+  // Issue a warning about a use of an undefined type.
+  void
+  warn() const;
+
+  // The type declaration.
+  Named_object* named_object_;
+  // Whether we have issued a warning about this type.
+  mutable bool warned_;
+};
+
+// The Type_context struct describes what we expect for the type of an
+// expression.
+
+struct Type_context
+{
+  // The exact type we expect, if known.  This may be NULL.
+  Type* type;
+  // Whether an abstract type is permitted.
+  bool may_be_abstract;
+
+  // Constructors.
+  Type_context()
+    : type(NULL), may_be_abstract(false)
+  { }
+
+  Type_context(Type* a_type, bool a_may_be_abstract)
+    : type(a_type), may_be_abstract(a_may_be_abstract)
+  { }
+};
+
+#endif // !defined(GO_TYPES_H)
diff --git a/gcc/go/gofrontend/unsafe.cc b/gcc/go/gofrontend/unsafe.cc
new file mode 100644 (file)
index 0000000..51d812b
--- /dev/null
@@ -0,0 +1,134 @@
+// unsafe.cc -- Go frontend builtin unsafe package.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "types.h"
+#include "gogo.h"
+
+// Set up the builtin unsafe package.  This should probably be driven
+// by a table.
+
+void
+Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
+                   source_location location)
+{
+  location_t bloc = BUILTINS_LOCATION;
+
+  bool add_to_globals;
+  Package* package = this->add_imported_package("unsafe", local_name,
+                                               is_local_name_exported,
+                                               "libgo_unsafe",
+                                               location, &add_to_globals);
+  package->set_is_imported();
+
+  Bindings* bindings = package->bindings();
+
+  // The type may have already been created by an import.
+  Named_object* no = package->bindings()->lookup("Pointer");
+  if (no == NULL)
+    {
+      Type* type = Type::make_pointer_type(Type::make_void_type());
+      no = bindings->add_type("Pointer", package, type, UNKNOWN_LOCATION);
+    }
+  else
+    {
+      gcc_assert(no->package() == package);
+      gcc_assert(no->is_type());
+      gcc_assert(no->type_value()->is_unsafe_pointer_type());
+      no->type_value()->set_is_visible();
+    }
+  Named_type* pointer_type = no->type_value();
+  if (add_to_globals)
+    this->add_named_type(pointer_type);
+
+  Type* int_type = this->lookup_global("int")->type_value();
+
+  // Sizeof.
+  Typed_identifier_list* results = new Typed_identifier_list;
+  results->push_back(Typed_identifier("", int_type, bloc));
+  Function_type* fntype = Type::make_function_type(NULL, NULL, results, bloc);
+  fntype->set_is_builtin();
+  no = bindings->add_function_declaration("Sizeof", package, fntype, bloc);
+  if (add_to_globals)
+    this->add_named_object(no);
+
+  // Offsetof.
+  results = new Typed_identifier_list;
+  results->push_back(Typed_identifier("", int_type, bloc));
+  fntype = Type::make_function_type(NULL, NULL, results, bloc);
+  fntype->set_is_varargs();
+  fntype->set_is_builtin();
+  no = bindings->add_function_declaration("Offsetof", package, fntype, bloc);
+  if (add_to_globals)
+    this->add_named_object(no);
+
+  // Alignof.
+  results = new Typed_identifier_list;
+  results->push_back(Typed_identifier("", int_type, bloc));
+  fntype = Type::make_function_type(NULL, NULL, results, bloc);
+  fntype->set_is_varargs();
+  fntype->set_is_builtin();
+  no = bindings->add_function_declaration("Alignof", package, fntype, bloc);
+  if (add_to_globals)
+    this->add_named_object(no);
+
+  // Typeof.
+  Type* empty_interface = Type::make_interface_type(NULL, bloc);
+  Typed_identifier_list* parameters = new Typed_identifier_list;
+  parameters->push_back(Typed_identifier("i", empty_interface, bloc));
+  results = new Typed_identifier_list;
+  results->push_back(Typed_identifier("", empty_interface, bloc));
+  fntype = Type::make_function_type(NULL, parameters, results, bloc);
+  no = bindings->add_function_declaration("Typeof", package, fntype, bloc);
+  if (add_to_globals)
+    this->add_named_object(no);
+
+  // Reflect.
+  parameters = new Typed_identifier_list;
+  parameters->push_back(Typed_identifier("it", empty_interface, bloc));
+  results = new Typed_identifier_list;
+  results->push_back(Typed_identifier("", empty_interface, bloc));
+  results->push_back(Typed_identifier("", pointer_type, bloc));
+  fntype = Type::make_function_type(NULL, parameters, results, bloc);
+  no = bindings->add_function_declaration("Reflect", package, fntype, bloc);
+  if (add_to_globals)
+    this->add_named_object(no);
+
+  // Unreflect.
+  parameters = new Typed_identifier_list;
+  parameters->push_back(Typed_identifier("typ", empty_interface, bloc));
+  parameters->push_back(Typed_identifier("addr", pointer_type, bloc));
+  results = new Typed_identifier_list;
+  results->push_back(Typed_identifier("", empty_interface, bloc));
+  fntype = Type::make_function_type(NULL, parameters, results, bloc);
+  no = bindings->add_function_declaration("Unreflect", package, fntype, bloc);
+  if (add_to_globals)
+    this->add_named_object(no);
+
+  // New.
+  parameters = new Typed_identifier_list;
+  parameters->push_back(Typed_identifier("typ", empty_interface, bloc));
+  results = new Typed_identifier_list;
+  results->push_back(Typed_identifier("", pointer_type, bloc));
+  fntype = Type::make_function_type(NULL, parameters, results, bloc);
+  no = bindings->add_function_declaration("New", package, fntype, bloc);
+  if (add_to_globals)
+    this->add_named_object(no);
+
+  // NewArray.
+  parameters = new Typed_identifier_list;
+  parameters->push_back(Typed_identifier("typ", empty_interface, bloc));
+  parameters->push_back(Typed_identifier("n", int_type, bloc));
+  results = new Typed_identifier_list;
+  results->push_back(Typed_identifier("", pointer_type, bloc));
+  fntype = Type::make_function_type(NULL, parameters, results, bloc);
+  no = bindings->add_function_declaration("NewArray", package, fntype, bloc);
+  if (add_to_globals)
+    this->add_named_object(no);
+
+  this->imported_unsafe_ = true;
+}
diff --git a/gcc/go/gospec.c b/gcc/go/gospec.c
new file mode 100644 (file)
index 0000000..c8f2bad
--- /dev/null
@@ -0,0 +1,327 @@
+/* gospec.c -- Specific flags and argument handling of the gcc Go front end.
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "gcc.h"
+#include "opts.h"
+
+/* This bit is set if we saw a `-xfoo' language specification.  */
+#define LANGSPEC       (1<<1)
+/* This bit is set if they did `-lm' or `-lmath'.  */
+#define MATHLIB                (1<<2)
+/* This bit is set if they did `-lpthread'.  */
+#define THREADLIB      (1<<3)
+/* This bit is set if they did `-lc'.  */
+#define WITHLIBC       (1<<4)
+/* Skip this option.  */
+#define SKIPOPT                (1<<5)
+
+#ifndef MATH_LIBRARY
+#define MATH_LIBRARY "m"
+#endif
+#ifndef MATH_LIBRARY_PROFILE
+#define MATH_LIBRARY_PROFILE MATH_LIBRARY
+#endif
+
+#define THREAD_LIBRARY "pthread"
+#define THREAD_LIBRARY_PROFILE THREAD_LIBRARY
+
+#define LIBGO "go"
+#define LIBGO_PROFILE LIBGO
+#define LIBGOBEGIN "gobegin"
+
+void
+lang_specific_driver (struct cl_decoded_option **in_decoded_options,
+                     unsigned int *in_decoded_options_count,
+                     int *in_added_libraries)
+{
+  unsigned int i, j;
+
+  /* If true, the user gave us the `-p' or `-pg' flag.  */
+  bool saw_profile_flag = false;
+
+  /* This is a tristate:
+     -1 means we should not link in libgo
+     0  means we should link in libgo if it is needed
+     1  means libgo is needed and should be linked in.
+     2  means libgo is needed and should be linked statically.  */
+  int library = 0;
+
+  /* The new argument list will be contained in this.  */
+  struct cl_decoded_option *new_decoded_options;
+
+  /* "-lm" or "-lmath" if it appears on the command line.  */
+  const struct cl_decoded_option *saw_math = 0;
+
+  /* "-lpthread" if it appears on the command line.  */
+  const struct cl_decoded_option *saw_thread = 0;
+
+  /* "-lc" if it appears on the command line.  */
+  const struct cl_decoded_option *saw_libc = 0;
+
+  /* An array used to flag each argument that needs a bit set for
+     LANGSPEC, MATHLIB, or WITHLIBC.  */
+  int *args;
+
+  /* Whether we need the thread library.  */
+  int need_thread = 0;
+
+  /* By default, we throw on the math library if we have one.  */
+  int need_math = (MATH_LIBRARY[0] != '\0');
+
+  /* True if we saw -static.  */
+  int static_link = 0;
+
+  /* True if we should add -shared-libgcc to the command-line.  */
+  int shared_libgcc = 1;
+
+  /* The total number of arguments with the new stuff.  */
+  unsigned int argc;
+
+  /* The argument list.  */
+  struct cl_decoded_option *decoded_options;
+
+  /* The number of libraries added in.  */
+  int added_libraries;
+
+  /* The total number of arguments with the new stuff.  */
+  int num_args = 1;
+
+  argc = *in_decoded_options_count;
+  decoded_options = *in_decoded_options;
+  added_libraries = *in_added_libraries;
+
+  args = XCNEWVEC (int, argc);
+
+  for (i = 1; i < argc; i++)
+    {
+      const char *arg = decoded_options[i].arg;
+
+      switch (decoded_options[i].opt_index)
+       {
+       case OPT_nostdlib:
+       case OPT_nodefaultlibs:
+         library = -1;
+         break;
+
+       case OPT_l:
+         if (strcmp (arg, MATH_LIBRARY) == 0)
+           {
+             args[i] |= MATHLIB;
+             need_math = 0;
+           }
+         else if (strcmp (arg, THREAD_LIBRARY) == 0)
+           args[i] |= THREADLIB;
+         else if (strcmp (arg, "c") == 0)
+           args[i] |= WITHLIBC;
+         else
+           /* Unrecognized libraries (e.g. -lfoo) may require libgo.  */
+           library = (library == 0) ? 1 : library;
+         break;
+
+       case OPT_pg:
+       case OPT_p:
+         saw_profile_flag = true;
+         break;
+
+       case OPT_x:
+         if (library == 0 && strcmp (arg, "go") == 0)
+           library = 1;
+         break;
+
+       case OPT_Xlinker:
+       case OPT_Wl_:
+         /* Arguments that go directly to the linker might be .o files,
+            or something, and so might cause libgo to be needed.  */
+         if (library == 0)
+           library = 1;
+         break;
+
+       case OPT_c:
+       case OPT_S:
+       case OPT_E:
+       case OPT_M:
+       case OPT_MM:
+       case OPT_fsyntax_only:
+         /* Don't specify libraries if we won't link, since that would
+            cause a warning.  */
+         library = -1;
+         break;
+
+       case OPT_static:
+         static_link = 1;
+         break;
+
+       case OPT_static_libgcc:
+         shared_libgcc = 0;
+         break;
+
+       case OPT_static_libgo:
+         library = library >= 0 ? 2 : library;
+         args[i] |= SKIPOPT;
+         break;
+
+       case OPT_SPECIAL_input_file:
+         if (library == 0)
+           library = 1;
+         break;
+       }
+    }
+
+  /* There's no point adding -shared-libgcc if we don't have a shared
+     libgcc.  */
+#ifndef ENABLE_SHARED_LIBGCC
+  shared_libgcc = 0;
+#endif
+
+  /* Make sure to have room for the trailing NULL argument.  */
+  num_args = argc + need_math + shared_libgcc + (library > 0) * 5 + 5;
+  new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args);
+
+  i = 0;
+  j = 0;
+
+  /* Copy the 0th argument, i.e., the name of the program itself.  */
+  new_decoded_options[j++] = decoded_options[i++];
+
+  /* If we are linking, pass -fsplit-stack if it is supported.  */
+#ifdef TARGET_CAN_SPLIT_STACK
+  if (library >= 0)
+    {
+      generate_option (OPT_fsplit_stack, NULL, 1, CL_DRIVER,
+                      &new_decoded_options[j]);
+      j++;
+    }
+#endif
+
+  /* NOTE: We start at 1 now, not 0.  */
+  while (i < argc)
+    {
+      new_decoded_options[j] = decoded_options[i];
+
+      /* Make sure -lgo is before the math library, since libgo itself
+        uses those math routines.  */
+      if (!saw_math && (args[i] & MATHLIB) && library > 0)
+       {
+         --j;
+         saw_math = &decoded_options[i];
+       }
+
+      if (!saw_thread && (args[i] & THREADLIB) && library > 0)
+       {
+         --j;
+         saw_thread = &decoded_options[i];
+       }
+
+      if (!saw_libc && (args[i] & WITHLIBC) && library > 0)
+       {
+         --j;
+         saw_libc = &decoded_options[i];
+       }
+
+      if ((args[i] & SKIPOPT) != 0)
+       --j;
+
+      i++;
+      j++;
+    }
+
+  /* Add `-lgo' if we haven't already done so.  */
+  if (library > 0)
+    {
+      generate_option (OPT_l, LIBGOBEGIN, 1, CL_DRIVER,
+                      &new_decoded_options[j]);
+      added_libraries++;
+      j++;
+
+#ifdef HAVE_LD_STATIC_DYNAMIC
+      if (library > 1 && !static_link)
+       {
+         generate_option (OPT_Wl_, "-Bstatic", 1, CL_DRIVER,
+                          &new_decoded_options[j]);
+         j++;
+       }
+#endif
+
+      generate_option (OPT_l, saw_profile_flag ? LIBGO_PROFILE : LIBGO, 1,
+                      CL_DRIVER, &new_decoded_options[j]);
+      added_libraries++;
+      j++;
+
+#ifdef HAVE_LD_STATIC_DYNAMIC
+      if (library > 1 && !static_link)
+       {
+         generate_option (OPT_Wl_, "-Bdynamic", 1, CL_DRIVER,
+                          &new_decoded_options[j]);
+         j++;
+       }
+#endif
+
+      /* When linking libgo statically we also need to link with the
+        pthread library.  */
+      if (library > 1 || static_link)
+       need_thread = 1;
+    }
+
+  if (saw_thread)
+    new_decoded_options[j++] = *saw_thread;
+  else if (library > 0 && need_thread)
+    {
+      generate_option (OPT_l,
+                      (saw_profile_flag
+                       ? THREAD_LIBRARY_PROFILE
+                       : THREAD_LIBRARY),
+                      1, CL_DRIVER, &new_decoded_options[j]);
+      added_libraries++;
+      j++;
+    }
+
+  if (saw_math)
+    new_decoded_options[j++] = *saw_math;
+  else if (library > 0 && need_math)
+    {
+      generate_option (OPT_l,
+                      saw_profile_flag ? MATH_LIBRARY_PROFILE : MATH_LIBRARY,
+                      1, CL_DRIVER, &new_decoded_options[j]);
+      added_libraries++;
+      j++;
+    }
+
+  if (saw_libc)
+    new_decoded_options[j++] = *saw_libc;
+  if (shared_libgcc && !static_link)
+    generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER,
+                    &new_decoded_options[j++]);
+
+  *in_decoded_options_count = j;
+  *in_decoded_options = new_decoded_options;
+  *in_added_libraries = added_libraries;
+}
+
+/* Called before linking.  Returns 0 on success and -1 on failure.  */
+int lang_specific_pre_link (void)  /* Not used for Go.  */
+{
+  return 0;
+}
+
+/* Number of extra output files that lang_specific_pre_link may generate.  */
+int lang_specific_extra_outfiles = 0;  /* Not used for Go.  */
diff --git a/gcc/go/lang-specs.h b/gcc/go/lang-specs.h
new file mode 100644 (file)
index 0000000..a47379d
--- /dev/null
@@ -0,0 +1,25 @@
+/* lang-specs.h -- gcc driver specs for Go frontend.
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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
+<http://www.gnu.org/licenses/>.  */
+
+/* This is the contribution to the `default_compilers' array in gcc.c
+   for the Go language.  */
+
+{".go",  "@go", 0, 1, 0},
+{"@go",  "go1 %i %(cc1_options) %{I*} %{L*} %D %{!fsyntax-only:%(invoke_as)}",
+    0, 1, 0},
diff --git a/gcc/go/lang.opt b/gcc/go/lang.opt
new file mode 100644 (file)
index 0000000..9d9b1ff
--- /dev/null
@@ -0,0 +1,56 @@
+; lang.opt -- Options for the gcc Go front end.
+
+; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC 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, or (at your option) any later
+; version.
+; 
+; GCC 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
+; <http://www.gnu.org/licenses/>.
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Language
+Go
+
+I
+Go Joined Separate
+; Documented in c.opt
+
+L
+Go Joined Separate
+; Not documented
+
+Wall
+Go
+; Documented in c.opt
+
+fgo-dump-
+Go Joined RejectNegative
+-fgo-dump-<type>       Dump Go frontend internal information
+
+fgo-prefix=
+Go Joined RejectNegative
+-fgo-prefix=<string>   Set package-specific prefix for exported Go names
+
+frequire-return-statement
+Go Var(go_require_return_statement) Init(1) Warning
+Functions which return values must end with return statements
+
+o
+Go Joined Separate
+; Documented in common.opt
+
+; This comment is to ensure we retain the blank line above.
index 71faa57..e0769f5 100644 (file)
@@ -1,4 +1,11 @@
-2010-11-02  Eric Botcazou  <ebotcazou@adacore.com>
+2010-12-02  Ian Lance Taylor  <iant@google.com>
+
+       * lib/go.exp: New file.
+       * lib/go-dg.exp: New file.
+       * lib/go-torture.exp: New file.
+       * lib/target-supports.exp (check_compile): Match // Go.
+
+2010-12-02  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc.dg/pr46685.c: New test.
 
diff --git a/gcc/testsuite/go.dg/dg.exp b/gcc/testsuite/go.dg/dg.exp
new file mode 100644 (file)
index 0000000..62c8c06
--- /dev/null
@@ -0,0 +1,36 @@
+#   Copyright (C) 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib go-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_GOCFLAGS
+if ![info exists DEFAULT_GOCFLAGS] then {
+    set DEFAULT_GOCFLAGS " -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+go-dg-runtest [lsort \
+       [glob -nocomplain $srcdir/$subdir/*.go ] ] $DEFAULT_GOCFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/go.dg/err-1.go b/gcc/testsuite/go.dg/err-1.go
new file mode 100644 (file)
index 0000000..0536d76
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-do compile }
+
+package main
+
+func main() {
+  var ret;             // { dg-error "expected type" }
+}
diff --git a/gcc/testsuite/go.dg/goto-1.go b/gcc/testsuite/go.dg/goto-1.go
new file mode 100644 (file)
index 0000000..e20fe4d
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-do compile }
+
+package main
+
+func main() {
+  goto lab;    // { dg-error "undefined label" }
+}
diff --git a/gcc/testsuite/go.dg/undef-1.go b/gcc/testsuite/go.dg/undef-1.go
new file mode 100644 (file)
index 0000000..e3ea918
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-do compile }
+
+package main
+
+func main() {
+  sys.Exit(i)          // { dg-error "undefined" }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/array-1.go b/gcc/testsuite/go.go-torture/execute/array-1.go
new file mode 100644 (file)
index 0000000..7b34eca
--- /dev/null
@@ -0,0 +1,10 @@
+package main
+var a [2]int;
+func fn() {
+  a[0] = 1;
+  a[1] = 1;
+}
+func main() {
+  fn();
+  if a[0] != a[1] { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/array-2.go b/gcc/testsuite/go.go-torture/execute/array-2.go
new file mode 100644 (file)
index 0000000..516a131
--- /dev/null
@@ -0,0 +1,19 @@
+package main
+
+func fn(a []int) int {
+  alen := len(a);
+  for i := 0; i < alen; i++ {
+    a[i] = i
+  }
+  return alen;
+}
+
+func main() {
+  var a [2]int;
+  if fn(a[0:]) != 2 {
+    panic(0);
+  }
+  if a[0] != 0 || a[1] != 1 {
+    panic(1);
+  }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/chan-1.go b/gcc/testsuite/go.go-torture/execute/chan-1.go
new file mode 100644 (file)
index 0000000..c3d4ddb
--- /dev/null
@@ -0,0 +1,7 @@
+package main
+
+func main() {
+  c := make(chan int, 1);
+  c <- 0;
+  if <-c != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/const-1.go b/gcc/testsuite/go.go-torture/execute/const-1.go
new file mode 100644 (file)
index 0000000..2292692
--- /dev/null
@@ -0,0 +1,6 @@
+package main
+
+func main() {
+  const c = 2;
+  if c != 2 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/const-2.go b/gcc/testsuite/go.go-torture/execute/const-2.go
new file mode 100644 (file)
index 0000000..a7301a5
--- /dev/null
@@ -0,0 +1,7 @@
+package main
+
+const c = 3;
+
+func main() {
+  if c != 3 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/execute.exp b/gcc/testsuite/go.go-torture/execute/execute.exp
new file mode 100644 (file)
index 0000000..350d751
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (C) 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# This is based on a file written by Rob Savoye (rob@cygnus.com) and
+# Jeffrey Wheat (cassidy@cygnus.com).
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# load support procs
+load_lib go-torture.exp
+
+foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.go]] {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $testcase] then {
+       continue
+    }
+    go-torture-execute $testcase
+}
diff --git a/gcc/testsuite/go.go-torture/execute/expr-1.go b/gcc/testsuite/go.go-torture/execute/expr-1.go
new file mode 100644 (file)
index 0000000..076388a
--- /dev/null
@@ -0,0 +1,11 @@
+package main
+
+func main() {
+  var v1 = 1;
+  var v2 = 1;
+  var v3 = (v1 + v2) / (v1 + v2);
+  var v4 = (v3 * v3) % (v3 * v3);
+  if v4 != 0 {
+    panic(0)
+  }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/for-1.go b/gcc/testsuite/go.go-torture/execute/for-1.go
new file mode 100644 (file)
index 0000000..7aa91f0
--- /dev/null
@@ -0,0 +1,9 @@
+package main
+
+func main() {
+  sum := 0;
+  for i := 0; i < 10; i++ {
+    sum += i;
+  }
+  if sum != 45 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/for-2.go b/gcc/testsuite/go.go-torture/execute/for-2.go
new file mode 100644 (file)
index 0000000..af790ed
--- /dev/null
@@ -0,0 +1,52 @@
+package main
+
+func f1() {
+  j := 0;
+  for i := 0; i < 10; i++ {
+    if i > 2 {
+      break;
+    }
+    j = i;
+  }
+  if (j != 2) {
+    panic(0);
+  }
+}
+
+func f2() {
+  for i := 0; i < 10; i++ {
+    if i >= 0 {
+      continue;
+    }
+    panic(1);
+  }
+}
+
+func f3() {
+  lab1:
+  for i := 0; i < 10; i++ {
+    for j := 0; j < 10; j++ {
+      if j > 2 {
+        break lab1;
+      }
+    }
+    panic(2);
+  }
+}
+
+func f4() {
+  lab1:
+  for i := 0; i < 10; i++ {
+    for j := 0; j < 10; j++ {
+      continue lab1;
+    }
+    panic(3);
+  }
+}
+
+func main() {
+  f1();
+  f2();
+  f3();
+  f4()
+}
diff --git a/gcc/testsuite/go.go-torture/execute/function-1.go b/gcc/testsuite/go.go-torture/execute/function-1.go
new file mode 100644 (file)
index 0000000..06244ac
--- /dev/null
@@ -0,0 +1,9 @@
+package main
+
+func subr() int {
+  return 0
+}
+
+func main() {
+  if subr() != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/function-2.go b/gcc/testsuite/go.go-torture/execute/function-2.go
new file mode 100644 (file)
index 0000000..8b9aa87
--- /dev/null
@@ -0,0 +1,9 @@
+package main
+
+func subr(p int) int {
+  return p
+}
+
+func main() {
+  if subr(0) != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/go-1.go b/gcc/testsuite/go.go-torture/execute/go-1.go
new file mode 100644 (file)
index 0000000..7d9dbd4
--- /dev/null
@@ -0,0 +1,11 @@
+package main
+
+func send_one(c chan <- int) {
+  c <- 0;
+}
+
+func main() {
+  c := make(chan int);
+  go send_one(c);
+  if <-c != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/go-2.go b/gcc/testsuite/go.go-torture/execute/go-2.go
new file mode 100644 (file)
index 0000000..8ce5fc8
--- /dev/null
@@ -0,0 +1,11 @@
+package main
+
+func send_one(c chan <- int, val int) {
+  c <- val;
+}
+
+func main() {
+  c := make(chan int);
+  go send_one(c, 0);
+  if <-c != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/go-3.go b/gcc/testsuite/go.go-torture/execute/go-3.go
new file mode 100644 (file)
index 0000000..af8fa38
--- /dev/null
@@ -0,0 +1,14 @@
+package main
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+  s := S{0};
+  var i I = &s;
+  c := make(chan int);
+  go i.send(c);
+  if <- c != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/goto-1.go b/gcc/testsuite/go.go-torture/execute/goto-1.go
new file mode 100644 (file)
index 0000000..0a10c2e
--- /dev/null
@@ -0,0 +1,7 @@
+package main
+
+func main() {
+  goto lab;
+  panic(0);
+ lab:
+}
diff --git a/gcc/testsuite/go.go-torture/execute/map-1.go b/gcc/testsuite/go.go-torture/execute/map-1.go
new file mode 100644 (file)
index 0000000..8307c6c
--- /dev/null
@@ -0,0 +1,46 @@
+package main
+
+func main() {
+  v := make(map[int] int);
+  v[0] = 0;
+  v[1000000] = 1;
+  if v[0] != 0 {
+    panic(1)
+  }
+  val, present := v[0];
+  if !present || val != 0 {
+    panic(2)
+  }
+  val = 5;
+  val, present = v[1];
+  if present || val != 0 {
+    panic(3);
+  }
+  if v[2] != 0 {
+    panic(4)
+  }
+  val, present = v[2];
+  if present {
+    panic(5)
+  }
+  if len(v) != 2 {
+    panic(6)
+  }
+  v[0] = 0, false;
+  if len(v) != 1 {
+    panic(7)
+  }
+
+  w := make(map[string] string);
+  if len(w) != 0 {
+    panic(8)
+  }
+  w["Hello"] = "world";
+  w["Goodbye"] = "sweet prince";
+  if w["Hello"] != "world" {
+    panic(9)
+  }
+  if w["Hej"] != "" {
+    panic(10)
+  }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/method-1.go b/gcc/testsuite/go.go-torture/execute/method-1.go
new file mode 100644 (file)
index 0000000..e4c17c1
--- /dev/null
@@ -0,0 +1,7 @@
+package main
+type s struct { i int };
+func (v *s) val() int { return v.i }
+func main() {
+  p := new(s);
+  if p.val() != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/nested-1.go b/gcc/testsuite/go.go-torture/execute/nested-1.go
new file mode 100644 (file)
index 0000000..cbd96f2
--- /dev/null
@@ -0,0 +1,4 @@
+package main
+func main() {
+  if func (i int) int { return i} (0) != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/pointer-1.go b/gcc/testsuite/go.go-torture/execute/pointer-1.go
new file mode 100644 (file)
index 0000000..f6b30a1
--- /dev/null
@@ -0,0 +1,7 @@
+package main
+
+func main() {
+  p := new(int);
+  *p = 0;
+  if *p != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/return-1.go b/gcc/testsuite/go.go-torture/execute/return-1.go
new file mode 100644 (file)
index 0000000..da29a2c
--- /dev/null
@@ -0,0 +1,4 @@
+package main
+
+func main() {
+}
diff --git a/gcc/testsuite/go.go-torture/execute/return-2.go b/gcc/testsuite/go.go-torture/execute/return-2.go
new file mode 100644 (file)
index 0000000..08b2e61
--- /dev/null
@@ -0,0 +1,18 @@
+package main
+
+func fn() (i, j int) {
+     i = 1;
+     j = 2;
+     return;
+}
+
+func main() {
+  var i, j = fn();
+  var ret int;
+  if i == 1 && j == 2 {
+    ret = 0;
+  } else {
+    ret = 1;
+  }
+  if ret != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/return-3.go b/gcc/testsuite/go.go-torture/execute/return-3.go
new file mode 100644 (file)
index 0000000..f7fe09c
--- /dev/null
@@ -0,0 +1,16 @@
+package main
+
+func fn() (i, j int) {
+     return 1, 2
+}
+
+func main() {
+  var i, j = fn();
+  var ret int;
+  if i == 1 && j == 2 {
+    ret = 0;
+  } else {
+    ret = 1;
+  }
+  if ret != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/select-1.go b/gcc/testsuite/go.go-torture/execute/select-1.go
new file mode 100644 (file)
index 0000000..8fc6963
--- /dev/null
@@ -0,0 +1,28 @@
+package main
+
+func main() {
+  ch1 := make(chan int);
+  ch2 := make(chan int);
+  go func (ch1, ch2 chan int) { ch1 <- 1; ch2 <- 2; } (ch1, ch2);
+  count := 0;
+  var v int;
+  for count != 2 {
+      select
+       {
+       case v := <- ch1:
+         if v != 1 {
+           panic(0)
+         }
+         count++
+
+       case v = <- ch2:
+         if v != 2 {
+           panic(1)
+         }
+         count++
+       }
+    }
+  if v != 2 {
+    panic(2)
+  }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/string-1.go b/gcc/testsuite/go.go-torture/execute/string-1.go
new file mode 100644 (file)
index 0000000..f999d87
--- /dev/null
@@ -0,0 +1,15 @@
+package main
+
+func fn(s string) int {
+  if s[0] != 'a' || s[1] != 'b' || s[2] != 'c' {
+    panic(0);
+  }
+  return len(s);
+}
+
+func main() {
+  s := "abc";
+  if fn(s) != 3 {
+    panic(1);
+  }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/string-2.go b/gcc/testsuite/go.go-torture/execute/string-2.go
new file mode 100644 (file)
index 0000000..72b0f23
--- /dev/null
@@ -0,0 +1,16 @@
+package main
+
+func fn(s string) string {
+  if len(s) != 3 {
+    panic(0)
+  }
+  i := len(s) - 1;
+  return s + s[0 : i];
+}
+
+func main() {
+  s := fn("abc");
+  if s != "abcab" {
+    panic(1)
+  }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/struct-1.go b/gcc/testsuite/go.go-torture/execute/struct-1.go
new file mode 100644 (file)
index 0000000..edf38b2
--- /dev/null
@@ -0,0 +1,8 @@
+package main
+
+func main() {
+  type s struct { x int; };
+  var ret s;
+  ret.x = 1;
+  if ret.x != 1 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/struct-2.go b/gcc/testsuite/go.go-torture/execute/struct-2.go
new file mode 100644 (file)
index 0000000..cc01f6b
--- /dev/null
@@ -0,0 +1,7 @@
+package main
+
+func main() {
+  type s struct { x int; y int; };
+  var ret s = s{1, 2};
+  if ret.y - (ret.x + ret.x) != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/switch-1.go b/gcc/testsuite/go.go-torture/execute/switch-1.go
new file mode 100644 (file)
index 0000000..fdc93ce
--- /dev/null
@@ -0,0 +1,68 @@
+package main
+
+func f1(i int) bool {
+  switch j := i; j {
+  case 3: fallthrough
+  case 1: return true
+  case 2: return false
+  default: return false
+  case 4: return true
+  }
+}
+
+func f2(i int) int {
+  switch {
+    case i < 0: return -1
+    case i > 0: return 1
+    default: return 0
+    case i != 0: return 1000
+  }
+  panic(0)
+}
+
+func f3(i int) int {
+ lab:
+  switch i {
+    case 1: break
+    case 2: return 2
+    case 3, 4:
+      switch i {
+        case 3: break lab
+        case 4: break
+      }
+      return 4
+  }
+  return 1
+}
+
+func main() {
+  if !f1(1) {
+    panic(1);
+  }
+  if f1(2) {
+    panic(2);
+  }
+  if !f1(3) {
+    panic(3);
+  }
+  if !f1(4) {
+    panic(4);
+  }
+  if f1(5) {
+    panic(5);
+  }
+
+  if f2(-100) != -1 {
+    panic(6);
+  }
+  if f2(1000) != 1 {
+    panic(7);
+  }
+  if f2(0) != 0 {
+    panic(8);
+  }
+
+  if f3(1) != 1 || f3(2) != 2 || f3(3) != 1 || f3(4) != 4 {
+    panic(9);
+  }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/var-1.go b/gcc/testsuite/go.go-torture/execute/var-1.go
new file mode 100644 (file)
index 0000000..d4b20b6
--- /dev/null
@@ -0,0 +1,6 @@
+package main
+
+func main() {
+  var ret = 0;
+  if ret != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/var-2.go b/gcc/testsuite/go.go-torture/execute/var-2.go
new file mode 100644 (file)
index 0000000..dd0ec4e
--- /dev/null
@@ -0,0 +1,6 @@
+package main
+
+func main() {
+  var ret int;
+  if ret != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.go-torture/execute/var-3.go b/gcc/testsuite/go.go-torture/execute/var-3.go
new file mode 100644 (file)
index 0000000..80b1004
--- /dev/null
@@ -0,0 +1,6 @@
+package main
+
+func main() {
+  ret := 0;
+  if ret != 0 { panic(0) }
+}
diff --git a/gcc/testsuite/go.test/go-test.exp b/gcc/testsuite/go.test/go-test.exp
new file mode 100644 (file)
index 0000000..6226dd1
--- /dev/null
@@ -0,0 +1,666 @@
+#   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+#   Written by Ian Lance Taylor <iant@google.com>.
+
+# 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
+# <http://www.gnu.org/licenses/>.
+
+
+# Test using the testsuite for the gc Go compiler.  In these tests the
+# first line is a shell script to run.  That line expects the
+# following environment variables to be set:
+#   A   The file extension of the object file and the name of the executable
+#   G   The name of the compiler
+#   L   The name of the linker
+#   F   The basename of the test
+#   D   The directory of the test.
+#
+# Typical command lines:
+# // $G $D/$F.go && $L $F.$A && ./$A.out
+# // $G $D/$F.go && $L $F.$A || echo BUG: known to fail incorrectly
+# // $G $D/$F.go && echo BUG: compilation succeeds incorrectly
+# // $G $D/$F.go || echo BUG: compilation should succeed
+
+load_lib go-dg.exp
+load_lib go-torture.exp
+
+# Implement errchk
+proc errchk { test } {
+    global dg-do-what-default
+    global DEFAULT_GOCFLAGS
+
+    set saved-dg-do-what-default ${dg-do-what-default}
+    set dg-do-what-default compile
+    set filename [file tail $test]
+    if { "$filename" == "$test" } {
+       set filename "errchk-$filename"
+    }
+    set fdin [open $test r]
+    fconfigure $fdin -encoding binary
+    set fdout [open $filename w]
+    fconfigure $fdout -encoding binary
+    while { [gets $fdin copy_line] >= 0 } {
+       regsub "// \(GCCGO_\)?ERROR \"\(\[^\"\]*\)\".*$" $copy_line "// \{ dg-error \"\\2\" \}" out_line
+       if [string match "*dg-error*.\**" $out_line] {
+           # I worked out the right number of backslashes by
+           # experimentation, not analysis.
+           regsub -all "\\.\\*" $out_line "\\\\\[ -~\\\\\]*" out_line
+       }
+       if [string match "*dg-error*\{*" $out_line] {
+           set index [string first "dg-error" $out_line]
+           regsub -start $index -all "\{" $out_line "\\\\\[\\\{\\\\\]" out_line
+       }
+       if [string match "*dg-error*\}*\}" $out_line] {
+           set index [string first "dg-error" $out_line]
+           regsub -start $index -all "\}\(.\)" $out_line "\\\\\[\\\}\\\\\]\\1" out_line
+       }
+       if [string match "*dg-error*\[.\]*" $out_line] {
+           set index [string first "dg-error" $out_line]
+           regsub -all "\\\[\\.\\\]" $out_line "\\\\\[.\\\\\]" out_line
+       }
+       puts $fdout $out_line
+    }
+    close $fdin
+    close $fdout
+    go-dg-runtest $filename "-fno-show-column $DEFAULT_GOCFLAGS"
+    file delete $filename
+    set dg-do-what-default ${saved-dg-do-what-default}
+}
+
+# This is an execution test which should fail.
+proc go-execute-xfail { test } {
+    global DEFAULT_GOCFLAGS
+
+    set filename [file tail $test]
+    set fdin [open $test r]
+    set fdout [open $filename w]
+    puts $fdout "// { dg-do run { xfail *-*-* } }"
+    while { [gets $fdin copy_line] >= 0 } {
+       puts $fdout $copy_line
+    }
+    close $fdin
+    close $fdout
+    go-dg-runtest $filename "-w $DEFAULT_GOCFLAGS"
+    file delete $filename
+}
+
+proc go-gc-tests { } {
+    global srcdir subdir
+    global runtests
+    global GCC_UNDER_TEST
+    global TOOL_OPTIONS
+    global TORTURE_OPTIONS
+    global dg-do-what-default
+    global go_execute_args
+    global target_triplet
+
+    # If a testcase doesn't have special options, use these.
+    global DEFAULT_GOCFLAGS
+    if ![info exists DEFAULT_GOCFLAGS] {
+       set DEFAULT_GOCFLAGS " -pedantic-errors"
+    }
+
+    # Running all the torture options takes too long and, since the
+    # frontend ignores the standard options, it doesn't significantly
+    # improve testing.
+    set saved_torture_options $TORTURE_OPTIONS
+    set TORTURE_OPTIONS [ list { -O2 -g }]
+
+    set saved-dg-do-what-default ${dg-do-what-default}
+
+    set testdir [pwd]
+
+    set tests [lsort [find $srcdir/$subdir *.go]]
+    foreach test $tests {
+       if ![runtest_file_p $runtests $test] {
+           continue
+       }
+
+       # Skip the files in bench and garbage; they are not tests.
+       if [string match "*go.test/test/bench/*" $test] {
+           continue
+       }
+       if [string match "*go.test/test/garbage/*" $test] {
+           continue
+       }
+
+       # Skip files in sub-subdirectories: they are components of
+       # other tests.
+       if [string match "*go.test/test/*/*/*" $test] {
+           continue
+       }
+
+       set name [dg-trim-dirname $srcdir $test]
+
+       # Skip certain tests if target is RTEMS OS.
+       if [istarget "*-*-rtems*"] {
+           if { [string match "*go.test/test/args.go" \
+                  $test] \
+                || [string match "*go.test/test/env.go" \
+                  $test] } {
+                   untested "$name: uses the command-line or environment variables"
+                   continue
+           }
+
+           if { [string match "*go.test/test/stack.go" \
+                  $test] \
+                || [string match "*go.test/test/peano.go" \
+                  $test] \
+                || [string match "*go.test/test/chan/goroutines.go" \
+                  $test] } {
+                   untested "$name: has very high memory requirement"
+                   continue
+           }
+       }
+
+       set fd [open $test r]
+
+       set lines_ok 1
+
+       while 1 {
+           if { [gets $fd test_line] < 0 } {
+               close $fd
+               clone_output "$test: could not read first line"
+               unresolved $name
+               set lines_ok 0
+               break
+           }
+
+           if { [ string match "*nacl*exit 0*" $test_line ] \
+                    || [ string match "*exit 0*nacl*" $test_line ] \
+                    || [ string match "*Android*exit 0*" $test_line ] \
+                    || [ string match "*exit 0*Android*" $test_line ] } {
+               continue
+           }
+
+           break
+       }
+
+       if { $lines_ok == 0 } {
+           continue
+       }
+
+       set lineno 1
+       set test_line1 $test_line
+
+       while { [eval "string match \"//*&&\" \${test_line$lineno}"] } {
+           set lineno [expr $lineno + 1]
+           if { [eval "gets \$fd test_line$lineno"] < 0 } {
+               close $fd
+               clone_output "$test: could not read line $lineno"
+               unresolved $name
+               set lines_ok 0
+               break
+           }
+       }
+       if { $lines_ok == 0 } {
+           continue
+       }
+
+       close $fd
+
+       set go_execute_args ""
+       if { [regexp ".*\\\$A.out (\[^|&>\].*)\$" $test_line match progargs] } {
+           set go_execute_args $progargs
+           verbose -log "$test: go_execute_args is $go_execute_args"
+           set index [string last " $progargs" $test_line]
+           set test_line [string replace $test_line $index end]
+       }
+
+       if { $test_line == "// \$G \$D/\$F\.go && \$L \$F\.\$A && \./\$A\.out >tmp.go &&" \
+            && $test_line2 == "// \$G tmp\.go && \$L tmp\.\$A && \./\$A\.out || echo BUG: 64bit" } {
+           # 64bit.go is a special case.
+           set go_execute_args ""
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "link"
+           dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
+           set output_file "./[file rootname [file tail $test]].exe"
+           set base "[file rootname [file tail $test]]"
+           if [isnative] {
+               if { [catch "exec $output_file >$base-out.go"] != 0 } {
+                   fail "$name execution"
+               } else {
+                   pass "$name execution"
+                   file delete $base-out.x
+                   go-torture-execute "./$base-out.go"
+               }
+               file delete $base-out.go
+           }
+           file delete $output_file
+           set runtests $hold_runtests
+       } elseif { $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out" \
+                  || $test_line == "// \$G \$F.go && \$L \$F.\$A && ./\$A.out" \
+                  || $test_line == "// \$G \$F.go && \$L \$F.\$A &&./\$A.out" \
+                  || $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A && \$A.out" \
+                  || [string match \
+                          "// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out || echo BUG*" \
+                          $test_line]
+                  || [string match \
+                          "// \$G \$F.go && \$L \$F.\$A && (./\$A.out || echo BUG*" \
+                          $test_line]
+                  || [string match \
+                          "// \$G \$D/\$F.go && \$L \$F.\$A && (./\$A.out || echo BUG*" \
+                          $test_line]
+                  || [string match \
+                          "// \$G \$F.go && \$L \$F.\$A && GOMAXPROCS=* ./\$A.out" \
+                          $test_line]
+                  || [string match \
+                          "// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out >* || echo BUG*" \
+                          $test_line] } {
+           # This is a vanilla execution test.
+           go-torture-execute $test
+           file delete core [glob -nocomplain core.*]
+       } elseif { [string match \
+                       "// \$G \$D/\$F.go && \$L \$F.\$A || echo BUG*" \
+                       $test_line] \
+                  || [string match "// \$G \$F.go && \$L \$F.\$A  #*" \
+                          $test_line] } {
+           # This is a vanilla compile and link test.
+           set dg-do-what-default "link"
+           go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
+       } elseif { [string match "// \$G \$D/\$F.go" $test_line] \
+                  || [string match "// \$G \$D/\$F.go || echo BUG*" \
+                          $test_line] \
+                  || [string match "// \$G \$F.go || echo BUG*" \
+                          $test_line] \
+                  || [string match "// ! \$G \$D/\$F.go && echo BUG*" \
+                          $test_line] } {
+           # This is a vanilla compile test.
+           set dg-do-what-default "assemble"
+           go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
+       } elseif { [string match "// \$G \$D/\$F.go && echo BUG*" \
+                       $test_line] \
+                  || $test_line == "// ! \$G \$D/\$F.go >/dev/null" \
+                  || $test_line == "// ! \$G \$D/\$F.go" \
+                  || $test_line == "// ! \$G \$F.go" \
+                  || [string match "// ! \$G \$D/\$F.go || echo BUG*" \
+                       $test_line] } {
+           # This is a compile test which should fail.
+           set dg-do-what-default "assemble"
+           setup_xfail "*-*-*"
+           go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
+       } elseif { [string match "// \$G \$D/\$F.go && \$L \$F.\$A && ! ./\$A.out" \
+                       $test_line] \
+                  || [string match "// \$G \$D/\$F.go && \$L \$F.\$A && ! ./\$A.out || echo BUG: *" \
+                       $test_line] \
+                  || [string match "// \$G \$D/\$F.go && \$L \$F.\$A && (! ./\$A.out || echo BUG: *" \
+                       $test_line] \
+                  || ($test_line == "// \$G \$D/\$F.go && \$L \$F.\$A &&"
+                      && $test_line2 == "//    ((! sh -c ./\$A.out) >/dev/null 2>&1 || echo BUG: should fail)") } {
+           go-execute-xfail $test
+       } elseif { [string match "// errchk \$G \$F.go" $test_line] \
+                   || [string match "// errchk \$G -e \$F.go" $test_line] \
+                   || [string match "// errchk \$G \$D/\$F.go" $test_line] \
+                   || [string match "//errchk \$G \$D/\$F.go" $test_line] \
+                   || [string match "// errchk \$G -e \$D/\$F.go" \
+                           $test_line] \
+                   || [string match "// ! errchk \$G \$D/\$F.go" $test_line] \
+                   || [string match "// ! errchk \$G -e \$D/\$F.go" \
+                           $test_line] \
+                   || [string match "// errchk \$G \$F.go || true" \
+                           $test_line] \
+                   || [string match "// errchk \$G \$D/\$F.go || true" \
+                           $test_line] \
+                   || [string match "// errchk \$G -e \$D/\$F.go || true" \
+                           $test_line] \
+                   || [string match "// errchk \$G \$D/\$F.go || echo BUG*" \
+                           $test_line] } {
+           errchk $test
+       } elseif { [string match \
+                       "// \$G \$D/\$F.dir/bug0.go && \$G \$D/\$F.dir/bug1.go || echo BUG*" \
+                       $test_line] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/bug0.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           regsub "\\.go$" $test ".dir/bug1.go" file2
+           dg-test $file2 "-O" "-w $DEFAULT_GOCFLAGS"
+           file delete "[file rootname [file tail $file1]].o"
+           set runtests $hold_runtests
+       } elseif { [string match \
+                       "// \$G \$D/\$F.dir/bug0.go && errchk \$G \$D/\$F.dir/bug1.go" \
+                       $test_line] \
+                      || [string match \
+                              "// \$G \$D/\$F.dir/p1.go && \$G \$D/\$F.dir/p2.go" \
+                              $test_line] } {
+           if { [string match \
+                     "// \$G \$D/\$F.dir/p1.go && \$G \$D/\$F.dir/p2.go" \
+                     $test_line] } {
+               set name1 "p1.go"
+               set name2 "p2.go"
+           } else {
+               set name1 "bug0.go"
+               set name2 "bug1.go"
+           }
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/$name1" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           regsub "\\.go$" $test ".dir/$name2" file2
+           errchk $file2
+           file delete "[file rootname [file tail $file1]].o"
+           set runtests $hold_runtests
+       } elseif { [string match \
+                       "// \$G \$D/\$F.dir/bug0.go && (! \$G \$D/\$F.dir/bug1.go || echo BUG*" \
+                       $test_line] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/bug0.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           regsub "\\.go$" $test ".dir/bug1.go" file2
+           setup_xfail "*-*-*"
+           dg-test $file2 "-O" "-w $DEFAULT_GOCFLAGS"
+           file delete "[file rootname [file tail $file1]].o"
+           set runtests $hold_runtests
+       } elseif { [string match \
+                       "// \$G \$D/\$F.dir/bug0.go && \$G \$D/\$F.dir/bug1.go && (! \$G \$D/\$F.dir/bug2.go || echo BUG*" \
+                       $test_line] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/bug0.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           regsub "\\.go$" $test ".dir/bug1.go" file2
+           dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
+           regsub "\\.go$" $test ".dir/bug2.go" file3
+           setup_xfail "*-*-*"
+           dg-test $file3 "-O" "-w $DEFAULT_GOCFLAGS"
+           file delete "[file rootname [file tail $file1]].o"
+           file delete "[file rootname [file tail $file2]].o"
+           set runtests $hold_runtests
+       } elseif { [string match \
+                       "// \$G \$D/\$F.dir/bug0.go && \$G \$D/\$F.dir/bug1.go && errchk \$G \$D/\$F.dir/bug2.go" \
+                       $test_line] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/bug0.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           regsub "\\.go$" $test ".dir/bug1.go" file2
+           dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
+           regsub "\\.go$" $test ".dir/bug2.go" file3
+           errchk $file3
+           file delete "[file rootname [file tail $file1]].o"
+           file delete "[file rootname [file tail $file2]].o"
+           set runtests $hold_runtests
+       } elseif { [string match \
+                       "// \$G \$D/bug160.dir/x.go && \$G \$D/bug160.dir/y.go && \$L y.\$A && ./\$A.out" \
+                       $test_line] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/x.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile1 "[file rootname [file tail $file1]].o"
+           regsub "\\.go$" $test ".dir/y.go" file2
+           dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile2 "[file rootname [file tail $file2]].o"
+           set dg-do-what-default "link"
+           set output_file "./[file rootname [file tail $test]].exe"
+           set comp_output [go_target_compile "$ofile1 $ofile2" \
+                                $output_file "executable" "$DEFAULT_GOCFLAGS"]
+           set comp_output [go-dg-prune $target_triplet $comp_output]
+           verbose -log $comp_output
+           set result [go_load "$output_file" "" ""]
+           set status [lindex $result 0]
+           $status $name
+           file delete $ofile1 $ofile2 $output_file
+           set runtests $hold_runtests
+       } elseif { [string match \
+                       "// \$G \$D/bug191.dir/a.go && \$G \$D/bug191.dir/b.go && \$G \$D/\$F.go && \$L \$F.\$A" \
+                       $test_line] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/a.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile1 "[file rootname [file tail $file1]].o"
+           regsub "\\.go$" $test ".dir/b.go" file2
+           dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile2 "[file rootname [file tail $file2]].o"
+           dg-test -keep-output "$test" "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile3 "[file rootname [file tail $test]].o"
+           set dg-do-what-default "link"
+           set output_file "./[file rootname [file tail $test]].exe"
+           set comp_output [go_target_compile "$ofile1 $ofile2 $ofile3" \
+                                $output_file "executable" "$DEFAULT_GOCFLAGS"]
+           set comp_output [go-dg-prune $target_triplet $comp_output]
+           if [string match "" $comp_output] {
+               pass $name
+           } else {
+               verbose -log $comp_output
+               fail $name
+           }
+           file delete $ofile1 $ofile2 $ofile3 $output_file
+           set runtests $hold_runtests
+       } elseif { [string match \
+                       "// \$G \$D/embed0.go && \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out" \
+                       $test_line ] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "/\[^/\]*$" $test "/embed0.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile1 "[file rootname [file tail $file1]].o"
+           dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile2 "[file rootname [file tail $test]].o"
+           set output_file "./[file rootname [file tail $test]].exe"
+           set comp_output [go_target_compile "$ofile1 $ofile2" \
+                                $output_file "executable" "$DEFAULT_GOCFLAGS"]
+           set comp_output [go-dg-prune $target_triplet $comp_output]
+           if [string match "" $comp_output] {
+               set result [go_load "$output_file" "" ""]
+               set status [lindex $result 0]
+               $status $name
+           } else {
+               verbose -log $comp_output
+               fail $name
+           }
+           file delete $ofile1 $ofile2 $output_file
+           set runtests $hold_runtests
+       } elseif { [string match \
+                       "// \$G \$D/\$F.dir/chanbug.go && \$G -I. \$D/\$F.dir/chanbug2.go" \
+                       $test_line] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/chanbug.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           regsub "\\.go$" $test ".dir/chanbug2.go" file2
+           dg-test $file2 "-O" "-w $DEFAULT_GOCFLAGS"
+           file delete "[file rootname [file tail $file1]].o"
+           set runtests $hold_runtests
+       } elseif { [string match \
+                       "// (! \$G \$D/\$F.go) | grep 'initialization loop' *" \
+                       $test_line] } {
+           set dg-do-what-default "assemble"
+           setup_xfail "*-*-*"
+           go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
+       } elseif { [string match \
+                       "// \$G \$D/\$F.dir/x.go && errchk \$G \$D/\$F.dir/y.go" \
+                       $test_line] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/x.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           regsub "\\.go$" $test ".dir/y.go" file2
+           errchk $file2
+           file delete "[file rootname [file tail $file1]].o"
+           set runtests $hold_runtests
+       } elseif { [string match "// true*" $test_line] } {
+           # Not a real test, just ignore.
+       } elseif { $test_line == "// \$G \$D/\$F.dir/bug0.go &&" \
+                      && $test_line2 == "// \$G \$D/\$F.dir/bug1.go &&" \
+                      && $test_line3 == "// \$G \$D/\$F.dir/bug2.go &&" \
+                      && $test_line4 == "// errchk \$G -e \$D/\$F.dir/bug3.go &&" \
+                      && $test_line5 == "// \$L bug2.\$A &&" \
+                      && [string match "// ./\$A.out || echo BUG*" $test_line6] } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "\\.go$" $test ".dir/bug0.go" file0
+           dg-test -keep-output $file0 "-O -fgo-prefix=bug0" "-w $DEFAULT_GOCFLAGS"
+           set ofile0 "[file rootname [file tail $file0]].o"
+           regsub "\\.go$" $test ".dir/bug1.go" file1
+           dg-test -keep-output $file1 "-O -fgo-prefix=bug1" "-w $DEFAULT_GOCFLAGS"
+           set ofile1 "[file rootname [file tail $file1]].o"
+           regsub "\\.go$" $test ".dir/bug2.go" file2
+           dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile2 "[file rootname [file tail $file2]].o"
+           regsub "\\.go$" $test ".dir/bug3.go" file3
+           errchk $file3
+           set output_file "./[file rootname [file tail $test]].exe"
+           set comp_output [go_target_compile "$ofile0 $ofile1 $ofile2" \
+                                $output_file "executable" "$DEFAULT_GOCFLAGS"]
+           set comp-output [go-dg-prune $target_triplet $comp_output]
+           if [string match "" $comp_output] {
+               set result [go_load "$output_file" "" ""]
+               set status [lindex $result 0]
+               $status $name
+           } else {
+               verbose -log $comp_output
+               fail $name
+           }
+           file delete $ofile0 $ofile1 $ofile2 $output_file
+           set runtests $hold_runtests
+       } elseif { $test_line == "// \$G \$D/import2.go && \$G \$D/\$F\.go" } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "/\[^/\]*$" $test "/import2.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile1 "[file rootname [file tail $file1]].o"
+           dg-test $test "-O" "-w $DEFAULT_GOCFLAGS"
+           file delete $ofile1
+           set runtests $hold_runtests
+       } elseif { $test_line == "// \$G \$D/ddd2.go && \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out" } {
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "assemble"
+           regsub "/\[^/\]*$" $test "/ddd2.go" file1
+           dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile1 "[file rootname [file tail $file1]].o"
+           dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
+           set ofile2 "[file rootname [file tail $test]].o"
+           set output_file "./[file rootname [file tail $test]].exe"
+           set comp_output [go_target_compile "$ofile1 $ofile2" \
+                                $output_file "executable" "$DEFAULT_GOCFLAGS"]
+           set comp_output [go-dg-prune $target_triplet $comp_output]
+           if [string match "" $comp_output] {
+               set result [go_load "$output_file" "" ""]
+               set status [lindex $result 0]
+               $status $name
+           } else {
+               verbose -log $comp_output
+               fail $name
+           }
+           file delete $ofile1 $ofile2 $output_file
+           set runtests $hold_runtests
+       } elseif { $test_line == "// \$G \$D/\$F.go \$D/cmplxdivide1.go && \$L \$D/\$F.\$A && ./\$A.out" } {
+           regsub "/\[^/\]*$" $test "/cmplxdivide1.go" test2
+           set output_file "./[file rootname [file tail $test]].o"
+           set comp_output [go_target_compile "$test $test2" \
+                            $output_file "executable" "$DEFAULT_GOCFLAGS"]
+           set comp_output [go-dg-prune $target_triplet $comp_output]
+           if [string match "" $comp_output] {
+               set result [go_load "$output_file" "" ""]
+               set status [lindex $result 0]
+               $status $name
+           } else {
+               verbose -log $comp_output
+               fail $name
+           }
+           file delete $output_file
+       } elseif { $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A &&" \
+                      && $test_line2 == "// ./\$A.out -pass 0 >tmp.go && \$G tmp.go && \$L -o tmp1.\$A tmp.\$A && ./tmp1.\$A &&" \
+                      && $test_line3 == "// ./\$A.out -pass 1 >tmp.go && errchk \$G -e tmp.go &&" \
+                      && $test_line4 == "// ./\$A.out -pass 2 >tmp.go && errchk \$G -e tmp.go" } {
+           set go_execute_args ""
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "link"
+           dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
+           set output_file "./[file rootname [file tail $test]].exe"
+           if [isnative] {
+               if { [catch "exec $output_file -pass 0 >tmp.go"] != 0 } {
+                   fail "$name execution 0"
+               } else {
+                   pass "$name execution 0"
+                   file delete tmp.x
+                   go-torture-execute "./tmp.go"
+               }
+               if { [catch "exec $output_file -pass 1 >tmp.go"] != 0 } {
+                   fail "$name execution 1"
+               } else {
+                   pass "$name execution 1"
+                   errchk tmp.go
+               }
+               if { [catch "exec $output_file -pass 2 >tmp.go"] != 0 } {
+                   fail "$name execution 2"
+               } else {
+                   pass "$name execution 2"
+                   errchk tmp.go
+               }
+               file delete tmp.go
+           }
+           file delete $output_file
+           set runtests $hold_runtests
+       } elseif { $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out >tmp.go &&" \
+                       && $test_line2 == "// errchk \$G -e tmp.go" } {
+           set go_execute_args ""
+           set hold_runtests $runtests
+           set runtests "go-test.exp"
+           set dg-do-what-default "link"
+           dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
+           set output_file "./[file rootname [file tail $test]].exe"
+           if [isnative] {
+               if { [catch "exec $output_file >tmp.go"] != 0 } {
+                   fail "$name execution"
+               } else {
+                   pass "$name execution"
+                   file delete tmp.x
+                   errchk tmp.go
+               }
+           }
+           file delete $output_file
+           set runtests $hold_runtests
+       } elseif { $test_line == "// # generated by cmplxdivide.c" } {
+           # Ignore.
+       } elseif { $test_line == "// \$G \$D/bug302.dir/p.go && gopack grc pp.a p.\$A && \$G \$D/bug302.dir/main.go" \
+                  || $test_line == "// \$G \$D/empty.go && errchk \$G \$D/\$F.go" } {
+           # These tests import the same package under two different
+           # names, which gccgo does not support.
+       } elseif { $test_line == "// \$G -S \$D/\$F.go | egrep initdone >/dev/null && echo FAIL || true" } {
+           # This tests whether initializers are written out
+           # statically.  gccgo does not provide a way to test that,
+           # as an initializer will be generated for any code which
+           # has global variables which need to be registered as GC
+           # roots.
+       } else {
+           clone_output "$name: unrecognized test line: $test_line"
+           unsupported $name
+       }
+
+       set go_execute_args ""
+    }
+
+    set dg-do-what-default ${saved-dg-do-what-default}
+    set TORTURE_OPTIONS $saved_torture_options
+}
+
+go-gc-tests
diff --git a/gcc/testsuite/go.test/test/235.go b/gcc/testsuite/go.test/test/235.go
new file mode 100644 (file)
index 0000000..03143a6
--- /dev/null
@@ -0,0 +1,72 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T chan uint64
+
+func M(f uint64) (in, out T) {
+       in = make(T, 100)
+       out = make(T, 100)
+       go func(in, out T, f uint64) {
+               for {
+                       out <- f*<-in
+               }
+       }(in, out, f)
+       return in, out
+}
+
+
+func min(xs []uint64) uint64 {
+       m := xs[0]
+       for i := 1; i < len(xs); i++ {
+               if xs[i] < m {
+                       m = xs[i]
+               }
+       }
+       return m
+}
+
+
+func main() {
+       F := []uint64{2, 3, 5}
+       var n = len(F)
+       OUT := []uint64{
+               2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36,
+               40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125,
+               128, 135, 144, 150, 160, 162, 180, 192, 200, 216, 225, 240, 243, 250,
+               256, 270, 288, 300, 320, 324, 360, 375, 384, 400, 405, 432, 450, 480,
+               486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720, 729, 750, 768,
+               800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125, 1152, 1200, 1215,
+               1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536, 1600}
+
+       x := uint64(1)
+       ins := make([]T, n)
+       outs := make([]T, n)
+       xs := make([]uint64, n)
+       for i := 0; i < n; i++ {
+               ins[i], outs[i] = M(F[i])
+               xs[i] = x
+       }
+
+       for i := 0; i < len(OUT); i++ {
+               for i := 0; i < n; i++ {
+                       ins[i] <- x
+               }
+
+               for i := 0; i < n; i++ {
+                       if xs[i] == x {
+                               xs[i] = <-outs[i]
+                       }
+               }
+
+               x = min(xs)
+               if x != OUT[i] {
+                       println("bad: ", x, " should be ", OUT[i])
+                       panic("235")
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/64bit.go b/gcc/testsuite/go.test/test/64bit.go
new file mode 100644 (file)
index 0000000..9e91a97
--- /dev/null
@@ -0,0 +1,709 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
+// $G tmp.go && $L tmp.$A && ./$A.out || echo BUG: 64bit
+// rm -f tmp.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate test of 64-bit arithmetic.
+// Most synthesized routines have different cases for
+// constants vs variables and even the generated code has
+// different cases for large and small constants,
+// so try a good range of inputs.
+
+package main
+
+import (
+       "bufio"
+       "fmt"
+       "os"
+)
+
+var bout *bufio.Writer
+
+// 64-bit math without using 64-bit numbers,
+// so that we can generate the test program even
+// if the compiler has buggy or missing 64-bit support.
+
+type Uint64 struct {
+       hi      uint32
+       lo      uint32
+}
+
+type Int64 struct {
+       hi      int32
+       lo      uint32
+}
+
+func (a Uint64) Int64() (c Int64) {
+       c.hi = int32(a.hi)
+       c.lo = a.lo
+       return
+}
+
+func (a Uint64) Cmp(b Uint64) int {
+       switch {
+       case a.hi < b.hi:
+               return -1
+       case a.hi > b.hi:
+               return 1
+       case a.lo < b.lo:
+               return -1
+       case a.lo > b.lo:
+               return 1
+       }
+       return 0
+}
+
+func (a Uint64) LeftShift(b uint) (c Uint64) {
+       switch {
+       case b >= 64:
+               c.hi = 0
+               c.lo = 0
+       case b >= 32:
+               c.hi = a.lo << (b - 32)
+               c.lo = 0
+       default:
+               c.hi = a.hi<<b | a.lo>>(32-b)
+               c.lo = a.lo << b
+       }
+       return
+}
+
+func (a Uint64) RightShift(b uint) (c Uint64) {
+       switch {
+       case b >= 64:
+               c.hi = 0
+               c.lo = a.hi
+       case b >= 32:
+               c.hi = 0
+               c.lo = a.hi >> (b - 32)
+       default:
+               c.hi = a.hi >> b
+               c.lo = a.hi<<(32-b) | a.lo>>b
+       }
+       return
+}
+
+func (a Uint64) LeftShift64(b Uint64) (c Uint64) {
+       if b.hi != 0 || b.lo >= 64 {
+               return
+       }
+       return a.LeftShift(uint(b.lo))
+}
+
+func (a Uint64) RightShift64(b Uint64) (c Uint64) {
+       if b.hi != 0 || b.lo >= 64 {
+               return
+       }
+       return a.RightShift(uint(b.lo))
+}
+
+func (a Uint64) Plus(b Uint64) (c Uint64) {
+       var carry uint32
+       if c.lo = a.lo + b.lo; c.lo < a.lo {
+               carry = 1
+       }
+       c.hi = a.hi + b.hi + carry
+       return
+}
+
+func (a Uint64) Minus(b Uint64) (c Uint64) {
+       var borrow uint32
+       if c.lo = a.lo - b.lo; c.lo > a.lo {
+               borrow = 1
+       }
+       c.hi = a.hi - b.hi - borrow
+       return
+}
+
+func (a Uint64) Neg() (c Uint64) {
+       var zero Uint64
+       return zero.Minus(a)
+}
+
+func (a Uint64) Com() (c Uint64) {
+       c.hi = ^a.hi
+       c.lo = ^a.lo
+       return
+}
+
+func (a Uint64) Len() int {
+       switch {
+       case a.hi != 0:
+               for i := 31; i >= 0; i-- {
+                       if a.hi&(1<<uint(i)) != 0 {
+                               return i + 1 + 32
+                       }
+               }
+       case a.lo != 0:
+               for i := 31; i >= 0; i-- {
+                       if a.lo&(1<<uint(i)) != 0 {
+                               return i + 1
+                       }
+               }
+       }
+       return 0
+}
+
+func (a Uint64) HasBit(b uint) bool {
+       switch {
+       case b >= 64:
+               return false
+       case b >= 32:
+               return a.hi&(1<<(b-32)) != 0
+       }
+       return a.lo&(1<<b) != 0
+}
+
+func (a Uint64) Times(b Uint64) (c Uint64) {
+       for i := uint(0); i < 64; i++ {
+               if b.HasBit(i) {
+                       c = c.Plus(a.LeftShift(i))
+               }
+       }
+       return
+}
+
+func (a Uint64) DivMod(b Uint64) (quo, rem Uint64) {
+       n := a.Len() - b.Len()
+       if n >= 0 {
+               b = b.LeftShift(uint(n))
+               for i := 0; i <= n; i++ {
+                       quo = quo.LeftShift(1)
+                       if b.Cmp(a) <= 0 {      // b <= a
+                               quo.lo |= 1
+                               a = a.Minus(b)
+                       }
+                       b = b.RightShift(1)
+               }
+       }
+       rem = a
+       return
+}
+
+func (a Uint64) And(b Uint64) (c Uint64) {
+       c.hi = a.hi & b.hi
+       c.lo = a.lo & b.lo
+       return
+}
+
+func (a Uint64) AndNot(b Uint64) (c Uint64) {
+       c.hi = a.hi &^ b.hi
+       c.lo = a.lo &^ b.lo
+       return
+}
+
+func (a Uint64) Or(b Uint64) (c Uint64) {
+       c.hi = a.hi | b.hi
+       c.lo = a.lo | b.lo
+       return
+}
+
+func (a Uint64) Xor(b Uint64) (c Uint64) {
+       c.hi = a.hi ^ b.hi
+       c.lo = a.lo ^ b.lo
+       return
+}
+
+func (a Uint64) String() string        { return fmt.Sprintf("%#x%08x", a.hi, a.lo) }
+
+func (a Int64) Uint64() (c Uint64) {
+       c.hi = uint32(a.hi)
+       c.lo = a.lo
+       return
+}
+
+func (a Int64) Cmp(b Int64) int {
+       // Same body as Uint64.Cmp,
+       // but behaves differently
+       // because hi is uint32 not int32.
+       switch {
+       case a.hi < b.hi:
+               return -1
+       case a.hi > b.hi:
+               return 1
+       case a.lo < b.lo:
+               return -1
+       case a.lo > b.lo:
+               return 1
+       }
+       return 0
+}
+
+func (a Int64) LeftShift(b uint) (c Int64)     { return a.Uint64().LeftShift(b).Int64() }
+
+func (a Int64) RightShift(b uint) (c Int64) {
+       switch {
+       case b >= 64:
+               c.hi = a.hi >> 31       // sign extend
+               c.lo = uint32(c.hi)
+       case b >= 32:
+               c.hi = a.hi >> 31       // sign extend
+               c.lo = uint32(a.hi >> (b - 32))
+       default:
+               c.hi = a.hi >> b
+               c.lo = uint32(a.hi<<(32-b)) | a.lo>>b
+       }
+       return
+}
+
+func (a Int64) LeftShift64(b Uint64) (c Int64) {
+       if b.hi != 0 || b.lo >= 64 {
+               return
+       }
+       return a.LeftShift(uint(b.lo))
+}
+
+func (a Int64) RightShift64(b Uint64) (c Int64) {
+       if b.hi != 0 || b.lo >= 64 {
+               return a.RightShift(64)
+       }
+       return a.RightShift(uint(b.lo))
+}
+
+func (a Int64) Plus(b Int64) (c Int64) { return a.Uint64().Plus(b.Uint64()).Int64() }
+
+func (a Int64) Minus(b Int64) (c Int64)        { return a.Uint64().Minus(b.Uint64()).Int64() }
+
+func (a Int64) Neg() (c Int64) { return a.Uint64().Neg().Int64() }
+
+func (a Int64) Com() (c Int64) { return a.Uint64().Com().Int64() }
+
+func (a Int64) Times(b Int64) (c Int64)        { return a.Uint64().Times(b.Uint64()).Int64() }
+
+func (a Int64) DivMod(b Int64) (quo Int64, rem Int64) {
+       var zero Int64
+
+       quoSign := +1
+       remSign := +1
+       if a.Cmp(zero) < 0 {
+               quoSign = -1
+               remSign = -1
+               a = a.Neg()
+       }
+       if b.Cmp(zero) < 0 {
+               quoSign = -quoSign
+               b = b.Neg()
+       }
+
+       q, r := a.Uint64().DivMod(b.Uint64())
+       quo = q.Int64()
+       rem = r.Int64()
+
+       if quoSign < 0 {
+               quo = quo.Neg()
+       }
+       if remSign < 0 {
+               rem = rem.Neg()
+       }
+       return
+}
+
+func (a Int64) And(b Int64) (c Int64)  { return a.Uint64().And(b.Uint64()).Int64() }
+
+func (a Int64) AndNot(b Int64) (c Int64)       { return a.Uint64().AndNot(b.Uint64()).Int64() }
+
+func (a Int64) Or(b Int64) (c Int64)   { return a.Uint64().Or(b.Uint64()).Int64() }
+
+func (a Int64) Xor(b Int64) (c Int64)  { return a.Uint64().Xor(b.Uint64()).Int64() }
+
+func (a Int64) String() string {
+       if a.hi < 0 {
+               return fmt.Sprintf("-%s", a.Neg().Uint64())
+       }
+       return a.Uint64().String()
+}
+
+var int64Values = []Int64{
+       Int64{0, 0},
+       Int64{0, 1},
+       Int64{0, 2},
+       Int64{0, 3},
+       Int64{0, 100},
+       Int64{0, 10001},
+       Int64{0, 1<<31 - 1},
+       Int64{0, 1 << 31},
+       Int64{0, 1<<31 + 1},
+       Int64{0, 1<<32 - 1<<30},
+       Int64{0, 1<<32 - 1},
+       Int64{1, 0},
+       Int64{1, 1},
+       Int64{2, 0},
+       Int64{1<<31 - 1, 1<<32 - 10000},
+       Int64{1<<31 - 1, 1<<32 - 1},
+       Int64{0x789abcde, 0xf0123456},
+
+       Int64{-1, 1<<32 - 1},
+       Int64{-1, 1<<32 - 2},
+       Int64{-1, 1<<32 - 3},
+       Int64{-1, 1<<32 - 100},
+       Int64{-1, 1<<32 - 10001},
+       Int64{-1, 1<<32 - (1<<31 - 1)},
+       Int64{-1, 1<<32 - 1<<31},
+       Int64{-1, 1<<32 - (1<<31 + 1)},
+       Int64{-1, 1<<32 - (1<<32 - 1<<30)},
+       Int64{-1, 0},
+       Int64{-1, 1},
+       Int64{-2, 0},
+       Int64{-(1 << 31), 10000},
+       Int64{-(1 << 31), 1},
+       Int64{-(1 << 31), 0},
+       Int64{-0x789abcde, 0xf0123456},
+}
+
+var uint64Values = []Uint64{
+       Uint64{0, 0},
+       Uint64{0, 1},
+       Uint64{0, 2},
+       Uint64{0, 3},
+       Uint64{0, 100},
+       Uint64{0, 10001},
+       Uint64{0, 1<<31 - 1},
+       Uint64{0, 1 << 31},
+       Uint64{0, 1<<31 + 1},
+       Uint64{0, 1<<32 - 1<<30},
+       Uint64{0, 1<<32 - 1},
+       Uint64{1, 0},
+       Uint64{1, 1},
+       Uint64{2, 0},
+       Uint64{1<<31 - 1, 1<<32 - 10000},
+       Uint64{1<<31 - 1, 1<<32 - 1},
+       Uint64{1<<32 - 1<<30, 0},
+       Uint64{1<<32 - 1, 0},
+       Uint64{1<<32 - 1, 1<<32 - 100},
+       Uint64{1<<32 - 1, 1<<32 - 1},
+       Uint64{0x789abcde, 0xf0123456},
+       Uint64{0xfedcba98, 0x76543210},
+}
+
+var shiftValues = []Uint64{
+       Uint64{0, 0},
+       Uint64{0, 1},
+       Uint64{0, 2},
+       Uint64{0, 3},
+       Uint64{0, 15},
+       Uint64{0, 16},
+       Uint64{0, 17},
+       Uint64{0, 31},
+       Uint64{0, 32},
+       Uint64{0, 33},
+       Uint64{0, 61},
+       Uint64{0, 62},
+       Uint64{0, 63},
+       Uint64{0, 64},
+       Uint64{0, 65},
+       Uint64{0, 1<<32 - 1},
+       Uint64{1, 0},
+       Uint64{1, 1},
+       Uint64{1 << 28, 0},
+       Uint64{1 << 31, 0},
+       Uint64{1<<32 - 1, 0},
+       Uint64{1<<32 - 1, 1<<32 - 1},
+}
+
+var ntest = 0
+
+// Part 1 is tests of variable operations; generic functions
+// called by repetitive code.  Could make a table but not worth it.
+
+const prolog = "\n" +
+       "package main\n" +
+       "\n" +
+       "import \"os\"\n" +
+       "\n" +
+       "var ok = true\n" +
+       "\n" +
+       "func testInt64Unary(a, plus, xor, minus int64) {\n" +
+       "       if n, op, want := +a, `+`, plus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := -a, `-`, minus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
+       "}\n" +
+       "\n" +
+       "func testInt64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot int64, dodiv bool) {\n" +
+       "       if n, op, want := a + b, `+`, add; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if dodiv {\n" +
+       "               if n, op, want := a / b, `/`, div; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "               if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if n, op, want := a & b, `&`, and; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a | b, `|`, or; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "}\n" +
+       "\n" +
+       "func testInt64Shift(a int64, b uint64, left, right int64) {\n" +
+       "       if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
+       "       if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
+       "       if uint64(uint(b)) == b {\n" +
+       "               b := uint(b);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if uint64(uint32(b)) == b {\n" +
+       "               b := uint32(b);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if uint64(uint16(b)) == b {\n" +
+       "               b := uint16(b);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if uint64(uint8(b)) == b {\n" +
+       "               b := uint8(b);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "}\n" +
+       "\n" +
+       "func testUint64Unary(a, plus, xor, minus uint64) {\n" +
+       "       if n, op, want := +a, `+`, plus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := -a, `-`, minus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
+       "}\n" +
+       "\n" +
+       "func testUint64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot uint64, dodiv bool) {\n" +
+       "       if n, op, want := a + b, `+`, add; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if dodiv {\n" +
+       "               if n, op, want := a / b, `/`, div; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "               if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if n, op, want := a & b, `&`, and; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a | b, `|`, or; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+       "}\n" +
+       "\n" +
+       "func testUint64Shift(a, b, left, right uint64) {\n" +
+       "       if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
+       "       if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
+       "       if uint64(uint(b)) == b {\n" +
+       "               b := uint(b);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if uint64(uint32(b)) == b {\n" +
+       "               b := uint32(b);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if uint64(uint16(b)) == b {\n" +
+       "               b := uint16(b);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if uint64(uint8(b)) == b {\n" +
+       "               b := uint8(b);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "}\n" +
+       "\n"
+
+func varTests() {
+       fmt.Fprint(bout, prolog)
+       for _, a := range int64Values {
+               fmt.Fprintf(bout, "func test%v() {\n", ntest)
+               ntest++
+               fmt.Fprintf(bout, "\ttestInt64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
+               for _, b := range int64Values {
+                       var div, mod Int64
+                       dodiv := false
+                       var zero Int64
+                       if b.Cmp(zero) != 0 {   // b != 0
+                               // Can't divide by zero but also can't divide -0x8000...000 by -1.
+                               var bigneg = Int64{-0x80000000, 0}
+                               var minus1 = Int64{-1, ^uint32(0)}
+                               if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 {   // a != -1<<63 || b != -1
+                                       div, mod = a.DivMod(b)
+                                       dodiv = true
+                               }
+                       }
+                       fmt.Fprintf(bout, "\ttestInt64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
+                               a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
+                               a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
+               }
+               for _, b := range shiftValues {
+                       fmt.Fprintf(bout, "\ttestInt64Shift(%v, %v, %v, %v);\n",
+                               a, b, a.LeftShift64(b), a.RightShift64(b))
+               }
+               fmt.Fprintf(bout, "}\n")
+       }
+
+       for _, a := range uint64Values {
+               fmt.Fprintf(bout, "func test%v() {\n", ntest)
+               ntest++
+               fmt.Fprintf(bout, "\ttestUint64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
+               for _, b := range uint64Values {
+                       var div, mod Uint64
+                       dodiv := false
+                       var zero Uint64
+                       if b.Cmp(zero) != 0 {   // b != 0
+                               div, mod = a.DivMod(b)
+                               dodiv = true
+                       }
+                       fmt.Fprintf(bout, "\ttestUint64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
+                               a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
+                               a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
+               }
+               for _, b := range shiftValues {
+                       fmt.Fprintf(bout, "\ttestUint64Shift(%v, %v, %v, %v);\n",
+                               a, b, a.LeftShift64(b), a.RightShift64(b))
+               }
+               fmt.Fprintf(bout, "}\n")
+       }
+}
+
+// Part 2 is tests of operations involving one variable and one constant.
+
+const binaryConstL = "func test%vBinaryL%v(b, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
+       "       const a %v = %v;\n" +
+       "       const typ = `%s`;\n" +
+       "       if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+       "       if dodiv {\n" +
+       "               if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+       "               if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+       "}\n" +
+       "\n"
+
+const binaryConstR = "func test%vBinaryR%v(a, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
+       "       const b %v = %v;\n" +
+       "       const typ = `%s`;\n" +
+       "       if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+       "       if dodiv {\n" +
+       "               if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+       "               if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "       if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+       "       if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+       "}\n" +
+       "\n"
+
+const shiftConstL = "func test%vShiftL%v(b uint64, left, right %v) {\n" +
+       "       const a %v = %v;\n" +
+       "       const typ = `%s`;\n" +
+       "       if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
+       "       if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
+       "       if uint64(uint32(b)) == b {\n" +
+       "               b := uint32(b);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "}\n"
+
+const shiftConstR = "func test%vShiftR%v(a, left, right %v) {\n" +
+       "       const b uint64 = %v;\n" +
+       "       const typ = `%s`;\n" +
+       "       if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
+       "       if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
+       "       if b & 0xffffffff == b {\n" +
+       "               const b = uint32(b & 0xffffffff);\n" +
+       "               if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
+       "               if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
+       "       }\n" +
+       "}\n"
+
+func constTests() {
+       for i, a := range int64Values {
+               fmt.Fprintf(bout, binaryConstL, "Int64", i, "int64", "int64", a, "int64")
+               fmt.Fprintf(bout, binaryConstR, "Int64", i, "int64", "int64", a, "int64")
+               fmt.Fprintf(bout, shiftConstL, "Int64", i, "int64", "int64", a, "int64")
+       }
+       for i, a := range uint64Values {
+               fmt.Fprintf(bout, binaryConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
+               fmt.Fprintf(bout, binaryConstR, "Uint64", i, "uint64", "uint64", a, "uint64")
+               fmt.Fprintf(bout, shiftConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
+       }
+       for i, a := range shiftValues {
+               fmt.Fprintf(bout, shiftConstR, "Int64", i, "int64", a, "int64")
+               fmt.Fprintf(bout, shiftConstR, "Uint64", i, "uint64", a, "uint64")
+       }
+       for i, a := range int64Values {
+               fmt.Fprintf(bout, "func test%v() {\n", ntest)
+               ntest++
+               for j, b := range int64Values {
+                       var div, mod Int64
+                       dodiv := false
+                       var zero Int64
+                       if b.Cmp(zero) != 0 {   // b != 0
+                               // Can't divide by zero but also can't divide -0x8000...000 by -1.
+                               var bigneg = Int64{-0x80000000, 0}
+                               var minus1 = Int64{-1, ^uint32(0)}
+                               if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 {   // a != -1<<63 || b != -1
+                                       div, mod = a.DivMod(b)
+                                       dodiv = true
+                               }
+                       }
+                       fmt.Fprintf(bout, "\ttestInt64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
+                               i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
+                               a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
+                       fmt.Fprintf(bout, "\ttestInt64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
+                               j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
+                               a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
+               }
+               for j, b := range shiftValues {
+                       fmt.Fprintf(bout, "\ttestInt64ShiftL%v(%v, %v, %v);\n",
+                               i, b, a.LeftShift64(b), a.RightShift64(b))
+                       fmt.Fprintf(bout, "\ttestInt64ShiftR%v(%v, %v, %v);\n",
+                               j, a, a.LeftShift64(b), a.RightShift64(b))
+               }
+               fmt.Fprintf(bout, "}\n")
+       }
+       for i, a := range uint64Values {
+               fmt.Fprintf(bout, "func test%v() {\n", ntest)
+               ntest++
+               for j, b := range uint64Values {
+                       var div, mod Uint64
+                       dodiv := false
+                       var zero Uint64
+                       if b.Cmp(zero) != 0 {   // b != 0
+                               div, mod = a.DivMod(b)
+                               dodiv = true
+                       }
+                       fmt.Fprintf(bout, "\ttestUint64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
+                               i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
+                               a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
+                       fmt.Fprintf(bout, "\ttestUint64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
+                               j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
+                               a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
+               }
+               for j, b := range shiftValues {
+                       fmt.Fprintf(bout, "\ttestUint64ShiftL%v(%v, %v, %v);\n",
+                               i, b, a.LeftShift64(b), a.RightShift64(b))
+                       fmt.Fprintf(bout, "\ttestUint64ShiftR%v(%v, %v, %v);\n",
+                               j, a, a.LeftShift64(b), a.RightShift64(b))
+               }
+               fmt.Fprintf(bout, "}\n")
+       }
+}
+
+func main() {
+       bout = bufio.NewWriter(os.Stdout)
+       varTests()
+       constTests()
+
+       fmt.Fprintf(bout, "func main() {\n")
+       for i := 0; i < ntest; i++ {
+               fmt.Fprintf(bout, "\ttest%v();\n", i)
+       }
+       fmt.Fprintf(bout, "\tif !ok { os.Exit(1) }\n")
+       fmt.Fprintf(bout, "}\n")
+       bout.Flush()
+}
diff --git a/gcc/testsuite/go.test/test/README.gcc b/gcc/testsuite/go.test/test/README.gcc
new file mode 100644 (file)
index 0000000..446110f
--- /dev/null
@@ -0,0 +1,7 @@
+This directory is an exact copy (except for this file) of the Go
+testsuite from the test subdirectory of http://code.google.com/p/go.
+This is here so that we run the same tests as the gc Go compiler.  We
+do not, however, run the tests in the same way.  The gc compiler uses
+the run shell script in this directory.  For gccgo, we use the file
+go-test.exp in the parent directory to run the tests in gcc's usual
+DejaGNU test harness.
diff --git a/gcc/testsuite/go.test/test/args.go b/gcc/testsuite/go.test/test/args.go
new file mode 100644 (file)
index 0000000..ba9a377
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $F.go && $L $F.$A && ./$A.out arg1 arg2
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+       if len(os.Args) != 3 {
+               panic("argc")
+       }
+       if os.Args[1] != "arg1" {
+               panic("arg1")
+       }
+       if os.Args[2] != "arg2" {
+               panic("arg2")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/arm-pass.txt b/gcc/testsuite/go.test/test/arm-pass.txt
new file mode 100644 (file)
index 0000000..2c7230f
--- /dev/null
@@ -0,0 +1,488 @@
+./235.go
+# ./64bit.go   # fail, flaky on android build
+./args.go
+./assign.go
+./assign1.go
+./bigalg.go
+./bigmap.go
+./blank.go
+./blank1.go
+./chancap.go
+./char_lit.go
+./char_lit1.go
+./closedchan.go
+./closure.go
+./cmp1.go
+./cmp2.go
+./cmp3.go
+./cmp4.go
+./cmp5.go
+./cmplx.go
+# ./cmplxdivide.go     # fail, BUG
+./cmplxdivide1.go
+./complit.go
+./compos.go
+./const.go
+./const1.go
+./const2.go
+./const3.go
+./convert.go
+./convert3.go
+./convlit.go
+./convlit1.go
+./copy.go
+./ddd.go
+./ddd1.go
+./ddd2.go
+./ddd3.go
+./decl.go
+./declbad.go
+./defer.go
+./deferprint.go
+./empty.go
+./env.go
+./escape.go
+./float_lit.go
+./floatcmp.go
+./for.go
+./func.go
+./func1.go
+./func2.go
+./func3.go
+./func4.go
+./func5.go
+./gc.go
+./gc1.go
+./hashmap.go
+./helloworld.go
+./if.go
+./if1.go
+./import.go
+./import1.go
+./import2.go
+./import3.go
+./import4.go
+./indirect.go
+./indirect1.go
+./initcomma.go
+./initialize.go
+./initializerr.go
+./initsyscall.go
+./int_lit.go
+./intcvt.go
+./iota.go
+./literal.go
+./malloc1.go
+# ./mallocfin.go       # fail
+./mallocrand.go
+./mallocrep.go
+./mallocrep1.go
+# ./map.go     # fail
+./method.go
+./method1.go
+./method2.go
+./method3.go
+./named.go
+./named1.go
+./nil.go
+./nul1.go
+./parentype.go
+./peano.go
+./printbig.go
+./range.go
+./recover.go
+./recover1.go
+./recover2.go
+# ./recover3.go        # fail
+./rename.go
+./rename1.go
+./runtime.go
+./sieve.go
+./sigchld.go
+./simassign.go
+./sinit.go
+./stack.go
+./string_lit.go
+./stringrange.go
+./switch.go
+./switch1.go
+./test0.go
+./turing.go
+./typeswitch.go
+./typeswitch1.go
+./typeswitch2.go
+./undef.go
+./utf.go
+./varerr.go
+./varinit.go
+./vectors.go
+./zerodivide.go
+ken/array.go
+ken/chan.go
+ken/chan1.go
+ken/complit.go
+# ken/cplx0.go # output fail
+# ken/cplx1.go # fail
+# ken/cplx2.go # fail
+# ken/cplx3.go # output fail
+# ken/cplx4.go # fail, BUG
+# ken/cplx5.go # output fail
+ken/divconst.go
+ken/divmod.go
+ken/embed.go
+ken/for.go
+ken/interbasic.go
+ken/interfun.go
+ken/intervar.go
+ken/label.go
+ken/litfun.go
+ken/mfunc.go
+ken/modconst.go
+ken/ptrfun.go
+ken/ptrvar.go
+ken/range.go
+ken/rob1.go
+ken/rob2.go
+ken/robfor.go
+ken/robfunc.go
+ken/robif.go
+ken/shift.go
+ken/simparray.go
+ken/simpbool.go
+ken/simpconv.go
+ken/simpfun.go
+ken/simpprint.go
+ken/simpswitch.go
+ken/simpvar.go
+ken/slicearray.go
+ken/sliceslice.go
+ken/string.go
+ken/strvar.go
+chan/doubleselect.go
+chan/fifo.go
+chan/goroutines.go
+chan/nonblock.go
+chan/perm.go
+chan/powser1.go
+chan/powser2.go
+chan/select.go
+chan/select2.go
+# chan/select3.go      # fail
+chan/sieve1.go
+chan/sieve2.go
+interface/bigdata.go
+interface/convert.go
+interface/convert1.go
+interface/convert2.go
+interface/embed.go
+interface/embed0.go
+interface/embed1.go
+interface/explicit.go
+interface/fail.go
+interface/fake.go
+interface/pointer.go
+interface/receiver.go
+interface/receiver1.go
+interface/recursive.go
+interface/returntype.go
+interface/struct.go
+nilptr/arrayindex.go
+nilptr/arrayindex1.go
+nilptr/arraytoslice.go
+nilptr/arraytoslice1.go
+nilptr/arraytoslice2.go
+nilptr/slicearray.go
+nilptr/structfield.go
+nilptr/structfield1.go
+nilptr/structfield2.go
+nilptr/structfieldaddr.go
+syntax/forvar.go
+syntax/import.go
+syntax/interface.go
+syntax/semi1.go
+syntax/semi2.go
+syntax/semi3.go
+syntax/semi4.go
+syntax/semi5.go
+syntax/semi6.go
+syntax/semi7.go
+syntax/slice.go
+syntax/topexpr.go
+syntax/vareq.go
+syntax/vareq1.go
+fixedbugs/bug000.go
+fixedbugs/bug001.go
+fixedbugs/bug002.go
+fixedbugs/bug003.go
+fixedbugs/bug004.go
+fixedbugs/bug005.go
+fixedbugs/bug006.go
+fixedbugs/bug007.go
+fixedbugs/bug008.go
+fixedbugs/bug009.go
+fixedbugs/bug010.go
+fixedbugs/bug011.go
+fixedbugs/bug012.go
+fixedbugs/bug013.go
+fixedbugs/bug014.go
+fixedbugs/bug015.go
+fixedbugs/bug016.go
+fixedbugs/bug017.go
+fixedbugs/bug020.go
+fixedbugs/bug021.go
+fixedbugs/bug022.go
+fixedbugs/bug023.go
+fixedbugs/bug024.go
+fixedbugs/bug026.go
+fixedbugs/bug027.go
+fixedbugs/bug028.go
+fixedbugs/bug030.go
+fixedbugs/bug031.go
+fixedbugs/bug035.go
+fixedbugs/bug036.go
+fixedbugs/bug037.go
+fixedbugs/bug038.go
+fixedbugs/bug039.go
+fixedbugs/bug040.go
+fixedbugs/bug045.go
+fixedbugs/bug046.go
+fixedbugs/bug047.go
+fixedbugs/bug048.go
+fixedbugs/bug049.go
+fixedbugs/bug050.go
+fixedbugs/bug051.go
+fixedbugs/bug052.go
+fixedbugs/bug053.go
+fixedbugs/bug054.go
+fixedbugs/bug055.go
+fixedbugs/bug056.go
+fixedbugs/bug057.go
+fixedbugs/bug058.go
+fixedbugs/bug059.go
+fixedbugs/bug060.go
+fixedbugs/bug061.go
+fixedbugs/bug062.go
+fixedbugs/bug063.go
+fixedbugs/bug064.go
+fixedbugs/bug065.go
+fixedbugs/bug066.go
+fixedbugs/bug067.go
+fixedbugs/bug068.go
+fixedbugs/bug069.go
+fixedbugs/bug070.go
+fixedbugs/bug071.go
+fixedbugs/bug072.go
+fixedbugs/bug073.go
+fixedbugs/bug074.go
+fixedbugs/bug075.go
+fixedbugs/bug076.go
+fixedbugs/bug077.go
+fixedbugs/bug078.go
+fixedbugs/bug080.go
+fixedbugs/bug081.go
+fixedbugs/bug082.go
+fixedbugs/bug083.go
+fixedbugs/bug084.go
+fixedbugs/bug085.go
+fixedbugs/bug086.go
+fixedbugs/bug087.go
+fixedbugs/bug088.go
+fixedbugs/bug089.go
+fixedbugs/bug090.go
+fixedbugs/bug091.go
+fixedbugs/bug092.go
+fixedbugs/bug093.go
+fixedbugs/bug094.go
+fixedbugs/bug096.go
+fixedbugs/bug097.go
+fixedbugs/bug098.go
+fixedbugs/bug099.go
+fixedbugs/bug101.go
+fixedbugs/bug102.go
+fixedbugs/bug103.go
+fixedbugs/bug104.go
+fixedbugs/bug106.go
+fixedbugs/bug107.go
+fixedbugs/bug108.go
+fixedbugs/bug109.go
+fixedbugs/bug110.go
+fixedbugs/bug111.go
+fixedbugs/bug112.go
+fixedbugs/bug113.go
+fixedbugs/bug114.go
+fixedbugs/bug115.go
+fixedbugs/bug116.go
+fixedbugs/bug117.go
+fixedbugs/bug118.go
+fixedbugs/bug119.go
+fixedbugs/bug120.go
+fixedbugs/bug121.go
+fixedbugs/bug122.go
+fixedbugs/bug123.go
+fixedbugs/bug126.go
+fixedbugs/bug127.go
+fixedbugs/bug128.go
+fixedbugs/bug129.go
+fixedbugs/bug130.go
+fixedbugs/bug131.go
+fixedbugs/bug132.go
+fixedbugs/bug133.go
+fixedbugs/bug135.go
+fixedbugs/bug136.go
+fixedbugs/bug137.go
+fixedbugs/bug139.go
+fixedbugs/bug140.go
+fixedbugs/bug141.go
+fixedbugs/bug142.go
+fixedbugs/bug143.go
+fixedbugs/bug144.go
+fixedbugs/bug145.go
+fixedbugs/bug146.go
+fixedbugs/bug147.go
+fixedbugs/bug148.go
+fixedbugs/bug149.go
+fixedbugs/bug150.go
+fixedbugs/bug151.go
+fixedbugs/bug152.go
+fixedbugs/bug154.go
+fixedbugs/bug155.go
+fixedbugs/bug156.go
+fixedbugs/bug157.go
+fixedbugs/bug158.go
+fixedbugs/bug159.go
+fixedbugs/bug160.go
+fixedbugs/bug161.go
+fixedbugs/bug163.go
+fixedbugs/bug164.go
+fixedbugs/bug165.go
+fixedbugs/bug167.go
+fixedbugs/bug168.go
+fixedbugs/bug169.go
+fixedbugs/bug170.go
+fixedbugs/bug171.go
+fixedbugs/bug172.go
+fixedbugs/bug173.go
+fixedbugs/bug174.go
+fixedbugs/bug175.go
+fixedbugs/bug176.go
+fixedbugs/bug177.go
+fixedbugs/bug178.go
+fixedbugs/bug179.go
+fixedbugs/bug180.go
+fixedbugs/bug181.go
+fixedbugs/bug182.go
+fixedbugs/bug183.go
+fixedbugs/bug184.go
+fixedbugs/bug185.go
+fixedbugs/bug186.go
+fixedbugs/bug187.go
+fixedbugs/bug188.go
+fixedbugs/bug189.go
+fixedbugs/bug190.go
+fixedbugs/bug191.go
+fixedbugs/bug192.go
+fixedbugs/bug193.go
+fixedbugs/bug194.go
+fixedbugs/bug195.go
+fixedbugs/bug196.go
+fixedbugs/bug197.go
+fixedbugs/bug198.go
+fixedbugs/bug199.go
+fixedbugs/bug200.go
+fixedbugs/bug201.go
+fixedbugs/bug202.go
+fixedbugs/bug203.go
+fixedbugs/bug204.go
+fixedbugs/bug205.go
+fixedbugs/bug206.go
+fixedbugs/bug207.go
+fixedbugs/bug208.go
+fixedbugs/bug209.go
+fixedbugs/bug211.go
+fixedbugs/bug212.go
+fixedbugs/bug213.go
+fixedbugs/bug214.go
+fixedbugs/bug215.go
+fixedbugs/bug216.go
+fixedbugs/bug217.go
+fixedbugs/bug218.go
+fixedbugs/bug219.go
+fixedbugs/bug220.go
+fixedbugs/bug221.go
+fixedbugs/bug222.go
+fixedbugs/bug223.go
+fixedbugs/bug224.go
+fixedbugs/bug225.go
+fixedbugs/bug226.go
+fixedbugs/bug227.go
+fixedbugs/bug228.go
+fixedbugs/bug229.go
+fixedbugs/bug230.go
+fixedbugs/bug231.go
+fixedbugs/bug232.go
+fixedbugs/bug233.go
+fixedbugs/bug234.go
+fixedbugs/bug235.go
+fixedbugs/bug236.go
+fixedbugs/bug237.go
+fixedbugs/bug238.go
+fixedbugs/bug239.go
+fixedbugs/bug240.go
+fixedbugs/bug241.go
+fixedbugs/bug242.go
+# fixedbugs/bug243.go  # fail, flaky on android build
+fixedbugs/bug244.go
+fixedbugs/bug245.go
+fixedbugs/bug246.go
+fixedbugs/bug247.go
+fixedbugs/bug248.go
+fixedbugs/bug249.go
+fixedbugs/bug250.go
+fixedbugs/bug251.go
+fixedbugs/bug252.go
+fixedbugs/bug253.go
+fixedbugs/bug254.go
+fixedbugs/bug255.go
+fixedbugs/bug256.go
+fixedbugs/bug257.go
+fixedbugs/bug258.go
+fixedbugs/bug259.go
+fixedbugs/bug261.go
+fixedbugs/bug262.go
+fixedbugs/bug263.go
+fixedbugs/bug264.go
+fixedbugs/bug265.go
+fixedbugs/bug266.go
+fixedbugs/bug267.go
+fixedbugs/bug268.go
+fixedbugs/bug269.go
+fixedbugs/bug270.go
+fixedbugs/bug271.go
+fixedbugs/bug272.go
+fixedbugs/bug273.go
+fixedbugs/bug274.go
+fixedbugs/bug275.go
+fixedbugs/bug276.go
+fixedbugs/bug277.go
+fixedbugs/bug278.go
+fixedbugs/bug279.go
+fixedbugs/bug280.go
+fixedbugs/bug281.go
+fixedbugs/bug282.go
+fixedbugs/bug283.go
+fixedbugs/bug284.go
+fixedbugs/bug285.go
+fixedbugs/bug286.go
+fixedbugs/bug287.go
+fixedbugs/bug288.go
+fixedbugs/bug289.go
+fixedbugs/bug290.go
+fixedbugs/bug291.go
+fixedbugs/bug292.go
+fixedbugs/bug293.go
+fixedbugs/bug294.go
+fixedbugs/bug295.go
+fixedbugs/bug296.go
+fixedbugs/bug297.go
+fixedbugs/bug298.go
+# bugs/bug260.go       # fail, BUG
diff --git a/gcc/testsuite/go.test/test/assign.go b/gcc/testsuite/go.test/test/assign.go
new file mode 100644 (file)
index 0000000..5947138
--- /dev/null
@@ -0,0 +1,53 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "sync"
+
+type T struct {
+       int
+       sync.Mutex
+}
+
+func main() {
+       {
+               var x, y sync.Mutex
+               x = y   // ERROR "assignment.*Mutex"
+               _ = x
+       }
+       {
+               var x, y T
+               x = y   // ERROR "assignment.*Mutex"
+               _ = x
+       }
+       {
+               var x, y [2]sync.Mutex
+               x = y   // ERROR "assignment.*Mutex"
+               _ = x
+       }
+       {
+               var x, y [2]T
+               x = y   // ERROR "assignment.*Mutex"
+               _ = x
+       }
+       {
+               x := sync.Mutex{0, 0}   // ERROR "assignment.*Mutex"
+               _ = x
+       }
+       {
+               x := sync.Mutex{key: 0} // ERROR "(unknown|assignment).*Mutex"
+               _ = x
+       }
+       {
+               x := &sync.Mutex{}      // ok
+               var y sync.Mutex        // ok
+               y = *x  // ERROR "assignment.*Mutex"
+               *x = y  // ERROR "assignment.*Mutex"
+               _ = x
+               _ = y
+       }               
+}
diff --git a/gcc/testsuite/go.test/test/assign1.go b/gcc/testsuite/go.test/test/assign1.go
new file mode 100644 (file)
index 0000000..71e5b40
--- /dev/null
@@ -0,0 +1,343 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type (
+       A [10]int
+       B []int
+       C chan int
+       F func() int
+       I interface {
+               m() int
+       }
+       M map[int]int
+       P *int
+       S struct {
+               X int
+       }
+
+       A1 [10]int
+       B1 []int
+       C1 chan int
+       F1 func() int
+       I1 interface {
+               m() int
+       }
+       M1 map[int]int
+       P1 *int
+       S1 struct {
+               X int
+       }
+)
+
+var (
+       a0 [10]int
+       b0 []int
+       c0 chan int
+       f0 func() int
+       i0 interface {
+               m() int
+       }
+       m0 map[int]int
+       p0 *int
+       s0 struct {
+               X int
+       }
+
+       a A
+       b B
+       c C
+       f F
+       i I
+       m M
+       p P
+       s S
+
+       a1 A1
+       b1 B1
+       c1 C1
+       f1 F1
+       i1 I1
+       m1 M1
+       p1 P1
+       s1 S1
+
+       pa0 *[10]int
+       pb0 *[]int
+       pc0 *chan int
+       pf0 *func() int
+       pi0 *interface {
+               m() int
+       }
+       pm0 *map[int]int
+       pp0 **int
+       ps0 *struct {
+               X int
+       }
+
+       pa *A
+       pb *B
+       pc *C
+       pf *F
+       pi *I
+       pm *M
+       pp *P
+       ps *S
+
+       pa1 *A1
+       pb1 *B1
+       pc1 *C1
+       pf1 *F1
+       pi1 *I1
+       pm1 *M1
+       pp1 *P1
+       ps1 *S1
+)
+
+func main() {
+       a0 = a
+       a0 = a1
+       a = a0
+       a = a1 // ERROR "cannot use"
+       a1 = a0
+       a1 = a // ERROR "cannot use"
+
+       b0 = b
+       b0 = b1
+       b = b0
+       b = b1 // ERROR "cannot use"
+       b1 = b0
+       b1 = b // ERROR "cannot use"
+
+       c0 = c
+       c0 = c1
+       c = c0
+       c = c1 // ERROR "cannot use"
+       c1 = c0
+       c1 = c // ERROR "cannot use"
+
+       f0 = f
+       f0 = f1
+       f = f0
+       f = f1 // ERROR "cannot use"
+       f1 = f0
+       f1 = f // ERROR "cannot use"
+
+       i0 = i
+       i0 = i1
+       i = i0
+       i = i1
+       i1 = i0
+       i1 = i
+
+       m0 = m
+       m0 = m1
+       m = m0
+       m = m1 // ERROR "cannot use"
+       m1 = m0
+       m1 = m // ERROR "cannot use"
+
+       p0 = p
+       p0 = p1
+       p = p0
+       p = p1 // ERROR "cannot use"
+       p1 = p0
+       p1 = p // ERROR "cannot use"
+
+       s0 = s
+       s0 = s1
+       s = s0
+       s = s1 // ERROR "cannot use"
+       s1 = s0
+       s1 = s // ERROR "cannot use"
+
+       pa0 = pa  // ERROR "cannot use|incompatible"
+       pa0 = pa1 // ERROR "cannot use|incompatible"
+       pa = pa0  // ERROR "cannot use|incompatible"
+       pa = pa1  // ERROR "cannot use|incompatible"
+       pa1 = pa0 // ERROR "cannot use|incompatible"
+       pa1 = pa  // ERROR "cannot use|incompatible"
+
+       pb0 = pb  // ERROR "cannot use|incompatible"
+       pb0 = pb1 // ERROR "cannot use|incompatible"
+       pb = pb0  // ERROR "cannot use|incompatible"
+       pb = pb1  // ERROR "cannot use|incompatible"
+       pb1 = pb0 // ERROR "cannot use|incompatible"
+       pb1 = pb  // ERROR "cannot use|incompatible"
+
+       pc0 = pc  // ERROR "cannot use|incompatible"
+       pc0 = pc1 // ERROR "cannot use|incompatible"
+       pc = pc0  // ERROR "cannot use|incompatible"
+       pc = pc1  // ERROR "cannot use|incompatible"
+       pc1 = pc0 // ERROR "cannot use|incompatible"
+       pc1 = pc  // ERROR "cannot use|incompatible"
+
+       pf0 = pf  // ERROR "cannot use|incompatible"
+       pf0 = pf1 // ERROR "cannot use|incompatible"
+       pf = pf0  // ERROR "cannot use|incompatible"
+       pf = pf1  // ERROR "cannot use|incompatible"
+       pf1 = pf0 // ERROR "cannot use|incompatible"
+       pf1 = pf  // ERROR "cannot use|incompatible"
+
+       pi0 = pi  // ERROR "cannot use|incompatible"
+       pi0 = pi1 // ERROR "cannot use|incompatible"
+       pi = pi0  // ERROR "cannot use|incompatible"
+       pi = pi1  // ERROR "cannot use|incompatible"
+       pi1 = pi0 // ERROR "cannot use|incompatible"
+       pi1 = pi  // ERROR "cannot use|incompatible"
+
+       pm0 = pm  // ERROR "cannot use|incompatible"
+       pm0 = pm1 // ERROR "cannot use|incompatible"
+       pm = pm0  // ERROR "cannot use|incompatible"
+       pm = pm1  // ERROR "cannot use|incompatible"
+       pm1 = pm0 // ERROR "cannot use|incompatible"
+       pm1 = pm  // ERROR "cannot use|incompatible"
+
+       pp0 = pp  // ERROR "cannot use|incompatible"
+       pp0 = pp1 // ERROR "cannot use|incompatible"
+       pp = pp0  // ERROR "cannot use|incompatible"
+       pp = pp1  // ERROR "cannot use|incompatible"
+       pp1 = pp0 // ERROR "cannot use|incompatible"
+       pp1 = pp  // ERROR "cannot use|incompatible"
+
+       ps0 = ps  // ERROR "cannot use|incompatible"
+       ps0 = ps1 // ERROR "cannot use|incompatible"
+       ps = ps0  // ERROR "cannot use|incompatible"
+       ps = ps1  // ERROR "cannot use|incompatible"
+       ps1 = ps0 // ERROR "cannot use|incompatible"
+       ps1 = ps  // ERROR "cannot use|incompatible"
+
+
+       a0 = [10]int(a)
+       a0 = [10]int(a1)
+       a = A(a0)
+       a = A(a1)
+       a1 = A1(a0)
+       a1 = A1(a)
+
+       b0 = []int(b)
+       b0 = []int(b1)
+       b = B(b0)
+       b = B(b1)
+       b1 = B1(b0)
+       b1 = B1(b)
+
+       c0 = chan int(c)
+       c0 = chan int(c1)
+       c = C(c0)
+       c = C(c1)
+       c1 = C1(c0)
+       c1 = C1(c)
+
+       f0 = func() int(f)
+       f0 = func() int(f1)
+       f = F(f0)
+       f = F(f1)
+       f1 = F1(f0)
+       f1 = F1(f)
+
+       i0 = interface {
+               m() int
+       }(i)
+       i0 = interface {
+               m() int
+       }(i1)
+       i = I(i0)
+       i = I(i1)
+       i1 = I1(i0)
+       i1 = I1(i)
+
+       m0 = map[int]int(m)
+       m0 = map[int]int(m1)
+       m = M(m0)
+       m = M(m1)
+       m1 = M1(m0)
+       m1 = M1(m)
+
+       p0 = (*int)(p)
+       p0 = (*int)(p1)
+       p = P(p0)
+       p = P(p1)
+       p1 = P1(p0)
+       p1 = P1(p)
+
+       s0 = struct {
+               X int
+       }(s)
+       s0 = struct {
+               X int
+       }(s1)
+       s = S(s0)
+       s = S(s1)
+       s1 = S1(s0)
+       s1 = S1(s)
+
+       pa0 = (*[10]int)(pa)
+       pa0 = (*[10]int)(pa1)
+       pa = (*A)(pa0)
+       pa = (*A)(pa1)
+       pa1 = (*A1)(pa0)
+       pa1 = (*A1)(pa)
+
+       pb0 = (*[]int)(pb)
+       pb0 = (*[]int)(pb1)
+       pb = (*B)(pb0)
+       pb = (*B)(pb1)
+       pb1 = (*B1)(pb0)
+       pb1 = (*B1)(pb)
+
+       pc0 = (*chan int)(pc)
+       pc0 = (*chan int)(pc1)
+       pc = (*C)(pc0)
+       pc = (*C)(pc1)
+       pc1 = (*C1)(pc0)
+       pc1 = (*C1)(pc)
+
+       pf0 = (*func() int)(pf)
+       pf0 = (*func() int)(pf1)
+       pf = (*F)(pf0)
+       pf = (*F)(pf1)
+       pf1 = (*F1)(pf0)
+       pf1 = (*F1)(pf)
+
+       pi0 = (*interface {
+               m() int
+       })(pi)
+       pi0 = (*interface {
+               m() int
+       })(pi1)
+       pi = (*I)(pi0)
+       pi = (*I)(pi1)
+       pi1 = (*I1)(pi0)
+       pi1 = (*I1)(pi)
+
+       pm0 = (*map[int]int)(pm)
+       pm0 = (*map[int]int)(pm1)
+       pm = (*M)(pm0)
+       pm = (*M)(pm1)
+       pm1 = (*M1)(pm0)
+       pm1 = (*M1)(pm)
+
+       pp0 = (**int)(pp)
+       pp0 = (**int)(pp1)
+       pp = (*P)(pp0)
+       pp = (*P)(pp1)
+       pp1 = (*P1)(pp0)
+       pp1 = (*P1)(pp)
+
+       ps0 = (*struct {
+               X int
+       })(ps)
+       ps0 = (*struct {
+               X int
+       })(ps1)
+       ps = (*S)(ps0)
+       ps = (*S)(ps1)
+       ps1 = (*S1)(ps0)
+       ps1 = (*S1)(ps)
+
+}
diff --git a/gcc/testsuite/go.test/test/bench/binary-tree-freelist.go b/gcc/testsuite/go.test/test/bench/binary-tree-freelist.go
new file mode 100644 (file)
index 0000000..071a4e0
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on C program by Kevin Carson
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+)
+
+var n = flag.Int("n", 15, "depth")
+
+type Node struct {
+       item        int
+       left, right *Node
+}
+
+type Arena struct {
+       head *Node
+}
+
+var arena Arena
+
+func (n *Node) free() {
+       if n.left != nil {
+               n.left.free()
+       }
+       if n.right != nil {
+               n.right.free()
+       }
+       n.left = arena.head
+       arena.head = n
+}
+
+func (a *Arena) New(item int, left, right *Node) *Node {
+       if a.head == nil {
+               nodes := make([]Node, 3<<uint(*n))
+               for i := 0; i < len(nodes)-1; i++ {
+                       nodes[i].left = &nodes[i+1]
+               }
+               a.head = &nodes[0]
+       }
+       n := a.head
+       a.head = a.head.left
+       n.item = item
+       n.left = left
+       n.right = right
+       return n
+}
+
+func bottomUpTree(item, depth int) *Node {
+       if depth <= 0 {
+               return arena.New(item, nil, nil)
+       }
+       return arena.New(item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1))
+}
+
+func (n *Node) itemCheck() int {
+       if n.left == nil {
+               return n.item
+       }
+       return n.item + n.left.itemCheck() - n.right.itemCheck()
+}
+
+const minDepth = 4
+
+func main() {
+       flag.Parse()
+
+       maxDepth := *n
+       if minDepth+2 > *n {
+               maxDepth = minDepth + 2
+       }
+       stretchDepth := maxDepth + 1
+
+       check := bottomUpTree(0, stretchDepth).itemCheck()
+       fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
+
+       longLivedTree := bottomUpTree(0, maxDepth)
+
+       for depth := minDepth; depth <= maxDepth; depth += 2 {
+               iterations := 1 << uint(maxDepth-depth+minDepth)
+               check = 0
+
+               for i := 1; i <= iterations; i++ {
+                       t := bottomUpTree(i, depth)
+                       check += t.itemCheck()
+                       t.free()
+                       t = bottomUpTree(-i, depth)
+                       check += t.itemCheck()
+                       t.free()
+               }
+               fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
+       }
+       fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
+}
diff --git a/gcc/testsuite/go.test/test/bench/binary-tree-freelist.txt b/gcc/testsuite/go.test/test/bench/binary-tree-freelist.txt
new file mode 100644 (file)
index 0000000..f8286dd
--- /dev/null
@@ -0,0 +1,8 @@
+stretch tree of depth 16        check: -1
+65536   trees of depth 4        check: -65536
+16384   trees of depth 6        check: -16384
+4096    trees of depth 8        check: -4096
+1024    trees of depth 10       check: -1024
+256     trees of depth 12       check: -256
+64      trees of depth 14       check: -64
+long lived tree of depth 15     check: -1
diff --git a/gcc/testsuite/go.test/test/bench/binary-tree.c b/gcc/testsuite/go.test/test/bench/binary-tree.c
new file mode 100644 (file)
index 0000000..1b40704
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Shootout Benchmarks
+   http://shootout.alioth.debian.org/
+
+   contributed by Kevin Carson
+   compilation:
+       gcc -O3 -fomit-frame-pointer -funroll-loops -static binary-trees.c -lm
+       icc -O3 -ip -unroll -static binary-trees.c -lm
+*/
+
+#include <malloc.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef struct tn {
+    struct tn*    left;
+    struct tn*    right;
+    long          item;
+} treeNode;
+
+
+treeNode* NewTreeNode(treeNode* left, treeNode* right, long item)
+{
+    treeNode*    new;
+
+    new = (treeNode*)malloc(sizeof(treeNode));
+
+    new->left = left;
+    new->right = right;
+    new->item = item;
+
+    return new;
+} /* NewTreeNode() */
+
+
+long ItemCheck(treeNode* tree)
+{
+    if (tree->left == NULL)
+        return tree->item;
+    else
+        return tree->item + ItemCheck(tree->left) - ItemCheck(tree->right);
+} /* ItemCheck() */
+
+
+treeNode* BottomUpTree(long item, unsigned depth)
+{
+    if (depth > 0)
+        return NewTreeNode
+        (
+            BottomUpTree(2 * item - 1, depth - 1),
+            BottomUpTree(2 * item, depth - 1),
+            item
+        );
+    else
+        return NewTreeNode(NULL, NULL, item);
+} /* BottomUpTree() */
+
+
+void DeleteTree(treeNode* tree)
+{
+    if (tree->left != NULL)
+    {
+        DeleteTree(tree->left);
+        DeleteTree(tree->right);
+    }
+
+    free(tree);
+} /* DeleteTree() */
+
+
+int main(int argc, char* argv[])
+{
+    unsigned   N, depth, minDepth, maxDepth, stretchDepth;
+    treeNode   *stretchTree, *longLivedTree, *tempTree;
+
+    N = atol(argv[1]);
+
+    minDepth = 4;
+
+    if ((minDepth + 2) > N)
+        maxDepth = minDepth + 2;
+    else
+        maxDepth = N;
+
+    stretchDepth = maxDepth + 1;
+
+    stretchTree = BottomUpTree(0, stretchDepth);
+    printf
+    (
+        "stretch tree of depth %u\t check: %li\n",
+        stretchDepth,
+        ItemCheck(stretchTree)
+    );
+
+    DeleteTree(stretchTree);
+
+    longLivedTree = BottomUpTree(0, maxDepth);
+
+    for (depth = minDepth; depth <= maxDepth; depth += 2)
+    {
+        long    i, iterations, check;
+
+        iterations = pow(2, maxDepth - depth + minDepth);
+
+        check = 0;
+
+        for (i = 1; i <= iterations; i++)
+        {
+            tempTree = BottomUpTree(i, depth);
+            check += ItemCheck(tempTree);
+            DeleteTree(tempTree);
+
+            tempTree = BottomUpTree(-i, depth);
+            check += ItemCheck(tempTree);
+            DeleteTree(tempTree);
+        } /* for(i = 1...) */
+
+        printf
+        (
+            "%li\t trees of depth %u\t check: %li\n",
+            iterations * 2,
+            depth,
+            check
+        );
+    } /* for(depth = minDepth...) */
+
+    printf
+    (
+        "long lived tree of depth %u\t check: %li\n",
+        maxDepth,
+        ItemCheck(longLivedTree)
+    );
+
+    return 0;
+} /* main() */
diff --git a/gcc/testsuite/go.test/test/bench/binary-tree.go b/gcc/testsuite/go.test/test/bench/binary-tree.go
new file mode 100644 (file)
index 0000000..9f867d1
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on C program by Kevin Carson
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+)
+
+var n = flag.Int("n", 15, "depth")
+
+type Node struct {
+       item        int
+       left, right *Node
+}
+
+func bottomUpTree(item, depth int) *Node {
+       if depth <= 0 {
+               return &Node{item: item}
+       }
+       return &Node{item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1)}
+}
+
+func (n *Node) itemCheck() int {
+       if n.left == nil {
+               return n.item
+       }
+       return n.item + n.left.itemCheck() - n.right.itemCheck()
+}
+
+const minDepth = 4
+
+func main() {
+       flag.Parse()
+
+       maxDepth := *n
+       if minDepth+2 > *n {
+               maxDepth = minDepth + 2
+       }
+       stretchDepth := maxDepth + 1
+
+       check := bottomUpTree(0, stretchDepth).itemCheck()
+       fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
+
+       longLivedTree := bottomUpTree(0, maxDepth)
+
+       for depth := minDepth; depth <= maxDepth; depth += 2 {
+               iterations := 1 << uint(maxDepth-depth+minDepth)
+               check = 0
+
+               for i := 1; i <= iterations; i++ {
+                       check += bottomUpTree(i, depth).itemCheck()
+                       check += bottomUpTree(-i, depth).itemCheck()
+               }
+               fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
+       }
+       fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
+}
diff --git a/gcc/testsuite/go.test/test/bench/binary-tree.txt b/gcc/testsuite/go.test/test/bench/binary-tree.txt
new file mode 100644 (file)
index 0000000..f8286dd
--- /dev/null
@@ -0,0 +1,8 @@
+stretch tree of depth 16        check: -1
+65536   trees of depth 4        check: -65536
+16384   trees of depth 6        check: -16384
+4096    trees of depth 8        check: -4096
+1024    trees of depth 10       check: -1024
+256     trees of depth 12       check: -256
+64      trees of depth 14       check: -64
+long lived tree of depth 15     check: -1
diff --git a/gcc/testsuite/go.test/test/bench/chameneosredux.c b/gcc/testsuite/go.test/test/bench/chameneosredux.c
new file mode 100644 (file)
index 0000000..ed78c31
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+   http://shootout.alioth.debian.org/
+
+   contributed by Michael Barker
+   based on a Java contribution by Luzius Meisser
+
+   convert to C by dualamd
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+
+
+enum Colour
+{
+   blue      = 0,
+   red      = 1,
+   yellow   = 2,
+   Invalid   = 3
+};
+
+const char* ColourName[] = {"blue", "red", "yellow"};
+const int STACK_SIZE   = 32*1024;
+
+typedef unsigned int BOOL;
+const BOOL TRUE = 1;
+const BOOL FALSE = 0;
+
+int CreatureID = 0;
+
+
+enum Colour doCompliment(enum Colour c1, enum Colour c2)
+{
+   switch (c1)
+   {
+   case blue:
+      switch (c2)
+      {
+      case blue:
+         return blue;
+      case red:
+         return yellow;
+      case yellow:
+         return red;
+      default:
+         goto errlb;
+      }
+   case red:
+      switch (c2)
+      {
+      case blue:
+         return yellow;
+      case red:
+         return red;
+      case yellow:
+         return blue;
+      default:
+         goto errlb;
+      }
+   case yellow:
+      switch (c2)
+      {
+      case blue:
+         return red;
+      case red:
+         return blue;
+      case yellow:
+         return yellow;
+      default:
+         goto errlb;
+      }
+   default:
+      break;
+   }
+
+errlb:
+   printf("Invalid colour\n");
+   exit( 1 );
+}
+
+/* convert integer to number string: 1234 -> "one two three four" */
+char* formatNumber(int n, char* outbuf)
+{
+   int ochar = 0, ichar = 0;
+   int i;
+   char tmp[64];
+
+   const char* NUMBERS[] =
+   {
+      "zero", "one", "two", "three", "four", "five",
+      "six", "seven", "eight", "nine"
+   };
+
+   ichar = sprintf(tmp, "%d", n);
+
+   for (i = 0; i < ichar; i++)
+      ochar += sprintf( outbuf + ochar, " %s", NUMBERS[ tmp[i] - '0' ] );
+
+   return outbuf;
+}
+
+
+struct MeetingPlace
+{
+   pthread_mutex_t   mutex;
+   int             meetingsLeft;
+   struct Creature*   firstCreature;
+};
+
+struct Creature
+{
+   pthread_t         ht;
+   pthread_attr_t      stack_att;
+
+   struct MeetingPlace* place;
+   int         count;
+   int         sameCount;
+
+   enum Colour   colour;
+   int          id;
+
+   BOOL      two_met;
+   BOOL      sameid;
+};
+
+
+void MeetingPlace_Init(struct MeetingPlace* m, int meetings )
+{
+   pthread_mutex_init( &m->mutex, 0 );
+   m->meetingsLeft = meetings;
+   m->firstCreature = 0;
+}
+
+
+BOOL Meet( struct Creature* cr)
+{
+   BOOL retval = TRUE;
+
+   struct MeetingPlace* mp = cr->place;
+   pthread_mutex_lock( &(mp->mutex) );
+
+   if ( mp->meetingsLeft > 0 )
+   {
+      if ( mp->firstCreature == 0 )
+      {
+         cr->two_met = FALSE;
+         mp->firstCreature = cr;
+      }
+      else
+      {
+         struct Creature* first;
+         enum Colour newColour;
+
+         first = mp->firstCreature;
+         newColour = doCompliment( cr->colour, first->colour );
+
+         cr->sameid = cr->id == first->id;
+         cr->colour = newColour;
+         cr->two_met = TRUE;
+
+         first->sameid = cr->sameid;
+         first->colour = newColour;
+         first->two_met = TRUE;
+
+         mp->firstCreature = 0;
+         mp->meetingsLeft--;
+      }
+   }
+   else
+      retval = FALSE;
+
+   pthread_mutex_unlock( &(mp->mutex) );
+   return retval;
+}
+
+
+void* CreatureThreadRun(void* param)
+{
+   struct Creature* cr = (struct Creature*)param;
+
+   while (TRUE)
+   {
+      if ( Meet(cr) )
+      {
+         while (cr->two_met == FALSE)
+            sched_yield();
+
+         if (cr->sameid)
+            cr->sameCount++;
+         cr->count++;
+      }
+      else
+         break;
+   }
+
+   return 0;
+}
+
+void Creature_Init( struct Creature *cr, struct MeetingPlace* place, enum Colour colour )
+{
+   cr->place = place;
+   cr->count = cr->sameCount = 0;
+
+   cr->id = ++CreatureID;
+   cr->colour = colour;
+   cr->two_met = FALSE;
+
+   pthread_attr_init( &cr->stack_att );
+   pthread_attr_setstacksize( &cr->stack_att, STACK_SIZE );
+   pthread_create( &cr->ht, &cr->stack_att, &CreatureThreadRun, (void*)(cr) );
+}
+
+/* format meeting times of each creature to string */
+char* Creature_getResult(struct Creature* cr, char* str)
+{
+   char numstr[256];
+   formatNumber(cr->sameCount, numstr);
+
+   sprintf( str, "%u%s", cr->count, numstr );
+   return str;
+}
+
+
+void runGame( int n_meeting, int ncolor, const enum Colour* colours )
+{
+   int i;
+   int total = 0;
+   char str[256];
+
+   struct MeetingPlace place;
+   struct Creature *creatures = (struct Creature*) calloc( ncolor, sizeof(struct Creature) );
+
+   MeetingPlace_Init( &place, n_meeting );
+
+   /* print initial color of each creature */
+   for (i = 0; i < ncolor; i++)
+   {
+      printf( "%s ", ColourName[ colours[i] ] );
+      Creature_Init( &(creatures[i]), &place, colours[i] );
+   }
+   printf("\n");
+
+   /* wait for them to meet */
+   for (i = 0; i < ncolor; i++)
+      pthread_join( creatures[i].ht, 0 );
+
+   /* print meeting times of each creature */
+   for (i = 0; i < ncolor; i++)
+   {
+      printf( "%s\n", Creature_getResult(&(creatures[i]), str) );
+      total += creatures[i].count;
+   }
+
+   /* print total meeting times, should equal n_meeting */
+   printf( "%s\n\n", formatNumber(total, str) );
+
+   /* cleaup & quit */
+   pthread_mutex_destroy( &place.mutex );
+   free( creatures );
+}
+
+
+void printColours( enum Colour c1, enum Colour c2 )
+{
+   printf( "%s + %s -> %s\n",
+      ColourName[c1],
+      ColourName[c2],
+      ColourName[doCompliment(c1, c2)]   );
+}
+
+void printColoursTable(void)
+{
+   printColours(blue, blue);
+   printColours(blue, red);
+   printColours(blue, yellow);
+   printColours(red, blue);
+   printColours(red, red);
+   printColours(red, yellow);
+   printColours(yellow, blue);
+   printColours(yellow, red);
+   printColours(yellow, yellow);
+}
+
+int main(int argc, char** argv)
+{
+   int n = (argc == 2) ? atoi(argv[1]) : 600;
+
+   printColoursTable();
+   printf("\n");
+
+   const enum Colour r1[] = {   blue, red, yellow   };
+   const enum Colour r2[] = {   blue, red, yellow,
+               red, yellow, blue,
+               red, yellow, red, blue   };
+
+   runGame( n, sizeof(r1) / sizeof(r1[0]), r1 );
+   runGame( n, sizeof(r2) / sizeof(r2[0]), r2 );
+
+   return 0;
+}
diff --git a/gcc/testsuite/go.test/test/bench/chameneosredux.go b/gcc/testsuite/go.test/test/bench/chameneosredux.go
new file mode 100644 (file)
index 0000000..2cb1440
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "strconv"
+)
+
+const (
+       blue = iota
+       red
+       yellow
+       ncol
+)
+
+var complement = [...]int{
+       red | red<<2: red,
+       red | yellow<<2: blue,
+       red | blue<<2: yellow,
+       yellow | red<<2: blue,
+       yellow | yellow<<2: yellow,
+       yellow | blue<<2: red,
+       blue | red<<2: yellow,
+       blue | yellow<<2: red,
+       blue | blue<<2: blue,
+}
+
+var colname = [...]string{
+       blue: "blue",
+       red: "red",
+       yellow: "yellow",
+}
+
+// information about the current state of a creature.
+type info struct {
+       colour int // creature's current colour.
+       name   int // creature's name.
+}
+
+// exclusive access data-structure kept inside meetingplace.
+// if mate is nil, it indicates there's no creature currently waiting;
+// otherwise the creature's info is stored in info, and
+// it is waiting to receive its mate's information on the mate channel.
+type rendez struct {
+       n    int         // current number of encounters.
+       mate chan<- info // creature waiting when non-nil.
+       info info        // info about creature waiting.
+}
+
+// result sent by each creature at the end of processing.
+type result struct {
+       met  int
+       same int
+}
+
+var n = 600
+
+func main() {
+       flag.Parse()
+       if flag.NArg() > 0 {
+               n, _ = strconv.Atoi(flag.Arg(0))
+       }
+
+       for c0 := 0; c0 < ncol; c0++ {
+               for c1 := 0; c1 < ncol; c1++ {
+                       fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
+               }
+       }
+       fmt.Print("\n")
+
+       pallmall([]int{blue, red, yellow})
+       pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue})
+}
+
+func pallmall(cols []int) {
+
+       // invariant: meetingplace always contains a value unless a creature
+       // is currently dealing with it (whereupon it must put it back).
+       meetingplace := make(chan rendez, 1)
+       meetingplace <- rendez{n: 0}
+
+       ended := make(chan result)
+       msg := ""
+       for i, col := range cols {
+               go creature(info{col, i}, meetingplace, ended)
+               msg += " " + colname[col]
+       }
+       fmt.Println(msg)
+       tot := 0
+       // wait for all results
+       for _ = range cols {
+               result := <-ended
+               tot += result.met
+               fmt.Printf("%v%v\n", result.met, spell(result.same, true))
+       }
+       fmt.Printf("%v\n\n", spell(tot, true))
+}
+
+// in this function, variables ending in 0 refer to the local creature,
+// variables ending in 1 to the creature we've met.
+func creature(info0 info, meetingplace chan rendez, ended chan result) {
+       c0 := make(chan info)
+       met := 0
+       same := 0
+       for {
+               var othername int
+               // get access to rendez data and decide what to do.
+               switch r := <-meetingplace; {
+               case r.n >= n:
+                       // if no more meetings left, then send our result data and exit.
+                       meetingplace <- rendez{n: r.n}
+                       ended <- result{met, same}
+                       return
+               case r.mate == nil:
+                       // no creature waiting; wait for someone to meet us,
+                       // get their info and send our info in reply.
+                       meetingplace <- rendez{n: r.n, info: info0, mate: c0}
+                       info1 := <-c0
+                       othername = info1.name
+                       info0.colour = complement[info0.colour|info1.colour<<2]
+               default:
+                       // another creature is waiting for us with its info;
+                       // increment meeting count,
+                       // send them our info in reply.
+                       r.n++
+                       meetingplace <- rendez{n: r.n, mate: nil}
+                       r.mate <- info0
+                       othername = r.info.name
+                       info0.colour = complement[info0.colour|r.info.colour<<2]
+               }
+               if othername == info0.name {
+                       same++
+               }
+               met++
+       }
+}
+
+var digits = [...]string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
+
+func spell(n int, required bool) string {
+       if n == 0 && !required {
+               return ""
+       }
+       return spell(n/10, false) + " " + digits[n%10]
+}
diff --git a/gcc/testsuite/go.test/test/bench/chameneosredux.txt b/gcc/testsuite/go.test/test/bench/chameneosredux.txt
new file mode 100644 (file)
index 0000000..6016d59
--- /dev/null
@@ -0,0 +1,29 @@
+blue + blue -> blue
+blue + red -> yellow
+blue + yellow -> red
+red + blue -> yellow
+red + red -> red
+red + yellow -> blue
+yellow + blue -> red
+yellow + red -> blue
+yellow + yellow -> yellow
+
+ blue red yellow
+400 zero
+400 zero
+400 zero
+ one two zero zero
+
+ blue red yellow red yellow blue red yellow red blue
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+ one two zero zero
+
diff --git a/gcc/testsuite/go.test/test/bench/clean.bash b/gcc/testsuite/go.test/test/bench/clean.bash
new file mode 100755 (executable)
index 0000000..d56c0e3
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+OS=568
+rm -f [$OS].out *.[$OS]
diff --git a/gcc/testsuite/go.test/test/bench/fannkuch-parallel.go b/gcc/testsuite/go.test/test/bench/fannkuch-parallel.go
new file mode 100644 (file)
index 0000000..7897eac
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on fannkuch.scala by Rex Kerr
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "runtime"
+)
+
+var n = flag.Int("n", 7, "count")
+var nCPU = flag.Int("ncpu", 2, "number of cpus")
+
+type Job struct {
+       start []int
+       n     int
+}
+
+type Found struct {
+       who *Kucher
+       k   int
+}
+
+type Kucher struct {
+       perm []int
+       temp []int
+       flip []int
+       in   chan Job
+}
+
+func NewKucher(length int) *Kucher {
+       return &Kucher{
+               perm: make([]int, length),
+               temp: make([]int, length),
+               flip: make([]int, length),
+               in:   make(chan Job),
+       }
+}
+
+func (k *Kucher) permute(n int) bool {
+       i := 0
+       for ; i < n-1 && k.flip[i] == 0; i++ {
+               t := k.perm[0]
+               j := 0
+               for ; j <= i; j++ {
+                       k.perm[j] = k.perm[j+1]
+               }
+               k.perm[j] = t
+       }
+       k.flip[i]--
+       for i > 0 {
+               i--
+               k.flip[i] = i
+       }
+       return k.flip[n-1] >= 0
+}
+
+func (k *Kucher) count() int {
+       K := 0
+       copy(k.temp, k.perm)
+       for k.temp[0] != 0 {
+               m := k.temp[0]
+               for i := 0; i < m; i++ {
+                       k.temp[i], k.temp[m] = k.temp[m], k.temp[i]
+                       m--
+               }
+               K++
+       }
+       return K
+}
+
+func (k *Kucher) Run(foreman chan<- Found) {
+       for job := range k.in {
+               verbose := 30
+               copy(k.perm, job.start)
+               for i, v := range k.perm {
+                       if v != i {
+                               verbose = 0
+                       }
+                       k.flip[i] = i
+               }
+               K := 0
+               for {
+                       if verbose > 0 {
+                               for _, p := range k.perm {
+                                       fmt.Print(p + 1)
+                               }
+                               fmt.Println()
+                               verbose--
+                       }
+                       count := k.count()
+                       if count > K {
+                               K = count
+                       }
+                       if !k.permute(job.n) {
+                               break
+                       }
+               }
+               foreman <- Found{k, K}
+       }
+}
+
+type Fanner struct {
+       jobind   int
+       jobsdone int
+       k        int
+       jobs     []Job
+       workers  []*Kucher
+       in       chan Found
+       result   chan int
+}
+
+func NewFanner(jobs []Job, workers []*Kucher) *Fanner {
+       return &Fanner{
+               jobs: jobs, workers: workers,
+               in:     make(chan Found),
+               result: make(chan int),
+       }
+}
+
+func (f *Fanner) Run(N int) {
+       for msg := range f.in {
+               if msg.k > f.k {
+                       f.k = msg.k
+               }
+               if msg.k >= 0 {
+                       f.jobsdone++
+               }
+               if f.jobind < len(f.jobs) {
+                       msg.who.in <- f.jobs[f.jobind]
+                       f.jobind++
+               } else if f.jobsdone == len(f.jobs) {
+                       f.result <- f.k
+                       return
+               }
+       }
+}
+
+func swapped(a []int, i, j int) []int {
+       b := make([]int, len(a))
+       copy(b, a)
+       b[i], b[j] = a[j], a[i]
+       return b
+}
+
+func main() {
+       flag.Parse()
+       runtime.GOMAXPROCS(*nCPU)
+       N := *n
+       base := make([]int, N)
+       for i := range base {
+               base[i] = i
+       }
+
+       njobs := 1
+       if N > 8 {
+               njobs += (N*(N-1))/2 - 28 // njobs = 1 + sum(8..N-1) = 1 + sum(1..N-1) - sum(1..7)
+       }
+       jobs := make([]Job, njobs)
+       jobsind := 0
+
+       firstN := N
+       if firstN > 8 {
+               firstN = 8
+       }
+       jobs[jobsind] = Job{base, firstN}
+       jobsind++
+       for i := N - 1; i >= 8; i-- {
+               for j := 0; j < i; j++ {
+                       jobs[jobsind] = Job{swapped(base, i, j), i}
+                       jobsind++
+               }
+       }
+
+       nworkers := *nCPU
+       if njobs < nworkers {
+               nworkers = njobs
+       }
+       workers := make([]*Kucher, nworkers)
+       foreman := NewFanner(jobs, workers)
+       go foreman.Run(N)
+       for i := range workers {
+               k := NewKucher(N)
+               workers[i] = k
+               go k.Run(foreman.in)
+               foreman.in <- Found{k, -1}
+       }
+       fmt.Printf("Pfannkuchen(%d) = %d\n", N, <-foreman.result)
+}
diff --git a/gcc/testsuite/go.test/test/bench/fannkuch-parallel.txt b/gcc/testsuite/go.test/test/bench/fannkuch-parallel.txt
new file mode 100644 (file)
index 0000000..e66f779
--- /dev/null
@@ -0,0 +1,31 @@
+1234567
+2134567
+2314567
+3214567
+3124567
+1324567
+2341567
+3241567
+3421567
+4321567
+4231567
+2431567
+3412567
+4312567
+4132567
+1432567
+1342567
+3142567
+4123567
+1423567
+1243567
+2143567
+2413567
+4213567
+2345167
+3245167
+3425167
+4325167
+4235167
+2435167
+Pfannkuchen(7) = 16
diff --git a/gcc/testsuite/go.test/test/bench/fannkuch.c b/gcc/testsuite/go.test/test/bench/fannkuch.c
new file mode 100644 (file)
index 0000000..e576b54
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Computer Language Shootout
+ * http://shootout.alioth.debian.org/
+ * Contributed by Heiner Marxen
+ *
+ * "fannkuch"  for C gcc
+ *
+ * $Id: fannkuch.1.gcc.code,v 1.15 2009-04-28 15:39:31 igouy-guest Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define Int    int
+#define Aint   int
+
+    static long
+fannkuch( int n )
+{
+    Aint*      perm;
+    Aint*      perm1;
+    Aint*      count;
+    long       flips;
+    long       flipsMax;
+    Int                r;
+    Int                i;
+    Int                k;
+    Int                didpr;
+    const Int  n1      = n - 1;
+
+    if( n < 1 ) return 0;
+
+    perm  = calloc(n, sizeof(*perm ));
+    perm1 = calloc(n, sizeof(*perm1));
+    count = calloc(n, sizeof(*count));
+
+    for( i=0 ; i<n ; ++i ) perm1[i] = i;       /* initial (trivial) permu */
+
+    r = n; didpr = 0; flipsMax = 0;
+    for(;;) {
+       if( didpr < 30 ) {
+           for( i=0 ; i<n ; ++i ) printf("%d", (int)(1+perm1[i]));
+           printf("\n");
+           ++didpr;
+       }
+       for( ; r!=1 ; --r ) {
+           count[r-1] = r;
+       }
+
+#define XCH(x,y)       { Aint t_mp; t_mp=(x); (x)=(y); (y)=t_mp; }
+
+       if( ! (perm1[0]==0 || perm1[n1]==n1) ) {
+           flips = 0;
+           for( i=1 ; i<n ; ++i ) {    /* perm = perm1 */
+               perm[i] = perm1[i];
+           }
+           k = perm1[0];               /* cache perm[0] in k */
+           do {                        /* k!=0 ==> k>0 */
+               Int     j;
+               for( i=1, j=k-1 ; i<j ; ++i, --j ) {
+                   XCH(perm[i], perm[j])
+               }
+               ++flips;
+               /*
+                * Now exchange k (caching perm[0]) and perm[k]... with care!
+                * XCH(k, perm[k]) does NOT work!
+                */
+               j=perm[k]; perm[k]=k ; k=j;
+           }while( k );
+           if( flipsMax < flips ) {
+               flipsMax = flips;
+           }
+       }
+
+       for(;;) {
+           if( r == n ) {
+               return flipsMax;
+           }
+           /* rotate down perm[0..r] by one */
+           {
+               Int     perm0 = perm1[0];
+               i = 0;
+               while( i < r ) {
+                   k = i+1;
+                   perm1[i] = perm1[k];
+                   i = k;
+               }
+               perm1[r] = perm0;
+           }
+           if( (count[r] -= 1) > 0 ) {
+               break;
+           }
+           ++r;
+       }
+    }
+}
+
+    int
+main( int argc, char* argv[] )
+{
+    int                n = (argc>1) ? atoi(argv[1]) : 0;
+
+    printf("Pfannkuchen(%d) = %ld\n", n, fannkuch(n));
+    return 0;
+}
diff --git a/gcc/testsuite/go.test/test/bench/fannkuch.go b/gcc/testsuite/go.test/test/bench/fannkuch.go
new file mode 100644 (file)
index 0000000..b554c77
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on fannkuch.c by Heiner Marxen
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+)
+
+var n = flag.Int("n", 7, "count")
+
+func fannkuch(n int) int {
+       if n < 1 {
+               return 0
+       }
+
+       n1 := n - 1
+       perm := make([]int, n)
+       perm1 := make([]int, n)
+       count := make([]int, n)
+
+       for i := 0; i < n; i++ {
+               perm1[i] = i // initial (trivial) permutation
+       }
+
+       r := n
+       didpr := 0
+       flipsMax := 0
+       for {
+               if didpr < 30 {
+                       for i := 0; i < n; i++ {
+                               fmt.Printf("%d", 1+perm1[i])
+                       }
+                       fmt.Printf("\n")
+                       didpr++
+               }
+               for ; r != 1; r-- {
+                       count[r-1] = r
+               }
+
+               if perm1[0] != 0 && perm1[n1] != n1 {
+                       flips := 0
+                       for i := 1; i < n; i++ { // perm = perm1
+                               perm[i] = perm1[i]
+                       }
+                       k := perm1[0] // cache perm[0] in k
+                       for {         // k!=0 ==> k>0
+                               for i, j := 1, k-1; i < j; i, j = i+1, j-1 {
+                                       perm[i], perm[j] = perm[j], perm[i]
+                               }
+                               flips++
+                               // Now exchange k (caching perm[0]) and perm[k]... with care!
+                               j := perm[k]
+                               perm[k] = k
+                               k = j
+                               if k == 0 {
+                                       break
+                               }
+                       }
+                       if flipsMax < flips {
+                               flipsMax = flips
+                       }
+               }
+
+               for ; r < n; r++ {
+                       // rotate down perm[0..r] by one
+                       perm0 := perm1[0]
+                       for i := 0; i < r; i++ {
+                               perm1[i] = perm1[i+1]
+                       }
+                       perm1[r] = perm0
+                       count[r]--
+                       if count[r] > 0 {
+                               break
+                       }
+               }
+               if r == n {
+                       return flipsMax
+               }
+       }
+       return 0
+}
+
+func main() {
+       flag.Parse()
+       fmt.Printf("Pfannkuchen(%d) = %d\n", *n, fannkuch(*n))
+}
diff --git a/gcc/testsuite/go.test/test/bench/fannkuch.txt b/gcc/testsuite/go.test/test/bench/fannkuch.txt
new file mode 100644 (file)
index 0000000..e66f779
--- /dev/null
@@ -0,0 +1,31 @@
+1234567
+2134567
+2314567
+3214567
+3124567
+1324567
+2341567
+3241567
+3421567
+4321567
+4231567
+2431567
+3412567
+4312567
+4132567
+1432567
+1342567
+3142567
+4123567
+1423567
+1243567
+2143567
+2413567
+4213567
+2345167
+3245167
+3425167
+4325167
+4235167
+2435167
+Pfannkuchen(7) = 16
diff --git a/gcc/testsuite/go.test/test/bench/fasta-1000.out b/gcc/testsuite/go.test/test/bench/fasta-1000.out
new file mode 100644 (file)
index 0000000..f1caba0
--- /dev/null
@@ -0,0 +1,171 @@
+>ONE Homo sapiens alu
+GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA
+TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT
+AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG
+GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG
+CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT
+GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA
+GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA
+TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG
+AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA
+GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT
+AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC
+AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG
+GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC
+CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG
+AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT
+TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA
+TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT
+GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG
+TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT
+CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG
+CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG
+TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA
+CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG
+AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG
+GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC
+TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA
+TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA
+GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT
+GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC
+ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT
+TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC
+CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG
+CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG
+GGCGACAGAGCGAGACTCCG
+>TWO IUB ambiguity codes
+cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg
+tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa
+NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt
+cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga
+gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa
+HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca
+tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt
+tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt
+acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct
+tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt
+gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa
+accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt
+RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt
+tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag
+cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg
+ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat
+actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg
+YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa
+KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata
+aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa
+aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg
+gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc
+tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK
+tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt
+ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg
+ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa
+BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt
+aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc
+tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc
+cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac
+aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga
+tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga
+aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD
+gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg
+ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV
+taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa
+ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat
+gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg
+gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa
+tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt
+tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt
+taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca
+cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag
+aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt
+cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt
+ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW
+attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag
+ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa
+attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc
+tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta
+>THREE Homo sapiens frequency
+aacacttcaccaggtatcgtgaaggctcaagattacccagagaacctttgcaatataaga
+atatgtatgcagcattaccctaagtaattatattctttttctgactcaaagtgacaagcc
+ctagtgtatattaaatcggtatatttgggaaattcctcaaactatcctaatcaggtagcc
+atgaaagtgatcaaaaaagttcgtacttataccatacatgaattctggccaagtaaaaaa
+tagattgcgcaaaattcgtaccttaagtctctcgccaagatattaggatcctattactca
+tatcgtgtttttctttattgccgccatccccggagtatctcacccatccttctcttaaag
+gcctaatattacctatgcaaataaacatatattgttgaaaattgagaacctgatcgtgat
+tcttatgtgtaccatatgtatagtaatcacgcgactatatagtgctttagtatcgcccgt
+gggtgagtgaatattctgggctagcgtgagatagtttcttgtcctaatatttttcagatc
+gaatagcttctatttttgtgtttattgacatatgtcgaaactccttactcagtgaaagtc
+atgaccagatccacgaacaatcttcggaatcagtctcgttttacggcggaatcttgagtc
+taacttatatcccgtcgcttactttctaacaccccttatgtatttttaaaattacgttta
+ttcgaacgtacttggcggaagcgttattttttgaagtaagttacattgggcagactcttg
+acattttcgatacgactttctttcatccatcacaggactcgttcgtattgatatcagaag
+ctcgtgatgattagttgtcttctttaccaatactttgaggcctattctgcgaaatttttg
+ttgccctgcgaacttcacataccaaggaacacctcgcaacatgccttcatatccatcgtt
+cattgtaattcttacacaatgaatcctaagtaattacatccctgcgtaaaagatggtagg
+ggcactgaggatatattaccaagcatttagttatgagtaatcagcaatgtttcttgtatt
+aagttctctaaaatagttacatcgtaatgttatctcgggttccgcgaataaacgagatag
+attcattatatatggccctaagcaaaaacctcctcgtattctgttggtaattagaatcac
+acaatacgggttgagatattaattatttgtagtacgaagagatataaaaagatgaacaat
+tactcaagtcaagatgtatacgggatttataataaaaatcgggtagagatctgctttgca
+attcagacgtgccactaaatcgtaatatgtcgcgttacatcagaaagggtaactattatt
+aattaataaagggcttaatcactacatattagatcttatccgatagtcttatctattcgt
+tgtatttttaagcggttctaattcagtcattatatcagtgctccgagttctttattattg
+ttttaaggatgacaaaatgcctcttgttataacgctgggagaagcagactaagagtcgga
+gcagttggtagaatgaggctgcaaaagacggtctcgacgaatggacagactttactaaac
+caatgaaagacagaagtagagcaaagtctgaagtggtatcagcttaattatgacaaccct
+taatacttccctttcgccgaatactggcgtggaaaggttttaaaagtcgaagtagttaga
+ggcatctctcgctcataaataggtagactactcgcaatccaatgtgactatgtaatactg
+ggaacatcagtccgcgatgcagcgtgtttatcaaccgtccccactcgcctggggagacat
+gagaccacccccgtggggattattagtccgcagtaatcgactcttgacaatccttttcga
+ttatgtcatagcaatttacgacagttcagcgaagtgactactcggcgaaatggtattact
+aaagcattcgaacccacatgaatgtgattcttggcaatttctaatccactaaagcttttc
+cgttgaatctggttgtagatatttatataagttcactaattaagatcacggtagtatatt
+gatagtgatgtctttgcaagaggttggccgaggaatttacggattctctattgatacaat
+ttgtctggcttataactcttaaggctgaaccaggcgtttttagacgacttgatcagctgt
+tagaatggtttggactccctctttcatgtcagtaacatttcagccgttattgttacgata
+tgcttgaacaatattgatctaccacacacccatagtatattttataggtcatgctgttac
+ctacgagcatggtattccacttcccattcaatgagtattcaacatcactagcctcagaga
+tgatgacccacctctaataacgtcacgttgcggccatgtgaaacctgaacttgagtagac
+gatatcaagcgctttaaattgcatataacatttgagggtaaagctaagcggatgctttat
+ataatcaatactcaataataagatttgattgcattttagagttatgacacgacatagttc
+actaacgagttactattcccagatctagactgaagtactgatcgagacgatccttacgtc
+gatgatcgttagttatcgacttaggtcgggtctctagcggtattggtacttaaccggaca
+ctatactaataacccatgatcaaagcataacagaatacagacgataatttcgccaacata
+tatgtacagaccccaagcatgagaagctcattgaaagctatcattgaagtcccgctcaca
+atgtgtcttttccagacggtttaactggttcccgggagtcctggagtttcgacttacata
+aatggaaacaatgtattttgctaatttatctatagcgtcatttggaccaatacagaatat
+tatgttgcctagtaatccactataacccgcaagtgctgatagaaaatttttagacgattt
+ataaatgccccaagtatccctcccgtgaatcctccgttatactaattagtattcgttcat
+acgtataccgcgcatatatgaacatttggcgataaggcgcgtgaattgttacgtgacaga
+gatagcagtttcttgtgatatggttaacagacgtacatgaagggaaactttatatctata
+gtgatgcttccgtagaaataccgccactggtctgccaatgatgaagtatgtagctttagg
+tttgtactatgaggctttcgtttgtttgcagagtataacagttgcgagtgaaaaaccgac
+gaatttatactaatacgctttcactattggctacaaaatagggaagagtttcaatcatga
+gagggagtatatggatgctttgtagctaaaggtagaacgtatgtatatgctgccgttcat
+tcttgaaagatacataagcgataagttacgacaattataagcaacatccctaccttcgta
+acgatttcactgttactgcgcttgaaatacactatggggctattggcggagagaagcaga
+tcgcgccgagcatatacgagacctataatgttgatgatagagaaggcgtctgaattgata
+catcgaagtacactttctttcgtagtatctctcgtcctctttctatctccggacacaaga
+attaagttatatatatagagtcttaccaatcatgttgaatcctgattctcagagttcttt
+ggcgggccttgtgatgactgagaaacaatgcaatattgctccaaatttcctaagcaaatt
+ctcggttatgttatgttatcagcaaagcgttacgttatgttatttaaatctggaatgacg
+gagcgaagttcttatgtcggtgtgggaataattcttttgaagacagcactccttaaataa
+tatcgctccgtgtttgtatttatcgaatgggtctgtaaccttgcacaagcaaatcggtgg
+tgtatatatcggataacaattaatacgatgttcatagtgacagtatactgatcgagtcct
+ctaaagtcaattacctcacttaacaatctcattgatgttgtgtcattcccggtatcgccc
+gtagtatgtgctctgattgaccgagtgtgaaccaaggaacatctactaatgcctttgtta
+ggtaagatctctctgaattccttcgtgccaacttaaaacattatcaaaatttcttctact
+tggattaactacttttacgagcatggcaaattcccctgtggaagacggttcattattatc
+ggaaaccttatagaaattgcgtgttgactgaaattagatttttattgtaagagttgcatc
+tttgcgattcctctggtctagcttccaatgaacagtcctcccttctattcgacatcgggt
+ccttcgtacatgtctttgcgatgtaataattaggttcggagtgtggccttaatgggtgca
+actaggaatacaacgcaaatttgctgacatgatagcaaatcggtatgccggcaccaaaac
+gtgctccttgcttagcttgtgaatgagactcagtagttaaataaatccatatctgcaatc
+gattccacaggtattgtccactatctttgaactactctaagagatacaagcttagctgag
+accgaggtgtatatgactacgctgatatctgtaaggtaccaatgcaggcaaagtatgcga
+gaagctaataccggctgtttccagctttataagattaaaatttggctgtcctggcggcct
+cagaattgttctatcgtaatcagttggttcattaattagctaagtacgaggtacaactta
+tctgtcccagaacagctccacaagtttttttacagccgaaacccctgtgtgaatcttaat
+atccaagcgcgttatctgattagagtttacaactcagtattttatcagtacgttttgttt
+ccaacattacccggtatgacaaaatgacgccacgtgtcgaataatggtctgaccaatgta
+ggaagtgaaaagataaatat
diff --git a/gcc/testsuite/go.test/test/bench/fasta.c b/gcc/testsuite/go.test/test/bench/fasta.c
new file mode 100644 (file)
index 0000000..78a8490
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * http://shootout.alioth.debian.org/u32/program.php?test=fasta&lang=gcc&id=3
+ */
+
+/*  The Computer Language Benchmarks Game
+ *  http://shootout.alioth.debian.org/
+ *
+ *  contributed by Petr Prokhorenkov
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// not available on OS X 
+#define fwrite_unlocked fwrite
+#define fputc_unlocked fputc
+#define fputs_unlocked fputs
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#define unlikely(x) __builtin_expect((x), 0)
+
+#define IM 139968
+#define IA 3877
+#define IC 29573
+
+#define LINE_LEN 60
+#define LOOKUP_SIZE 4096
+#define LOOKUP_SCALE ((float)(LOOKUP_SIZE - 1))
+
+typedef unsigned random_t;
+
+void
+random_init(random_t *random) {
+    *random = 42;
+}
+
+// Special version with result rescaled to LOOKUP_SCALE.
+static inline
+float
+random_next_lookup(random_t *random) {
+    *random = (*random*IA + IC)%IM;
+
+    return (*random)*(LOOKUP_SCALE/IM);
+}
+
+struct amino_acid {
+   char sym;
+   float prob;
+   float cprob_lookup;
+};
+
+void
+repeat(const char *alu, const char *title, int n) {
+    int len = strlen(alu);
+    char buffer[len + LINE_LEN];
+    int pos = 0;
+
+    memcpy(buffer, alu, len);
+    memcpy(buffer + len, alu, LINE_LEN);
+
+    fputs_unlocked(title, stdout);
+    while (n > 0) {
+        int bytes = n > LINE_LEN ? LINE_LEN : n;
+
+        fwrite_unlocked(buffer + pos, bytes, 1, stdout);
+        pos += bytes;
+        if (pos > len) {
+            pos -= len;
+        }
+        fputc_unlocked('\n', stdout);
+        n -= bytes;
+    }
+}
+
+/*
+ * Lookup table contains mapping from real values to cumulative
+ * probabilities. Careful selection of table size allows lookup
+ * virtually in constant time.
+ *
+ * All cumulative probabilities are rescaled to LOOKUP_SCALE,
+ * this allows to save one multiplication operation on each iteration
+ * in randomize().
+ */
+
+void *
+fill_lookup(struct amino_acid **lookup, struct amino_acid *amino_acid, int amino_acid_size) {
+    float p = 0;
+    int i, j;
+
+    for (i = 0; i < amino_acid_size; i++) {
+        p += amino_acid[i].prob;
+        amino_acid[i].cprob_lookup = p*LOOKUP_SCALE;
+    }
+
+    // Prevent rounding error.
+    amino_acid[amino_acid_size - 1].cprob_lookup = LOOKUP_SIZE - 1;
+
+    for (i = 0, j = 0; i < LOOKUP_SIZE; i++) {
+        while (amino_acid[j].cprob_lookup < i) {
+            j++;
+        }
+        lookup[i] = &amino_acid[j];
+    }
+
+    return 0;
+}
+
+void
+randomize(struct amino_acid *amino_acid, int amino_acid_size,
+        const char *title, int n, random_t *rand) {
+    struct amino_acid *lookup[LOOKUP_SIZE];
+    char line_buffer[LINE_LEN + 1];
+    int i, j;
+
+    line_buffer[LINE_LEN] = '\n';
+
+    fill_lookup(lookup, amino_acid, amino_acid_size);
+
+    fputs_unlocked(title, stdout);
+
+    for (i = 0, j = 0; i < n; i++, j++) {
+        if (j == LINE_LEN) {
+            fwrite_unlocked(line_buffer, LINE_LEN + 1, 1, stdout);
+            j = 0;
+        }
+
+        float r = random_next_lookup(rand);
+        struct amino_acid *u = lookup[(short)r];
+        while (unlikely(u->cprob_lookup < r)) {
+            ++u;
+        }
+        line_buffer[j] = u->sym;
+    }
+    line_buffer[j] = '\n';
+    fwrite_unlocked(line_buffer, j + 1, 1, stdout);
+}
+
+struct amino_acid amino_acid[] = {
+   { '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 },
+};
+
+struct amino_acid homo_sapiens[] = {
+   { 'a', 0.3029549426680 },
+   { 'c', 0.1979883004921 },
+   { 'g', 0.1975473066391 },
+   { 't', 0.3015094502008 },
+};
+
+static const char alu[] =
+   "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG"
+   "GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA"
+   "GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA"
+   "AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT"
+   "CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC"
+   "CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG"
+   "CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
+
+int
+main(int argc, const char **argv) {
+    int n = argc > 1 ? atoi( argv[1] ) : 512;
+    random_t rand;
+
+    random_init(&rand);
+
+    repeat(alu, ">ONE Homo sapiens alu\n", n*2);
+    randomize(amino_acid, ARRAY_SIZE(amino_acid),
+            ">TWO IUB ambiguity codes\n", n*3, &rand);
+    randomize(homo_sapiens, ARRAY_SIZE(homo_sapiens),
+            ">THREE Homo sapiens frequency\n", n*5, &rand);
+
+    return 0;
+}
\ No newline at end of file
diff --git a/gcc/testsuite/go.test/test/bench/fasta.go b/gcc/testsuite/go.test/test/bench/fasta.go
new file mode 100644 (file)
index 0000000..470bdb3
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on C program by by Petr Prokhorenkov.
+ */
+
+package main
+
+import (
+       "bytes"
+       "flag"
+       "os"
+)
+
+var out = make(buffer, 0, 32768)
+
+var n = flag.Int("n", 1000, "length of result")
+
+const Line = 60
+
+func Repeat(alu []byte, n int) {
+       buf := bytes.Add(alu, alu)
+       off := 0
+       for n > 0 {
+               m := n
+               if m > Line {
+                       m = Line
+               }
+               buf1 := out.NextWrite(m + 1)
+               copy(buf1, buf[off:])
+               buf1[m] = '\n'
+               if off += m; off >= len(alu) {
+                       off -= len(alu)
+               }
+               n -= m
+       }
+}
+
+const (
+       IM = 139968
+       IA = 3877
+       IC = 29573
+
+       LookupSize  = 4096
+       LookupScale float64 = LookupSize - 1
+)
+
+var rand uint32 = 42
+
+type Acid struct {
+       sym   byte
+       prob  float64
+       cprob float64
+       next  *Acid
+}
+
+func computeLookup(acid []Acid) *[LookupSize]*Acid {
+       var lookup [LookupSize]*Acid
+       var p float64
+       for i := range acid {
+               p += acid[i].prob
+               acid[i].cprob = p * LookupScale
+               if i > 0 {
+                       acid[i-1].next = &acid[i]
+               }
+       }
+       acid[len(acid)-1].cprob = 1.0 * LookupScale
+
+       j := 0
+       for i := range lookup {
+               for acid[j].cprob < float64(i) {
+                       j++
+               }
+               lookup[i] = &acid[j]
+       }
+
+       return &lookup
+}
+
+func Random(acid []Acid, n int) {
+       lookup := computeLookup(acid)
+       for n > 0 {
+               m := n
+               if m > Line {
+                       m = Line
+               }
+               buf := out.NextWrite(m + 1)
+               f := LookupScale / IM
+               myrand := rand
+               for i := 0; i < m; i++ {
+                       myrand = (myrand*IA + IC) % IM
+                       r := float64(int(myrand)) * f
+                       a := lookup[int(r)]
+                       for a.cprob < r {
+                               a = a.next
+                       }
+                       buf[i] = a.sym
+               }
+               rand = myrand
+               buf[m] = '\n'
+               n -= m
+       }
+}
+
+func main() {
+       defer out.Flush()
+
+       flag.Parse()
+
+       iub := []Acid{
+               Acid{prob: 0.27, sym: 'a'},
+               Acid{prob: 0.12, sym: 'c'},
+               Acid{prob: 0.12, sym: 'g'},
+               Acid{prob: 0.27, sym: 't'},
+               Acid{prob: 0.02, sym: 'B'},
+               Acid{prob: 0.02, sym: 'D'},
+               Acid{prob: 0.02, sym: 'H'},
+               Acid{prob: 0.02, sym: 'K'},
+               Acid{prob: 0.02, sym: 'M'},
+               Acid{prob: 0.02, sym: 'N'},
+               Acid{prob: 0.02, sym: 'R'},
+               Acid{prob: 0.02, sym: 'S'},
+               Acid{prob: 0.02, sym: 'V'},
+               Acid{prob: 0.02, sym: 'W'},
+               Acid{prob: 0.02, sym: 'Y'},
+       }
+
+       homosapiens := []Acid{
+               Acid{prob: 0.3029549426680, sym: 'a'},
+               Acid{prob: 0.1979883004921, sym: 'c'},
+               Acid{prob: 0.1975473066391, sym: 'g'},
+               Acid{prob: 0.3015094502008, sym: 't'},
+       }
+
+       alu := []byte(
+               "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
+                       "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" +
+                       "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" +
+                       "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
+                       "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
+                       "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
+                       "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA")
+
+       out.WriteString(">ONE Homo sapiens alu\n")
+       Repeat(alu, 2**n)
+       out.WriteString(">TWO IUB ambiguity codes\n")
+       Random(iub, 3**n)
+       out.WriteString(">THREE Homo sapiens frequency\n")
+       Random(homosapiens, 5**n)
+}
+
+
+type buffer []byte
+
+func (b *buffer) Flush() {
+       p := *b
+       if len(p) > 0 {
+               os.Stdout.Write(p)
+       }
+       *b = p[0:0]
+}
+
+func (b *buffer) WriteString(s string) {
+       p := b.NextWrite(len(s))
+       for i := 0; i < len(s); i++ {
+               p[i] = s[i]
+       }
+}
+
+func (b *buffer) NextWrite(n int) []byte {
+       p := *b
+       if len(p)+n > cap(p) {
+               b.Flush()
+               p = *b
+       }
+       out := p[len(p) : len(p)+n]
+       *b = p[0 : len(p)+n]
+       return out
+}
diff --git a/gcc/testsuite/go.test/test/bench/fasta.txt b/gcc/testsuite/go.test/test/bench/fasta.txt
new file mode 100644 (file)
index 0000000..f1caba0
--- /dev/null
@@ -0,0 +1,171 @@
+>ONE Homo sapiens alu
+GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA
+TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT
+AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG
+GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG
+CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT
+GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA
+GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA
+TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG
+AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA
+GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT
+AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC
+AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG
+GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC
+CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG
+AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT
+TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA
+TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT
+GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG
+TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT
+CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG
+CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG
+TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA
+CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG
+AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG
+GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC
+TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA
+TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA
+GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT
+GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC
+ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT
+TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC
+CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG
+CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG
+GGCGACAGAGCGAGACTCCG
+>TWO IUB ambiguity codes
+cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg
+tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa
+NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt
+cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga
+gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa
+HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca
+tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt
+tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt
+acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct
+tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt
+gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa
+accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt
+RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt
+tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag
+cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg
+ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat
+actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg
+YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa
+KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata
+aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa
+aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg
+gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc
+tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK
+tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt
+ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg
+ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa
+BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt
+aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc
+tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc
+cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac
+aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga
+tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga
+aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD
+gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg
+ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV
+taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa
+ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat
+gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg
+gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa
+tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt
+tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt
+taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca
+cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag
+aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt
+cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt
+ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW
+attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag
+ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa
+attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc
+tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta
+>THREE Homo sapiens frequency
+aacacttcaccaggtatcgtgaaggctcaagattacccagagaacctttgcaatataaga
+atatgtatgcagcattaccctaagtaattatattctttttctgactcaaagtgacaagcc
+ctagtgtatattaaatcggtatatttgggaaattcctcaaactatcctaatcaggtagcc
+atgaaagtgatcaaaaaagttcgtacttataccatacatgaattctggccaagtaaaaaa
+tagattgcgcaaaattcgtaccttaagtctctcgccaagatattaggatcctattactca
+tatcgtgtttttctttattgccgccatccccggagtatctcacccatccttctcttaaag
+gcctaatattacctatgcaaataaacatatattgttgaaaattgagaacctgatcgtgat
+tcttatgtgtaccatatgtatagtaatcacgcgactatatagtgctttagtatcgcccgt
+gggtgagtgaatattctgggctagcgtgagatagtttcttgtcctaatatttttcagatc
+gaatagcttctatttttgtgtttattgacatatgtcgaaactccttactcagtgaaagtc
+atgaccagatccacgaacaatcttcggaatcagtctcgttttacggcggaatcttgagtc
+taacttatatcccgtcgcttactttctaacaccccttatgtatttttaaaattacgttta
+ttcgaacgtacttggcggaagcgttattttttgaagtaagttacattgggcagactcttg
+acattttcgatacgactttctttcatccatcacaggactcgttcgtattgatatcagaag
+ctcgtgatgattagttgtcttctttaccaatactttgaggcctattctgcgaaatttttg
+ttgccctgcgaacttcacataccaaggaacacctcgcaacatgccttcatatccatcgtt
+cattgtaattcttacacaatgaatcctaagtaattacatccctgcgtaaaagatggtagg
+ggcactgaggatatattaccaagcatttagttatgagtaatcagcaatgtttcttgtatt
+aagttctctaaaatagttacatcgtaatgttatctcgggttccgcgaataaacgagatag
+attcattatatatggccctaagcaaaaacctcctcgtattctgttggtaattagaatcac
+acaatacgggttgagatattaattatttgtagtacgaagagatataaaaagatgaacaat
+tactcaagtcaagatgtatacgggatttataataaaaatcgggtagagatctgctttgca
+attcagacgtgccactaaatcgtaatatgtcgcgttacatcagaaagggtaactattatt
+aattaataaagggcttaatcactacatattagatcttatccgatagtcttatctattcgt
+tgtatttttaagcggttctaattcagtcattatatcagtgctccgagttctttattattg
+ttttaaggatgacaaaatgcctcttgttataacgctgggagaagcagactaagagtcgga
+gcagttggtagaatgaggctgcaaaagacggtctcgacgaatggacagactttactaaac
+caatgaaagacagaagtagagcaaagtctgaagtggtatcagcttaattatgacaaccct
+taatacttccctttcgccgaatactggcgtggaaaggttttaaaagtcgaagtagttaga
+ggcatctctcgctcataaataggtagactactcgcaatccaatgtgactatgtaatactg
+ggaacatcagtccgcgatgcagcgtgtttatcaaccgtccccactcgcctggggagacat
+gagaccacccccgtggggattattagtccgcagtaatcgactcttgacaatccttttcga
+ttatgtcatagcaatttacgacagttcagcgaagtgactactcggcgaaatggtattact
+aaagcattcgaacccacatgaatgtgattcttggcaatttctaatccactaaagcttttc
+cgttgaatctggttgtagatatttatataagttcactaattaagatcacggtagtatatt
+gatagtgatgtctttgcaagaggttggccgaggaatttacggattctctattgatacaat
+ttgtctggcttataactcttaaggctgaaccaggcgtttttagacgacttgatcagctgt
+tagaatggtttggactccctctttcatgtcagtaacatttcagccgttattgttacgata
+tgcttgaacaatattgatctaccacacacccatagtatattttataggtcatgctgttac
+ctacgagcatggtattccacttcccattcaatgagtattcaacatcactagcctcagaga
+tgatgacccacctctaataacgtcacgttgcggccatgtgaaacctgaacttgagtagac
+gatatcaagcgctttaaattgcatataacatttgagggtaaagctaagcggatgctttat
+ataatcaatactcaataataagatttgattgcattttagagttatgacacgacatagttc
+actaacgagttactattcccagatctagactgaagtactgatcgagacgatccttacgtc
+gatgatcgttagttatcgacttaggtcgggtctctagcggtattggtacttaaccggaca
+ctatactaataacccatgatcaaagcataacagaatacagacgataatttcgccaacata
+tatgtacagaccccaagcatgagaagctcattgaaagctatcattgaagtcccgctcaca
+atgtgtcttttccagacggtttaactggttcccgggagtcctggagtttcgacttacata
+aatggaaacaatgtattttgctaatttatctatagcgtcatttggaccaatacagaatat
+tatgttgcctagtaatccactataacccgcaagtgctgatagaaaatttttagacgattt
+ataaatgccccaagtatccctcccgtgaatcctccgttatactaattagtattcgttcat
+acgtataccgcgcatatatgaacatttggcgataaggcgcgtgaattgttacgtgacaga
+gatagcagtttcttgtgatatggttaacagacgtacatgaagggaaactttatatctata
+gtgatgcttccgtagaaataccgccactggtctgccaatgatgaagtatgtagctttagg
+tttgtactatgaggctttcgtttgtttgcagagtataacagttgcgagtgaaaaaccgac
+gaatttatactaatacgctttcactattggctacaaaatagggaagagtttcaatcatga
+gagggagtatatggatgctttgtagctaaaggtagaacgtatgtatatgctgccgttcat
+tcttgaaagatacataagcgataagttacgacaattataagcaacatccctaccttcgta
+acgatttcactgttactgcgcttgaaatacactatggggctattggcggagagaagcaga
+tcgcgccgagcatatacgagacctataatgttgatgatagagaaggcgtctgaattgata
+catcgaagtacactttctttcgtagtatctctcgtcctctttctatctccggacacaaga
+attaagttatatatatagagtcttaccaatcatgttgaatcctgattctcagagttcttt
+ggcgggccttgtgatgactgagaaacaatgcaatattgctccaaatttcctaagcaaatt
+ctcggttatgttatgttatcagcaaagcgttacgttatgttatttaaatctggaatgacg
+gagcgaagttcttatgtcggtgtgggaataattcttttgaagacagcactccttaaataa
+tatcgctccgtgtttgtatttatcgaatgggtctgtaaccttgcacaagcaaatcggtgg
+tgtatatatcggataacaattaatacgatgttcatagtgacagtatactgatcgagtcct
+ctaaagtcaattacctcacttaacaatctcattgatgttgtgtcattcccggtatcgccc
+gtagtatgtgctctgattgaccgagtgtgaaccaaggaacatctactaatgcctttgtta
+ggtaagatctctctgaattccttcgtgccaacttaaaacattatcaaaatttcttctact
+tggattaactacttttacgagcatggcaaattcccctgtggaagacggttcattattatc
+ggaaaccttatagaaattgcgtgttgactgaaattagatttttattgtaagagttgcatc
+tttgcgattcctctggtctagcttccaatgaacagtcctcccttctattcgacatcgggt
+ccttcgtacatgtctttgcgatgtaataattaggttcggagtgtggccttaatgggtgca
+actaggaatacaacgcaaatttgctgacatgatagcaaatcggtatgccggcaccaaaac
+gtgctccttgcttagcttgtgaatgagactcagtagttaaataaatccatatctgcaatc
+gattccacaggtattgtccactatctttgaactactctaagagatacaagcttagctgag
+accgaggtgtatatgactacgctgatatctgtaaggtaccaatgcaggcaaagtatgcga
+gaagctaataccggctgtttccagctttataagattaaaatttggctgtcctggcggcct
+cagaattgttctatcgtaatcagttggttcattaattagctaagtacgaggtacaactta
+tctgtcccagaacagctccacaagtttttttacagccgaaacccctgtgtgaatcttaat
+atccaagcgcgttatctgattagagtttacaactcagtattttatcagtacgttttgttt
+ccaacattacccggtatgacaaaatgacgccacgtgtcgaataatggtctgaccaatgta
+ggaagtgaaaagataaatat
diff --git a/gcc/testsuite/go.test/test/bench/k-nucleotide-parallel.go b/gcc/testsuite/go.test/test/bench/k-nucleotide-parallel.go
new file mode 100644 (file)
index 0000000..0234f33
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "sort"
+)
+
+func count(data string, n int) map[string]int {
+       counts := make(map[string]int)
+       top := len(data) - n
+       for i := 0; i <= top; i++ {
+               s := data[i : i+n]
+               counts[s]++
+       }
+       return counts
+}
+
+func countOne(data string, s string) int {
+       return count(data, len(s))[s]
+}
+
+type kNuc struct {
+       name  string
+       count int
+}
+
+type kNucArray []kNuc
+
+func (kn kNucArray) Len() int      { return len(kn) }
+func (kn kNucArray) Swap(i, j int) { kn[i], kn[j] = kn[j], kn[i] }
+func (kn kNucArray) Less(i, j int) bool {
+       if kn[i].count == kn[j].count {
+               return kn[i].name > kn[j].name // sort down
+       }
+       return kn[i].count > kn[j].count
+}
+
+func sortedArray(m map[string]int) kNucArray {
+       kn := make(kNucArray, len(m))
+       i := 0
+       for k, v := range m {
+               kn[i] = kNuc{k, v}
+               i++
+       }
+       sort.Sort(kn)
+       return kn
+}
+
+func printKnucs(a kNucArray) {
+       sum := 0
+       for _, kn := range a {
+               sum += kn.count
+       }
+       for _, kn := range a {
+               fmt.Printf("%s %.3f\n", kn.name, 100*float64(kn.count)/float64(sum))
+       }
+       fmt.Print("\n")
+}
+
+func main() {
+       in := bufio.NewReader(os.Stdin)
+       three := []byte(">THREE ")
+       for {
+               line, err := in.ReadSlice('\n')
+               if err != nil {
+                       fmt.Fprintln(os.Stderr, "ReadLine err:", err)
+                       os.Exit(2)
+               }
+               if line[0] == '>' && bytes.Equal(line[0:len(three)], three) {
+                       break
+               }
+       }
+       data, err := ioutil.ReadAll(in)
+       if err != nil {
+               fmt.Fprintln(os.Stderr, "ReadAll err:", err)
+               os.Exit(2)
+       }
+       // delete the newlines and convert to upper case
+       j := 0
+       for i := 0; i < len(data); i++ {
+               if data[i] != '\n' {
+                       data[j] = data[i] &^ ' ' // upper case
+                       j++
+               }
+       }
+       str := string(data[0:j])
+
+       var arr1, arr2 kNucArray
+       countsdone := make(chan bool)
+       go func() {
+               arr1 = sortedArray(count(str, 1))
+               countsdone <- true
+       }()
+       go func() {
+               arr2 = sortedArray(count(str, 2))
+               countsdone <- true
+       }()
+
+       interests := []string{"GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT"}
+       results := make([]chan string, len(interests))
+       for i, s := range interests {
+               ch := make(chan string)
+               results[i] = ch
+               go func(result chan string, ss string) {
+                       result <- fmt.Sprintf("%d %s\n", countOne(str, ss), ss)
+               }(ch, s)
+       }
+       <-countsdone
+       <-countsdone
+       printKnucs(arr1)
+       printKnucs(arr2)
+       for _, rc := range results {
+               fmt.Print(<-rc)
+       }
+
+}
diff --git a/gcc/testsuite/go.test/test/bench/k-nucleotide-parallel.txt b/gcc/testsuite/go.test/test/bench/k-nucleotide-parallel.txt
new file mode 100644 (file)
index 0000000..84169b8
--- /dev/null
@@ -0,0 +1,27 @@
+T 31.520
+A 29.600
+C 19.480
+G 19.400
+
+AT 9.922
+TT 9.602
+TA 9.402
+AA 8.402
+GA 6.321
+TC 6.301
+TG 6.201
+GT 6.041
+CT 5.961
+AG 5.841
+CA 5.461
+AC 5.441
+CC 4.041
+CG 4.021
+GC 3.701
+GG 3.341
+
+54 GGT
+24 GGTA
+4 GGTATT
+0 GGTATTTTAATT
+0 GGTATTTTAATTTATAGT
diff --git a/gcc/testsuite/go.test/test/bench/k-nucleotide.c b/gcc/testsuite/go.test/test/bench/k-nucleotide.c
new file mode 100644 (file)
index 0000000..3bace39
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <glib.h>
+
+typedef struct stat_s stat_t;
+struct stat_s
+{
+   const gchar *key;
+   long stat;
+};
+
+#define MAX_ELM (8192 / sizeof (stat_t))
+
+static int
+generate_frequencies (int fl, char *buffer, long buflen,
+                     GHashTable *ht, GTrashStack **ts, GPtrArray *roots, GStringChunk *sc)
+{
+   gchar *key;
+   long i;
+
+   if (fl > buflen) return 0;
+   if (fl == 0) return 0;
+
+   for (i = 0; i < buflen - fl + 1; ++i)
+     {
+       char nulled;
+       stat_t *stat;
+
+       nulled = buffer[i + fl];
+       buffer[i + fl] = '\0';
+
+       key = g_string_chunk_insert_const(sc, buffer + i);
+
+       stat = g_hash_table_lookup(ht, key);
+       if (!stat)
+         {
+            stat = g_trash_stack_pop(ts);
+            if (!stat)
+              {
+                 int j;
+
+                 stat = malloc(sizeof (stat_t) * MAX_ELM);
+                 g_ptr_array_add(roots, stat);
+
+                 for (j = 1; j < MAX_ELM; ++j)
+                   g_trash_stack_push(ts, stat + j);
+              }
+            stat->stat = 1;
+            stat->key = key;
+
+            g_hash_table_insert(ht, key, stat);
+         }
+       else
+         stat->stat++;
+
+       buffer[i + fl] = nulled;
+     }
+
+   return buflen - fl + 1;
+}
+
+static int
+cmp_func(gconstpointer a, gconstpointer b)
+{
+   const stat_t *left = a;
+   const stat_t *right = b;
+
+   return right->stat - left->stat;
+}
+
+static void
+sorted_list(gpointer key, gpointer value, gpointer user_data)
+{
+   stat_t *data = value;
+   GList **lst = user_data;
+
+   *lst = g_list_insert_sorted(*lst, data, cmp_func);
+}
+
+static void
+display_stat(gpointer data, gpointer user_data)
+{
+   long *total = user_data;
+   stat_t *st = data;
+
+   printf("%s %.3f\n", st->key, 100 * (float) st->stat / *total);
+}
+
+void
+write_frequencies (int fl, char *buffer, long buflen, GTrashStack **ts, GPtrArray *roots)
+{
+   GStringChunk *sc;
+   GHashTable *ht;
+   GList *lst;
+   long total;
+
+   ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL /* free key */, NULL /* free value */);
+   sc = g_string_chunk_new(buflen);
+   lst = NULL;
+
+   total = generate_frequencies (fl, buffer, buflen, ht, ts, roots, sc);
+
+   if (!total) goto on_error;
+
+   g_hash_table_foreach(ht, sorted_list, &lst);
+   g_list_foreach(lst, display_stat, &total);
+   g_list_free(lst);
+
+ on_error:
+   g_hash_table_destroy(ht);
+   g_string_chunk_free(sc);
+}
+
+void
+write_count (char *searchFor, char *buffer, long buflen, GTrashStack **ts, GPtrArray *roots)
+{
+   GStringChunk *sc;
+   GHashTable *ht;
+   stat_t *result;
+   GList *lst;
+   long total;
+   long fl;
+
+   fl = strlen(searchFor);
+
+   ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL /* free key */, NULL /* free value */);
+   sc = g_string_chunk_new(buflen);
+   lst = NULL;
+   result = NULL;
+
+   total = generate_frequencies (fl, buffer, buflen, ht, ts, roots, sc);
+
+   if (!total) goto on_error;
+
+   result = g_hash_table_lookup(ht, searchFor);
+
+ on_error:
+   printf("%ld\t%s\n", result ? result->stat : 0, searchFor);
+
+   g_hash_table_destroy(ht);
+   g_string_chunk_free(sc);
+}
+
+int
+main ()
+{
+   char buffer[4096];
+   GTrashStack *ts;
+   GPtrArray *roots;
+   GString *stuff;
+   gchar *s;
+   int len;
+
+   roots = g_ptr_array_new();
+   ts = NULL;
+
+   while (fgets(buffer, sizeof (buffer), stdin))
+     if (strncmp(buffer, ">THREE", 6) == 0)
+       break;
+
+   stuff = g_string_new(NULL);
+
+   while (fgets(buffer, sizeof (buffer), stdin))
+     {
+       size_t sz;
+
+       if (buffer[0] == '>')
+         break;
+
+       sz = strlen(buffer);
+       if (buffer[sz - 1] == '\n')
+         --sz;
+
+       stuff = g_string_append_len(stuff, buffer, sz);
+     }
+
+   stuff = g_string_ascii_up(stuff);
+   len = stuff->len;
+   s = g_string_free(stuff, FALSE);
+
+   write_frequencies(1, s, len, &ts, roots);
+   printf("\n");
+   write_frequencies(2, s, len, &ts, roots);
+   printf("\n");
+   write_count("GGT", s, len, &ts, roots);
+   write_count("GGTA", s, len, &ts, roots);
+   write_count("GGTATT", s, len, &ts, roots);
+   write_count("GGTATTTTAATT", s, len, &ts, roots);
+   write_count("GGTATTTTAATTTATAGT", s, len, &ts, roots);
+
+   free(s);
+
+   g_ptr_array_foreach(roots, free, NULL);
+   g_ptr_array_free(roots, TRUE);
+
+   return 0;
+}
diff --git a/gcc/testsuite/go.test/test/bench/k-nucleotide.go b/gcc/testsuite/go.test/test/bench/k-nucleotide.go
new file mode 100644 (file)
index 0000000..fdc98ed
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "sort"
+)
+
+var in *bufio.Reader
+
+func count(data string, n int) map[string]int {
+       counts := make(map[string]int)
+       top := len(data) - n
+       for i := 0; i <= top; i++ {
+               s := data[i : i+n]
+               counts[s]++
+       }
+       return counts
+}
+
+func countOne(data string, s string) int {
+       return count(data, len(s))[s]
+}
+
+type kNuc struct {
+       name  string
+       count int
+}
+
+type kNucArray []kNuc
+
+func (kn kNucArray) Len() int      { return len(kn) }
+func (kn kNucArray) Swap(i, j int) { kn[i], kn[j] = kn[j], kn[i] }
+func (kn kNucArray) Less(i, j int) bool {
+       if kn[i].count == kn[j].count {
+               return kn[i].name > kn[j].name // sort down
+       }
+       return kn[i].count > kn[j].count
+}
+
+func sortedArray(m map[string]int) kNucArray {
+       kn := make(kNucArray, len(m))
+       i := 0
+       for k, v := range m {
+               kn[i].name = k
+               kn[i].count = v
+               i++
+       }
+       sort.Sort(kn)
+       return kn
+}
+
+func print(m map[string]int) {
+       a := sortedArray(m)
+       sum := 0
+       for _, kn := range a {
+               sum += kn.count
+       }
+       for _, kn := range a {
+               fmt.Printf("%s %.3f\n", kn.name, 100*float64(kn.count)/float64(sum))
+       }
+}
+
+func main() {
+       in = bufio.NewReader(os.Stdin)
+       three := []byte(">THREE ")
+       for {
+               line, err := in.ReadSlice('\n')
+               if err != nil {
+                       fmt.Fprintln(os.Stderr, "ReadLine err:", err)
+                       os.Exit(2)
+               }
+               if line[0] == '>' && bytes.Equal(line[0:len(three)], three) {
+                       break
+               }
+       }
+       data, err := ioutil.ReadAll(in)
+       if err != nil {
+               fmt.Fprintln(os.Stderr, "ReadAll err:", err)
+               os.Exit(2)
+       }
+       // delete the newlines and convert to upper case
+       j := 0
+       for i := 0; i < len(data); i++ {
+               if data[i] != '\n' {
+                       data[j] = data[i] &^ ' ' // upper case
+                       j++
+               }
+       }
+       str := string(data[0:j])
+
+       print(count(str, 1))
+       fmt.Print("\n")
+
+       print(count(str, 2))
+       fmt.Print("\n")
+
+       interests := []string{"GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT"}
+       for _, s := range interests {
+               fmt.Printf("%d %s\n", countOne(str, s), s)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/bench/k-nucleotide.txt b/gcc/testsuite/go.test/test/bench/k-nucleotide.txt
new file mode 100644 (file)
index 0000000..84169b8
--- /dev/null
@@ -0,0 +1,27 @@
+T 31.520
+A 29.600
+C 19.480
+G 19.400
+
+AT 9.922
+TT 9.602
+TA 9.402
+AA 8.402
+GA 6.321
+TC 6.301
+TG 6.201
+GT 6.041
+CT 5.961
+AG 5.841
+CA 5.461
+AC 5.441
+CC 4.041
+CG 4.021
+GC 3.701
+GG 3.341
+
+54 GGT
+24 GGTA
+4 GGTATT
+0 GGTATTTTAATT
+0 GGTATTTTAATTTATAGT
diff --git a/gcc/testsuite/go.test/test/bench/mandelbrot.c b/gcc/testsuite/go.test/test/bench/mandelbrot.c
new file mode 100644 (file)
index 0000000..c177c08
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Shootout
+   http://shootout.alioth.debian.org/
+
+   contributed by Greg Buchholz
+
+   for the debian (AMD) machine...
+   compile flags:  -O3 -ffast-math -march=athlon-xp -funroll-loops
+
+   for the gp4 (Intel) machine...
+   compile flags:  -O3 -ffast-math -march=pentium4 -funroll-loops
+*/
+
+#include<stdio.h>
+
+int main (int argc, char **argv)
+{
+    int w, h, bit_num = 0;
+    char byte_acc = 0;
+    int i, iter = 50;
+    double x, y, limit = 2.0;
+    double Zr, Zi, Cr, Ci, Tr, Ti;
+
+    w = h = atoi(argv[1]);
+
+    printf("P4\n%d %d\n",w,h);
+
+    for(y=0;y<h;++y)
+    {
+        for(x=0;x<w;++x)
+        {
+            Zr = Zi = Tr = Ti = 0.0;
+            Cr = (2.0*x/w - 1.5); Ci=(2.0*y/h - 1.0);
+
+            for (i=0;i<iter && (Tr+Ti <= limit*limit);++i)
+            {
+                Zi = 2.0*Zr*Zi + Ci;
+                Zr = Tr - Ti + Cr;
+                Tr = Zr * Zr;
+                Ti = Zi * Zi;
+            }
+
+            byte_acc <<= 1;
+            if(Tr+Ti <= limit*limit) byte_acc |= 0x01;
+
+            ++bit_num;
+
+            if(bit_num == 8)
+            {
+                putc(byte_acc,stdout);
+                byte_acc = 0;
+                bit_num = 0;
+            }
+            else if(x == w-1)
+            {
+                byte_acc <<= (8-w%8);
+                putc(byte_acc,stdout);
+                byte_acc = 0;
+                bit_num = 0;
+            }
+        }
+    }
+}
diff --git a/gcc/testsuite/go.test/test/bench/mandelbrot.go b/gcc/testsuite/go.test/test/bench/mandelbrot.go
new file mode 100644 (file)
index 0000000..1f9fbfd
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on mandelbrot.c contributed by Greg Buchholz
+ */
+
+package main
+
+import (
+       "bufio"
+       "flag"
+       "fmt"
+       "os"
+)
+
+var n = flag.Int("n", 200, "size")
+
+func main() {
+       flag.Parse()
+       out := bufio.NewWriter(os.Stdout)
+       defer out.Flush()
+
+       w := *n
+       h := *n
+       bit_num := 0
+       byte_acc := byte(0)
+       const Iter = 50
+       const Zero float64 = 0
+       const Limit = 2.0
+
+       fmt.Fprintf(out, "P4\n%d %d\n", w, h)
+
+       for y := 0; y < h; y++ {
+               for x := 0; x < w; x++ {
+                       Zr, Zi, Tr, Ti := Zero, Zero, Zero, Zero
+                       Cr := (2*float64(x)/float64(w) - 1.5)
+                       Ci := (2*float64(y)/float64(h) - 1.0)
+
+                       for i := 0; i < Iter && (Tr+Ti <= Limit*Limit); i++ {
+                               Zi = 2*Zr*Zi + Ci
+                               Zr = Tr - Ti + Cr
+                               Tr = Zr * Zr
+                               Ti = Zi * Zi
+                       }
+
+                       byte_acc <<= 1
+                       if Tr+Ti <= Limit*Limit {
+                               byte_acc |= 0x01
+                       }
+
+                       bit_num++
+
+                       if bit_num == 8 {
+                               out.WriteByte(byte_acc)
+                               byte_acc = 0
+                               bit_num = 0
+                       } else if x == w-1 {
+                               byte_acc <<= uint(8 - w%8)
+                               out.WriteByte(byte_acc)
+                               byte_acc = 0
+                               bit_num = 0
+                       }
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/bench/mandelbrot.txt b/gcc/testsuite/go.test/test/bench/mandelbrot.txt
new file mode 100644 (file)
index 0000000..2f7bbbc
Binary files /dev/null and b/gcc/testsuite/go.test/test/bench/mandelbrot.txt differ
diff --git a/gcc/testsuite/go.test/test/bench/meteor-contest.c b/gcc/testsuite/go.test/test/bench/meteor-contest.c
new file mode 100644 (file)
index 0000000..19c4340
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by Christian Vosteen
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#define TRUE 1
+#define FALSE 0
+
+/* The board is a 50 cell hexagonal pattern.  For    . . . . .
+ * maximum speed the board will be implemented as     . . . . .
+ * 50 bits, which will fit into a 64 bit long long   . . . . .
+ * int.                                               . . . . .
+ *                                                   . . . . .
+ * I will represent 0's as empty cells and 1's        . . . . .
+ * as full cells.                                    . . . . .
+ *                                                    . . . . .
+ *                                                   . . . . .
+ *                                                    . . . . .
+ */
+
+unsigned long long board = 0xFFFC000000000000ULL;
+
+/* The puzzle pieces must be specified by the path followed
+ * from one end to the other along 12 hexagonal directions.
+ *
+ *   Piece 0   Piece 1   Piece 2   Piece 3   Piece 4
+ *
+ *  O O O O    O   O O   O O O     O O O     O   O
+ *         O    O O           O       O       O O
+ *                           O         O         O
+ *
+ *   Piece 5   Piece 6   Piece 7   Piece 8   Piece 9
+ *
+ *    O O O     O O       O O     O O        O O O O
+ *       O O       O O       O       O O O        O
+ *                  O       O O
+ *
+ * I had to make it 12 directions because I wanted all of the
+ * piece definitions to fit into the same size arrays.  It is
+ * not possible to define piece 4 in terms of the 6 cardinal
+ * directions in 4 moves.
+ */
+
+#define E     0
+#define ESE   1
+#define SE    2
+#define S     3
+#define SW    4
+#define WSW   5
+#define W     6
+#define WNW   7
+#define NW    8
+#define N     9
+#define NE    10
+#define ENE   11
+#define PIVOT 12
+
+char piece_def[10][4] = {
+   {  E,  E,  E, SE},
+   { SE,  E, NE,  E},
+   {  E,  E, SE, SW},
+   {  E,  E, SW, SE},
+   { SE,  E, NE,  S},
+   {  E,  E, SW,  E},
+   {  E, SE, SE, NE},
+   {  E, SE, SE,  W},
+   {  E, SE,  E,  E},
+   {  E,  E,  E, SW}
+};
+
+
+/* To minimize the amount of work done in the recursive solve function below,
+ * I'm going to allocate enough space for all legal rotations of each piece
+ * at each position on the board. That's 10 pieces x 50 board positions x
+ * 12 rotations.  However, not all 12 rotations will fit on every cell, so
+ * I'll have to keep count of the actual number that do.
+ * The pieces are going to be unsigned long long ints just like the board so
+ * they can be bitwise-anded with the board to determine if they fit.
+ * I'm also going to record the next possible open cell for each piece and
+ * location to reduce the burden on the solve function.
+ */
+unsigned long long pieces[10][50][12];
+int piece_counts[10][50];
+char next_cell[10][50][12];
+
+/* Returns the direction rotated 60 degrees clockwise */
+char rotate(char dir) {
+   return (dir + 2) % PIVOT;
+}
+
+/* Returns the direction flipped on the horizontal axis */
+char flip(char dir) {
+   return (PIVOT - dir) % PIVOT;
+}
+
+
+/* Returns the new cell index from the specified cell in the
+ * specified direction.  The index is only valid if the
+ * starting cell and direction have been checked by the
+ * out_of_bounds function first.
+ */
+char shift(char cell, char dir) {
+   switch(dir) {
+      case E:
+         return cell + 1;
+      case ESE:
+         if((cell / 5) % 2)
+            return cell + 7;
+         else
+            return cell + 6;
+      case SE:
+         if((cell / 5) % 2)
+            return cell + 6;
+         else
+            return cell + 5;
+      case S:
+         return cell + 10;
+      case SW:
+         if((cell / 5) % 2)
+            return cell + 5;
+         else
+            return cell + 4;
+      case WSW:
+         if((cell / 5) % 2)
+            return cell + 4;
+         else
+            return cell + 3;
+      case W:
+         return cell - 1;
+      case WNW:
+         if((cell / 5) % 2)
+            return cell - 6;
+         else
+            return cell - 7;
+      case NW:
+         if((cell / 5) % 2)
+            return cell - 5;
+         else
+            return cell - 6;
+      case N:
+         return cell - 10;
+      case NE:
+         if((cell / 5) % 2)
+            return cell - 4;
+         else
+            return cell - 5;
+      case ENE:
+         if((cell / 5) % 2)
+            return cell - 3;
+         else
+            return cell - 4;
+      default:
+         return cell;
+   }
+}
+
+/* Returns wether the specified cell and direction will land outside
+ * of the board.  Used to determine if a piece is at a legal board
+ * location or not.
+ */
+char out_of_bounds(char cell, char dir) {
+   char i;
+   switch(dir) {
+      case E:
+         return cell % 5 == 4;
+      case ESE:
+         i = cell % 10;
+         return i == 4 || i == 8 || i == 9 || cell >= 45;
+      case SE:
+         return cell % 10 == 9 || cell >= 45;
+      case S:
+         return cell >= 40;
+      case SW:
+         return cell % 10 == 0 || cell >= 45;
+      case WSW:
+         i = cell % 10;
+         return i == 0 || i == 1 || i == 5 || cell >= 45;
+      case W:
+         return cell % 5 == 0;
+      case WNW:
+         i = cell % 10;
+         return i == 0 || i == 1 || i == 5 || cell < 5;
+      case NW:
+         return cell % 10 == 0 || cell < 5;
+      case N:
+         return cell < 10;
+      case NE:
+         return cell % 10 == 9 || cell < 5;
+      case ENE:
+         i = cell % 10;
+         return i == 4 || i == 8 || i == 9 || cell < 5;
+      default:
+         return FALSE;
+   }
+}
+
+/* Rotate a piece 60 degrees clockwise */
+void rotate_piece(int piece) {
+   int i;
+   for(i = 0; i < 4; i++)
+      piece_def[piece][i] = rotate(piece_def[piece][i]);
+}
+
+/* Flip a piece along the horizontal axis */
+void flip_piece(int piece) {
+   int i;
+   for(i = 0; i < 4; i++)
+      piece_def[piece][i] = flip(piece_def[piece][i]);
+}
+
+/* Convenience function to quickly calculate all of the indices for a piece */
+void calc_cell_indices(char *cell, int piece, char index) {
+   cell[0] = index;
+   cell[1] = shift(cell[0], piece_def[piece][0]);
+   cell[2] = shift(cell[1], piece_def[piece][1]);
+   cell[3] = shift(cell[2], piece_def[piece][2]);
+   cell[4] = shift(cell[3], piece_def[piece][3]);
+}
+
+/* Convenience function to quickly calculate if a piece fits on the board */
+int cells_fit_on_board(char *cell, int piece) {
+   return (!out_of_bounds(cell[0], piece_def[piece][0]) &&
+         !out_of_bounds(cell[1], piece_def[piece][1]) &&
+         !out_of_bounds(cell[2], piece_def[piece][2]) &&
+         !out_of_bounds(cell[3], piece_def[piece][3]));
+}
+
+/* Returns the lowest index of the cells of a piece.
+ * I use the lowest index that a piece occupies as the index for looking up
+ * the piece in the solve function.
+ */
+char minimum_of_cells(char *cell) {
+   char minimum = cell[0];
+   minimum = cell[1] < minimum ? cell[1] : minimum;
+   minimum = cell[2] < minimum ? cell[2] : minimum;
+   minimum = cell[3] < minimum ? cell[3] : minimum;
+   minimum = cell[4] < minimum ? cell[4] : minimum;
+   return minimum;
+}
+
+/* Calculate the lowest possible open cell if the piece is placed on the board.
+ * Used to later reduce the amount of time searching for open cells in the
+ * solve function.
+ */
+char first_empty_cell(char *cell, char minimum) {
+   char first_empty = minimum;
+   while(first_empty == cell[0] || first_empty == cell[1] ||
+         first_empty == cell[2] || first_empty == cell[3] ||
+         first_empty == cell[4])
+      first_empty++;
+   return first_empty;
+}
+
+/* Generate the unsigned long long int that will later be anded with the
+ * board to determine if it fits.
+ */
+unsigned long long bitmask_from_cells(char *cell) {
+   unsigned long long piece_mask = 0ULL;
+   int i;
+   for(i = 0; i < 5; i++)
+      piece_mask |= 1ULL << cell[i];
+   return piece_mask;
+}
+
+/* Record the piece and other important information in arrays that will
+ * later be used by the solve function.
+ */
+void record_piece(int piece, int minimum, char first_empty,
+      unsigned long long piece_mask) {
+   pieces[piece][minimum][piece_counts[piece][minimum]] = piece_mask;
+   next_cell[piece][minimum][piece_counts[piece][minimum]] = first_empty;
+   piece_counts[piece][minimum]++;
+}
+
+
+/* Fill the entire board going cell by cell.  If any cells are "trapped"
+ * they will be left alone.
+ */
+void fill_contiguous_space(char *board, int index) {
+   if(board[index] == 1)
+      return;
+   board[index] = 1;
+   if(!out_of_bounds(index, E))
+      fill_contiguous_space(board, shift(index, E));
+   if(!out_of_bounds(index, SE))
+      fill_contiguous_space(board, shift(index, SE));
+   if(!out_of_bounds(index, SW))
+      fill_contiguous_space(board, shift(index, SW));
+   if(!out_of_bounds(index, W))
+      fill_contiguous_space(board, shift(index, W));
+   if(!out_of_bounds(index, NW))
+      fill_contiguous_space(board, shift(index, NW));
+   if(!out_of_bounds(index, NE))
+      fill_contiguous_space(board, shift(index, NE));
+}
+
+
+/* To thin the number of pieces, I calculate if any of them trap any empty
+ * cells at the edges.  There are only a handful of exceptions where the
+ * the board can be solved with the trapped cells.  For example:  piece 8 can
+ * trap 5 cells in the corner, but piece 3 can fit in those cells, or piece 0
+ * can split the board in half where both halves are viable.
+ */
+int has_island(char *cell, int piece) {
+   char temp_board[50];
+   char c;
+   int i;
+   for(i = 0; i < 50; i++)
+      temp_board[i] = 0;
+   for(i = 0; i < 5; i++)
+      temp_board[((int)cell[i])] = 1;
+   i = 49;
+   while(temp_board[i] == 1)
+      i--;
+   fill_contiguous_space(temp_board, i);
+   c = 0;
+   for(i = 0; i < 50; i++)
+      if(temp_board[i] == 0)
+         c++;
+   if(c == 0 || (c == 5 && piece == 8) || (c == 40 && piece == 8) ||
+         (c % 5 == 0 && piece == 0))
+      return FALSE;
+   else
+      return TRUE;
+}
+
+
+/* Calculate all six rotations of the specified piece at the specified index.
+ * We calculate only half of piece 3's rotations.  This is because any solution
+ * found has an identical solution rotated 180 degrees.  Thus we can reduce the
+ * number of attempted pieces in the solve algorithm by not including the 180-
+ * degree-rotated pieces of ONE of the pieces.  I chose piece 3 because it gave
+ * me the best time ;)
+ */
+ void calc_six_rotations(char piece, char index) {
+   char rotation, cell[5];
+   char minimum, first_empty;
+   unsigned long long piece_mask;
+
+   for(rotation = 0; rotation < 6; rotation++) {
+      if(piece != 3 || rotation < 3) {
+         calc_cell_indices(cell, piece, index);
+         if(cells_fit_on_board(cell, piece) && !has_island(cell, piece)) {
+            minimum = minimum_of_cells(cell);
+            first_empty = first_empty_cell(cell, minimum);
+            piece_mask = bitmask_from_cells(cell);
+            record_piece(piece, minimum, first_empty, piece_mask);
+         }
+      }
+      rotate_piece(piece);
+   }
+}
+
+/* Calculate every legal rotation for each piece at each board location. */
+void calc_pieces(void) {
+   char piece, index;
+
+   for(piece = 0; piece < 10; piece++) {
+      for(index = 0; index < 50; index++) {
+         calc_six_rotations(piece, index);
+         flip_piece(piece);
+         calc_six_rotations(piece, index);
+      }
+   }
+}
+
+
+
+/* Calculate all 32 possible states for a 5-bit row and all rows that will
+ * create islands that follow any of the 32 possible rows.  These pre-
+ * calculated 5-bit rows will be used to find islands in a partially solved
+ * board in the solve function.
+ */
+#define ROW_MASK 0x1F
+#define TRIPLE_MASK 0x7FFF
+char all_rows[32] = {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};
+int bad_even_rows[32][32];
+int bad_odd_rows[32][32];
+int bad_even_triple[32768];
+int bad_odd_triple[32768];
+
+int rows_bad(char row1, char row2, int even) {
+   /* even is referring to row1 */
+   int i, in_zeroes, group_okay;
+   char block, row2_shift;
+   /* Test for blockages at same index and shifted index */
+   if(even)
+      row2_shift = ((row2 << 1) & ROW_MASK) | 0x01;
+   else
+      row2_shift = (row2 >> 1) | 0x10;
+   block = ((row1 ^ row2) & row2) & ((row1 ^ row2_shift) & row2_shift);
+   /* Test for groups of 0's */
+   in_zeroes = FALSE;
+   group_okay = FALSE;
+   for(i = 0; i < 5; i++) {
+      if(row1 & (1 << i)) {
+         if(in_zeroes) {
+            if(!group_okay)
+               return TRUE;
+            in_zeroes = FALSE;
+            group_okay = FALSE;
+         }
+      } else {
+         if(!in_zeroes)
+            in_zeroes = TRUE;
+         if(!(block & (1 << i)))
+            group_okay = TRUE;
+      }
+   }
+   if(in_zeroes)
+      return !group_okay;
+   else
+      return FALSE;
+}
+
+/* Check for cases where three rows checked sequentially cause a false
+ * positive.  One scenario is when 5 cells may be surrounded where piece 5
+ * or 7 can fit.  The other scenario is when piece 2 creates a hook shape.
+ */
+int triple_is_okay(char row1, char row2, char row3, int even) {
+   if(even) {
+      /* There are four cases:
+       * row1: 00011  00001  11001  10101
+       * row2: 01011  00101  10001  10001
+       * row3: 011??  00110  ?????  ?????
+       */
+      return ((row1 == 0x03) && (row2 == 0x0B) && ((row3 & 0x1C) == 0x0C)) ||
+            ((row1 == 0x01) && (row2 == 0x05) && (row3 == 0x06)) ||
+            ((row1 == 0x19) && (row2 == 0x11)) ||
+            ((row1 == 0x15) && (row2 == 0x11));
+   } else {
+      /* There are two cases:
+       * row1: 10011  10101
+       * row2: 10001  10001
+       * row3: ?????  ?????
+       */
+      return ((row1 == 0x13) && (row2 == 0x11)) ||
+            ((row1 == 0x15) && (row2 == 0x11));
+   }
+}
+
+
+void calc_rows(void) {
+   int row1, row2, row3;
+   int result1, result2;
+   for(row1 = 0; row1 < 32; row1++) {
+      for(row2 = 0; row2 < 32; row2++) {
+         bad_even_rows[row1][row2] = rows_bad(row1, row2, TRUE);
+         bad_odd_rows[row1][row2] = rows_bad(row1, row2, FALSE);
+      }
+   }
+   for(row1 = 0; row1 < 32; row1++) {
+      for(row2 = 0; row2 < 32; row2++) {
+         for(row3 = 0; row3 < 32; row3++) {
+            result1 = bad_even_rows[row1][row2];
+            result2 = bad_odd_rows[row2][row3];
+            if(result1 == FALSE && result2 == TRUE
+                  && triple_is_okay(row1, row2, row3, TRUE))
+               bad_even_triple[row1+(row2*32)+(row3*1024)] = FALSE;
+            else
+               bad_even_triple[row1+(row2*32)+(row3*1024)] = result1 || result2;
+
+            result1 = bad_odd_rows[row1][row2];
+            result2 = bad_even_rows[row2][row3];
+            if(result1 == FALSE && result2 == TRUE
+                  && triple_is_okay(row1, row2, row3, FALSE))
+               bad_odd_triple[row1+(row2*32)+(row3*1024)] = FALSE;
+            else
+               bad_odd_triple[row1+(row2*32)+(row3*1024)] = result1 || result2;
+         }
+      }
+   }
+}
+
+
+
+/* Calculate islands while solving the board.
+ */
+int boardHasIslands(char cell) {
+   /* Too low on board, don't bother checking */
+   if(cell >= 40)
+      return FALSE;
+   int current_triple = (board >> ((cell / 5) * 5)) & TRIPLE_MASK;
+   if((cell / 5) % 2)
+      return bad_odd_triple[current_triple];
+   else
+      return bad_even_triple[current_triple];
+}
+
+
+/* The recursive solve algorithm.  Try to place each permutation in the upper-
+ * leftmost empty cell.  Mark off available pieces as it goes along.
+ * Because the board is a bit mask, the piece number and bit mask must be saved
+ * at each successful piece placement.  This data is used to create a 50 char
+ * array if a solution is found.
+ */
+short avail = 0x03FF;
+char sol_nums[10];
+unsigned long long sol_masks[10];
+signed char solutions[2100][50];
+int solution_count = 0;
+int max_solutions = 2100;
+
+void record_solution(void) {
+   int sol_no, index;
+   unsigned long long sol_mask;
+   for(sol_no = 0; sol_no < 10; sol_no++) {
+      sol_mask = sol_masks[sol_no];
+      for(index = 0; index < 50; index++) {
+         if(sol_mask & 1ULL) {
+            solutions[solution_count][index] = sol_nums[sol_no];
+            /* Board rotated 180 degrees is a solution too! */
+            solutions[solution_count+1][49-index] = sol_nums[sol_no];
+         }
+         sol_mask = sol_mask >> 1;
+      }
+   }
+   solution_count += 2;
+}
+
+void solve(int depth, int cell) {
+   int piece, rotation, max_rots;
+   unsigned long long *piece_mask;
+   short piece_no_mask;
+
+   if(solution_count >= max_solutions)
+      return;
+
+   while(board & (1ULL << cell))
+      cell++;
+
+   for(piece = 0; piece < 10; piece++) {
+      piece_no_mask = 1 << piece;
+      if(!(avail & piece_no_mask))
+         continue;
+      avail ^= piece_no_mask;
+      max_rots = piece_counts[piece][cell];
+      piece_mask = pieces[piece][cell];
+      for(rotation = 0; rotation < max_rots; rotation++) {
+         if(!(board & *(piece_mask + rotation))) {
+            sol_nums[depth] = piece;
+            sol_masks[depth] = *(piece_mask + rotation);
+            if(depth == 9) {
+               /* Solution found!!!!!11!!ONE! */
+               record_solution();
+               avail ^= piece_no_mask;
+               return;
+            }
+            board |= *(piece_mask + rotation);
+            if(!boardHasIslands(next_cell[piece][cell][rotation]))
+               solve(depth + 1, next_cell[piece][cell][rotation]);
+            board ^= *(piece_mask + rotation);
+         }
+      }
+      avail ^= piece_no_mask;
+   }
+}
+
+
+/* qsort comparator - used to find first and last solutions */
+int solution_sort(const void *elem1, const void *elem2) {
+   signed char *char1 = (signed char *) elem1;
+   signed char *char2 = (signed char *) elem2;
+   int i = 0;
+   while(i < 50 && char1[i] == char2[i])
+      i++;
+   return char1[i] - char2[i];
+}
+
+
+/* pretty print a board in the specified hexagonal format */
+void pretty(signed char *b) {
+   int i;
+   for(i = 0; i < 50; i += 10) {
+      printf("%c %c %c %c %c \n %c %c %c %c %c \n", b[i]+'0', b[i+1]+'0',
+            b[i+2]+'0', b[i+3]+'0', b[i+4]+'0', b[i+5]+'0', b[i+6]+'0',
+            b[i+7]+'0', b[i+8]+'0', b[i+9]+'0');
+   }
+   printf("\n");
+}
+
+int main(int argc, char **argv) {
+   if(argc > 1)
+      max_solutions = atoi(argv[1]);
+   calc_pieces();
+   calc_rows();
+   solve(0, 0);
+   printf("%d solutions found\n\n", solution_count);
+   qsort(solutions, solution_count, 50 * sizeof(signed char), solution_sort);
+   pretty(solutions[0]);
+   pretty(solutions[solution_count-1]);
+   return 0;
+}
diff --git a/gcc/testsuite/go.test/test/bench/meteor-contest.go b/gcc/testsuite/go.test/test/bench/meteor-contest.go
new file mode 100644 (file)
index 0000000..6660810
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on meteor-contest.c by Christian Vosteen
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+)
+
+var max_solutions = flag.Int("n", 2100, "maximum number of solutions")
+
+
+func boolInt(b bool) int8 {
+       if b {
+               return 1
+       }
+       return 0
+}
+
+/* The board is a 50 cell hexagonal pattern.  For    . . . . .
+ * maximum speed the board will be implemented as     . . . . .
+ * 50 bits, which will fit into a 64 bit long long   . . . . .
+ * int.                                               . . . . .
+ *                                                   . . . . .
+ * I will represent 0's as empty cells and 1's        . . . . .
+ * as full cells.                                    . . . . .
+ *                                                    . . . . .
+ *                                                   . . . . .
+ *                                                    . . . . .
+ */
+
+var board uint64 = 0xFFFC000000000000
+
+/* The puzzle pieces must be specified by the path followed
+ * from one end to the other along 12 hexagonal directions.
+ *
+ *   Piece 0   Piece 1   Piece 2   Piece 3   Piece 4
+ *
+ *  O O O O    O   O O   O O O     O O O     O   O
+ *         O    O O           O       O       O O
+ *                           O         O         O
+ *
+ *   Piece 5   Piece 6   Piece 7   Piece 8   Piece 9
+ *
+ *    O O O     O O       O O     O O        O O O O
+ *       O O       O O       O       O O O        O
+ *                  O       O O
+ *
+ * I had to make it 12 directions because I wanted all of the
+ * piece definitions to fit into the same size arrays.  It is
+ * not possible to define piece 4 in terms of the 6 cardinal
+ * directions in 4 moves.
+ */
+
+const (
+       E = iota
+       ESE
+       SE
+       S
+       SW
+       WSW
+       W
+       WNW
+       NW
+       N
+       NE
+       ENE
+       PIVOT
+)
+
+var piece_def = [10][4]int8{
+       [4]int8{E, E, E, SE},
+       [4]int8{SE, E, NE, E},
+       [4]int8{E, E, SE, SW},
+       [4]int8{E, E, SW, SE},
+       [4]int8{SE, E, NE, S},
+       [4]int8{E, E, SW, E},
+       [4]int8{E, SE, SE, NE},
+       [4]int8{E, SE, SE, W},
+       [4]int8{E, SE, E, E},
+       [4]int8{E, E, E, SW},
+}
+
+
+/* To minimize the amount of work done in the recursive solve function below,
+ * I'm going to allocate enough space for all legal rotations of each piece
+ * at each position on the board. That's 10 pieces x 50 board positions x
+ * 12 rotations.  However, not all 12 rotations will fit on every cell, so
+ * I'll have to keep count of the actual number that do.
+ * The pieces are going to be unsigned long long ints just like the board so
+ * they can be bitwise-anded with the board to determine if they fit.
+ * I'm also going to record the next possible open cell for each piece and
+ * location to reduce the burden on the solve function.
+ */
+var (
+       pieces       [10][50][12]uint64
+       piece_counts [10][50]int
+       next_cell    [10][50][12]int8
+)
+
+/* Returns the direction rotated 60 degrees clockwise */
+func rotate(dir int8) int8 { return (dir + 2) % PIVOT }
+
+/* Returns the direction flipped on the horizontal axis */
+func flip(dir int8) int8 { return (PIVOT - dir) % PIVOT }
+
+
+/* Returns the new cell index from the specified cell in the
+ * specified direction.  The index is only valid if the
+ * starting cell and direction have been checked by the
+ * out_of_bounds function first.
+ */
+func shift(cell, dir int8) int8 {
+       switch dir {
+       case E:
+               return cell + 1
+       case ESE:
+               if ((cell / 5) % 2) != 0 {
+                       return cell + 7
+               } else {
+                       return cell + 6
+               }
+       case SE:
+               if ((cell / 5) % 2) != 0 {
+                       return cell + 6
+               } else {
+                       return cell + 5
+               }
+       case S:
+               return cell + 10
+       case SW:
+               if ((cell / 5) % 2) != 0 {
+                       return cell + 5
+               } else {
+                       return cell + 4
+               }
+       case WSW:
+               if ((cell / 5) % 2) != 0 {
+                       return cell + 4
+               } else {
+                       return cell + 3
+               }
+       case W:
+               return cell - 1
+       case WNW:
+               if ((cell / 5) % 2) != 0 {
+                       return cell - 6
+               } else {
+                       return cell - 7
+               }
+       case NW:
+               if ((cell / 5) % 2) != 0 {
+                       return cell - 5
+               } else {
+                       return cell - 6
+               }
+       case N:
+               return cell - 10
+       case NE:
+               if ((cell / 5) % 2) != 0 {
+                       return cell - 4
+               } else {
+                       return cell - 5
+               }
+       case ENE:
+               if ((cell / 5) % 2) != 0 {
+                       return cell - 3
+               } else {
+                       return cell - 4
+               }
+       }
+       return cell
+}
+
+/* Returns wether the specified cell and direction will land outside
+ * of the board.  Used to determine if a piece is at a legal board
+ * location or not.
+ */
+func out_of_bounds(cell, dir int8) bool {
+       switch dir {
+       case E:
+               return cell%5 == 4
+       case ESE:
+               i := cell % 10
+               return i == 4 || i == 8 || i == 9 || cell >= 45
+       case SE:
+               return cell%10 == 9 || cell >= 45
+       case S:
+               return cell >= 40
+       case SW:
+               return cell%10 == 0 || cell >= 45
+       case WSW:
+               i := cell % 10
+               return i == 0 || i == 1 || i == 5 || cell >= 45
+       case W:
+               return cell%5 == 0
+       case WNW:
+               i := cell % 10
+               return i == 0 || i == 1 || i == 5 || cell < 5
+       case NW:
+               return cell%10 == 0 || cell < 5
+       case N:
+               return cell < 10
+       case NE:
+               return cell%10 == 9 || cell < 5
+       case ENE:
+               i := cell % 10
+               return i == 4 || i == 8 || i == 9 || cell < 5
+       }
+       return false
+}
+
+/* Rotate a piece 60 degrees clockwise */
+func rotate_piece(piece int) {
+       for i := 0; i < 4; i++ {
+               piece_def[piece][i] = rotate(piece_def[piece][i])
+       }
+}
+
+/* Flip a piece along the horizontal axis */
+func flip_piece(piece int) {
+       for i := 0; i < 4; i++ {
+               piece_def[piece][i] = flip(piece_def[piece][i])
+       }
+}
+
+/* Convenience function to quickly calculate all of the indices for a piece */
+func calc_cell_indices(cell []int8, piece int, index int8) {
+       cell[0] = index
+       for i := 1; i < 5; i++ {
+               cell[i] = shift(cell[i-1], piece_def[piece][i-1])
+       }
+}
+
+/* Convenience function to quickly calculate if a piece fits on the board */
+func cells_fit_on_board(cell []int8, piece int) bool {
+       return !out_of_bounds(cell[0], piece_def[piece][0]) &&
+               !out_of_bounds(cell[1], piece_def[piece][1]) &&
+               !out_of_bounds(cell[2], piece_def[piece][2]) &&
+               !out_of_bounds(cell[3], piece_def[piece][3])
+}
+
+/* Returns the lowest index of the cells of a piece.
+ * I use the lowest index that a piece occupies as the index for looking up
+ * the piece in the solve function.
+ */
+func minimum_of_cells(cell []int8) int8 {
+       minimum := cell[0]
+       for i := 1; i < 5; i++ {
+               if cell[i] < minimum {
+                       minimum = cell[i]
+               }
+       }
+       return minimum
+}
+
+/* Calculate the lowest possible open cell if the piece is placed on the board.
+ * Used to later reduce the amount of time searching for open cells in the
+ * solve function.
+ */
+func first_empty_cell(cell []int8, minimum int8) int8 {
+       first_empty := minimum
+       for first_empty == cell[0] || first_empty == cell[1] ||
+               first_empty == cell[2] || first_empty == cell[3] ||
+               first_empty == cell[4] {
+               first_empty++
+       }
+       return first_empty
+}
+
+/* Generate the unsigned long long int that will later be anded with the
+ * board to determine if it fits.
+ */
+func bitmask_from_cells(cell []int8) uint64 {
+       var piece_mask uint64
+       for i := 0; i < 5; i++ {
+               piece_mask |= 1 << uint(cell[i])
+       }
+       return piece_mask
+}
+
+/* Record the piece and other important information in arrays that will
+ * later be used by the solve function.
+ */
+func record_piece(piece int, minimum int8, first_empty int8, piece_mask uint64) {
+       pieces[piece][minimum][piece_counts[piece][minimum]] = piece_mask
+       next_cell[piece][minimum][piece_counts[piece][minimum]] = first_empty
+       piece_counts[piece][minimum]++
+}
+
+
+/* Fill the entire board going cell by cell.  If any cells are "trapped"
+ * they will be left alone.
+ */
+func fill_contiguous_space(board []int8, index int8) {
+       if board[index] == 1 {
+               return
+       }
+       board[index] = 1
+       if !out_of_bounds(index, E) {
+               fill_contiguous_space(board, shift(index, E))
+       }
+       if !out_of_bounds(index, SE) {
+               fill_contiguous_space(board, shift(index, SE))
+       }
+       if !out_of_bounds(index, SW) {
+               fill_contiguous_space(board, shift(index, SW))
+       }
+       if !out_of_bounds(index, W) {
+               fill_contiguous_space(board, shift(index, W))
+       }
+       if !out_of_bounds(index, NW) {
+               fill_contiguous_space(board, shift(index, NW))
+       }
+       if !out_of_bounds(index, NE) {
+               fill_contiguous_space(board, shift(index, NE))
+       }
+}
+
+
+/* To thin the number of pieces, I calculate if any of them trap any empty
+ * cells at the edges.  There are only a handful of exceptions where the
+ * the board can be solved with the trapped cells.  For example:  piece 8 can
+ * trap 5 cells in the corner, but piece 3 can fit in those cells, or piece 0
+ * can split the board in half where both halves are viable.
+ */
+func has_island(cell []int8, piece int) bool {
+       temp_board := make([]int8, 50)
+       var i int
+       for i = 0; i < 5; i++ {
+               temp_board[cell[i]] = 1
+       }
+       i = 49
+       for temp_board[i] == 1 {
+               i--
+       }
+       fill_contiguous_space(temp_board, int8(i))
+       c := 0
+       for i = 0; i < 50; i++ {
+               if temp_board[i] == 0 {
+                       c++
+               }
+       }
+       if c == 0 || (c == 5 && piece == 8) || (c == 40 && piece == 8) ||
+               (c%5 == 0 && piece == 0) {
+               return false
+       }
+       return true
+}
+
+
+/* Calculate all six rotations of the specified piece at the specified index.
+ * We calculate only half of piece 3's rotations.  This is because any solution
+ * found has an identical solution rotated 180 degrees.  Thus we can reduce the
+ * number of attempted pieces in the solve algorithm by not including the 180-
+ * degree-rotated pieces of ONE of the pieces.  I chose piece 3 because it gave
+ * me the best time ;)
+ */
+func calc_six_rotations(piece, index int) {
+       cell := make([]int8, 5)
+       for rotation := 0; rotation < 6; rotation++ {
+               if piece != 3 || rotation < 3 {
+                       calc_cell_indices(cell, piece, int8(index))
+                       if cells_fit_on_board(cell, piece) && !has_island(cell, piece) {
+                               minimum := minimum_of_cells(cell)
+                               first_empty := first_empty_cell(cell, minimum)
+                               piece_mask := bitmask_from_cells(cell)
+                               record_piece(piece, minimum, first_empty, piece_mask)
+                       }
+               }
+               rotate_piece(piece)
+       }
+}
+
+/* Calculate every legal rotation for each piece at each board location. */
+func calc_pieces() {
+       for piece := 0; piece < 10; piece++ {
+               for index := 0; index < 50; index++ {
+                       calc_six_rotations(piece, index)
+                       flip_piece(piece)
+                       calc_six_rotations(piece, index)
+               }
+       }
+}
+
+
+/* Calculate all 32 possible states for a 5-bit row and all rows that will
+ * create islands that follow any of the 32 possible rows.  These pre-
+ * calculated 5-bit rows will be used to find islands in a partially solved
+ * board in the solve function.
+ */
+const (
+       ROW_MASK    = 0x1F
+       TRIPLE_MASK = 0x7FFF
+)
+
+var (
+       all_rows = [32]int8{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,
+       }
+       bad_even_rows   [32][32]int8
+       bad_odd_rows    [32][32]int8
+       bad_even_triple [32768]int8
+       bad_odd_triple  [32768]int8
+)
+
+func rows_bad(row1, row2 int8, even bool) int8 {
+       /* even is referring to row1 */
+       var row2_shift int8
+       /* Test for blockages at same index and shifted index */
+       if even {
+               row2_shift = ((row2 << 1) & ROW_MASK) | 0x01
+       } else {
+               row2_shift = (row2 >> 1) | 0x10
+       }
+       block := ((row1 ^ row2) & row2) & ((row1 ^ row2_shift) & row2_shift)
+       /* Test for groups of 0's */
+       in_zeroes := false
+       group_okay := false
+       for i := uint8(0); i < 5; i++ {
+               if row1&(1<<i) != 0 {
+                       if in_zeroes {
+                               if !group_okay {
+                                       return 1
+                               }
+                               in_zeroes = false
+                               group_okay = false
+                       }
+               } else {
+                       if !in_zeroes {
+                               in_zeroes = true
+                       }
+                       if (block & (1 << i)) == 0 {
+                               group_okay = true
+                       }
+               }
+       }
+       if in_zeroes {
+               return boolInt(!group_okay)
+       }
+       return 0
+}
+
+/* Check for cases where three rows checked sequentially cause a false
+ * positive.  One scenario is when 5 cells may be surrounded where piece 5
+ * or 7 can fit.  The other scenario is when piece 2 creates a hook shape.
+ */
+func triple_is_okay(row1, row2, row3 int, even bool) bool {
+       if even {
+               /* There are four cases:
+                * row1: 00011  00001  11001  10101
+                * row2: 01011  00101  10001  10001
+                * row3: 011??  00110  ?????  ?????
+                */
+               return ((row1 == 0x03) && (row2 == 0x0B) && ((row3 & 0x1C) == 0x0C)) ||
+                       ((row1 == 0x01) && (row2 == 0x05) && (row3 == 0x06)) ||
+                       ((row1 == 0x19) && (row2 == 0x11)) ||
+                       ((row1 == 0x15) && (row2 == 0x11))
+       }
+       /* There are two cases:
+        * row1: 10011  10101
+        * row2: 10001  10001
+        * row3: ?????  ?????
+        */
+       return ((row1 == 0x13) && (row2 == 0x11)) ||
+               ((row1 == 0x15) && (row2 == 0x11))
+}
+
+func calc_rows() {
+       for row1 := int8(0); row1 < 32; row1++ {
+               for row2 := int8(0); row2 < 32; row2++ {
+                       bad_even_rows[row1][row2] = rows_bad(row1, row2, true)
+                       bad_odd_rows[row1][row2] = rows_bad(row1, row2, false)
+               }
+       }
+       for row1 := 0; row1 < 32; row1++ {
+               for row2 := 0; row2 < 32; row2++ {
+                       for row3 := 0; row3 < 32; row3++ {
+                               result1 := bad_even_rows[row1][row2]
+                               result2 := bad_odd_rows[row2][row3]
+                               if result1 == 0 && result2 != 0 && triple_is_okay(row1, row2, row3, true) {
+                                       bad_even_triple[row1+(row2*32)+(row3*1024)] = 0
+                               } else {
+                                       bad_even_triple[row1+(row2*32)+(row3*1024)] = boolInt(result1 != 0 || result2 != 0)
+                               }
+
+                               result1 = bad_odd_rows[row1][row2]
+                               result2 = bad_even_rows[row2][row3]
+                               if result1 == 0 && result2 != 0 && triple_is_okay(row1, row2, row3, false) {
+                                       bad_odd_triple[row1+(row2*32)+(row3*1024)] = 0
+                               } else {
+                                       bad_odd_triple[row1+(row2*32)+(row3*1024)] = boolInt(result1 != 0 || result2 != 0)
+                               }
+                       }
+               }
+       }
+}
+
+
+/* Calculate islands while solving the board.
+ */
+func boardHasIslands(cell int8) int8 {
+       /* Too low on board, don't bother checking */
+       if cell >= 40 {
+               return 0
+       }
+       current_triple := (board >> uint((cell/5)*5)) & TRIPLE_MASK
+       if (cell/5)%2 != 0 {
+               return bad_odd_triple[current_triple]
+       }
+       return bad_even_triple[current_triple]
+}
+
+
+/* The recursive solve algorithm.  Try to place each permutation in the upper-
+ * leftmost empty cell.  Mark off available pieces as it goes along.
+ * Because the board is a bit mask, the piece number and bit mask must be saved
+ * at each successful piece placement.  This data is used to create a 50 char
+ * array if a solution is found.
+ */
+var (
+       avail          uint16 = 0x03FF
+       sol_nums       [10]int8
+       sol_masks      [10]uint64
+       solutions      [2100][50]int8
+       solution_count = 0
+)
+
+func record_solution() {
+       for sol_no := 0; sol_no < 10; sol_no++ {
+               sol_mask := sol_masks[sol_no]
+               for index := 0; index < 50; index++ {
+                       if sol_mask&1 == 1 {
+                               solutions[solution_count][index] = sol_nums[sol_no]
+                               /* Board rotated 180 degrees is a solution too! */
+                               solutions[solution_count+1][49-index] = sol_nums[sol_no]
+                       }
+                       sol_mask = sol_mask >> 1
+               }
+       }
+       solution_count += 2
+}
+
+func solve(depth, cell int8) {
+       if solution_count >= *max_solutions {
+               return
+       }
+
+       for board&(1<<uint(cell)) != 0 {
+               cell++
+       }
+
+       for piece := int8(0); piece < 10; piece++ {
+               var piece_no_mask uint16 = 1 << uint(piece)
+               if avail&piece_no_mask == 0 {
+                       continue
+               }
+               avail ^= piece_no_mask
+               max_rots := piece_counts[piece][cell]
+               piece_mask := pieces[piece][cell]
+               for rotation := 0; rotation < max_rots; rotation++ {
+                       if board&piece_mask[rotation] == 0 {
+                               sol_nums[depth] = piece
+                               sol_masks[depth] = piece_mask[rotation]
+                               if depth == 9 {
+                                       /* Solution found!!!!!11!!ONE! */
+                                       record_solution()
+                                       avail ^= piece_no_mask
+                                       return
+                               }
+                               board |= piece_mask[rotation]
+                               if boardHasIslands(next_cell[piece][cell][rotation]) == 0 {
+                                       solve(depth+1, next_cell[piece][cell][rotation])
+                               }
+                               board ^= piece_mask[rotation]
+                       }
+               }
+               avail ^= piece_no_mask
+       }
+}
+
+/* pretty print a board in the specified hexagonal format */
+func pretty(b *[50]int8) {
+       for i := 0; i < 50; i += 10 {
+               fmt.Printf("%c %c %c %c %c \n %c %c %c %c %c \n", b[i]+'0', b[i+1]+'0',
+                       b[i+2]+'0', b[i+3]+'0', b[i+4]+'0', b[i+5]+'0', b[i+6]+'0',
+                       b[i+7]+'0', b[i+8]+'0', b[i+9]+'0')
+       }
+       fmt.Printf("\n")
+}
+
+/* Find smallest and largest solutions */
+func smallest_largest() (smallest, largest *[50]int8) {
+       smallest = &solutions[0]
+       largest = &solutions[0]
+       for i := 1; i < solution_count; i++ {
+               candidate := &solutions[i]
+               for j, s := range *smallest {
+                       c := candidate[j]
+                       if c == s {
+                               continue
+                       }
+                       if c < s {
+                               smallest = candidate
+                       }
+                       break
+               }
+               for j, s := range *largest {
+                       c := candidate[j]
+                       if c == s {
+                               continue
+                       }
+                       if c > s {
+                               largest = candidate
+                       }
+                       break
+               }
+       }
+       return
+}
+
+func main() {
+       flag.Parse()
+       calc_pieces()
+       calc_rows()
+       solve(0, 0)
+       fmt.Printf("%d solutions found\n\n", solution_count)
+       smallest, largest := smallest_largest()
+       pretty(smallest)
+       pretty(largest)
+}
diff --git a/gcc/testsuite/go.test/test/bench/meteor-contest.txt b/gcc/testsuite/go.test/test/bench/meteor-contest.txt
new file mode 100644 (file)
index 0000000..38d9783
--- /dev/null
@@ -0,0 +1,24 @@
+2098 solutions found
+
+0 0 0 0 1 
+ 2 2 2 0 1 
+2 6 6 1 1 
+ 2 6 1 5 5 
+8 6 5 5 5 
+ 8 6 3 3 3 
+4 8 8 9 3 
+ 4 4 8 9 3 
+4 7 4 7 9 
+ 7 7 7 9 9 
+
+9 9 9 9 8 
+ 9 6 6 8 5 
+6 6 8 8 5 
+ 6 8 2 5 5 
+7 7 7 2 5 
+ 7 4 7 2 0 
+1 4 2 2 0 
+ 1 4 4 0 3 
+1 4 0 0 3 
+ 1 1 3 3 3 
+
diff --git a/gcc/testsuite/go.test/test/bench/nbody.c b/gcc/testsuite/go.test/test/bench/nbody.c
new file mode 100644 (file)
index 0000000..3b95b05
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Great Computer Language Shootout
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by Christoph Bauer
+ *
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define pi 3.141592653589793
+#define solar_mass (4 * pi * pi)
+#define days_per_year 365.24
+
+struct planet {
+  double x, y, z;
+  double vx, vy, vz;
+  double mass;
+};
+
+void advance(int nbodies, struct planet * bodies, double dt)
+{
+  int i, j;
+
+  for (i = 0; i < nbodies; i++) {
+    struct planet * b = &(bodies[i]);
+    for (j = i + 1; j < nbodies; j++) {
+      struct planet * b2 = &(bodies[j]);
+      double dx = b->x - b2->x;
+      double dy = b->y - b2->y;
+      double dz = b->z - b2->z;
+      double distance = sqrt(dx * dx + dy * dy + dz * dz);
+      double mag = dt / (distance * distance * distance);
+      b->vx -= dx * b2->mass * mag;
+      b->vy -= dy * b2->mass * mag;
+      b->vz -= dz * b2->mass * mag;
+      b2->vx += dx * b->mass * mag;
+      b2->vy += dy * b->mass * mag;
+      b2->vz += dz * b->mass * mag;
+    }
+  }
+  for (i = 0; i < nbodies; i++) {
+    struct planet * b = &(bodies[i]);
+    b->x += dt * b->vx;
+    b->y += dt * b->vy;
+    b->z += dt * b->vz;
+  }
+}
+
+double energy(int nbodies, struct planet * bodies)
+{
+  double e;
+  int i, j;
+
+  e = 0.0;
+  for (i = 0; i < nbodies; i++) {
+    struct planet * b = &(bodies[i]);
+    e += 0.5 * b->mass * (b->vx * b->vx + b->vy * b->vy + b->vz * b->vz);
+    for (j = i + 1; j < nbodies; j++) {
+      struct planet * b2 = &(bodies[j]);
+      double dx = b->x - b2->x;
+      double dy = b->y - b2->y;
+      double dz = b->z - b2->z;
+      double distance = sqrt(dx * dx + dy * dy + dz * dz);
+      e -= (b->mass * b2->mass) / distance;
+    }
+  }
+  return e;
+}
+
+void offset_momentum(int nbodies, struct planet * bodies)
+{
+  double px = 0.0, py = 0.0, pz = 0.0;
+  int i;
+  for (i = 0; i < nbodies; i++) {
+    px += bodies[i].vx * bodies[i].mass;
+    py += bodies[i].vy * bodies[i].mass;
+    pz += bodies[i].vz * bodies[i].mass;
+  }
+  bodies[0].vx = - px / solar_mass;
+  bodies[0].vy = - py / solar_mass;
+  bodies[0].vz = - pz / solar_mass;
+}
+
+#define NBODIES 5
+struct planet bodies[NBODIES] = {
+  {                               /* sun */
+    0, 0, 0, 0, 0, 0, solar_mass
+  },
+  {                               /* jupiter */
+    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
+  },
+  {                               /* saturn */
+    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
+  },
+  {                               /* uranus */
+    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
+  },
+  {                               /* neptune */
+    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
+  }
+};
+
+int main(int argc, char ** argv)
+{
+  int n = atoi(argv[1]);
+  int i;
+
+  offset_momentum(NBODIES, bodies);
+  printf ("%.9f\n", energy(NBODIES, bodies));
+  for (i = 1; i <= n; i++)
+    advance(NBODIES, bodies, 0.01);
+  printf ("%.9f\n", energy(NBODIES, bodies));
+  return 0;
+}
diff --git a/gcc/testsuite/go.test/test/bench/nbody.go b/gcc/testsuite/go.test/test/bench/nbody.go
new file mode 100644 (file)
index 0000000..e9f4517
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on C program by Christoph Bauer
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "math"
+)
+
+var n = flag.Int("n", 1000, "number of iterations")
+
+type Body struct {
+       x, y, z, vx, vy, vz, mass float64
+}
+
+const (
+       solarMass   = 4 * math.Pi * math.Pi
+       daysPerYear = 365.24
+)
+
+func (b *Body) offsetMomentum(px, py, pz float64) {
+       b.vx = -px / solarMass
+       b.vy = -py / solarMass
+       b.vz = -pz / solarMass
+}
+
+type System []*Body
+
+func NewSystem(body []Body) System {
+       n := make(System, len(body))
+       for i := 0; i < len(body); i++ {
+               n[i] = new(Body) // copy to avoid overwriting the inputs
+               *n[i] = body[i]
+       }
+       var px, py, pz float64
+       for _, body := range n {
+               px += body.vx * body.mass
+               py += body.vy * body.mass
+               pz += body.vz * body.mass
+       }
+       n[0].offsetMomentum(px, py, pz)
+       return n
+}
+
+func (sys System) energy() float64 {
+       var e float64
+       for i, body := range sys {
+               e += 0.5 * body.mass *
+                       (body.vx*body.vx + body.vy*body.vy + body.vz*body.vz)
+               for j := i + 1; j < len(sys); j++ {
+                       body2 := sys[j]
+                       dx := body.x - body2.x
+                       dy := body.y - body2.y
+                       dz := body.z - body2.z
+                       distance := math.Sqrt(dx*dx + dy*dy + dz*dz)
+                       e -= (body.mass * body2.mass) / distance
+               }
+       }
+       return e
+}
+
+func (sys System) advance(dt float64) {
+       for i, body := range sys {
+               for j := i + 1; j < len(sys); j++ {
+                       body2 := sys[j]
+                       dx := body.x - body2.x
+                       dy := body.y - body2.y
+                       dz := body.z - body2.z
+
+                       dSquared := dx*dx + dy*dy + dz*dz
+                       distance := math.Sqrt(dSquared)
+                       mag := dt / (dSquared * distance)
+
+                       body.vx -= dx * body2.mass * mag
+                       body.vy -= dy * body2.mass * mag
+                       body.vz -= dz * body2.mass * mag
+
+                       body2.vx += dx * body.mass * mag
+                       body2.vy += dy * body.mass * mag
+                       body2.vz += dz * body.mass * mag
+               }
+       }
+
+       for _, body := range sys {
+               body.x += dt * body.vx
+               body.y += dt * body.vy
+               body.z += dt * body.vz
+       }
+}
+
+var (
+       jupiter = Body{
+               x: 4.84143144246472090e+00,
+               y: -1.16032004402742839e+00,
+               z: -1.03622044471123109e-01,
+               vx: 1.66007664274403694e-03 * daysPerYear,
+               vy: 7.69901118419740425e-03 * daysPerYear,
+               vz: -6.90460016972063023e-05 * daysPerYear,
+               mass: 9.54791938424326609e-04 * solarMass,
+       }
+       saturn = Body{
+               x: 8.34336671824457987e+00,
+               y: 4.12479856412430479e+00,
+               z: -4.03523417114321381e-01,
+               vx: -2.76742510726862411e-03 * daysPerYear,
+               vy: 4.99852801234917238e-03 * daysPerYear,
+               vz: 2.30417297573763929e-05 * daysPerYear,
+               mass: 2.85885980666130812e-04 * solarMass,
+       }
+       uranus = Body{
+               x: 1.28943695621391310e+01,
+               y: -1.51111514016986312e+01,
+               z: -2.23307578892655734e-01,
+               vx: 2.96460137564761618e-03 * daysPerYear,
+               vy: 2.37847173959480950e-03 * daysPerYear,
+               vz: -2.96589568540237556e-05 * daysPerYear,
+               mass: 4.36624404335156298e-05 * solarMass,
+       }
+       neptune = Body{
+               x: 1.53796971148509165e+01,
+               y: -2.59193146099879641e+01,
+               z: 1.79258772950371181e-01,
+               vx: 2.68067772490389322e-03 * daysPerYear,
+               vy: 1.62824170038242295e-03 * daysPerYear,
+               vz: -9.51592254519715870e-05 * daysPerYear,
+               mass: 5.15138902046611451e-05 * solarMass,
+       }
+       sun = Body{
+               mass: solarMass,
+       }
+)
+
+func main() {
+       flag.Parse()
+
+       system := NewSystem([]Body{sun, jupiter, saturn, uranus, neptune})
+       fmt.Printf("%.9f\n", system.energy())
+       for i := 0; i < *n; i++ {
+               system.advance(0.01)
+       }
+       fmt.Printf("%.9f\n", system.energy())
+}
diff --git a/gcc/testsuite/go.test/test/bench/nbody.txt b/gcc/testsuite/go.test/test/bench/nbody.txt
new file mode 100644 (file)
index 0000000..1731557
--- /dev/null
@@ -0,0 +1,2 @@
+-0.169075164
+-0.169087605
diff --git a/gcc/testsuite/go.test/test/bench/pidigits.c b/gcc/testsuite/go.test/test/bench/pidigits.c
new file mode 100644 (file)
index 0000000..c064da0
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+  http://shootout.alioth.debian.org/
+
+  contributed by Paolo Bonzini & Sean Bartlett
+  modified by Michael Mellor
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gmp.h>
+
+static mpz_t numer, accum, denom, tmp1, tmp2;
+
+static int extract_digit()
+{
+  if (mpz_cmp(numer, accum) > 0)
+    return -1;
+
+  /* Compute (numer * 3 + accum) / denom */
+  mpz_mul_2exp(tmp1, numer, 1);
+  mpz_add(tmp1, tmp1, numer);
+  mpz_add(tmp1, tmp1, accum);
+  mpz_fdiv_qr(tmp1, tmp2, tmp1, denom);
+
+  /* Now, if (numer * 4 + accum) % denom... */
+  mpz_add(tmp2, tmp2, numer);
+
+  /* ... is normalized, then the two divisions have the same result.  */
+  if (mpz_cmp(tmp2, denom) >= 0)
+    return -1;
+
+  return mpz_get_ui(tmp1);
+}
+
+static void next_term(unsigned int k)
+{
+  unsigned int y2 = k*2 + 1;
+
+  mpz_mul_2exp(tmp1, numer, 1);
+  mpz_add(accum, accum, tmp1);
+  mpz_mul_ui(accum, accum, y2);
+  mpz_mul_ui(numer, numer, k);
+  mpz_mul_ui(denom, denom, y2);
+}
+
+static void eliminate_digit(unsigned int d)
+{
+  mpz_submul_ui(accum, denom, d);
+  mpz_mul_ui(accum, accum, 10);
+  mpz_mul_ui(numer, numer, 10);
+}
+
+static void pidigits(unsigned int n)
+{
+  int d;
+  unsigned int i = 0, k = 0, m;
+  mpz_init(tmp1);
+  mpz_init(tmp2);
+  mpz_init_set_ui(numer, 1);
+  mpz_init_set_ui(accum, 0);
+  mpz_init_set_ui(denom, 1);
+
+  for(;;)
+  {
+    do {
+      k++;
+      next_term(k);
+      d = extract_digit();
+    } while(d == -1);
+
+    putchar(d + '0');
+
+    i++;
+    m = i%10;
+    if(m == 0)
+      printf("\t:%d\n", i);
+    if(i >= n)
+      break;
+    eliminate_digit(d);
+  }
+
+  if(m) {
+    m = 10 - m;
+    while(m--)
+      putchar(' ');
+    printf("\t:%d\n", n);
+  }
+}
+
+int main(int argc, char **argv)
+{
+  pidigits(argc > 1 ? atoi(argv[1]) : 27);
+  return 0;
+}
diff --git a/gcc/testsuite/go.test/test/bench/pidigits.go b/gcc/testsuite/go.test/test/bench/pidigits.go
new file mode 100644 (file)
index 0000000..dcfb502
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on pidigits.c (by Paolo Bonzini & Sean Bartlett,
+ *                      modified by Michael Mellor)
+ */
+
+package main
+
+import (
+       "big"
+       "flag"
+       "fmt"
+)
+
+var n = flag.Int("n", 27, "number of digits")
+var silent = flag.Bool("s", false, "don't print result")
+
+var (
+       tmp1  = big.NewInt(0)
+       tmp2  = big.NewInt(0)
+       y2    = big.NewInt(0)
+       bigk  = big.NewInt(0)
+       numer = big.NewInt(1)
+       accum = big.NewInt(0)
+       denom = big.NewInt(1)
+       ten   = big.NewInt(10)
+)
+
+func extract_digit() int64 {
+       if numer.Cmp(accum) > 0 {
+               return -1
+       }
+
+       // Compute (numer * 3 + accum) / denom
+       tmp1.Lsh(numer, 1)
+       tmp1.Add(tmp1, numer)
+       tmp1.Add(tmp1, accum)
+       tmp1.DivMod(tmp1, denom, tmp2)
+
+       // Now, if (numer * 4 + accum) % denom...
+       tmp2.Add(tmp2, numer)
+
+       // ... is normalized, then the two divisions have the same result.
+       if tmp2.Cmp(denom) >= 0 {
+               return -1
+       }
+
+       return tmp1.Int64()
+}
+
+func next_term(k int64) {
+       // TODO(eds) If big.Int ever gets a Scale method, y2 and bigk could be int64
+       y2.SetInt64(k*2 + 1)
+       bigk.SetInt64(k)
+
+       tmp1.Lsh(numer, 1)
+       accum.Add(accum, tmp1)
+       accum.Mul(accum, y2)
+       numer.Mul(numer, bigk)
+       denom.Mul(denom, y2)
+}
+
+func eliminate_digit(d int64) {
+       tmp := big.NewInt(0).Set(denom)
+       accum.Sub(accum, tmp.Mul(tmp, big.NewInt(d)))
+       accum.Mul(accum, ten)
+       numer.Mul(numer, ten)
+}
+
+func printf(s string, arg ...interface{}) {
+       if !*silent {
+               fmt.Printf(s, arg)
+       }
+}
+
+func main() {
+       flag.Parse()
+
+       var m int // 0 <= m < 10
+       for i, k := 0, int64(0); ; {
+               d := int64(-1)
+               for d < 0 {
+                       k++
+                       next_term(k)
+                       d = extract_digit()
+               }
+
+               printf("%c", d+'0')
+
+               i++
+               m = i % 10
+               if m == 0 {
+                       printf("\t:%d\n", i)
+               }
+               if i >= *n {
+                       break
+               }
+               eliminate_digit(d)
+       }
+
+       if m > 0 {
+               printf("%s\t:%d\n", "          "[m:10], *n)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/bench/pidigits.txt b/gcc/testsuite/go.test/test/bench/pidigits.txt
new file mode 100644 (file)
index 0000000..ad946a9
--- /dev/null
@@ -0,0 +1,3 @@
+3141592653     :10
+5897932384     :20
+6264338        :27
diff --git a/gcc/testsuite/go.test/test/bench/regex-dna-parallel.go b/gcc/testsuite/go.test/test/bench/regex-dna-parallel.go
new file mode 100644 (file)
index 0000000..e8e62b8
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+       "fmt"
+       "io/ioutil"
+       "os"
+       "runtime"
+       "regexp"
+)
+
+var variants = []string{
+       "agggtaaa|tttaccct",
+       "[cgt]gggtaaa|tttaccc[acg]",
+       "a[act]ggtaaa|tttacc[agt]t",
+       "ag[act]gtaaa|tttac[agt]ct",
+       "agg[act]taaa|ttta[agt]cct",
+       "aggg[acg]aaa|ttt[cgt]ccct",
+       "agggt[cgt]aa|tt[acg]accct",
+       "agggta[cgt]a|t[acg]taccct",
+       "agggtaa[cgt]|[acg]ttaccct",
+}
+
+type Subst struct {
+       pat, repl string
+}
+
+var substs = []Subst{
+       Subst{"B", "(c|g|t)"},
+       Subst{"D", "(a|g|t)"},
+       Subst{"H", "(a|c|t)"},
+       Subst{"K", "(g|t)"},
+       Subst{"M", "(a|c)"},
+       Subst{"N", "(a|c|g|t)"},
+       Subst{"R", "(a|g)"},
+       Subst{"S", "(c|g)"},
+       Subst{"V", "(a|c|g)"},
+       Subst{"W", "(a|t)"},
+       Subst{"Y", "(c|t)"},
+}
+
+func countMatches(pat string, bytes []byte) int {
+       re := regexp.MustCompile(pat)
+       n := 0
+       for {
+               e := re.FindIndex(bytes)
+               if e == nil {
+                       break
+               }
+               n++
+               bytes = bytes[e[1]:]
+       }
+       return n
+}
+
+func main() {
+       runtime.GOMAXPROCS(4)
+       bytes, err := ioutil.ReadFile("/dev/stdin")
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "can't read input: %s\n", err)
+               os.Exit(2)
+       }
+       ilen := len(bytes)
+       // Delete the comment lines and newlines
+       bytes = regexp.MustCompile("(>[^\n]+)?\n").ReplaceAll(bytes, []byte{})
+       clen := len(bytes)
+
+       mresults := make([]chan int, len(variants))
+       for i, s := range variants {
+               ch := make(chan int)
+               mresults[i] = ch
+               go func(ss string) {
+                       ch <- countMatches(ss, bytes)
+               }(s)
+       }
+
+       lenresult := make(chan int)
+       bb := bytes
+       go func() {
+               for _, sub := range substs {
+                       bb = regexp.MustCompile(sub.pat).ReplaceAll(bb, []byte(sub.repl))
+               }
+               lenresult <- len(bb)
+       }()
+
+       for i, s := range variants {
+               fmt.Printf("%s %d\n", s, <-mresults[i])
+       }
+       fmt.Printf("\n%d\n%d\n%d\n", ilen, clen, <-lenresult)
+}
diff --git a/gcc/testsuite/go.test/test/bench/regex-dna-parallel.txt b/gcc/testsuite/go.test/test/bench/regex-dna-parallel.txt
new file mode 100644 (file)
index 0000000..e23e71f
--- /dev/null
@@ -0,0 +1,13 @@
+agggtaaa|tttaccct 1
+[cgt]gggtaaa|tttaccc[acg] 0
+a[act]ggtaaa|tttacc[agt]t 0
+ag[act]gtaaa|tttac[agt]ct 0
+agg[act]taaa|ttta[agt]cct 1
+aggg[acg]aaa|ttt[cgt]ccct 0
+agggt[cgt]aa|tt[acg]accct 0
+agggta[cgt]a|t[acg]taccct 0
+agggtaa[cgt]|[acg]ttaccct 2
+
+10245
+10000
+13348
diff --git a/gcc/testsuite/go.test/test/bench/regex-dna.c b/gcc/testsuite/go.test/test/bench/regex-dna.c
new file mode 100644 (file)
index 0000000..134f821
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+** The Computer Language Shootout
+** http://shootout.alioth.debian.org/
+** contributed by Mike Pall
+**
+** regex-dna benchmark using PCRE
+**
+** compile with:
+**   gcc -O3 -fomit-frame-pointer -o regexdna regexdna.c -lpcre
+*/
+
+#define __USE_STRING_INLINES
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pcre.h>
+
+typedef struct fbuf {
+  char *buf;
+  size_t size, len;
+} fbuf_t;
+
+static void fb_init(fbuf_t *b)
+{
+  b->buf = NULL;
+  b->len = b->size = 0;
+}
+
+static char *fb_need(fbuf_t *b, size_t need)
+{
+  need += b->len;
+  if (need > b->size) {
+    if (b->size == 0) b->size = need;
+    else while (need > b->size) b->size += b->size;
+    if (!(b->buf = realloc(b->buf, b->size))) exit(1);
+  }
+  return b->buf+b->len;
+}
+
+#define FB_MINREAD     (3<<16)
+
+/* Read all of a stdio stream into dst buffer. */
+static size_t fb_readall(fbuf_t *dst, FILE *fp)
+{
+  char *dp;
+  int n;
+  for (dp = fb_need(dst, FB_MINREAD);
+       (n = fread(dp, 1, dst->size-dst->len, fp)) > 0;
+       dp = fb_need(dst, FB_MINREAD)) dst->len += n;
+  if (ferror(fp)) exit(1);
+  return dst->len;
+}
+
+/* Substitute pattern p with replacement r, copying from src to dst buffer. */
+static size_t fb_subst(fbuf_t *dst, fbuf_t *src, const char *p, const char *r)
+{
+  pcre *re;
+  pcre_extra *re_ex;
+  const char *re_e;
+  char *dp;
+  int re_eo, m[3], pos, rlen, clen;
+  if (!(re = pcre_compile(p, PCRE_CASELESS, &re_e, &re_eo, NULL))) exit(1);
+  re_ex = pcre_study(re, 0, &re_e);
+  for (dst->len = 0, rlen = strlen(r), pos = 0;
+       pcre_exec(re, re_ex, src->buf, src->len, pos, 0, m, 3) >= 0;
+       pos = m[1]) {
+    clen = m[0]-pos;
+    dp = fb_need(dst, clen+rlen);
+    dst->len += clen+rlen;
+    memcpy(dp, src->buf+pos, clen);
+    memcpy(dp+clen, r, rlen);
+  }
+  clen = src->len-pos;
+  dp = fb_need(dst, clen);
+  dst->len += clen;
+  memcpy(dp, src->buf+pos, clen);
+  return dst->len;
+}
+
+/* Count all matches with pattern p in src buffer. */
+static int fb_countmatches(fbuf_t *src, const char *p)
+{
+  pcre *re;
+  pcre_extra *re_ex;
+  const char *re_e;
+  int re_eo, m[3], pos, count;
+  if (!(re = pcre_compile(p, PCRE_CASELESS, &re_e, &re_eo, NULL))) exit(1);
+  re_ex = pcre_study(re, 0, &re_e);
+  for (count = 0, pos = 0;
+       pcre_exec(re, re_ex, src->buf, src->len, pos, 0, m, 3) >= 0;
+       pos = m[1]) count++;
+  return count;
+}
+
+static const char *variants[] = {
+  "agggtaaa|tttaccct",         "[cgt]gggtaaa|tttaccc[acg]",
+  "a[act]ggtaaa|tttacc[agt]t", "ag[act]gtaaa|tttac[agt]ct",
+  "agg[act]taaa|ttta[agt]cct", "aggg[acg]aaa|ttt[cgt]ccct",
+  "agggt[cgt]aa|tt[acg]accct", "agggta[cgt]a|t[acg]taccct",
+  "agggtaa[cgt]|[acg]ttaccct", NULL
+};
+
+static const char *subst[] = {
+  "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|g)",
+  "V", "(a|c|g)", "W", "(a|t)",     "Y", "(c|t)",   NULL
+};
+
+int main(int argc, char **argv)
+{
+  fbuf_t seq[2];
+  const char **pp;
+  size_t ilen, clen, slen;
+  int flip;
+  fb_init(&seq[0]);
+  fb_init(&seq[1]);
+  ilen = fb_readall(&seq[0], stdin);
+  clen = fb_subst(&seq[1], &seq[0], ">.*|\n", "");
+  for (pp = variants; *pp; pp++)
+    printf("%s %d\n", *pp, fb_countmatches(&seq[1], *pp));
+  for (slen = 0, flip = 1, pp = subst; *pp; pp += 2, flip = 1-flip)
+    slen = fb_subst(&seq[1-flip], &seq[flip], *pp, pp[1]);
+  printf("\n%zu\n%zu\n%zu\n", ilen, clen, slen);
+  return 0;
+}
diff --git a/gcc/testsuite/go.test/test/bench/regex-dna.go b/gcc/testsuite/go.test/test/bench/regex-dna.go
new file mode 100644 (file)
index 0000000..dc31db7
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+       "fmt"
+       "io/ioutil"
+       "os"
+       "regexp"
+)
+
+var variants = []string{
+       "agggtaaa|tttaccct",
+       "[cgt]gggtaaa|tttaccc[acg]",
+       "a[act]ggtaaa|tttacc[agt]t",
+       "ag[act]gtaaa|tttac[agt]ct",
+       "agg[act]taaa|ttta[agt]cct",
+       "aggg[acg]aaa|ttt[cgt]ccct",
+       "agggt[cgt]aa|tt[acg]accct",
+       "agggta[cgt]a|t[acg]taccct",
+       "agggtaa[cgt]|[acg]ttaccct",
+}
+
+type Subst struct {
+       pat, repl string
+}
+
+var substs = []Subst{
+       Subst{"B", "(c|g|t)"},
+       Subst{"D", "(a|g|t)"},
+       Subst{"H", "(a|c|t)"},
+       Subst{"K", "(g|t)"},
+       Subst{"M", "(a|c)"},
+       Subst{"N", "(a|c|g|t)"},
+       Subst{"R", "(a|g)"},
+       Subst{"S", "(c|g)"},
+       Subst{"V", "(a|c|g)"},
+       Subst{"W", "(a|t)"},
+       Subst{"Y", "(c|t)"},
+}
+
+func countMatches(pat string, bytes []byte) int {
+       re := regexp.MustCompile(pat)
+       n := 0
+       for {
+               e := re.FindIndex(bytes)
+               if len(e) == 0 {
+                       break
+               }
+               n++
+               bytes = bytes[e[1]:]
+       }
+       return n
+}
+
+func main() {
+       bytes, err := ioutil.ReadFile("/dev/stdin")
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "can't read input: %s\n", err)
+               os.Exit(2)
+       }
+       ilen := len(bytes)
+       // Delete the comment lines and newlines
+       bytes = regexp.MustCompile("(>[^\n]+)?\n").ReplaceAll(bytes, []byte{})
+       clen := len(bytes)
+       for _, s := range variants {
+               fmt.Printf("%s %d\n", s, countMatches(s, bytes))
+       }
+       for _, sub := range substs {
+               bytes = regexp.MustCompile(sub.pat).ReplaceAll(bytes, []byte(sub.repl))
+       }
+       fmt.Printf("\n%d\n%d\n%d\n", ilen, clen, len(bytes))
+}
diff --git a/gcc/testsuite/go.test/test/bench/regex-dna.txt b/gcc/testsuite/go.test/test/bench/regex-dna.txt
new file mode 100644 (file)
index 0000000..e23e71f
--- /dev/null
@@ -0,0 +1,13 @@
+agggtaaa|tttaccct 1
+[cgt]gggtaaa|tttaccc[acg] 0
+a[act]ggtaaa|tttacc[agt]t 0
+ag[act]gtaaa|tttac[agt]ct 0
+agg[act]taaa|ttta[agt]cct 1
+aggg[acg]aaa|ttt[cgt]ccct 0
+agggt[cgt]aa|tt[acg]accct 0
+agggta[cgt]a|t[acg]taccct 0
+agggtaa[cgt]|[acg]ttaccct 2
+
+10245
+10000
+13348
diff --git a/gcc/testsuite/go.test/test/bench/reverse-complement.c b/gcc/testsuite/go.test/test/bench/reverse-complement.c
new file mode 100644 (file)
index 0000000..b34c846
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org
+ *
+ * contributed by Bob W
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define JBFSIZE 82      // line input buffer size
+#define QBFSIZE 5200     // output buffer initial size
+#define Z16     "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+#define V32     "\0TVGH\0\0CD\0\0M\0KN\0\0\0YSA\0BW\0R\0\0\0\0\0\0"
+#define VALL    Z16 Z16 Z16 Z16 V32 V32 Z16 Z16 Z16 Z16 Z16 Z16 Z16 Z16
+
+int errex(char *s, int n) {      // error message+value, return 1
+  fprintf(stderr,"\n*** Error: %s [%d]!\n", s, n);
+  return 1;
+}
+
+int main () {                    // ***** main *****
+  char *pj, *pq, *pr;            // buffer pointers: inp,out,/out
+  char *jjj = malloc(JBFSIZE);   // allocate input line buffer
+  char *qqq = malloc(QBFSIZE);   // output buffer (dyn. size)
+  char *pqstop = qqq+QBFSIZE;    // end-of-buffer pointer
+  char xtab[256] = VALL;         // char conversion table
+
+  if (!jjj || !qqq)
+    return errex("Buffer allocation", !jjj + !qqq);
+  pj = fgets(jjj,JBFSIZE,stdin);         // fetch 1st line
+  if (!pj)
+    return errex("No input data",0);
+  if (*jjj != '>')
+    return errex("1st char not '>'", 0);
+
+  while (pj) {                           // MAIN LOOP: process data
+    fputs(jjj, stdout);                  // output ID line
+
+    for (pq=qqq+1, pr=pqstop; ; pq++) {  // LOOP: fill output buffer
+      pj = fgets(jjj, JBFSIZE, stdin);   // get line from stdin
+      if (!pj || (*jjj=='>'))  break;    // EOF or new ID line
+      if (pr <= (pq+61)) {               // need to resize buffer
+        char *newstop = pqstop + 12777888;
+        char *newptr  = realloc(qqq, newstop-qqq);
+        if (!newptr)
+          return errex("Out of memory", 0);
+        if (newptr != qqq) {             // new base: adj. pointers
+          size_t x = newptr-qqq;         // offset for pointer update
+          pq+=x;  pr+=x;  qqq+=x;
+          newstop+=x;  pqstop+=x;
+        }
+        pr = __builtin_memmove(newstop-(pqstop-pr), pr, pqstop-pr);
+        pqstop = newstop;                // buffer resize complete
+      }
+      while (*pj) {                      // LOOP: conv. & revert line
+        char c = xtab[(unsigned char)(*pj++)];
+        if (c)                           // conversion valid
+          *(--pr) = c;
+      }
+    }
+
+    for (pq = qqq; pr<pqstop; ) {        // LOOP: format output
+      size_t x = (pqstop-pr)<60 ? pqstop-pr : 60;
+      __builtin_memmove(pq,pr,x);        // move line to free space
+      pr+=x;  pq+=x;  *(pq++) = 0xA;     // adjust pointers, add LF
+    }
+    fwrite(qqq, 1, pq-qqq, stdout);      // output converted data
+  }
+  return 0;
+}
diff --git a/gcc/testsuite/go.test/test/bench/reverse-complement.go b/gcc/testsuite/go.test/test/bench/reverse-complement.go
new file mode 100644 (file)
index 0000000..baa30ff
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+       "bufio"
+       "os"
+)
+
+const lineSize = 60
+
+var complement = [256]uint8{
+       'A': 'T', 'a': 'T',
+       'C': 'G', 'c': 'G',
+       'G': 'C', 'g': 'C',
+       'T': 'A', 't': 'A',
+       'U': 'A', 'u': 'A',
+       'M': 'K', 'm': 'K',
+       'R': 'Y', 'r': 'Y',
+       'W': 'W', 'w': 'W',
+       'S': 'S', 's': 'S',
+       'Y': 'R', 'y': 'R',
+       'K': 'M', 'k': 'M',
+       'V': 'B', 'v': 'B',
+       'H': 'D', 'h': 'D',
+       'D': 'H', 'd': 'H',
+       'B': 'V', 'b': 'V',
+       'N': 'N', 'n': 'N',
+}
+
+func main() {
+       in := bufio.NewReader(os.Stdin)
+       buf := make([]byte, 1024*1024)
+       line, err := in.ReadSlice('\n')
+       for err == nil {
+               os.Stdout.Write(line)
+
+               // Accumulate reversed complement in buf[w:]
+               nchar := 0
+               w := len(buf)
+               for {
+                       line, err = in.ReadSlice('\n')
+                       if err != nil || line[0] == '>' {
+                               break
+                       }
+                       line = line[0 : len(line)-1]
+                       nchar += len(line)
+                       if len(line)+nchar/60+128 >= w {
+                               nbuf := make([]byte, len(buf)*5)
+                               copy(nbuf[len(nbuf)-len(buf):], buf)
+                               w += len(nbuf) - len(buf)
+                               buf = nbuf
+                       }
+
+                       // This loop is the bottleneck.
+                       for _, c := range line {
+                               w--
+                               buf[w] = complement[c]
+                       }
+               }
+
+               // Copy down to beginning of buffer, inserting newlines.
+               // The loop left room for the newlines and 128 bytes of padding.
+               i := 0
+               for j := w; j < len(buf); j += 60 {
+                       n := copy(buf[i:i+60], buf[j:])
+                       buf[i+n] = '\n'
+                       i += n + 1
+               }
+               os.Stdout.Write(buf[0:i])
+       }
+}
diff --git a/gcc/testsuite/go.test/test/bench/reverse-complement.txt b/gcc/testsuite/go.test/test/bench/reverse-complement.txt
new file mode 100644 (file)
index 0000000..14d792a
--- /dev/null
@@ -0,0 +1,171 @@
+>ONE Homo sapiens alu
+CGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAAC
+CTCCGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACA
+GGCGCGCGCCACCACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCAT
+GTTGGCCAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAA
+AGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTC
+TGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCGCCTCCCGG
+GTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCGCGCCACC
+ACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGGCCAGGCTG
+GTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTA
+CAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCT
+GGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCGCCTCCCGGGTTCAAGCGATTC
+TCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCGCGCCACCACGCCCGGCTAAT
+TTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGGCCAGGCTGGTCTCGAACTCCT
+GACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCA
+CCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGC
+GCGATCTCGGCTCACTGCAACCTCCGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCC
+TCCCGAGTAGCTGGGATTACAGGCGCGCGCCACCACGCCCGGCTAATTTTTGTATTTTTA
+GTAGAGACGGGGTTTCACCATGTTGGCCAGGCTGGTCTCGAACTCCTGACCTCAGGTGAT
+CCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCT
+TTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTC
+ACTGCAACCTCCGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTG
+GGATTACAGGCGCGCGCCACCACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGT
+TTCACCATGTTGGCCAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGG
+CCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAG
+TCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCG
+CCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGC
+GCGCCACCACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGG
+CCAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGC
+TGGGATTACAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTCTGTCG
+CCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCGCCTCCCGGGTTCA
+AGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCGCGCCACCACGCC
+CGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGGCCAGGCTGGTCTC
+GAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGC
+GTGAGCCACCGCGCCCGGCC
+>TWO IUB ambiguity codes
+TAGGDHACHATCRGTRGVTGAGWTATGYTGCTGTCABACDWVTRTAAGAVVAGATTTNDA
+GASMTCTGCATBYTTCAAKTTACMTATTACTTCATARGGYACMRTGTTTTYTATACVAAT
+TTCTAKGDACKADACTATATNTANTCGTTCACGBCGYSCBHTANGGTGATCGTAAAGTAA
+CTATBAAAAGATSTGWATBCSGAKHTTABBAACGTSYCATGCAAVATKTSKTASCGGAAT
+WVATTTNTCCTTCTTCTTDDAGTGGTTGGATACVGTTAYMTMTBTACTTTHAGCTAGBAA
+AAGAGKAAGTTRATWATCAGATTMDDTTTAAAVAAATATTKTCYTAAATTVCNKTTRACG
+ADTATATTTATGATSADSCAATAWAGCGRTAGTGTAAGTGACVGRADYGTGCTACHVSDT
+CTVCARCSYTTAATATARAAAATTTAATTTACDAATTGBACAGTAYAABATBTGCAGBVG
+TGATGGDCAAAATBNMSTTABKATTGGSTCCTAGBTTACTTGTTTAGTTTATHCGATSTA
+AAGTCGAKAAASTGTTTTAWAKCAGATATACTTTTMTTTTGBATAGAGGAGCMATGATRA
+AAGGNCAYDCCDDGAAAGTHGBTAATCKYTBTACBGTBCTTTTTGDTAASSWTAAWAARA
+TTGGCTAAGWGRADTYACATAGCTCBTAGATAWAGCAATNGTATMATGTTKMMAGTAWTC
+CCNTSGAAWATWCAAAAMACTGAADNTYGATNAATCCGAYWNCTAACGTTAGAGDTTTTC
+ATCTGGKRTAVGAABVCTGWGBTCTDVGKATTBTCTAAGGVADAAAVWTCTAGGGGAGGG
+TTAGAACAATTAAHTAATNAAATGCATKATCTAAYRTDTCAGSAYTTYHGATRTTWAVTA
+BGNTCDACAGBCCRCAGWCRTCABTGMMAWGMCTCAACCGATRTGBCAVAATCGTDWDAA
+CAYAWAATWCTGGTAHCCCTAAGATAACSCTTAGTGSAACAWTBGTCDTTDGACWDBAAC
+HTTTNGSKTYYAAYGGATNTGATTTAARTTAMBAATCTAAGTBTCATYTAACTTADTGTT
+TCGATACGAAHGGCYATATACCWDTKYATDCSHTDTCAAAATGTGBACTGSCCVGATGTA
+TCMMAGCCTTDAAABAATGAAGAGTAACTHATMGVTTAATAACCCGGTTVSANTGCAATT
+GTGAGATTTAMGTTTAMAAYGCTGACAYAAAAAGGCACAMYTAAGVGGCTGGAABVTACG
+GATTSTYGTBVAKTATWACCGTGTKAGTDTGTATGTTTAAAGGAAAAAGTAACATARAAA
+GGTYCAMNYAAABTATAGNTSATANAGTCATCCTATWADKAACTRGTMSACDGTATSAYT
+AAHSHGTAABYGACTYTATADTGSTATAGAGAAATCGNTAAAGGAAATCAGTTGTNCYMV
+TNACDRTATBNATATASTAGAAMSCGGGANRCKKMCAAACATTNAGTCTRMAATBMTACC
+CGTACTTCTBGDSYAATWGAAAATGACADDCHAKAAAYATATTKTTTTCACANACWAGAA
+AKATCCTTATTAYKHKCTAAACARTATTTTDATBTVWCYGCAATACTAGGKAAASTTDGA
+MGGCHTTHAATVCAHDRYAGGRCTATACGTCMAGAGAGCTBTHGNACARTCCBDCTAAGA
+GCGGCTTTARTAAAGAATCCNAGTAWBTGACTTGAATTACWTVACAGAAABCAATNAAAC
+CGTNTRANTTGAYCMAWBADTANABRGGTKTHTWTAGTTVCTMBKTAGMTVKCCAGCANT
+TVAGSWTTAGCCGCRHTTTCCTTHNTATTAAGAAGAATAGGMTRAARTCTABGTACDTTT
+TATAAVDHAHTATAGATCCTAGTAAGYTWATDWCATGAGGGATAGTAAMDMNGBASTWAM
+TSTATRBAYDABATGTATATYCGCACTGTTTTAACMCWBTATAWAGTATBTSTATVTTAR
+CCTMTTAAKADATCAACTAATYTSVTAKGDATTATGCKTCAYCAKAATACTTKAANGAGT
+ATTSDAGATCGGAAATACTTAAYAAVGTATMCGCTTGTGTDCTAATYTATTTTATTTWAA
+CAGWRCTATGTAGMTGTTTGTTYKTNGTTKTCAGAACNTRACCTACKTGSRATGTGGGGG
+CTGTCATTAAGTAAATNGSTTABCCCCTCGCAGCTCWHTCGCGAAGCAVATGCKACGHCA
+ACAKTTAATAACASAAADATTWNYTGTAATTGTTCGTMHACHTWATGTGCWTTTTGAAHY
+ACTTTGTAYAMSAAACTTAADAAATATAGTABMATATYAATGSGGTAGTTTGTGTBYGGT
+TWSGSVGWMATTDMTCCWWCABTCSVACAGBAATGTTKATBGTCAATAATCTTCTTAAAC
+ARVAATHAGYBWCTRWCABGTWWAATCTAAGTCASTAAAKTAAGVKBAATTBGABACGTA
+AGGTTAAATAAAAACTRMDTWBCTTTTTAATAAAAGATMGCCTACKAKNTBAGYRASTGT
+ASSTCGTHCGAAKTTATTATATTYTTTGTAGAACATGTCAAAACTWTWTHGKTCCYAATA
+AAGTGGAYTMCYTAARCSTAAATWAKTGAATTTRAGTCTSSATACGACWAKAASATDAAA
+TGYYACTSAACAAHAKTSHYARGASTATTATTHAGGYGGASTTTBGAKGATSANAACACD
+TRGSTTRAAAAAAAACAAGARTCVTAGTAAGATAWATGVHAAKATWGAAAAGTYAHVTAC
+TCTGRTGTCAWGATRVAAKTCGCAAVCGASWGGTTRTCSAMCCTAACASGWKKAWDAATG
+ACRCBACTATGTGTCTTCAAAHGSCTATATTTCGTVWAGAAGTAYCKGARAKSGKAGTAN
+TTTCYACATWATGTCTAAAADMDTWCAATSTKDACAMAADADBSAAATAGGCTHAHAGTA
+CGACVGAATTATAAAGAHCCVAYHGHTTTACATSTTTATGNCCMTAGCATATGATAVAAG
+>THREE Homo sapiens frequency
+ATATTTATCTTTTCACTTCCTACATTGGTCAGACCATTATTCGACACGTGGCGTCATTTT
+GTCATACCGGGTAATGTTGGAAACAAAACGTACTGATAAAATACTGAGTTGTAAACTCTA
+ATCAGATAACGCGCTTGGATATTAAGATTCACACAGGGGTTTCGGCTGTAAAAAAACTTG
+TGGAGCTGTTCTGGGACAGATAAGTTGTACCTCGTACTTAGCTAATTAATGAACCAACTG
+ATTACGATAGAACAATTCTGAGGCCGCCAGGACAGCCAAATTTTAATCTTATAAAGCTGG
+AAACAGCCGGTATTAGCTTCTCGCATACTTTGCCTGCATTGGTACCTTACAGATATCAGC
+GTAGTCATATACACCTCGGTCTCAGCTAAGCTTGTATCTCTTAGAGTAGTTCAAAGATAG
+TGGACAATACCTGTGGAATCGATTGCAGATATGGATTTATTTAACTACTGAGTCTCATTC
+ACAAGCTAAGCAAGGAGCACGTTTTGGTGCCGGCATACCGATTTGCTATCATGTCAGCAA
+ATTTGCGTTGTATTCCTAGTTGCACCCATTAAGGCCACACTCCGAACCTAATTATTACAT
+CGCAAAGACATGTACGAAGGACCCGATGTCGAATAGAAGGGAGGACTGTTCATTGGAAGC
+TAGACCAGAGGAATCGCAAAGATGCAACTCTTACAATAAAAATCTAATTTCAGTCAACAC
+GCAATTTCTATAAGGTTTCCGATAATAATGAACCGTCTTCCACAGGGGAATTTGCCATGC
+TCGTAAAAGTAGTTAATCCAAGTAGAAGAAATTTTGATAATGTTTTAAGTTGGCACGAAG
+GAATTCAGAGAGATCTTACCTAACAAAGGCATTAGTAGATGTTCCTTGGTTCACACTCGG
+TCAATCAGAGCACATACTACGGGCGATACCGGGAATGACACAACATCAATGAGATTGTTA
+AGTGAGGTAATTGACTTTAGAGGACTCGATCAGTATACTGTCACTATGAACATCGTATTA
+ATTGTTATCCGATATATACACCACCGATTTGCTTGTGCAAGGTTACAGACCCATTCGATA
+AATACAAACACGGAGCGATATTATTTAAGGAGTGCTGTCTTCAAAAGAATTATTCCCACA
+CCGACATAAGAACTTCGCTCCGTCATTCCAGATTTAAATAACATAACGTAACGCTTTGCT
+GATAACATAACATAACCGAGAATTTGCTTAGGAAATTTGGAGCAATATTGCATTGTTTCT
+CAGTCATCACAAGGCCCGCCAAAGAACTCTGAGAATCAGGATTCAACATGATTGGTAAGA
+CTCTATATATATAACTTAATTCTTGTGTCCGGAGATAGAAAGAGGACGAGAGATACTACG
+AAAGAAAGTGTACTTCGATGTATCAATTCAGACGCCTTCTCTATCATCAACATTATAGGT
+CTCGTATATGCTCGGCGCGATCTGCTTCTCTCCGCCAATAGCCCCATAGTGTATTTCAAG
+CGCAGTAACAGTGAAATCGTTACGAAGGTAGGGATGTTGCTTATAATTGTCGTAACTTAT
+CGCTTATGTATCTTTCAAGAATGAACGGCAGCATATACATACGTTCTACCTTTAGCTACA
+AAGCATCCATATACTCCCTCTCATGATTGAAACTCTTCCCTATTTTGTAGCCAATAGTGA
+AAGCGTATTAGTATAAATTCGTCGGTTTTTCACTCGCAACTGTTATACTCTGCAAACAAA
+CGAAAGCCTCATAGTACAAACCTAAAGCTACATACTTCATCATTGGCAGACCAGTGGCGG
+TATTTCTACGGAAGCATCACTATAGATATAAAGTTTCCCTTCATGTACGTCTGTTAACCA
+TATCACAAGAAACTGCTATCTCTGTCACGTAACAATTCACGCGCCTTATCGCCAAATGTT
+CATATATGCGCGGTATACGTATGAACGAATACTAATTAGTATAACGGAGGATTCACGGGA
+GGGATACTTGGGGCATTTATAAATCGTCTAAAAATTTTCTATCAGCACTTGCGGGTTATA
+GTGGATTACTAGGCAACATAATATTCTGTATTGGTCCAAATGACGCTATAGATAAATTAG
+CAAAATACATTGTTTCCATTTATGTAAGTCGAAACTCCAGGACTCCCGGGAACCAGTTAA
+ACCGTCTGGAAAAGACACATTGTGAGCGGGACTTCAATGATAGCTTTCAATGAGCTTCTC
+ATGCTTGGGGTCTGTACATATATGTTGGCGAAATTATCGTCTGTATTCTGTTATGCTTTG
+ATCATGGGTTATTAGTATAGTGTCCGGTTAAGTACCAATACCGCTAGAGACCCGACCTAA
+GTCGATAACTAACGATCATCGACGTAAGGATCGTCTCGATCAGTACTTCAGTCTAGATCT
+GGGAATAGTAACTCGTTAGTGAACTATGTCGTGTCATAACTCTAAAATGCAATCAAATCT
+TATTATTGAGTATTGATTATATAAAGCATCCGCTTAGCTTTACCCTCAAATGTTATATGC
+AATTTAAAGCGCTTGATATCGTCTACTCAAGTTCAGGTTTCACATGGCCGCAACGTGACG
+TTATTAGAGGTGGGTCATCATCTCTGAGGCTAGTGATGTTGAATACTCATTGAATGGGAA
+GTGGAATACCATGCTCGTAGGTAACAGCATGACCTATAAAATATACTATGGGTGTGTGGT
+AGATCAATATTGTTCAAGCATATCGTAACAATAACGGCTGAAATGTTACTGACATGAAAG
+AGGGAGTCCAAACCATTCTAACAGCTGATCAAGTCGTCTAAAAACGCCTGGTTCAGCCTT
+AAGAGTTATAAGCCAGACAAATTGTATCAATAGAGAATCCGTAAATTCCTCGGCCAACCT
+CTTGCAAAGACATCACTATCAATATACTACCGTGATCTTAATTAGTGAACTTATATAAAT
+ATCTACAACCAGATTCAACGGAAAAGCTTTAGTGGATTAGAAATTGCCAAGAATCACATT
+CATGTGGGTTCGAATGCTTTAGTAATACCATTTCGCCGAGTAGTCACTTCGCTGAACTGT
+CGTAAATTGCTATGACATAATCGAAAAGGATTGTCAAGAGTCGATTACTGCGGACTAATA
+ATCCCCACGGGGGTGGTCTCATGTCTCCCCAGGCGAGTGGGGACGGTTGATAAACACGCT
+GCATCGCGGACTGATGTTCCCAGTATTACATAGTCACATTGGATTGCGAGTAGTCTACCT
+ATTTATGAGCGAGAGATGCCTCTAACTACTTCGACTTTTAAAACCTTTCCACGCCAGTAT
+TCGGCGAAAGGGAAGTATTAAGGGTTGTCATAATTAAGCTGATACCACTTCAGACTTTGC
+TCTACTTCTGTCTTTCATTGGTTTAGTAAAGTCTGTCCATTCGTCGAGACCGTCTTTTGC
+AGCCTCATTCTACCAACTGCTCCGACTCTTAGTCTGCTTCTCCCAGCGTTATAACAAGAG
+GCATTTTGTCATCCTTAAAACAATAATAAAGAACTCGGAGCACTGATATAATGACTGAAT
+TAGAACCGCTTAAAAATACAACGAATAGATAAGACTATCGGATAAGATCTAATATGTAGT
+GATTAAGCCCTTTATTAATTAATAATAGTTACCCTTTCTGATGTAACGCGACATATTACG
+ATTTAGTGGCACGTCTGAATTGCAAAGCAGATCTCTACCCGATTTTTATTATAAATCCCG
+TATACATCTTGACTTGAGTAATTGTTCATCTTTTTATATCTCTTCGTACTACAAATAATT
+AATATCTCAACCCGTATTGTGTGATTCTAATTACCAACAGAATACGAGGAGGTTTTTGCT
+TAGGGCCATATATAATGAATCTATCTCGTTTATTCGCGGAACCCGAGATAACATTACGAT
+GTAACTATTTTAGAGAACTTAATACAAGAAACATTGCTGATTACTCATAACTAAATGCTT
+GGTAATATATCCTCAGTGCCCCTACCATCTTTTACGCAGGGATGTAATTACTTAGGATTC
+ATTGTGTAAGAATTACAATGAACGATGGATATGAAGGCATGTTGCGAGGTGTTCCTTGGT
+ATGTGAAGTTCGCAGGGCAACAAAAATTTCGCAGAATAGGCCTCAAAGTATTGGTAAAGA
+AGACAACTAATCATCACGAGCTTCTGATATCAATACGAACGAGTCCTGTGATGGATGAAA
+GAAAGTCGTATCGAAAATGTCAAGAGTCTGCCCAATGTAACTTACTTCAAAAAATAACGC
+TTCCGCCAAGTACGTTCGAATAAACGTAATTTTAAAAATACATAAGGGGTGTTAGAAAGT
+AAGCGACGGGATATAAGTTAGACTCAAGATTCCGCCGTAAAACGAGACTGATTCCGAAGA
+TTGTTCGTGGATCTGGTCATGACTTTCACTGAGTAAGGAGTTTCGACATATGTCAATAAA
+CACAAAAATAGAAGCTATTCGATCTGAAAAATATTAGGACAAGAAACTATCTCACGCTAG
+CCCAGAATATTCACTCACCCACGGGCGATACTAAAGCACTATATAGTCGCGTGATTACTA
+TACATATGGTACACATAAGAATCACGATCAGGTTCTCAATTTTCAACAATATATGTTTAT
+TTGCATAGGTAATATTAGGCCTTTAAGAGAAGGATGGGTGAGATACTCCGGGGATGGCGG
+CAATAAAGAAAAACACGATATGAGTAATAGGATCCTAATATCTTGGCGAGAGACTTAAGG
+TACGAATTTTGCGCAATCTATTTTTTACTTGGCCAGAATTCATGTATGGTATAAGTACGA
+ACTTTTTTGATCACTTTCATGGCTACCTGATTAGGATAGTTTGAGGAATTTCCCAAATAT
+ACCGATTTAATATACACTAGGGCTTGTCACTTTGAGTCAGAAAAAGAATATAATTACTTA
+GGGTAATGCTGCATACATATTCTTATATTGCAAAGGTTCTCTGGGTAATCTTGAGCCTTC
+ACGATACCTGGTGAAGTGTT
diff --git a/gcc/testsuite/go.test/test/bench/spectral-norm-parallel.go b/gcc/testsuite/go.test/test/bench/spectral-norm-parallel.go
new file mode 100644 (file)
index 0000000..2706f39
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on spectral-norm.c by Sebastien Loisel
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "math"
+       "runtime"
+)
+
+var n = flag.Int("n", 2000, "count")
+var nCPU = flag.Int("ncpu", 4, "number of cpus")
+
+func evalA(i, j int) float64 { return 1 / float64(((i+j)*(i+j+1)/2 + i + 1)) }
+
+type Vec []float64
+
+func (v Vec) Times(i, n int, u Vec, c chan int) {
+       for ; i < n; i++ {
+               v[i] = 0
+               for j := 0; j < len(u); j++ {
+                       v[i] += evalA(i, j) * u[j]
+               }
+       }
+       c <- 1
+}
+
+func (v Vec) TimesTransp(i, n int, u Vec, c chan int) {
+       for ; i < n; i++ {
+               v[i] = 0
+               for j := 0; j < len(u); j++ {
+                       v[i] += evalA(j, i) * u[j]
+               }
+       }
+       c <- 1
+}
+
+func wait(c chan int) {
+       for i := 0; i < *nCPU; i++ {
+               <-c
+       }
+}
+
+func (v Vec) ATimesTransp(u Vec) {
+       x := make(Vec, len(u))
+       c := make(chan int, *nCPU)
+       for i := 0; i < *nCPU; i++ {
+               go x.Times(i*len(v) / *nCPU, (i+1)*len(v) / *nCPU, u, c)
+       }
+       wait(c)
+       for i := 0; i < *nCPU; i++ {
+               go v.TimesTransp(i*len(v) / *nCPU, (i+1)*len(v) / *nCPU, x, c)
+       }
+       wait(c)
+}
+
+func main() {
+       flag.Parse()
+       runtime.GOMAXPROCS(*nCPU)
+       N := *n
+       u := make(Vec, N)
+       for i := 0; i < N; i++ {
+               u[i] = 1
+       }
+       v := make(Vec, N)
+       for i := 0; i < 10; i++ {
+               v.ATimesTransp(u)
+               u.ATimesTransp(v)
+       }
+       var vBv, vv float64
+       for i := 0; i < N; i++ {
+               vBv += u[i] * v[i]
+               vv += v[i] * v[i]
+       }
+       fmt.Printf("%0.9f\n", math.Sqrt(vBv/vv))
+}
diff --git a/gcc/testsuite/go.test/test/bench/spectral-norm.c b/gcc/testsuite/go.test/test/bench/spectral-norm.c
new file mode 100644 (file)
index 0000000..832eb3d
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* -*- mode: c -*-
+ *
+ * The Great Computer Language Shootout
+ * http://shootout.alioth.debian.org/
+ *
+ * Contributed by Sebastien Loisel
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+double eval_A(int i, int j) { return 1.0/((i+j)*(i+j+1)/2+i+1); }
+
+void eval_A_times_u(int N, const double u[], double Au[])
+{
+  int i,j;
+  for(i=0;i<N;i++)
+    {
+      Au[i]=0;
+      for(j=0;j<N;j++) Au[i]+=eval_A(i,j)*u[j];
+    }
+}
+
+void eval_At_times_u(int N, const double u[], double Au[])
+{
+  int i,j;
+  for(i=0;i<N;i++)
+    {
+      Au[i]=0;
+      for(j=0;j<N;j++) Au[i]+=eval_A(j,i)*u[j];
+    }
+}
+
+void eval_AtA_times_u(int N, const double u[], double AtAu[])
+{ double v[N]; eval_A_times_u(N,u,v); eval_At_times_u(N,v,AtAu); }
+
+int main(int argc, char *argv[])
+{
+  int i;
+  int N = ((argc == 2) ? atoi(argv[1]) : 2000);
+  double u[N],v[N],vBv,vv;
+  for(i=0;i<N;i++) u[i]=1;
+  for(i=0;i<10;i++)
+    {
+      eval_AtA_times_u(N,u,v);
+      eval_AtA_times_u(N,v,u);
+    }
+  vBv=vv=0;
+  for(i=0;i<N;i++) { vBv+=u[i]*v[i]; vv+=v[i]*v[i]; }
+  printf("%0.9f\n",sqrt(vBv/vv));
+  return 0;
+}
diff --git a/gcc/testsuite/go.test/test/bench/spectral-norm.go b/gcc/testsuite/go.test/test/bench/spectral-norm.go
new file mode 100644 (file)
index 0000000..6667f3e
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on spectral-norm.c by Sebastien Loisel
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "math"
+)
+
+var n = flag.Int("n", 2000, "count")
+
+func evalA(i, j int) float64 { return 1 / float64(((i+j)*(i+j+1)/2 + i + 1)) }
+
+type Vec []float64
+
+func (v Vec) Times(u Vec) {
+       for i := 0; i < len(v); i++ {
+               v[i] = 0
+               for j := 0; j < len(u); j++ {
+                       v[i] += evalA(i, j) * u[j]
+               }
+       }
+}
+
+func (v Vec) TimesTransp(u Vec) {
+       for i := 0; i < len(v); i++ {
+               v[i] = 0
+               for j := 0; j < len(u); j++ {
+                       v[i] += evalA(j, i) * u[j]
+               }
+       }
+}
+
+func (v Vec) ATimesTransp(u Vec) {
+       x := make(Vec, len(u))
+       x.Times(u)
+       v.TimesTransp(x)
+}
+
+func main() {
+       flag.Parse()
+       N := *n
+       u := make(Vec, N)
+       for i := 0; i < N; i++ {
+               u[i] = 1
+       }
+       v := make(Vec, N)
+       for i := 0; i < 10; i++ {
+               v.ATimesTransp(u)
+               u.ATimesTransp(v)
+       }
+       var vBv, vv float64
+       for i := 0; i < N; i++ {
+               vBv += u[i] * v[i]
+               vv += v[i] * v[i]
+       }
+       fmt.Printf("%0.9f\n", math.Sqrt(vBv/vv))
+}
diff --git a/gcc/testsuite/go.test/test/bench/spectral-norm.txt b/gcc/testsuite/go.test/test/bench/spectral-norm.txt
new file mode 100644 (file)
index 0000000..b988598
--- /dev/null
@@ -0,0 +1 @@
+1.274224152
diff --git a/gcc/testsuite/go.test/test/bench/threadring.c b/gcc/testsuite/go.test/test/bench/threadring.c
new file mode 100644 (file)
index 0000000..2c4fb77
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+* The Computer Language Benchmarks Game
+* http://shootout.alioth.debian.org/
+
+* contributed by Premysl Hruby
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+#include <limits.h>
+
+#define THREADS (503)
+
+
+struct stack {
+   char x[PTHREAD_STACK_MIN];
+};
+
+
+/* staticaly initialize mutex[0] mutex */
+static pthread_mutex_t mutex[THREADS];
+static int data[THREADS];
+static struct stack stacks[THREADS];
+/* stacks must be defined staticaly, or my i386 box run of virtual memory for this
+ * process while creating thread +- #400 */
+
+static void* thread(void *num)
+{
+   int l = (int)num;
+   int r = (l+1) % THREADS;
+   int token;
+
+   while(1) {
+      pthread_mutex_lock(mutex + l);
+      token = data[l];
+      if (token) {
+         data[r] = token - 1;
+         pthread_mutex_unlock(mutex + r);
+      }
+      else {
+         printf("%i\n", l+1);
+         exit(0);
+      }
+   }
+}
+
+
+
+int main(int argc, char **argv)
+{
+   int i;
+   pthread_t cthread;
+   pthread_attr_t stack_attr;
+
+   if (argc != 2)
+      exit(255);
+   data[0] = atoi(argv[1]);
+
+   pthread_attr_init(&stack_attr);
+
+   for (i = 0; i < THREADS; i++) {
+      pthread_mutex_init(mutex + i, NULL);
+      pthread_mutex_lock(mutex + i);
+
+      pthread_attr_setstack(&stack_attr, &stacks[i], sizeof(struct stack));
+      pthread_create(&cthread, &stack_attr, thread, (void*)i);
+   }
+
+   pthread_mutex_unlock(mutex + 0);
+   pthread_join(cthread, NULL);
+}
diff --git a/gcc/testsuite/go.test/test/bench/threadring.go b/gcc/testsuite/go.test/test/bench/threadring.go
new file mode 100644 (file)
index 0000000..031908a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "os"
+)
+
+var n = flag.Int("n", 1000, "how many passes")
+
+const Nthread = 503
+
+func f(i int, in <-chan int, out chan<- int) {
+       for {
+               n := <-in
+               if n == 0 {
+                       fmt.Printf("%d\n", i)
+                       os.Exit(0)
+               }
+               out <- n-1
+       }
+}
+
+func main() {
+       flag.Parse()
+
+       one := make(chan int) // will be input to thread 1
+       var in, out chan int = nil, one
+       for i := 1; i <= Nthread-1; i++ {
+               in, out = out, make(chan int)
+               go f(i, in, out)
+       }
+       go f(Nthread, out, one)
+       one <- *n
+       <-make(chan int) // hang until ring completes
+}
diff --git a/gcc/testsuite/go.test/test/bench/threadring.txt b/gcc/testsuite/go.test/test/bench/threadring.txt
new file mode 100644 (file)
index 0000000..f9aaa4d
--- /dev/null
@@ -0,0 +1 @@
+498
diff --git a/gcc/testsuite/go.test/test/bench/timing.log b/gcc/testsuite/go.test/test/bench/timing.log
new file mode 100644 (file)
index 0000000..e7b0b48
--- /dev/null
@@ -0,0 +1,500 @@
+All tests on r45 or r70
+
+Aug 3 2009
+
+First version of fasta. Translation of fasta.c, fetched from
+       http://shootout.alioth.debian.org/u32q/benchmark.php?test=fasta&lang=gpp&id=4
+
+fasta -n 25000000
+       gcc -O2 fasta.c 5.98u 0.00s 6.01r
+       gccgo -O2 fasta.go      8.82u 0.02s 8.85r
+       6g fasta.go     13.50u 0.02s 13.53r
+       6g -B fata.go   12.99u 0.02s 13.02r
+
+Aug 4 2009
+[added timing.sh]
+
+# myrandom:
+#   hand-written optimization of integer division
+#   use int32->float conversion
+fasta -n 25000000
+       # probably I/O library inefficiencies
+       gcc -O2 fasta.c 5.99u 0.00s 6.00r 
+       gccgo -O2 fasta.go      8.82u 0.02s 8.85r
+       gc fasta        10.70u 0.00s 10.77r
+       gc_B fasta      10.09u 0.03s 10.12r
+
+reverse-complement < output-of-fasta-25000000
+       # we don't know - memory cache behavior?
+       gcc -O2 reverse-complement.c    2.04u 0.94s 10.54r
+       gccgo -O2 reverse-complement.go 6.54u 0.63s 7.17r
+       gc reverse-complement   6.55u 0.70s 7.26r
+       gc_B reverse-complement 6.32u 0.70s 7.10r
+
+nbody 50000000
+       # math.Sqrt needs to be in assembly; inlining is probably the other 50%
+       gcc -O2 nbody.c 21.61u 0.01s 24.80r
+       gccgo -O2 nbody.go      118.55u 0.02s 120.32r
+       gc nbody        100.84u 0.00s 100.85r
+       gc_B nbody      103.33u 0.00s 103.39r
+[
+hacked Sqrt in assembler
+       gc nbody        31.97u 0.00s 32.01r
+]
+
+binary-tree 15 # too slow to use 20
+       # memory allocation and garbage collection
+       gcc -O2 binary-tree.c -lm       0.86u 0.00s 0.87r
+       gccgo -O2 binary-tree.go        1.69u 0.46s 2.15r
+       gccgo -O2 binary-tree-freelist.go       8.48u 0.00s 8.48r
+       gc binary-tree  9.60u 0.01s 9.62r
+       gc binary-tree-freelist 0.48u 0.01s 0.50r
+
+August 5, 2009
+
+fannkuch 12
+       # bounds checking is half the difference
+       # rest might be registerization
+       gcc -O2 fannkuch.c      60.09u 0.01s 60.32r
+       gccgo -O2 fannkuch.go   64.89u 0.00s 64.92r
+       gc fannkuch     124.59u 0.00s 124.67r
+       gc_B fannkuch   91.14u 0.00s 91.16r
+
+regex-dna 100000
+       # regexp code is slow on trivial regexp
+       gcc -O2 regex-dna.c -lpcre      0.92u 0.00s 0.99r
+       gc regexp-dna   26.94u 0.18s 28.75r
+       gc_B regexp-dna 26.51u 0.09s 26.75r
+
+spectral-norm 5500
+       gcc -O2 spectral-norm.c -lm     11.54u 0.00s 11.55r
+       gccgo -O2 spectral-norm.go      12.20u 0.00s 12.23r
+       gc spectral-norm        50.23u 0.00s 50.36r
+       gc_B spectral-norm      49.69u 0.01s 49.83r
+       gc spectral-norm-parallel       24.47u 0.03s 11.05r  # has shift >>1 not div /2
+       [using >>1 instead of /2 : gc gives 24.33u 0.00s 24.33r]
+
+August 6, 2009
+
+k-nucleotide 5000000
+       # string maps are slower than glib string maps
+       gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0   k-nucleotide.c: 10.72u 0.01s 10.74r
+       gccgo -O2 k-nucleotide.go       21.64u 0.83s 22.78r
+       gc k-nucleotide 16.08u 0.06s 16.50r
+       gc_B k-nucleotide       17.32u 0.02s 17.37r
+
+mandelbrot 5500
+       # floating point code generator should use more registers
+       gcc -O2 mandelbrot.c    56.13u 0.02s 56.17r
+       gccgo -O2 mandelbrot.go 57.49u 0.01s 57.51r
+       gc mandelbrot   74.32u 0.00s 74.35r
+       gc_B mandelbrot 74.28u 0.01s 74.31r
+
+meteor 16000
+       # we don't know
+       gcc -O2 meteor-contest.c        0.10u 0.00s 0.10r
+       gccgo -O2 meteor-contest.go     0.12u 0.00s 0.14r
+       gc meteor-contest       0.24u 0.00s 0.26r
+       gc_B meteor-contest     0.23u 0.00s 0.24r
+
+pidigits 10000
+       # bignum is slower than gmp
+       gcc -O2 pidigits.c -lgmp        2.60u 0.00s 2.62r
+       gc pidigits     77.69u 0.14s 78.18r
+       gc_B pidigits   74.26u 0.18s 75.41r
+       gc_B pidigits   68.48u 0.20s 69.31r   # special case: no bounds checking in bignum
+
+August 7 2009
+
+# New gc does better division by powers of 2.  Significant improvements:
+
+spectral-norm 5500
+       # floating point code generator should use more registers; possibly inline evalA
+       gcc -O2 spectral-norm.c -lm     11.50u 0.00s 11.50r
+       gccgo -O2 spectral-norm.go      12.02u 0.00s 12.02r
+       gc spectral-norm        23.98u 0.00s 24.00r     # new time is 0.48 times old time, 52% faster
+       gc_B spectral-norm      23.71u 0.01s 23.72r     # ditto
+       gc spectral-norm-parallel       24.04u 0.00s 6.26r  # /2 put back.  note: 4x faster (on r70, idle)
+
+k-nucleotide 1000000
+       # string maps are slower than glib string maps
+       gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0   10.82u 0.04s 10.87r
+       gccgo -O2 k-nucleotide.go       22.73u 0.89s 23.63r
+       gc k-nucleotide 15.97u 0.03s 16.04r
+       gc_B k-nucleotide       15.86u 0.06s 15.93r     # 8.5% faster, but probably due to weird cache effeccts in previous version
+
+pidigits 10000
+       # bignum is slower than gmp
+       gcc -O2 pidigits.c -lgmp        2.58u 0.00s 2.58r
+       gc pidigits     71.24u 0.04s 71.28r     # 8.5% faster
+       gc_B pidigits   71.25u 0.03s 71.29r     # 4% faster
+
+threadring 50000000
+       gcc -O2 threadring.c -lpthread  35.51u 160.21s 199.50r
+       gccgo -O2 threadring.go 90.33u 459.95s 448.03r
+       gc threadring   33.11u 0.00s 33.14r
+       GOMAXPROCS=4 gc threadring      114.48u 226.65s 371.59r
+       # change wait code to do <-make(chan int) instead of time.Sleep
+       gc threadring   28.41u 0.01s 29.35r
+       GOMAXPROCS=4 gc threadring      112.59u 232.83s 384.72r
+       
+chameneos 6000000
+       gcc -O2 chameneosredux.c -lpthread      18.14u 276.52s 76.93r
+       gc chameneosredux       20.19u 0.01s 20.23r
+
+Aug 10 2009
+
+# new 6g with better fp registers, fast div and mod of integers
+# complete set of timings listed. significant changes marked ***
+
+fasta -n 25000000
+       # probably I/O library inefficiencies
+       gcc -O2 fasta.c 5.96u 0.00s 5.97r
+       gc fasta        10.59u 0.01s 10.61r
+       gc_B fasta      9.92u 0.02s 9.95r
+
+reverse-complement < output-of-fasta-25000000
+       # we don't know - memory cache behavior?
+       gcc -O2 reverse-complement.c    1.96u 1.56s 16.23r
+       gccgo -O2 reverse-complement.go 6.41u 0.62s 7.05r
+       gc reverse-complement   6.46u 0.70s 7.17r
+       gc_B reverse-complement 6.22u 0.72s 6.95r
+
+nbody 50000000
+       # math.Sqrt needs to be in assembly; inlining is probably the other 50%
+       gcc -O2 nbody.c 21.26u 0.01s 21.28r
+       gccgo -O2 nbody.go      116.68u 0.07s 116.80r
+       gc nbody        86.64u 0.01s 86.68r     # -14%
+       gc_B nbody      85.72u 0.02s 85.77r     # *** -17%
+
+binary-tree 15 # too slow to use 20
+       # memory allocation and garbage collection
+       gcc -O2 binary-tree.c -lm       0.87u 0.00s 0.87r
+       gccgo -O2 binary-tree.go        1.61u 0.47s 2.09r
+       gccgo -O2 binary-tree-freelist.go       0.00u 0.00s 0.01r
+       gc binary-tree  9.11u 0.01s 9.13r       # *** -5%
+       gc binary-tree-freelist 0.47u 0.01s 0.48r
+
+fannkuch 12
+       # bounds checking is half the difference
+       # rest might be registerization
+       gcc -O2 fannkuch.c      59.92u 0.00s 59.94r
+       gccgo -O2 fannkuch.go   65.54u 0.00s 65.58r
+       gc fannkuch     123.98u 0.01s 124.04r
+       gc_B fannkuch   90.75u 0.00s 90.78r
+
+regex-dna 100000
+       # regexp code is slow on trivial regexp
+       gcc -O2 regex-dna.c -lpcre      0.91u 0.00s 0.92r
+       gc regex-dna    27.25u 0.02s 27.28r
+       gc_B regex-dna  29.51u 0.03s 29.55r
+
+spectral-norm 5500
+       # possibly inline evalA
+       gcc -O2 spectral-norm.c -lm     11.57u 0.00s 11.57r
+       gccgo -O2 spectral-norm.go      12.07u 0.01s 12.08r
+       gc spectral-norm        23.99u 0.00s 24.00r
+       gc_B spectral-norm      23.73u 0.00s 23.75r
+
+k-nucleotide 1000000
+       # string maps are slower than glib string maps
+       gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0   10.63u 0.02s 10.69r
+       gccgo -O2 k-nucleotide.go       23.19u 0.91s 24.12r
+       gc k-nucleotide 16.73u 0.04s 16.78r     # *** +5% (but this one seems to vary by more than that)
+       gc_B k-nucleotide       16.46u 0.04s 16.51r     # *** +5%
+
+mandelbrot 16000
+       gcc -O2 mandelbrot.c    56.16u 0.00s 56.16r
+       gccgo -O2 mandelbrot.go 57.41u 0.01s 57.42r
+       gc mandelbrot   64.05u 0.02s 64.08r     # *** -14%
+       gc_B mandelbrot 64.10u 0.02s 64.14r     # *** -14%
+
+meteor 16000
+       # we don't know
+       gcc -O2 meteor-contest.c        0.10u 0.00s 0.10r
+       gccgo -O2 meteor-contest.go     0.12u 0.00s 0.12r
+       gc meteor-contest       0.18u 0.00s 0.20r       # *** -25%
+       gc_B meteor-contest     0.17u 0.00s 0.18r       # *** -24%
+
+pidigits 10000
+       # bignum is slower than gmp
+       gcc -O2 pidigits.c -lgmp        2.57u 0.00s 2.57r
+       gc pidigits     71.82u 0.04s 71.89r
+       gc_B pidigits   71.84u 0.08s 71.98r
+
+threadring 50000000
+       gcc -O2 threadring.c -lpthread  30.91u 164.33s 204.57r
+       gccgo -O2 threadring.go 87.12u 460.04s 447.61r
+       gc threadring   38.55u 0.00s 38.56r     # *** +16%
+
+chameneos 6000000
+       gcc -O2 chameneosredux.c -lpthread      17.93u 323.65s 88.47r
+       gc chameneosredux       21.72u 0.00s 21.73r
+
+August 10 2009
+
+# In-place versions for some bignum operations.
+pidigits 10000
+       gcc -O2 pidigits.c -lgmp        2.56u 0.00s 2.57r
+       gc pidigits     55.22u 0.04s 55.29r     # *** -23%
+       gc_B pidigits   55.49u 0.02s 55.60r     # *** -23%
+
+September 3 2009
+
+# New 6g inlines slices, has a few other tweaks.
+# Complete rerun. Significant changes marked.
+
+fasta -n 25000000
+       # probably I/O library inefficiencies
+       gcc -O2 fasta.c 5.96u 0.00s 5.96r
+       gc fasta        10.63u 0.02s 10.66r
+       gc_B fasta      9.92u 0.01s 9.94r
+
+reverse-complement < output-of-fasta-25000000
+       # we don't know - memory cache behavior?
+       gcc -O2 reverse-complement.c    1.92u 0.33s 2.93r
+       gccgo -O2 reverse-complement.go 6.76u 0.72s 7.58r       # +5%
+       gc reverse-complement   6.59u 0.70s 7.29r       # +2%
+       gc_B reverse-complement 5.57u 0.80s 6.37r       # -10%
+
+nbody 50000000
+       # math.Sqrt needs to be in assembly; inlining is probably the other 50%
+       # also loop alignment appears to be critical
+       gcc -O2 nbody.c 21.28u 0.00s 21.28r
+       gccgo -O2 nbody.go      119.21u 0.00s 119.22r   # +2%
+       gc nbody        109.72u 0.00s 109.78r   # + 28% *****
+       gc_B nbody      85.90u 0.00s 85.91r
+
+binary-tree 15 # too slow to use 20
+       # memory allocation and garbage collection
+       gcc -O2 binary-tree.c -lm       0.86u 0.00s 0.87r
+       gccgo -O2 binary-tree.go        1.88u 0.54s 2.42r       # +17%
+       gccgo -O2 binary-tree-freelist.go       0.01u 0.01s 0.02r
+       gc binary-tree  8.94u 0.01s 8.96r       # -2%
+       gc binary-tree-freelist 0.47u 0.01s 0.48r
+
+fannkuch 12
+       # bounds checking is half the difference
+       # rest might be registerization
+       gcc -O2 fannkuch.c      60.12u 0.00s 60.12r
+       gccgo -O2 fannkuch.go   92.62u 0.00s 92.66r             # +41% ***
+       gc fannkuch     123.90u 0.00s 123.92r
+       gc_B fannkuch   89.71u 0.00s 89.74r     # -1%
+
+regex-dna 100000
+       # regexp code is slow on trivial regexp
+       gcc -O2 regex-dna.c -lpcre      0.88u 0.00s 0.88r
+       gc regex-dna    25.77u 0.01s 25.79r             # -5%
+       gc_B regex-dna  26.05u 0.02s 26.09r     # -12% ***
+
+spectral-norm 5500
+       # possibly inline evalA
+       gcc -O2 spectral-norm.c -lm     11.51u 0.00s 11.51r
+       gccgo -O2 spectral-norm.go      11.95u 0.00s 11.96r
+       gc spectral-norm        24.23u 0.00s 24.23r
+       gc_B spectral-norm      23.83u 0.00s 23.84r
+
+k-nucleotide 1000000
+       # string maps are slower than glib string maps
+       gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0   10.68u 0.04s 10.72r
+       gccgo -O2 k-nucleotide.go       23.03u 0.88s 23.92r
+       gc k-nucleotide 15.79u 0.05s 15.85r     # -5% (but this one seems to vary by more than that)
+       gc_B k-nucleotide       17.88u 0.05s 17.95r # +8% (ditto)
+
+mandelbrot 16000
+       gcc -O2 mandelbrot.c    56.17u 0.02s 56.20r
+       gccgo -O2 mandelbrot.go 56.74u 0.02s 56.79r      # -1%
+       gc mandelbrot   63.31u 0.01s 63.35r     # -1%
+       gc_B mandelbrot 63.29u 0.00s 63.31r     # -1%
+
+meteor 16000
+       # we don't know
+       gcc -O2 meteor-contest.c        0.10u 0.00s 0.10r
+       gccgo -O2 meteor-contest.go     0.11u 0.00s 0.12r
+       gc meteor-contest       0.18u 0.00s 0.19r
+       gc_B meteor-contest     0.17u 0.00s 0.18r
+
+pidigits 10000
+       # bignum is slower than gmp
+       gcc -O2 pidigits.c -lgmp        2.56u 0.00s 2.57r
+       gc pidigits     55.87u 0.03s 55.91r
+       gc_B pidigits   55.93u 0.03s 55.99r
+
+# these tests are compared using real time, since they run multiple processors
+# accuracy probably low
+threadring 50000000
+       gcc -O2 threadring.c -lpthread  26.31u 164.69s 199.92r  # -2%
+       gccgo -O2 threadring.go 87.90u 487.26s 472.81r  # +6%
+       gc threadring   28.89u 0.00s 28.90r     # -25% ***
+
+chameneos 6000000
+       gcc -O2 chameneosredux.c -lpthread      16.41u 296.91s 81.17r   # -8%
+       gc chameneosredux       19.97u 0.00s 19.97r     # -8%
+
+Sep 22, 2009
+
+# 6g inlines sliceslice in most cases.
+
+fasta -n 25000000
+       # probably I/O library inefficiencies
+       gc fasta        10.24u 0.00s 10.25r     # -4%
+       gc_B fasta      9.68u 0.01s 9.69r       # -3%
+
+reverse-complement < output-of-fasta-25000000
+       # we don't know - memory cache behavior?
+       gc reverse-complement   6.67u 0.69s 7.37r       # +1%
+       gc_B reverse-complement 6.00u 0.64s 6.65r       # +7%
+
+nbody -n 50000000
+       # math.Sqrt needs to be in assembly; inlining is probably the other 50%
+       # also loop alignment appears to be critical
+       gc nbody        86.27u 0.00s 86.29r     # -21%
+       gc_B nbody      104.52u 0.00s 104.54r   # +22%
+
+fannkuch 12
+       # bounds checking is half the difference
+       # rest might be registerization
+       gc fannkuch     128.36u 0.00s 128.37r   # +4%
+       gc_B fannkuch   89.32u 0.00s 89.34r
+
+regex-dna 100000
+       # regexp code is slow on trivial regexp
+       gc regex-dna    24.82u 0.01s 24.86r     # -4%
+       gc_B regex-dna  24.55u 0.01s 24.57r     # -6%
+
+spectral-norm 5500
+       # possibly inline evalA
+       gc spectral-norm        24.05u 0.00s 24.07r     # -1%
+       gc_B spectral-norm      23.60u 0.00s 23.65r      # -1%
+
+k-nucleotide 1000000
+       # string maps are slower than glib string maps
+       gc k-nucleotide 17.84u 0.04s 17.89r     # +13% but mysterious variation continues
+       gc_B k-nucleotide       15.56u 0.08s 15.65r     # -13% (ditto)
+
+mandelbrot 16000
+       gc mandelbrot   64.08u 0.01s 64.11r     # +1%
+       gc_B mandelbrot 64.04u 0.00s 64.05r     # +1%
+
+pidigits 10000
+       # bignum is slower than gmp
+       gc pidigits     58.68u 0.02s 58.72r     # +5%
+       gc_B pidigits   58.86u 0.05s 58.99r     # +5%
+
+# these tests are compared using real time, since they run multiple processors
+# accuracy probably low
+threadring 50000000
+       gc threadring   32.70u 0.02s 32.77r     # +13%
+
+chameneos 6000000
+       gc chameneosredux       26.62u 0.00s 26.63r     # +13%
+
+Sep 24, 2009
+
+# Sqrt now in assembler for 6g.
+nbody -n 50000000
+       # remember, at least for 6g, alignment of loops may be important
+       gcc -O2 nbody.c 21.24u 0.00s 21.25r
+       gccgo -O2 nbody.go      121.03u 0.00s 121.04r
+       gc nbody        30.26u 0.00s 30.27r     # -65% ***
+       gc_B nbody      30.20u 0.02s 30.22r     # -72% *** 
+
+Nov 13 2009
+
+# fix bug in regexp; take performance hit.  good regexps will come in time.
+regex-dna 100000
+       gcc -O2 regex-dna.c -lpcre      0.92u 0.00s 0.94r
+       gc regex-dna    29.78u 0.03s 29.83r
+       gc_B regex-dna  32.63u 0.03s 32.74r
+
+Nov 24 2009
+
+# Roger Peppe's rewrite of the benchmark
+chameneos 6000000
+       gcc -O2 chameneosredux.c -lpthread      18.00u 303.29s 83.64r
+       gc chameneosredux       12.10u 0.00s 12.10r  # 2.22X faster
+
+Jan 6, 2009
+
+# Long-overdue update.  All numbers included in this complete run.
+# Some programs (e.g. reverse-complement) rewritten for speed.
+# Regular expressions much faster in common cases (although still far behind PCRE)
+# Bignum stuff improved
+# Better (but sometimes slower) locking in channels.
+
+fasta -n 25000000
+       gcc -O2 fasta.c 5.99u 0.01s 6.00r
+       gc fasta        9.11u 0.00s 9.12r       # -11%
+       gc_B fasta      8.60u 0.00s 8.62r       # +12% ??
+
+reverse-complement < output-of-fasta-25000000
+       gcc -O2 reverse-complement.c    2.00u 0.80s 9.54r
+       gccgo -O2 reverse-complement.go 4.57u 0.35s 4.94r       # 33% faster
+       gc reverse-complement   2.01u 0.38s 2.40r       # 3.3X faster
+       gc_B reverse-complement 1.88u 0.36s 2.24r       # 3.2X faster
+GOGC=off
+       gc reverse-complement   2.01u 0.35s 2.37r
+       gc_B reverse-complement 1.86u 0.32s 2.19r
+
+nbody -n 50000000
+       gcc -O2 nbody.c 21.28u 0.00s 21.31r
+       gccgo -O2 nbody.go      80.02u 0.00s 80.05r     # 33% faster
+       gc nbody        30.13u 0.00s 30.13r
+       gc_B nbody      29.89u 0.01s 29.91r
+
+binary-tree 15 # too slow to use 20
+       gcc -O2 binary-tree.c -lm       0.86u 0.00s 0.87r
+       gccgo -O2 binary-tree.go        4.82u 0.41s 5.24r       # 2.5X slower
+       gccgo -O2 binary-tree-freelist.go       0.00u 0.00s 0.00r
+       gc binary-tree  7.23u 0.01s 7.25r       # # -19%
+       gc binary-tree-freelist 0.43u 0.00s 0.44r       # -9%
+
+fannkuch 12
+       gcc -O2 fannkuch.c      60.17u 0.00s 60.17r
+       gccgo -O2 fannkuch.go   78.47u 0.01s 78.49r
+       gc fannkuch     128.86u 0.00s 128.96r
+       gc_B fannkuch   90.17u 0.00s 90.21r
+
+regex-dna 100000
+       gcc -O2 regex-dna.c -lpcre      0.90u 0.00s 0.92r
+       gc regex-dna    9.48u 0.01s 9.50r       # 3.1X faster
+       gc_B regex-dna  9.08u 0.00s 9.10r       # 3.6X faster
+
+spectral-norm 5500
+       gcc -O2 spectral-norm.c -lm     11.48u 0.00s 11.48r
+       gccgo -O2 spectral-norm.go      11.68u 0.00s 11.70r
+       gc spectral-norm        23.98u 0.00s 23.99r
+       gc_B spectral-norm      23.68u 0.00s 23.69r
+
+k-nucleotide 1000000
+       gcc -O2 k-nucleotide.c  10.85u 0.04s 10.90r
+       gccgo -O2 k-nucleotide.go       25.26u 0.87s 26.14r
+       gc k-nucleotide 15.28u 0.06s 15.37r     # restored; mysterious variation continues
+       gc_B k-nucleotide       15.97u 0.03s 16.00r
+
+mandelbrot 16000
+       gcc -O2 mandelbrot.c    56.12u 0.01s 56.15r
+       gccgo -O2 mandelbrot.go 56.86u 0.01s 56.89r
+       gc mandelbrot   66.05u 0.00s 66.07r     # -3%
+       gc_B mandelbrot 66.06u 0.00s 66.07r     # -3%
+
+meteor 16000
+       gcc -O2 meteor-contest.c        0.10u 0.00s 0.10r
+       gccgo -O2 meteor-contest.go     0.12u 0.00s 0.12r
+       gc meteor-contest       0.17u 0.00s 0.17r
+       gc_B meteor-contest     0.15u 0.00s 0.16r
+
+pidigits 10000
+       gcc -O2 pidigits.c -lgmp        2.57u 0.00s 2.59r
+       gc pidigits     38.27u 0.02s 38.30r     # 1.5X faster
+       gc_B pidigits   38.27u 0.02s 38.31r     # 1.5X faster
+
+threadring 50000000
+       gcc -O2 threadring.c    37.11u 170.59s 212.75r
+       gccgo -O2 threadring.go 89.67u 447.56s 442.55r  # -6.5%
+       gc threadring   36.08u 0.04s 36.15r     # +10%
+
+chameneos 6000000
+       gcc -O2 chameneosredux.c -lpthread      19.02u 331.08s 90.79r
+       gc chameneosredux       12.54u 0.00s 12.55r
+
diff --git a/gcc/testsuite/go.test/test/bench/timing.sh b/gcc/testsuite/go.test/test/bench/timing.sh
new file mode 100755 (executable)
index 0000000..c52c0af
--- /dev/null
@@ -0,0 +1,196 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+set -e
+
+eval $(gomake --no-print-directory -f ../../src/Make.inc go-env)
+PATH=.:$PATH
+
+mode=run
+case X"$1" in
+X-test)
+       mode=test
+       shift
+esac
+
+gc() {
+       $GC $1.go; $LD $1.$O
+}
+
+gc_B() {
+       $GC -B $1.go; $LD $1.$O
+}
+
+runonly() {
+       if [ $mode = run ]
+       then
+               "$@"
+       fi
+}
+
+
+
+run() {
+       if [ $mode = test ]
+       then
+               if echo $1 | grep -q '^gc '
+               then
+                       $1      # compile the program
+                       program=$(echo $1 | sed 's/gc //')
+                       shift
+                       echo $program
+                       $1 <fasta-1000.out > /tmp/$$
+                       case $program in
+                       chameneosredux)
+                               # exact numbers may vary but non-numbers should match
+                               grep -v '[0-9]' /tmp/$$ > /tmp/$$x
+                               grep -v '[0-9]' chameneosredux.txt > /tmp/$$y
+                               cmp /tmp/$$x /tmp/$$y
+                               rm -f /tmp/$$ /tmp/$$x /tmp/$$y
+                               ;;
+                       *)
+                               cmp /tmp/$$ $program.txt
+                               rm -f /tmp/$$
+                       esac
+               fi
+               return
+       fi
+       echo -n '       '$1'    '
+       $1
+       shift
+       
+       echo $((time -p $* >/dev/null) 2>&1) | awk '{print $4 "u " $6 "s " $2 "r"}'
+}
+
+fasta() {
+       runonly echo 'fasta -n 25000000'
+       run 'gcc -O2 fasta.c' a.out 25000000
+       #run 'gccgo -O2 fasta.go' a.out -n 25000000     #commented out until WriteString is in bufio
+       run 'gc fasta' $O.out -n 25000000
+       run 'gc_B fasta' $O.out -n 25000000
+}
+
+revcomp() {
+       runonly gcc -O2 fasta.c
+       runonly a.out 25000000 > x
+       runonly echo 'reverse-complement < output-of-fasta-25000000'
+       run 'gcc -O2 reverse-complement.c' a.out < x
+       run 'gccgo -O2 reverse-complement.go' a.out < x
+       run 'gc reverse-complement' $O.out < x
+       run 'gc_B reverse-complement' $O.out < x
+       rm x
+}
+
+nbody() {
+       runonly echo 'nbody -n 50000000'
+       run 'gcc -O2 nbody.c' a.out 50000000
+       run 'gccgo -O2 nbody.go' a.out -n 50000000
+       run 'gc nbody' $O.out -n 50000000
+       run 'gc_B nbody' $O.out -n 50000000
+}
+
+binarytree() {
+       runonly echo 'binary-tree 15 # too slow to use 20'
+       run 'gcc -O2 binary-tree.c -lm' a.out 15
+       run 'gccgo -O2 binary-tree.go' a.out -n 15
+       run 'gccgo -O2 binary-tree-freelist.go' $O.out -n 15
+       run 'gc binary-tree' $O.out -n 15
+       run 'gc binary-tree-freelist' $O.out -n 15
+}
+
+fannkuch() {
+       runonly echo 'fannkuch 12'
+       run 'gcc -O2 fannkuch.c' a.out 12
+       run 'gccgo -O2 fannkuch.go' a.out -n 12
+       run 'gccgo -O2 fannkuch-parallel.go' a.out -n 12
+       run 'gc fannkuch' $O.out -n 12
+       run 'gc fannkuch-parallel' $O.out -n 12
+       run 'gc_B fannkuch' $O.out -n 12
+}
+
+regexdna() {
+       runonly gcc -O2 fasta.c
+       runonly a.out 100000 > x
+       runonly echo 'regex-dna 100000'
+       run 'gcc -O2 regex-dna.c -lpcre' a.out <x
+#      run 'gccgo -O2 regex-dna.go' a.out <x   # pages badly; don't run
+       run 'gc regex-dna' $O.out <x
+       run 'gc regex-dna-parallel' $O.out <x
+       run 'gc_B regex-dna' $O.out <x
+       rm x
+}
+
+spectralnorm() {
+       runonly echo 'spectral-norm 5500'
+       run 'gcc -O2 spectral-norm.c -lm' a.out 5500
+       run 'gccgo -O2 spectral-norm.go' a.out -n 5500
+       run 'gc spectral-norm' $O.out -n 5500
+       run 'gc_B spectral-norm' $O.out -n 5500
+}
+
+knucleotide() {
+       runonly gcc -O2 fasta.c
+       runonly a.out 1000000 > x  # should be using 25000000
+       runonly echo 'k-nucleotide 1000000'
+       run 'gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0' a.out <x
+       run 'gccgo -O2 k-nucleotide.go' a.out <x        # warning: pages badly!
+       run 'gccgo -O2 k-nucleotide-parallel.go' a.out <x       # warning: pages badly!
+       run 'gc k-nucleotide' $O.out <x
+       run 'gc k-nucleotide-parallel' $O.out <x
+       run 'gc_B k-nucleotide' $O.out <x
+       rm x
+}
+
+mandelbrot() {
+       runonly echo 'mandelbrot 16000'
+       run 'gcc -O2 mandelbrot.c' a.out 16000
+       run 'gccgo -O2 mandelbrot.go' a.out -n 16000
+       run 'gc mandelbrot' $O.out -n 16000
+       run 'gc_B mandelbrot' $O.out -n 16000
+}
+
+meteor() {
+       runonly echo 'meteor 16000'
+       run 'gcc -O2 meteor-contest.c' a.out
+       run 'gccgo -O2 meteor-contest.go' a.out
+       run 'gc meteor-contest' $O.out
+       run 'gc_B  meteor-contest' $O.out
+}
+
+pidigits() {
+       runonly echo 'pidigits 10000'
+       run 'gcc -O2 pidigits.c -lgmp' a.out 10000
+#      run 'gccgo -O2 pidigits.go' a.out -n 10000  # uncomment when gccgo library updated
+       run 'gc pidigits' $O.out -n 10000
+       run 'gc_B  pidigits' $O.out -n 10000
+}
+
+threadring() {
+       runonly echo 'threadring 50000000'
+       run 'gcc -O2 threadring.c -lpthread' a.out 50000000
+       run 'gccgo -O2 threadring.go' a.out -n 50000000
+       run 'gc threadring' $O.out -n 50000000
+}
+
+chameneos() {
+       runonly echo 'chameneos 6000000'
+       run 'gcc -O2 chameneosredux.c -lpthread' a.out 6000000
+       run 'gccgo -O2 chameneosredux.go' a.out 6000000
+       run 'gc chameneosredux' $O.out 6000000
+}
+
+case $# in
+0)
+       run="fasta revcomp nbody binarytree fannkuch regexdna spectralnorm knucleotide mandelbrot meteor pidigits threadring chameneos"
+       ;;
+*)
+       run=$*
+esac
+
+for i in $run
+do
+       $i
+       runonly echo
+done
diff --git a/gcc/testsuite/go.test/test/bigalg.go b/gcc/testsuite/go.test/test/bigalg.go
new file mode 100644 (file)
index 0000000..902ba84
--- /dev/null
@@ -0,0 +1,117 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+       a float64
+       b int64
+       c string
+       d byte
+}
+
+var a = []int{ 1, 2, 3 }
+var NIL []int
+
+func arraycmptest() {
+       if NIL != nil {
+               println("fail1:", NIL, "!= nil")
+       }
+       if nil != NIL {
+               println("fail2: nil !=", NIL)
+       }
+       if a == nil || nil == a {
+               println("fail3:", a, "== nil")
+       }
+}
+
+func SameArray(a, b []int) bool {
+       if len(a) != len(b) || cap(a) != cap(b) {
+               return false
+       }
+       if len(a) > 0 && &a[0] != &b[0] {
+               return false
+       }
+       return true
+}
+
+var t = T{1.5, 123, "hello", 255}
+var mt = make(map[int]T)
+var ma = make(map[int][]int)
+
+func maptest() {
+       mt[0] = t
+       t1 := mt[0]
+       if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
+               println("fail: map val struct", t1.a, t1.b, t1.c, t1.d)
+       }
+
+       ma[1] = a
+       a1 := ma[1]
+       if !SameArray(a, a1) {
+               println("fail: map val array", a, a1)
+       }
+}
+
+var ct = make(chan T)
+var ca = make(chan []int)
+
+func send() {
+       ct <- t
+       ca <- a
+}
+
+func chantest() {
+       go send()
+
+       t1 := <-ct
+       if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
+               println("fail: map val struct", t1.a, t1.b, t1.c, t1.d)
+       }
+
+       a1 := <-ca
+       if !SameArray(a, a1) {
+               println("fail: map val array", a, a1)
+       }
+}
+
+type E struct { }
+var e E
+
+func interfacetest() {
+       var i interface{}
+
+       i = a
+       a1 := i.([]int)
+       if !SameArray(a, a1) {
+               println("interface <-> []int", a, a1)
+       }
+       pa := new([]int)
+       *pa = a
+       i = pa
+       a1 = *i.(*[]int)
+       if !SameArray(a, a1) {
+               println("interface <-> *[]int", a, a1)
+       }
+
+       i = t
+       t1 := i.(T)
+       if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
+               println("interface <-> struct", t1.a, t1.b, t1.c, t1.d)
+       }
+
+       i = e
+       e1 := i.(E)
+       // nothing to check; just verify it doesn't crash
+       _ = e1
+}
+
+func main() {
+       arraycmptest()
+       maptest()
+       chantest()
+       interfacetest()
+}
diff --git a/gcc/testsuite/go.test/test/bigmap.go b/gcc/testsuite/go.test/test/bigmap.go
new file mode 100644 (file)
index 0000000..843a151
--- /dev/null
@@ -0,0 +1,34 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func seq(x, y int) [1000]byte {
+       var r [1000]byte
+       for i := 0; i < len(r); i++ {
+               r[i] = byte(x + i*y)
+       }
+       return r
+}
+
+func cmp(x, y [1000]byte) {
+       for i := 0; i < len(x); i++ {
+               if x[i] != y[i] {
+                       panic("BUG mismatch")
+               }
+       }
+}
+
+func main() {
+       m := make(map[int][1000]byte)
+       m[1] = seq(11, 13)
+       m[2] = seq(2, 9)
+       m[3] = seq(3, 17)
+
+       cmp(m[1], seq(11, 13))
+       cmp(m[2], seq(2, 9))
+       cmp(m[3], seq(3, 17))
+}
diff --git a/gcc/testsuite/go.test/test/blank.go b/gcc/testsuite/go.test/test/blank.go
new file mode 100644 (file)
index 0000000..b9d3a32
--- /dev/null
@@ -0,0 +1,101 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import _ "fmt"
+
+var call string
+
+type T struct {
+       _, _, _ int
+}
+
+func (T) _() {
+}
+
+func (T) _() {
+}
+
+const (
+       c0 = iota
+       _
+       _
+       _
+       c4
+)
+
+var ints = []string {
+       "1",
+       "2",
+       "3",
+}
+
+func f() (int, int) {
+       call += "f"
+       return 1,2
+}
+
+func g() (float, float) {
+       call += "g"
+       return 3,4
+}
+
+func h(_ int, _ float) {
+}
+
+func i() int {
+       call += "i"
+       return 23
+}
+
+var _ = i()
+
+func main() {
+       if call != "i" {panic("init did not run")}
+       call = ""
+       _, _ = f()
+       a, _ := f()
+       if a != 1 {panic(a)}
+       b, _ := g()
+       if b != 3 {panic(b)}
+       _, a = f()
+       if a != 2 {panic(a)}
+       _, b = g()
+       if b != 4 {panic(b)}
+       _ = i()
+       if call != "ffgfgi" {panic(call)}
+       if c4 != 4 {panic(c4)}
+
+       out := ""
+       for _, s := range ints {
+               out += s
+       }
+       if out != "123" {panic(out)}
+
+       sum := 0
+       for s, _ := range ints {
+               sum += s
+       }
+       if sum != 3 {panic(sum)}
+
+       h(a,b)
+}
+
+// useless but legal
+var _ int = 1
+var _ = 2
+var _, _ = 3, 4
+const _ = 3
+const _, _ = 4, 5
+type _ int
+func _() {
+       panic("oops")
+}
+
+func ff() {
+       var _ int = 1
+}
diff --git a/gcc/testsuite/go.test/test/blank1.go b/gcc/testsuite/go.test/test/blank1.go
new file mode 100644 (file)
index 0000000..5bc1efc
--- /dev/null
@@ -0,0 +1,12 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package _      // ERROR "invalid package name _"
+
+func main() {
+       _()     // ERROR "cannot use _ as value"
+       x := _+1        // ERROR "cannot use _ as value"
+}
diff --git a/gcc/testsuite/go.test/test/bugs/bug260.go b/gcc/testsuite/go.test/test/bugs/bug260.go
new file mode 100644 (file)
index 0000000..6a6331e
--- /dev/null
@@ -0,0 +1,55 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug260 failed
+
+// Test that structures pack densely, according to the alignment of the largest field.
+
+package main
+
+import (
+       "fmt"
+       "os"
+       "strconv"
+)
+
+type T1 struct { x uint8 }
+type T2 struct { x uint16 }
+type T4 struct { x uint32 }
+
+func main() {
+       report := len(os.Args) > 1
+       status := 0
+       var b1 [10]T1
+       a0, _ := strconv.Btoui64(fmt.Sprintf("%p", &b1[0])[2:], 16)
+       a1, _ := strconv.Btoui64(fmt.Sprintf("%p", &b1[1])[2:], 16)
+       if a1 != a0 + 1 {
+               fmt.Println("FAIL")
+               if report {
+                       fmt.Println("alignment should be 1, is", a1-a0)
+               }
+               status = 1
+       }
+       var b2 [10]T2
+       a0, _ = strconv.Btoui64(fmt.Sprintf("%p", &b2[0])[2:], 16)
+       a1, _ = strconv.Btoui64(fmt.Sprintf("%p", &b2[1])[2:], 16)
+       if a1 != a0 + 2 {
+               if status == 0 {
+                       fmt.Println("FAIL")
+                       status = 1
+               }
+               if report {
+                       fmt.Println("alignment should be 2, is", a1-a0)
+               }
+       }
+       var b4 [10]T4
+       a0, _ = strconv.Btoui64(fmt.Sprintf("%p", &b4[0])[2:], 16)
+       a1, _ = strconv.Btoui64(fmt.Sprintf("%p", &b4[1])[2:], 16)
+       if a1 != a0 + 4 {
+               if status == 0 {
+                       fmt.Println("FAIL")
+                       status = 1
+               }
+               if report {
+                       fmt.Println("alignment should be 4, is", a1-a0)
+               }
+       }
+       os.Exit(status)
+}
diff --git a/gcc/testsuite/go.test/test/bugs/placeholder b/gcc/testsuite/go.test/test/bugs/placeholder
new file mode 100644 (file)
index 0000000..b816d34
--- /dev/null
@@ -0,0 +1,2 @@
+This file keeps Mercurial from deleting the directory
+when there are no known bugs.
diff --git a/gcc/testsuite/go.test/test/chan/doubleselect.go b/gcc/testsuite/go.test/test/chan/doubleselect.go
new file mode 100644 (file)
index 0000000..592d2f5
--- /dev/null
@@ -0,0 +1,84 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test is designed to flush out the case where two cases of a select can
+// both end up running. See http://codereview.appspot.com/180068.
+package main
+
+import (
+       "flag"
+       "runtime"
+)
+
+var iterations *int = flag.Int("n", 100000, "number of iterations")
+
+// sender sends a counter to one of four different channels. If two
+// cases both end up running in the same iteration, the same value will be sent
+// to two different channels.
+func sender(n int, c1, c2, c3, c4 chan<- int) {
+       defer close(c1)
+       defer close(c2)
+
+       for i := 0; i < n; i++ {
+               select {
+               case c1 <- i:
+               case c2 <- i:
+               case c3 <- i:
+               case c4 <- i:
+               }
+       }
+}
+
+// mux receives the values from sender and forwards them onto another channel.
+// It would be simplier to just have sender's four cases all be the same
+// channel, but this doesn't actually trigger the bug.
+func mux(out chan<- int, in <-chan int) {
+       for {
+               v := <-in
+               if closed(in) {
+                       close(out)
+                       break
+               }
+               out <- v
+       }
+}
+
+// recver gets a steam of values from the four mux's and checks for duplicates.
+func recver(in <-chan int) {
+       seen := make(map[int]bool)
+
+       for {
+               v := <-in
+               if closed(in) {
+                       break
+               }
+               if _, ok := seen[v]; ok {
+                       println("got duplicate value: ", v)
+                       panic("fail")
+               }
+               seen[v] = true
+       }
+}
+
+func main() {
+       runtime.GOMAXPROCS(2)
+
+       c1 := make(chan int)
+       c2 := make(chan int)
+       c3 := make(chan int)
+       c4 := make(chan int)
+       cmux := make(chan int)
+       go sender(*iterations, c1, c2, c3, c4)
+       go mux(cmux, c1)
+       go mux(cmux, c2)
+       go mux(cmux, c3)
+       go mux(cmux, c4)
+       // We keep the recver because it might catch more bugs in the future.
+       // However, the result of the bug linked to at the top is that we'll
+       // end up panicing with: "throw: bad g->status in ready".
+       recver(cmux)
+       print("PASS\n")
+}
diff --git a/gcc/testsuite/go.test/test/chan/fifo.go b/gcc/testsuite/go.test/test/chan/fifo.go
new file mode 100644 (file)
index 0000000..0dddfca
--- /dev/null
@@ -0,0 +1,57 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Verify that unbuffered channels act as pure fifos.
+
+package main
+
+import "os"
+
+const N = 10
+
+func AsynchFifo() {
+       ch := make(chan int, N)
+       for i := 0; i < N; i++ {
+               ch <- i
+       }
+       for i := 0; i < N; i++ {
+               if <-ch != i {
+                       print("bad receive\n")
+                       os.Exit(1)
+               }
+       }
+}
+
+func Chain(ch <-chan int, val int, in <-chan int, out chan<- int) {
+       <-in
+       if <-ch != val {
+               panic(val)
+       }
+       out <- 1
+}
+
+// thread together a daisy chain to read the elements in sequence
+func SynchFifo() {
+       ch := make(chan int)
+       in := make(chan int)
+       start := in
+       for i := 0; i < N; i++ {
+               out := make(chan int)
+               go Chain(ch, i, in, out)
+               in = out
+       }
+       start <- 0
+       for i := 0; i < N; i++ {
+               ch <- i
+       }
+       <-in
+}
+
+func main() {
+       AsynchFifo()
+       SynchFifo()
+}
+
diff --git a/gcc/testsuite/go.test/test/chan/goroutines.go b/gcc/testsuite/go.test/test/chan/goroutines.go
new file mode 100644 (file)
index 0000000..d8f8803
--- /dev/null
@@ -0,0 +1,41 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// make a lot of goroutines, threaded together.
+// tear them down cleanly.
+
+package main
+
+import (
+       "os"
+       "strconv"
+)
+
+func f(left, right chan int) {
+       left <- <-right
+}
+
+func main() {
+       var n = 10000
+       if len(os.Args) > 1 {
+               var err os.Error
+               n, err = strconv.Atoi(os.Args[1])
+               if err != nil {
+                       print("bad arg\n")
+                       os.Exit(1)
+               }
+       }
+       leftmost := make(chan int)
+       right := leftmost
+       left := leftmost
+       for i := 0; i < n; i++ {
+               right = make(chan int)
+               go f(left, right)
+               left = right
+       }
+       go func(c chan int) { c <- 1 }(right)
+       <-leftmost
+}
diff --git a/gcc/testsuite/go.test/test/chan/nonblock.go b/gcc/testsuite/go.test/test/chan/nonblock.go
new file mode 100644 (file)
index 0000000..52f04bf
--- /dev/null
@@ -0,0 +1,232 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Verify channel operations that test for blocking
+// Use several sizes and types of operands
+
+package main
+
+import "runtime"
+import "time"
+
+func i32receiver(c chan int32, strobe chan bool) {
+       if <-c != 123 {
+               panic("i32 value")
+       }
+       strobe <- true
+}
+
+func i32sender(c chan int32, strobe chan bool) {
+       c <- 234
+       strobe <- true
+}
+
+func i64receiver(c chan int64, strobe chan bool) {
+       if <-c != 123456 {
+               panic("i64 value")
+       }
+       strobe <- true
+}
+
+func i64sender(c chan int64, strobe chan bool) {
+       c <- 234567
+       strobe <- true
+}
+
+func breceiver(c chan bool, strobe chan bool) {
+       if !<-c {
+               panic("b value")
+       }
+       strobe <- true
+}
+
+func bsender(c chan bool, strobe chan bool) {
+       c <- true
+       strobe <- true
+}
+
+func sreceiver(c chan string, strobe chan bool) {
+       if <-c != "hello" {
+               panic("s value")
+       }
+       strobe <- true
+}
+
+func ssender(c chan string, strobe chan bool) {
+       c <- "hello again"
+       strobe <- true
+}
+
+var ticker = time.Tick(10 * 1000) // 10 us
+func sleep() {
+       <-ticker
+       <-ticker
+       runtime.Gosched()
+       runtime.Gosched()
+       runtime.Gosched()
+}
+
+const maxTries = 10000 // Up to 100ms per test.
+
+func main() {
+       var i32 int32
+       var i64 int64
+       var b bool
+       var s string
+       var ok bool
+
+       var sync = make(chan bool)
+
+       for buffer := 0; buffer < 2; buffer++ {
+               c32 := make(chan int32, buffer)
+               c64 := make(chan int64, buffer)
+               cb := make(chan bool, buffer)
+               cs := make(chan string, buffer)
+
+               i32, ok = <-c32
+               if ok {
+                       panic("blocked i32sender")
+               }
+
+               i64, ok = <-c64
+               if ok {
+                       panic("blocked i64sender")
+               }
+
+               b, ok = <-cb
+               if ok {
+                       panic("blocked bsender")
+               }
+
+               s, ok = <-cs
+               if ok {
+                       panic("blocked ssender")
+               }
+
+               go i32receiver(c32, sync)
+               try := 0
+               for !(c32 <- 123) {
+                       try++
+                       if try > maxTries {
+                               println("i32receiver buffer=", buffer)
+                               panic("fail")
+                       }
+                       sleep()
+               }
+               <-sync
+
+               go i32sender(c32, sync)
+               if buffer > 0 {
+                       <-sync
+               }
+               try = 0
+               for i32, ok = <-c32; !ok; i32, ok = <-c32 {
+                       try++
+                       if try > maxTries {
+                               println("i32sender buffer=", buffer)
+                               panic("fail")
+                       }
+                       sleep()
+               }
+               if i32 != 234 {
+                       panic("i32sender value")
+               }
+               if buffer == 0 {
+                       <-sync
+               }
+
+               go i64receiver(c64, sync)
+               try = 0
+               for !(c64 <- 123456) {
+                       try++
+                       if try > maxTries {
+                               panic("i64receiver")
+                       }
+                       sleep()
+               }
+               <-sync
+
+               go i64sender(c64, sync)
+               if buffer > 0 {
+                       <-sync
+               }
+               try = 0
+               for i64, ok = <-c64; !ok; i64, ok = <-c64 {
+                       try++
+                       if try > maxTries {
+                               panic("i64sender")
+                       }
+                       sleep()
+               }
+               if i64 != 234567 {
+                       panic("i64sender value")
+               }
+               if buffer == 0 {
+                       <-sync
+               }
+
+               go breceiver(cb, sync)
+               try = 0
+               for !(cb <- true) {
+                       try++
+                       if try > maxTries {
+                               panic("breceiver")
+                       }
+                       sleep()
+               }
+               <-sync
+
+               go bsender(cb, sync)
+               if buffer > 0 {
+                       <-sync
+               }
+               try = 0
+               for b, ok = <-cb; !ok; b, ok = <-cb {
+                       try++
+                       if try > maxTries {
+                               panic("bsender")
+                       }
+                       sleep()
+               }
+               if !b {
+                       panic("bsender value")
+               }
+               if buffer == 0 {
+                       <-sync
+               }
+
+               go sreceiver(cs, sync)
+               try = 0
+               for !(cs <- "hello") {
+                       try++
+                       if try > maxTries {
+                               panic("sreceiver")
+                       }
+                       sleep()
+               }
+               <-sync
+
+               go ssender(cs, sync)
+               if buffer > 0 {
+                       <-sync
+               }
+               try = 0
+               for s, ok = <-cs; !ok; s, ok = <-cs {
+                       try++
+                       if try > maxTries {
+                               panic("ssender")
+                       }
+                       sleep()
+               }
+               if s != "hello again" {
+                       panic("ssender value")
+               }
+               if buffer == 0 {
+                       <-sync
+               }
+       }
+       print("PASS\n")
+}
diff --git a/gcc/testsuite/go.test/test/chan/perm.go b/gcc/testsuite/go.test/test/chan/perm.go
new file mode 100644 (file)
index 0000000..d08c035
--- /dev/null
@@ -0,0 +1,57 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var (
+       cr <-chan int
+       cs chan<- int
+       c chan int
+)
+
+func main() {
+       cr = c          // ok
+       cs = c          // ok
+       c = cr          // ERROR "illegal types|incompatible|cannot"
+       c = cs          // ERROR "illegal types|incompatible|cannot"
+       cr = cs // ERROR "illegal types|incompatible|cannot"
+       cs = cr // ERROR "illegal types|incompatible|cannot"
+
+       c <- 0          // ok
+       ok := c <- 0    // ok
+       _ = ok
+       <-c             // ok
+       x, ok := <-c    // ok
+       _, _ = x, ok
+
+       cr <- 0 // ERROR "send"
+       ok = cr <- 0    // ERROR "send"
+       _ = ok
+       <-cr            // ok
+       x, ok = <-cr    // ok
+       _, _ = x, ok
+
+       cs <- 0 // ok
+       ok = cs <- 0    // ok
+       _ = ok
+       <-cs            // ERROR "receive"
+       x, ok = <-cs    // ERROR "receive"
+       _, _ = x, ok
+
+       select {
+       case c <- 0:    // ok
+       case x := <-c:  // ok
+               _ = x
+
+       case cr <- 0:   // ERROR "send"
+       case x := <-cr: // ok
+               _ = x
+
+       case cs <- 0:   // ok
+       case x := <-cs: // ERROR "receive"
+               _ = x
+       }
+}
diff --git a/gcc/testsuite/go.test/test/chan/powser1.go b/gcc/testsuite/go.test/test/chan/powser1.go
new file mode 100644 (file)
index 0000000..dc4ff53
--- /dev/null
@@ -0,0 +1,709 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Power series package
+// A power series is a channel, along which flow rational
+// coefficients.  A denominator of zero signifies the end.
+// Original code in Newsqueak by Doug McIlroy.
+// See Squinting at Power Series by Doug McIlroy,
+//   http://www.cs.bell-labs.com/who/rsc/thread/squint.pdf
+
+package main
+
+import "os"
+
+type rat struct  {
+       num, den  int64 // numerator, denominator
+}
+
+func (u rat) pr() {
+       if u.den==1 {
+               print(u.num)
+       } else {
+               print(u.num, "/", u.den)
+       }
+       print(" ")
+}
+
+func (u rat) eq(c rat) bool {
+       return u.num == c.num && u.den == c.den
+}
+
+type dch struct {
+       req chan  int
+       dat chan  rat
+       nam int
+}
+
+type dch2 [2] *dch
+
+var chnames string
+var chnameserial int
+var seqno int
+
+func mkdch() *dch {
+       c := chnameserial % len(chnames)
+       chnameserial++
+       d := new(dch)
+       d.req = make(chan int)
+       d.dat = make(chan rat)
+       d.nam = c
+       return d
+}
+
+func mkdch2() *dch2 {
+       d2 := new(dch2)
+       d2[0] = mkdch()
+       d2[1] = mkdch()
+       return d2
+}
+
+// split reads a single demand channel and replicates its
+// output onto two, which may be read at different rates.
+// A process is created at first demand for a rat and dies
+// after the rat has been sent to both outputs.
+
+// When multiple generations of split exist, the newest
+// will service requests on one channel, which is
+// always renamed to be out[0]; the oldest will service
+// requests on the other channel, out[1].  All generations but the
+// newest hold queued data that has already been sent to
+// out[0].  When data has finally been sent to out[1],
+// a signal on the release-wait channel tells the next newer
+// generation to begin servicing out[1].
+
+func dosplit(in *dch, out *dch2, wait chan int ) {
+       both := false   // do not service both channels
+
+       select {
+       case <-out[0].req:
+               
+       case <-wait:
+               both = true
+               select {
+               case <-out[0].req:
+                       
+               case <-out[1].req:
+                       out[0], out[1] = out[1], out[0]
+               }
+       }
+
+       seqno++
+       in.req <- seqno
+       release := make(chan  int)
+       go dosplit(in, out, release)
+       dat := <-in.dat
+       out[0].dat <- dat
+       if !both {
+               <-wait
+       }
+       <-out[1].req
+       out[1].dat <- dat
+       release <- 0
+}
+
+func split(in *dch, out *dch2) {
+       release := make(chan int)
+       go dosplit(in, out, release)
+       release <- 0
+}
+
+func put(dat rat, out *dch) {
+       <-out.req
+       out.dat <- dat
+}
+
+func get(in *dch) rat {
+       seqno++
+       in.req <- seqno
+       return <-in.dat
+}
+
+// Get one rat from each of n demand channels
+
+func getn(in []*dch) []rat {
+       n := len(in)
+       if n != 2 { panic("bad n in getn") }
+       req := new([2] chan int)
+       dat := new([2] chan rat)
+       out := make([]rat, 2)
+       var i int
+       var it rat
+       for i=0; i<n; i++ {
+               req[i] = in[i].req
+               dat[i] = nil
+       }
+       for n=2*n; n>0; n-- {
+               seqno++
+
+               select {
+               case req[0] <- seqno:
+                       dat[0] = in[0].dat
+                       req[0] = nil
+               case req[1] <- seqno:
+                       dat[1] = in[1].dat
+                       req[1] = nil
+               case it = <-dat[0]:
+                       out[0] = it
+                       dat[0] = nil
+               case it = <-dat[1]:
+                       out[1] = it
+                       dat[1] = nil
+               }
+       }
+       return out
+}
+
+// Get one rat from each of 2 demand channels
+
+func get2(in0 *dch, in1 *dch) []rat {
+       return getn([]*dch{in0, in1})
+}
+
+func copy(in *dch, out *dch) {
+       for {
+               <-out.req
+               out.dat <- get(in)
+       }
+}
+
+func repeat(dat rat, out *dch) {
+       for {
+               put(dat, out)
+       }
+}
+
+type PS *dch   // power series
+type PS2 *[2] PS // pair of power series
+
+var Ones PS
+var Twos PS
+
+func mkPS() *dch {
+       return mkdch()
+}
+
+func mkPS2() *dch2 {
+       return mkdch2()
+}
+
+// Conventions
+// Upper-case for power series.
+// Lower-case for rationals.
+// Input variables: U,V,...
+// Output variables: ...,Y,Z
+
+// Integer gcd; needed for rational arithmetic
+
+func gcd (u, v int64) int64 {
+       if u < 0 { return gcd(-u, v) }
+       if u == 0 { return v }
+       return gcd(v%u, u)
+}
+
+// Make a rational from two ints and from one int
+
+func i2tor(u, v int64) rat {
+       g := gcd(u,v)
+       var r rat
+       if v > 0 {
+               r.num = u/g
+               r.den = v/g
+       } else {
+               r.num = -u/g
+               r.den = -v/g
+       }
+       return r
+}
+
+func itor(u int64) rat {
+       return i2tor(u, 1)
+}
+
+var zero rat
+var one rat
+
+
+// End mark and end test
+
+var finis rat
+
+func end(u rat) int64 {
+       if u.den==0 { return 1 }
+       return 0
+}
+
+// Operations on rationals
+
+func add(u, v rat) rat {
+       g := gcd(u.den,v.den)
+       return  i2tor(u.num*(v.den/g)+v.num*(u.den/g),u.den*(v.den/g))
+}
+
+func mul(u, v rat) rat {
+       g1 := gcd(u.num,v.den)
+       g2 := gcd(u.den,v.num)
+       var r rat
+       r.num = (u.num/g1)*(v.num/g2)
+       r.den = (u.den/g2)*(v.den/g1)
+       return r
+}
+
+func neg(u rat) rat {
+       return i2tor(-u.num, u.den)
+}
+
+func sub(u, v rat) rat {
+       return add(u, neg(v))
+}
+
+func inv(u rat) rat {  // invert a rat
+       if u.num == 0 { panic("zero divide in inv") }
+       return i2tor(u.den, u.num)
+}
+
+// print eval in floating point of PS at x=c to n terms
+func evaln(c rat, U PS, n int) {
+       xn := float64(1)
+       x := float64(c.num)/float64(c.den)
+       val := float64(0)
+       for i:=0; i<n; i++ {
+               u := get(U)
+               if end(u) != 0 {
+                       break
+               }
+               val = val + x * float64(u.num)/float64(u.den)
+               xn = xn*x
+       }
+       print(val, "\n")
+}
+
+// Print n terms of a power series
+func printn(U PS, n int) {
+       done := false
+       for ; !done && n>0; n-- {
+               u := get(U)
+               if end(u) != 0 {
+                       done = true
+               } else {
+                       u.pr()
+               }
+       }
+       print(("\n"))
+}
+
+// Evaluate n terms of power series U at x=c
+func eval(c rat, U PS, n int) rat {
+       if n==0 { return zero }
+       y := get(U)
+       if end(y) != 0 { return zero }
+       return add(y,mul(c,eval(c,U,n-1)))
+}
+
+// Power-series constructors return channels on which power
+// series flow.  They start an encapsulated generator that
+// puts the terms of the series on the channel.
+
+// Make a pair of power series identical to a given power series
+
+func Split(U PS) *dch2 {
+       UU := mkdch2()
+       go split(U,UU)
+       return UU
+}
+
+// Add two power series
+func Add(U, V PS) PS {
+       Z := mkPS()
+       go func() {
+               var uv []rat
+               for {
+                       <-Z.req
+                       uv = get2(U,V)
+                       switch end(uv[0])+2*end(uv[1]) {
+                       case 0:
+                               Z.dat <- add(uv[0], uv[1])
+                       case 1:
+                               Z.dat <- uv[1]
+                               copy(V,Z)
+                       case 2:
+                               Z.dat <- uv[0]
+                               copy(U,Z)
+                       case 3:
+                               Z.dat <- finis
+                       }
+               }
+       }()
+       return Z
+}
+
+// Multiply a power series by a constant
+func Cmul(c rat,U PS) PS {
+       Z := mkPS()
+       go func() {
+               done := false
+               for !done {
+                       <-Z.req
+                       u := get(U)
+                       if end(u) != 0 {
+                               done = true
+                       } else {
+                               Z.dat <- mul(c,u)
+                       }
+               }
+               Z.dat <- finis
+       }()
+       return Z
+}
+
+// Subtract
+
+func Sub(U, V PS) PS {
+       return Add(U, Cmul(neg(one), V))
+}
+
+// Multiply a power series by the monomial x^n
+
+func Monmul(U PS, n int) PS {
+       Z := mkPS()
+       go func() {
+               for ; n>0; n-- { put(zero,Z) }
+               copy(U,Z)
+       }()
+       return Z
+}
+
+// Multiply by x
+
+func Xmul(U PS) PS {
+       return Monmul(U,1)
+}
+
+func Rep(c rat) PS {
+       Z := mkPS()
+       go repeat(c,Z)
+       return Z
+}
+
+// Monomial c*x^n
+
+func Mon(c rat, n int) PS {
+       Z:=mkPS()
+       go func() {
+               if(c.num!=0) {
+                       for ; n>0; n=n-1 { put(zero,Z) }
+                       put(c,Z)
+               }
+               put(finis,Z)
+       }()
+       return Z
+}
+
+func Shift(c rat, U PS) PS {
+       Z := mkPS()
+       go func() {
+               put(c,Z)
+               copy(U,Z)
+       }()
+       return Z
+}
+
+// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
+
+// Convert array of coefficients, constant term first
+// to a (finite) power series
+
+/*
+func Poly(a []rat) PS {
+       Z:=mkPS()
+       begin func(a []rat, Z PS) {
+               j:=0
+               done:=0
+               for j=len(a); !done&&j>0; j=j-1)
+                       if(a[j-1].num!=0) done=1
+               i:=0
+               for(; i<j; i=i+1) put(a[i],Z)
+               put(finis,Z)
+       }()
+       return Z
+}
+*/
+
+// Multiply. The algorithm is
+//     let U = u + x*UU
+//     let V = v + x*VV
+//     then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
+
+func Mul(U, V PS) PS {
+       Z:=mkPS()
+       go func() {
+               <-Z.req
+               uv := get2(U,V)
+               if end(uv[0])!=0 || end(uv[1]) != 0 {
+                       Z.dat <- finis
+               } else {
+                       Z.dat <- mul(uv[0],uv[1])
+                       UU := Split(U)
+                       VV := Split(V)
+                       W := Add(Cmul(uv[0],VV[0]),Cmul(uv[1],UU[0]))
+                       <-Z.req
+                       Z.dat <- get(W)
+                       copy(Add(W,Mul(UU[1],VV[1])),Z)
+               }
+       }()
+       return Z
+}
+
+// Differentiate
+
+func Diff(U PS) PS {
+       Z:=mkPS()
+       go func() {
+               <-Z.req
+               u := get(U)
+               if end(u) == 0 {
+                       done:=false
+                       for i:=1; !done; i++ {
+                               u = get(U)
+                               if end(u) != 0 {
+                                       done = true
+                               } else {
+                                       Z.dat <- mul(itor(int64(i)),u)
+                                       <-Z.req
+                               }
+                       }
+               }
+               Z.dat <- finis
+       }()
+       return Z
+}
+
+// Integrate, with const of integration
+func Integ(c rat,U PS) PS {
+       Z:=mkPS()
+       go func() {
+               put(c,Z)
+               done:=false
+               for i:=1; !done; i++ {
+                       <-Z.req
+                       u := get(U)
+                       if end(u) != 0 { done= true }
+                       Z.dat <- mul(i2tor(1,int64(i)),u)
+               }
+               Z.dat <- finis
+       }()
+       return Z
+}
+
+// Binomial theorem (1+x)^c
+
+func Binom(c rat) PS {
+       Z:=mkPS()
+       go func() {
+               n := 1
+               t := itor(1)
+               for c.num!=0 {
+                       put(t,Z)
+                       t = mul(mul(t,c),i2tor(1,int64(n)))
+                       c = sub(c,one)
+                       n++
+               }
+               put(finis,Z)
+       }()
+       return Z
+}
+
+// Reciprocal of a power series
+//     let U = u + x*UU
+//     let Z = z + x*ZZ
+//     (u+x*UU)*(z+x*ZZ) = 1
+//     z = 1/u
+//     u*ZZ + z*UU +x*UU*ZZ = 0
+//     ZZ = -UU*(z+x*ZZ)/u
+
+func Recip(U PS) PS {
+       Z:=mkPS()
+       go func() {
+               ZZ:=mkPS2()
+               <-Z.req
+               z := inv(get(U))
+               Z.dat <- z
+               split(Mul(Cmul(neg(z),U),Shift(z,ZZ[0])),ZZ)
+               copy(ZZ[1],Z)
+       }()
+       return Z
+}
+
+// Exponential of a power series with constant term 0
+// (nonzero constant term would make nonrational coefficients)
+// bug: the constant term is simply ignored
+//     Z = exp(U)
+//     DZ = Z*DU
+//     integrate to get Z
+
+func Exp(U PS) PS {
+       ZZ := mkPS2()
+       split(Integ(one,Mul(ZZ[0],Diff(U))),ZZ)
+       return ZZ[1]
+}
+
+// Substitute V for x in U, where the leading term of V is zero
+//     let U = u + x*UU
+//     let V = v + x*VV
+//     then S(U,V) = u + VV*S(V,UU)
+// bug: a nonzero constant term is ignored
+
+func Subst(U, V PS) PS {
+       Z:= mkPS()
+       go func() {
+               VV := Split(V)
+               <-Z.req
+               u := get(U)
+               Z.dat <- u
+               if end(u) == 0 {
+                       if end(get(VV[0])) != 0 {
+                               put(finis,Z)
+                       } else {
+                               copy(Mul(VV[0],Subst(U,VV[1])),Z)
+                       }
+               }
+       }()
+       return Z
+}
+
+// Monomial Substition: U(c x^n)
+// Each Ui is multiplied by c^i and followed by n-1 zeros
+
+func MonSubst(U PS, c0 rat, n int) PS {
+       Z:= mkPS()
+       go func() {
+               c := one
+               for {
+                       <-Z.req
+                       u := get(U)
+                       Z.dat <- mul(u, c)
+                       c = mul(c, c0)
+                       if end(u) != 0 {
+                               Z.dat <- finis
+                               break
+                       }
+                       for i := 1; i < n; i++ {
+                               <-Z.req
+                               Z.dat <- zero
+                       }
+               }
+       }()
+       return Z
+}
+
+
+func Init() {
+       chnameserial = -1
+       seqno = 0
+       chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+       zero = itor(0)
+       one = itor(1)
+       finis = i2tor(1,0)
+       Ones = Rep(one)
+       Twos = Rep(itor(2))
+}
+
+func check(U PS, c rat, count int, str string) {
+       for i := 0; i < count; i++ {
+               r := get(U)
+               if !r.eq(c) {
+                       print("got: ")
+                       r.pr()
+                       print("should get ")
+                       c.pr()
+                       print("\n")
+                       panic(str)
+               }
+       }
+}
+
+const N=10
+func checka(U PS, a []rat, str string) {
+       for i := 0; i < N; i++ {
+               check(U, a[i], 1, str)
+       }
+}
+
+func main() {
+       Init()
+       if len(os.Args) > 1 {  // print
+               print("Ones: "); printn(Ones, 10)
+               print("Twos: "); printn(Twos, 10)
+               print("Add: "); printn(Add(Ones, Twos), 10)
+               print("Diff: "); printn(Diff(Ones), 10)
+               print("Integ: "); printn(Integ(zero, Ones), 10)
+               print("CMul: "); printn(Cmul(neg(one), Ones), 10)
+               print("Sub: "); printn(Sub(Ones, Twos), 10)
+               print("Mul: "); printn(Mul(Ones, Ones), 10)
+               print("Exp: "); printn(Exp(Ones), 15)
+               print("MonSubst: "); printn(MonSubst(Ones, neg(one), 2), 10)
+               print("ATan: "); printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
+       } else {  // test
+               check(Ones, one, 5, "Ones")
+               check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones")  // 1 1 1 1 1
+               check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
+               a := make([]rat, N)
+               d := Diff(Ones)
+               for i:=0; i < N; i++ {
+                       a[i] = itor(int64(i+1))
+               }
+               checka(d, a, "Diff")  // 1 2 3 4 5
+               in := Integ(zero, Ones)
+               a[0] = zero  // integration constant
+               for i:=1; i < N; i++ {
+                       a[i] = i2tor(1, int64(i))
+               }
+               checka(in, a, "Integ")  // 0 1 1/2 1/3 1/4 1/5
+               check(Cmul(neg(one), Twos), itor(-2), 10, "CMul")  // -1 -1 -1 -1 -1
+               check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos")  // -1 -1 -1 -1 -1
+               m := Mul(Ones, Ones)
+               for i:=0; i < N; i++ {
+                       a[i] = itor(int64(i+1))
+               }
+               checka(m, a, "Mul")  // 1 2 3 4 5
+               e := Exp(Ones)
+               a[0] = itor(1)
+               a[1] = itor(1)
+               a[2] = i2tor(3,2)
+               a[3] = i2tor(13,6)
+               a[4] = i2tor(73,24)
+               a[5] = i2tor(167,40)
+               a[6] = i2tor(4051,720)
+               a[7] = i2tor(37633,5040)
+               a[8] = i2tor(43817,4480)
+               a[9] = i2tor(4596553,362880)
+               checka(e, a, "Exp")  // 1 1 3/2 13/6 73/24
+               at := Integ(zero, MonSubst(Ones, neg(one), 2))
+               for c, i := 1, 0; i < N; i++ {
+                       if i%2 == 0 {
+                               a[i] = zero
+                       } else {
+                               a[i] = i2tor(int64(c), int64(i))
+                               c *= -1
+                       }
+               }
+               checka(at, a, "ATan")  // 0 -1 0 -1/3 0 -1/5
+/*
+               t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
+               a[0] = zero
+               a[1] = itor(1)
+               a[2] = zero
+               a[3] = i2tor(1,3)
+               a[4] = zero
+               a[5] = i2tor(2,15)
+               a[6] = zero
+               a[7] = i2tor(17,315)
+               a[8] = zero
+               a[9] = i2tor(62,2835)
+               checka(t, a, "Tan")  // 0 1 0 1/3 0 2/15
+*/
+       }
+}
diff --git a/gcc/testsuite/go.test/test/chan/powser2.go b/gcc/testsuite/go.test/test/chan/powser2.go
new file mode 100644 (file)
index 0000000..bc32927
--- /dev/null
@@ -0,0 +1,722 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Power series package
+// A power series is a channel, along which flow rational
+// coefficients.  A denominator of zero signifies the end.
+// Original code in Newsqueak by Doug McIlroy.
+// See Squinting at Power Series by Doug McIlroy,
+//   http://www.cs.bell-labs.com/who/rsc/thread/squint.pdf
+// Like powser1.go but uses channels of interfaces.
+// Has not been cleaned up as much as powser1.go, to keep
+// it distinct and therefore a different test.
+
+package main
+
+import "os"
+
+type rat struct  {
+       num, den  int64 // numerator, denominator
+}
+
+type item interface {
+       pr()
+       eq(c item) bool
+}
+
+func (u *rat) pr(){
+       if u.den==1 {
+               print(u.num)
+       } else {
+               print(u.num, "/", u.den)
+       }
+       print(" ")
+}
+
+func (u *rat) eq(c item) bool {
+       c1 := c.(*rat)
+       return u.num == c1.num && u.den == c1.den
+}
+
+type dch struct {
+       req chan  int
+       dat chan  item
+       nam int
+}
+
+type dch2 [2] *dch
+
+var chnames string
+var chnameserial int
+var seqno int
+
+func mkdch() *dch {
+       c := chnameserial % len(chnames)
+       chnameserial++
+       d := new(dch)
+       d.req = make(chan int)
+       d.dat = make(chan item)
+       d.nam = c
+       return d
+}
+
+func mkdch2() *dch2 {
+       d2 := new(dch2)
+       d2[0] = mkdch()
+       d2[1] = mkdch()
+       return d2
+}
+
+// split reads a single demand channel and replicates its
+// output onto two, which may be read at different rates.
+// A process is created at first demand for an item and dies
+// after the item has been sent to both outputs.
+
+// When multiple generations of split exist, the newest
+// will service requests on one channel, which is
+// always renamed to be out[0]; the oldest will service
+// requests on the other channel, out[1].  All generations but the
+// newest hold queued data that has already been sent to
+// out[0].  When data has finally been sent to out[1],
+// a signal on the release-wait channel tells the next newer
+// generation to begin servicing out[1].
+
+func dosplit(in *dch, out *dch2, wait chan int ){
+       both := false   // do not service both channels
+
+       select {
+       case <-out[0].req:
+               
+       case <-wait:
+               both = true
+               select {
+               case <-out[0].req:
+                       
+               case <-out[1].req:
+                       out[0],out[1] = out[1], out[0]
+               }
+       }
+
+       seqno++
+       in.req <- seqno
+       release := make(chan  int)
+       go dosplit(in, out, release)
+       dat := <-in.dat
+       out[0].dat <- dat
+       if !both {
+               <-wait
+       }
+       <-out[1].req
+       out[1].dat <- dat
+       release <- 0
+}
+
+func split(in *dch, out *dch2){
+       release := make(chan int)
+       go dosplit(in, out, release)
+       release <- 0
+}
+
+func put(dat item, out *dch){
+       <-out.req
+       out.dat <- dat
+}
+
+func get(in *dch) *rat {
+       seqno++
+       in.req <- seqno
+       return (<-in.dat).(*rat)
+}
+
+// Get one item from each of n demand channels
+
+func getn(in []*dch) []item {
+       n:=len(in)
+       if n != 2 { panic("bad n in getn") }
+       req := make([] chan int, 2)
+       dat := make([] chan item, 2)
+       out := make([]item, 2)
+       var i int
+       var it item
+       for i=0; i<n; i++ {
+               req[i] = in[i].req
+               dat[i] = nil
+       }
+       for n=2*n; n>0; n-- {
+               seqno++
+
+               select{
+               case req[0] <- seqno:
+                       dat[0] = in[0].dat
+                       req[0] = nil
+               case req[1] <- seqno:
+                       dat[1] = in[1].dat
+                       req[1] = nil
+               case it = <-dat[0]:
+                       out[0] = it
+                       dat[0] = nil
+               case it = <-dat[1]:
+                       out[1] = it
+                       dat[1] = nil
+               }
+       }
+       return out
+}
+
+// Get one item from each of 2 demand channels
+
+func get2(in0 *dch, in1 *dch)  []item {
+       return getn([]*dch{in0, in1})
+}
+
+func copy(in *dch, out *dch){
+       for {
+               <-out.req
+               out.dat <- get(in)
+       }
+}
+
+func repeat(dat item, out *dch){
+       for {
+               put(dat, out)
+       }
+}
+
+type PS *dch   // power series
+type PS2 *[2] PS // pair of power series
+
+var Ones PS
+var Twos PS
+
+func mkPS() *dch {
+       return mkdch()
+}
+
+func mkPS2() *dch2 {
+       return mkdch2()
+}
+
+// Conventions
+// Upper-case for power series.
+// Lower-case for rationals.
+// Input variables: U,V,...
+// Output variables: ...,Y,Z
+
+// Integer gcd; needed for rational arithmetic
+
+func gcd (u, v int64) int64{
+       if u < 0 { return gcd(-u, v) }
+       if u == 0 { return v }
+       return gcd(v%u, u)
+}
+
+// Make a rational from two ints and from one int
+
+func i2tor(u, v int64) *rat{
+       g := gcd(u,v)
+       r := new(rat)
+       if v > 0 {
+               r.num = u/g
+               r.den = v/g
+       } else {
+               r.num = -u/g
+               r.den = -v/g
+       }
+       return r
+}
+
+func itor(u int64) *rat{
+       return i2tor(u, 1)
+}
+
+var zero *rat
+var one *rat
+
+
+// End mark and end test
+
+var finis *rat
+
+func end(u *rat) int64 {
+       if u.den==0 { return 1 }
+       return 0
+}
+
+// Operations on rationals
+
+func add(u, v *rat) *rat {
+       g := gcd(u.den,v.den)
+       return  i2tor(u.num*(v.den/g)+v.num*(u.den/g),u.den*(v.den/g))
+}
+
+func mul(u, v *rat) *rat{
+       g1 := gcd(u.num,v.den)
+       g2 := gcd(u.den,v.num)
+       r := new(rat)
+       r.num =(u.num/g1)*(v.num/g2)
+       r.den = (u.den/g2)*(v.den/g1)
+       return r
+}
+
+func neg(u *rat) *rat{
+       return i2tor(-u.num, u.den)
+}
+
+func sub(u, v *rat) *rat{
+       return add(u, neg(v))
+}
+
+func inv(u *rat) *rat{ // invert a rat
+       if u.num == 0 { panic("zero divide in inv") }
+       return i2tor(u.den, u.num)
+}
+
+// print eval in floating point of PS at x=c to n terms
+func Evaln(c *rat, U PS, n int) {
+       xn := float64(1)
+       x := float64(c.num)/float64(c.den)
+       val := float64(0)
+       for i:=0; i<n; i++ {
+               u := get(U)
+               if end(u) != 0 {
+                       break
+               }
+               val = val + x * float64(u.num)/float64(u.den)
+               xn = xn*x
+       }
+       print(val, "\n")
+}
+
+// Print n terms of a power series
+func Printn(U PS, n int){
+       done := false
+       for ; !done && n>0; n-- {
+               u := get(U)
+               if end(u) != 0 {
+                       done = true
+               } else {
+                       u.pr()
+               }
+       }
+       print(("\n"))
+}
+
+func Print(U PS){
+       Printn(U,1000000000)
+}
+
+// Evaluate n terms of power series U at x=c
+func eval(c *rat, U PS, n int) *rat{
+       if n==0 { return zero }
+       y := get(U)
+       if end(y) != 0 { return zero }
+       return add(y,mul(c,eval(c,U,n-1)))
+}
+
+// Power-series constructors return channels on which power
+// series flow.  They start an encapsulated generator that
+// puts the terms of the series on the channel.
+
+// Make a pair of power series identical to a given power series
+
+func Split(U PS) *dch2{
+       UU := mkdch2()
+       go split(U,UU)
+       return UU
+}
+
+// Add two power series
+func Add(U, V PS) PS{
+       Z := mkPS()
+       go func(U, V, Z PS){
+               var uv [] item
+               for {
+                       <-Z.req
+                       uv = get2(U,V)
+                       switch end(uv[0].(*rat))+2*end(uv[1].(*rat)) {
+                       case 0:
+                               Z.dat <- add(uv[0].(*rat), uv[1].(*rat))
+                       case 1:
+                               Z.dat <- uv[1]
+                               copy(V,Z)
+                       case 2:
+                               Z.dat <- uv[0]
+                               copy(U,Z)
+                       case 3:
+                               Z.dat <- finis
+                       }
+               }
+       }(U, V, Z)
+       return Z
+}
+
+// Multiply a power series by a constant
+func Cmul(c *rat,U PS) PS{
+       Z := mkPS()
+       go func(c *rat, U, Z PS){
+               done := false
+               for !done {
+                       <-Z.req
+                       u := get(U)
+                       if end(u) != 0 {
+                               done = true
+                       } else {
+                               Z.dat <- mul(c,u)
+                       }
+               }
+               Z.dat <- finis
+       }(c, U, Z)
+       return Z
+}
+
+// Subtract
+
+func Sub(U, V PS) PS{
+       return Add(U, Cmul(neg(one), V))
+}
+
+// Multiply a power series by the monomial x^n
+
+func Monmul(U PS, n int) PS{
+       Z := mkPS()
+       go func(n int, U PS, Z PS){
+               for ; n>0; n-- { put(zero,Z) }
+               copy(U,Z)
+       }(n, U, Z)
+       return Z
+}
+
+// Multiply by x
+
+func Xmul(U PS) PS{
+       return Monmul(U,1)
+}
+
+func Rep(c *rat) PS{
+       Z := mkPS()
+       go repeat(c,Z)
+       return Z
+}
+
+// Monomial c*x^n
+
+func Mon(c *rat, n int) PS{
+       Z:=mkPS()
+       go func(c *rat, n int, Z PS){
+               if(c.num!=0) {
+                       for ; n>0; n=n-1 { put(zero,Z) }
+                       put(c,Z)
+               }
+               put(finis,Z)
+       }(c, n, Z)
+       return Z
+}
+
+func Shift(c *rat, U PS) PS{
+       Z := mkPS()
+       go func(c *rat, U, Z PS){
+               put(c,Z)
+               copy(U,Z)
+       }(c, U, Z)
+       return Z
+}
+
+// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
+
+// Convert array of coefficients, constant term first
+// to a (finite) power series
+
+/*
+func Poly(a [] *rat) PS{
+       Z:=mkPS()
+       begin func(a [] *rat, Z PS){
+               j:=0
+               done:=0
+               for j=len(a); !done&&j>0; j=j-1)
+                       if(a[j-1].num!=0) done=1
+               i:=0
+               for(; i<j; i=i+1) put(a[i],Z)
+               put(finis,Z)
+       }()
+       return Z
+}
+*/
+
+// Multiply. The algorithm is
+//     let U = u + x*UU
+//     let V = v + x*VV
+//     then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
+
+func Mul(U, V PS) PS{
+       Z:=mkPS()
+       go func(U, V, Z PS){
+               <-Z.req
+               uv := get2(U,V)
+               if end(uv[0].(*rat))!=0 || end(uv[1].(*rat)) != 0 {
+                       Z.dat <- finis
+               } else {
+                       Z.dat <- mul(uv[0].(*rat),uv[1].(*rat))
+                       UU := Split(U)
+                       VV := Split(V)
+                       W := Add(Cmul(uv[0].(*rat),VV[0]),Cmul(uv[1].(*rat),UU[0]))
+                       <-Z.req
+                       Z.dat <- get(W)
+                       copy(Add(W,Mul(UU[1],VV[1])),Z)
+               }
+       }(U, V, Z)
+       return Z
+}
+
+// Differentiate
+
+func Diff(U PS) PS{
+       Z:=mkPS()
+       go func(U, Z PS){
+               <-Z.req
+               u := get(U)
+               if end(u) == 0 {
+                       done:=false
+                       for i:=1; !done; i++ {
+                               u = get(U)
+                               if end(u) != 0 {
+                                       done=true
+                               } else {
+                                       Z.dat <- mul(itor(int64(i)),u)
+                                       <-Z.req
+                               }
+                       }
+               }
+               Z.dat <- finis
+       }(U, Z)
+       return Z
+}
+
+// Integrate, with const of integration
+func Integ(c *rat,U PS) PS{
+       Z:=mkPS()
+       go func(c *rat, U, Z PS){
+               put(c,Z)
+               done:=false
+               for i:=1; !done; i++ {
+                       <-Z.req
+                       u := get(U)
+                       if end(u) != 0 { done= true }
+                       Z.dat <- mul(i2tor(1,int64(i)),u)
+               }
+               Z.dat <- finis
+       }(c, U, Z)
+       return Z
+}
+
+// Binomial theorem (1+x)^c
+
+func Binom(c *rat) PS{
+       Z:=mkPS()
+       go func(c *rat, Z PS){
+               n := 1
+               t := itor(1)
+               for c.num!=0 {
+                       put(t,Z)
+                       t = mul(mul(t,c),i2tor(1,int64(n)))
+                       c = sub(c,one)
+                       n++
+               }
+               put(finis,Z)
+       }(c, Z)
+       return Z
+}
+
+// Reciprocal of a power series
+//     let U = u + x*UU
+//     let Z = z + x*ZZ
+//     (u+x*UU)*(z+x*ZZ) = 1
+//     z = 1/u
+//     u*ZZ + z*UU +x*UU*ZZ = 0
+//     ZZ = -UU*(z+x*ZZ)/u
+
+func Recip(U PS) PS{
+       Z:=mkPS()
+       go func(U, Z PS){
+               ZZ:=mkPS2()
+               <-Z.req
+               z := inv(get(U))
+               Z.dat <- z
+               split(Mul(Cmul(neg(z),U),Shift(z,ZZ[0])),ZZ)
+               copy(ZZ[1],Z)
+       }(U, Z)
+       return Z
+}
+
+// Exponential of a power series with constant term 0
+// (nonzero constant term would make nonrational coefficients)
+// bug: the constant term is simply ignored
+//     Z = exp(U)
+//     DZ = Z*DU
+//     integrate to get Z
+
+func Exp(U PS) PS{
+       ZZ := mkPS2()
+       split(Integ(one,Mul(ZZ[0],Diff(U))),ZZ)
+       return ZZ[1]
+}
+
+// Substitute V for x in U, where the leading term of V is zero
+//     let U = u + x*UU
+//     let V = v + x*VV
+//     then S(U,V) = u + VV*S(V,UU)
+// bug: a nonzero constant term is ignored
+
+func Subst(U, V PS) PS {
+       Z:= mkPS()
+       go func(U, V, Z PS) {
+               VV := Split(V)
+               <-Z.req
+               u := get(U)
+               Z.dat <- u
+               if end(u) == 0 {
+                       if end(get(VV[0])) != 0 {
+                               put(finis,Z)
+                       } else {
+                               copy(Mul(VV[0],Subst(U,VV[1])),Z)
+                       }
+               }
+       }(U, V, Z)
+       return Z
+}
+
+// Monomial Substition: U(c x^n)
+// Each Ui is multiplied by c^i and followed by n-1 zeros
+
+func MonSubst(U PS, c0 *rat, n int) PS {
+       Z:= mkPS()
+       go func(U, Z PS, c0 *rat, n int) {
+               c := one
+               for {
+                       <-Z.req
+                       u := get(U)
+                       Z.dat <- mul(u, c)
+                       c = mul(c, c0)
+                       if end(u) != 0 {
+                               Z.dat <- finis
+                               break
+                       }
+                       for i := 1; i < n; i++ {
+                               <-Z.req
+                               Z.dat <- zero
+                       }
+               }
+       }(U, Z, c0, n)
+       return Z
+}
+
+
+func Init() {
+       chnameserial = -1
+       seqno = 0
+       chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+       zero = itor(0)
+       one = itor(1)
+       finis = i2tor(1,0)
+       Ones = Rep(one)
+       Twos = Rep(itor(2))
+}
+
+func check(U PS, c *rat, count int, str string) {
+       for i := 0; i < count; i++ {
+               r := get(U)
+               if !r.eq(c) {
+                       print("got: ")
+                       r.pr()
+                       print("should get ")
+                       c.pr()
+                       print("\n")
+                       panic(str)
+               }
+       }
+}
+
+const N=10
+func checka(U PS, a []*rat, str string) {
+       for i := 0; i < N; i++ {
+               check(U, a[i], 1, str)
+       }
+}
+
+func main() {
+       Init()
+       if len(os.Args) > 1 {  // print
+               print("Ones: "); Printn(Ones, 10)
+               print("Twos: "); Printn(Twos, 10)
+               print("Add: "); Printn(Add(Ones, Twos), 10)
+               print("Diff: "); Printn(Diff(Ones), 10)
+               print("Integ: "); Printn(Integ(zero, Ones), 10)
+               print("CMul: "); Printn(Cmul(neg(one), Ones), 10)
+               print("Sub: "); Printn(Sub(Ones, Twos), 10)
+               print("Mul: "); Printn(Mul(Ones, Ones), 10)
+               print("Exp: "); Printn(Exp(Ones), 15)
+               print("MonSubst: "); Printn(MonSubst(Ones, neg(one), 2), 10)
+               print("ATan: "); Printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
+       } else {  // test
+               check(Ones, one, 5, "Ones")
+               check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones")  // 1 1 1 1 1
+               check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
+               a := make([]*rat, N)
+               d := Diff(Ones)
+               for i:=0; i < N; i++ {
+                       a[i] = itor(int64(i+1))
+               }
+               checka(d, a, "Diff")  // 1 2 3 4 5
+               in := Integ(zero, Ones)
+               a[0] = zero  // integration constant
+               for i:=1; i < N; i++ {
+                       a[i] = i2tor(1, int64(i))
+               }
+               checka(in, a, "Integ")  // 0 1 1/2 1/3 1/4 1/5
+               check(Cmul(neg(one), Twos), itor(-2), 10, "CMul")  // -1 -1 -1 -1 -1
+               check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos")  // -1 -1 -1 -1 -1
+               m := Mul(Ones, Ones)
+               for i:=0; i < N; i++ {
+                       a[i] = itor(int64(i+1))
+               }
+               checka(m, a, "Mul")  // 1 2 3 4 5
+               e := Exp(Ones)
+               a[0] = itor(1)
+               a[1] = itor(1)
+               a[2] = i2tor(3,2)
+               a[3] = i2tor(13,6)
+               a[4] = i2tor(73,24)
+               a[5] = i2tor(167,40)
+               a[6] = i2tor(4051,720)
+               a[7] = i2tor(37633,5040)
+               a[8] = i2tor(43817,4480)
+               a[9] = i2tor(4596553,362880)
+               checka(e, a, "Exp")  // 1 1 3/2 13/6 73/24
+               at := Integ(zero, MonSubst(Ones, neg(one), 2))
+               for c, i := 1, 0; i < N; i++ {
+                       if i%2 == 0 {
+                               a[i] = zero
+                       } else {
+                               a[i] = i2tor(int64(c), int64(i))
+                               c *= -1
+                       }
+               }
+               checka(at, a, "ATan");  // 0 -1 0 -1/3 0 -1/5
+/*
+               t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
+               a[0] = zero
+               a[1] = itor(1)
+               a[2] = zero
+               a[3] = i2tor(1,3)
+               a[4] = zero
+               a[5] = i2tor(2,15)
+               a[6] = zero
+               a[7] = i2tor(17,315)
+               a[8] = zero
+               a[9] = i2tor(62,2835)
+               checka(t, a, "Tan")  // 0 1 0 1/3 0 2/15
+*/
+       }
+}
diff --git a/gcc/testsuite/go.test/test/chan/select.go b/gcc/testsuite/go.test/test/chan/select.go
new file mode 100644 (file)
index 0000000..be4eb3f
--- /dev/null
@@ -0,0 +1,56 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var counter uint
+var shift uint
+
+func GetValue() uint {
+       counter++
+       return 1 << shift
+}
+
+func Send(a, b chan uint) int {
+       var i int
+
+LOOP:
+       for {
+               select {
+               case a <- GetValue():
+                       i++
+                       a = nil
+               case b <- GetValue():
+                       i++
+                       b = nil
+               default:
+                       break LOOP
+               }
+               shift++
+       }
+       return i
+}
+
+func main() {
+       a := make(chan uint, 1)
+       b := make(chan uint, 1)
+       if v := Send(a, b); v != 2 {
+               println("Send returned", v, "!= 2")
+               panic("fail")
+       }
+       if av, bv := <-a, <-b; av|bv != 3 {
+               println("bad values", av, bv)
+               panic("fail")
+       }
+       if v := Send(a, nil); v != 1 {
+               println("Send returned", v, "!= 1")
+               panic("fail")
+       }
+       if counter != 10 {
+               println("counter is", counter, "!= 10")
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/chan/select2.go b/gcc/testsuite/go.test/test/chan/select2.go
new file mode 100644 (file)
index 0000000..e24c51e
--- /dev/null
@@ -0,0 +1,48 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+func sender(c chan int, n int) {
+       for i := 0; i < n; i++ {
+               c <- 1
+       }
+}
+
+func receiver(c, dummy chan int, n int) {
+       for i := 0; i < n; i++ {
+               select {
+               case <-c:
+                       // nothing
+               case <-dummy:
+                       panic("dummy")
+               }
+       }
+}
+
+func main() {
+       runtime.MemProfileRate = 0
+
+       c := make(chan int)
+       dummy := make(chan int)
+
+       // warm up
+       go sender(c, 100000)
+       receiver(c, dummy, 100000)
+       runtime.GC()
+       runtime.MemStats.Alloc = 0
+
+       // second time shouldn't increase footprint by much
+       go sender(c, 100000)
+       receiver(c, dummy, 100000)
+       runtime.GC()
+
+       if runtime.MemStats.Alloc > 1e5 {
+               println("BUG: too much memory for 100,000 selects:", runtime.MemStats.Alloc)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/chan/select3.go b/gcc/testsuite/go.test/test/chan/select3.go
new file mode 100644 (file)
index 0000000..a1a2ef5
--- /dev/null
@@ -0,0 +1,203 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests verifying the semantics of the select statement
+// for basic empty/non-empty cases.
+
+package main
+
+import "time"
+
+const always = "function did not"
+const never = "function did"
+
+
+func unreachable() {
+       panic("control flow shouldn't reach here")
+}
+
+
+// Calls f and verifies that f always/never panics depending on signal.
+func testPanic(signal string, f func()) {
+       defer func() {
+               s := never
+               if recover() != nil {
+                       s = always // f panicked
+               }
+               if s != signal {
+                       panic(signal + " panic")
+               }
+       }()
+       f()
+}
+
+
+// Calls f and empirically verifies that f always/never blocks depending on signal.
+func testBlock(signal string, f func()) {
+       c := make(chan string)
+       go func() {
+               f()
+               c <- never // f didn't block
+       }()
+       go func() {
+               time.Sleep(1e8) // 0.1s seems plenty long
+               c <- always     // f blocked always
+       }()
+       if <-c != signal {
+               panic(signal + " block")
+       }
+}
+
+
+func main() {
+       const async = 1 // asynchronous channels
+       var nilch chan int
+       closedch := make(chan int)
+       close(closedch)
+
+       // sending/receiving from a nil channel outside a select panics
+       testPanic(always, func() {
+               nilch <- 7
+       })
+       testPanic(always, func() {
+               <-nilch
+       })
+
+       // sending/receiving from a nil channel inside a select never panics
+       testPanic(never, func() {
+               select {
+               case nilch <- 7:
+                       unreachable()
+               default:
+               }
+       })
+       testPanic(never, func() {
+               select {
+               case <-nilch:
+                       unreachable()
+               default:
+               }
+       })
+
+       // sending to an async channel with free buffer space never blocks
+       testBlock(never, func() {
+               ch := make(chan int, async)
+               ch <- 7
+       })
+
+       // receiving (a small number of times) from a closed channel never blocks
+       testBlock(never, func() {
+               for i := 0; i < 10; i++ {
+                       if <-closedch != 0 {
+                               panic("expected zero value when reading from closed channel")
+                       }
+               }
+       })
+
+       // sending (a small number of times) to a closed channel is not specified
+       // but the current implementation doesn't block: test that different
+       // implementations behave the same
+       testBlock(never, func() {
+               for i := 0; i < 10; i++ {
+                       closedch <- 7
+               }
+       })
+
+       // receiving from a non-ready channel always blocks
+       testBlock(always, func() {
+               ch := make(chan int)
+               <-ch
+       })
+
+       // empty selects always block
+       testBlock(always, func() {
+               select {
+               }
+       })
+
+       // selects with only nil channels always block
+       testBlock(always, func() {
+               select {
+               case <-nilch:
+                       unreachable()
+               }
+       })
+       testBlock(always, func() {
+               select {
+               case nilch <- 7:
+                       unreachable()
+               }
+       })
+       testBlock(always, func() {
+               select {
+               case <-nilch:
+                       unreachable()
+               case nilch <- 7:
+                       unreachable()
+               }
+       })
+
+       // selects with non-ready non-nil channels always block
+       testBlock(always, func() {
+               ch := make(chan int)
+               select {
+               case <-ch:
+                       unreachable()
+               }
+       })
+
+       // selects with default cases don't block
+       testBlock(never, func() {
+               select {
+               default:
+               }
+       })
+       testBlock(never, func() {
+               select {
+               case <-nilch:
+                       unreachable()
+               default:
+               }
+       })
+       testBlock(never, func() {
+               select {
+               case nilch <- 7:
+                       unreachable()
+               default:
+               }
+       })
+
+       // selects with ready channels don't block
+       testBlock(never, func() {
+               ch := make(chan int, async)
+               select {
+               case ch <- 7:
+               default:
+                       unreachable()
+               }
+       })
+       testBlock(never, func() {
+               ch := make(chan int, async)
+               ch <- 7
+               select {
+               case <-ch:
+               default:
+                       unreachable()
+               }
+       })
+
+       // selects with closed channels don't block
+       testBlock(never, func() {
+               select {
+               case <-closedch:
+               }
+       })
+       testBlock(never, func() {
+               select {
+               case closedch <- 7:
+               }
+       })
+}
diff --git a/gcc/testsuite/go.test/test/chan/sieve1.go b/gcc/testsuite/go.test/test/chan/sieve1.go
new file mode 100644 (file)
index 0000000..55076c9
--- /dev/null
@@ -0,0 +1,54 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate primes up to 100 using channels, checking the results.
+// This sieve consists of a linear chain of divisibility filters,
+// equivalent to trial-dividing each n by all primes p ≤ n.
+
+package main
+
+// Send the sequence 2, 3, 4, ... to channel 'ch'.
+func Generate(ch chan<- int) {
+       for i := 2; ; i++ {
+               ch <- i // Send 'i' to channel 'ch'.
+       }
+}
+
+// Copy the values from channel 'in' to channel 'out',
+// removing those divisible by 'prime'.
+func Filter(in <-chan int, out chan<- int, prime int) {
+       for i := range in { // Loop over values received from 'in'.
+               if i%prime != 0 {
+                       out <- i // Send 'i' to channel 'out'.
+               }
+       }
+}
+
+// The prime sieve: Daisy-chain Filter processes together.
+func Sieve(primes chan<- int) {
+       ch := make(chan int) // Create a new channel.
+       go Generate(ch)      // Start Generate() as a subprocess.
+       for {
+               // Note that ch is different on each iteration.
+               prime := <-ch
+               primes <- prime
+               ch1 := make(chan int)
+               go Filter(ch, ch1, prime)
+               ch = ch1
+       }
+}
+
+func main() {
+       primes := make(chan int)
+       go Sieve(primes)
+       a := []int{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}
+       for i := 0; i < len(a); i++ {
+               if x := <-primes; x != a[i] {
+                       println(x, " != ", a[i])
+                       panic("fail")
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/chan/sieve2.go b/gcc/testsuite/go.test/test/chan/sieve2.go
new file mode 100644 (file)
index 0000000..7f2ed91
--- /dev/null
@@ -0,0 +1,172 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate primes up to 100 using channels, checking the results.
+// This sieve is Eratosthenesque and only considers odd candidates.
+// See discussion at <http://blog.onideas.ws/eratosthenes.go>.
+
+package main
+
+import (
+       "container/heap"
+       "container/ring"
+       "container/vector"
+)
+
+// Return a chan of odd numbers, starting from 5.
+func odds() chan int {
+       out := make(chan int, 50)
+       go func() {
+               n := 5
+               for {
+                       out <- n
+                       n += 2
+               }
+       }()
+       return out
+}
+
+// Return a chan of odd multiples of the prime number p, starting from p*p.
+func multiples(p int) chan int {
+       out := make(chan int, 10)
+       go func() {
+               n := p * p
+               for {
+                       out <- n
+                       n += 2 * p
+               }
+       }()
+       return out
+}
+
+type PeekCh struct {
+       head int
+       ch   chan int
+}
+
+// Heap of PeekCh, sorting by head values.
+type PeekChHeap struct {
+       *vector.Vector
+}
+
+func (h *PeekChHeap) Less(i, j int) bool {
+       return h.At(i).(*PeekCh).head < h.At(j).(*PeekCh).head
+}
+
+// Return a channel to serve as a sending proxy to 'out'.
+// Use a goroutine to receive values from 'out' and store them
+// in an expanding buffer, so that sending to 'out' never blocks.
+func sendproxy(out chan<- int) chan<- int {
+       proxy := make(chan int, 10)
+       go func() {
+               n := 16 // the allocated size of the circular queue
+               first := ring.New(n)
+               last := first
+               var c chan<- int
+               var e int
+               for {
+                       c = out
+                       if first == last {
+                               // buffer empty: disable output
+                               c = nil
+                       } else {
+                               e = first.Value.(int)
+                       }
+                       select {
+                       case e = <-proxy:
+                               last.Value = e
+                               if last.Next() == first {
+                                       // buffer full: expand it
+                                       last.Link(ring.New(n))
+                                       n *= 2
+                               }
+                               last = last.Next()
+                       case c <- e:
+                               first = first.Next()
+                       }
+               }
+       }()
+       return proxy
+}
+
+// Return a chan int of primes.
+func Sieve() chan int {
+       // The output values.
+       out := make(chan int, 10)
+       out <- 2
+       out <- 3
+
+       // The channel of all composites to be eliminated in increasing order.
+       composites := make(chan int, 50)
+
+       // The feedback loop.
+       primes := make(chan int, 10)
+       primes <- 3
+
+       // Merge channels of multiples of 'primes' into 'composites'.
+       go func() {
+               h := &PeekChHeap{new(vector.Vector)}
+               min := 15
+               for {
+                       m := multiples(<-primes)
+                       head := <-m
+                       for min < head {
+                               composites <- min
+                               minchan := heap.Pop(h).(*PeekCh)
+                               min = minchan.head
+                               minchan.head = <-minchan.ch
+                               heap.Push(h, minchan)
+                       }
+                       for min == head {
+                               minchan := heap.Pop(h).(*PeekCh)
+                               min = minchan.head
+                               minchan.head = <-minchan.ch
+                               heap.Push(h, minchan)
+                       }
+                       composites <- head
+                       heap.Push(h, &PeekCh{<-m, m})
+               }
+       }()
+
+       // Sieve out 'composites' from 'candidates'.
+       go func() {
+               // In order to generate the nth prime we only need multiples of
+               // primes ≤ sqrt(nth prime).  Thus, the merging goroutine will
+               // receive from 'primes' much slower than this goroutine
+               // will send to it, making the buffer accumulate and block this
+               // goroutine from sending, causing a deadlock.  The solution is to
+               // use a proxy goroutine to do automatic buffering.
+               primes := sendproxy(primes)
+
+               candidates := odds()
+               p := <-candidates
+
+               for {
+                       c := <-composites
+                       for p < c {
+                               primes <- p
+                               out <- p
+                               p = <-candidates
+                       }
+                       if p == c {
+                               p = <-candidates
+                       }
+               }
+       }()
+
+       return out
+}
+
+func main() {
+       primes := Sieve()
+       a := []int{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}
+       for i := 0; i < len(a); i++ {
+               if x := <-primes; x != a[i] {
+                       println(x, " != ", a[i])
+                       panic("fail")
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/chancap.go b/gcc/testsuite/go.test/test/chancap.go
new file mode 100644 (file)
index 0000000..3f3789f
--- /dev/null
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       c := make(chan int, 10)
+       if len(c) != 0 || cap(c) != 10 {
+               println("chan len/cap ", len(c), cap(c), " want 0 10")
+               panic("fail")
+       }
+
+       for i := 0; i < 3; i++ {
+               c <- i
+       }
+       if len(c) != 3 || cap(c) != 10 {
+               println("chan len/cap ", len(c), cap(c), " want 3 10")
+               panic("fail")
+       }
+
+       c = make(chan int)
+       if len(c) != 0 || cap(c) != 0 {
+               println("chan len/cap ", len(c), cap(c), " want 0 0")
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/char_lit.go b/gcc/testsuite/go.test/test/char_lit.go
new file mode 100644 (file)
index 0000000..99be77a
--- /dev/null
@@ -0,0 +1,43 @@
+// $G $F.go && $L $F.$A &&./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+       var i uint64 =
+               ' ' +
+               'a' +
+               'ä' +
+               '本' +
+               '\a' +
+               '\b' +
+               '\f' +
+               '\n' +
+               '\r' +
+               '\t' +
+               '\v' +
+               '\\' +
+               '\'' +
+               '\000' +
+               '\123' +
+               '\x00' +
+               '\xca' +
+               '\xFE' +
+               '\u0123' +
+               '\ubabe' +
+               '\U0010FFFF' +
+               '\U000ebabe'
+       if '\U000ebabe' != 0x000ebabe {
+               print("ebabe wrong\n")
+               os.Exit(1)
+       }
+       if i != 0x20e213 {
+               print("number is ", i, " should be ", 0x20e213, "\n")
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/char_lit1.go b/gcc/testsuite/go.test/test/char_lit1.go
new file mode 100644 (file)
index 0000000..dc53852
--- /dev/null
@@ -0,0 +1,25 @@
+// errchk $G -e $F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+       // check that surrogate pair elements are invalid
+       // (d800-dbff, dc00-dfff).
+       _ = '\ud7ff' // ok
+       _ = '\ud800'  // ERROR "Unicode|unicode"
+       _ = "\U0000D999"  // ERROR "Unicode|unicode"
+       _ = '\udc01' // ERROR "Unicode|unicode"
+       _ = '\U0000dddd'  // ERROR "Unicode|unicode"
+       _ = '\udfff' // ERROR "Unicode|unicode"
+       _ = '\ue000' // ok
+       _ = '\U0010ffff'  // ok
+       _ = '\U00110000'  // ERROR "Unicode|unicode"
+       _ = "abc\U0010ffffdef"  // ok
+       _ = "abc\U00110000def"  // ERROR "Unicode|unicode"
+       _ = '\Uffffffff'  // ERROR "Unicode|unicode"
+)
+
diff --git a/gcc/testsuite/go.test/test/closedchan.go b/gcc/testsuite/go.test/test/closedchan.go
new file mode 100644 (file)
index 0000000..c7c759b
--- /dev/null
@@ -0,0 +1,197 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test close(c), closed(c).
+//
+// TODO(rsc): Doesn't check behavior of close(c) when there
+// are blocked senders/receivers.
+
+package main
+
+type Chan interface {
+       Send(int)
+       Nbsend(int) bool
+       Recv() int
+       Nbrecv() (int, bool)
+       Close()
+       Closed() bool
+       Impl() string
+}
+
+// direct channel operations
+type XChan chan int
+func (c XChan) Send(x int) {
+       c <- x
+}
+
+func (c XChan) Nbsend(x int) bool {
+       return c <- x
+}
+
+func (c XChan) Recv() int {
+       return <-c
+}
+
+func (c XChan) Nbrecv() (int, bool) {
+       x, ok := <-c
+       return x, ok
+}
+
+func (c XChan) Close() {
+       close(c)
+}
+
+func (c XChan) Closed() bool {
+       return closed(c)
+}
+
+func (c XChan) Impl() string {
+       return "(<- operator)"
+}
+
+// indirect operations via select
+type SChan chan int
+func (c SChan) Send(x int) {
+       select {
+       case c <- x:
+       }
+}
+
+func (c SChan) Nbsend(x int) bool {
+       select {
+       case c <- x:
+               return true
+       default:
+               return false
+       }
+       panic("nbsend")
+}
+
+func (c SChan) Recv() int {
+       select {
+       case x := <-c:
+               return x
+       }
+       panic("recv")
+}
+
+func (c SChan) Nbrecv() (int, bool) {
+       select {
+       case x := <-c:
+               return x, true
+       default:
+               return 0, false
+       }
+       panic("nbrecv")
+}
+
+func (c SChan) Close() {
+       close(c)
+}
+
+func (c SChan) Closed() bool {
+       return closed(c)
+}
+
+func (c SChan) Impl() string {
+       return "(select)"
+}
+
+func test1(c Chan) {
+       // not closed until the close signal (a zero value) has been received.
+       if c.Closed() {
+               println("test1: Closed before Recv zero:", c.Impl())
+       }
+
+       for i := 0; i < 3; i++ {
+               // recv a close signal (a zero value)
+               if x := c.Recv(); x != 0 {
+                       println("test1: recv on closed got non-zero:", x, c.Impl())
+               }
+
+               // should now be closed.
+               if !c.Closed() {
+                       println("test1: not closed after recv zero", c.Impl())
+               }
+
+               // should work with ,ok: received a value without blocking, so ok == true.
+               x, ok := c.Nbrecv()
+               if !ok {
+                       println("test1: recv on closed got not ok", c.Impl())
+               }
+               if x != 0 {
+                       println("test1: recv ,ok on closed got non-zero:", x, c.Impl())
+               }
+       }
+
+       // send should work with ,ok too: sent a value without blocking, so ok == true.
+       ok := c.Nbsend(1)
+       if !ok {
+               println("test1: send on closed got not ok", c.Impl())
+       }
+
+       // but the value should have been discarded.
+       if x := c.Recv(); x != 0 {
+               println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
+       }
+
+       // similarly Send.
+       c.Send(2)
+       if x := c.Recv(); x != 0 {
+               println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
+       }
+}
+
+func testasync1(c Chan) {
+       // not closed until the close signal (a zero value) has been received.
+       if c.Closed() {
+               println("testasync1: Closed before Recv zero:", c.Impl())
+       }
+
+       // should be able to get the last value via Recv
+       if x := c.Recv(); x != 1 {
+               println("testasync1: Recv did not get 1:", x, c.Impl())
+       }
+
+       test1(c)
+}
+
+func testasync2(c Chan) {
+       // not closed until the close signal (a zero value) has been received.
+       if c.Closed() {
+               println("testasync2: Closed before Recv zero:", c.Impl())
+       }
+
+       // should be able to get the last value via Nbrecv
+       if x, ok := c.Nbrecv(); !ok || x != 1 {
+               println("testasync2: Nbrecv did not get 1, true:", x, ok, c.Impl())
+       }
+
+       test1(c)
+}
+
+func closedsync() chan int {
+       c := make(chan int)
+       close(c)
+       return c
+}
+
+func closedasync() chan int {
+       c := make(chan int, 2)
+       c <- 1
+       close(c)
+       return c
+}
+
+func main() {
+       test1(XChan(closedsync()))
+       test1(SChan(closedsync()))
+
+       testasync1(XChan(closedasync()))
+       testasync1(SChan(closedasync()))
+       testasync2(XChan(closedasync()))
+       testasync2(SChan(closedasync()))
+}
diff --git a/gcc/testsuite/go.test/test/closure.go b/gcc/testsuite/go.test/test/closure.go
new file mode 100644 (file)
index 0000000..54e4cf8
--- /dev/null
@@ -0,0 +1,101 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var c = make(chan int)
+
+func check(a []int) {
+       for i := 0; i < len(a); i++ {
+               n := <-c
+               if n != a[i] {
+                       println("want", a[i], "got", n, "at", i)
+                       panic("fail")
+               }
+       }
+}
+
+func f() {
+       var i, j int
+
+       i = 1
+       j = 2
+       f := func() {
+               c <- i
+               i = 4
+               g := func() {
+                       c <- i
+                       c <- j
+               }
+               g()
+               c <- i
+       }
+       j = 5
+       f()
+}
+
+// Accumulator generator
+func accum(n int) func(int) int {
+       return func(i int) int {
+               n += i
+               return n
+       }
+}
+
+func g(a, b func(int) int) {
+       c <- a(2)
+       c <- b(3)
+       c <- a(4)
+       c <- b(5)
+}
+
+func h() {
+       var x8 byte = 100
+       var x64 int64 = 200
+
+       c <- int(x8)
+       c <- int(x64)
+       f := func(z int) {
+               g := func() {
+                       c <- int(x8)
+                       c <- int(x64)
+                       c <- z
+               }
+               g()
+               c <- int(x8)
+               c <- int(x64)
+               c <- int(z)
+       }
+       x8 = 101
+       x64 = 201
+       f(500)
+}
+
+func newfunc() func(int) int { return func(x int) int { return x } }
+
+
+func main() {
+       go f()
+       check([]int{1, 4, 5, 4})
+
+       a := accum(0)
+       b := accum(1)
+       go g(a, b)
+       check([]int{2, 4, 6, 9})
+
+       go h()
+       check([]int{100, 200, 101, 201, 500, 101, 201, 500})
+
+       x, y := newfunc(), newfunc()
+       if x == y {
+               println("newfunc returned same func")
+               panic("fail")
+       }
+       if x(1) != 1 || y(2) != 2 {
+               println("newfunc returned broken funcs")
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/cmp1.go b/gcc/testsuite/go.test/test/cmp1.go
new file mode 100644 (file)
index 0000000..db0a486
--- /dev/null
@@ -0,0 +1,76 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+func use(bool) {}
+
+func stringptr(s string) uintptr { return *(*uintptr)(unsafe.Pointer(&s)) }
+
+func isfalse(b bool) {
+       if b {
+               // stack will explain where
+               panic("wanted false, got true")
+       }
+}
+
+func istrue(b bool) {
+       if !b {
+               // stack will explain where
+               panic("wanted true, got false")
+       }
+}
+
+func main() {
+       var a []int
+       var b map[string]int
+
+       var c string = "hello"
+       var d string = "hel" // try to get different pointer
+       d = d + "lo"
+       if stringptr(c) == stringptr(d) {
+               panic("compiler too smart -- got same string")
+       }
+
+       var e = make(chan int)
+
+       var ia interface{} = a
+       var ib interface{} = b
+       var ic interface{} = c
+       var id interface{} = d
+       var ie interface{} = e
+
+       // these comparisons are okay because
+       // string compare is okay and the others
+       // are comparisons where the types differ.
+       isfalse(ia == ib)
+       isfalse(ia == ic)
+       isfalse(ia == id)
+       isfalse(ib == ic)
+       isfalse(ib == id)
+       istrue(ic == id)
+       istrue(ie == ie)
+
+       // 6g used to let this go through as true.
+       var g uint64 = 123
+       var h int64 = 123
+       var ig interface{} = g
+       var ih interface{} = h
+       isfalse(ig == ih)
+
+       // map of interface should use == on interface values,
+       // not memory.
+       // TODO: should m[c], m[d] be valid here?
+       var m = make(map[interface{}]int)
+       m[ic] = 1
+       m[id] = 2
+       if m[ic] != 2 {
+               println("m[ic] = ", m[ic])
+               panic("bad m[ic]")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/cmp2.go b/gcc/testsuite/go.test/test/cmp2.go
new file mode 100644 (file)
index 0000000..f6f124f
--- /dev/null
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func use(bool) { }
+
+func main() {
+       var a []int
+       var ia interface{} = a
+       use(ia == ia)
+}
diff --git a/gcc/testsuite/go.test/test/cmp3.go b/gcc/testsuite/go.test/test/cmp3.go
new file mode 100644 (file)
index 0000000..dd90bfb
--- /dev/null
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func use(bool) { }
+
+func main() {
+       var b []int
+       var ib interface{} = b
+       use(ib == ib)
+}
diff --git a/gcc/testsuite/go.test/test/cmp4.go b/gcc/testsuite/go.test/test/cmp4.go
new file mode 100644 (file)
index 0000000..3f9b2c0
--- /dev/null
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var a []int
+       var ia interface{} = a
+       var m = make(map[interface{}] int)
+       m[ia] = 1
+}
diff --git a/gcc/testsuite/go.test/test/cmp5.go b/gcc/testsuite/go.test/test/cmp5.go
new file mode 100644 (file)
index 0000000..3a7d733
--- /dev/null
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var b []int
+       var ib interface{} = b
+       var m = make(map[interface{}] int)
+       m[ib] = 1
+}
diff --git a/gcc/testsuite/go.test/test/cmplx.go b/gcc/testsuite/go.test/test/cmplx.go
new file mode 100644 (file)
index 0000000..6262c68
--- /dev/null
@@ -0,0 +1,31 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var (
+       f float
+       f32 float32
+       f64 float64
+
+       c complex
+       c64 complex64
+       c128 complex128
+)
+       
+func main() {
+       // ok
+       c = cmplx(f, f)
+       c64 = cmplx(f32, f32)
+       c128 = cmplx(f64, f64)
+
+       _ = cmplx(f, f32)       // ERROR "cmplx"
+       _ = cmplx(f, f64)       // ERROR "cmplx"
+       _ = cmplx(f32, f)       // ERROR "cmplx"
+       _ = cmplx(f32, f64)     // ERROR "cmplx"
+       _ = cmplx(f64, f)       // ERROR "cmplx"
+       _ = cmplx(f64, f32)     // ERROR "cmplx"
+}
diff --git a/gcc/testsuite/go.test/test/cmplxdivide.c b/gcc/testsuite/go.test/test/cmplxdivide.c
new file mode 100644 (file)
index 0000000..b3c6055
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// gcc '-std=c99' cmplxdivide.c && a.out >cmplxdivide1.go
+
+#include <complex.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+double f[] = {
+       0,
+       1,
+       -1,
+       2,
+       NAN,
+       INFINITY,
+       -INFINITY,
+};
+
+char*
+fmt(double g)
+{
+       static char buf[10][30];
+       static int n;
+       char *p;
+       
+       p = buf[n++];
+       if(n == 10)
+               n = 0;
+       sprintf(p, "%g", g);
+       if(strcmp(p, "-0") == 0)
+               strcpy(p, "negzero");
+       return p;
+}
+
+int
+iscnan(double complex d)
+{
+       return !isinf(creal(d)) && !isinf(cimag(d)) && (isnan(creal(d)) || isnan(cimag(d)));
+}
+
+double complex zero;   // attempt to hide zero division from gcc
+
+int
+main(void)
+{
+       int i, j, k, l;
+       double complex n, d, q;
+       
+       printf("// # generated by cmplxdivide.c\n");
+       printf("\n");
+       printf("package main\n");
+       printf("var tests = []Test{\n");
+       for(i=0; i<nelem(f); i++)
+       for(j=0; j<nelem(f); j++)
+       for(k=0; k<nelem(f); k++)
+       for(l=0; l<nelem(f); l++) {
+               n = f[i] + f[j]*I;
+               d = f[k] + f[l]*I;
+               q = n/d;
+               
+               // BUG FIX.
+               // Gcc gets the wrong answer for NaN/0 unless both sides are NaN.
+               // That is, it treats (NaN+NaN*I)/0 = NaN+NaN*I (a complex NaN)
+               // but it then computes (1+NaN*I)/0 = Inf+NaN*I (a complex infinity).
+               // Since both numerators are complex NaNs, it seems that the
+               // results should agree in kind.  Override the gcc computation in this case.
+               if(iscnan(n) && d == 0)
+                       q = (NAN+NAN*I) / zero;
+
+               printf("\tTest{cmplx(%s, %s), cmplx(%s, %s), cmplx(%s, %s)},\n",
+                       fmt(creal(n)), fmt(cimag(n)),
+                       fmt(creal(d)), fmt(cimag(d)),
+                       fmt(creal(q)), fmt(cimag(q)));
+       }
+       printf("}\n");
+       return 0;
+}
diff --git a/gcc/testsuite/go.test/test/cmplxdivide.go b/gcc/testsuite/go.test/test/cmplxdivide.go
new file mode 100644 (file)
index 0000000..6a67b17
--- /dev/null
@@ -0,0 +1,48 @@
+// $G $D/$F.go $D/cmplxdivide1.go && $L $D/$F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Driver for complex division table defined in cmplxdivide1.go
+
+package main
+
+import (
+       "cmath"
+       "fmt"
+       "math"
+)
+
+type Test struct{
+       f, g    complex128
+       out     complex128
+}
+
+var nan = math.NaN()
+var inf = math.Inf(1)
+var negzero = math.Copysign(0, -1)
+
+func calike(a, b complex128) bool {
+       switch {
+       case cmath.IsInf(a) && cmath.IsInf(b):
+               return true
+       case cmath.IsNaN(a) && cmath.IsNaN(b):
+               return true
+       }
+       return a == b
+}
+
+func main() {
+       bad := false
+       for _, t := range tests {
+               x := t.f/t.g
+               if !calike(x, t.out) {
+                       if !bad {
+                               fmt.Printf("BUG\n")
+                               bad = true
+                       }
+                       fmt.Printf("%v/%v: expected %v error; got %v\n", t.f, t.g, t.out, x)
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/cmplxdivide1.go b/gcc/testsuite/go.test/test/cmplxdivide1.go
new file mode 100644 (file)
index 0000000..96ea704
--- /dev/null
@@ -0,0 +1,2407 @@
+// # generated by cmplxdivide.c
+
+package main
+
+var tests = []Test{
+       Test{cmplx(0, 0), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(0, 1), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(0, -1), cmplx(negzero, 0)},
+       Test{cmplx(0, 0), cmplx(0, 2), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(0, inf), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(0, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 0), cmplx(1, 0), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(1, 1), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(1, -1), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(1, 2), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(1, inf), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 0), cmplx(-1, 0), cmplx(negzero, negzero)},
+       Test{cmplx(0, 0), cmplx(-1, 1), cmplx(negzero, negzero)},
+       Test{cmplx(0, 0), cmplx(-1, -1), cmplx(negzero, negzero)},
+       Test{cmplx(0, 0), cmplx(-1, 2), cmplx(0, negzero)},
+       Test{cmplx(0, 0), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(-1, inf), cmplx(0, negzero)},
+       Test{cmplx(0, 0), cmplx(-1, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, 0), cmplx(2, 0), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(2, 1), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(2, -1), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(2, 2), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(2, inf), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(2, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 0), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 0), cmplx(nan, inf), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(nan, -inf), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(inf, 0), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(inf, 1), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(inf, -1), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(inf, 2), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(inf, nan), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(inf, inf), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(inf, -inf), cmplx(0, 0)},
+       Test{cmplx(0, 0), cmplx(-inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(0, 0), cmplx(-inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(0, 0), cmplx(-inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(0, 0), cmplx(-inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(0, 0), cmplx(-inf, nan), cmplx(0, negzero)},
+       Test{cmplx(0, 0), cmplx(-inf, inf), cmplx(0, negzero)},
+       Test{cmplx(0, 0), cmplx(-inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 1), cmplx(0, 0), cmplx(nan, inf)},
+       Test{cmplx(0, 1), cmplx(0, 1), cmplx(1, 0)},
+       Test{cmplx(0, 1), cmplx(0, -1), cmplx(-1, 0)},
+       Test{cmplx(0, 1), cmplx(0, 2), cmplx(0.5, 0)},
+       Test{cmplx(0, 1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 1), cmplx(0, inf), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(0, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 1), cmplx(1, 0), cmplx(0, 1)},
+       Test{cmplx(0, 1), cmplx(1, 1), cmplx(0.5, 0.5)},
+       Test{cmplx(0, 1), cmplx(1, -1), cmplx(-0.5, 0.5)},
+       Test{cmplx(0, 1), cmplx(1, 2), cmplx(0.4, 0.2)},
+       Test{cmplx(0, 1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 1), cmplx(1, inf), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 1), cmplx(-1, 0), cmplx(negzero, -1)},
+       Test{cmplx(0, 1), cmplx(-1, 1), cmplx(0.5, -0.5)},
+       Test{cmplx(0, 1), cmplx(-1, -1), cmplx(-0.5, -0.5)},
+       Test{cmplx(0, 1), cmplx(-1, 2), cmplx(0.4, -0.2)},
+       Test{cmplx(0, 1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 1), cmplx(-1, inf), cmplx(0, negzero)},
+       Test{cmplx(0, 1), cmplx(-1, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, 1), cmplx(2, 0), cmplx(0, 0.5)},
+       Test{cmplx(0, 1), cmplx(2, 1), cmplx(0.2, 0.4)},
+       Test{cmplx(0, 1), cmplx(2, -1), cmplx(-0.2, 0.4)},
+       Test{cmplx(0, 1), cmplx(2, 2), cmplx(0.25, 0.25)},
+       Test{cmplx(0, 1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 1), cmplx(2, inf), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(2, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(0, 1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(0, 1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(0, 1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(0, 1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 1), cmplx(nan, inf), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(nan, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 1), cmplx(inf, 0), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(inf, 1), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(inf, -1), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(inf, 2), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(inf, nan), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(inf, inf), cmplx(0, 0)},
+       Test{cmplx(0, 1), cmplx(inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 1), cmplx(-inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(0, 1), cmplx(-inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(0, 1), cmplx(-inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(0, 1), cmplx(-inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(0, 1), cmplx(-inf, nan), cmplx(0, negzero)},
+       Test{cmplx(0, 1), cmplx(-inf, inf), cmplx(0, negzero)},
+       Test{cmplx(0, 1), cmplx(-inf, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, -1), cmplx(0, 0), cmplx(nan, -inf)},
+       Test{cmplx(0, -1), cmplx(0, 1), cmplx(-1, negzero)},
+       Test{cmplx(0, -1), cmplx(0, -1), cmplx(1, negzero)},
+       Test{cmplx(0, -1), cmplx(0, 2), cmplx(-0.5, negzero)},
+       Test{cmplx(0, -1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -1), cmplx(0, inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, -1), cmplx(0, -inf), cmplx(0, negzero)},
+       Test{cmplx(0, -1), cmplx(1, 0), cmplx(0, -1)},
+       Test{cmplx(0, -1), cmplx(1, 1), cmplx(-0.5, -0.5)},
+       Test{cmplx(0, -1), cmplx(1, -1), cmplx(0.5, -0.5)},
+       Test{cmplx(0, -1), cmplx(1, 2), cmplx(-0.4, -0.2)},
+       Test{cmplx(0, -1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -1), cmplx(1, inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, -1), cmplx(1, -inf), cmplx(0, negzero)},
+       Test{cmplx(0, -1), cmplx(-1, 0), cmplx(negzero, 1)},
+       Test{cmplx(0, -1), cmplx(-1, 1), cmplx(-0.5, 0.5)},
+       Test{cmplx(0, -1), cmplx(-1, -1), cmplx(0.5, 0.5)},
+       Test{cmplx(0, -1), cmplx(-1, 2), cmplx(-0.4, 0.2)},
+       Test{cmplx(0, -1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -1), cmplx(-1, inf), cmplx(negzero, 0)},
+       Test{cmplx(0, -1), cmplx(-1, -inf), cmplx(0, 0)},
+       Test{cmplx(0, -1), cmplx(2, 0), cmplx(0, -0.5)},
+       Test{cmplx(0, -1), cmplx(2, 1), cmplx(-0.2, -0.4)},
+       Test{cmplx(0, -1), cmplx(2, -1), cmplx(0.2, -0.4)},
+       Test{cmplx(0, -1), cmplx(2, 2), cmplx(-0.25, -0.25)},
+       Test{cmplx(0, -1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -1), cmplx(2, inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, -1), cmplx(2, -inf), cmplx(0, negzero)},
+       Test{cmplx(0, -1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(0, -1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(0, -1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(0, -1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(0, -1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -1), cmplx(nan, inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, -1), cmplx(nan, -inf), cmplx(0, 0)},
+       Test{cmplx(0, -1), cmplx(inf, 0), cmplx(0, negzero)},
+       Test{cmplx(0, -1), cmplx(inf, 1), cmplx(0, negzero)},
+       Test{cmplx(0, -1), cmplx(inf, -1), cmplx(0, negzero)},
+       Test{cmplx(0, -1), cmplx(inf, 2), cmplx(0, negzero)},
+       Test{cmplx(0, -1), cmplx(inf, nan), cmplx(0, negzero)},
+       Test{cmplx(0, -1), cmplx(inf, inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, -1), cmplx(inf, -inf), cmplx(0, negzero)},
+       Test{cmplx(0, -1), cmplx(-inf, 0), cmplx(negzero, 0)},
+       Test{cmplx(0, -1), cmplx(-inf, 1), cmplx(negzero, 0)},
+       Test{cmplx(0, -1), cmplx(-inf, -1), cmplx(negzero, 0)},
+       Test{cmplx(0, -1), cmplx(-inf, 2), cmplx(negzero, 0)},
+       Test{cmplx(0, -1), cmplx(-inf, nan), cmplx(negzero, 0)},
+       Test{cmplx(0, -1), cmplx(-inf, inf), cmplx(negzero, 0)},
+       Test{cmplx(0, -1), cmplx(-inf, -inf), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(0, 0), cmplx(nan, inf)},
+       Test{cmplx(0, 2), cmplx(0, 1), cmplx(2, 0)},
+       Test{cmplx(0, 2), cmplx(0, -1), cmplx(-2, 0)},
+       Test{cmplx(0, 2), cmplx(0, 2), cmplx(1, 0)},
+       Test{cmplx(0, 2), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 2), cmplx(0, inf), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(0, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 2), cmplx(1, 0), cmplx(0, 2)},
+       Test{cmplx(0, 2), cmplx(1, 1), cmplx(1, 1)},
+       Test{cmplx(0, 2), cmplx(1, -1), cmplx(-1, 1)},
+       Test{cmplx(0, 2), cmplx(1, 2), cmplx(0.8, 0.4)},
+       Test{cmplx(0, 2), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 2), cmplx(1, inf), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 2), cmplx(-1, 0), cmplx(negzero, -2)},
+       Test{cmplx(0, 2), cmplx(-1, 1), cmplx(1, -1)},
+       Test{cmplx(0, 2), cmplx(-1, -1), cmplx(-1, -1)},
+       Test{cmplx(0, 2), cmplx(-1, 2), cmplx(0.8, -0.4)},
+       Test{cmplx(0, 2), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 2), cmplx(-1, inf), cmplx(0, negzero)},
+       Test{cmplx(0, 2), cmplx(-1, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, 2), cmplx(2, 0), cmplx(0, 1)},
+       Test{cmplx(0, 2), cmplx(2, 1), cmplx(0.4, 0.8)},
+       Test{cmplx(0, 2), cmplx(2, -1), cmplx(-0.4, 0.8)},
+       Test{cmplx(0, 2), cmplx(2, 2), cmplx(0.5, 0.5)},
+       Test{cmplx(0, 2), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 2), cmplx(2, inf), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(2, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 2), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(0, 2), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(0, 2), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(0, 2), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(0, 2), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(0, 2), cmplx(nan, inf), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(nan, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 2), cmplx(inf, 0), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(inf, 1), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(inf, -1), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(inf, 2), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(inf, nan), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(inf, inf), cmplx(0, 0)},
+       Test{cmplx(0, 2), cmplx(inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(0, 2), cmplx(-inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(0, 2), cmplx(-inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(0, 2), cmplx(-inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(0, 2), cmplx(-inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(0, 2), cmplx(-inf, nan), cmplx(0, negzero)},
+       Test{cmplx(0, 2), cmplx(-inf, inf), cmplx(0, negzero)},
+       Test{cmplx(0, 2), cmplx(-inf, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(0, nan), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(0, 1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(0, -1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(0, 2), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(1, 0), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(1, 1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(1, -1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(1, 2), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-1, 0), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-1, 1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-1, -1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-1, 2), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(2, 0), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(2, 1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(2, -1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(2, 2), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(0, nan), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(0, 0), cmplx(nan, inf)},
+       Test{cmplx(0, inf), cmplx(0, 1), cmplx(inf, nan)},
+       Test{cmplx(0, inf), cmplx(0, -1), cmplx(-inf, nan)},
+       Test{cmplx(0, inf), cmplx(0, 2), cmplx(inf, nan)},
+       Test{cmplx(0, inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(1, 0), cmplx(nan, inf)},
+       Test{cmplx(0, inf), cmplx(1, 1), cmplx(inf, inf)},
+       Test{cmplx(0, inf), cmplx(1, -1), cmplx(-inf, inf)},
+       Test{cmplx(0, inf), cmplx(1, 2), cmplx(inf, inf)},
+       Test{cmplx(0, inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-1, 0), cmplx(nan, -inf)},
+       Test{cmplx(0, inf), cmplx(-1, 1), cmplx(inf, -inf)},
+       Test{cmplx(0, inf), cmplx(-1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(0, inf), cmplx(-1, 2), cmplx(inf, -inf)},
+       Test{cmplx(0, inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(2, 0), cmplx(nan, inf)},
+       Test{cmplx(0, inf), cmplx(2, 1), cmplx(inf, inf)},
+       Test{cmplx(0, inf), cmplx(2, -1), cmplx(-inf, inf)},
+       Test{cmplx(0, inf), cmplx(2, 2), cmplx(inf, inf)},
+       Test{cmplx(0, inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(0, inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(0, 0), cmplx(nan, -inf)},
+       Test{cmplx(0, -inf), cmplx(0, 1), cmplx(-inf, nan)},
+       Test{cmplx(0, -inf), cmplx(0, -1), cmplx(inf, nan)},
+       Test{cmplx(0, -inf), cmplx(0, 2), cmplx(-inf, nan)},
+       Test{cmplx(0, -inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(1, 0), cmplx(nan, -inf)},
+       Test{cmplx(0, -inf), cmplx(1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(0, -inf), cmplx(1, -1), cmplx(inf, -inf)},
+       Test{cmplx(0, -inf), cmplx(1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(0, -inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-1, 0), cmplx(nan, inf)},
+       Test{cmplx(0, -inf), cmplx(-1, 1), cmplx(-inf, inf)},
+       Test{cmplx(0, -inf), cmplx(-1, -1), cmplx(inf, inf)},
+       Test{cmplx(0, -inf), cmplx(-1, 2), cmplx(-inf, inf)},
+       Test{cmplx(0, -inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(2, 0), cmplx(nan, -inf)},
+       Test{cmplx(0, -inf), cmplx(2, 1), cmplx(-inf, -inf)},
+       Test{cmplx(0, -inf), cmplx(2, -1), cmplx(inf, -inf)},
+       Test{cmplx(0, -inf), cmplx(2, 2), cmplx(-inf, -inf)},
+       Test{cmplx(0, -inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(0, -inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(0, 0), cmplx(inf, nan)},
+       Test{cmplx(1, 0), cmplx(0, 1), cmplx(0, -1)},
+       Test{cmplx(1, 0), cmplx(0, -1), cmplx(negzero, 1)},
+       Test{cmplx(1, 0), cmplx(0, 2), cmplx(0, -0.5)},
+       Test{cmplx(1, 0), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(0, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 0), cmplx(0, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 0), cmplx(1, 0), cmplx(1, 0)},
+       Test{cmplx(1, 0), cmplx(1, 1), cmplx(0.5, -0.5)},
+       Test{cmplx(1, 0), cmplx(1, -1), cmplx(0.5, 0.5)},
+       Test{cmplx(1, 0), cmplx(1, 2), cmplx(0.2, -0.4)},
+       Test{cmplx(1, 0), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(1, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 0), cmplx(1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 0), cmplx(-1, 0), cmplx(-1, negzero)},
+       Test{cmplx(1, 0), cmplx(-1, 1), cmplx(-0.5, -0.5)},
+       Test{cmplx(1, 0), cmplx(-1, -1), cmplx(-0.5, 0.5)},
+       Test{cmplx(1, 0), cmplx(-1, 2), cmplx(-0.2, -0.4)},
+       Test{cmplx(1, 0), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(-1, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 0), cmplx(-1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 0), cmplx(2, 0), cmplx(0.5, 0)},
+       Test{cmplx(1, 0), cmplx(2, 1), cmplx(0.4, -0.2)},
+       Test{cmplx(1, 0), cmplx(2, -1), cmplx(0.4, 0.2)},
+       Test{cmplx(1, 0), cmplx(2, 2), cmplx(0.25, -0.25)},
+       Test{cmplx(1, 0), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(2, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 0), cmplx(2, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 0), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 0), cmplx(nan, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 0), cmplx(nan, -inf), cmplx(0, 0)},
+       Test{cmplx(1, 0), cmplx(inf, 0), cmplx(0, 0)},
+       Test{cmplx(1, 0), cmplx(inf, 1), cmplx(0, 0)},
+       Test{cmplx(1, 0), cmplx(inf, -1), cmplx(0, 0)},
+       Test{cmplx(1, 0), cmplx(inf, 2), cmplx(0, 0)},
+       Test{cmplx(1, 0), cmplx(inf, nan), cmplx(0, 0)},
+       Test{cmplx(1, 0), cmplx(inf, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 0), cmplx(inf, -inf), cmplx(0, 0)},
+       Test{cmplx(1, 0), cmplx(-inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(1, 0), cmplx(-inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(1, 0), cmplx(-inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(1, 0), cmplx(-inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(1, 0), cmplx(-inf, nan), cmplx(negzero, negzero)},
+       Test{cmplx(1, 0), cmplx(-inf, inf), cmplx(negzero, negzero)},
+       Test{cmplx(1, 0), cmplx(-inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 1), cmplx(0, 0), cmplx(inf, inf)},
+       Test{cmplx(1, 1), cmplx(0, 1), cmplx(1, -1)},
+       Test{cmplx(1, 1), cmplx(0, -1), cmplx(-1, 1)},
+       Test{cmplx(1, 1), cmplx(0, 2), cmplx(0.5, -0.5)},
+       Test{cmplx(1, 1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 1), cmplx(0, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 1), cmplx(0, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 1), cmplx(1, 0), cmplx(1, 1)},
+       Test{cmplx(1, 1), cmplx(1, 1), cmplx(1, 0)},
+       Test{cmplx(1, 1), cmplx(1, -1), cmplx(0, 1)},
+       Test{cmplx(1, 1), cmplx(1, 2), cmplx(0.6, -0.2)},
+       Test{cmplx(1, 1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 1), cmplx(1, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 1), cmplx(1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 1), cmplx(-1, 0), cmplx(-1, -1)},
+       Test{cmplx(1, 1), cmplx(-1, 1), cmplx(negzero, -1)},
+       Test{cmplx(1, 1), cmplx(-1, -1), cmplx(-1, negzero)},
+       Test{cmplx(1, 1), cmplx(-1, 2), cmplx(0.2, -0.6)},
+       Test{cmplx(1, 1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 1), cmplx(-1, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 1), cmplx(-1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 1), cmplx(2, 0), cmplx(0.5, 0.5)},
+       Test{cmplx(1, 1), cmplx(2, 1), cmplx(0.6, 0.2)},
+       Test{cmplx(1, 1), cmplx(2, -1), cmplx(0.2, 0.6)},
+       Test{cmplx(1, 1), cmplx(2, 2), cmplx(0.5, 0)},
+       Test{cmplx(1, 1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 1), cmplx(2, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 1), cmplx(2, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(1, 1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(1, 1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(1, 1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(1, 1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 1), cmplx(nan, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 1), cmplx(nan, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 1), cmplx(inf, 0), cmplx(0, 0)},
+       Test{cmplx(1, 1), cmplx(inf, 1), cmplx(0, 0)},
+       Test{cmplx(1, 1), cmplx(inf, -1), cmplx(0, 0)},
+       Test{cmplx(1, 1), cmplx(inf, 2), cmplx(0, 0)},
+       Test{cmplx(1, 1), cmplx(inf, nan), cmplx(0, 0)},
+       Test{cmplx(1, 1), cmplx(inf, inf), cmplx(0, 0)},
+       Test{cmplx(1, 1), cmplx(inf, -inf), cmplx(0, 0)},
+       Test{cmplx(1, 1), cmplx(-inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(1, 1), cmplx(-inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(1, 1), cmplx(-inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(1, 1), cmplx(-inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(1, 1), cmplx(-inf, nan), cmplx(negzero, negzero)},
+       Test{cmplx(1, 1), cmplx(-inf, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 1), cmplx(-inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, -1), cmplx(0, 0), cmplx(inf, -inf)},
+       Test{cmplx(1, -1), cmplx(0, 1), cmplx(-1, -1)},
+       Test{cmplx(1, -1), cmplx(0, -1), cmplx(1, 1)},
+       Test{cmplx(1, -1), cmplx(0, 2), cmplx(-0.5, -0.5)},
+       Test{cmplx(1, -1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -1), cmplx(0, inf), cmplx(negzero, negzero)},
+       Test{cmplx(1, -1), cmplx(0, -inf), cmplx(0, 0)},
+       Test{cmplx(1, -1), cmplx(1, 0), cmplx(1, -1)},
+       Test{cmplx(1, -1), cmplx(1, 1), cmplx(0, -1)},
+       Test{cmplx(1, -1), cmplx(1, -1), cmplx(1, 0)},
+       Test{cmplx(1, -1), cmplx(1, 2), cmplx(-0.2, -0.6)},
+       Test{cmplx(1, -1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -1), cmplx(1, inf), cmplx(negzero, negzero)},
+       Test{cmplx(1, -1), cmplx(1, -inf), cmplx(0, 0)},
+       Test{cmplx(1, -1), cmplx(-1, 0), cmplx(-1, 1)},
+       Test{cmplx(1, -1), cmplx(-1, 1), cmplx(-1, negzero)},
+       Test{cmplx(1, -1), cmplx(-1, -1), cmplx(negzero, 1)},
+       Test{cmplx(1, -1), cmplx(-1, 2), cmplx(-0.6, -0.2)},
+       Test{cmplx(1, -1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -1), cmplx(-1, inf), cmplx(negzero, negzero)},
+       Test{cmplx(1, -1), cmplx(-1, -inf), cmplx(0, 0)},
+       Test{cmplx(1, -1), cmplx(2, 0), cmplx(0.5, -0.5)},
+       Test{cmplx(1, -1), cmplx(2, 1), cmplx(0.2, -0.6)},
+       Test{cmplx(1, -1), cmplx(2, -1), cmplx(0.6, -0.2)},
+       Test{cmplx(1, -1), cmplx(2, 2), cmplx(0, -0.5)},
+       Test{cmplx(1, -1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -1), cmplx(2, inf), cmplx(negzero, negzero)},
+       Test{cmplx(1, -1), cmplx(2, -inf), cmplx(0, 0)},
+       Test{cmplx(1, -1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(1, -1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(1, -1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(1, -1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(1, -1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -1), cmplx(nan, inf), cmplx(negzero, negzero)},
+       Test{cmplx(1, -1), cmplx(nan, -inf), cmplx(0, 0)},
+       Test{cmplx(1, -1), cmplx(inf, 0), cmplx(0, negzero)},
+       Test{cmplx(1, -1), cmplx(inf, 1), cmplx(0, negzero)},
+       Test{cmplx(1, -1), cmplx(inf, -1), cmplx(0, negzero)},
+       Test{cmplx(1, -1), cmplx(inf, 2), cmplx(0, negzero)},
+       Test{cmplx(1, -1), cmplx(inf, nan), cmplx(0, negzero)},
+       Test{cmplx(1, -1), cmplx(inf, inf), cmplx(0, negzero)},
+       Test{cmplx(1, -1), cmplx(inf, -inf), cmplx(0, 0)},
+       Test{cmplx(1, -1), cmplx(-inf, 0), cmplx(negzero, 0)},
+       Test{cmplx(1, -1), cmplx(-inf, 1), cmplx(negzero, 0)},
+       Test{cmplx(1, -1), cmplx(-inf, -1), cmplx(negzero, 0)},
+       Test{cmplx(1, -1), cmplx(-inf, 2), cmplx(negzero, 0)},
+       Test{cmplx(1, -1), cmplx(-inf, nan), cmplx(negzero, 0)},
+       Test{cmplx(1, -1), cmplx(-inf, inf), cmplx(negzero, 0)},
+       Test{cmplx(1, -1), cmplx(-inf, -inf), cmplx(0, 0)},
+       Test{cmplx(1, 2), cmplx(0, 0), cmplx(inf, inf)},
+       Test{cmplx(1, 2), cmplx(0, 1), cmplx(2, -1)},
+       Test{cmplx(1, 2), cmplx(0, -1), cmplx(-2, 1)},
+       Test{cmplx(1, 2), cmplx(0, 2), cmplx(1, -0.5)},
+       Test{cmplx(1, 2), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 2), cmplx(0, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 2), cmplx(0, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 2), cmplx(1, 0), cmplx(1, 2)},
+       Test{cmplx(1, 2), cmplx(1, 1), cmplx(1.5, 0.5)},
+       Test{cmplx(1, 2), cmplx(1, -1), cmplx(-0.5, 1.5)},
+       Test{cmplx(1, 2), cmplx(1, 2), cmplx(1, 0)},
+       Test{cmplx(1, 2), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 2), cmplx(1, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 2), cmplx(1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 2), cmplx(-1, 0), cmplx(-1, -2)},
+       Test{cmplx(1, 2), cmplx(-1, 1), cmplx(0.5, -1.5)},
+       Test{cmplx(1, 2), cmplx(-1, -1), cmplx(-1.5, -0.5)},
+       Test{cmplx(1, 2), cmplx(-1, 2), cmplx(0.6, -0.8)},
+       Test{cmplx(1, 2), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 2), cmplx(-1, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 2), cmplx(-1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 2), cmplx(2, 0), cmplx(0.5, 1)},
+       Test{cmplx(1, 2), cmplx(2, 1), cmplx(0.8, 0.6)},
+       Test{cmplx(1, 2), cmplx(2, -1), cmplx(0, 1)},
+       Test{cmplx(1, 2), cmplx(2, 2), cmplx(0.75, 0.25)},
+       Test{cmplx(1, 2), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 2), cmplx(2, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 2), cmplx(2, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 2), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(1, 2), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(1, 2), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(1, 2), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(1, 2), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(1, 2), cmplx(nan, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 2), cmplx(nan, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 2), cmplx(inf, 0), cmplx(0, 0)},
+       Test{cmplx(1, 2), cmplx(inf, 1), cmplx(0, 0)},
+       Test{cmplx(1, 2), cmplx(inf, -1), cmplx(0, 0)},
+       Test{cmplx(1, 2), cmplx(inf, 2), cmplx(0, 0)},
+       Test{cmplx(1, 2), cmplx(inf, nan), cmplx(0, 0)},
+       Test{cmplx(1, 2), cmplx(inf, inf), cmplx(0, 0)},
+       Test{cmplx(1, 2), cmplx(inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(1, 2), cmplx(-inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(1, 2), cmplx(-inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(1, 2), cmplx(-inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(1, 2), cmplx(-inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(1, 2), cmplx(-inf, nan), cmplx(negzero, negzero)},
+       Test{cmplx(1, 2), cmplx(-inf, inf), cmplx(0, negzero)},
+       Test{cmplx(1, 2), cmplx(-inf, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(1, nan), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(0, 1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(0, -1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(0, 2), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(1, 0), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(1, 1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(1, -1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(1, 2), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-1, 0), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-1, 1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-1, -1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-1, 2), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(2, 0), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(2, 1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(2, -1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(2, 2), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(1, nan), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(0, 0), cmplx(inf, inf)},
+       Test{cmplx(1, inf), cmplx(0, 1), cmplx(inf, nan)},
+       Test{cmplx(1, inf), cmplx(0, -1), cmplx(-inf, nan)},
+       Test{cmplx(1, inf), cmplx(0, 2), cmplx(inf, nan)},
+       Test{cmplx(1, inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(1, 0), cmplx(nan, inf)},
+       Test{cmplx(1, inf), cmplx(1, 1), cmplx(inf, inf)},
+       Test{cmplx(1, inf), cmplx(1, -1), cmplx(-inf, inf)},
+       Test{cmplx(1, inf), cmplx(1, 2), cmplx(inf, inf)},
+       Test{cmplx(1, inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-1, 0), cmplx(nan, -inf)},
+       Test{cmplx(1, inf), cmplx(-1, 1), cmplx(inf, -inf)},
+       Test{cmplx(1, inf), cmplx(-1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(1, inf), cmplx(-1, 2), cmplx(inf, -inf)},
+       Test{cmplx(1, inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(2, 0), cmplx(nan, inf)},
+       Test{cmplx(1, inf), cmplx(2, 1), cmplx(inf, inf)},
+       Test{cmplx(1, inf), cmplx(2, -1), cmplx(-inf, inf)},
+       Test{cmplx(1, inf), cmplx(2, 2), cmplx(inf, inf)},
+       Test{cmplx(1, inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(1, inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(0, 0), cmplx(inf, -inf)},
+       Test{cmplx(1, -inf), cmplx(0, 1), cmplx(-inf, nan)},
+       Test{cmplx(1, -inf), cmplx(0, -1), cmplx(inf, nan)},
+       Test{cmplx(1, -inf), cmplx(0, 2), cmplx(-inf, nan)},
+       Test{cmplx(1, -inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(1, 0), cmplx(nan, -inf)},
+       Test{cmplx(1, -inf), cmplx(1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(1, -inf), cmplx(1, -1), cmplx(inf, -inf)},
+       Test{cmplx(1, -inf), cmplx(1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(1, -inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-1, 0), cmplx(nan, inf)},
+       Test{cmplx(1, -inf), cmplx(-1, 1), cmplx(-inf, inf)},
+       Test{cmplx(1, -inf), cmplx(-1, -1), cmplx(inf, inf)},
+       Test{cmplx(1, -inf), cmplx(-1, 2), cmplx(-inf, inf)},
+       Test{cmplx(1, -inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(2, 0), cmplx(nan, -inf)},
+       Test{cmplx(1, -inf), cmplx(2, 1), cmplx(-inf, -inf)},
+       Test{cmplx(1, -inf), cmplx(2, -1), cmplx(inf, -inf)},
+       Test{cmplx(1, -inf), cmplx(2, 2), cmplx(-inf, -inf)},
+       Test{cmplx(1, -inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(1, -inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(0, 0), cmplx(-inf, nan)},
+       Test{cmplx(-1, 0), cmplx(0, 1), cmplx(0, 1)},
+       Test{cmplx(-1, 0), cmplx(0, -1), cmplx(negzero, -1)},
+       Test{cmplx(-1, 0), cmplx(0, 2), cmplx(0, 0.5)},
+       Test{cmplx(-1, 0), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(0, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 0), cmplx(0, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 0), cmplx(1, 0), cmplx(-1, 0)},
+       Test{cmplx(-1, 0), cmplx(1, 1), cmplx(-0.5, 0.5)},
+       Test{cmplx(-1, 0), cmplx(1, -1), cmplx(-0.5, -0.5)},
+       Test{cmplx(-1, 0), cmplx(1, 2), cmplx(-0.2, 0.4)},
+       Test{cmplx(-1, 0), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(1, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 0), cmplx(1, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 0), cmplx(-1, 0), cmplx(1, negzero)},
+       Test{cmplx(-1, 0), cmplx(-1, 1), cmplx(0.5, 0.5)},
+       Test{cmplx(-1, 0), cmplx(-1, -1), cmplx(0.5, -0.5)},
+       Test{cmplx(-1, 0), cmplx(-1, 2), cmplx(0.2, 0.4)},
+       Test{cmplx(-1, 0), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(-1, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 0), cmplx(-1, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 0), cmplx(2, 0), cmplx(-0.5, 0)},
+       Test{cmplx(-1, 0), cmplx(2, 1), cmplx(-0.4, 0.2)},
+       Test{cmplx(-1, 0), cmplx(2, -1), cmplx(-0.4, -0.2)},
+       Test{cmplx(-1, 0), cmplx(2, 2), cmplx(-0.25, 0.25)},
+       Test{cmplx(-1, 0), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(2, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 0), cmplx(2, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 0), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 0), cmplx(nan, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 0), cmplx(nan, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 0), cmplx(inf, 0), cmplx(negzero, 0)},
+       Test{cmplx(-1, 0), cmplx(inf, 1), cmplx(negzero, 0)},
+       Test{cmplx(-1, 0), cmplx(inf, -1), cmplx(negzero, 0)},
+       Test{cmplx(-1, 0), cmplx(inf, 2), cmplx(negzero, 0)},
+       Test{cmplx(-1, 0), cmplx(inf, nan), cmplx(negzero, 0)},
+       Test{cmplx(-1, 0), cmplx(inf, inf), cmplx(negzero, 0)},
+       Test{cmplx(-1, 0), cmplx(inf, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 0), cmplx(-inf, 0), cmplx(0, negzero)},
+       Test{cmplx(-1, 0), cmplx(-inf, 1), cmplx(0, negzero)},
+       Test{cmplx(-1, 0), cmplx(-inf, -1), cmplx(0, negzero)},
+       Test{cmplx(-1, 0), cmplx(-inf, 2), cmplx(0, negzero)},
+       Test{cmplx(-1, 0), cmplx(-inf, nan), cmplx(0, 0)},
+       Test{cmplx(-1, 0), cmplx(-inf, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 0), cmplx(-inf, -inf), cmplx(0, negzero)},
+       Test{cmplx(-1, 1), cmplx(0, 0), cmplx(-inf, inf)},
+       Test{cmplx(-1, 1), cmplx(0, 1), cmplx(1, 1)},
+       Test{cmplx(-1, 1), cmplx(0, -1), cmplx(-1, -1)},
+       Test{cmplx(-1, 1), cmplx(0, 2), cmplx(0.5, 0.5)},
+       Test{cmplx(-1, 1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 1), cmplx(0, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 1), cmplx(0, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 1), cmplx(1, 0), cmplx(-1, 1)},
+       Test{cmplx(-1, 1), cmplx(1, 1), cmplx(0, 1)},
+       Test{cmplx(-1, 1), cmplx(1, -1), cmplx(-1, 0)},
+       Test{cmplx(-1, 1), cmplx(1, 2), cmplx(0.2, 0.6)},
+       Test{cmplx(-1, 1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 1), cmplx(1, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 1), cmplx(1, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 1), cmplx(-1, 0), cmplx(1, -1)},
+       Test{cmplx(-1, 1), cmplx(-1, 1), cmplx(1, negzero)},
+       Test{cmplx(-1, 1), cmplx(-1, -1), cmplx(negzero, -1)},
+       Test{cmplx(-1, 1), cmplx(-1, 2), cmplx(0.6, 0.2)},
+       Test{cmplx(-1, 1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 1), cmplx(-1, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 1), cmplx(-1, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 1), cmplx(2, 0), cmplx(-0.5, 0.5)},
+       Test{cmplx(-1, 1), cmplx(2, 1), cmplx(-0.2, 0.6)},
+       Test{cmplx(-1, 1), cmplx(2, -1), cmplx(-0.6, 0.2)},
+       Test{cmplx(-1, 1), cmplx(2, 2), cmplx(0, 0.5)},
+       Test{cmplx(-1, 1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 1), cmplx(2, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 1), cmplx(2, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, 1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, 1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, 1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, 1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 1), cmplx(nan, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 1), cmplx(nan, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 1), cmplx(inf, 0), cmplx(negzero, 0)},
+       Test{cmplx(-1, 1), cmplx(inf, 1), cmplx(negzero, 0)},
+       Test{cmplx(-1, 1), cmplx(inf, -1), cmplx(negzero, 0)},
+       Test{cmplx(-1, 1), cmplx(inf, 2), cmplx(negzero, 0)},
+       Test{cmplx(-1, 1), cmplx(inf, nan), cmplx(negzero, 0)},
+       Test{cmplx(-1, 1), cmplx(inf, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 1), cmplx(inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(-1, 1), cmplx(-inf, 0), cmplx(0, negzero)},
+       Test{cmplx(-1, 1), cmplx(-inf, 1), cmplx(0, negzero)},
+       Test{cmplx(-1, 1), cmplx(-inf, -1), cmplx(0, negzero)},
+       Test{cmplx(-1, 1), cmplx(-inf, 2), cmplx(0, negzero)},
+       Test{cmplx(-1, 1), cmplx(-inf, nan), cmplx(0, negzero)},
+       Test{cmplx(-1, 1), cmplx(-inf, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 1), cmplx(-inf, -inf), cmplx(0, negzero)},
+       Test{cmplx(-1, -1), cmplx(0, 0), cmplx(-inf, -inf)},
+       Test{cmplx(-1, -1), cmplx(0, 1), cmplx(-1, 1)},
+       Test{cmplx(-1, -1), cmplx(0, -1), cmplx(1, -1)},
+       Test{cmplx(-1, -1), cmplx(0, 2), cmplx(-0.5, 0.5)},
+       Test{cmplx(-1, -1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -1), cmplx(0, inf), cmplx(negzero, 0)},
+       Test{cmplx(-1, -1), cmplx(0, -inf), cmplx(0, negzero)},
+       Test{cmplx(-1, -1), cmplx(1, 0), cmplx(-1, -1)},
+       Test{cmplx(-1, -1), cmplx(1, 1), cmplx(-1, 0)},
+       Test{cmplx(-1, -1), cmplx(1, -1), cmplx(0, -1)},
+       Test{cmplx(-1, -1), cmplx(1, 2), cmplx(-0.6, 0.2)},
+       Test{cmplx(-1, -1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -1), cmplx(1, inf), cmplx(negzero, 0)},
+       Test{cmplx(-1, -1), cmplx(1, -inf), cmplx(0, negzero)},
+       Test{cmplx(-1, -1), cmplx(-1, 0), cmplx(1, 1)},
+       Test{cmplx(-1, -1), cmplx(-1, 1), cmplx(negzero, 1)},
+       Test{cmplx(-1, -1), cmplx(-1, -1), cmplx(1, negzero)},
+       Test{cmplx(-1, -1), cmplx(-1, 2), cmplx(-0.2, 0.6)},
+       Test{cmplx(-1, -1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -1), cmplx(-1, inf), cmplx(negzero, 0)},
+       Test{cmplx(-1, -1), cmplx(-1, -inf), cmplx(0, negzero)},
+       Test{cmplx(-1, -1), cmplx(2, 0), cmplx(-0.5, -0.5)},
+       Test{cmplx(-1, -1), cmplx(2, 1), cmplx(-0.6, -0.2)},
+       Test{cmplx(-1, -1), cmplx(2, -1), cmplx(-0.2, -0.6)},
+       Test{cmplx(-1, -1), cmplx(2, 2), cmplx(-0.5, 0)},
+       Test{cmplx(-1, -1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -1), cmplx(2, inf), cmplx(negzero, 0)},
+       Test{cmplx(-1, -1), cmplx(2, -inf), cmplx(0, negzero)},
+       Test{cmplx(-1, -1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, -1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, -1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, -1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, -1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -1), cmplx(nan, inf), cmplx(negzero, 0)},
+       Test{cmplx(-1, -1), cmplx(nan, -inf), cmplx(0, negzero)},
+       Test{cmplx(-1, -1), cmplx(inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(-1, -1), cmplx(inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(-1, -1), cmplx(inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(-1, -1), cmplx(inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(-1, -1), cmplx(inf, nan), cmplx(negzero, negzero)},
+       Test{cmplx(-1, -1), cmplx(inf, inf), cmplx(negzero, 0)},
+       Test{cmplx(-1, -1), cmplx(inf, -inf), cmplx(0, negzero)},
+       Test{cmplx(-1, -1), cmplx(-inf, 0), cmplx(0, 0)},
+       Test{cmplx(-1, -1), cmplx(-inf, 1), cmplx(0, 0)},
+       Test{cmplx(-1, -1), cmplx(-inf, -1), cmplx(0, 0)},
+       Test{cmplx(-1, -1), cmplx(-inf, 2), cmplx(0, 0)},
+       Test{cmplx(-1, -1), cmplx(-inf, nan), cmplx(0, 0)},
+       Test{cmplx(-1, -1), cmplx(-inf, inf), cmplx(0, 0)},
+       Test{cmplx(-1, -1), cmplx(-inf, -inf), cmplx(0, 0)},
+       Test{cmplx(-1, 2), cmplx(0, 0), cmplx(-inf, inf)},
+       Test{cmplx(-1, 2), cmplx(0, 1), cmplx(2, 1)},
+       Test{cmplx(-1, 2), cmplx(0, -1), cmplx(-2, -1)},
+       Test{cmplx(-1, 2), cmplx(0, 2), cmplx(1, 0.5)},
+       Test{cmplx(-1, 2), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 2), cmplx(0, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 2), cmplx(0, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 2), cmplx(1, 0), cmplx(-1, 2)},
+       Test{cmplx(-1, 2), cmplx(1, 1), cmplx(0.5, 1.5)},
+       Test{cmplx(-1, 2), cmplx(1, -1), cmplx(-1.5, 0.5)},
+       Test{cmplx(-1, 2), cmplx(1, 2), cmplx(0.6, 0.8)},
+       Test{cmplx(-1, 2), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 2), cmplx(1, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 2), cmplx(1, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 2), cmplx(-1, 0), cmplx(1, -2)},
+       Test{cmplx(-1, 2), cmplx(-1, 1), cmplx(1.5, -0.5)},
+       Test{cmplx(-1, 2), cmplx(-1, -1), cmplx(-0.5, -1.5)},
+       Test{cmplx(-1, 2), cmplx(-1, 2), cmplx(1, 0)},
+       Test{cmplx(-1, 2), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 2), cmplx(-1, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 2), cmplx(-1, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 2), cmplx(2, 0), cmplx(-0.5, 1)},
+       Test{cmplx(-1, 2), cmplx(2, 1), cmplx(0, 1)},
+       Test{cmplx(-1, 2), cmplx(2, -1), cmplx(-0.8, 0.6)},
+       Test{cmplx(-1, 2), cmplx(2, 2), cmplx(0.25, 0.75)},
+       Test{cmplx(-1, 2), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 2), cmplx(2, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 2), cmplx(2, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 2), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, 2), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, 2), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, 2), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, 2), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, 2), cmplx(nan, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 2), cmplx(nan, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, 2), cmplx(inf, 0), cmplx(negzero, 0)},
+       Test{cmplx(-1, 2), cmplx(inf, 1), cmplx(negzero, 0)},
+       Test{cmplx(-1, 2), cmplx(inf, -1), cmplx(negzero, 0)},
+       Test{cmplx(-1, 2), cmplx(inf, 2), cmplx(negzero, 0)},
+       Test{cmplx(-1, 2), cmplx(inf, nan), cmplx(negzero, 0)},
+       Test{cmplx(-1, 2), cmplx(inf, inf), cmplx(0, 0)},
+       Test{cmplx(-1, 2), cmplx(inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(-1, 2), cmplx(-inf, 0), cmplx(0, negzero)},
+       Test{cmplx(-1, 2), cmplx(-inf, 1), cmplx(0, negzero)},
+       Test{cmplx(-1, 2), cmplx(-inf, -1), cmplx(0, negzero)},
+       Test{cmplx(-1, 2), cmplx(-inf, 2), cmplx(0, negzero)},
+       Test{cmplx(-1, 2), cmplx(-inf, nan), cmplx(0, negzero)},
+       Test{cmplx(-1, 2), cmplx(-inf, inf), cmplx(0, negzero)},
+       Test{cmplx(-1, 2), cmplx(-inf, -inf), cmplx(negzero, negzero)},
+       Test{cmplx(-1, nan), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(0, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(0, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(0, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(1, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(1, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(1, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(1, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-1, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-1, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-1, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-1, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(2, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(2, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(2, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(2, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, nan), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(0, 0), cmplx(-inf, inf)},
+       Test{cmplx(-1, inf), cmplx(0, 1), cmplx(inf, nan)},
+       Test{cmplx(-1, inf), cmplx(0, -1), cmplx(-inf, nan)},
+       Test{cmplx(-1, inf), cmplx(0, 2), cmplx(inf, nan)},
+       Test{cmplx(-1, inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(1, 0), cmplx(nan, inf)},
+       Test{cmplx(-1, inf), cmplx(1, 1), cmplx(inf, inf)},
+       Test{cmplx(-1, inf), cmplx(1, -1), cmplx(-inf, inf)},
+       Test{cmplx(-1, inf), cmplx(1, 2), cmplx(inf, inf)},
+       Test{cmplx(-1, inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-1, 0), cmplx(nan, -inf)},
+       Test{cmplx(-1, inf), cmplx(-1, 1), cmplx(inf, -inf)},
+       Test{cmplx(-1, inf), cmplx(-1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-1, inf), cmplx(-1, 2), cmplx(inf, -inf)},
+       Test{cmplx(-1, inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(2, 0), cmplx(nan, inf)},
+       Test{cmplx(-1, inf), cmplx(2, 1), cmplx(inf, inf)},
+       Test{cmplx(-1, inf), cmplx(2, -1), cmplx(-inf, inf)},
+       Test{cmplx(-1, inf), cmplx(2, 2), cmplx(inf, inf)},
+       Test{cmplx(-1, inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(0, 0), cmplx(-inf, -inf)},
+       Test{cmplx(-1, -inf), cmplx(0, 1), cmplx(-inf, nan)},
+       Test{cmplx(-1, -inf), cmplx(0, -1), cmplx(inf, nan)},
+       Test{cmplx(-1, -inf), cmplx(0, 2), cmplx(-inf, nan)},
+       Test{cmplx(-1, -inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(1, 0), cmplx(nan, -inf)},
+       Test{cmplx(-1, -inf), cmplx(1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(-1, -inf), cmplx(1, -1), cmplx(inf, -inf)},
+       Test{cmplx(-1, -inf), cmplx(1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(-1, -inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-1, 0), cmplx(nan, inf)},
+       Test{cmplx(-1, -inf), cmplx(-1, 1), cmplx(-inf, inf)},
+       Test{cmplx(-1, -inf), cmplx(-1, -1), cmplx(inf, inf)},
+       Test{cmplx(-1, -inf), cmplx(-1, 2), cmplx(-inf, inf)},
+       Test{cmplx(-1, -inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(2, 0), cmplx(nan, -inf)},
+       Test{cmplx(-1, -inf), cmplx(2, 1), cmplx(-inf, -inf)},
+       Test{cmplx(-1, -inf), cmplx(2, -1), cmplx(inf, -inf)},
+       Test{cmplx(-1, -inf), cmplx(2, 2), cmplx(-inf, -inf)},
+       Test{cmplx(-1, -inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-1, -inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(0, 0), cmplx(inf, nan)},
+       Test{cmplx(2, 0), cmplx(0, 1), cmplx(0, -2)},
+       Test{cmplx(2, 0), cmplx(0, -1), cmplx(negzero, 2)},
+       Test{cmplx(2, 0), cmplx(0, 2), cmplx(0, -1)},
+       Test{cmplx(2, 0), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(0, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 0), cmplx(0, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 0), cmplx(1, 0), cmplx(2, 0)},
+       Test{cmplx(2, 0), cmplx(1, 1), cmplx(1, -1)},
+       Test{cmplx(2, 0), cmplx(1, -1), cmplx(1, 1)},
+       Test{cmplx(2, 0), cmplx(1, 2), cmplx(0.4, -0.8)},
+       Test{cmplx(2, 0), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(1, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 0), cmplx(1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 0), cmplx(-1, 0), cmplx(-2, negzero)},
+       Test{cmplx(2, 0), cmplx(-1, 1), cmplx(-1, -1)},
+       Test{cmplx(2, 0), cmplx(-1, -1), cmplx(-1, 1)},
+       Test{cmplx(2, 0), cmplx(-1, 2), cmplx(-0.4, -0.8)},
+       Test{cmplx(2, 0), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(-1, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 0), cmplx(-1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 0), cmplx(2, 0), cmplx(1, 0)},
+       Test{cmplx(2, 0), cmplx(2, 1), cmplx(0.8, -0.4)},
+       Test{cmplx(2, 0), cmplx(2, -1), cmplx(0.8, 0.4)},
+       Test{cmplx(2, 0), cmplx(2, 2), cmplx(0.5, -0.5)},
+       Test{cmplx(2, 0), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(2, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 0), cmplx(2, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 0), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 0), cmplx(nan, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 0), cmplx(nan, -inf), cmplx(0, 0)},
+       Test{cmplx(2, 0), cmplx(inf, 0), cmplx(0, 0)},
+       Test{cmplx(2, 0), cmplx(inf, 1), cmplx(0, 0)},
+       Test{cmplx(2, 0), cmplx(inf, -1), cmplx(0, 0)},
+       Test{cmplx(2, 0), cmplx(inf, 2), cmplx(0, 0)},
+       Test{cmplx(2, 0), cmplx(inf, nan), cmplx(0, 0)},
+       Test{cmplx(2, 0), cmplx(inf, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 0), cmplx(inf, -inf), cmplx(0, 0)},
+       Test{cmplx(2, 0), cmplx(-inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(2, 0), cmplx(-inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(2, 0), cmplx(-inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(2, 0), cmplx(-inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(2, 0), cmplx(-inf, nan), cmplx(negzero, negzero)},
+       Test{cmplx(2, 0), cmplx(-inf, inf), cmplx(negzero, negzero)},
+       Test{cmplx(2, 0), cmplx(-inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 1), cmplx(0, 0), cmplx(inf, inf)},
+       Test{cmplx(2, 1), cmplx(0, 1), cmplx(1, -2)},
+       Test{cmplx(2, 1), cmplx(0, -1), cmplx(-1, 2)},
+       Test{cmplx(2, 1), cmplx(0, 2), cmplx(0.5, -1)},
+       Test{cmplx(2, 1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 1), cmplx(0, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 1), cmplx(0, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 1), cmplx(1, 0), cmplx(2, 1)},
+       Test{cmplx(2, 1), cmplx(1, 1), cmplx(1.5, -0.5)},
+       Test{cmplx(2, 1), cmplx(1, -1), cmplx(0.5, 1.5)},
+       Test{cmplx(2, 1), cmplx(1, 2), cmplx(0.8, -0.6)},
+       Test{cmplx(2, 1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 1), cmplx(1, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 1), cmplx(1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 1), cmplx(-1, 0), cmplx(-2, -1)},
+       Test{cmplx(2, 1), cmplx(-1, 1), cmplx(-0.5, -1.5)},
+       Test{cmplx(2, 1), cmplx(-1, -1), cmplx(-1.5, 0.5)},
+       Test{cmplx(2, 1), cmplx(-1, 2), cmplx(0, -1)},
+       Test{cmplx(2, 1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 1), cmplx(-1, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 1), cmplx(-1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 1), cmplx(2, 0), cmplx(1, 0.5)},
+       Test{cmplx(2, 1), cmplx(2, 1), cmplx(1, 0)},
+       Test{cmplx(2, 1), cmplx(2, -1), cmplx(0.6, 0.8)},
+       Test{cmplx(2, 1), cmplx(2, 2), cmplx(0.75, -0.25)},
+       Test{cmplx(2, 1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 1), cmplx(2, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 1), cmplx(2, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(2, 1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(2, 1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(2, 1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(2, 1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 1), cmplx(nan, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 1), cmplx(nan, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 1), cmplx(inf, 0), cmplx(0, 0)},
+       Test{cmplx(2, 1), cmplx(inf, 1), cmplx(0, 0)},
+       Test{cmplx(2, 1), cmplx(inf, -1), cmplx(0, 0)},
+       Test{cmplx(2, 1), cmplx(inf, 2), cmplx(0, 0)},
+       Test{cmplx(2, 1), cmplx(inf, nan), cmplx(0, 0)},
+       Test{cmplx(2, 1), cmplx(inf, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 1), cmplx(inf, -inf), cmplx(0, 0)},
+       Test{cmplx(2, 1), cmplx(-inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(2, 1), cmplx(-inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(2, 1), cmplx(-inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(2, 1), cmplx(-inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(2, 1), cmplx(-inf, nan), cmplx(negzero, negzero)},
+       Test{cmplx(2, 1), cmplx(-inf, inf), cmplx(negzero, negzero)},
+       Test{cmplx(2, 1), cmplx(-inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, -1), cmplx(0, 0), cmplx(inf, -inf)},
+       Test{cmplx(2, -1), cmplx(0, 1), cmplx(-1, -2)},
+       Test{cmplx(2, -1), cmplx(0, -1), cmplx(1, 2)},
+       Test{cmplx(2, -1), cmplx(0, 2), cmplx(-0.5, -1)},
+       Test{cmplx(2, -1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -1), cmplx(0, inf), cmplx(negzero, negzero)},
+       Test{cmplx(2, -1), cmplx(0, -inf), cmplx(0, 0)},
+       Test{cmplx(2, -1), cmplx(1, 0), cmplx(2, -1)},
+       Test{cmplx(2, -1), cmplx(1, 1), cmplx(0.5, -1.5)},
+       Test{cmplx(2, -1), cmplx(1, -1), cmplx(1.5, 0.5)},
+       Test{cmplx(2, -1), cmplx(1, 2), cmplx(0, -1)},
+       Test{cmplx(2, -1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -1), cmplx(1, inf), cmplx(negzero, negzero)},
+       Test{cmplx(2, -1), cmplx(1, -inf), cmplx(0, 0)},
+       Test{cmplx(2, -1), cmplx(-1, 0), cmplx(-2, 1)},
+       Test{cmplx(2, -1), cmplx(-1, 1), cmplx(-1.5, -0.5)},
+       Test{cmplx(2, -1), cmplx(-1, -1), cmplx(-0.5, 1.5)},
+       Test{cmplx(2, -1), cmplx(-1, 2), cmplx(-0.8, -0.6)},
+       Test{cmplx(2, -1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -1), cmplx(-1, inf), cmplx(negzero, negzero)},
+       Test{cmplx(2, -1), cmplx(-1, -inf), cmplx(0, 0)},
+       Test{cmplx(2, -1), cmplx(2, 0), cmplx(1, -0.5)},
+       Test{cmplx(2, -1), cmplx(2, 1), cmplx(0.6, -0.8)},
+       Test{cmplx(2, -1), cmplx(2, -1), cmplx(1, 0)},
+       Test{cmplx(2, -1), cmplx(2, 2), cmplx(0.25, -0.75)},
+       Test{cmplx(2, -1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -1), cmplx(2, inf), cmplx(negzero, negzero)},
+       Test{cmplx(2, -1), cmplx(2, -inf), cmplx(0, 0)},
+       Test{cmplx(2, -1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(2, -1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(2, -1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(2, -1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(2, -1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -1), cmplx(nan, inf), cmplx(negzero, negzero)},
+       Test{cmplx(2, -1), cmplx(nan, -inf), cmplx(0, 0)},
+       Test{cmplx(2, -1), cmplx(inf, 0), cmplx(0, negzero)},
+       Test{cmplx(2, -1), cmplx(inf, 1), cmplx(0, negzero)},
+       Test{cmplx(2, -1), cmplx(inf, -1), cmplx(0, negzero)},
+       Test{cmplx(2, -1), cmplx(inf, 2), cmplx(0, negzero)},
+       Test{cmplx(2, -1), cmplx(inf, nan), cmplx(0, negzero)},
+       Test{cmplx(2, -1), cmplx(inf, inf), cmplx(0, negzero)},
+       Test{cmplx(2, -1), cmplx(inf, -inf), cmplx(0, 0)},
+       Test{cmplx(2, -1), cmplx(-inf, 0), cmplx(negzero, 0)},
+       Test{cmplx(2, -1), cmplx(-inf, 1), cmplx(negzero, 0)},
+       Test{cmplx(2, -1), cmplx(-inf, -1), cmplx(negzero, 0)},
+       Test{cmplx(2, -1), cmplx(-inf, 2), cmplx(negzero, 0)},
+       Test{cmplx(2, -1), cmplx(-inf, nan), cmplx(negzero, 0)},
+       Test{cmplx(2, -1), cmplx(-inf, inf), cmplx(negzero, negzero)},
+       Test{cmplx(2, -1), cmplx(-inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 2), cmplx(0, 0), cmplx(inf, inf)},
+       Test{cmplx(2, 2), cmplx(0, 1), cmplx(2, -2)},
+       Test{cmplx(2, 2), cmplx(0, -1), cmplx(-2, 2)},
+       Test{cmplx(2, 2), cmplx(0, 2), cmplx(1, -1)},
+       Test{cmplx(2, 2), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 2), cmplx(0, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 2), cmplx(0, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 2), cmplx(1, 0), cmplx(2, 2)},
+       Test{cmplx(2, 2), cmplx(1, 1), cmplx(2, 0)},
+       Test{cmplx(2, 2), cmplx(1, -1), cmplx(0, 2)},
+       Test{cmplx(2, 2), cmplx(1, 2), cmplx(1.2, -0.4)},
+       Test{cmplx(2, 2), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 2), cmplx(1, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 2), cmplx(1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 2), cmplx(-1, 0), cmplx(-2, -2)},
+       Test{cmplx(2, 2), cmplx(-1, 1), cmplx(negzero, -2)},
+       Test{cmplx(2, 2), cmplx(-1, -1), cmplx(-2, negzero)},
+       Test{cmplx(2, 2), cmplx(-1, 2), cmplx(0.4, -1.2)},
+       Test{cmplx(2, 2), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 2), cmplx(-1, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 2), cmplx(-1, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 2), cmplx(2, 0), cmplx(1, 1)},
+       Test{cmplx(2, 2), cmplx(2, 1), cmplx(1.2, 0.4)},
+       Test{cmplx(2, 2), cmplx(2, -1), cmplx(0.4, 1.2)},
+       Test{cmplx(2, 2), cmplx(2, 2), cmplx(1, 0)},
+       Test{cmplx(2, 2), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 2), cmplx(2, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 2), cmplx(2, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 2), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(2, 2), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(2, 2), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(2, 2), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(2, 2), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(2, 2), cmplx(nan, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 2), cmplx(nan, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, 2), cmplx(inf, 0), cmplx(0, 0)},
+       Test{cmplx(2, 2), cmplx(inf, 1), cmplx(0, 0)},
+       Test{cmplx(2, 2), cmplx(inf, -1), cmplx(0, 0)},
+       Test{cmplx(2, 2), cmplx(inf, 2), cmplx(0, 0)},
+       Test{cmplx(2, 2), cmplx(inf, nan), cmplx(0, 0)},
+       Test{cmplx(2, 2), cmplx(inf, inf), cmplx(0, 0)},
+       Test{cmplx(2, 2), cmplx(inf, -inf), cmplx(0, 0)},
+       Test{cmplx(2, 2), cmplx(-inf, 0), cmplx(negzero, negzero)},
+       Test{cmplx(2, 2), cmplx(-inf, 1), cmplx(negzero, negzero)},
+       Test{cmplx(2, 2), cmplx(-inf, -1), cmplx(negzero, negzero)},
+       Test{cmplx(2, 2), cmplx(-inf, 2), cmplx(negzero, negzero)},
+       Test{cmplx(2, 2), cmplx(-inf, nan), cmplx(negzero, negzero)},
+       Test{cmplx(2, 2), cmplx(-inf, inf), cmplx(0, negzero)},
+       Test{cmplx(2, 2), cmplx(-inf, -inf), cmplx(negzero, 0)},
+       Test{cmplx(2, nan), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(0, 1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(0, -1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(0, 2), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(1, 0), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(1, 1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(1, -1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(1, 2), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-1, 0), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-1, 1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-1, -1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-1, 2), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(2, 0), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(2, 1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(2, -1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(2, 2), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(2, nan), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(0, 0), cmplx(inf, inf)},
+       Test{cmplx(2, inf), cmplx(0, 1), cmplx(inf, nan)},
+       Test{cmplx(2, inf), cmplx(0, -1), cmplx(-inf, nan)},
+       Test{cmplx(2, inf), cmplx(0, 2), cmplx(inf, nan)},
+       Test{cmplx(2, inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(1, 0), cmplx(nan, inf)},
+       Test{cmplx(2, inf), cmplx(1, 1), cmplx(inf, inf)},
+       Test{cmplx(2, inf), cmplx(1, -1), cmplx(-inf, inf)},
+       Test{cmplx(2, inf), cmplx(1, 2), cmplx(inf, inf)},
+       Test{cmplx(2, inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-1, 0), cmplx(nan, -inf)},
+       Test{cmplx(2, inf), cmplx(-1, 1), cmplx(inf, -inf)},
+       Test{cmplx(2, inf), cmplx(-1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(2, inf), cmplx(-1, 2), cmplx(inf, -inf)},
+       Test{cmplx(2, inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(2, 0), cmplx(nan, inf)},
+       Test{cmplx(2, inf), cmplx(2, 1), cmplx(inf, inf)},
+       Test{cmplx(2, inf), cmplx(2, -1), cmplx(-inf, inf)},
+       Test{cmplx(2, inf), cmplx(2, 2), cmplx(inf, inf)},
+       Test{cmplx(2, inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(2, inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(0, 0), cmplx(inf, -inf)},
+       Test{cmplx(2, -inf), cmplx(0, 1), cmplx(-inf, nan)},
+       Test{cmplx(2, -inf), cmplx(0, -1), cmplx(inf, nan)},
+       Test{cmplx(2, -inf), cmplx(0, 2), cmplx(-inf, nan)},
+       Test{cmplx(2, -inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(1, 0), cmplx(nan, -inf)},
+       Test{cmplx(2, -inf), cmplx(1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(2, -inf), cmplx(1, -1), cmplx(inf, -inf)},
+       Test{cmplx(2, -inf), cmplx(1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(2, -inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-1, 0), cmplx(nan, inf)},
+       Test{cmplx(2, -inf), cmplx(-1, 1), cmplx(-inf, inf)},
+       Test{cmplx(2, -inf), cmplx(-1, -1), cmplx(inf, inf)},
+       Test{cmplx(2, -inf), cmplx(-1, 2), cmplx(-inf, inf)},
+       Test{cmplx(2, -inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(2, 0), cmplx(nan, -inf)},
+       Test{cmplx(2, -inf), cmplx(2, 1), cmplx(-inf, -inf)},
+       Test{cmplx(2, -inf), cmplx(2, -1), cmplx(inf, -inf)},
+       Test{cmplx(2, -inf), cmplx(2, 2), cmplx(-inf, -inf)},
+       Test{cmplx(2, -inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(2, -inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(0, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(0, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(0, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(2, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(2, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(2, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(2, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 0), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(0, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(0, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(0, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(2, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(2, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(2, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(2, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 1), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(0, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(0, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(0, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(2, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(2, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(2, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(2, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -1), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(0, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(0, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(0, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(2, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(2, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(2, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(2, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, 2), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(0, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(0, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(0, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(0, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-1, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-1, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-1, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-1, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(2, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(2, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(2, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(2, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, nan), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(0, 0), cmplx(nan, inf)},
+       Test{cmplx(nan, inf), cmplx(0, 1), cmplx(inf, nan)},
+       Test{cmplx(nan, inf), cmplx(0, -1), cmplx(-inf, nan)},
+       Test{cmplx(nan, inf), cmplx(0, 2), cmplx(inf, nan)},
+       Test{cmplx(nan, inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(1, 0), cmplx(nan, inf)},
+       Test{cmplx(nan, inf), cmplx(1, 1), cmplx(inf, inf)},
+       Test{cmplx(nan, inf), cmplx(1, -1), cmplx(-inf, inf)},
+       Test{cmplx(nan, inf), cmplx(1, 2), cmplx(inf, inf)},
+       Test{cmplx(nan, inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-1, 0), cmplx(nan, -inf)},
+       Test{cmplx(nan, inf), cmplx(-1, 1), cmplx(inf, -inf)},
+       Test{cmplx(nan, inf), cmplx(-1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(nan, inf), cmplx(-1, 2), cmplx(inf, -inf)},
+       Test{cmplx(nan, inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(2, 0), cmplx(nan, inf)},
+       Test{cmplx(nan, inf), cmplx(2, 1), cmplx(inf, inf)},
+       Test{cmplx(nan, inf), cmplx(2, -1), cmplx(-inf, inf)},
+       Test{cmplx(nan, inf), cmplx(2, 2), cmplx(inf, inf)},
+       Test{cmplx(nan, inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(0, 0), cmplx(nan, -inf)},
+       Test{cmplx(nan, -inf), cmplx(0, 1), cmplx(-inf, nan)},
+       Test{cmplx(nan, -inf), cmplx(0, -1), cmplx(inf, nan)},
+       Test{cmplx(nan, -inf), cmplx(0, 2), cmplx(-inf, nan)},
+       Test{cmplx(nan, -inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(1, 0), cmplx(nan, -inf)},
+       Test{cmplx(nan, -inf), cmplx(1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(nan, -inf), cmplx(1, -1), cmplx(inf, -inf)},
+       Test{cmplx(nan, -inf), cmplx(1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(nan, -inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-1, 0), cmplx(nan, inf)},
+       Test{cmplx(nan, -inf), cmplx(-1, 1), cmplx(-inf, inf)},
+       Test{cmplx(nan, -inf), cmplx(-1, -1), cmplx(inf, inf)},
+       Test{cmplx(nan, -inf), cmplx(-1, 2), cmplx(-inf, inf)},
+       Test{cmplx(nan, -inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(2, 0), cmplx(nan, -inf)},
+       Test{cmplx(nan, -inf), cmplx(2, 1), cmplx(-inf, -inf)},
+       Test{cmplx(nan, -inf), cmplx(2, -1), cmplx(inf, -inf)},
+       Test{cmplx(nan, -inf), cmplx(2, 2), cmplx(-inf, -inf)},
+       Test{cmplx(nan, -inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(nan, -inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(0, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, 0), cmplx(0, 1), cmplx(nan, -inf)},
+       Test{cmplx(inf, 0), cmplx(0, -1), cmplx(nan, inf)},
+       Test{cmplx(inf, 0), cmplx(0, 2), cmplx(nan, -inf)},
+       Test{cmplx(inf, 0), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(1, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, 0), cmplx(1, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, 0), cmplx(1, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, 0), cmplx(1, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, 0), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-1, 0), cmplx(-inf, nan)},
+       Test{cmplx(inf, 0), cmplx(-1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(inf, 0), cmplx(-1, -1), cmplx(-inf, inf)},
+       Test{cmplx(inf, 0), cmplx(-1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(inf, 0), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(2, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, 0), cmplx(2, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, 0), cmplx(2, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, 0), cmplx(2, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, 0), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 0), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(0, 0), cmplx(inf, inf)},
+       Test{cmplx(inf, 1), cmplx(0, 1), cmplx(nan, -inf)},
+       Test{cmplx(inf, 1), cmplx(0, -1), cmplx(nan, inf)},
+       Test{cmplx(inf, 1), cmplx(0, 2), cmplx(nan, -inf)},
+       Test{cmplx(inf, 1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(1, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, 1), cmplx(1, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, 1), cmplx(1, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, 1), cmplx(1, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, 1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-1, 0), cmplx(-inf, nan)},
+       Test{cmplx(inf, 1), cmplx(-1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(inf, 1), cmplx(-1, -1), cmplx(-inf, inf)},
+       Test{cmplx(inf, 1), cmplx(-1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(inf, 1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(2, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, 1), cmplx(2, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, 1), cmplx(2, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, 1), cmplx(2, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, 1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 1), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(0, 0), cmplx(inf, -inf)},
+       Test{cmplx(inf, -1), cmplx(0, 1), cmplx(nan, -inf)},
+       Test{cmplx(inf, -1), cmplx(0, -1), cmplx(nan, inf)},
+       Test{cmplx(inf, -1), cmplx(0, 2), cmplx(nan, -inf)},
+       Test{cmplx(inf, -1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(1, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, -1), cmplx(1, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, -1), cmplx(1, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, -1), cmplx(1, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, -1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-1, 0), cmplx(-inf, nan)},
+       Test{cmplx(inf, -1), cmplx(-1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(inf, -1), cmplx(-1, -1), cmplx(-inf, inf)},
+       Test{cmplx(inf, -1), cmplx(-1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(inf, -1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(2, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, -1), cmplx(2, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, -1), cmplx(2, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, -1), cmplx(2, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, -1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -1), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(0, 0), cmplx(inf, inf)},
+       Test{cmplx(inf, 2), cmplx(0, 1), cmplx(nan, -inf)},
+       Test{cmplx(inf, 2), cmplx(0, -1), cmplx(nan, inf)},
+       Test{cmplx(inf, 2), cmplx(0, 2), cmplx(nan, -inf)},
+       Test{cmplx(inf, 2), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(1, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, 2), cmplx(1, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, 2), cmplx(1, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, 2), cmplx(1, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, 2), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-1, 0), cmplx(-inf, nan)},
+       Test{cmplx(inf, 2), cmplx(-1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(inf, 2), cmplx(-1, -1), cmplx(-inf, inf)},
+       Test{cmplx(inf, 2), cmplx(-1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(inf, 2), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(2, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, 2), cmplx(2, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, 2), cmplx(2, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, 2), cmplx(2, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, 2), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, 2), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(0, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, nan), cmplx(0, 1), cmplx(nan, -inf)},
+       Test{cmplx(inf, nan), cmplx(0, -1), cmplx(nan, inf)},
+       Test{cmplx(inf, nan), cmplx(0, 2), cmplx(nan, -inf)},
+       Test{cmplx(inf, nan), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(1, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, nan), cmplx(1, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, nan), cmplx(1, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, nan), cmplx(1, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, nan), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-1, 0), cmplx(-inf, nan)},
+       Test{cmplx(inf, nan), cmplx(-1, 1), cmplx(-inf, -inf)},
+       Test{cmplx(inf, nan), cmplx(-1, -1), cmplx(-inf, inf)},
+       Test{cmplx(inf, nan), cmplx(-1, 2), cmplx(-inf, -inf)},
+       Test{cmplx(inf, nan), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(2, 0), cmplx(inf, nan)},
+       Test{cmplx(inf, nan), cmplx(2, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, nan), cmplx(2, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, nan), cmplx(2, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, nan), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, nan), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(0, 0), cmplx(inf, inf)},
+       Test{cmplx(inf, inf), cmplx(0, 1), cmplx(inf, -inf)},
+       Test{cmplx(inf, inf), cmplx(0, -1), cmplx(-inf, inf)},
+       Test{cmplx(inf, inf), cmplx(0, 2), cmplx(inf, -inf)},
+       Test{cmplx(inf, inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(1, 0), cmplx(inf, inf)},
+       Test{cmplx(inf, inf), cmplx(1, 1), cmplx(inf, nan)},
+       Test{cmplx(inf, inf), cmplx(1, -1), cmplx(nan, inf)},
+       Test{cmplx(inf, inf), cmplx(1, 2), cmplx(inf, nan)},
+       Test{cmplx(inf, inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-1, 0), cmplx(-inf, -inf)},
+       Test{cmplx(inf, inf), cmplx(-1, 1), cmplx(nan, -inf)},
+       Test{cmplx(inf, inf), cmplx(-1, -1), cmplx(-inf, nan)},
+       Test{cmplx(inf, inf), cmplx(-1, 2), cmplx(nan, -inf)},
+       Test{cmplx(inf, inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(2, 0), cmplx(inf, inf)},
+       Test{cmplx(inf, inf), cmplx(2, 1), cmplx(inf, nan)},
+       Test{cmplx(inf, inf), cmplx(2, -1), cmplx(nan, inf)},
+       Test{cmplx(inf, inf), cmplx(2, 2), cmplx(inf, nan)},
+       Test{cmplx(inf, inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(0, 0), cmplx(inf, -inf)},
+       Test{cmplx(inf, -inf), cmplx(0, 1), cmplx(-inf, -inf)},
+       Test{cmplx(inf, -inf), cmplx(0, -1), cmplx(inf, inf)},
+       Test{cmplx(inf, -inf), cmplx(0, 2), cmplx(-inf, -inf)},
+       Test{cmplx(inf, -inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(1, 0), cmplx(inf, -inf)},
+       Test{cmplx(inf, -inf), cmplx(1, 1), cmplx(nan, -inf)},
+       Test{cmplx(inf, -inf), cmplx(1, -1), cmplx(inf, nan)},
+       Test{cmplx(inf, -inf), cmplx(1, 2), cmplx(nan, -inf)},
+       Test{cmplx(inf, -inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-1, 0), cmplx(-inf, inf)},
+       Test{cmplx(inf, -inf), cmplx(-1, 1), cmplx(-inf, nan)},
+       Test{cmplx(inf, -inf), cmplx(-1, -1), cmplx(nan, inf)},
+       Test{cmplx(inf, -inf), cmplx(-1, 2), cmplx(-inf, nan)},
+       Test{cmplx(inf, -inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(2, 0), cmplx(inf, -inf)},
+       Test{cmplx(inf, -inf), cmplx(2, 1), cmplx(nan, -inf)},
+       Test{cmplx(inf, -inf), cmplx(2, -1), cmplx(inf, nan)},
+       Test{cmplx(inf, -inf), cmplx(2, 2), cmplx(nan, -inf)},
+       Test{cmplx(inf, -inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(inf, -inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(0, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, 0), cmplx(0, 1), cmplx(nan, inf)},
+       Test{cmplx(-inf, 0), cmplx(0, -1), cmplx(nan, -inf)},
+       Test{cmplx(-inf, 0), cmplx(0, 2), cmplx(nan, inf)},
+       Test{cmplx(-inf, 0), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(1, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, 0), cmplx(1, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 0), cmplx(1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, 0), cmplx(1, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 0), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-1, 0), cmplx(inf, nan)},
+       Test{cmplx(-inf, 0), cmplx(-1, 1), cmplx(inf, inf)},
+       Test{cmplx(-inf, 0), cmplx(-1, -1), cmplx(inf, -inf)},
+       Test{cmplx(-inf, 0), cmplx(-1, 2), cmplx(inf, inf)},
+       Test{cmplx(-inf, 0), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(2, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, 0), cmplx(2, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 0), cmplx(2, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, 0), cmplx(2, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 0), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 0), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(0, 0), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 1), cmplx(0, 1), cmplx(nan, inf)},
+       Test{cmplx(-inf, 1), cmplx(0, -1), cmplx(nan, -inf)},
+       Test{cmplx(-inf, 1), cmplx(0, 2), cmplx(nan, inf)},
+       Test{cmplx(-inf, 1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(1, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, 1), cmplx(1, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 1), cmplx(1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, 1), cmplx(1, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-1, 0), cmplx(inf, nan)},
+       Test{cmplx(-inf, 1), cmplx(-1, 1), cmplx(inf, inf)},
+       Test{cmplx(-inf, 1), cmplx(-1, -1), cmplx(inf, -inf)},
+       Test{cmplx(-inf, 1), cmplx(-1, 2), cmplx(inf, inf)},
+       Test{cmplx(-inf, 1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(2, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, 1), cmplx(2, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 1), cmplx(2, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, 1), cmplx(2, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 1), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(0, 0), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, -1), cmplx(0, 1), cmplx(nan, inf)},
+       Test{cmplx(-inf, -1), cmplx(0, -1), cmplx(nan, -inf)},
+       Test{cmplx(-inf, -1), cmplx(0, 2), cmplx(nan, inf)},
+       Test{cmplx(-inf, -1), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(1, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, -1), cmplx(1, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, -1), cmplx(1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, -1), cmplx(1, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, -1), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-1, 0), cmplx(inf, nan)},
+       Test{cmplx(-inf, -1), cmplx(-1, 1), cmplx(inf, inf)},
+       Test{cmplx(-inf, -1), cmplx(-1, -1), cmplx(inf, -inf)},
+       Test{cmplx(-inf, -1), cmplx(-1, 2), cmplx(inf, inf)},
+       Test{cmplx(-inf, -1), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(2, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, -1), cmplx(2, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, -1), cmplx(2, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, -1), cmplx(2, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, -1), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -1), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(0, 0), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 2), cmplx(0, 1), cmplx(nan, inf)},
+       Test{cmplx(-inf, 2), cmplx(0, -1), cmplx(nan, -inf)},
+       Test{cmplx(-inf, 2), cmplx(0, 2), cmplx(nan, inf)},
+       Test{cmplx(-inf, 2), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(1, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, 2), cmplx(1, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 2), cmplx(1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, 2), cmplx(1, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 2), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-1, 0), cmplx(inf, nan)},
+       Test{cmplx(-inf, 2), cmplx(-1, 1), cmplx(inf, inf)},
+       Test{cmplx(-inf, 2), cmplx(-1, -1), cmplx(inf, -inf)},
+       Test{cmplx(-inf, 2), cmplx(-1, 2), cmplx(inf, inf)},
+       Test{cmplx(-inf, 2), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(2, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, 2), cmplx(2, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 2), cmplx(2, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, 2), cmplx(2, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, 2), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, 2), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(0, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, nan), cmplx(0, 1), cmplx(nan, inf)},
+       Test{cmplx(-inf, nan), cmplx(0, -1), cmplx(nan, -inf)},
+       Test{cmplx(-inf, nan), cmplx(0, 2), cmplx(nan, inf)},
+       Test{cmplx(-inf, nan), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(1, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, nan), cmplx(1, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, nan), cmplx(1, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, nan), cmplx(1, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, nan), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-1, 0), cmplx(inf, nan)},
+       Test{cmplx(-inf, nan), cmplx(-1, 1), cmplx(inf, inf)},
+       Test{cmplx(-inf, nan), cmplx(-1, -1), cmplx(inf, -inf)},
+       Test{cmplx(-inf, nan), cmplx(-1, 2), cmplx(inf, inf)},
+       Test{cmplx(-inf, nan), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(2, 0), cmplx(-inf, nan)},
+       Test{cmplx(-inf, nan), cmplx(2, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, nan), cmplx(2, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, nan), cmplx(2, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, nan), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, nan), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(0, 0), cmplx(-inf, inf)},
+       Test{cmplx(-inf, inf), cmplx(0, 1), cmplx(inf, inf)},
+       Test{cmplx(-inf, inf), cmplx(0, -1), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, inf), cmplx(0, 2), cmplx(inf, inf)},
+       Test{cmplx(-inf, inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(1, 0), cmplx(-inf, inf)},
+       Test{cmplx(-inf, inf), cmplx(1, 1), cmplx(nan, inf)},
+       Test{cmplx(-inf, inf), cmplx(1, -1), cmplx(-inf, nan)},
+       Test{cmplx(-inf, inf), cmplx(1, 2), cmplx(nan, inf)},
+       Test{cmplx(-inf, inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-1, 0), cmplx(inf, -inf)},
+       Test{cmplx(-inf, inf), cmplx(-1, 1), cmplx(inf, nan)},
+       Test{cmplx(-inf, inf), cmplx(-1, -1), cmplx(nan, -inf)},
+       Test{cmplx(-inf, inf), cmplx(-1, 2), cmplx(inf, nan)},
+       Test{cmplx(-inf, inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(2, 0), cmplx(-inf, inf)},
+       Test{cmplx(-inf, inf), cmplx(2, 1), cmplx(nan, inf)},
+       Test{cmplx(-inf, inf), cmplx(2, -1), cmplx(-inf, nan)},
+       Test{cmplx(-inf, inf), cmplx(2, 2), cmplx(nan, inf)},
+       Test{cmplx(-inf, inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(0, 0), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, -inf), cmplx(0, 1), cmplx(-inf, inf)},
+       Test{cmplx(-inf, -inf), cmplx(0, -1), cmplx(inf, -inf)},
+       Test{cmplx(-inf, -inf), cmplx(0, 2), cmplx(-inf, inf)},
+       Test{cmplx(-inf, -inf), cmplx(0, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(0, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(0, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(1, 0), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, -inf), cmplx(1, 1), cmplx(-inf, nan)},
+       Test{cmplx(-inf, -inf), cmplx(1, -1), cmplx(nan, -inf)},
+       Test{cmplx(-inf, -inf), cmplx(1, 2), cmplx(-inf, nan)},
+       Test{cmplx(-inf, -inf), cmplx(1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-1, 0), cmplx(inf, inf)},
+       Test{cmplx(-inf, -inf), cmplx(-1, 1), cmplx(nan, inf)},
+       Test{cmplx(-inf, -inf), cmplx(-1, -1), cmplx(inf, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-1, 2), cmplx(nan, inf)},
+       Test{cmplx(-inf, -inf), cmplx(-1, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-1, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-1, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(2, 0), cmplx(-inf, -inf)},
+       Test{cmplx(-inf, -inf), cmplx(2, 1), cmplx(-inf, nan)},
+       Test{cmplx(-inf, -inf), cmplx(2, -1), cmplx(nan, -inf)},
+       Test{cmplx(-inf, -inf), cmplx(2, 2), cmplx(-inf, nan)},
+       Test{cmplx(-inf, -inf), cmplx(2, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(2, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(2, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(nan, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(nan, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(nan, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(nan, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(nan, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(nan, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(nan, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(inf, -inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-inf, 0), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-inf, 1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-inf, -1), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-inf, 2), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-inf, nan), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-inf, inf), cmplx(nan, nan)},
+       Test{cmplx(-inf, -inf), cmplx(-inf, -inf), cmplx(nan, nan)},
+}
diff --git a/gcc/testsuite/go.test/test/complit.go b/gcc/testsuite/go.test/test/complit.go
new file mode 100644 (file)
index 0000000..f3b7c9a
--- /dev/null
@@ -0,0 +1,70 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct { i int; f float; s string; next *T }
+
+type R struct { num int }
+
+func itor(a int) *R {
+       r := new(R)
+       r.num = a
+       return r
+}
+
+func eq(a []*R) {
+       for i := 0; i < len(a); i++ {
+               if a[i].num != i { panic("bad") }
+       }
+}
+
+type P struct { a, b int }
+func NewP(a, b int) *P {
+       return &P{a, b}
+}
+
+func main() {
+       var t T
+       t = T{0, 7.2, "hi", &t}
+
+       var tp *T
+       tp = &T{0, 7.2, "hi", &t}
+
+       a1 := []int{1,2,3}
+       if len(a1) != 3 { panic("a1") }
+       a2 := [10]int{1,2,3}
+       if len(a2) != 10 || cap(a2) != 10 { panic("a2") }
+
+       a3 := [10]int{1,2,3,}
+       if len(a3) != 10 || a2[3] != 0 { panic("a3") }
+
+       var oai []int
+       oai = []int{1,2,3}
+       if len(oai) != 3 { panic("oai") }
+
+       at := [...]*T{&t, tp, &t}
+       if len(at) != 3 { panic("at") }
+
+       c := make(chan int)
+       ac := []chan int{c, c, c}
+       if len(ac) != 3 { panic("ac") }
+
+       aat := [][len(at)]*T{at, at}
+       if len(aat) != 2 || len(aat[1]) != 3 { panic("aat") }
+
+       s := string([]byte{'h', 'e', 'l', 'l', 'o'})
+       if s != "hello" { panic("s") }
+
+       m := map[string]float{"one":1.0, "two":2.0, "pi":22./7.}
+       if len(m) != 3 { panic("m") }
+
+       eq([]*R{itor(0), itor(1), itor(2), itor(3), itor(4), itor(5)})
+
+       p1 := NewP(1, 2)
+       p2 := NewP(1, 2)
+       if p1 == p2 { panic("NewP") }
+}
diff --git a/gcc/testsuite/go.test/test/compos.go b/gcc/testsuite/go.test/test/compos.go
new file mode 100644 (file)
index 0000000..70f90f3
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: compos
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+       int
+}
+
+func f() *T {
+       return &T{1}
+}
+
+func main() {
+       x := f()
+       y := f()
+       if x == y {
+               panic("not allocating & composite literals")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/const.go b/gcc/testsuite/go.test/test/const.go
new file mode 100644 (file)
index 0000000..a55e13a
--- /dev/null
@@ -0,0 +1,120 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+       c0 = 0
+       cm1 = -1
+       chuge = 1 << 100
+       chuge_1 = chuge - 1
+       c1 = chuge >> 100
+       c3div2 = 3/2
+       c1e3 = 1e3
+
+       ctrue = true
+       cfalse = !ctrue
+)
+
+const (
+       f0 = 0.0
+       fm1 = -1.
+       fhuge float64 = 1 << 100
+       fhuge_1 float64 = chuge - 1
+       f1 float64 = chuge >> 100
+       f3div2 = 3./2.
+       f1e3 float64 = 1e3
+)
+
+func assert(t bool, s string) {
+       if !t {
+               panic(s)
+       }
+}
+
+func ints() {
+       assert(c0 == 0, "c0")
+       assert(c1 == 1, "c1")
+       assert(chuge > chuge_1, "chuge")
+       assert(chuge_1 + 1 == chuge, "chuge 1")
+       assert(chuge + cm1 +1  == chuge, "cm1")
+       assert(c3div2 == 1, "3/2")
+       assert(c1e3 == 1000, "c1e3 int")
+       assert(c1e3 == 1e3, "c1e3 float")
+
+       // verify that all (in range) are assignable as ints
+       var i int
+       i = c0
+       assert(i == c0, "i == c0")
+       i = cm1
+       assert(i == cm1, "i == cm1")
+       i = c1
+       assert(i == c1, "i == c1")
+       i = c3div2
+       assert(i == c3div2, "i == c3div2")
+       i = c1e3
+       assert(i == c1e3, "i == c1e3")
+
+       // verify that all are assignable as floats
+       var f float64
+       f = c0
+       assert(f == c0, "f == c0")
+       f = cm1
+       assert(f == cm1, "f == cm1")
+       f = chuge
+       assert(f == chuge, "f == chuge")
+       f = chuge_1
+       assert(f == chuge_1, "f == chuge_1")
+       f = c1
+       assert(f == c1, "f == c1")
+       f = c3div2
+       assert(f == c3div2, "f == c3div2")
+       f = c1e3
+       assert(f == c1e3, "f == c1e3")
+}
+
+func floats() {
+       assert(f0 == c0, "f0")
+       assert(f1 == c1, "f1")
+       assert(fhuge == fhuge_1, "fhuge")       // float64 can't distinguish fhuge, fhuge_1.
+       assert(fhuge_1 + 1 == fhuge, "fhuge 1")
+       assert(fhuge + fm1 +1  == fhuge, "fm1")
+       assert(f3div2 == 1.5, "3./2.")
+       assert(f1e3 == 1000, "f1e3 int")
+       assert(f1e3 == 1.e3, "f1e3 float")
+
+       // verify that all (in range) are assignable as ints
+       var i int
+       i = f0
+       assert(i == f0, "i == f0")
+       i = fm1
+       assert(i == fm1, "i == fm1")
+
+       // verify that all are assignable as floats
+       var f float64
+       f = f0
+       assert(f == f0, "f == f0")
+       f = fm1
+       assert(f == fm1, "f == fm1")
+       f = fhuge
+       assert(f == fhuge, "f == fhuge")
+       f = fhuge_1
+       assert(f == fhuge_1, "f == fhuge_1")
+       f = f1
+       assert(f == f1, "f == f1")
+       f = f3div2
+       assert(f == f3div2, "f == f3div2")
+       f = f1e3
+       assert(f == f1e3, "f == f1e3")
+}
+
+func main() {
+       ints()
+       floats()
+
+       assert(ctrue == true, "ctrue == true")
+       assert(cfalse == false, "cfalse == false")
+}
diff --git a/gcc/testsuite/go.test/test/const1.go b/gcc/testsuite/go.test/test/const1.go
new file mode 100644 (file)
index 0000000..427d61e
--- /dev/null
@@ -0,0 +1,79 @@
+// errchk $G -e $F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface {}
+const (
+       // assume all types behave similarly to int8/uint8
+       Int8 int8 = 101
+       Minus1 int8 = -1
+       Uint8 uint8 = 102
+       Const = 103
+
+       Float32 float32 = 104.5
+       Float float = 105.5
+       ConstFloat = 106.5
+       Big float64 = 1e300
+
+       String = "abc"
+       Bool = true
+)
+
+var (
+       a1 = Int8 * 100 // ERROR "overflow"
+       a2 = Int8 * -1  // OK
+       a3 = Int8 * 1000        // ERROR "overflow"
+       a4 = Int8 * int8(1000)  // ERROR "overflow"
+       a5 = int8(Int8 * 1000)  // ERROR "overflow"
+       a6 = int8(Int8 * int8(1000))    // ERROR "overflow"
+       a7 = Int8 - 2*Int8 - 2*Int8     // ERROR "overflow"
+       a8 = Int8 * Const / 100 // ERROR "overflow"
+       a9 = Int8 * (Const / 100)       // OK
+
+       b1 = Uint8 * Uint8      // ERROR "overflow"
+       b2 = Uint8 * -1 // ERROR "overflow"
+       b3 = Uint8 - Uint8      // OK
+       b4 = Uint8 - Uint8 - Uint8      // ERROR "overflow"
+       b5 = uint8(^0)  // ERROR "overflow"
+       b6 = ^uint8(0)  // OK
+       b7 = uint8(Minus1)      // ERROR "overflow"
+       b8 = uint8(int8(-1))    // ERROR "overflow"
+       b8a = uint8(-1) // ERROR "overflow"
+       b9 byte = (1<<10) >> 8  // OK
+       b10 byte = (1<<10)      // ERROR "overflow"
+       b11 byte = (byte(1)<<10) >> 8   // ERROR "overflow"
+       b12 byte = 1000 // ERROR "overflow"
+       b13 byte = byte(1000)   // ERROR "overflow"
+       b14 byte = byte(100) * byte(100)        // ERROR "overflow"
+       b15 byte = byte(100) * 100      // ERROR "overflow"
+       b16 byte = byte(0) * 1000       // ERROR "overflow"
+       b16a byte = 0 * 1000    // OK
+       b17 byte = byte(0) * byte(1000) // ERROR "overflow"
+       b18 byte = Uint8/0      // ERROR "division by zero"
+
+       c1 float64 = Big
+       c2 float64 = Big*Big    // ERROR "overflow"
+       c3 float64 = float64(Big)*Big   // ERROR "overflow"
+       c4 = Big*Big    // ERROR "overflow"
+       c5 = Big/0      // ERROR "division by zero"
+)
+
+func f(int)
+
+func main() {
+       f(Int8) // ERROR "convert|wrong type|cannot"
+       f(Minus1)       // ERROR "convert|wrong type|cannot"
+       f(Uint8)        // ERROR "convert|wrong type|cannot"
+       f(Const)        // OK
+       f(Float32)      // ERROR "convert|wrong type|cannot"
+       f(Float)        // ERROR "convert|wrong type|cannot"
+       f(ConstFloat)   // ERROR "truncate"
+       f(ConstFloat - 0.5)     // OK
+       f(Big)  // ERROR "convert|wrong type|cannot"
+       f(String)       // ERROR "convert|wrong type|cannot|incompatible"
+       f(Bool) // ERROR "convert|wrong type|cannot|incompatible"
+}
diff --git a/gcc/testsuite/go.test/test/const2.go b/gcc/testsuite/go.test/test/const2.go
new file mode 100644 (file)
index 0000000..bea1b99
--- /dev/null
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+       A int = 1
+       B byte; // ERROR "type without expr|expected .=."
+)
diff --git a/gcc/testsuite/go.test/test/const3.go b/gcc/testsuite/go.test/test/const3.go
new file mode 100644 (file)
index 0000000..dd5c889
--- /dev/null
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type T int
+
+func (t T) String() string { return fmt.Sprintf("T%d", int(t)) }
+
+const (
+       A T = 1 << (1 << iota)
+       B
+       C
+       D
+       E
+)
+
+func main() {
+       s := fmt.Sprintf("%v %v %v %v %v", A, B, C, D, E)
+       if s != "T2 T4 T16 T256 T65536" {
+               println("type info didn't propagate in const: got", s)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/convert.go b/gcc/testsuite/go.test/test/convert.go
new file mode 100644 (file)
index 0000000..e7361aa
--- /dev/null
@@ -0,0 +1,44 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "reflect"
+
+func typeof(x interface{}) string { return reflect.Typeof(x).String() }
+
+func f() int { return 0 }
+
+func g() int { return 0 }
+
+type T func() int
+
+var m = map[string]T{"f": f}
+
+type A int
+type B int
+
+var a A = 1
+var b B = 2
+var x int
+
+func main() {
+       want := typeof(g)
+       if t := typeof(f); t != want {
+               println("type of f is", t, "want", want)
+               panic("fail")
+       }
+
+       want = typeof(a)
+       if t := typeof(+a); t != want {
+               println("type of +a is", t, "want", want)
+               panic("fail")
+       }
+       if t := typeof(a + 0); t != want {
+               println("type of a+0 is", t, "want", want)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/convert3.go b/gcc/testsuite/go.test/test/convert3.go
new file mode 100644 (file)
index 0000000..be68c95
--- /dev/null
@@ -0,0 +1,26 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// everything here is legal except the ERROR line
+
+var c chan int
+var d1 chan<- int = c
+var d2 = (chan<- int)(c)
+
+var e *[4]int
+var f1 []int = e[0:]
+var f2 = []int(e[0:])
+
+var g = []int(nil)
+
+type H []int
+type J []int
+
+var h H
+var j1 J = h // ERROR "compat|illegal|cannot"
+var j2 = J(h)
diff --git a/gcc/testsuite/go.test/test/convlit.go b/gcc/testsuite/go.test/test/convlit.go
new file mode 100644 (file)
index 0000000..94889d4
--- /dev/null
@@ -0,0 +1,64 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// explicit conversion of constants is work in progress.
+// the ERRORs in this block are debatable, but they're what
+// the language spec says for now.
+var x1 = string(1)
+var x2 string = string(1)
+var x3 = int(1.5)      // ERROR "convert|truncate"
+var x4 int = int(1.5)  // ERROR "convert|truncate"
+var x5 = "a" + string(1)
+var x6 = int(1e100)    // ERROR "overflow"
+var x7 = float(1e1000) // ERROR "overflow"
+
+// implicit conversions merit scrutiny
+var s string
+var bad1 string = 1    // ERROR "conver|incompatible|invalid|cannot"
+var bad2 = s + 1               // ERROR "conver|incompatible|invalid"
+var bad3 = s + 'a'     // ERROR "conver|incompatible|invalid"
+var bad4 = "a" + 1     // ERROR "literals|incompatible|convert|invalid"
+var bad5 = "a" + 'a'   // ERROR "literals|incompatible|convert|invalid"
+
+var bad6 int = 1.5     // ERROR "convert|truncate"
+var bad7 int = 1e100   // ERROR "overflow"
+var bad8 float32 = 1e200       // ERROR "overflow"
+
+// but these implicit conversions are okay
+var good1 string = "a"
+var good2 int = 1.0
+var good3 int = 1e9
+var good4 float = 1e20
+
+// explicit conversion of string is okay
+var _ = []int("abc")
+var _ = []byte("abc")
+
+// implicit is not
+var _ []int = "abc"    // ERROR "cannot use|incompatible|invalid"
+var _ []byte = "abc"   // ERROR "cannot use|incompatible|invalid"
+
+// named string is okay
+type Tstring string
+var ss Tstring = "abc"
+var _ = []int(ss)
+var _ = []byte(ss)
+
+// implicit is still not
+var _ []int = ss       // ERROR "cannot use|incompatible|invalid"
+var _ []byte = ss      // ERROR "cannot use|incompatible|invalid"
+
+// named slice is not
+type Tint []int
+type Tbyte []byte
+var _ = Tint("abc")    // ERROR "convert|incompatible|invalid"
+var _ = Tbyte("abc")   // ERROR "convert|incompatible|invalid"
+
+// implicit is still not
+var _ Tint = "abc"     // ERROR "cannot use|incompatible|invalid"
+var _ Tbyte = "abc"    // ERROR "cannot use|incompatible|invalid"
diff --git a/gcc/testsuite/go.test/test/convlit1.go b/gcc/testsuite/go.test/test/convlit1.go
new file mode 100644 (file)
index 0000000..1e6673c
--- /dev/null
@@ -0,0 +1,17 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a = []int { "a" }; // ERROR "conver|incompatible|cannot"
+var b = int { 1 };     // ERROR "compos"
+
+
+func f() int
+
+func main() {
+       if f < 1 { }    // ERROR "conver|incompatible|invalid"
+}
diff --git a/gcc/testsuite/go.test/test/copy.go b/gcc/testsuite/go.test/test/copy.go
new file mode 100644 (file)
index 0000000..037d3f4
--- /dev/null
@@ -0,0 +1,293 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Semi-exhaustive test for copy()
+
+package main
+
+import (
+       "fmt"
+       "os"
+)
+
+const N = 40
+
+var input8 = make([]uint8, N)
+var output8 = make([]uint8, N)
+var input16 = make([]uint16, N)
+var output16 = make([]uint16, N)
+var input32 = make([]uint32, N)
+var output32 = make([]uint32, N)
+var input64 = make([]uint64, N)
+var output64 = make([]uint64, N)
+
+func u8(i int) uint8 {
+       i = 'a' + i%26
+       return uint8(i)
+}
+
+func u16(ii int) uint16 {
+       var i = uint16(ii)
+       i = 'a' + i%26
+       i |= i << 8
+       return i
+}
+
+func u32(ii int) uint32 {
+       var i = uint32(ii)
+       i = 'a' + i%26
+       i |= i << 8
+       i |= i << 16
+       return i
+}
+
+func u64(ii int) uint64 {
+       var i = uint64(ii)
+       i = 'a' + i%26
+       i |= i << 8
+       i |= i << 16
+       i |= i << 32
+       return i
+}
+
+func reset() {
+       // swap in and out to exercise copy-up and copy-down
+       input8, output8 = output8, input8
+       input16, output16 = output16, input16
+       input32, output32 = output32, input32
+       input64, output64 = output64, input64
+       in := 0
+       out := 13
+       for i := range input8 {
+               input8[i] = u8(in)
+               output8[i] = u8(out)
+               input16[i] = u16(in)
+               output16[i] = u16(out)
+               input32[i] = u32(in)
+               output32[i] = u32(out)
+               input64[i] = u64(in)
+               output64[i] = u64(out)
+               in++
+               out++
+       }
+}
+
+func clamp(n int) int {
+       if n > N {
+               return N
+       }
+       return n
+}
+
+func ncopied(length, in, out int) int {
+       n := length
+       if in+n > N {
+               n = N - in
+       }
+       if out+n > N {
+               n = N - out
+       }
+       return n
+}
+
+func doAllSlices(length, in, out int) {
+       reset()
+       n := copy(output8[out:clamp(out+length)], input8[in:clamp(in+length)])
+       verify8(length, in, out, n)
+       n = copy(output16[out:clamp(out+length)], input16[in:clamp(in+length)])
+       verify16(length, in, out, n)
+       n = copy(output32[out:clamp(out+length)], input32[in:clamp(in+length)])
+       verify32(length, in, out, n)
+       n = copy(output64[out:clamp(out+length)], input64[in:clamp(in+length)])
+       verify64(length, in, out, n)
+}
+
+func bad8(state string, i, length, in, out int) {
+       fmt.Printf("%s bad(%d %d %d): %c not %c:\n\t%s\n\t%s\n",
+               state,
+               length, in, out,
+               output8[i],
+               uint8(i+13),
+               input8, output8)
+       os.Exit(1)
+}
+
+func verify8(length, in, out, m int) {
+       n := ncopied(length, in, out)
+       if m != n {
+               fmt.Printf("count bad(%d %d %d): %d not %d\n", length, in, out, m, n)
+               return
+       }
+       // before
+       var i int
+       for i = 0; i < out; i++ {
+               if output8[i] != u8(i+13) {
+                       bad8("before8", i, length, in, out)
+                       return
+               }
+       }
+       // copied part
+       for ; i < out+n; i++ {
+               if output8[i] != u8(i+in-out) {
+                       bad8("copied8", i, length, in, out)
+                       return
+               }
+       }
+       // after
+       for ; i < len(output8); i++ {
+               if output8[i] != u8(i+13) {
+                       bad8("after8", i, length, in, out)
+                       return
+               }
+       }
+}
+
+func bad16(state string, i, length, in, out int) {
+       fmt.Printf("%s bad(%d %d %d): %x not %x:\n\t%v\n\t%v\n",
+               state,
+               length, in, out,
+               output16[i],
+               uint16(i+13),
+               input16, output16)
+       os.Exit(1)
+}
+
+func verify16(length, in, out, m int) {
+       n := ncopied(length, in, out)
+       if m != n {
+               fmt.Printf("count bad(%d %d %d): %d not %d\n", length, in, out, m, n)
+               return
+       }
+       // before
+       var i int
+       for i = 0; i < out; i++ {
+               if output16[i] != u16(i+13) {
+                       bad16("before16", i, length, in, out)
+                       return
+               }
+       }
+       // copied part
+       for ; i < out+n; i++ {
+               if output16[i] != u16(i+in-out) {
+                       bad16("copied16", i, length, in, out)
+                       return
+               }
+       }
+       // after
+       for ; i < len(output16); i++ {
+               if output16[i] != u16(i+13) {
+                       bad16("after16", i, length, in, out)
+                       return
+               }
+       }
+}
+
+func bad32(state string, i, length, in, out int) {
+       fmt.Printf("%s bad(%d %d %d): %x not %x:\n\t%v\n\t%v\n",
+               state,
+               length, in, out,
+               output32[i],
+               uint32(i+13),
+               input32, output32)
+       os.Exit(1)
+}
+
+func verify32(length, in, out, m int) {
+       n := ncopied(length, in, out)
+       if m != n {
+               fmt.Printf("count bad(%d %d %d): %d not %d\n", length, in, out, m, n)
+               return
+       }
+       // before
+       var i int
+       for i = 0; i < out; i++ {
+               if output32[i] != u32(i+13) {
+                       bad32("before32", i, length, in, out)
+                       return
+               }
+       }
+       // copied part
+       for ; i < out+n; i++ {
+               if output32[i] != u32(i+in-out) {
+                       bad32("copied32", i, length, in, out)
+                       return
+               }
+       }
+       // after
+       for ; i < len(output32); i++ {
+               if output32[i] != u32(i+13) {
+                       bad32("after32", i, length, in, out)
+                       return
+               }
+       }
+}
+
+func bad64(state string, i, length, in, out int) {
+       fmt.Printf("%s bad(%d %d %d): %x not %x:\n\t%v\n\t%v\n",
+               state,
+               length, in, out,
+               output64[i],
+               uint64(i+13),
+               input64, output64)
+       os.Exit(1)
+}
+
+func verify64(length, in, out, m int) {
+       n := ncopied(length, in, out)
+       if m != n {
+               fmt.Printf("count bad(%d %d %d): %d not %d\n", length, in, out, m, n)
+               return
+       }
+       // before
+       var i int
+       for i = 0; i < out; i++ {
+               if output64[i] != u64(i+13) {
+                       bad64("before64", i, length, in, out)
+                       return
+               }
+       }
+       // copied part
+       for ; i < out+n; i++ {
+               if output64[i] != u64(i+in-out) {
+                       bad64("copied64", i, length, in, out)
+                       return
+               }
+       }
+       // after
+       for ; i < len(output64); i++ {
+               if output64[i] != u64(i+13) {
+                       bad64("after64", i, length, in, out)
+                       return
+               }
+       }
+}
+
+func slice() {
+       for length := 0; length < N; length++ {
+               for in := 0; in <= 32; in++ {
+                       for out := 0; out <= 32; out++ {
+                               doAllSlices(length, in, out)
+                       }
+               }
+       }
+}
+
+// Array test. Can be much simpler. It's only checking for correct handling of [0:].
+func array() {
+       var array [N]uint8
+       reset()
+       copy(array[0:], input8)
+       for i := 0; i < N; i++ {
+               output8[i] = 0
+       }
+       copy(output8, array[0:])
+       verify8(N, 0, 0, N)
+}
+
+func main() {
+       slice()
+       array()
+}
diff --git a/gcc/testsuite/go.test/test/ddd.go b/gcc/testsuite/go.test/test/ddd.go
new file mode 100644 (file)
index 0000000..c9949c3
--- /dev/null
@@ -0,0 +1,198 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func sum(args ...int) int {
+       s := 0
+       for _, v := range args {
+               s += v
+       }
+       return s
+}
+
+func sumC(args ...int) int { return func() int { return sum(args) }() }
+
+var sumD = func(args ...int) int { return sum(args) }
+
+var sumE = func() func(...int) int { return func(args ...int) int { return sum(args) } }()
+
+var sumF = func(args ...int) func() int { return func() int { return sum(args) } }
+
+func sumA(args []int) int {
+       s := 0
+       for _, v := range args {
+               s += v
+       }
+       return s
+}
+
+func sum2(args ...int) int { return 2 * sum(args) }
+
+func sum3(args ...int) int { return 3 * sumA(args) }
+
+func intersum(args ...interface{}) int {
+       s := 0
+       for _, v := range args {
+               s += v.(int)
+       }
+       return s
+}
+
+type T []T
+
+func ln(args ...T) int { return len(args) }
+
+func ln2(args ...T) int { return 2 * ln(args) }
+
+func (*T) Sum(args ...int) int { return sum(args) }
+
+type U struct {
+       *T
+}
+
+func main() {
+       if x := sum(1, 2, 3); x != 6 {
+               println("sum 6", x)
+               panic("fail")
+       }
+       if x := sum(); x != 0 {
+               println("sum 0", x)
+               panic("fail")
+       }
+       if x := sum(10); x != 10 {
+               println("sum 10", x)
+               panic("fail")
+       }
+       if x := sum(1, 8); x != 9 {
+               println("sum 9", x)
+               panic("fail")
+       }
+       if x := sumC(4, 5, 6); x != 15 {
+               println("sumC 15", x)
+               panic("fail")
+       }
+       if x := sumD(4, 5, 7); x != 16 {
+               println("sumD 16", x)
+               panic("fail")
+       }
+       if x := sumE(4, 5, 8); x != 17 {
+               println("sumE 17", x)
+               panic("fail")
+       }
+       if x := sumF(4, 5, 9)(); x != 18 {
+               println("sumF 18", x)
+               panic("fail")
+       }
+       if x := sum2(1, 2, 3); x != 2*6 {
+               println("sum 6", x)
+               panic("fail")
+       }
+       if x := sum2(); x != 2*0 {
+               println("sum 0", x)
+               panic("fail")
+       }
+       if x := sum2(10); x != 2*10 {
+               println("sum 10", x)
+               panic("fail")
+       }
+       if x := sum2(1, 8); x != 2*9 {
+               println("sum 9", x)
+               panic("fail")
+       }
+       if x := sum3(1, 2, 3); x != 3*6 {
+               println("sum 6", x)
+               panic("fail")
+       }
+       if x := sum3(); x != 3*0 {
+               println("sum 0", x)
+               panic("fail")
+       }
+       if x := sum3(10); x != 3*10 {
+               println("sum 10", x)
+               panic("fail")
+       }
+       if x := sum3(1, 8); x != 3*9 {
+               println("sum 9", x)
+               panic("fail")
+       }
+       if x := intersum(1, 2, 3); x != 6 {
+               println("intersum 6", x)
+               panic("fail")
+       }
+       if x := intersum(); x != 0 {
+               println("intersum 0", x)
+               panic("fail")
+       }
+       if x := intersum(10); x != 10 {
+               println("intersum 10", x)
+               panic("fail")
+       }
+       if x := intersum(1, 8); x != 9 {
+               println("intersum 9", x)
+               panic("fail")
+       }
+
+       if x := ln(nil, nil, nil); x != 3 {
+               println("ln 3", x)
+               panic("fail")
+       }
+       if x := ln([]T{}); x != 1 {
+               println("ln 1", x)
+               panic("fail")
+       }
+       if x := ln2(nil, nil, nil); x != 2*3 {
+               println("ln2 3", x)
+               panic("fail")
+       }
+       if x := ln2([]T{}); x != 2*1 {
+               println("ln2 1", x)
+               panic("fail")
+       }
+       if x := ((*T)(nil)).Sum(1, 3, 5, 7); x != 16 {
+               println("(*T)(nil).Sum", x)
+               panic("fail")
+       }
+       if x := (*T).Sum(nil, 1, 3, 5, 6); x != 15 {
+               println("(*T).Sum", x)
+               panic("fail")
+       }
+       if x := (&U{}).Sum(1, 3, 5, 5); x != 14 {
+               println("(&U{}).Sum", x)
+               panic("fail")
+       }
+       var u U
+       if x := u.Sum(1, 3, 5, 4); x != 13 {
+               println("u.Sum", x)
+               panic("fail")
+       }
+       if x := (&u).Sum(1, 3, 5, 3); x != 12 {
+               println("(&u).Sum", x)
+               panic("fail")
+       }
+       var i interface {
+               Sum(...int) int
+       } = &u
+       if x := i.Sum(2, 3, 5, 7); x != 17 {
+               println("i(=&u).Sum", x)
+               panic("fail")
+       }
+       i = u
+       if x := i.Sum(2, 3, 5, 6); x != 16 {
+               println("i(=u).Sum", x)
+               panic("fail")
+       }
+       /* TODO(rsc): Enable once nested method expressions work.
+       if x := (*U).Sum(&U{}, 1, 3, 5, 2); x != 11 {
+               println("(*U).Sum", x)
+               panic("fail")
+       }
+       if x := U.Sum(U{}, 1, 3, 5, 1); x != 10 {
+               println("U.Sum", x)
+               panic("fail")
+       }
+       */
+}
diff --git a/gcc/testsuite/go.test/test/ddd1.go b/gcc/testsuite/go.test/test/ddd1.go
new file mode 100644 (file)
index 0000000..6f714c0
--- /dev/null
@@ -0,0 +1,28 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func sum(args ...int) int { return 0 }
+
+var (
+       _ = sum(1, 2, 3)
+       _ = sum()
+       _ = sum(1.0, 2.0)
+       _ = sum(1.5)      // ERROR "integer"
+       _ = sum("hello")  // ERROR "convert|incompatible"
+       _ = sum([]int{1}) // ERROR "slice literal.*as type int|incompatible"
+)
+
+type T []T
+
+func funny(args ...T) int { return 0 }
+
+var (
+       _ = funny(nil)
+       _ = funny(nil, nil)
+       _ = funny([]T{}) // ok because []T{} is a T; passes []T{[]T{}}
+)
diff --git a/gcc/testsuite/go.test/test/ddd2.go b/gcc/testsuite/go.test/test/ddd2.go
new file mode 100644 (file)
index 0000000..a06af0c
--- /dev/null
@@ -0,0 +1,16 @@
+// true
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ddd
+
+func Sum(args ...int) int {
+       s := 0
+       for _, v := range args {
+               s += v
+       }
+       return s
+}
+
diff --git a/gcc/testsuite/go.test/test/ddd3.go b/gcc/testsuite/go.test/test/ddd3.go
new file mode 100644 (file)
index 0000000..5d5ebdf
--- /dev/null
@@ -0,0 +1,28 @@
+// $G $D/ddd2.go && $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./ddd2"
+
+func main() {
+       if x := ddd.Sum(1, 2, 3); x != 6 {
+               println("ddd.Sum 6", x)
+               panic("fail")
+       }
+       if x := ddd.Sum(); x != 0 {
+               println("ddd.Sum 0", x)
+               panic("fail")
+       }
+       if x := ddd.Sum(10); x != 10 {
+               println("ddd.Sum 10", x)
+               panic("fail")
+       }
+       if x := ddd.Sum(1, 8); x != 9 {
+               println("ddd.Sum 9", x)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/decl.go b/gcc/testsuite/go.test/test/decl.go
new file mode 100644 (file)
index 0000000..c31082b
--- /dev/null
@@ -0,0 +1,40 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Correct short declarations and redeclarations.
+
+package main
+
+func f1() int { return 1 }
+func f2() (float, int) { return 1, 2 }
+func f3() (float, int, string) { return 1, 2, "3" }
+
+func x() (s string) {
+       a, b, s := f3()
+       _, _ = a, b
+       return  // tests that result var is in scope for redeclaration
+}
+
+func main() {
+       i, f, s := f3()
+       j, f := f2()    // redeclare f
+       k := f1()
+       m, g, s := f3()
+       m, h, s := f3()
+       {
+               // new block should be ok.
+               i, f, s := f3()
+               j, f := f2()    // redeclare f
+               k := f1()
+               m, g, s := f3()
+               m, h, s := f3()
+               _, _, _, _, _, _, _, _, _ = i, f, s, j, k, m, g, s, h
+       }
+       if x() != "3" {
+               println("x() failed")
+       }
+       _, _, _, _, _, _, _, _, _ = i, f, s, j, k, m, g, s, h
+}
diff --git a/gcc/testsuite/go.test/test/declbad.go b/gcc/testsuite/go.test/test/declbad.go
new file mode 100644 (file)
index 0000000..269ebde
--- /dev/null
@@ -0,0 +1,58 @@
+// errchk $G -e $F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Incorrect short declarations and redeclarations.
+
+package main
+
+func f1() int { return 1 }
+func f2() (float, int) { return 1, 2 }
+func f3() (float, int, string) { return 1, 2, "3" }
+
+func main() {
+       {
+               // simple redeclaration
+               i := f1()
+               i := f1()       // ERROR "redeclared|no new"
+               _ = i
+       }
+       {
+               // change of type for f
+               i, f, s := f3()
+               f, g, t := f3() // ERROR "redeclared|cannot assign|incompatible"
+               _, _, _, _, _ = i, f, s, g, t
+       }
+       {
+               // change of type for i
+               i, f, s := f3()
+               j, i, t := f3() // ERROR "redeclared|cannot assign|incompatible"
+               _, _, _, _, _ = i, f, s, j, t
+       }
+       {
+               // no new variables
+               i, f, s := f3()
+               i, f := f2()    // ERROR "redeclared|no new"
+               _, _, _ = i, f, s
+       }
+       {
+               // single redeclaration
+               i, f, s := f3()
+               i := f1()               // ERROR "redeclared|no new|incompatible"
+               _, _, _ = i, f, s
+       }
+               // double redeclaration
+       {
+               i, f, s := f3()
+               i, f := f2()    // ERROR "redeclared|no new"
+               _, _, _ = i, f, s
+       }
+       {
+               // triple redeclaration
+               i, f, s := f3()
+               i, f, s := f3() // ERROR "redeclared|no new"
+               _, _, _ = i, f, s
+       }
+}
diff --git a/gcc/testsuite/go.test/test/defer.go b/gcc/testsuite/go.test/test/defer.go
new file mode 100644 (file)
index 0000000..8b83122
--- /dev/null
@@ -0,0 +1,48 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+var result string
+
+func addInt(i int) { result += fmt.Sprint(i) }
+
+func test1helper() {
+       for i := 0; i < 10; i++ {
+               defer addInt(i)
+       }
+}
+
+func test1() {
+       result = ""
+       test1helper()
+       if result != "9876543210" {
+               fmt.Printf("test1: bad defer result (should be 9876543210): %q\n", result)
+       }
+}
+
+func addDotDotDot(v ...interface{}) { result += fmt.Sprint(v) }
+
+func test2helper() {
+       for i := 0; i < 10; i++ {
+               defer addDotDotDot(i)
+       }
+}
+
+func test2() {
+       result = ""
+       test2helper()
+       if result != "9876543210" {
+               fmt.Printf("test2: bad defer result (should be 9876543210): %q\n", result)
+       }
+}
+
+func main() {
+       test1()
+       test2()
+}
diff --git a/gcc/testsuite/go.test/test/deferprint.go b/gcc/testsuite/go.test/test/deferprint.go
new file mode 100644 (file)
index 0000000..f1e7526
--- /dev/null
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       defer println(42, true, false, true, 1.5, "world", (chan int)(nil), []int(nil), (map[string]int)(nil), (func())(nil), byte(255))
+       defer println(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
+//     defer panic("dead")
+       defer print("printing: ")
+}
diff --git a/gcc/testsuite/go.test/test/empty.go b/gcc/testsuite/go.test/test/empty.go
new file mode 100644 (file)
index 0000000..fa10d69
--- /dev/null
@@ -0,0 +1,12 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package P
+
+import ( )
+const ( )
+var ( )
+type ( )
diff --git a/gcc/testsuite/go.test/test/env.go b/gcc/testsuite/go.test/test/env.go
new file mode 100644 (file)
index 0000000..7646e07
--- /dev/null
@@ -0,0 +1,27 @@
+// [ $GOOS != nacl ] || exit 0  # NaCl runner does not expose environment
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import os "os"
+
+func main() {
+       ga, e0 := os.Getenverror("GOARCH")
+       if e0 != nil {
+               print("$GOARCH: ", e0.String(), "\n")
+               os.Exit(1)
+       }
+       if ga != "amd64" && ga != "386" && ga != "arm" {
+               print("$GOARCH=", ga, "\n")
+               os.Exit(1)
+       }
+       xxx, e1 := os.Getenverror("DOES_NOT_EXIST")
+       if e1 != os.ENOENV {
+               print("$DOES_NOT_EXIST=", xxx, "; err = ", e1.String(), "\n")
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/errchk b/gcc/testsuite/go.test/test/errchk
new file mode 100755 (executable)
index 0000000..ab7192d
--- /dev/null
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This script checks that the compilers emits the errors which we
+# expect.  Usage: errchk COMPILER [OPTS] SOURCEFILE.  This will run
+# the command COMPILER [OPTS] SOURCEFILE.  The compilation is expected
+# to fail; if it succeeds, this script will report an error.  The
+# stderr output of the compiler will be matched against comments in
+# SOURCEFILE.  For each line of the source file which should generate
+# an error, there should be a comment of the form // ERROR "regexp".
+# If the compiler generates an error for a line which has no such
+# commnt, this script will report an error.  Likewise if the compiler
+# does not generate an error for a line which has a comment, or if the
+# error message does not match the <regexp>.  The <regexp> syntax
+# is Perl but its best to stick to egrep.
+
+use POSIX;
+
+if(@ARGV < 1) {
+       print STDERR "Usage: errchk COMPILER [OPTS] SOURCEFILE\n";
+       exit 1;
+}
+
+$file = $ARGV[@ARGV-1];
+open(SRC, $file) || die "BUG: errchk: open $file: $!";
+@src = <SRC>;
+close(SRC);
+
+# Run command
+$cmd = join(' ', @ARGV);
+open(CMD, "exec $cmd </dev/null 2>&1 |") || die "BUG: errchk: run $cmd: $!";
+
+# 6g error messages continue onto additional lines with leading tabs.
+# Split the output at the beginning of each line that doesn't begin with a tab.
+$out = join('', <CMD>);
+@out = split(/^(?!\t)/m, $out);
+
+close CMD;
+
+if($? == 0) {
+       print STDERR "BUG: errchk: command succeeded unexpectedly\n";
+       print STDERR @out;
+       exit 0;
+}
+
+if(!WIFEXITED($?)) {
+       print STDERR "BUG: errchk: compiler crashed\n";
+       print STDERR @out, "\n";
+       exit 0;
+}
+
+sub bug() {
+       if(!$bug++) {
+               print STDERR "BUG: ";
+       }
+}
+
+$line = 0;
+foreach $src (@src) {
+       $line++;
+       next unless $src =~ m|// (GC_)?ERROR (.*)|;
+       $regexp = $2;
+       if($regexp !~ /^"([^"]*)"/) {
+               print STDERR "$file:$line: malformed regexp\n";
+               next;
+       }
+       $regexp = $1;
+
+       @errmsg = grep { /$file:$line:/ } @out;
+       @out = grep { !/$file:$line:/ } @out;
+       if(@errmsg == 0) {
+               bug();
+               print STDERR "errchk: $file:$line: missing expected error: '$regexp'\n";
+               next;
+       }
+       @match = grep { /$regexp/ } @errmsg;
+       if(@match == 0) {
+               bug();
+               print STDERR "errchk: $file:$line: error message does not match '$regexp'\n";
+               next;
+       }
+}
+
+if(@out != 0) {
+       bug();
+       print STDERR "errchk: $file: unmatched error messages:\n";
+       print STDERR "==================================================\n";
+       print STDERR @out;
+       print STDERR "==================================================\n";
+}
+
+exit 0;
diff --git a/gcc/testsuite/go.test/test/escape.go b/gcc/testsuite/go.test/test/escape.go
new file mode 100644 (file)
index 0000000..d4d8447
--- /dev/null
@@ -0,0 +1,207 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// check for correct heap-moving of escaped variables.
+// it is hard to check for the allocations, but it is easy
+// to check that if you call the function twice at the
+// same stack level, the pointers returned should be
+// different.
+
+var bad = false
+
+var allptr = make([]*int, 0, 100)
+
+func noalias(p, q *int, s string) {
+       n := len(allptr)
+       *p = -(n+1)
+       *q = -(n+2)
+       allptr = allptr[0:n+2]
+       allptr[n] = p
+       allptr[n+1] = q
+       n += 2
+       for i := 0; i < n; i++ {
+               if allptr[i] != nil && *allptr[i] != -(i+1) {
+                       println("aliased pointers", -(i+1), *allptr[i], "after", s)
+                       allptr[i] = nil
+                       bad = true
+               }
+       }
+}
+
+func val(p, q *int, v int, s string) {
+       if *p != v {
+               println("wrong value want", v, "got", *p, "after", s)
+               bad = true
+       }
+       if *q != v+1 {
+               println("wrong value want", v+1, "got", *q, "after", s)
+               bad = true
+       }
+}
+
+func chk(p, q *int, v int, s string) {
+       val(p, q, v, s)
+       noalias(p, q, s)
+}
+
+func chkalias(p, q *int, v int, s string) {
+       if p != q {
+               println("want aliased pointers but got different after", s)
+       }
+       if *q != v+1 {
+               println("wrong value want", v+1, "got", *q, "after", s)
+       }
+}
+
+func i_escapes(x int) *int {
+       var i int
+       i = x
+       return &i
+}
+
+func j_escapes(x int) *int {
+       var j int = x
+       j = x
+       return &j
+}
+
+func k_escapes(x int) *int {
+       k := x
+       return &k
+}
+
+func in_escapes(x int) *int {
+       return &x
+}
+
+func send(c chan int, x int) {
+       c <- x
+}
+
+func select_escapes(x int) *int {
+       c := make(chan int)
+       go send(c, x)
+       select {
+       case req := <-c:
+               return &req
+       }
+       return nil
+}
+
+func select_escapes1(x int, y int) (*int, *int) {
+       c := make(chan int)
+       var a [2]int
+       var p [2]*int
+       a[0] = x
+       a[1] = y
+       for i := 0; i < 2; i++ {
+               go send(c, a[i])
+               select {
+               case req := <-c:
+                       p[i] = &req
+               }
+       }
+       return p[0], p[1]
+}
+
+func range_escapes(x int) *int {
+       var a [1]int
+       a[0] = x
+       for _, v := range a {
+               return &v
+       }
+       return nil
+}
+
+// *is* aliased
+func range_escapes2(x, y int) (*int, *int) {
+       var a [2]int
+       var p [2]*int
+       a[0] = x
+       a[1] = y
+       for k, v := range a {
+               p[k] = &v
+       }
+       return p[0], p[1]
+}
+
+// *is* aliased
+func for_escapes2(x int, y int) (*int, *int) {
+       var p [2]*int
+       n := 0
+       for i := x; n < 2; i = y {
+               p[n] = &i
+               n++
+       }
+       return p[0], p[1]
+}
+
+func out_escapes(i int) (x int, p *int) {
+       x = i
+       p = &x  // ERROR "address of out parameter"
+       return
+}
+
+func out_escapes_2(i int) (x int, p *int) {
+       x = i
+       return x, &x    // ERROR "address of out parameter"
+}
+
+func defer1(i int) (x int) {
+       c := make(chan int)
+       go func() { x = i; c <- 1 }()
+       <-c
+       return
+}
+
+func main() {
+       p, q := i_escapes(1), i_escapes(2)
+       chk(p, q, 1, "i_escapes")
+
+       p, q = j_escapes(3), j_escapes(4)
+       chk(p, q, 3, "j_escapes")
+
+       p, q = k_escapes(5), k_escapes(6)
+       chk(p, q, 5, "k_escapes")
+
+       p, q = in_escapes(7), in_escapes(8)
+       chk(p, q, 7, "in_escapes")
+
+       p, q = select_escapes(9), select_escapes(10)
+       chk(p, q, 9, "select_escapes")
+
+       p, q = select_escapes1(11, 12)
+       chk(p, q, 11, "select_escapes1")
+
+       p, q = range_escapes(13), range_escapes(14)
+       chk(p, q, 13, "range_escapes")
+
+       p, q = range_escapes2(101, 102)
+       chkalias(p, q, 101, "range_escapes2")
+
+       p, q = for_escapes2(103, 104)
+       chkalias(p, q, 103, "for_escapes2")
+
+       _, p = out_escapes(15)
+       _, q = out_escapes(16)
+       chk(p, q, 15, "out_escapes")
+
+       _, p = out_escapes_2(17)
+       _, q = out_escapes_2(18)
+       chk(p, q, 17, "out_escapes_2")
+
+       x := defer1(20)
+       if x != 20 {
+               println("defer failed", x)
+               bad = true
+       }
+
+       if bad {
+               panic("BUG: no escape")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug000.go b/gcc/testsuite/go.test/test/fixedbugs/bug000.go
new file mode 100644 (file)
index 0000000..ccb24e8
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var x int;
+       switch x {
+       case 0:
+               {}
+       case 1:
+               x = 0;
+       }
+}
+/*
+bug0.go:8: case statement out of place
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug001.go b/gcc/testsuite/go.test/test/fixedbugs/bug001.go
new file mode 100644 (file)
index 0000000..2df8791
--- /dev/null
@@ -0,0 +1,11 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       if {}  // compiles; should be an error (must be an expression)
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug002.go b/gcc/testsuite/go.test/test/fixedbugs/bug002.go
new file mode 100644 (file)
index 0000000..2308419
--- /dev/null
@@ -0,0 +1,11 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       if ; false {}  // compiles; should be an error (should be simplevardecl before ;)
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug003.go b/gcc/testsuite/go.test/test/fixedbugs/bug003.go
new file mode 100644 (file)
index 0000000..e45975b
--- /dev/null
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       switch ; { case true: return; default: return }
+}
+/*
+bug003.go:6: fatal error: walkswitch: not case EMPTY
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug004.go b/gcc/testsuite/go.test/test/fixedbugs/bug004.go
new file mode 100644 (file)
index 0000000..20f467a
--- /dev/null
@@ -0,0 +1,11 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       switch ; { case false: return; }  // compiles; should be an error (should be simplevardecl before ;)
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug005.go b/gcc/testsuite/go.test/test/fixedbugs/bug005.go
new file mode 100644 (file)
index 0000000..3bd2fe8
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       Foo: {
+               return;
+       }
+       goto Foo;
+}
+/*
+bug5.go:4: Foo undefined
+bug5.go:4: fatal error: walktype: switch 1 unknown op GOTO l(4)
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug006.go b/gcc/testsuite/go.test/test/fixedbugs/bug006.go
new file mode 100644 (file)
index 0000000..e7694f9
--- /dev/null
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+const (
+       x float = iota;
+       g float = 4.5 * iota;
+);
+
+func main() {
+       if g == 0.0 { print("zero\n");}
+       if g != 4.5 { print(" fail\n"); os.Exit(1); }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug007.go b/gcc/testsuite/go.test/test/fixedbugs/bug007.go
new file mode 100644 (file)
index 0000000..bd970de
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type (
+       Point struct { x, y float };
+       Polar Point
+)
+
+func main() {
+}
+
+/*
+bug7.go:5: addtyp: renaming Point to Polar
+main.go.c:14: error: redefinition of typedef ‘_T_2’
+main.go.c:13: error: previous declaration of ‘_T_2’ was here
+main.go.c:16: error: redefinition of ‘struct _T_2’
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug008.go b/gcc/testsuite/go.test/test/fixedbugs/bug008.go
new file mode 100644 (file)
index 0000000..2baead1
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       i5 := 5;
+
+       switch {  // compiler crash fixable with 'switch true'
+       case i5 < 5: dummy := 0; _ = dummy;
+       case i5 == 5: dummy := 0; _ = dummy;
+       case i5 > 5: dummy := 0; _ = dummy;
+       }
+}
+/*
+Segmentation fault
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug009.go b/gcc/testsuite/go.test/test/fixedbugs/bug009.go
new file mode 100644 (file)
index 0000000..ef8263b
--- /dev/null
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+
+func main() {
+       fired := false; _ = fired;
+}
+/*
+bug9.go:5: defaultlit: unknown literal: LITERAL-B0 a(1)
+bug9.go:5: fatal error: addvar: n=NAME-fired G0 a(1) l(5) t=<N> nil
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug010.go b/gcc/testsuite/go.test/test/fixedbugs/bug010.go
new file mode 100644 (file)
index 0000000..e71c4d7
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+
+func f(i int, f float) {
+       i = 8;
+       f = 8.0;
+       return;
+}
+
+func main() {
+       f(3, float(5))
+}
+
+/*
+bug10.go:5: i undefined
+bug10.go:6: illegal conversion of constant to 020({},<_o001>{<i><int32>INT32;<f><float32>FLOAT32;},{})
+bug10.go:7: error in shape across assignment
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug011.go b/gcc/testsuite/go.test/test/fixedbugs/bug011.go
new file mode 100644 (file)
index 0000000..551adb7
--- /dev/null
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+
+type T struct {
+       x, y int;
+}
+
+func (t *T) m(a int, b float) int {
+       return (t.x+a) * (t.y+int(b));
+}
+
+func main() {
+       var t *T = new(T);
+       t.x = 1;
+       t.y = 2;
+       r10 := t.m(1, 3.0);
+       _ = r10;
+}
+/*
+bug11.go:16: fatal error: walktype: switch 1 unknown op CALLMETH l(16) <int32>INT32
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug012.go b/gcc/testsuite/go.test/test/fixedbugs/bug012.go
new file mode 100644 (file)
index 0000000..ffd5b55
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+
+func main() {
+       var u30 uint64 = 0;
+       var u31 uint64 = 1;
+       _, _ = u30, u31;
+       var u32 uint64 = 18446744073709551615;
+       var u33 uint64 = +18446744073709551615;
+       if u32 != (1<<64)-1 { panic("u32\n"); }
+       if u33 != (1<<64)-1 { panic("u33\n"); }
+       var i34 int64 = ^0;  // note: 2's complement means ^0 == -1
+       if i34 != -1 { panic("i34") }
+}
+/*
+bug12.go:5: overflow converting constant to <uint64>UINT64
+bug12.go:6: overflow converting constant to <uint64>UINT64
+bug12.go:7: overflow converting constant to <uint64>UINT64
+bug12.go:8: overflow converting constant to <uint64>UINT64
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug013.go b/gcc/testsuite/go.test/test/fixedbugs/bug013.go
new file mode 100644 (file)
index 0000000..4b10677
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var cu0 uint16 = '\u1234';
+       var cU1 uint32 = '\U00101234';
+       _, _ = cu0, cU1;
+}
+/*
+bug13.go:4: missing '
+bug13.go:4: syntax error
+bug13.go:5: newline in string
+bug13.go:5: missing '
+bug13.go:6: newline in string
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug014.go b/gcc/testsuite/go.test/test/fixedbugs/bug014.go
new file mode 100644 (file)
index 0000000..dac2ce5
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var c00 uint8 = '\0';  // ERROR "oct|char"
+       var c01 uint8 = '\07';  // ERROR "oct|char"
+       var cx0 uint8 = '\x0';  // ERROR "hex|char"
+       var cx1 uint8 = '\x';  // ERROR "hex|char"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug015.go b/gcc/testsuite/go.test/test/fixedbugs/bug015.go
new file mode 100644 (file)
index 0000000..9178f62
--- /dev/null
@@ -0,0 +1,13 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var i33 int64;
+       if i33 == (1<<64) -1 {  // ERROR "overflow"
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug016.go b/gcc/testsuite/go.test/test/fixedbugs/bug016.go
new file mode 100644 (file)
index 0000000..461bcf8
--- /dev/null
@@ -0,0 +1,18 @@
+// ! $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var i int = 100;
+       i = i << -3;  // BUG: should not compile (negative shift)
+}
+
+/*
+ixedbugs/bug016.go:7: overflow converting constant to <uint32>UINT32
+fixedbugs/bug016.go:7: illegal types for operand: AS
+       (<int32>INT32)
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug017.go b/gcc/testsuite/go.test/test/fixedbugs/bug017.go
new file mode 100644 (file)
index 0000000..fdc986d
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var s2 string = "\a\b\f\n\r\t\v";  // \r is miscompiled
+       _ = s2;
+}
+/*
+main.go.c: In function ‘main_main’:
+main.go.c:20: error: missing terminating " character
+main.go.c:21: error: missing terminating " character
+main.go.c:24: error: ‘def’ undeclared (first use in this function)
+main.go.c:24: error: (Each undeclared identifier is reported only once
+main.go.c:24: error: for each function it appears in.)
+main.go.c:24: error: syntax error before ‘def’
+main.go.c:24: error: missing terminating " character
+main.go.c:25: warning: excess elements in struct initializer
+main.go.c:25: warning: (near initialization for ‘slit’)
+main.go.c:36: error: syntax error at end of input
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug020.go b/gcc/testsuite/go.test/test/fixedbugs/bug020.go
new file mode 100644 (file)
index 0000000..896bf57
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var digits string;
+
+func putint(buf []byte, i, base, val int, digits string) {
+               buf[i] = digits[val];
+}
+
+func main() {
+}
+
+/*
+uetli:~/Source/go1/test gri$ 6g bugs/bug020.go
+bugs/bug020.go:7: type of a structure field cannot be an open array
+bugs/bug020.go:7: fatal error: width of a dynamic array
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug021.go b/gcc/testsuite/go.test/test/fixedbugs/bug021.go
new file mode 100644 (file)
index 0000000..201fa5f
--- /dev/null
@@ -0,0 +1,13 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       s1 := "hi";
+       s2 := "ho";
+       s1 += s2;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug022.go b/gcc/testsuite/go.test/test/fixedbugs/bug022.go
new file mode 100644 (file)
index 0000000..f94a585
--- /dev/null
@@ -0,0 +1,26 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func putint(digits *string) {
+       var i byte;
+       i = (*digits)[7];  // compiles
+       i = digits[7];  // ERROR "illegal|is not|invalid"
+       _ = i;
+}
+
+func main() {
+       s := "asdfasdfasdfasdf";
+       putint(&s);
+}
+
+/*
+bug022.go:8: illegal types for operand
+       (*<string>*STRING) INDEXPTR (<int32>INT32)
+bug022.go:8: illegal types for operand
+       (<uint8>UINT8) AS
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug023.go b/gcc/testsuite/go.test/test/fixedbugs/bug023.go
new file mode 100644 (file)
index 0000000..b3d3d4a
--- /dev/null
@@ -0,0 +1,30 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Type interface {
+       TypeName() string;
+}
+
+type TInt struct {
+}
+
+// TInt
+func (i *TInt) TypeName() string {
+       return "int";
+}
+
+
+func main() {
+       var t Type;
+       t = nil;
+       _ = t;
+}
+
+/*
+bug023.go:20: fatal error: naddr: const <Type>I{<TypeName>110(<_t117>{},<_o119>{},{});}
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug024.go b/gcc/testsuite/go.test/test/fixedbugs/bug024.go
new file mode 100644 (file)
index 0000000..c7b17b7
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var i int;
+       i = '\'';
+       i = '\\';
+       var s string;
+       s = "\"";
+       _, _ = i, s;
+}
+/*
+bug.go:5: unknown escape sequence: '
+bug.go:6: unknown escape sequence: \
+bug.go:8: unknown escape sequence: "
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug026.go b/gcc/testsuite/go.test/test/fixedbugs/bug026.go
new file mode 100644 (file)
index 0000000..eacea37
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Element interface {
+}
+
+type Vector struct {
+}
+
+func (v *Vector) Insert(i int, e Element) {
+}
+
+
+func main() {
+       type I struct { val int; };  // BUG: can't be local; works if global
+       v := new(Vector);
+       v.Insert(0, new(I));
+}
+/*
+check: main_sigs_I: not defined
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug027.go b/gcc/testsuite/go.test/test/fixedbugs/bug027.go
new file mode 100644 (file)
index 0000000..acc295d
--- /dev/null
@@ -0,0 +1,61 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Element interface {
+}
+
+type Vector struct {
+       nelem int;
+       elem []Element;
+}
+
+func New() *Vector {
+       v := new(Vector);
+       v.nelem = 0;
+       v.elem = make([]Element, 10);
+       return v;
+}
+
+func (v *Vector) At(i int) Element {
+       return v.elem[i];
+}
+
+func (v *Vector) Insert(e Element) {
+       v.elem[v.nelem] = e;
+       v.nelem++;
+}
+
+func main() {
+       type I struct { val int; };
+       i0 := new(I); i0.val = 0;
+       i1 := new(I); i1.val = 11;
+       i2 := new(I); i2.val = 222;
+       i3 := new(I); i3.val = 3333;
+       i4 := new(I); i4.val = 44444;
+       v := New();
+       print("hi\n");
+       v.Insert(i4);
+       v.Insert(i3);
+       v.Insert(i2);
+       v.Insert(i1);
+       v.Insert(i0);
+       for i := 0; i < v.nelem; i++ {
+               var x *I;
+               x = v.At(i).(*I);
+               print(i, " ", x.val, "\n");  // prints correct list
+       }
+       for i := 0; i < v.nelem; i++ {
+               print(i, " ", v.At(i).(*I).val, "\n");
+       }
+}
+/*
+bug027.go:50: illegal types for operand
+       (<Element>I{}) CONV (<I>{})
+bug027.go:50: illegal types for operand
+       (<Element>I{}) CONV (<I>{})
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug028.go b/gcc/testsuite/go.test/test/fixedbugs/bug028.go
new file mode 100644 (file)
index 0000000..0488ad2
--- /dev/null
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+
+func Alloc(i int) int {
+       switch i {
+       default:
+               return 5;
+       case 1:
+               return 1;
+       case 10:
+               return 10;
+       }
+       return 0
+}
+
+func main() {
+       s := Alloc(7);
+       if s != 5 { panic("bad") }
+}
+
+/*
+bug028.go:7: unreachable statements in a switch
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug030.go b/gcc/testsuite/go.test/test/fixedbugs/bug030.go
new file mode 100644 (file)
index 0000000..7efde9b
--- /dev/null
@@ -0,0 +1,13 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var x int;
+       x := 0; // ERROR "declar|:="
+       _ = x;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug031.go b/gcc/testsuite/go.test/test/fixedbugs/bug031.go
new file mode 100644 (file)
index 0000000..acb4741
--- /dev/null
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+prog := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxx"+
+"xxxxxx"+
+"xxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+;
+_ = prog;
+}
+
+/* Segmentation fault */
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug035.go b/gcc/testsuite/go.test/test/fixedbugs/bug035.go
new file mode 100644 (file)
index 0000000..461c060
--- /dev/null
@@ -0,0 +1,13 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f9(a int) (i int, f float) {
+       i := 9;  // ERROR "redecl|no new"
+       f := float(9);  // ERROR "redecl|no new"
+       return i, f;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug036.go b/gcc/testsuite/go.test/test/fixedbugs/bug036.go
new file mode 100644 (file)
index 0000000..cc20516
--- /dev/null
@@ -0,0 +1,13 @@
+// ! $G $D/$F.go >/dev/null
+// # ignoring error messages...
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       s := float(0);
+       s := float(0);  // BUG redeclaration
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug037.go b/gcc/testsuite/go.test/test/fixedbugs/bug037.go
new file mode 100644 (file)
index 0000000..ff7d287
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       s := vlong(0);  // ERROR "undef"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug038.go b/gcc/testsuite/go.test/test/fixedbugs/bug038.go
new file mode 100644 (file)
index 0000000..7585376
--- /dev/null
@@ -0,0 +1,13 @@
+// ! $G $D/$F.go >/dev/null
+// # ignoring error messages...
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var z [3]byte;
+       z := new([3]byte);  // BUG redeclaration
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug039.go b/gcc/testsuite/go.test/test/fixedbugs/bug039.go
new file mode 100644 (file)
index 0000000..7ac02ce
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f (x int) {       // GCCGO_ERROR "previous"
+       var x int;      // ERROR "redecl|redefinition"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug040.go b/gcc/testsuite/go.test/test/fixedbugs/bug040.go
new file mode 100644 (file)
index 0000000..912316c
--- /dev/null
@@ -0,0 +1,11 @@
+// ! $G $D/$F.go >/dev/null
+// # ignoring error messages...
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main (x, x int) {  // BUG redeclaration error
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug045.go b/gcc/testsuite/go.test/test/fixedbugs/bug045.go
new file mode 100644 (file)
index 0000000..94888c4
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+       i int
+}
+
+func main() {
+       var ta []*T;
+
+       ta = new([1]*T)[0:];
+       ta[0] = nil;
+}
+/*
+bug045.go:13: fatal error: goc: exit 1
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug046.go b/gcc/testsuite/go.test/test/fixedbugs/bug046.go
new file mode 100644 (file)
index 0000000..8a9b797
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T *struct {}
+
+func (x T) M () {}  // ERROR "pointer|receiver"
+
+/*
+bug046.go:7: illegal <this> pointer
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug047.go b/gcc/testsuite/go.test/test/fixedbugs/bug047.go
new file mode 100644 (file)
index 0000000..f3749e7
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+
+       type T struct {
+               s string;
+               f float;
+       };
+       var s string = "hello";
+       var f float = 0.2;
+       t := T{s, f};
+
+       type M map[int] int;
+       m0 := M{7:8};
+
+       _, _ = t, m0;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug048.go b/gcc/testsuite/go.test/test/fixedbugs/bug048.go
new file mode 100644 (file)
index 0000000..b9fee78
--- /dev/null
@@ -0,0 +1,13 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       type M map[int] int;
+       m1 := M{7 : 8};
+       _ = m1;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug049.go b/gcc/testsuite/go.test/test/fixedbugs/bug049.go
new file mode 100644 (file)
index 0000000..8fd67cc
--- /dev/null
@@ -0,0 +1,19 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func atom(s string) {
+       if s == nil {   // ERROR "nil|incompatible"
+               return;
+       }
+}
+
+func main() {}
+
+/*
+bug047.go:4: fatal error: stringpool: not string
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug050.go b/gcc/testsuite/go.test/test/fixedbugs/bug050.go
new file mode 100644 (file)
index 0000000..585c446
--- /dev/null
@@ -0,0 +1,8 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+func main() {  // ERROR "package"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug051.go b/gcc/testsuite/go.test/test/fixedbugs/bug051.go
new file mode 100644 (file)
index 0000000..dd16623
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() int {
+       return 0;
+}
+
+func main() {
+       const n = f();  // ERROR "const"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug052.go b/gcc/testsuite/go.test/test/fixedbugs/bug052.go
new file mode 100644 (file)
index 0000000..d2c1b50
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       c := 10;
+       d := 7;
+       var x [10]int;
+       i := 0;
+       /* this works:
+       q := c/d;
+       x[i] = q;
+       */
+       // this doesn't:
+       x[i] = c/d;     // BUG segmentation fault
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug053.go b/gcc/testsuite/go.test/test/fixedbugs/bug053.go
new file mode 100644 (file)
index 0000000..c981403
--- /dev/null
@@ -0,0 +1,12 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var len int;    // len should not be a keyword - this doesn't compile
+       _ = len;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug054.go b/gcc/testsuite/go.test/test/fixedbugs/bug054.go
new file mode 100644 (file)
index 0000000..c8a2272
--- /dev/null
@@ -0,0 +1,41 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Element interface {
+}
+
+type Vector struct {
+       elem []Element;
+}
+
+func (v *Vector) At(i int) Element {
+       return v.elem[i];
+}
+
+type TStruct struct {
+       name string;
+       fields *Vector;
+}
+
+func (s *TStruct) field(i int) *TStruct {
+       return s.fields.At(i).(*TStruct);
+}
+
+func main() {
+       v := new(Vector);
+       v.elem = make([]Element, 10);
+       t := new(TStruct);
+       t.name = "hi";
+       v.elem[0] = t;
+       s := new(TStruct);
+       s.name = "foo";
+       s.fields = v;
+       if s.field(0).name != "hi" {
+               panic("bad name")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug055.go b/gcc/testsuite/go.test/test/fixedbugs/bug055.go
new file mode 100644 (file)
index 0000000..0326d82
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var i int;
+       var j int;
+       if true {}
+       { return }
+       i = 0;
+       if true {} else i++;
+       type s struct {};
+       i = 0;
+       type s2 int;
+       var k = func (a int) int { return a+1 }(3);
+       _, _ = j, k;
+ro: ;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug056.go b/gcc/testsuite/go.test/test/fixedbugs/bug056.go
new file mode 100644 (file)
index 0000000..050a4a5
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func frexp() (a int, b float64) {
+       return 1, 2.0
+}
+
+func main() {
+       a, b := frexp();
+       _, _ = a, b;
+}
+
+/*
+bug056.go:8: illegal types for operand: AS
+       (<int32>INT32)
+       (<int32>INT32)
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug057.go b/gcc/testsuite/go.test/test/fixedbugs/bug057.go
new file mode 100644 (file)
index 0000000..d5d0f1d
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+       s string;
+}
+
+
+func main() {
+       s := "";
+       l1 := len(s);
+       var t T;
+       l2 := len(t.s); // BUG: cannot take len() of a string field
+       _, _ = l1, l2;
+}
+
+/*
+uetli:/home/gri/go/test/bugs gri$ 6g bug057.go
+bug057.go:14: syntax error
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug058.go b/gcc/testsuite/go.test/test/fixedbugs/bug058.go
new file mode 100644 (file)
index 0000000..e2b4a24
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Box struct {};
+var m map[string] *Box;
+
+func main() {
+       m := make(map[string] *Box);
+       s := "foo";
+       var x *Box = nil;
+       m[s] = x;
+}
+
+/*
+bug058.go:9: illegal types for operand: INDEX
+       (MAP[<string>*STRING]*<Box>{})
+       (<string>*STRING)
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug059.go b/gcc/testsuite/go.test/test/fixedbugs/bug059.go
new file mode 100644 (file)
index 0000000..6a77367
--- /dev/null
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func P(a []string) string {
+       s := "{";
+       for i := 0; i < 2; i++ {
+               if i > 0 {
+                       s += ","
+               }
+               s += `"` + a[i] + `"`;
+       }
+       s +="}";
+       return s;
+}
+
+func main() {
+       m := make(map[string] []string);
+       as := new([2]string);
+       as[0] = "0";
+       as[1] = "1";
+       m["0"] = as[0:];
+
+       a := m["0"];
+       a[0] = "x";
+       m["0"][0] = "deleted";
+       if m["0"][0] != "deleted" {
+               os.Exit(1);
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug060.go b/gcc/testsuite/go.test/test/fixedbugs/bug060.go
new file mode 100644 (file)
index 0000000..82778b8
--- /dev/null
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+       m := make(map[int]int);
+       m[0] = 0;
+       m[0]++;
+       if m[0] != 1 {
+               print("map does not increment\n");
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug061.go b/gcc/testsuite/go.test/test/fixedbugs/bug061.go
new file mode 100644 (file)
index 0000000..aedcf70
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var s string;
+       s = "0000000000000000000000000000000000000000000000000000000000"[0:7];
+       _ = s;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug061.go
+Bus error
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug062.go b/gcc/testsuite/go.test/test/fixedbugs/bug062.go
new file mode 100644 (file)
index 0000000..8ee5c84
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var s string = nil;     // ERROR "illegal|invalid|incompatible|cannot"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug063.go b/gcc/testsuite/go.test/test/fixedbugs/bug063.go
new file mode 100644 (file)
index 0000000..543e0b7
--- /dev/null
@@ -0,0 +1,8 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+const c = 0 ^ 0
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug064.go b/gcc/testsuite/go.test/test/fixedbugs/bug064.go
new file mode 100644 (file)
index 0000000..92d2154
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go || echo BUG: compilation should succeed
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func
+swap(x, y int) (u, v int) {
+       return y, x
+}
+
+func
+main() {
+       a := 1;
+       b := 2;
+       a, b = swap(swap(a, b));
+       if a != 2 || b != 1 {
+               panic("bad swap");
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug065.go b/gcc/testsuite/go.test/test/fixedbugs/bug065.go
new file mode 100644 (file)
index 0000000..a5d1bed
--- /dev/null
@@ -0,0 +1,12 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       k, l, m := 0,0,0;
+       _, _, _ = k, l, m;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug066.go b/gcc/testsuite/go.test/test/fixedbugs/bug066.go
new file mode 100644 (file)
index 0000000..2fa5048
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Scope struct {
+       entries map[string] *Object;
+}
+
+
+type Type struct {
+       scope *Scope;
+}
+
+
+type Object struct {
+       typ *Type;
+}
+
+
+func Lookup(scope *Scope) *Object {
+       return scope.entries["foo"];
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug067.go b/gcc/testsuite/go.test/test/fixedbugs/bug067.go
new file mode 100644 (file)
index 0000000..b812f01
--- /dev/null
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var c chan int
+
+func main() {
+       c = make(chan int);
+       go func() { print("ok\n"); c <- 0 } ();
+       <-c
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug068.go b/gcc/testsuite/go.test/test/fixedbugs/bug068.go
new file mode 100644 (file)
index 0000000..a7cf423
--- /dev/null
@@ -0,0 +1,19 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// RESOLUTION: This program is illegal.  We should reject all unnecessary backslashes.
+
+package main
+
+const c = '\'';  // this works
+const s = "\'";  // ERROR "invalid|escape"
+
+/*
+There is no reason why the escapes need to be different inside strings and chars.
+
+uetli:~/go/test/bugs gri$ 6g bug068.go
+bug068.go:6: unknown escape sequence: '
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug069.go b/gcc/testsuite/go.test/test/fixedbugs/bug069.go
new file mode 100644 (file)
index 0000000..d6796cd
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main(){
+       c := make(chan int);
+       ok := false;
+       var i int;
+
+       i, ok = <-c;  // works
+       _, _ = i, ok;
+
+       ca := new([2]chan int);
+       i, ok = <-(ca[0]);  // fails: c.go:11: bad shape across assignment - cr=1 cl=2
+       _, _ = i, ok;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug070.go b/gcc/testsuite/go.test/test/fixedbugs/bug070.go
new file mode 100644 (file)
index 0000000..6afdd46
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var i, k int;
+       outer:
+       for k=0; k<2; k++ {
+               print("outer loop top k ", k, "\n");
+               if k != 0 { panic("k not zero") }  // inner loop breaks this one every time
+               for i=0; i<2; i++ {
+                       if i != 0 { panic("i not zero") }  // loop breaks every time
+                       print("inner loop top i ", i, "\n");
+                       if true {
+                               print("do break\n");
+                               break outer;
+                       }
+               }
+       }
+       print("broke\n");
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug071.go b/gcc/testsuite/go.test/test/fixedbugs/bug071.go
new file mode 100644 (file)
index 0000000..a5003ff
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go || echo BUG: compiler crashes
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type rat struct  {
+       den  int;
+}
+
+func (u *rat) pr() {
+}
+
+type dch struct {
+       dat chan  *rat;
+}
+
+func dosplit(in *dch){
+       dat := <-in.dat;
+       _ = dat;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug072.go b/gcc/testsuite/go.test/test/fixedbugs/bug072.go
new file mode 100644 (file)
index 0000000..efe5626
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       s := string(bug);  // ERROR "undef"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug073.go b/gcc/testsuite/go.test/test/fixedbugs/bug073.go
new file mode 100644 (file)
index 0000000..99e7cd1
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var s int = 0;
+       var x int = 0;
+       x = x << s;  // ERROR "illegal|inval|shift"
+       x = x >> s;  // ERROR "illegal|inval|shift"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug074.go b/gcc/testsuite/go.test/test/fixedbugs/bug074.go
new file mode 100644 (file)
index 0000000..7b6d14e
--- /dev/null
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       x := string{'a', 'b', '\n'};    // ERROR "composite"
+       print(x);
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug075.go b/gcc/testsuite/go.test/test/fixedbugs/bug075.go
new file mode 100644 (file)
index 0000000..7aed130
--- /dev/null
@@ -0,0 +1,17 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct { m map[int]int }
+func main() {
+       t := new(T);
+       t.m = make(map[int]int);
+       var x int;
+       var ok bool;
+       x, ok = t.m[0];  //bug075.go:11: bad shape across assignment - cr=1 cl=2
+       _, _ = x, ok;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug076.go b/gcc/testsuite/go.test/test/fixedbugs/bug076.go
new file mode 100644 (file)
index 0000000..065cecc
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() {
+exit: ;
+}
+
+
+func main() {
+exit: ; // this should be legal (labels not properly scoped?)
+}
+
+/*
+uetli:~/Source/go/test/bugs gri$ 6g bug076.go 
+bug076.go:11: label redeclared: exit
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug077.go b/gcc/testsuite/go.test/test/fixedbugs/bug077.go
new file mode 100644 (file)
index 0000000..08028ab
--- /dev/null
@@ -0,0 +1,13 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var exit int;
+exit:
+       _ = exit;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug078.go b/gcc/testsuite/go.test/test/fixedbugs/bug078.go
new file mode 100644 (file)
index 0000000..ddd3fae
--- /dev/null
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func dosplit(wait chan int ){
+       select {
+       case <-wait:
+       }
+}
+
+func main() {
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug080.go b/gcc/testsuite/go.test/test/fixedbugs/bug080.go
new file mode 100644 (file)
index 0000000..a5003d2
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main   
+       
+func f1() (x int, y float) {
+       return;
+}
+
+func f2   (x int, y float) {
+       return;
+}
+
+func main() {
+       f2(f1());  // this should be a legal call
+}
+
+/*
+bug080.go:12: illegal types for operand: CALL
+       (<int32>INT32)
+       ({<x><int32>INT32;<y><float32>FLOAT32;})
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug081.go b/gcc/testsuite/go.test/test/fixedbugs/bug081.go
new file mode 100644 (file)
index 0000000..ccb3699
--- /dev/null
@@ -0,0 +1,14 @@
+// ! $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main   
+       
+const x x = 2;
+
+/*
+bug081.go:3: first constant must evaluate an expression
+Bus error
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug082.go b/gcc/testsuite/go.test/test/fixedbugs/bug082.go
new file mode 100644 (file)
index 0000000..8353ec2
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       x := 0
+       x = ^x // unary ^ not yet implemented
+       if x != ^0 {
+               println(x, " ", ^0)
+               panic("fail")
+       }
+}
+
+/*
+uetli:~/Source/go/test/bugs gri$ 6g bug082.go
+bug082.go:7: fatal error: optoas: no entry COM-<int32>INT32
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug083.dir/bug0.go b/gcc/testsuite/go.test/test/fixedbugs/bug083.dir/bug0.go
new file mode 100644 (file)
index 0000000..e312256
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug0
+
+type t0 struct {
+}
+
+var V0 t0
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug083.dir/bug1.go b/gcc/testsuite/go.test/test/fixedbugs/bug083.dir/bug1.go
new file mode 100644 (file)
index 0000000..486fe76
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug1
+
+import "./bug0"
+
+// This is expected to fail--t0 is in package bug0 and should not be
+// visible here in package bug1.  The test for failure is in
+// ../bug083.go.
+
+var v1 bug0.t0;        // ERROR "bug0"
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug083.go b/gcc/testsuite/go.test/test/fixedbugs/bug083.go
new file mode 100644 (file)
index 0000000..984969d
--- /dev/null
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/bug0.go && errchk $G $D/$F.dir/bug1.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ignored
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug084.go b/gcc/testsuite/go.test/test/fixedbugs/bug084.go
new file mode 100644 (file)
index 0000000..c1054e5
--- /dev/null
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Service struct {
+       rpc [2]int
+}
+
+func (s *Service) Serve(a int64) {
+       if a != 1234 {
+               print(a, " not 1234\n")
+               panic("fail")
+       }
+}
+
+var arith Service
+
+func main() {
+       c := make(chan string)
+       a := new(Service)
+       go a.Serve(1234)
+       _ = c
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug085.go b/gcc/testsuite/go.test/test/fixedbugs/bug085.go
new file mode 100644 (file)
index 0000000..02be717
--- /dev/null
@@ -0,0 +1,27 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package P
+
+var x int
+
+func foo() {
+       print(P.x);  // ERROR "undefined"
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug085.go
+bug085.go:6: P: undefined
+Bus error
+*/
+
+/* expected scope hierarchy (outermost to innermost)
+
+universe scope (contains predeclared identifiers int, float, int32, len, etc.)
+"solar" scope (just holds the package name P so it can be found but doesn't conflict)
+global scope (the package global scope)
+local scopes (function scopes)
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug086.go b/gcc/testsuite/go.test/test/fixedbugs/bug086.go
new file mode 100644 (file)
index 0000000..f96472f
--- /dev/null
@@ -0,0 +1,23 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() int { // ERROR "return|control"
+       if false {
+               return 0;
+       }
+       // we should not be able to return successfully w/o a return statement
+}
+
+func main() {
+       print(f(), "\n");
+}
+
+/*
+uetli:~/Source/go1/usr/gri/gosrc gri$ 6g bug.go && 6l bug.6 && 6.out
+4882
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug087.go b/gcc/testsuite/go.test/test/fixedbugs/bug087.go
new file mode 100644 (file)
index 0000000..4af8d97
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const s string = "foo";
+
+func main() {
+       i := len(s);  // should be legal to take len() of a constant
+       _ = i;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug087.go
+bug087.go:6: illegal combination of literals LEN 9
+bug087.go:6: illegal combination of literals LEN 9
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug088.dir/bug0.go b/gcc/testsuite/go.test/test/fixedbugs/bug088.dir/bug0.go
new file mode 100644 (file)
index 0000000..af9d991
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug0
+
+var V0 func() int;
+var V1 func() (a int);
+var V2 func() (a, b int);
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug088.dir/bug1.go b/gcc/testsuite/go.test/test/fixedbugs/bug088.dir/bug1.go
new file mode 100644 (file)
index 0000000..cadf0e6
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import P "./bug0"
+
+func main() {
+       a0 := P.V0();  // works
+       a1 := P.V1();  // works
+       a2, b2 := P.V2();  // doesn't work
+       _, _, _, _ = a0, a1, a2, b2;
+}
+
+/*
+uetli:~/Source/go1/test/bugs/bug088.dir gri$ 6g bug0.go && 6g bug1.go
+bug1.go:8: shape error across :=
+bug1.go:8: a2: undefined
+bug1.go:8: b2: undefined
+bug1.go:8: illegal types for operand: AS
+       (<(bug0)P.int32>INT32)
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug088.go b/gcc/testsuite/go.test/test/fixedbugs/bug088.go
new file mode 100644 (file)
index 0000000..9715a70
--- /dev/null
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/bug0.go && $G $D/$F.dir/bug1.go || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ignored
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug089.go b/gcc/testsuite/go.test/test/fixedbugs/bug089.go
new file mode 100644 (file)
index 0000000..fd3dff3
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type   I1      interface {}
+type   I2      interface { pr() }
+
+func   e()     I1;
+
+var    i1      I1;
+var    i2      I2;
+
+func
+main() {
+
+       i2 = e().(I2);  // bug089.go:16: fatal error: agen_inter i2i
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug090.go b/gcc/testsuite/go.test/test/fixedbugs/bug090.go
new file mode 100644 (file)
index 0000000..8318ab9
--- /dev/null
@@ -0,0 +1,46 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+       c3div2 = 3/2;
+       f3div2 = 3./2.;
+)
+
+func assert(t bool, s string) {
+       if !t {
+               panic(s)
+       }
+}
+
+func main() {
+       var i int;
+       var f float64;
+
+       assert(c3div2 == 1, "3/2");
+       assert(f3div2 == 1.5, "3/2");
+
+       i = c3div2;
+       assert(i == c3div2, "i == c3div2");
+
+       f = c3div2;
+       assert(f == c3div2, "f == c3div2");
+
+       f = f3div2;
+       assert(f == f3div2, "f == f3div2");
+
+       i = f3div2;     // ERROR "truncate"
+       assert(i == c3div2, "i == c3div2 from f3div2");
+       assert(i != f3div2, "i != f3div2");     // ERROR "truncate"
+
+       const g float64 = 1.0;
+       i = g;  // ERROR "convert|incompatible|cannot"
+
+       const h float64 = 3.14;
+       i = h;  // ERROR "convert|incompatible|cannot"
+       i = int(h);     // ERROR "truncate"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug091.go b/gcc/testsuite/go.test/test/fixedbugs/bug091.go
new file mode 100644 (file)
index 0000000..cfbb09c
--- /dev/null
@@ -0,0 +1,24 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f1() {
+       exit:
+               print("hi\n");
+}
+
+func f2() {
+       const c = 1234;
+}
+
+func f3() {
+       i := c; // ERROR "undef"
+}
+
+func main() {
+       f3();
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug092.go b/gcc/testsuite/go.test/test/fixedbugs/bug092.go
new file mode 100644 (file)
index 0000000..8f05c47
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var a [1000] int64;  // this alone works
+       var b [10000] int64;  // this causes a runtime crash
+       _, _ = a, b;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug092.go && 6l bug092.6 && 6.out
+Illegal instruction
+
+gri: array size matters, possibly related to stack overflow check?
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug093.go b/gcc/testsuite/go.test/test/fixedbugs/bug093.go
new file mode 100644 (file)
index 0000000..f80eee0
--- /dev/null
@@ -0,0 +1,64 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S struct {
+}
+
+func (p *S) M() {
+       print("M\n");
+}
+
+type I interface {
+       M();
+}
+
+func main() {
+       var p *S = nil;
+       var i I = p;  // this should be possible even though p is nil: we still know the type
+       i.M();  // should be possible since we know the type, and don't ever use the receiver
+}
+
+
+/*
+throw: ifaces2i: nil pointer
+SIGSEGV: segmentation violation
+Faulting address: 0x0
+pc: 0x1b7d
+
+0x1b7d?zi
+       throw(30409, 0, 0, ...)
+       throw(0x76c9, 0x0, 0x0, ...)
+0x207f?zi
+       sys·ifaces2i(31440, 0, 31480, ...)
+       sys·ifaces2i(0x7ad0, 0x7af8, 0x0, ...)
+0x136f?zi
+       main·main(1, 0, 1606416424, ...)
+       main·main(0x1, 0x7fff5fbff828, 0x0, ...)
+
+rax     0x1
+rbx     0x1
+rcx     0x33b5
+rdx     0x0
+rdi     0x1
+rsi     0x7684
+rbp     0x7684
+rsp     0xafb8
+r8      0x0
+r9      0x0
+r10     0x1002
+r11     0x206
+r12     0x0
+r13     0x0
+r14     0x7c48
+r15     0xa000
+rip     0x1b7d
+rflags  0x10202
+cs      0x27
+fs      0x10
+gs      0x48
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug094.go b/gcc/testsuite/go.test/test/fixedbugs/bug094.go
new file mode 100644 (file)
index 0000000..2953eb2
--- /dev/null
@@ -0,0 +1,32 @@
+// $G $D/$F.go || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f0() {
+       const x = 0;
+}
+
+
+func f1() {
+       x := 0;
+       _ = x;
+}
+
+
+func main() {
+       f0();
+       f1();
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug094.go && 6l bug094.6 && 6.out
+bug094.go:11: left side of := must be a name
+bad top
+.   LITERAL-I0 l(343)
+bug094.go:11: fatal error: walktype: top=3 LITERAL
+uetli:~/Source/go1/test/bugs gri$
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug096.go b/gcc/testsuite/go.test/test/fixedbugs/bug096.go
new file mode 100644 (file)
index 0000000..9be687a
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type A []int;
+
+func main() {
+       a := &A{0};
+       b := &A{0, 1};
+       _, _ = a, b;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug096.go && 6l bug096.6 && 6.out
+Trace/BPT trap
+uetli:~/Source/go1/test/bugs gri$
+*/
+
+/*
+It appears that the first assignment changes the size of A from open
+into a fixed array.
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug097.go b/gcc/testsuite/go.test/test/fixedbugs/bug097.go
new file mode 100644 (file)
index 0000000..ec3c215
--- /dev/null
@@ -0,0 +1,53 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG wrong result
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type A []int
+
+func main() {
+       var a [3]A
+       for i := 0; i < 3; i++ {
+               a[i] = A{i}
+       }
+       if a[0][0] != 0 {
+               panic("fail a[0][0]")
+       }
+       if a[1][0] != 1 {
+               panic("fail a[1][0]")
+       }
+       if a[2][0] != 2 {
+               panic("fail a[2][0]")
+       }
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug097.go && 6l bug097.6 && 6.out
+
+panic on line 342 PC=0x13c2
+0x13c2?zi
+       main·main(1, 0, 1606416416, ...)
+       main·main(0x1, 0x7fff5fbff820, 0x0, ...)
+SIGTRAP: trace trap
+Faulting address: 0x4558
+pc: 0x4558
+
+0x4558?zi
+       sys·Breakpoint(40960, 0, 45128, ...)
+       sys·Breakpoint(0xa000, 0xb048, 0xa000, ...)
+0x156a?zi
+       sys·panicl(342, 0, 0, ...)
+       sys·panicl(0x156, 0x300000000, 0xb024, ...)
+0x13c2?zi
+       main·main(1, 0, 1606416416, ...)
+       main·main(0x1, 0x7fff5fbff820, 0x0, ...)
+*/
+
+/* An array composite literal needs to be created freshly every time.
+It is a "construction" of an array after all. If I pass the address
+of the array to some function, it may store it globally. Same applies
+to struct literals.
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug098.go b/gcc/testsuite/go.test/test/fixedbugs/bug098.go
new file mode 100644 (file)
index 0000000..1dad4d5
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type A []int;
+type M map[int] int;
+
+func main() {
+       var a *A = &A{0};
+       var m *M = &M{0 : 0};  // should be legal to use & here for consistency with other composite constructors (prev. line)
+       _, _ = a, m;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug098.go && 6l bug098.6 && 6.out
+bug098.go:10: illegal types for operand: AS
+       (*MAP[<int32>INT32]<int32>INT32)
+       (**MAP[<int32>INT32]<int32>INT32)
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug099.go b/gcc/testsuite/go.test/test/fixedbugs/bug099.go
new file mode 100644 (file)
index 0000000..f76f0e8
--- /dev/null
@@ -0,0 +1,37 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG should not crash
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Interface
+type I interface { F() int }
+
+// Implements interface
+type S struct { }
+func (s *S) F() int { return 1 }
+
+// Allocates S but returns I
+// Arg is unused but important:
+// if you take it out (and the 0s below)
+// then the bug goes away.
+func NewI(i int) I {
+       return new(S)
+}
+
+// Uses interface method.
+func Use(x I) {
+       x.F()
+}
+
+func main() {
+       i := NewI(0);
+       Use(i);
+
+       // Again, without temporary
+       // Crashes because x.F is 0.
+       Use(NewI(0));
+}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug101.go b/gcc/testsuite/go.test/test/fixedbugs/bug101.go
new file mode 100644 (file)
index 0000000..92487de
--- /dev/null
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a = []int { 1, 2, 3 }
+
+func main() {
+       if len(a) != 3 { panic("array len") }
+       // print(a[0], " ", a[1], " ", a[2], "\n")
+       if a[0] != 1 || a[1] != 2 || a[2] != 3 { panic("array contents") }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug102.go b/gcc/testsuite/go.test/test/fixedbugs/bug102.go
new file mode 100644 (file)
index 0000000..1d97eb4
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should not crash
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var b [0]byte
+       s := string(b[0:]) // out of bounds trap
+       if s != "" {
+               panic("bad convert")
+       }
+       var b1 = [5]byte{'h', 'e', 'l', 'l', 'o'}
+       if string(b1[0:]) != "hello" {
+               panic("bad convert 1")
+       }
+       var b2 = make([]byte, 5)
+       for i := 0; i < 5; i++ {
+               b2[i] = b1[i]
+       }
+       if string(b2) != "hello" {
+               panic("bad convert 2")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug103.go b/gcc/testsuite/go.test/test/fixedbugs/bug103.go
new file mode 100644 (file)
index 0000000..b789be1
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() /* no return type */ {}
+
+func main() {
+       x := f();  // ERROR "mismatch|as value|no type"
+}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug104.go b/gcc/testsuite/go.test/test/fixedbugs/bug104.go
new file mode 100644 (file)
index 0000000..dd4bb58
--- /dev/null
@@ -0,0 +1,10 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+func f() string {
+       return 0        // ERROR "conversion|type"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug106.dir/bug0.go b/gcc/testsuite/go.test/test/fixedbugs/bug106.dir/bug0.go
new file mode 100644 (file)
index 0000000..d9c26a0
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug0
+
+const A = -1
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug106.dir/bug1.go b/gcc/testsuite/go.test/test/fixedbugs/bug106.dir/bug1.go
new file mode 100644 (file)
index 0000000..0f1d20e
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug1
+
+import _ "./bug0"
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug106.go b/gcc/testsuite/go.test/test/fixedbugs/bug106.go
new file mode 100644 (file)
index 0000000..1874b20
--- /dev/null
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/bug0.go && $G $D/$F.dir/bug1.go || echo BUG: failed to compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ignored
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug107.go b/gcc/testsuite/go.test/test/fixedbugs/bug107.go
new file mode 100644 (file)
index 0000000..d0b062a
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+import os "os"
+type _ os.Error
+func f() (os int) {
+        // In the next line "os" should refer to the result variable, not
+        // to the package.
+        v := os.Open("", 0, 0);        // ERROR "undefined"
+        return 0
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug108.go b/gcc/testsuite/go.test/test/fixedbugs/bug108.go
new file mode 100644 (file)
index 0000000..5c7649f
--- /dev/null
@@ -0,0 +1,10 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+func f() {
+       v := 1 << 1025;         // ERROR "overflow|stupid shift"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug109.go b/gcc/testsuite/go.test/test/fixedbugs/bug109.go
new file mode 100644 (file)
index 0000000..c679771
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+func f(a float) float {
+       e := 1.0;
+       e = e * a;
+       return e;
+}
+
+/*
+6g bugs/bug109.go
+bugs/bug109.go:5: illegal types for operand: MUL
+       (<float64>FLOAT64)
+       (<float32>FLOAT32)
+bugs/bug109.go:5: illegal types for operand: AS
+       (<float64>FLOAT64)
+bugs/bug109.go:6: illegal types for operand: RETURN
+       (<float32>FLOAT32)
+       (<float64>FLOAT64)
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug110.go b/gcc/testsuite/go.test/test/fixedbugs/bug110.go
new file mode 100644 (file)
index 0000000..4e43d1c
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A || echo BUG: const bug
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const a = 0
+
+func f() {
+       const a = 5
+}
+
+func main() {
+       if a != 0 {
+               println("a=", a)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug111.go b/gcc/testsuite/go.test/test/fixedbugs/bug111.go
new file mode 100644 (file)
index 0000000..e72b343
--- /dev/null
@@ -0,0 +1,32 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG should compile and run
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var ncall int;
+
+type Iffy interface {
+       Me() Iffy
+}
+
+type Stucky struct {
+       n int
+}
+
+func (s *Stucky) Me() Iffy {
+       ncall++;
+       return s
+}
+
+func main() {
+       s := new(Stucky);
+       i := s.Me();
+       j := i.Me();
+       j.Me();
+       if ncall != 3 {
+               panic("bug111")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug112.go b/gcc/testsuite/go.test/test/fixedbugs/bug112.go
new file mode 100644 (file)
index 0000000..3c93284
--- /dev/null
@@ -0,0 +1,16 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct { s string }
+var t = T{"hi"}
+
+func main() {}
+
+/*
+bug112.go:6: illegal conversion of constant to T
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug113.go b/gcc/testsuite/go.test/test/fixedbugs/bug113.go
new file mode 100644 (file)
index 0000000..4fd322d
--- /dev/null
@@ -0,0 +1,28 @@
+// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should not succeed)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface{}
+
+func foo1(i int) int     { return i }
+func foo2(i int32) int32 { return i }
+func main() {
+       var i I
+       i = 1
+       var v1 = i.(int)
+       if foo1(v1) != 1 {
+               panic(1)
+       }
+       var v2 = int32(i.(int))
+       if foo2(v2) != 1 {
+               panic(2)
+       }
+       var v3 = i.(int32) // This type conversion should fail at runtime.
+       if foo2(v3) != 1 {
+               panic(3)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug114.go b/gcc/testsuite/go.test/test/fixedbugs/bug114.go
new file mode 100644 (file)
index 0000000..974b7cf
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && (./$A.out || echo BUG: bug114 failed)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const B32 = 1<<32 - 1
+const C32 = (-1) & ((1 << 32) - 1)
+const D32 = ^0
+
+func main() {
+       if B32 != 0xFFFFFFFF {
+               println("1<<32 - 1 is", B32, "should be", 0xFFFFFFFF)
+               panic("fail")
+       }
+       if C32 != 0xFFFFFFFF {
+               println("(-1) & ((1<<32) - 1) is", C32, "should be", 0xFFFFFFFF)
+               panic("fail")
+       }
+       if D32 != -1 {
+               println("^0 is", D32, "should be", -1)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug115.go b/gcc/testsuite/go.test/test/fixedbugs/bug115.go
new file mode 100644 (file)
index 0000000..16b22d7
--- /dev/null
@@ -0,0 +1,14 @@
+// $G $D/$F.go || echo BUG: bug115 should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func isuint(i uint) { }
+
+func main() {
+       i := ^uint(0);
+       isuint(i);
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug116.go b/gcc/testsuite/go.test/test/fixedbugs/bug116.go
new file mode 100644 (file)
index 0000000..42ca803
--- /dev/null
@@ -0,0 +1,35 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug116
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       bad := false
+       if (-5 >> 1) != -3 {
+               println("-5>>1 =", -5>>1, "want -3")
+               bad = true
+       }
+       if (-4 >> 1) != -2 {
+               println("-4>>1 =", -4>>1, "want -2")
+               bad = true
+       }
+       if (-3 >> 1) != -2 {
+               println("-3>>1 =", -3>>1, "want -2")
+               bad = true
+       }
+       if (-2 >> 1) != -1 {
+               println("-2>>1 =", -2>>1, "want -1")
+               bad = true
+       }
+       if (-1 >> 1) != -1 {
+               println("-1>>1 =", -1>>1, "want -1")
+               bad = true
+       }
+       if bad {
+               println("errors")
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug117.go b/gcc/testsuite/go.test/test/fixedbugs/bug117.go
new file mode 100644 (file)
index 0000000..ad89ebf
--- /dev/null
@@ -0,0 +1,29 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S struct {
+       a int
+}
+type PS *S
+
+func (p *S) get() int {
+       return p.a
+}
+
+func fn(p PS) int {
+       // p has type PS, and PS has no methods.
+       // (a compiler might see that p is a pointer
+       // and go looking in S without noticing PS.)
+       return p.get() // ERROR "undefined"
+}
+func main() {
+       s := S{1}
+       if s.get() != 1 {
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug118.go b/gcc/testsuite/go.test/test/fixedbugs/bug118.go
new file mode 100644 (file)
index 0000000..1271f5b
--- /dev/null
@@ -0,0 +1,15 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func Send(c chan int) int {
+       select {
+       default:
+               return 1;
+       }
+       return 2;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug119.go b/gcc/testsuite/go.test/test/fixedbugs/bug119.go
new file mode 100644 (file)
index 0000000..7505078
--- /dev/null
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should not fail
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func foo(a []int) int {
+       return a[0] // this seems to do the wrong thing
+}
+
+func main() {
+       a := &[]int{12}
+       if x := (*a)[0]; x != 12 {
+               panic(2)
+       }
+       if x := foo(*a); x != 12 {
+               // fails (x is incorrect)
+               panic(3)
+       }
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6go bug119
+3 70160
+
+panic on line 83 PC=0x14d6
+0x14d6?zi
+       main·main(23659, 0, 1, ...)
+       main·main(0x5c6b, 0x1, 0x7fff5fbff830, ...)
+0x52bb?zi
+       mainstart(1, 0, 1606416432, ...)
+       mainstart(0x1, 0x7fff5fbff830, 0x0, ...)
+uetli:~/Source/go1/test/bugs gri$
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug120.go b/gcc/testsuite/go.test/test/fixedbugs/bug120.go
new file mode 100644 (file)
index 0000000..2a71957
--- /dev/null
@@ -0,0 +1,60 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug120
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+import "strconv"
+
+type Test struct {
+       f   float64
+       in  string
+       out string
+}
+
+var tests = []Test{
+       Test{123.5, "123.5", "123.5"},
+       Test{456.7, "456.7", "456.7"},
+       Test{1e23 + 8.5e6, "1e23+8.5e6", "1.0000000000000001e+23"},
+       Test{100000000000000008388608, "100000000000000008388608", "1.0000000000000001e+23"},
+       Test{1e23 + 8388609, "1e23+8388609", "1.0000000000000001e+23"},
+
+       // "x" = the floating point value from converting the string x.
+       // These are exactly representable in 64-bit floating point:
+       //      1e23-8388608
+       //      1e23+8388608
+       // The former has an even mantissa, so "1e23" rounds to 1e23-8388608.
+       // If "1e23+8388608" is implemented as "1e23" + "8388608",
+       // that ends up computing 1e23-8388608 + 8388608 = 1e23,
+       // which rounds back to 1e23-8388608.
+       // The correct answer, of course, would be "1e23+8388608" = 1e23+8388608.
+       // This is not going to be correct until 6g has multiprecision floating point.
+       // A simpler case is "1e23+1", which should also round to 1e23+8388608.
+       Test{1e23 + 8.388608e6, "1e23+8.388608e6", "1.0000000000000001e+23"},
+       Test{1e23 + 1, "1e23+1", "1.0000000000000001e+23"},
+}
+
+func main() {
+       ok := true
+       for i := 0; i < len(tests); i++ {
+               t := tests[i]
+               v := strconv.Ftoa64(t.f, 'g', -1)
+               if v != t.out {
+                       println("Bad float64 const:", t.in, "want", t.out, "got", v)
+                       x, err := strconv.Atof64(t.out)
+                       if err != nil {
+                               println("bug120: strconv.Atof64", t.out)
+                               panic("fail")
+                       }
+                       println("\twant exact:", strconv.Ftoa64(x, 'g', 1000))
+                       println("\tgot exact: ", strconv.Ftoa64(t.f, 'g', 1000))
+                       ok = false
+               }
+       }
+       if !ok {
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug121.go b/gcc/testsuite/go.test/test/fixedbugs/bug121.go
new file mode 100644 (file)
index 0000000..15c8451
--- /dev/null
@@ -0,0 +1,18 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T func()
+
+type I interface {
+       f, g ();        // ERROR "name list not allowed"
+}
+
+type J interface {
+       h T;  // ERROR "syntax|signature"
+}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug122.go b/gcc/testsuite/go.test/test/fixedbugs/bug122.go
new file mode 100644 (file)
index 0000000..72bf38a
--- /dev/null
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       // should allow at most 2 sizes
+       a := make([]int, 10, 20, 30, 40); // ERROR "too many"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug123.go b/gcc/testsuite/go.test/test/fixedbugs/bug123.go
new file mode 100644 (file)
index 0000000..bdac674
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+const ( F = 1 )
+func fn(i int) int {
+       if i == F() {           // ERROR "func"
+               return 0
+       }
+       return 1
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug126.go b/gcc/testsuite/go.test/test/fixedbugs/bug126.go
new file mode 100644 (file)
index 0000000..a8d56e1
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// same const identifier declared twice should not be accepted
+const none = 0  // GCCGO_ERROR "previous"
+const none = 1;  // ERROR "redeclared|redef"
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug127.go b/gcc/testsuite/go.test/test/fixedbugs/bug127.go
new file mode 100644 (file)
index 0000000..25b4811
--- /dev/null
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+func main() {
+       var x int64 = 0;
+       println(x != nil);      // ERROR "illegal|incompatible|nil"
+       println(0 != nil);      // ERROR "illegal|incompatible|nil"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug128.go b/gcc/testsuite/go.test/test/fixedbugs/bug128.go
new file mode 100644 (file)
index 0000000..3fd647c
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+func main() {
+       switch {
+               // empty switch is allowed according to syntax
+               // unclear why it shouldn't be allowed
+       }
+       switch tag := 0; tag {
+               // empty switch is allowed according to syntax
+               // unclear why it shouldn't be allowed
+       }
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug127.go 
+bug127.go:5: switch statement must have case labels
+bug127.go:9: switch statement must have case labels
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug129.go b/gcc/testsuite/go.test/test/fixedbugs/bug129.go
new file mode 100644 (file)
index 0000000..d1e2d8b
--- /dev/null
@@ -0,0 +1,14 @@
+// $G $D/$F.go || echo BUG129
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package foo
+import "fmt"
+
+func f() {
+       fmt.Println();
+       fmt := 1;
+       _ = fmt;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug130.go b/gcc/testsuite/go.test/test/fixedbugs/bug130.go
new file mode 100644 (file)
index 0000000..855c707
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+       s := S{0};
+       var i I = &s;
+       c := make(chan int);
+       go i.send(c);
+       os.Exit(<-c);
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug131.go b/gcc/testsuite/go.test/test/fixedbugs/bug131.go
new file mode 100644 (file)
index 0000000..e5d4ca0
--- /dev/null
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       const a uint64 = 10;
+       var b int64 = a;        // ERROR "convert|cannot|incompatible"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug132.go b/gcc/testsuite/go.test/test/fixedbugs/bug132.go
new file mode 100644 (file)
index 0000000..bab8996
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+       x, x int  // ERROR "duplicate"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug133.dir/bug0.go b/gcc/testsuite/go.test/test/fixedbugs/bug133.dir/bug0.go
new file mode 100644 (file)
index 0000000..48cd104
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug0
+
+type T struct { i int }
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug133.dir/bug1.go b/gcc/testsuite/go.test/test/fixedbugs/bug133.dir/bug1.go
new file mode 100644 (file)
index 0000000..7562147
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug1
+
+import "./bug0"
+
+type T struct { t bug0.T }
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug133.dir/bug2.go b/gcc/testsuite/go.test/test/fixedbugs/bug133.dir/bug2.go
new file mode 100644 (file)
index 0000000..e531001
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug2
+
+import _ "./bug1"
+import "./bug0"
+
+type T2 struct { t bug0.T }
+
+func fn(p *T2) int {
+       // This reference should be invalid, because bug0.T.i is local
+       // to package bug0 and should not be visible in package bug1.
+       return p.t.i;   // ERROR "field|undef"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug133.go b/gcc/testsuite/go.test/test/fixedbugs/bug133.go
new file mode 100644 (file)
index 0000000..2beeb07
--- /dev/null
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/bug0.go && $G $D/$F.dir/bug1.go && errchk $G $D/$F.dir/bug2.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ignored
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug135.go b/gcc/testsuite/go.test/test/fixedbugs/bug135.go
new file mode 100644 (file)
index 0000000..470135e
--- /dev/null
@@ -0,0 +1,19 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Foo interface { }
+
+type T struct {}
+func (t *T) foo() {}
+
+func main() {
+       t := new(T);
+       var i interface {};
+       f, ok := i.(Foo);
+       _, _, _ = t, f, ok;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug136.go b/gcc/testsuite/go.test/test/fixedbugs/bug136.go
new file mode 100644 (file)
index 0000000..7491b65
--- /dev/null
@@ -0,0 +1,22 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       L: ;  // ';' terminates empty statement => L does not apply to for loop
+       for i := 0; i < 10; i++ {
+               println(i);
+               break L;  // ERROR "L"
+       }
+
+       L1: { // L1 labels block => L1 does not apply to for loop
+               for i := 0; i < 10; i++ {
+                       println(i);
+                       break L1;  // ERROR "L1"
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug137.go b/gcc/testsuite/go.test/test/fixedbugs/bug137.go
new file mode 100644 (file)
index 0000000..1527924
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+L1:
+L2:    for i := 0; i < 10; i++ {
+               print(i);
+               break L2;
+       }
+
+L3: ;
+L4:    for i := 0; i < 10; i++ {
+               print(i);
+               break L4;
+       }
+}
+
+/*
+bug137.go:9: break label is not defined: L2
+bug137.go:15: break label is not defined: L4
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug139.go b/gcc/testsuite/go.test/test/fixedbugs/bug139.go
new file mode 100644 (file)
index 0000000..2bdbef1
--- /dev/null
@@ -0,0 +1,17 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       x := false;
+       func () { if x          { println(1); } }();  // this does not compile
+       func () { if x == false { println(2); } }();  // this works as expected
+}
+
+/*
+bug139.go:7: fatal error: naddr: ONAME class x 5
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug140.go b/gcc/testsuite/go.test/test/fixedbugs/bug140.go
new file mode 100644 (file)
index 0000000..33d1deb
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       if {} else L1: ;
+       if {} else L2: main() ;
+}
+
+/*
+These should be legal according to the spec.
+bug140.go:6: syntax error near L1
+bug140.go:7: syntax error near L2
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug141.go b/gcc/testsuite/go.test/test/fixedbugs/bug141.go
new file mode 100644 (file)
index 0000000..756ba30
--- /dev/null
@@ -0,0 +1,32 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+type S struct { i int }
+func (p *S) Get() int { return p.i }
+
+type Empty interface {
+}
+
+type Getter interface {
+       Get() int;
+}
+
+func f1(p Empty) {
+       switch x := p.(type) {
+       default: println("failed to match interface"); os.Exit(1);
+       case Getter: break;
+       }
+
+}
+
+func main() {
+       var s S;
+       f1(&s);
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug142.go b/gcc/testsuite/go.test/test/fixedbugs/bug142.go
new file mode 100644 (file)
index 0000000..e54458b
--- /dev/null
@@ -0,0 +1,31 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug142
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func panic1(s string) bool {
+       panic(s);
+}
+
+func main() {
+       x := false && panic1("first") && panic1("second");
+       x = x == true && panic1("first") && panic1("second");
+}
+
+/*
+; 6.out
+second
+panic PC=0x250f98
+main·panic1+0x36 /Users/rsc/goX/test/bugs/bug142.go:6
+       main·panic1(0xae30, 0x0)
+main·main+0x23 /Users/rsc/goX/test/bugs/bug142.go:10
+       main·main()
+mainstart+0xf /Users/rsc/goX/src/runtime/amd64/asm.s:53
+       mainstart()
+sys·Goexit /Users/rsc/goX/src/runtime/proc.c:124
+       sys·Goexit()
+; 
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug143.go b/gcc/testsuite/go.test/test/fixedbugs/bug143.go
new file mode 100644 (file)
index 0000000..2f575fc
--- /dev/null
@@ -0,0 +1,44 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type myMap map[string] int;
+
+func f() myMap {
+       m := make(map[string] int);
+       return m
+}
+
+func main() {
+       m := make(myMap);
+       mp := &m;
+
+       {
+               x, ok := m["key"];
+               _, _ = x, ok;
+       }
+       {
+               x, ok := (*mp)["key"];
+               _, _ = x, ok;
+       }
+       {
+               x, ok := f()["key"];
+               _, _ = x, ok;
+       }
+       {
+               var x int;
+               var ok bool;
+               x, ok = f()["key"];
+               _, _ = x, ok;
+       }
+}
+
+/*
+ * bug143.go:19: assignment count mismatch: 2 = 1
+ * bug143.go:18: x: undefined
+ * bug143.go:18: ok: undefined
+ */
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug144.go b/gcc/testsuite/go.test/test/fixedbugs/bug144.go
new file mode 100644 (file)
index 0000000..bab9a44
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const c = 1;
+
+func main() {
+       c := 0;
+       _ = c;
+}
+
+/*
+bug144.go:8: left side of := must be a name
+bug144.go:8: operation LITERAL not allowed in assignment context
+bug144.go:8: illegal types for operand: AS
+       ideal
+       int
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug145.go b/gcc/testsuite/go.test/test/fixedbugs/bug145.go
new file mode 100644 (file)
index 0000000..c59bceb
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type t int
+
+func main() {
+       t := 0;
+       _ = t;
+}
+
+/*
+bug145.go:8: t is type, not var
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug146.go b/gcc/testsuite/go.test/test/fixedbugs/bug146.go
new file mode 100644 (file)
index 0000000..16324c7
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       type Slice []byte;
+       a := [...]byte{ 0 };
+       b := Slice(a[0:]);      // This should be OK.
+       c := Slice(a);          // ERROR "invalid|illegal|cannot"
+       _, _ = b, c;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug147.go b/gcc/testsuite/go.test/test/fixedbugs/bug147.go
new file mode 100644 (file)
index 0000000..a16630b
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug147
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "time"
+
+func main() {
+       var count int
+       c := make(chan byte)
+       go func(c chan byte) {
+               <-c
+               count++
+               time.Sleep(1000000)
+               count++
+               <-c
+       }(c)
+       c <- 1
+       c <- 2
+       if count != 2 {
+               panic("synchronous send did not wait")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug148.go b/gcc/testsuite/go.test/test/fixedbugs/bug148.go
new file mode 100644 (file)
index 0000000..daedff1
--- /dev/null
@@ -0,0 +1,39 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out || echo BUG: should crash
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {a, b int};
+
+func f(x interface{}) interface{} {
+       type T struct {a, b int};
+
+       if x == nil {
+               return T{2, 3};
+       }
+
+       t := x.(T);
+       println(t.a, t.b);
+       return x;
+}
+
+func main() {
+       inner_T := f(nil);
+       f(inner_T);
+
+       outer_T := T{5, 7};
+       f(outer_T);
+}
+
+/*
+This prints:
+
+2 3
+5 7
+
+but it should crash: The type assertion on line 14 should fail
+for the 2nd call to f with outer_T.
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug149.go b/gcc/testsuite/go.test/test/fixedbugs/bug149.go
new file mode 100644 (file)
index 0000000..a40403b
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var b1 []byte;
+       s1 := string(b1);
+       println(len(s1));  // prints 0
+
+       b2 := ([]byte)(nil);
+       s2 := string(b2);
+       println(len(s2));  // prints 0
+
+       s3 := string(([]byte)(nil));  // does not compile (literal substitution of b2)
+       println(len(s3));
+}
+
+/*
+bug149.go:14: cannot convert []uint8 constant to string
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug150.go b/gcc/testsuite/go.test/test/fixedbugs/bug150.go
new file mode 100644 (file)
index 0000000..fc25444
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go || echo BUG: bug150 
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T int
+func (t T) M()
+
+type M interface { M() } 
+
+func g() (T, T)
+
+func f() (a, b M) {
+       a, b = g();
+       return;
+}
+
+/*
+bugs/bug150.go:13: reorder2: too many funcation calls evaluating parameters
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug151.go b/gcc/testsuite/go.test/test/fixedbugs/bug151.go
new file mode 100644 (file)
index 0000000..46546df
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: bug151
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S string
+
+type Empty interface {}
+
+func (v S) Less(e Empty) bool {
+       return v < e.(S);
+}
+
+/*
+bugs/bug151.go:10: illegal types for operand: CALL
+       string
+       S
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug152.go b/gcc/testsuite/go.test/test/fixedbugs/bug152.go
new file mode 100644 (file)
index 0000000..30c3cac
--- /dev/null
@@ -0,0 +1,17 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       s := 0;
+       for _, v := range []int{1} {
+               s += v;
+       }
+       if s != 1 {
+               println("BUG: s =", s);
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug154.go b/gcc/testsuite/go.test/test/fixedbugs/bug154.go
new file mode 100644 (file)
index 0000000..4371cc5
--- /dev/null
@@ -0,0 +1,33 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should not panic
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func f0() string {
+       const f = 3.141592;
+       return fmt.Sprintf("%v", float64(f));
+}
+
+
+func f1() string {
+       const f = 3.141592;
+       x := float64(float32(f));  // appears to change the precision of f
+       _ = x;
+       return fmt.Sprintf("%v", float64(f));
+}
+
+
+func main() {
+       r0 := f0();
+       r1 := f1();
+       if r0 != r1 {
+               println("r0 =", r0);
+               println("r1 =", r1);
+               panic("r0 and r1 should be the same");
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug155.go b/gcc/testsuite/go.test/test/fixedbugs/bug155.go
new file mode 100644 (file)
index 0000000..312c8e6
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A || echo BUG: bug155
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const big uint64 = 1<<63
+
+func f(a uint64) uint64 {
+       return a << big
+}
+
+func main() {
+       f(1)
+}
+
+/*
+main·f: doasm: notfound from=75 to=13 (82)    SHLQ    $-9223372036854775808,BX
+main·f: doasm: notfound from=75 to=13 (82)    SHLQ    $-9223372036854775808,BX
+main·f: doasm: notfound from=75 to=13 (82)    SHLQ    $-9223372036854775808,BX
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug156.go b/gcc/testsuite/go.test/test/fixedbugs/bug156.go
new file mode 100644 (file)
index 0000000..0b77a72
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: bug156
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f(a int64) int64 {
+       const b int64 = 0;
+       n := a &^ b;
+       return n;
+}
+
+func main() {
+       f(1)
+}
+
+/*
+bug156.go:7: constant 18446744073709551615 overflows int64
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug157.go b/gcc/testsuite/go.test/test/fixedbugs/bug157.go
new file mode 100644 (file)
index 0000000..9bf68f7
--- /dev/null
@@ -0,0 +1,32 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() {}
+
+func main() {
+       x := 0;
+
+       // this compiles
+       switch x {
+       case 0: f();
+       default: f();
+       }
+
+       // this doesn't but it should
+       // (semicolons are not needed at the end of a statement list)
+       switch x {
+       case 0: f()
+       default: f()
+       }
+}
+
+
+/*
+bug157.go:20: syntax error near default
+bug157.go:20: first switch statement must be a case
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug158.go b/gcc/testsuite/go.test/test/fixedbugs/bug158.go
new file mode 100644 (file)
index 0000000..cdf3195
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       x := 0;
+
+       // this compiles
+       switch x {
+       case 0:
+       }
+
+       // this doesn't but should
+       switch 0 {
+       case 0:
+       }
+}
+
+
+/*
+bug158.go:14: fatal error: dowidth: unknown type: E-33
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug159.go b/gcc/testsuite/go.test/test/fixedbugs/bug159.go
new file mode 100644 (file)
index 0000000..1aa6443
--- /dev/null
@@ -0,0 +1,39 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug159
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+       ok := true;
+       var a, b, c, x, y, z int;
+       f := func() int { b--; return -b };
+
+       // this fails on 6g: apparently it rewrites
+       // the list into
+       //      z = f();
+       //      y = f();
+       //      x = f();
+       // so that the values come out backward.
+       x, y, z = f(), f(), f();
+       if x != 1 || y != 2 || z != 3 {
+               println("xyz: expected 1 2 3 got", x, y, z);
+               ok = false;
+       }
+
+       // this fails on 6g too.  one of the function calls
+       // happens after assigning to b.
+       a, b, c = f(), f(), f();
+       if a != 4 || b != 5 || c != 6 {
+               println("abc: expected 4 5 6 got", a, b, c);
+               ok = false;
+       }
+
+       if !ok {
+               os.Exit(1);
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug160.dir/x.go b/gcc/testsuite/go.test/test/fixedbugs/bug160.dir/x.go
new file mode 100644 (file)
index 0000000..bd52c6c
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x
+
+const Zero = 0.0
+const Ten = 10.0
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug160.dir/y.go b/gcc/testsuite/go.test/test/fixedbugs/bug160.dir/y.go
new file mode 100644 (file)
index 0000000..27e2f35
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+import "./x"
+
+func main() {
+       if x.Zero != 0 {
+               println("x.Zero = ", x.Zero);
+               os.Exit(1);
+       }
+       if x.Ten != 10 {
+               println("x.Ten = ", x.Ten);
+               os.Exit(1);
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug160.go b/gcc/testsuite/go.test/test/fixedbugs/bug160.go
new file mode 100644 (file)
index 0000000..8fd53ea
--- /dev/null
@@ -0,0 +1,7 @@
+// $G $D/bug160.dir/x.go && $G $D/bug160.dir/y.go && $L y.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+nothing to see here
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug161.go b/gcc/testsuite/go.test/test/fixedbugs/bug161.go
new file mode 100644 (file)
index 0000000..e5f25f7
--- /dev/null
@@ -0,0 +1,17 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package P
+
+const a = 0;
+
+func f(a int) {
+       a = 0;
+}
+
+/*
+bug161.go:8: operation LITERAL not allowed in assignment context
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug163.go b/gcc/testsuite/go.test/test/fixedbugs/bug163.go
new file mode 100644 (file)
index 0000000..919298e
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       x⊛y := 1;     // ERROR "identifier"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug164.go b/gcc/testsuite/go.test/test/fixedbugs/bug164.go
new file mode 100644 (file)
index 0000000..746f631
--- /dev/null
@@ -0,0 +1,17 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Multi-line string literal now allowed.
+
+const s = `
+Hello, World!
+`
+
+func main() {
+       print(s)
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug165.go b/gcc/testsuite/go.test/test/fixedbugs/bug165.go
new file mode 100644 (file)
index 0000000..8ce67a4
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface {
+       m(map[I] bool); // ok
+}
+
+type S struct {
+       m map[S] bool;  // ERROR "map key type"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug167.go b/gcc/testsuite/go.test/test/fixedbugs/bug167.go
new file mode 100644 (file)
index 0000000..729299b
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A || echo BUG: bug167
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f1() {
+       type T struct { x int }
+}
+
+func f2() {
+       type T struct { x float }
+}
+
+func main() {
+       f1();
+       f2();
+}
+
+/*
+1606416576: conflicting definitions for main.T·bug167
+bug167.6:      type main.T·bug167 struct { x int }
+bug167.6:      type main.T·bug167 struct { x float }
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug168.go b/gcc/testsuite/go.test/test/fixedbugs/bug168.go
new file mode 100644 (file)
index 0000000..e25eb56
--- /dev/null
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug168
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var g byte = 123
+var f *byte = &g
+var b = make([]byte, 5)
+
+func main() {
+       b[0:1][0] = *f
+       if b[0] != 123 {
+               println("want 123 got", b[0])
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug169.go b/gcc/testsuite/go.test/test/fixedbugs/bug169.go
new file mode 100644 (file)
index 0000000..c42727f
--- /dev/null
@@ -0,0 +1,10 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+var x = ''';           // ERROR "char"
+
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug170.go b/gcc/testsuite/go.test/test/fixedbugs/bug170.go
new file mode 100644 (file)
index 0000000..e7f1c51
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+var v1 = ([10]int)(nil);       // ERROR "illegal|nil|invalid"
+var v2 [10]int = nil;          // ERROR "illegal|nil|incompatible"
+var v3 [10]int;
+var v4 = nil;  // ERROR "nil"
+func main() {
+       v3 = nil;               // ERROR "illegal|nil|incompatible"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug171.go b/gcc/testsuite/go.test/test/fixedbugs/bug171.go
new file mode 100644 (file)
index 0000000..5357b2a
--- /dev/null
@@ -0,0 +1,10 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() int { }       // ERROR "return|control"
+func g() (foo int) { } // ERROR "return|control"
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug172.go b/gcc/testsuite/go.test/test/fixedbugs/bug172.go
new file mode 100644 (file)
index 0000000..1837a11
--- /dev/null
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() {
+       a := true;
+       a |= a; // ERROR "illegal.*OR|bool|expected"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug173.go b/gcc/testsuite/go.test/test/fixedbugs/bug173.go
new file mode 100644 (file)
index 0000000..898b840
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: bug173
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// these used to fail because the runtime
+// functions that get called to implement them
+// expected string, not T.
+
+package main
+
+type T string
+func main() {
+       var t T = "hello";
+       println(t[0:4], t[4]);
+       for _, _ = range t {
+       }
+       for _ = range t {
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug174.go b/gcc/testsuite/go.test/test/fixedbugs/bug174.go
new file mode 100644 (file)
index 0000000..7ff8655
--- /dev/null
@@ -0,0 +1,12 @@
+// $G $D/$F.go || echo BUG: bug174
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var x uint;
+       println(1<<x);
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug175.go b/gcc/testsuite/go.test/test/fixedbugs/bug175.go
new file mode 100644 (file)
index 0000000..a8f6e3c
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() (int, bool) { return 0, true }
+
+func main() {
+       x, y := f(), 2; // ERROR "multi"
+}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug176.go b/gcc/testsuite/go.test/test/fixedbugs/bug176.go
new file mode 100644 (file)
index 0000000..5820df3
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var x int
+
+var a = []int{ x: 1}   // ERROR "constant"
+var b = [...]int{ x : 1}       // ERROR "constant"
+var c = map[int]int{ x: 1}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug177.go b/gcc/testsuite/go.test/test/fixedbugs/bug177.go
new file mode 100644 (file)
index 0000000..84ff59d
--- /dev/null
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+import "reflect"
+type S1 struct { i int }
+type S2 struct { S1 }
+func main() {
+       typ := reflect.Typeof(S2{}).(*reflect.StructType);
+       f := typ.Field(0);
+       if f.Name != "S1" || f.Anonymous != true {
+               println("BUG: ", f.Name, f.Anonymous);
+               return;
+       }
+       f, ok := typ.FieldByName("S1");
+       if !ok {
+               println("BUG: missing S1");
+               return;
+       }
+       if !f.Anonymous {
+               println("BUG: S1 is not anonymous");
+               return;
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug178.go b/gcc/testsuite/go.test/test/fixedbugs/bug178.go
new file mode 100644 (file)
index 0000000..4f58634
--- /dev/null
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+L:
+       for i := 0; i < 1; i++ {
+L1:
+               for {
+                       break L;
+               }
+               panic("BUG: not reached - break");
+       }
+
+L2:
+       for i := 0; i < 1; i++ {
+L3:
+               for {
+                       continue L2;
+               }
+               panic("BUG: not reached - continue");
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug179.go b/gcc/testsuite/go.test/test/fixedbugs/bug179.go
new file mode 100644 (file)
index 0000000..6754873
--- /dev/null
@@ -0,0 +1,25 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+L:
+       for {
+               for {
+                       break L2;       // ERROR "L2"
+                       continue L2;    // ERROR "L2"
+               }
+       }
+
+L1:
+       x := 1;
+       _ = x;
+       for {
+               break L1;       // ERROR "L1"
+               continue L1;    // ERROR "L1"
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug180.go b/gcc/testsuite/go.test/test/fixedbugs/bug180.go
new file mode 100644 (file)
index 0000000..96823fb
--- /dev/null
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func shift(x int) int { return 1 << (1 << (1 << (uint(x)))) }
+
+func main() {
+       if n := shift(2); n != 1<<(1<<(1<<2)) {
+               println("bad shift", n)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug181.go b/gcc/testsuite/go.test/test/fixedbugs/bug181.go
new file mode 100644 (file)
index 0000000..f87bc9d
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T *struct {
+       T;      // ERROR "embed.*pointer"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug182.go b/gcc/testsuite/go.test/test/fixedbugs/bug182.go
new file mode 100644 (file)
index 0000000..81df2ca
--- /dev/null
@@ -0,0 +1,13 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       x := 0;
+       if x {  // ERROR "x.*int|bool"
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug183.go b/gcc/testsuite/go.test/test/fixedbugs/bug183.go
new file mode 100644 (file)
index 0000000..7fd6e49
--- /dev/null
@@ -0,0 +1,27 @@
+//errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T int
+
+func f() {
+       var x struct { T };
+       var y struct { T T };
+       x = y;  // ERROR "cannot|incompatible"
+       _ = x;
+}
+
+type T1 struct { T }
+type T2 struct { T T }
+
+func g() {
+       var x T1;
+       var y T2;
+       x = y;  // ERROR "cannot|incompatible"
+       _ = x;
+}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug184.go b/gcc/testsuite/go.test/test/fixedbugs/bug184.go
new file mode 100644 (file)
index 0000000..3cc9845
--- /dev/null
@@ -0,0 +1,49 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type Buffer int
+
+func (*Buffer) Read() {}
+
+type Reader interface {
+       Read()
+}
+
+func f() *Buffer { return nil }
+
+func g() Reader {
+       // implicit interface conversion in assignment during return
+       return f()
+}
+
+func h() (b *Buffer, ok bool) { return }
+
+func i() (r Reader, ok bool) {
+       // implicit interface conversion in multi-assignment during return
+       return h()
+}
+
+func fmter() (s string, i int, t string) { return "%#x %q", 100, "hello" }
+
+func main() {
+       b := g()
+       bb, ok := b.(*Buffer)
+       _, _, _ = b, bb, ok
+
+       b, ok = i()
+       bb, ok = b.(*Buffer)
+       _, _, _ = b, bb, ok
+
+       s := fmt.Sprintf(fmter())
+       if s != "0x64 \"hello\"" {
+               println(s)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug185.go b/gcc/testsuite/go.test/test/fixedbugs/bug185.go
new file mode 100644 (file)
index 0000000..acae174
--- /dev/null
@@ -0,0 +1,35 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func g() {}
+
+func f1() (a, b int) {
+       a, b = 2, 1
+       g() // defeat optimizer
+       return a, b
+}
+
+func f2() (a, b int) {
+       a, b = 1, 2
+       g() // defeat optimizer
+       return b, a
+}
+
+func main() {
+       x, y := f1()
+       if x != 2 || y != 1 {
+               println("f1", x, y)
+               panic("fail")
+       }
+
+       x, y = f2()
+       if x != 2 || y != 1 {
+               println("f2", x, y)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug186.go b/gcc/testsuite/go.test/test/fixedbugs/bug186.go
new file mode 100644 (file)
index 0000000..dde794a
--- /dev/null
@@ -0,0 +1,17 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const X = iota
+
+func f(x int) { }
+
+func main() {
+       f(X);
+       f(iota);        // ERROR "iota"
+       f(X);
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug187.go b/gcc/testsuite/go.test/test/fixedbugs/bug187.go
new file mode 100644 (file)
index 0000000..66aa5f0
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+       // This bug doesn't arise with [...]int, or []interface{} or [3]interface{}.
+       a := [...]interface{} { 1, 2, 3 };
+       n := 1;
+       for _, v := range a {
+               if v.(int) != n {
+                       println("BUG:", n, v.(int));
+                       os.Exit(0);
+               }
+               n++;
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug188.go b/gcc/testsuite/go.test/test/fixedbugs/bug188.go
new file mode 100644 (file)
index 0000000..e1cbce0
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "sort"
+
+func main() {
+       sort.Sort(nil);
+       var x int;
+       sort(x);        // ERROR "package"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug189.go b/gcc/testsuite/go.test/test/fixedbugs/bug189.go
new file mode 100644 (file)
index 0000000..ce33830
--- /dev/null
@@ -0,0 +1,18 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S struct {
+       a, b int
+}
+
+func main() {
+       s1 := S{a: 7};  // ok - field is named
+       s3 := S{7, 11}; // ok - all fields have values
+       s2 := S{7};     // ERROR "too few"
+       _, _, _ = s1, s3, s2;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug190.go b/gcc/testsuite/go.test/test/fixedbugs/bug190.go
new file mode 100644 (file)
index 0000000..da0bfde
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S struct {
+       p *S;
+       s []S;
+       m map[int] S;
+       c chan S;
+       i interface { f(S); };
+       f func(S) S;
+}
+
+func main() {
+       var s S;
+       s.p = &s;
+       s.s = make([]S, 1);
+       s.s[0] = s;
+       s.m[0] = s;
+       s.c <- s;
+       s.i.f(s);
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug191.dir/a.go b/gcc/testsuite/go.test/test/fixedbugs/bug191.dir/a.go
new file mode 100644 (file)
index 0000000..b87ad6f
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func init() {
+       println("a");
+}
+
+type T int;
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug191.dir/b.go b/gcc/testsuite/go.test/test/fixedbugs/bug191.dir/b.go
new file mode 100644 (file)
index 0000000..3e780ac
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+func init() {
+       println("b");
+}
+
+type V int;
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug191.go b/gcc/testsuite/go.test/test/fixedbugs/bug191.go
new file mode 100644 (file)
index 0000000..44fcccf
--- /dev/null
@@ -0,0 +1,16 @@
+// $G $D/bug191.dir/a.go && $G $D/bug191.dir/b.go && $G $D/$F.go && $L $F.$A
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import . "./a"
+import . "./b"
+
+var _ T
+var _ V
+
+func main() {
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug192.go b/gcc/testsuite/go.test/test/fixedbugs/bug192.go
new file mode 100644 (file)
index 0000000..282ed30
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"   // GCCGO_ERROR "previous"
+
+var fmt int    // ERROR "redecl|redefinition"
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug193.go b/gcc/testsuite/go.test/test/fixedbugs/bug193.go
new file mode 100644 (file)
index 0000000..f6b03e1
--- /dev/null
@@ -0,0 +1,16 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       s := uint(10);
+       ss := 1<<s;
+       y1 := float(ss);
+       y2 := float(1<<s);  // ERROR "shift"
+       y3 := string(1<<s);  // ERROR "shift"
+       _, _, _, _, _ = s, ss, y1, y2, y3;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug194.go b/gcc/testsuite/go.test/test/fixedbugs/bug194.go
new file mode 100644 (file)
index 0000000..dcd633d
--- /dev/null
@@ -0,0 +1,35 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG should compile and run
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var v1 = T1(1)
+var v2 = T2{2}
+var v3 = T3{0: 3, 1: 4}
+var v4 = T4{0: 5, 1: 6}
+var v5 = T5{0: 7, 1: 8}
+var v6 = T2{f: 9}
+var v7 = T4{f: 10}
+var v8 = T5{f: 11}
+var pf func(T1)
+
+func main() {
+       if v1 != 1 || v2.f != 2 || v3[0] != 3 || v3[1] != 4 ||
+               v4[0] != 5 || v4[1] != 6 || v5[0] != 7 || v5[1] != 8 ||
+               v6.f != 9 || v7[0] != 10 || v8[0] != 11 {
+               panic("fail")
+       }
+}
+
+type T1 int
+type T2 struct {
+       f int
+}
+type T3 []int
+type T4 [2]int
+type T5 map[int]int
+
+const f = 0
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug195.go b/gcc/testsuite/go.test/test/fixedbugs/bug195.go
new file mode 100644 (file)
index 0000000..65ab02a
--- /dev/null
@@ -0,0 +1,27 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I1 interface { I2 }       // ERROR "interface"
+type I2 int
+
+type I3 interface { int }      // ERROR "interface"
+
+type S struct {
+       x interface{ S }        // ERROR "interface"
+}
+type I4 interface {
+       I4      // ERROR "interface"
+}
+
+type I5 interface {
+       I6      // GCCGO_ERROR "interface"
+}
+
+type I6 interface {
+       I5      // GC_ERROR "interface"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug196.go b/gcc/testsuite/go.test/test/fixedbugs/bug196.go
new file mode 100644 (file)
index 0000000..ea8ab0d
--- /dev/null
@@ -0,0 +1,50 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug196
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var m = map[int]int{0: 0, 1: 0}
+var nf = 0
+var i int
+
+func multi() (int, int) { return 1, 2 }
+
+func xxx() {
+       var c chan int
+       x, ok := <-c
+
+       var m map[int]int
+       x, ok = m[1]
+
+       var i interface{}
+       var xx int
+       xx, ok = i.(int)
+
+       a, b := multi()
+
+       _, _, _, _, _ = x, ok, xx, a, b
+}
+
+func f() map[int]int {
+       nf++
+       return m
+}
+
+func g() *int {
+       nf++
+       return &i
+}
+
+func main() {
+       f()[0]++
+       f()[1] += 2
+       *g() %= 2
+       if nf != 3 {
+               println("too many calls:", nf)
+               panic("fail")
+       }
+
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug197.go b/gcc/testsuite/go.test/test/fixedbugs/bug197.go
new file mode 100644 (file)
index 0000000..c205c5b
--- /dev/null
@@ -0,0 +1,33 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T int
+type U int
+
+var x int
+
+var t T = int(0)       // ERROR "cannot use|incompatible"
+var t1 T = int(x)      // ERROR "cannot use|incompatible"
+var u U = int(0)       // ERROR "cannot use|incompatible"
+var u1 U = int(x)      // ERROR "cannot use|incompatible"
+
+type S string
+var s S
+
+var s1 = s + "hello"
+var s2 = "hello" + s
+var s3 = s + string("hello")   // ERROR "invalid operation|incompatible"
+var s4 = string("hello") + s   // ERROR "invalid operation|incompatible"
+
+var r string
+
+var r1 = r + "hello"
+var r2 = "hello" + r
+var r3 = r + string("hello")
+var r4 = string("hello") + r
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug198.go b/gcc/testsuite/go.test/test/fixedbugs/bug198.go
new file mode 100644 (file)
index 0000000..ea71fad
--- /dev/null
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+func f(a T) T { return a }     // ERROR "undefined"
+func main() {
+       x := f(0);
+       _ = x;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug199.go b/gcc/testsuite/go.test/test/fixedbugs/bug199.go
new file mode 100644 (file)
index 0000000..7122629
--- /dev/null
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S struct {
+       a []int
+}
+
+var s = &S{make([]int, 10)}
+
+func main() {
+       s.a[f()] = 1 // 6g used to call f twice here
+}
+
+var n int
+
+func f() int {
+       if n++; n > 1 {
+               println("f twice")
+               panic("fail")
+       }
+       return 0
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug200.go b/gcc/testsuite/go.test/test/fixedbugs/bug200.go
new file mode 100644 (file)
index 0000000..123f687
--- /dev/null
@@ -0,0 +1,19 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       // 6g used to compile these as two different
+       // hash codes so it missed the duplication
+       // and worse, compiled the wrong code
+       // for one of them.
+       var x interface{};
+       switch v := x.(type) {
+       case func(int):
+       case func(f int):       // ERROR "duplicate"
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug201.go b/gcc/testsuite/go.test/test/fixedbugs/bug201.go
new file mode 100644 (file)
index 0000000..f7db62f
--- /dev/null
@@ -0,0 +1,48 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T1 struct {
+       x, y int
+}
+type T2 struct {
+       z, w byte
+}
+type T3 T1
+
+type MyInt int
+
+func (MyInt) m(*T1) {}
+
+func main() {
+       {
+               var i interface{} = new(T1)
+               _, ok1 := i.(*T1)
+               _, ok2 := i.(*T2)
+               _, ok3 := i.(*T3)
+               if !ok1 || ok2 || ok3 {
+                       println("*T1", ok1, ok2, ok3)
+                       panic("fail")
+               }
+       }
+       {
+               var i interface{} = MyInt(0)
+               _, ok1 := i.(interface {
+                       m(*T1)
+               })
+               _, ok2 := i.(interface {
+                       m(*T2)
+               })
+               _, ok3 := i.(interface {
+                       m(*T3)
+               })
+               if !ok1 || ok2 || ok3 {
+                       println("T", ok1, ok2, ok3)
+                       panic("fail")
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug202.go b/gcc/testsuite/go.test/test/fixedbugs/bug202.go
new file mode 100644 (file)
index 0000000..2fc91b5
--- /dev/null
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG should run
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+func f() {
+       v := [...]string{"a", "b"};
+       _ = v;
+}
+func main() {
+       f();
+}
+
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug203.go b/gcc/testsuite/go.test/test/fixedbugs/bug203.go
new file mode 100644 (file)
index 0000000..bf86ee9
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var s [8]string
+
+func
+init() {
+       s = [...]string{ "now", "is", "the", "time", "to", "fix", "this", "bug"}
+}
+
+func
+main() {
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug204.go b/gcc/testsuite/go.test/test/fixedbugs/bug204.go
new file mode 100644 (file)
index 0000000..d4534c2
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       nchar := 0;
+       a := []int { '日', '本', '語', 0xFFFD };
+       for _, char := range "日本語\xc0" {
+               if nchar >= len(a) {
+                       println("BUG");
+                       break;
+               }
+               if char != a[nchar] {
+                       println("expected", a[nchar], "got", char);
+                       println("BUG");
+                       break;
+               }
+               nchar++;
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug205.go b/gcc/testsuite/go.test/test/fixedbugs/bug205.go
new file mode 100644 (file)
index 0000000..4262ec1
--- /dev/null
@@ -0,0 +1,18 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var t []int
+var s string;
+var m map[string]int;
+
+func main() {
+       println(t["hi"]);       // ERROR "integer"
+       println(s["hi"]);       // ERROR "integer"
+       println(m[0]);  // ERROR "map index"
+}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug206.go b/gcc/testsuite/go.test/test/fixedbugs/bug206.go
new file mode 100644 (file)
index 0000000..3879e8c
--- /dev/null
@@ -0,0 +1,48 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out >/dev/null 2>&1 || echo BUG: bug206
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/ast";
+
+func g(list []ast.Expr) {
+       n := len(list)-1;
+       println(list[n].Pos().Line);
+}
+
+
+// f is the same as g except that the expression assigned to n is inlined.
+func f(list []ast.Expr) {
+       // n := len(list)-1;
+       println(list[len(list)-1 /* n */].Pos().Line);
+}
+
+
+func main() {
+       list := []ast.Expr{&ast.Ident{}};
+       g(list);  // this works
+       f(list);  // this doesn't
+}
+
+
+/*
+0
+throw: index out of range
+
+panic PC=0x2bcf10
+throw+0x33 /home/gri/go/src/pkg/runtime/runtime.c:71
+       throw(0x470f8, 0x0)
+sys·throwindex+0x1c /home/gri/go/src/pkg/runtime/runtime.c:45
+       sys·throwindex()
+main·f+0x26 /home/gri/go/test/bugs/bug206.go:16
+       main·f(0x2b9560, 0x0)
+main·main+0xc3 /home/gri/go/test/bugs/bug206.go:23
+       main·main()
+mainstart+0xf /home/gri/go/src/pkg/runtime/amd64/asm.s:55
+       mainstart()
+goexit /home/gri/go/src/pkg/runtime/proc.c:133
+       goexit()
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug207.go b/gcc/testsuite/go.test/test/fixedbugs/bug207.go
new file mode 100644 (file)
index 0000000..5810d66
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// used to panic because 6g didn't generate
+// the code to fill in the ... argument to fmt.Sprint.
+
+package main
+
+import "fmt"
+
+type T struct {
+       a, b, c, d, e []int;
+}
+
+var t T
+
+func main() {
+       if fmt.Sprint("xxx", t) != "yyy" { 
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug208.go b/gcc/testsuite/go.test/test/fixedbugs/bug208.go
new file mode 100644 (file)
index 0000000..13b0400
--- /dev/null
@@ -0,0 +1,20 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type   T struct
+{
+       f int;
+}
+
+// 6g used to get confused by the f:1 above
+// and allow uses of f that would be silently
+// dropped during the compilation.
+var _ = f;     // ERROR "undefined"
+
+var _ = T{f: 1}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug209.go b/gcc/testsuite/go.test/test/fixedbugs/bug209.go
new file mode 100644 (file)
index 0000000..ae6f10f
--- /dev/null
@@ -0,0 +1,18 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var buf [10]int;
+       for ; len(buf); {  // ERROR "bool"
+       }
+}
+
+/*
+uetli:/home/gri/go/test/bugs gri$ 6g bug209.go
+bug209.go:5: Bus error
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug211.go b/gcc/testsuite/go.test/test/fixedbugs/bug211.go
new file mode 100644 (file)
index 0000000..69aeeee
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type R interface { duplicate() }
+type S interface { duplicate() }
+type T interface { R; S }      // ERROR "duplicate"
+
+func main() {
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug212.go b/gcc/testsuite/go.test/test/fixedbugs/bug212.go
new file mode 100644 (file)
index 0000000..51df9b8
--- /dev/null
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+type I int
+type S struct { f map[I]int }
+var v1 = S{ make(map[int]int) }                // ERROR "cannot|illegal|incompatible|wrong"
+var v2 map[I]int = map[int]int{}       // ERROR "cannot|illegal|incompatible|wrong"
+var v3 = S{ make(map[uint]int) }       // ERROR "cannot|illegal|incompatible|wrong"
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug213.go b/gcc/testsuite/go.test/test/fixedbugs/bug213.go
new file mode 100644 (file)
index 0000000..07d9f90
--- /dev/null
@@ -0,0 +1,16 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+func main() {
+       var v interface{} = 0;
+       switch x := v.(type) {
+       case int:
+               fallthrough;            // ERROR "fallthrough"
+       default:
+               panic("fell through");
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug214.go b/gcc/testsuite/go.test/test/fixedbugs/bug214.go
new file mode 100644 (file)
index 0000000..502e698
--- /dev/null
@@ -0,0 +1,15 @@
+// $G $D/$F.go || echo BUG: bug214
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to crash the compiler.
+// http://code.google.com/p/go/issues/detail?id=88
+
+package main
+
+func main() {
+       x := make(map[int]int, 10);
+       x[0], x[1] = 2, 6;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug215.go b/gcc/testsuite/go.test/test/fixedbugs/bug215.go
new file mode 100644 (file)
index 0000000..8f7fb2d
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to crash the compiler.
+// http://code.google.com/p/go/issues/detail?id=158
+
+package main
+
+type A struct {        a A }   // ERROR "recursive"
+func foo()             { new(A).bar() }
+func (a A) bar()       {}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug216.go b/gcc/testsuite/go.test/test/fixedbugs/bug216.go
new file mode 100644 (file)
index 0000000..76f8546
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go || echo BUG: bug216
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to be rejected
+// http://code.google.com/p/go/issues/detail?id=188
+
+package main
+
+func complexSqrt(i int) (int, int)     { return 0, 1 }
+
+var re, im = complexSqrt(-1)
+
+func main() {
+       if re != 0 || im != 1 {
+               println("BUG: bug216: want 0,-1 have ", re, im)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug217.go b/gcc/testsuite/go.test/test/fixedbugs/bug217.go
new file mode 100644 (file)
index 0000000..98334c4
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to crash
+// http://code.google.com/p/go/issues/detail?id=204
+
+package main
+
+func () x()    // ERROR "no receiver"
+
+func (a b, c d) x()    // ERROR "multiple receiver"
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug218.go b/gcc/testsuite/go.test/test/fixedbugs/bug218.go
new file mode 100644 (file)
index 0000000..b2c9ede
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go || echo BUG: bug218
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Crashes 6g, 8g
+// http://code.google.com/p/go/issues/detail?id=238
+
+package main
+
+func main() {
+       bar := make(chan bool);
+       select {
+       case _ = <-bar:
+               return
+       }
+}
+
+/*
+6g bug218.go 
+<epoch>: fatal error: dowidth: unknown type: blank
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug219.go b/gcc/testsuite/go.test/test/fixedbugs/bug219.go
new file mode 100644 (file)
index 0000000..21361a2
--- /dev/null
@@ -0,0 +1,38 @@
+// $G $D/$F.go || echo BUG: bug219
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f(func()) int { return 0 }
+
+// this doesn't work:
+// bug219.go:16: syntax error near if
+func g1() {
+       if x := f(func() {
+               if {}
+       }); {
+               _ = x;
+       }
+}
+
+// this works
+func g2() {
+       if x := f(func() {
+               //if {}
+       }); {
+               _ = x;
+       }
+}
+
+// this works
+func g3() {
+       x := f(func() {
+               if {}
+       });
+       if {
+               _ = x;
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug220.go b/gcc/testsuite/go.test/test/fixedbugs/bug220.go
new file mode 100644 (file)
index 0000000..3f8aaa4
--- /dev/null
@@ -0,0 +1,14 @@
+// $G $D/$F.go || echo BUG: bug220
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       m := make(map[int]map[uint]float);
+       
+       m[0] = make(map[uint]float), false;     // 6g used to reject this
+       m[1] = nil;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug221.go b/gcc/testsuite/go.test/test/fixedbugs/bug221.go
new file mode 100644 (file)
index 0000000..b645831
--- /dev/null
@@ -0,0 +1,42 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// function call arg reordering was picking out 1 call that
+// didn't need to be in a temporary, but it was picking
+// out the first call instead of the last call.
+// http://code.google.com/p/go/issues/detail?id=370
+
+package main
+
+var gen = 'a'
+
+func f(n int) string {
+       s := string(gen) + string(n+'A'-1)
+       gen++
+       return s
+}
+
+func g(x, y string) string {
+       return x + y
+}
+
+func main() {
+       s := f(1) + f(2)
+       if s != "aAbB" {
+               println("BUG: bug221a: ", s)
+               panic("fail")
+       }
+       s = g(f(3), f(4))
+       if s != "cCdD" {
+               println("BUG: bug221b: ", s)
+               panic("fail")
+       }
+       s = f(5) + f(6) + f(7) + f(8) + f(9)
+       if s != "eEfFgGhHiI" {
+               println("BUG: bug221c: ", s)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug222.dir/chanbug.go b/gcc/testsuite/go.test/test/fixedbugs/bug222.dir/chanbug.go
new file mode 100644 (file)
index 0000000..9194927
--- /dev/null
@@ -0,0 +1,5 @@
+package chanbug
+var C chan<- (chan int)
+var D chan<- func()
+var E func() chan int
+var F func() (func())
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug222.dir/chanbug2.go b/gcc/testsuite/go.test/test/fixedbugs/bug222.dir/chanbug2.go
new file mode 100644 (file)
index 0000000..73e1667
--- /dev/null
@@ -0,0 +1,2 @@
+package Bar
+import _ "chanbug"
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug222.go b/gcc/testsuite/go.test/test/fixedbugs/bug222.go
new file mode 100644 (file)
index 0000000..5c23a53
--- /dev/null
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/chanbug.go && $G -I. $D/$F.dir/chanbug2.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ignored
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug223.go b/gcc/testsuite/go.test/test/fixedbugs/bug223.go
new file mode 100644 (file)
index 0000000..80f9cae
--- /dev/null
@@ -0,0 +1,21 @@
+// (! $G $D/$F.go) | grep 'initialization loop' >/dev/null || echo BUG: bug223
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// check that initialization loop is diagnosed
+// and that closure cannot be used to hide it.
+// error message is not standard format, so no errchk above.
+
+package main
+
+type F func()
+
+func f() {
+       if true {
+               _ = func() { _ = m }
+       }
+}
+
+var m = map[string]F{"f": f}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug224.go b/gcc/testsuite/go.test/test/fixedbugs/bug224.go
new file mode 100644 (file)
index 0000000..11ee57e
--- /dev/null
@@ -0,0 +1,10 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T T               // ERROR "recursive"
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug225.go b/gcc/testsuite/go.test/test/fixedbugs/bug225.go
new file mode 100644 (file)
index 0000000..8acf66c
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {  
+       c := make(chan bool, 1);
+       select {
+       case _ = <-c:
+               panic("BUG: recv should not");
+       default:
+       }
+       c <- true;
+       select {
+       case _ = <-c:
+       default:
+               panic("BUG: recv should");
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug226.dir/x.go b/gcc/testsuite/go.test/test/fixedbugs/bug226.dir/x.go
new file mode 100644 (file)
index 0000000..64d7a29
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x
+
+type T struct { x, Y int }
+
+func (t T) M()
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go b/gcc/testsuite/go.test/test/fixedbugs/bug226.dir/y.go
new file mode 100644 (file)
index 0000000..01e8b7b
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package y
+
+import "./x"
+
+func f() {
+       ok := new(x.T);
+       var ok1 x.T;
+       ok2 := &ok1;
+       ok3 := &x.T{};
+       ok4 := &x.T{Y:2};
+       _ = x.T{};
+       _ = x.T{Y:2};
+       
+       ok1.M();        // ERROR "assignment.*T"
+       bad1 := *ok;    // ERROR "assignment.*T"
+       bad2 := ok1;    // ERROR "assignment.*T"
+       *ok4 = ok1;     // ERROR "assignment.*T"
+       *ok4 = *ok2;    // ERROR "assignment.*T"
+       ok1 = *ok4;     // ERROR "assignment.*T"
+       _ = bad1;
+       _ = bad2;
+       _ = ok4;
+       _ = ok3;
+       _ = ok2;
+       _ = ok1;
+       _ = ok;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug226.go b/gcc/testsuite/go.test/test/fixedbugs/bug226.go
new file mode 100644 (file)
index 0000000..5457a64
--- /dev/null
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/x.go && errchk $G $D/$F.dir/y.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ignored
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug227.go b/gcc/testsuite/go.test/test/fixedbugs/bug227.go
new file mode 100644 (file)
index 0000000..a608660
--- /dev/null
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var (
+       nf      int
+       x, y, z = f(), f(), f()
+       m       = map[string]string{"a": "A"}
+       a, aok  = m["a"]
+       b, bok  = m["b"]
+)
+
+func look(s string) (string, bool) {
+       x, ok := m[s]
+       return x, ok
+}
+
+func f() int {
+       nf++
+       return nf
+}
+
+func main() {
+       if nf != 3 || x != 1 || y != 2 || z != 3 {
+               println("nf=", nf, " x=", x, " y=", y)
+               panic("fail")
+       }
+       if a != "A" || aok != true || b != "" || bok != false {
+               println("a=", a, " aok=", aok, " b=", b, " bok=", bok)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug228.go b/gcc/testsuite/go.test/test/fixedbugs/bug228.go
new file mode 100644 (file)
index 0000000..81bc908
--- /dev/null
@@ -0,0 +1,19 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f(x int, y ...int)        // ok
+
+func g(x int, y float) (...)   // ERROR "[.][.][.]"
+
+func h(x, y ...int)            // ERROR "[.][.][.]"
+
+func i(x int, y ...int, z float)       // ERROR "[.][.][.]"
+
+var x ...int;          // ERROR "[.][.][.]|syntax|type"
+
+type T ...int;         // ERROR "[.][.][.]|syntax|type"
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug229.go b/gcc/testsuite/go.test/test/fixedbugs/bug229.go
new file mode 100644 (file)
index 0000000..fe0f0d8
--- /dev/null
@@ -0,0 +1,20 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "testing"
+
+func main() {
+       var t testing.T
+       
+       // make sure error mentions that
+       // ch is unexported, not just "ch not found".
+
+       t.ch = nil      // ERROR "unexported"
+       
+       println(testing.anyLowercaseName("asdf"))       // ERROR "unexported"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug230.go b/gcc/testsuite/go.test/test/fixedbugs/bug230.go
new file mode 100644 (file)
index 0000000..81b256e
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S string
+type I int
+type F float
+
+func (S) m() {}
+func (I) m() {}
+func (F) m() {}
+
+func main() {
+       c := make(chan interface { m() }, 10)
+       c <- I(0)
+       c <- F(1)
+       c <- S("hi")
+       <-c
+       <-c
+       <-c
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug231.go b/gcc/testsuite/go.test/test/fixedbugs/bug231.go
new file mode 100644 (file)
index 0000000..91996d3
--- /dev/null
@@ -0,0 +1,22 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface { m() }
+type T struct { m func() }
+type M struct {}
+func (M) m() {}
+
+func main() {
+       var t T
+       var m M
+       var i I
+       
+       i = m
+       i = t   // ERROR "not a method|has no methods"
+       _ = i
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug232.go b/gcc/testsuite/go.test/test/fixedbugs/bug232.go
new file mode 100644 (file)
index 0000000..99bd02f
--- /dev/null
@@ -0,0 +1,8 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+type I interface { X(...int) }
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug233.go b/gcc/testsuite/go.test/test/fixedbugs/bug233.go
new file mode 100644 (file)
index 0000000..31bb673
--- /dev/null
@@ -0,0 +1,10 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+import p "fmt"
+var _ = p.Print
+var fmt = 10
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug234.go b/gcc/testsuite/go.test/test/fixedbugs/bug234.go
new file mode 100644 (file)
index 0000000..b806ca6
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       c := make(chan int, 1)
+       c <- 100
+       x, ok := <-c
+       if x != 100 || !ok {
+               println("x=", x, " ok=", ok, " want 100, true")
+               panic("fail")
+       }
+       x, ok = <-c
+       if x != 0 || ok {
+               println("x=", x, " ok=", ok, " want 0, false")
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug235.go b/gcc/testsuite/go.test/test/fixedbugs/bug235.go
new file mode 100644 (file)
index 0000000..8cecd9d
--- /dev/null
@@ -0,0 +1,17 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// used to crash the compiler
+
+package main
+
+type T struct {
+       x [4]byte
+}
+
+var p *T
+var v = *p
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug236.go b/gcc/testsuite/go.test/test/fixedbugs/bug236.go
new file mode 100644 (file)
index 0000000..895f82a
--- /dev/null
@@ -0,0 +1,53 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var gen = 'a'
+
+func f(n int) string {
+       s := string(gen) + string(n+'A'-1)
+       gen++
+       return s
+}
+
+func g(x, y string) string { return x + y }
+
+var v1 = f(1) + f(2)
+var v2 = g(f(3), f(4))
+var v3 = f(5) + f(6) + f(7) + f(8) + f(9)
+
+func main() {
+       gen = 'a'
+
+       if v1 != "aAbB" {
+               panic("BUG: bug236a")
+       }
+       if v2 != "cCdD" {
+               panic("BUG: bug236b")
+       }
+       if v3 != "eEfFgGhHiI" {
+               panic("BUG: bug236c")
+       }
+
+       switch "aAbB" {
+       case f(1) + f(2):
+       default:
+               panic("BUG: bug236d")
+       }
+
+       switch "cCdD" {
+       case g(f(3), f(4)):
+       default:
+               panic("BUG: bug236e")
+       }
+
+       switch "eEfFgGhHiI" {
+       case f(5) + f(6) + f(7) + f(8) + f(9):
+       default:
+               panic("BUG: bug236f")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug237.go b/gcc/testsuite/go.test/test/fixedbugs/bug237.go
new file mode 100644 (file)
index 0000000..55cc86a
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+var indent uint = 10
+func main() {
+       const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +
+               ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
+       const n = uint(len(dots))
+       i := 2 * indent
+       var s string
+       for ; i > n; i -= n {
+               s += fmt.Sprint(dots)
+       }
+       s += dots[0:i]
+       if s != ". . . . . . . . . . " {
+               panic(s)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug238.go b/gcc/testsuite/go.test/test/fixedbugs/bug238.go
new file mode 100644 (file)
index 0000000..8b7c7ac
--- /dev/null
@@ -0,0 +1,22 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 471. This file shouldn't compile.
+
+package main
+
+const a *int = 1        // ERROR "convert|wrong|invalid"
+const b [2]int = 2      // ERROR "convert|wrong|invalid"
+const c map[int]int = 3 // ERROR "convert|wrong|invalid"
+const d chan int = 4    // ERROR "convert|wrong|invalid"
+const e func() = 5      // ERROR "convert|wrong|invalid"
+const f struct{} = 6    // ERROR "convert|wrong|invalid"
+const g interface{} = 7 // ERROR "constant|wrong|invalid"
+const h bool = false
+const i int = 2
+const j float = 5
+
+func main() { println(a, b, c, d, e, f, g) }
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug239.go b/gcc/testsuite/go.test/test/fixedbugs/bug239.go
new file mode 100644 (file)
index 0000000..32c3d7e
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: bug239
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 475. This file should compile.
+
+package main
+
+import . "unsafe"
+
+func main() {
+       var x int
+       println(Sizeof(x))
+}
+
+/*
+bug239.go:11: imported and not used: unsafe
+bug239.go:15: undefined: Sizeof
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug240.go b/gcc/testsuite/go.test/test/fixedbugs/bug240.go
new file mode 100644 (file)
index 0000000..6cba9c8
--- /dev/null
@@ -0,0 +1,20 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import . "unsafe"      // ERROR "not used"
+
+func main() {
+       var x int
+       println(unsafe.Sizeof(x)) // ERROR "undefined"
+}
+
+/*
+After a '.' import, "unsafe" shouldn't be defined as
+an identifier. 6g complains correctly for imports other
+than "unsafe".
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug241.go b/gcc/testsuite/go.test/test/fixedbugs/bug241.go
new file mode 100644 (file)
index 0000000..172b374
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const c = 3
+var x = c.String()     // ERROR "String"
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug242.go b/gcc/testsuite/go.test/test/fixedbugs/bug242.go
new file mode 100644 (file)
index 0000000..5c21eaa
--- /dev/null
@@ -0,0 +1,131 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: tuple evaluation order
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test order of evaluation in tuple assignments.
+
+package main
+
+var i byte = 0
+var a [30]byte
+
+func f() *byte {
+       i++
+       return &a[i-1]
+}
+func gbyte() byte {
+       i++
+       return 'a' + i - 1
+}
+func gint() byte {
+       i++
+       return i - 1
+}
+func x() (byte, byte) {
+       i++
+       return 'a' + i - 1, 'a' + i - 1
+}
+func e1(c chan byte, expected byte) chan byte {
+       if i != expected {
+               println("e1: got", i, "expected", expected)
+               panic("fail")
+       }
+       i++
+       return c
+}
+
+type Empty interface{}
+type I interface {
+       Get() byte
+}
+type S1 struct {
+       i byte
+}
+
+func (p S1) Get() byte { return p.i }
+
+type S2 struct {
+       i byte
+}
+
+func e2(p Empty, expected byte) Empty {
+       if i != expected {
+               println("e2: got", i, "expected", expected)
+               panic("fail")
+       }
+       i++
+       return p
+}
+func e3(p *I, expected byte) *I {
+       if i != expected {
+               println("e3: got", i, "expected", expected)
+               panic("fail")
+       }
+       i++
+       return p
+}
+
+func main() {
+       for i := range a {
+               a[i] = ' '
+       }
+
+       // 0     1     2     3        4        5
+       *f(), *f(), *f() = gbyte(), gbyte(), gbyte()
+
+       // 6     7     8
+       *f(), *f() = x()
+
+       m := make(map[byte]byte)
+       m[10] = 'A'
+       var p1, p2 bool
+       // 9           10
+       *f(), p1 = m[gint()]
+       // 11          12
+       *f(), p2 = m[gint()]
+       a[11] += '0'
+       if !p1 || p2 {
+               println("bad map check", i, p1, p2)
+               panic("fail")
+       }
+
+       m[13] = 'B'
+       //  13        14
+       m[gint()] = gbyte(), false
+       if _, present := m[13]; present {
+               println("bad map removal")
+               panic("fail")
+       }
+
+       c := make(chan byte, 1)
+       c <- 'C'
+       // 15          16
+       *f(), p1 = <-e1(c, 16)
+       // 17          18
+       *f(), p2 = <-e1(c, 18)
+       a[17] += '0'
+       if !p1 || p2 {
+               println("bad chan check", i, p1, p2)
+               panic("fail")
+       }
+
+       s1 := S1{'D'}
+       s2 := S2{'E'}
+       var iv I
+       // 19                20
+       *e3(&iv, 19), p1 = e2(s1, 20).(I)
+       // 21                22
+       *e3(&iv, 21), p2 = e2(s2, 22).(I)
+       if !p1 || p2 {
+               println("bad interface check", i, p1, p2)
+               panic("fail")
+       }
+
+       s := string(a[0:i])
+       if s != "def   ii A 0   C 0     " {
+               println("bad array results:", s)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug243.go b/gcc/testsuite/go.test/test/fixedbugs/bug243.go
new file mode 100644 (file)
index 0000000..357f22e
--- /dev/null
@@ -0,0 +1,26 @@
+// [ $GOOS != nacl ] || exit 0  # no network
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "net"
+)
+
+func main() {
+       var listen, _ = net.Listen("tcp", "127.0.0.1:0")
+
+       go func() {
+               for {
+                       var conn, _ = listen.Accept()
+                       _ = conn
+               }
+       }()
+
+       var conn, _ = net.Dial("tcp", "", listen.Addr().String())
+       _ = conn
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug244.go b/gcc/testsuite/go.test/test/fixedbugs/bug244.go
new file mode 100644 (file)
index 0000000..915c3fc
--- /dev/null
@@ -0,0 +1,31 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var nf int
+var ng int
+
+func f() (int, int, int) {
+       nf++
+       return 1, 2, 3
+}
+
+func g() int {
+       ng++
+       return 4
+}
+
+var x, y, z = f()
+var m = make(map[int]int)
+var v, ok = m[g()]
+
+func main() {
+       if x != 1 || y != 2 || z != 3 || nf != 1 || v != 0 || ok != false || ng != 1 {
+               println("x=", x, " y=", y, " z=", z, " nf=", nf, " v=", v, " ok=", ok, " ng=", ng)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug245.go b/gcc/testsuite/go.test/test/fixedbugs/bug245.go
new file mode 100644 (file)
index 0000000..6e5a8b3
--- /dev/null
@@ -0,0 +1,16 @@
+// $G $D/$F.go || echo BUG: bug245
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T []int
+func (t T) m()
+
+func main() {
+       _ = T{}
+}
+
+// bug245.go:14: fatal error: method mismatch: T for T
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug246.go b/gcc/testsuite/go.test/test/fixedbugs/bug246.go
new file mode 100644 (file)
index 0000000..12041eb
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug246
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+func main() {
+       // works
+       addr := uintptr(0x234)
+       x1 := (*int)(unsafe.Pointer(addr))
+
+       // fails
+       x2 := (*int)(unsafe.Pointer(uintptr(0x234)))
+
+       if x1 != x2 {
+               println("mismatch", x1, x2)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug247.go b/gcc/testsuite/go.test/test/fixedbugs/bug247.go
new file mode 100644 (file)
index 0000000..2f56b88
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug247
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       const (
+               Delta = 100 * 1e6
+               Count = 10
+       )
+       _ = int64(Delta * Count)
+       var i interface{} = Count
+       j := i.(int)
+       if j != Count {
+               println("j=", j)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug0.go b/gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug0.go
new file mode 100644 (file)
index 0000000..7fc7401
--- /dev/null
@@ -0,0 +1,9 @@
+package p
+
+type T struct {
+       X, Y int
+}
+
+type I interface {
+       M(T)
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug1.go b/gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug1.go
new file mode 100644 (file)
index 0000000..7fc7401
--- /dev/null
@@ -0,0 +1,9 @@
+package p
+
+type T struct {
+       X, Y int
+}
+
+type I interface {
+       M(T)
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug2.go b/gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug2.go
new file mode 100644 (file)
index 0000000..68c0ce0
--- /dev/null
@@ -0,0 +1,101 @@
+package main
+
+import (
+       p0 "./bug0"
+       p1 "./bug1"
+
+       "reflect"
+       "strings"
+)
+
+var v0 p0.T
+var v1 p1.T
+
+type I0 interface {
+       M(p0.T)
+}
+
+type I1 interface {
+       M(p1.T)
+}
+
+type t0 int
+
+func (t0) M(p0.T) {}
+
+type t1 float
+
+func (t1) M(p1.T) {}
+
+var i0 I0 = t0(0) // ok
+var i1 I1 = t1(0) // ok
+
+var p0i p0.I = t0(0) // ok
+var p1i p1.I = t1(0) // ok
+
+func main() {
+       // check that reflect paths are correct,
+       // meaning that reflect data for v0, v1 didn't get confused.
+
+       // path is full (rooted) path name.  check suffix for gc, prefix for gccgo
+       if s := reflect.Typeof(v0).PkgPath(); !strings.HasSuffix(s, "/bug0") && !strings.HasPrefix(s, "bug0") {
+               println("bad v0 path", len(s), s)
+               panic("fail")
+       }
+       if s := reflect.Typeof(v1).PkgPath(); !strings.HasSuffix(s, "/bug1") && !strings.HasPrefix(s, "bug1") {
+               println("bad v1 path", s)
+               panic("fail")
+       }
+
+       // check that dynamic interface check doesn't get confused
+       var i interface{} = t0(0)
+       if _, ok := i.(I1); ok {
+               println("used t0 as i1")
+               panic("fail")
+       }
+       if _, ok := i.(p1.I); ok {
+               println("used t0 as p1.I")
+               panic("fail")
+       }
+
+       i = t1(1)
+       if _, ok := i.(I0); ok {
+               println("used t1 as i0")
+               panic("fail")
+       }
+       if _, ok := i.(p0.I); ok {
+               println("used t1 as p0.I")
+               panic("fail")
+       }
+
+       // check that type switch works.
+       // the worry is that if p0.T and p1.T have the same hash,
+       // the binary search will handle one of them incorrectly.
+       for j := 0; j < 3; j++ {
+               switch j {
+               case 0:
+                       i = p0.T{}
+               case 1:
+                       i = p1.T{}
+               case 2:
+                       i = 3.14
+               }
+               switch k := i.(type) {
+               case p0.T:
+                       if j != 0 {
+                               println("type switch p0.T")
+                               panic("fail")
+                       }
+               case p1.T:
+                       if j != 1 {
+                               println("type switch p1.T")
+                               panic("fail")
+                       }
+               default:
+                       if j != 2 {
+                               println("type switch default", j)
+                               panic("fail")
+                       }
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug3.go b/gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug3.go
new file mode 100644 (file)
index 0000000..c96bf16
--- /dev/null
@@ -0,0 +1,69 @@
+package main
+
+import (
+       p0 "./bug0"
+       p1 "./bug1"
+)
+
+// both p0.T and p1.T are struct { X, Y int }.
+
+var v0 p0.T
+var v1 p1.T
+
+// interfaces involving the two
+
+type I0 interface {
+       M(p0.T)
+}
+
+type I1 interface {
+       M(p1.T)
+}
+
+// t0 satisfies I0 and p0.I
+type t0 int
+
+func (t0) M(p0.T) {}
+
+// t1 satisfies I1 and p1.I
+type t1 float
+
+func (t1) M(p1.T) {}
+
+// check static interface assignments
+var i0 I0 = t0(0) // ok
+var i1 I1 = t1(0) // ok
+
+var i2 I0 = t1(0) // ERROR "does not implement|incompatible"
+var i3 I1 = t0(0) // ERROR "does not implement|incompatible"
+
+var p0i p0.I = t0(0) // ok
+var p1i p1.I = t1(0) // ok
+
+var p0i1 p0.I = t1(0) // ERROR "does not implement|incompatible"
+var p0i2 p1.I = t0(0) // ERROR "does not implement|incompatible"
+
+func main() {
+       // check that cannot assign one to the other,
+       // but can convert.
+       v0 = v1 // ERROR "assign"
+       v1 = v0 // ERROR "assign"
+
+       v0 = p0.T(v1)
+       v1 = p1.T(v0)
+
+       i0 = i1   // ERROR "cannot use|incompatible"
+       i1 = i0   // ERROR "cannot use|incompatible"
+       p0i = i1  // ERROR "cannot use|incompatible"
+       p1i = i0  // ERROR "cannot use|incompatible"
+       i0 = p1i  // ERROR "cannot use|incompatible"
+       i1 = p0i  // ERROR "cannot use|incompatible"
+       p0i = p1i // ERROR "cannot use|incompatible"
+       p1i = p0i // ERROR "cannot use|incompatible"
+
+       i0 = p0i
+       p0i = i0
+
+       i1 = p1i
+       p1i = i1
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug248.go b/gcc/testsuite/go.test/test/fixedbugs/bug248.go
new file mode 100644 (file)
index 0000000..055bf1f
--- /dev/null
@@ -0,0 +1,12 @@
+// $G $D/$F.dir/bug0.go &&
+// $G $D/$F.dir/bug1.go &&
+// $G $D/$F.dir/bug2.go &&
+// errchk $G -e $D/$F.dir/bug3.go &&
+// $L bug2.$A &&
+// ./$A.out || echo BUG: failed to compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ignored
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug249.go b/gcc/testsuite/go.test/test/fixedbugs/bug249.go
new file mode 100644 (file)
index 0000000..c85708f
--- /dev/null
@@ -0,0 +1,39 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var c1 chan <- chan int = (chan<- (chan int))(nil)
+var c2 chan <- chan int = (chan (<-chan int))(nil)  // ERROR "chan|incompatible"
+var c3 <- chan chan int = (<-chan (chan int))(nil)
+var c4 chan chan <- int = (chan (chan<- int))(nil)
+
+var c5 <- chan <- chan int = (<-chan (<-chan int))(nil)
+var c6 chan <- <- chan int = (chan<- (<-chan int))(nil)
+var c7 chan <- chan <- int = (chan<- (chan<- int))(nil)
+
+var c8 <- chan <- chan chan int = (<-chan (<-chan (chan int)))(nil)
+var c9 <- chan chan <- chan int = (<-chan (chan<- (chan int)))(nil)
+var c10 chan <- <- chan chan int = (chan<- (<-chan (chan int)))(nil)
+var c11 chan <- chan <- chan int = (chan<- (chan<- (chan int)))(nil)
+var c12 chan chan <- <- chan int = (chan (chan<- (<-chan int)))(nil)
+var c13 chan chan <- chan <- int = (chan (chan<- (chan<- int)))(nil)
+
+var r1 chan<- (chan int) = (chan <- chan int)(nil)
+var r2 chan (<-chan int) = (chan <- chan int)(nil)  // ERROR "chan|incompatible"
+var r3 <-chan (chan int) = (<- chan chan int)(nil)
+var r4 chan (chan<- int) = (chan chan <- int)(nil)
+
+var r5 <-chan (<-chan int) = (<- chan <- chan int)(nil)
+var r6 chan<- (<-chan int) = (chan <- <- chan int)(nil)
+var r7 chan<- (chan<- int) = (chan <- chan <- int)(nil)
+
+var r8 <-chan (<-chan (chan int)) = (<- chan <- chan chan int)(nil)
+var r9 <-chan (chan<- (chan int)) = (<- chan chan <- chan int)(nil)
+var r10 chan<- (<-chan (chan int)) = (chan <- <- chan chan int)(nil)
+var r11 chan<- (chan<- (chan int)) = (chan <- chan <- chan int)(nil)
+var r12 chan (chan<- (<-chan int)) = (chan chan <- <- chan int)(nil)
+var r13 chan (chan<- (chan<- int)) = (chan chan <- chan <- int)(nil)
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug250.go b/gcc/testsuite/go.test/test/fixedbugs/bug250.go
new file mode 100644 (file)
index 0000000..cd28642
--- /dev/null
@@ -0,0 +1,19 @@
+// $G $D/$F.go || echo BUG: bug250
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I1 interface {
+       m() I2
+}
+
+type I2 interface {
+       I1
+}
+
+var i1 I1 = i2
+var i2 I2
+var i2a I2 = i1
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug251.go b/gcc/testsuite/go.test/test/fixedbugs/bug251.go
new file mode 100644 (file)
index 0000000..c94ad2a
--- /dev/null
@@ -0,0 +1,21 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I1 interface {
+       m() I2
+       I2 // GCCGO_ERROR "loop|interface"
+}
+
+type I2 interface {
+       I1 // GC_ERROR "loop|interface"
+}
+
+
+var i1 I1 = i2 // GC_ERROR "missing m method|need type assertion"
+var i2 I2
+var i2a I2 = i1
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug252.go b/gcc/testsuite/go.test/test/fixedbugs/bug252.go
new file mode 100644 (file)
index 0000000..bd11b86
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f(args ...int) {
+       g(args) // ERROR "[.][.][.] mismatch"
+}
+
+func g(args ...interface{}) {
+       f(args) // ERROR "[.][.][.] mismatch"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug253.go b/gcc/testsuite/go.test/test/fixedbugs/bug253.go
new file mode 100644 (file)
index 0000000..bb5b770
--- /dev/null
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug253
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S1 struct {
+       i int
+}
+type S2 struct {
+       i int
+}
+type S3 struct {
+       S1
+       S2
+}
+type S4 struct {
+       S3
+       S1
+}
+
+func main() {
+       var s4 S4
+       if s4.i != 0 { // .i refers to s4.S1.i, unambiguously
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug254.go b/gcc/testsuite/go.test/test/fixedbugs/bug254.go
new file mode 100644 (file)
index 0000000..c0c7f24
--- /dev/null
@@ -0,0 +1,17 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug254
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a [10]int
+var b [1e1]int
+
+func main() {
+       if len(a) != 10 || len(b) != 10 {
+               println("len", len(a), len(b))
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug255.go b/gcc/testsuite/go.test/test/fixedbugs/bug255.go
new file mode 100644 (file)
index 0000000..44427cf
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a [10]int  // ok
+var b [1e1]int // ok
+var c [1.5]int // ERROR "truncated"
+var d ["abc"]int       // ERROR "invalid array bound|not numeric"
+var e [nil]int // ERROR "invalid array bound|not numeric"
+var f [e]int   // ERROR "invalid array bound|not constant"
+var g [1<<65]int       // ERROR "overflows"
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug256.go b/gcc/testsuite/go.test/test/fixedbugs/bug256.go
new file mode 100644 (file)
index 0000000..37fa5f5
--- /dev/null
@@ -0,0 +1,16 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T U       // bogus "invalid recursive type T" from 6g
+type U int
+
+const x T = 123
+
+type V V       // ERROR "invalid recursive type"
+
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug257.go b/gcc/testsuite/go.test/test/fixedbugs/bug257.go
new file mode 100644 (file)
index 0000000..713c424
--- /dev/null
@@ -0,0 +1,20070 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bugxxx
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// very long strings, string concatenation
+
+package main
+
+import (
+       "crypto/md5"
+       "fmt"
+       "io"
+)
+
+const data = `
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+`
+
+var gettysburg = "  Four score and seven years ago our fathers brought forth on\n" +
+       "this continent, a new nation, conceived in Liberty, and dedicated\n" +
+       "to the proposition that all men are created equal.\n" +
+       "  Now we are engaged in a great Civil War, testing whether that\n" +
+       "nation, or any nation so conceived and so dedicated, can long\n" +
+       "endure.\n" +
+       "  We are met on a great battle-field of that war.\n" +
+       "  We have come to dedicate a portion of that field, as a final\n" +
+       "resting place for those who here gave their lives that that\n" +
+       "nation might live.  It is altogether fitting and proper that\n" +
+       "we should do this.\n" +
+       "  But, in a larger sense, we can not dedicate — we can not\n" +
+       "consecrate — we can not hallow — this ground.\n" +
+       "  The brave men, living and dead, who struggled here, have\n" +
+       "consecrated it, far above our poor power to add or detract.\n" +
+       "The world will little note, nor long remember what we say here,\n" +
+       "but it can never forget what they did here.\n" +
+       "  It is for us the living, rather, to be dedicated here to the\n" +
+       "unfinished work which they who fought here have thus far so\n" +
+       "nobly advanced.  It is rather for us to be here dedicated to\n" +
+       "the great task remaining before us — that from these honored\n" +
+       "dead we take increased devotion to that cause for which they\n" +
+       "gave the last full measure of devotion —\n" +
+       "  that we here highly resolve that these dead shall not have\n" +
+       "died in vain — that this nation, under God, shall have a new\n" +
+       "birth of freedom — and that government of the people, by the\n" +
+       "people, for the people, shall not perish from this earth.\n" +
+       "\n" +
+       "Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania\n"
+
+
+func main() {
+       m := md5.New()
+       io.WriteString(m, data)
+       hash := fmt.Sprintf("%x", m.Sum())
+       if hash != "525f06bc62a65017cd2217d7584e5920" {
+               println("BUG a", hash)
+               return
+       }
+
+       m = md5.New()
+       io.WriteString(m, gettysburg)
+       hash = fmt.Sprintf("%x", m.Sum())
+       if hash != "d7ec5d9d47a4d166091e8d9ebd7ea0aa" {
+               println("BUG gettysburg", hash)
+               println(len(gettysburg))
+               fmt.Println(gettysburg)
+               return
+       }
+
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug258.go b/gcc/testsuite/go.test/test/fixedbugs/bug258.go
new file mode 100644 (file)
index 0000000..8984df5
--- /dev/null
@@ -0,0 +1,33 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "math"
+
+func f() float64 {
+       math.Pow(2, 2)
+       return 1
+}
+
+func main() {
+       for i := 0; i < 10; i++ {
+               // 386 float register bug used to load constant before call
+               if -5 < f() {
+               } else {
+                       println("BUG 1")
+                       return
+               }
+               if f() > -7 {
+               } else {
+                       println("BUG 2")
+               }
+               
+               if math.Pow(2, 3) != 8 {
+                       println("BUG 3")
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug259.go b/gcc/testsuite/go.test/test/fixedbugs/bug259.go
new file mode 100644 (file)
index 0000000..d148fb3
--- /dev/null
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+var x = uint32(0x01020304)
+var y = [...]uint32{1,2,3,4,5}
+
+func main() {
+       fmt.Sprint(y[byte(x)])
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug261.go b/gcc/testsuite/go.test/test/fixedbugs/bug261.go
new file mode 100644 (file)
index 0000000..8c3fda1
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var n int
+
+func f() int {
+       n++
+       return n
+}
+
+func main() {
+       x := []int{0,1,2,3,4,5,6,7,8,9,10}
+       n = 5
+       y := x[f():f()]
+       if len(y) != 1 || y[0] != 6 {
+               println("BUG bug261", len(y), y[0])
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug262.go b/gcc/testsuite/go.test/test/fixedbugs/bug262.go
new file mode 100644 (file)
index 0000000..66f580b
--- /dev/null
@@ -0,0 +1,54 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "os"
+       "strconv"
+)
+
+var trace string
+
+func f() string {
+       trace += "f"
+       return "abc"
+}
+
+func g() *os.Error {
+       trace += "g"
+       var x os.Error
+       return &x
+}
+
+func h() string {
+       trace += "h"
+       return "123"
+}
+
+func i() *int {
+       trace += "i"
+       var i int
+       return &i
+}
+
+
+func main() {
+       m := make(map[string]int)
+       m[f()], *g() = strconv.Atoi(h())
+       if m["abc"] != 123 || trace != "fgh" {
+               println("BUG", m["abc"], trace)
+               panic("fail")
+       }
+       mm := make(map[string]os.Error)
+       trace = ""
+       mm["abc"] = os.EINVAL
+       *i(), mm[f()] = strconv.Atoi(h())
+       if mm["abc"] != nil || trace != "ifh" {
+               println("BUG1", mm["abc"], trace)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug263.go b/gcc/testsuite/go.test/test/fixedbugs/bug263.go
new file mode 100644 (file)
index 0000000..cab986a
--- /dev/null
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       data := make(map[int]string, 1)
+       data[0] = "hello, "
+       data[0] += "world!"
+       if data[0] != "hello, world!" {
+               panic("BUG: " + data[0])
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug264.go b/gcc/testsuite/go.test/test/fixedbugs/bug264.go
new file mode 100644 (file)
index 0000000..6d86c6f
--- /dev/null
@@ -0,0 +1,44 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for http://code.google.com/p/go/issues/detail?id=692
+
+package main
+
+var fooCount = 0
+var barCount = 0
+var balCount = 0
+
+func foo() (int, int) {
+       fooCount++
+       return 0, 0
+}
+
+func bar() (int, int) {
+       barCount++
+       return 0, 0
+}
+
+func bal() (int, int) {
+       balCount++
+       return 0, 0
+}
+
+var a, b = foo() // foo is called once
+var c, _ = bar() // bar is called twice
+var _, _ = bal() // bal is called twice
+
+func main() {
+       if fooCount != 1 {
+               panic("fooCount != 1")
+       }
+       if barCount != 1 {
+               panic("barCount != 1")
+       }
+       if balCount != 1 {
+               panic("balCount != 1")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug265.go b/gcc/testsuite/go.test/test/fixedbugs/bug265.go
new file mode 100644 (file)
index 0000000..55f32ec
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for http://code.google.com/p/go/issues/detail?id=700
+
+package main
+
+import "os"
+
+func f() (e int) {
+       _ = &e
+       return 999
+}
+
+func main() {
+       if f() != 999 {
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug266.go b/gcc/testsuite/go.test/test/fixedbugs/bug266.go
new file mode 100644 (file)
index 0000000..25c246f
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug266
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() int {
+       defer func() {
+               recover()
+       }()
+       panic("oops")
+}
+
+func g() int { 
+       return 12345
+}
+
+func main() {
+       g()     // leave 12345 on stack
+       x := f()
+       if x != 0 {
+               panic(x)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug267.go b/gcc/testsuite/go.test/test/fixedbugs/bug267.go
new file mode 100644 (file)
index 0000000..9646142
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go || echo BUG
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T []int
+
+var a []bool
+
+func _() {
+       if a[T{42}[0]] {
+       }
+       // if (a[T{42}[0]]) {}  // this compiles
+}
+
+/*
+6g bugs/bug267.go
+bugs/bug267.go:14: syntax error: unexpected {, expecting :
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug268.go b/gcc/testsuite/go.test/test/fixedbugs/bug268.go
new file mode 100644 (file)
index 0000000..a38d054
--- /dev/null
@@ -0,0 +1,53 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=745
+
+package main
+
+type T1 struct {
+       T2 *T2
+}
+
+type T2 struct {
+       T3 *T3
+}
+
+type T3 struct {
+       T4 []*T4
+}
+
+type T4 struct {
+       X int
+}
+
+func f() *T1 {
+       x := &T1{
+               &T2{
+                       &T3{
+                               [1]*T4{
+                                       &T4{5},
+                               }[0:],
+                       },
+               },
+       }
+       return x
+}
+
+func g(x int) {
+       if x == 0 {
+               return
+       }
+       g(x-1)
+}
+
+func main() {
+       x := f()
+       g(100) // smash temporaries left over on stack
+       if x.T2.T3.T4[0].X != 5 {
+               println("BUG", x.T2.T3.T4[0].X)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug269.go b/gcc/testsuite/go.test/test/fixedbugs/bug269.go
new file mode 100644 (file)
index 0000000..4cc0408
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=749
+
+package main
+
+func f() (ok bool) { return false }
+
+func main() {
+       var i interface{}
+       i = f
+       _ = i.(func()bool)
+       _ = i.(func()(bool))
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug270.go b/gcc/testsuite/go.test/test/fixedbugs/bug270.go
new file mode 100644 (file)
index 0000000..a9cda7b
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=746
+
+package main
+
+type I interface { F() }
+
+type T struct{}
+
+func (T) F() {}
+
+func main() {
+       switch I(T{}).(type) {
+       case interface{}:
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug271.go b/gcc/testsuite/go.test/test/fixedbugs/bug271.go
new file mode 100644 (file)
index 0000000..ba93d93
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=662
+
+package main
+
+import "fmt"
+
+func f() (int, int) { return 1, 2 }
+
+func main() {
+       s := fmt.Sprint(f())
+       if s != "1 2" { // with bug, was "{1 2}"
+               println("BUG")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug272.go b/gcc/testsuite/go.test/test/fixedbugs/bug272.go
new file mode 100644 (file)
index 0000000..3b7c466
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=589
+
+package main
+
+func main() {  
+       n := int64(100)
+       x := make([]int, n)
+       x[99] = 234;    
+       z := x[n-1]
+       if z != 234 {
+               println("BUG")
+       }
+       n |= 1<<32
+       defer func() {
+               recover()
+       }()
+       z = x[n-1]
+       println("BUG2")
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug273.go b/gcc/testsuite/go.test/test/fixedbugs/bug273.go
new file mode 100644 (file)
index 0000000..816f69e
--- /dev/null
@@ -0,0 +1,101 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=589
+
+package main
+
+import "unsafe"
+
+var bug = false
+
+var minus1 = -1
+var big int64 = 10 | 1<<32
+
+var g1 []int
+
+func shouldfail(f func(), desc string) {
+       defer func() { recover() }()
+       f()
+       if !bug {
+               println("BUG")
+               bug = true
+       }
+       println("didn't crash: ", desc)
+}
+
+func badlen() {
+       g1 = make([]int, minus1)
+}
+
+func biglen() {
+       g1 = make([]int, big)
+}
+
+func badcap() {
+       g1 = make([]int, 10, minus1)
+}
+
+func badcap1() {
+       g1 = make([]int, 10, 5)
+}
+
+func bigcap() {
+       g1 = make([]int, 10, big)
+}
+
+const (
+       addrBits = 8*uint(unsafe.Sizeof((*byte)(nil)))
+       sh = addrBits/2 - 2
+)
+var g2 [][1<<sh][1<<sh]byte
+func overflow() {
+       g2 = make([][1<<sh][1<<sh]byte, 64)
+}
+
+var g3 map[int]int
+func badmapcap() {
+       g3 = make(map[int]int, minus1)
+}
+
+func bigmapcap() {
+       g3 = make(map[int]int, big)
+}
+
+var g4 chan int
+func badchancap() {
+       g4 = make(chan int, minus1)
+}
+
+func bigchancap() {
+       g4 = make(chan int, big)
+}
+
+var g5 chan [1<<15]byte
+func overflowchan() {
+       if addrBits == 32 {
+               g5 = make(chan [1<<15]byte, 1<<20)
+       } else {
+               // cannot overflow on 64-bit, because
+               // int is 32 bits and max chan value size
+               // in the implementation is 64 kB.
+               panic(1)
+       }
+}
+
+func main() {
+       shouldfail(badlen, "badlen")
+       shouldfail(biglen, "biglen")
+       shouldfail(badcap, "badcap")
+       shouldfail(badcap1, "badcap1")
+       shouldfail(bigcap, "bigcap")
+       shouldfail(overflow, "overflow")
+       shouldfail(badmapcap, "badmapcap")
+       shouldfail(bigmapcap, "bigmapcap")
+       shouldfail(badchancap, "badchancap")
+       shouldfail(bigchancap, "bigchancap")
+       shouldfail(overflowchan, "overflowchan")
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug274.go b/gcc/testsuite/go.test/test/fixedbugs/bug274.go
new file mode 100644 (file)
index 0000000..621f31e
--- /dev/null
@@ -0,0 +1,29 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// 6g accepts the program below even though it is syntactically incorrect:
+// Each statement in the list of statements for each case clause must be
+// terminated with a semicolon. No semicolon is present for the labeled
+// statements and because the last token is a colon ":", no semicolon is
+// inserted automatically.
+//
+// Both gccgo and gofmt correctly refuse this program as is and accept it
+// when the semicolons are present.
+
+// This is a test case for issue 777 ( http://code.google.com/p/go/issues/detail?id=777 ).
+
+package main
+
+func main() {
+       switch 0 {
+       case 0:
+               L0:  // ERROR "statement"
+       case 1:
+               L1:  // ERROR "statement"
+       default:
+               L2:  // correct since no semicolon is required before a '}'
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug275.go b/gcc/testsuite/go.test/test/fixedbugs/bug275.go
new file mode 100644 (file)
index 0000000..2bbc807
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a test case for issue 788.
+
+package main
+
+func main() {
+       var a [1]complex64
+
+       t := a[0]
+       _ = real(t) // this works
+
+       _ = real(a[0]) // this doesn't
+}
+
+// bug275.go:17: internal compiler error: subnode not addable
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug276.go b/gcc/testsuite/go.test/test/fixedbugs/bug276.go
new file mode 100644 (file)
index 0000000..844a6b2
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG code should run
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 789. The bug only appeared for GOARCH=386.
+
+package main
+
+func main() {
+       i := 0
+       x := 0
+
+       a := (x & 1) << uint(1-i)
+       
+       s := uint(1-i)
+       b := (x & 1) << s
+       
+       if a != b {
+               panic(0)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug277.go b/gcc/testsuite/go.test/test/fixedbugs/bug277.go
new file mode 100644 (file)
index 0000000..22b2908
--- /dev/null
@@ -0,0 +1,72 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test cases for conversion syntax.
+
+package main
+
+type (
+       A [3]int
+       S struct {
+               x int
+       }
+       P *S
+       F func(x int) int
+       I interface {
+               m(x int) int
+       }
+       L []int
+       M map[string]int
+       C chan int
+)
+
+func (s S) m(x int) int { return x }
+
+var (
+       a A = [...]int{1, 2, 3}
+       s S = struct{ x int }{0}
+       p P = &s
+       f F = func(x int) int { return x }
+       i I = s
+       l L = []int{}
+       m M = map[string]int{"foo": 0}
+       c C = make(chan int)
+)
+
+func main() {
+       a = A(a)
+       a = [3]int(a)
+       s = struct {
+               x int
+       }(s)
+       p = (*S)(p)
+       f = func(x int) int(f)
+       i = (interface {
+               m(x int) int
+       })(s) // this is accepted by 6g
+       i = interface {
+               m(x int) int
+       }(s) // this is not accepted by 6g (but should be)
+       l = []int(l)
+       m = map[string]int(m)
+       c = chan int(c)
+       _ = chan<- int(c)
+       _ = <-(chan int)(c)
+       _ = <-(<-chan int)(c)
+}
+
+/*
+6g bug277.go
+bug277.go:46: syntax error: unexpected (, expecting {
+bug277.go:50: syntax error: unexpected interface
+bug277.go:53: non-declaration statement outside function body
+bug277.go:54: non-declaration statement outside function body
+bug277.go:55: syntax error: unexpected LCHAN
+bug277.go:56: syntax error: unexpected LCHAN
+bug277.go:57: non-declaration statement outside function body
+bug277.go:58: non-declaration statement outside function body
+bug277.go:59: syntax error: unexpected }
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug278.go b/gcc/testsuite/go.test/test/fixedbugs/bug278.go
new file mode 100644 (file)
index 0000000..3699b9a
--- /dev/null
@@ -0,0 +1,23 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a test case for issue 804.
+
+package main
+
+func f() [10]int {
+       return [10]int{}
+}
+
+var m map[int][10]int
+
+func main() {
+       f()[1] = 2      // ERROR "cannot|invalid"
+       f()[2:3][0] = 4 // ERROR "cannot|addressable"
+       var x = "abc"
+       x[2] = 3        // ERROR "cannot|invalid"
+       m[0][5] = 6  // ERROR "cannot|invalid"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug279.go b/gcc/testsuite/go.test/test/fixedbugs/bug279.go
new file mode 100644 (file)
index 0000000..af8e056
--- /dev/null
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=799
+
+package main
+
+import "unsafe"
+
+func main() {
+       n := unsafe.Sizeof(0)
+       if n != 4 && n != 8 {
+               println("BUG sizeof 0", n)
+               return
+       }
+       n = unsafe.Alignof(0)
+       if n != 4 && n != 8 {
+               println("BUG alignof 0", n)
+               return
+       }
+       
+       n = unsafe.Sizeof("")
+       if n != 8 && n != 16 {
+               println("BUG sizeof \"\"", n)
+               return
+       }
+       n = unsafe.Alignof("")
+       if n != 4 && n != 8 {
+               println("BUG alignof \"\"", n)
+               return
+       }
+}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug280.go b/gcc/testsuite/go.test/test/fixedbugs/bug280.go
new file mode 100644 (file)
index 0000000..869d446
--- /dev/null
@@ -0,0 +1,13 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=808
+
+package main
+
+type A [...]int        // ERROR "outside of array literal"
+
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug281.go b/gcc/testsuite/go.test/test/fixedbugs/bug281.go
new file mode 100644 (file)
index 0000000..821b028
--- /dev/null
@@ -0,0 +1,55 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=807
+
+package main
+
+type Point struct {
+       X, Y int64
+}
+
+type Rect struct {
+       Min, Max Point
+}
+
+func (p Point) Sub(q Point) Point {
+       return Point{p.X-q.X, p.Y-q.Y}
+}
+
+type Obj struct {
+       bbox Rect
+}
+
+func (o *Obj) Bbox() Rect {
+       return o.bbox
+}
+
+func (o *Obj) Points() [2]Point{
+       return [2]Point{o.bbox.Min, o.bbox.Max}
+}
+
+var x = 0
+
+func main() {
+       o := &Obj{Rect{Point{800, 0}, Point{}}}
+       p := Point{800, 300}
+       q := p.Sub(o.Bbox().Min)
+       if q.X != 0 || q.Y != 300 {
+               println("BUG dot: ", q.X, q.Y)
+               return
+       }
+       
+       q = p.Sub(o.Points()[0])
+       if q.X != 0 || q.Y != 300 {
+               println("BUG index const: ", q.X, q.Y)
+       }
+       
+       q = p.Sub(o.Points()[x])
+       if q.X != 0 || q.Y != 300 {
+               println("BUG index var: ", q.X, q.Y)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug282.dir/p1.go b/gcc/testsuite/go.test/test/fixedbugs/bug282.dir/p1.go
new file mode 100644 (file)
index 0000000..b562755
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p1
+
+type T struct {
+       f func() "x"
+}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug282.dir/p2.go b/gcc/testsuite/go.test/test/fixedbugs/bug282.dir/p2.go
new file mode 100644 (file)
index 0000000..3f8bd9d
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p2
+
+import _ "./p1"
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug282.go b/gcc/testsuite/go.test/test/fixedbugs/bug282.go
new file mode 100644 (file)
index 0000000..463f21e
--- /dev/null
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/p1.go && $G $D/$F.dir/p2.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ignored
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug283.go b/gcc/testsuite/go.test/test/fixedbugs/bug283.go
new file mode 100644 (file)
index 0000000..45ee908
--- /dev/null
@@ -0,0 +1,19 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=806
+// triggered out of registers on 8g
+
+package main
+
+type Point struct {
+       x int
+       y int
+}
+
+func dist(p0, p1 Point) float64 {
+       return float64((p0.x-p1.x)*(p0.x-p1.x) + (p0.y-p1.y)*(p0.y-p1.y))
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug284.go b/gcc/testsuite/go.test/test/fixedbugs/bug284.go
new file mode 100644 (file)
index 0000000..bcf161e
--- /dev/null
@@ -0,0 +1,191 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test cases for revised conversion rules.
+
+package main
+
+func main() {
+       type NewInt int
+       i0 := 0
+       var i1 int = 1
+       var i2 NewInt = 1
+       i0 = i0
+       i0 = i1
+       i0 = int(i2)
+       i1 = i0
+       i1 = i1
+       i1 = int(i2)
+       i2 = NewInt(i0)
+       i2 = NewInt(i1)
+       i2 = i2
+
+       type A1 [3]int
+       type A2 [3]NewInt
+       var a0 [3]int
+       var a1 A1
+       var a2 A2
+       a0 = a0
+       a0 = a1
+       a0 = [3]int(a2) // ERROR "cannot|invalid"
+       a1 = a0
+       a1 = a1
+       a1 = A1(a2) // ERROR "cannot|invalid"
+       a2 = A2(a0) // ERROR "cannot|invalid"
+       a2 = A2(a1) // ERROR "cannot|invalid"
+       a2 = a2
+
+       type S1 struct {
+               x int
+       }
+       type S2 struct {
+               x NewInt
+       }
+       var s0 struct {
+               x int
+       }
+       var s1 S1
+       var s2 S2
+       s0 = s0
+       s0 = s1
+       s0 = struct {
+               x int
+       }(s2) // ERROR "cannot|invalid"
+       s1 = s0
+       s1 = s1
+       s1 = S1(s2) // ERROR "cannot|invalid"
+       s2 = S2(s0) // ERROR "cannot|invalid"
+       s2 = S2(s1) // ERROR "cannot|invalid"
+       s2 = s2
+
+       type P1 *int
+       type P2 *NewInt
+       var p0 *int
+       var p1 P1
+       var p2 P2
+       p0 = p0
+       p0 = p1
+       p0 = (*int)(p2) // ERROR "cannot|invalid"
+       p1 = p0
+       p1 = p1
+       p1 = P1(p2) // ERROR "cannot|invalid"
+       p2 = P2(p0) // ERROR "cannot|invalid"
+       p2 = P2(p1) // ERROR "cannot|invalid"
+       p2 = p2
+
+       type Q1 *struct {
+               x int
+       }
+       type Q2 *S1
+       var q0 *struct {
+               x int
+       }
+       var q1 Q1
+       var q2 Q2
+       var ps1 *S1
+       q0 = q0
+       q0 = q1
+       q0 = (*struct {
+               x int
+       })(ps1) // legal because of special conversion exception for pointers
+       q0 = (*struct {
+               x int
+       })(q2) // ERROR "cannot|invalid"
+       q1 = q0
+       q1 = q1
+       q1 = Q1(q2)    // ERROR "cannot|invalid"
+       q2 = (*S1)(q0) // legal because of special conversion exception for pointers
+       q2 = Q2(q1)    // ERROR "cannot|invalid"
+       q2 = q2
+
+       type F1 func(x NewInt) int
+       type F2 func(x int) NewInt
+       var f0 func(x NewInt) int
+       var f1 F1
+       var f2 F2
+       f0 = f0
+       f0 = f1
+       f0 = func(x NewInt) int(f2) // ERROR "cannot|invalid"
+       f1 = f0
+       f1 = f1
+       f1 = F1(f2) // ERROR "cannot|invalid"
+       f2 = F2(f0) // ERROR "cannot|invalid"
+       f2 = F2(f1) // ERROR "cannot|invalid"
+       f2 = f2
+
+       type X1 interface {
+               f() int
+       }
+       type X2 interface {
+               f() NewInt
+       }
+       var x0 interface {
+               f() int
+       }
+       var x1 X1
+       var x2 X2
+       x0 = x0
+       x0 = x1
+       x0 = interface {
+               f() int
+       }(x2) // ERROR "cannot|need type assertion|incompatible"
+       x1 = x0
+       x1 = x1
+       x1 = X1(x2) // ERROR "cannot|need type assertion|incompatible"
+       x2 = X2(x0) // ERROR "cannot|need type assertion|incompatible"
+       x2 = X2(x1) // ERROR "cannot|need type assertion|incompatible"
+       x2 = x2
+
+       type L1 []int
+       type L2 []NewInt
+       var l0 []int
+       var l1 L1
+       var l2 L2
+       l0 = l0
+       l0 = l1
+       l0 = []int(l2) // ERROR "cannot|invalid"
+       l1 = l0
+       l1 = l1
+       l1 = L1(l2) // ERROR "cannot|invalid"
+       l2 = L2(l0) // ERROR "cannot|invalid"
+       l2 = L2(l1) // ERROR "cannot|invalid"
+       l2 = l2
+
+       type M1 map[string]int
+       type M2 map[string]NewInt
+       var m0 []int
+       var m1 L1
+       var m2 L2
+       m0 = m0
+       m0 = m1
+       m0 = []int(m2) // ERROR "cannot|invalid"
+       m1 = m0
+       m1 = m1
+       m1 = L1(m2) // ERROR "cannot|invalid"
+       m2 = L2(m0) // ERROR "cannot|invalid"
+       m2 = L2(m1) // ERROR "cannot|invalid"
+       m2 = m2
+
+       type C1 chan int
+       type C2 chan NewInt
+       var c0 chan int
+       var c1 C1
+       var c2 C2
+       c0 = c0
+       c0 = c1
+       c0 = chan int(c2) // ERROR "cannot|invalid"
+       c1 = c0
+       c1 = c1
+       c1 = C1(c2) // ERROR "cannot|invalid"
+       c2 = C2(c0) // ERROR "cannot|invalid"
+       c2 = C2(c1) // ERROR "cannot|invalid"
+       c2 = c2
+
+       // internal compiler error (6g and gccgo)
+       type T interface{}
+       var _ T = 17 // assignment compatible
+       _ = T(17)    // internal compiler error even though assignment compatible
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug285.go b/gcc/testsuite/go.test/test/fixedbugs/bug285.go
new file mode 100644 (file)
index 0000000..544d348
--- /dev/null
@@ -0,0 +1,116 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug285
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test for issue 778: Map key values that are assignment
+// compatible with the map key type must be accepted according
+// to the spec: http://golang.org/doc/go_spec.html#Indexes .
+
+package main
+
+type T2 struct {
+       x int
+}
+
+func (t *T2) f() int { return t.x }
+
+func main() {
+       type B bool
+       b := B(false)
+       mb := make(map[B]int)
+       mb[false] = 42 // this should work: false is assignment compatible with B
+       mb[b] = 42
+
+       type Z int
+       z := Z(0)
+       mz := make(map[Z]int)
+       mz[0] = 42
+       mz[z] = 42
+
+       type S string
+       s := S("foo")
+       ms := make(map[S]int)
+       ms["foo"] = 42
+       ms[s] = 42
+
+       type T struct {
+               x int
+       }
+       type P *T
+       p := P(nil)
+       mp := make(map[P]int)
+       mp[nil] = 42
+       mp[p] = 42
+       mp[&T{7}] = 42
+
+       type F func(x int)
+       f := func(x int) {}
+       mf := make(map[F]int)
+       mf[nil] = 42
+       mf[f] = 42
+       mf[func(x int) {}] = 42
+
+       type M map[int]int
+       m := make(M)
+       mm := make(map[M]int)
+       mm[nil] = 42
+       mm[m] = 42
+       mm[make(M)] = 42
+
+       type C chan int
+       c := make(C)
+       mc := make(map[C]int)
+       mc[nil] = 42
+       mc[c] = 42
+       mc[make(C)] = 42
+
+       type I1 interface{}
+       type I2 interface {
+               f() int
+       }
+       var i0 interface{} = z
+       var i1 I1 = p
+       m0 := make(map[interface{}]int)
+       m1 := make(map[I1]int)
+       m2 := make(map[I2]int)
+       m0[i0] = 42
+       m0[i1] = 42
+       m0[z] = 42 // this should work: z is assignment-compatible with interface{}
+       m0[new(struct {
+               x int
+       })] = 42       // this should work: *struct{x int} is assignment-compatible with interface{}
+       m0[p] = 42     // this should work: p is assignment-compatible with interface{}
+       m0[false] = 42 // this should work: false is assignment-compatible with interface{}
+       m0[17] = 42    // this should work: 17 is assignment-compatible with interface{}
+       m0["foo"] = 42 // this should work: "foo" is assignment-compatible with interface{}
+
+       m1[i0] = 42
+       m1[i1] = 42
+       m1[new(struct {
+               x int
+       })] = 42       // this should work: *struct{x int} is assignment-compatible with I1
+       m1[false] = 42 // this should work: false is assignment-compatible with I1
+       m1[17] = 42    // this should work: 17 is assignment-compatible with I1
+       m1["foo"] = 42 // this should work: "foo" is assignment-compatible with I1
+
+       m2[new(T2)] = 42 // this should work: *T2 is assignment-compatible with I2
+}
+
+/*
+6g -e bug286.go
+bug286.go:23: invalid map index false - need type B
+bug286.go:80: invalid map index z - need type interface { }
+bug286.go:83: invalid map index new(struct { x int }) - need type interface { }
+bug286.go:84: invalid map index p - need type interface { }
+bug286.go:85: invalid map index false - need type interface { }
+bug286.go:86: invalid map index 17 - need type interface { }
+bug286.go:87: invalid map index "foo" - need type interface { }
+bug286.go:93: invalid map index new(struct { x int }) - need type I1
+bug286.go:94: invalid map index false - need type I1
+bug286.go:95: invalid map index 17 - need type I1
+bug286.go:96: invalid map index "foo" - need type I1
+bug286.go:99: invalid map index new(T2) - need type I2
+bug286.go:100: invalid map index t2 - need type I2
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug286.go b/gcc/testsuite/go.test/test/fixedbugs/bug286.go
new file mode 100644 (file)
index 0000000..94423be
--- /dev/null
@@ -0,0 +1,94 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug286 failed
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 849.
+
+package main
+
+type I interface {
+       f()
+}
+
+
+var callee string
+var error bool
+
+type T int
+
+func (t *T) f() { callee = "f" }
+func (i *T) g() { callee = "g" }
+
+
+// test1 and test2 are the same except that in the interface J
+// the entries are swapped. test2 and test3 are the same except
+// that in test3 the interface J is declared outside the function.
+//
+// Error: test2 calls g instead of f
+
+func test1(x I) {
+       type J interface {
+               I
+               g()
+       }
+       x.(J).f()
+       if callee != "f" {
+               println("test1 called", callee)
+               error = true
+       }
+}
+
+
+func test2(x I) {
+       type J interface {
+               g()
+               I
+       }
+       x.(J).f()
+       if callee != "f" {
+               println("test2 called", callee)
+               error = true
+       }
+}
+
+
+type J interface {
+       g()
+       I
+}
+
+func test3(x I) {
+       x.(J).f()
+       if callee != "f" {
+               println("test3 called", callee)
+               error = true
+       }
+}
+
+func main() {
+       x := new(T)
+       test1(x)
+       test2(x)
+       test3(x)
+       if error {
+               panic("wrong method called")
+       }
+}
+
+/*
+6g bug286.go && 6l bug286.6 && 6.out
+test2 called g
+panic: wrong method called
+
+panic PC=0x24e040
+runtime.panic+0x7c /home/gri/go1/src/pkg/runtime/proc.c:1012
+       runtime.panic(0x0, 0x24e0a0)
+main.main+0xef /home/gri/go1/test/bugs/bug286.go:76
+       main.main()
+mainstart+0xf /home/gri/go1/src/pkg/runtime/amd64/asm.s:60
+       mainstart()
+goexit /home/gri/go1/src/pkg/runtime/proc.c:145
+       goexit()
+*/
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug287.go b/gcc/testsuite/go.test/test/fixedbugs/bug287.go
new file mode 100644 (file)
index 0000000..a4a08ee
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to die dividing by zero; issue 879.
+
+package main
+
+var mult [3][...]byte = [3][5]byte{}   // ERROR "\.\.\."
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug288.go b/gcc/testsuite/go.test/test/fixedbugs/bug288.go
new file mode 100644 (file)
index 0000000..0105159
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to run out of registers on 8g.  Issue 868.
+
+package main
+
+func main() {
+       var r uint32
+       var buf [4]byte
+       a := buf[0:4]
+       r = (((((uint32(a[3]) << 8) | uint32(a[2])) << 8) |
+               uint32(a[1])) << 8) | uint32(a[0])
+       _ = r
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug289.go b/gcc/testsuite/go.test/test/fixedbugs/bug289.go
new file mode 100644 (file)
index 0000000..f7180ff
--- /dev/null
@@ -0,0 +1,26 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// https://code.google.com/p/gofrontend/issues/detail?id=1
+
+package main
+
+func f1() {
+       a, b := f()     // ERROR "mismatch|does not match"
+       _ = a
+       _ = b
+}
+
+func f2() {
+       var a, b int
+       a, b = f()      // ERROR "mismatch|does not match"
+       _ = a
+       _ = b
+}
+
+func f() int {
+       return 1;
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug290.go b/gcc/testsuite/go.test/test/fixedbugs/bug290.go
new file mode 100644 (file)
index 0000000..80437c7
--- /dev/null
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=920
+
+package main
+
+type X struct { x []X }
+
+func main() {
+       type Y struct { x []Y } // used to get invalid recursive type
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug291.go b/gcc/testsuite/go.test/test/fixedbugs/bug291.go
new file mode 100644 (file)
index 0000000..09334c9
--- /dev/null
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=915
+
+package main
+
+type T struct {
+       x int
+}
+
+var t = &T{42}
+var i interface{} = t
+var tt, ok = i.(*T)
+
+func main() {
+       if tt == nil || tt.x != 42 {
+               println("BUG")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug292.go b/gcc/testsuite/go.test/test/fixedbugs/bug292.go
new file mode 100644 (file)
index 0000000..05852cd
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=843
+
+package main
+
+import "unsafe"
+
+type T struct {
+       X, Y uint8
+}
+
+func main() {
+       var t T
+       if unsafe.Offsetof(t.X) != 0 || unsafe.Offsetof(t.Y) != 1 {
+               println("BUG", unsafe.Offsetof(t.X), unsafe.Offsetof(t.Y))
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug293.go b/gcc/testsuite/go.test/test/fixedbugs/bug293.go
new file mode 100644 (file)
index 0000000..ca9b71a
--- /dev/null
@@ -0,0 +1,37 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=846
+
+package main
+
+func x() (a int, b bool) {
+       defer func(){
+               a++
+       }()
+       a, b = y()
+       return
+}
+
+func x2() (a int, b bool) {
+       defer func(){
+               a++
+       }()
+       return y()
+}
+
+func y() (int, bool) {
+       return 4, false
+}
+
+func main() {
+       if a, _ := x(); a != 5 {
+               println("BUG", a)
+       }
+       if a, _ := x2(); a != 5 {
+               println("BUG", a)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug294.go b/gcc/testsuite/go.test/test/fixedbugs/bug294.go
new file mode 100644 (file)
index 0000000..18f4593
--- /dev/null
@@ -0,0 +1,79 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=800
+
+package main
+
+var log string
+
+type T int
+
+func (t T) a(s string) T {
+       log += "a(" + s + ")"
+       return t
+}
+
+func (T) b(s string) string {
+       log += "b"
+       return s
+}
+
+type F func(s string) F
+
+func a(s string) F {
+       log += "a(" + s + ")"
+       return F(a)
+}
+
+func b(s string) string {
+       log += "b"
+       return s
+}
+
+type I interface {
+       a(s string) I
+       b(s string) string
+}
+
+type T1 int
+
+func (t T1) a(s string) I {
+       log += "a(" + s + ")"
+       return t
+}
+
+func (T1) b(s string) string {
+       log += "b"
+       return s
+}
+
+var ok = true
+
+func bad() {
+       if !ok {
+               println("BUG")
+               ok = false
+       }
+       println(log)
+}
+
+func main() {
+       var t T
+       if t.a("1").a(t.b("2")); log != "a(1)ba(2)" {
+               bad()
+       }
+       log = ""
+       if a("3")(b("4"))(b("5")); log != "a(3)ba(4)ba(5)" {
+               bad()
+       }
+       log = ""
+       var i I = T1(0)
+       if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)ba(7)ba(8)ba(9)" {
+               bad()
+       }
+}
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug295.go b/gcc/testsuite/go.test/test/fixedbugs/bug295.go
new file mode 100644 (file)
index 0000000..fec2351
--- /dev/null
@@ -0,0 +1,17 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import . "testing"  // defines top-level T
+
+type S struct {
+       T int
+}
+
+func main() {
+       _ = &S{T: 1}    // should work
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug296.go b/gcc/testsuite/go.test/test/fixedbugs/bug296.go
new file mode 100644 (file)
index 0000000..46d8dbc
--- /dev/null
@@ -0,0 +1,88 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface {
+       m(a, b, c, d, e, f, g, h byte)
+}
+
+type Int8 int8
+
+func (x Int8) m(a, b, c, d, e, f, g, h byte) {
+       check("Int8", int64(x), 0x01, a, b, c, d, e, f, g, h)
+}
+
+type Uint8 uint8
+
+func (x Uint8) m(a, b, c, d, e, f, g, h byte) {
+       check("Uint8", int64(x), 0x01, a, b, c, d, e, f, g, h)
+}
+
+type Int16 int16
+
+func (x Int16) m(a, b, c, d, e, f, g, h byte) {
+       check("Int16", int64(x), 0x0102, a, b, c, d, e, f, g, h)
+}
+
+type Uint16 uint16
+
+func (x Uint16) m(a, b, c, d, e, f, g, h byte) {
+       check("Uint16", int64(x), 0x0102, a, b, c, d, e, f, g, h)
+}
+
+type Int32 int32
+
+func (x Int32) m(a, b, c, d, e, f, g, h byte) {
+       check("Int32", int64(x), 0x01020304, a, b, c, d, e, f, g, h)
+}
+
+type Uint32 uint32
+
+func (x Uint32) m(a, b, c, d, e, f, g, h byte) {
+       check("Uint32", int64(x), 0x01020304, a, b, c, d, e, f, g, h)
+}
+
+type Int64 int64
+
+func (x Int64) m(a, b, c, d, e, f, g, h byte) {
+       check("Int64", int64(x), 0x0102030405060708, a, b, c, d, e, f, g, h)
+}
+
+type Uint64 uint64
+
+func (x Uint64) m(a, b, c, d, e, f, g, h byte) {
+       check("Uint64", int64(x), 0x0102030405060708, a, b, c, d, e, f, g, h)
+}
+
+var test = []I{
+       Int8(0x01),
+       Uint8(0x01),
+       Int16(0x0102),
+       Uint16(0x0102),
+       Int32(0x01020304),
+       Uint32(0x01020304),
+       Int64(0x0102030405060708),
+       Uint64(0x0102030405060708),
+}
+
+func main() {
+       for _, t := range test {
+               t.m(0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17)
+       }
+}
+
+var bug = false
+
+func check(desc string, have, want int64, a, b, c, d, e, f, g, h byte) {
+       if have != want || a != 0x10 || b != 0x11 || c != 0x12 || d != 0x13 || e != 0x14 || f != 0x15 || g != 0x16 || h != 0x17 {
+               if !bug {
+                       bug = true
+                       println("BUG")
+               }
+               println(desc, "check", have, want, a, b, c, d, e, f, g, h)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug297.go b/gcc/testsuite/go.test/test/fixedbugs/bug297.go
new file mode 100644 (file)
index 0000000..ba02942
--- /dev/null
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to crash; issue 961.
+
+package main
+
+type ByteSize float64
+const (
+       _ = iota;   // ignore first value by assigning to blank identifier
+       KB ByteSize = 1<<(10*X) // ERROR "undefined"
+)
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug298.go b/gcc/testsuite/go.test/test/fixedbugs/bug298.go
new file mode 100644 (file)
index 0000000..fe4a99a
--- /dev/null
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ddd
+
+func Sum() int
+       for i := range []int{} { return i }  // ERROR "return outside function|expected"
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug299.go b/gcc/testsuite/go.test/test/fixedbugs/bug299.go
new file mode 100644 (file)
index 0000000..4d73144
--- /dev/null
@@ -0,0 +1,27 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+       // legal according to spec
+       x int
+       y (int)
+       int
+       *float
+       // not legal according to spec
+       (complex)  // ERROR "non-declaration|expected|parenthesize"
+       (*string)  // ERROR "non-declaration|expected|parenthesize"
+       *(bool)    // ERROR "non-declaration|expected|parenthesize"
+}
+
+// legal according to spec
+func (p T) m() {}
+
+// not legal according to spec
+func (p (T)) f() {}   // ERROR "parenthesize|expected"
+func (p *(T)) g() {}  // ERROR "parenthesize|expected"
+func (p (*T)) h() {}  // ERROR "parenthesize|expected"
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug300.go b/gcc/testsuite/go.test/test/fixedbugs/bug300.go
new file mode 100644 (file)
index 0000000..09ee3ab
--- /dev/null
@@ -0,0 +1,29 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+       x, y *T
+}
+
+func main() {
+       // legal composite literals
+       _ = struct{}{}
+       _ = [42]int{}
+       _ = [...]int{}
+       _ = []int{}
+       _ = map[int]int{}
+       _ = T{}
+
+       // illegal composite literals: parentheses not allowed around literal type
+       _ = (struct{}){}    // ERROR "parenthesize"
+       _ = ([42]int){}     // ERROR "parenthesize"
+       _ = ([...]int){}    // ERROR "parenthesize"
+       _ = ([]int){}       // ERROR "parenthesize"
+       _ = (map[int]int){} // ERROR "parenthesize"
+       _ = (T){}           // ERROR "parenthesize"
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug301.go b/gcc/testsuite/go.test/test/fixedbugs/bug301.go
new file mode 100644 (file)
index 0000000..a58f4e1
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go || echo BUG: bug301.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=990
+
+package main
+
+func main() {
+       defer func() {
+               if recover() != nil {
+                       panic("non-nil recover")
+               }
+       }()
+       panic(nil)
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug302.dir/main.go b/gcc/testsuite/go.test/test/fixedbugs/bug302.dir/main.go
new file mode 100644 (file)
index 0000000..9f874d0
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Check that the export information is correct in p.6.
+import _ "./p"
+
+// Check that it's still correct in pp.a (which contains p.6).
+import _ "./pp"
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug302.dir/p.go b/gcc/testsuite/go.test/test/fixedbugs/bug302.dir/p.go
new file mode 100644 (file)
index 0000000..7c54b90
--- /dev/null
@@ -0,0 +1,1011 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T struct {
+       x1 int
+       x2 int
+       x3 int
+       x4 int
+       x5 int
+       x6 int
+       x7 int
+       x8 int
+       x9 int
+       x10 int
+       x11 int
+       x12 int
+       x13 int
+       x14 int
+       x15 int
+       x16 int
+       x17 int
+       x18 int
+       x19 int
+       x20 int
+       x21 int
+       x22 int
+       x23 int
+       x24 int
+       x25 int
+       x26 int
+       x27 int
+       x28 int
+       x29 int
+       x30 int
+       x31 int
+       x32 int
+       x33 int
+       x34 int
+       x35 int
+       x36 int
+       x37 int
+       x38 int
+       x39 int
+       x40 int
+       x41 int
+       x42 int
+       x43 int
+       x44 int
+       x45 int
+       x46 int
+       x47 int
+       x48 int
+       x49 int
+       x50 int
+       x51 int
+       x52 int
+       x53 int
+       x54 int
+       x55 int
+       x56 int
+       x57 int
+       x58 int
+       x59 int
+       x60 int
+       x61 int
+       x62 int
+       x63 int
+       x64 int
+       x65 int
+       x66 int
+       x67 int
+       x68 int
+       x69 int
+       x70 int
+       x71 int
+       x72 int
+       x73 int
+       x74 int
+       x75 int
+       x76 int
+       x77 int
+       x78 int
+       x79 int
+       x80 int
+       x81 int
+       x82 int
+       x83 int
+       x84 int
+       x85 int
+       x86 int
+       x87 int
+       x88 int
+       x89 int
+       x90 int
+       x91 int
+       x92 int
+       x93 int
+       x94 int
+       x95 int
+       x96 int
+       x97 int
+       x98 int
+       x99 int
+       x100 int
+       x101 int
+       x102 int
+       x103 int
+       x104 int
+       x105 int
+       x106 int
+       x107 int
+       x108 int
+       x109 int
+       x110 int
+       x111 int
+       x112 int
+       x113 int
+       x114 int
+       x115 int
+       x116 int
+       x117 int
+       x118 int
+       x119 int
+       x120 int
+       x121 int
+       x122 int
+       x123 int
+       x124 int
+       x125 int
+       x126 int
+       x127 int
+       x128 int
+       x129 int
+       x130 int
+       x131 int
+       x132 int
+       x133 int
+       x134 int
+       x135 int
+       x136 int
+       x137 int
+       x138 int
+       x139 int
+       x140 int
+       x141 int
+       x142 int
+       x143 int
+       x144 int
+       x145 int
+       x146 int
+       x147 int
+       x148 int
+       x149 int
+       x150 int
+       x151 int
+       x152 int
+       x153 int
+       x154 int
+       x155 int
+       x156 int
+       x157 int
+       x158 int
+       x159 int
+       x160 int
+       x161 int
+       x162 int
+       x163 int
+       x164 int
+       x165 int
+       x166 int
+       x167 int
+       x168 int
+       x169 int
+       x170 int
+       x171 int
+       x172 int
+       x173 int
+       x174 int
+       x175 int
+       x176 int
+       x177 int
+       x178 int
+       x179 int
+       x180 int
+       x181 int
+       x182 int
+       x183 int
+       x184 int
+       x185 int
+       x186 int
+       x187 int
+       x188 int
+       x189 int
+       x190 int
+       x191 int
+       x192 int
+       x193 int
+       x194 int
+       x195 int
+       x196 int
+       x197 int
+       x198 int
+       x199 int
+       x200 int
+       x201 int
+       x202 int
+       x203 int
+       x204 int
+       x205 int
+       x206 int
+       x207 int
+       x208 int
+       x209 int
+       x210 int
+       x211 int
+       x212 int
+       x213 int
+       x214 int
+       x215 int
+       x216 int
+       x217 int
+       x218 int
+       x219 int
+       x220 int
+       x221 int
+       x222 int
+       x223 int
+       x224 int
+       x225 int
+       x226 int
+       x227 int
+       x228 int
+       x229 int
+       x230 int
+       x231 int
+       x232 int
+       x233 int
+       x234 int
+       x235 int
+       x236 int
+       x237 int
+       x238 int
+       x239 int
+       x240 int
+       x241 int
+       x242 int
+       x243 int
+       x244 int
+       x245 int
+       x246 int
+       x247 int
+       x248 int
+       x249 int
+       x250 int
+       x251 int
+       x252 int
+       x253 int
+       x254 int
+       x255 int
+       x256 int
+       x257 int
+       x258 int
+       x259 int
+       x260 int
+       x261 int
+       x262 int
+       x263 int
+       x264 int
+       x265 int
+       x266 int
+       x267 int
+       x268 int
+       x269 int
+       x270 int
+       x271 int
+       x272 int
+       x273 int
+       x274 int
+       x275 int
+       x276 int
+       x277 int
+       x278 int
+       x279 int
+       x280 int
+       x281 int
+       x282 int
+       x283 int
+       x284 int
+       x285 int
+       x286 int
+       x287 int
+       x288 int
+       x289 int
+       x290 int
+       x291 int
+       x292 int
+       x293 int
+       x294 int
+       x295 int
+       x296 int
+       x297 int
+       x298 int
+       x299 int
+       x300 int
+       x301 int
+       x302 int
+       x303 int
+       x304 int
+       x305 int
+       x306 int
+       x307 int
+       x308 int
+       x309 int
+       x310 int
+       x311 int
+       x312 int
+       x313 int
+       x314 int
+       x315 int
+       x316 int
+       x317 int
+       x318 int
+       x319 int
+       x320 int
+       x321 int
+       x322 int
+       x323 int
+       x324 int
+       x325 int
+       x326 int
+       x327 int
+       x328 int
+       x329 int
+       x330 int
+       x331 int
+       x332 int
+       x333 int
+       x334 int
+       x335 int
+       x336 int
+       x337 int
+       x338 int
+       x339 int
+       x340 int
+       x341 int
+       x342 int
+       x343 int
+       x344 int
+       x345 int
+       x346 int
+       x347 int
+       x348 int
+       x349 int
+       x350 int
+       x351 int
+       x352 int
+       x353 int
+       x354 int
+       x355 int
+       x356 int
+       x357 int
+       x358 int
+       x359 int
+       x360 int
+       x361 int
+       x362 int
+       x363 int
+       x364 int
+       x365 int
+       x366 int
+       x367 int
+       x368 int
+       x369 int
+       x370 int
+       x371 int
+       x372 int
+       x373 int
+       x374 int
+       x375 int
+       x376 int
+       x377 int
+       x378 int
+       x379 int
+       x380 int
+       x381 int
+       x382 int
+       x383 int
+       x384 int
+       x385 int
+       x386 int
+       x387 int
+       x388 int
+       x389 int
+       x390 int
+       x391 int
+       x392 int
+       x393 int
+       x394 int
+       x395 int
+       x396 int
+       x397 int
+       x398 int
+       x399 int
+       x400 int
+       x401 int
+       x402 int
+       x403 int
+       x404 int
+       x405 int
+       x406 int
+       x407 int
+       x408 int
+       x409 int
+       x410 int
+       x411 int
+       x412 int
+       x413 int
+       x414 int
+       x415 int
+       x416 int
+       x417 int
+       x418 int
+       x419 int
+       x420 int
+       x421 int
+       x422 int
+       x423 int
+       x424 int
+       x425 int
+       x426 int
+       x427 int
+       x428 int
+       x429 int
+       x430 int
+       x431 int
+       x432 int
+       x433 int
+       x434 int
+       x435 int
+       x436 int
+       x437 int
+       x438 int
+       x439 int
+       x440 int
+       x441 int
+       x442 int
+       x443 int
+       x444 int
+       x445 int
+       x446 int
+       x447 int
+       x448 int
+       x449 int
+       x450 int
+       x451 int
+       x452 int
+       x453 int
+       x454 int
+       x455 int
+       x456 int
+       x457 int
+       x458 int
+       x459 int
+       x460 int
+       x461 int
+       x462 int
+       x463 int
+       x464 int
+       x465 int
+       x466 int
+       x467 int
+       x468 int
+       x469 int
+       x470 int
+       x471 int
+       x472 int
+       x473 int
+       x474 int
+       x475 int
+       x476 int
+       x477 int
+       x478 int
+       x479 int
+       x480 int
+       x481 int
+       x482 int
+       x483 int
+       x484 int
+       x485 int
+       x486 int
+       x487 int
+       x488 int
+       x489 int
+       x490 int
+       x491 int
+       x492 int
+       x493 int
+       x494 int
+       x495 int
+       x496 int
+       x497 int
+       x498 int
+       x499 int
+       x500 int
+       x501 int
+       x502 int
+       x503 int
+       x504 int
+       x505 int
+       x506 int
+       x507 int
+       x508 int
+       x509 int
+       x510 int
+       x511 int
+       x512 int
+       x513 int
+       x514 int
+       x515 int
+       x516 int
+       x517 int
+       x518 int
+       x519 int
+       x520 int
+       x521 int
+       x522 int
+       x523 int
+       x524 int
+       x525 int
+       x526 int
+       x527 int
+       x528 int
+       x529 int
+       x530 int
+       x531 int
+       x532 int
+       x533 int
+       x534 int
+       x535 int
+       x536 int
+       x537 int
+       x538 int
+       x539 int
+       x540 int
+       x541 int
+       x542 int
+       x543 int
+       x544 int
+       x545 int
+       x546 int
+       x547 int
+       x548 int
+       x549 int
+       x550 int
+       x551 int
+       x552 int
+       x553 int
+       x554 int
+       x555 int
+       x556 int
+       x557 int
+       x558 int
+       x559 int
+       x560 int
+       x561 int
+       x562 int
+       x563 int
+       x564 int
+       x565 int
+       x566 int
+       x567 int
+       x568 int
+       x569 int
+       x570 int
+       x571 int
+       x572 int
+       x573 int
+       x574 int
+       x575 int
+       x576 int
+       x577 int
+       x578 int
+       x579 int
+       x580 int
+       x581 int
+       x582 int
+       x583 int
+       x584 int
+       x585 int
+       x586 int
+       x587 int
+       x588 int
+       x589 int
+       x590 int
+       x591 int
+       x592 int
+       x593 int
+       x594 int
+       x595 int
+       x596 int
+       x597 int
+       x598 int
+       x599 int
+       x600 int
+       x601 int
+       x602 int
+       x603 int
+       x604 int
+       x605 int
+       x606 int
+       x607 int
+       x608 int
+       x609 int
+       x610 int
+       x611 int
+       x612 int
+       x613 int
+       x614 int
+       x615 int
+       x616 int
+       x617 int
+       x618 int
+       x619 int
+       x620 int
+       x621 int
+       x622 int
+       x623 int
+       x624 int
+       x625 int
+       x626 int
+       x627 int
+       x628 int
+       x629 int
+       x630 int
+       x631 int
+       x632 int
+       x633 int
+       x634 int
+       x635 int
+       x636 int
+       x637 int
+       x638 int
+       x639 int
+       x640 int
+       x641 int
+       x642 int
+       x643 int
+       x644 int
+       x645 int
+       x646 int
+       x647 int
+       x648 int
+       x649 int
+       x650 int
+       x651 int
+       x652 int
+       x653 int
+       x654 int
+       x655 int
+       x656 int
+       x657 int
+       x658 int
+       x659 int
+       x660 int
+       x661 int
+       x662 int
+       x663 int
+       x664 int
+       x665 int
+       x666 int
+       x667 int
+       x668 int
+       x669 int
+       x670 int
+       x671 int
+       x672 int
+       x673 int
+       x674 int
+       x675 int
+       x676 int
+       x677 int
+       x678 int
+       x679 int
+       x680 int
+       x681 int
+       x682 int
+       x683 int
+       x684 int
+       x685 int
+       x686 int
+       x687 int
+       x688 int
+       x689 int
+       x690 int
+       x691 int
+       x692 int
+       x693 int
+       x694 int
+       x695 int
+       x696 int
+       x697 int
+       x698 int
+       x699 int
+       x700 int
+       x701 int
+       x702 int
+       x703 int
+       x704 int
+       x705 int
+       x706 int
+       x707 int
+       x708 int
+       x709 int
+       x710 int
+       x711 int
+       x712 int
+       x713 int
+       x714 int
+       x715 int
+       x716 int
+       x717 int
+       x718 int
+       x719 int
+       x720 int
+       x721 int
+       x722 int
+       x723 int
+       x724 int
+       x725 int
+       x726 int
+       x727 int
+       x728 int
+       x729 int
+       x730 int
+       x731 int
+       x732 int
+       x733 int
+       x734 int
+       x735 int
+       x736 int
+       x737 int
+       x738 int
+       x739 int
+       x740 int
+       x741 int
+       x742 int
+       x743 int
+       x744 int
+       x745 int
+       x746 int
+       x747 int
+       x748 int
+       x749 int
+       x750 int
+       x751 int
+       x752 int
+       x753 int
+       x754 int
+       x755 int
+       x756 int
+       x757 int
+       x758 int
+       x759 int
+       x760 int
+       x761 int
+       x762 int
+       x763 int
+       x764 int
+       x765 int
+       x766 int
+       x767 int
+       x768 int
+       x769 int
+       x770 int
+       x771 int
+       x772 int
+       x773 int
+       x774 int
+       x775 int
+       x776 int
+       x777 int
+       x778 int
+       x779 int
+       x780 int
+       x781 int
+       x782 int
+       x783 int
+       x784 int
+       x785 int
+       x786 int
+       x787 int
+       x788 int
+       x789 int
+       x790 int
+       x791 int
+       x792 int
+       x793 int
+       x794 int
+       x795 int
+       x796 int
+       x797 int
+       x798 int
+       x799 int
+       x800 int
+       x801 int
+       x802 int
+       x803 int
+       x804 int
+       x805 int
+       x806 int
+       x807 int
+       x808 int
+       x809 int
+       x810 int
+       x811 int
+       x812 int
+       x813 int
+       x814 int
+       x815 int
+       x816 int
+       x817 int
+       x818 int
+       x819 int
+       x820 int
+       x821 int
+       x822 int
+       x823 int
+       x824 int
+       x825 int
+       x826 int
+       x827 int
+       x828 int
+       x829 int
+       x830 int
+       x831 int
+       x832 int
+       x833 int
+       x834 int
+       x835 int
+       x836 int
+       x837 int
+       x838 int
+       x839 int
+       x840 int
+       x841 int
+       x842 int
+       x843 int
+       x844 int
+       x845 int
+       x846 int
+       x847 int
+       x848 int
+       x849 int
+       x850 int
+       x851 int
+       x852 int
+       x853 int
+       x854 int
+       x855 int
+       x856 int
+       x857 int
+       x858 int
+       x859 int
+       x860 int
+       x861 int
+       x862 int
+       x863 int
+       x864 int
+       x865 int
+       x866 int
+       x867 int
+       x868 int
+       x869 int
+       x870 int
+       x871 int
+       x872 int
+       x873 int
+       x874 int
+       x875 int
+       x876 int
+       x877 int
+       x878 int
+       x879 int
+       x880 int
+       x881 int
+       x882 int
+       x883 int
+       x884 int
+       x885 int
+       x886 int
+       x887 int
+       x888 int
+       x889 int
+       x890 int
+       x891 int
+       x892 int
+       x893 int
+       x894 int
+       x895 int
+       x896 int
+       x897 int
+       x898 int
+       x899 int
+       x900 int
+       x901 int
+       x902 int
+       x903 int
+       x904 int
+       x905 int
+       x906 int
+       x907 int
+       x908 int
+       x909 int
+       x910 int
+       x911 int
+       x912 int
+       x913 int
+       x914 int
+       x915 int
+       x916 int
+       x917 int
+       x918 int
+       x919 int
+       x920 int
+       x921 int
+       x922 int
+       x923 int
+       x924 int
+       x925 int
+       x926 int
+       x927 int
+       x928 int
+       x929 int
+       x930 int
+       x931 int
+       x932 int
+       x933 int
+       x934 int
+       x935 int
+       x936 int
+       x937 int
+       x938 int
+       x939 int
+       x940 int
+       x941 int
+       x942 int
+       x943 int
+       x944 int
+       x945 int
+       x946 int
+       x947 int
+       x948 int
+       x949 int
+       x950 int
+       x951 int
+       x952 int
+       x953 int
+       x954 int
+       x955 int
+       x956 int
+       x957 int
+       x958 int
+       x959 int
+       x960 int
+       x961 int
+       x962 int
+       x963 int
+       x964 int
+       x965 int
+       x966 int
+       x967 int
+       x968 int
+       x969 int
+       x970 int
+       x971 int
+       x972 int
+       x973 int
+       x974 int
+       x975 int
+       x976 int
+       x977 int
+       x978 int
+       x979 int
+       x980 int
+       x981 int
+       x982 int
+       x983 int
+       x984 int
+       x985 int
+       x986 int
+       x987 int
+       x988 int
+       x989 int
+       x990 int
+       x991 int
+       x992 int
+       x993 int
+       x994 int
+       x995 int
+       x996 int
+       x997 int
+       x998 int
+       x999 int
+       x1000 int
+}
+
+func (t *T) M() {
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug302.go b/gcc/testsuite/go.test/test/fixedbugs/bug302.go
new file mode 100644 (file)
index 0000000..e9edb94
--- /dev/null
@@ -0,0 +1,6 @@
+// $G $D/bug302.dir/p.go && gopack grc pp.a p.$A && $G $D/bug302.dir/main.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug303.go b/gcc/testsuite/go.test/test/fixedbugs/bug303.go
new file mode 100644 (file)
index 0000000..3bd790f
--- /dev/null
@@ -0,0 +1,37 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1011.  Removing either #1 or #3 avoided the crash at #2.
+
+package main
+
+import (
+       "io"
+       "strings"
+)
+
+func readU16BE(b []byte) uint16 {
+       b[0] = 0
+       b[1] = 1
+       return uint16(b[0])<<8 + uint16(b[1]) // #1
+       n := uint16(b[0])<<8 + uint16(b[1])
+       return n
+}
+
+func readStr(r io.Reader, b []byte) string {
+       n := readU16BE(b)
+       if int(n) > len(b) {
+               return "err: n>b"
+       }
+       io.ReadFull(r, b[0:n]) // #2
+       return string(b[0:n])  // #3
+       return "ok"
+}
+
+func main() {
+       br := strings.NewReader("abcd")
+       readStr(br, make([]byte, 256))
+}
diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug304.go b/gcc/testsuite/go.test/test/fixedbugs/bug304.go
new file mode 100644 (file)
index 0000000..adcf08a
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Caused a gccgo crash on compilation.
+// bug304.go: In function ‘p.f’:
+// bug304.go:15:2: internal compiler error: in copy_tree_r, at tree-inline.c:4114
+
+package p
+type S struct {
+       v interface{}
+}
+func g(e interface{}) { }
+func f(s S) {
+       g(s.v.(*int))
+}
diff --git a/gcc/testsuite/go.test/test/float_lit.go b/gcc/testsuite/go.test/test/float_lit.go
new file mode 100644 (file)
index 0000000..3ffc5c1
--- /dev/null
@@ -0,0 +1,118 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+var deLim float64
+var bad bool
+
+func
+init() {
+       if os.Getenv("GOARCH") == "arm" {
+               deLim = 1.0e-8
+       } else {
+               deLim = 10.e-14
+       }
+}
+
+func
+pow10(pow int) float64 {
+       if pow < 0 { return 1/pow10(-pow); }
+       if pow > 0 { return pow10(pow-1)*10; }
+       return 1
+}
+
+func
+close(da float64, ia, ib int64, pow int) bool {
+       db := float64(ia) / float64(ib)
+       db *= pow10(pow)
+
+       if da == 0 || db == 0 {
+               if da == 0 && db == 0 {
+                       return true
+               }
+               return false
+       }
+
+       de := (da-db) /da
+       if de < 0 {
+               de = -de
+       }
+
+       if de < deLim {
+               return true
+       }
+       if !bad {
+               println("BUG")
+               bad = true
+       }
+       return false
+}
+
+func
+main() {
+       if !close(0., 0, 1, 0) { print("0. is ", 0., "\n"); }
+       if !close(+10., 10, 1, 0) { print("+10. is ", +10., "\n"); }
+       if !close(-210., -210, 1, 0) { print("-210. is ", -210., "\n"); }
+
+       if !close(.0, 0, 1, 0) { print(".0 is ", .0, "\n"); }
+       if !close(+.01, 1, 100, 0) { print("+.01 is ", +.01, "\n"); }
+       if !close(-.012, -12, 1000, 0) { print("-.012 is ", -.012, "\n"); }
+
+       if !close(0.0, 0, 1, 0) { print("0.0 is ", 0.0, "\n"); }
+       if !close(+10.01, 1001, 100, 0) { print("+10.01 is ", +10.01, "\n"); }
+       if !close(-210.012, -210012, 1000, 0) { print("-210.012 is ", -210.012, "\n"); }
+
+       if !close(0E+1, 0, 1, 0) { print("0E+1 is ", 0E+1, "\n"); }
+       if !close(+10e2, 10, 1, 2) { print("+10e2 is ", +10e2, "\n"); }
+       if !close(-210e3, -210, 1, 3) { print("-210e3 is ", -210e3, "\n"); }
+
+       if !close(0E-1, 0, 1, 0) { print("0E-1 is ", 0E-1, "\n"); }
+       if !close(+0e23, 0, 1, 1) { print("+0e23 is ", +0e23, "\n"); }
+       if !close(-0e345, 0, 1, 1) { print("-0e345 is ", -0e345, "\n"); }
+
+       if !close(0E1, 0, 1, 1) { print("0E1 is ", 0E1, "\n"); }
+       if !close(+10e23, 10, 1, 23) { print("+10e23 is ", +10e23, "\n"); }
+       if !close(-210e34, -210, 1, 34) { print("-210e34 is ", -210e34, "\n"); }
+
+       if !close(0.E1, 0, 1, 1) { print("0.E1 is ", 0.E1, "\n"); }
+       if !close(+10.e+2, 10, 1, 2) { print("+10.e+2 is ", +10.e+2, "\n"); }
+       if !close(-210.e-3, -210, 1, -3) { print("-210.e-3 is ", -210.e-3, "\n"); }
+
+       if !close(.0E1, 0, 1, 1) { print(".0E1 is ", .0E1, "\n"); }
+       if !close(+.01e2, 1, 100, 2) { print("+.01e2 is ", +.01e2, "\n"); }
+       if !close(-.012e3, -12, 1000, 3) { print("-.012e3 is ", -.012e3, "\n"); }
+
+       if !close(0.0E1, 0, 1, 0) { print("0.0E1 is ", 0.0E1, "\n"); }
+       if !close(+10.01e2, 1001, 100, 2) { print("+10.01e2 is ", +10.01e2, "\n"); }
+       if !close(-210.012e3, -210012, 1000, 3) { print("-210.012e3 is ", -210.012e3, "\n"); }
+
+       if !close(0.E+12, 0, 1, 0) { print("0.E+12 is ", 0.E+12, "\n"); }
+       if !close(+10.e23, 10, 1, 23) { print("+10.e23 is ", +10.e23, "\n"); }
+       if !close(-210.e33, -210, 1, 33) { print("-210.e33 is ", -210.e33, "\n"); }
+
+       if !close(.0E-12, 0, 1, 0) { print(".0E-12 is ", .0E-12, "\n"); }
+       if !close(+.01e23, 1, 100, 23) { print("+.01e23 is ", +.01e23, "\n"); }
+       if !close(-.012e34, -12, 1000, 34) { print("-.012e34 is ", -.012e34, "\n"); }
+
+       if !close(0.0E12, 0, 1, 12) { print("0.0E12 is ", 0.0E12, "\n"); }
+       if !close(+10.01e23, 1001, 100, 23) { print("+10.01e23 is ", +10.01e23, "\n"); }
+       if !close(-210.012e33, -210012, 1000, 33) { print("-210.012e33 is ", -210.012e33, "\n"); }
+
+       if !close(0.E123, 0, 1, 123) { print("0.E123 is ", 0.E123, "\n"); }
+       if !close(+10.e+23, 10, 1, 23) { print("+10.e+234 is ", +10.e+234, "\n"); }
+       if !close(-210.e-35, -210, 1, -35) { print("-210.e-35 is ", -210.e-35, "\n"); }
+
+       if !close(.0E123, 0, 1, 123) { print(".0E123 is ", .0E123, "\n"); }
+       if !close(+.01e29, 1, 100, 29) { print("+.01e29 is ", +.01e29, "\n"); }
+       if !close(-.012e29, -12, 1000, 29) { print("-.012e29 is ", -.012e29, "\n"); }
+
+       if !close(0.0E123, 0, 1, 123) { print("0.0E123 is ", 0.0E123, "\n"); }
+       if !close(+10.01e31, 1001, 100, 31) { print("+10.01e31 is ", +10.01e31, "\n"); }
+       if !close(-210.012e19, -210012, 1000, 19) { print("-210.012e19 is ", -210.012e19, "\n"); }
+}
diff --git a/gcc/testsuite/go.test/test/floatcmp.go b/gcc/testsuite/go.test/test/floatcmp.go
new file mode 100644 (file)
index 0000000..f51cbc2
--- /dev/null
@@ -0,0 +1,88 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "math"
+
+type floatTest struct {
+       name string
+       expr bool
+       want bool
+}
+
+var nan float64 = math.NaN()
+var f float64 = 1
+
+var tests = []floatTest{
+       floatTest{"nan == nan", nan == nan, false},
+       floatTest{"nan != nan", nan != nan, true},
+       floatTest{"nan < nan", nan < nan, false},
+       floatTest{"nan > nan", nan > nan, false},
+       floatTest{"nan <= nan", nan <= nan, false},
+       floatTest{"nan >= nan", nan >= nan, false},
+       floatTest{"f == nan", f == nan, false},
+       floatTest{"f != nan", f != nan, true},
+       floatTest{"f < nan", f < nan, false},
+       floatTest{"f > nan", f > nan, false},
+       floatTest{"f <= nan", f <= nan, false},
+       floatTest{"f >= nan", f >= nan, false},
+       floatTest{"nan == f", nan == f, false},
+       floatTest{"nan != f", nan != f, true},
+       floatTest{"nan < f", nan < f, false},
+       floatTest{"nan > f", nan > f, false},
+       floatTest{"nan <= f", nan <= f, false},
+       floatTest{"nan >= f", nan >= f, false},
+       floatTest{"!(nan == nan)", !(nan == nan), true},
+       floatTest{"!(nan != nan)", !(nan != nan), false},
+       floatTest{"!(nan < nan)", !(nan < nan), true},
+       floatTest{"!(nan > nan)", !(nan > nan), true},
+       floatTest{"!(nan <= nan)", !(nan <= nan), true},
+       floatTest{"!(nan >= nan)", !(nan >= nan), true},
+       floatTest{"!(f == nan)", !(f == nan), true},
+       floatTest{"!(f != nan)", !(f != nan), false},
+       floatTest{"!(f < nan)", !(f < nan), true},
+       floatTest{"!(f > nan)", !(f > nan), true},
+       floatTest{"!(f <= nan)", !(f <= nan), true},
+       floatTest{"!(f >= nan)", !(f >= nan), true},
+       floatTest{"!(nan == f)", !(nan == f), true},
+       floatTest{"!(nan != f)", !(nan != f), false},
+       floatTest{"!(nan < f)", !(nan < f), true},
+       floatTest{"!(nan > f)", !(nan > f), true},
+       floatTest{"!(nan <= f)", !(nan <= f), true},
+       floatTest{"!(nan >= f)", !(nan >= f), true},
+       floatTest{"!!(nan == nan)", !!(nan == nan), false},
+       floatTest{"!!(nan != nan)", !!(nan != nan), true},
+       floatTest{"!!(nan < nan)", !!(nan < nan), false},
+       floatTest{"!!(nan > nan)", !!(nan > nan), false},
+       floatTest{"!!(nan <= nan)", !!(nan <= nan), false},
+       floatTest{"!!(nan >= nan)", !!(nan >= nan), false},
+       floatTest{"!!(f == nan)", !!(f == nan), false},
+       floatTest{"!!(f != nan)", !!(f != nan), true},
+       floatTest{"!!(f < nan)", !!(f < nan), false},
+       floatTest{"!!(f > nan)", !!(f > nan), false},
+       floatTest{"!!(f <= nan)", !!(f <= nan), false},
+       floatTest{"!!(f >= nan)", !!(f >= nan), false},
+       floatTest{"!!(nan == f)", !!(nan == f), false},
+       floatTest{"!!(nan != f)", !!(nan != f), true},
+       floatTest{"!!(nan < f)", !!(nan < f), false},
+       floatTest{"!!(nan > f)", !!(nan > f), false},
+       floatTest{"!!(nan <= f)", !!(nan <= f), false},
+       floatTest{"!!(nan >= f)", !!(nan >= f), false},
+}
+
+func main() {
+       bad := false
+       for _, t := range tests {
+               if t.expr != t.want {
+                       if !bad {
+                               bad = true
+                               println("BUG: floatcmp")
+                       }
+                       println(t.name, "=", t.expr, "want", t.want)
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/for.go b/gcc/testsuite/go.test/test/for.go
new file mode 100644 (file)
index 0000000..36ad157
--- /dev/null
@@ -0,0 +1,56 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func assertequal(is, shouldbe int, msg string) {
+       if is != shouldbe {
+               print("assertion fail", msg, "\n")
+               panic(1)
+       }
+}
+
+func main() {
+       var i, sum int
+
+       i = 0
+       for {
+               i = i + 1
+               if i > 5 {
+                       break
+               }
+       }
+       assertequal(i, 6, "break")
+
+       sum = 0
+       for i := 0; i <= 10; i++ {
+               sum = sum + i
+       }
+       assertequal(sum, 55, "all three")
+
+       sum = 0
+       for i := 0; i <= 10; {
+               sum = sum + i
+               i++
+       }
+       assertequal(sum, 55, "only two")
+
+       sum = 0
+       for sum < 100 {
+               sum = sum + 9
+       }
+       assertequal(sum, 99 + 9, "only one")
+
+       sum = 0
+       for i := 0; i <= 10; i++ {
+               if i % 2 == 0 {
+                       continue
+               }
+               sum = sum + i
+       }
+       assertequal(sum, 1+3+5+7+9, "continue")
+
+}
diff --git a/gcc/testsuite/go.test/test/func.go b/gcc/testsuite/go.test/test/func.go
new file mode 100644 (file)
index 0000000..0c1a079
--- /dev/null
@@ -0,0 +1,89 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+func assertequal(is, shouldbe int, msg string) {
+       if is != shouldbe {
+               print("assertion fail", msg, "\n")
+               panic(1)
+       }
+}
+
+func f1() {
+}
+
+func f2(a int) {
+}
+
+func f3(a, b int) int {
+       return a+b
+}
+
+func f4(a, b int, c float) int {
+       return (a+b)/2 + int(c)
+}
+
+func f5(a int) int {
+       return 5
+}
+
+func f6(a int) (r int) {
+       return 6
+}
+
+func f7(a int) (x int, y float) {
+       return 7, 7.0
+}
+
+
+func f8(a int) (x int, y float) {
+       return 8, 8.0
+}
+
+type T struct {
+       x, y int
+}
+
+func (t *T) m10(a int, b float) int {
+       return (t.x+a) * (t.y+int(b))
+}
+
+
+func f9(a int) (i int, f float) {
+       i = 9
+       f = 9.0
+       return
+}
+
+
+func main() {
+       f1()
+       f2(1)
+       r3 := f3(1, 2)
+       assertequal(r3, 3, "3")
+       r4 := f4(0, 2, 3.0)
+       assertequal(r4, 4, "4")
+       r5 := f5(1)
+       assertequal(r5, 5, "5")
+       r6 := f6(1)
+       assertequal(r6, 6, "6")
+       r7, s7 := f7(1)
+       assertequal(r7, 7, "r7")
+       assertequal(int(s7), 7, "s7")
+       r8, s8 := f8(1)
+       assertequal(r8, 8, "r8")
+       assertequal(int(s8), 8, "s8")
+       r9, s9 := f9(1)
+       assertequal(r9, 9, "r9")
+       assertequal(int(s9), 9, "s9")
+       var t *T = new(T)
+       t.x = 1
+       t.y = 2
+       r10 := t.m10(1, 3.0)
+       assertequal(r10, 10, "10")
+}
diff --git a/gcc/testsuite/go.test/test/func1.go b/gcc/testsuite/go.test/test/func1.go
new file mode 100644 (file)
index 0000000..56f4dfc
--- /dev/null
@@ -0,0 +1,18 @@
+// errchk $G $F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// does not compile and should not compile
+
+package main
+
+func f1(a int) (int, float) {  // BUG (not caught by compiler): multiple return values must have names
+       return 7, 7.0
+}
+
+
+func f2(a int) (a int, b float) {  // ERROR "redeclared|definition"
+       return 8, 8.0
+}
diff --git a/gcc/testsuite/go.test/test/func2.go b/gcc/testsuite/go.test/test/func2.go
new file mode 100644 (file)
index 0000000..5a6d7d0
--- /dev/null
@@ -0,0 +1,31 @@
+// $G $F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+import os "os"
+
+type t1 int
+type t2 int
+type t3 int
+
+func f1(t1, t2, t3)
+func f2(t1, t2, t3 bool)
+func f3(t1, t2, x t3)
+func f4(t1, *t3)
+func (x *t1) f5(y []t2) (t1, *t3)
+func f6() (int, *string)
+func f7(*t2, t3)
+func f8(os int) int
+
+func f9(os int) int {
+       return os
+}
+func f10(err os.Error) os.Error {
+       return err
+}
+func f11(t1 string) string {
+       return t1
+}
diff --git a/gcc/testsuite/go.test/test/func3.go b/gcc/testsuite/go.test/test/func3.go
new file mode 100644 (file)
index 0000000..110b0ef
--- /dev/null
@@ -0,0 +1,17 @@
+// errchk $G $F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type t1 int
+type t2 int
+type t3 int
+
+func f1(*t2, x t3)     // ERROR "named"
+func f2(t1, *t2, x t3) // ERROR "named"
+func f3() (x int, *string)     // ERROR "named"
+
+func f4() (t1 t1)      // legal - scope of parameter named t1 starts in body of f4.
diff --git a/gcc/testsuite/go.test/test/func4.go b/gcc/testsuite/go.test/test/func4.go
new file mode 100644 (file)
index 0000000..69ce56a
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var notmain func()
+
+func main() {
+       var x = &main           // ERROR "address of|invalid"
+       main = notmain  // ERROR "assign to|invalid"
+}
diff --git a/gcc/testsuite/go.test/test/func5.go b/gcc/testsuite/go.test/test/func5.go
new file mode 100644 (file)
index 0000000..e27825c
--- /dev/null
@@ -0,0 +1,89 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func caller(f func(int, int) int, a, b int, c chan int) {
+       c <- f(a, b)
+}
+
+func gocall(f func(int, int) int, a, b int) int {
+       c := make(chan int)
+       go caller(f, a, b, c)
+       return <-c
+}
+
+func call(f func(int, int) int, a, b int) int {
+       return f(a, b)
+}
+
+func call1(f func(int, int) int, a, b int) int {
+       return call(f, a, b)
+}
+
+var f func(int, int) int
+
+func add(x, y int) int {
+       return x + y
+}
+
+func fn() func(int, int) int {
+       return f
+}
+
+var fc func(int, int, chan int)
+
+func addc(x, y int, c chan int) {
+       c <- x+y
+}
+
+func fnc() func(int, int, chan int) {
+       return fc
+}
+
+func three(x int) {
+       if x != 3 {
+               println("wrong val", x)
+               panic("fail")
+       }
+}
+
+var notmain func()
+
+func emptyresults() {}
+func noresults()    {}
+
+var nothing func()
+
+func main() {
+       three(call(add, 1, 2))
+       three(call1(add, 1, 2))
+       f = add
+       three(call(f, 1, 2))
+       three(call1(f, 1, 2))
+       three(call(fn(), 1, 2))
+       three(call1(fn(), 1, 2))
+       three(call(func(a, b int) int { return a + b }, 1, 2))
+       three(call1(func(a, b int) int { return a + b }, 1, 2))
+
+       fc = addc
+       c := make(chan int)
+       go addc(1, 2, c)
+       three(<-c)
+       go fc(1, 2, c)
+       three(<-c)
+       go fnc()(1, 2, c)
+       three(<-c)
+       go func(a, b int, c chan int) { c <- a+b }(1, 2, c)
+       three(<-c)
+
+       emptyresults()
+       noresults()
+       nothing = emptyresults
+       nothing()
+       nothing = noresults
+       nothing()
+}
diff --git a/gcc/testsuite/go.test/test/garbage/Makefile b/gcc/testsuite/go.test/test/garbage/Makefile
new file mode 100644 (file)
index 0000000..ab29e09
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright 2010 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../src/Make.inc
+
+ALL=\
+       parser\
+       peano\
+       tree\
+
+all: $(addsuffix .out, $(ALL))
+
+%.$O: %.go
+       $(GC) $*.go
+
+%.out: %.$O
+       $(LD) -o $@ $*.$O
+
+%.bench: %.out
+       ./$*.out
+
+bench: $(addsuffix .bench, $(ALL))
+
+clean:
+       rm -f *.[$(OS)] $(addsuffix .out, $(ALL))
+
diff --git a/gcc/testsuite/go.test/test/garbage/parser.go b/gcc/testsuite/go.test/test/garbage/parser.go
new file mode 100644 (file)
index 0000000..cf68737
--- /dev/null
@@ -0,0 +1,215 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Garbage collection benchmark: parse Go packages repeatedly.
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "os"
+       "path"
+       "runtime"
+       "strings"
+       "time"
+)
+
+func isGoFile(dir *os.FileInfo) bool {
+       return dir.IsRegular() &&
+               !strings.HasPrefix(dir.Name, ".") && // ignore .files
+               path.Ext(dir.Name) == ".go"
+}
+
+func isPkgFile(dir *os.FileInfo) bool {
+       return isGoFile(dir) &&
+               !strings.HasSuffix(dir.Name, "_test.go") // ignore test files
+}
+
+func pkgName(filename string) string {
+       file, err := parser.ParseFile(filename, nil, parser.PackageClauseOnly)
+       if err != nil || file == nil {
+               return ""
+       }
+       return file.Name.Name
+}
+
+func parseDir(dirpath string) map[string]*ast.Package {
+       // the package name is the directory name within its parent
+       // (use dirname instead of path because dirname is clean; i.e. has no trailing '/')
+       _, pkgname := path.Split(dirpath)
+
+       // filter function to select the desired .go files
+       filter := func(d *os.FileInfo) bool {
+               if isPkgFile(d) {
+                       // Some directories contain main packages: Only accept
+                       // files that belong to the expected package so that
+                       // parser.ParsePackage doesn't return "multiple packages
+                       // found" errors.
+                       // Additionally, accept the special package name
+                       // fakePkgName if we are looking at cmd documentation.
+                       name := pkgName(dirpath + "/" + d.Name)
+                       return name == pkgname
+               }
+               return false
+       }
+
+       // get package AST
+       pkgs, err := parser.ParseDir(dirpath, filter, parser.ParseComments)
+       if err != nil {
+               println("parse", dirpath, err.String())
+               panic("fail")
+       }
+       return pkgs
+}
+
+func main() {
+       st := &runtime.MemStats
+       n := flag.Int("n", 4, "iterations")
+       p := flag.Int("p", len(packages), "# of packages to keep in memory")
+       flag.BoolVar(&st.DebugGC, "d", st.DebugGC, "print GC debugging info (pause times)")
+       flag.Parse()
+
+       var t0 int64
+       pkgroot := runtime.GOROOT() + "/src/pkg/"
+       for pass := 0; pass < 2; pass++ {
+               // Once the heap is grown to full size, reset counters.
+               // This hides the start-up pauses, which are much smaller
+               // than the normal pauses and would otherwise make
+               // the average look much better than it actually is.
+               st.NumGC = 0
+               st.PauseNs = 0
+               t0 = time.Nanoseconds()
+
+               for i := 0; i < *n; i++ {
+                       parsed := make([]map[string]*ast.Package, *p)
+                       for j := range parsed {
+                               parsed[j] = parseDir(pkgroot + packages[j%len(packages)])
+                       }
+               }
+               runtime.GC()
+       }
+       t1 := time.Nanoseconds()
+
+       fmt.Printf("Alloc=%d/%d Heap=%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n",
+               st.Alloc, st.TotalAlloc,
+               st.Sys,
+               st.Mallocs, float64(st.PauseNs)/1e9,
+               st.NumGC, float64(st.PauseNs)/1e9/float64(st.NumGC))
+
+       fmt.Printf("%10s %10s %10s\n", "size", "#alloc", "#free")
+       for _, s := range st.BySize {
+               fmt.Printf("%10d %10d %10d\n", s.Size, s.Mallocs, s.Frees)
+       }
+
+       // Standard gotest benchmark output, collected by build dashboard.
+       fmt.Printf("garbage.BenchmarkParser %d %d ns/op\n", *n, (t1-t0)/int64(*n))
+       fmt.Printf("garbage.BenchmarkParserPause %d %d ns/op\n", st.NumGC, int64(st.PauseNs)/int64(st.NumGC))
+}
+
+
+var packages = []string{
+       "archive/tar",
+       "asn1",
+       "big",
+       "bufio",
+       "bytes",
+       "cmath",
+       "compress/flate",
+       "compress/gzip",
+       "compress/zlib",
+       "container/heap",
+       "container/list",
+       "container/ring",
+       "container/vector",
+       "crypto/aes",
+       "crypto/block",
+       "crypto/blowfish",
+       "crypto/hmac",
+       "crypto/md4",
+       "crypto/md5",
+       "crypto/rand",
+       "crypto/rc4",
+       "crypto/rsa",
+       "crypto/sha1",
+       "crypto/sha256",
+       "crypto/sha512",
+       "crypto/subtle",
+       "crypto/tls",
+       "crypto/x509",
+       "crypto/xtea",
+       "debug/dwarf",
+       "debug/macho",
+       "debug/elf",
+       "debug/gosym",
+       "debug/proc",
+       "ebnf",
+       "encoding/ascii85",
+       "encoding/base64",
+       "encoding/binary",
+       "encoding/git85",
+       "encoding/hex",
+       "encoding/pem",
+       "exec",
+       "exp/datafmt",
+       "exp/draw",
+       "exp/eval",
+       "exp/iterable",
+       "expvar",
+       "flag",
+       "fmt",
+       "go/ast",
+       "go/doc",
+       "go/parser",
+       "go/printer",
+       "go/scanner",
+       "go/token",
+       "gob",
+       "hash",
+       "hash/adler32",
+       "hash/crc32",
+       "hash/crc64",
+       "http",
+       "image",
+       "image/jpeg",
+       "image/png",
+       "io",
+       "io/ioutil",
+       "json",
+       "log",
+       "math",
+       "mime",
+       "net",
+       "nntp",
+       "os",
+       "os/signal",
+       "patch",
+       "path",
+       "rand",
+       "reflect",
+       "regexp",
+       "rpc",
+       "runtime",
+       "scanner",
+       "sort",
+       "strconv",
+       "strings",
+       "sync",
+       "syscall",
+       "syslog",
+       "tabwriter",
+       "template",
+       "testing",
+       "testing/iotest",
+       "testing/quick",
+       "testing/script",
+       "time",
+       "unicode",
+       "utf8",
+       "utf16",
+       "websocket",
+       "xml",
+}
diff --git a/gcc/testsuite/go.test/test/garbage/peano.go b/gcc/testsuite/go.test/test/garbage/peano.go
new file mode 100644 (file)
index 0000000..b026354
--- /dev/null
@@ -0,0 +1,137 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt"
+       "runtime"
+       "time"
+)
+
+
+type Number struct {
+       next *Number
+}
+
+
+// -------------------------------------
+// Peano primitives
+
+func zero() *Number { return nil }
+
+
+func is_zero(x *Number) bool { return x == nil }
+
+
+func add1(x *Number) *Number {
+       e := new(Number)
+       e.next = x
+       return e
+}
+
+
+func sub1(x *Number) *Number { return x.next }
+
+
+func add(x, y *Number) *Number {
+       if is_zero(y) {
+               return x
+       }
+
+       return add(add1(x), sub1(y))
+}
+
+
+func mul(x, y *Number) *Number {
+       if is_zero(x) || is_zero(y) {
+               return zero()
+       }
+
+       return add(mul(x, sub1(y)), x)
+}
+
+
+func fact(n *Number) *Number {
+       if is_zero(n) {
+               return add1(zero())
+       }
+
+       return mul(fact(sub1(n)), n)
+}
+
+
+// -------------------------------------
+// Helpers to generate/count Peano integers
+
+func gen(n int) *Number {
+       if n > 0 {
+               return add1(gen(n - 1))
+       }
+
+       return zero()
+}
+
+
+func count(x *Number) int {
+       if is_zero(x) {
+               return 0
+       }
+
+       return count(sub1(x)) + 1
+}
+
+
+func check(x *Number, expected int) {
+       var c = count(x)
+       if c != expected {
+               panic(fmt.Sprintf("error: found %d; expected %d", c, expected))
+       }
+}
+
+
+// -------------------------------------
+// Test basic functionality
+
+func verify() {
+       check(zero(), 0)
+       check(add1(zero()), 1)
+       check(gen(10), 10)
+
+       check(add(gen(3), zero()), 3)
+       check(add(zero(), gen(4)), 4)
+       check(add(gen(3), gen(4)), 7)
+
+       check(mul(zero(), zero()), 0)
+       check(mul(gen(3), zero()), 0)
+       check(mul(zero(), gen(4)), 0)
+       check(mul(gen(3), add1(zero())), 3)
+       check(mul(add1(zero()), gen(4)), 4)
+       check(mul(gen(3), gen(4)), 12)
+
+       check(fact(zero()), 1)
+       check(fact(add1(zero())), 1)
+       check(fact(gen(5)), 120)
+}
+
+
+// -------------------------------------
+// Factorial
+
+
+func main() {
+       st := &runtime.MemStats
+       t0 := time.Nanoseconds()
+       verify()
+       for i := 0; i <= 9; i++ {
+               print(i, "! = ", count(fact(gen(i))), "\n")
+       }
+       runtime.GC()
+       t1 := time.Nanoseconds()
+
+       fmt.Printf("garbage.BenchmarkPeano 1 %d ns/op\n", t1-t0)
+       fmt.Printf("garbage.BenchmarkPeanoPause %d %d ns/op\n", st.NumGC, int64(st.PauseNs)/int64(st.NumGC))
+}
diff --git a/gcc/testsuite/go.test/test/garbage/tree.go b/gcc/testsuite/go.test/test/garbage/tree.go
new file mode 100644 (file)
index 0000000..816693f
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+    name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on C program by Kevin Carson
+ */
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "runtime"
+       "time"
+)
+
+var n = flag.Int("n", 16, "depth")
+
+type Node struct {
+       item        int
+       left, right *Node
+}
+
+func bottomUpTree(item, depth int) *Node {
+       if depth <= 0 {
+               return &Node{item: item}
+       }
+       return &Node{item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1)}
+}
+
+func (n *Node) itemCheck() int {
+       if n.left == nil {
+               return n.item
+       }
+       return n.item + n.left.itemCheck() - n.right.itemCheck()
+}
+
+const minDepth = 4
+
+func main() {
+       flag.Parse()
+
+       t0 := time.Nanoseconds()
+
+       maxDepth := *n
+       if minDepth+2 > *n {
+               maxDepth = minDepth + 2
+       }
+       stretchDepth := maxDepth + 1
+
+       check := bottomUpTree(0, stretchDepth).itemCheck()
+       fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
+
+       longLivedTree := bottomUpTree(0, maxDepth)
+
+       for depth := minDepth; depth <= maxDepth; depth += 2 {
+               iterations := 1 << uint(maxDepth-depth+minDepth)
+               check = 0
+
+               for i := 1; i <= iterations; i++ {
+                       check += bottomUpTree(i, depth).itemCheck()
+                       check += bottomUpTree(-i, depth).itemCheck()
+               }
+               fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
+       }
+       fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
+
+       t1 := time.Nanoseconds()
+       st := &runtime.MemStats
+
+       // Standard gotest benchmark output, collected by build dashboard.
+       fmt.Printf("garbage.BenchmarkTree %d %d ns/op\n", *n, (t1-t0)/int64(*n))
+       fmt.Printf("garbage.BenchmarkTreePause %d %d ns/op\n", st.NumGC, int64(st.PauseNs)/int64(st.NumGC))
+
+}
diff --git a/gcc/testsuite/go.test/test/gc.go b/gcc/testsuite/go.test/test/gc.go
new file mode 100644 (file)
index 0000000..3aab8fa
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+func mk2() {
+       b := new([10000]byte)
+       _ = b
+       //      println(b, "stored at", &b)
+}
+
+func mk1() { mk2() }
+
+func main() {
+       for i := 0; i < 10; i++ {
+               mk1()
+               runtime.GC()
+       }
+}
diff --git a/gcc/testsuite/go.test/test/gc1.go b/gcc/testsuite/go.test/test/gc1.go
new file mode 100644 (file)
index 0000000..84034e7
--- /dev/null
@@ -0,0 +1,14 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       for i := 0; i < 1e5; i++ {
+               x := new([100]byte)
+               _ = x
+       }
+}
diff --git a/gcc/testsuite/go.test/test/golden-arm.out b/gcc/testsuite/go.test/test/golden-arm.out
new file mode 100644 (file)
index 0000000..41829fb
--- /dev/null
@@ -0,0 +1,131 @@
+
+=========== ./cmp2.go
+panic: runtime error: comparing uncomparable type []int
+
+panic PC=xxx
+
+=========== ./cmp3.go
+panic: runtime error: comparing uncomparable type []int
+
+panic PC=xxx
+
+=========== ./cmp4.go
+panic: runtime error: hash of unhashable type []int
+
+panic PC=xxx
+
+=========== ./cmp5.go
+panic: runtime error: hash of unhashable type []int
+
+panic PC=xxx
+
+=========== ./deferprint.go
+printing: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+42 true false true +1.500000e+000 world 0x0 [0/0]0x0 0x0 0x0 255
+
+=========== ./helloworld.go
+hello, world
+
+=========== ./peano.go
+0! = 1
+1! = 1
+2! = 2
+3! = 6
+4! = 24
+5! = 120
+6! = 720
+7! = 5040
+8! = 40320
+9! = 362880
+
+=========== ./printbig.go
+-9223372036854775808
+9223372036854775807
+
+=========== ./sigchld.go
+survived SIGCHLD
+
+=========== ./sinit.go
+FAIL
+
+=========== ./turing.go
+Hello World!
+
+=========== ken/intervar.go
+ print 1 bio 2 file 3 -- abc
+
+=========== ken/label.go
+100
+
+=========== ken/rob1.go
+9876543210
+
+=========== ken/rob2.go
+(defn foo (add 12 34))
+
+=========== ken/simpprint.go
+hello world
+
+=========== ken/simpswitch.go
+0out01out12out2aout34out4fiveout56out6aout78out89out9
+
+=========== ken/string.go
+abcxyz-abcxyz-abcxyz-abcxyz-abcxyz-abcxyz-abcxyz
+
+=========== chan/doubleselect.go
+PASS
+
+=========== chan/nonblock.go
+PASS
+
+=========== interface/fail.go
+panic: interface conversion: *main.S is not main.I: missing method Foo
+
+panic PC=xxx
+
+=========== interface/returntype.go
+panic: interface conversion: *main.S is not main.I2: missing method Name
+
+panic PC=xxx
+
+=========== fixedbugs/bug016.go
+fixedbugs/bug016.go:11: constant -3 overflows uint
+
+=========== fixedbugs/bug027.go
+hi
+0 44444
+1 3333
+2 222
+3 11
+4 0
+0 44444
+1 3333
+2 222
+3 11
+4 0
+
+=========== fixedbugs/bug067.go
+ok
+
+=========== fixedbugs/bug070.go
+outer loop top k 0
+inner loop top i 0
+do break
+broke
+
+=========== fixedbugs/bug081.go
+fixedbugs/bug081.go:9: typechecking loop
+
+=========== fixedbugs/bug093.go
+M
+
+=========== fixedbugs/bug113.go
+panic: interface conversion: interface is int, not int32
+
+panic PC=xxx
+
+=========== fixedbugs/bug148.go
+2 3
+panic: interface conversion: interface is main.T, not main.T
+
+panic PC=xxx
diff --git a/gcc/testsuite/go.test/test/golden.out b/gcc/testsuite/go.test/test/golden.out
new file mode 100644 (file)
index 0000000..49bca4b
--- /dev/null
@@ -0,0 +1,179 @@
+
+== ./
+
+=========== ./cmp2.go
+panic: runtime error: comparing uncomparable type []int
+
+panic PC=xxx
+
+=========== ./cmp3.go
+panic: runtime error: comparing uncomparable type []int
+
+panic PC=xxx
+
+=========== ./cmp4.go
+panic: runtime error: hash of unhashable type []int
+
+panic PC=xxx
+
+=========== ./cmp5.go
+panic: runtime error: hash of unhashable type []int
+
+panic PC=xxx
+
+=========== ./deferprint.go
+printing: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+42 true false true +1.500000e+000 world 0x0 [0/0]0x0 0x0 0x0 255
+
+=========== ./helloworld.go
+hello, world
+
+=========== ./peano.go
+0! = 1
+1! = 1
+2! = 2
+3! = 6
+4! = 24
+5! = 120
+6! = 720
+7! = 5040
+8! = 40320
+9! = 362880
+
+=========== ./printbig.go
+-9223372036854775808
+9223372036854775807
+
+=========== ./sigchld.go
+survived SIGCHLD
+
+=========== ./sinit.go
+FAIL
+
+=========== ./turing.go
+Hello World!
+
+== ken/
+
+=========== ken/cplx0.go
+(+5.000000e+000+6.000000e+000i)
+(+5.000000e+000+6.000000e+000i)
+(+5.000000e+000+6.000000e+000i)
+(+5.000000e+000+6.000000e+000i)
+
+=========== ken/cplx3.go
+(+1.292308e+000-1.384615e-001i)
+(+1.292308e+000-1.384615e-001i)
+64
+
+=========== ken/cplx4.go
+c = (-5.000000-6.000000i)
+c = (5.000000+6.000000i)
+c = (5.000000+6.000000i)
+c = (5.000000+6.000000i)
+c = (5+6i)
+c = (13+7i)
+
+=========== ken/cplx5.go
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+
+=========== ken/intervar.go
+ print 1 bio 2 file 3 -- abc
+
+=========== ken/label.go
+100
+
+=========== ken/rob1.go
+9876543210
+
+=========== ken/rob2.go
+(defn foo (add 12 34))
+
+=========== ken/simpprint.go
+hello world
+
+=========== ken/simpswitch.go
+0out01out12out2aout34out4fiveout56out6aout78out89out9
+
+=========== ken/string.go
+abcxyz-abcxyz-abcxyz-abcxyz-abcxyz-abcxyz-abcxyz
+
+== chan/
+
+=========== chan/doubleselect.go
+PASS
+
+=========== chan/nonblock.go
+PASS
+
+== interface/
+
+=========== interface/fail.go
+panic: interface conversion: *main.S is not main.I: missing method Foo
+
+panic PC=xxx
+
+=========== interface/returntype.go
+panic: interface conversion: *main.S is not main.I2: missing method Name
+
+panic PC=xxx
+
+== nilptr/
+
+== syntax/
+
+== fixedbugs/
+
+=========== fixedbugs/bug016.go
+fixedbugs/bug016.go:11: constant -3 overflows uint
+
+=========== fixedbugs/bug027.go
+hi
+0 44444
+1 3333
+2 222
+3 11
+4 0
+0 44444
+1 3333
+2 222
+3 11
+4 0
+
+=========== fixedbugs/bug067.go
+ok
+
+=========== fixedbugs/bug070.go
+outer loop top k 0
+inner loop top i 0
+do break
+broke
+
+=========== fixedbugs/bug081.go
+fixedbugs/bug081.go:9: typechecking loop
+
+=========== fixedbugs/bug093.go
+M
+
+=========== fixedbugs/bug113.go
+panic: interface conversion: interface is int, not int32
+
+panic PC=xxx
+
+=========== fixedbugs/bug148.go
+2 3
+panic: interface conversion: interface is main.T, not main.T
+
+panic PC=xxx
+
+== bugs/
+
+=========== bugs/bug260.go
+FAIL
+BUG: bug260 failed
diff --git a/gcc/testsuite/go.test/test/hashmap.go b/gcc/testsuite/go.test/test/hashmap.go
new file mode 100755 (executable)
index 0000000..096ece0
--- /dev/null
@@ -0,0 +1,181 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// ----------------------------------------------------------------------------
+// Helper functions
+
+func ASSERT(p bool) {
+       if !p {
+               // panic 0
+       }
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of the HashMap
+
+type KeyType interface {
+       Hash() uint32
+       Match(other *KeyType) bool
+}
+
+
+type ValueType interface {
+       // empty interface
+}
+
+
+type Entry struct {
+       key *KeyType
+       value *ValueType
+}
+
+
+type Array [1024]Entry
+
+type HashMap struct {
+       map_ *Array
+       log2_capacity_ uint32
+       occupancy_ uint32
+}
+
+
+func (m *HashMap) capacity() uint32 {
+       return 1 << m.log2_capacity_
+}
+
+
+func (m *HashMap) Clear() {
+       // Mark all entries as empty.
+       var i uint32 = m.capacity() - 1
+       for i > 0 {
+               m.map_[i].key = nil
+               i = i - 1
+       }
+       m.occupancy_ = 0
+}
+
+
+func (m *HashMap) Initialize (initial_log2_capacity uint32) {
+       m.log2_capacity_ = initial_log2_capacity
+       m.map_ = new(Array)
+       m.Clear()
+}
+
+
+func (m *HashMap) Probe (key *KeyType) *Entry {
+       ASSERT(key != nil)
+
+       var i uint32 = key.Hash() % m.capacity()
+       ASSERT(0 <= i && i < m.capacity())
+
+       ASSERT(m.occupancy_ < m.capacity())     // guarantees loop termination
+       for m.map_[i].key != nil && !m.map_[i].key.Match(key) {
+               i++
+               if i >= m.capacity() {
+                       i = 0
+               }
+       }
+
+       return &m.map_[i]
+}
+
+
+func (m *HashMap) Lookup (key *KeyType, insert bool) *Entry {
+       // Find a matching entry.
+       var p *Entry = m.Probe(key)
+               if p.key != nil {
+               return p
+       }
+
+       // No entry found; insert one if necessary.
+       if insert {
+               p.key = key
+               p.value = nil
+               m.occupancy_++
+
+               // Grow the map if we reached >= 80% occupancy.
+               if m.occupancy_ + m.occupancy_/4 >= m.capacity() {
+                       m.Resize()
+                       p = m.Probe(key)
+               }
+
+               return p
+       }
+
+       // No entry found and none inserted.
+       return nil
+}
+
+
+func (m *HashMap) Resize() {
+       var hmap *Array = m.map_
+       var n uint32 = m.occupancy_
+
+       // Allocate a new map of twice the current size.
+       m.Initialize(m.log2_capacity_ << 1)
+
+       // Rehash all current entries.
+       var i uint32 = 0
+       for n > 0 {
+               if hmap[i].key != nil {
+                       m.Lookup(hmap[i].key, true).value = hmap[i].value
+                       n = n - 1
+               }
+               i++
+       }
+}
+
+
+// ----------------------------------------------------------------------------
+// Test code
+
+type Number struct {
+       x uint32
+}
+
+
+func (n *Number) Hash() uint32 {
+       return n.x * 23
+}
+
+
+func (n *Number) Match(other *KeyType) bool {
+       // var y *Number = other
+       // return n.x == y.x
+       return false
+}
+
+
+func MakeNumber (x uint32) *Number {
+       var n *Number = new(Number)
+       n.x = x
+       return n
+}
+
+
+func main() {
+       // func (n int) int { return n + 1; }(1)
+
+       //print "HashMap - gri 2/8/2008\n"
+
+       var hmap *HashMap = new(HashMap)
+       hmap.Initialize(0)
+
+       var x1 *Number = MakeNumber(1001)
+       var x2 *Number = MakeNumber(2002)
+       var x3 *Number = MakeNumber(3003)
+       _, _, _ = x1, x2, x3
+
+       // this doesn't work I think...
+       //hmap.Lookup(x1, true)
+       //hmap.Lookup(x2, true)
+       //hmap.Lookup(x3, true)
+
+       //print "done\n"
+}
diff --git a/gcc/testsuite/go.test/test/helloworld.go b/gcc/testsuite/go.test/test/helloworld.go
new file mode 100644 (file)
index 0000000..e55a74b
--- /dev/null
@@ -0,0 +1,11 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       print("hello, world\n")
+}
diff --git a/gcc/testsuite/go.test/test/if.go b/gcc/testsuite/go.test/test/if.go
new file mode 100644 (file)
index 0000000..db1fe8b
--- /dev/null
@@ -0,0 +1,99 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func assertequal(is, shouldbe int, msg string) {
+       if is != shouldbe {
+               print("assertion fail", msg, "\n")
+               panic(1)
+       }
+}
+
+func main() {
+       i5 := 5
+       i7 := 7
+
+       var count int
+
+       count = 0
+       if true {
+               count = count + 1
+       }
+       assertequal(count, 1, "if true")
+
+       count = 0
+       if false {
+               count = count + 1
+       }
+       assertequal(count, 0, "if false")
+
+       count = 0
+       if one := 1; true {
+               count = count + one
+       }
+       assertequal(count, 1, "if true one")
+
+       count = 0
+       if one := 1; false {
+               count = count + 1
+               _ = one
+       }
+       assertequal(count, 0, "if false one")
+
+       count = 0
+       if {
+               count = count + 1
+       }
+       assertequal(count, 1, "if empty")
+
+       count = 0
+       if one := 1; true {
+               count = count + one
+       }
+       assertequal(count, 1, "if empty one")
+
+       count = 0
+       if i5 < i7 {
+               count = count + 1
+       }
+       assertequal(count, 1, "if cond")
+
+       count = 0
+       if true {
+               count = count + 1
+       } else
+               count = count - 1
+       assertequal(count, 1, "if else true")
+
+       count = 0
+       if false {
+               count = count + 1
+       } else
+               count = count - 1
+       assertequal(count, -1, "if else false")
+
+       count = 0
+       if t:=1; false {
+               count = count + 1
+               _ = t
+               t := 7
+               _ = t
+       } else
+               count = count - t
+       assertequal(count, -1, "if else false var")
+
+       count = 0
+       t := 1
+       if false {
+               count = count + 1
+               t := 7
+               _ = t
+       } else
+               count = count - t
+       _ = t
+       assertequal(count, -1, "if else false var outside")
+}
diff --git a/gcc/testsuite/go.test/test/if1.go b/gcc/testsuite/go.test/test/if1.go
new file mode 100644 (file)
index 0000000..061c364
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+       count := 7
+       if one := 1; {
+               count = count + one
+       }
+       if count != 8 {
+               print(count, " should be 8\n")
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/import.go b/gcc/testsuite/go.test/test/import.go
new file mode 100644 (file)
index 0000000..9633034
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// check that when import gives multiple names
+// to a type, they're still all the same type
+
+package main
+
+import _os_ "os"
+import "os"
+import . "os"
+
+func f(e os.Error)
+
+func main() {
+       var _e_ _os_.Error
+       var dot Error
+
+       f(_e_)
+       f(dot)
+}
+
diff --git a/gcc/testsuite/go.test/test/import1.go b/gcc/testsuite/go.test/test/import1.go
new file mode 100644 (file)
index 0000000..8bb2a94
--- /dev/null
@@ -0,0 +1,17 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// check for import conflicts
+
+package main
+
+import "bufio" // GCCGO_ERROR "previous|not used"
+import bufio "os"      // ERROR "redeclared|redefinition|incompatible"
+
+import (
+       "fmt"   // GCCGO_ERROR "previous|not used"
+       fmt "math"      // ERROR "redeclared|redefinition|incompatible"
+)
diff --git a/gcc/testsuite/go.test/test/import2.go b/gcc/testsuite/go.test/test/import2.go
new file mode 100644 (file)
index 0000000..0efc285
--- /dev/null
@@ -0,0 +1,42 @@
+// true  # used by import3
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+var C1 chan <- chan int = (chan<- (chan int))(nil)
+var C2 chan (<- chan int) = (chan (<-chan int))(nil)
+var C3 <- chan chan int = (<-chan (chan int))(nil)
+var C4 chan chan <- int = (chan (chan<- int))(nil)
+
+var C5 <- chan <- chan int = (<-chan (<-chan int))(nil)
+var C6 chan <- <- chan int = (chan<- (<-chan int))(nil)
+var C7 chan <- chan <- int = (chan<- (chan<- int))(nil)
+
+var C8 <- chan <- chan chan int = (<-chan (<-chan (chan int)))(nil)
+var C9 <- chan chan <- chan int = (<-chan (chan<- (chan int)))(nil)
+var C10 chan <- <- chan chan int = (chan<- (<-chan (chan int)))(nil)
+var C11 chan <- chan <- chan int = (chan<- (chan<- (chan int)))(nil)
+var C12 chan chan <- <- chan int = (chan (chan<- (<-chan int)))(nil)
+var C13 chan chan <- chan <- int = (chan (chan<- (chan<- int)))(nil)
+
+var R1 chan<- (chan int) = (chan <- chan int)(nil)
+var R3 <-chan (chan int) = (<- chan chan int)(nil)
+var R4 chan (chan<- int) = (chan chan <- int)(nil)
+
+var R5 <-chan (<-chan int) = (<- chan <- chan int)(nil)
+var R6 chan<- (<-chan int) = (chan <- <- chan int)(nil)
+var R7 chan<- (chan<- int) = (chan <- chan <- int)(nil)
+
+var R8 <-chan (<-chan (chan int)) = (<- chan <- chan chan int)(nil)
+var R9 <-chan (chan<- (chan int)) = (<- chan chan <- chan int)(nil)
+var R10 chan<- (<-chan (chan int)) = (chan <- <- chan chan int)(nil)
+var R11 chan<- (chan<- (chan int)) = (chan <- chan <- chan int)(nil)
+var R12 chan (chan<- (<-chan int)) = (chan chan <- <- chan int)(nil)
+var R13 chan (chan<- (chan<- int)) = (chan chan <- chan <- int)(nil)
+
+var F1 func() func() int
+func F2() func() func() int
+func F3(func() func() int)
diff --git a/gcc/testsuite/go.test/test/import3.go b/gcc/testsuite/go.test/test/import3.go
new file mode 100644 (file)
index 0000000..e4900b9
--- /dev/null
@@ -0,0 +1,54 @@
+// $G $D/import2.go && $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that all the types from import2.go made it
+// intact and with the same meaning, by assigning to or using them.
+
+package main
+
+import "./import2"
+
+func f3(func() func() int)
+
+func main() {
+       p.F3(p.F1)
+       p.F3(p.F2())
+       f3(p.F1)
+       f3(p.F2())
+
+       p.C1 = (chan<- (chan int))(nil)
+       p.C2 = (chan (<-chan int))(nil)
+       p.C3 = (<-chan (chan int))(nil)
+       p.C4 = (chan (chan<- int))(nil)
+
+       p.C5 = (<-chan (<-chan int))(nil)
+       p.C6 = (chan<- (<-chan int))(nil)
+       p.C7 = (chan<- (chan<- int))(nil)
+
+       p.C8 = (<-chan (<-chan (chan int)))(nil)
+       p.C9 = (<-chan (chan<- (chan int)))(nil)
+       p.C10 = (chan<- (<-chan (chan int)))(nil)
+       p.C11 = (chan<- (chan<- (chan int)))(nil)
+       p.C12 = (chan (chan<- (<-chan int)))(nil)
+       p.C13 = (chan (chan<- (chan<- int)))(nil)
+
+       p.R1 = (chan <- chan int)(nil)
+       p.R3 = (<- chan chan int)(nil)
+       p.R4 = (chan chan <- int)(nil)
+
+       p.R5 = (<- chan <- chan int)(nil)
+       p.R6 = (chan <- <- chan int)(nil)
+       p.R7 = (chan <- chan <- int)(nil)
+
+       p.R8 = (<- chan <- chan chan int)(nil)
+       p.R9 = (<- chan chan <- chan int)(nil)
+       p.R10 = (chan <- <- chan chan int)(nil)
+       p.R11 = (chan <- chan <- chan int)(nil)
+       p.R12 = (chan chan <- <- chan int)(nil)
+       p.R13 = (chan chan <- chan <- int)(nil)
+
+}
+
diff --git a/gcc/testsuite/go.test/test/import4.go b/gcc/testsuite/go.test/test/import4.go
new file mode 100644 (file)
index 0000000..1ae1d0e
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $D/empty.go && errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// various kinds of imported and not used
+
+// standard
+import "fmt"   // ERROR "imported and not used.*fmt"
+
+// renamed
+import X "math"        // ERROR "imported and not used.*math"
+
+// import dot
+import . "bufio"       // ERROR "imported and not used.*bufio"
+
+// again, package without anything in it
+import "./empty"       // ERROR "imported and not used.*empty"
+import Z "./empty"     // ERROR "imported and not used.*empty"
+import . "./empty"     // ERROR "imported and not used.*empty"
+
diff --git a/gcc/testsuite/go.test/test/index.go b/gcc/testsuite/go.test/test/index.go
new file mode 100644 (file)
index 0000000..a91294c
--- /dev/null
@@ -0,0 +1,224 @@
+// $G $D/$F.go && $L $F.$A &&
+// ./$A.out -pass 0 >tmp.go && $G tmp.go && $L -o tmp1.$A tmp.$A && ./tmp1.$A &&
+// ./$A.out -pass 1 >tmp.go && errchk $G -e tmp.go &&
+// ./$A.out -pass 2 >tmp.go && errchk $G -e tmp.go
+// rm -f tmp.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate test of index and slice bounds checks.
+
+package main
+
+import (
+       "bufio"
+       "flag"
+       "fmt"
+       "os"
+)
+
+const prolog = `
+
+package main
+
+import (
+       "runtime"
+)
+
+type quad struct { x, y, z, w int }
+
+const (
+       cj = 11
+       ci int = 12
+       ci32 int32 = 13
+       ci64 int64 = 14
+       ci64big int64 = 1<<31
+       ci64bigger int64 = 1<<32
+       chuge = 1<<100
+
+       cnj = -2
+       cni int = -3
+       cni32 int32 = -4
+       cni64 int64 = -5
+       cni64big int64 = -1<<31
+       cni64bigger int64 = -1<<32
+       cnhuge = -1<<100
+)
+
+var j int = 20
+var i int = 21
+var i32 int32 = 22
+var i64 int64 = 23
+var i64big int64 = 1<<31
+var i64bigger int64 = 1<<32
+var huge uint64 = 1<<64 - 1
+
+var nj int = -10
+var ni int = -11
+var ni32 int32 = -12
+var ni64 int64 = -13
+var ni64big int64 = -1<<31
+var ni64bigger int64 = -1<<32
+var nhuge int64 = -1<<63
+
+var si []int = make([]int, 10)
+var ai [10]int
+var pai *[10]int = &ai
+
+var sq []quad = make([]quad, 10)
+var aq [10]quad
+var paq *[10]quad = &aq
+
+type T struct {
+       si []int
+       ai [10]int
+       pai *[10]int
+       sq []quad
+       aq [10]quad
+       paq *[10]quad
+}
+
+var t = T{si, ai, pai, sq, aq, paq}
+
+var pt = &T{si, ai, pai, sq, aq, paq}
+
+// test that f panics
+func test(f func(), s string) {
+       defer func() {
+               if err := recover(); err == nil {
+                       _, file, line, _ := runtime.Caller(2)
+                       bug()
+                       print(file, ":", line, ": ", s, " did not panic\n")
+               }
+       }()
+       f()
+}
+
+var X interface{}
+func use(y interface{}) {
+       X = y
+}
+
+var didBug = false
+
+func bug() {
+       if !didBug {
+               didBug = true
+               println("BUG")
+       }
+}
+
+func main() {
+`
+
+// Passes:
+//     0 - dynamic checks
+//     1 - static checks of invalid constants (cannot assign to types)
+//     2 - static checks of array bounds
+var pass = flag.Int("pass", 0, "which test (0,1,2)")
+
+func testExpr(b *bufio.Writer, expr string) {
+       if *pass == 0 {
+               fmt.Fprintf(b, "\ttest(func(){use(%s)}, %q)\n", expr, expr)
+       } else {
+               fmt.Fprintf(b, "\tuse(%s)  // ERROR \"index|overflow\"\n", expr)
+       }
+}
+
+func main() {
+       b := bufio.NewWriter(os.Stdout)
+
+       flag.Parse()
+       
+       if *pass == 0 {
+               fmt.Fprint(b, "// $G $D/$F.go && $L $F.$A && ./$A.out\n\n")
+       } else {
+               fmt.Fprint(b, "// errchk $G -e $D/$F.go\n\n")
+       }
+       fmt.Fprint(b, prolog)
+       
+       var choices = [][]string{
+               // Direct value, fetch from struct, fetch from struct pointer.
+               // The last two cases get us to oindex_const_sudo in gsubr.c.
+               []string{"", "t.", "pt."},
+               
+               // Array, pointer to array, slice.
+               []string{"a", "pa", "s"},
+
+               // Element is int, element is quad (struct).
+               // This controls whether we end up in gsubr.c (i) or cgen.c (q).
+               []string{"i", "q"},
+
+               // Variable or constant.
+               []string{"", "c"},
+
+               // Positive or negative.
+               []string{"", "n"},
+
+               // Size of index.
+               []string{"j", "i", "i32", "i64", "i64big", "i64bigger", "huge"},
+       }
+       
+       forall(choices, func(x []string) {
+               p, a, e, c, n, i := x[0], x[1], x[2], x[3], x[4], x[5]
+
+               // Pass: dynamic=0, static=1, 2.
+               // Which cases should be caught statically?
+               // Only constants, obviously.
+               // Beyond that, must be one of these:
+               //      indexing into array or pointer to array
+               //      negative constant
+               //      large constant
+               thisPass := 0
+               if c == "c" && (a == "a" || a == "pa" || n == "n" || i == "i64big" || i == "i64bigger" || i == "huge") {
+                       if i == "huge" {
+                               // Due to a detail of 6g's internals,
+                               // the huge constant errors happen in an
+                               // earlier pass than the others and inhibits
+                               // the next pass from running.
+                               // So run it as a separate check.
+                               thisPass = 1
+                       } else {
+                               thisPass = 2
+                       }
+               }
+
+               // Only print the test case if it is appropriate for this pass.
+               if thisPass == *pass {
+                       pae := p+a+e
+                       cni := c+n+i
+                       
+                       // Index operation
+                       testExpr(b, pae + "[" + cni + "]")
+                       
+                       // Slice operation.
+                       // Low index 0 is a special case in ggen.c
+                       // so test both 0 and 1.
+                       testExpr(b, pae + "[0:" + cni + "]")
+                       testExpr(b, pae + "[1:" + cni + "]")
+                       testExpr(b, pae + "[" + cni + ":]")
+                       testExpr(b, pae + "[" + cni + ":" + cni + "]")
+               }
+       })
+
+       fmt.Fprintln(b, "}")
+       b.Flush()
+}
+
+func forall(choices [][]string, f func([]string)) {
+       x := make([]string, len(choices))
+       
+       var recurse func(d int)
+       recurse = func(d int) {
+               if d >= len(choices) {
+                       f(x)
+                       return
+               }
+               for _, x[d] = range choices[d] {
+                       recurse(d+1)
+               }
+       }
+       recurse(0)
+}
diff --git a/gcc/testsuite/go.test/test/indirect.go b/gcc/testsuite/go.test/test/indirect.go
new file mode 100644 (file)
index 0000000..cfddde9
--- /dev/null
@@ -0,0 +1,85 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG indirect
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var m0 map[string]int
+var m1 *map[string]int
+var m2 *map[string]int = &m0
+var m3 map[string]int = map[string]int{"a": 1}
+var m4 *map[string]int = &m3
+
+var s0 string
+var s1 *string
+var s2 *string = &s0
+var s3 string = "a"
+var s4 *string = &s3
+
+var a0 [10]int
+var a1 *[10]int
+var a2 *[10]int = &a0
+
+var b0 []int
+var b1 *[]int
+var b2 *[]int = &b0
+var b3 []int = []int{1, 2, 3}
+var b4 *[]int = &b3
+
+func crash() {
+       // these uses of nil pointers
+       // would crash but should type check
+       println("crash",
+               len(a1)+cap(a1))
+}
+
+func nocrash() {
+       // this is spaced funny so that
+       // the compiler will print a different
+       // line number for each len call if
+       // it decides there are type errors.
+       // it might also help in the traceback.
+       x :=
+               len(m0) +
+                       len(m3)
+       if x != 1 {
+               println("wrong maplen")
+               panic("fail")
+       }
+
+       x =
+               len(s0) +
+                       len(s3)
+       if x != 1 {
+               println("wrong stringlen")
+               panic("fail")
+       }
+
+       x =
+               len(a0) +
+                       len(a2)
+       if x != 20 {
+               println("wrong arraylen")
+               panic("fail")
+       }
+
+       x =
+               len(b0) +
+                       len(b3)
+       if x != 3 {
+               println("wrong slicelen")
+               panic("fail")
+       }
+
+       x =
+               cap(b0) +
+                       cap(b3)
+       if x != 3 {
+               println("wrong slicecap")
+               panic("fail")
+       }
+}
+
+func main() { nocrash() }
diff --git a/gcc/testsuite/go.test/test/indirect1.go b/gcc/testsuite/go.test/test/indirect1.go
new file mode 100644 (file)
index 0000000..0fd5c19
--- /dev/null
@@ -0,0 +1,68 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var m0 map[string]int
+var m1 *map[string]int
+var m2 *map[string]int = &m0
+var m3 map[string]int = map[string]int{"a": 1}
+var m4 *map[string]int = &m3
+
+var s0 string
+var s1 *string
+var s2 *string = &s0
+var s3 string = "a"
+var s4 *string = &s3
+
+var a0 [10]int
+var a1 *[10]int
+var a2 *[10]int = &a0
+
+var b0 []int
+var b1 *[]int
+var b2 *[]int = &b0
+var b3 []int = []int{1, 2, 3}
+var b4 *[]int = &b3
+
+func f() {
+       // this is spaced funny so that
+       // the compiler will print a different
+       // line number for each len call when
+       // it decides there are type errors.
+       x :=
+               len(m0)+
+               len(m1)+        // ERROR "illegal|invalid|must be"
+               len(m2)+        // ERROR "illegal|invalid|must be"
+               len(m3)+
+               len(m4)+        // ERROR "illegal|invalid|must be"
+
+               len(s0)+
+               len(s1)+        // ERROR "illegal|invalid|must be"
+               len(s2)+        // ERROR "illegal|invalid|must be"
+               len(s3)+
+               len(s4)+        // ERROR "illegal|invalid|must be"
+
+               len(a0)+
+               len(a1)+
+               len(a2)+
+
+               cap(a0)+
+               cap(a1)+
+               cap(a2)+
+
+               len(b0)+
+               len(b1)+        // ERROR "illegal|invalid|must be"
+               len(b2)+        // ERROR "illegal|invalid|must be"
+               len(b3)+
+               len(b4)+        // ERROR "illegal|invalid|must be"
+
+               cap(b0)+
+               cap(b1)+        // ERROR "illegal|invalid|must be"
+               cap(b2)+        // ERROR "illegal|invalid|must be"
+               cap(b3)+
+               cap(b4) // ERROR "illegal|invalid|must be"
+}
diff --git a/gcc/testsuite/go.test/test/initcomma.go b/gcc/testsuite/go.test/test/initcomma.go
new file mode 100644 (file)
index 0000000..195d457
--- /dev/null
@@ -0,0 +1,79 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a = []int{1, 2}
+var b = [5]int{1, 2, 3}
+var c = []int{1}
+var d = [...]int{1, 2, 3}
+
+func main() {
+       if len(a) != 2 {
+               println("len a", len(a))
+               panic("fail")
+       }
+       if len(b) != 5 {
+               println("len b", len(b))
+               panic("fail")
+       }
+       if len(c) != 1 {
+               println("len d", len(c))
+               panic("fail")
+       }
+       if len(d) != 3 {
+               println("len c", len(d))
+               panic("fail")
+       }
+
+       if a[0] != 1 {
+               println("a[0]", a[0])
+               panic("fail")
+       }
+       if a[1] != 2 {
+               println("a[1]", a[1])
+               panic("fail")
+       }
+
+       if b[0] != 1 {
+               println("b[0]", b[0])
+               panic("fail")
+       }
+       if b[1] != 2 {
+               println("b[1]", b[1])
+               panic("fail")
+       }
+       if b[2] != 3 {
+               println("b[2]", b[2])
+               panic("fail")
+       }
+       if b[3] != 0 {
+               println("b[3]", b[3])
+               panic("fail")
+       }
+       if b[4] != 0 {
+               println("b[4]", b[4])
+               panic("fail")
+       }
+
+       if c[0] != 1 {
+               println("c[0]", c[0])
+               panic("fail")
+       }
+
+       if d[0] != 1 {
+               println("d[0]", d[0])
+               panic("fail")
+       }
+       if d[1] != 2 {
+               println("d[1]", d[1])
+               panic("fail")
+       }
+       if d[2] != 3 {
+               println("d[2]", d[2])
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/initialize.go b/gcc/testsuite/go.test/test/initialize.go
new file mode 100644 (file)
index 0000000..6dd7d67
--- /dev/null
@@ -0,0 +1,62 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+import "reflect"
+
+type S struct {
+       A, B, C, X, Y, Z int
+}
+
+type T struct {
+       S
+}
+
+var a1 = S { 0, 0, 0, 1, 2, 3 }
+var b1 = S { X: 1, Z: 3, Y: 2 }
+
+var a2 = S { 0, 0, 0, 0, 0, 0, }
+var b2 = S { }
+
+var a3 = T { S { 1, 2, 3, 0, 0, 0, } }
+var b3 = T { S: S{ A: 1, B: 2, C: 3 } }
+
+var a4 = &[16]byte { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, }
+var b4 = &[16]byte { 4: 1, 1, 1, 1, 12: 1, 1, }
+
+var a5 = &[16]byte { 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, }
+var b5 = &[16]byte { 1, 4: 1, 1, 1, 1, 12: 1, 1, }
+
+var a6 = &[16]byte { 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, }
+var b6 = &[...]byte { 1, 4: 1, 1, 1, 1, 12: 1, 1, 0, 0,}
+
+type Same struct {
+       a, b interface{}
+}
+
+var same = []Same {
+       Same{ a1, b1 },
+       Same{ a2, b2 },
+       Same{ a3, b3 },
+       Same{ a4, b4 },
+       Same{ a5, b5 },
+       Same{ a6, b6 },
+}
+
+func main() {
+       ok := true
+       for _, s := range same {
+               if !reflect.DeepEqual(s.a, s.b) {
+                       ok = false
+                       fmt.Printf("not same: %v and %v\n", s.a, s.b)
+               }
+       }
+       if !ok {
+               fmt.Println("BUG: test/initialize")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/initializerr.go b/gcc/testsuite/go.test/test/initializerr.go
new file mode 100644 (file)
index 0000000..37f8a60
--- /dev/null
@@ -0,0 +1,25 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S struct {
+       A, B, C, X, Y, Z int
+}
+
+type T struct {
+       S
+}
+
+var x = 1
+var a1 = S { 0, X: 1 } // ERROR "mixture|undefined"
+var a2 = S { Y: 3, Z: 2, Y: 3 } // ERROR "duplicate"
+var a3 = T { 1, 2, 3, 4, 5, 6 }        // ERROR "convert|too many"
+var a4 = [5]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }      // ERROR "index|too many"
+var a5 = []byte { x: 2 }       // ERROR "index"
+
+var ok1 = S { }        // should be ok
+var ok2 = T { S: ok1 } // should be ok
diff --git a/gcc/testsuite/go.test/test/initsyscall.go b/gcc/testsuite/go.test/test/initsyscall.go
new file mode 100644 (file)
index 0000000..b5e5812
--- /dev/null
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This used to crash because the scheduler
+// tried to kick off a new scheduling thread for f
+// when time.Nanoseconds went into the system call.
+// It's not okay to schedule new goroutines
+// until main has started.
+
+package main
+
+import "time"
+
+func f() {
+}
+
+func init() {
+       go f()
+       time.Nanoseconds()
+}
+
+func main() {
+}
+
diff --git a/gcc/testsuite/go.test/test/int_lit.go b/gcc/testsuite/go.test/test/int_lit.go
new file mode 100644 (file)
index 0000000..2644e17
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+       s :=    0 +
+               123 +
+               0123 +
+               0000 +
+               0x0 +
+               0x123 +
+               0X0 +
+               0X123
+       if s != 788 {
+               print("s is ", s, "; should be 788\n")
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/intcvt.go b/gcc/testsuite/go.test/test/intcvt.go
new file mode 100644 (file)
index 0000000..407bcfd
--- /dev/null
@@ -0,0 +1,179 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+       ci8  = -1 << 7
+       ci16 = -1<<15 + 100
+       ci32 = -1<<31 + 100000
+       ci64 = -1<<63 + 10000000001
+
+       cu8  = 1<<8 - 1
+       cu16 = 1<<16 - 1234
+       cu32 = 1<<32 - 1234567
+       cu64 = 1<<64 - 1234567890123
+
+       cf32 = 1e8 + 0.5
+       cf64 = -1e8 + 0.5
+)
+
+var (
+       i8  int8  = ci8
+       i16 int16 = ci16
+       i32 int32 = ci32
+       i64 int64 = ci64
+
+       u8  uint8  = cu8
+       u16 uint16 = cu16
+       u32 uint32 = cu32
+       u64 uint64 = cu64
+
+       //      f32 float32 = 1e8 + 0.5
+       //      f64 float64 = -1e8 + 0.5
+)
+
+func chki8(i, v int8) {
+       if i != v {
+               println(i, "!=", v)
+               panic("fail")
+       }
+}
+func chki16(i, v int16) {
+       if i != v {
+               println(i, "!=", v)
+               panic("fail")
+       }
+}
+func chki32(i, v int32) {
+       if i != v {
+               println(i, "!=", v)
+               panic("fail")
+       }
+}
+func chki64(i, v int64) {
+       if i != v {
+               println(i, "!=", v)
+               panic("fail")
+       }
+}
+func chku8(i, v uint8) {
+       if i != v {
+               println(i, "!=", v)
+               panic("fail")
+       }
+}
+func chku16(i, v uint16) {
+       if i != v {
+               println(i, "!=", v)
+               panic("fail")
+       }
+}
+func chku32(i, v uint32) {
+       if i != v {
+               println(i, "!=", v)
+               panic("fail")
+       }
+}
+func chku64(i, v uint64) {
+       if i != v {
+               println(i, "!=", v)
+               panic("fail")
+       }
+}
+//func chkf32(f, v float32) { if f != v { println(f, "!=", v); panic("fail") } }
+//func chkf64(f, v float64) { if f != v { println(f, "!=", v); panic("fail") } }
+
+func main() {
+       chki8(int8(i8), ci8&0xff-1<<8)
+       chki8(int8(i16), ci16&0xff)
+       chki8(int8(i32), ci32&0xff-1<<8)
+       chki8(int8(i64), ci64&0xff)
+       chki8(int8(u8), cu8&0xff-1<<8)
+       chki8(int8(u16), cu16&0xff)
+       chki8(int8(u32), cu32&0xff)
+       chki8(int8(u64), cu64&0xff)
+       //      chki8(int8(f32), 0)
+       //      chki8(int8(f64), 0)
+
+       chki16(int16(i8), ci8&0xffff-1<<16)
+       chki16(int16(i16), ci16&0xffff-1<<16)
+       chki16(int16(i32), ci32&0xffff-1<<16)
+       chki16(int16(i64), ci64&0xffff-1<<16)
+       chki16(int16(u8), cu8&0xffff)
+       chki16(int16(u16), cu16&0xffff-1<<16)
+       chki16(int16(u32), cu32&0xffff)
+       chki16(int16(u64), cu64&0xffff-1<<16)
+       //      chki16(int16(f32), 0)
+       //      chki16(int16(f64), 0)
+
+       chki32(int32(i8), ci8&0xffffffff-1<<32)
+       chki32(int32(i16), ci16&0xffffffff-1<<32)
+       chki32(int32(i32), ci32&0xffffffff-1<<32)
+       chki32(int32(i64), ci64&0xffffffff)
+       chki32(int32(u8), cu8&0xffffffff)
+       chki32(int32(u16), cu16&0xffffffff)
+       chki32(int32(u32), cu32&0xffffffff-1<<32)
+       chki32(int32(u64), cu64&0xffffffff-1<<32)
+       //      chki32(int32(f32), 0)
+       //      chki32(int32(f64), 0)
+
+       chki64(int64(i8), ci8&0xffffffffffffffff-1<<64)
+       chki64(int64(i16), ci16&0xffffffffffffffff-1<<64)
+       chki64(int64(i32), ci32&0xffffffffffffffff-1<<64)
+       chki64(int64(i64), ci64&0xffffffffffffffff-1<<64)
+       chki64(int64(u8), cu8&0xffffffffffffffff)
+       chki64(int64(u16), cu16&0xffffffffffffffff)
+       chki64(int64(u32), cu32&0xffffffffffffffff)
+       chki64(int64(u64), cu64&0xffffffffffffffff-1<<64)
+       //      chki64(int64(f32), 0)
+       //      chki64(int64(f64), 0)
+
+
+       chku8(uint8(i8), ci8&0xff)
+       chku8(uint8(i16), ci16&0xff)
+       chku8(uint8(i32), ci32&0xff)
+       chku8(uint8(i64), ci64&0xff)
+       chku8(uint8(u8), cu8&0xff)
+       chku8(uint8(u16), cu16&0xff)
+       chku8(uint8(u32), cu32&0xff)
+       chku8(uint8(u64), cu64&0xff)
+       //      chku8(uint8(f32), 0)
+       //      chku8(uint8(f64), 0)
+
+       chku16(uint16(i8), ci8&0xffff)
+       chku16(uint16(i16), ci16&0xffff)
+       chku16(uint16(i32), ci32&0xffff)
+       chku16(uint16(i64), ci64&0xffff)
+       chku16(uint16(u8), cu8&0xffff)
+       chku16(uint16(u16), cu16&0xffff)
+       chku16(uint16(u32), cu32&0xffff)
+       chku16(uint16(u64), cu64&0xffff)
+       //      chku16(uint16(f32), 0)
+       //      chku16(uint16(f64), 0)
+
+       chku32(uint32(i8), ci8&0xffffffff)
+       chku32(uint32(i16), ci16&0xffffffff)
+       chku32(uint32(i32), ci32&0xffffffff)
+       chku32(uint32(i64), ci64&0xffffffff)
+       chku32(uint32(u8), cu8&0xffffffff)
+       chku32(uint32(u16), cu16&0xffffffff)
+       chku32(uint32(u32), cu32&0xffffffff)
+       chku32(uint32(u64), cu64&0xffffffff)
+       //      chku32(uint32(f32), 0)
+       //      chku32(uint32(f64), 0)
+
+       chku64(uint64(i8), ci8&0xffffffffffffffff)
+       chku64(uint64(i16), ci16&0xffffffffffffffff)
+       chku64(uint64(i32), ci32&0xffffffffffffffff)
+       chku64(uint64(i64), ci64&0xffffffffffffffff)
+       chku64(uint64(u8), cu8&0xffffffffffffffff)
+       chku64(uint64(u16), cu16&0xffffffffffffffff)
+       chku64(uint64(u32), cu32&0xffffffffffffffff)
+       chku64(uint64(u64), cu64&0xffffffffffffffff)
+       //      chku64(uint64(f32), 0)
+       //      chku64(uint64(f64), 0)
+}
diff --git a/gcc/testsuite/go.test/test/interface/bigdata.go b/gcc/testsuite/go.test/test/interface/bigdata.go
new file mode 100644 (file)
index 0000000..44f6ab1
--- /dev/null
@@ -0,0 +1,75 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// check that big vs small, pointer vs not
+// interface methods work.
+
+package main
+
+type I interface { M() int64 }
+
+type BigPtr struct { a, b, c, d int64 }
+func (z *BigPtr) M() int64 { return z.a+z.b+z.c+z.d }
+
+type SmallPtr struct { a int32 }
+func (z *SmallPtr) M() int64 { return int64(z.a) }
+
+type IntPtr int32
+func (z *IntPtr) M() int64 { return int64(*z) }
+
+var bad bool
+
+func test(name string, i I) {
+       m := i.M()
+       if m != 12345 {
+               println(name, m)
+               bad = true
+       }
+}
+
+func ptrs() {
+       var bigptr BigPtr = BigPtr{ 10000, 2000, 300, 45 }
+       var smallptr SmallPtr = SmallPtr{ 12345 }
+       var intptr IntPtr = 12345
+
+//     test("bigptr", bigptr)
+       test("&bigptr", &bigptr)
+//     test("smallptr", smallptr)
+       test("&smallptr", &smallptr)
+//     test("intptr", intptr)
+       test("&intptr", &intptr)
+}
+
+type Big struct { a, b, c, d int64 }
+func (z Big) M() int64 { return z.a+z.b+z.c+z.d }
+
+type Small struct { a int32 }
+func (z Small) M() int64 { return int64(z.a) }
+
+type Int int32
+func (z Int) M() int64 { return int64(z) }
+
+func nonptrs() {
+       var big Big = Big{ 10000, 2000, 300, 45 }
+       var small Small = Small{ 12345 }
+       var int Int = 12345
+
+       test("big", big)
+       test("&big", &big)
+       test("small", small)
+       test("&small", &small)
+       test("int", int)
+       test("&int", &int)
+}
+
+func main() {
+       ptrs()
+       nonptrs()
+
+       if bad {
+               println("BUG: interface4")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/interface/convert.go b/gcc/testsuite/go.test/test/interface/convert.go
new file mode 100644 (file)
index 0000000..7f429f7
--- /dev/null
@@ -0,0 +1,147 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check uses of all the different interface
+// conversion runtime functions.
+
+package main
+
+type Stringer interface {
+       String() string
+}
+type StringLengther interface {
+       String() string
+       Length() int
+}
+type Empty interface{}
+
+type T string
+
+func (t T) String() string {
+       return string(t)
+}
+func (t T) Length() int {
+       return len(t)
+}
+
+type U string
+
+func (u U) String() string {
+       return string(u)
+}
+
+var t = T("hello")
+var u = U("goodbye")
+var e Empty
+var s Stringer = t
+var sl StringLengther = t
+var i int
+var ok bool
+
+func hello(s string) {
+       if s != "hello" {
+               println("not hello: ", s)
+               panic("fail")
+       }
+}
+
+func five(i int) {
+       if i != 5 {
+               println("not 5: ", i)
+               panic("fail")
+       }
+}
+
+func true(ok bool) {
+       if !ok {
+               panic("not true")
+       }
+}
+
+func false(ok bool) {
+       if ok {
+               panic("not false")
+       }
+}
+
+func main() {
+       // T2I
+       s = t
+       hello(s.String())
+
+       // I2T
+       t = s.(T)
+       hello(t.String())
+
+       // T2E
+       e = t
+
+       // E2T
+       t = e.(T)
+       hello(t.String())
+
+       // T2I again
+       sl = t
+       hello(sl.String())
+       five(sl.Length())
+
+       // I2I static
+       s = sl
+       hello(s.String())
+
+       // I2I dynamic
+       sl = s.(StringLengther)
+       hello(sl.String())
+       five(sl.Length())
+
+       // I2E (and E2T)
+       e = s
+       hello(e.(T).String())
+
+       // E2I
+       s = e.(Stringer)
+       hello(s.String())
+
+       // I2T2 true
+       t, ok = s.(T)
+       true(ok)
+       hello(t.String())
+
+       // I2T2 false
+       _, ok = s.(U)
+       false(ok)
+
+       // I2I2 true
+       sl, ok = s.(StringLengther)
+       true(ok)
+       hello(sl.String())
+       five(sl.Length())
+
+       // I2I2 false (and T2I)
+       s = u
+       sl, ok = s.(StringLengther)
+       false(ok)
+
+       // E2T2 true
+       t, ok = e.(T)
+       true(ok)
+       hello(t.String())
+
+       // E2T2 false
+       i, ok = e.(int)
+       false(ok)
+
+       // E2I2 true
+       sl, ok = e.(StringLengther)
+       true(ok)
+       hello(sl.String())
+       five(sl.Length())
+
+       // E2I2 false (and T2E)
+       e = u
+       sl, ok = e.(StringLengther)
+       false(ok)
+}
diff --git a/gcc/testsuite/go.test/test/interface/convert1.go b/gcc/testsuite/go.test/test/interface/convert1.go
new file mode 100644 (file)
index 0000000..658b1a9
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that static interface conversion of
+// interface value nil succeeds.
+
+package main
+
+type R interface { R() }
+type RW interface { R(); W() }
+
+var e interface {}
+var r R
+var rw RW
+
+func main() {
+       r = r
+       r = rw
+       e = r
+       e = rw
+       rw = rw
+}
diff --git a/gcc/testsuite/go.test/test/interface/convert2.go b/gcc/testsuite/go.test/test/interface/convert2.go
new file mode 100644 (file)
index 0000000..658b1a9
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that static interface conversion of
+// interface value nil succeeds.
+
+package main
+
+type R interface { R() }
+type RW interface { R(); W() }
+
+var e interface {}
+var r R
+var rw RW
+
+func main() {
+       r = r
+       r = rw
+       e = r
+       e = rw
+       rw = rw
+}
diff --git a/gcc/testsuite/go.test/test/interface/embed.go b/gcc/testsuite/go.test/test/interface/embed.go
new file mode 100644 (file)
index 0000000..4a70239
--- /dev/null
@@ -0,0 +1,82 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check methods derived from embedded interface and *interface values.
+
+package main
+
+import "os"
+
+const Value = 1e12
+
+type Inter interface { M() int64 }
+
+type T int64
+func (t T) M() int64 { return int64(t) }
+var t = T(Value)
+var pt = &t
+var ti Inter = t
+var pti = &ti
+
+type S struct { Inter }
+var s = S{ ti }
+var ps = &s
+
+type SP struct { *Inter }
+var sp = SP{ &ti }
+var psp = &sp
+
+var i Inter
+var pi = &i
+
+var ok = true
+
+func check(s string, v int64) {
+       if v != Value {
+               println(s, v)
+               ok = false
+       }
+}
+
+func main() {
+       check("t.M()", t.M())
+       check("pt.M()", pt.M())
+       check("ti.M()", ti.M())
+       check("pti.M()", pti.M())
+       check("s.M()", s.M())
+       check("ps.M()", ps.M())
+       check("sp.M()", sp.M())
+       check("psp.M()", psp.M())
+
+       i = t
+       check("i = t; i.M()", i.M())
+       check("i = t; pi.M()", pi.M())
+
+       i = pt
+       check("i = pt; i.M()", i.M())
+       check("i = pt; pi.M()", pi.M())
+
+       i = s
+       check("i = s; i.M()", i.M())
+       check("i = s; pi.M()", pi.M())
+
+       i = ps
+       check("i = ps; i.M()", i.M())
+       check("i = ps; pi.M()", pi.M())
+
+       i = sp
+       check("i = sp; i.M()", i.M())
+       check("i = sp; pi.M()", pi.M())
+
+       i = psp
+       check("i = psp; i.M()", i.M())
+       check("i = psp; pi.M()", pi.M())
+
+       if !ok {
+               println("BUG: interface10")
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/interface/embed0.go b/gcc/testsuite/go.test/test/interface/embed0.go
new file mode 100644 (file)
index 0000000..bbd81e7
--- /dev/null
@@ -0,0 +1,29 @@
+// true        # used by embed1.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that embedded interface types can have local methods.
+
+package p
+
+type T int
+func (t T) m() {}
+
+type I interface { m() }
+type J interface { I }
+
+func main() {
+       var i I
+       var j J
+       var t T
+       i = t
+       j = t
+       _ = i
+       _ = j
+       i = j
+       _ = i
+       j = i
+       _ = j
+}
diff --git a/gcc/testsuite/go.test/test/interface/embed1.go b/gcc/testsuite/go.test/test/interface/embed1.go
new file mode 100644 (file)
index 0000000..24e5047
--- /dev/null
@@ -0,0 +1,45 @@
+// $G $D/embed0.go && $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that embedded interface types can have local methods.
+
+package main
+
+import "./embed0"
+
+type T int
+func (t T) m() {}
+
+type I interface { m() }
+type J interface { I }
+
+type PI interface { p.I }
+type PJ interface { p.J }
+
+func main() {
+       var i I
+       var j J
+       var t T
+       i = t
+       j = t
+       _ = i
+       _ = j
+       i = j
+       _ = i
+       j = i
+       _ = j
+       var pi PI
+       var pj PJ
+       var pt p.T
+       pi = pt
+       pj = pt
+       _ = pi
+       _ = pj
+       pi = pj
+       _ = pi
+       pj = pi
+       _ = pj
+}
diff --git a/gcc/testsuite/go.test/test/interface/explicit.go b/gcc/testsuite/go.test/test/interface/explicit.go
new file mode 100644 (file)
index 0000000..b952f8f
--- /dev/null
@@ -0,0 +1,71 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Static error messages about interface conversions.
+
+package main
+
+type T struct {
+       a int
+}
+
+var t *T
+
+type I interface {
+       M()
+}
+
+var i I
+
+type I2 interface {
+       M()
+       N()
+}
+
+var i2 I2
+
+type E interface{}
+
+var e E
+
+func main() {
+       e = t // ok
+       t = e // ERROR "need explicit|need type assertion"
+
+       // neither of these can work,
+       // because i has an extra method
+       // that t does not, so i cannot contain a t.
+       i = t // ERROR "incompatible|missing M method"
+       t = i // ERROR "incompatible|need type assertion"
+
+       i = i2 // ok
+       i2 = i // ERROR "incompatible|missing N method"
+
+       i = I(i2)  // ok
+       i2 = I2(i) // ERROR "invalid|missing N method"
+
+       e = E(t) // ok
+       t = T(e) // ERROR "need explicit|need type assertion|incompatible"
+}
+
+type M interface { M() }
+var m M
+
+var _ = m.(int)        // ERROR "impossible type assertion"
+
+type Int int
+func (Int) M(float) {}
+
+var _ = m.(Int)        // ERROR "impossible type assertion"
+
+var ii int
+var jj Int
+
+var m1 M = ii  // ERROR "incompatible|missing"
+var m2 M = jj  // ERROR "incompatible|wrong type for M method"
+
+var m3 = M(ii) // ERROR "invalid|missing"
+var m4 = M(jj) // ERROR "invalid|wrong type for M method"
diff --git a/gcc/testsuite/go.test/test/interface/fail.go b/gcc/testsuite/go.test/test/interface/fail.go
new file mode 100644 (file)
index 0000000..3e741d3
--- /dev/null
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that interface conversion fails when method is missing.
+
+package main
+
+type I interface {
+       Foo()
+}
+
+func main() {
+       var s *S
+       var i I
+       var e interface {}
+       e = s
+       i = e.(I)
+       _ = i
+}
+
+// hide S down here to avoid static warning
+type S struct {
+}
diff --git a/gcc/testsuite/go.test/test/interface/fake.go b/gcc/testsuite/go.test/test/interface/fake.go
new file mode 100644 (file)
index 0000000..5cf3be0
--- /dev/null
@@ -0,0 +1,97 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Interface comparisons using types hidden
+// inside reflected-on structs.
+
+package main
+
+import "reflect"
+
+type T struct {
+       f float32
+       g float32
+
+       s string
+       t string
+
+       u uint32
+       v uint32
+
+       w uint32
+       x uint32
+
+       y uint32
+       z uint32
+}
+
+func add(s, t string) string {
+       return s + t
+}
+
+func assert(b bool) {
+       if !b {
+               panic("assert")
+       }
+}
+
+func main() {
+       var x T
+       x.f = 1.0
+       x.g = x.f
+       x.s = add("abc", "def")
+       x.t = add("abc", "def")
+       x.u = 1
+       x.v = 2
+       x.w = 1<<28
+       x.x = 2<<28
+       x.y = 0x12345678
+       x.z = x.y
+
+       // check mem and string
+       v := reflect.NewValue(x)
+       i := v.(*reflect.StructValue).Field(0)
+       j := v.(*reflect.StructValue).Field(1)
+       assert(i.Interface() == j.Interface())
+
+       s := v.(*reflect.StructValue).Field(2)
+       t := v.(*reflect.StructValue).Field(3)
+       assert(s.Interface() == t.Interface())
+
+       // make sure different values are different.
+       // make sure whole word is being compared,
+       // not just a single byte.
+       i = v.(*reflect.StructValue).Field(4)
+       j = v.(*reflect.StructValue).Field(5)
+       assert(i.Interface() != j.Interface())
+
+       i = v.(*reflect.StructValue).Field(6)
+       j = v.(*reflect.StructValue).Field(7)
+       assert(i.Interface() != j.Interface())
+
+       i = v.(*reflect.StructValue).Field(8)
+       j = v.(*reflect.StructValue).Field(9)
+       assert(i.Interface() == j.Interface())
+}
+
+/*
+comparing uncomparable type float32
+throw: interface compare
+
+panic PC=0x28ceb8 [1]
+throw+0x41 /Users/rsc/goX/src/runtime/runtime.c:54
+       throw(0x3014a, 0x0)
+ifaceeq+0x15c /Users/rsc/goX/src/runtime/iface.c:501
+       ifaceeq(0x2aa7c0, 0x0, 0x0, 0x0, 0x2aa7c0, ...)
+sys·ifaceeq+0x48 /Users/rsc/goX/src/runtime/iface.c:527
+       sys·ifaceeq(0x2aa7c0, 0x0, 0x0, 0x0, 0x2aa7c0, ...)
+main·main+0x190 /Users/rsc/goX/src/cmd/gc/x.go:10
+       main·main()
+mainstart+0xf /Users/rsc/goX/src/runtime/amd64/asm.s:53
+       mainstart()
+sys·Goexit /Users/rsc/goX/src/runtime/proc.c:124
+       sys·Goexit()
+*/
diff --git a/gcc/testsuite/go.test/test/interface/pointer.go b/gcc/testsuite/go.test/test/interface/pointer.go
new file mode 100644 (file)
index 0000000..e628b55
--- /dev/null
@@ -0,0 +1,36 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that interface{M()} = *interface{M()} produces a compiler error.
+
+package main
+
+type Inst interface {
+       Next() *Inst
+}
+
+type Regexp struct {
+       code  []Inst
+       start Inst
+}
+
+type Start struct {
+       foo *Inst
+}
+
+func (start *Start) Next() *Inst { return nil }
+
+
+func AddInst(Inst) *Inst {
+       print("ok in addinst\n")
+       return nil
+}
+
+func main() {
+       print("call addinst\n")
+       var x Inst = AddInst(new(Start)) // ERROR "pointer to interface"
+       print("return from  addinst\n")
+}
diff --git a/gcc/testsuite/go.test/test/interface/receiver.go b/gcc/testsuite/go.test/test/interface/receiver.go
new file mode 100644 (file)
index 0000000..f53daf8
--- /dev/null
@@ -0,0 +1,121 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Implicit methods for embedded types.
+// Mixed pointer and non-pointer receivers.
+
+package main
+
+type T int
+
+var nv, np int
+
+func (t T) V() {
+       if t != 42 {
+               panic(t)
+       }
+       nv++
+}
+
+func (t *T) P() {
+       if *t != 42 {
+               println(t, *t)
+               panic("fail")
+       }
+       np++
+}
+
+type V interface {
+       V()
+}
+type P interface {
+       P()
+       V()
+}
+
+type S struct {
+       T
+}
+
+type SP struct {
+       *T
+}
+
+func main() {
+       var t T
+       var v V
+       var p P
+
+       t = 42
+
+       t.P()
+       t.V()
+
+       v = t
+       v.V()
+
+       p = &t
+       p.P()
+       p.V()
+
+       v = &t
+       v.V()
+
+       //      p = t   // ERROR
+       var i interface{} = t
+       if _, ok := i.(P); ok {
+               println("dynamic i.(P) succeeded incorrectly")
+               panic("fail")
+       }
+
+       //      println("--struct--");
+       var s S
+       s.T = 42
+       s.P()
+       s.V()
+
+       v = s
+       s.V()
+
+       p = &s
+       p.P()
+       p.V()
+
+       v = &s
+       v.V()
+
+       //      p = s   // ERROR
+       var j interface{} = s
+       if _, ok := j.(P); ok {
+               println("dynamic j.(P) succeeded incorrectly")
+               panic("fail")
+       }
+
+       //      println("--struct pointer--");
+       var sp SP
+       sp.T = &t
+       sp.P()
+       sp.V()
+
+       v = sp
+       sp.V()
+
+       p = &sp
+       p.P()
+       p.V()
+
+       v = &sp
+       v.V()
+
+       p = sp // not error
+       p.P()
+       p.V()
+
+       if nv != 13 || np != 7 {
+               println("bad count", nv, np)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/interface/receiver1.go b/gcc/testsuite/go.test/test/interface/receiver1.go
new file mode 100644 (file)
index 0000000..51312d0
--- /dev/null
@@ -0,0 +1,58 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Error messages about missing implicit methods.
+
+package main
+
+type T int
+
+func (t T) V()
+func (t *T) P()
+
+type V interface {
+       V()
+}
+type P interface {
+       P()
+       V()
+}
+
+type S struct {
+       T
+}
+type SP struct {
+       *T
+}
+
+func main() {
+       var t T
+       var v V
+       var p P
+       var s S
+       var sp SP
+
+       v = t
+       p = t // ERROR "does not implement|requires a pointer"
+       _, _ = v, p
+       v = &t
+       p = &t
+       _, _ = v, p
+
+       v = s
+       p = s // ERROR "does not implement|requires a pointer"
+       _, _ = v, p
+       v = &s
+       p = &s
+       _, _ = v, p
+
+       v = sp
+       p = sp // no error!
+       _, _ = v, p
+       v = &sp
+       p = &sp
+       _, _ = v, p
+}
diff --git a/gcc/testsuite/go.test/test/interface/recursive.go b/gcc/testsuite/go.test/test/interface/recursive.go
new file mode 100644 (file)
index 0000000..1eb56e9
--- /dev/null
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check mutually recursive interfaces
+
+package main
+
+type I1 interface {
+       foo() I2
+}
+
+type I2 interface {
+       bar() I1
+}
+
+type T int
+func (t T) foo() I2 { return t }
+func (t T) bar() I1 { return t }
diff --git a/gcc/testsuite/go.test/test/interface/returntype.go b/gcc/testsuite/go.test/test/interface/returntype.go
new file mode 100644 (file)
index 0000000..c526b3b
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should not succeed)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check methods with different return types.
+
+package main
+
+type S struct { a int }
+type T struct { b string }
+
+func (s *S) Name() int8 { return 1 }
+func (t *T) Name() int64 { return 64 }
+
+type I1 interface { Name() int8 }
+type I2 interface { Name() int64 }
+
+func main() {
+       var i1 I1
+       var s *S
+       i1 = s
+       print(i1.(I2).Name())
+}
diff --git a/gcc/testsuite/go.test/test/interface/struct.go b/gcc/testsuite/go.test/test/interface/struct.go
new file mode 100644 (file)
index 0000000..40b7f4f
--- /dev/null
@@ -0,0 +1,156 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG interface6
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Interface values containing structures.
+
+package main
+
+import "os"
+
+var fail int
+
+func check(b bool, msg string) {
+       if (!b) {
+               println("failure in", msg)
+               fail++
+       }
+}
+
+type I1 interface { Get() int; Put(int) }
+
+type S1 struct { i int }
+func (p S1) Get() int { return p.i }
+func (p S1) Put(i int) { p.i = i }
+
+func f1() {
+       s := S1{1}
+       var i I1 = s
+       i.Put(2)
+       check(i.Get() == 1, "f1 i")
+       check(s.i == 1, "f1 s")
+}
+
+func f2() {
+       s := S1{1}
+       var i I1 = &s
+       i.Put(2)
+       check(i.Get() == 1, "f2 i")
+       check(s.i == 1, "f2 s")
+}
+
+func f3() {
+       s := &S1{1}
+       var i I1 = s
+       i.Put(2)
+       check(i.Get() == 1, "f3 i")
+       check(s.i == 1, "f3 s")
+}
+
+type S2 struct { i int }
+func (p *S2) Get() int { return p.i }
+func (p *S2) Put(i int) { p.i = i }
+
+// Disallowed by restriction of values going to pointer receivers
+// func f4() {
+//      s := S2{1}
+//      var i I1 = s
+//      i.Put(2)
+//      check(i.Get() == 2, "f4 i")
+//      check(s.i == 1, "f4 s")
+// }
+
+func f5() {
+       s := S2{1}
+       var i I1 = &s
+       i.Put(2)
+       check(i.Get() == 2, "f5 i")
+       check(s.i == 2, "f5 s")
+}
+
+func f6() {
+       s := &S2{1}
+       var i I1 = s
+       i.Put(2)
+       check(i.Get() == 2, "f6 i")
+       check(s.i == 2, "f6 s")
+}
+
+type I2 interface { Get() int64; Put(int64) }
+
+type S3 struct { i, j, k, l int64 }
+func (p S3) Get() int64 { return p.l }
+func (p S3) Put(i int64) { p.l = i }
+
+func f7() {
+       s := S3{1, 2, 3, 4}
+       var i I2 = s
+       i.Put(5)
+       check(i.Get() == 4, "f7 i")
+       check(s.l == 4, "f7 s")
+}
+
+func f8() {
+       s := S3{1, 2, 3, 4}
+       var i I2 = &s
+       i.Put(5)
+       check(i.Get() == 4, "f8 i")
+       check(s.l == 4, "f8 s")
+}
+
+func f9() {
+       s := &S3{1, 2, 3, 4}
+       var i I2 = s
+       i.Put(5)
+       check(i.Get() == 4, "f9 i")
+       check(s.l == 4, "f9 s")
+}
+
+type S4 struct { i, j, k, l int64 }
+func (p *S4) Get() int64 { return p.l }
+func (p *S4) Put(i int64) { p.l = i }
+
+// Disallowed by restriction of values going to pointer receivers
+// func f10() {
+//      s := S4{1, 2, 3, 4}
+//      var i I2 = s
+//      i.Put(5)
+//      check(i.Get() == 5, "f10 i")
+//      check(s.l == 4, "f10 s")
+// }
+
+func f11() {
+       s := S4{1, 2, 3, 4}
+       var i I2 = &s
+       i.Put(5)
+       check(i.Get() == 5, "f11 i")
+       check(s.l == 5, "f11 s")
+}
+
+func f12() {
+       s := &S4{1, 2, 3, 4}
+       var i I2 = s
+       i.Put(5)
+       check(i.Get() == 5, "f12 i")
+       check(s.l == 5, "f12 s")
+}
+
+func main() {
+       f1()
+       f2()
+       f3()
+//     f4()
+       f5()
+       f6()
+       f7()
+       f8()
+       f9()
+//     f10()
+       f11()
+       f12()
+       if fail > 0 {
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/iota.go b/gcc/testsuite/go.test/test/iota.go
new file mode 100644 (file)
index 0000000..20b77c6
--- /dev/null
@@ -0,0 +1,120 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func assert(cond bool, msg string) {
+       if !cond {
+               print("assertion fail: ", msg, "\n")
+               panic(1)
+       }
+}
+
+const (
+       x int = iota
+       y = iota
+       z = 1 << iota
+       f float = 2 * iota
+       g float = 4.5 * float(iota)
+)
+
+const (
+       X = 0
+       Y
+       Z
+)
+
+const (
+       A = 1 << iota
+       B
+       C
+       D
+       E = iota * iota
+       F
+       G
+)
+
+const (
+       a = 1
+       b = iota << a
+       c = iota << b
+       d
+)
+
+const (
+       i = (a << iota) + (b * iota)
+       j
+       k
+       l
+)
+
+const (
+       m = iota == 0
+       n
+)
+
+const (
+       p = float(iota)
+       q
+       r
+)
+
+const (
+       s = string(iota + 'a')
+       t
+)
+
+const (
+       abit, amask = 1 << iota, 1 << iota - 1
+       bbit, bmask = 1 << iota, 1 << iota - 1
+       cbit, cmask = 1 << iota, 1 << iota - 1
+)
+
+func main() {
+       assert(x == 0, "x")
+       assert(y == 1, "y")
+       assert(z == 4, "z")
+       assert(f == 6.0, "f")
+       assert(g == 18.0, "g")
+
+       assert(X == 0, "X")
+       assert(Y == 0, "Y")
+       assert(Z == 0, "Z")
+
+       assert(A == 1, "A")
+       assert(B == 2, "B")
+       assert(C == 4, "C")
+       assert(D == 8, "D")
+       assert(E == 16, "E")
+       assert(F == 25, "F")
+
+       assert(a == 1, "a")
+       assert(b == 2, "b")
+       assert(c == 8, "c")
+       assert(d == 12, "d")
+
+       assert(i == 1, "i")
+       assert(j == 4, "j")
+       assert(k == 8, "k")
+       assert(l == 14, "l")
+
+       assert(m, "m")
+       assert(!n, "n")
+
+       assert(p == 0.0, "p")
+       assert(q == 1.0, "q")
+       assert(r == 2.0, "r")
+
+       assert(s == "a", "s")
+       assert(t == "b", "t")
+
+       assert(abit == 1, "abit")
+       assert(amask == 0, "amask")
+       assert(bbit == 2, "bbit")
+       assert(bmask == 1, "bmask")
+       assert(cbit == 4, "cbit")
+       assert(cmask == 3, "cmask")
+}
diff --git a/gcc/testsuite/go.test/test/ken/array.go b/gcc/testsuite/go.test/test/ken/array.go
new file mode 100644 (file)
index 0000000..40209f5
--- /dev/null
@@ -0,0 +1,133 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func setpd(a []int) {
+       //      print("setpd a=", a, " len=", len(a), " cap=", cap(a), "\n");
+       for i := 0; i < len(a); i++ {
+               a[i] = i
+       }
+}
+
+func sumpd(a []int) int {
+       //      print("sumpd a=", a, " len=", len(a), " cap=", cap(a), "\n");
+       t := 0
+       for i := 0; i < len(a); i++ {
+               t += a[i]
+       }
+       //      print("sumpd t=", t, "\n");
+       return t
+}
+
+func setpf(a *[20]int) {
+       //      print("setpf a=", a, " len=", len(a), " cap=", cap(a), "\n");
+       for i := 0; i < len(a); i++ {
+               a[i] = i
+       }
+}
+
+func sumpf(a *[20]int) int {
+       //      print("sumpf a=", a, " len=", len(a), " cap=", cap(a), "\n");
+       t := 0
+       for i := 0; i < len(a); i++ {
+               t += a[i]
+       }
+       //      print("sumpf t=", t, "\n");
+       return t
+}
+
+func res(t int, lb, hb int) {
+       sb := (hb - lb) * (hb + lb - 1) / 2
+       if t != sb {
+               print("lb=", lb,
+                       "; hb=", hb,
+                       "; t=", t,
+                       "; sb=", sb,
+                       "\n")
+               panic("res")
+       }
+}
+
+// call ptr dynamic with ptr dynamic
+func testpdpd() {
+       a := make([]int, 10, 100)
+       if len(a) != 10 && cap(a) != 100 {
+               print("len and cap from new: ", len(a), " ", cap(a), "\n")
+               panic("fail")
+       }
+
+       a = a[0:100]
+       setpd(a)
+
+       a = a[0:10]
+       res(sumpd(a), 0, 10)
+
+       a = a[5:25]
+       res(sumpd(a), 5, 25)
+}
+
+// call ptr fixed with ptr fixed
+func testpfpf() {
+       var a [20]int
+
+       setpf(&a)
+       res(sumpf(&a), 0, 20)
+}
+
+// call ptr dynamic with ptr fixed from new
+func testpdpf1() {
+       a := new([40]int)
+       setpd(a[0:])
+       res(sumpd(a[0:]), 0, 40)
+
+       b := (*a)[5:30]
+       res(sumpd(b), 5, 30)
+}
+
+// call ptr dynamic with ptr fixed from var
+func testpdpf2() {
+       var a [80]int
+
+       setpd(a[0:])
+       res(sumpd(a[0:]), 0, 80)
+}
+
+// generate bounds error with ptr dynamic
+func testpdfault() {
+       a := make([]int, 100)
+
+       print("good\n")
+       for i := 0; i < 100; i++ {
+               a[i] = 0
+       }
+       print("should fault\n")
+       a[100] = 0
+       print("bad\n")
+}
+
+// generate bounds error with ptr fixed
+func testfdfault() {
+       var a [80]int
+
+       print("good\n")
+       for i := 0; i < 80; i++ {
+               a[i] = 0
+       }
+       print("should fault\n")
+       x := 80
+       a[x] = 0
+       print("bad\n")
+}
+
+func main() {
+       testpdpd()
+       testpfpf()
+       testpdpf1()
+       testpdpf2()
+       //      print("testpdfault\n"); testpdfault();
+       //      print("testfdfault\n"); testfdfault();
+}
diff --git a/gcc/testsuite/go.test/test/ken/chan.go b/gcc/testsuite/go.test/test/ken/chan.go
new file mode 100644 (file)
index 0000000..ef75b04
--- /dev/null
@@ -0,0 +1,329 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+import "runtime"
+import "sync"
+
+var randx int
+
+func nrand(n int) int {
+       randx += 10007
+       if randx >= 1000000 {
+               randx -= 1000000
+       }
+       return randx % n
+}
+
+type Chan struct {
+       sc, rc chan int // send and recv chan
+       sv, rv int      // send and recv seq
+}
+
+var (
+       nproc      int
+       nprocLock  sync.Mutex
+       cval       int
+       end        int = 10000
+       totr, tots int
+       totLock    sync.Mutex
+       nc         *Chan
+)
+
+func init() {
+       nc = new(Chan)
+}
+
+func changeNproc(adjust int) int {
+       nprocLock.Lock()
+       nproc += adjust
+       ret := nproc
+       nprocLock.Unlock()
+       return ret
+}
+
+func mkchan(c, n int) []*Chan {
+       ca := make([]*Chan, n)
+       for i := 0; i < n; i++ {
+               cval = cval + 100
+               ch := new(Chan)
+               ch.sc = make(chan int, c)
+               ch.rc = ch.sc
+               ch.sv = cval
+               ch.rv = cval
+               ca[i] = ch
+       }
+       return ca
+}
+
+func expect(v, v0 int) (newv int) {
+       if v == v0 {
+               if v%100 == 75 {
+                       return end
+               }
+               return v + 1
+       }
+       print("got ", v, " expected ", v0+1, "\n")
+       panic("fail")
+}
+
+func (c *Chan) send() bool {
+       //      print("send ", c.sv, "\n");
+       totLock.Lock()
+       tots++
+       totLock.Unlock()
+       c.sv = expect(c.sv, c.sv)
+       if c.sv == end {
+               c.sc = nil
+               return true
+       }
+       return false
+}
+
+func send(c *Chan) {
+       for {
+               for r := nrand(10); r >= 0; r-- {
+                       runtime.Gosched()
+               }
+               c.sc <- c.sv
+               if c.send() {
+                       break
+               }
+       }
+       changeNproc(-1)
+}
+
+func (c *Chan) recv(v int) bool {
+       //      print("recv ", v, "\n");
+       totLock.Lock()
+       totr++
+       totLock.Unlock()
+       c.rv = expect(c.rv, v)
+       if c.rv == end {
+               c.rc = nil
+               return true
+       }
+       return false
+}
+
+func recv(c *Chan) {
+       var v int
+
+       for {
+               for r := nrand(10); r >= 0; r-- {
+                       runtime.Gosched()
+               }
+               v = <-c.rc
+               if c.recv(v) {
+                       break
+               }
+       }
+       changeNproc(-1)
+}
+
+func sel(r0, r1, r2, r3, s0, s1, s2, s3 *Chan) {
+       var v int
+
+       a := 0 // local chans running
+
+       if r0.rc != nil {
+               a++
+       }
+       if r1.rc != nil {
+               a++
+       }
+       if r2.rc != nil {
+               a++
+       }
+       if r3.rc != nil {
+               a++
+       }
+       if s0.sc != nil {
+               a++
+       }
+       if s1.sc != nil {
+               a++
+       }
+       if s2.sc != nil {
+               a++
+       }
+       if s3.sc != nil {
+               a++
+       }
+
+       for {
+               for r := nrand(5); r >= 0; r-- {
+                       runtime.Gosched()
+               }
+
+               select {
+               case v = <-r0.rc:
+                       if r0.recv(v) {
+                               a--
+                       }
+               case v = <-r1.rc:
+                       if r1.recv(v) {
+                               a--
+                       }
+               case v = <-r2.rc:
+                       if r2.recv(v) {
+                               a--
+                       }
+               case v = <-r3.rc:
+                       if r3.recv(v) {
+                               a--
+                       }
+               case s0.sc <- s0.sv:
+                       if s0.send() {
+                               a--
+                       }
+               case s1.sc <- s1.sv:
+                       if s1.send() {
+                               a--
+                       }
+               case s2.sc <- s2.sv:
+                       if s2.send() {
+                               a--
+                       }
+               case s3.sc <- s3.sv:
+                       if s3.send() {
+                               a--
+                       }
+               }
+               if a == 0 {
+                       break
+               }
+       }
+       changeNproc(-1)
+}
+
+// direct send to direct recv
+func test1(c *Chan) {
+       changeNproc(2)
+       go send(c)
+       go recv(c)
+}
+
+// direct send to select recv
+func test2(c int) {
+       ca := mkchan(c, 4)
+
+       changeNproc(4)
+       go send(ca[0])
+       go send(ca[1])
+       go send(ca[2])
+       go send(ca[3])
+
+       changeNproc(1)
+       go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
+}
+
+// select send to direct recv
+func test3(c int) {
+       ca := mkchan(c, 4)
+
+       changeNproc(4)
+       go recv(ca[0])
+       go recv(ca[1])
+       go recv(ca[2])
+       go recv(ca[3])
+
+       changeNproc(1)
+       go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
+}
+
+// select send to select recv
+func test4(c int) {
+       ca := mkchan(c, 4)
+
+       changeNproc(2)
+       go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
+       go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
+}
+
+func test5(c int) {
+       ca := mkchan(c, 8)
+
+       changeNproc(2)
+       go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
+       go sel(ca[0], ca[1], ca[2], ca[3], ca[4], ca[5], ca[6], ca[7])
+}
+
+func test6(c int) {
+       ca := mkchan(c, 12)
+
+       changeNproc(4)
+       go send(ca[4])
+       go send(ca[5])
+       go send(ca[6])
+       go send(ca[7])
+
+       changeNproc(4)
+       go recv(ca[8])
+       go recv(ca[9])
+       go recv(ca[10])
+       go recv(ca[11])
+
+       changeNproc(2)
+       go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
+       go sel(ca[0], ca[1], ca[2], ca[3], ca[8], ca[9], ca[10], ca[11])
+}
+
+// wait for outstanding tests to finish
+func wait() {
+       runtime.Gosched()
+       for changeNproc(0) != 0 {
+               runtime.Gosched()
+       }
+}
+
+// run all tests with specified buffer size
+func tests(c int) {
+       ca := mkchan(c, 4)
+       test1(ca[0])
+       test1(ca[1])
+       test1(ca[2])
+       test1(ca[3])
+       wait()
+
+       test2(c)
+       wait()
+
+       test3(c)
+       wait()
+
+       test4(c)
+       wait()
+
+       test5(c)
+       wait()
+
+       test6(c)
+       wait()
+}
+
+// run all test with 4 buffser sizes
+func main() {
+
+       tests(0)
+       tests(1)
+       tests(10)
+       tests(100)
+
+       t := 4 * // buffer sizes
+               (4*4 + // tests 1,2,3,4 channels
+                       8 + // test 5 channels
+                       12) * // test 6 channels
+               76 // sends/recvs on a channel
+
+       if tots != t || totr != t {
+               print("tots=", tots, " totr=", totr, " sb=", t, "\n")
+               os.Exit(1)
+       }
+       os.Exit(0)
+}
diff --git a/gcc/testsuite/go.test/test/ken/chan1.go b/gcc/testsuite/go.test/test/ken/chan1.go
new file mode 100644 (file)
index 0000000..e5fc033
--- /dev/null
@@ -0,0 +1,53 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+const N = 1000 // sent messages
+const M = 10   // receiving goroutines
+const W = 2    // channel buffering
+var h [N]int   // marking of send/recv
+
+func r(c chan int, m int) {
+       for {
+               select {
+               case r := <-c:
+                       if h[r] != 1 {
+                               println("r",
+                                       "m=", m,
+                                       "r=", r,
+                                       "h=", h[r])
+                               panic("fail")
+                       }
+                       h[r] = 2
+               }
+       }
+}
+
+func s(c chan int) {
+       for n := 0; n < N; n++ {
+               r := n
+               if h[r] != 0 {
+                       println("s")
+                       panic("fail")
+               }
+               h[r] = 1
+               c <- r
+       }
+}
+
+func main() {
+       c := make(chan int, W)
+       for m := 0; m < M; m++ {
+               go r(c, m)
+               runtime.Gosched()
+       }
+       runtime.Gosched()
+       runtime.Gosched()
+       s(c)
+}
diff --git a/gcc/testsuite/go.test/test/ken/complit.go b/gcc/testsuite/go.test/test/ken/complit.go
new file mode 100644 (file)
index 0000000..da0a84a
--- /dev/null
@@ -0,0 +1,170 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type   M       map[int]int
+type   S       struct{ a,b,c int };
+type   SS      struct{ aa,bb,cc S };
+type   SA      struct{ a,b,c [3]int };
+type   SC      struct{ a,b,c []int };
+type   SM      struct{ a,b,c M };
+
+func
+main() {
+       test("s.a", s.a);
+       test("s.b", s.b);
+       test("s.c", s.c);
+
+       test("ss.aa.a", ss.aa.a);
+       test("ss.aa.b", ss.aa.b);
+       test("ss.aa.c", ss.aa.c);
+
+       test("ss.bb.a", ss.bb.a);
+       test("ss.bb.b", ss.bb.b);
+       test("ss.bb.c", ss.bb.c);
+
+       test("ss.cc.a", ss.cc.a);
+       test("ss.cc.b", ss.cc.b);
+       test("ss.cc.c", ss.cc.c);
+
+       for i:=0; i<3; i++ {
+               test("a[i]", a[i]);
+               test("c[i]", c[i]);
+               test("m[i]", m[i]);
+
+               test("as[i].a", as[i].a);
+               test("as[i].b", as[i].b);
+               test("as[i].c", as[i].c);
+
+               test("cs[i].a", cs[i].a);
+               test("cs[i].b", cs[i].b);
+               test("cs[i].c", cs[i].c);
+
+               test("ms[i].a", ms[i].a);
+               test("ms[i].b", ms[i].b);
+               test("ms[i].c", ms[i].c);
+
+               test("sa.a[i]", sa.a[i]);
+               test("sa.b[i]", sa.b[i]);
+               test("sa.c[i]", sa.c[i]);
+
+               test("sc.a[i]", sc.a[i]);
+               test("sc.b[i]", sc.b[i]);
+               test("sc.c[i]", sc.c[i]);
+
+               test("sm.a[i]", sm.a[i]);
+               test("sm.b[i]", sm.b[i]);
+               test("sm.c[i]", sm.c[i]);
+
+               for j:=0; j<3; j++ {
+                       test("aa[i][j]", aa[i][j]);
+                       test("ac[i][j]", ac[i][j]);
+                       test("am[i][j]", am[i][j]);
+                       test("ca[i][j]", ca[i][j]);
+                       test("cc[i][j]", cc[i][j]);
+                       test("cm[i][j]", cm[i][j]);
+                       test("ma[i][j]", ma[i][j]);
+                       test("mc[i][j]", mc[i][j]);
+                       test("mm[i][j]", mm[i][j]);
+               }
+       }
+
+}
+
+var    ref     = 0;
+
+func
+test(xs string, x int) {
+
+       if ref >= len(answers) {
+               println(xs, x);
+               return;
+       }
+
+       if x != answers[ref] {
+               println(xs, "is", x, "should be", answers[ref])
+       }
+       ref++;
+}
+
+
+var    a       = [3]int{1001, 1002, 1003}
+var    s       = S{1101, 1102, 1103}
+var    c       = []int{1201, 1202, 1203}
+var    m       = M{0:1301, 1:1302, 2:1303}
+
+var    aa      = [3][3]int{[3]int{2001,2002,2003}, [3]int{2004,2005,2006}, [3]int{2007,2008,2009}}
+var    as      = [3]S{S{2101,2102,2103},S{2104,2105,2106},S{2107,2108,2109}}
+var    ac      = [3][]int{[]int{2201,2202,2203}, []int{2204,2205,2206}, []int{2207,2208,2209}}
+var    am      = [3]M{M{0:2301,1:2302,2:2303}, M{0:2304,1:2305,2:2306}, M{0:2307,1:2308,2:2309}}
+
+var    sa      = SA{[3]int{3001,3002,3003},[3]int{3004,3005,3006},[3]int{3007,3008,3009}}
+var    ss      = SS{S{3101,3102,3103},S{3104,3105,3106},S{3107,3108,3109}}
+var    sc      = SC{[]int{3201,3202,3203},[]int{3204,3205,3206},[]int{3207,3208,3209}}
+var    sm      = SM{M{0:3301,1:3302,2:3303}, M{0:3304,1:3305,2:3306}, M{0:3307,1:3308,2:3309}}
+
+var    ca      = [][3]int{[3]int{4001,4002,4003}, [3]int{4004,4005,4006}, [3]int{4007,4008,4009}}
+var    cs      = []S{S{4101,4102,4103},S{4104,4105,4106},S{4107,4108,4109}}
+var    cc      = [][]int{[]int{4201,4202,4203}, []int{4204,4205,4206}, []int{4207,4208,4209}}
+var    cm      = []M{M{0:4301,1:4302,2:4303}, M{0:4304,1:4305,2:4306}, M{0:4307,1:4308,2:4309}}
+
+var    ma      = map[int][3]int{0:[3]int{5001,5002,5003}, 1:[3]int{5004,5005,5006}, 2:[3]int{5007,5008,5009}}
+var    ms      = map[int]S{0:S{5101,5102,5103},1:S{5104,5105,5106},2:S{5107,5108,5109}}
+var    mc      = map[int][]int{0:[]int{5201,5202,5203}, 1:[]int{5204,5205,5206}, 2:[]int{5207,5208,5209}}
+var    mm      = map[int]M{0:M{0:5301,1:5302,2:5303}, 1:M{0:5304,1:5305,2:5306}, 2:M{0:5307,1:5308,2:5309}}
+
+var    answers = [...]int {
+       // s
+       1101, 1102, 1103,
+
+       // ss
+       3101, 3102, 3103,
+       3104, 3105, 3106,
+       3107, 3108, 3109,
+
+       // [0]
+       1001, 1201, 1301,
+       2101, 2102, 2103,
+       4101, 4102, 4103,
+       5101, 5102, 5103,
+       3001, 3004, 3007,
+       3201, 3204, 3207,
+       3301, 3304, 3307,
+
+       // [0][j]
+       2001, 2201, 2301, 4001, 4201, 4301, 5001, 5201, 5301,
+       2002, 2202, 2302, 4002, 4202, 4302, 5002, 5202, 5302,
+       2003, 2203, 2303, 4003, 4203, 4303, 5003, 5203, 5303,
+
+       // [1]
+       1002, 1202, 1302,
+       2104, 2105, 2106,
+       4104, 4105, 4106,
+       5104, 5105, 5106,
+       3002, 3005, 3008,
+       3202, 3205, 3208,
+       3302, 3305, 3308,
+
+       // [1][j]
+       2004, 2204, 2304, 4004, 4204, 4304, 5004, 5204, 5304,
+       2005, 2205, 2305, 4005, 4205, 4305, 5005, 5205, 5305,
+       2006, 2206, 2306, 4006, 4206, 4306, 5006, 5206, 5306,
+
+       // [2]
+       1003, 1203, 1303,
+       2107, 2108, 2109,
+       4107, 4108, 4109,
+       5107, 5108, 5109,
+       3003, 3006, 3009,
+       3203, 3206, 3209,
+       3303, 3306, 3309,
+
+       // [2][j]
+       2007, 2207, 2307, 4007, 4207, 4307, 5007, 5207, 5307,
+       2008, 2208, 2308, 4008, 4208, 4308, 5008, 5208, 5308,
+       2009, 2209, 2309, 4009, 4209, 4309, 5009, 5209, 5309,
+}
diff --git a/gcc/testsuite/go.test/test/ken/cplx0.go b/gcc/testsuite/go.test/test/ken/cplx0.go
new file mode 100644 (file)
index 0000000..6e9bfd0
--- /dev/null
@@ -0,0 +1,28 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+       R = 5
+       I = 6i
+
+       C1 = R + I // ADD(5,6)
+)
+
+func doprint(c complex) { println(c) }
+
+func main() {
+
+       // constants
+       println(C1)
+       doprint(C1)
+
+       // variables
+       c1 := C1
+       println(c1)
+       doprint(c1)
+}
diff --git a/gcc/testsuite/go.test/test/ken/cplx1.go b/gcc/testsuite/go.test/test/ken/cplx1.go
new file mode 100644 (file)
index 0000000..26b1139
--- /dev/null
@@ -0,0 +1,97 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+       R = 5
+       I = 6i
+
+       C1 = R + I // ADD(5,6)
+)
+
+func main() {
+       var b bool
+
+       // constants
+       b = (5 + 6i) == C1
+       if !b {
+               println("const bool 1", b)
+               panic("fail")
+       }
+
+       b = (5 + 6i) != C1
+       if b {
+               println("const bool 2", b)
+               panic("fail")
+       }
+
+       b = C1 == (5 + 6i)
+       if !b {
+               println("const bool 3", b)
+               panic("fail")
+       }
+
+       b = C1 != (5 + 6i)
+       if b {
+               println("const bool 4", b)
+               panic("fail")
+       }
+
+       // vars passed through parameters
+       booltest(5+6i, true)
+       booltest(5+7i, false)
+       booltest(6+6i, false)
+       booltest(6+9i, false)
+}
+
+func booltest(a complex, r bool) {
+       var b bool
+
+       b = a == C1
+       if b != r {
+               println("param bool 1", a, b, r)
+               panic("fail")
+       }
+
+       b = a != C1
+       if b == r {
+               println("param bool 2", a, b, r)
+               panic("fail")
+       }
+
+       b = C1 == a
+       if b != r {
+               println("param bool 3", a, b, r)
+               panic("fail")
+       }
+
+       b = C1 != a
+       if b == r {
+               println("param bool 4", a, b, r)
+               panic("fail")
+       }
+
+       if r {
+               if a != C1 {
+                       println("param bool 5", a, b, r)
+                       panic("fail")
+               }
+               if C1 != a {
+                       println("param bool 6", a, b, r)
+                       panic("fail")
+               }
+       } else {
+               if a == C1 {
+                       println("param bool 6", a, b, r)
+                       panic("fail")
+               }
+               if C1 == a {
+                       println("param bool 7", a, b, r)
+                       panic("fail")
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/ken/cplx2.go b/gcc/testsuite/go.test/test/ken/cplx2.go
new file mode 100644 (file)
index 0000000..5a66dc9
--- /dev/null
@@ -0,0 +1,108 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+       R = 5
+       I = 6i
+
+       C1 = R + I    // ADD(5,6)
+       C2 = R - I    // SUB(5,-6)
+       C3 = -(R + I) // ADD(5,6) NEG(-5,-6)
+       C4 = -(R - I) // SUB(5,-6) NEG(-5,6)
+
+       C5 = C1 + R // ADD(10,6)
+       C6 = C1 + I // ADD(5,12)
+
+       Ca = C5 + C6 // ADD(15,18)
+       Cb = C5 - C6 // SUB(5,-6)
+
+       Cc = C5 * C6 // MUL(-22,-150)
+       Cd = C5 / C6 // DIV(0.721893,-0.532544)
+       Ce = Cd * C6 // MUL(10,6) sb C5
+)
+
+func main() {
+
+       r := 5 + 0i
+       if r != R {
+               println("opcode 1", r, R)
+               panic("fail")
+       }
+
+       i := 6i
+       if i != I {
+               println("opcode 2", i, I)
+               panic("fail")
+       }
+
+       c1 := r + i
+       if c1 != C1 {
+               println("opcode x", c1, C1)
+               panic("fail")
+       }
+
+       c2 := r - i
+       if c2 != C2 {
+               println("opcode x", c2, C2)
+               panic("fail")
+       }
+
+       c3 := -(r + i)
+       if c3 != C3 {
+               println("opcode x", c3, C3)
+               panic("fail")
+       }
+
+       c4 := -(r - i)
+       if c4 != C4 {
+               println("opcode x", c4, C4)
+               panic("fail")
+       }
+
+       c5 := c1 + r
+       if c5 != C5 {
+               println("opcode x", c5, C5)
+               panic("fail")
+       }
+
+       c6 := c1 + i
+       if c6 != C6 {
+               println("opcode x", c6, C6)
+               panic("fail")
+       }
+
+       ca := c5 + c6
+       if ca != Ca {
+               println("opcode x", ca, Ca)
+               panic("fail")
+       }
+
+       cb := c5 - c6
+       if cb != Cb {
+               println("opcode x", cb, Cb)
+               panic("fail")
+       }
+
+       cc := c5 * c6
+       if cc != Cc {
+               println("opcode x", cc, Cc)
+               panic("fail")
+       }
+
+       cd := c5 / c6
+       if cd != Cd {
+               println("opcode x", cd, Cd)
+               panic("fail")
+       }
+
+       ce := cd * c6
+       if ce != Ce {
+               println("opcode x", ce, Ce)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/ken/cplx3.go b/gcc/testsuite/go.test/test/ken/cplx3.go
new file mode 100644 (file)
index 0000000..997894b
--- /dev/null
@@ -0,0 +1,39 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+import "reflect"
+
+const (
+       R = 5
+       I = 6i
+
+       C1 = R + I // ADD(5,6)
+)
+
+var complexBits = reflect.Typeof(complex(0i)).Size() * 8
+
+func main() {
+       c0 := C1
+       c0 = (c0 + c0 + c0) / (c0 + c0 + 3i)
+       println(c0)
+
+       c := *(*complex)(unsafe.Pointer(&c0))
+       println(c)
+
+       println(complexBits)
+
+       var a interface{}
+       switch c := reflect.NewValue(a).(type) {
+       case *reflect.ComplexValue:
+               if complexBits == 64 {
+                       v := c.Get()
+                       _, _ = complex64(v), true
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/ken/cplx4.go b/gcc/testsuite/go.test/test/ken/cplx4.go
new file mode 100644 (file)
index 0000000..3c6f1f6
--- /dev/null
@@ -0,0 +1,44 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+const (
+       R = 5
+       I = 6i
+
+       C1 = R + I // ADD(5,6)
+)
+
+func doprint(c complex) { fmt.Printf("c = %f\n", c) }
+
+func main() {
+
+       // constants
+       fmt.Printf("c = %f\n", -C1)
+       doprint(C1)
+
+       // variables
+       c1 := C1
+       fmt.Printf("c = %f\n", c1)
+       doprint(c1)
+
+       // 128
+       c2 := complex128(C1)
+       fmt.Printf("c = %G\n", c2)
+
+       // real, imag, cmplx
+       c3 := cmplx(real(c2)+3, imag(c2)-5) + c2
+       fmt.Printf("c = %G\n", c3)
+
+       // compiler used to crash on nested divide
+       c4 := cmplx(real(c3/2), imag(c3/2))
+       if c4 != c3/2 {
+               fmt.Printf("BUG: c3 = %G != c4 = %G\n", c3, c4)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/ken/cplx5.go b/gcc/testsuite/go.test/test/ken/cplx5.go
new file mode 100644 (file)
index 0000000..af2a1c5
--- /dev/null
@@ -0,0 +1,54 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a [12]complex
+var s []complex
+var c chan complex
+var f struct {
+       c complex
+}
+var m map[complex]complex
+
+func main() {
+       // array of complex
+       for i := 0; i < len(a); i++ {
+               a[i] = cmplx(float(i), float(-i))
+       }
+       println(a[5])
+
+       // slice of complex
+       s = make([]complex, len(a))
+       for i := 0; i < len(s); i++ {
+               s[i] = a[i]
+       }
+       println(s[5])
+
+       // chan
+       c = make(chan complex)
+       go chantest(c)
+       println(<-c)
+
+       // pointer of complex
+       v := a[5]
+       pv := &v
+       println(*pv)
+
+       // field of complex
+       f.c = a[5]
+       println(f.c)
+
+       // map of complex
+       m = make(map[complex]complex)
+       for i := 0; i < len(s); i++ {
+               m[-a[i]] = a[i]
+       }
+       println(m[5i-5])
+       println(m[cmplx(-5, 5)])
+}
+
+func chantest(c chan complex) { c <- a[5] }
diff --git a/gcc/testsuite/go.test/test/ken/divconst.go b/gcc/testsuite/go.test/test/ken/divconst.go
new file mode 100644 (file)
index 0000000..c3b9092
--- /dev/null
@@ -0,0 +1,632 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "rand"
+
+const Count = 1e5
+
+func i64rand() int64 {
+       for {
+               a := int64(rand.Uint32())
+               a = (a << 32) | int64(rand.Uint32())
+               a >>= uint(rand.Intn(64))
+               if -a != a {
+                       return a
+               }
+       }
+       return 0 // impossible
+}
+
+func i64test(a, b, c int64) {
+       d := a / c
+       if d != b {
+               println("i64", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func i64run() {
+       var a, b int64
+
+       for i := 0; i < Count; i++ {
+               a = i64rand()
+
+               b = a / 1
+               i64test(a, b, 1)
+               b = a / 2
+               i64test(a, b, 2)
+               b = a / 3
+               i64test(a, b, 3)
+               b = a / 4
+               i64test(a, b, 4)
+               b = a / 5
+               i64test(a, b, 5)
+               b = a / 6
+               i64test(a, b, 6)
+               b = a / 7
+               i64test(a, b, 7)
+               b = a / 8
+               i64test(a, b, 8)
+               b = a / 10
+               i64test(a, b, 10)
+               b = a / 16
+               i64test(a, b, 16)
+               b = a / 20
+               i64test(a, b, 20)
+               b = a / 32
+               i64test(a, b, 32)
+               b = a / 60
+               i64test(a, b, 60)
+               b = a / 64
+               i64test(a, b, 64)
+               b = a / 128
+               i64test(a, b, 128)
+               b = a / 256
+               i64test(a, b, 256)
+               b = a / 16384
+               i64test(a, b, 16384)
+
+               b = a / -1
+               i64test(a, b, -1)
+               b = a / -2
+               i64test(a, b, -2)
+               b = a / -3
+               i64test(a, b, -3)
+               b = a / -4
+               i64test(a, b, -4)
+               b = a / -5
+               i64test(a, b, -5)
+               b = a / -6
+               i64test(a, b, -6)
+               b = a / -7
+               i64test(a, b, -7)
+               b = a / -8
+               i64test(a, b, -8)
+               b = a / -10
+               i64test(a, b, -10)
+               b = a / -16
+               i64test(a, b, -16)
+               b = a / -20
+               i64test(a, b, -20)
+               b = a / -32
+               i64test(a, b, -32)
+               b = a / -60
+               i64test(a, b, -60)
+               b = a / -64
+               i64test(a, b, -64)
+               b = a / -128
+               i64test(a, b, -128)
+               b = a / -256
+               i64test(a, b, -256)
+               b = a / -16384
+               i64test(a, b, -16384)
+       }
+}
+
+func u64rand() uint64 {
+       a := uint64(rand.Uint32())
+       a = (a << 32) | uint64(rand.Uint32())
+       a >>= uint(rand.Intn(64))
+       return a
+}
+
+func u64test(a, b, c uint64) {
+       d := a / c
+       if d != b {
+               println("u64", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func u64run() {
+       var a, b uint64
+
+       for i := 0; i < Count; i++ {
+               a = u64rand()
+
+               b = a / 1
+               u64test(a, b, 1)
+               b = a / 2
+               u64test(a, b, 2)
+               b = a / 3
+               u64test(a, b, 3)
+               b = a / 4
+               u64test(a, b, 4)
+               b = a / 5
+               u64test(a, b, 5)
+               b = a / 6
+               u64test(a, b, 6)
+               b = a / 7
+               u64test(a, b, 7)
+               b = a / 8
+               u64test(a, b, 8)
+               b = a / 10
+               u64test(a, b, 10)
+               b = a / 16
+               u64test(a, b, 16)
+               b = a / 20
+               u64test(a, b, 20)
+               b = a / 32
+               u64test(a, b, 32)
+               b = a / 60
+               u64test(a, b, 60)
+               b = a / 64
+               u64test(a, b, 64)
+               b = a / 128
+               u64test(a, b, 128)
+               b = a / 256
+               u64test(a, b, 256)
+               b = a / 16384
+               u64test(a, b, 16384)
+       }
+}
+
+func i32rand() int32 {
+       for {
+               a := int32(rand.Uint32())
+               a >>= uint(rand.Intn(32))
+               if -a != a {
+                       return a
+               }
+       }
+       return 0 // impossible
+}
+
+func i32test(a, b, c int32) {
+       d := a / c
+       if d != b {
+               println("i32", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func i32run() {
+       var a, b int32
+
+       for i := 0; i < Count; i++ {
+               a = i32rand()
+
+               b = a / 1
+               i32test(a, b, 1)
+               b = a / 2
+               i32test(a, b, 2)
+               b = a / 3
+               i32test(a, b, 3)
+               b = a / 4
+               i32test(a, b, 4)
+               b = a / 5
+               i32test(a, b, 5)
+               b = a / 6
+               i32test(a, b, 6)
+               b = a / 7
+               i32test(a, b, 7)
+               b = a / 8
+               i32test(a, b, 8)
+               b = a / 10
+               i32test(a, b, 10)
+               b = a / 16
+               i32test(a, b, 16)
+               b = a / 20
+               i32test(a, b, 20)
+               b = a / 32
+               i32test(a, b, 32)
+               b = a / 60
+               i32test(a, b, 60)
+               b = a / 64
+               i32test(a, b, 64)
+               b = a / 128
+               i32test(a, b, 128)
+               b = a / 256
+               i32test(a, b, 256)
+               b = a / 16384
+               i32test(a, b, 16384)
+
+               b = a / -1
+               i32test(a, b, -1)
+               b = a / -2
+               i32test(a, b, -2)
+               b = a / -3
+               i32test(a, b, -3)
+               b = a / -4
+               i32test(a, b, -4)
+               b = a / -5
+               i32test(a, b, -5)
+               b = a / -6
+               i32test(a, b, -6)
+               b = a / -7
+               i32test(a, b, -7)
+               b = a / -8
+               i32test(a, b, -8)
+               b = a / -10
+               i32test(a, b, -10)
+               b = a / -16
+               i32test(a, b, -16)
+               b = a / -20
+               i32test(a, b, -20)
+               b = a / -32
+               i32test(a, b, -32)
+               b = a / -60
+               i32test(a, b, -60)
+               b = a / -64
+               i32test(a, b, -64)
+               b = a / -128
+               i32test(a, b, -128)
+               b = a / -256
+               i32test(a, b, -256)
+       }
+}
+
+func u32rand() uint32 {
+       a := uint32(rand.Uint32())
+       a >>= uint(rand.Intn(32))
+       return a
+}
+
+func u32test(a, b, c uint32) {
+       d := a / c
+       if d != b {
+               println("u32", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func u32run() {
+       var a, b uint32
+
+       for i := 0; i < Count; i++ {
+               a = u32rand()
+
+               b = a / 1
+               u32test(a, b, 1)
+               b = a / 2
+               u32test(a, b, 2)
+               b = a / 3
+               u32test(a, b, 3)
+               b = a / 4
+               u32test(a, b, 4)
+               b = a / 5
+               u32test(a, b, 5)
+               b = a / 6
+               u32test(a, b, 6)
+               b = a / 7
+               u32test(a, b, 7)
+               b = a / 8
+               u32test(a, b, 8)
+               b = a / 10
+               u32test(a, b, 10)
+               b = a / 16
+               u32test(a, b, 16)
+               b = a / 20
+               u32test(a, b, 20)
+               b = a / 32
+               u32test(a, b, 32)
+               b = a / 60
+               u32test(a, b, 60)
+               b = a / 64
+               u32test(a, b, 64)
+               b = a / 128
+               u32test(a, b, 128)
+               b = a / 256
+               u32test(a, b, 256)
+               b = a / 16384
+               u32test(a, b, 16384)
+       }
+}
+
+func i16rand() int16 {
+       for {
+               a := int16(rand.Uint32())
+               a >>= uint(rand.Intn(16))
+               if -a != a {
+                       return a
+               }
+       }
+       return 0 // impossible
+}
+
+func i16test(a, b, c int16) {
+       d := a / c
+       if d != b {
+               println("i16", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func i16run() {
+       var a, b int16
+
+       for i := 0; i < Count; i++ {
+               a = i16rand()
+
+               b = a / 1
+               i16test(a, b, 1)
+               b = a / 2
+               i16test(a, b, 2)
+               b = a / 3
+               i16test(a, b, 3)
+               b = a / 4
+               i16test(a, b, 4)
+               b = a / 5
+               i16test(a, b, 5)
+               b = a / 6
+               i16test(a, b, 6)
+               b = a / 7
+               i16test(a, b, 7)
+               b = a / 8
+               i16test(a, b, 8)
+               b = a / 10
+               i16test(a, b, 10)
+               b = a / 16
+               i16test(a, b, 16)
+               b = a / 20
+               i16test(a, b, 20)
+               b = a / 32
+               i16test(a, b, 32)
+               b = a / 60
+               i16test(a, b, 60)
+               b = a / 64
+               i16test(a, b, 64)
+               b = a / 128
+               i16test(a, b, 128)
+               b = a / 256
+               i16test(a, b, 256)
+               b = a / 16384
+               i16test(a, b, 16384)
+
+               b = a / -1
+               i16test(a, b, -1)
+               b = a / -2
+               i16test(a, b, -2)
+               b = a / -3
+               i16test(a, b, -3)
+               b = a / -4
+               i16test(a, b, -4)
+               b = a / -5
+               i16test(a, b, -5)
+               b = a / -6
+               i16test(a, b, -6)
+               b = a / -7
+               i16test(a, b, -7)
+               b = a / -8
+               i16test(a, b, -8)
+               b = a / -10
+               i16test(a, b, -10)
+               b = a / -16
+               i16test(a, b, -16)
+               b = a / -20
+               i16test(a, b, -20)
+               b = a / -32
+               i16test(a, b, -32)
+               b = a / -60
+               i16test(a, b, -60)
+               b = a / -64
+               i16test(a, b, -64)
+               b = a / -128
+               i16test(a, b, -128)
+               b = a / -256
+               i16test(a, b, -256)
+               b = a / -16384
+               i16test(a, b, -16384)
+       }
+}
+
+func u16rand() uint16 {
+       a := uint16(rand.Uint32())
+       a >>= uint(rand.Intn(16))
+       return a
+}
+
+func u16test(a, b, c uint16) {
+       d := a / c
+       if d != b {
+               println("u16", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func u16run() {
+       var a, b uint16
+
+       for i := 0; i < Count; i++ {
+               a = u16rand()
+
+               b = a / 1
+               u16test(a, b, 1)
+               b = a / 2
+               u16test(a, b, 2)
+               b = a / 3
+               u16test(a, b, 3)
+               b = a / 4
+               u16test(a, b, 4)
+               b = a / 5
+               u16test(a, b, 5)
+               b = a / 6
+               u16test(a, b, 6)
+               b = a / 7
+               u16test(a, b, 7)
+               b = a / 8
+               u16test(a, b, 8)
+               b = a / 10
+               u16test(a, b, 10)
+               b = a / 16
+               u16test(a, b, 16)
+               b = a / 20
+               u16test(a, b, 20)
+               b = a / 32
+               u16test(a, b, 32)
+               b = a / 60
+               u16test(a, b, 60)
+               b = a / 64
+               u16test(a, b, 64)
+               b = a / 128
+               u16test(a, b, 128)
+               b = a / 256
+               u16test(a, b, 256)
+               b = a / 16384
+               u16test(a, b, 16384)
+       }
+}
+
+func i8rand() int8 {
+       for {
+               a := int8(rand.Uint32())
+               a >>= uint(rand.Intn(8))
+               if -a != a {
+                       return a
+               }
+       }
+       return 0 // impossible
+}
+
+func i8test(a, b, c int8) {
+       d := a / c
+       if d != b {
+               println("i8", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func i8run() {
+       var a, b int8
+
+       for i := 0; i < Count; i++ {
+               a = i8rand()
+
+               b = a / 1
+               i8test(a, b, 1)
+               b = a / 2
+               i8test(a, b, 2)
+               b = a / 3
+               i8test(a, b, 3)
+               b = a / 4
+               i8test(a, b, 4)
+               b = a / 5
+               i8test(a, b, 5)
+               b = a / 6
+               i8test(a, b, 6)
+               b = a / 7
+               i8test(a, b, 7)
+               b = a / 8
+               i8test(a, b, 8)
+               b = a / 10
+               i8test(a, b, 10)
+               b = a / 8
+               i8test(a, b, 8)
+               b = a / 20
+               i8test(a, b, 20)
+               b = a / 32
+               i8test(a, b, 32)
+               b = a / 60
+               i8test(a, b, 60)
+               b = a / 64
+               i8test(a, b, 64)
+               b = a / 127
+               i8test(a, b, 127)
+
+               b = a / -1
+               i8test(a, b, -1)
+               b = a / -2
+               i8test(a, b, -2)
+               b = a / -3
+               i8test(a, b, -3)
+               b = a / -4
+               i8test(a, b, -4)
+               b = a / -5
+               i8test(a, b, -5)
+               b = a / -6
+               i8test(a, b, -6)
+               b = a / -7
+               i8test(a, b, -7)
+               b = a / -8
+               i8test(a, b, -8)
+               b = a / -10
+               i8test(a, b, -10)
+               b = a / -8
+               i8test(a, b, -8)
+               b = a / -20
+               i8test(a, b, -20)
+               b = a / -32
+               i8test(a, b, -32)
+               b = a / -60
+               i8test(a, b, -60)
+               b = a / -64
+               i8test(a, b, -64)
+               b = a / -128
+               i8test(a, b, -128)
+       }
+}
+
+func u8rand() uint8 {
+       a := uint8(rand.Uint32())
+       a >>= uint(rand.Intn(8))
+       return a
+}
+
+func u8test(a, b, c uint8) {
+       d := a / c
+       if d != b {
+               println("u8", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func u8run() {
+       var a, b uint8
+
+       for i := 0; i < Count; i++ {
+               a = u8rand()
+
+               b = a / 1
+               u8test(a, b, 1)
+               b = a / 2
+               u8test(a, b, 2)
+               b = a / 3
+               u8test(a, b, 3)
+               b = a / 4
+               u8test(a, b, 4)
+               b = a / 5
+               u8test(a, b, 5)
+               b = a / 6
+               u8test(a, b, 6)
+               b = a / 7
+               u8test(a, b, 7)
+               b = a / 8
+               u8test(a, b, 8)
+               b = a / 10
+               u8test(a, b, 10)
+               b = a / 8
+               u8test(a, b, 8)
+               b = a / 20
+               u8test(a, b, 20)
+               b = a / 32
+               u8test(a, b, 32)
+               b = a / 60
+               u8test(a, b, 60)
+               b = a / 64
+               u8test(a, b, 64)
+               b = a / 128
+               u8test(a, b, 128)
+               b = a / 184
+               u8test(a, b, 184)
+       }
+}
+
+func main() {
+       xtest()
+       i64run()
+       u64run()
+       i32run()
+       u32run()
+       i16run()
+       u16run()
+       i8run()
+       u8run()
+}
+
+func xtest() {
+}
diff --git a/gcc/testsuite/go.test/test/ken/divmod.go b/gcc/testsuite/go.test/test/ken/divmod.go
new file mode 100644 (file)
index 0000000..dc44ea2
--- /dev/null
@@ -0,0 +1,247 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+       // example from the spec
+       n1 = +5
+       n2 = -5
+       d1 = +3
+       d2 = -3
+
+       q1 = +1
+       q2 = -1
+       q3 = -1
+       q4 = +1
+
+       r1 = +2
+       r2 = -2
+       r3 = +2
+       r4 = -2
+)
+
+func main() {
+       /* ideals */
+       if n1/d1 != q1 || n1%d1 != r1 {
+               println("ideal-1", n1, d1, n1/d1, n1%d1)
+               panic("fail")
+       }
+       if n2/d1 != q2 || n2%d1 != r2 {
+               println("ideal-2", n2, d1, n2/d1, n2%d1)
+               panic("fail")
+       }
+       if n1/d2 != q3 || n1%d2 != r3 {
+               println("ideal-3", n1, d2, n1/d2, n1%d2)
+               panic("fail")
+       }
+       if n2/d2 != q4 || n2%d2 != r4 {
+               println("ideal-4", n2, d2, n2/d2, n2%d2)
+               panic("fail")
+       }
+
+       /* int */
+       var in1 int = +5
+       var in2 int = -5
+       var id1 int = +3
+       var id2 int = -3
+
+       if in1/id1 != q1 || in1%id1 != r1 {
+               println("int-1", in1, id1, in1/id1, in1%id1)
+               panic("fail")
+       }
+       if in2/id1 != q2 || in2%id1 != r2 {
+               println("int-2", in2, id1, in2/id1, in2%id1)
+               panic("fail")
+       }
+       if in1/id2 != q3 || in1%id2 != r3 {
+               println("int-3", in1, id2, in1/id2, in1%id2)
+               panic("fail")
+       }
+       if in2/id2 != q4 || in2%id2 != r4 {
+               println("int-4", in2, id2, in2/id2, in2%id2)
+               panic("fail")
+       }
+
+       /* int8 */
+       var bn1 int8 = +5
+       var bn2 int8 = -5
+       var bd1 int8 = +3
+       var bd2 int8 = -3
+
+       if bn1/bd1 != q1 || bn1%bd1 != r1 {
+               println("int8-1", bn1, bd1, bn1/bd1, bn1%bd1)
+               panic("fail")
+       }
+       if bn2/bd1 != q2 || bn2%bd1 != r2 {
+               println("int8-2", bn2, bd1, bn2/bd1, bn2%bd1)
+               panic("fail")
+       }
+       if bn1/bd2 != q3 || bn1%bd2 != r3 {
+               println("int8-3", bn1, bd2, bn1/bd2, bn1%bd2)
+               panic("fail")
+       }
+       if bn2/bd2 != q4 || bn2%bd2 != r4 {
+               println("int8-4", bn2, bd2, bn2/bd2, bn2%bd2)
+               panic("fail")
+       }
+
+       /* int16 */
+       var sn1 int16 = +5
+       var sn2 int16 = -5
+       var sd1 int16 = +3
+       var sd2 int16 = -3
+
+       if sn1/sd1 != q1 || sn1%sd1 != r1 {
+               println("int16-1", sn1, sd1, sn1/sd1, sn1%sd1)
+               panic("fail")
+       }
+       if sn2/sd1 != q2 || sn2%sd1 != r2 {
+               println("int16-2", sn2, sd1, sn2/sd1, sn2%sd1)
+               panic("fail")
+       }
+       if sn1/sd2 != q3 || sn1%sd2 != r3 {
+               println("int16-3", sn1, sd2, sn1/sd2, sn1%sd2)
+               panic("fail")
+       }
+       if sn2/sd2 != q4 || sn2%sd2 != r4 {
+               println("int16-4", sn2, sd2, sn2/sd2, sn2%sd2)
+               panic("fail")
+       }
+
+       /* int32 */
+       var ln1 int32 = +5
+       var ln2 int32 = -5
+       var ld1 int32 = +3
+       var ld2 int32 = -3
+
+       if ln1/ld1 != q1 || ln1%ld1 != r1 {
+               println("int32-1", ln1, ld1, ln1/ld1, ln1%ld1)
+               panic("fail")
+       }
+       if ln2/ld1 != q2 || ln2%ld1 != r2 {
+               println("int32-2", ln2, ld1, ln2/ld1, ln2%ld1)
+               panic("fail")
+       }
+       if ln1/ld2 != q3 || ln1%ld2 != r3 {
+               println("int32-3", ln1, ld2, ln1/ld2, ln1%ld2)
+               panic("fail")
+       }
+       if ln2/ld2 != q4 || ln2%ld2 != r4 {
+               println("int32-4", ln2, ld2, ln2/ld2, ln2%ld2)
+               panic("fail")
+       }
+
+       /* int64 */
+       var qn1 int64 = +5
+       var qn2 int64 = -5
+       var qd1 int64 = +3
+       var qd2 int64 = -3
+
+       if qn1/qd1 != q1 || qn1%qd1 != r1 {
+               println("int64-1", qn1, qd1, qn1/qd1, qn1%qd1)
+               panic("fail")
+       }
+       if qn2/qd1 != q2 || qn2%qd1 != r2 {
+               println("int64-2", qn2, qd1, qn2/qd1, qn2%qd1)
+               panic("fail")
+       }
+       if qn1/qd2 != q3 || qn1%qd2 != r3 {
+               println("int64-3", qn1, qd2, qn1/qd2, qn1%qd2)
+               panic("fail")
+       }
+       if qn2/qd2 != q4 || qn2%qd2 != r4 {
+               println("int64-4", qn2, qd2, qn2/qd2, qn2%qd2)
+               panic("fail")
+       }
+
+       if n1/qd1 != q1 || n1%qd1 != r1 {
+               println("mixed int64-1", n1, qd1, n1/qd1, n1%qd1)
+               panic("fail")
+       }
+       if n2/qd1 != q2 || n2%qd1 != r2 {
+               println("mixed int64-2", n2, qd1, n2/qd1, n2%qd1)
+               panic("fail")
+       }
+       if n1/qd2 != q3 || n1%qd2 != r3 {
+               println("mixed int64-3", n1, qd2, n1/qd2, n1%qd2)
+               panic("fail")
+       }
+       if n2/qd2 != q4 || n2%qd2 != r4 {
+               println("mixed int64-4", n2, qd2, n2/qd2, n2%qd2)
+               panic("fail")
+       }
+
+       if qn1/d1 != q1 || qn1%d1 != r1 {
+               println("mixed int64-5", qn1, d1, qn1/d1, qn1%d1)
+               panic("fail")
+       }
+       if qn2/d1 != q2 || qn2%d1 != r2 {
+               println("mixed int64-6", qn2, d1, qn2/d1, qn2%d1)
+               panic("fail")
+       }
+       if qn1/d2 != q3 || qn1%d2 != r3 {
+               println("mixed int64-7", qn1, d2, qn1/d2, qn1%d2)
+               panic("fail")
+       }
+       if qn2/d2 != q4 || qn2%d2 != r4 {
+               println("mixed int64-8", qn2, d2, qn2/d2, qn2%d2)
+               panic("fail")
+       }
+
+       /* uint */
+       var uin1 uint = +5
+       var uid1 uint = +3
+
+       if uin1/uid1 != q1 || uin1%uid1 != r1 {
+               println("uint", uin1, uid1, uin1/uid1, uin1%uid1)
+               panic("fail")
+       }
+
+       /* uint8 */
+       var ubn1 uint8 = +5
+       var ubd1 uint8 = +3
+
+       if ubn1/ubd1 != q1 || ubn1%ubd1 != r1 {
+               println("uint8", ubn1, ubd1, ubn1/ubd1, ubn1%ubd1)
+               panic("fail")
+       }
+
+       /* uint16 */
+       var usn1 uint16 = +5
+       var usd1 uint16 = +3
+
+       if usn1/usd1 != q1 || usn1%usd1 != r1 {
+               println("uint16", usn1, usd1, usn1/usd1, usn1%usd1)
+               panic("fail")
+       }
+
+       /* uint32 */
+       var uln1 uint32 = +5
+       var uld1 uint32 = +3
+
+       if uln1/uld1 != q1 || uln1%uld1 != r1 {
+               println("uint32", uln1, uld1, uln1/uld1, uln1%uld1)
+               panic("fail")
+       }
+
+       /* uint64 */
+       var uqn1 uint64 = +5
+       var uqd1 uint64 = +3
+
+       if uqn1/uqd1 != q1 || uqn1%uqd1 != r1 {
+               println("uint64", uqn1, uqd1, uqn1/uqd1, uqn1%uqd1)
+               panic("fail")
+       }
+       if n1/uqd1 != q1 || n1%uqd1 != r1 {
+               println("mixed uint64-1", n1, uqd1, n1/uqd1, n1%uqd1)
+               panic("fail")
+       }
+       if uqn1/d1 != q1 || uqn1%d1 != r1 {
+               println("mixed uint64-2", uqn1, d1, uqn1/d1, uqn1%d1)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/ken/embed.go b/gcc/testsuite/go.test/test/ken/embed.go
new file mode 100644 (file)
index 0000000..9805e47
--- /dev/null
@@ -0,0 +1,317 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+
+type I interface {
+       test1() int
+       test2() int
+       test3() int
+       test4() int
+       test5() int
+       test6() int
+       test7() int
+}
+
+/******
+ ******
+ ******/
+
+type SubpSubp struct {
+       a7 int
+       a  int
+}
+
+func (p *SubpSubp) test7() int {
+       if p.a != p.a7 {
+               println("SubpSubp", p, p.a7)
+               panic("fail")
+       }
+       return p.a
+}
+func (p *SubpSubp) testx() { println("SubpSubp", p, p.a7) }
+
+/******
+ ******
+ ******/
+
+type SubpSub struct {
+       a6 int
+       SubpSubp
+       a int
+}
+
+func (p *SubpSub) test6() int {
+       if p.a != p.a6 {
+               println("SubpSub", p, p.a6)
+               panic("fail")
+       }
+       return p.a
+}
+func (p *SubpSub) testx() { println("SubpSub", p, p.a6) }
+
+/******
+ ******
+ ******/
+
+type SubSubp struct {
+       a5 int
+       a  int
+}
+
+func (p *SubSubp) test5() int {
+       if p.a != p.a5 {
+               println("SubpSub", p, p.a5)
+               panic("fail")
+       }
+       return p.a
+}
+
+/******
+ ******
+ ******/
+
+type SubSub struct {
+       a4 int
+       a  int
+}
+
+func (p *SubSub) test4() int {
+       if p.a != p.a4 {
+               println("SubpSub", p, p.a4)
+               panic("fail")
+       }
+       return p.a
+}
+
+/******
+ ******
+ ******/
+
+type Subp struct {
+       a3 int
+       *SubpSubp
+       SubpSub
+       a int
+}
+
+func (p *Subp) test3() int {
+       if p.a != p.a3 {
+               println("SubpSub", p, p.a3)
+               panic("fail")
+       }
+       return p.a
+}
+
+/******
+ ******
+ ******/
+
+type Sub struct {
+       a2 int
+       *SubSubp
+       SubSub
+       a int
+}
+
+func (p *Sub) test2() int {
+       if p.a != p.a2 {
+               println("SubpSub", p, p.a2)
+               panic("fail")
+       }
+       return p.a
+}
+
+/******
+ ******
+ ******/
+
+type S struct {
+       a1 int
+       Sub
+       *Subp
+       a int
+}
+
+func (p *S) test1() int {
+       if p.a != p.a1 {
+               println("SubpSub", p, p.a1)
+               panic("fail")
+       }
+       return p.a
+}
+
+/******
+ ******
+ ******/
+
+func main() {
+       var i I
+       var s *S
+
+       // allocate
+       s = new(S)
+       s.Subp = new(Subp)
+       s.Sub.SubSubp = new(SubSubp)
+       s.Subp.SubpSubp = new(SubpSubp)
+
+       // explicit assignment
+       s.a = 1
+       s.Sub.a = 2
+       s.Subp.a = 3
+       s.Sub.SubSub.a = 4
+       s.Sub.SubSubp.a = 5
+       s.Subp.SubpSub.a = 6
+       s.Subp.SubpSubp.a = 7
+
+       // embedded (unique) assignment
+       s.a1 = 1
+       s.a2 = 2
+       s.a3 = 3
+       s.a4 = 4
+       s.a5 = 5
+       s.a6 = 6
+       s.a7 = 7
+
+       // unique calls with explicit &
+       if s.test1() != 1 {
+               println("t1", 1)
+               panic("fail")
+       }
+       if (&s.Sub).test2() != 2 {
+               println("t1", 2)
+               panic("fail")
+       }
+       if s.Subp.test3() != 3 {
+               println("t1", 3)
+               panic("fail")
+       }
+       if (&s.Sub.SubSub).test4() != 4 {
+               println("t1", 4)
+               panic("fail")
+       }
+       if s.Sub.SubSubp.test5() != 5 {
+               println("t1", 5)
+               panic("fail")
+       }
+       if (&s.Subp.SubpSub).test6() != 6 {
+               println("t1", 6)
+               panic("fail")
+       }
+       if s.Subp.SubpSubp.test7() != 7 {
+               println("t1", 7)
+               panic("fail")
+       }
+
+       // automatic &
+       if s.Sub.test2() != 2 {
+               println("t2", 2)
+               panic("fail")
+       }
+       if s.Sub.SubSub.test4() != 4 {
+               println("t2", 4)
+               panic("fail")
+       }
+       if s.Subp.SubpSub.test6() != 6 {
+               println("t2", 6)
+               panic("fail")
+       }
+
+       // embedded calls
+       if s.test1() != s.a1 {
+               println("t3", 1)
+               panic("fail")
+       }
+       if s.test2() != s.a2 {
+               println("t3", 2)
+               panic("fail")
+       }
+       if s.test3() != s.a3 {
+               println("t3", 3)
+               panic("fail")
+       }
+       if s.test4() != s.a4 {
+               println("t3", 4)
+               panic("fail")
+       }
+       if s.test5() != s.a5 {
+               println("t3", 5)
+               panic("fail")
+       }
+       if s.test6() != s.a6 {
+               println("t3", 6)
+               panic("fail")
+       }
+       if s.test7() != s.a7 {
+               println("t3", 7)
+               panic("fail")
+       }
+
+       // run it thru an interface
+       i = s
+       s = i.(*S)
+
+       // same as t3
+       if s.test1() != s.a1 {
+               println("t4", 1)
+               panic("fail")
+       }
+       if s.test2() != s.a2 {
+               println("t4", 2)
+               panic("fail")
+       }
+       if s.test3() != s.a3 {
+               println("t4", 3)
+               panic("fail")
+       }
+       if s.test4() != s.a4 {
+               println("t4", 4)
+               panic("fail")
+       }
+       if s.test5() != s.a5 {
+               println("t4", 5)
+               panic("fail")
+       }
+       if s.test6() != s.a6 {
+               println("t4", 6)
+               panic("fail")
+       }
+       if s.test7() != s.a7 {
+               println("t4", 7)
+               panic("fail")
+       }
+
+       // call interface
+       if i.test1() != s.test1() {
+               println("t5", 1)
+               panic("fail")
+       }
+       if i.test2() != s.test2() {
+               println("t5", 2)
+               panic("fail")
+       }
+       if i.test3() != s.test3() {
+               println("t5", 3)
+               panic("fail")
+       }
+       if i.test4() != s.test4() {
+               println("t5", 4)
+               panic("fail")
+       }
+       if i.test5() != s.test5() {
+               println("t5", 5)
+               panic("fail")
+       }
+       if i.test6() != s.test6() {
+               println("t5", 6)
+               panic("fail")
+       }
+       if i.test7() != s.test7() {
+               println("t5", 7)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/ken/for.go b/gcc/testsuite/go.test/test/ken/for.go
new file mode 100644 (file)
index 0000000..176ecd7
--- /dev/null
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+func
+main() {
+       var t,i int;
+
+       for i=0; i<100; i=i+1 {
+               t = t+i;
+       }
+       if t != 50*99  { panic(t); }
+}
diff --git a/gcc/testsuite/go.test/test/ken/interbasic.go b/gcc/testsuite/go.test/test/ken/interbasic.go
new file mode 100644 (file)
index 0000000..9bb5088
--- /dev/null
@@ -0,0 +1,182 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type myint int
+type mystring string
+type I0 interface{}
+
+func f() {
+       var ia, ib I0
+       var i myint
+       var s mystring
+
+       if ia != ib {
+               panic("1")
+       }
+
+       i = 1
+       ia = i
+       ib = i
+       if ia != ib {
+               panic("2")
+       }
+       if ia == nil {
+               panic("3")
+       }
+
+       i = 2
+       ia = i
+       if ia == ib {
+               panic("4")
+       }
+
+       ia = nil
+       if ia == ib {
+               panic("5")
+       }
+
+       ib = nil
+       if ia != ib {
+               panic("6")
+       }
+
+       if ia != nil {
+               panic("7")
+       }
+
+       s = "abc"
+       ia = s
+       ib = nil
+       if ia == ib {
+               panic("8")
+       }
+
+       s = "def"
+       ib = s
+       if ia == ib {
+               panic("9")
+       }
+
+       s = "abc"
+       ib = s
+       if ia != ib {
+               panic("a")
+       }
+}
+
+func main() {
+       var ia [20]I0
+       var b bool
+       var s string
+       var i8 int8
+       var i16 int16
+       var i32 int32
+       var i64 int64
+       var u8 uint8
+       var u16 uint16
+       var u32 uint32
+       var u64 uint64
+
+       f()
+
+       ia[0] = "xxx"
+       ia[1] = 12345
+       ia[2] = true
+
+       s = "now is"
+       ia[3] = s
+       b = false
+       ia[4] = b
+
+       i8 = 29
+       ia[5] = i8
+       i16 = 994
+       ia[6] = i16
+       i32 = 3434
+       ia[7] = i32
+       i64 = 1234567
+       ia[8] = i64
+
+       u8 = 12
+       ia[9] = u8
+       u16 = 799
+       ia[10] = u16
+       u32 = 4455
+       ia[11] = u32
+       u64 = 765432
+       ia[12] = u64
+
+       s = ia[0].(string)
+       if s != "xxx" {
+               println(0, s)
+               panic("fail")
+       }
+       i32 = int32(ia[1].(int))
+       if i32 != 12345 {
+               println(1, i32)
+               panic("fail")
+       }
+       b = ia[2].(bool)
+       if b != true {
+               println(2, b)
+               panic("fail")
+       }
+
+       s = ia[3].(string)
+       if s != "now is" {
+               println(3, s)
+               panic("fail")
+       }
+       b = ia[4].(bool)
+       if b != false {
+               println(4, b)
+               panic("fail")
+       }
+
+       i8 = ia[5].(int8)
+       if i8 != 29 {
+               println(5, i8)
+               panic("fail")
+       }
+       i16 = ia[6].(int16)
+       if i16 != 994 {
+               println(6, i16)
+               panic("fail")
+       }
+       i32 = ia[7].(int32)
+       if i32 != 3434 {
+               println(7, i32)
+               panic("fail")
+       }
+       i64 = ia[8].(int64)
+       if i64 != 1234567 {
+               println(8, i64)
+               panic("fail")
+       }
+
+       u8 = ia[9].(uint8)
+       if u8 != 12 {
+               println(5, u8)
+               panic("fail")
+       }
+       u16 = ia[10].(uint16)
+       if u16 != 799 {
+               println(6, u16)
+               panic("fail")
+       }
+       u32 = ia[11].(uint32)
+       if u32 != 4455 {
+               println(7, u32)
+               panic("fail")
+       }
+       u64 = ia[12].(uint64)
+       if u64 != 765432 {
+               println(8, u64)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/ken/interfun.go b/gcc/testsuite/go.test/test/ken/interfun.go
new file mode 100644 (file)
index 0000000..94bc7ea
--- /dev/null
@@ -0,0 +1,57 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S struct {
+       a,b     int;
+}
+
+type I1 interface {
+       f       ()int;
+}
+
+type I2 interface {
+       g() int;
+       f() int;
+}
+
+func (this *S) f()int {
+       return this.a;
+}
+
+func (this *S) g()int {
+       return this.b;
+}
+
+func
+main() {
+       var i1 I1;
+       var i2 I2;
+       var g *S;
+
+       s := new(S);
+       s.a = 5;
+       s.b = 6;
+
+       // call structure
+       if s.f() != 5 { panic(11); }
+       if s.g() != 6 { panic(12); }
+
+       i1 = s;         // convert S to I1
+       i2 = i1.(I2);   // convert I1 to I2
+
+       // call interface
+       if i1.f() != 5 { panic(21); }
+       if i2.f() != 5 { panic(22); }
+       if i2.g() != 6 { panic(23); }
+
+       g = i1.(*S);            // convert I1 to S
+       if g != s { panic(31); }
+
+       g = i2.(*S);            // convert I2 to S
+       if g != s { panic(32); }
+}
diff --git a/gcc/testsuite/go.test/test/ken/intervar.go b/gcc/testsuite/go.test/test/ken/intervar.go
new file mode 100644 (file)
index 0000000..c2aaaa8
--- /dev/null
@@ -0,0 +1,64 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type   Iputs   interface {
+       puts    (s string);
+}
+
+// ---------
+
+type   Print   struct {
+       whoami  int;
+       put     Iputs;
+}
+
+func (p *Print) dop() {
+       print(" print ", p.whoami);
+       p.put.puts("abc");
+}
+
+// ---------
+
+type   Bio     struct {
+       whoami  int;
+       put     Iputs;
+}
+
+func (b *Bio) puts(s string) {
+       print(" bio ", b.whoami);
+       b.put.puts(s);
+}
+
+// ---------
+
+type   File    struct {
+       whoami  int;
+       put     Iputs;
+}
+
+func (f *File) puts(s string) {
+       print(" file ", f.whoami, " -- ", s);
+}
+
+func
+main() {
+       p := new(Print);
+       b := new(Bio);
+       f := new(File);
+
+       p.whoami = 1;
+       p.put = b;
+
+       b.whoami = 2;
+       b.put = f;
+
+       f.whoami = 3;
+
+       p.dop();
+       print("\n");
+}
diff --git a/gcc/testsuite/go.test/test/ken/label.go b/gcc/testsuite/go.test/test/ken/label.go
new file mode 100644 (file)
index 0000000..770f33e
--- /dev/null
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+func
+main() {
+       i := 0;
+       if false {
+               goto gogoloop;
+       }
+       if false {
+               goto gogoloop;
+       }
+       if false {
+               goto gogoloop;
+       }
+       goto gogoloop;
+
+// backward declared
+loop:
+       i = i+1;
+       if i < 100 {
+               goto loop;
+       }
+       print(i);
+       print("\n");
+       return;
+
+gogoloop:
+       goto loop;
+}
diff --git a/gcc/testsuite/go.test/test/ken/litfun.go b/gcc/testsuite/go.test/test/ken/litfun.go
new file mode 100644 (file)
index 0000000..bac2bc1
--- /dev/null
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+func
+main() {
+       x := func(a int)int {
+               x := func(a int)int {
+                       x := func(a int)int {
+                               return a+5;
+                       };
+                       return x(a)+7;
+               };
+               return x(a)+11;
+       };
+       if x(3) != 3+5+7+11 { panic(x(3)); }
+}
diff --git a/gcc/testsuite/go.test/test/ken/mfunc.go b/gcc/testsuite/go.test/test/ken/mfunc.go
new file mode 100644 (file)
index 0000000..ae0bc0c
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func
+main() {
+       var x,y int;
+
+       x,y = simple(10,20,30);
+       if x+y != 65 { panic(x+y); }
+}
+
+func
+simple(ia,ib,ic int) (oa,ob int) {
+       return ia+5, ib+ic;
+}
diff --git a/gcc/testsuite/go.test/test/ken/modconst.go b/gcc/testsuite/go.test/test/ken/modconst.go
new file mode 100644 (file)
index 0000000..acb8831
--- /dev/null
@@ -0,0 +1,632 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "rand"
+
+const Count = 1e5
+
+func i64rand() int64 {
+       for {
+               a := int64(rand.Uint32())
+               a = (a << 32) | int64(rand.Uint32())
+               a >>= uint(rand.Intn(64))
+               if -a != a {
+                       return a
+               }
+       }
+       return 0 // impossible
+}
+
+func i64test(a, b, c int64) {
+       d := a % c
+       if d != b {
+               println("i64", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func i64run() {
+       var a, b int64
+
+       for i := 0; i < Count; i++ {
+               a = i64rand()
+
+               b = a % 1
+               i64test(a, b, 1)
+               b = a % 2
+               i64test(a, b, 2)
+               b = a % 3
+               i64test(a, b, 3)
+               b = a % 4
+               i64test(a, b, 4)
+               b = a % 5
+               i64test(a, b, 5)
+               b = a % 6
+               i64test(a, b, 6)
+               b = a % 7
+               i64test(a, b, 7)
+               b = a % 8
+               i64test(a, b, 8)
+               b = a % 10
+               i64test(a, b, 10)
+               b = a % 16
+               i64test(a, b, 16)
+               b = a % 20
+               i64test(a, b, 20)
+               b = a % 32
+               i64test(a, b, 32)
+               b = a % 60
+               i64test(a, b, 60)
+               b = a % 64
+               i64test(a, b, 64)
+               b = a % 128
+               i64test(a, b, 128)
+               b = a % 256
+               i64test(a, b, 256)
+               b = a % 16384
+               i64test(a, b, 16384)
+
+               b = a % -1
+               i64test(a, b, -1)
+               b = a % -2
+               i64test(a, b, -2)
+               b = a % -3
+               i64test(a, b, -3)
+               b = a % -4
+               i64test(a, b, -4)
+               b = a % -5
+               i64test(a, b, -5)
+               b = a % -6
+               i64test(a, b, -6)
+               b = a % -7
+               i64test(a, b, -7)
+               b = a % -8
+               i64test(a, b, -8)
+               b = a % -10
+               i64test(a, b, -10)
+               b = a % -16
+               i64test(a, b, -16)
+               b = a % -20
+               i64test(a, b, -20)
+               b = a % -32
+               i64test(a, b, -32)
+               b = a % -60
+               i64test(a, b, -60)
+               b = a % -64
+               i64test(a, b, -64)
+               b = a % -128
+               i64test(a, b, -128)
+               b = a % -256
+               i64test(a, b, -256)
+               b = a % -16384
+               i64test(a, b, -16384)
+       }
+}
+
+func u64rand() uint64 {
+       a := uint64(rand.Uint32())
+       a = (a << 32) | uint64(rand.Uint32())
+       a >>= uint(rand.Intn(64))
+       return a
+}
+
+func u64test(a, b, c uint64) {
+       d := a % c
+       if d != b {
+               println("u64", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func u64run() {
+       var a, b uint64
+
+       for i := 0; i < Count; i++ {
+               a = u64rand()
+
+               b = a % 1
+               u64test(a, b, 1)
+               b = a % 2
+               u64test(a, b, 2)
+               b = a % 3
+               u64test(a, b, 3)
+               b = a % 4
+               u64test(a, b, 4)
+               b = a % 5
+               u64test(a, b, 5)
+               b = a % 6
+               u64test(a, b, 6)
+               b = a % 7
+               u64test(a, b, 7)
+               b = a % 8
+               u64test(a, b, 8)
+               b = a % 10
+               u64test(a, b, 10)
+               b = a % 16
+               u64test(a, b, 16)
+               b = a % 20
+               u64test(a, b, 20)
+               b = a % 32
+               u64test(a, b, 32)
+               b = a % 60
+               u64test(a, b, 60)
+               b = a % 64
+               u64test(a, b, 64)
+               b = a % 128
+               u64test(a, b, 128)
+               b = a % 256
+               u64test(a, b, 256)
+               b = a % 16384
+               u64test(a, b, 16384)
+       }
+}
+
+func i32rand() int32 {
+       for {
+               a := int32(rand.Uint32())
+               a >>= uint(rand.Intn(32))
+               if -a != a {
+                       return a
+               }
+       }
+       return 0 // impossible
+}
+
+func i32test(a, b, c int32) {
+       d := a % c
+       if d != b {
+               println("i32", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func i32run() {
+       var a, b int32
+
+       for i := 0; i < Count; i++ {
+               a = i32rand()
+
+               b = a % 1
+               i32test(a, b, 1)
+               b = a % 2
+               i32test(a, b, 2)
+               b = a % 3
+               i32test(a, b, 3)
+               b = a % 4
+               i32test(a, b, 4)
+               b = a % 5
+               i32test(a, b, 5)
+               b = a % 6
+               i32test(a, b, 6)
+               b = a % 7
+               i32test(a, b, 7)
+               b = a % 8
+               i32test(a, b, 8)
+               b = a % 10
+               i32test(a, b, 10)
+               b = a % 16
+               i32test(a, b, 16)
+               b = a % 20
+               i32test(a, b, 20)
+               b = a % 32
+               i32test(a, b, 32)
+               b = a % 60
+               i32test(a, b, 60)
+               b = a % 64
+               i32test(a, b, 64)
+               b = a % 128
+               i32test(a, b, 128)
+               b = a % 256
+               i32test(a, b, 256)
+               b = a % 16384
+               i32test(a, b, 16384)
+
+               b = a % -1
+               i32test(a, b, -1)
+               b = a % -2
+               i32test(a, b, -2)
+               b = a % -3
+               i32test(a, b, -3)
+               b = a % -4
+               i32test(a, b, -4)
+               b = a % -5
+               i32test(a, b, -5)
+               b = a % -6
+               i32test(a, b, -6)
+               b = a % -7
+               i32test(a, b, -7)
+               b = a % -8
+               i32test(a, b, -8)
+               b = a % -10
+               i32test(a, b, -10)
+               b = a % -16
+               i32test(a, b, -16)
+               b = a % -20
+               i32test(a, b, -20)
+               b = a % -32
+               i32test(a, b, -32)
+               b = a % -60
+               i32test(a, b, -60)
+               b = a % -64
+               i32test(a, b, -64)
+               b = a % -128
+               i32test(a, b, -128)
+               b = a % -256
+               i32test(a, b, -256)
+       }
+}
+
+func u32rand() uint32 {
+       a := uint32(rand.Uint32())
+       a >>= uint(rand.Intn(32))
+       return a
+}
+
+func u32test(a, b, c uint32) {
+       d := a % c
+       if d != b {
+               println("u32", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func u32run() {
+       var a, b uint32
+
+       for i := 0; i < Count; i++ {
+               a = u32rand()
+
+               b = a % 1
+               u32test(a, b, 1)
+               b = a % 2
+               u32test(a, b, 2)
+               b = a % 3
+               u32test(a, b, 3)
+               b = a % 4
+               u32test(a, b, 4)
+               b = a % 5
+               u32test(a, b, 5)
+               b = a % 6
+               u32test(a, b, 6)
+               b = a % 7
+               u32test(a, b, 7)
+               b = a % 8
+               u32test(a, b, 8)
+               b = a % 10
+               u32test(a, b, 10)
+               b = a % 16
+               u32test(a, b, 16)
+               b = a % 20
+               u32test(a, b, 20)
+               b = a % 32
+               u32test(a, b, 32)
+               b = a % 60
+               u32test(a, b, 60)
+               b = a % 64
+               u32test(a, b, 64)
+               b = a % 128
+               u32test(a, b, 128)
+               b = a % 256
+               u32test(a, b, 256)
+               b = a % 16384
+               u32test(a, b, 16384)
+       }
+}
+
+func i16rand() int16 {
+       for {
+               a := int16(rand.Uint32())
+               a >>= uint(rand.Intn(16))
+               if -a != a {
+                       return a
+               }
+       }
+       return 0 // impossible
+}
+
+func i16test(a, b, c int16) {
+       d := a % c
+       if d != b {
+               println("i16", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func i16run() {
+       var a, b int16
+
+       for i := 0; i < Count; i++ {
+               a = i16rand()
+
+               b = a % 1
+               i16test(a, b, 1)
+               b = a % 2
+               i16test(a, b, 2)
+               b = a % 3
+               i16test(a, b, 3)
+               b = a % 4
+               i16test(a, b, 4)
+               b = a % 5
+               i16test(a, b, 5)
+               b = a % 6
+               i16test(a, b, 6)
+               b = a % 7
+               i16test(a, b, 7)
+               b = a % 8
+               i16test(a, b, 8)
+               b = a % 10
+               i16test(a, b, 10)
+               b = a % 16
+               i16test(a, b, 16)
+               b = a % 20
+               i16test(a, b, 20)
+               b = a % 32
+               i16test(a, b, 32)
+               b = a % 60
+               i16test(a, b, 60)
+               b = a % 64
+               i16test(a, b, 64)
+               b = a % 128
+               i16test(a, b, 128)
+               b = a % 256
+               i16test(a, b, 256)
+               b = a % 16384
+               i16test(a, b, 16384)
+
+               b = a % -1
+               i16test(a, b, -1)
+               b = a % -2
+               i16test(a, b, -2)
+               b = a % -3
+               i16test(a, b, -3)
+               b = a % -4
+               i16test(a, b, -4)
+               b = a % -5
+               i16test(a, b, -5)
+               b = a % -6
+               i16test(a, b, -6)
+               b = a % -7
+               i16test(a, b, -7)
+               b = a % -8
+               i16test(a, b, -8)
+               b = a % -10
+               i16test(a, b, -10)
+               b = a % -16
+               i16test(a, b, -16)
+               b = a % -20
+               i16test(a, b, -20)
+               b = a % -32
+               i16test(a, b, -32)
+               b = a % -60
+               i16test(a, b, -60)
+               b = a % -64
+               i16test(a, b, -64)
+               b = a % -128
+               i16test(a, b, -128)
+               b = a % -256
+               i16test(a, b, -256)
+               b = a % -16384
+               i16test(a, b, -16384)
+       }
+}
+
+func u16rand() uint16 {
+       a := uint16(rand.Uint32())
+       a >>= uint(rand.Intn(16))
+       return a
+}
+
+func u16test(a, b, c uint16) {
+       d := a % c
+       if d != b {
+               println("u16", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func u16run() {
+       var a, b uint16
+
+       for i := 0; i < Count; i++ {
+               a = u16rand()
+
+               b = a % 1
+               u16test(a, b, 1)
+               b = a % 2
+               u16test(a, b, 2)
+               b = a % 3
+               u16test(a, b, 3)
+               b = a % 4
+               u16test(a, b, 4)
+               b = a % 5
+               u16test(a, b, 5)
+               b = a % 6
+               u16test(a, b, 6)
+               b = a % 7
+               u16test(a, b, 7)
+               b = a % 8
+               u16test(a, b, 8)
+               b = a % 10
+               u16test(a, b, 10)
+               b = a % 16
+               u16test(a, b, 16)
+               b = a % 20
+               u16test(a, b, 20)
+               b = a % 32
+               u16test(a, b, 32)
+               b = a % 60
+               u16test(a, b, 60)
+               b = a % 64
+               u16test(a, b, 64)
+               b = a % 128
+               u16test(a, b, 128)
+               b = a % 256
+               u16test(a, b, 256)
+               b = a % 16384
+               u16test(a, b, 16384)
+       }
+}
+
+func i8rand() int8 {
+       for {
+               a := int8(rand.Uint32())
+               a >>= uint(rand.Intn(8))
+               if -a != a {
+                       return a
+               }
+       }
+       return 0 // impossible
+}
+
+func i8test(a, b, c int8) {
+       d := a % c
+       if d != b {
+               println("i8", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func i8run() {
+       var a, b int8
+
+       for i := 0; i < Count; i++ {
+               a = i8rand()
+
+               b = a % 1
+               i8test(a, b, 1)
+               b = a % 2
+               i8test(a, b, 2)
+               b = a % 3
+               i8test(a, b, 3)
+               b = a % 4
+               i8test(a, b, 4)
+               b = a % 5
+               i8test(a, b, 5)
+               b = a % 6
+               i8test(a, b, 6)
+               b = a % 7
+               i8test(a, b, 7)
+               b = a % 8
+               i8test(a, b, 8)
+               b = a % 10
+               i8test(a, b, 10)
+               b = a % 8
+               i8test(a, b, 8)
+               b = a % 20
+               i8test(a, b, 20)
+               b = a % 32
+               i8test(a, b, 32)
+               b = a % 60
+               i8test(a, b, 60)
+               b = a % 64
+               i8test(a, b, 64)
+               b = a % 127
+               i8test(a, b, 127)
+
+               b = a % -1
+               i8test(a, b, -1)
+               b = a % -2
+               i8test(a, b, -2)
+               b = a % -3
+               i8test(a, b, -3)
+               b = a % -4
+               i8test(a, b, -4)
+               b = a % -5
+               i8test(a, b, -5)
+               b = a % -6
+               i8test(a, b, -6)
+               b = a % -7
+               i8test(a, b, -7)
+               b = a % -8
+               i8test(a, b, -8)
+               b = a % -10
+               i8test(a, b, -10)
+               b = a % -8
+               i8test(a, b, -8)
+               b = a % -20
+               i8test(a, b, -20)
+               b = a % -32
+               i8test(a, b, -32)
+               b = a % -60
+               i8test(a, b, -60)
+               b = a % -64
+               i8test(a, b, -64)
+               b = a % -128
+               i8test(a, b, -128)
+               b = a % -101
+               i8test(a, b, -101)
+       }
+}
+
+func u8rand() uint8 {
+       a := uint8(rand.Uint32())
+       a >>= uint(rand.Intn(8))
+       return a
+}
+
+func u8test(a, b, c uint8) {
+       d := a % c
+       if d != b {
+               println("u8", a, b, c, d)
+               panic("fail")
+       }
+}
+
+func u8run() {
+       var a, b uint8
+
+       for i := 0; i < Count; i++ {
+               a = u8rand()
+
+               b = a % 1
+               u8test(a, b, 1)
+               b = a % 2
+               u8test(a, b, 2)
+               b = a % 3
+               u8test(a, b, 3)
+               b = a % 4
+               u8test(a, b, 4)
+               b = a % 5
+               u8test(a, b, 5)
+               b = a % 6
+               u8test(a, b, 6)
+               b = a % 7
+               u8test(a, b, 7)
+               b = a % 8
+               u8test(a, b, 8)
+               b = a % 10
+               u8test(a, b, 10)
+               b = a % 8
+               u8test(a, b, 8)
+               b = a % 20
+               u8test(a, b, 20)
+               b = a % 32
+               u8test(a, b, 32)
+               b = a % 60
+               u8test(a, b, 60)
+               b = a % 64
+               u8test(a, b, 64)
+               b = a % 127
+               u8test(a, b, 127)
+       }
+}
+
+func main() {
+       xtest()
+       i64run()
+       u64run()
+       i32run()
+       u32run()
+       i16run()
+       u16run()
+       i8run()
+       u8run()
+}
+
+func xtest() {
+}
diff --git a/gcc/testsuite/go.test/test/ken/ptrfun.go b/gcc/testsuite/go.test/test/ken/ptrfun.go
new file mode 100644 (file)
index 0000000..6739ba3
--- /dev/null
@@ -0,0 +1,44 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+type C struct {
+       a       int;
+       x       func(p *C)int;
+}
+
+func (this *C) f()int {
+       return this.a;
+}
+
+func
+main() {
+       var v int;
+       var c *C;
+
+       c = new(C);
+       c.a = 6;
+       c.x = g;
+
+       v = g(c);
+       if v != 6 { panic(v); }
+
+       v = c.x(c);
+       if v != 6 { panic(v); }
+
+       v = c.f();
+       if v != 6 { panic(v); }
+}
+
+func g(p *C)int {
+       var v int;
+
+       v = p.a;
+       if v != 6 { panic(v); }
+       return p.a;
+}
diff --git a/gcc/testsuite/go.test/test/ken/ptrvar.go b/gcc/testsuite/go.test/test/ken/ptrvar.go
new file mode 100644 (file)
index 0000000..e2ddde6
--- /dev/null
@@ -0,0 +1,53 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+type   x2      struct { a,b,c int; d int; };
+var    g1      x2;
+var    g2      struct { a,b,c int; d x2; };
+
+func
+main() {
+       var x int;
+       var s1 *x2;
+       var s2 *struct { a,b,c int; d x2; };
+
+       s1 = &g1;
+       s2 = &g2;
+
+       s1.a = 1;
+       s1.b = 2;
+       s1.c = 3;
+       s1.d = 5;
+
+       s2.a = 7;
+       s2.b = 11;
+       s2.c = 13;
+       s2.d.a = 17;
+       s2.d.b = 19;
+       s2.d.c = 23;
+       s2.d.d = 20;
+
+       if(s2.d.c != 23) { panic(1); }
+       if(g2.d.c != 23) { panic(2); }
+
+       x =     s1.a +
+               s1.b +
+               s1.c +
+               s1.d +
+
+               s2.a +
+               s2.b +
+               s2.c +
+               s2.d.a +
+               s2.d.b +
+               s2.d.c +
+               s2.d.d;
+
+       if(x != 121) { panic(x); }
+}
diff --git a/gcc/testsuite/go.test/test/ken/range.go b/gcc/testsuite/go.test/test/ken/range.go
new file mode 100644 (file)
index 0000000..9535fd4
--- /dev/null
@@ -0,0 +1,119 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const size = 16
+
+var a [size]byte
+var p []byte
+var m map[int]byte
+
+func f(k int) byte {
+       return byte(k * 10007 % size)
+}
+
+func init() {
+       p = make([]byte, size)
+       m = make(map[int]byte)
+       for k := 0; k < size; k++ {
+               v := f(k)
+               a[k] = v
+               p[k] = v
+               m[k] = v
+       }
+}
+
+func main() {
+       var i int
+
+       /*
+        * key only
+        */
+       i = 0
+       for k := range a {
+               v := a[k]
+               if v != f(k) {
+                       println("key array range", k, v, a[k])
+                       panic("fail")
+               }
+               i++
+       }
+       if i != size {
+               println("key array size", i)
+               panic("fail")
+       }
+
+       i = 0
+       for k := range p {
+               v := p[k]
+               if v != f(k) {
+                       println("key pointer range", k, v, p[k])
+                       panic("fail")
+               }
+               i++
+       }
+       if i != size {
+               println("key pointer size", i)
+               panic("fail")
+       }
+
+       i = 0
+       for k := range m {
+               v := m[k]
+               if v != f(k) {
+                       println("key map range", k, v, m[k])
+                       panic("fail")
+               }
+               i++
+       }
+       if i != size {
+               println("key map size", i)
+               panic("fail")
+       }
+
+       /*
+        * key,value
+        */
+       i = 0
+       for k, v := range a {
+               if v != f(k) {
+                       println("key:value array range", k, v, a[k])
+                       panic("fail")
+               }
+               i++
+       }
+       if i != size {
+               println("key:value array size", i)
+               panic("fail")
+       }
+
+       i = 0
+       for k, v := range p {
+               if v != f(k) {
+                       println("key:value pointer range", k, v, p[k])
+                       panic("fail")
+               }
+               i++
+       }
+       if i != size {
+               println("key:value pointer size", i)
+               panic("fail")
+       }
+
+       i = 0
+       for k, v := range m {
+               if v != f(k) {
+                       println("key:value map range", k, v, m[k])
+                       panic("fail")
+               }
+               i++
+       }
+       if i != size {
+               println("key:value map size", i)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/ken/rob1.go b/gcc/testsuite/go.test/test/ken/rob1.go
new file mode 100644 (file)
index 0000000..0335066
--- /dev/null
@@ -0,0 +1,67 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Item interface {
+       Print();
+}
+
+type ListItem struct {
+       item    Item;
+       next    *ListItem;
+}
+
+type List struct {
+       head    *ListItem;
+}
+
+func (list *List) Init() {
+       list.head = nil;
+}
+
+func (list *List) Insert(i Item) {
+       item := new(ListItem);
+       item.item = i;
+       item.next = list.head;
+       list.head = item;
+}
+
+func (list *List) Print() {
+       i := list.head;
+       for i != nil {
+               i.item.Print();
+               i = i.next;
+       }
+}
+
+// Something to put in a list
+type Integer struct {
+       val             int;
+}
+
+func (this *Integer) Init(i int) *Integer {
+       this.val = i;
+       return this;
+}
+
+func (this *Integer) Print() {
+       print(this.val);
+}
+
+func
+main() {
+       list := new(List);
+       list.Init();
+       for i := 0; i < 10; i = i + 1 {
+               integer := new(Integer);
+               integer.Init(i);
+               list.Insert(integer);
+       }
+
+       list.Print();
+       print("\n");
+}
diff --git a/gcc/testsuite/go.test/test/ken/rob2.go b/gcc/testsuite/go.test/test/ken/rob2.go
new file mode 100644 (file)
index 0000000..af63e4d
--- /dev/null
@@ -0,0 +1,272 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+const nilchar = 0;
+
+type Atom struct {
+       str             string;
+       integer         int;
+       next            *Slist; /* in hash bucket */
+}
+
+type List struct {
+       car             *Slist;
+       cdr*Slist;
+}
+
+type Slist struct {
+       isatom          bool;
+       isstring        bool;
+       //union {
+       atom            Atom;
+       list            List;
+       //} u;
+
+}
+
+func (this *Slist) Car() *Slist {
+       return this.list.car;
+}
+
+func (this *Slist) Cdr() *Slist {
+       return this.list.cdr;
+}
+
+func (this *Slist) String() string {
+       return this.atom.str;
+}
+
+func (this *Slist) Integer() int {
+       return this.atom.integer;
+}
+
+func (slist *Slist) Free() {
+       if slist == nil {
+               return;
+       }
+       if slist.isatom {
+//             free(slist.String());
+       } else {
+               slist.Car().Free();
+               slist.Cdr().Free();
+       }
+//     free(slist);
+}
+
+//Slist* atom(byte *s, int i);
+
+var token int;
+var peekc int = -1;
+var lineno int32 = 1;
+
+var input string;
+var inputindex int = 0;
+var tokenbuf [100]byte;
+var tokenlen int = 0;
+
+const EOF int = -1;
+
+func main() {
+       var list *Slist;
+
+       OpenFile();
+       for ;; {
+               list = Parse();
+               if list == nil {
+                       break;
+               }
+               list.Print();
+               list.Free();
+               break;
+       }
+}
+
+func (slist *Slist) PrintOne(doparen bool) {
+       if slist == nil {
+               return;
+       }
+       if slist.isatom {
+               if slist.isstring {
+                       print(slist.String());
+               } else {
+                       print(slist.Integer());
+               }
+       } else {
+               if doparen {
+                       print("(" );
+               }
+               slist.Car().PrintOne(true);
+               if slist.Cdr() != nil {
+                       print(" ");
+                       slist.Cdr().PrintOne(false);
+               }
+               if doparen {
+                       print(")");
+               }
+       }
+}
+
+func (slist *Slist) Print() {
+       slist.PrintOne(true);
+       print("\n");
+}
+
+func Get() int {
+       var c int;
+
+       if peekc >= 0 {
+               c = peekc;
+               peekc = -1;
+       } else {
+               c = int(input[inputindex]);
+               inputindex++;
+               if c == '\n' {
+                       lineno = lineno + 1;
+               }
+               if c == nilchar {
+                       inputindex = inputindex - 1;
+                       c = EOF;
+               }
+       }
+       return c;
+}
+
+func WhiteSpace(c int) bool {
+       return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+}
+
+func NextToken() {
+       var i, c int;
+
+       tokenbuf[0] = nilchar;  // clear previous token
+       c = Get();
+       for WhiteSpace(c) {
+               c = Get();
+       }
+       switch c {
+       case EOF:
+               token = EOF;
+       case '(', ')':
+               token = c;
+               break;
+       default:
+               for i = 0; i < 100 - 1; {       // sizeof tokenbuf - 1
+                       tokenbuf[i] = byte(c);
+                       i = i + 1;
+                       c = Get();
+                       if c == EOF {
+                               break;
+                       }
+                       if WhiteSpace(c) || c == ')' {
+                               peekc = c;
+                               break;
+                       }
+               }
+               if i >= 100 - 1 {       // sizeof tokenbuf - 1
+                       panic("atom too long\n");
+               }
+               tokenlen = i;
+               tokenbuf[i] = nilchar;
+               if '0' <= tokenbuf[0] && tokenbuf[0] <= '9' {
+                       token = '0';
+               } else {
+                       token = 'A';
+               }
+       }
+}
+
+func Expect(c int) {
+       if token != c {
+               print("parse error: expected ", c, "\n");
+               panic("parse");
+       }
+       NextToken();
+}
+
+// Parse a non-parenthesized list up to a closing paren or EOF
+func ParseList() *Slist {
+       var slist, retval *Slist;
+
+       slist = new(Slist);
+       slist.list.car = nil;
+       slist.list.cdr = nil;
+       slist.isatom = false;
+       slist.isstring = false;
+
+       retval = slist;
+       for ;; {
+               slist.list.car = Parse();
+               if token == ')' || token == EOF {       // empty cdr
+                       break;
+               }
+               slist.list.cdr = new(Slist);
+               slist = slist.list.cdr;
+       }
+       return retval;
+}
+
+func atom(i int) *Slist        { // BUG: uses tokenbuf; should take argument)
+       var slist *Slist;
+
+       slist = new(Slist);
+       if token == '0' {
+               slist.atom.integer = i;
+               slist.isstring = false;
+       } else {
+               slist.atom.str = string(tokenbuf[0:tokenlen]);
+               slist.isstring = true;
+       }
+       slist.isatom = true;
+       return slist;
+}
+
+func atoi() int        { // BUG: uses tokenbuf; should take argument)
+       var v int = 0;
+       for i := 0; i < tokenlen && '0' <= tokenbuf[i] && tokenbuf[i] <= '9'; i = i + 1 {
+               v = 10 * v + int(tokenbuf[i] - '0');
+       }
+       return v;
+}
+
+func Parse() *Slist {
+       var slist *Slist;
+
+       if token == EOF || token == ')' {
+               return nil;
+       }
+       if token == '(' {
+               NextToken();
+               slist = ParseList();
+               Expect(')');
+               return slist;
+       } else {
+               // Atom
+               switch token {
+               case EOF:
+                       return nil;
+               case '0':
+                       slist = atom(atoi());
+               case '"', 'A':
+                       slist = atom(0);
+               default:
+                       slist = nil;
+                       print("unknown token: ", token, "\n");
+               }
+               NextToken();
+               return slist;
+       }
+       return nil;
+}
+
+func OpenFile() {
+       input = "(defn foo (add 12 34))\n\x00";
+       inputindex = 0;
+       peekc = -1;             // BUG
+       NextToken();
+}
diff --git a/gcc/testsuite/go.test/test/ken/robfor.go b/gcc/testsuite/go.test/test/ken/robfor.go
new file mode 100644 (file)
index 0000000..05188a4
--- /dev/null
@@ -0,0 +1,56 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func assertequal(is, shouldbe int, msg string) {
+       if is != shouldbe {
+               print("assertion fail" + msg + "\n");
+               panic(1);
+       }
+}
+
+func main() {
+       var i, sum int;
+
+       i = 0;
+       for {
+               i = i + 1;
+               if i > 5 {
+                       break;
+               }
+       }
+       assertequal(i, 6, "break");
+
+       sum = 0;
+       for i := 0; i <= 10; i++ {
+               sum = sum + i;
+       }
+       assertequal(sum, 55, "all three");
+
+       sum = 0;
+       for i := 0; i <= 10; {
+               sum = sum + i;
+               i++;
+       }
+       assertequal(sum, 55, "only two");
+
+       sum = 0;
+       for sum < 100 {
+               sum = sum + 9;
+       }
+       assertequal(sum, 99 + 9, "only one");
+
+       sum = 0;
+       for i := 0; i <= 10; i++ {
+               if i % 2 == 0 {
+                       continue;
+               }
+               sum = sum + i;
+       }
+       assertequal(sum, 1+3+5+7+9, "continue");
+
+}
diff --git a/gcc/testsuite/go.test/test/ken/robfunc.go b/gcc/testsuite/go.test/test/ken/robfunc.go
new file mode 100644 (file)
index 0000000..12b4b6d
--- /dev/null
@@ -0,0 +1,94 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func assertequal(is, shouldbe int, msg string) {
+       if is != shouldbe {
+               print("assertion fail" + msg + "\n");
+               panic(1);
+       }
+}
+
+func f1() {
+}
+
+func f2(a int) {
+}
+
+func f3(a, b int) int {
+       return a+b;
+}
+
+func f4(a, b int, c float) int {
+       return (a+b)/2 + int(c);
+}
+
+func f5(a int) int {
+       return 5;
+}
+
+func f6(a int) (r int) {
+       return 6;
+}
+
+func f7(a int) (x int, y float) {
+       return 7, 7.0;
+}
+
+
+func f8(a int) (x int, y float) {
+       return 8, 8.0;
+}
+
+type T struct {
+       x, y int;
+}
+
+func (t *T) m10(a int, b float) int {
+       return (t.x+a) * (t.y+int(b));
+}
+
+
+func f9(a int) (in int, fl float) {
+       i := 9;
+       f := float(9);
+       return i, f;
+}
+
+
+func main() {
+       f1();
+       f2(1);
+       r3 := f3(1, 2);
+       assertequal(r3, 3, "3");
+       r4 := f4(0, 2, 3.0);
+       assertequal(r4, 4, "4");
+       r5 := f5(1);
+       assertequal(r5, 5, "5");
+       r6 := f6(1);
+       assertequal(r6, 6, "6");
+       var r7 int;
+       var s7 float;
+       r7, s7 = f7(1);
+       assertequal(r7, 7, "r7");
+       assertequal(int(s7), 7, "s7");
+       var r8 int;
+       var s8 float;
+       r8, s8 = f8(1);
+       assertequal(r8, 8, "r8");
+       assertequal(int(s8), 8, "s8");
+       var r9 int;
+       var s9 float;
+       r9, s9 = f9(1);
+       assertequal(r9, 9, "r9");
+       assertequal(int(s9), 9, "s9");
+       var t *T = new(T);
+       t.x = 1;
+       t.y = 2;
+       r10 := t.m10(1, 3.0);
+       assertequal(r10, 10, "10");
+}
diff --git a/gcc/testsuite/go.test/test/ken/robif.go b/gcc/testsuite/go.test/test/ken/robif.go
new file mode 100644 (file)
index 0000000..b6fe4e4
--- /dev/null
@@ -0,0 +1,97 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func assertequal(is, shouldbe int, msg string) {
+       if is != shouldbe {
+               print("assertion fail" + msg + "\n");
+               panic(1);
+       }
+}
+
+func main() {
+       i5 := 5;
+       i7 := 7;
+
+       var count int;
+
+       count = 0;
+       if true {
+               count = count + 1;
+       }
+       assertequal(count, 1, "if true");
+
+       count = 0;
+       if false {
+               count = count + 1;
+       }
+       assertequal(count, 0, "if false");
+
+       count = 0;
+       if one := 1; true {
+               count = count + one;
+       }
+       assertequal(count, 1, "if true one");
+
+       count = 0;
+       if one := 1; false {
+               _ = one;
+               count = count + 1;
+       }
+       assertequal(count, 0, "if false one");
+
+       count = 0;
+       if {
+               count = count + 1;
+       }
+       assertequal(count, 1, "if empty");
+
+       count = 0;
+       if one := 1; {
+               count = count + one;
+       }
+       assertequal(count, 1, "if empty one");
+
+       count = 0;
+       if i5 < i7 {
+               count = count + 1;
+       }
+       assertequal(count, 1, "if cond");
+
+       count = 0;
+       if true {
+               count = count + 1;
+       } else
+               count = count - 1;
+       assertequal(count, 1, "if else true");
+
+       count = 0;
+       if false {
+               count = count + 1;
+       } else
+               count = count - 1;
+       assertequal(count, -1, "if else false");
+
+       count = 0;
+       if t:=1; false {
+               count = count + 1;
+               t := 7;
+               _ = t;
+       } else
+               count = count - t;
+       assertequal(count, -1, "if else false var");
+
+       count = 0;
+       t := 1;
+       if false {
+               count = count + 1;
+               t := 7;
+               _ = t;
+       } else
+               count = count - t;
+       assertequal(count, -1, "if else false var outside");
+}
diff --git a/gcc/testsuite/go.test/test/ken/shift.go b/gcc/testsuite/go.test/test/ken/shift.go
new file mode 100644 (file)
index 0000000..157a07a
--- /dev/null
@@ -0,0 +1,119 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var    ians    [18]int;
+var    uans    [18]uint;
+var    pass    string;
+
+func
+testi(i int, t1,t2,t3 int) {
+       n := ((t1*3) + t2)*2 + t3;
+       if i != ians[n] {
+               print("itest ", t1,t2,t3,pass,
+                       " is ", i, " sb ", ians[n], "\n");
+       }
+}
+
+func
+index(t1,t2,t3 int) int {
+       return ((t1*3) + t2)*2 + t3;
+}
+
+func
+testu(u uint, t1,t2,t3 int) {
+       n := index(t1,t2,t3);
+       if u != uans[n] {
+               print("utest ", t1,t2,t3,pass,
+                       " is ", u, " sb ", uans[n], "\n");
+       }
+}
+
+func
+main() {
+       var i int;
+       var u,c uint;
+
+       /*
+        * test constant evaluations
+        */
+       pass = "con";   // constant part
+
+       testi( int(1234) <<    0, 0,0,0);
+       testi( int(1234) >>    0, 0,0,1);
+       testi( int(1234) <<    5, 0,1,0);
+       testi( int(1234) >>    5, 0,1,1);
+
+       testi(int(-1234) <<    0, 1,0,0);
+       testi(int(-1234) >>    0, 1,0,1);
+       testi(int(-1234) <<    5, 1,1,0);
+       testi(int(-1234) >>    5, 1,1,1);
+
+       testu(uint(5678) <<    0, 2,0,0);
+       testu(uint(5678) >>    0, 2,0,1);
+       testu(uint(5678) <<    5, 2,1,0);
+       testu(uint(5678) >>    5, 2,1,1);
+
+       /*
+        * test variable evaluations
+        */
+       pass = "var";   // variable part
+
+       for t1:=0; t1<3; t1++ { // +int, -int, uint
+       for t2:=0; t2<3; t2++ { // 0, +small, +large
+       for t3:=0; t3<2; t3++ { // <<, >>
+               switch t1 {
+               case 0: i =  1234;
+               case 1: i = -1234;
+               case 2: u =  5678;
+               }
+               switch t2 {
+               case 0: c =    0;
+               case 1: c =    5;
+               case 2: c = 1025;
+               }
+               switch t3 {
+               case 0: i <<= c; u <<= c;
+               case 1: i >>= c; u >>= c;
+               }
+               switch t1 {
+               case 0: testi(i,t1,t2,t3);
+               case 1: testi(i,t1,t2,t3);
+               case 2: testu(u,t1,t2,t3);
+               }
+       }
+       }
+       }
+}
+
+func
+init() {
+       /*
+        * set the 'correct' answer
+        */
+
+       ians[index(0,0,0)] =   1234;
+       ians[index(0,0,1)] =   1234;
+       ians[index(0,1,0)] =  39488;
+       ians[index(0,1,1)] =     38;
+       ians[index(0,2,0)] =      0;
+       ians[index(0,2,1)] =      0;
+
+       ians[index(1,0,0)] =  -1234;
+       ians[index(1,0,1)] =  -1234;
+       ians[index(1,1,0)] = -39488;
+       ians[index(1,1,1)] =    -39;
+       ians[index(1,2,0)] =      0;
+       ians[index(1,2,1)] =     -1;
+
+       uans[index(2,0,0)] =   5678;
+       uans[index(2,0,1)] =   5678;
+       uans[index(2,1,0)] = 181696;
+       uans[index(2,1,1)] =    177;
+       uans[index(2,2,0)] =      0;
+       uans[index(2,2,1)] =      0;
+}
diff --git a/gcc/testsuite/go.test/test/ken/simparray.go b/gcc/testsuite/go.test/test/ken/simparray.go
new file mode 100644 (file)
index 0000000..1b6f245
--- /dev/null
@@ -0,0 +1,48 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var b[10] float32;
+
+func
+main() {
+       var a[10] float32;
+
+       for i:=int16(5); i<10; i=i+1 {
+               a[i] = float32(i);
+       }
+
+       s1 := float32(0);
+       for i:=5; i<10; i=i+1 {
+               s1 = s1 + a[i];
+       }
+
+       if s1 != 35 { panic(s1); }
+
+       for i:=int16(5); i<10; i=i+1 {
+               b[i] = float32(i);
+       }
+
+       s2 := float32(0);
+       for i:=5; i<10; i=i+1 {
+               s2 = s2 + b[i];
+       }
+
+       if s2 != 35 { panic(s2); }
+
+       b := new([100]int);
+       for i:=0; i<100; i=i+1 {
+               b[i] = i;
+       }
+
+       s3 := 0;
+       for i:=0; i<100; i=i+1 {
+               s3 = s3+b[i];
+       }
+
+       if s3 != 4950 { panic(s3); }
+}
diff --git a/gcc/testsuite/go.test/test/ken/simpbool.go b/gcc/testsuite/go.test/test/ken/simpbool.go
new file mode 100644 (file)
index 0000000..dbd9c8d
--- /dev/null
@@ -0,0 +1,105 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type s struct {
+       a       bool;
+       b       bool;
+}
+
+func
+main() {
+       var a,b bool;
+
+       a = true;
+       b = false;
+
+       if !a { panic(1); }
+       if b { panic(2); }
+       if !!!a { panic(3); }
+       if !!b { panic(4); }
+
+       a = !b;
+       if !a { panic(5); }
+       if !!!a { panic(6); }
+
+       var x *s;
+       x = new(s);
+       x.a = true;
+       x.b = false;
+
+       if !x.a { panic(7); }
+       if x.b { panic(8); }
+       if !!!x.a { panic(9); }
+       if !!x.b { panic(10); }
+
+       x.a = !x.b;
+       if !x.a { panic(11); }
+       if !!!x.a { panic(12); }
+
+       /*
+        * test &&
+        */
+       a = true;
+       b = true;
+       if !(a && b) { panic(21); }
+       if a && !b { panic(22); }
+       if !a && b { panic(23); }
+       if !a && !b { panic(24); }
+
+       a = false;
+       b = true;
+       if !(!a && b) { panic(31); }
+       if !a && !b { panic(32); }
+       if a && b { panic(33); }
+       if a && !b { panic(34); }
+
+       a = true;
+       b = false;
+       if !(a && !b) { panic(41); }
+       if a && b { panic(41); }
+       if !a && !b { panic(41); }
+       if !a && b { panic(44); }
+
+       a = false;
+       b = false;
+       if !(!a && !b) { panic(51); }
+       if !a && b { panic(52); }
+       if a && !b { panic(53); }
+       if a && b { panic(54); }
+
+       /*
+        * test ||
+        */
+       a = true;
+       b = true;
+       if !(a || b) { panic(61); }
+       if !(a || !b) { panic(62); }
+       if !(!a || b) { panic(63); }
+       if !a || !b { panic(64); }
+
+       a = false;
+       b = true;
+       if !(!a || b) { panic(71); }
+       if !(!a || !b) { panic(72); }
+       if !(a || b) { panic(73); }
+       if a || !b { panic(74); }
+
+       a = true;
+       b = false;
+       if !(a || !b) { panic(81); }
+       if !(a || b) { panic(82); }
+       if !(!a || !b) { panic(83); }
+       if !a || b { panic(84); }
+
+       a = false;
+       b = false;
+       if !(!a || !b) { panic(91); }
+       if !(!a || b) { panic(92); }
+       if !(a || !b) { panic(93); }
+       if a || b { panic(94); }
+}
diff --git a/gcc/testsuite/go.test/test/ken/simpconv.go b/gcc/testsuite/go.test/test/ken/simpconv.go
new file mode 100644 (file)
index 0000000..cb443e3
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type vlong int64;
+type short int16;
+
+func
+main() {
+       s1 := vlong(0);
+       for i:=short(0); i<10; i=i+1 {
+               s1 = s1 + vlong(i);
+       }
+       if s1 != 45 { panic(s1); }
+
+       s2 := float(0);
+       for i:=0; i<10; i=i+1 {
+               s2 = s2 + float(i);
+       }
+       if s2 != 45 { panic(s2); }
+}
diff --git a/gcc/testsuite/go.test/test/ken/simpfun.go b/gcc/testsuite/go.test/test/ken/simpfun.go
new file mode 100644 (file)
index 0000000..ba9ce6f
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+func
+main() {
+       var x int;
+
+       x = fun(10,20,30);
+       if x != 60 { panic(x); }
+}
+
+func
+fun(ia,ib,ic int)int {
+       var o int;
+
+       o = ia+ib+ic;
+       if o != 60 { panic(o); }
+       return o;
+}
diff --git a/gcc/testsuite/go.test/test/ken/simpprint.go b/gcc/testsuite/go.test/test/ken/simpprint.go
new file mode 100644 (file)
index 0000000..6077f7e
--- /dev/null
@@ -0,0 +1,13 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+func
+main() {
+       print("hello world\n");
+}
diff --git a/gcc/testsuite/go.test/test/ken/simpswitch.go b/gcc/testsuite/go.test/test/ken/simpswitch.go
new file mode 100644 (file)
index 0000000..ab5dd35
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func
+main() {
+       a := 3;
+       for i:=0; i<10; i=i+1 {
+               switch(i) {
+               case 5:
+                       print("five");
+               case a,7:
+                       print("a");
+               default:
+                       print(i);
+               }
+               print("out", i);
+       }
+       print("\n");
+}
diff --git a/gcc/testsuite/go.test/test/ken/simpvar.go b/gcc/testsuite/go.test/test/ken/simpvar.go
new file mode 100644 (file)
index 0000000..fd060b0
--- /dev/null
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+var    x,y     int;
+
+func
+main() {
+
+       x = 15;
+       y = 20;
+       {
+               var x int;
+               x = 25;
+               y = 25;
+               _ = x;
+       }
+       x = x+y;
+       if(x != 40) { panic(x); }
+}
diff --git a/gcc/testsuite/go.test/test/ken/slicearray.go b/gcc/testsuite/go.test/test/ken/slicearray.go
new file mode 100644 (file)
index 0000000..6e7088e
--- /dev/null
@@ -0,0 +1,210 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var bx [10]byte
+var by []byte
+var fx [10]float
+var fy []float
+var lb, hb int
+var t int
+
+func main() {
+       lb = 0
+       hb = 10
+       by = bx[0:]
+       tstb()
+
+       lb = 0
+       hb = 10
+       fy = fx[0:]
+       tstf()
+
+       // width 1 (byte)
+       lb = 0
+       hb = 10
+       by = bx[lb:hb]
+       tstb()
+       by = bx[lb:10]
+       tstb()
+       by = bx[lb:]
+       tstb()
+       by = bx[:hb]
+       tstb()
+       by = bx[0:hb]
+       tstb()
+       by = bx[0:10]
+       tstb()
+       by = bx[0:]
+       tstb()
+       by = bx[:10]
+       tstb()
+       by = bx[:]
+       tstb()
+
+       lb = 2
+       hb = 10
+       by = bx[lb:hb]
+       tstb()
+       by = bx[lb:10]
+       tstb()
+       by = bx[lb:]
+       tstb()
+       by = bx[2:hb]
+       tstb()
+       by = bx[2:10]
+       tstb()
+       by = bx[2:]
+       tstb()
+
+       lb = 0
+       hb = 8
+       by = bx[lb:hb]
+       tstb()
+       by = bx[lb:8]
+       tstb()
+       by = bx[0:hb]
+       tstb()
+       by = bx[0:8]
+       tstb()
+       by = bx[:8]
+       tstb()
+       by = bx[:hb]
+       tstb()
+
+       lb = 2
+       hb = 8
+       by = bx[lb:hb]
+       tstb()
+       by = bx[lb:8]
+       tstb()
+       by = bx[2:hb]
+       tstb()
+       by = bx[2:8]
+       tstb()
+
+       // width 4 (float)
+       lb = 0
+       hb = 10
+       fy = fx[lb:hb]
+       tstf()
+       fy = fx[lb:10]
+       tstf()
+       fy = fx[lb:]
+       tstf()
+       fy = fx[:hb]
+       tstf()
+       fy = fx[0:hb]
+       tstf()
+       fy = fx[0:10]
+       tstf()
+       fy = fx[0:]
+       tstf()
+       fy = fx[:10]
+       tstf()
+       fy = fx[:]
+       tstf()
+
+       lb = 2
+       hb = 10
+       fy = fx[lb:hb]
+       tstf()
+       fy = fx[lb:10]
+       tstf()
+       fy = fx[lb:]
+       tstf()
+       fy = fx[2:hb]
+       tstf()
+       fy = fx[2:10]
+       tstf()
+       fy = fx[2:]
+       tstf()
+
+       lb = 0
+       hb = 8
+       fy = fx[lb:hb]
+       tstf()
+       fy = fx[lb:8]
+       tstf()
+       fy = fx[:hb]
+       tstf()
+       fy = fx[0:hb]
+       tstf()
+       fy = fx[0:8]
+       tstf()
+       fy = fx[:8]
+       tstf()
+
+       lb = 2
+       hb = 8
+       fy = fx[lb:hb]
+       tstf()
+       fy = fx[lb:8]
+       tstf()
+       fy = fx[2:hb]
+       tstf()
+       fy = fx[2:8]
+       tstf()
+}
+
+func tstb() {
+       t++
+       if len(by) != hb-lb {
+               println("t=", t, "lb=", lb, "hb=", hb,
+                       "len=", len(by), "hb-lb=", hb-lb)
+               panic("fail")
+       }
+       if cap(by) != len(bx)-lb {
+               println("t=", t, "lb=", lb, "hb=", hb,
+                       "cap=", cap(by), "len(bx)-lb=", len(bx)-lb)
+               panic("fail")
+       }
+       for i := lb; i < hb; i++ {
+               if bx[i] != by[i-lb] {
+                       println("t=", t, "lb=", lb, "hb=", hb,
+                               "bx[", i, "]=", bx[i],
+                               "by[", i-lb, "]=", by[i-lb])
+                       panic("fail")
+               }
+       }
+       by = nil
+}
+
+func tstf() {
+       t++
+       if len(fy) != hb-lb {
+               println("t=", t, "lb=", lb, "hb=", hb,
+                       "len=", len(fy), "hb-lb=", hb-lb)
+               panic("fail")
+       }
+       if cap(fy) != len(fx)-lb {
+               println("t=", t, "lb=", lb, "hb=", hb,
+                       "cap=", cap(fy), "len(fx)-lb=", len(fx)-lb)
+               panic("fail")
+       }
+       for i := lb; i < hb; i++ {
+               if fx[i] != fy[i-lb] {
+                       println("t=", t, "lb=", lb, "hb=", hb,
+                               "fx[", i, "]=", fx[i],
+                               "fy[", i-lb, "]=", fy[i-lb])
+                       panic("fail")
+               }
+       }
+       fy = nil
+}
+
+func init() {
+       for i := 0; i < len(bx); i++ {
+               bx[i] = byte(i + 20)
+       }
+       by = nil
+
+       for i := 0; i < len(fx); i++ {
+               fx[i] = float(i + 20)
+       }
+       fy = nil
+}
diff --git a/gcc/testsuite/go.test/test/ken/sliceslice.go b/gcc/testsuite/go.test/test/ken/sliceslice.go
new file mode 100644 (file)
index 0000000..5a35aca
--- /dev/null
@@ -0,0 +1,203 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var bx []byte
+var by []byte
+var fx []float
+var fy []float
+var lb, hb int
+var t int
+
+func main() {
+
+       // width 1 (byte)
+       lb = 0
+       hb = 10
+       by = bx[lb:hb]
+       tstb()
+       by = bx[lb:10]
+       tstb()
+       by = bx[lb:]
+       tstb()
+       by = bx[:hb]
+       tstb()
+       by = bx[0:hb]
+       tstb()
+       by = bx[0:10]
+       tstb()
+       by = bx[0:]
+       tstb()
+       by = bx[:10]
+       tstb()
+       by = bx[:]
+       tstb()
+
+       lb = 2
+       hb = 10
+       by = bx[lb:hb]
+       tstb()
+       by = bx[lb:10]
+       tstb()
+       by = bx[lb:]
+       tstb()
+       by = bx[2:hb]
+       tstb()
+       by = bx[2:10]
+       tstb()
+       by = bx[2:]
+       tstb()
+
+       lb = 0
+       hb = 8
+       by = bx[lb:hb]
+       tstb()
+       by = bx[lb:8]
+       tstb()
+       by = bx[0:hb]
+       tstb()
+       by = bx[0:8]
+       tstb()
+       by = bx[:8]
+       tstb()
+       by = bx[:hb]
+       tstb()
+
+       lb = 2
+       hb = 8
+       by = bx[lb:hb]
+       tstb()
+       by = bx[lb:8]
+       tstb()
+       by = bx[2:hb]
+       tstb()
+       by = bx[2:8]
+       tstb()
+
+       // width 4 (float)
+       lb = 0
+       hb = 10
+       fy = fx[lb:hb]
+       tstf()
+       fy = fx[lb:10]
+       tstf()
+       fy = fx[lb:]
+       tstf()
+       fy = fx[:hb]
+       tstf()
+       fy = fx[0:hb]
+       tstf()
+       fy = fx[0:10]
+       tstf()
+       fy = fx[0:]
+       tstf()
+       fy = fx[:10]
+       tstf()
+       fy = fx[:]
+       tstf()
+
+       lb = 2
+       hb = 10
+       fy = fx[lb:hb]
+       tstf()
+       fy = fx[lb:10]
+       tstf()
+       fy = fx[lb:]
+       tstf()
+       fy = fx[2:hb]
+       tstf()
+       fy = fx[2:10]
+       tstf()
+       fy = fx[2:]
+       tstf()
+
+       lb = 0
+       hb = 8
+       fy = fx[lb:hb]
+       tstf()
+       fy = fx[lb:8]
+       tstf()
+       fy = fx[:hb]
+       tstf()
+       fy = fx[0:hb]
+       tstf()
+       fy = fx[0:8]
+       tstf()
+       fy = fx[:8]
+       tstf()
+
+       lb = 2
+       hb = 8
+       fy = fx[lb:hb]
+       tstf()
+       fy = fx[lb:8]
+       tstf()
+       fy = fx[2:hb]
+       tstf()
+       fy = fx[2:8]
+       tstf()
+}
+
+func tstb() {
+       t++
+       if len(by) != hb-lb {
+               println("t=", t, "lb=", lb, "hb=", hb,
+                       "len=", len(by), "hb-lb=", hb-lb)
+               panic("fail")
+       }
+       if cap(by) != len(bx)-lb {
+               println("t=", t, "lb=", lb, "hb=", hb,
+                       "cap=", cap(by), "len(bx)-lb=", len(bx)-lb)
+               panic("fail")
+       }
+       for i := lb; i < hb; i++ {
+               if bx[i] != by[i-lb] {
+                       println("t=", t, "lb=", lb, "hb=", hb,
+                               "bx[", i, "]=", bx[i],
+                               "by[", i-lb, "]=", by[i-lb])
+                       panic("fail")
+               }
+       }
+       by = nil
+}
+
+func tstf() {
+       t++
+       if len(fy) != hb-lb {
+               println("t=", t, "lb=", lb, "hb=", hb,
+                       "len=", len(fy), "hb-lb=", hb-lb)
+               panic("fail")
+       }
+       if cap(fy) != len(fx)-lb {
+               println("t=", t, "lb=", lb, "hb=", hb,
+                       "cap=", cap(fy), "len(fx)-lb=", len(fx)-lb)
+               panic("fail")
+       }
+       for i := lb; i < hb; i++ {
+               if fx[i] != fy[i-lb] {
+                       println("t=", t, "lb=", lb, "hb=", hb,
+                               "fx[", i, "]=", fx[i],
+                               "fy[", i-lb, "]=", fy[i-lb])
+                       panic("fail")
+               }
+       }
+       fy = nil
+}
+
+func init() {
+       bx = make([]byte, 10)
+       for i := 0; i < len(bx); i++ {
+               bx[i] = byte(i + 20)
+       }
+       by = nil
+
+       fx = make([]float, 10)
+       for i := 0; i < len(fx); i++ {
+               fx[i] = float(i + 20)
+       }
+       fy = nil
+}
diff --git a/gcc/testsuite/go.test/test/ken/string.go b/gcc/testsuite/go.test/test/ken/string.go
new file mode 100644 (file)
index 0000000..cbedad4
--- /dev/null
@@ -0,0 +1,118 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+func main() {
+       var c string
+
+       a := `abc`
+       b := `xyz`
+
+       /* print a literal */
+       print(`abc`)
+
+       /* print a variable */
+       print(b, "-")
+
+       /* catenate literals */
+       print(`abc`+`xyz`, "-")
+
+       /* catenate variables */
+       print(a+b, "-")
+
+       /* compare literals */
+       if `abc` == `xyz` || `abc` != "abc" || `abc` > `xyz` {
+               panic("compare literals")
+       }
+
+       /* compare variables */
+       if a == b || a != a || a > b {
+               panic("compare variables")
+       }
+
+       /* cat */
+       c = a + b
+       print(c, "-")
+
+       /* catequal */
+       c = a
+       c += b
+       print(c, "-")
+
+       /* clumsy evaluation */
+       c = b
+       c = a + c
+       print(c, "-")
+
+       /* len */
+       if len(c) != 6 {
+               print("len ", len(c))
+               panic("fail")
+       }
+
+       /* index strings */
+       for i := 0; i < len(c); i = i + 1 {
+               if c[i] != (a + b)[i] {
+                       print("index ", i, " ", c[i], " ", (a + b)[i])
+                       panic("fail")
+               }
+       }
+
+       /* slice strings */
+       print(c[0:3], c[3:])
+
+       print("\n")
+
+       /* create string with integer constant */
+       c = string('x')
+       if c != "x" {
+               print("create int ", c)
+               panic("fail")
+       }
+
+       /* create string with integer variable */
+       v := 'x'
+       c = string(v)
+       if c != "x" {
+               print("create int ", c)
+               panic("fail")
+       }
+
+       /* create string with byte array */
+       var z1 [3]byte
+       z1[0] = 'a'
+       z1[1] = 'b'
+       z1[2] = 'c'
+       c = string(z1[0:])
+       if c != "abc" {
+               print("create byte array ", c)
+               panic("fail")
+       }
+
+       /* create string with int array */
+       var z2 [3]int
+       z2[0] = 'a'
+       z2[1] = '\u1234'
+       z2[2] = 'c'
+       c = string(z2[0:])
+       if c != "a\u1234c" {
+               print("create int array ", c)
+               panic("fail")
+       }
+
+       /* create string with byte array pointer */
+       z3 := new([3]byte)
+       z3[0] = 'a'
+       z3[1] = 'b'
+       z3[2] = 'c'
+       c = string(z3[0:])
+       if c != "abc" {
+               print("create array pointer ", c)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/ken/strvar.go b/gcc/testsuite/go.test/test/ken/strvar.go
new file mode 100644 (file)
index 0000000..dfaaf12
--- /dev/null
@@ -0,0 +1,78 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+type   x2      struct { a,b,c int; d int; };
+var    g1      x2;
+var    g2      struct { a,b,c int; d x2; };
+
+func
+main() {
+       var x int;
+       var s1 *x2;
+       var s2 *struct { a,b,c int; d x2; };
+       var s3 struct { a,b,c int; d x2; };
+
+       s1 = &g1;
+       s2 = &g2;
+
+       s1.a = 1;
+       s1.b = 2;
+       s1.c = 3;
+       s1.d = 5;
+
+       if(s1.c != 3) { panic(s1.c); }
+       if(g1.c != 3) { panic(g1.c); }
+
+       s2.a = 7;
+       s2.b = 11;
+       s2.c = 13;
+       s2.d.a = 17;
+       s2.d.b = 19;
+       s2.d.c = 23;
+       s2.d.d = 29;
+
+       if(s2.d.c != 23) { panic(s2.d.c); }
+       if(g2.d.c != 23) { panic(g2.d.c); }
+
+       x =     s1.a +
+               s1.b +
+               s1.c +
+               s1.d +
+
+               s2.a +
+               s2.b +
+               s2.c +
+               s2.d.a +
+               s2.d.b +
+               s2.d.c +
+               s2.d.d;
+
+       if(x != 130) { panic(x); }
+
+       // test an automatic struct
+       s3.a = 7;
+       s3.b = 11;
+       s3.c = 13;
+       s3.d.a = 17;
+       s3.d.b = 19;
+       s3.d.c = 23;
+       s3.d.d = 29;
+
+       if(s3.d.c != 23) { panic(s3.d.c); }
+
+       x =     s3.a +
+               s3.b +
+               s3.c +
+               s3.d.a +
+               s3.d.b +
+               s3.d.c +
+               s3.d.d;
+
+       if(x != 119) { panic(x); }
+}
diff --git a/gcc/testsuite/go.test/test/literal.go b/gcc/testsuite/go.test/test/literal.go
new file mode 100644 (file)
index 0000000..10176bc
--- /dev/null
@@ -0,0 +1,239 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+var nbad int
+
+func assert(cond bool, msg string) {
+       if !cond {
+               if nbad == 0 {
+                       print("BUG")
+               }
+               nbad++
+               print(" ", msg)
+       }
+}
+
+func equal(a, b float) bool {
+       if os.Getenv("GOARCH") != "arm" {
+               return a == b
+       }
+       d := a-b
+       if a > b {
+               return d < a * 1.0e-7
+       }
+       d = -d
+       return d < b * 1.0e-7
+}
+
+
+func main() {
+       // bool
+       var t bool = true
+       var f bool = false
+       assert(t == !f, "bool")
+
+       // int8
+       var i00 int8 = 0
+       var i01 int8 = 1
+       var i02 int8 = -1
+       var i03 int8 = 127
+       var i04 int8 = -127
+       var i05 int8 = -128
+       var i06 int8 = +127
+       assert(i01 == i00 + 1, "i01")
+       assert(i02 == -i01, "i02")
+       assert(i03 == -i04, "i03")
+       assert(-(i05+1) == i06, "i05")
+
+       // int16
+       var i10 int16 = 0
+       var i11 int16 = 1
+       var i12 int16 = -1
+       var i13 int16 = 32767
+       var i14 int16 = -32767
+       var i15 int16 = -32768
+       var i16 int16 = +32767
+       assert(i11 == i10 + 1, "i11")
+       assert(i12 == -i11, "i12")
+       assert(i13 == -i14, "i13")
+       assert(-(i15+1) == i16, "i15")
+
+       // int32
+       var i20 int32 = 0
+       var i21 int32 = 1
+       var i22 int32 = -1
+       var i23 int32 = 2147483647
+       var i24 int32 = -2147483647
+       var i25 int32 = -2147483648
+       var i26 int32 = +2147483647
+       assert(i21 == i20 + 1, "i21")
+       assert(i22 == -i21, "i22")
+       assert(i23 == -i24, "i23")
+       assert(-(i25+1) == i26, "i25")
+       assert(i23 == (1 << 31) - 1, "i23 size")
+
+       // int64
+       var i30 int64 = 0
+       var i31 int64 = 1
+       var i32 int64 = -1
+       var i33 int64 = 9223372036854775807
+       var i34 int64 = -9223372036854775807
+       var i35 int64 = -9223372036854775808
+       var i36 int64 = +9223372036854775807
+       assert(i31 == i30 + 1, "i31")
+       assert(i32 == -i31, "i32")
+       assert(i33 == -i34, "i33")
+       assert(-(i35+1) == i36, "i35")
+       assert(i33 == (1<<63) - 1, "i33 size")
+
+       // uint8
+       var u00 uint8 = 0
+       var u01 uint8 = 1
+       var u02 uint8 = 255
+       var u03 uint8 = +255
+       assert(u01 == u00 + 1, "u01")
+       assert(u02 == u03, "u02")
+       assert(u03 == (1<<8) - 1, "u03 size")
+
+       // uint16
+       var u10 uint16 = 0
+       var u11 uint16 = 1
+       var u12 uint16 = 65535
+       var u13 uint16 = +65535
+       assert(u11 == u10 + 1, "u11")
+       assert(u12 == u13, "u12")
+
+       // uint32
+       var u20 uint32 = 0
+       var u21 uint32 = 1
+       var u22 uint32 = 4294967295
+       var u23 uint32 = +4294967295
+       assert(u21 == u20 + 1, "u21")
+       assert(u22 == u23, "u22")
+
+       // uint64
+       var u30 uint64 = 0
+       var u31 uint64 = 1
+       var u32 uint64 = 18446744073709551615
+       var u33 uint64 = +18446744073709551615
+       _, _, _, _ = u30, u31, u32, u33
+
+       // float
+       var f00 float = 3.14159
+       var f01 float = -3.14159
+       var f02 float = +3.14159
+       var f03 float = 0.0
+       var f04 float = .0
+       var f05 float = 0.
+       var f06 float = -0.0
+       var f07 float = 1e10
+       var f08 float = -1e10
+       var f09 float = 1e-10
+       var f10 float = 1e+10
+       var f11 float = 1.e-10
+       var f12 float = 1.e+10
+       var f13 float = .1e-10
+       var f14 float = .1e+10
+       var f15 float = 1.1e-10
+       var f16 float = 1.1e+10
+       assert(f01 == -f00, "f01")
+       assert(f02 == -f01, "f02")
+       assert(f03 == f04, "f03")
+       assert(f04 == f05, "f04")
+       assert(f05 == f06, "f05")
+       assert(f07 == -f08, "f07")
+       assert(equal(f09, 1/f10), "f09")
+       assert(f11 == f09, "f11")
+       assert(f12 == f10, "f12")
+       assert(equal(f13, f09/10.0), "f13")
+       assert(equal(f14, f12/10.0), "f14")
+       assert(equal(f15, f16/1e20), "f15")
+
+       // character
+       var c0 uint8 = 'a'
+       var c1 uint8 = 'ä'
+       var c2 uint8 = '\a'
+       var c3 uint8 = '\b'
+       var c4 uint8 = '\f'
+       var c5 uint8 = '\n'
+       var c6 uint8 = '\r'
+       var c7 uint8 = '\t'
+       var c8 uint8 = '\v'
+       // var c9 uint8 = '本' // correctly caught as error
+       var c9 uint16 = '本'
+       assert(c0 == 0x61, "c0")
+       assert(c1 == 0xe4, "c1")
+       assert(c2 == 0x07, "c2")
+       assert(c3 == 0x08, "c3")
+       assert(c4 == 0x0c, "c4")
+       assert(c5 == 0x0a, "c4")
+       assert(c6 == 0x0d, "c6")
+       assert(c7 == 0x09, "c7")
+       assert(c8 == 0x0b, "c8")
+       assert(c9 == 0x672c, "c9")
+
+
+       var c00 uint8 = '\000'
+       var c01 uint8 = '\007'
+       var c02 uint8 = '\177'
+       var c03 uint8 = '\377'
+       assert(c00 == 0, "c00")
+       assert(c01 == 7, "c01")
+       assert(c02 == 127, "c02")
+       assert(c03 == 255, "c03")
+
+       var cx0 uint8 = '\x00'
+       var cx1 uint8 = '\x0f'
+       var cx2 uint8 = '\xff'
+       assert(cx0 == 0, "cx0")
+       assert(cx1 == 15, "cx1")
+       assert(cx2 == 255, "cx2")
+
+       var cu0 uint16 = '\u1234'
+       var cu1 uint32 = '\U00101234'
+       assert(cu0 == 0x1234, "cu0")
+       assert(cu1 == 0x101234, "cu1")
+
+       // string
+       var s0 string = ""
+       var s1 string = "hellô"
+       assert(s1[0] == 'h', "s1-0")
+       assert(s1[4] == 0xc3, "s1-4")
+       assert(s1[5] == 0xb4, "s1-5")
+       var s2 string = "\a\b\f\n\r\t\v"
+       _, _ = s0, s2
+
+       var s00 string = "\000"
+       var s01 string = "\007"
+       var s02 string = "\377"
+       assert(s00[0] == 0, "s00")
+       assert(s01[0] == 7, "s01")
+       assert(s02[0] == 255, "s02")
+
+       var x00 string = "\x00"
+       var x01 string = "\x0f"
+       var x02 string = "\xff"
+       assert(x00[0] == 0, "x00")
+       assert(x01[0] == 15, "x01")
+       assert(x02[0] == 255, "x02")
+
+       // these are all the same string
+       var sj0 string = "日本語"
+       var sj1 string = "\u65e5\u672c\u8a9e"
+       var sj2 string = "\U000065e5\U0000672c\U00008a9e"
+       var sj3 string = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
+       assert(sj0 == sj1, "sj1")
+       assert(sj0 == sj2, "sj2")
+       assert(sj0 == sj3, "sj3")
+
+       if nbad > 0 {
+               println()
+       }
+}
diff --git a/gcc/testsuite/go.test/test/malloc1.go b/gcc/testsuite/go.test/test/malloc1.go
new file mode 100644 (file)
index 0000000..1469764
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// trivial malloc test
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "runtime"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+
+func main() {
+       runtime.Free(runtime.Alloc(1))
+       if *chatty {
+               fmt.Printf("%+v %v\n", runtime.MemStats, uint64(0))
+       }
+}
diff --git a/gcc/testsuite/go.test/test/mallocfin.go b/gcc/testsuite/go.test/test/mallocfin.go
new file mode 100644 (file)
index 0000000..dc6d74b
--- /dev/null
@@ -0,0 +1,67 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// trivial finalizer test
+
+package main
+
+import (
+       "runtime"
+       "time"
+)
+
+const N = 250
+
+type A struct {
+       b *B
+       n int
+}
+
+type B struct {
+       n int
+}
+
+var i int
+var nfinal int
+var final [N]int
+
+// the unused return is to test finalizers with return values
+func finalA(a *A) (unused [N]int) {
+       if final[a.n] != 0 {
+               println("finalA", a.n, final[a.n])
+               panic("fail")
+       }
+       final[a.n] = 1
+       return
+}
+
+func finalB(b *B) {
+       if final[b.n] != 1 {
+               println("finalB", b.n, final[b.n])
+               panic("fail")
+       }
+       final[b.n] = 2
+       nfinal++
+}
+
+func main() {
+       runtime.GOMAXPROCS(4)
+       for i = 0; i < N; i++ {
+               b := &B{i}
+               a := &A{b, i}
+               runtime.SetFinalizer(b, finalB)
+               runtime.SetFinalizer(a, finalA)
+       }
+       for i := 0; i < N; i++ {
+               runtime.GC()
+               runtime.Gosched()
+               time.Sleep(1e6)
+       }
+       if nfinal < N*8/10 {
+               println("not enough finalizing:", nfinal, "/", N)
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/mallocrand.go b/gcc/testsuite/go.test/test/mallocrand.go
new file mode 100644 (file)
index 0000000..e6b422e
--- /dev/null
@@ -0,0 +1,91 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Random malloc test.
+
+package main
+
+import (
+       "flag"
+       "rand"
+       "runtime"
+       "unsafe"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+
+var footprint uint64
+var allocated uint64
+
+func bigger() {
+       if f := runtime.MemStats.Sys; footprint < f {
+               footprint = f
+               if *chatty {
+                       println("Footprint", footprint, " for ", allocated)
+               }
+               if footprint > 1e9 {
+                       println("too big")
+                       panic("fail")
+               }
+       }
+}
+
+// Prime the data structures by allocating one of
+// each block in order.  After this, there should be
+// little reason to ask for more memory from the OS.
+func prime() {
+       for i := 0; i < 16; i++ {
+               b := runtime.Alloc(1 << uint(i))
+               runtime.Free(b)
+       }
+       for i := uintptr(0); i < 256; i++ {
+               b := runtime.Alloc(i << 12)
+               runtime.Free(b)
+       }
+}
+
+func memset(b *byte, c byte, n uintptr) {
+       np := uintptr(n)
+       for i := uintptr(0); i < np; i++ {
+               *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(b)) + i)) = c
+       }
+}
+
+func main() {
+       flag.Parse()
+       //      prime()
+       var blocks [1]struct {
+               base *byte
+               siz  uintptr
+       }
+       for i := 0; i < 1<<10; i++ {
+               if i%(1<<10) == 0 && *chatty {
+                       println(i)
+               }
+               b := rand.Int() % len(blocks)
+               if blocks[b].base != nil {
+                       //      println("Free", blocks[b].siz, blocks[b].base)
+                       runtime.Free(blocks[b].base)
+                       blocks[b].base = nil
+                       allocated -= uint64(blocks[b].siz)
+                       continue
+               }
+               siz := uintptr(rand.Int() >> (11 + rand.Uint32()%20))
+               base := runtime.Alloc(siz)
+               //      ptr := uintptr(syscall.BytePtr(base))+uintptr(siz/2)
+               //      obj, size, ref, ok := allocator.find(ptr)
+               //      if obj != base || *ref != 0 || !ok {
+               //              println("find", siz, obj, ref, ok)
+               //              panic("fail")
+               //      }
+               blocks[b].base = base
+               blocks[b].siz = siz
+               allocated += uint64(siz)
+               //      println("Alloc", siz, base)
+               memset(base, 0xbb, siz)
+               bigger()
+       }
+}
diff --git a/gcc/testsuite/go.test/test/mallocrep.go b/gcc/testsuite/go.test/test/mallocrep.go
new file mode 100644 (file)
index 0000000..762f375
--- /dev/null
@@ -0,0 +1,66 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Repeated malloc test.
+
+package main
+
+import (
+       "flag"
+       "runtime"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+
+var oldsys uint64
+
+func bigger() {
+       if st := runtime.MemStats; oldsys < st.Sys {
+               oldsys = st.Sys
+               if *chatty {
+                       println(st.Sys, " system bytes for ", st.Alloc, " Go bytes")
+               }
+               if st.Sys > 1e9 {
+                       println("too big")
+                       panic("fail")
+               }
+       }
+}
+
+func main() {
+       runtime.GC()               // clean up garbage from init
+       runtime.MemProfileRate = 0 // disable profiler
+       runtime.MemStats.Alloc = 0 // ignore stacks
+       flag.Parse()
+       for i := 0; i < 1<<7; i++ {
+               for j := 1; j <= 1<<22; j <<= 1 {
+                       if i == 0 && *chatty {
+                               println("First alloc:", j)
+                       }
+                       if a := runtime.MemStats.Alloc; a != 0 {
+                               println("no allocations but stats report", a, "bytes allocated")
+                               panic("fail")
+                       }
+                       b := runtime.Alloc(uintptr(j))
+                       during := runtime.MemStats.Alloc
+                       runtime.Free(b)
+                       if a := runtime.MemStats.Alloc; a != 0 {
+                               println("allocated ", j, ": wrong stats: during=", during, " after=", a, " (want 0)")
+                               panic("fail")
+                       }
+                       bigger()
+               }
+               if i%(1<<10) == 0 && *chatty {
+                       println(i)
+               }
+               if i == 0 {
+                       if *chatty {
+                               println("Primed", i)
+                       }
+                       //      runtime.frozen = true
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/mallocrep1.go b/gcc/testsuite/go.test/test/mallocrep1.go
new file mode 100644 (file)
index 0000000..eb67bed
--- /dev/null
@@ -0,0 +1,138 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Repeated malloc test.
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "runtime"
+       "strconv"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+var reverse = flag.Bool("r", false, "reverse")
+var longtest = flag.Bool("l", false, "long test")
+
+var b []*byte
+var stats = &runtime.MemStats
+
+func OkAmount(size, n uintptr) bool {
+       if n < size {
+               return false
+       }
+       if size < 16*8 {
+               if n > size+16 {
+                       return false
+               }
+       } else {
+               if n > size*9/8 {
+                       return false
+               }
+       }
+       return true
+}
+
+func AllocAndFree(size, count int) {
+       if *chatty {
+               fmt.Printf("size=%d count=%d ...\n", size, count)
+       }
+       n1 := stats.Alloc
+       for i := 0; i < count; i++ {
+               b[i] = runtime.Alloc(uintptr(size))
+               base, n := runtime.Lookup(b[i])
+               if base != b[i] || !OkAmount(uintptr(size), n) {
+                       println("lookup failed: got", base, n, "for", b[i])
+                       panic("fail")
+               }
+               if runtime.MemStats.Sys > 1e9 {
+                       println("too much memory allocated")
+                       panic("fail")
+               }
+       }
+       n2 := stats.Alloc
+       if *chatty {
+               fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
+       }
+       n3 := stats.Alloc
+       for j := 0; j < count; j++ {
+               i := j
+               if *reverse {
+                       i = count - 1 - j
+               }
+               alloc := uintptr(stats.Alloc)
+               base, n := runtime.Lookup(b[i])
+               if base != b[i] || !OkAmount(uintptr(size), n) {
+                       println("lookup failed: got", base, n, "for", b[i])
+                       panic("fail")
+               }
+               runtime.Free(b[i])
+               if stats.Alloc != uint64(alloc-n) {
+                       println("free alloc got", stats.Alloc, "expected", alloc-n, "after free of", n)
+                       panic("fail")
+               }
+               if runtime.MemStats.Sys > 1e9 {
+                       println("too much memory allocated")
+                       panic("fail")
+               }
+       }
+       n4 := stats.Alloc
+
+       if *chatty {
+               fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
+       }
+       if n2-n1 != n3-n4 {
+               println("wrong alloc count: ", n2-n1, n3-n4)
+               panic("fail")
+       }
+}
+
+func atoi(s string) int {
+       i, _ := strconv.Atoi(s)
+       return i
+}
+
+func main() {
+       runtime.MemProfileRate = 0 // disable profiler
+       flag.Parse()
+       b = make([]*byte, 10000)
+       if flag.NArg() > 0 {
+               AllocAndFree(atoi(flag.Arg(0)), atoi(flag.Arg(1)))
+               return
+       }
+       maxb := 1 << 22
+       if !*longtest {
+               maxb = 1 << 19
+       }
+       for j := 1; j <= maxb; j <<= 1 {
+               n := len(b)
+               max := uintptr(1 << 28)
+               if !*longtest {
+                       max = uintptr(maxb)
+               }
+               if uintptr(j)*uintptr(n) > max {
+                       n = int(max / uintptr(j))
+               }
+               if n < 10 {
+                       n = 10
+               }
+               for m := 1; m <= n; {
+                       AllocAndFree(j, m)
+                       if m == n {
+                               break
+                       }
+                       m = 5 * m / 4
+                       if m < 4 {
+                               m++
+                       }
+                       if m > n {
+                               m = n
+                       }
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/map.go b/gcc/testsuite/go.test/test/map.go
new file mode 100644 (file)
index 0000000..ddff7c7
--- /dev/null
@@ -0,0 +1,492 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt"
+       "strconv"
+)
+
+const count = 100
+
+func P(a []string) string {
+       s := "{"
+       for i := 0; i < len(a); i++ {
+               if i > 0 {
+                       s += ","
+               }
+               s += `"` + a[i] + `"`
+       }
+       s +="}"
+       return s
+}
+
+func main() {
+       // Test a map literal.
+       mlit := map[string] int { "0":0, "1":1, "2":2, "3":3, "4":4 }
+       for i := 0; i < len(mlit); i++ {
+               s := string([]byte{byte(i)+'0'})
+               if mlit[s] != i {
+                       fmt.Printf("mlit[%s] = %d\n", s, mlit[s])
+               }
+       }
+
+       mib := make(map[int] bool)
+       mii := make(map[int] int)
+       mfi := make(map[float] int)
+       mif := make(map[int] float)
+       msi := make(map[string] int)
+       mis := make(map[int] string)
+       mss := make(map[string] string)
+       mspa := make(map[string] []string)
+       // BUG need an interface map both ways too
+
+       type T struct {
+               i int64 // can't use string here; struct values are only compared at the top level
+               f float
+       }
+       mipT := make(map[int] *T)
+       mpTi := make(map[*T] int)
+       mit := make(map[int] T)
+//     mti := make(map[T] int)
+
+       type M map[int] int
+       mipM := make(map[int] M)
+
+       var apT [2*count]*T
+
+       for i := 0; i < count; i++ {
+               s := strconv.Itoa(i)
+               s10 := strconv.Itoa(i*10)
+               f := float(i)
+               t := T{int64(i),f}
+               apT[i] = new(T)
+               apT[i].i = int64(i)
+               apT[i].f = f
+               apT[2*i] = new(T)       // need twice as many entries as we use, for the nonexistence check
+               apT[2*i].i = int64(i)
+               apT[2*i].f = f
+               m := M{i: i+1}
+               mib[i] = (i != 0)
+               mii[i] = 10*i
+               mfi[float(i)] = 10*i
+               mif[i] = 10.0*f
+               mis[i] = s
+               msi[s] = i
+               mss[s] = s10
+               mss[s] = s10
+               as := make([]string, 2)
+                       as[0] = s10
+                       as[1] = s10
+               mspa[s] = as
+               mipT[i] = apT[i]
+               mpTi[apT[i]] = i
+               mipM[i] = m
+               mit[i] = t
+       //      mti[t] = i
+       }
+
+       // test len
+       if len(mib) != count {
+               fmt.Printf("len(mib) = %d\n", len(mib))
+       }
+       if len(mii) != count {
+               fmt.Printf("len(mii) = %d\n", len(mii))
+       }
+       if len(mfi) != count {
+               fmt.Printf("len(mfi) = %d\n", len(mfi))
+       }
+       if len(mif) != count {
+               fmt.Printf("len(mif) = %d\n", len(mif))
+       }
+       if len(msi) != count {
+               fmt.Printf("len(msi) = %d\n", len(msi))
+       }
+       if len(mis) != count {
+               fmt.Printf("len(mis) = %d\n", len(mis))
+       }
+       if len(mss) != count {
+               fmt.Printf("len(mss) = %d\n", len(mss))
+       }
+       if len(mspa) != count {
+               fmt.Printf("len(mspa) = %d\n", len(mspa))
+       }
+       if len(mipT) != count {
+               fmt.Printf("len(mipT) = %d\n", len(mipT))
+       }
+       if len(mpTi) != count {
+               fmt.Printf("len(mpTi) = %d\n", len(mpTi))
+       }
+//     if len(mti) != count {
+//             fmt.Printf("len(mti) = %d\n", len(mti))
+//     }
+       if len(mipM) != count {
+               fmt.Printf("len(mipM) = %d\n", len(mipM))
+       }
+//     if len(mti) != count {
+//             fmt.Printf("len(mti) = %d\n", len(mti))
+//     }
+       if len(mit) != count {
+               fmt.Printf("len(mit) = %d\n", len(mit))
+       }
+
+       // test construction directly
+       for i := 0; i < count; i++ {
+               s := strconv.Itoa(i)
+               s10 := strconv.Itoa(i*10)
+               f := float(i)
+               // BUG m := M(i, i+1)
+               if mib[i] != (i != 0) {
+                       fmt.Printf("mib[%d] = %t\n", i, mib[i])
+               }
+               if(mii[i] != 10*i) {
+                       fmt.Printf("mii[%d] = %d\n", i, mii[i])
+               }
+               if(mfi[f] != 10*i) {
+                       fmt.Printf("mfi[%d] = %d\n", i, mfi[f])
+               }
+               if(mif[i] != 10.0*f) {
+                       fmt.Printf("mif[%d] = %g\n", i, mif[i])
+               }
+               if(mis[i] != s) {
+                       fmt.Printf("mis[%d] = %s\n", i, mis[i])
+               }
+               if(msi[s] != i) {
+                       fmt.Printf("msi[%s] = %d\n", s, msi[s])
+               }
+               if mss[s] != s10 {
+                       fmt.Printf("mss[%s] = %g\n", s, mss[s])
+               }
+               for j := 0; j < len(mspa[s]); j++ {
+                       if mspa[s][j] != s10 {
+                               fmt.Printf("mspa[%s][%d] = %s\n", s, j, mspa[s][j])
+                       }
+               }
+               if(mipT[i].i != int64(i) || mipT[i].f != f) {
+                       fmt.Printf("mipT[%d] = %v\n", i, mipT[i])
+               }
+               if(mpTi[apT[i]] != i) {
+                       fmt.Printf("mpTi[apT[%d]] = %d\n", i, mpTi[apT[i]])
+               }
+       //      if(mti[t] != i) {
+       //              fmt.Printf("mti[%s] = %s\n", s, mti[t])
+       //      }
+               if (mipM[i][i] != i + 1) {
+                       fmt.Printf("mipM[%d][%d] = %d\n", i, i, mipM[i][i])
+               }
+       //      if(mti[t] != i) {
+       //              fmt.Printf("mti[%v] = %d\n", t, mti[t])
+       //      }
+               if(mit[i].i != int64(i) || mit[i].f != f) {
+                       fmt.Printf("mit[%d] = {%d %g}\n", i, mit[i].i, mit[i].f)
+               }
+       }
+
+       // test existence with tuple check
+       // failed lookups yield a false value for the boolean.
+       for i := 0; i < count; i++ {
+               s := strconv.Itoa(i)
+               f := float(i)
+               {
+                       _, b := mib[i]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mib[%d]\n", i)
+                       }
+                       _, b = mib[i]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mib[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := mii[i]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mii[%d]\n", i)
+                       }
+                       _, b = mii[i]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mii[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := mfi[f]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mfi[%d]\n", i)
+                       }
+                       _, b = mfi[f]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mfi[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := mif[i]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mif[%d]\n", i)
+                       }
+                       _, b = mif[i]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mif[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := mis[i]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mis[%d]\n", i)
+                       }
+                       _, b = mis[i]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mis[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := msi[s]
+                       if !b {
+                               fmt.Printf("tuple existence decl: msi[%d]\n", i)
+                       }
+                       _, b = msi[s]
+                       if !b {
+                               fmt.Printf("tuple existence assign: msi[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := mss[s]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mss[%d]\n", i)
+                       }
+                       _, b = mss[s]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mss[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := mspa[s]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mspa[%d]\n", i)
+                       }
+                       _, b = mspa[s]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mspa[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := mipT[i]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mipT[%d]\n", i)
+                       }
+                       _, b = mipT[i]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mipT[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := mpTi[apT[i]]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mpTi[apT[%d]]\n", i)
+                       }
+                       _, b = mpTi[apT[i]]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mpTi[apT[%d]]\n", i)
+                       }
+               }
+               {
+                       _, b := mipM[i]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mipM[%d]\n", i)
+                       }
+                       _, b = mipM[i]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mipM[%d]\n", i)
+                       }
+               }
+               {
+                       _, b := mit[i]
+                       if !b {
+                               fmt.Printf("tuple existence decl: mit[%d]\n", i)
+                       }
+                       _, b = mit[i]
+                       if !b {
+                               fmt.Printf("tuple existence assign: mit[%d]\n", i)
+                       }
+               }
+//             {
+//                     _, b := mti[t]
+//                     if !b {
+//                             fmt.Printf("tuple existence decl: mti[%d]\n", i)
+//                     }
+//                     _, b = mti[t]
+//                     if !b {
+//                             fmt.Printf("tuple existence assign: mti[%d]\n", i)
+//                     }
+//             }
+       }
+
+       // test nonexistence with tuple check
+       // failed lookups yield a false value for the boolean.
+       for i := count; i < 2*count; i++ {
+               s := strconv.Itoa(i)
+               f := float(i)
+               {
+                       _, b := mib[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mib[%d]", i)
+                       }
+                       _, b = mib[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mib[%d]", i)
+                       }
+               }
+               {
+                       _, b := mii[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mii[%d]", i)
+                       }
+                       _, b = mii[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mii[%d]", i)
+                       }
+               }
+               {
+                       _, b := mfi[f]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mfi[%d]", i)
+                       }
+                       _, b = mfi[f]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mfi[%d]", i)
+                       }
+               }
+               {
+                       _, b := mif[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mif[%d]", i)
+                       }
+                       _, b = mif[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mif[%d]", i)
+                       }
+               }
+               {
+                       _, b := mis[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mis[%d]", i)
+                       }
+                       _, b = mis[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mis[%d]", i)
+                       }
+               }
+               {
+                       _, b := msi[s]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: msi[%d]", i)
+                       }
+                       _, b = msi[s]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: msi[%d]", i)
+                       }
+               }
+               {
+                       _, b := mss[s]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mss[%d]", i)
+                       }
+                       _, b = mss[s]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mss[%d]", i)
+                       }
+               }
+               {
+                       _, b := mspa[s]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mspa[%d]", i)
+                       }
+                       _, b = mspa[s]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mspa[%d]", i)
+                       }
+               }
+               {
+                       _, b := mipT[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mipT[%d]", i)
+                       }
+                       _, b = mipT[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mipT[%d]", i)
+                       }
+               }
+               {
+                       _, b := mpTi[apT[i]]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mpTi[apt[%d]]", i)
+                       }
+                       _, b = mpTi[apT[i]]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mpTi[apT[%d]]", i)
+                       }
+               }
+               {
+                       _, b := mipM[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mipM[%d]", i)
+                       }
+                       _, b = mipM[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mipM[%d]", i)
+                       }
+               }
+//             {
+//                     _, b := mti[t]
+//                     if b {
+//                             fmt.Printf("tuple nonexistence decl: mti[%d]", i)
+//                     }
+//                     _, b = mti[t]
+//                     if b {
+//                             fmt.Printf("tuple nonexistence assign: mti[%d]", i)
+//                     }
+//             }
+               {
+                       _, b := mit[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence decl: mit[%d]", i)
+                       }
+                       _, b = mit[i]
+                       if b {
+                               fmt.Printf("tuple nonexistence assign: mit[%d]", i)
+                       }
+               }
+       }
+
+
+       // tests for structured map element updates
+       for i := 0; i < count; i++ {
+               s := strconv.Itoa(i)
+               mspa[s][i % 2] = "deleted"
+               if mspa[s][i % 2] != "deleted" {
+                       fmt.Printf("update mspa[%s][%d] = %s\n", s, i %2, mspa[s][i % 2])
+               }
+
+               mipT[i].i += 1
+               if mipT[i].i != int64(i)+1 {
+                       fmt.Printf("update mipT[%d].i = %d\n", i, mipT[i].i)
+               }
+               mipT[i].f = float(i + 1)
+               if (mipT[i].f != float(i + 1)) {
+                       fmt.Printf("update mipT[%d].f = %g\n", i, mipT[i].f)
+               }
+
+               mipM[i][i]++
+               if mipM[i][i] != (i + 1) + 1 {
+                       fmt.Printf("update mipM[%d][%d] = %i\n", i, i, mipM[i][i])
+               }
+       }
+
+       // test range on nil map
+       var mnil map[string] int
+       for _, _ = range mnil {
+               panic("range mnil")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/method.go b/gcc/testsuite/go.test/test/method.go
new file mode 100644 (file)
index 0000000..c751c1f
--- /dev/null
@@ -0,0 +1,111 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S string
+type S1 string
+type I int
+type I1 int
+type T struct {
+       x int
+}
+type T1 T
+
+func (s S) val() int   { return 1 }
+func (s *S1) val() int { return 2 }
+func (i I) val() int   { return 3 }
+func (i *I1) val() int { return 4 }
+//func (t T) val() int { return 7 }
+func (t *T1) val() int { return 8 }
+
+type Val interface {
+       val() int
+}
+
+func val(v Val) int { return v.val() }
+
+func main() {
+       var s S
+       var ps *S1
+       var i I
+       var pi *I1
+       var pt *T1
+
+       if s.val() != 1 {
+               println("s.val:", s.val())
+               panic("fail")
+       }
+       if S.val(s) != 1 {
+               println("S.val(s):", S.val(s))
+               panic("fail")
+       }
+       if (*S).val(&s) != 1 {
+               println("(*S).val(s):", (*S).val(&s))
+               panic("fail")
+       }
+       if ps.val() != 2 {
+               println("ps.val:", ps.val())
+               panic("fail")
+       }
+       if (*S1).val(ps) != 2 {
+               println("(*S1).val(ps):", (*S1).val(ps))
+               panic("fail")
+       }
+       if i.val() != 3 {
+               println("i.val:", i.val())
+               panic("fail")
+       }
+       if I.val(i) != 3 {
+               println("I.val(i):", I.val(i))
+               panic("fail")
+       }
+       if (*I).val(&i) != 3 {
+               println("(*I).val(&i):", (*I).val(&i))
+               panic("fail")
+       }
+       if pi.val() != 4 {
+               println("pi.val:", pi.val())
+               panic("fail")
+       }
+       if (*I1).val(pi) != 4 {
+               println("(*I1).val(pi):", (*I1).val(pi))
+               panic("fail")
+       }
+       //      if t.val() != 7 { prinln("t.val:", t.val()); panic("fail") }
+       if pt.val() != 8 {
+               println("pt.val:", pt.val())
+               panic("fail")
+       }
+       if (*T1).val(pt) != 8 {
+               println("(*T1).val(pt):", (*T1).val(pt))
+               panic("fail")
+       }
+
+       if val(s) != 1 {
+               println("s.val:", val(s))
+               panic("fail")
+       }
+       if val(ps) != 2 {
+               println("ps.val:", val(ps))
+               panic("fail")
+       }
+       if val(i) != 3 {
+               println("i.val:", val(i))
+               panic("fail")
+       }
+       if val(pi) != 4 {
+               println("pi.val:", val(pi))
+               panic("fail")
+       }
+       //      if val(t) != 7 { println("t.val:", val(t)); panic("fail") }
+       if val(pt) != 8 {
+               println("pt.val:", val(pt))
+               panic("fail")
+       }
+
+       //      if Val.val(i) != 3 { println("Val.val(i):", Val.val(i)); panic("fail") }
+}
diff --git a/gcc/testsuite/go.test/test/method1.go b/gcc/testsuite/go.test/test/method1.go
new file mode 100644 (file)
index 0000000..1a2f8ca
--- /dev/null
@@ -0,0 +1,17 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct { }
+func (t *T) M(int, string)     // GCCGO_ERROR "previous"
+func (t *T) M(int, float) { }   // ERROR "redeclared|redefinition"
+
+func f(int, string)    // GCCGO_ERROR "previous"
+func f(int, float) { }  // ERROR "redeclared|redefinition"
+
+func g(a int, b string)  // GCCGO_ERROR "previous"
+func g(a int, c string)  // ERROR "redeclared|redefinition"
diff --git a/gcc/testsuite/go.test/test/method2.go b/gcc/testsuite/go.test/test/method2.go
new file mode 100644 (file)
index 0000000..3ee0ae1
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {a int}
+type P *T
+type P1 *T
+
+func (p P) val() int { return 1 }  // ERROR "receiver"
+func (p *P1) val() int { return 1 }  // ERROR "receiver"
diff --git a/gcc/testsuite/go.test/test/method3.go b/gcc/testsuite/go.test/test/method3.go
new file mode 100644 (file)
index 0000000..7946a87
--- /dev/null
@@ -0,0 +1,35 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG method3
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// test that methods on slices work
+
+package main
+
+type T []int
+
+func (t T) Len() int { return len(t) }
+
+type I interface {
+       Len() int
+}
+
+func main() {
+       var t T = T{0, 1, 2, 3, 4}
+       var i I
+       i = t
+       if i.Len() != 5 {
+               println("i.Len", i.Len())
+               panic("fail")
+       }
+       if T.Len(t) != 5 {
+               println("T.Len", T.Len(t))
+               panic("fail")
+       }
+       if (*T).Len(&t) != 5 {
+               println("(*T).Len", (*T).Len(&t))
+               panic("fail")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/named.go b/gcc/testsuite/go.test/test/named.go
new file mode 100644 (file)
index 0000000..d2039ba
--- /dev/null
@@ -0,0 +1,281 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that basic operations on named types are valid
+// and preserve the type.
+
+package main
+
+type Array [10]byte
+type Bool bool
+type Chan chan int
+type Float float
+type Int int
+type Map map[int]byte
+type Slice []byte
+type String string
+
+// Calling these functions checks at compile time that the argument
+// can be converted implicitly to (used as) the given type.
+func asArray(Array)   {}
+func asBool(Bool)     {}
+func asChan(Chan)     {}
+func asFloat(Float)   {}
+func asInt(Int)       {}
+func asMap(Map)       {}
+func asSlice(Slice)   {}
+func asString(String) {}
+
+func (Map) M() {}
+
+
+// These functions check at run time that the default type
+// (in the absence of any implicit conversion hints)
+// is the given type.
+func isArray(x interface{})  { _ = x.(Array) }
+func isBool(x interface{})   { _ = x.(Bool) }
+func isChan(x interface{})   { _ = x.(Chan) }
+func isFloat(x interface{})  { _ = x.(Float) }
+func isInt(x interface{})    { _ = x.(Int) }
+func isMap(x interface{})    { _ = x.(Map) }
+func isSlice(x interface{})  { _ = x.(Slice) }
+func isString(x interface{}) { _ = x.(String) }
+
+func main() {
+       var (
+               a     Array
+               b     Bool   = true
+               c     Chan   = make(Chan)
+               f     Float  = 1
+               i     Int    = 1
+               m     Map    = make(Map)
+               slice Slice  = make(Slice, 10)
+               str   String = "hello"
+       )
+
+       asArray(a)
+       isArray(a)
+       asArray(*&a)
+       isArray(*&a)
+       asArray(Array{})
+       isArray(Array{})
+
+       asBool(b)
+       isBool(b)
+       asBool(!b)
+       isBool(!b)
+       asBool(true)
+       asBool(*&b)
+       isBool(*&b)
+       asBool(Bool(true))
+       isBool(Bool(true))
+
+       asChan(c)
+       isChan(c)
+       asChan(make(Chan))
+       isChan(make(Chan))
+       asChan(*&c)
+       isChan(*&c)
+       asChan(Chan(nil))
+       isChan(Chan(nil))
+
+       asFloat(f)
+       isFloat(f)
+       asFloat(-f)
+       isFloat(-f)
+       asFloat(+f)
+       isFloat(+f)
+       asFloat(f + 1)
+       isFloat(f + 1)
+       asFloat(1 + f)
+       isFloat(1 + f)
+       asFloat(f + f)
+       isFloat(f + f)
+       f++
+       f += 2
+       asFloat(f - 1)
+       isFloat(f - 1)
+       asFloat(1 - f)
+       isFloat(1 - f)
+       asFloat(f - f)
+       isFloat(f - f)
+       f--
+       f -= 2
+       asFloat(f * 2.5)
+       isFloat(f * 2.5)
+       asFloat(2.5 * f)
+       isFloat(2.5 * f)
+       asFloat(f * f)
+       isFloat(f * f)
+       f *= 4
+       asFloat(f / 2.5)
+       isFloat(f / 2.5)
+       asFloat(2.5 / f)
+       isFloat(2.5 / f)
+       asFloat(f / f)
+       isFloat(f / f)
+       f /= 4
+       asFloat(f)
+       isFloat(f)
+       f = 5
+       asFloat(*&f)
+       isFloat(*&f)
+       asFloat(234)
+       asFloat(Float(234))
+       isFloat(Float(234))
+       asFloat(1.2)
+       asFloat(Float(i))
+       isFloat(Float(i))
+
+       asInt(i)
+       isInt(i)
+       asInt(-i)
+       isInt(-i)
+       asInt(^i)
+       isInt(^i)
+       asInt(+i)
+       isInt(+i)
+       asInt(i + 1)
+       isInt(i + 1)
+       asInt(1 + i)
+       isInt(1 + i)
+       asInt(i + i)
+       isInt(i + i)
+       i++
+       i += 1
+       asInt(i - 1)
+       isInt(i - 1)
+       asInt(1 - i)
+       isInt(1 - i)
+       asInt(i - i)
+       isInt(i - i)
+       i--
+       i -= 1
+       asInt(i * 2)
+       isInt(i * 2)
+       asInt(2 * i)
+       isInt(2 * i)
+       asInt(i * i)
+       isInt(i * i)
+       i *= 2
+       asInt(i / 5)
+       isInt(i / 5)
+       asInt(5 / i)
+       isInt(5 / i)
+       asInt(i / i)
+       isInt(i / i)
+       i /= 2
+       asInt(i % 5)
+       isInt(i % 5)
+       asInt(5 % i)
+       isInt(5 % i)
+       asInt(i % i)
+       isInt(i % i)
+       i %= 2
+       asInt(i & 5)
+       isInt(i & 5)
+       asInt(5 & i)
+       isInt(5 & i)
+       asInt(i & i)
+       isInt(i & i)
+       i &= 2
+       asInt(i &^ 5)
+       isInt(i &^ 5)
+       asInt(5 &^ i)
+       isInt(5 &^ i)
+       asInt(i &^ i)
+       isInt(i &^ i)
+       i &^= 2
+       asInt(i | 5)
+       isInt(i | 5)
+       asInt(5 | i)
+       isInt(5 | i)
+       asInt(i | i)
+       isInt(i | i)
+       i |= 2
+       asInt(i ^ 5)
+       isInt(i ^ 5)
+       asInt(5 ^ i)
+       isInt(5 ^ i)
+       asInt(i ^ i)
+       isInt(i ^ i)
+       i ^= 2
+       asInt(i << 4)
+       isInt(i << 4)
+       i <<= 2
+       asInt(i >> 4)
+       isInt(i >> 4)
+       i >>= 2
+       asInt(i)
+       isInt(i)
+       asInt(0)
+       asInt(Int(0))
+       isInt(Int(0))
+       i = 10
+       asInt(*&i)
+       isInt(*&i)
+       asInt(23)
+       asInt(Int(f))
+       isInt(Int(f))
+
+       asMap(m)
+       isMap(m)
+       asMap(nil)
+       m = nil
+       asMap(make(Map))
+       isMap(make(Map))
+       asMap(*&m)
+       isMap(*&m)
+       asMap(Map(nil))
+       isMap(Map(nil))
+       asMap(Map{})
+       isMap(Map{})
+
+       asSlice(slice)
+       isSlice(slice)
+       asSlice(make(Slice, 5))
+       isSlice(make(Slice, 5))
+       asSlice([]byte{1, 2, 3})
+       asSlice([]byte{1, 2, 3}[0:2])
+       asSlice(slice[0:4])
+       isSlice(slice[0:4])
+       asSlice(slice[3:8])
+       isSlice(slice[3:8])
+       asSlice(nil)
+       asSlice(Slice(nil))
+       isSlice(Slice(nil))
+       slice = nil
+       asSlice(Slice{1, 2, 3})
+       isSlice(Slice{1, 2, 3})
+       asSlice(Slice{})
+       isSlice(Slice{})
+       asSlice(*&slice)
+       isSlice(*&slice)
+
+       asString(str)
+       isString(str)
+       asString(str + "a")
+       isString(str + "a")
+       asString("a" + str)
+       isString("a" + str)
+       asString(str + str)
+       isString(str + str)
+       str += "a"
+       str += str
+       asString(String('a'))
+       isString(String('a'))
+       asString(String([]byte(slice)))
+       isString(String([]byte(slice)))
+       asString(String([]byte(nil)))
+       isString(String([]byte(nil)))
+       asString("hello")
+       asString(String("hello"))
+       isString(String("hello"))
+       str = "hello"
+       isString(str)
+       asString(*&str)
+       isString(*&str)
+}
diff --git a/gcc/testsuite/go.test/test/named1.go b/gcc/testsuite/go.test/test/named1.go
new file mode 100644 (file)
index 0000000..600e502
--- /dev/null
@@ -0,0 +1,68 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that basic operations on named types are valid
+// and preserve the type.
+
+package main
+
+type Bool bool
+
+type Map map[int]int
+
+func (Map) M() {}
+
+type Slice []byte
+
+var slice Slice
+
+func asBool(Bool)     {}
+func asString(String) {}
+
+type String string
+
+func main() {
+       var (
+               b    Bool = true
+               i, j int
+               c    = make(chan int)
+               m    = make(Map)
+       )
+
+       asBool(b)
+       asBool(!b)
+       asBool(true)
+       asBool(*&b)
+       asBool(Bool(true))
+       asBool(1 != 2) // ERROR "cannot use.*type bool.*as type Bool"
+       asBool(i < j)  // ERROR "cannot use.*type bool.*as type Bool"
+
+       _, b = m[2] // ERROR "cannot .* bool.*type Bool"
+       m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool"
+
+       b = c <- 1 // ERROR "cannot use.*type bool.*type Bool"
+       _ = b
+       asBool(c <- 1) // ERROR "cannot use.*type bool.*as type Bool"
+
+       _, b = <-c // ERROR "cannot .* bool.*type Bool"
+       _ = b
+
+       var inter interface{}
+       _, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"
+       _ = b
+
+       var minter interface {
+               M()
+       }
+       _, b = minter.(Map) // ERROR "cannot .* bool.*type Bool"
+       _ = b
+
+       asBool(closed(c)) // ERROR "cannot use.*type bool.*as type Bool"
+       b = closed(c)     // ERROR "cannot use.*type bool.*type Bool"
+       _ = b
+
+       asString(String(slice)) // ERROR "cannot .*type Slice.*type String"
+}
diff --git a/gcc/testsuite/go.test/test/nil.go b/gcc/testsuite/go.test/test/nil.go
new file mode 100644 (file)
index 0000000..6a72b72
--- /dev/null
@@ -0,0 +1,37 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+       i int
+}
+
+type IN interface {
+}
+
+func main() {
+       var i *int
+       var f *float
+       var s *string
+       var m map[float] *int
+       var c chan int
+       var t *T
+       var in IN
+       var ta []IN
+
+       i = nil
+       f = nil
+       s = nil
+       m = nil
+       c = nil
+       t = nil
+       i = nil
+       ta = make([]IN, 1)
+       ta[0] = nil
+
+       _, _, _, _, _, _, _, _ = i, f, s, m, c, t, in, ta
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/arrayindex.go b/gcc/testsuite/go.test/test/nilptr/arrayindex.go
new file mode 100644 (file)
index 0000000..c564bce
--- /dev/null
@@ -0,0 +1,27 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var x byte
+
+func main() {
+       var p *[1<<30]byte = nil
+       x = 123
+
+       // The problem here is not the use of unsafe:
+       // it is that indexing into p[] with a large
+       // enough index jumps out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       // Pointer offsets and array indices, if they are
+       // very large, need to dereference the base pointer
+       // to trigger a trap.
+       println(p[uintptr(unsafe.Pointer(&x))]) // should crash
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/arrayindex1.go b/gcc/testsuite/go.test/test/nilptr/arrayindex1.go
new file mode 100644 (file)
index 0000000..701630e
--- /dev/null
@@ -0,0 +1,32 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte        // give us a big address space
+func main() {
+       // the test only tests what we intend to test
+       // if dummy starts in the first 256 MB of memory.
+       // otherwise there might not be anything mapped
+       // at the address that might be accidentally
+       // dereferenced below.
+       if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+               panic("dummy too far out")
+       }
+
+       // The problem here is that indexing into p[] with a large
+       // enough index jumps out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       // Pointer offsets and array indices, if they are
+       // very large, need to dereference the base pointer
+       // to trigger a trap.
+       var p *[1<<30]byte = nil
+       println(p[256<<20])     // very likely to be inside dummy, but should crash
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/arraytoslice.go b/gcc/testsuite/go.test/test/nilptr/arraytoslice.go
new file mode 100644 (file)
index 0000000..38206d5
--- /dev/null
@@ -0,0 +1,37 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+func f([]byte) {
+       panic("unreachable")
+}
+
+var dummy [512<<20]byte        // give us a big address space
+func main() {
+       // the test only tests what we intend to test
+       // if dummy starts in the first 256 MB of memory.
+       // otherwise there might not be anything mapped
+       // at the address that might be accidentally
+       // dereferenced below.
+       if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+               panic("dummy too far out")
+       }
+
+       // The problem here is that indexing into p[] with a large
+       // enough index can jump out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       //
+       // To avoid needing a check on every slice beyond the
+       // usual len and cap, we require the *array -> slice
+       // conversion to do the check.
+       var p *[1<<30]byte = nil
+       f(p[0:])        // should crash
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/arraytoslice1.go b/gcc/testsuite/go.test/test/nilptr/arraytoslice1.go
new file mode 100644 (file)
index 0000000..8c9531e
--- /dev/null
@@ -0,0 +1,34 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte        // give us a big address space
+func main() {
+       // the test only tests what we intend to test
+       // if dummy starts in the first 256 MB of memory.
+       // otherwise there might not be anything mapped
+       // at the address that might be accidentally
+       // dereferenced below.
+       if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+               panic("dummy too far out")
+       }
+
+       // The problem here is that indexing into p[] with a large
+       // enough index can jump out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       //
+       // To avoid needing a check on every slice beyond the
+       // usual len and cap, we require the *array -> slice
+       // conversion to do the check.
+       var p *[1<<30]byte = nil
+       var x []byte = p[0:]    // should crash
+       _ = x
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/arraytoslice2.go b/gcc/testsuite/go.test/test/nilptr/arraytoslice2.go
new file mode 100644 (file)
index 0000000..1b26513
--- /dev/null
@@ -0,0 +1,35 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte        // give us a big address space
+var q *[1<<30]byte
+func main() {
+       // the test only tests what we intend to test
+       // if dummy starts in the first 256 MB of memory.
+       // otherwise there might not be anything mapped
+       // at the address that might be accidentally
+       // dereferenced below.
+       if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+               panic("dummy too far out")
+       }
+
+       // The problem here is that indexing into p[] with a large
+       // enough index can jump out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       //
+       // To avoid needing a check on every slice beyond the
+       // usual len and cap, we require the *array -> slice
+       // conversion to do the check.
+       var x []byte
+       var y = &x
+       *y = q[0:]      // should crash (uses arraytoslice runtime routine)
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/slicearray.go b/gcc/testsuite/go.test/test/nilptr/slicearray.go
new file mode 100644 (file)
index 0000000..544536c
--- /dev/null
@@ -0,0 +1,33 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte        // give us a big address space
+func main() {
+       // the test only tests what we intend to test
+       // if dummy starts in the first 256 MB of memory.
+       // otherwise there might not be anything mapped
+       // at the address that might be accidentally
+       // dereferenced below.
+       if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+               panic("dummy too far out")
+       }
+
+       // The problem here is that indexing into p[] with a large
+       // enough index can jump out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       //
+       // To avoid needing a check on every slice beyond the
+       // usual len and cap, we require the slice operation
+       // to do the check.
+       var p *[1<<30]byte = nil
+       var _ []byte = p[10:len(p)-10]  // should crash
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/structfield.go b/gcc/testsuite/go.test/test/nilptr/structfield.go
new file mode 100644 (file)
index 0000000..e081f7a
--- /dev/null
@@ -0,0 +1,35 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte        // give us a big address space
+type T struct {
+       x [256<<20] byte
+       i int
+}
+
+func main() {
+       // the test only tests what we intend to test
+       // if dummy starts in the first 256 MB of memory.
+       // otherwise there might not be anything mapped
+       // at the address that might be accidentally
+       // dereferenced below.
+       if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+               panic("dummy too far out")
+       }
+
+       // The problem here is that indexing into t with a large
+       // enough index can jump out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       // We require the pointer dereference to check.
+       var t *T
+       println(t.i)    // should crash
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/structfield1.go b/gcc/testsuite/go.test/test/nilptr/structfield1.go
new file mode 100644 (file)
index 0000000..02d33a4
--- /dev/null
@@ -0,0 +1,38 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte        // give us a big address space
+type T struct {
+       x [256<<20] byte
+       i int
+}
+
+func f() *T {
+       return nil
+}
+
+func main() {
+       // the test only tests what we intend to test
+       // if dummy starts in the first 256 MB of memory.
+       // otherwise there might not be anything mapped
+       // at the address that might be accidentally
+       // dereferenced below.
+       if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+               panic("dummy too far out")
+       }
+
+       // The problem here is that indexing into t with a large
+       // enough index can jump out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       // We require the pointer dereference to check.
+       println(f().i)  // should crash
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/structfield2.go b/gcc/testsuite/go.test/test/nilptr/structfield2.go
new file mode 100644 (file)
index 0000000..4323b42
--- /dev/null
@@ -0,0 +1,37 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte        // give us a big address space
+type T struct {
+       x [256<<20] byte
+       i int
+}
+
+var y *T
+var x = &y
+
+func main() {
+       // the test only tests what we intend to test
+       // if dummy starts in the first 256 MB of memory.
+       // otherwise there might not be anything mapped
+       // at the address that might be accidentally
+       // dereferenced below.
+       if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+               panic("dummy too far out")
+       }
+
+       // The problem here is that indexing into t with a large
+       // enough index can jump out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       // We require the pointer dereference to check.
+       println((*x).i) // should crash
+}
diff --git a/gcc/testsuite/go.test/test/nilptr/structfieldaddr.go b/gcc/testsuite/go.test/test/nilptr/structfieldaddr.go
new file mode 100644 (file)
index 0000000..81551aa
--- /dev/null
@@ -0,0 +1,35 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
+// $G $D/$F.go && $L $F.$A &&
+//     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte        // give us a big address space
+type T struct {
+       x [256<<20] byte
+       i int
+}
+
+func main() {
+       // the test only tests what we intend to test
+       // if dummy starts in the first 256 MB of memory.
+       // otherwise there might not be anything mapped
+       // at the address that might be accidentally
+       // dereferenced below.
+       if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+               panic("dummy too far out")
+       }
+
+       // The problem here is that indexing into t with a large
+       // enough index can jump out of the unmapped section
+       // at the beginning of memory and into valid memory.
+       // We require the address calculation to check.
+       var t *T
+       println(&t.i)   // should crash
+}
diff --git a/gcc/testsuite/go.test/test/nul1.go b/gcc/testsuite/go.test/test/nul1.go
new file mode 100644 (file)
index 0000000..9d6974f
--- /dev/null
@@ -0,0 +1,60 @@
+// [ $GOOS != nacl ] || exit 0  # NaCl runner elides NUL in output
+// [ "$GORUN" == "" ] || exit 0  # Android runner gets confused by the NUL output 
+// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
+// errchk $G -e tmp.go
+// rm -f tmp.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test source files and strings containing NUL and invalid UTF-8.
+
+package main
+
+import (
+       "fmt"
+       "os"
+)
+
+func main() {
+       var s = "\xc2\xff"
+       var t = "\xd0\xfe"
+       var u = "\xab\x00\xfc"
+
+       if len(s) != 2 || s[0] != 0xc2 || s[1] != 0xff ||
+               len(t) != 2 || t[0] != 0xd0 || t[1] != 0xfe ||
+               len(u) != 3 || u[0] != 0xab || u[1] != 0x00 || u[2] != 0xfc {
+               println("BUG: non-UTF-8 string mangled")
+               os.Exit(2)
+       }
+
+       fmt.Print(`
+package main
+
+var x = "in string ` + "\x00" + `"     // ERROR "NUL"
+
+var y = ` + "`in raw string \x00 foo`" + `  // ERROR "NUL"
+
+// in comment ` + "\x00" + `  // ERROR "NUL"
+
+/* in other comment ` + "\x00" + ` */ // ERROR "NUL"
+
+/* in source code */ ` + "\x00" + `// ERROR "NUL"
+
+var xx = "in string ` + "\xc2\xff" + `" // ERROR "UTF-8"
+
+var yy = ` + "`in raw string \xff foo`" + `  // ERROR "UTF-8"
+
+// in comment ` + "\xe2\x80\x01" + `  // ERROR "UTF-8"
+
+/* in other comment ` + "\xe0\x00\x00" + ` */ // ERROR "UTF-8|NUL"
+
+/* in variable name */
+var z` + "\xc1\x81" + ` int // ERROR "UTF-8"
+
+/* in source code */ ` + "\xc2A" + `// ERROR "UTF-8"
+
+`)
+}
+
diff --git a/gcc/testsuite/go.test/test/parentype.go b/gcc/testsuite/go.test/test/parentype.go
new file mode 100644 (file)
index 0000000..1872cd0
--- /dev/null
@@ -0,0 +1,17 @@
+// $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f(interface{})
+func g() {}
+func main() {
+       f(map[string]string{"a":"b","c":"d"})
+       f([...]int{1,2,3})
+       f(map[string]func(){"a":g,"c":g})
+       f(make(chan(<-chan int)))
+       f(make(chan<-(chan int)))
+}
diff --git a/gcc/testsuite/go.test/test/peano.go b/gcc/testsuite/go.test/test/peano.go
new file mode 100644 (file)
index 0000000..f4c59d1
--- /dev/null
@@ -0,0 +1,126 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Number *Number
+
+
+// -------------------------------------
+// Peano primitives
+
+func zero() *Number {
+       return nil
+}
+
+
+func is_zero(x *Number) bool {
+       return x == nil
+}
+
+
+func add1(x *Number) *Number {
+       e := new(Number)
+       *e = x
+       return e
+}
+
+
+func sub1(x *Number) *Number {
+       return *x
+}
+
+
+func add(x, y *Number) *Number {
+       if is_zero(y) {
+               return x
+       }
+
+       return add(add1(x), sub1(y))
+}
+
+
+func mul(x, y *Number) *Number {
+       if is_zero(x) || is_zero(y) {
+               return zero()
+       }
+
+       return add(mul(x, sub1(y)), x)
+}
+
+
+func fact(n *Number) *Number {
+       if is_zero(n) {
+               return add1(zero())
+       }
+
+       return mul(fact(sub1(n)), n)
+}
+
+
+// -------------------------------------
+// Helpers to generate/count Peano integers
+
+func gen(n int) *Number {
+       if n > 0 {
+               return add1(gen(n - 1))
+       }
+
+       return zero()
+}
+
+
+func count(x *Number) int {
+       if is_zero(x) {
+               return 0
+       }
+
+       return count(sub1(x)) + 1
+}
+
+
+func check(x *Number, expected int) {
+       var c = count(x)
+       if c != expected {
+               print("error: found ", c, "; expected ", expected, "\n")
+               panic("fail")
+       }
+}
+
+
+// -------------------------------------
+// Test basic functionality
+
+func init() {
+       check(zero(), 0)
+       check(add1(zero()), 1)
+       check(gen(10), 10)
+
+       check(add(gen(3), zero()), 3)
+       check(add(zero(), gen(4)), 4)
+       check(add(gen(3), gen(4)), 7)
+
+       check(mul(zero(), zero()), 0)
+       check(mul(gen(3), zero()), 0)
+       check(mul(zero(), gen(4)), 0)
+       check(mul(gen(3), add1(zero())), 3)
+       check(mul(add1(zero()), gen(4)), 4)
+       check(mul(gen(3), gen(4)), 12)
+
+       check(fact(zero()), 1)
+       check(fact(add1(zero())), 1)
+       check(fact(gen(5)), 120)
+}
+
+
+// -------------------------------------
+// Factorial
+
+func main() {
+       for i := 0; i <= 9; i++ {
+               print(i, "! = ", count(fact(gen(i))), "\n")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/printbig.go b/gcc/testsuite/go.test/test/printbig.go
new file mode 100644 (file)
index 0000000..bbb7070
--- /dev/null
@@ -0,0 +1,12 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       print(-(1<<63), "\n")
+       print((1<<63)-1, "\n")
+}
diff --git a/gcc/testsuite/go.test/test/range.go b/gcc/testsuite/go.test/test/range.go
new file mode 100644 (file)
index 0000000..91ccd63
--- /dev/null
@@ -0,0 +1,297 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// test range over channels
+
+func gen(c chan int, lo, hi int) {
+       for i := lo; i <= hi; i++ {
+               c <- i
+       }
+       close(c)
+}
+
+func seq(lo, hi int) chan int {
+       c := make(chan int)
+       go gen(c, lo, hi)
+       return c
+}
+
+func testchan() {
+       s := ""
+       for i := range seq('a', 'z') {
+               s += string(i)
+       }
+       if s != "abcdefghijklmnopqrstuvwxyz" {
+               println("Wanted lowercase alphabet; got", s)
+               panic("fail")
+       }
+}
+
+// test that range over slice only evaluates
+// the expression after "range" once.
+
+var nmake = 0
+
+func makeslice() []int {
+       nmake++
+       return []int{1, 2, 3, 4, 5}
+}
+
+func testslice() {
+       s := 0
+       nmake = 0
+       for _, v := range makeslice() {
+               s += v
+       }
+       if nmake != 1 {
+               println("range called makeslice", nmake, "times")
+               panic("fail")
+       }
+       if s != 15 {
+               println("wrong sum ranging over makeslice")
+               panic("fail")
+       }
+}
+
+func testslice1() {
+       s := 0
+       nmake = 0
+       for i := range makeslice() {
+               s += i
+       }
+       if nmake != 1 {
+               println("range called makeslice", nmake, "times")
+               panic("fail")
+       }
+       if s != 10 {
+               println("wrong sum ranging over makeslice")
+               panic("fail")
+       }
+}
+
+// test that range over array only evaluates
+// the expression after "range" once.
+
+func makearray() [5]int {
+       nmake++
+       return [5]int{1, 2, 3, 4, 5}
+}
+
+func testarray() {
+       s := 0
+       nmake = 0
+       for _, v := range makearray() {
+               s += v
+       }
+       if nmake != 1 {
+               println("range called makearray", nmake, "times")
+               panic("fail")
+       }
+       if s != 15 {
+               println("wrong sum ranging over makearray")
+               panic("fail")
+       }
+}
+
+func testarray1() {
+       s := 0
+       nmake = 0
+       for i := range makearray() {
+               s += i
+       }
+       if nmake != 1 {
+               println("range called makearray", nmake, "times")
+               panic("fail")
+       }
+       if s != 10 {
+               println("wrong sum ranging over makearray")
+               panic("fail")
+       }
+}
+
+func makearrayptr() *[5]int {
+       nmake++
+       return &[5]int{1, 2, 3, 4, 5}
+}
+
+func testarrayptr() {
+       nmake = 0
+       x := len(makearrayptr())
+       if x != 5 || nmake != 1 {
+               println("len called makearrayptr", nmake, "times and got len", x)
+               panic("fail")
+       }
+       nmake = 0
+       x = cap(makearrayptr())
+       if x != 5 || nmake != 1 {
+               println("cap called makearrayptr", nmake, "times and got len", x)
+               panic("fail")
+       }
+       s := 0
+       nmake = 0
+       for _, v := range makearrayptr() {
+               s += v
+       }
+       if nmake != 1 {
+               println("range called makearrayptr", nmake, "times")
+               panic("fail")
+       }
+       if s != 15 {
+               println("wrong sum ranging over makearrayptr")
+               panic("fail")
+       }
+}
+
+func testarrayptr1() {
+       s := 0
+       nmake = 0
+       for i := range makearrayptr() {
+               s += i
+       }
+       if nmake != 1 {
+               println("range called makearrayptr", nmake, "times")
+               panic("fail")
+       }
+       if s != 10 {
+               println("wrong sum ranging over makearrayptr")
+               panic("fail")
+       }
+}
+
+// test that range over string only evaluates
+// the expression after "range" once.
+
+func makestring() string {
+       nmake++
+       return "abcd☺"
+}
+
+func teststring() {
+       s := 0
+       nmake = 0
+       for _, v := range makestring() {
+               s += v
+       }
+       if nmake != 1 {
+               println("range called makestring", nmake, "times")
+               panic("fail")
+       }
+       if s != 'a'+'b'+'c'+'d'+'☺' {
+               println("wrong sum ranging over makestring")
+               panic("fail")
+       }
+}
+
+func teststring1() {
+       s := 0
+       nmake = 0
+       for i := range makestring() {
+               s += i
+       }
+       if nmake != 1 {
+               println("range called makestring", nmake, "times")
+               panic("fail")
+       }
+       if s != 10 {
+               println("wrong sum ranging over makestring")
+               panic("fail")
+       }
+}
+
+// test that range over map only evaluates
+// the expression after "range" once.
+
+func makemap() map[int]int {
+       nmake++
+       return map[int]int{0:'a', 1:'b', 2:'c', 3:'d', 4:'☺'}
+}
+
+func testmap() {
+       s := 0
+       nmake = 0
+       for _, v := range makemap() {
+               s += v
+       }
+       if nmake != 1 {
+               println("range called makemap", nmake, "times")
+               panic("fail")
+       }
+       if s != 'a'+'b'+'c'+'d'+'☺' {
+               println("wrong sum ranging over makemap")
+               panic("fail")
+       }
+}
+
+func testmap1() {
+       s := 0
+       nmake = 0
+       for i := range makemap() {
+               s += i
+       }
+       if nmake != 1 {
+               println("range called makemap", nmake, "times")
+               panic("fail")
+       }
+       if s != 10 {
+               println("wrong sum ranging over makemap")
+               panic("fail")
+       }
+}
+
+// test that range evaluates the index and value expressions
+// exactly once per iteration.
+
+var ncalls = 0
+
+func getvar(p *int) *int {
+       ncalls++
+       return p
+}
+
+func testcalls() {
+       var i, v int
+       si := 0
+       sv := 0
+       for *getvar(&i), *getvar(&v) = range [2]int{1, 2} {
+               si += i
+               sv += v
+       }
+       if ncalls != 4 {
+               println("wrong number of calls:", ncalls, "!= 4")
+               panic("fail")
+       }
+       if si != 1 || sv != 3 {
+               println("wrong sum in testcalls", si, sv)
+               panic("fail")
+       }
+
+       ncalls = 0
+       for *getvar(&i), *getvar(&v) = range [0]int{} {
+               println("loop ran on empty array")
+               panic("fail")
+       }
+       if ncalls != 0 {
+               println("wrong number of calls:", ncalls, "!= 0")
+               panic("fail")
+       }
+}
+
+func main() {
+       testchan()
+       testarray()
+       testarray1()
+       testarrayptr()
+       testarrayptr1()
+       testslice()
+       testslice1()
+       teststring()
+       teststring1()
+       testmap()
+       testmap1()
+       testcalls()
+}
diff --git a/gcc/testsuite/go.test/test/recover.go b/gcc/testsuite/go.test/test/recover.go
new file mode 100644 (file)
index 0000000..ca6f072
--- /dev/null
@@ -0,0 +1,246 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test of basic recover functionality.
+
+package main
+
+import "runtime"
+
+func main() {
+       test1()
+       test1WithClosures()
+       test2()
+       test3()
+       test4()
+       test5()
+       test6()
+       test6WithClosures()
+       test7()
+}
+
+func die() {
+       runtime.Breakpoint() // can't depend on panic
+}
+
+func mustRecover(x interface{}) {
+       mustNotRecover() // because it's not a defer call
+       v := recover()
+       if v == nil {
+               println("missing recover")
+               die() // panic is useless here
+       }
+       if v != x {
+               println("wrong value", v, x)
+               die()
+       }
+
+       // the value should be gone now regardless
+       v = recover()
+       if v != nil {
+               println("recover didn't recover")
+               die()
+       }
+}
+
+func mustNotRecover() {
+       v := recover()
+       if v != nil {
+               println("spurious recover", v)
+               die()
+       }
+}
+
+func withoutRecover() {
+       mustNotRecover() // because it's a sub-call
+}
+
+func test1() {
+       defer mustNotRecover() // because mustRecover will squelch it
+       defer mustRecover(1)   // because of panic below
+       defer withoutRecover() // should be no-op, leaving for mustRecover to find
+       panic(1)
+}
+
+// Repeat test1 with closures instead of standard function.
+// Interesting because recover bases its decision
+// on the frame pointer of its caller, and a closure's
+// frame pointer is in the middle of its actual arguments
+// (after the hidden ones for the closed-over variables).
+func test1WithClosures() {
+       defer func() {
+               v := recover()
+               if v != nil {
+                       println("spurious recover in closure")
+                       die()
+               }
+       }()
+       defer func(x interface{}) {
+               mustNotRecover()
+               v := recover()
+               if v == nil {
+                       println("missing recover")
+                       die()
+               }
+               if v != x {
+                       println("wrong value", v, x)
+                       die()
+               }
+       }(1)
+       defer func() {
+               mustNotRecover()
+       }()
+       panic(1)
+}
+
+func test2() {
+       // Recover only sees the panic argument
+       // if it is called from a deferred call.
+       // It does not see the panic when called from a call within a deferred call (too late)
+       // nor does it see the panic when it *is* the deferred call (too early).
+       defer mustRecover(2)
+       defer recover() // should be no-op
+       panic(2)
+}
+
+func test3() {
+       defer mustNotRecover()
+       defer func() {
+               recover() // should squelch
+       }()
+       panic(3)
+}
+
+func test4() {
+       // Equivalent to test3 but using defer to make the call.
+       defer mustNotRecover()
+       defer func() {
+               defer recover() // should squelch
+       }()
+       panic(4)
+}
+
+// Check that closures can set output arguments.
+// Run g().  If it panics, return x; else return deflt.
+func try(g func(), deflt interface{}) (x interface{}) {
+       defer func() {
+               if v := recover(); v != nil {
+                       x = v
+               }
+       }()
+       defer g()
+       return deflt
+}
+
+// Check that closures can set output arguments.
+// Run g().  If it panics, return x; else return deflt.
+func try1(g func(), deflt interface{}) (x interface{}) {
+       defer func() {
+               if v := recover(); v != nil {
+                       x = v
+               }
+       }()
+       defer g()
+       x = deflt
+       return
+}
+
+func test5() {
+       v := try(func() { panic(5) }, 55).(int)
+       if v != 5 {
+               println("wrong value", v, 5)
+               die()
+       }
+
+       s := try(func() {}, "hi").(string)
+       if s != "hi" {
+               println("wrong value", s, "hi")
+               die()
+       }
+
+       v = try1(func() { panic(5) }, 55).(int)
+       if v != 5 {
+               println("try1 wrong value", v, 5)
+               die()
+       }
+
+       s = try1(func() {}, "hi").(string)
+       if s != "hi" {
+               println("try1 wrong value", s, "hi")
+               die()
+       }
+}
+
+// When a deferred big call starts, it must first
+// create yet another stack segment to hold the
+// giant frame for x.  Make sure that doesn't
+// confuse recover.
+func big(mustRecover bool) {
+       var x [100000]int
+       x[0] = 1
+       x[99999] = 1
+       _ = x
+
+       v := recover()
+       if mustRecover {
+               if v == nil {
+                       println("missing big recover")
+                       die()
+               }
+       } else {
+               if v != nil {
+                       println("spurious big recover")
+                       die()
+               }
+       }
+}
+
+func test6() {
+       defer big(false)
+       defer big(true)
+       panic(6)
+}
+
+func test6WithClosures() {
+       defer func() {
+               var x [100000]int
+               x[0] = 1
+               x[99999] = 1
+               _ = x
+               if recover() != nil {
+                       println("spurious big closure recover")
+                       die()
+               }
+       }()
+       defer func() {
+               var x [100000]int
+               x[0] = 1
+               x[99999] = 1
+               _ = x
+               if recover() == nil {
+                       println("missing big closure recover")
+                       die()
+               }
+       }()
+       panic("6WithClosures")
+}
+
+func test7() {
+       ok := false
+       func() {
+               // should panic, then call mustRecover 7, which stops the panic.
+               // then should keep processing ordinary defers earlier than that one
+               // before returning.
+               // this test checks that the defer func on the next line actually runs.
+               defer func() { ok = true }()
+               defer mustRecover(7)
+               panic(7)
+       }()
+       if !ok {
+               println("did not run ok func")
+               die()
+       }
+}
diff --git a/gcc/testsuite/go.test/test/recover1.go b/gcc/testsuite/go.test/test/recover1.go
new file mode 100644 (file)
index 0000000..db58473
--- /dev/null
@@ -0,0 +1,141 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test of recover during recursive panics.
+// Here be dragons.
+
+package main
+
+import "runtime"
+
+func main() {
+       test1()
+       test2()
+       test3()
+       test4()
+       test5()
+       test6()
+       test7()
+}
+
+func die() {
+       runtime.Breakpoint()    // can't depend on panic
+}
+
+func mustRecover(x interface{}) {
+       mustNotRecover()        // because it's not a defer call
+       v := recover()
+       if v == nil {
+               println("missing recover")
+               die()   // panic is useless here
+       }
+       if v != x {
+               println("wrong value", v, x)
+               die()
+       }
+       
+       // the value should be gone now regardless
+       v = recover()
+       if v != nil {
+               println("recover didn't recover")
+               die()
+       }
+}
+
+func mustNotRecover() {
+       v := recover()
+       if v != nil {
+               println("spurious recover")
+               die()
+       }
+}
+
+func withoutRecover() {
+       mustNotRecover()        // because it's a sub-call
+}
+
+func test1() {
+       // Easy nested recursive panic.
+       defer mustRecover(1)
+       defer func() {
+               defer mustRecover(2)
+               panic(2)
+       }()
+       panic(1)
+}
+
+func test2() {
+       // Sequential panic.
+       defer mustNotRecover()
+       defer func() {
+               v := recover()
+               if v == nil || v.(int) != 2 {
+                       println("wrong value", v, 2)
+                       die()
+               }
+               defer mustRecover(3)
+               panic(3)
+       }()
+       panic(2)
+}
+
+func test3() {
+       // Sequential panic - like test2 but less picky.
+       defer mustNotRecover()
+       defer func() {
+               recover()
+               defer mustRecover(3)
+               panic(3)
+       }()
+       panic(2)
+}
+
+func test4() {
+       // Single panic.
+       defer mustNotRecover()
+       defer func() {
+               recover()
+       }()
+       panic(4)
+}
+
+func test5() {
+       // Single panic but recover called via defer
+       defer mustNotRecover()
+       defer func() {
+               defer recover()
+       }()
+       panic(5)
+}
+
+func test6() {
+       // Sequential panic.
+       // Like test3, but changed recover to defer (same change as test4 → test5).
+       defer mustNotRecover()
+       defer func() {
+               defer recover() // like a normal call from this func; runs because mustRecover stops the panic
+               defer mustRecover(3)
+               panic(3)
+       }()
+       panic(2)
+}
+
+func test7() {
+       // Like test6, but swapped defer order.
+       // The recover in "defer recover()" is now a no-op,
+       // because it runs called from panic, not from the func,
+       // and therefore cannot see the panic of 2.
+       // (Alternately, it cannot see the panic of 2 because
+       // there is an active panic of 3.  And it cannot see the
+       // panic of 3 because it is at the wrong level (too high on the stack).)
+       defer mustRecover(2)
+       defer func() {
+               defer mustRecover(3)
+               defer recover() // now a no-op, unlike in test6.
+               panic(3)
+       }()
+       panic(2)
+}
diff --git a/gcc/testsuite/go.test/test/recover2.go b/gcc/testsuite/go.test/test/recover2.go
new file mode 100644 (file)
index 0000000..c95af8f
--- /dev/null
@@ -0,0 +1,93 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test of recover for run-time errors.
+
+// TODO(rsc):
+//     integer divide by zero?
+//     null pointer accesses
+
+package main
+
+import (
+       "os"
+       "strings"
+       "syscall"
+)
+
+var x = make([]byte, 10)
+
+func main() {
+       test1()
+       test2()
+       test3()
+       test4()
+       test5()
+       test6()
+       test7()
+}
+
+func mustRecover(s string) {
+       v := recover()
+       if v == nil {
+               panic("expected panic")
+       }
+       if e := v.(os.Error).String(); strings.Index(e, s) < 0 {
+               panic("want: " + s + "; have: " + e)
+       }
+}
+
+func test1() {
+       defer mustRecover("index")
+       println(x[123])
+}
+
+func test2() {
+       defer mustRecover("slice")
+       println(x[5:15])
+}
+
+func test3() {
+       defer mustRecover("slice")
+       var lo = 11
+       var hi = 9
+       println(x[lo:hi])
+}
+
+func test4() {
+       defer mustRecover("interface")
+       var x interface{} = 1
+       println(x.(float))
+}
+
+type T struct {
+       a, b int
+}
+
+func test5() {
+       defer mustRecover("uncomparable")
+       var x T
+       var z interface{} = x
+       println(z != z)
+}
+
+func test6() {
+       defer mustRecover("unhashable")
+       var x T
+       var z interface{} = x
+       m := make(map[interface{}]int)
+       m[z] = 1
+}
+
+func test7() {
+       if syscall.ARCH == "arm" || syscall.OS == "nacl" {
+               // ARM doesn't have integer divide trap yet
+               return
+       }
+       defer mustRecover("divide by zero")
+       var x, y int
+       println(x / y)
+}
diff --git a/gcc/testsuite/go.test/test/recover3.go b/gcc/testsuite/go.test/test/recover3.go
new file mode 100644 (file)
index 0000000..b982ec8
--- /dev/null
@@ -0,0 +1,79 @@
+// [ $GOOS != nacl ] || exit 0  # NaCl cannot recover from signals
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "runtime"
+       "strings"
+       "syscall"
+)
+
+var didbug bool
+
+func bug() {
+       if didbug {
+               return
+       }
+       println("BUG")
+       didbug = true
+}
+
+func check(name string, f func(), err string) {
+       defer func() {
+               v := recover()
+               if v == nil {
+                       bug()
+                       println(name, "did not panic")
+                       return
+               }
+               runt, ok := v.(runtime.Error)
+               if !ok {
+                       bug()
+                       println(name, "panicked but not with runtime.Error")
+                       return
+               }
+               s := runt.String()
+               if strings.Index(s, err) < 0 {
+                       bug()
+                       println(name, "panicked with", s, "not", err)
+                       return
+               }
+       }()
+       
+       f()
+}
+
+func main() {
+       var x int
+       var x64 int64
+       var p *[10]int
+       var q *[10000]int
+       var i int
+
+       // not catching divide by zero on the arm.  is that even possible?
+       if syscall.ARCH != "arm" {
+               check("int-div-zero", func() { println(1/x) }, "integer divide by zero")
+               check("int64-div-zero", func() { println(1/x64) }, "integer divide by zero")
+       }
+
+       check("nil-deref", func() { println(p[0]) }, "nil pointer dereference")
+       check("nil-deref-1", func() { println(p[1]) }, "nil pointer dereference")
+       check("nil-deref-big", func() { println(q[5000]) }, "nil pointer dereference")
+
+       i = 99999
+       var sl []int
+       check("array-bounds", func() { println(p[i]) }, "index out of range")
+       check("slice-bounds", func() { println(sl[i]) }, "index out of range")
+       
+       var inter interface{}
+       inter = 1
+       check("type-concrete", func() { println(inter.(string)) }, "int, not string")
+       check("type-interface", func() { println(inter.(m)) }, "missing method m")
+}
+
+type m interface{ m() }
diff --git a/gcc/testsuite/go.test/test/rename.go b/gcc/testsuite/go.test/test/rename.go
new file mode 100644 (file)
index 0000000..f21ef01
--- /dev/null
@@ -0,0 +1,73 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func main() {
+       n :=
+               bool +
+                       byte +
+                       float +
+                       float32 +
+                       float64 +
+                       int +
+                       int8 +
+                       int16 +
+                       int32 +
+                       int64 +
+                       uint +
+                       uint8 +
+                       uint16 +
+                       uint32 +
+                       uint64 +
+                       uintptr +
+                       true +
+                       false +
+                       iota +
+                       nil +
+                       cap +
+                       len +
+                       make +
+                       new +
+                       panic +
+                       print +
+                       println
+       if n != 27*28/2 {
+               fmt.Println("BUG: wrong n", n, 27*28/2)
+       }
+}
+
+const (
+       bool    = 1
+       byte    = 2
+       float   = 3
+       float32 = 4
+       float64 = 5
+       int     = 6
+       int8    = 7
+       int16   = 8
+       int32   = 9
+       int64   = 10
+       uint    = 11
+       uint8   = 12
+       uint16  = 13
+       uint32  = 14
+       uint64  = 15
+       uintptr = 16
+       true    = 17
+       false   = 18
+       iota    = 19
+       nil     = 20
+       cap     = 21
+       len     = 22
+       make    = 23
+       new     = 24
+       panic   = 25
+       print   = 26
+       println = 27
+)
diff --git a/gcc/testsuite/go.test/test/rename1.go b/gcc/testsuite/go.test/test/rename1.go
new file mode 100644 (file)
index 0000000..f239999
--- /dev/null
@@ -0,0 +1,46 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var n byte       // ERROR "not a type|expected type"
+       var y = float(0) // ERROR "cannot call|expected function"
+       const (
+               a = 1 + iota // ERROR "string|incompatible types"
+       )
+
+}
+
+const (
+       bool    = 1
+       byte    = 2
+       float   = 3
+       float32 = 4
+       float64 = 5
+       int     = 6
+       int8    = 7
+       int16   = 8
+       int32   = 9
+       int64   = 10
+       uint    = 11
+       uint8   = 12
+       uint16  = 13
+       uint32  = 14
+       uint64  = 15
+       uintptr = 16
+       true    = 17
+       false   = 18
+       iota    = "abc"
+       nil     = 20
+       cap     = 21
+       len     = 22
+       make    = 23
+       new     = 24
+       panic   = 25
+       print   = 26
+       println = 27
+)
diff --git a/gcc/testsuite/go.test/test/run b/gcc/testsuite/go.test/test/run
new file mode 100755 (executable)
index 0000000..4ca7754
--- /dev/null
@@ -0,0 +1,122 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+eval $(gomake --no-print-directory -f ../src/Make.inc go-env)
+
+case X"$GOARCH" in
+Xamd64)
+       export A=6
+       ;;
+X386)
+       export A=8
+       ;;
+Xarm)
+       export A=5
+       export E=${GORUN:-qemu-arm -cpu cortex-a8}
+       ;;
+*)
+       echo 1>&2 run: unsupported '$GOARCH'
+       exit 1
+esac
+
+case X"$GOOS" in
+Xnacl)
+       export E=${GORUN:-$GOROOT/misc/nacl/naclrun}
+esac
+
+export G=${A}g
+export L=${A}l
+export GOTRACEBACK=0
+export LANG=C
+unset GREP_OPTIONS     # in case user has a non-standard set
+
+failed=0
+
+PATH=/bin:/usr/bin:/usr/local/bin:${GOBIN:-$GOROOT/bin}:`pwd`
+
+RUNFILE=/tmp/gorun-$$-$USER
+TMP1FILE=/tmp/gotest1-$$-$USER
+TMP2FILE=/tmp/gotest2-$$-$USER
+
+# don't run the machine out of memory: limit individual processes to 4GB.
+# on thresher, 3GB suffices to run the tests; with 2GB, peano fails.
+ulimit -v 4000000
+
+# no core files please
+ulimit -c 0
+
+true >pass.out >times.out
+
+for dir in . ken chan interface nilptr syntax fixedbugs bugs
+do
+       echo
+       echo '==' $dir'/'
+       for i in $(ls $dir/*.go 2>/dev/null)
+       do
+               export F=$(basename $i .go)
+               export D=$dir
+               sed '/^\/\//!q' $i | sed 's@//@@; $d' |sed 's|./\$A.out|$E &|' >$RUNFILE
+               if ! { time -p bash -c "bash $RUNFILE >$TMP1FILE 2>&1" ; } 2>$TMP2FILE
+               then
+                       echo
+                       echo "===========" $i
+                       cat $TMP1FILE
+                       echo >&2 fail: $i
+                       echo "# $i      # fail" >>pass.out
+               elif test -s $TMP1FILE
+               then
+                       echo
+                       echo "===========" $i
+                       cat $TMP1FILE
+                       if grep -q '^BUG' $TMP1FILE
+                       then
+                               if [ $dir != bugs ]
+                               then
+                                       echo >&2 bug: $i
+                               fi
+                               echo "# $i      # fail, BUG" >>pass.out
+                       else
+                               echo $i >>pass.out
+                       fi
+               elif [ $dir = "bugs" ]
+               then
+                       echo $i succeeded with no output.
+               else
+                       echo $i >>pass.out
+               fi
+               echo $(awk 'NR==1{print $2}' $TMP2FILE) $D/$F >>times.out
+       done
+done | # clean up some stack noise
+       egrep -v '^(r[0-9a-z]+|[cfg]s)  +0x'  |
+       sed '/tmp.*Bus error/s/.*Bus/Bus/; /tmp.*Trace.BPT/s/.*Trace/Trace/
+               s!'$RUNFILE'!$RUNFILE!g
+               s/^PC=0x[0-9a-f]*/pc: xxx/
+               s/^pc: 0x[0-9a-f]*/pc: xxx/
+               s/PC=0x[0-9a-f]*/PC=xxx/
+               /^Trace\/breakpoint trap/d
+               /^Trace\/BPT trap/d
+               /RUNFILE/ s/line 1: *[0-9]*/line 1: PID/
+               /^\$RUNFILE: line 1: PID Trace\/breakpoint trap/d
+               /Segmentation fault/d
+               /^qemu: uncaught target signal 11 (Segmentation fault) - exiting/d' > run.out
+
+rm  -f $RUNFILE $TMP1FILE $TMP2FILE *.$A *.a $A.out
+diffmsg=""
+if ! diff golden.out run.out
+then
+       diffmsg="; test output differs"
+       failed=1
+fi
+
+notinbugs=$(sed '/^== bugs/q' run.out | grep -c '^BUG')
+inbugs=$(sed '1,/^== bugs/d' run.out | grep -c '^BUG')
+
+echo 2>&1 $inbugs known bugs';' $notinbugs unexpected bugs$diffmsg
+
+if [ "$failed" != "0" ]; then
+       echo FAILED
+fi
+
+exit $failed
diff --git a/gcc/testsuite/go.test/test/run-arm b/gcc/testsuite/go.test/test/run-arm
new file mode 100755 (executable)
index 0000000..a62df10
--- /dev/null
@@ -0,0 +1,102 @@
+#!/bin/sh
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+export E=""
+case X"$GOARCH" in
+Xamd64)
+       export A=6
+       ;;
+X386)
+       export A=8
+       ;;
+Xarm)
+       export A=5
+       export E="${GORUN:-qemu-arm -cpu cortex-a8}"
+       ;;
+*)
+       echo 1>&2 run: unsupported '$GOARCH'
+       exit 1
+esac
+
+export G=${A}g
+export L=${A}l
+export GOTRACEBACK=0
+
+PATH=/bin:/usr/bin:/usr/local/bin:${GOBIN:-$GOROOT/bin}:`pwd`
+
+RUNFILE=/tmp/gorun-$$-$USER
+TMP1FILE=/tmp/gotest1-$$-$USER
+TMP2FILE=/tmp/gotest2-$$-$USER
+FAILEDFILE=/tmp/gotest3-$$-$USER
+
+# don't run the machine out of memory: limit individual processes to 4GB.
+# on thresher, 3GB suffices to run the tests; with 2GB, peano fails.
+ulimit -v 4000000
+
+# no core files please
+ulimit -c 0
+
+true >times.out
+
+# TODO(kaib): figure out why the GC makes things so utterly slow.
+export GOGC=off
+export GOTRACEBACK=0
+
+for i in $(cat arm-pass.txt | sed 's/#.*//')
+do
+       export F=$(basename $i .go)
+       dir=$(dirname $i)
+       export D=$dir
+       sed '/^\/\//!q' $i | sed 's@//@@; $d' |sed 's|./\$A.out|$E &|' >$RUNFILE
+       if ! { time -p bash -c "bash $RUNFILE >$TMP1FILE 2>&1" ; } 2>$TMP2FILE
+       then
+               echo
+               echo "===========" $i
+               cat $TMP1FILE
+               echo >&2 fail: $i
+               touch $FAILEDFILE
+       elif test -s $TMP1FILE
+       then
+               echo
+               echo "===========" $i
+               cat $TMP1FILE
+       elif [ $dir = "bugs" ]
+       then
+               echo $i succeeded with no output.
+       fi
+       echo $(awk 'NR==1{print $2}' $TMP2FILE) $D/$F >>times.out
+done | # clean up some stack noise
+       egrep -v '^(r[0-9a-z]+|[cfg]s)  +0x'  |
+       sed '/tmp.*Bus error/s/.*Bus/Bus/; /tmp.*Trace.BPT/s/.*Trace/Trace/
+               s!'$RUNFILE'!$RUNFILE!g
+               s/ PC=0x[0-9a-f]*/ PC=xxx/
+               s/^pc: 0x[0-9a-f]*/pc: xxx/
+               /^Trace\/breakpoint trap/d
+               /^Trace\/BPT trap/d
+               s!'$GOROOT'!$GOROOT!g
+               /Segmentation fault/d
+               /RUNFILE/ s/line 1: *[0-9]*/line 1: PID/
+               /^\$RUNFILE: line 1: PID Trace\/breakpoint trap/d
+               /^qemu: uncaught target signal 11 (Segmentation fault) - exiting/d' > run.out
+
+failed=0
+rm  -f $RUNFILE $TMP1FILE $TMP2FILE *.$A $A.out
+diffmsg=""
+if ! diff -b golden-arm.out run.out
+then
+       diffmsg="; test output differs"
+       failed=1
+fi
+
+notinbugs=$(sed '/== bugs/q' run.out | grep -c '^BUG')
+inbugs=$(sed '1,/== bugs/d' run.out | grep -c '^BUG')
+
+echo 2>&1 $inbugs known bugs';' $notinbugs unexpected bugs$diffmsg
+
+if [ "$failed" != "0" ]; then
+       echo FAILED
+fi
+
+exit $failed
diff --git a/gcc/testsuite/go.test/test/runtime.go b/gcc/testsuite/go.test/test/runtime.go
new file mode 100644 (file)
index 0000000..4be1d05
--- /dev/null
@@ -0,0 +1,20 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// make sure that even if a file imports runtime,
+// it cannot get at the low-level runtime definitions
+// known to the compiler.  for normal packages
+// the compiler doesn't even record the lower case
+// functions in its symbol table, but some functions
+// in runtime are hard-coded into the compiler.
+
+package main
+
+import "runtime"
+
+func main() {
+       runtime.printbool(true) // ERROR "unexported"
+}
diff --git a/gcc/testsuite/go.test/test/sieve.go b/gcc/testsuite/go.test/test/sieve.go
new file mode 100644 (file)
index 0000000..4fa1115
--- /dev/null
@@ -0,0 +1,42 @@
+// $G $F.go && $L $F.$A  # don't run it - goes forever
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Send the sequence 2, 3, 4, ... to channel 'ch'.
+func Generate(ch chan<- int) {
+       for i := 2; ; i++ {
+               ch <- i // Send 'i' to channel 'ch'.
+       }
+}
+
+// Copy the values from channel 'in' to channel 'out',
+// removing those divisible by 'prime'.
+func Filter(in <-chan int, out chan<- int, prime int) {
+       for {
+               i := <-in // Receive value of new variable 'i' from 'in'.
+               if i%prime != 0 {
+                       out <- i // Send 'i' to channel 'out'.
+               }
+       }
+}
+
+// The prime sieve: Daisy-chain Filter processes together.
+func Sieve() {
+       ch := make(chan int) // Create a new channel.
+       go Generate(ch)      // Start Generate() as a subprocess.
+       for {
+               prime := <-ch
+               print(prime, "\n")
+               ch1 := make(chan int)
+               go Filter(ch, ch1, prime)
+               ch = ch1
+       }
+}
+
+func main() {
+       Sieve()
+}
diff --git a/gcc/testsuite/go.test/test/sigchld.go b/gcc/testsuite/go.test/test/sigchld.go
new file mode 100644 (file)
index 0000000..09188fc
--- /dev/null
@@ -0,0 +1,15 @@
+// if [ $GOOS == nacl ]; then echo survived SIGCHLD; exit 0; fi  # NaCl has no signals.
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "syscall"
+
+func main() {
+       syscall.Kill(syscall.Getpid(), syscall.SIGCHLD)
+       println("survived SIGCHLD")
+}
diff --git a/gcc/testsuite/go.test/test/simassign.go b/gcc/testsuite/go.test/test/simassign.go
new file mode 100644 (file)
index 0000000..28408ab
--- /dev/null
@@ -0,0 +1,77 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a, b, c, d, e, f, g, h, i int
+
+func printit() {
+       println(a, b, c, d, e, f, g, h, i)
+}
+
+func testit(permuteok bool) bool {
+       if a+b+c+d+e+f+g+h+i != 45 {
+               print("sum does not add to 45\n")
+               printit()
+               return false
+       }
+       return permuteok ||
+               a == 1 &&
+                       b == 2 &&
+                       c == 3 &&
+                       d == 4 &&
+                       e == 5 &&
+                       f == 6 &&
+                       g == 7 &&
+                       h == 8 &&
+                       i == 9
+}
+
+func swap(x, y int) (u, v int) {
+       return y, x
+}
+
+func main() {
+       a = 1
+       b = 2
+       c = 3
+       d = 4
+       e = 5
+       f = 6
+       g = 7
+       h = 8
+       i = 9
+
+       if !testit(false) {
+               panic("init val\n")
+       }
+
+       for z := 0; z < 100; z++ {
+               a, b, c, d, e, f, g, h, i = b, c, d, a, i, e, f, g, h
+
+               if !testit(z%20 != 19) {
+                       print("on ", z, "th iteration\n")
+                       printit()
+                       panic("fail")
+               }
+       }
+
+       if !testit(false) {
+               print("final val\n")
+               printit()
+               panic("fail")
+       }
+
+       a, b = swap(1, 2)
+       if a != 2 || b != 1 {
+               panic("bad swap")
+       }
+
+       a, b = swap(swap(a, b))
+       if a != 2 || b != 1 {
+               panic("bad swap")
+       }
+}
diff --git a/gcc/testsuite/go.test/test/sinit.go b/gcc/testsuite/go.test/test/sinit.go
new file mode 100644 (file)
index 0000000..2adb931
--- /dev/null
@@ -0,0 +1,100 @@
+// $G -S $D/$F.go | egrep initdone >/dev/null && echo FAIL || true
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+// Should be no init func in the assembly.
+// All these initializations should be done at link time.
+
+type   S       struct{ a,b,c int }
+type   SS      struct{ aa,bb,cc S }
+type   SA      struct{ a,b,c [3]int }
+type   SC      struct{ a,b,c []int }
+
+var (
+       zero = 2
+       one = 1
+       pi = 3.14
+       slice = []byte{1,2,3}
+       sliceInt = []int{1,2,3}
+       hello = "hello, world"
+       bytes = []byte("hello, world")
+       four, five = 4, 5
+       x, y = 0.1, "hello"
+       nilslice []byte = nil
+       nilmap map[string]int = nil
+       nilfunc func() = nil
+       nilchan chan int = nil
+       nilptr *byte = nil
+)
+
+var    a       = [3]int{1001, 1002, 1003}
+var    s       = S{1101, 1102, 1103}
+var    c       = []int{1201, 1202, 1203}
+
+var    aa      = [3][3]int{[3]int{2001,2002,2003}, [3]int{2004,2005,2006}, [3]int{2007,2008,2009}}
+var    as      = [3]S{S{2101,2102,2103},S{2104,2105,2106},S{2107,2108,2109}}
+var    ac      = [3][]int{[]int{2201,2202,2203}, []int{2204,2205,2206}, []int{2207,2208,2209}}
+
+var    sa      = SA{[3]int{3001,3002,3003},[3]int{3004,3005,3006},[3]int{3007,3008,3009}}
+var    ss      = SS{S{3101,3102,3103},S{3104,3105,3106},S{3107,3108,3109}}
+var    sc      = SC{[]int{3201,3202,3203},[]int{3204,3205,3206},[]int{3207,3208,3209}}
+
+var    ca      = [][3]int{[3]int{4001,4002,4003}, [3]int{4004,4005,4006}, [3]int{4007,4008,4009}}
+var    cs      = []S{S{4101,4102,4103},S{4104,4105,4106},S{4107,4108,4109}}
+var    cc      = [][]int{[]int{4201,4202,4203}, []int{4204,4205,4206}, []int{4207,4208,4209}}
+
+var    answers = [...]int {
+       // s
+       1101, 1102, 1103,
+
+       // ss
+       3101, 3102, 3103,
+       3104, 3105, 3106,
+       3107, 3108, 3109,
+
+       // [0]
+       1001, 1201, 1301,
+       2101, 2102, 2103,
+       4101, 4102, 4103,
+       5101, 5102, 5103,
+       3001, 3004, 3007,
+       3201, 3204, 3207,
+       3301, 3304, 3307,
+
+       // [0][j]
+       2001, 2201, 2301, 4001, 4201, 4301, 5001, 5201, 5301,
+       2002, 2202, 2302, 4002, 4202, 4302, 5002, 5202, 5302,
+       2003, 2203, 2303, 4003, 4203, 4303, 5003, 5203, 5303,
+
+       // [1]
+       1002, 1202, 1302,
+       2104, 2105, 2106,
+       4104, 4105, 4106,
+       5104, 5105, 5106,
+       3002, 3005, 3008,
+       3202, 3205, 3208,
+       3302, 3305, 3308,
+
+       // [1][j]
+       2004, 2204, 2304, 4004, 4204, 4304, 5004, 5204, 5304,
+       2005, 2205, 2305, 4005, 4205, 4305, 5005, 5205, 5305,
+       2006, 2206, 2306, 4006, 4206, 4306, 5006, 5206, 5306,
+
+       // [2]
+       1003, 1203, 1303,
+       2107, 2108, 2109,
+       4107, 4108, 4109,
+       5107, 5108, 5109,
+       3003, 3006, 3009,
+       3203, 3206, 3209,
+       3303, 3306, 3309,
+
+       // [2][j]
+       2007, 2207, 2307, 4007, 4207, 4307, 5007, 5207, 5307,
+       2008, 2208, 2308, 4008, 4208, 4308, 5008, 5208, 5308,
+       2009, 2209, 2309, 4009, 4209, 4309, 5009, 5209, 5309,
+}
diff --git a/gcc/testsuite/go.test/test/solitaire.go b/gcc/testsuite/go.test/test/solitaire.go
new file mode 100644 (file)
index 0000000..c789bf2
--- /dev/null
@@ -0,0 +1,119 @@
+// $G $F.go && $L $F.$A  # don't run it - produces too much output
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This program solves the (English) peg solitaire board game.
+// See also: http://en.wikipedia.org/wiki/Peg_solitaire
+
+package main
+
+const N = 11 + 1 // length of a board row (+1 for newline)
+
+// The board must be surrounded by 2 illegal fields in each direction
+// so that move() doesn't need to check the board boundaries. Periods
+// represent illegal fields, ● are pegs, and ○ are holes.
+var board = []int(
+       `...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`)
+
+
+// center is the position of the center hole if there is a single one;
+// otherwise it is -1.
+var center int
+
+func init() {
+       n := 0
+       for pos, field := range board {
+               if field == '○' {
+                       center = pos
+                       n++
+               }
+       }
+       if n != 1 {
+               center = -1 // no single hole
+       }
+}
+
+
+var moves int // number of times move is called
+
+// move tests if there is a peg at position pos that can jump over another peg
+// in direction dir. If the move is valid, it is executed and move returns true.
+// Otherwise, move returns false.
+func move(pos, dir int) bool {
+       moves++
+       if board[pos] == '●' && board[pos+dir] == '●' && board[pos+2*dir] == '○' {
+               board[pos] = '○'
+               board[pos+dir] = '○'
+               board[pos+2*dir] = '●'
+               return true
+       }
+       return false
+}
+
+
+// unmove reverts a previously executed valid move.
+func unmove(pos, dir int) {
+       board[pos] = '●'
+       board[pos+dir] = '●'
+       board[pos+2*dir] = '○'
+}
+
+
+// solve tries to find a sequence of moves such that there is only one peg left
+// at the end; if center is >= 0, that last peg must be in the center position.
+// If a solution is found, solve prints the board after each move in a backward
+// fashion (i.e., the last board position is printed first, all the way back to
+// the starting board position).
+func solve() bool {
+       var last, n int
+       for pos, field := range board {
+               // try each board position
+               if field == '●' {
+                       // found a peg
+                       for _, dir := range [...]int{-1, -N, +1, +N} {
+                               // try each direction
+                               if move(pos, dir) {
+                                       // a valid move was found and executed,
+                                       // see if this new board has a solution
+                                       if solve() {
+                                               unmove(pos, dir)
+                                               println(string(board))
+                                               return true
+                                       }
+                                       unmove(pos, dir)
+                               }
+                       }
+                       last = pos
+                       n++
+               }
+       }
+       // tried each possible move
+       if n == 1 && (center < 0 || last == center) {
+               // there's only one peg left
+               println(string(board))
+               return true
+       }
+       // no solution found for this board
+       return false
+}
+
+
+func main() {
+       if !solve() {
+               println("no solution found")
+       }
+       println(moves, "moves tried")
+}
diff --git a/gcc/testsuite/go.test/test/stack.go b/gcc/testsuite/go.test/test/stack.go
new file mode 100644 (file)
index 0000000..816b555
--- /dev/null
@@ -0,0 +1,72 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Try to tickle stack splitting bugs by doing
+// go, defer, and closure calls at different stack depths.
+
+package main
+
+type T [20]int
+
+func g(c chan int, t T) {
+       s := 0
+       for i := 0; i < len(t); i++ {
+               s += t[i]
+       }
+       c <- s
+}
+
+func d(t T) {
+       s := 0
+       for i := 0; i < len(t); i++ {
+               s += t[i]
+       }
+       if s != len(t) {
+               println("bad defer", s)
+               panic("fail")
+       }
+}
+
+var c = make(chan int)
+var t T
+var b = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+
+func recur(n int) {
+       ss := string(b)
+       if len(ss) != len(b) {
+               panic("bad []byte -> string")
+       }
+       go g(c, t)
+       s := <-c
+       if s != len(t) {
+               println("bad go", s)
+               panic("fail")
+       }
+       f := func(t T) int {
+               s := 0
+               for i := 0; i < len(t); i++ {
+                       s += t[i]
+               }
+               s += n
+               return s
+       }
+       s = f(t)
+       if s != len(t)+n {
+               println("bad func", s, "at level", n)
+               panic("fail")
+       }
+       if n > 0 {
+               recur(n - 1)
+       }
+       defer d(t)
+}
+
+func main() {
+       for i := 0; i < len(t); i++ {
+               t[i] = 1
+       }
+       recur(8000)
+}
diff --git a/gcc/testsuite/go.test/test/string_lit.go b/gcc/testsuite/go.test/test/string_lit.go
new file mode 100644 (file)
index 0000000..4358dd8
--- /dev/null
@@ -0,0 +1,120 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+var ecode int
+
+func assert(a, b, c string) {
+       if a != b {
+               ecode = 1
+               print("FAIL: ", c, ": ", a, "!=", b, "\n")
+               var max int = len(a)
+               if len(b) > max {
+                       max = len(b)
+               }
+               for i := 0; i < max; i++ {
+                       ac := 0
+                       bc := 0
+                       if i < len(a) {
+                               ac = int(a[i])
+                       }
+                       if i < len(b) {
+                               bc = int(b[i])
+                       }
+                       if ac != bc {
+                               print("\ta[", i, "] = ", ac, "; b[", i, "] =", bc, "\n")
+                       }
+               }
+       }
+}
+
+const (
+       gx1 = "aä本☺"
+       gx2 = "aä\xFF\xFF本☺"
+       gx2fix = "aä\uFFFD\uFFFD本☺"
+)
+
+var (
+       gr1 = []int(gx1)
+       gr2 = []int(gx2)
+       gb1 = []byte(gx1)
+       gb2 = []byte(gx2)
+)
+
+func main() {
+       ecode = 0
+       s :=
+               "" +
+                       " " +
+                       "'`" +
+                       "a" +
+                       "ä" +
+                       "本" +
+                       "\a\b\f\n\r\t\v\\\"" +
+                       "\000\123\x00\xca\xFE\u0123\ubabe\U0000babe" +
+
+                       `` +
+                       ` ` +
+                       `'"` +
+                       `a` +
+                       `ä` +
+                       `本` +
+                       `\a\b\f\n\r\t\v\\\'` +
+                       `\000\123\x00\xca\xFE\u0123\ubabe\U0000babe` +
+                       `\x\u\U\`
+
+       assert("", ``, "empty")
+       assert(" ", " ", "blank")
+       assert("\x61", "a", "lowercase a")
+       assert("\x61", `a`, "lowercase a (backquote)")
+       assert("\u00e4", "ä", "a umlaut")
+       assert("\u00e4", `ä`, "a umlaut (backquote)")
+       assert("\u672c", "本", "nihon")
+       assert("\u672c", `本`, "nihon (backquote)")
+       assert("\x07\x08\x0c\x0a\x0d\x09\x0b\x5c\x22",
+               "\a\b\f\n\r\t\v\\\"",
+               "backslashes")
+       assert("\\a\\b\\f\\n\\r\\t\\v\\\\\\\"",
+               `\a\b\f\n\r\t\v\\\"`,
+               "backslashes (backquote)")
+       assert("\x00\x53\000\xca\376S몾몾",
+               "\000\123\x00\312\xFE\u0053\ubabe\U0000babe",
+               "backslashes 2")
+       assert("\\000\\123\\x00\\312\\xFE\\u0123\\ubabe\\U0000babe",
+               `\000\123\x00\312\xFE\u0123\ubabe\U0000babe`,
+               "backslashes 2 (backquote)")
+       assert("\\x\\u\\U\\", `\x\u\U\`, "backslash 3 (backquote)")
+
+       // test large runes. perhaps not the most logical place for this test.
+       var r int32
+       r = 0x10ffff;   // largest rune value
+       s = string(r)
+       assert(s, "\xf4\x8f\xbf\xbf", "largest rune")
+       r = 0x10ffff + 1
+       s = string(r)
+       assert(s, "\xef\xbf\xbd", "too-large rune")
+
+       assert(string(gr1), gx1, "global ->[]int")
+       assert(string(gr2), gx2fix, "global invalid ->[]int")
+       assert(string(gb1), gx1, "->[]byte")
+       assert(string(gb2), gx2, "global invalid ->[]byte")
+
+       var (
+               r1 = []int(gx1)
+               r2 = []int(gx2)
+               b1 = []byte(gx1)
+               b2 = []byte(gx2)
+       )
+       assert(string(r1), gx1, "->[]int")
+       assert(string(r2), gx2fix, "invalid ->[]int")
+       assert(string(b1), gx1, "->[]byte")
+       assert(string(b2), gx2, "invalid ->[]byte")
+
+       os.Exit(ecode)
+}
diff --git a/gcc/testsuite/go.test/test/stringrange.go b/gcc/testsuite/go.test/test/stringrange.go
new file mode 100644 (file)
index 0000000..d5ada26
--- /dev/null
@@ -0,0 +1,61 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt"
+       "os"
+       "utf8"
+)
+
+func main() {
+       s := "\000\123\x00\xca\xFE\u0123\ubabe\U0000babe\U0010FFFFx"
+       expect := []int{ 0, 0123, 0, 0xFFFD, 0xFFFD, 0x123, 0xbabe, 0xbabe, 0x10FFFF, 'x' }
+       offset := 0
+       var i, c int
+       ok := true
+       cnum := 0
+       for i, c = range s {
+               rune, size := utf8.DecodeRuneInString(s[i:len(s)])  // check it another way
+               if i != offset {
+                       fmt.Printf("unexpected offset %d not %d\n", i, offset)
+                       ok = false
+               }
+               if rune != expect[cnum] {
+                       fmt.Printf("unexpected rune %d from DecodeRuneInString: %x not %x\n", i, rune, expect[cnum])
+                       ok = false
+               }
+               if c != expect[cnum] {
+                       fmt.Printf("unexpected rune %d from range: %x not %x\n", i, rune, expect[cnum])
+                       ok = false
+               }
+               offset += size
+               cnum++
+       }
+       if i != len(s)-1 {
+               fmt.Println("after loop i is", i, "not", len(s)-1)
+               ok = false
+       }
+
+       i = 12345
+       c = 23456
+       for i, c = range "" {
+       }
+       if i != 12345 {
+               fmt.Println("range empty string assigned to index:", i)
+               ok = false
+       }
+       if c != 23456 {
+               fmt.Println("range empty string assigned to value:", c)
+               ok = false
+       }
+
+       if !ok {
+               fmt.Println("BUG: stringrange")
+               os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/switch.go b/gcc/testsuite/go.test/test/switch.go
new file mode 100644 (file)
index 0000000..0c253d6
--- /dev/null
@@ -0,0 +1,139 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func assert(cond bool, msg string) {
+       if !cond {
+               print("assertion fail: ", msg, "\n")
+               panic(1)
+       }
+}
+
+func main() {
+       i5 := 5
+       i7 := 7
+       hello := "hello"
+
+       switch true {
+       case i5 < 5: assert(false, "<")
+       case i5 == 5: assert(true, "!")
+       case i5 > 5: assert(false, ">")
+       }
+
+       switch {
+       case i5 < 5: assert(false, "<")
+       case i5 == 5: assert(true, "!")
+       case i5 > 5: assert(false, ">")
+       }
+
+       switch x := 5; true {
+       case i5 < x: assert(false, "<")
+       case i5 == x: assert(true, "!")
+       case i5 > x: assert(false, ">")
+       }
+
+       switch x := 5; true {
+       case i5 < x: assert(false, "<")
+       case i5 == x: assert(true, "!")
+       case i5 > x: assert(false, ">")
+       }
+
+       switch i5 {
+       case 0: assert(false, "0")
+       case 1: assert(false, "1")
+       case 2: assert(false, "2")
+       case 3: assert(false, "3")
+       case 4: assert(false, "4")
+       case 5: assert(true, "5")
+       case 6: assert(false, "6")
+       case 7: assert(false, "7")
+       case 8: assert(false, "8")
+       case 9: assert(false, "9")
+       default: assert(false, "default")
+       }
+
+       switch i5 {
+       case 0,1,2,3,4: assert(false, "4")
+       case 5: assert(true, "5")
+       case 6,7,8,9: assert(false, "9")
+       default: assert(false, "default")
+       }
+
+       switch i5 {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4: assert(false, "4")
+       case 5: assert(true, "5")
+       case 6:
+       case 7:
+       case 8:
+       case 9:
+       default: assert(i5 == 5, "good")
+       }
+
+       switch i5 {
+       case 0: dummy := 0; _ = dummy; fallthrough
+       case 1: dummy := 0; _ = dummy; fallthrough
+       case 2: dummy := 0; _ = dummy; fallthrough
+       case 3: dummy := 0; _ = dummy; fallthrough
+       case 4: dummy := 0; _ = dummy; assert(false, "4")
+       case 5: dummy := 0; _ = dummy; fallthrough
+       case 6: dummy := 0; _ = dummy; fallthrough
+       case 7: dummy := 0; _ = dummy; fallthrough
+       case 8: dummy := 0; _ = dummy; fallthrough
+       case 9: dummy := 0; _ = dummy; fallthrough
+       default: dummy := 0; _ = dummy; assert(i5 == 5, "good")
+       }
+
+       fired := false
+       switch i5 {
+       case 0: dummy := 0; _ = dummy; fallthrough;  // tests scoping of cases
+       case 1: dummy := 0; _ = dummy; fallthrough
+       case 2: dummy := 0; _ = dummy; fallthrough
+       case 3: dummy := 0; _ = dummy; fallthrough
+       case 4: dummy := 0; _ = dummy; assert(false, "4")
+       case 5: dummy := 0; _ = dummy; fallthrough
+       case 6: dummy := 0; _ = dummy; fallthrough
+       case 7: dummy := 0; _ = dummy; fallthrough
+       case 8: dummy := 0; _ = dummy; fallthrough
+       case 9: dummy := 0; _ = dummy; fallthrough
+       default: dummy := 0; _ = dummy; fired = !fired; assert(i5 == 5, "good")
+       }
+       assert(fired, "fired")
+
+       count := 0
+       switch i5 {
+       case 0: count = count + 1; fallthrough
+       case 1: count = count + 1; fallthrough
+       case 2: count = count + 1; fallthrough
+       case 3: count = count + 1; fallthrough
+       case 4: count = count + 1; assert(false, "4")
+       case 5: count = count + 1; fallthrough
+       case 6: count = count + 1; fallthrough
+       case 7: count = count + 1; fallthrough
+       case 8: count = count + 1; fallthrough
+       case 9: count = count + 1; fallthrough
+       default: assert(i5 == count, "good")
+       }
+       assert(fired, "fired")
+
+       switch hello {
+       case "wowie": assert(false, "wowie")
+       case "hello": assert(true, "hello")
+       case "jumpn": assert(false, "jumpn")
+       default: assert(false, "default")
+       }
+
+       fired = false
+       switch i := i5 + 2; i {
+       case i7: fired = true
+       default: assert(false, "fail")
+       }
+       assert(fired, "var")
+}
diff --git a/gcc/testsuite/go.test/test/switch1.go b/gcc/testsuite/go.test/test/switch1.go
new file mode 100644 (file)
index 0000000..5bd9d7c
--- /dev/null
@@ -0,0 +1,20 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+       i := 0
+       switch x := 5; {
+               case i < x:
+                       os.Exit(0)
+               case i == x:
+               case i > x:
+                       os.Exit(1)
+       }
+}
diff --git a/gcc/testsuite/go.test/test/syntax/forvar.go b/gcc/testsuite/go.test/test/syntax/forvar.go
new file mode 100644 (file)
index 0000000..f12ce55
--- /dev/null
@@ -0,0 +1,10 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       for var x = 0; x < 10; x++ {    // ERROR "var declaration not allowed in for initializer"
diff --git a/gcc/testsuite/go.test/test/syntax/import.go b/gcc/testsuite/go.test/test/syntax/import.go
new file mode 100644 (file)
index 0000000..dd1f261
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "io",   // ERROR "unexpected comma"
+       "os"
+)
+
+
diff --git a/gcc/testsuite/go.test/test/syntax/interface.go b/gcc/testsuite/go.test/test/syntax/interface.go
new file mode 100644 (file)
index 0000000..a7f4353
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T interface {
+       f, g () // ERROR "name list not allowed in interface type"
+}
+
+
+
diff --git a/gcc/testsuite/go.test/test/syntax/semi1.go b/gcc/testsuite/go.test/test/syntax/semi1.go
new file mode 100644 (file)
index 0000000..547d9bf
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       if x; y         // ERROR "unexpected semicolon or newline before .?{.?|undefined"
+       {
+               z       // GCCGO_ERROR "undefined"
+
+
diff --git a/gcc/testsuite/go.test/test/syntax/semi2.go b/gcc/testsuite/go.test/test/syntax/semi2.go
new file mode 100644 (file)
index 0000000..28d1d39
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       switch x; y     // ERROR "unexpected semicolon or newline before .?{.?|undefined"
+       {
+               z
+
+
diff --git a/gcc/testsuite/go.test/test/syntax/semi3.go b/gcc/testsuite/go.test/test/syntax/semi3.go
new file mode 100644 (file)
index 0000000..ab5941b
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       for x; y; z     // ERROR "unexpected semicolon or newline before .?{.?|undefined"
+       {
+               z       // GCCGO_ERROR "undefined"
+
+
diff --git a/gcc/testsuite/go.test/test/syntax/semi4.go b/gcc/testsuite/go.test/test/syntax/semi4.go
new file mode 100644 (file)
index 0000000..7a9c295
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       for x           // GCCGO_ERROR "undefined"
+       {               // ERROR "unexpected semicolon or newline before .?{.?"
+               z       // GCCGO_ERROR "undefined"
+
+
diff --git a/gcc/testsuite/go.test/test/syntax/semi5.go b/gcc/testsuite/go.test/test/syntax/semi5.go
new file mode 100644 (file)
index 0000000..5f8ccc6
--- /dev/null
@@ -0,0 +1,13 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main()
+{      // ERROR "unexpected semicolon or newline before .?{.?"
+
+
+
diff --git a/gcc/testsuite/go.test/test/syntax/semi6.go b/gcc/testsuite/go.test/test/syntax/semi6.go
new file mode 100644 (file)
index 0000000..b6279ed
--- /dev/null
@@ -0,0 +1,13 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T // ERROR "unexpected semicolon or newline in type declaration"
+{
+
+
+
diff --git a/gcc/testsuite/go.test/test/syntax/semi7.go b/gcc/testsuite/go.test/test/syntax/semi7.go
new file mode 100644 (file)
index 0000000..5a7b3ff
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       if x { }        // GCCGO_ERROR "undefined"
+       else { }        // ERROR "unexpected semicolon or newline before .?else.?"
+}
+
+
diff --git a/gcc/testsuite/go.test/test/syntax/topexpr.go b/gcc/testsuite/go.test/test/syntax/topexpr.go
new file mode 100644 (file)
index 0000000..93d86fb
--- /dev/null
@@ -0,0 +1,20 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+fmt.Printf("hello")    // ERROR "non-declaration statement outside function body|expected declaration"
+
+func main() {
+}
+
+x++    // ERROR "non-declaration statement outside function body|expected declaration"
+
+func init() {
+}
+
+x,y := 1, 2    // ERROR "non-declaration statement outside function body|expected declaration"
+
diff --git a/gcc/testsuite/go.test/test/syntax/vareq.go b/gcc/testsuite/go.test/test/syntax/vareq.go
new file mode 100644 (file)
index 0000000..8525be8
--- /dev/null
@@ -0,0 +1,10 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var x map[string]string{"a":"b"}                // ERROR "unexpected { at end of statement|expected ';' or '}' or newline"
diff --git a/gcc/testsuite/go.test/test/syntax/vareq1.go b/gcc/testsuite/go.test/test/syntax/vareq1.go
new file mode 100644 (file)
index 0000000..9d70bea
--- /dev/null
@@ -0,0 +1,10 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var x map[string]string{"a":"b"}               // ERROR "unexpected { at end of statement|expected ';' or newline after top level declaration"
+
diff --git a/gcc/testsuite/go.test/test/test0.go b/gcc/testsuite/go.test/test/test0.go
new file mode 100644 (file)
index 0000000..dd2033a
--- /dev/null
@@ -0,0 +1,86 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const
+       a_const = 0
+
+const (
+       pi = /* the usual */ 3.14159265358979323
+       e = 2.718281828
+       mask1 int = 1 << iota
+       mask2 = 1 << iota
+       mask3 = 1 << iota
+       mask4 = 1 << iota
+)
+
+type (
+       Empty interface {}
+       Point struct {
+               x, y int
+       }
+       Point2 Point
+)
+
+func (p *Point) Initialize(x, y int) *Point {
+       p.x, p.y = x, y
+       return p
+}
+
+func (p *Point) Distance() int {
+       return p.x * p.x + p.y * p.y
+}
+
+var (
+       x1 int
+       x2 int
+       u, v, w float
+)
+
+func foo() {}
+
+func min(x, y int) int {
+       if x < y { return x; }
+       return y
+}
+
+func swap(x, y int) (u, v int) {
+       u = y
+       v = x
+       return
+}
+
+func control_structs() {
+       var p *Point = new(Point).Initialize(2, 3)
+       i := p.Distance()
+       var f float = 0.3
+       _ = f
+       for {}
+       for {}
+       for j := 0; j < i; j++ {
+               if i == 0 {
+               } else i = 0
+               var x float
+               _ = x
+       }
+       foo:    // a label
+       var j int
+       switch y := 0; true {
+       case i < y:
+               fallthrough
+       case i < j:
+       case i == 0, i == 1, i == j:
+               i++; i++
+               goto foo
+       default:
+               i = -+-+i
+               break
+       }
+}
+
+func main() {
+}
diff --git a/gcc/testsuite/go.test/test/turing.go b/gcc/testsuite/go.test/test/turing.go
new file mode 100644 (file)
index 0000000..0af39de
--- /dev/null
@@ -0,0 +1,52 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// brainfuck
+
+var p, pc int
+var a [30000]byte
+const prog = "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.!"
+
+func scan(dir int) {
+       for nest := dir; dir*nest > 0; pc += dir {
+               switch prog[pc+dir] {
+                       case ']':
+                               nest--
+                       case '[':
+                               nest++
+               }
+       }
+}
+
+func main() {
+       for {
+               switch prog[pc] {
+                       case '>':
+                                       p++
+                       case '<':
+                                       p--
+                       case '+':
+                                       a[p]++
+                       case '-':
+                                       a[p]--
+                       case '.':
+                                       print(string(a[p]))
+                       case '[':
+                               if a[p] == 0 {
+                                       scan(1)
+                               }
+                       case ']':
+                               if a[p] != 0 {
+                                       scan(-1)
+                               }
+                       default:
+                                       return
+               }
+               pc++
+       }
+}
diff --git a/gcc/testsuite/go.test/test/typeswitch.go b/gcc/testsuite/go.test/test/typeswitch.go
new file mode 100644 (file)
index 0000000..9e6d10e
--- /dev/null
@@ -0,0 +1,112 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+const (
+       Bool = iota
+       Int
+       Float
+       String
+       Struct
+       Chan
+       Array
+       Map
+       Func
+       Last
+)
+
+type S struct { a int }
+var s S = S{1234}
+
+var c = make(chan int)
+
+var a  = []int{0,1,2,3}
+
+var m = make(map[string]int)
+
+func assert(b bool, s string) {
+       if !b {
+               println(s)
+               os.Exit(1)
+       }
+}
+
+func f(i int) interface{} {
+       switch i {
+       case Bool:
+               return true
+       case Int:
+               return 7
+       case Float:
+               return 7.4
+       case String:
+               return "hello"
+       case Struct:
+               return s
+       case Chan:
+               return c
+       case Array:
+               return a
+       case Map:
+               return m
+       case Func:
+               return f
+       }
+       panic("bad type number")
+}
+
+func main() {
+       for i := Bool; i < Last; i++ {
+               switch x := f(i).(type) {
+               case bool:
+                       assert(x == true && i == Bool, "bool")
+               case int:
+                       assert(x == 7 && i == Int, "int")
+               case float:
+                       assert(x == 7.4 && i == Float, "float")
+               case string:
+                       assert(x == "hello"&& i == String, "string")
+               case S:
+                       assert(x.a == 1234 && i == Struct, "struct")
+               case chan int:
+                       assert(x == c && i == Chan, "chan")
+               case []int:
+                       assert(x[3] == 3 && i == Array, "array")
+               case map[string]int:
+                       assert(x == m && i == Map, "map")
+               case func(i int) interface{}:
+                       assert(x == f && i == Func, "fun")
+               default:
+                       assert(false, "unknown")
+               }
+       }
+
+       // boolean switch (has had bugs in past; worth writing down)
+       switch {
+       case true:
+               assert(true, "switch 2 bool")
+       default:
+               assert(false, "switch 2 unknown")
+       }
+
+       switch true {
+       case true:
+               assert(true, "switch 3 bool")
+       default:
+               assert(false, "switch 3 unknown")
+       }
+
+       switch false {
+       case false:
+               assert(true, "switch 4 bool")
+       default:
+               assert(false, "switch 4 unknown")
+       }
+
+}
diff --git a/gcc/testsuite/go.test/test/typeswitch1.go b/gcc/testsuite/go.test/test/typeswitch1.go
new file mode 100644 (file)
index 0000000..9613b16
--- /dev/null
@@ -0,0 +1,83 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+const (
+       a = iota
+       b
+       c
+       d
+       e
+)
+
+var x = []int{1, 2, 3}
+
+func f(x int, len *byte) {
+       *len = byte(x)
+}
+
+func whatis(x interface{}) string {
+       switch xx := x.(type) {
+       default:
+               return fmt.Sprint("default ", xx)
+       case int, int8, int16, int32:
+               return fmt.Sprint("signed ", xx)
+       case int64:
+               return fmt.Sprint("signed64 ", int64(xx))
+       case uint, uint8, uint16, uint32:
+               return fmt.Sprint("unsigned ", xx)
+       case uint64:
+               return fmt.Sprint("unsigned64 ", uint64(xx))
+       case nil:
+               return fmt.Sprint("nil ", xx)
+       }
+       panic("not reached")
+}
+
+func whatis1(x interface{}) string {
+       xx := x
+       switch xx.(type) {
+       default:
+               return fmt.Sprint("default ", xx)
+       case int, int8, int16, int32:
+               return fmt.Sprint("signed ", xx)
+       case int64:
+               return fmt.Sprint("signed64 ", xx.(int64))
+       case uint, uint8, uint16, uint32:
+               return fmt.Sprint("unsigned ", xx)
+       case uint64:
+               return fmt.Sprint("unsigned64 ", xx.(uint64))
+       case nil:
+               return fmt.Sprint("nil ", xx)
+       }
+       panic("not reached")
+}
+
+func check(x interface{}, s string) {
+       w := whatis(x)
+       if w != s {
+               fmt.Println("whatis", x, "=>", w, "!=", s)
+               panic("fail")
+       }
+
+       w = whatis1(x)
+       if w != s {
+               fmt.Println("whatis1", x, "=>", w, "!=", s)
+               panic("fail")
+       }
+}
+
+func main() {
+       check(1, "signed 1")
+       check(uint(1), "unsigned 1")
+       check(int64(1), "signed64 1")
+       check(uint64(1), "unsigned64 1")
+       check(1.5, "default 1.5")
+       check(nil, "nil <nil>")
+}
diff --git a/gcc/testsuite/go.test/test/typeswitch2.go b/gcc/testsuite/go.test/test/typeswitch2.go
new file mode 100644 (file)
index 0000000..f8fe396
--- /dev/null
@@ -0,0 +1,28 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "io"
+
+func whatis(x interface{}) string {
+       switch x.(type) {
+       case int:
+               return "int"
+       case int: // ERROR "duplicate"
+               return "int8"
+       case io.Reader:
+               return "Reader1"
+       case io.Reader: // ERROR "duplicate"
+               return "Reader2"
+       case interface { r(); w() }:
+               return "rw"
+       case interface { w(); r() }:    // ERROR "duplicate"
+               return "wr"
+       
+       }
+       return ""
+}
diff --git a/gcc/testsuite/go.test/test/undef.go b/gcc/testsuite/go.test/test/undef.go
new file mode 100644 (file)
index 0000000..7ef0788
--- /dev/null
@@ -0,0 +1,44 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check line numbers in error messages.
+
+package main
+
+var (
+       _ = x   // ERROR "undefined.*x"
+       _ = x   // ERROR "undefined.*x"
+       _ = x   // ERROR "undefined.*x"
+)
+
+type T struct {
+       y int
+}
+
+func foo() *T { return &T{y: 99} }
+func bar() int { return y }    // ERROR "undefined.*y"
+
+type T1 struct {
+       y1 int
+}
+
+func foo1() *T1 { return &T1{y1: 99} }
+var y1 = 2
+func bar1() int { return y1 }
+
+func f1(val interface{}) {
+       switch v := val.(type) {
+       default:
+               println(v)
+       }
+}
+
+func f2(val interface{}) {
+       switch val.(type) {
+       default:
+               println(v)      // ERROR "undefined.*v"
+       }
+}
diff --git a/gcc/testsuite/go.test/test/utf.go b/gcc/testsuite/go.test/test/utf.go
new file mode 100644 (file)
index 0000000..a93fc29
--- /dev/null
@@ -0,0 +1,54 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "utf8"
+
+func main() {
+       var chars [6] int
+       chars[0] = 'a'
+       chars[1] = 'b'
+       chars[2] = 'c'
+       chars[3] = '\u65e5'
+       chars[4] = '\u672c'
+       chars[5] = '\u8a9e'
+       s := ""
+       for i := 0; i < 6; i++ {
+               s += string(chars[i])
+       }
+       var l = len(s)
+       for w, i, j := 0,0,0; i < l; i += w {
+               var r int
+               r, w = utf8.DecodeRuneInString(s[i:len(s)])
+               if w == 0 { panic("zero width in string") }
+               if r != chars[j] { panic("wrong value from string") }
+               j++
+       }
+       // encoded as bytes:  'a' 'b' 'c' e6 97 a5 e6 9c ac e8 aa 9e
+       const L = 12
+       if L != l { panic("wrong length constructing array") }
+       a := make([]byte, L)
+       a[0] = 'a'
+       a[1] = 'b'
+       a[2] = 'c'
+       a[3] = 0xe6
+       a[4] = 0x97
+       a[5] = 0xa5
+       a[6] = 0xe6
+       a[7] = 0x9c
+       a[8] = 0xac
+       a[9] = 0xe8
+       a[10] = 0xaa
+       a[11] = 0x9e
+       for w, i, j := 0,0,0; i < L; i += w {
+               var r int
+               r, w = utf8.DecodeRune(a[i:L])
+               if w == 0 { panic("zero width in bytes") }
+               if r != chars[j] { panic("wrong value from bytes") }
+               j++
+       }
+}
diff --git a/gcc/testsuite/go.test/test/varerr.go b/gcc/testsuite/go.test/test/varerr.go
new file mode 100644 (file)
index 0000000..ddd718f
--- /dev/null
@@ -0,0 +1,14 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       _ = asdf        // ERROR "undefined.*asdf"
+
+       new = 1 // ERROR "use of builtin new not in function call|invalid left hand side"
+}
+
diff --git a/gcc/testsuite/go.test/test/varinit.go b/gcc/testsuite/go.test/test/varinit.go
new file mode 100644 (file)
index 0000000..c768777
--- /dev/null
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG wrong result
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       var x int = 1
+       if x != 1 {
+               print("found ", x, ", expected 1\n")
+               panic("fail")
+       }
+       {
+               var x int = x + 1
+               if x != 2 {
+                       print("found ", x, ", expected 2\n")
+                       panic("fail")
+               }
+       }
+       {
+               x := x + 1
+               if x != 2 {
+                       print("found ", x, ", expected 2\n")
+                       panic("fail")
+               }
+       }
+}
diff --git a/gcc/testsuite/go.test/test/vectors.go b/gcc/testsuite/go.test/test/vectors.go
new file mode 100644 (file)
index 0000000..ed5905d
--- /dev/null
@@ -0,0 +1,64 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "container/vector"
+
+
+type S struct {
+       val int
+}
+
+
+func (p *S) Init(val int) *S {
+       p.val = val
+       return p
+}
+
+
+func test0() {
+       v := new(vector.Vector)
+       if v.Len() != 0 {
+               print("len = ", v.Len(), "\n")
+               panic("fail")
+       }
+}
+
+
+func test1() {
+       var a [1000]*S
+       for i := 0; i < len(a); i++ {
+               a[i] = new(S).Init(i)
+       }
+
+       v := new(vector.Vector)
+       for i := 0; i < len(a); i++ {
+               v.Insert(0, a[i])
+               if v.Len() != i+1 {
+                       print("len = ", v.Len(), "\n")
+                       panic("fail")
+               }
+       }
+
+       for i := 0; i < v.Len(); i++ {
+               x := v.At(i).(*S)
+               if x.val != v.Len()-i-1 {
+                       print("expected ", i, ", found ", x.val, "\n")
+                       panic("fail")
+               }
+       }
+
+       for v.Len() > 10 {
+               v.Delete(10)
+       }
+}
+
+
+func main() {
+       test0()
+       test1()
+}
diff --git a/gcc/testsuite/go.test/test/zerodivide.go b/gcc/testsuite/go.test/test/zerodivide.go
new file mode 100644 (file)
index 0000000..5fe1eb0
--- /dev/null
@@ -0,0 +1,208 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt"
+       "math"
+       "strings"
+       "syscall"
+)
+
+type Error interface {
+       String() string
+}
+
+type ErrorTest struct {
+       name    string
+       fn      func()
+       err     string
+}
+
+var (
+       i, j, k int = 0, 0, 1
+       i8, j8, k8 int8 = 0, 0, 1
+       i16, j16, k16 int16 = 0, 0, 1
+       i32, j32, k32 int32 = 0, 0, 1
+       i64, j64, k64 int64 = 0, 0, 1
+
+       u, v, w uint = 0, 0, 1
+       u8, v8, w8 uint8 = 0, 0, 1
+       u16, v16, w16 uint16 = 0, 0, 1
+       u32, v32, w32 uint32 = 0, 0, 1
+       u64, v64, w64 uint64 = 0, 0, 1
+       up, vp, wp uintptr = 0, 0, 1
+
+       f, g, h float = 0, 0, 1
+       f32, g32, h32 float32 = 0, 0, 1
+       f64, g64, h64, inf, negInf, nan float64 = 0, 0, 1, math.Inf(1), math.Inf(-1), math.NaN()
+
+       c, d, e complex = 0+0i, 0+0i, 1+1i
+       c64, d64, e64 complex64 = 0+0i, 0+0i, 1+1i
+       c128, d128, e128 complex128 = 0+0i, 0+0i, 1+1i
+)
+
+// Fool gccgo into thinking that these variables can change.
+func NotCalled() {
+       i++; j++; k++
+       i8++; j8++; k8++
+       i16++; j16++; k16++
+       i32++; j32++; k32++
+       i64++; j64++; k64++
+
+       u++; v++; w++
+       u8++; v8++; w8++
+       u16++; v16++; w16++
+       u32++; v32++; w32++
+       u64++; v64++; w64++
+       up++; vp++; wp++
+
+       f += 1; g += 1; h += 1
+       f32 += 1; g32 += 1; h32 += 1
+       f64 += 1; g64 += 1; h64 += 1
+
+       c += 1+1i; d += 1+1i; e += 1+1i
+       c64 += 1+1i; d64 += 1+1i; e64 += 1+1i
+       c128 += 1+1i; d128 += 1+1i; e128 += 1+1i
+}
+
+var tmp interface{}
+
+// We could assign to _ but the compiler optimizes it too easily.
+func use(v interface{}) {
+       tmp = v
+}
+
+// Verify error/no error for all types.
+var errorTests = []ErrorTest{
+       // All integer divide by zero should error.
+       ErrorTest{ "int 0/0", func() { use(i/j) }, "divide", },
+       ErrorTest{ "int8 0/0", func() { use(i8/j8) }, "divide", },
+       ErrorTest{ "int16 0/0", func() { use(i16/j16) }, "divide", },
+       ErrorTest{ "int32 0/0", func() { use(i32/j32) }, "divide", },
+       ErrorTest{ "int64 0/0", func() { use(i64/j64) }, "divide", },
+
+       ErrorTest{ "int 1/0", func() { use(k/j) }, "divide", },
+       ErrorTest{ "int8 1/0", func() { use(k8/j8) }, "divide", },
+       ErrorTest{ "int16 1/0", func() { use(k16/j16) }, "divide", },
+       ErrorTest{ "int32 1/0", func() { use(k32/j32) }, "divide", },
+       ErrorTest{ "int64 1/0", func() { use(k64/j64) }, "divide", },
+
+       ErrorTest{ "uint 0/0", func() { use(u/v) }, "divide", },
+       ErrorTest{ "uint8 0/0", func() { use(u8/v8) }, "divide", },
+       ErrorTest{ "uint16 0/0", func() { use(u16/v16) }, "divide", },
+       ErrorTest{ "uint32 0/0", func() { use(u32/v32) }, "divide", },
+       ErrorTest{ "uint64 0/0", func() { use(u64/v64) }, "divide", },
+       ErrorTest{ "uintptr 0/0", func() { use(up/vp) }, "divide", },
+
+       ErrorTest{ "uint 1/0", func() { use(w/v) }, "divide", },
+       ErrorTest{ "uint8 1/0", func() { use(w8/v8) }, "divide", },
+       ErrorTest{ "uint16 1/0", func() { use(w16/v16) }, "divide", },
+       ErrorTest{ "uint32 1/0", func() { use(w32/v32) }, "divide", },
+       ErrorTest{ "uint64 1/0", func() { use(w64/v64) }, "divide", },
+       ErrorTest{ "uintptr 1/0", func() { use(wp/vp) }, "divide", },
+
+       // All floating divide by zero should not error.
+       ErrorTest{ "float 0/0", func() { use(f/g) }, "", },
+       ErrorTest{ "float32 0/0", func() { use(f32/g32) }, "", },
+       ErrorTest{ "float64 0/0", func() { use(f64/g64) }, "", },
+
+       ErrorTest{ "float 1/0", func() { use(h/g) }, "", },
+       ErrorTest{ "float32 1/0", func() { use(h32/g32) }, "", },
+       ErrorTest{ "float64 1/0", func() { use(h64/g64) }, "", },
+       ErrorTest{ "float64 inf/0", func() { use(inf/g64) }, "", },
+       ErrorTest{ "float64 -inf/0", func() { use(negInf/g64) }, "", },
+       ErrorTest{ "float64 nan/0", func() { use(nan/g64) }, "", },
+
+       // All complex divide by zero should not error.
+       ErrorTest{ "complex 0/0", func() { use(c/d) }, "", },
+       ErrorTest{ "complex64 0/0", func() { use(c64/d64) }, "", },
+       ErrorTest{ "complex128 0/0", func() { use(c128/d128) }, "", },
+
+       ErrorTest{ "complex 1/0", func() { use(e/d) }, "", },
+       ErrorTest{ "complex64 1/0", func() { use(e64/d64) }, "", },
+       ErrorTest{ "complex128 1/0", func() { use(e128/d128) }, "", },
+}
+
+func error(fn func()) (error string) {
+       defer func() {
+               if e := recover(); e != nil {
+                       error = e.(Error).String()
+               }
+       }()
+       fn()
+       return ""
+}
+
+type FloatTest struct{
+       f, g    float64
+       out     float64
+}
+
+var floatTests = []FloatTest{
+       FloatTest{0, 0, nan},
+       FloatTest{nan, 0, nan},
+       FloatTest{inf, 0, inf},
+       FloatTest{negInf, 0, negInf},
+}
+
+func alike(a, b float64) bool {
+       switch {
+       case math.IsNaN(a) && math.IsNaN(b):
+               return true
+       case a == b:
+               return math.Signbit(a) == math.Signbit(b)
+       }
+       return false
+}
+
+func main() {
+       bad := false
+       for _, t := range errorTests {
+               if t.err != "" && syscall.OS == "nacl" {
+                       continue
+               }
+               err := error(t.fn)
+               switch {
+               case t.err == "" && err == "":
+                       // fine
+               case t.err != "" && err == "":
+                       if !bad {
+                               bad = true
+                               fmt.Printf("BUG\n")
+                       }
+                       fmt.Printf("%s: expected %q; got no error\n", t.name, t.err)
+               case t.err == "" && err != "":
+                       if !bad {
+                               bad = true
+                               fmt.Printf("BUG\n")
+                       }
+                       fmt.Printf("%s: expected no error; got %q\n", t.name, err)
+               case t.err != "" && err != "":
+                       if strings.Index(err, t.err) < 0 {
+                               if !bad {
+                                       bad = true
+                                       fmt.Printf("BUG\n")
+                               }
+                               fmt.Printf("%s: expected %q; got %q\n", t.name, t.err, err)
+                               continue
+                       }
+               }
+       }
+
+       // At this point we know we don't error on the values we're testing
+       for _, t := range floatTests {
+               x := t.f/t.g
+               if !alike(x, t.out) {
+                       if !bad {
+                               bad = true
+                               fmt.Printf("BUG\n")
+                       }
+                       fmt.Printf("%v/%v: expected %g error; got %g\n", t.f, t.g, t.out, x)
+               }
+       }
+}
diff --git a/gcc/testsuite/lib/go-dg.exp b/gcc/testsuite/lib/go-dg.exp
new file mode 100644 (file)
index 0000000..16bf12d
--- /dev/null
@@ -0,0 +1,65 @@
+#   Copyright (C) 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib gcc-dg.exp
+
+# Define go callbacks for dg.exp.
+
+proc go-dg-test { prog do_what extra_tool_flags } {
+    set result \
+       [gcc-dg-test-1 go_target_compile $prog $do_what $extra_tool_flags]
+    
+    set comp_output [lindex $result 0]
+    set output_file [lindex $result 1]
+
+    return [list $comp_output $output_file]
+}
+
+proc go-dg-prune { system text } {
+    return [gcc-dg-prune $system $text]
+}
+
+# Utility routines.
+
+# Modified dg-runtest that can cycle through a list of optimization options
+# as c-torture does.
+proc go-dg-runtest { testcases default-extra-flags } {
+    global runtests
+    global TORTURE_OPTIONS
+
+    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 if this is dg-do-run test, in which case
+       # we cycle through the option list, otherwise we don't
+       if [expr [search_for $test "dg-do run"]] {
+           set option_list $TORTURE_OPTIONS
+       } else {
+           set option_list [list { -O } ]
+       }
+
+       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}
+       }
+    }
+}
diff --git a/gcc/testsuite/lib/go-torture.exp b/gcc/testsuite/lib/go-torture.exp
new file mode 100644 (file)
index 0000000..8c4be20
--- /dev/null
@@ -0,0 +1,369 @@
+# Copyright (C) 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to
+# the author.
+
+# This file was written by Ian Lance Taylor <iant@google.com> based on
+# fortran-torture.exp by Steven Bosscher and Rob Savoye.
+
+load_lib target-supports.exp
+
+# The default option list can be overridden by
+# TORTURE_OPTIONS="{ { list1 } ... { listN } }"
+
+if ![info exists TORTURE_OPTIONS] {
+    set TORTURE_OPTIONS [list \
+       { -O0 } { -O1 } { -O2 } \
+       { -O2 -fomit-frame-pointer -finline-functions } \
+       { -O2 -fomit-frame-pointer -finline-functions -funroll-loops } \
+       { -O2 -fbounds-check } \
+       { -O3 -g } \
+       { -Os }]
+}
+
+
+#
+# go-torture-compile -- compile a go.go-torture testcase.
+#
+# SRC is the full pathname of the testcase.
+# OPTION is the specific compiler flag we're testing (eg: -O2).
+#
+proc go-torture-compile { src option } {
+    global output
+    global srcdir tmpdir
+    global host_triplet
+
+    set output "$tmpdir/[file tail [file rootname $src]].o"
+
+    regsub "(?q)$srcdir/" $src "" testcase
+
+    # If we couldn't rip $srcdir out of `src' then just do the best we can.
+    # The point is to reduce the unnecessary noise in the logs.  Don't strip
+    # out too much because different testcases with the same name can confuse
+    # `test-tool'.
+    if [string match "/*" $testcase] {
+       set testcase "[file tail [file dirname $src]]/[file tail $src]"
+    }
+
+    verbose "Testing $testcase, $option" 1
+
+    # Run the compiler and get results in comp_output.
+    set options ""
+    lappend options "additional_flags=-w $option"
+
+    set comp_output [go_target_compile "$src" "$output" object $options]
+    
+    # See if we got something bad.
+    set fatal_signal "*go*: Internal compiler error: program*got fatal signal"
+    if [string match "$fatal_signal 6" $comp_output] then {
+       go_fail $testcase "Got Signal 6, $option"
+       catch { remote_file build delete $output }
+       return
+    }
+
+    if [string match "$fatal_signal 11" $comp_output] then {
+       go_fail $testcase "Got Signal 11, $option"
+       catch { remote_file build delete $output }
+       return
+    }
+
+    if [string match "*internal compiler error*" $comp_output] then {
+       go_fail $testcase "$option (internal compiler error)"
+       catch { remote_file build delete $output }
+       return
+    }
+
+    # We shouldn't get these because of -w, but just in case.
+    if [string match "*go*:*warning:*" $comp_output] then {
+       warning "$testcase: (with warnings) $option"
+       send_log "$comp_output\n"
+       unresolved "$testcase, $option"
+       catch { remote_file build delete $output }
+       return
+    }
+
+    # Prune warnings we know are unwanted.
+    set comp_output [prune_warnings $comp_output]
+
+    # Report if the testcase is not supported.
+    set unsupported_message [go_check_unsupported_p $comp_output]
+    if { $unsupported_message != "" } {
+       unsupported "$testcase: $unsupported_message"
+       catch { remote_file build delete $output }
+       return
+    }
+
+    # remove any leftover LF/CR to make sure any output is legit
+    regsub -all -- "\[\r\n\]*" $comp_output "" comp_output
+
+    # If any message remains, we fail.
+    if ![string match "" $comp_output] then {
+       go_fail $testcase $option
+       catch { remote_file build delete $output }
+       return
+    }
+
+    go_pass $testcase $option
+    catch { remote_file build delete $output }
+}
+
+
+#
+# go-torture-execute -- compile and execute a testcase.
+#
+# SRC is the full pathname of the testcase.
+#
+# If the testcase has an associated .x file, we source that to run the
+# test instead.  We use .x so that we don't lengthen the existing filename
+# to more than 14 chars.
+#
+proc go-torture-execute { src } {
+    global output
+    global srcdir tmpdir
+    global tool
+    global compiler_conditional_xfail_data
+    global TORTURE_OPTIONS
+    global go_execute_args
+
+    # Check for alternate driver.
+    set additional_flags ""
+    if [file exists [file rootname $src].x] {
+       verbose "Using alternate driver [file rootname [file tail $src]].x" 2
+       set done_p 0
+       catch "set done_p \[source [file rootname $src].x\]"
+       if { $done_p } {
+           return
+       }
+    }
+
+    # Setup the options for the testcase run.
+    set option_list $TORTURE_OPTIONS
+    set executable $tmpdir/[file tail [file rootname $src].x]
+    regsub "(?q)$srcdir/" $src "" testcase
+
+    if { ! [info exists go_execute_args] } {
+       set go_execute_args ""
+    }
+
+    # If we couldn't rip $srcdir out of `src' then just do the best we can.
+    # The point is to reduce the unnecessary noise in the logs.  Don't strip
+    # out too much because different testcases with the same name can confuse
+    # `test-tool'.
+    if [string match "/*" $testcase] {
+       set testcase "[file tail [file dirname $src]]/[file tail $src]"
+    }
+
+    # Walk the list of options and copmile and run the testcase for all
+    # options that are not explicitly disabled by the .x script (if present).
+    foreach option $option_list {
+
+       # Torture_{compile,execute}_xfail are set by the .x script.
+       if [info exists torture_compile_xfail] {
+           setup_xfail $torture_compile_xfail
+       }
+
+       # Torture_execute_before_{compile,execute} can be set by the .x script.
+       if [info exists torture_eval_before_compile] {
+            set ignore_me [eval $torture_eval_before_compile]
+       }
+
+       # FIXME: We should make sure that the modules required by this testcase
+       # exist.  If not, the testcase should XFAIL.
+
+       # Compile the testcase.
+       catch { remote_file build delete $executable }
+       verbose "Testing $testcase, $option" 1
+
+       set options ""
+       lappend options "additional_flags=-w $option"
+       if { $additional_flags != "" } {
+           lappend options "additional_flags=$additional_flags"
+       }
+       set comp_output [go_target_compile "$src" "$executable" executable $options]
+
+       # See if we got something bad.
+       set fatal_signal "*go*: Internal compiler error: program*got fatal signal"
+       
+       if [string match "$fatal_signal 6" $comp_output] then {
+           go_fail $testcase "Got Signal 6, $option"
+           catch { remote_file build delete $executable }
+           continue
+       }
+       
+       if [string match "$fatal_signal 11" $comp_output] then {
+           go_fail $testcase "Got Signal 11, $option"
+           catch { remote_file build delete $executable }
+           continue
+       }
+
+       if [string match "*internal compiler error*" $comp_output] then {
+           go_fail $testcase "$option (internal compiler error)"
+           catch { remote_file build delete $executable }
+           continue
+       }
+       
+       # We shouldn't get these because of -w, but just in case.
+       if [string match "*go*:*warning:*" $comp_output] then {
+           warning "$testcase: (with warnings) $option"
+           send_log "$comp_output\n"
+           unresolved "$testcase, $option"
+           catch { remote_file build delete $executable }
+           continue
+       }
+       
+       # Prune warnings we know are unwanted.
+       set comp_output [prune_warnings $comp_output]
+
+       # Report if the testcase is not supported.
+       set unsupported_message [go_check_unsupported_p $comp_output]
+       if { $unsupported_message != "" } {
+           unsupported "$testcase: $unsupported_message"
+           continue
+       } elseif ![file exists $executable] {
+           if ![is3way] {
+               fail "$testcase compilation, $option"
+               untested "$testcase execution, $option"
+               continue
+           } else {
+               # FIXME: since we can't test for the existence of a remote
+               # file without short of doing an remote file list, we assume
+               # that since we got no output, it must have compiled.
+               pass "$testcase compilation, $option"           
+           }
+       } else {
+           pass "$testcase compilation, $option"
+       }
+
+       if [info exists torture_execute_xfail] {
+           setup_xfail $torture_execute_xfail
+       }
+
+       if [info exists torture_eval_before_execute] {
+            set ignore_me [eval $torture_eval_before_execute]
+       }
+
+       # Run the testcase, and analyse the output.
+       set result [go_load "$executable" "$go_execute_args" ""]
+       set status [lindex $result 0]
+       set output [lindex $result 1]
+
+       # In order to cooperate nicely with the master Go testsuite,
+       # if the output contains the string BUG, we treat the test as
+       # failing.
+       if [ string match "*BUG*" $output ] {
+           set status "fail"
+       }
+
+        if { $status == "pass" } {
+           catch { remote_file build delete $executable }
+        }
+       $status "$testcase execution, $option"
+    }
+}
+
+
+#
+# search_for_re -- looks for a string match in a file
+#
+proc search_for_re { file pattern } {
+    set fd [open $file r]
+    while { [gets $fd cur_line]>=0 } {
+       set lower [string tolower $cur_line]
+       if [regexp "$pattern" $lower] then {
+           close $fd
+           return 1
+       }
+    }
+    close $fd
+    return 0
+}
+
+
+#
+# go-torture -- the go-torture testcase source file processor
+#
+# This runs compilation only tests (no execute tests).
+#
+# SRC is the full pathname of the testcase, or just a file name in which
+# case we prepend $srcdir/$subdir.
+#
+# If the testcase has an associated .x file, we source that to run the
+# test instead.  We use .x so that we don't lengthen the existing filename
+# to more than 14 chars.
+#
+proc go-torture { args } {
+    global srcdir subdir
+    global compiler_conditional_xfail_data
+    global TORTURE_OPTIONS
+
+    set src [lindex $args 0]
+    if { [llength $args] > 1 } {
+       set options [lindex $args 1]
+    } else {
+       set options ""
+    }
+
+    # Prepend $srdir/$subdir if missing.
+    if ![string match "*/*" $src] {
+       set src "$srcdir/$subdir/$src"
+    }
+
+    # Check for alternate driver.
+    if [file exists [file rootname $src].x] {
+       verbose "Using alternate driver [file rootname [file tail $src]].x" 2
+       set done_p 0
+       catch "set done_p \[source [file rootname $src].x\]"
+       if { $done_p } {
+           return
+       }
+    }
+   
+    # loop through all the options
+    set option_list $TORTURE_OPTIONS
+    foreach option $option_list {
+
+       # torture_compile_xfail is set by the .x script (if present)
+       if [info exists torture_compile_xfail] {
+           setup_xfail $torture_compile_xfail
+       }
+
+       # torture_execute_before_compile is set by the .x script (if present)
+       if [info exists torture_eval_before_compile] {
+            set ignore_me [eval $torture_eval_before_compile]
+       }
+
+       go-torture-compile $src "$option $options"
+    }
+}
+
+#
+# add-ieee-options -- add options necessary for 100% ieee conformance.
+#
+proc add-ieee-options { } {
+    # Ensure that excess precision does not cause problems.
+    if { [istarget "i?86-*-*"]
+        || [istarget "m68k-*-*"] } then {
+      uplevel 1 lappend additional_flags "-ffloat-store"
+    }
+
+    # Enable full IEEE compliance mode.
+    if { [istarget "alpha*-*-*"]
+         || [istarget "sh*-*-*"] } then {
+      uplevel 1 lappend additional_flags "-mieee"
+    }
+}
diff --git a/gcc/testsuite/lib/go.exp b/gcc/testsuite/lib/go.exp
new file mode 100644 (file)
index 0000000..ee5eb76
--- /dev/null
@@ -0,0 +1,216 @@
+# Copyright (C) 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+#
+# go support library routines
+#
+load_lib prune.exp
+load_lib gcc-defs.exp
+load_lib target-libpath.exp
+
+#
+# GOC_UNDER_TEST is the compiler under test.
+#
+
+
+set gpp_compile_options ""
+
+
+#
+# go_version -- extract and print the version number of the compiler
+#
+
+proc go_version { } {
+    global GOC_UNDER_TEST
+    
+    go_init
+
+    # ignore any arguments after the command
+    set compiler [lindex $GOC_UNDER_TEST 0]
+    
+    # verify that the compiler exists
+    if { [is_remote host] || [which $compiler] != 0 } then {
+       set tmp [remote_exec host "$compiler -v"]
+       set status [lindex $tmp 0]
+       set output [lindex $tmp 1]
+       regexp " version \[^\n\r\]*" $output version
+       if { $status == 0 && [info exists version] } then {
+           if [is_remote host] {
+               clone_output "$compiler $version\n"
+           } else {
+               clone_output "[which $compiler] $version\n"
+           }
+       } else {
+           clone_output "Couldn't determine version of [which $compiler]\n"
+       }
+    } else {
+       # compiler does not exist (this should have already been detected)
+       warning "$compiler does not exist"
+    }
+}
+
+#
+# go_include_flags -- include flags for the gcc tree structure
+#
+
+proc go_include_flags { paths } {
+    global srcdir
+    global TESTING_IN_BUILD_TREE
+
+    set flags ""
+
+    if { [is_remote host] || ![info exists TESTING_IN_BUILD_TREE] } {
+       return "${flags}"
+    }
+
+    set gccpath ${paths}
+
+    if { $gccpath != "" } {
+       if [file exists "${gccpath}/libgo/os.gox"] {
+           append flags "-I${gccpath}/libgo "
+       }
+    }
+}
+
+#
+# go_link_flags -- linker flags for the gcc tree structure
+#
+
+proc go_link_flags { paths } {
+    global srcdir
+    global ld_library_path
+    global GOC_UNDER_TEST
+    global shlib_ext
+
+    set gccpath ${paths}
+    set libio_dir ""
+    set flags ""
+    set ld_library_path "."
+    set shlib_ext [get_shlib_extension]
+    verbose "shared lib extension: $shlib_ext"
+
+    if { $gccpath != "" } {
+      if [file exists "${gccpath}/libgo/libgobegin.a"] {
+         append flags "-L${gccpath}/libgo "
+      }
+      if { [file exists "${gccpath}/libgo/.libs/libgo.a"] \
+          || [file exists "${gccpath}/libgo/.libs/libgo.${shlib_ext}"] } {
+          append flags "-L${gccpath}/libgo/.libs "
+          append ld_library_path ":${gccpath}/libgo/.libs"
+      }
+      if [file exists "${gccpath}/libiberty/libiberty.a"] {
+          append flags "-L${gccpath}/libiberty "
+      }
+      append ld_library_path \
+       [gcc-set-multilib-library-path $GOC_UNDER_TEST]
+    }
+
+    set_ld_library_path_env_vars
+
+    return "$flags"
+}
+
+#
+# go_init -- called at the start of each subdir of tests
+#
+
+proc go_init { args } {
+    global subdir
+    global gpp_initialized
+    global base_dir
+    global tmpdir
+    global libdir
+    global gluefile wrap_flags
+    global objdir srcdir
+    global ALWAYS_GOCFLAGS
+    global TOOL_EXECUTABLE TOOL_OPTIONS
+    global GOC_UNDER_TEST
+    global TESTING_IN_BUILD_TREE
+
+    # We set LC_ALL and LANG to C so that we get the same error messages as expected.
+    setenv LC_ALL C
+    setenv LANG C
+
+    if ![info exists GOC_UNDER_TEST] then {
+       if [info exists TOOL_EXECUTABLE] {
+           set GOC_UNDER_TEST $TOOL_EXECUTABLE
+       } else {
+           if { [is_remote host] || ! [info exists TESTING_IN_BUILD_TREE] } {
+               set GOC_UNDER_TEST [transform gccgo]
+           } else {
+               set GOC_UNDER_TEST [findfile $base_dir/../../gccgo "$base_dir/../../gccgo -B$base_dir/../../" [findfile $base_dir/gccgo "$base_dir/gccgo -B$base_dir/" [transform gccgo]]]
+           }
+       }
+    }
+
+    if ![is_remote host] {
+       if { [which $GOC_UNDER_TEST] == 0 } then {
+           perror "GOC_UNDER_TEST ($GOC_UNDER_TEST) does not exist"
+           exit 1
+       }
+    }
+    if ![info exists tmpdir] {
+       set tmpdir "/tmp"
+    }
+
+    if [info exists gluefile] {
+       unset gluefile
+    }
+
+    go_maybe_build_wrapper "${tmpdir}/go-testglue.o"
+
+    set ALWAYS_GOCFLAGS ""
+
+    if ![is_remote host] {
+       if [info exists TOOL_OPTIONS] {
+           lappend ALWAYS_GOCFLAGS "additional_flags=[go_include_flags [get_multilibs ${TOOL_OPTIONS}] ]"
+           lappend ALWAYS_GOCFLAGS "ldflags=[go_link_flags [get_multilibs ${TOOL_OPTIONS}] ]"
+       } else {
+           lappend ALWAYS_GOCFLAGS "additional_flags=[go_include_flags [get_multilibs] ]"
+           lappend ALWAYS_GOCFLAGS "ldflags=[go_link_flags [get_multilibs] ]"
+       }
+    }
+
+    if [info exists TOOL_OPTIONS] {
+       lappend ALWAYS_GOCFLAGS "additional_flags=$TOOL_OPTIONS"
+    }
+
+    verbose -log "ALWAYS_GOCFLAGS set to $ALWAYS_GOCFLAGS"
+
+    verbose "go is initialized" 3
+}
+
+#
+# go_target_compile -- compile a source file
+#
+
+proc go_target_compile { source dest type options } {
+    global tmpdir
+    global gluefile wrap_flags
+    global ALWAYS_GOCFLAGS
+    global GOC_UNDER_TEST
+
+    if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } {
+       lappend options "libs=${gluefile}"
+       lappend options "ldflags=${wrap_flags}"
+    }
+
+    lappend options "compiler=$GOC_UNDER_TEST"
+
+    set options [concat "$ALWAYS_GOCFLAGS" $options]
+    set options [dg-additional-files-options $options $source]
+    return [target_compile $source $dest $type $options]
+}
index b2c3d2a..ee7a8bf 100644 (file)
@@ -34,7 +34,8 @@
 # "// C++" for c++,
 # "! Fortran" for Fortran code,
 # "/* ObjC", for ObjC
-# and "// ObjC++" for ObjC++
+# "// ObjC++" for ObjC++
+# and "// Go" for Go
 # If the tool is ObjC/ObjC++ then we overide the extension to .m/.mm to 
 # allow for ObjC/ObjC++ specific flags.
 proc check_compile {basename type contents args} {
@@ -51,6 +52,7 @@ proc check_compile {basename type contents args} {
        "*// C++*" { set src ${basename}[pid].cc }
        "*// ObjC++*" { set src ${basename}[pid].mm }
        "*/* ObjC*" { set src ${basename}[pid].m }
+       "*// Go*" { set src ${basename}[pid].go }
        default {
            switch -- $tool {
                "objc" { set src ${basename}[pid].m }
diff --git a/libgo/LICENSE b/libgo/LICENSE
new file mode 100644 (file)
index 0000000..d77335f
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (c) 2009 The Go 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.
+//
+// Subject to the terms and conditions of this License, Google hereby
+// grants to You a perpetual, worldwide, non-exclusive, no-charge,
+// royalty-free, irrevocable (except as stated in this section) patent
+// license to make, have made, use, offer to sell, sell, import, and
+// otherwise transfer this implementation of Go, where such license
+// applies only to those patent claims licensable by Google that are
+// necessarily infringed by use of this implementation of Go. If You
+// institute patent litigation against any entity (including a
+// cross-claim or counterclaim in a lawsuit) alleging that this
+// implementation of Go or a Contribution incorporated within this
+// implementation of Go constitutes direct or contributory patent
+// infringement, then any patent licenses granted to You under this
+// License for this implementation of Go shall terminate as of the date
+// such litigation is filed.
diff --git a/libgo/MERGE b/libgo/MERGE
new file mode 100644 (file)
index 0000000..436cbf9
--- /dev/null
@@ -0,0 +1,4 @@
+b547c5b04a18
+
+The first line of this file holds the Mercurial revision number of the
+last merge done from the master library sources.
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
new file mode 100644 (file)
index 0000000..bcd5b92
--- /dev/null
@@ -0,0 +1,2686 @@
+# Makefile.am -- Go library Makefile.
+
+# Copyright 2009, 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Process this file with autoreconf to produce Makefile.in.
+
+# Go support.
+SUFFIXES = .c .go .gox .o .obj .lo .a
+
+if LIBGO_IS_RTEMS
+subdirs = testsuite
+endif
+
+SUBDIRS = ${subdirs}
+
+MAINT_CHARSET = latin1
+
+mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
+PWD_COMMAND = $${PWDCMD-pwd}
+STAMP = echo timestamp >
+
+toolexecdir = $(glibgo_toolexecdir)
+toolexeclibdir = $(glibgo_toolexeclibdir)
+
+LIBFFI = @LIBFFI@
+LIBFFIINCS = @LIBFFIINCS@
+
+WARN_CFLAGS = $(WARN_FLAGS) $(WERROR)
+
+# -I/-D flags to pass when compiling.
+AM_CPPFLAGS = -I $(srcdir)/runtime $(LIBFFIINCS) -pthread
+
+ACLOCAL_AMFLAGS = -I ./config -I ../config
+
+AM_CFLAGS = -fexceptions -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS) \
+       $(STRINGOPS_FLAG) \
+       -I $(srcdir)/../gcc -I $(MULTIBUILDTOP)../../gcc/include
+
+if USING_SPLIT_STACK
+AM_LDFLAGS = -XCClinker $(SPLIT_STACK)
+endif
+
+# Multilib support.
+MAKEOVERRIDES=
+
+# Work around what appears to be a GNU make  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)" \
+       "CC_FOR_TARGET=$(CC_FOR_TARGET)" \
+       "CFLAGS=$(CFLAGS)" \
+       "CXXFLAGS=$(CXXFLAGS)" \
+       "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+       "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+       "GOC_FOR_TARGET=$(GOC_FOR_TARGET)" \
+       "GOC=$(GOC)" \
+       "GOCFLAGS=$(GOCFLAGS)" \
+       "INSTALL=$(INSTALL)" \
+       "INSTALL_DATA=$(INSTALL_DATA)" \
+       "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+       "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+       "LDFLAGS=$(LDFLAGS)" \
+       "LIBCFLAGS=$(LIBCFLAGS)" \
+       "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+       "MAKE=$(MAKE)" \
+       "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+       "PICFLAG=$(PICFLAG)" \
+       "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+       "SHELL=$(SHELL)" \
+       "RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+       "exec_prefix=$(exec_prefix)" \
+       "infodir=$(infodir)" \
+       "libdir=$(libdir)" \
+       "includedir=$(includedir)" \
+       "prefix=$(prefix)" \
+       "tooldir=$(tooldir)" \
+       "gxx_include_dir=$(gxx_include_dir)" \
+       "AR=$(AR)" \
+       "AS=$(AS)" \
+       "LD=$(LD)" \
+       "RANLIB=$(RANLIB)" \
+       "NM=$(NM)" \
+       "NM_FOR_BUILD=$(NM_FOR_BUILD)" \
+       "NM_FOR_TARGET=$(NM_FOR_TARGET)" \
+       "DESTDIR=$(DESTDIR)" \
+       "WERROR=$(WERROR)"
+
+# Subdir rules rely on $(FLAGS_TO_PASS)
+FLAGS_TO_PASS = $(AM_MAKEFLAGS)
+
+toolexeclib_LTLIBRARIES = libgo.la
+toolexeclib_LIBRARIES = libgobegin.a
+
+toolexeclib_DATA = \
+       asn1.gox \
+       big.gox \
+       bufio.gox \
+       bytes.gox \
+       cmath.gox \
+       ebnf.gox \
+       exec.gox \
+       expvar.gox \
+       flag.gox \
+       fmt.gox \
+       gob.gox \
+       hash.gox \
+       html.gox \
+       http.gox \
+       image.gox \
+       io.gox \
+       json.gox \
+       log.gox \
+       math.gox \
+       mime.gox \
+       net.gox \
+       netchan.gox \
+       os.gox \
+       patch.gox \
+       path.gox \
+       rand.gox \
+       reflect.gox \
+       regexp.gox \
+       rpc.gox \
+       runtime.gox \
+       scanner.gox \
+       smtp.gox \
+       sort.gox \
+       strconv.gox \
+       strings.gox \
+       sync.gox \
+       syscall.gox \
+       syslog.gox \
+       tabwriter.gox \
+       template.gox \
+       testing.gox \
+       time.gox \
+       try.gox \
+       unicode.gox \
+       utf16.gox \
+       utf8.gox \
+       websocket.gox \
+       xml.gox
+
+toolexeclibarchivedir = $(toolexeclibdir)/archive
+
+toolexeclibarchive_DATA = \
+       archive/tar.gox \
+       archive/zip.gox
+
+toolexeclibcompressdir = $(toolexeclibdir)/compress
+
+toolexeclibcompress_DATA = \
+       compress/flate.gox \
+       compress/gzip.gox \
+       compress/zlib.gox
+
+toolexeclibcontainerdir = $(toolexeclibdir)/container
+
+toolexeclibcontainer_DATA = \
+       container/heap.gox \
+       container/list.gox \
+       container/ring.gox \
+       container/vector.gox
+
+toolexeclibcryptodir = $(toolexeclibdir)/crypto
+
+toolexeclibcrypto_DATA = \
+       crypto/aes.gox \
+       crypto/block.gox \
+       crypto/blowfish.gox \
+       crypto/cast5.gox \
+       crypto/hmac.gox \
+       crypto/md4.gox \
+       crypto/md5.gox \
+       crypto/ocsp.gox \
+       crypto/rand.gox \
+       crypto/rc4.gox \
+       crypto/ripemd160.gox \
+       crypto/rsa.gox \
+       crypto/sha1.gox \
+       crypto/sha256.gox \
+       crypto/sha512.gox \
+       crypto/subtle.gox \
+       crypto/tls.gox \
+       crypto/x509.gox \
+       crypto/xtea.gox
+
+toolexeclibdebugdir = $(toolexeclibdir)/debug
+
+toolexeclibdebug_DATA = \
+       debug/dwarf.gox \
+       debug/elf.gox \
+       debug/gosym.gox \
+       debug/macho.gox \
+       debug/pe.gox \
+       debug/proc.gox
+
+toolexeclibencodingdir = $(toolexeclibdir)/encoding
+
+toolexeclibencoding_DATA = \
+       encoding/ascii85.gox \
+       encoding/base64.gox \
+       encoding/binary.gox \
+       encoding/git85.gox \
+       encoding/hex.gox \
+       encoding/pem.gox
+
+toolexeclibexpdir = $(toolexeclibdir)/exp
+
+toolexeclibexp_DATA = \
+       exp/datafmt.gox \
+       exp/draw.gox \
+       exp/eval.gox
+
+toolexeclibgodir = $(toolexeclibdir)/go
+
+toolexeclibgo_DATA = \
+       go/ast.gox \
+       go/doc.gox \
+       go/parser.gox \
+       go/printer.gox \
+       go/scanner.gox \
+       go/token.gox \
+       go/typechecker.gox
+
+toolexeclibhashdir = $(toolexeclibdir)/hash
+
+toolexeclibhash_DATA = \
+       hash/adler32.gox \
+       hash/crc32.gox \
+       hash/crc64.gox
+
+toolexeclibhttpdir = $(toolexeclibdir)/http
+
+toolexeclibhttp_DATA = \
+       http/pprof.gox
+
+toolexeclibimagedir = $(toolexeclibdir)/image
+
+toolexeclibimage_DATA = \
+       image/jpeg.gox \
+       image/png.gox
+
+toolexeclibindexdir = $(toolexeclibdir)/index
+
+toolexeclibindex_DATA = \
+       index/suffixarray.gox
+
+toolexeclibiodir = $(toolexeclibdir)/io
+
+toolexeclibio_DATA = \
+       io/ioutil.gox
+
+toolexeclibmimedir = $(toolexeclibdir)/mime
+
+toolexeclibmime_DATA = \
+       mime/multipart.gox
+
+toolexeclibnetdir = $(toolexeclibdir)/net
+
+toolexeclibnet_DATA = \
+       net/dict.gox \
+       net/textproto.gox
+
+toolexeclibosdir = $(toolexeclibdir)/os
+
+toolexeclibos_DATA = \
+       os/signal.gox
+
+toolexeclibrpcdir = $(toolexeclibdir)/rpc
+
+toolexeclibrpc_DATA = \
+       rpc/jsonrpc.gox
+
+toolexeclibruntimedir = $(toolexeclibdir)/runtime
+
+toolexeclibruntime_DATA = \
+       runtime/pprof.gox
+
+toolexeclibtestingdir = $(toolexeclibdir)/testing
+
+toolexeclibtesting_DATA = \
+       testing/iotest.gox \
+       testing/quick.gox \
+       testing/script.gox
+
+if HAVE_SYS_MMAN_H
+runtime_mem_file = runtime/mem.c
+else
+runtime_mem_file = runtime/mem_posix_memalign.c
+endif
+
+if LIBGO_IS_RTEMS
+rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
+else
+rtems_task_variable_add_file =
+endif
+
+runtime_files = \
+       runtime/go-append.c \
+       runtime/go-assert.c \
+       runtime/go-assert-interface.c \
+       runtime/go-byte-array-to-string.c \
+       runtime/go-breakpoint.c \
+       runtime/go-caller.c \
+       runtime/go-can-convert-interface.c \
+       runtime/go-chan-cap.c \
+       runtime/go-chan-len.c \
+       runtime/go-check-interface.c \
+       runtime/go-close.c \
+       runtime/go-closed.c \
+       runtime/go-construct-map.c \
+       runtime/go-convert-interface.c \
+       runtime/go-defer.c \
+       runtime/go-deferred-recover.c \
+       runtime/go-eface-compare.c \
+       runtime/go-eface-val-compare.c \
+       runtime/go-getgoroot.c \
+       runtime/go-go.c \
+       runtime/go-gomaxprocs.c \
+       runtime/go-int-array-to-string.c \
+       runtime/go-int-to-string.c \
+       runtime/go-interface-compare.c \
+       runtime/go-interface-val-compare.c \
+       runtime/go-lock-os-thread.c \
+       runtime/go-map-delete.c \
+       runtime/go-map-index.c \
+       runtime/go-map-len.c \
+       runtime/go-map-range.c \
+       runtime/go-nanotime.c \
+       runtime/go-new-channel.c \
+       runtime/go-new-map.c \
+       runtime/go-new.c \
+       runtime/go-note.c \
+       runtime/go-panic.c \
+       runtime/go-panic-defer.c \
+       runtime/go-print.c \
+       runtime/go-rec-big.c \
+       runtime/go-rec-nb-big.c \
+       runtime/go-rec-nb-small.c \
+       runtime/go-rec-small.c \
+       runtime/go-recover.c \
+       runtime/go-reflect.c \
+       runtime/go-reflect-call.c \
+       runtime/go-reflect-chan.c \
+       runtime/go-reflect-map.c \
+       runtime/go-rune.c \
+       runtime/go-runtime-error.c \
+       runtime/go-sched.c \
+       runtime/go-select.c \
+       runtime/go-semacquire.c \
+       runtime/go-send-big.c \
+       runtime/go-send-nb-big.c \
+       runtime/go-send-nb-small.c \
+       runtime/go-send-small.c \
+       runtime/go-signal.c \
+       runtime/go-strcmp.c \
+       runtime/go-string-to-byte-array.c \
+       runtime/go-string-to-int-array.c \
+       runtime/go-strplus.c \
+       runtime/go-strslice.c \
+       runtime/go-trampoline.c \
+       runtime/go-type-eface.c \
+       runtime/go-type-error.c \
+       runtime/go-type-identity.c \
+       runtime/go-type-interface.c \
+       runtime/go-type-string.c \
+       runtime/go-typedesc-equal.c \
+       runtime/go-typestring.c \
+       runtime/go-unreflect.c \
+       runtime/go-unsafe-new.c \
+       runtime/go-unsafe-newarray.c \
+       runtime/go-unsafe-pointer.c \
+       runtime/go-unwind.c \
+       runtime/mcache.c \
+       runtime/mcentral.c \
+       $(runtime_mem_file) \
+       runtime/mfinal.c \
+       runtime/mfixalloc.c \
+       runtime/mgc0.c \
+       runtime/mheap.c \
+       runtime/mheapmap32.c \
+       runtime/mheapmap64.c \
+       runtime/msize.c \
+       runtime/proc.c \
+       runtime/thread.c \
+       $(rtems_task_variable_add_file) \
+       chan.c \
+       iface.c \
+       malloc.c \
+       map.c \
+       mprof.c \
+       reflect.c \
+       sigqueue.c \
+       string.c
+
+goc2c.$(OBJEXT): runtime/goc2c.c
+       $(CC_FOR_BUILD) -c $(CFLAGS_FOR_BUILD) $<
+
+goc2c: goc2c.$(OBJEXT)
+       $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $<
+
+malloc.c: $(srcdir)/runtime/malloc.goc goc2c
+       ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+       mv -f $@.tmp $@
+
+mprof.c: $(srcdir)/runtime/mprof.goc goc2c
+       ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+       mv -f $@.tmp $@
+
+reflect.c: $(srcdir)/runtime/reflect.goc goc2c
+       ./goc2c --gcc --go-prefix libgo_reflect $< > $@.tmp
+       mv -f $@.tmp $@
+
+sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
+       ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+       mv -f $@.tmp $@
+
+%.c: $(srcdir)/runtime/%.goc goc2c
+       ./goc2c --gcc $< > $@.tmp
+       mv -f $@.tmp $@
+
+go_asn1_files = \
+       go/asn1/asn1.go \
+       go/asn1/common.go \
+       go/asn1/marshal.go
+
+go_big_files = \
+       go/big/arith.go \
+       go/big/int.go \
+       go/big/nat.go \
+       go/big/rat.go
+
+go_bufio_files = \
+       go/bufio/bufio.go
+
+go_bytes_files = \
+       go/bytes/buffer.go \
+       go/bytes/bytes.go \
+       go/bytes/bytes_decl.go
+go_bytes_c_files = \
+       go/bytes/indexbyte.c
+
+go_cmath_files = \
+       go/cmath/abs.go \
+       go/cmath/asin.go \
+       go/cmath/conj.go \
+       go/cmath/exp.go \
+       go/cmath/isinf.go \
+       go/cmath/isnan.go \
+       go/cmath/log.go \
+       go/cmath/phase.go \
+       go/cmath/polar.go \
+       go/cmath/pow.go \
+       go/cmath/rect.go \
+       go/cmath/sin.go \
+       go/cmath/sqrt.go \
+       go/cmath/tan.go
+
+go_ebnf_files = \
+       go/ebnf/ebnf.go \
+       go/ebnf/parser.go
+
+go_exec_files = \
+       go/exec/exec.go \
+       go/exec/lp_unix.go
+
+go_expvar_files = \
+       go/expvar/expvar.go
+
+go_flag_files = \
+       go/flag/flag.go
+
+go_fmt_files = \
+       go/fmt/doc.go \
+       go/fmt/format.go \
+       go/fmt/print.go \
+       go/fmt/scan.go
+
+go_gob_files = \
+       go/gob/decode.go \
+       go/gob/decoder.go \
+       go/gob/doc.go \
+       go/gob/encode.go \
+       go/gob/encoder.go \
+       go/gob/error.go \
+       go/gob/type.go
+
+go_hash_files = \
+       go/hash/hash.go
+
+go_html_files = \
+       go/html/doc.go \
+       go/html/entity.go \
+       go/html/escape.go \
+       go/html/token.go
+
+go_http_files = \
+       go/http/chunked.go \
+       go/http/client.go \
+       go/http/dump.go \
+       go/http/fs.go \
+       go/http/lex.go \
+       go/http/persist.go \
+       go/http/request.go \
+       go/http/response.go \
+       go/http/server.go \
+       go/http/status.go \
+       go/http/transfer.go \
+       go/http/url.go
+
+go_image_files = \
+       go/image/color.go \
+       go/image/format.go \
+       go/image/geom.go \
+       go/image/image.go \
+       go/image/names.go
+
+go_io_files = \
+       go/io/multi.go \
+       go/io/io.go \
+       go/io/pipe.go
+
+go_json_files = \
+       go/json/decode.go \
+       go/json/encode.go \
+       go/json/indent.go \
+       go/json/scanner.go \
+       go/json/stream.go
+
+go_log_files = \
+       go/log/log.go
+
+go_math_files = \
+       go/math/acosh.go \
+       go/math/asin.go \
+       go/math/asinh.go \
+       go/math/atan.go \
+       go/math/atanh.go \
+       go/math/atan2.go \
+       go/math/bits.go \
+       go/math/cbrt.go \
+       go/math/const.go \
+       go/math/copysign.go \
+       go/math/erf.go \
+       go/math/exp.go \
+       go/math/exp2.go \
+       go/math/expm1.go \
+       go/math/fabs.go \
+       go/math/fdim.go \
+       go/math/floor.go \
+       go/math/fmod.go \
+       go/math/frexp.go \
+       go/math/gamma.go \
+       go/math/hypot.go \
+       go/math/hypot_port.go \
+       go/math/j0.go \
+       go/math/j1.go \
+       go/math/jn.go \
+       go/math/ldexp.go \
+       go/math/lgamma.go \
+       go/math/log.go \
+       go/math/log1p.go \
+       go/math/log10.go \
+       go/math/logb.go \
+       go/math/modf.go \
+       go/math/nextafter.go \
+       go/math/pow.go \
+       go/math/pow10.go \
+       go/math/remainder.go \
+       go/math/signbit.go \
+       go/math/sin.go \
+       go/math/sincos.go \
+       go/math/sinh.go \
+       go/math/sqrt.go \
+       go/math/sqrt_port.go \
+       go/math/tan.go \
+       go/math/tanh.go \
+       go/math/unsafe.go
+
+go_mime_files = \
+       go/mime/grammar.go \
+       go/mime/mediatype.go \
+       go/mime/type.go
+
+if LIBGO_IS_RTEMS
+go_net_fd_os_file = go/net/fd_rtems.go
+go_net_newpollserver_file = go/net/newpollserver_rtems.go
+else
+go_net_fd_os_file = go/net/fd_linux.go
+go_net_newpollserver_file = go/net/newpollserver.go
+endif
+
+go_net_files = \
+       go/net/dial.go \
+       go/net/dnsclient.go \
+       go/net/dnsconfig.go \
+       go/net/dnsmsg.go \
+       $(go_net_newpollserver_file) \
+       go/net/fd.go \
+       $(go_net_fd_os_file) \
+       go/net/hosts.go \
+       go/net/ip.go \
+       go/net/iprawsock.go \
+       go/net/ipsock.go \
+       go/net/net.go \
+       go/net/parse.go \
+       go/net/pipe.go \
+       go/net/port.go \
+       go/net/sock.go \
+       go/net/tcpsock.go \
+       go/net/udpsock.go \
+       go/net/unixsock.go
+
+go_netchan_files = \
+       go/netchan/common.go \
+       go/netchan/export.go \
+       go/netchan/import.go
+
+go_os_files = \
+       go/os/dir.go \
+       go/os/env.go \
+       go/os/env_unix.go \
+       go/os/error.go \
+       go/os/exec.go \
+       go/os/file.go \
+       go/os/file_unix.go \
+       go/os/getwd.go \
+       go/os/path.go \
+       go/os/proc.go \
+       go/os/stat.go \
+       go/os/sys_linux.go \
+       go/os/time.go \
+       go/os/types.go
+
+go_patch_files = \
+       go/patch/apply.go \
+       go/patch/git.go \
+       go/patch/patch.go \
+       go/patch/textdiff.go
+
+go_path_files = \
+       go/path/match.go \
+       go/path/path.go
+
+go_rand_files = \
+       go/rand/exp.go \
+       go/rand/normal.go \
+       go/rand/rand.go \
+       go/rand/rng.go \
+       go/rand/zipf.go
+
+go_reflect_files = \
+       go/reflect/deepequal.go \
+       go/reflect/type.go \
+       go/reflect/value.go
+
+go_regexp_files = \
+       go/regexp/regexp.go
+
+go_rpc_files = \
+       go/rpc/client.go \
+       go/rpc/debug.go \
+       go/rpc/server.go
+
+go_runtime_files = \
+       go/runtime/debug.go \
+       go/runtime/error.go \
+       go/runtime/extern.go \
+       go/runtime/sig.go \
+       go/runtime/softfloat64.go \
+       go/runtime/type.go \
+       version.go
+
+if LIBGO_IS_386
+GOARCH = 386
+else
+if LIBGO_IS_X86_64
+GOARCH = amd64
+else
+if LIBGO_IS_ARM
+GOARCH = arm
+else
+GOARCH = unknown
+endif
+endif
+endif
+
+if LIBGO_IS_LINUX
+GOOS = linux
+else
+if LIBGO_IS_DARWIN
+GOOS = darwin
+else
+if LIBGO_IS_FREEBSD
+GOOS = freebsd
+else
+if LIBGO_IS_RTEMS
+GOOS = rtems
+else
+GOOS = unknown
+endif
+endif
+endif
+endif
+
+version.go: s-version; @true
+s-version: Makefile
+       rm -f version.go.tmp
+       echo "package runtime" > version.go.tmp
+       echo 'const defaultGoroot = "$(prefix)"' >> version.go.tmp
+       echo 'const theVersion = "'`$(CC) --version | sed 1q`'"' >> version.go.tmp
+       echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
+       echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
+       $(SHELL) $(srcdir)/../move-if-change version.go.tmp version.go
+       $(STAMP) $@
+
+go_scanner_files = \
+       go/scanner/scanner.go
+
+go_smtp_files = \
+       go/smtp/auth.go \
+       go/smtp/smtp.go
+
+go_sort_files = \
+       go/sort/sort.go
+
+go_strconv_files = \
+       go/strconv/atob.go \
+       go/strconv/atof.go \
+       go/strconv/atoi.go \
+       go/strconv/decimal.go \
+       go/strconv/ftoa.go \
+       go/strconv/itoa.go \
+       go/strconv/quote.go
+
+go_strings_files = \
+       go/strings/reader.go \
+       go/strings/strings.go
+
+go_sync_files = \
+       go/sync/mutex.go \
+       go/sync/once.go \
+       go/sync/rwmutex.go
+go_sync_c_files = \
+       go/sync/cas.c
+
+go_syslog_files = \
+       go/syslog/syslog.go
+
+go_tabwriter_files = \
+       go/tabwriter/tabwriter.go
+
+go_template_files = \
+       go/template/format.go \
+       go/template/template.go
+
+go_testing_files = \
+       go/testing/benchmark.go \
+       go/testing/testing.go
+
+go_time_files = \
+       go/time/format.go \
+       go/time/sleep.go \
+       go/time/tick.go \
+       go/time/time.go \
+       go/time/zoneinfo_unix.go
+
+go_try_files = \
+       go/try/try.go
+
+go_unicode_files = \
+       go/unicode/casetables.go \
+       go/unicode/digit.go \
+       go/unicode/letter.go \
+       go/unicode/tables.go
+
+go_utf16_files = \
+       go/utf16/utf16.go
+
+go_utf8_files = \
+       go/utf8/string.go \
+       go/utf8/utf8.go
+
+go_websocket_files = \
+       go/websocket/client.go \
+       go/websocket/server.go \
+       go/websocket/websocket.go
+
+go_xml_files = \
+       go/xml/read.go \
+       go/xml/xml.go
+
+go_archive_tar_files = \
+       go/archive/tar/common.go \
+       go/archive/tar/reader.go \
+       go/archive/tar/writer.go
+
+go_archive_zip_files = \
+       go/archive/zip/reader.go \
+       go/archive/zip/struct.go
+
+go_compress_flate_files = \
+       go/compress/flate/deflate.go \
+       go/compress/flate/huffman_bit_writer.go \
+       go/compress/flate/huffman_code.go \
+       go/compress/flate/inflate.go \
+       go/compress/flate/reverse_bits.go \
+       go/compress/flate/token.go \
+       go/compress/flate/util.go
+
+go_compress_gzip_files = \
+       go/compress/gzip/gzip.go \
+       go/compress/gzip/gunzip.go
+
+go_compress_zlib_files = \
+       go/compress/zlib/reader.go \
+       go/compress/zlib/writer.go
+
+go_container_heap_files = \
+       go/container/heap/heap.go
+
+go_container_list_files = \
+       go/container/list/list.go
+
+go_container_ring_files = \
+       go/container/ring/ring.go
+
+go_container_vector_files = \
+       go/container/vector/defs.go \
+       go/container/vector/intvector.go \
+       go/container/vector/stringvector.go \
+       go/container/vector/vector.go
+
+go_crypto_aes_files = \
+       go/crypto/aes/block.go \
+       go/crypto/aes/cipher.go \
+       go/crypto/aes/const.go
+go_crypto_block_files = \
+       go/crypto/block/cbc.go \
+       go/crypto/block/cfb.go \
+       go/crypto/block/cmac.go \
+       go/crypto/block/cipher.go \
+       go/crypto/block/ctr.go \
+       go/crypto/block/eax.go \
+       go/crypto/block/ecb.go \
+       go/crypto/block/ofb.go \
+       go/crypto/block/xor.go
+go_crypto_blowfish_files = \
+       go/crypto/blowfish/block.go \
+       go/crypto/blowfish/const.go \
+       go/crypto/blowfish/cipher.go
+go_crypto_cast5_files = \
+       go/crypto/cast5/cast5.go
+go_crypto_hmac_files = \
+       go/crypto/hmac/hmac.go
+go_crypto_md4_files = \
+       go/crypto/md4/md4.go \
+       go/crypto/md4/md4block.go
+go_crypto_md5_files = \
+       go/crypto/md5/md5.go \
+       go/crypto/md5/md5block.go
+go_crypto_ocsp_files = \
+       go/crypto/ocsp/ocsp.go
+go_crypto_rand_files = \
+       go/crypto/rand/rand.go \
+       go/crypto/rand/rand_unix.go
+go_crypto_rc4_files = \
+       go/crypto/rc4/rc4.go
+go_crypto_ripemd160_files = \
+       go/crypto/ripemd160/ripemd160.go \
+       go/crypto/ripemd160/ripemd160block.go
+go_crypto_rsa_files = \
+       go/crypto/rsa/pkcs1v15.go \
+       go/crypto/rsa/rsa.go
+go_crypto_sha1_files = \
+       go/crypto/sha1/sha1.go \
+       go/crypto/sha1/sha1block.go
+go_crypto_sha256_files = \
+       go/crypto/sha256/sha256.go \
+       go/crypto/sha256/sha256block.go
+go_crypto_sha512_files = \
+       go/crypto/sha512/sha512.go \
+       go/crypto/sha512/sha512block.go
+go_crypto_subtle_files = \
+       go/crypto/subtle/constant_time.go
+go_crypto_tls_files = \
+       go/crypto/tls/alert.go \
+       go/crypto/tls/ca_set.go \
+       go/crypto/tls/common.go \
+       go/crypto/tls/conn.go \
+       go/crypto/tls/handshake_client.go \
+       go/crypto/tls/handshake_messages.go \
+       go/crypto/tls/handshake_server.go \
+       go/crypto/tls/prf.go \
+       go/crypto/tls/tls.go
+go_crypto_x509_files = \
+       go/crypto/x509/x509.go
+go_crypto_xtea_files = \
+       go/crypto/xtea/block.go \
+       go/crypto/xtea/cipher.go
+
+go_debug_dwarf_files = \
+       go/debug/dwarf/buf.go \
+       go/debug/dwarf/const.go \
+       go/debug/dwarf/entry.go \
+       go/debug/dwarf/open.go \
+       go/debug/dwarf/type.go \
+       go/debug/dwarf/unit.go
+go_debug_elf_files = \
+       go/debug/elf/elf.go \
+       go/debug/elf/file.go
+go_debug_gosym_files = \
+       go/debug/gosym/pclntab.go \
+       go/debug/gosym/symtab.go
+go_debug_macho_files = \
+       go/debug/macho/file.go \
+       go/debug/macho/macho.go
+go_debug_pe_files = \
+       go/debug/pe/file.go \
+       go/debug/pe/pe.go
+
+if LIBGO_IS_LINUX
+proc_file = go/debug/proc/proc_linux.go
+if LIBGO_IS_386
+regs_file = go/debug/proc/regs_linux_386.go
+else
+if LIBGO_IS_X86_64
+regs_file = go/debug/proc/regs_linux_amd64.go
+else
+regs_file =
+endif
+endif
+else
+if LIBGO_IS_DARWIN
+proc_file = go/debug/proc/proc_darwin.go
+if LIBGO_IS_386
+regs_file = go/debug/proc/regs_darwin_386.go
+else
+if LIBGO_IS_X86_64
+regs_file = go/debug/proc/regs_darwin_amd64.go
+else
+regs_file =
+endif
+endif
+else
+if LIBGO_IS_FREEBSD
+proc_file = go/debug/proc/proc_freebsd.go
+if LIBGO_IS_386
+regs_file = go/debug/proc/regs_freebsd_386.go
+else
+if LIBGO_IS_X86_64
+regs_file = go/debug/proc/regs_freebsd_amd64.go
+else
+regs_file =
+endif
+endif
+else
+proc_file =
+regs_file =
+endif
+endif
+endif
+
+go_debug_proc_files = \
+       go/debug/proc/proc.go \
+       $(proc_file) \
+       $(regs_file)
+
+go_encoding_ascii85_files = \
+       go/encoding/ascii85/ascii85.go
+go_encoding_base64_files = \
+       go/encoding/base64/base64.go
+go_encoding_binary_files = \
+       go/encoding/binary/binary.go
+go_encoding_git85_files = \
+       go/encoding/git85/git.go
+go_encoding_hex_files = \
+       go/encoding/hex/hex.go
+go_encoding_pem_files = \
+       go/encoding/pem/pem.go
+
+go_exp_datafmt_files = \
+       go/exp/datafmt/datafmt.go \
+       go/exp/datafmt/parser.go
+go_exp_draw_files = \
+       go/exp/draw/draw.go \
+       go/exp/draw/event.go
+go_exp_eval_files = \
+       go/exp/eval/abort.go \
+       go/exp/eval/bridge.go \
+       go/exp/eval/compiler.go \
+       go/exp/eval/expr.go \
+       go/exp/eval/expr1.go \
+       go/exp/eval/func.go \
+       go/exp/eval/scope.go \
+       go/exp/eval/stmt.go \
+       go/exp/eval/type.go \
+       go/exp/eval/typec.go \
+       go/exp/eval/value.go \
+       go/exp/eval/world.go
+
+go_go_ast_files = \
+       go/go/ast/ast.go \
+       go/go/ast/filter.go \
+       go/go/ast/print.go \
+       go/go/ast/scope.go \
+       go/go/ast/walk.go
+go_go_doc_files = \
+       go/go/doc/comment.go \
+       go/go/doc/doc.go
+go_go_parser_files = \
+       go/go/parser/interface.go \
+       go/go/parser/parser.go
+go_go_printer_files = \
+       go/go/printer/nodes.go \
+       go/go/printer/printer.go
+go_go_scanner_files = \
+       go/go/scanner/errors.go \
+       go/go/scanner/scanner.go
+go_go_token_files = \
+       go/go/token/token.go
+go_go_typechecker_files = \
+       go/go/typechecker/scope.go \
+       go/go/typechecker/typechecker.go \
+       go/go/typechecker/universe.go
+
+go_hash_adler32_files = \
+       go/hash/adler32/adler32.go
+go_hash_crc32_files = \
+       go/hash/crc32/crc32.go
+go_hash_crc64_files = \
+       go/hash/crc64/crc64.go
+
+go_http_pprof_files = \
+       go/http/pprof/pprof.go
+
+go_image_jpeg_files = \
+       go/image/jpeg/huffman.go \
+       go/image/jpeg/idct.go \
+       go/image/jpeg/reader.go
+
+go_image_png_files = \
+       go/image/png/reader.go \
+       go/image/png/writer.go
+
+go_index_suffixarray_files = \
+       go/index/suffixarray/suffixarray.go
+
+go_io_ioutil_files = \
+       go/io/ioutil/ioutil.go \
+       go/io/ioutil/tempfile.go
+
+go_mime_multipart_files = \
+       go/mime/multipart/multipart.go
+
+go_net_dict_files = \
+       go/net/dict/dict.go
+
+go_net_textproto_files = \
+       go/net/textproto/pipeline.go \
+       go/net/textproto/reader.go \
+       go/net/textproto/textproto.go \
+       go/net/textproto/writer.go
+
+go_os_signal_files = \
+       go/os/signal/signal.go \
+       unix.go
+
+go_rpc_jsonrpc_files = \
+       go/rpc/jsonrpc/client.go \
+       go/rpc/jsonrpc/server.go
+
+go_runtime_pprof_files = \
+       go/runtime/pprof/pprof.go
+
+go_testing_iotest_files = \
+       go/testing/iotest/logger.go \
+       go/testing/iotest/reader.go \
+       go/testing/iotest/writer.go
+go_testing_quick_files = \
+       go/testing/quick/quick.go
+go_testing_script_files = \
+       go/testing/script/script.go
+
+if LIBGO_IS_LINUX
+syscall_os_file = syscalls/syscall_linux.go
+if LIBGO_IS_386
+syscall_arch_file = syscalls/syscall_linux_386.go
+else
+if LIBGO_IS_X86_64
+syscall_arch_file = syscalls/syscall_linux_amd64.go
+else
+syscall_arch_file =
+endif
+endif
+else
+syscall_os_file =
+syscall_arch_file =
+endif
+
+if LIBGO_IS_RTEMS
+syscall_exec_os_file = syscalls/exec_stubs.go
+syscall_socket_os_file = syscalls/socket_bsd.go
+syscall_socket_epoll_file=
+syscall_sysfile_os_file = syscalls/sysfile_rtems.go
+syscall_syscall_file = syscalls/syscall_stubs.go
+syscall_errstr_file = syscalls/errstr_rtems.go
+syscall_errstr_decl_file = syscalls/errstr_decl_rtems.go
+else
+syscall_exec_os_file = syscalls/exec.go
+syscall_socket_os_file = syscalls/socket_linux.go
+syscall_socket_epoll_file = syscalls/socket_epoll.go
+syscall_sysfile_os_file = syscalls/sysfile_linux.go
+syscall_syscall_file = syscalls/syscall.go
+syscall_errstr_file = syscalls/errstr.go
+if LIBGO_IS_LINUX
+syscall_errstr_decl_file = syscalls/errstr_decl_linux.go
+else
+syscall_errstr_decl_file = syscalls/errstr_decl.go
+endif
+endif
+
+go_syscall_files = \
+       $(syscall_errstr_file) \
+       $(syscall_errstr_decl_file) \
+       syscalls/exec_helpers.go \
+       $(syscall_exec_os_file) \
+       syscalls/socket.go \
+       $(syscall_socket_os_file) \
+       $(syscall_socket_epoll_file) \
+       $(syscall_syscall_file) \
+       syscalls/syscall_unix.go \
+       syscalls/stringbyte.go \
+       $(syscall_os_file) \
+       $(syscall_arch_file) \
+       syscalls/sysfile_posix.go \
+       $(syscall_sysfile_os_file) \
+       sysinfo.go
+go_syscall_c_files = \
+       syscalls/errno.c
+
+libgo_go_objs = \
+       asn1/libasn1.la \
+       big/libbig.la \
+       bufio/libbufio.la \
+       bytes/libbytes.la \
+       cmath/libcmath.la \
+       ebnf/libebnf.la \
+       exec/libexec.la \
+       expvar/libexpvar.la \
+       flag/libflag.la \
+       fmt/libfmt.la \
+       gob/libgob.la \
+       hash/libhash.la \
+       html/libhtml.la \
+       http/libhttp.la \
+       image/libimage.la \
+       io/libio.la \
+       json/libjson.la \
+       log/liblog.la \
+       math/libmath.la \
+       mime/libmime.la \
+       net/libnet.la \
+       netchan/libnetchan.la \
+       os/libos.la \
+       patch/libpatch.la \
+       path/libpath.la \
+       rand/librand.la \
+       reflect/libreflect.la \
+       regexp/libregexp.la \
+       rpc/librpc.la \
+       runtime/libruntime.la \
+       scanner/libscanner.la \
+       smtp/libsmtp.la \
+       sort/libsort.la \
+       strconv/libstrconv.la \
+       strings/libstrings.la \
+       sync/libsync.la \
+       syslog/libsyslog.la \
+       tabwriter/libtabwriter.la \
+       template/libtemplate.la \
+       time/libtime.la \
+       try/libtry.la \
+       unicode/libunicode.la \
+       utf16/libutf16.la \
+       utf8/libutf8.la \
+       websocket/libwebsocket.la \
+       xml/libxml.la \
+       archive/libtar.la \
+       archive/libzip.la \
+       compress/libflate.la \
+       compress/libgzip.la \
+       compress/libzlib.la \
+       container/libheap.la \
+       container/liblist.la \
+       container/libring.la \
+       container/libvector.la \
+       crypto/libaes.la \
+       crypto/libblock.la \
+       crypto/libblowfish.la \
+       crypto/libcast5.la \
+       crypto/libhmac.la \
+       crypto/libmd4.la \
+       crypto/libmd5.la \
+       crypto/libocsp.la \
+       crypto/librand.la \
+       crypto/librc4.la \
+       crypto/libripemd160.la \
+       crypto/librsa.la \
+       crypto/libsha1.la \
+       crypto/libsha256.la \
+       crypto/libsha512.la \
+       crypto/libsubtle.la \
+       crypto/libtls.la \
+       crypto/libx509.la \
+       crypto/libxtea.la \
+       debug/libdwarf.la \
+       debug/libelf.la \
+       debug/libgosym.la \
+       debug/libmacho.la \
+       debug/libpe.la \
+       debug/libproc.la \
+       encoding/libascii85.la \
+       encoding/libbase64.la \
+       encoding/libbinary.la \
+       encoding/libgit85.la \
+       encoding/libhex.la \
+       encoding/libpem.la \
+       exp/libdatafmt.la \
+       exp/libdraw.la \
+       exp/libeval.la \
+       go/libast.la \
+       go/libdoc.la \
+       go/libparser.la \
+       go/libprinter.la \
+       go/libscanner.la \
+       go/libtoken.la \
+       go/libtypechecker.la \
+       hash/libadler32.la \
+       hash/libcrc32.la \
+       hash/libcrc64.la \
+       http/libpprof.la \
+       image/libjpeg.la \
+       image/libpng.la \
+       index/libsuffixarray.la \
+       io/libioutil.la \
+       mime/libmultipart.la \
+       net/libdict.la \
+       net/libtextproto.la \
+       os/libsignal.la \
+       rpc/libjsonrpc.la \
+       runtime/libpprof.la \
+       syscalls/libsyscall.la \
+       testing/libtesting.la \
+       testing/libiotest.la \
+       testing/libquick.la \
+       testing/libscript.la
+
+libgo_la_SOURCES = $(runtime_files)
+
+libgo_la_LIBADD = $(libgo_go_objs) $(LIBFFI) -lpthread
+
+libgobegin_a_SOURCES = \
+       runtime/go-main.c
+
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
+
+GOCFLAGS = $(CFLAGS)
+AM_GOCFLAGS = $(STRINGOPS_FLAG)
+GOCOMPILE = $(GOC) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_GOCFLAGS) $(GOCFLAGS)
+
+LTGOCOMPILE = $(LIBTOOL) --tag GO --mode=compile $(GOC) $(INCLUDES) \
+       $(AM_GOCFLAGS) $(GOCFLAGS)
+
+GOLINK = $(LIBTOOL) --tag GO --mode-link $(GOC) \
+       $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_GOCFLAGS) $(LTLDFLAGS) \
+       -lpthread -o $@
+
+# Build a package.
+BUILDARCHIVE = \
+       rm -f `echo $@ | sed -e 's|/lib|/|' -e 's/\.a/.gox/'`; \
+       test -d $(@D) || $(MKDIR_P) $(@D); \
+       rm -f $@; \
+       files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
+       if $(LTGOCOMPILE) -c -fgo-prefix="libgo_$(@D)" -o $@.$(OBJEXT) $$files; then \
+         $(AR) rc $@ $@.$(OBJEXT); \
+       else exit 1; fi
+
+# Build a .la file from a .a file.
+.a.la:
+       $(LINK) $<.lo
+
+if LIBGO_IS_RTEMS
+use_dejagnu = yes
+else
+use_dejagnu = no
+endif
+
+# Check a package.
+CHECK = \
+       @GC="$(GOC) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs -Wl,-R,`${PWD_COMMAND}`/.libs"; \
+       export GC; \
+       RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
+       export RUNTESTFLAGS; \
+       MAKE="$(MAKE)"; \
+       export MAKE; \
+       rm -f $@-log; \
+       echo -n "$(@D) " >$@-log 2>&1; \
+       prefix=`if test "$(@D)" = "regexp"; then echo regexp-test; else dirname $(@D); fi`; \
+       test "$${prefix}" != "." || prefix="$(@D)"; \
+       $(srcdir)/testsuite/gotest --dejagnu=$(use_dejagnu) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --prefix="libgo_$${prefix}" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" >>$@-log 2>&1; \
+       x=$$?; \
+       cat $@-log; \
+       exit $$x
+
+# Build all packages before checking any.
+CHECK_DEPS = libgo.la libgobegin.a \
+       $(toolexeclib_DATA) \
+       $(toolexeclibarchive_DATA) \
+       $(toolexeclibcompress_DATA) \
+       $(toolexeclibcontainer_DATA) \
+       $(toolexeclibcrypto_DATA) \
+       $(toolexeclibdebug_DATA) \
+       $(toolexeclibencoding_DATA) \
+       $(toolexeclibexp_DATA) \
+       $(toolexeclibgo_DATA) \
+       $(toolexeclibhash_DATA) \
+       $(toolexeclibhttp_DATA) \
+       $(toolexeclibimage_DATA) \
+       $(toolexeclibio_DATA) \
+       $(toolexeclibos_DATA) \
+       $(toolexeclibrpc_DATA) \
+       $(toolexeclibruntime_DATA) \
+       $(toolexeclibtesting_DATA)
+
+asn1/libasn1.a: $(go_asn1_files) bytes.gox fmt.gox io.gox os.gox reflect.gox \
+               strconv.gox strings.gox time.gox
+       $(BUILDARCHIVE)
+asn1/libasn1.la: asn1/libasn1.a
+asn1/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: asn1/check
+
+big/libbig.a: $(go_big_files) fmt.gox rand.gox strings.gox
+       $(BUILDARCHIVE)
+big/libbig.la: big/libbig.a
+big/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: big/check
+
+bufio/libbufio.a: $(go_bufio_files) bytes.gox io.gox os.gox strconv.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+bufio/libbufio.la: bufio/libbufio.a
+bufio/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: bufio/check
+
+bytes/libbytes.a: $(go_bytes_files) $(go_bytes_c_files) io.gox os.gox utf8.gox
+       test -d bytes || $(MKDIR_P) bytes
+       $(LTGOCOMPILE) -c -o bytes/bytes.$(OBJEXT) -fgo-prefix=libgo_bytes $(srcdir)/go/bytes/buffer.go $(srcdir)/go/bytes/bytes.go $(srcdir)/go/bytes/bytes_decl.go
+       $(LTCOMPILE) -c -o bytes/index.$(OBJEXT) $(srcdir)/go/bytes/indexbyte.c
+       rm -f $@
+       $(AR) rc $@ bytes/bytes.$(OBJEXT) bytes/index.$(OBJEXT)
+bytes/libbytes.la: bytes/libbytes.a
+       $(LINK) bytes/bytes.lo bytes/index.lo
+bytes/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: bytes/check
+
+cmath/libcmath.a: $(go_cmath_files) math.gox
+       $(BUILDARCHIVE)
+cmath/libcmath.la: cmath/libcmath.a
+cmath/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: cmath/check
+
+ebnf/libebnf.a: $(go_ebnf_files) container/vector.gox go/scanner.gox \
+               go/token.gox os.gox strconv.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+ebnf/libebnf.la: ebnf/libebnf.a
+ebnf/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: ebnf/check
+
+exec/libexec.a: $(go_exec_files) os.gox strings.gox
+       $(BUILDARCHIVE)
+exec/libexec.la: exec/libexec.a
+exec/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: exec/check
+
+expvar/libexpvar.a: $(go_expvar_files) bytes.gox fmt.gox http.gox json.gox \
+               log.gox os.gox runtime.gox strconv.gox sync.gox
+       $(BUILDARCHIVE)
+expvar/libexpvar.la: expvar/libexpvar.a
+expvar/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: expvar/check
+
+flag/libflag.a: $(go_flag_files) fmt.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+flag/libflag.la: flag/libflag.a
+flag/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: flag/check
+
+fmt/libfmt.a: $(go_fmt_files) bytes.gox io.gox os.gox reflect.gox strconv.gox \
+               strings.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+fmt/libfmt.la: fmt/libfmt.a
+fmt/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: fmt/check
+
+gob/libgob.a: $(go_gob_files) bytes.gox fmt.gox io.gox math.gox os.gox \
+               reflect.gox runtime.gox strings.gox sync.gox unicode.gox
+       $(BUILDARCHIVE)
+gob/libgob.la: gob/libgob.a
+gob/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: gob/check
+
+hash/libhash.a: $(go_hash_files) io.gox
+       $(BUILDARCHIVE)
+hash/libhash.la: hash/libhash.a
+hash/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: hash/check
+
+html/libhtml.a: $(go_html_files) bytes.gox io.gox os.gox strconv.gox \
+               strings.gox utf8.gox
+       $(BUILDARCHIVE)
+html/libhtml.la: html/libhtml.a
+html/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: html/check
+
+http/libhttp.a: $(go_http_files) bufio.gox bytes.gox container/list.gox \
+               container/vector.gox crypto/rand.gox crypto/tls.gox \
+               encoding/base64.gox fmt.gox io.gox io/ioutil.gox log.gox \
+               mime.gox mime/multipart.gox net.gox os.gox path.gox sort.gox \
+               strconv.gox strings.gox sync.gox time.gox utf8.gox
+       $(BUILDARCHIVE)
+http/libhttp.la: http/libhttp.a
+http/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: http/check
+
+image/libimage.a: $(go_image_files) bufio.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+image/libimage.la: image/libimage.a
+image/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: image/check
+
+io/libio.a: $(go_io_files) os.gox runtime.gox sync.gox
+       $(BUILDARCHIVE)
+io/libio.la: io/libio.a
+io/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: io/check
+
+json/libjson.a: $(go_json_files) bytes.gox container/vector.gox fmt.gox \
+               io.gox math.gox os.gox reflect.gox runtime.gox strconv.gox \
+               strings.gox unicode.gox utf16.gox utf8.gox
+       $(BUILDARCHIVE)
+json/libjson.la: json/libjson.a
+json/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: json/check
+
+log/liblog.a: $(go_log_files) bytes.gox fmt.gox io.gox runtime.gox os.gox \
+               time.gox
+       $(BUILDARCHIVE)
+log/liblog.la: log/liblog.a
+log/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: log/check
+
+math/libmath.a: $(go_math_files)
+       $(BUILDARCHIVE)
+math/libmath.la: math/libmath.a
+math/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: math/check
+
+mime/libmime.a: $(go_mime_files) bufio.gox bytes.gox os.gox strings.gox \
+               sync.gox unicode.gox
+       $(BUILDARCHIVE)
+mime/libmime.la: mime/libmime.a
+mime/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: mime/check
+
+net/libnet.a: $(go_net_files) fmt.gox io.gox os.gox reflect.gox strconv.gox \
+               strings.gox sync.gox syscall.gox
+       $(BUILDARCHIVE)
+net/libnet.la: net/libnet.a
+net/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: net/check
+
+netchan/libnetchan.a: $(go_netchan_files) gob.gox log.gox net.gox os.gox \
+               reflect.gox sync.gox time.gox
+       $(BUILDARCHIVE)
+netchan/libnetchan.la: netchan/libnetchan.a
+netchan/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: netchan/check
+
+os/libos.a: $(go_os_files) sync.gox syscall.gox
+       $(BUILDARCHIVE)
+os/libos.la: os/libos.a
+os/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: os/check
+
+patch/libpatch.a: $(go_patch_files) bytes.gox compress/zlib.gox \
+               crypto/sha1.gox encoding/git85.gox fmt.gox io.gox os.gox \
+               path.gox strings.gox
+       $(BUILDARCHIVE)
+patch/libpatch.la: patch/libpatch.a
+patch/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: patch/check
+
+path/libpath.a: $(go_path_files) io/ioutil.gox os.gox sort.gox strings.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+path/libpath.la: path/libpath.a
+path/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: path/check
+
+rand/librand.a: $(go_rand_files) math.gox sync.gox
+       $(BUILDARCHIVE)
+rand/librand.la: rand/librand.a
+rand/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: rand/check
+
+reflect/libreflect.a: $(go_reflect_files) math.gox runtime.gox strconv.gox \
+               sync.gox
+       $(BUILDARCHIVE)
+reflect/libreflect.la: reflect/libreflect.a
+reflect/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: reflect/check
+
+regexp/libregexp.a: $(go_regexp_files) bytes.gox io.gox os.gox strings.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+regexp/libregexp.la: regexp/libregexp.a
+regexp/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: regexp/check
+
+rpc/librpc.a: $(go_rpc_files) bufio.gox fmt.gox gob.gox http.gox io.gox \
+               log.gox net.gox os.gox reflect.gox sort.gox strings.gox \
+               strconv.gox sync.gox template.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+rpc/librpc.la: rpc/librpc.a
+rpc/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: rpc/check
+
+runtime/libruntime.a: $(go_runtime_files)
+       $(BUILDARCHIVE)
+runtime/libruntime.la: runtime/libruntime.a
+runtime/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: runtime/check
+
+scanner/libscanner.a: $(go_scanner_files) bytes.gox fmt.gox io.gox os.gox \
+               unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+scanner/libscanner.la: scanner/libscanner.a
+scanner/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: scanner/check
+
+smtp/libsmtp.a: $(go_smtp_files) crypto/tls.gox encoding/base64.gox io.gox \
+               net.gox net/textproto.gox os.gox strings.gox
+       $(BUILDARCHIVE)
+smtp/libsmtp.la: smtp/libsmtp.a
+smtp/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: smtp/check
+
+sort/libsort.a: $(go_sort_files)
+       $(BUILDARCHIVE)
+sort/libsort.la: sort/libsort.a
+sort/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: sort/check
+
+strconv/libstrconv.a: $(go_strconv_files) bytes.gox math.gox os.gox \
+               strings.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+strconv/libstrconv.la: strconv/libstrconv.a
+strconv/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: strconv/check
+
+strings/libstrings.a: $(go_strings_files) os.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+strings/libstrings.la: strings/libstrings.a
+strings/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: strings/check
+
+sync/libsync.a: $(go_sync_files) $(go_sync_c_files) runtime.gox
+       test -d sync || $(MKDIR_P) sync
+       $(LTGOCOMPILE) -c -o sync/mutex.$(OBJEXT) -fgo-prefix=libgo_sync $(srcdir)/go/sync/mutex.go $(srcdir)/go/sync/once.go $(srcdir)/go/sync/rwmutex.go
+       $(LTCOMPILE) -c -o sync/cas.$(OBJEXT) $(srcdir)/go/sync/cas.c
+       rm -f $@
+       $(AR) rc $@ sync/mutex.$(OBJEXT) sync/cas.$(OBJEXT)
+sync/libsync.la: sync/libsync.a
+       $(LINK) sync/mutex.lo sync/cas.lo
+sync/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: sync/check
+
+syslog/libsyslog.a: $(go_syslog_files) fmt.gox log.gox net.gox os.gox
+       $(BUILDARCHIVE)
+syslog/libsyslog.la: syslog/libsyslog.a
+syslog/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: syslog/check
+
+tabwriter/libtabwriter.a: $(go_tabwriter_files) bytes.gox io.gox os.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+tabwriter/libtabwriter.la: tabwriter/libtabwriter.a
+tabwriter/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: tabwriter/check
+
+template/libtemplate.a: $(go_template_files) bytes.gox fmt.gox io.gox os.gox \
+               reflect.gox runtime.gox strings.gox container/vector.gox
+       $(BUILDARCHIVE)
+template/libtemplate.la: template/libtemplate.a
+template/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: template/check
+
+testing/libtesting.a: $(go_testing_files) flag.gox fmt.gox os.gox regexp.gox \
+               runtime.gox time.gox
+       $(BUILDARCHIVE)
+testing/libtesting.la: testing/libtesting.a
+testing/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: testing/check
+
+time/libtime.a: $(go_time_files) bytes.gox io/ioutil.gox os.gox strconv.gox \
+               sync.gox syscall.gox
+       $(BUILDARCHIVE)
+time/libtime.la: time/libtime.a
+time/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: time/check
+
+try/libtry.a: $(go_try_files) fmt.gox io.gox os.gox reflect.gox unicode.gox
+       $(BUILDARCHIVE)
+try/libtry.la: try/libtry.a
+try/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: try/check
+
+unicode/libunicode.a: $(go_unicode_files)
+       $(BUILDARCHIVE)
+unicode/libunicode.la: unicode/libunicode.a
+unicode/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: unicode/check
+
+utf16/libutf16.a: $(go_utf16_files) unicode.gox
+       $(BUILDARCHIVE)
+utf16/libutf16.la: utf16/libutf16.a
+utf16/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: utf16/check
+
+utf8/libutf8.a: $(go_utf8_files) unicode.gox
+       $(BUILDARCHIVE)
+utf8/libutf8.la: utf8/libutf8.a
+utf8/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: utf8/check
+
+websocket/libwebsocket.a: $(go_websocket_files) bufio.gox bytes.gox \
+               container/vector.gox crypto/md5.gox crypto/tls.gox \
+               encoding/binary.gox fmt.gox http.gox io.gox net.gox os.gox \
+               rand.gox strings.gox
+       $(BUILDARCHIVE)
+websocket/libwebsocket.la: websocket/libwebsocket.a
+websocket/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: websocket/check
+
+xml/libxml.a: $(go_xml_files) bufio.gox bytes.gox io.gox os.gox reflect.gox \
+               strconv.gox strings.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+xml/libxml.la: xml/libxml.a
+xml/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: xml/check
+
+archive/libtar.a: $(go_archive_tar_files) bytes.gox io.gox os.gox strconv.gox \
+               strings.gox
+       $(BUILDARCHIVE)
+archive/libtar.la: archive/libtar.a
+archive/tar/check: $(CHECK_DEPS)
+       @$(MKDIR_P) archive/tar
+       $(CHECK)
+.PHONY: archive/tar/check
+
+archive/libzip.a: $(go_archive_zip_files) bufio.gox bytes.gox \
+               compress/flate.gox hash.gox hash/crc32.gox \
+               encoding/binary.gox io.gox os.gox
+       $(BUILDARCHIVE)
+archive/libzip.la: archive/libzip.a
+archive/zip/check: $(CHECK_DEPS)
+       @$(MKDIR_P) archive/zip
+       $(CHECK)
+.PHONY: archive/zip/check
+
+compress/libflate.a: $(go_compress_flate_files) bufio.gox io.gox math.gox \
+               os.gox sort.gox strconv.gox
+       $(BUILDARCHIVE)
+compress/libflate.la: compress/libflate.a
+compress/flate/check: $(CHECK_DEPS)
+       @$(MKDIR_P) compress/flate
+       $(CHECK)
+.PHONY: compress/flate/check
+
+compress/libgzip.a: $(go_compress_gzip_files) bufio.gox compress/flate.gox \
+               hash.gox hash/crc32.gox io.gox os.gox
+       $(BUILDARCHIVE)
+compress/libgzip.la: compress/libgzip.a
+compress/gzip/check: $(CHECK_DEPS)
+       @$(MKDIR_P) compress/gzip
+       $(CHECK)
+.PHONY: compress/gzip/check
+
+compress/libzlib.a: $(go_compress_zlib_files) bufio.gox compress/flate.gox \
+               hash.gox hash/adler32.gox io.gox os.gox
+       $(BUILDARCHIVE)
+compress/libzlib.la: compress/libzlib.a
+compress/zlib/check: $(CHECK_DEPS)
+       @$(MKDIR_P) compress/zlib
+       $(CHECK)
+.PHONY: compress/zlib/check
+
+container/libheap.a: $(go_container_heap_files) sort.gox
+       $(BUILDARCHIVE)
+container/libheap.la: container/libheap.a
+container/heap/check: $(CHECK_DEPS)
+       @$(MKDIR_P) container/heap
+       $(CHECK)
+.PHONY: container/heap/check
+
+container/liblist.a: $(go_container_list_files)
+       $(BUILDARCHIVE)
+container/liblist.la: container/liblist.a
+container/list/check: $(CHECK_DEPS)
+       @$(MKDIR_P) container/list
+       $(CHECK)
+.PHONY: container/list/check
+
+container/libring.a: $(go_container_ring_files)
+       $(BUILDARCHIVE)
+container/libring.la: container/libring.a
+container/ring/check: $(CHECK_DEPS)
+       @$(MKDIR_P) container/ring
+       $(CHECK)
+.PHONY: container/ring/check
+
+container/libvector.a: $(go_container_vector_files)
+       $(BUILDARCHIVE)
+container/libvector.la: container/libvector.a
+container/vector/check: $(CHECK_DEPS)
+       @$(MKDIR_P) container/vector
+       $(CHECK)
+.PHONY: container/vector/check
+
+crypto/libaes.a: $(go_crypto_aes_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/libaes.la: crypto/libaes.a
+crypto/aes/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/aes
+       $(CHECK)
+.PHONY: crypto/aes/check
+
+crypto/libblock.a: $(go_crypto_block_files) fmt.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/libblock.la: crypto/libblock.a
+crypto/block/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/block
+       $(CHECK)
+.PHONY: crypto/block/check
+
+crypto/libblowfish.a: $(go_crypto_blowfish_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/libblowfish.la: crypto/libblowfish.a
+crypto/blowfish/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/blowfish
+       $(CHECK)
+.PHONY: crypto/blowfish/check
+
+crypto/libcast5.a: $(go_crypto_cast5_files) os.gox
+       $(BUILDARCHIVE)
+crypto/libcast5.la: crypto/libcast5.a
+crypt/cast5/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/cast5
+       $(CHECK)
+.PHONY: crypto/cast5/check
+
+crypto/libhmac.a: $(go_crypto_hmac_files) crypto/md5.gox crypto/sha1.gox \
+               hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libhmac.la: crypto/libhmac.a
+crypto/hmac/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/hmac
+       $(CHECK)
+.PHONY: crypto/hmac/check
+
+crypto/libmd4.a: $(go_crypto_md4_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libmd4.la: crypto/libmd4.a
+crypto/md4/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/md4
+       $(CHECK)
+.PHONY: crypto/md4/check
+
+crypto/libmd5.a: $(go_crypto_md5_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libmd5.la: crypto/libmd5.a
+crypto/md5/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/md5
+       $(CHECK)
+.PHONY: crypto/md5/check
+
+crypto/libocsp.a: $(go_crypto_ocsp_files) asn1.gox crypto/rsa.gox \
+               crypto/sha1.gox crypto/x509.gox os.gox time.gox
+       $(BUILDARCHIVE)
+crypto/libocsp.la: crypto/libocsp.a
+crypto/ocsp/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/ocsp
+       $(CHECK)
+.PHONY: crypto/ocsp/check
+
+crypto/librand.a: $(go_crypto_rand_files) crypto/aes.gox io.gox os.gox \
+               sync.gox time.gox
+       $(BUILDARCHIVE)
+crypto/librand.la: crypto/librand.a
+crypto/rand/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/rand
+       $(CHECK)
+.PHONY: crypto/rand/check
+
+crypto/librc4.a: $(go_crypto_rc4_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/librc4.la: crypto/librc4.a
+crypto/rc4/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/rc4
+       $(CHECK)
+.PHONY: crypto/rc4/check
+
+crypto/libripemd160.a: $(go_crypto_ripemd160_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libripemd160.la: crypto/libripemd160.a
+crypto/ripemd160/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/ripemd160
+       $(CHECK)
+.PHONY: crypto/ripemd160/check
+
+crypto/librsa.a: $(go_crypto_rsa_files) big.gox crypto/sha1.gox \
+               crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox
+       $(BUILDARCHIVE)
+crypto/librsa.la: crypto/librsa.a
+crypto/rsa/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/rsa
+       $(CHECK)
+.PHONY: crypto/rsa/check
+
+crypto/libsha1.a: $(go_crypto_sha1_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libsha1.la: crypto/libsha1.a
+crypto/sha1/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/sha1
+       $(CHECK)
+.PHONY: crypto/sha1/check
+
+crypto/libsha256.a: $(go_crypto_sha256_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libsha256.la: crypto/libsha256.a
+crypto/sha256/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/sha256
+       $(CHECK)
+.PHONY: crypto/sha256/check
+
+crypto/libsha512.a: $(go_crypto_sha512_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libsha512.la: crypto/libsha512.a
+crypto/sha512/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/sha512
+       $(CHECK)
+.PHONY: crypto/sha512/check
+
+crypto/libsubtle.a: $(go_crypto_subtle_files)
+       $(BUILDARCHIVE)
+crypto/libsubtle.la: crypto/libsubtle.a
+crypto/subtle/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/subtle
+       $(CHECK)
+.PHONY: crypto/subtle/check
+
+crypto/libtls.a: $(go_crypto_tls_files) bufio.gox bytes.gox container/list.gox \
+               crypto/hmac.gox crypto/md5.gox crypto/rc4.gox crypto/rand.gox \
+               crypto/rsa.gox crypto/sha1.gox crypto/subtle.gox \
+               crypto/rsa.gox crypto/x509.gox encoding/pem.gox fmt.gox \
+               hash.gox io.gox io/ioutil.gox net.gox os.gox strings.gox \
+               sync.gox time.gox
+       $(BUILDARCHIVE)
+crypto/libtls.la: crypto/libtls.a
+crypto/tls/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/tls
+       $(CHECK)
+.PHONY: crypto/tls/check
+
+crypto/libx509.a: $(go_crypto_x509_files) asn1.gox big.gox \
+               container/vector.gox crypto/rsa.gox crypto/sha1.gox hash.gox \
+               os.gox strings.gox time.gox
+       $(BUILDARCHIVE)
+crypto/libx509.la: crypto/libx509.a
+crypto/x509/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/x509
+       $(CHECK)
+.PHONY: crypto/x509/check
+
+crypto/libxtea.a: $(go_crypto_xtea_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/libxtea.la: crypto/libxtea.a
+crypto/xtea/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/xtea
+       $(CHECK)
+.PHONY: crypto/xtea/check
+
+debug/libdwarf.a: $(go_debug_dwarf_files) encoding/binary.gox os.gox \
+               strconv.gox
+       $(BUILDARCHIVE)
+debug/libdwarf.la: debug/libdwarf.a
+debug/dwarf/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/dwarf
+       $(CHECK)
+.PHONY: debug/dwarf/check
+
+debug/libelf.a: $(go_debug_elf_files) bytes.gox debug/dwarf.gox \
+               encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+debug/libelf.la: debug/libelf.a
+debug/elf/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/elf
+       $(CHECK)
+.PHONY: debug/elf/check
+
+debug/libgosym.a: $(go_debug_gosym_files) encoding/binary.gox fmt.gox os.gox \
+               strconv.gox strings.gox
+       $(BUILDARCHIVE)
+debug/libgosym.la: debug/libgosym.a
+debug/gosym/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/gosym
+       $(CHECK)
+.PHONY: debug/gosym/check
+
+debug/libmacho.a: $(go_debug_macho_files) bytes.gox debug/dwarf.gox \
+               encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+debug/libmacho.la: debug/libmacho.a
+debug/macho/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/macho
+       $(CHECK)
+.PHONY: debug/macho/check
+
+debug/libpe.a: $(go_debug_pe_files) debug/dwarf.gox encoding/binary.gox \
+               fmt.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+debug/libpe.la: debug/libpe.a
+debug/pe/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/pe
+       $(CHECK)
+.PHONY: debug/pe/check
+
+debug/libproc.a: $(go_debug_proc_files) container/vector.gox fmt.gox \
+               io/ioutil.gox os.gox runtime.gox strconv.gox strings.gox \
+               sync.gox syscall.gox
+       $(BUILDARCHIVE)
+debug/libproc.la: debug/libproc.a
+debug/proc/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/proc
+       $(CHECK)
+.PHONY: debug/proc/check
+
+encoding/libascii85.a: $(go_encoding_ascii85_files) io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+encoding/libascii85.la: encoding/libascii85.a
+encoding/ascii85/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/ascii85
+       $(CHECK)
+.PHONY: encoding/ascii85/check
+
+encoding/libbase64.a: $(go_encoding_base64_files) io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+encoding/libbase64.la: encoding/libbase64.a
+encoding/base64/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/base64
+       $(CHECK)
+.PHONY: encoding/base64/check
+
+encoding/libbinary.a: $(go_encoding_binary_files) io.gox math.gox os.gox \
+               reflect.gox
+       $(BUILDARCHIVE)
+encoding/libbinary.la: encoding/libbinary.a
+encoding/binary/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/binary
+       $(CHECK)
+.PHONY: encoding/binary/check
+
+encoding/libgit85.a: $(go_encoding_git85_files) bytes.gox io.gox os.gox \
+               strconv.gox
+       $(BUILDARCHIVE)
+encoding/libgit85.la: encoding/libgit85.a
+encoding/git85/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/git85
+       $(CHECK)
+.PHONY: encoding/git85/check
+
+encoding/libhex.a: $(go_encoding_hex_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+encoding/libhex.la: encoding/libhex.a
+encoding/hex/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/hex
+       $(CHECK)
+.PHONY: encoding/hex/check
+
+encoding/libpem.a: $(go_encoding_pem_files) bytes.gox encoding/base64.gox
+       $(BUILDARCHIVE)
+encoding/libpem.la: encoding/libpem.a
+encoding/pem/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/pem
+       $(CHECK)
+.PHONY: encoding/pem/check
+
+exp/libdatafmt.a: $(go_exp_datafmt_files) bytes.gox container/vector.gox \
+               fmt.gox go/scanner.gox go/token.gox io.gox os.gox reflect.gox \
+               runtime.gox strconv.gox strings.gox
+       $(BUILDARCHIVE)
+exp/libdatafmt.la: exp/libdatafmt.a
+exp/datafmt/check: $(CHECK_DEPS)
+       @$(MKDIR_P) exp/datafmt
+       $(CHECK)
+.PHONY: exp/datafmt/check
+
+exp/libdraw.a: $(go_exp_draw_files) image.gox os.gox
+       $(BUILDARCHIVE)
+exp/libdraw.la: exp/libdraw.a
+exp/draw/check: $(CHECK_DEPS)
+       @$(MKDIR_P) exp/draw
+       $(CHECK)
+.PHONY: exp/draw/check
+
+exp/libeval.a: $(go_exp_eval_files) big.gox go/ast.gox go/parser.gox \
+               go/scanner.gox go/token.gox fmt.gox log.gox strconv.gox \
+               strings.gox os.gox reflect.gox runtime.gox sort.gox template.gox
+       $(BUILDARCHIVE)
+exp/libeval.la: exp/libeval.a
+exp/eval/check: $(CHECK_DEPS)
+       @$(MKDIR_P) exp/eval
+       $(CHECK)
+.PHONY: exp/eval/check
+
+go/libast.a: $(go_go_ast_files) fmt.gox go/token.gox io.gox os.gox \
+               reflect.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+go/libast.la: go/libast.a
+go/ast/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/ast
+       $(CHECK)
+.PHONY: go/ast/check
+
+go/libdoc.a: $(go_go_doc_files) go/ast.gox go/token.gox io.gox regexp.gox \
+               sort.gox strings.gox template.gox
+       $(BUILDARCHIVE)
+go/libdoc.la: go/libdoc.a
+go/doc/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/doc
+       $(CHECK)
+.PHONY: go/doc/check
+
+go/libparser.a: $(go_go_parser_files) bytes.gox fmt.gox go/ast.gox \
+               go/scanner.gox go/token.gox io.gox io/ioutil.gox os.gox \
+               path.gox strings.gox
+       $(BUILDARCHIVE)
+go/libparser.la: go/libparser.a
+go/parser/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/parser
+       $(CHECK)
+.PHONY: go/parser/check
+
+go/libprinter.a: $(go_go_printer_files) bytes.gox fmt.gox go/ast.gox \
+               go/token.gox io.gox os.gox reflect.gox runtime.gox \
+               strings.gox tabwriter.gox
+       $(BUILDARCHIVE)
+go/libprinter.la: go/libprinter.a
+go/printer/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/printer
+       $(CHECK)
+.PHONY: go/printer/check
+
+go/libscanner.a: $(go_go_scanner_files) bytes.gox container/vector.gox fmt.gox \
+               go/token.gox io.gox os.gox sort.gox strconv.gox unicode.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+go/libscanner.la: go/libscanner.a
+go/scanner/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/scanner
+       $(CHECK)
+.PHONY: go/scanner/check
+
+go/libtoken.a: $(go_go_token_files) fmt.gox strconv.gox
+       $(BUILDARCHIVE)
+go/libtoken.la: go/libtoken.a
+go/token/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/token
+       $(CHECK)
+.PHONY: go/token/check
+
+go/libtypechecker.a: $(go_go_typechecker_files) fmt.gox go/ast.gox \
+               go/token.gox go/scanner.gox os.gox
+       $(BUILDARCHIVE)
+go/libtypechecker.la: go/libtypechecker.a
+go/typechecker/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/typechecker
+       $(CHECK)
+.PHONY: go/typechecker/check
+
+hash/libadler32.a: $(go_hash_adler32_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+hash/libadler32.la: hash/libadler32.a
+hash/adler32/check: $(CHECK_DEPS)
+       @$(MKDIR_P) hash/adler32
+       $(CHECK)
+.PHONY: hash/adler32/check
+
+hash/libcrc32.a: $(go_hash_crc32_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+hash/libcrc32.la: hash/libcrc32.a
+hash/crc32/check: $(CHECK_DEPS)
+       @$(MKDIR_P) hash/crc32
+       $(CHECK)
+.PHONY: hash/crc32/check
+
+hash/libcrc64.a: $(go_hash_crc64_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+hash/libcrc64.la: hash/libcrc64.a
+hash/crc64/check: $(CHECK_DEPS)
+       @$(MKDIR_P) hash/crc64
+       $(CHECK)
+.PHONY: hash/crc64/check
+
+http/libpprof.a: $(go_http_pprof_files) bufio.gox fmt.gox http.gox os.gox \
+               runtime.gox runtime/pprof.gox strconv.gox strings.gox
+       $(BUILDARCHIVE)
+http/libpprof.la: http/libpprof.a
+http/pprof/check: $(CHECK_DEPS)
+       @$(MKDIR_P) http/pprof
+       $(CHECK)
+.PHONY: http/pprof/check
+
+image/libjpeg.a: $(go_image_jpeg_files) bufio.gox image.gox io.gox os.gox
+       $(BUILDARCHIVE)
+image/libjpeg.la: image/libjpeg.a
+image/jpeg/check: $(CHECK_DEPS)
+       @$(MKDIR_P) image/jpeg
+       $(CHECK)
+.PHONY: image/jpeg/check
+
+image/libpng.a: $(go_image_png_files) bufio.gox compress/zlib.gox fmt.gox \
+               hash.gox hash/crc32.gox image.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+image/libpng.la: image/libpng.a
+image/png/check: $(CHECK_DEPS)
+       @$(MKDIR_P) image/png
+       $(CHECK)
+.PHONY: image/png/check
+
+index/libsuffixarray.a: $(go_index_suffixarray_files) bytes.gox \
+               container/vector.gox sort.gox
+       $(BUILDARCHIVE)
+index/libsuffixarray.la: index/libsuffixarray.a
+index/suffixarray/check: $(CHECK_DEPS)
+       @$(MKDIR_P) index/suffixarray
+       $(CHECK)
+.PHONY: index/suffixarray/check
+
+io/libioutil.a: $(go_io_ioutil_files) bytes.gox io.gox os.gox sort.gox \
+               strconv.gox
+       $(BUILDARCHIVE)
+io/libioutil.la: io/libioutil.a
+io/ioutil/check: $(CHECK_DEPS)
+       @$(MKDIR_P) io/ioutil
+       $(CHECK)
+.PHONY: io/ioutil/check
+
+mime/libmultipart.a: $(go_mime_multipart_files) bufio.gox bytes.gox io.gox \
+               mime.gox os.gox regexp.gox strings.gox
+       $(BUILDARCHIVE)
+mime/libmultipart.la: mime/libmultipart.a
+mime/multipart/check: $(CHECK_DEPS)
+       @$(MKDIR_P) mime/multipart
+       $(CHECK)
+.PHONY: mime/multipart/check
+
+net/libdict.a: $(go_net_dict_files) container/vector.gox net/textproto.gox \
+               os.gox strconv.gox strings.gox
+       $(BUILDARCHIVE)
+net/libdict.la: net/libdict.a
+
+net/libtextproto.a: $(go_net_textproto_files) bufio.gox bytes.gox \
+               container/vector.gox fmt.gox io.gox io/ioutil.gox net.gox \
+               os.gox strconv.gox sync.gox
+       $(BUILDARCHIVE)
+net/libtextproto.la: net/libtextproto.a
+net/textproto/check: $(CHECK_DEPS)
+       @$(MKDIR_P) net/textproto
+       $(CHECK)
+.PHONY: net/textproto/check
+
+os/libsignal.a: $(go_os_signal_files) runtime.gox strconv.gox
+       $(BUILDARCHIVE)
+os/libsignal.la: os/libsignal.a
+os/signal/check: $(CHECK_DEPS)
+       @$(MKDIR_P) os/signal
+       $(CHECK)
+.PHONY: os/signal/check
+
+unix.go: $(srcdir)/go/os/signal/mkunix.sh sysinfo.go
+       $(SHELL) $(srcdir)/go/os/signal/mkunix.sh sysinfo.go > $@.tmp
+       mv -f $@.tmp $@
+
+rpc/libjsonrpc.a: $(go_rpc_jsonrpc_files) fmt.gox io.gox json.gox net.gox \
+               os.gox rpc.gox sync.gox
+       $(BUILDARCHIVE)
+rpc/libjsonrpc.la: rpc/libjsonrpc.a
+rpc/jsonrpc/check: $(CHECK_DEPS)
+       @$(MKDIR_P) rpc/jsonrpc
+       $(CHECK)
+.PHONY: rpc/jsonrpc/check
+
+runtime/libpprof.a: $(go_runtime_pprof_files) bufio.gox fmt.gox io.gox os.gox \
+               runtime.gox
+       $(BUILDARCHIVE)
+runtime/libpprof.la: runtime/libpprof.a
+runtime/pprof/check: $(CHECK_DEPS)
+       @$(MKDIR_P) runtime/pprof
+       $(CHECK)
+.PHONY: runtime/pprof/check
+
+testing/libiotest.a: $(go_testing_iotest_files) io.gox log.gox os.gox
+       $(BUILDARCHIVE)
+testing/libiotest.la: testing/libiotest.a
+testing/iotest/check: $(CHECK_DEPS)
+       @$(MKDIR_P) testing/iotest
+       $(CHECK)
+.PHONY: testing/iotest/check
+
+testing/libquick.a: $(go_testing_quick_files) flag.gox fmt.gox math.gox \
+               os.gox rand.gox reflect.gox strings.gox
+       $(BUILDARCHIVE)
+testing/libquick.la: testing/libquick.a
+testing/quick/check: $(CHECK_DEPS)
+       @$(MKDIR_P) testing/quick
+       $(CHECK)
+.PHONY: testing/quick/check
+
+testing/libscript.a: $(go_testing_script_files) fmt.gox os.gox rand.gox \
+               reflect.gox strings.gox
+       $(BUILDARCHIVE)
+testing/libscript.la: testing/libscript.a
+testing/script/check: $(CHECK_DEPS)
+       @$(MKDIR_P) testing/script
+       $(CHECK)
+.PHONY: testing/script/check
+
+sysinfo.go: $(srcdir)/mksysinfo.sh config.h
+       $(SHELL) $(srcdir)/mksysinfo.sh
+syscalls/libsyscall.a: $(go_syscall_files) $(go_syscall_c_files) sync.gox
+       rm -f syscall.gox syscalls/libsyscall.a
+       test -d syscalls || $(MKDIR_P) syscalls
+       files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e's/[^ ]*\.c//g'`; \
+       $(LTGOCOMPILE) -c -fgo-prefix="libgo_syscalls" -o syscalls/syscall.$(OBJEXT) $$files
+       $(LTCOMPILE) -c -o syscalls/errno.$(OBJEXT) $(srcdir)/syscalls/errno.c
+       $(AR) rc syscalls/libsyscall.a syscalls/syscall.$(OBJEXT) syscalls/errno.$(OBJEXT)
+syscalls/libsyscall.la: syscalls/libsyscall.a
+       $(LINK) syscalls/syscall.lo syscalls/errno.lo
+
+# How to build a .gox file from a .a file.
+BUILDGOX = \
+       set -e; \
+       rm -f $@.$(OBJEXT); \
+       $(CC) -r -nostdlib -o $@.$(OBJEXT) -Wl,--whole-archive $<; \
+       $(OBJCOPY) -j .go_export $@.$(OBJEXT) $@.tmp; \
+       mv -f $@.tmp $@; \
+       rm -f $@.$(OBJEXT)
+
+asn1.gox: asn1/libasn1.a
+       $(BUILDGOX)
+big.gox: big/libbig.a
+       $(BUILDGOX)
+bufio.gox: bufio/libbufio.a
+       $(BUILDGOX)
+bytes.gox: bytes/libbytes.a
+       $(BUILDGOX)
+cmath.gox: cmath/libcmath.a
+       $(BUILDGOX)
+ebnf.gox: ebnf/libebnf.a
+       $(BUILDGOX)
+exec.gox: exec/libexec.a
+       $(BUILDGOX)
+expvar.gox: expvar/libexpvar.a
+       $(BUILDGOX)
+flag.gox: flag/libflag.a
+       $(BUILDGOX)
+fmt.gox: fmt/libfmt.a
+       $(BUILDGOX)
+gob.gox: gob/libgob.a
+       $(BUILDGOX)
+hash.gox: hash/libhash.a
+       $(BUILDGOX)
+html.gox: html/libhtml.a
+       $(BUILDGOX)
+http.gox: http/libhttp.a
+       $(BUILDGOX)
+image.gox: image/libimage.a
+       $(BUILDGOX)
+io.gox: io/libio.a
+       $(BUILDGOX)
+json.gox: json/libjson.a
+       $(BUILDGOX)
+log.gox: log/liblog.a
+       $(BUILDGOX)
+math.gox: math/libmath.a
+       $(BUILDGOX)
+mime.gox: mime/libmime.a
+       $(BUILDGOX)
+net.gox: net/libnet.a
+       $(BUILDGOX)
+netchan.gox: netchan/libnetchan.a
+       $(BUILDGOX)
+os.gox: os/libos.a
+       $(BUILDGOX)
+patch.gox: patch/libpatch.a
+       $(BUILDGOX)
+path.gox: path/libpath.a
+       $(BUILDGOX)
+rand.gox: rand/librand.a
+       $(BUILDGOX)
+reflect.gox: reflect/libreflect.a
+       $(BUILDGOX)
+regexp.gox: regexp/libregexp.a
+       $(BUILDGOX)
+rpc.gox: rpc/librpc.a
+       $(BUILDGOX)
+runtime.gox: runtime/libruntime.a
+       $(BUILDGOX)
+scanner.gox: scanner/libscanner.a
+       $(BUILDGOX)
+smtp.gox: smtp/libsmtp.a
+       $(BUILDGOX)
+sort.gox: sort/libsort.a
+       $(BUILDGOX)
+strconv.gox: strconv/libstrconv.a
+       $(BUILDGOX)
+strings.gox: strings/libstrings.a
+       $(BUILDGOX)
+sync.gox: sync/libsync.a
+       $(BUILDGOX)
+syslog.gox: syslog/libsyslog.a
+       $(BUILDGOX)
+syscall.gox: syscalls/libsyscall.a
+       $(BUILDGOX)
+tabwriter.gox: tabwriter/libtabwriter.a
+       $(BUILDGOX)
+template.gox: template/libtemplate.a
+       $(BUILDGOX)
+testing.gox: testing/libtesting.a
+       $(BUILDGOX)
+time.gox: time/libtime.a
+       $(BUILDGOX)
+try.gox: try/libtry.a
+       $(BUILDGOX)
+unicode.gox: unicode/libunicode.a
+       $(BUILDGOX)
+utf16.gox: utf16/libutf16.a
+       $(BUILDGOX)
+utf8.gox: utf8/libutf8.a
+       $(BUILDGOX)
+websocket.gox: websocket/libwebsocket.a
+       $(BUILDGOX)
+xml.gox: xml/libxml.a
+       $(BUILDGOX)
+
+archive/tar.gox: archive/libtar.a
+       $(BUILDGOX)
+archive/zip.gox: archive/libzip.a
+       $(BUILDGOX)
+
+compress/flate.gox: compress/libflate.a
+       $(BUILDGOX)
+compress/gzip.gox: compress/libgzip.a
+       $(BUILDGOX)
+compress/zlib.gox: compress/libzlib.a
+       $(BUILDGOX)
+
+container/heap.gox: container/libheap.a
+       $(BUILDGOX)
+container/list.gox: container/liblist.a
+       $(BUILDGOX)
+container/ring.gox: container/libring.a
+       $(BUILDGOX)
+container/vector.gox: container/libvector.a
+       $(BUILDGOX)
+
+crypto/aes.gox: crypto/libaes.a
+       $(BUILDGOX)
+crypto/block.gox: crypto/libblock.a
+       $(BUILDGOX)
+crypto/blowfish.gox: crypto/libblowfish.a
+       $(BUILDGOX)
+crypto/cast5.gox: crypto/libcast5.a
+       $(BUILDGOX)
+crypto/hmac.gox: crypto/libhmac.a
+       $(BUILDGOX)
+crypto/md4.gox: crypto/libmd4.a
+       $(BUILDGOX)
+crypto/md5.gox: crypto/libmd5.a
+       $(BUILDGOX)
+crypto/ocsp.gox: crypto/libocsp.a
+       $(BUILDGOX)
+crypto/rand.gox: crypto/librand.a
+       $(BUILDGOX)
+crypto/rc4.gox: crypto/librc4.a
+       $(BUILDGOX)
+crypto/ripemd160.gox: crypto/libripemd160.a
+       $(BUILDGOX)
+crypto/rsa.gox: crypto/librsa.a
+       $(BUILDGOX)
+crypto/sha1.gox: crypto/libsha1.a
+       $(BUILDGOX)
+crypto/sha256.gox: crypto/libsha256.a
+       $(BUILDGOX)
+crypto/sha512.gox: crypto/libsha512.a
+       $(BUILDGOX)
+crypto/subtle.gox: crypto/libsubtle.a
+       $(BUILDGOX)
+crypto/tls.gox: crypto/libtls.a
+       $(BUILDGOX)
+crypto/x509.gox: crypto/libx509.a
+       $(BUILDGOX)
+crypto/xtea.gox: crypto/libxtea.a
+       $(BUILDGOX)
+
+debug/dwarf.gox: debug/libdwarf.a
+       $(BUILDGOX)
+debug/elf.gox: debug/libelf.a
+       $(BUILDGOX)
+debug/gosym.gox: debug/libgosym.a
+       $(BUILDGOX)
+debug/macho.gox: debug/libmacho.a
+       $(BUILDGOX)
+debug/pe.gox: debug/libpe.a
+       $(BUILDGOX)
+debug/proc.gox: debug/libproc.a
+       $(BUILDGOX)
+
+encoding/ascii85.gox: encoding/libascii85.a
+       $(BUILDGOX)
+encoding/base64.gox: encoding/libbase64.a
+       $(BUILDGOX)
+encoding/binary.gox: encoding/libbinary.a
+       $(BUILDGOX)
+encoding/git85.gox: encoding/libgit85.a
+       $(BUILDGOX)
+encoding/hex.gox: encoding/libhex.a
+       $(BUILDGOX)
+encoding/pem.gox: encoding/libpem.a
+       $(BUILDGOX)
+
+exp/datafmt.gox: exp/libdatafmt.a
+       $(BUILDGOX)
+exp/draw.gox: exp/libdraw.a
+       $(BUILDGOX)
+exp/eval.gox: exp/libeval.a
+       $(BUILDGOX)
+
+go/ast.gox: go/libast.a
+       $(BUILDGOX)
+go/doc.gox: go/libdoc.a
+       $(BUILDGOX)
+go/parser.gox: go/libparser.a
+       $(BUILDGOX)
+go/printer.gox: go/libprinter.a
+       $(BUILDGOX)
+go/scanner.gox: go/libscanner.a
+       $(BUILDGOX)
+go/token.gox: go/libtoken.a
+       $(BUILDGOX)
+go/typechecker.gox: go/libtypechecker.a
+       $(BUILDGOX)
+
+hash/adler32.gox: hash/libadler32.a
+       $(BUILDGOX)
+hash/crc32.gox: hash/libcrc32.a
+       $(BUILDGOX)
+hash/crc64.gox: hash/libcrc64.a
+       $(BUILDGOX)
+
+http/pprof.gox: http/libpprof.a
+       $(BUILDGOX)
+
+image/jpeg.gox: image/libjpeg.a
+       $(BUILDGOX)
+image/png.gox: image/libpng.a
+       $(BUILDGOX)
+
+index/suffixarray.gox: index/libsuffixarray.a
+       $(BUILDGOX)
+
+io/ioutil.gox: io/libioutil.a
+       $(BUILDGOX)
+
+mime/multipart.gox: mime/libmultipart.a
+       $(BUILDGOX)
+
+net/dict.gox: net/libdict.a
+       $(BUILDGOX)
+net/textproto.gox: net/libtextproto.a
+       $(BUILDGOX)
+
+os/signal.gox: os/libsignal.a
+       $(BUILDGOX)
+
+rpc/jsonrpc.gox: rpc/libjsonrpc.a
+       $(BUILDGOX)
+
+runtime/pprof.gox: runtime/libpprof.a
+       $(BUILDGOX)
+
+testing/iotest.gox: testing/libiotest.a
+       $(BUILDGOX)
+testing/quick.gox: testing/libquick.a
+       $(BUILDGOX)
+testing/script.gox: testing/libscript.a
+       $(BUILDGOX)
+
+TEST_PACKAGES = \
+       asn1/check \
+       big/check \
+       bufio/check \
+       bytes/check \
+       cmath/check \
+       ebnf/check \
+       exec/check \
+       expvar/check \
+       flag/check \
+       fmt/check \
+       gob/check \
+       html/check \
+       http/check \
+       io/check \
+       json/check \
+       log/check \
+       math/check \
+       mime/check \
+       net/check \
+       netchan/check \
+       os/check \
+       patch/check \
+       path/check \
+       rand/check \
+       reflect/check \
+       regexp/check \
+       rpc/check \
+       runtime/check \
+       scanner/check \
+       smtp/check \
+       sort/check \
+       strconv/check \
+       strings/check \
+       sync/check \
+       syslog/check \
+       tabwriter/check \
+       template/check \
+       time/check \
+       try/check \
+       unicode/check \
+       utf16/check \
+       utf8/check \
+       websocket/check \
+       xml/check \
+       archive/tar/check \
+       archive/zip/check \
+       compress/flate/check \
+       compress/gzip/check \
+       compress/zlib/check \
+       container/heap/check \
+       container/list/check \
+       container/ring/check \
+       container/vector/check \
+       crypto/aes/check \
+       crypto/block/check \
+       crypto/blowfish/check \
+       crypto/cast5/check \
+       crypto/hmac/check \
+       crypto/md4/check \
+       crypto/md5/check \
+       crypto/ocsp/check \
+       crypto/rand/check \
+       crypto/rc4/check \
+       crypto/ripemd160/check \
+       crypto/rsa/check \
+       crypto/sha1/check \
+       crypto/sha256/check \
+       crypto/sha512/check \
+       crypto/subtle/check \
+       crypto/tls/check \
+       crypto/x509/check \
+       crypto/xtea/check \
+       debug/dwarf/check \
+       debug/elf/check \
+       debug/macho/check \
+       debug/pe/check \
+       encoding/ascii85/check \
+       encoding/base64/check \
+       encoding/binary/check \
+       encoding/git85/check \
+       encoding/hex/check \
+       encoding/pem/check \
+       exp/datafmt/check \
+       exp/draw/check \
+       exp/eval/check \
+       go/parser/check \
+       go/printer/check \
+       go/scanner/check \
+       go/typechecker/check \
+       hash/adler32/check \
+       hash/crc32/check \
+       hash/crc64/check \
+       image/png/check \
+       index/suffixarray/check \
+       io/ioutil/check \
+       mime/multipart/check \
+       net/textproto/check \
+       os/signal/check \
+       rpc/jsonrpc/check \
+       testing/quick/check \
+       testing/script/check
+
+check-recursive: $(TEST_PACKAGES)
+
+mostlyclean-local:
+       find . -name '*.lo' -print | xargs $(LIBTOOL) --mode=clean rm -f
+       find . -name '*.$(OBJEXT)' -print | xargs rm -f
+
+clean-local:
+       find . -name '*.la' -print | xargs $(LIBTOOL) --mode=clean rm -f
+       find . -name '*.a' -print | xargs rm -f
+
+CLEANFILES = *.go *.gox goc2c *.c s-version
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
new file mode 100644 (file)
index 0000000..30b4ef1
--- /dev/null
@@ -0,0 +1,4829 @@
+# 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@
+
+# Makefile.am -- Go library Makefile.
+
+# Copyright 2009, 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Process this file with autoreconf to produce Makefile.in.
+
+
+
+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 = .
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/../config.guess \
+       $(srcdir)/../config.sub $(srcdir)/../depcomp \
+       $(srcdir)/../install-sh $(srcdir)/../ltmain.sh \
+       $(srcdir)/../missing $(srcdir)/../mkinstalldirs \
+       $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(srcdir)/config.h.in $(top_srcdir)/configure
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
+       $(top_srcdir)/../config/lead-dot.m4 \
+       $(top_srcdir)/../config/multi.m4 \
+       $(top_srcdir)/../config/override.m4 \
+       $(top_srcdir)/../config/unwind_ipinfo.m4 \
+       $(top_srcdir)/config/go.m4 $(top_srcdir)/config/libtool.m4 \
+       $(top_srcdir)/config/ltoptions.m4 \
+       $(top_srcdir)/config/ltsugar.m4 \
+       $(top_srcdir)/config/ltversion.m4 \
+       $(top_srcdir)/config/lt~obsolete.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
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+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)$(toolexeclibdir)" \
+       "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" \
+       "$(DESTDIR)$(toolexeclibarchivedir)" \
+       "$(DESTDIR)$(toolexeclibcompressdir)" \
+       "$(DESTDIR)$(toolexeclibcontainerdir)" \
+       "$(DESTDIR)$(toolexeclibcryptodir)" \
+       "$(DESTDIR)$(toolexeclibdebugdir)" \
+       "$(DESTDIR)$(toolexeclibencodingdir)" \
+       "$(DESTDIR)$(toolexeclibexpdir)" \
+       "$(DESTDIR)$(toolexeclibgodir)" \
+       "$(DESTDIR)$(toolexeclibhashdir)" \
+       "$(DESTDIR)$(toolexeclibhttpdir)" \
+       "$(DESTDIR)$(toolexeclibimagedir)" \
+       "$(DESTDIR)$(toolexeclibindexdir)" \
+       "$(DESTDIR)$(toolexeclibiodir)" \
+       "$(DESTDIR)$(toolexeclibmimedir)" \
+       "$(DESTDIR)$(toolexeclibnetdir)" \
+       "$(DESTDIR)$(toolexeclibosdir)" \
+       "$(DESTDIR)$(toolexeclibrpcdir)" \
+       "$(DESTDIR)$(toolexeclibruntimedir)" \
+       "$(DESTDIR)$(toolexeclibtestingdir)"
+LIBRARIES = $(toolexeclib_LIBRARIES)
+ARFLAGS = cru
+libgobegin_a_AR = $(AR) $(ARFLAGS)
+libgobegin_a_LIBADD =
+am_libgobegin_a_OBJECTS = go-main.$(OBJEXT)
+libgobegin_a_OBJECTS = $(am_libgobegin_a_OBJECTS)
+LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgo_la_DEPENDENCIES = $(libgo_go_objs) $(am__DEPENDENCIES_1)
+am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \
+       runtime/go-assert-interface.c \
+       runtime/go-byte-array-to-string.c runtime/go-breakpoint.c \
+       runtime/go-caller.c runtime/go-can-convert-interface.c \
+       runtime/go-chan-cap.c runtime/go-chan-len.c \
+       runtime/go-check-interface.c runtime/go-close.c \
+       runtime/go-closed.c runtime/go-construct-map.c \
+       runtime/go-convert-interface.c runtime/go-defer.c \
+       runtime/go-deferred-recover.c runtime/go-eface-compare.c \
+       runtime/go-eface-val-compare.c runtime/go-getgoroot.c \
+       runtime/go-go.c runtime/go-gomaxprocs.c \
+       runtime/go-int-array-to-string.c runtime/go-int-to-string.c \
+       runtime/go-interface-compare.c \
+       runtime/go-interface-val-compare.c runtime/go-lock-os-thread.c \
+       runtime/go-map-delete.c runtime/go-map-index.c \
+       runtime/go-map-len.c runtime/go-map-range.c \
+       runtime/go-nanotime.c runtime/go-new-channel.c \
+       runtime/go-new-map.c runtime/go-new.c runtime/go-note.c \
+       runtime/go-panic.c runtime/go-panic-defer.c runtime/go-print.c \
+       runtime/go-rec-big.c runtime/go-rec-nb-big.c \
+       runtime/go-rec-nb-small.c runtime/go-rec-small.c \
+       runtime/go-recover.c runtime/go-reflect.c \
+       runtime/go-reflect-call.c runtime/go-reflect-chan.c \
+       runtime/go-reflect-map.c runtime/go-rune.c \
+       runtime/go-runtime-error.c runtime/go-sched.c \
+       runtime/go-select.c runtime/go-semacquire.c \
+       runtime/go-send-big.c runtime/go-send-nb-big.c \
+       runtime/go-send-nb-small.c runtime/go-send-small.c \
+       runtime/go-signal.c runtime/go-strcmp.c \
+       runtime/go-string-to-byte-array.c \
+       runtime/go-string-to-int-array.c runtime/go-strplus.c \
+       runtime/go-strslice.c runtime/go-trampoline.c \
+       runtime/go-type-eface.c runtime/go-type-error.c \
+       runtime/go-type-identity.c runtime/go-type-interface.c \
+       runtime/go-type-string.c runtime/go-typedesc-equal.c \
+       runtime/go-typestring.c runtime/go-unreflect.c \
+       runtime/go-unsafe-new.c runtime/go-unsafe-newarray.c \
+       runtime/go-unsafe-pointer.c runtime/go-unwind.c \
+       runtime/mcache.c runtime/mcentral.c \
+       runtime/mem_posix_memalign.c runtime/mem.c runtime/mfinal.c \
+       runtime/mfixalloc.c runtime/mgc0.c runtime/mheap.c \
+       runtime/mheapmap32.c runtime/mheapmap64.c runtime/msize.c \
+       runtime/proc.c runtime/thread.c \
+       runtime/rtems-task-variable-add.c chan.c iface.c malloc.c \
+       map.c mprof.c reflect.c sigqueue.c string.c
+@HAVE_SYS_MMAN_H_FALSE@am__objects_1 = mem_posix_memalign.lo
+@HAVE_SYS_MMAN_H_TRUE@am__objects_1 = mem.lo
+@LIBGO_IS_RTEMS_TRUE@am__objects_2 = rtems-task-variable-add.lo
+am__objects_3 = go-append.lo go-assert.lo go-assert-interface.lo \
+       go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \
+       go-can-convert-interface.lo go-chan-cap.lo go-chan-len.lo \
+       go-check-interface.lo go-close.lo go-closed.lo \
+       go-construct-map.lo go-convert-interface.lo go-defer.lo \
+       go-deferred-recover.lo go-eface-compare.lo \
+       go-eface-val-compare.lo go-getgoroot.lo go-go.lo \
+       go-gomaxprocs.lo go-int-array-to-string.lo go-int-to-string.lo \
+       go-interface-compare.lo go-interface-val-compare.lo \
+       go-lock-os-thread.lo go-map-delete.lo go-map-index.lo \
+       go-map-len.lo go-map-range.lo go-nanotime.lo go-new-channel.lo \
+       go-new-map.lo go-new.lo go-note.lo go-panic.lo \
+       go-panic-defer.lo go-print.lo go-rec-big.lo go-rec-nb-big.lo \
+       go-rec-nb-small.lo go-rec-small.lo go-recover.lo go-reflect.lo \
+       go-reflect-call.lo go-reflect-chan.lo go-reflect-map.lo \
+       go-rune.lo go-runtime-error.lo go-sched.lo go-select.lo \
+       go-semacquire.lo go-send-big.lo go-send-nb-big.lo \
+       go-send-nb-small.lo go-send-small.lo go-signal.lo go-strcmp.lo \
+       go-string-to-byte-array.lo go-string-to-int-array.lo \
+       go-strplus.lo go-strslice.lo go-trampoline.lo go-type-eface.lo \
+       go-type-error.lo go-type-identity.lo go-type-interface.lo \
+       go-type-string.lo go-typedesc-equal.lo go-typestring.lo \
+       go-unreflect.lo go-unsafe-new.lo go-unsafe-newarray.lo \
+       go-unsafe-pointer.lo go-unwind.lo mcache.lo mcentral.lo \
+       $(am__objects_1) mfinal.lo mfixalloc.lo mgc0.lo mheap.lo \
+       mheapmap32.lo mheapmap64.lo msize.lo proc.lo thread.lo \
+       $(am__objects_2) chan.lo iface.lo malloc.lo map.lo mprof.lo \
+       reflect.lo sigqueue.lo string.lo
+am_libgo_la_OBJECTS = $(am__objects_3)
+libgo_la_OBJECTS = $(am_libgo_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+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 = $(libgobegin_a_SOURCES) $(libgo_la_SOURCES)
+DIST_SOURCES = $(libgobegin_a_SOURCES) $(am__libgo_la_SOURCES_DIST)
+MULTISRCTOP = 
+MULTIBUILDTOP = 
+MULTIDIRS = 
+MULTISUBDIR = 
+MULTIDO = true
+MULTICLEAN = true
+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 = $(toolexeclib_DATA) $(toolexeclibarchive_DATA) \
+       $(toolexeclibcompress_DATA) $(toolexeclibcontainer_DATA) \
+       $(toolexeclibcrypto_DATA) $(toolexeclibdebug_DATA) \
+       $(toolexeclibencoding_DATA) $(toolexeclibexp_DATA) \
+       $(toolexeclibgo_DATA) $(toolexeclibhash_DATA) \
+       $(toolexeclibhttp_DATA) $(toolexeclibimage_DATA) \
+       $(toolexeclibindex_DATA) $(toolexeclibio_DATA) \
+       $(toolexeclibmime_DATA) $(toolexeclibnet_DATA) \
+       $(toolexeclibos_DATA) $(toolexeclibrpc_DATA) \
+       $(toolexeclibruntime_DATA) $(toolexeclibtesting_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 = testsuite
+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@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+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@
+GOC = @GOC@
+GOCFLAGS = $(CFLAGS)
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBFFI = @LIBFFI@
+LIBFFIINCS = @LIBFFIINCS@
+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@
+OBJCOPY = @OBJCOPY@
+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@
+SPLIT_STACK = @SPLIT_STACK@
+STRINGOPS_FLAG = @STRINGOPS_FLAG@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_FLAGS = @WARN_FLAGS@
+WERROR = @WERROR@
+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@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
+exec_prefix = @exec_prefix@
+glibgo_prefixdir = @glibgo_prefixdir@
+glibgo_toolexecdir = @glibgo_toolexecdir@
+glibgo_toolexeclibdir = @glibgo_toolexeclibdir@
+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@
+libtool_VERSION = @libtool_VERSION@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+multi_basedir = @multi_basedir@
+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@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Go support.
+SUFFIXES = .c .go .gox .o .obj .lo .a
+@LIBGO_IS_RTEMS_TRUE@subdirs = testsuite
+SUBDIRS = ${subdirs}
+MAINT_CHARSET = latin1
+mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
+PWD_COMMAND = $${PWDCMD-pwd}
+STAMP = echo timestamp >
+toolexecdir = $(glibgo_toolexecdir)
+toolexeclibdir = $(glibgo_toolexeclibdir)
+WARN_CFLAGS = $(WARN_FLAGS) $(WERROR)
+
+# -I/-D flags to pass when compiling.
+AM_CPPFLAGS = -I $(srcdir)/runtime $(LIBFFIINCS) -pthread
+ACLOCAL_AMFLAGS = -I ./config -I ../config
+AM_CFLAGS = -fexceptions -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS) \
+       $(STRINGOPS_FLAG) \
+       -I $(srcdir)/../gcc -I $(MULTIBUILDTOP)../../gcc/include
+
+@USING_SPLIT_STACK_TRUE@AM_LDFLAGS = -XCClinker $(SPLIT_STACK)
+
+# Multilib support.
+MAKEOVERRIDES = 
+
+# Work around what appears to be a GNU make  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)" \
+       "CC_FOR_TARGET=$(CC_FOR_TARGET)" \
+       "CFLAGS=$(CFLAGS)" \
+       "CXXFLAGS=$(CXXFLAGS)" \
+       "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+       "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+       "GOC_FOR_TARGET=$(GOC_FOR_TARGET)" \
+       "GOC=$(GOC)" \
+       "GOCFLAGS=$(GOCFLAGS)" \
+       "INSTALL=$(INSTALL)" \
+       "INSTALL_DATA=$(INSTALL_DATA)" \
+       "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+       "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+       "LDFLAGS=$(LDFLAGS)" \
+       "LIBCFLAGS=$(LIBCFLAGS)" \
+       "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+       "MAKE=$(MAKE)" \
+       "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+       "PICFLAG=$(PICFLAG)" \
+       "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+       "SHELL=$(SHELL)" \
+       "RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+       "exec_prefix=$(exec_prefix)" \
+       "infodir=$(infodir)" \
+       "libdir=$(libdir)" \
+       "includedir=$(includedir)" \
+       "prefix=$(prefix)" \
+       "tooldir=$(tooldir)" \
+       "gxx_include_dir=$(gxx_include_dir)" \
+       "AR=$(AR)" \
+       "AS=$(AS)" \
+       "LD=$(LD)" \
+       "RANLIB=$(RANLIB)" \
+       "NM=$(NM)" \
+       "NM_FOR_BUILD=$(NM_FOR_BUILD)" \
+       "NM_FOR_TARGET=$(NM_FOR_TARGET)" \
+       "DESTDIR=$(DESTDIR)" \
+       "WERROR=$(WERROR)"
+
+
+# Subdir rules rely on $(FLAGS_TO_PASS)
+FLAGS_TO_PASS = $(AM_MAKEFLAGS)
+toolexeclib_LTLIBRARIES = libgo.la
+toolexeclib_LIBRARIES = libgobegin.a
+toolexeclib_DATA = \
+       asn1.gox \
+       big.gox \
+       bufio.gox \
+       bytes.gox \
+       cmath.gox \
+       ebnf.gox \
+       exec.gox \
+       expvar.gox \
+       flag.gox \
+       fmt.gox \
+       gob.gox \
+       hash.gox \
+       html.gox \
+       http.gox \
+       image.gox \
+       io.gox \
+       json.gox \
+       log.gox \
+       math.gox \
+       mime.gox \
+       net.gox \
+       netchan.gox \
+       os.gox \
+       patch.gox \
+       path.gox \
+       rand.gox \
+       reflect.gox \
+       regexp.gox \
+       rpc.gox \
+       runtime.gox \
+       scanner.gox \
+       smtp.gox \
+       sort.gox \
+       strconv.gox \
+       strings.gox \
+       sync.gox \
+       syscall.gox \
+       syslog.gox \
+       tabwriter.gox \
+       template.gox \
+       testing.gox \
+       time.gox \
+       try.gox \
+       unicode.gox \
+       utf16.gox \
+       utf8.gox \
+       websocket.gox \
+       xml.gox
+
+toolexeclibarchivedir = $(toolexeclibdir)/archive
+toolexeclibarchive_DATA = \
+       archive/tar.gox \
+       archive/zip.gox
+
+toolexeclibcompressdir = $(toolexeclibdir)/compress
+toolexeclibcompress_DATA = \
+       compress/flate.gox \
+       compress/gzip.gox \
+       compress/zlib.gox
+
+toolexeclibcontainerdir = $(toolexeclibdir)/container
+toolexeclibcontainer_DATA = \
+       container/heap.gox \
+       container/list.gox \
+       container/ring.gox \
+       container/vector.gox
+
+toolexeclibcryptodir = $(toolexeclibdir)/crypto
+toolexeclibcrypto_DATA = \
+       crypto/aes.gox \
+       crypto/block.gox \
+       crypto/blowfish.gox \
+       crypto/cast5.gox \
+       crypto/hmac.gox \
+       crypto/md4.gox \
+       crypto/md5.gox \
+       crypto/ocsp.gox \
+       crypto/rand.gox \
+       crypto/rc4.gox \
+       crypto/ripemd160.gox \
+       crypto/rsa.gox \
+       crypto/sha1.gox \
+       crypto/sha256.gox \
+       crypto/sha512.gox \
+       crypto/subtle.gox \
+       crypto/tls.gox \
+       crypto/x509.gox \
+       crypto/xtea.gox
+
+toolexeclibdebugdir = $(toolexeclibdir)/debug
+toolexeclibdebug_DATA = \
+       debug/dwarf.gox \
+       debug/elf.gox \
+       debug/gosym.gox \
+       debug/macho.gox \
+       debug/pe.gox \
+       debug/proc.gox
+
+toolexeclibencodingdir = $(toolexeclibdir)/encoding
+toolexeclibencoding_DATA = \
+       encoding/ascii85.gox \
+       encoding/base64.gox \
+       encoding/binary.gox \
+       encoding/git85.gox \
+       encoding/hex.gox \
+       encoding/pem.gox
+
+toolexeclibexpdir = $(toolexeclibdir)/exp
+toolexeclibexp_DATA = \
+       exp/datafmt.gox \
+       exp/draw.gox \
+       exp/eval.gox
+
+toolexeclibgodir = $(toolexeclibdir)/go
+toolexeclibgo_DATA = \
+       go/ast.gox \
+       go/doc.gox \
+       go/parser.gox \
+       go/printer.gox \
+       go/scanner.gox \
+       go/token.gox \
+       go/typechecker.gox
+
+toolexeclibhashdir = $(toolexeclibdir)/hash
+toolexeclibhash_DATA = \
+       hash/adler32.gox \
+       hash/crc32.gox \
+       hash/crc64.gox
+
+toolexeclibhttpdir = $(toolexeclibdir)/http
+toolexeclibhttp_DATA = \
+       http/pprof.gox
+
+toolexeclibimagedir = $(toolexeclibdir)/image
+toolexeclibimage_DATA = \
+       image/jpeg.gox \
+       image/png.gox
+
+toolexeclibindexdir = $(toolexeclibdir)/index
+toolexeclibindex_DATA = \
+       index/suffixarray.gox
+
+toolexeclibiodir = $(toolexeclibdir)/io
+toolexeclibio_DATA = \
+       io/ioutil.gox
+
+toolexeclibmimedir = $(toolexeclibdir)/mime
+toolexeclibmime_DATA = \
+       mime/multipart.gox
+
+toolexeclibnetdir = $(toolexeclibdir)/net
+toolexeclibnet_DATA = \
+       net/dict.gox \
+       net/textproto.gox
+
+toolexeclibosdir = $(toolexeclibdir)/os
+toolexeclibos_DATA = \
+       os/signal.gox
+
+toolexeclibrpcdir = $(toolexeclibdir)/rpc
+toolexeclibrpc_DATA = \
+       rpc/jsonrpc.gox
+
+toolexeclibruntimedir = $(toolexeclibdir)/runtime
+toolexeclibruntime_DATA = \
+       runtime/pprof.gox
+
+toolexeclibtestingdir = $(toolexeclibdir)/testing
+toolexeclibtesting_DATA = \
+       testing/iotest.gox \
+       testing/quick.gox \
+       testing/script.gox
+
+@HAVE_SYS_MMAN_H_FALSE@runtime_mem_file = runtime/mem_posix_memalign.c
+@HAVE_SYS_MMAN_H_TRUE@runtime_mem_file = runtime/mem.c
+@LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file = 
+@LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
+runtime_files = \
+       runtime/go-append.c \
+       runtime/go-assert.c \
+       runtime/go-assert-interface.c \
+       runtime/go-byte-array-to-string.c \
+       runtime/go-breakpoint.c \
+       runtime/go-caller.c \
+       runtime/go-can-convert-interface.c \
+       runtime/go-chan-cap.c \
+       runtime/go-chan-len.c \
+       runtime/go-check-interface.c \
+       runtime/go-close.c \
+       runtime/go-closed.c \
+       runtime/go-construct-map.c \
+       runtime/go-convert-interface.c \
+       runtime/go-defer.c \
+       runtime/go-deferred-recover.c \
+       runtime/go-eface-compare.c \
+       runtime/go-eface-val-compare.c \
+       runtime/go-getgoroot.c \
+       runtime/go-go.c \
+       runtime/go-gomaxprocs.c \
+       runtime/go-int-array-to-string.c \
+       runtime/go-int-to-string.c \
+       runtime/go-interface-compare.c \
+       runtime/go-interface-val-compare.c \
+       runtime/go-lock-os-thread.c \
+       runtime/go-map-delete.c \
+       runtime/go-map-index.c \
+       runtime/go-map-len.c \
+       runtime/go-map-range.c \
+       runtime/go-nanotime.c \
+       runtime/go-new-channel.c \
+       runtime/go-new-map.c \
+       runtime/go-new.c \
+       runtime/go-note.c \
+       runtime/go-panic.c \
+       runtime/go-panic-defer.c \
+       runtime/go-print.c \
+       runtime/go-rec-big.c \
+       runtime/go-rec-nb-big.c \
+       runtime/go-rec-nb-small.c \
+       runtime/go-rec-small.c \
+       runtime/go-recover.c \
+       runtime/go-reflect.c \
+       runtime/go-reflect-call.c \
+       runtime/go-reflect-chan.c \
+       runtime/go-reflect-map.c \
+       runtime/go-rune.c \
+       runtime/go-runtime-error.c \
+       runtime/go-sched.c \
+       runtime/go-select.c \
+       runtime/go-semacquire.c \
+       runtime/go-send-big.c \
+       runtime/go-send-nb-big.c \
+       runtime/go-send-nb-small.c \
+       runtime/go-send-small.c \
+       runtime/go-signal.c \
+       runtime/go-strcmp.c \
+       runtime/go-string-to-byte-array.c \
+       runtime/go-string-to-int-array.c \
+       runtime/go-strplus.c \
+       runtime/go-strslice.c \
+       runtime/go-trampoline.c \
+       runtime/go-type-eface.c \
+       runtime/go-type-error.c \
+       runtime/go-type-identity.c \
+       runtime/go-type-interface.c \
+       runtime/go-type-string.c \
+       runtime/go-typedesc-equal.c \
+       runtime/go-typestring.c \
+       runtime/go-unreflect.c \
+       runtime/go-unsafe-new.c \
+       runtime/go-unsafe-newarray.c \
+       runtime/go-unsafe-pointer.c \
+       runtime/go-unwind.c \
+       runtime/mcache.c \
+       runtime/mcentral.c \
+       $(runtime_mem_file) \
+       runtime/mfinal.c \
+       runtime/mfixalloc.c \
+       runtime/mgc0.c \
+       runtime/mheap.c \
+       runtime/mheapmap32.c \
+       runtime/mheapmap64.c \
+       runtime/msize.c \
+       runtime/proc.c \
+       runtime/thread.c \
+       $(rtems_task_variable_add_file) \
+       chan.c \
+       iface.c \
+       malloc.c \
+       map.c \
+       mprof.c \
+       reflect.c \
+       sigqueue.c \
+       string.c
+
+go_asn1_files = \
+       go/asn1/asn1.go \
+       go/asn1/common.go \
+       go/asn1/marshal.go
+
+go_big_files = \
+       go/big/arith.go \
+       go/big/int.go \
+       go/big/nat.go \
+       go/big/rat.go
+
+go_bufio_files = \
+       go/bufio/bufio.go
+
+go_bytes_files = \
+       go/bytes/buffer.go \
+       go/bytes/bytes.go \
+       go/bytes/bytes_decl.go
+
+go_bytes_c_files = \
+       go/bytes/indexbyte.c
+
+go_cmath_files = \
+       go/cmath/abs.go \
+       go/cmath/asin.go \
+       go/cmath/conj.go \
+       go/cmath/exp.go \
+       go/cmath/isinf.go \
+       go/cmath/isnan.go \
+       go/cmath/log.go \
+       go/cmath/phase.go \
+       go/cmath/polar.go \
+       go/cmath/pow.go \
+       go/cmath/rect.go \
+       go/cmath/sin.go \
+       go/cmath/sqrt.go \
+       go/cmath/tan.go
+
+go_ebnf_files = \
+       go/ebnf/ebnf.go \
+       go/ebnf/parser.go
+
+go_exec_files = \
+       go/exec/exec.go \
+       go/exec/lp_unix.go
+
+go_expvar_files = \
+       go/expvar/expvar.go
+
+go_flag_files = \
+       go/flag/flag.go
+
+go_fmt_files = \
+       go/fmt/doc.go \
+       go/fmt/format.go \
+       go/fmt/print.go \
+       go/fmt/scan.go
+
+go_gob_files = \
+       go/gob/decode.go \
+       go/gob/decoder.go \
+       go/gob/doc.go \
+       go/gob/encode.go \
+       go/gob/encoder.go \
+       go/gob/error.go \
+       go/gob/type.go
+
+go_hash_files = \
+       go/hash/hash.go
+
+go_html_files = \
+       go/html/doc.go \
+       go/html/entity.go \
+       go/html/escape.go \
+       go/html/token.go
+
+go_http_files = \
+       go/http/chunked.go \
+       go/http/client.go \
+       go/http/dump.go \
+       go/http/fs.go \
+       go/http/lex.go \
+       go/http/persist.go \
+       go/http/request.go \
+       go/http/response.go \
+       go/http/server.go \
+       go/http/status.go \
+       go/http/transfer.go \
+       go/http/url.go
+
+go_image_files = \
+       go/image/color.go \
+       go/image/format.go \
+       go/image/geom.go \
+       go/image/image.go \
+       go/image/names.go
+
+go_io_files = \
+       go/io/multi.go \
+       go/io/io.go \
+       go/io/pipe.go
+
+go_json_files = \
+       go/json/decode.go \
+       go/json/encode.go \
+       go/json/indent.go \
+       go/json/scanner.go \
+       go/json/stream.go
+
+go_log_files = \
+       go/log/log.go
+
+go_math_files = \
+       go/math/acosh.go \
+       go/math/asin.go \
+       go/math/asinh.go \
+       go/math/atan.go \
+       go/math/atanh.go \
+       go/math/atan2.go \
+       go/math/bits.go \
+       go/math/cbrt.go \
+       go/math/const.go \
+       go/math/copysign.go \
+       go/math/erf.go \
+       go/math/exp.go \
+       go/math/exp2.go \
+       go/math/expm1.go \
+       go/math/fabs.go \
+       go/math/fdim.go \
+       go/math/floor.go \
+       go/math/fmod.go \
+       go/math/frexp.go \
+       go/math/gamma.go \
+       go/math/hypot.go \
+       go/math/hypot_port.go \
+       go/math/j0.go \
+       go/math/j1.go \
+       go/math/jn.go \
+       go/math/ldexp.go \
+       go/math/lgamma.go \
+       go/math/log.go \
+       go/math/log1p.go \
+       go/math/log10.go \
+       go/math/logb.go \
+       go/math/modf.go \
+       go/math/nextafter.go \
+       go/math/pow.go \
+       go/math/pow10.go \
+       go/math/remainder.go \
+       go/math/signbit.go \
+       go/math/sin.go \
+       go/math/sincos.go \
+       go/math/sinh.go \
+       go/math/sqrt.go \
+       go/math/sqrt_port.go \
+       go/math/tan.go \
+       go/math/tanh.go \
+       go/math/unsafe.go
+
+go_mime_files = \
+       go/mime/grammar.go \
+       go/mime/mediatype.go \
+       go/mime/type.go
+
+@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_linux.go
+@LIBGO_IS_RTEMS_TRUE@go_net_fd_os_file = go/net/fd_rtems.go
+@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
+@LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go
+go_net_files = \
+       go/net/dial.go \
+       go/net/dnsclient.go \
+       go/net/dnsconfig.go \
+       go/net/dnsmsg.go \
+       $(go_net_newpollserver_file) \
+       go/net/fd.go \
+       $(go_net_fd_os_file) \
+       go/net/hosts.go \
+       go/net/ip.go \
+       go/net/iprawsock.go \
+       go/net/ipsock.go \
+       go/net/net.go \
+       go/net/parse.go \
+       go/net/pipe.go \
+       go/net/port.go \
+       go/net/sock.go \
+       go/net/tcpsock.go \
+       go/net/udpsock.go \
+       go/net/unixsock.go
+
+go_netchan_files = \
+       go/netchan/common.go \
+       go/netchan/export.go \
+       go/netchan/import.go
+
+go_os_files = \
+       go/os/dir.go \
+       go/os/env.go \
+       go/os/env_unix.go \
+       go/os/error.go \
+       go/os/exec.go \
+       go/os/file.go \
+       go/os/file_unix.go \
+       go/os/getwd.go \
+       go/os/path.go \
+       go/os/proc.go \
+       go/os/stat.go \
+       go/os/sys_linux.go \
+       go/os/time.go \
+       go/os/types.go
+
+go_patch_files = \
+       go/patch/apply.go \
+       go/patch/git.go \
+       go/patch/patch.go \
+       go/patch/textdiff.go
+
+go_path_files = \
+       go/path/match.go \
+       go/path/path.go
+
+go_rand_files = \
+       go/rand/exp.go \
+       go/rand/normal.go \
+       go/rand/rand.go \
+       go/rand/rng.go \
+       go/rand/zipf.go
+
+go_reflect_files = \
+       go/reflect/deepequal.go \
+       go/reflect/type.go \
+       go/reflect/value.go
+
+go_regexp_files = \
+       go/regexp/regexp.go
+
+go_rpc_files = \
+       go/rpc/client.go \
+       go/rpc/debug.go \
+       go/rpc/server.go
+
+go_runtime_files = \
+       go/runtime/debug.go \
+       go/runtime/error.go \
+       go/runtime/extern.go \
+       go/runtime/sig.go \
+       go/runtime/softfloat64.go \
+       go/runtime/type.go \
+       version.go
+
+@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_FALSE@@LIBGO_IS_X86_64_FALSE@GOARCH = unknown
+@LIBGO_IS_386_FALSE@@LIBGO_IS_ARM_TRUE@@LIBGO_IS_X86_64_FALSE@GOARCH = arm
+@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_TRUE@GOARCH = amd64
+@LIBGO_IS_386_TRUE@GOARCH = 386
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@GOOS = unknown
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_TRUE@GOOS = rtems
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@GOOS = freebsd
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@GOOS = darwin
+@LIBGO_IS_LINUX_TRUE@GOOS = linux
+go_scanner_files = \
+       go/scanner/scanner.go
+
+go_smtp_files = \
+       go/smtp/auth.go \
+       go/smtp/smtp.go
+
+go_sort_files = \
+       go/sort/sort.go
+
+go_strconv_files = \
+       go/strconv/atob.go \
+       go/strconv/atof.go \
+       go/strconv/atoi.go \
+       go/strconv/decimal.go \
+       go/strconv/ftoa.go \
+       go/strconv/itoa.go \
+       go/strconv/quote.go
+
+go_strings_files = \
+       go/strings/reader.go \
+       go/strings/strings.go
+
+go_sync_files = \
+       go/sync/mutex.go \
+       go/sync/once.go \
+       go/sync/rwmutex.go
+
+go_sync_c_files = \
+       go/sync/cas.c
+
+go_syslog_files = \
+       go/syslog/syslog.go
+
+go_tabwriter_files = \
+       go/tabwriter/tabwriter.go
+
+go_template_files = \
+       go/template/format.go \
+       go/template/template.go
+
+go_testing_files = \
+       go/testing/benchmark.go \
+       go/testing/testing.go
+
+go_time_files = \
+       go/time/format.go \
+       go/time/sleep.go \
+       go/time/tick.go \
+       go/time/time.go \
+       go/time/zoneinfo_unix.go
+
+go_try_files = \
+       go/try/try.go
+
+go_unicode_files = \
+       go/unicode/casetables.go \
+       go/unicode/digit.go \
+       go/unicode/letter.go \
+       go/unicode/tables.go
+
+go_utf16_files = \
+       go/utf16/utf16.go
+
+go_utf8_files = \
+       go/utf8/string.go \
+       go/utf8/utf8.go
+
+go_websocket_files = \
+       go/websocket/client.go \
+       go/websocket/server.go \
+       go/websocket/websocket.go
+
+go_xml_files = \
+       go/xml/read.go \
+       go/xml/xml.go
+
+go_archive_tar_files = \
+       go/archive/tar/common.go \
+       go/archive/tar/reader.go \
+       go/archive/tar/writer.go
+
+go_archive_zip_files = \
+       go/archive/zip/reader.go \
+       go/archive/zip/struct.go
+
+go_compress_flate_files = \
+       go/compress/flate/deflate.go \
+       go/compress/flate/huffman_bit_writer.go \
+       go/compress/flate/huffman_code.go \
+       go/compress/flate/inflate.go \
+       go/compress/flate/reverse_bits.go \
+       go/compress/flate/token.go \
+       go/compress/flate/util.go
+
+go_compress_gzip_files = \
+       go/compress/gzip/gzip.go \
+       go/compress/gzip/gunzip.go
+
+go_compress_zlib_files = \
+       go/compress/zlib/reader.go \
+       go/compress/zlib/writer.go
+
+go_container_heap_files = \
+       go/container/heap/heap.go
+
+go_container_list_files = \
+       go/container/list/list.go
+
+go_container_ring_files = \
+       go/container/ring/ring.go
+
+go_container_vector_files = \
+       go/container/vector/defs.go \
+       go/container/vector/intvector.go \
+       go/container/vector/stringvector.go \
+       go/container/vector/vector.go
+
+go_crypto_aes_files = \
+       go/crypto/aes/block.go \
+       go/crypto/aes/cipher.go \
+       go/crypto/aes/const.go
+
+go_crypto_block_files = \
+       go/crypto/block/cbc.go \
+       go/crypto/block/cfb.go \
+       go/crypto/block/cmac.go \
+       go/crypto/block/cipher.go \
+       go/crypto/block/ctr.go \
+       go/crypto/block/eax.go \
+       go/crypto/block/ecb.go \
+       go/crypto/block/ofb.go \
+       go/crypto/block/xor.go
+
+go_crypto_blowfish_files = \
+       go/crypto/blowfish/block.go \
+       go/crypto/blowfish/const.go \
+       go/crypto/blowfish/cipher.go
+
+go_crypto_cast5_files = \
+       go/crypto/cast5/cast5.go
+
+go_crypto_hmac_files = \
+       go/crypto/hmac/hmac.go
+
+go_crypto_md4_files = \
+       go/crypto/md4/md4.go \
+       go/crypto/md4/md4block.go
+
+go_crypto_md5_files = \
+       go/crypto/md5/md5.go \
+       go/crypto/md5/md5block.go
+
+go_crypto_ocsp_files = \
+       go/crypto/ocsp/ocsp.go
+
+go_crypto_rand_files = \
+       go/crypto/rand/rand.go \
+       go/crypto/rand/rand_unix.go
+
+go_crypto_rc4_files = \
+       go/crypto/rc4/rc4.go
+
+go_crypto_ripemd160_files = \
+       go/crypto/ripemd160/ripemd160.go \
+       go/crypto/ripemd160/ripemd160block.go
+
+go_crypto_rsa_files = \
+       go/crypto/rsa/pkcs1v15.go \
+       go/crypto/rsa/rsa.go
+
+go_crypto_sha1_files = \
+       go/crypto/sha1/sha1.go \
+       go/crypto/sha1/sha1block.go
+
+go_crypto_sha256_files = \
+       go/crypto/sha256/sha256.go \
+       go/crypto/sha256/sha256block.go
+
+go_crypto_sha512_files = \
+       go/crypto/sha512/sha512.go \
+       go/crypto/sha512/sha512block.go
+
+go_crypto_subtle_files = \
+       go/crypto/subtle/constant_time.go
+
+go_crypto_tls_files = \
+       go/crypto/tls/alert.go \
+       go/crypto/tls/ca_set.go \
+       go/crypto/tls/common.go \
+       go/crypto/tls/conn.go \
+       go/crypto/tls/handshake_client.go \
+       go/crypto/tls/handshake_messages.go \
+       go/crypto/tls/handshake_server.go \
+       go/crypto/tls/prf.go \
+       go/crypto/tls/tls.go
+
+go_crypto_x509_files = \
+       go/crypto/x509/x509.go
+
+go_crypto_xtea_files = \
+       go/crypto/xtea/block.go \
+       go/crypto/xtea/cipher.go
+
+go_debug_dwarf_files = \
+       go/debug/dwarf/buf.go \
+       go/debug/dwarf/const.go \
+       go/debug/dwarf/entry.go \
+       go/debug/dwarf/open.go \
+       go/debug/dwarf/type.go \
+       go/debug/dwarf/unit.go
+
+go_debug_elf_files = \
+       go/debug/elf/elf.go \
+       go/debug/elf/file.go
+
+go_debug_gosym_files = \
+       go/debug/gosym/pclntab.go \
+       go/debug/gosym/symtab.go
+
+go_debug_macho_files = \
+       go/debug/macho/file.go \
+       go/debug/macho/macho.go
+
+go_debug_pe_files = \
+       go/debug/pe/file.go \
+       go/debug/pe/pe.go
+
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@proc_file = 
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@proc_file = go/debug/proc/proc_freebsd.go
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@proc_file = go/debug/proc/proc_darwin.go
+@LIBGO_IS_LINUX_TRUE@proc_file = go/debug/proc/proc_linux.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_X86_64_FALSE@regs_file = 
+@LIBGO_IS_386_FALSE@@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_X86_64_TRUE@regs_file = go/debug/proc/regs_freebsd_amd64.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_X86_64_FALSE@regs_file = 
+@LIBGO_IS_386_FALSE@@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_X86_64_TRUE@regs_file = go/debug/proc/regs_darwin_amd64.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_64_FALSE@regs_file = 
+@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_64_TRUE@regs_file = go/debug/proc/regs_linux_amd64.go
+@LIBGO_IS_386_TRUE@@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@regs_file = go/debug/proc/regs_freebsd_386.go
+@LIBGO_IS_386_TRUE@@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@regs_file = go/debug/proc/regs_darwin_386.go
+@LIBGO_IS_386_TRUE@@LIBGO_IS_LINUX_TRUE@regs_file = go/debug/proc/regs_linux_386.go
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@regs_file = 
+go_debug_proc_files = \
+       go/debug/proc/proc.go \
+       $(proc_file) \
+       $(regs_file)
+
+go_encoding_ascii85_files = \
+       go/encoding/ascii85/ascii85.go
+
+go_encoding_base64_files = \
+       go/encoding/base64/base64.go
+
+go_encoding_binary_files = \
+       go/encoding/binary/binary.go
+
+go_encoding_git85_files = \
+       go/encoding/git85/git.go
+
+go_encoding_hex_files = \
+       go/encoding/hex/hex.go
+
+go_encoding_pem_files = \
+       go/encoding/pem/pem.go
+
+go_exp_datafmt_files = \
+       go/exp/datafmt/datafmt.go \
+       go/exp/datafmt/parser.go
+
+go_exp_draw_files = \
+       go/exp/draw/draw.go \
+       go/exp/draw/event.go
+
+go_exp_eval_files = \
+       go/exp/eval/abort.go \
+       go/exp/eval/bridge.go \
+       go/exp/eval/compiler.go \
+       go/exp/eval/expr.go \
+       go/exp/eval/expr1.go \
+       go/exp/eval/func.go \
+       go/exp/eval/scope.go \
+       go/exp/eval/stmt.go \
+       go/exp/eval/type.go \
+       go/exp/eval/typec.go \
+       go/exp/eval/value.go \
+       go/exp/eval/world.go
+
+go_go_ast_files = \
+       go/go/ast/ast.go \
+       go/go/ast/filter.go \
+       go/go/ast/print.go \
+       go/go/ast/scope.go \
+       go/go/ast/walk.go
+
+go_go_doc_files = \
+       go/go/doc/comment.go \
+       go/go/doc/doc.go
+
+go_go_parser_files = \
+       go/go/parser/interface.go \
+       go/go/parser/parser.go
+
+go_go_printer_files = \
+       go/go/printer/nodes.go \
+       go/go/printer/printer.go
+
+go_go_scanner_files = \
+       go/go/scanner/errors.go \
+       go/go/scanner/scanner.go
+
+go_go_token_files = \
+       go/go/token/token.go
+
+go_go_typechecker_files = \
+       go/go/typechecker/scope.go \
+       go/go/typechecker/typechecker.go \
+       go/go/typechecker/universe.go
+
+go_hash_adler32_files = \
+       go/hash/adler32/adler32.go
+
+go_hash_crc32_files = \
+       go/hash/crc32/crc32.go
+
+go_hash_crc64_files = \
+       go/hash/crc64/crc64.go
+
+go_http_pprof_files = \
+       go/http/pprof/pprof.go
+
+go_image_jpeg_files = \
+       go/image/jpeg/huffman.go \
+       go/image/jpeg/idct.go \
+       go/image/jpeg/reader.go
+
+go_image_png_files = \
+       go/image/png/reader.go \
+       go/image/png/writer.go
+
+go_index_suffixarray_files = \
+       go/index/suffixarray/suffixarray.go
+
+go_io_ioutil_files = \
+       go/io/ioutil/ioutil.go \
+       go/io/ioutil/tempfile.go
+
+go_mime_multipart_files = \
+       go/mime/multipart/multipart.go
+
+go_net_dict_files = \
+       go/net/dict/dict.go
+
+go_net_textproto_files = \
+       go/net/textproto/pipeline.go \
+       go/net/textproto/reader.go \
+       go/net/textproto/textproto.go \
+       go/net/textproto/writer.go
+
+go_os_signal_files = \
+       go/os/signal/signal.go \
+       unix.go
+
+go_rpc_jsonrpc_files = \
+       go/rpc/jsonrpc/client.go \
+       go/rpc/jsonrpc/server.go
+
+go_runtime_pprof_files = \
+       go/runtime/pprof/pprof.go
+
+go_testing_iotest_files = \
+       go/testing/iotest/logger.go \
+       go/testing/iotest/reader.go \
+       go/testing/iotest/writer.go
+
+go_testing_quick_files = \
+       go/testing/quick/quick.go
+
+go_testing_script_files = \
+       go/testing/script/script.go
+
+@LIBGO_IS_LINUX_FALSE@syscall_os_file = 
+@LIBGO_IS_LINUX_TRUE@syscall_os_file = syscalls/syscall_linux.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_64_FALSE@syscall_arch_file = 
+@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_64_TRUE@syscall_arch_file = syscalls/syscall_linux_amd64.go
+@LIBGO_IS_386_TRUE@@LIBGO_IS_LINUX_TRUE@syscall_arch_file = syscalls/syscall_linux_386.go
+@LIBGO_IS_LINUX_FALSE@syscall_arch_file = 
+@LIBGO_IS_RTEMS_FALSE@syscall_exec_os_file = syscalls/exec.go
+@LIBGO_IS_RTEMS_TRUE@syscall_exec_os_file = syscalls/exec_stubs.go
+@LIBGO_IS_RTEMS_FALSE@syscall_socket_os_file = syscalls/socket_linux.go
+@LIBGO_IS_RTEMS_TRUE@syscall_socket_os_file = syscalls/socket_bsd.go
+@LIBGO_IS_RTEMS_FALSE@syscall_socket_epoll_file = syscalls/socket_epoll.go
+@LIBGO_IS_RTEMS_TRUE@syscall_socket_epoll_file = 
+@LIBGO_IS_RTEMS_FALSE@syscall_sysfile_os_file = syscalls/sysfile_linux.go
+@LIBGO_IS_RTEMS_TRUE@syscall_sysfile_os_file = syscalls/sysfile_rtems.go
+@LIBGO_IS_RTEMS_FALSE@syscall_syscall_file = syscalls/syscall.go
+@LIBGO_IS_RTEMS_TRUE@syscall_syscall_file = syscalls/syscall_stubs.go
+@LIBGO_IS_RTEMS_FALSE@syscall_errstr_file = syscalls/errstr.go
+@LIBGO_IS_RTEMS_TRUE@syscall_errstr_file = syscalls/errstr_rtems.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@syscall_errstr_decl_file = syscalls/errstr_decl.go
+@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@syscall_errstr_decl_file = syscalls/errstr_decl_linux.go
+@LIBGO_IS_RTEMS_TRUE@syscall_errstr_decl_file = syscalls/errstr_decl_rtems.go
+go_syscall_files = \
+       $(syscall_errstr_file) \
+       $(syscall_errstr_decl_file) \
+       syscalls/exec_helpers.go \
+       $(syscall_exec_os_file) \
+       syscalls/socket.go \
+       $(syscall_socket_os_file) \
+       $(syscall_socket_epoll_file) \
+       $(syscall_syscall_file) \
+       syscalls/syscall_unix.go \
+       syscalls/stringbyte.go \
+       $(syscall_os_file) \
+       $(syscall_arch_file) \
+       syscalls/sysfile_posix.go \
+       $(syscall_sysfile_os_file) \
+       sysinfo.go
+
+go_syscall_c_files = \
+       syscalls/errno.c
+
+libgo_go_objs = \
+       asn1/libasn1.la \
+       big/libbig.la \
+       bufio/libbufio.la \
+       bytes/libbytes.la \
+       cmath/libcmath.la \
+       ebnf/libebnf.la \
+       exec/libexec.la \
+       expvar/libexpvar.la \
+       flag/libflag.la \
+       fmt/libfmt.la \
+       gob/libgob.la \
+       hash/libhash.la \
+       html/libhtml.la \
+       http/libhttp.la \
+       image/libimage.la \
+       io/libio.la \
+       json/libjson.la \
+       log/liblog.la \
+       math/libmath.la \
+       mime/libmime.la \
+       net/libnet.la \
+       netchan/libnetchan.la \
+       os/libos.la \
+       patch/libpatch.la \
+       path/libpath.la \
+       rand/librand.la \
+       reflect/libreflect.la \
+       regexp/libregexp.la \
+       rpc/librpc.la \
+       runtime/libruntime.la \
+       scanner/libscanner.la \
+       smtp/libsmtp.la \
+       sort/libsort.la \
+       strconv/libstrconv.la \
+       strings/libstrings.la \
+       sync/libsync.la \
+       syslog/libsyslog.la \
+       tabwriter/libtabwriter.la \
+       template/libtemplate.la \
+       time/libtime.la \
+       try/libtry.la \
+       unicode/libunicode.la \
+       utf16/libutf16.la \
+       utf8/libutf8.la \
+       websocket/libwebsocket.la \
+       xml/libxml.la \
+       archive/libtar.la \
+       archive/libzip.la \
+       compress/libflate.la \
+       compress/libgzip.la \
+       compress/libzlib.la \
+       container/libheap.la \
+       container/liblist.la \
+       container/libring.la \
+       container/libvector.la \
+       crypto/libaes.la \
+       crypto/libblock.la \
+       crypto/libblowfish.la \
+       crypto/libcast5.la \
+       crypto/libhmac.la \
+       crypto/libmd4.la \
+       crypto/libmd5.la \
+       crypto/libocsp.la \
+       crypto/librand.la \
+       crypto/librc4.la \
+       crypto/libripemd160.la \
+       crypto/librsa.la \
+       crypto/libsha1.la \
+       crypto/libsha256.la \
+       crypto/libsha512.la \
+       crypto/libsubtle.la \
+       crypto/libtls.la \
+       crypto/libx509.la \
+       crypto/libxtea.la \
+       debug/libdwarf.la \
+       debug/libelf.la \
+       debug/libgosym.la \
+       debug/libmacho.la \
+       debug/libpe.la \
+       debug/libproc.la \
+       encoding/libascii85.la \
+       encoding/libbase64.la \
+       encoding/libbinary.la \
+       encoding/libgit85.la \
+       encoding/libhex.la \
+       encoding/libpem.la \
+       exp/libdatafmt.la \
+       exp/libdraw.la \
+       exp/libeval.la \
+       go/libast.la \
+       go/libdoc.la \
+       go/libparser.la \
+       go/libprinter.la \
+       go/libscanner.la \
+       go/libtoken.la \
+       go/libtypechecker.la \
+       hash/libadler32.la \
+       hash/libcrc32.la \
+       hash/libcrc64.la \
+       http/libpprof.la \
+       image/libjpeg.la \
+       image/libpng.la \
+       index/libsuffixarray.la \
+       io/libioutil.la \
+       mime/libmultipart.la \
+       net/libdict.la \
+       net/libtextproto.la \
+       os/libsignal.la \
+       rpc/libjsonrpc.la \
+       runtime/libpprof.la \
+       syscalls/libsyscall.la \
+       testing/libtesting.la \
+       testing/libiotest.la \
+       testing/libquick.la \
+       testing/libscript.la
+
+libgo_la_SOURCES = $(runtime_files)
+libgo_la_LIBADD = $(libgo_go_objs) $(LIBFFI) -lpthread
+libgobegin_a_SOURCES = \
+       runtime/go-main.c
+
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
+AM_GOCFLAGS = $(STRINGOPS_FLAG)
+GOCOMPILE = $(GOC) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_GOCFLAGS) $(GOCFLAGS)
+LTGOCOMPILE = $(LIBTOOL) --tag GO --mode=compile $(GOC) $(INCLUDES) \
+       $(AM_GOCFLAGS) $(GOCFLAGS)
+
+GOLINK = $(LIBTOOL) --tag GO --mode-link $(GOC) \
+       $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_GOCFLAGS) $(LTLDFLAGS) \
+       -lpthread -o $@
+
+
+# Build a package.
+BUILDARCHIVE = \
+       rm -f `echo $@ | sed -e 's|/lib|/|' -e 's/\.a/.gox/'`; \
+       test -d $(@D) || $(MKDIR_P) $(@D); \
+       rm -f $@; \
+       files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
+       if $(LTGOCOMPILE) -c -fgo-prefix="libgo_$(@D)" -o $@.$(OBJEXT) $$files; then \
+         $(AR) rc $@ $@.$(OBJEXT); \
+       else exit 1; fi
+
+@LIBGO_IS_RTEMS_FALSE@use_dejagnu = no
+@LIBGO_IS_RTEMS_TRUE@use_dejagnu = yes
+
+# Check a package.
+CHECK = \
+       @GC="$(GOC) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs -Wl,-R,`${PWD_COMMAND}`/.libs"; \
+       export GC; \
+       RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
+       export RUNTESTFLAGS; \
+       MAKE="$(MAKE)"; \
+       export MAKE; \
+       rm -f $@-log; \
+       echo -n "$(@D) " >$@-log 2>&1; \
+       prefix=`if test "$(@D)" = "regexp"; then echo regexp-test; else dirname $(@D); fi`; \
+       test "$${prefix}" != "." || prefix="$(@D)"; \
+       $(srcdir)/testsuite/gotest --dejagnu=$(use_dejagnu) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --prefix="libgo_$${prefix}" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" >>$@-log 2>&1; \
+       x=$$?; \
+       cat $@-log; \
+       exit $$x
+
+
+# Build all packages before checking any.
+CHECK_DEPS = libgo.la libgobegin.a \
+       $(toolexeclib_DATA) \
+       $(toolexeclibarchive_DATA) \
+       $(toolexeclibcompress_DATA) \
+       $(toolexeclibcontainer_DATA) \
+       $(toolexeclibcrypto_DATA) \
+       $(toolexeclibdebug_DATA) \
+       $(toolexeclibencoding_DATA) \
+       $(toolexeclibexp_DATA) \
+       $(toolexeclibgo_DATA) \
+       $(toolexeclibhash_DATA) \
+       $(toolexeclibhttp_DATA) \
+       $(toolexeclibimage_DATA) \
+       $(toolexeclibio_DATA) \
+       $(toolexeclibos_DATA) \
+       $(toolexeclibrpc_DATA) \
+       $(toolexeclibruntime_DATA) \
+       $(toolexeclibtesting_DATA)
+
+
+# How to build a .gox file from a .a file.
+BUILDGOX = \
+       set -e; \
+       rm -f $@.$(OBJEXT); \
+       $(CC) -r -nostdlib -o $@.$(OBJEXT) -Wl,--whole-archive $<; \
+       $(OBJCOPY) -j .go_export $@.$(OBJEXT) $@.tmp; \
+       mv -f $@.tmp $@; \
+       rm -f $@.$(OBJEXT)
+
+TEST_PACKAGES = \
+       asn1/check \
+       big/check \
+       bufio/check \
+       bytes/check \
+       cmath/check \
+       ebnf/check \
+       exec/check \
+       expvar/check \
+       flag/check \
+       fmt/check \
+       gob/check \
+       html/check \
+       http/check \
+       io/check \
+       json/check \
+       log/check \
+       math/check \
+       mime/check \
+       net/check \
+       netchan/check \
+       os/check \
+       patch/check \
+       path/check \
+       rand/check \
+       reflect/check \
+       regexp/check \
+       rpc/check \
+       runtime/check \
+       scanner/check \
+       smtp/check \
+       sort/check \
+       strconv/check \
+       strings/check \
+       sync/check \
+       syslog/check \
+       tabwriter/check \
+       template/check \
+       time/check \
+       try/check \
+       unicode/check \
+       utf16/check \
+       utf8/check \
+       websocket/check \
+       xml/check \
+       archive/tar/check \
+       archive/zip/check \
+       compress/flate/check \
+       compress/gzip/check \
+       compress/zlib/check \
+       container/heap/check \
+       container/list/check \
+       container/ring/check \
+       container/vector/check \
+       crypto/aes/check \
+       crypto/block/check \
+       crypto/blowfish/check \
+       crypto/cast5/check \
+       crypto/hmac/check \
+       crypto/md4/check \
+       crypto/md5/check \
+       crypto/ocsp/check \
+       crypto/rand/check \
+       crypto/rc4/check \
+       crypto/ripemd160/check \
+       crypto/rsa/check \
+       crypto/sha1/check \
+       crypto/sha256/check \
+       crypto/sha512/check \
+       crypto/subtle/check \
+       crypto/tls/check \
+       crypto/x509/check \
+       crypto/xtea/check \
+       debug/dwarf/check \
+       debug/elf/check \
+       debug/macho/check \
+       debug/pe/check \
+       encoding/ascii85/check \
+       encoding/base64/check \
+       encoding/binary/check \
+       encoding/git85/check \
+       encoding/hex/check \
+       encoding/pem/check \
+       exp/datafmt/check \
+       exp/draw/check \
+       exp/eval/check \
+       go/parser/check \
+       go/printer/check \
+       go/scanner/check \
+       go/typechecker/check \
+       hash/adler32/check \
+       hash/crc32/check \
+       hash/crc64/check \
+       image/png/check \
+       index/suffixarray/check \
+       io/ioutil/check \
+       mime/multipart/check \
+       net/textproto/check \
+       os/signal/check \
+       rpc/jsonrpc/check \
+       testing/quick/check \
+       testing/script/check
+
+CLEANFILES = *.go *.gox goc2c *.c s-version
+all: config.h
+       $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .go .gox .o .obj .lo .a .la
+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):
+
+config.h: stamp-h1
+       @if test ! -f $@; then \
+         rm -f stamp-h1; \
+         $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+       else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+       @rm -f stamp-h1
+       cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+       ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+       rm -f stamp-h1
+       touch $@
+
+distclean-hdr:
+       -rm -f config.h stamp-h1
+install-toolexeclibLIBRARIES: $(toolexeclib_LIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)"
+       @list='$(toolexeclib_LIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+       list2=; for p in $$list; do \
+         if test -f $$p; then \
+           list2="$$list2 $$p"; \
+         else :; fi; \
+       done; \
+       test -z "$$list2" || { \
+         echo " $(INSTALL_DATA) $$list2 '$(DESTDIR)$(toolexeclibdir)'"; \
+         $(INSTALL_DATA) $$list2 "$(DESTDIR)$(toolexeclibdir)" || exit $$?; }
+       @$(POST_INSTALL)
+       @list='$(toolexeclib_LIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+       for p in $$list; do \
+         if test -f $$p; then \
+           $(am__strip_dir) \
+           echo " ( cd '$(DESTDIR)$(toolexeclibdir)' && $(RANLIB) $$f )"; \
+           ( cd "$(DESTDIR)$(toolexeclibdir)" && $(RANLIB) $$f ) || exit $$?; \
+         else :; fi; \
+       done
+
+uninstall-toolexeclibLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclib_LIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibdir)' && rm -f "$$files" )"; \
+       cd "$(DESTDIR)$(toolexeclibdir)" && rm -f $$files
+
+clean-toolexeclibLIBRARIES:
+       -test -z "$(toolexeclib_LIBRARIES)" || rm -f $(toolexeclib_LIBRARIES)
+libgobegin.a: $(libgobegin_a_OBJECTS) $(libgobegin_a_DEPENDENCIES) 
+       -rm -f libgobegin.a
+       $(libgobegin_a_AR) libgobegin.a $(libgobegin_a_OBJECTS) $(libgobegin_a_LIBADD)
+       $(RANLIB) libgobegin.a
+install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)"
+       @list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || 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)$(toolexeclibdir)'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(toolexeclibdir)"; \
+       }
+
+uninstall-toolexeclibLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(toolexeclibdir)/$$f'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(toolexeclibdir)/$$f"; \
+       done
+
+clean-toolexeclibLTLIBRARIES:
+       -test -z "$(toolexeclib_LTLIBRARIES)" || rm -f $(toolexeclib_LTLIBRARIES)
+       @list='$(toolexeclib_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
+libgo.la: $(libgo_la_OBJECTS) $(libgo_la_DEPENDENCIES) 
+       $(LINK) -rpath $(toolexeclibdir) $(libgo_la_OBJECTS) $(libgo_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-append.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-assert-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-assert.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-breakpoint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-byte-array-to-string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-caller.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-can-convert-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-cap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-len.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-check-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-close.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-closed.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-convert-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-defer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-deferred-recover.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-val-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-getgoroot.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-go.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-gomaxprocs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-array-to-string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-to-string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-interface-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-interface-val-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-lock-os-thread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-delete.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-index.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-len.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-range.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-nanotime.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-channel.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-note.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic-defer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-print.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-big.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-big.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-small.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-small.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-recover.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-call.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-chan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rune.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-runtime-error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-sched.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-select.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-semacquire.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-big.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-big.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-small.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-small.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-signal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strcmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-string-to-byte-array.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-string-to-int-array.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strplus.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strslice.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-trampoline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-eface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-identity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-typedesc-equal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-typestring.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unreflect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-new.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-newarray.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-pointer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unwind.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcentral.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_posix_memalign.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfinal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfixalloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mgc0.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheapmap32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheapmap64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mprof.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msize.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reflect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtems-task-variable-add.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sigqueue.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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 $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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 `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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 $@ $<
+
+go-main.o: runtime/go-main.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-main.o -MD -MP -MF $(DEPDIR)/go-main.Tpo -c -o go-main.o `test -f 'runtime/go-main.c' || echo '$(srcdir)/'`runtime/go-main.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-main.Tpo $(DEPDIR)/go-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-main.c' object='go-main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-main.o `test -f 'runtime/go-main.c' || echo '$(srcdir)/'`runtime/go-main.c
+
+go-main.obj: runtime/go-main.c
+@am__fastdepCC_TRUE@   $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-main.obj -MD -MP -MF $(DEPDIR)/go-main.Tpo -c -o go-main.obj `if test -f 'runtime/go-main.c'; then $(CYGPATH_W) 'runtime/go-main.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-main.c'; fi`
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-main.Tpo $(DEPDIR)/go-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-main.c' object='go-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-main.obj `if test -f 'runtime/go-main.c'; then $(CYGPATH_W) 'runtime/go-main.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-main.c'; fi`
+
+go-append.lo: runtime/go-append.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-append.lo -MD -MP -MF $(DEPDIR)/go-append.Tpo -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-append.Tpo $(DEPDIR)/go-append.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-append.c' object='go-append.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
+
+go-assert.lo: runtime/go-assert.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-assert.lo -MD -MP -MF $(DEPDIR)/go-assert.Tpo -c -o go-assert.lo `test -f 'runtime/go-assert.c' || echo '$(srcdir)/'`runtime/go-assert.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-assert.Tpo $(DEPDIR)/go-assert.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-assert.c' object='go-assert.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-assert.lo `test -f 'runtime/go-assert.c' || echo '$(srcdir)/'`runtime/go-assert.c
+
+go-assert-interface.lo: runtime/go-assert-interface.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-assert-interface.lo -MD -MP -MF $(DEPDIR)/go-assert-interface.Tpo -c -o go-assert-interface.lo `test -f 'runtime/go-assert-interface.c' || echo '$(srcdir)/'`runtime/go-assert-interface.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-assert-interface.Tpo $(DEPDIR)/go-assert-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-assert-interface.c' object='go-assert-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-assert-interface.lo `test -f 'runtime/go-assert-interface.c' || echo '$(srcdir)/'`runtime/go-assert-interface.c
+
+go-byte-array-to-string.lo: runtime/go-byte-array-to-string.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-byte-array-to-string.lo -MD -MP -MF $(DEPDIR)/go-byte-array-to-string.Tpo -c -o go-byte-array-to-string.lo `test -f 'runtime/go-byte-array-to-string.c' || echo '$(srcdir)/'`runtime/go-byte-array-to-string.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-byte-array-to-string.Tpo $(DEPDIR)/go-byte-array-to-string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-byte-array-to-string.c' object='go-byte-array-to-string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-byte-array-to-string.lo `test -f 'runtime/go-byte-array-to-string.c' || echo '$(srcdir)/'`runtime/go-byte-array-to-string.c
+
+go-breakpoint.lo: runtime/go-breakpoint.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-breakpoint.lo -MD -MP -MF $(DEPDIR)/go-breakpoint.Tpo -c -o go-breakpoint.lo `test -f 'runtime/go-breakpoint.c' || echo '$(srcdir)/'`runtime/go-breakpoint.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-breakpoint.Tpo $(DEPDIR)/go-breakpoint.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-breakpoint.c' object='go-breakpoint.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-breakpoint.lo `test -f 'runtime/go-breakpoint.c' || echo '$(srcdir)/'`runtime/go-breakpoint.c
+
+go-caller.lo: runtime/go-caller.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-caller.lo -MD -MP -MF $(DEPDIR)/go-caller.Tpo -c -o go-caller.lo `test -f 'runtime/go-caller.c' || echo '$(srcdir)/'`runtime/go-caller.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-caller.Tpo $(DEPDIR)/go-caller.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-caller.c' object='go-caller.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-caller.lo `test -f 'runtime/go-caller.c' || echo '$(srcdir)/'`runtime/go-caller.c
+
+go-can-convert-interface.lo: runtime/go-can-convert-interface.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-can-convert-interface.lo -MD -MP -MF $(DEPDIR)/go-can-convert-interface.Tpo -c -o go-can-convert-interface.lo `test -f 'runtime/go-can-convert-interface.c' || echo '$(srcdir)/'`runtime/go-can-convert-interface.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-can-convert-interface.Tpo $(DEPDIR)/go-can-convert-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-can-convert-interface.c' object='go-can-convert-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-can-convert-interface.lo `test -f 'runtime/go-can-convert-interface.c' || echo '$(srcdir)/'`runtime/go-can-convert-interface.c
+
+go-chan-cap.lo: runtime/go-chan-cap.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-cap.lo -MD -MP -MF $(DEPDIR)/go-chan-cap.Tpo -c -o go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-chan-cap.Tpo $(DEPDIR)/go-chan-cap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-chan-cap.c' object='go-chan-cap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c
+
+go-chan-len.lo: runtime/go-chan-len.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-len.lo -MD -MP -MF $(DEPDIR)/go-chan-len.Tpo -c -o go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-chan-len.Tpo $(DEPDIR)/go-chan-len.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-chan-len.c' object='go-chan-len.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c
+
+go-check-interface.lo: runtime/go-check-interface.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-check-interface.lo -MD -MP -MF $(DEPDIR)/go-check-interface.Tpo -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-check-interface.Tpo $(DEPDIR)/go-check-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-check-interface.c' object='go-check-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c
+
+go-close.lo: runtime/go-close.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-close.lo -MD -MP -MF $(DEPDIR)/go-close.Tpo -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-close.Tpo $(DEPDIR)/go-close.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-close.c' object='go-close.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c
+
+go-closed.lo: runtime/go-closed.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-closed.lo -MD -MP -MF $(DEPDIR)/go-closed.Tpo -c -o go-closed.lo `test -f 'runtime/go-closed.c' || echo '$(srcdir)/'`runtime/go-closed.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-closed.Tpo $(DEPDIR)/go-closed.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-closed.c' object='go-closed.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-closed.lo `test -f 'runtime/go-closed.c' || echo '$(srcdir)/'`runtime/go-closed.c
+
+go-construct-map.lo: runtime/go-construct-map.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-construct-map.lo -MD -MP -MF $(DEPDIR)/go-construct-map.Tpo -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-construct-map.Tpo $(DEPDIR)/go-construct-map.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-construct-map.c' object='go-construct-map.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c
+
+go-convert-interface.lo: runtime/go-convert-interface.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-convert-interface.lo -MD -MP -MF $(DEPDIR)/go-convert-interface.Tpo -c -o go-convert-interface.lo `test -f 'runtime/go-convert-interface.c' || echo '$(srcdir)/'`runtime/go-convert-interface.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-convert-interface.Tpo $(DEPDIR)/go-convert-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-convert-interface.c' object='go-convert-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-convert-interface.lo `test -f 'runtime/go-convert-interface.c' || echo '$(srcdir)/'`runtime/go-convert-interface.c
+
+go-defer.lo: runtime/go-defer.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-defer.lo -MD -MP -MF $(DEPDIR)/go-defer.Tpo -c -o go-defer.lo `test -f 'runtime/go-defer.c' || echo '$(srcdir)/'`runtime/go-defer.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-defer.Tpo $(DEPDIR)/go-defer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-defer.c' object='go-defer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-defer.lo `test -f 'runtime/go-defer.c' || echo '$(srcdir)/'`runtime/go-defer.c
+
+go-deferred-recover.lo: runtime/go-deferred-recover.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-deferred-recover.lo -MD -MP -MF $(DEPDIR)/go-deferred-recover.Tpo -c -o go-deferred-recover.lo `test -f 'runtime/go-deferred-recover.c' || echo '$(srcdir)/'`runtime/go-deferred-recover.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-deferred-recover.Tpo $(DEPDIR)/go-deferred-recover.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-deferred-recover.c' object='go-deferred-recover.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-deferred-recover.lo `test -f 'runtime/go-deferred-recover.c' || echo '$(srcdir)/'`runtime/go-deferred-recover.c
+
+go-eface-compare.lo: runtime/go-eface-compare.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-eface-compare.lo -MD -MP -MF $(DEPDIR)/go-eface-compare.Tpo -c -o go-eface-compare.lo `test -f 'runtime/go-eface-compare.c' || echo '$(srcdir)/'`runtime/go-eface-compare.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-eface-compare.Tpo $(DEPDIR)/go-eface-compare.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-eface-compare.c' object='go-eface-compare.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-compare.lo `test -f 'runtime/go-eface-compare.c' || echo '$(srcdir)/'`runtime/go-eface-compare.c
+
+go-eface-val-compare.lo: runtime/go-eface-val-compare.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-eface-val-compare.lo -MD -MP -MF $(DEPDIR)/go-eface-val-compare.Tpo -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-eface-val-compare.Tpo $(DEPDIR)/go-eface-val-compare.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-eface-val-compare.c' object='go-eface-val-compare.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
+
+go-getgoroot.lo: runtime/go-getgoroot.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-getgoroot.lo -MD -MP -MF $(DEPDIR)/go-getgoroot.Tpo -c -o go-getgoroot.lo `test -f 'runtime/go-getgoroot.c' || echo '$(srcdir)/'`runtime/go-getgoroot.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-getgoroot.Tpo $(DEPDIR)/go-getgoroot.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-getgoroot.c' object='go-getgoroot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-getgoroot.lo `test -f 'runtime/go-getgoroot.c' || echo '$(srcdir)/'`runtime/go-getgoroot.c
+
+go-go.lo: runtime/go-go.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-go.lo -MD -MP -MF $(DEPDIR)/go-go.Tpo -c -o go-go.lo `test -f 'runtime/go-go.c' || echo '$(srcdir)/'`runtime/go-go.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-go.Tpo $(DEPDIR)/go-go.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-go.c' object='go-go.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-go.lo `test -f 'runtime/go-go.c' || echo '$(srcdir)/'`runtime/go-go.c
+
+go-gomaxprocs.lo: runtime/go-gomaxprocs.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-gomaxprocs.lo -MD -MP -MF $(DEPDIR)/go-gomaxprocs.Tpo -c -o go-gomaxprocs.lo `test -f 'runtime/go-gomaxprocs.c' || echo '$(srcdir)/'`runtime/go-gomaxprocs.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-gomaxprocs.Tpo $(DEPDIR)/go-gomaxprocs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-gomaxprocs.c' object='go-gomaxprocs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-gomaxprocs.lo `test -f 'runtime/go-gomaxprocs.c' || echo '$(srcdir)/'`runtime/go-gomaxprocs.c
+
+go-int-array-to-string.lo: runtime/go-int-array-to-string.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-int-array-to-string.lo -MD -MP -MF $(DEPDIR)/go-int-array-to-string.Tpo -c -o go-int-array-to-string.lo `test -f 'runtime/go-int-array-to-string.c' || echo '$(srcdir)/'`runtime/go-int-array-to-string.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-int-array-to-string.Tpo $(DEPDIR)/go-int-array-to-string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-int-array-to-string.c' object='go-int-array-to-string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-int-array-to-string.lo `test -f 'runtime/go-int-array-to-string.c' || echo '$(srcdir)/'`runtime/go-int-array-to-string.c
+
+go-int-to-string.lo: runtime/go-int-to-string.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-int-to-string.lo -MD -MP -MF $(DEPDIR)/go-int-to-string.Tpo -c -o go-int-to-string.lo `test -f 'runtime/go-int-to-string.c' || echo '$(srcdir)/'`runtime/go-int-to-string.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-int-to-string.Tpo $(DEPDIR)/go-int-to-string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-int-to-string.c' object='go-int-to-string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-int-to-string.lo `test -f 'runtime/go-int-to-string.c' || echo '$(srcdir)/'`runtime/go-int-to-string.c
+
+go-interface-compare.lo: runtime/go-interface-compare.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-interface-compare.lo -MD -MP -MF $(DEPDIR)/go-interface-compare.Tpo -c -o go-interface-compare.lo `test -f 'runtime/go-interface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-compare.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-interface-compare.Tpo $(DEPDIR)/go-interface-compare.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-interface-compare.c' object='go-interface-compare.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-interface-compare.lo `test -f 'runtime/go-interface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-compare.c
+
+go-interface-val-compare.lo: runtime/go-interface-val-compare.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-interface-val-compare.lo -MD -MP -MF $(DEPDIR)/go-interface-val-compare.Tpo -c -o go-interface-val-compare.lo `test -f 'runtime/go-interface-val-compare.c' || echo '$(srcdir)/'`runtime/go-interface-val-compare.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-interface-val-compare.Tpo $(DEPDIR)/go-interface-val-compare.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-interface-val-compare.c' object='go-interface-val-compare.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-interface-val-compare.lo `test -f 'runtime/go-interface-val-compare.c' || echo '$(srcdir)/'`runtime/go-interface-val-compare.c
+
+go-lock-os-thread.lo: runtime/go-lock-os-thread.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-lock-os-thread.lo -MD -MP -MF $(DEPDIR)/go-lock-os-thread.Tpo -c -o go-lock-os-thread.lo `test -f 'runtime/go-lock-os-thread.c' || echo '$(srcdir)/'`runtime/go-lock-os-thread.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-lock-os-thread.Tpo $(DEPDIR)/go-lock-os-thread.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-lock-os-thread.c' object='go-lock-os-thread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-lock-os-thread.lo `test -f 'runtime/go-lock-os-thread.c' || echo '$(srcdir)/'`runtime/go-lock-os-thread.c
+
+go-map-delete.lo: runtime/go-map-delete.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-delete.lo -MD -MP -MF $(DEPDIR)/go-map-delete.Tpo -c -o go-map-delete.lo `test -f 'runtime/go-map-delete.c' || echo '$(srcdir)/'`runtime/go-map-delete.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-map-delete.Tpo $(DEPDIR)/go-map-delete.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-map-delete.c' object='go-map-delete.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-delete.lo `test -f 'runtime/go-map-delete.c' || echo '$(srcdir)/'`runtime/go-map-delete.c
+
+go-map-index.lo: runtime/go-map-index.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-index.lo -MD -MP -MF $(DEPDIR)/go-map-index.Tpo -c -o go-map-index.lo `test -f 'runtime/go-map-index.c' || echo '$(srcdir)/'`runtime/go-map-index.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-map-index.Tpo $(DEPDIR)/go-map-index.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-map-index.c' object='go-map-index.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-index.lo `test -f 'runtime/go-map-index.c' || echo '$(srcdir)/'`runtime/go-map-index.c
+
+go-map-len.lo: runtime/go-map-len.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-len.lo -MD -MP -MF $(DEPDIR)/go-map-len.Tpo -c -o go-map-len.lo `test -f 'runtime/go-map-len.c' || echo '$(srcdir)/'`runtime/go-map-len.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-map-len.Tpo $(DEPDIR)/go-map-len.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-map-len.c' object='go-map-len.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-len.lo `test -f 'runtime/go-map-len.c' || echo '$(srcdir)/'`runtime/go-map-len.c
+
+go-map-range.lo: runtime/go-map-range.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-range.lo -MD -MP -MF $(DEPDIR)/go-map-range.Tpo -c -o go-map-range.lo `test -f 'runtime/go-map-range.c' || echo '$(srcdir)/'`runtime/go-map-range.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-map-range.Tpo $(DEPDIR)/go-map-range.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-map-range.c' object='go-map-range.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-range.lo `test -f 'runtime/go-map-range.c' || echo '$(srcdir)/'`runtime/go-map-range.c
+
+go-nanotime.lo: runtime/go-nanotime.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-nanotime.lo -MD -MP -MF $(DEPDIR)/go-nanotime.Tpo -c -o go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-nanotime.Tpo $(DEPDIR)/go-nanotime.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-nanotime.c' object='go-nanotime.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c
+
+go-new-channel.lo: runtime/go-new-channel.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-channel.lo -MD -MP -MF $(DEPDIR)/go-new-channel.Tpo -c -o go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-new-channel.Tpo $(DEPDIR)/go-new-channel.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-new-channel.c' object='go-new-channel.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c
+
+go-new-map.lo: runtime/go-new-map.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-map.lo -MD -MP -MF $(DEPDIR)/go-new-map.Tpo -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-new-map.Tpo $(DEPDIR)/go-new-map.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-new-map.c' object='go-new-map.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c
+
+go-new.lo: runtime/go-new.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new.lo -MD -MP -MF $(DEPDIR)/go-new.Tpo -c -o go-new.lo `test -f 'runtime/go-new.c' || echo '$(srcdir)/'`runtime/go-new.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-new.Tpo $(DEPDIR)/go-new.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-new.c' object='go-new.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-new.lo `test -f 'runtime/go-new.c' || echo '$(srcdir)/'`runtime/go-new.c
+
+go-note.lo: runtime/go-note.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-note.lo -MD -MP -MF $(DEPDIR)/go-note.Tpo -c -o go-note.lo `test -f 'runtime/go-note.c' || echo '$(srcdir)/'`runtime/go-note.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-note.Tpo $(DEPDIR)/go-note.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-note.c' object='go-note.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-note.lo `test -f 'runtime/go-note.c' || echo '$(srcdir)/'`runtime/go-note.c
+
+go-panic.lo: runtime/go-panic.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-panic.lo -MD -MP -MF $(DEPDIR)/go-panic.Tpo -c -o go-panic.lo `test -f 'runtime/go-panic.c' || echo '$(srcdir)/'`runtime/go-panic.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-panic.Tpo $(DEPDIR)/go-panic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-panic.c' object='go-panic.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-panic.lo `test -f 'runtime/go-panic.c' || echo '$(srcdir)/'`runtime/go-panic.c
+
+go-panic-defer.lo: runtime/go-panic-defer.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-panic-defer.lo -MD -MP -MF $(DEPDIR)/go-panic-defer.Tpo -c -o go-panic-defer.lo `test -f 'runtime/go-panic-defer.c' || echo '$(srcdir)/'`runtime/go-panic-defer.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-panic-defer.Tpo $(DEPDIR)/go-panic-defer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-panic-defer.c' object='go-panic-defer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-panic-defer.lo `test -f 'runtime/go-panic-defer.c' || echo '$(srcdir)/'`runtime/go-panic-defer.c
+
+go-print.lo: runtime/go-print.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-print.lo -MD -MP -MF $(DEPDIR)/go-print.Tpo -c -o go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-print.Tpo $(DEPDIR)/go-print.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-print.c' object='go-print.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c
+
+go-rec-big.lo: runtime/go-rec-big.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-big.lo -MD -MP -MF $(DEPDIR)/go-rec-big.Tpo -c -o go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-rec-big.Tpo $(DEPDIR)/go-rec-big.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-rec-big.c' object='go-rec-big.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c
+
+go-rec-nb-big.lo: runtime/go-rec-nb-big.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-big.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-big.Tpo -c -o go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-rec-nb-big.Tpo $(DEPDIR)/go-rec-nb-big.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-rec-nb-big.c' object='go-rec-nb-big.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c
+
+go-rec-nb-small.lo: runtime/go-rec-nb-small.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-small.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-small.Tpo -c -o go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-rec-nb-small.Tpo $(DEPDIR)/go-rec-nb-small.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-rec-nb-small.c' object='go-rec-nb-small.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c
+
+go-rec-small.lo: runtime/go-rec-small.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-small.lo -MD -MP -MF $(DEPDIR)/go-rec-small.Tpo -c -o go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-rec-small.Tpo $(DEPDIR)/go-rec-small.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-rec-small.c' object='go-rec-small.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c
+
+go-recover.lo: runtime/go-recover.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-recover.lo -MD -MP -MF $(DEPDIR)/go-recover.Tpo -c -o go-recover.lo `test -f 'runtime/go-recover.c' || echo '$(srcdir)/'`runtime/go-recover.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-recover.Tpo $(DEPDIR)/go-recover.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-recover.c' object='go-recover.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-recover.lo `test -f 'runtime/go-recover.c' || echo '$(srcdir)/'`runtime/go-recover.c
+
+go-reflect.lo: runtime/go-reflect.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect.lo -MD -MP -MF $(DEPDIR)/go-reflect.Tpo -c -o go-reflect.lo `test -f 'runtime/go-reflect.c' || echo '$(srcdir)/'`runtime/go-reflect.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-reflect.Tpo $(DEPDIR)/go-reflect.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-reflect.c' object='go-reflect.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect.lo `test -f 'runtime/go-reflect.c' || echo '$(srcdir)/'`runtime/go-reflect.c
+
+go-reflect-call.lo: runtime/go-reflect-call.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-call.lo -MD -MP -MF $(DEPDIR)/go-reflect-call.Tpo -c -o go-reflect-call.lo `test -f 'runtime/go-reflect-call.c' || echo '$(srcdir)/'`runtime/go-reflect-call.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-reflect-call.Tpo $(DEPDIR)/go-reflect-call.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-reflect-call.c' object='go-reflect-call.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-call.lo `test -f 'runtime/go-reflect-call.c' || echo '$(srcdir)/'`runtime/go-reflect-call.c
+
+go-reflect-chan.lo: runtime/go-reflect-chan.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-chan.lo -MD -MP -MF $(DEPDIR)/go-reflect-chan.Tpo -c -o go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-reflect-chan.Tpo $(DEPDIR)/go-reflect-chan.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-reflect-chan.c' object='go-reflect-chan.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c
+
+go-reflect-map.lo: runtime/go-reflect-map.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-map.lo -MD -MP -MF $(DEPDIR)/go-reflect-map.Tpo -c -o go-reflect-map.lo `test -f 'runtime/go-reflect-map.c' || echo '$(srcdir)/'`runtime/go-reflect-map.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-reflect-map.Tpo $(DEPDIR)/go-reflect-map.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-reflect-map.c' object='go-reflect-map.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-map.lo `test -f 'runtime/go-reflect-map.c' || echo '$(srcdir)/'`runtime/go-reflect-map.c
+
+go-rune.lo: runtime/go-rune.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rune.lo -MD -MP -MF $(DEPDIR)/go-rune.Tpo -c -o go-rune.lo `test -f 'runtime/go-rune.c' || echo '$(srcdir)/'`runtime/go-rune.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-rune.Tpo $(DEPDIR)/go-rune.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-rune.c' object='go-rune.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rune.lo `test -f 'runtime/go-rune.c' || echo '$(srcdir)/'`runtime/go-rune.c
+
+go-runtime-error.lo: runtime/go-runtime-error.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-runtime-error.lo -MD -MP -MF $(DEPDIR)/go-runtime-error.Tpo -c -o go-runtime-error.lo `test -f 'runtime/go-runtime-error.c' || echo '$(srcdir)/'`runtime/go-runtime-error.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-runtime-error.Tpo $(DEPDIR)/go-runtime-error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-runtime-error.c' object='go-runtime-error.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-runtime-error.lo `test -f 'runtime/go-runtime-error.c' || echo '$(srcdir)/'`runtime/go-runtime-error.c
+
+go-sched.lo: runtime/go-sched.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-sched.lo -MD -MP -MF $(DEPDIR)/go-sched.Tpo -c -o go-sched.lo `test -f 'runtime/go-sched.c' || echo '$(srcdir)/'`runtime/go-sched.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-sched.Tpo $(DEPDIR)/go-sched.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-sched.c' object='go-sched.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-sched.lo `test -f 'runtime/go-sched.c' || echo '$(srcdir)/'`runtime/go-sched.c
+
+go-select.lo: runtime/go-select.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-select.lo -MD -MP -MF $(DEPDIR)/go-select.Tpo -c -o go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-select.Tpo $(DEPDIR)/go-select.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-select.c' object='go-select.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c
+
+go-semacquire.lo: runtime/go-semacquire.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-semacquire.lo -MD -MP -MF $(DEPDIR)/go-semacquire.Tpo -c -o go-semacquire.lo `test -f 'runtime/go-semacquire.c' || echo '$(srcdir)/'`runtime/go-semacquire.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-semacquire.Tpo $(DEPDIR)/go-semacquire.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-semacquire.c' object='go-semacquire.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-semacquire.lo `test -f 'runtime/go-semacquire.c' || echo '$(srcdir)/'`runtime/go-semacquire.c
+
+go-send-big.lo: runtime/go-send-big.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-big.lo -MD -MP -MF $(DEPDIR)/go-send-big.Tpo -c -o go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-send-big.Tpo $(DEPDIR)/go-send-big.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-send-big.c' object='go-send-big.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c
+
+go-send-nb-big.lo: runtime/go-send-nb-big.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-big.lo -MD -MP -MF $(DEPDIR)/go-send-nb-big.Tpo -c -o go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-send-nb-big.Tpo $(DEPDIR)/go-send-nb-big.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-send-nb-big.c' object='go-send-nb-big.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c
+
+go-send-nb-small.lo: runtime/go-send-nb-small.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-small.lo -MD -MP -MF $(DEPDIR)/go-send-nb-small.Tpo -c -o go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-send-nb-small.Tpo $(DEPDIR)/go-send-nb-small.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-send-nb-small.c' object='go-send-nb-small.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c
+
+go-send-small.lo: runtime/go-send-small.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-small.lo -MD -MP -MF $(DEPDIR)/go-send-small.Tpo -c -o go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-send-small.Tpo $(DEPDIR)/go-send-small.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-send-small.c' object='go-send-small.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c
+
+go-signal.lo: runtime/go-signal.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-signal.lo -MD -MP -MF $(DEPDIR)/go-signal.Tpo -c -o go-signal.lo `test -f 'runtime/go-signal.c' || echo '$(srcdir)/'`runtime/go-signal.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-signal.Tpo $(DEPDIR)/go-signal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-signal.c' object='go-signal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-signal.lo `test -f 'runtime/go-signal.c' || echo '$(srcdir)/'`runtime/go-signal.c
+
+go-strcmp.lo: runtime/go-strcmp.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-strcmp.lo -MD -MP -MF $(DEPDIR)/go-strcmp.Tpo -c -o go-strcmp.lo `test -f 'runtime/go-strcmp.c' || echo '$(srcdir)/'`runtime/go-strcmp.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-strcmp.Tpo $(DEPDIR)/go-strcmp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-strcmp.c' object='go-strcmp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strcmp.lo `test -f 'runtime/go-strcmp.c' || echo '$(srcdir)/'`runtime/go-strcmp.c
+
+go-string-to-byte-array.lo: runtime/go-string-to-byte-array.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-string-to-byte-array.lo -MD -MP -MF $(DEPDIR)/go-string-to-byte-array.Tpo -c -o go-string-to-byte-array.lo `test -f 'runtime/go-string-to-byte-array.c' || echo '$(srcdir)/'`runtime/go-string-to-byte-array.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-string-to-byte-array.Tpo $(DEPDIR)/go-string-to-byte-array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-string-to-byte-array.c' object='go-string-to-byte-array.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-string-to-byte-array.lo `test -f 'runtime/go-string-to-byte-array.c' || echo '$(srcdir)/'`runtime/go-string-to-byte-array.c
+
+go-string-to-int-array.lo: runtime/go-string-to-int-array.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-string-to-int-array.lo -MD -MP -MF $(DEPDIR)/go-string-to-int-array.Tpo -c -o go-string-to-int-array.lo `test -f 'runtime/go-string-to-int-array.c' || echo '$(srcdir)/'`runtime/go-string-to-int-array.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-string-to-int-array.Tpo $(DEPDIR)/go-string-to-int-array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-string-to-int-array.c' object='go-string-to-int-array.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-string-to-int-array.lo `test -f 'runtime/go-string-to-int-array.c' || echo '$(srcdir)/'`runtime/go-string-to-int-array.c
+
+go-strplus.lo: runtime/go-strplus.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-strplus.lo -MD -MP -MF $(DEPDIR)/go-strplus.Tpo -c -o go-strplus.lo `test -f 'runtime/go-strplus.c' || echo '$(srcdir)/'`runtime/go-strplus.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-strplus.Tpo $(DEPDIR)/go-strplus.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-strplus.c' object='go-strplus.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strplus.lo `test -f 'runtime/go-strplus.c' || echo '$(srcdir)/'`runtime/go-strplus.c
+
+go-strslice.lo: runtime/go-strslice.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-strslice.lo -MD -MP -MF $(DEPDIR)/go-strslice.Tpo -c -o go-strslice.lo `test -f 'runtime/go-strslice.c' || echo '$(srcdir)/'`runtime/go-strslice.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-strslice.Tpo $(DEPDIR)/go-strslice.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-strslice.c' object='go-strslice.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strslice.lo `test -f 'runtime/go-strslice.c' || echo '$(srcdir)/'`runtime/go-strslice.c
+
+go-trampoline.lo: runtime/go-trampoline.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-trampoline.lo -MD -MP -MF $(DEPDIR)/go-trampoline.Tpo -c -o go-trampoline.lo `test -f 'runtime/go-trampoline.c' || echo '$(srcdir)/'`runtime/go-trampoline.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-trampoline.Tpo $(DEPDIR)/go-trampoline.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-trampoline.c' object='go-trampoline.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-trampoline.lo `test -f 'runtime/go-trampoline.c' || echo '$(srcdir)/'`runtime/go-trampoline.c
+
+go-type-eface.lo: runtime/go-type-eface.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-eface.lo -MD -MP -MF $(DEPDIR)/go-type-eface.Tpo -c -o go-type-eface.lo `test -f 'runtime/go-type-eface.c' || echo '$(srcdir)/'`runtime/go-type-eface.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-type-eface.Tpo $(DEPDIR)/go-type-eface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-type-eface.c' object='go-type-eface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-eface.lo `test -f 'runtime/go-type-eface.c' || echo '$(srcdir)/'`runtime/go-type-eface.c
+
+go-type-error.lo: runtime/go-type-error.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-error.lo -MD -MP -MF $(DEPDIR)/go-type-error.Tpo -c -o go-type-error.lo `test -f 'runtime/go-type-error.c' || echo '$(srcdir)/'`runtime/go-type-error.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-type-error.Tpo $(DEPDIR)/go-type-error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-type-error.c' object='go-type-error.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-error.lo `test -f 'runtime/go-type-error.c' || echo '$(srcdir)/'`runtime/go-type-error.c
+
+go-type-identity.lo: runtime/go-type-identity.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-identity.lo -MD -MP -MF $(DEPDIR)/go-type-identity.Tpo -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-type-identity.Tpo $(DEPDIR)/go-type-identity.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-type-identity.c' object='go-type-identity.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
+
+go-type-interface.lo: runtime/go-type-interface.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-interface.lo -MD -MP -MF $(DEPDIR)/go-type-interface.Tpo -c -o go-type-interface.lo `test -f 'runtime/go-type-interface.c' || echo '$(srcdir)/'`runtime/go-type-interface.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-type-interface.Tpo $(DEPDIR)/go-type-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-type-interface.c' object='go-type-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-interface.lo `test -f 'runtime/go-type-interface.c' || echo '$(srcdir)/'`runtime/go-type-interface.c
+
+go-type-string.lo: runtime/go-type-string.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-string.lo -MD -MP -MF $(DEPDIR)/go-type-string.Tpo -c -o go-type-string.lo `test -f 'runtime/go-type-string.c' || echo '$(srcdir)/'`runtime/go-type-string.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-type-string.Tpo $(DEPDIR)/go-type-string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-type-string.c' object='go-type-string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-string.lo `test -f 'runtime/go-type-string.c' || echo '$(srcdir)/'`runtime/go-type-string.c
+
+go-typedesc-equal.lo: runtime/go-typedesc-equal.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-typedesc-equal.lo -MD -MP -MF $(DEPDIR)/go-typedesc-equal.Tpo -c -o go-typedesc-equal.lo `test -f 'runtime/go-typedesc-equal.c' || echo '$(srcdir)/'`runtime/go-typedesc-equal.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-typedesc-equal.Tpo $(DEPDIR)/go-typedesc-equal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-typedesc-equal.c' object='go-typedesc-equal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-typedesc-equal.lo `test -f 'runtime/go-typedesc-equal.c' || echo '$(srcdir)/'`runtime/go-typedesc-equal.c
+
+go-typestring.lo: runtime/go-typestring.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-typestring.lo -MD -MP -MF $(DEPDIR)/go-typestring.Tpo -c -o go-typestring.lo `test -f 'runtime/go-typestring.c' || echo '$(srcdir)/'`runtime/go-typestring.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-typestring.Tpo $(DEPDIR)/go-typestring.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-typestring.c' object='go-typestring.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-typestring.lo `test -f 'runtime/go-typestring.c' || echo '$(srcdir)/'`runtime/go-typestring.c
+
+go-unreflect.lo: runtime/go-unreflect.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unreflect.lo -MD -MP -MF $(DEPDIR)/go-unreflect.Tpo -c -o go-unreflect.lo `test -f 'runtime/go-unreflect.c' || echo '$(srcdir)/'`runtime/go-unreflect.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-unreflect.Tpo $(DEPDIR)/go-unreflect.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-unreflect.c' object='go-unreflect.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unreflect.lo `test -f 'runtime/go-unreflect.c' || echo '$(srcdir)/'`runtime/go-unreflect.c
+
+go-unsafe-new.lo: runtime/go-unsafe-new.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsafe-new.lo -MD -MP -MF $(DEPDIR)/go-unsafe-new.Tpo -c -o go-unsafe-new.lo `test -f 'runtime/go-unsafe-new.c' || echo '$(srcdir)/'`runtime/go-unsafe-new.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-unsafe-new.Tpo $(DEPDIR)/go-unsafe-new.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-unsafe-new.c' object='go-unsafe-new.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-new.lo `test -f 'runtime/go-unsafe-new.c' || echo '$(srcdir)/'`runtime/go-unsafe-new.c
+
+go-unsafe-newarray.lo: runtime/go-unsafe-newarray.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsafe-newarray.lo -MD -MP -MF $(DEPDIR)/go-unsafe-newarray.Tpo -c -o go-unsafe-newarray.lo `test -f 'runtime/go-unsafe-newarray.c' || echo '$(srcdir)/'`runtime/go-unsafe-newarray.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-unsafe-newarray.Tpo $(DEPDIR)/go-unsafe-newarray.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-unsafe-newarray.c' object='go-unsafe-newarray.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-newarray.lo `test -f 'runtime/go-unsafe-newarray.c' || echo '$(srcdir)/'`runtime/go-unsafe-newarray.c
+
+go-unsafe-pointer.lo: runtime/go-unsafe-pointer.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsafe-pointer.lo -MD -MP -MF $(DEPDIR)/go-unsafe-pointer.Tpo -c -o go-unsafe-pointer.lo `test -f 'runtime/go-unsafe-pointer.c' || echo '$(srcdir)/'`runtime/go-unsafe-pointer.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-unsafe-pointer.Tpo $(DEPDIR)/go-unsafe-pointer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-unsafe-pointer.c' object='go-unsafe-pointer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-pointer.lo `test -f 'runtime/go-unsafe-pointer.c' || echo '$(srcdir)/'`runtime/go-unsafe-pointer.c
+
+go-unwind.lo: runtime/go-unwind.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unwind.lo -MD -MP -MF $(DEPDIR)/go-unwind.Tpo -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-unwind.Tpo $(DEPDIR)/go-unwind.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-unwind.c' object='go-unwind.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c
+
+mcache.lo: runtime/mcache.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mcache.lo -MD -MP -MF $(DEPDIR)/mcache.Tpo -c -o mcache.lo `test -f 'runtime/mcache.c' || echo '$(srcdir)/'`runtime/mcache.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mcache.Tpo $(DEPDIR)/mcache.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mcache.c' object='mcache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mcache.lo `test -f 'runtime/mcache.c' || echo '$(srcdir)/'`runtime/mcache.c
+
+mcentral.lo: runtime/mcentral.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mcentral.lo -MD -MP -MF $(DEPDIR)/mcentral.Tpo -c -o mcentral.lo `test -f 'runtime/mcentral.c' || echo '$(srcdir)/'`runtime/mcentral.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mcentral.Tpo $(DEPDIR)/mcentral.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mcentral.c' object='mcentral.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mcentral.lo `test -f 'runtime/mcentral.c' || echo '$(srcdir)/'`runtime/mcentral.c
+
+mem_posix_memalign.lo: runtime/mem_posix_memalign.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mem_posix_memalign.lo -MD -MP -MF $(DEPDIR)/mem_posix_memalign.Tpo -c -o mem_posix_memalign.lo `test -f 'runtime/mem_posix_memalign.c' || echo '$(srcdir)/'`runtime/mem_posix_memalign.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mem_posix_memalign.Tpo $(DEPDIR)/mem_posix_memalign.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mem_posix_memalign.c' object='mem_posix_memalign.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mem_posix_memalign.lo `test -f 'runtime/mem_posix_memalign.c' || echo '$(srcdir)/'`runtime/mem_posix_memalign.c
+
+mem.lo: runtime/mem.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mem.lo -MD -MP -MF $(DEPDIR)/mem.Tpo -c -o mem.lo `test -f 'runtime/mem.c' || echo '$(srcdir)/'`runtime/mem.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mem.Tpo $(DEPDIR)/mem.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mem.c' object='mem.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mem.lo `test -f 'runtime/mem.c' || echo '$(srcdir)/'`runtime/mem.c
+
+mfinal.lo: runtime/mfinal.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mfinal.lo -MD -MP -MF $(DEPDIR)/mfinal.Tpo -c -o mfinal.lo `test -f 'runtime/mfinal.c' || echo '$(srcdir)/'`runtime/mfinal.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mfinal.Tpo $(DEPDIR)/mfinal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mfinal.c' object='mfinal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mfinal.lo `test -f 'runtime/mfinal.c' || echo '$(srcdir)/'`runtime/mfinal.c
+
+mfixalloc.lo: runtime/mfixalloc.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mfixalloc.lo -MD -MP -MF $(DEPDIR)/mfixalloc.Tpo -c -o mfixalloc.lo `test -f 'runtime/mfixalloc.c' || echo '$(srcdir)/'`runtime/mfixalloc.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mfixalloc.Tpo $(DEPDIR)/mfixalloc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mfixalloc.c' object='mfixalloc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mfixalloc.lo `test -f 'runtime/mfixalloc.c' || echo '$(srcdir)/'`runtime/mfixalloc.c
+
+mgc0.lo: runtime/mgc0.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mgc0.lo -MD -MP -MF $(DEPDIR)/mgc0.Tpo -c -o mgc0.lo `test -f 'runtime/mgc0.c' || echo '$(srcdir)/'`runtime/mgc0.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mgc0.Tpo $(DEPDIR)/mgc0.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mgc0.c' object='mgc0.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mgc0.lo `test -f 'runtime/mgc0.c' || echo '$(srcdir)/'`runtime/mgc0.c
+
+mheap.lo: runtime/mheap.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mheap.lo -MD -MP -MF $(DEPDIR)/mheap.Tpo -c -o mheap.lo `test -f 'runtime/mheap.c' || echo '$(srcdir)/'`runtime/mheap.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mheap.Tpo $(DEPDIR)/mheap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mheap.c' object='mheap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mheap.lo `test -f 'runtime/mheap.c' || echo '$(srcdir)/'`runtime/mheap.c
+
+mheapmap32.lo: runtime/mheapmap32.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mheapmap32.lo -MD -MP -MF $(DEPDIR)/mheapmap32.Tpo -c -o mheapmap32.lo `test -f 'runtime/mheapmap32.c' || echo '$(srcdir)/'`runtime/mheapmap32.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mheapmap32.Tpo $(DEPDIR)/mheapmap32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mheapmap32.c' object='mheapmap32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mheapmap32.lo `test -f 'runtime/mheapmap32.c' || echo '$(srcdir)/'`runtime/mheapmap32.c
+
+mheapmap64.lo: runtime/mheapmap64.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mheapmap64.lo -MD -MP -MF $(DEPDIR)/mheapmap64.Tpo -c -o mheapmap64.lo `test -f 'runtime/mheapmap64.c' || echo '$(srcdir)/'`runtime/mheapmap64.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mheapmap64.Tpo $(DEPDIR)/mheapmap64.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/mheapmap64.c' object='mheapmap64.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mheapmap64.lo `test -f 'runtime/mheapmap64.c' || echo '$(srcdir)/'`runtime/mheapmap64.c
+
+msize.lo: runtime/msize.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT msize.lo -MD -MP -MF $(DEPDIR)/msize.Tpo -c -o msize.lo `test -f 'runtime/msize.c' || echo '$(srcdir)/'`runtime/msize.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/msize.Tpo $(DEPDIR)/msize.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/msize.c' object='msize.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o msize.lo `test -f 'runtime/msize.c' || echo '$(srcdir)/'`runtime/msize.c
+
+proc.lo: runtime/proc.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc.lo -MD -MP -MF $(DEPDIR)/proc.Tpo -c -o proc.lo `test -f 'runtime/proc.c' || echo '$(srcdir)/'`runtime/proc.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/proc.Tpo $(DEPDIR)/proc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/proc.c' object='proc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc.lo `test -f 'runtime/proc.c' || echo '$(srcdir)/'`runtime/proc.c
+
+thread.lo: runtime/thread.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread.lo -MD -MP -MF $(DEPDIR)/thread.Tpo -c -o thread.lo `test -f 'runtime/thread.c' || echo '$(srcdir)/'`runtime/thread.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/thread.Tpo $(DEPDIR)/thread.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/thread.c' object='thread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread.lo `test -f 'runtime/thread.c' || echo '$(srcdir)/'`runtime/thread.c
+
+rtems-task-variable-add.lo: runtime/rtems-task-variable-add.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rtems-task-variable-add.lo -MD -MP -MF $(DEPDIR)/rtems-task-variable-add.Tpo -c -o rtems-task-variable-add.lo `test -f 'runtime/rtems-task-variable-add.c' || echo '$(srcdir)/'`runtime/rtems-task-variable-add.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/rtems-task-variable-add.Tpo $(DEPDIR)/rtems-task-variable-add.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/rtems-task-variable-add.c' object='rtems-task-variable-add.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rtems-task-variable-add.lo `test -f 'runtime/rtems-task-variable-add.c' || echo '$(srcdir)/'`runtime/rtems-task-variable-add.c
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+       -rm -f libtool config.lt
+
+# GNU Make needs to see an explicit $(MAKE) variable in the command it
+# runs to enable its job server during parallel builds.  Hence the
+# comments below.
+all-multi:
+       $(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do # $(MAKE)
+install-multi:
+       $(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do # $(MAKE)
+
+mostlyclean-multi:
+       $(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean # $(MAKE)
+clean-multi:
+       $(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean # $(MAKE)
+distclean-multi:
+       $(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean # $(MAKE)
+maintainer-clean-multi:
+       $(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean # $(MAKE)
+install-toolexeclibDATA: $(toolexeclib_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)"
+       @list='$(toolexeclib_DATA)'; test -n "$(toolexeclibdir)" || 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)$(toolexeclibdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclib_DATA)'; test -n "$(toolexeclibdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibdir)" && rm -f $$files
+install-toolexeclibarchiveDATA: $(toolexeclibarchive_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibarchivedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibarchivedir)"
+       @list='$(toolexeclibarchive_DATA)'; test -n "$(toolexeclibarchivedir)" || 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)$(toolexeclibarchivedir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibarchivedir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibarchiveDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibarchive_DATA)'; test -n "$(toolexeclibarchivedir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibarchivedir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibarchivedir)" && rm -f $$files
+install-toolexeclibcompressDATA: $(toolexeclibcompress_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibcompressdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibcompressdir)"
+       @list='$(toolexeclibcompress_DATA)'; test -n "$(toolexeclibcompressdir)" || 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)$(toolexeclibcompressdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibcompressdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibcompressDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibcompress_DATA)'; test -n "$(toolexeclibcompressdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibcompressdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibcompressdir)" && rm -f $$files
+install-toolexeclibcontainerDATA: $(toolexeclibcontainer_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibcontainerdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibcontainerdir)"
+       @list='$(toolexeclibcontainer_DATA)'; test -n "$(toolexeclibcontainerdir)" || 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)$(toolexeclibcontainerdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibcontainerdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibcontainerDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibcontainer_DATA)'; test -n "$(toolexeclibcontainerdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibcontainerdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibcontainerdir)" && rm -f $$files
+install-toolexeclibcryptoDATA: $(toolexeclibcrypto_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibcryptodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibcryptodir)"
+       @list='$(toolexeclibcrypto_DATA)'; test -n "$(toolexeclibcryptodir)" || 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)$(toolexeclibcryptodir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibcryptodir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibcryptoDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibcrypto_DATA)'; test -n "$(toolexeclibcryptodir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibcryptodir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibcryptodir)" && rm -f $$files
+install-toolexeclibdebugDATA: $(toolexeclibdebug_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibdebugdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdebugdir)"
+       @list='$(toolexeclibdebug_DATA)'; test -n "$(toolexeclibdebugdir)" || 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)$(toolexeclibdebugdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibdebugdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibdebugDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibdebug_DATA)'; test -n "$(toolexeclibdebugdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibdebugdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibdebugdir)" && rm -f $$files
+install-toolexeclibencodingDATA: $(toolexeclibencoding_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibencodingdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibencodingdir)"
+       @list='$(toolexeclibencoding_DATA)'; test -n "$(toolexeclibencodingdir)" || 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)$(toolexeclibencodingdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibencodingdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibencodingDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibencoding_DATA)'; test -n "$(toolexeclibencodingdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibencodingdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibencodingdir)" && rm -f $$files
+install-toolexeclibexpDATA: $(toolexeclibexp_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibexpdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibexpdir)"
+       @list='$(toolexeclibexp_DATA)'; test -n "$(toolexeclibexpdir)" || 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)$(toolexeclibexpdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibexpdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibexpDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibexp_DATA)'; test -n "$(toolexeclibexpdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibexpdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibexpdir)" && rm -f $$files
+install-toolexeclibgoDATA: $(toolexeclibgo_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibgodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgodir)"
+       @list='$(toolexeclibgo_DATA)'; test -n "$(toolexeclibgodir)" || 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)$(toolexeclibgodir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgodir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibgoDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibgo_DATA)'; test -n "$(toolexeclibgodir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibgodir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibgodir)" && rm -f $$files
+install-toolexeclibhashDATA: $(toolexeclibhash_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibhashdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibhashdir)"
+       @list='$(toolexeclibhash_DATA)'; test -n "$(toolexeclibhashdir)" || 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)$(toolexeclibhashdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibhashdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibhashDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibhash_DATA)'; test -n "$(toolexeclibhashdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibhashdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibhashdir)" && rm -f $$files
+install-toolexeclibhttpDATA: $(toolexeclibhttp_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibhttpdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibhttpdir)"
+       @list='$(toolexeclibhttp_DATA)'; test -n "$(toolexeclibhttpdir)" || 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)$(toolexeclibhttpdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibhttpdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibhttpDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibhttp_DATA)'; test -n "$(toolexeclibhttpdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibhttpdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibhttpdir)" && rm -f $$files
+install-toolexeclibimageDATA: $(toolexeclibimage_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibimagedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibimagedir)"
+       @list='$(toolexeclibimage_DATA)'; test -n "$(toolexeclibimagedir)" || 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)$(toolexeclibimagedir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibimagedir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibimageDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibimage_DATA)'; test -n "$(toolexeclibimagedir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibimagedir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibimagedir)" && rm -f $$files
+install-toolexeclibindexDATA: $(toolexeclibindex_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibindexdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibindexdir)"
+       @list='$(toolexeclibindex_DATA)'; test -n "$(toolexeclibindexdir)" || 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)$(toolexeclibindexdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibindexdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibindexDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibindex_DATA)'; test -n "$(toolexeclibindexdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibindexdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibindexdir)" && rm -f $$files
+install-toolexeclibioDATA: $(toolexeclibio_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibiodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibiodir)"
+       @list='$(toolexeclibio_DATA)'; test -n "$(toolexeclibiodir)" || 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)$(toolexeclibiodir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibiodir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibioDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibio_DATA)'; test -n "$(toolexeclibiodir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibiodir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibiodir)" && rm -f $$files
+install-toolexeclibmimeDATA: $(toolexeclibmime_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibmimedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibmimedir)"
+       @list='$(toolexeclibmime_DATA)'; test -n "$(toolexeclibmimedir)" || 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)$(toolexeclibmimedir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibmimedir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibmimeDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibmime_DATA)'; test -n "$(toolexeclibmimedir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibmimedir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibmimedir)" && rm -f $$files
+install-toolexeclibnetDATA: $(toolexeclibnet_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibnetdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibnetdir)"
+       @list='$(toolexeclibnet_DATA)'; test -n "$(toolexeclibnetdir)" || 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)$(toolexeclibnetdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibnetdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibnetDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibnet_DATA)'; test -n "$(toolexeclibnetdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibnetdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibnetdir)" && rm -f $$files
+install-toolexeclibosDATA: $(toolexeclibos_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibosdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibosdir)"
+       @list='$(toolexeclibos_DATA)'; test -n "$(toolexeclibosdir)" || 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)$(toolexeclibosdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibosdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibosDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibos_DATA)'; test -n "$(toolexeclibosdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibosdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibosdir)" && rm -f $$files
+install-toolexeclibrpcDATA: $(toolexeclibrpc_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibrpcdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibrpcdir)"
+       @list='$(toolexeclibrpc_DATA)'; test -n "$(toolexeclibrpcdir)" || 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)$(toolexeclibrpcdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibrpcdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibrpcDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibrpc_DATA)'; test -n "$(toolexeclibrpcdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibrpcdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibrpcdir)" && rm -f $$files
+install-toolexeclibruntimeDATA: $(toolexeclibruntime_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibruntimedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibruntimedir)"
+       @list='$(toolexeclibruntime_DATA)'; test -n "$(toolexeclibruntimedir)" || 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)$(toolexeclibruntimedir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibruntimedir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibruntimeDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibruntime_DATA)'; test -n "$(toolexeclibruntimedir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibruntimedir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibruntimedir)" && rm -f $$files
+install-toolexeclibtestingDATA: $(toolexeclibtesting_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibtestingdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibtestingdir)"
+       @list='$(toolexeclibtesting_DATA)'; test -n "$(toolexeclibtestingdir)" || 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)$(toolexeclibtestingdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibtestingdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibtestingDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibtesting_DATA)'; test -n "$(toolexeclibtestingdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibtestingdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibtestingdir)" && 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) config.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) config.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) config.h.in $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS) config.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
+       -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 $(LIBRARIES) $(LTLIBRARIES) all-multi $(DATA) \
+               config.h
+installdirs: installdirs-recursive
+installdirs-am:
+       for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibarchivedir)" "$(DESTDIR)$(toolexeclibcompressdir)" "$(DESTDIR)$(toolexeclibcontainerdir)" "$(DESTDIR)$(toolexeclibcryptodir)" "$(DESTDIR)$(toolexeclibdebugdir)" "$(DESTDIR)$(toolexeclibencodingdir)" "$(DESTDIR)$(toolexeclibexpdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibhashdir)" "$(DESTDIR)$(toolexeclibhttpdir)" "$(DESTDIR)$(toolexeclibimagedir)" "$(DESTDIR)$(toolexeclibindexdir)" "$(DESTDIR)$(toolexeclibiodir)" "$(DESTDIR)$(toolexeclibmimedir)" "$(DESTDIR)$(toolexeclibnetdir)" "$(DESTDIR)$(toolexeclibosdir)" "$(DESTDIR)$(toolexeclibrpcdir)" "$(DESTDIR)$(toolexeclibruntimedir)" "$(DESTDIR)$(toolexeclibtestingdir)"; 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:
+       -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-multi clean-recursive
+
+clean-am: clean-generic clean-libtool clean-local \
+       clean-toolexeclibLIBRARIES clean-toolexeclibLTLIBRARIES \
+       mostlyclean-am
+
+distclean: distclean-multi distclean-recursive
+       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-multi install-toolexeclibDATA \
+       install-toolexeclibLIBRARIES install-toolexeclibLTLIBRARIES \
+       install-toolexeclibarchiveDATA install-toolexeclibcompressDATA \
+       install-toolexeclibcontainerDATA install-toolexeclibcryptoDATA \
+       install-toolexeclibdebugDATA install-toolexeclibencodingDATA \
+       install-toolexeclibexpDATA install-toolexeclibgoDATA \
+       install-toolexeclibhashDATA install-toolexeclibhttpDATA \
+       install-toolexeclibimageDATA install-toolexeclibindexDATA \
+       install-toolexeclibioDATA install-toolexeclibmimeDATA \
+       install-toolexeclibnetDATA install-toolexeclibosDATA \
+       install-toolexeclibrpcDATA install-toolexeclibruntimeDATA \
+       install-toolexeclibtestingDATA
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-multi maintainer-clean-recursive
+       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+       -rm -rf $(top_srcdir)/autom4te.cache
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-multi mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool mostlyclean-local
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-toolexeclibDATA uninstall-toolexeclibLIBRARIES \
+       uninstall-toolexeclibLTLIBRARIES \
+       uninstall-toolexeclibarchiveDATA \
+       uninstall-toolexeclibcompressDATA \
+       uninstall-toolexeclibcontainerDATA \
+       uninstall-toolexeclibcryptoDATA uninstall-toolexeclibdebugDATA \
+       uninstall-toolexeclibencodingDATA uninstall-toolexeclibexpDATA \
+       uninstall-toolexeclibgoDATA uninstall-toolexeclibhashDATA \
+       uninstall-toolexeclibhttpDATA uninstall-toolexeclibimageDATA \
+       uninstall-toolexeclibindexDATA uninstall-toolexeclibioDATA \
+       uninstall-toolexeclibmimeDATA uninstall-toolexeclibnetDATA \
+       uninstall-toolexeclibosDATA uninstall-toolexeclibrpcDATA \
+       uninstall-toolexeclibruntimeDATA \
+       uninstall-toolexeclibtestingDATA
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all all-multi \
+       clean-multi ctags-recursive distclean-multi install-am \
+       install-multi install-strip maintainer-clean-multi \
+       mostlyclean-multi tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+       all all-am all-multi am--refresh check check-am clean \
+       clean-generic clean-libtool clean-local clean-multi \
+       clean-toolexeclibLIBRARIES clean-toolexeclibLTLIBRARIES ctags \
+       ctags-recursive dist dist-all dist-bzip2 dist-gzip dist-lzma \
+       dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \
+       distclean-compile distclean-generic distclean-hdr \
+       distclean-libtool distclean-multi 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-man install-multi install-pdf \
+       install-pdf-am install-ps install-ps-am install-strip \
+       install-toolexeclibDATA install-toolexeclibLIBRARIES \
+       install-toolexeclibLTLIBRARIES install-toolexeclibarchiveDATA \
+       install-toolexeclibcompressDATA \
+       install-toolexeclibcontainerDATA install-toolexeclibcryptoDATA \
+       install-toolexeclibdebugDATA install-toolexeclibencodingDATA \
+       install-toolexeclibexpDATA install-toolexeclibgoDATA \
+       install-toolexeclibhashDATA install-toolexeclibhttpDATA \
+       install-toolexeclibimageDATA install-toolexeclibindexDATA \
+       install-toolexeclibioDATA install-toolexeclibmimeDATA \
+       install-toolexeclibnetDATA install-toolexeclibosDATA \
+       install-toolexeclibrpcDATA install-toolexeclibruntimeDATA \
+       install-toolexeclibtestingDATA installcheck installcheck-am \
+       installdirs installdirs-am maintainer-clean \
+       maintainer-clean-generic maintainer-clean-multi mostlyclean \
+       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+       mostlyclean-local mostlyclean-multi pdf pdf-am ps ps-am tags \
+       tags-recursive uninstall uninstall-am \
+       uninstall-toolexeclibDATA uninstall-toolexeclibLIBRARIES \
+       uninstall-toolexeclibLTLIBRARIES \
+       uninstall-toolexeclibarchiveDATA \
+       uninstall-toolexeclibcompressDATA \
+       uninstall-toolexeclibcontainerDATA \
+       uninstall-toolexeclibcryptoDATA uninstall-toolexeclibdebugDATA \
+       uninstall-toolexeclibencodingDATA uninstall-toolexeclibexpDATA \
+       uninstall-toolexeclibgoDATA uninstall-toolexeclibhashDATA \
+       uninstall-toolexeclibhttpDATA uninstall-toolexeclibimageDATA \
+       uninstall-toolexeclibindexDATA uninstall-toolexeclibioDATA \
+       uninstall-toolexeclibmimeDATA uninstall-toolexeclibnetDATA \
+       uninstall-toolexeclibosDATA uninstall-toolexeclibrpcDATA \
+       uninstall-toolexeclibruntimeDATA \
+       uninstall-toolexeclibtestingDATA
+
+
+goc2c.$(OBJEXT): runtime/goc2c.c
+       $(CC_FOR_BUILD) -c $(CFLAGS_FOR_BUILD) $<
+
+goc2c: goc2c.$(OBJEXT)
+       $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $<
+
+malloc.c: $(srcdir)/runtime/malloc.goc goc2c
+       ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+       mv -f $@.tmp $@
+
+mprof.c: $(srcdir)/runtime/mprof.goc goc2c
+       ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+       mv -f $@.tmp $@
+
+reflect.c: $(srcdir)/runtime/reflect.goc goc2c
+       ./goc2c --gcc --go-prefix libgo_reflect $< > $@.tmp
+       mv -f $@.tmp $@
+
+sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
+       ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+       mv -f $@.tmp $@
+
+%.c: $(srcdir)/runtime/%.goc goc2c
+       ./goc2c --gcc $< > $@.tmp
+       mv -f $@.tmp $@
+
+version.go: s-version; @true
+s-version: Makefile
+       rm -f version.go.tmp
+       echo "package runtime" > version.go.tmp
+       echo 'const defaultGoroot = "$(prefix)"' >> version.go.tmp
+       echo 'const theVersion = "'`$(CC) --version | sed 1q`'"' >> version.go.tmp
+       echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
+       echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
+       $(SHELL) $(srcdir)/../move-if-change version.go.tmp version.go
+       $(STAMP) $@
+
+# Build a .la file from a .a file.
+.a.la:
+       $(LINK) $<.lo
+
+asn1/libasn1.a: $(go_asn1_files) bytes.gox fmt.gox io.gox os.gox reflect.gox \
+               strconv.gox strings.gox time.gox
+       $(BUILDARCHIVE)
+asn1/libasn1.la: asn1/libasn1.a
+asn1/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: asn1/check
+
+big/libbig.a: $(go_big_files) fmt.gox rand.gox strings.gox
+       $(BUILDARCHIVE)
+big/libbig.la: big/libbig.a
+big/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: big/check
+
+bufio/libbufio.a: $(go_bufio_files) bytes.gox io.gox os.gox strconv.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+bufio/libbufio.la: bufio/libbufio.a
+bufio/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: bufio/check
+
+bytes/libbytes.a: $(go_bytes_files) $(go_bytes_c_files) io.gox os.gox utf8.gox
+       test -d bytes || $(MKDIR_P) bytes
+       $(LTGOCOMPILE) -c -o bytes/bytes.$(OBJEXT) -fgo-prefix=libgo_bytes $(srcdir)/go/bytes/buffer.go $(srcdir)/go/bytes/bytes.go $(srcdir)/go/bytes/bytes_decl.go
+       $(LTCOMPILE) -c -o bytes/index.$(OBJEXT) $(srcdir)/go/bytes/indexbyte.c
+       rm -f $@
+       $(AR) rc $@ bytes/bytes.$(OBJEXT) bytes/index.$(OBJEXT)
+bytes/libbytes.la: bytes/libbytes.a
+       $(LINK) bytes/bytes.lo bytes/index.lo
+bytes/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: bytes/check
+
+cmath/libcmath.a: $(go_cmath_files) math.gox
+       $(BUILDARCHIVE)
+cmath/libcmath.la: cmath/libcmath.a
+cmath/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: cmath/check
+
+ebnf/libebnf.a: $(go_ebnf_files) container/vector.gox go/scanner.gox \
+               go/token.gox os.gox strconv.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+ebnf/libebnf.la: ebnf/libebnf.a
+ebnf/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: ebnf/check
+
+exec/libexec.a: $(go_exec_files) os.gox strings.gox
+       $(BUILDARCHIVE)
+exec/libexec.la: exec/libexec.a
+exec/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: exec/check
+
+expvar/libexpvar.a: $(go_expvar_files) bytes.gox fmt.gox http.gox json.gox \
+               log.gox os.gox runtime.gox strconv.gox sync.gox
+       $(BUILDARCHIVE)
+expvar/libexpvar.la: expvar/libexpvar.a
+expvar/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: expvar/check
+
+flag/libflag.a: $(go_flag_files) fmt.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+flag/libflag.la: flag/libflag.a
+flag/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: flag/check
+
+fmt/libfmt.a: $(go_fmt_files) bytes.gox io.gox os.gox reflect.gox strconv.gox \
+               strings.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+fmt/libfmt.la: fmt/libfmt.a
+fmt/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: fmt/check
+
+gob/libgob.a: $(go_gob_files) bytes.gox fmt.gox io.gox math.gox os.gox \
+               reflect.gox runtime.gox strings.gox sync.gox unicode.gox
+       $(BUILDARCHIVE)
+gob/libgob.la: gob/libgob.a
+gob/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: gob/check
+
+hash/libhash.a: $(go_hash_files) io.gox
+       $(BUILDARCHIVE)
+hash/libhash.la: hash/libhash.a
+hash/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: hash/check
+
+html/libhtml.a: $(go_html_files) bytes.gox io.gox os.gox strconv.gox \
+               strings.gox utf8.gox
+       $(BUILDARCHIVE)
+html/libhtml.la: html/libhtml.a
+html/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: html/check
+
+http/libhttp.a: $(go_http_files) bufio.gox bytes.gox container/list.gox \
+               container/vector.gox crypto/rand.gox crypto/tls.gox \
+               encoding/base64.gox fmt.gox io.gox io/ioutil.gox log.gox \
+               mime.gox mime/multipart.gox net.gox os.gox path.gox sort.gox \
+               strconv.gox strings.gox sync.gox time.gox utf8.gox
+       $(BUILDARCHIVE)
+http/libhttp.la: http/libhttp.a
+http/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: http/check
+
+image/libimage.a: $(go_image_files) bufio.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+image/libimage.la: image/libimage.a
+image/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: image/check
+
+io/libio.a: $(go_io_files) os.gox runtime.gox sync.gox
+       $(BUILDARCHIVE)
+io/libio.la: io/libio.a
+io/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: io/check
+
+json/libjson.a: $(go_json_files) bytes.gox container/vector.gox fmt.gox \
+               io.gox math.gox os.gox reflect.gox runtime.gox strconv.gox \
+               strings.gox unicode.gox utf16.gox utf8.gox
+       $(BUILDARCHIVE)
+json/libjson.la: json/libjson.a
+json/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: json/check
+
+log/liblog.a: $(go_log_files) bytes.gox fmt.gox io.gox runtime.gox os.gox \
+               time.gox
+       $(BUILDARCHIVE)
+log/liblog.la: log/liblog.a
+log/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: log/check
+
+math/libmath.a: $(go_math_files)
+       $(BUILDARCHIVE)
+math/libmath.la: math/libmath.a
+math/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: math/check
+
+mime/libmime.a: $(go_mime_files) bufio.gox bytes.gox os.gox strings.gox \
+               sync.gox unicode.gox
+       $(BUILDARCHIVE)
+mime/libmime.la: mime/libmime.a
+mime/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: mime/check
+
+net/libnet.a: $(go_net_files) fmt.gox io.gox os.gox reflect.gox strconv.gox \
+               strings.gox sync.gox syscall.gox
+       $(BUILDARCHIVE)
+net/libnet.la: net/libnet.a
+net/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: net/check
+
+netchan/libnetchan.a: $(go_netchan_files) gob.gox log.gox net.gox os.gox \
+               reflect.gox sync.gox time.gox
+       $(BUILDARCHIVE)
+netchan/libnetchan.la: netchan/libnetchan.a
+netchan/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: netchan/check
+
+os/libos.a: $(go_os_files) sync.gox syscall.gox
+       $(BUILDARCHIVE)
+os/libos.la: os/libos.a
+os/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: os/check
+
+patch/libpatch.a: $(go_patch_files) bytes.gox compress/zlib.gox \
+               crypto/sha1.gox encoding/git85.gox fmt.gox io.gox os.gox \
+               path.gox strings.gox
+       $(BUILDARCHIVE)
+patch/libpatch.la: patch/libpatch.a
+patch/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: patch/check
+
+path/libpath.a: $(go_path_files) io/ioutil.gox os.gox sort.gox strings.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+path/libpath.la: path/libpath.a
+path/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: path/check
+
+rand/librand.a: $(go_rand_files) math.gox sync.gox
+       $(BUILDARCHIVE)
+rand/librand.la: rand/librand.a
+rand/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: rand/check
+
+reflect/libreflect.a: $(go_reflect_files) math.gox runtime.gox strconv.gox \
+               sync.gox
+       $(BUILDARCHIVE)
+reflect/libreflect.la: reflect/libreflect.a
+reflect/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: reflect/check
+
+regexp/libregexp.a: $(go_regexp_files) bytes.gox io.gox os.gox strings.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+regexp/libregexp.la: regexp/libregexp.a
+regexp/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: regexp/check
+
+rpc/librpc.a: $(go_rpc_files) bufio.gox fmt.gox gob.gox http.gox io.gox \
+               log.gox net.gox os.gox reflect.gox sort.gox strings.gox \
+               strconv.gox sync.gox template.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+rpc/librpc.la: rpc/librpc.a
+rpc/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: rpc/check
+
+runtime/libruntime.a: $(go_runtime_files)
+       $(BUILDARCHIVE)
+runtime/libruntime.la: runtime/libruntime.a
+runtime/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: runtime/check
+
+scanner/libscanner.a: $(go_scanner_files) bytes.gox fmt.gox io.gox os.gox \
+               unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+scanner/libscanner.la: scanner/libscanner.a
+scanner/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: scanner/check
+
+smtp/libsmtp.a: $(go_smtp_files) crypto/tls.gox encoding/base64.gox io.gox \
+               net.gox net/textproto.gox os.gox strings.gox
+       $(BUILDARCHIVE)
+smtp/libsmtp.la: smtp/libsmtp.a
+smtp/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: smtp/check
+
+sort/libsort.a: $(go_sort_files)
+       $(BUILDARCHIVE)
+sort/libsort.la: sort/libsort.a
+sort/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: sort/check
+
+strconv/libstrconv.a: $(go_strconv_files) bytes.gox math.gox os.gox \
+               strings.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+strconv/libstrconv.la: strconv/libstrconv.a
+strconv/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: strconv/check
+
+strings/libstrings.a: $(go_strings_files) os.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+strings/libstrings.la: strings/libstrings.a
+strings/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: strings/check
+
+sync/libsync.a: $(go_sync_files) $(go_sync_c_files) runtime.gox
+       test -d sync || $(MKDIR_P) sync
+       $(LTGOCOMPILE) -c -o sync/mutex.$(OBJEXT) -fgo-prefix=libgo_sync $(srcdir)/go/sync/mutex.go $(srcdir)/go/sync/once.go $(srcdir)/go/sync/rwmutex.go
+       $(LTCOMPILE) -c -o sync/cas.$(OBJEXT) $(srcdir)/go/sync/cas.c
+       rm -f $@
+       $(AR) rc $@ sync/mutex.$(OBJEXT) sync/cas.$(OBJEXT)
+sync/libsync.la: sync/libsync.a
+       $(LINK) sync/mutex.lo sync/cas.lo
+sync/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: sync/check
+
+syslog/libsyslog.a: $(go_syslog_files) fmt.gox log.gox net.gox os.gox
+       $(BUILDARCHIVE)
+syslog/libsyslog.la: syslog/libsyslog.a
+syslog/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: syslog/check
+
+tabwriter/libtabwriter.a: $(go_tabwriter_files) bytes.gox io.gox os.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+tabwriter/libtabwriter.la: tabwriter/libtabwriter.a
+tabwriter/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: tabwriter/check
+
+template/libtemplate.a: $(go_template_files) bytes.gox fmt.gox io.gox os.gox \
+               reflect.gox runtime.gox strings.gox container/vector.gox
+       $(BUILDARCHIVE)
+template/libtemplate.la: template/libtemplate.a
+template/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: template/check
+
+testing/libtesting.a: $(go_testing_files) flag.gox fmt.gox os.gox regexp.gox \
+               runtime.gox time.gox
+       $(BUILDARCHIVE)
+testing/libtesting.la: testing/libtesting.a
+testing/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: testing/check
+
+time/libtime.a: $(go_time_files) bytes.gox io/ioutil.gox os.gox strconv.gox \
+               sync.gox syscall.gox
+       $(BUILDARCHIVE)
+time/libtime.la: time/libtime.a
+time/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: time/check
+
+try/libtry.a: $(go_try_files) fmt.gox io.gox os.gox reflect.gox unicode.gox
+       $(BUILDARCHIVE)
+try/libtry.la: try/libtry.a
+try/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: try/check
+
+unicode/libunicode.a: $(go_unicode_files)
+       $(BUILDARCHIVE)
+unicode/libunicode.la: unicode/libunicode.a
+unicode/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: unicode/check
+
+utf16/libutf16.a: $(go_utf16_files) unicode.gox
+       $(BUILDARCHIVE)
+utf16/libutf16.la: utf16/libutf16.a
+utf16/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: utf16/check
+
+utf8/libutf8.a: $(go_utf8_files) unicode.gox
+       $(BUILDARCHIVE)
+utf8/libutf8.la: utf8/libutf8.a
+utf8/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: utf8/check
+
+websocket/libwebsocket.a: $(go_websocket_files) bufio.gox bytes.gox \
+               container/vector.gox crypto/md5.gox crypto/tls.gox \
+               encoding/binary.gox fmt.gox http.gox io.gox net.gox os.gox \
+               rand.gox strings.gox
+       $(BUILDARCHIVE)
+websocket/libwebsocket.la: websocket/libwebsocket.a
+websocket/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: websocket/check
+
+xml/libxml.a: $(go_xml_files) bufio.gox bytes.gox io.gox os.gox reflect.gox \
+               strconv.gox strings.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+xml/libxml.la: xml/libxml.a
+xml/check: $(CHECK_DEPS)
+       $(CHECK)
+.PHONY: xml/check
+
+archive/libtar.a: $(go_archive_tar_files) bytes.gox io.gox os.gox strconv.gox \
+               strings.gox
+       $(BUILDARCHIVE)
+archive/libtar.la: archive/libtar.a
+archive/tar/check: $(CHECK_DEPS)
+       @$(MKDIR_P) archive/tar
+       $(CHECK)
+.PHONY: archive/tar/check
+
+archive/libzip.a: $(go_archive_zip_files) bufio.gox bytes.gox \
+               compress/flate.gox hash.gox hash/crc32.gox \
+               encoding/binary.gox io.gox os.gox
+       $(BUILDARCHIVE)
+archive/libzip.la: archive/libzip.a
+archive/zip/check: $(CHECK_DEPS)
+       @$(MKDIR_P) archive/zip
+       $(CHECK)
+.PHONY: archive/zip/check
+
+compress/libflate.a: $(go_compress_flate_files) bufio.gox io.gox math.gox \
+               os.gox sort.gox strconv.gox
+       $(BUILDARCHIVE)
+compress/libflate.la: compress/libflate.a
+compress/flate/check: $(CHECK_DEPS)
+       @$(MKDIR_P) compress/flate
+       $(CHECK)
+.PHONY: compress/flate/check
+
+compress/libgzip.a: $(go_compress_gzip_files) bufio.gox compress/flate.gox \
+               hash.gox hash/crc32.gox io.gox os.gox
+       $(BUILDARCHIVE)
+compress/libgzip.la: compress/libgzip.a
+compress/gzip/check: $(CHECK_DEPS)
+       @$(MKDIR_P) compress/gzip
+       $(CHECK)
+.PHONY: compress/gzip/check
+
+compress/libzlib.a: $(go_compress_zlib_files) bufio.gox compress/flate.gox \
+               hash.gox hash/adler32.gox io.gox os.gox
+       $(BUILDARCHIVE)
+compress/libzlib.la: compress/libzlib.a
+compress/zlib/check: $(CHECK_DEPS)
+       @$(MKDIR_P) compress/zlib
+       $(CHECK)
+.PHONY: compress/zlib/check
+
+container/libheap.a: $(go_container_heap_files) sort.gox
+       $(BUILDARCHIVE)
+container/libheap.la: container/libheap.a
+container/heap/check: $(CHECK_DEPS)
+       @$(MKDIR_P) container/heap
+       $(CHECK)
+.PHONY: container/heap/check
+
+container/liblist.a: $(go_container_list_files)
+       $(BUILDARCHIVE)
+container/liblist.la: container/liblist.a
+container/list/check: $(CHECK_DEPS)
+       @$(MKDIR_P) container/list
+       $(CHECK)
+.PHONY: container/list/check
+
+container/libring.a: $(go_container_ring_files)
+       $(BUILDARCHIVE)
+container/libring.la: container/libring.a
+container/ring/check: $(CHECK_DEPS)
+       @$(MKDIR_P) container/ring
+       $(CHECK)
+.PHONY: container/ring/check
+
+container/libvector.a: $(go_container_vector_files)
+       $(BUILDARCHIVE)
+container/libvector.la: container/libvector.a
+container/vector/check: $(CHECK_DEPS)
+       @$(MKDIR_P) container/vector
+       $(CHECK)
+.PHONY: container/vector/check
+
+crypto/libaes.a: $(go_crypto_aes_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/libaes.la: crypto/libaes.a
+crypto/aes/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/aes
+       $(CHECK)
+.PHONY: crypto/aes/check
+
+crypto/libblock.a: $(go_crypto_block_files) fmt.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/libblock.la: crypto/libblock.a
+crypto/block/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/block
+       $(CHECK)
+.PHONY: crypto/block/check
+
+crypto/libblowfish.a: $(go_crypto_blowfish_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/libblowfish.la: crypto/libblowfish.a
+crypto/blowfish/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/blowfish
+       $(CHECK)
+.PHONY: crypto/blowfish/check
+
+crypto/libcast5.a: $(go_crypto_cast5_files) os.gox
+       $(BUILDARCHIVE)
+crypto/libcast5.la: crypto/libcast5.a
+crypt/cast5/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/cast5
+       $(CHECK)
+.PHONY: crypto/cast5/check
+
+crypto/libhmac.a: $(go_crypto_hmac_files) crypto/md5.gox crypto/sha1.gox \
+               hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libhmac.la: crypto/libhmac.a
+crypto/hmac/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/hmac
+       $(CHECK)
+.PHONY: crypto/hmac/check
+
+crypto/libmd4.a: $(go_crypto_md4_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libmd4.la: crypto/libmd4.a
+crypto/md4/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/md4
+       $(CHECK)
+.PHONY: crypto/md4/check
+
+crypto/libmd5.a: $(go_crypto_md5_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libmd5.la: crypto/libmd5.a
+crypto/md5/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/md5
+       $(CHECK)
+.PHONY: crypto/md5/check
+
+crypto/libocsp.a: $(go_crypto_ocsp_files) asn1.gox crypto/rsa.gox \
+               crypto/sha1.gox crypto/x509.gox os.gox time.gox
+       $(BUILDARCHIVE)
+crypto/libocsp.la: crypto/libocsp.a
+crypto/ocsp/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/ocsp
+       $(CHECK)
+.PHONY: crypto/ocsp/check
+
+crypto/librand.a: $(go_crypto_rand_files) crypto/aes.gox io.gox os.gox \
+               sync.gox time.gox
+       $(BUILDARCHIVE)
+crypto/librand.la: crypto/librand.a
+crypto/rand/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/rand
+       $(CHECK)
+.PHONY: crypto/rand/check
+
+crypto/librc4.a: $(go_crypto_rc4_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/librc4.la: crypto/librc4.a
+crypto/rc4/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/rc4
+       $(CHECK)
+.PHONY: crypto/rc4/check
+
+crypto/libripemd160.a: $(go_crypto_ripemd160_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libripemd160.la: crypto/libripemd160.a
+crypto/ripemd160/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/ripemd160
+       $(CHECK)
+.PHONY: crypto/ripemd160/check
+
+crypto/librsa.a: $(go_crypto_rsa_files) big.gox crypto/sha1.gox \
+               crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox
+       $(BUILDARCHIVE)
+crypto/librsa.la: crypto/librsa.a
+crypto/rsa/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/rsa
+       $(CHECK)
+.PHONY: crypto/rsa/check
+
+crypto/libsha1.a: $(go_crypto_sha1_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libsha1.la: crypto/libsha1.a
+crypto/sha1/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/sha1
+       $(CHECK)
+.PHONY: crypto/sha1/check
+
+crypto/libsha256.a: $(go_crypto_sha256_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libsha256.la: crypto/libsha256.a
+crypto/sha256/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/sha256
+       $(CHECK)
+.PHONY: crypto/sha256/check
+
+crypto/libsha512.a: $(go_crypto_sha512_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+crypto/libsha512.la: crypto/libsha512.a
+crypto/sha512/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/sha512
+       $(CHECK)
+.PHONY: crypto/sha512/check
+
+crypto/libsubtle.a: $(go_crypto_subtle_files)
+       $(BUILDARCHIVE)
+crypto/libsubtle.la: crypto/libsubtle.a
+crypto/subtle/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/subtle
+       $(CHECK)
+.PHONY: crypto/subtle/check
+
+crypto/libtls.a: $(go_crypto_tls_files) bufio.gox bytes.gox container/list.gox \
+               crypto/hmac.gox crypto/md5.gox crypto/rc4.gox crypto/rand.gox \
+               crypto/rsa.gox crypto/sha1.gox crypto/subtle.gox \
+               crypto/rsa.gox crypto/x509.gox encoding/pem.gox fmt.gox \
+               hash.gox io.gox io/ioutil.gox net.gox os.gox strings.gox \
+               sync.gox time.gox
+       $(BUILDARCHIVE)
+crypto/libtls.la: crypto/libtls.a
+crypto/tls/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/tls
+       $(CHECK)
+.PHONY: crypto/tls/check
+
+crypto/libx509.a: $(go_crypto_x509_files) asn1.gox big.gox \
+               container/vector.gox crypto/rsa.gox crypto/sha1.gox hash.gox \
+               os.gox strings.gox time.gox
+       $(BUILDARCHIVE)
+crypto/libx509.la: crypto/libx509.a
+crypto/x509/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/x509
+       $(CHECK)
+.PHONY: crypto/x509/check
+
+crypto/libxtea.a: $(go_crypto_xtea_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+crypto/libxtea.la: crypto/libxtea.a
+crypto/xtea/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/xtea
+       $(CHECK)
+.PHONY: crypto/xtea/check
+
+debug/libdwarf.a: $(go_debug_dwarf_files) encoding/binary.gox os.gox \
+               strconv.gox
+       $(BUILDARCHIVE)
+debug/libdwarf.la: debug/libdwarf.a
+debug/dwarf/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/dwarf
+       $(CHECK)
+.PHONY: debug/dwarf/check
+
+debug/libelf.a: $(go_debug_elf_files) bytes.gox debug/dwarf.gox \
+               encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+debug/libelf.la: debug/libelf.a
+debug/elf/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/elf
+       $(CHECK)
+.PHONY: debug/elf/check
+
+debug/libgosym.a: $(go_debug_gosym_files) encoding/binary.gox fmt.gox os.gox \
+               strconv.gox strings.gox
+       $(BUILDARCHIVE)
+debug/libgosym.la: debug/libgosym.a
+debug/gosym/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/gosym
+       $(CHECK)
+.PHONY: debug/gosym/check
+
+debug/libmacho.a: $(go_debug_macho_files) bytes.gox debug/dwarf.gox \
+               encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+debug/libmacho.la: debug/libmacho.a
+debug/macho/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/macho
+       $(CHECK)
+.PHONY: debug/macho/check
+
+debug/libpe.a: $(go_debug_pe_files) debug/dwarf.gox encoding/binary.gox \
+               fmt.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+debug/libpe.la: debug/libpe.a
+debug/pe/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/pe
+       $(CHECK)
+.PHONY: debug/pe/check
+
+debug/libproc.a: $(go_debug_proc_files) container/vector.gox fmt.gox \
+               io/ioutil.gox os.gox runtime.gox strconv.gox strings.gox \
+               sync.gox syscall.gox
+       $(BUILDARCHIVE)
+debug/libproc.la: debug/libproc.a
+debug/proc/check: $(CHECK_DEPS)
+       @$(MKDIR_P) debug/proc
+       $(CHECK)
+.PHONY: debug/proc/check
+
+encoding/libascii85.a: $(go_encoding_ascii85_files) io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+encoding/libascii85.la: encoding/libascii85.a
+encoding/ascii85/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/ascii85
+       $(CHECK)
+.PHONY: encoding/ascii85/check
+
+encoding/libbase64.a: $(go_encoding_base64_files) io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+encoding/libbase64.la: encoding/libbase64.a
+encoding/base64/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/base64
+       $(CHECK)
+.PHONY: encoding/base64/check
+
+encoding/libbinary.a: $(go_encoding_binary_files) io.gox math.gox os.gox \
+               reflect.gox
+       $(BUILDARCHIVE)
+encoding/libbinary.la: encoding/libbinary.a
+encoding/binary/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/binary
+       $(CHECK)
+.PHONY: encoding/binary/check
+
+encoding/libgit85.a: $(go_encoding_git85_files) bytes.gox io.gox os.gox \
+               strconv.gox
+       $(BUILDARCHIVE)
+encoding/libgit85.la: encoding/libgit85.a
+encoding/git85/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/git85
+       $(CHECK)
+.PHONY: encoding/git85/check
+
+encoding/libhex.a: $(go_encoding_hex_files) os.gox strconv.gox
+       $(BUILDARCHIVE)
+encoding/libhex.la: encoding/libhex.a
+encoding/hex/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/hex
+       $(CHECK)
+.PHONY: encoding/hex/check
+
+encoding/libpem.a: $(go_encoding_pem_files) bytes.gox encoding/base64.gox
+       $(BUILDARCHIVE)
+encoding/libpem.la: encoding/libpem.a
+encoding/pem/check: $(CHECK_DEPS)
+       @$(MKDIR_P) encoding/pem
+       $(CHECK)
+.PHONY: encoding/pem/check
+
+exp/libdatafmt.a: $(go_exp_datafmt_files) bytes.gox container/vector.gox \
+               fmt.gox go/scanner.gox go/token.gox io.gox os.gox reflect.gox \
+               runtime.gox strconv.gox strings.gox
+       $(BUILDARCHIVE)
+exp/libdatafmt.la: exp/libdatafmt.a
+exp/datafmt/check: $(CHECK_DEPS)
+       @$(MKDIR_P) exp/datafmt
+       $(CHECK)
+.PHONY: exp/datafmt/check
+
+exp/libdraw.a: $(go_exp_draw_files) image.gox os.gox
+       $(BUILDARCHIVE)
+exp/libdraw.la: exp/libdraw.a
+exp/draw/check: $(CHECK_DEPS)
+       @$(MKDIR_P) exp/draw
+       $(CHECK)
+.PHONY: exp/draw/check
+
+exp/libeval.a: $(go_exp_eval_files) big.gox go/ast.gox go/parser.gox \
+               go/scanner.gox go/token.gox fmt.gox log.gox strconv.gox \
+               strings.gox os.gox reflect.gox runtime.gox sort.gox template.gox
+       $(BUILDARCHIVE)
+exp/libeval.la: exp/libeval.a
+exp/eval/check: $(CHECK_DEPS)
+       @$(MKDIR_P) exp/eval
+       $(CHECK)
+.PHONY: exp/eval/check
+
+go/libast.a: $(go_go_ast_files) fmt.gox go/token.gox io.gox os.gox \
+               reflect.gox unicode.gox utf8.gox
+       $(BUILDARCHIVE)
+go/libast.la: go/libast.a
+go/ast/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/ast
+       $(CHECK)
+.PHONY: go/ast/check
+
+go/libdoc.a: $(go_go_doc_files) go/ast.gox go/token.gox io.gox regexp.gox \
+               sort.gox strings.gox template.gox
+       $(BUILDARCHIVE)
+go/libdoc.la: go/libdoc.a
+go/doc/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/doc
+       $(CHECK)
+.PHONY: go/doc/check
+
+go/libparser.a: $(go_go_parser_files) bytes.gox fmt.gox go/ast.gox \
+               go/scanner.gox go/token.gox io.gox io/ioutil.gox os.gox \
+               path.gox strings.gox
+       $(BUILDARCHIVE)
+go/libparser.la: go/libparser.a
+go/parser/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/parser
+       $(CHECK)
+.PHONY: go/parser/check
+
+go/libprinter.a: $(go_go_printer_files) bytes.gox fmt.gox go/ast.gox \
+               go/token.gox io.gox os.gox reflect.gox runtime.gox \
+               strings.gox tabwriter.gox
+       $(BUILDARCHIVE)
+go/libprinter.la: go/libprinter.a
+go/printer/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/printer
+       $(CHECK)
+.PHONY: go/printer/check
+
+go/libscanner.a: $(go_go_scanner_files) bytes.gox container/vector.gox fmt.gox \
+               go/token.gox io.gox os.gox sort.gox strconv.gox unicode.gox \
+               utf8.gox
+       $(BUILDARCHIVE)
+go/libscanner.la: go/libscanner.a
+go/scanner/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/scanner
+       $(CHECK)
+.PHONY: go/scanner/check
+
+go/libtoken.a: $(go_go_token_files) fmt.gox strconv.gox
+       $(BUILDARCHIVE)
+go/libtoken.la: go/libtoken.a
+go/token/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/token
+       $(CHECK)
+.PHONY: go/token/check
+
+go/libtypechecker.a: $(go_go_typechecker_files) fmt.gox go/ast.gox \
+               go/token.gox go/scanner.gox os.gox
+       $(BUILDARCHIVE)
+go/libtypechecker.la: go/libtypechecker.a
+go/typechecker/check: $(CHECK_DEPS)
+       @$(MKDIR_P) go/typechecker
+       $(CHECK)
+.PHONY: go/typechecker/check
+
+hash/libadler32.a: $(go_hash_adler32_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+hash/libadler32.la: hash/libadler32.a
+hash/adler32/check: $(CHECK_DEPS)
+       @$(MKDIR_P) hash/adler32
+       $(CHECK)
+.PHONY: hash/adler32/check
+
+hash/libcrc32.a: $(go_hash_crc32_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+hash/libcrc32.la: hash/libcrc32.a
+hash/crc32/check: $(CHECK_DEPS)
+       @$(MKDIR_P) hash/crc32
+       $(CHECK)
+.PHONY: hash/crc32/check
+
+hash/libcrc64.a: $(go_hash_crc64_files) hash.gox os.gox
+       $(BUILDARCHIVE)
+hash/libcrc64.la: hash/libcrc64.a
+hash/crc64/check: $(CHECK_DEPS)
+       @$(MKDIR_P) hash/crc64
+       $(CHECK)
+.PHONY: hash/crc64/check
+
+http/libpprof.a: $(go_http_pprof_files) bufio.gox fmt.gox http.gox os.gox \
+               runtime.gox runtime/pprof.gox strconv.gox strings.gox
+       $(BUILDARCHIVE)
+http/libpprof.la: http/libpprof.a
+http/pprof/check: $(CHECK_DEPS)
+       @$(MKDIR_P) http/pprof
+       $(CHECK)
+.PHONY: http/pprof/check
+
+image/libjpeg.a: $(go_image_jpeg_files) bufio.gox image.gox io.gox os.gox
+       $(BUILDARCHIVE)
+image/libjpeg.la: image/libjpeg.a
+image/jpeg/check: $(CHECK_DEPS)
+       @$(MKDIR_P) image/jpeg
+       $(CHECK)
+.PHONY: image/jpeg/check
+
+image/libpng.a: $(go_image_png_files) bufio.gox compress/zlib.gox fmt.gox \
+               hash.gox hash/crc32.gox image.gox io.gox os.gox strconv.gox
+       $(BUILDARCHIVE)
+image/libpng.la: image/libpng.a
+image/png/check: $(CHECK_DEPS)
+       @$(MKDIR_P) image/png
+       $(CHECK)
+.PHONY: image/png/check
+
+index/libsuffixarray.a: $(go_index_suffixarray_files) bytes.gox \
+               container/vector.gox sort.gox
+       $(BUILDARCHIVE)
+index/libsuffixarray.la: index/libsuffixarray.a
+index/suffixarray/check: $(CHECK_DEPS)
+       @$(MKDIR_P) index/suffixarray
+       $(CHECK)
+.PHONY: index/suffixarray/check
+
+io/libioutil.a: $(go_io_ioutil_files) bytes.gox io.gox os.gox sort.gox \
+               strconv.gox
+       $(BUILDARCHIVE)
+io/libioutil.la: io/libioutil.a
+io/ioutil/check: $(CHECK_DEPS)
+       @$(MKDIR_P) io/ioutil
+       $(CHECK)
+.PHONY: io/ioutil/check
+
+mime/libmultipart.a: $(go_mime_multipart_files) bufio.gox bytes.gox io.gox \
+               mime.gox os.gox regexp.gox strings.gox
+       $(BUILDARCHIVE)
+mime/libmultipart.la: mime/libmultipart.a
+mime/multipart/check: $(CHECK_DEPS)
+       @$(MKDIR_P) mime/multipart
+       $(CHECK)
+.PHONY: mime/multipart/check
+
+net/libdict.a: $(go_net_dict_files) container/vector.gox net/textproto.gox \
+               os.gox strconv.gox strings.gox
+       $(BUILDARCHIVE)
+net/libdict.la: net/libdict.a
+
+net/libtextproto.a: $(go_net_textproto_files) bufio.gox bytes.gox \
+               container/vector.gox fmt.gox io.gox io/ioutil.gox net.gox \
+               os.gox strconv.gox sync.gox
+       $(BUILDARCHIVE)
+net/libtextproto.la: net/libtextproto.a
+net/textproto/check: $(CHECK_DEPS)
+       @$(MKDIR_P) net/textproto
+       $(CHECK)
+.PHONY: net/textproto/check
+
+os/libsignal.a: $(go_os_signal_files) runtime.gox strconv.gox
+       $(BUILDARCHIVE)
+os/libsignal.la: os/libsignal.a
+os/signal/check: $(CHECK_DEPS)
+       @$(MKDIR_P) os/signal
+       $(CHECK)
+.PHONY: os/signal/check
+
+unix.go: $(srcdir)/go/os/signal/mkunix.sh sysinfo.go
+       $(SHELL) $(srcdir)/go/os/signal/mkunix.sh sysinfo.go > $@.tmp
+       mv -f $@.tmp $@
+
+rpc/libjsonrpc.a: $(go_rpc_jsonrpc_files) fmt.gox io.gox json.gox net.gox \
+               os.gox rpc.gox sync.gox
+       $(BUILDARCHIVE)
+rpc/libjsonrpc.la: rpc/libjsonrpc.a
+rpc/jsonrpc/check: $(CHECK_DEPS)
+       @$(MKDIR_P) rpc/jsonrpc
+       $(CHECK)
+.PHONY: rpc/jsonrpc/check
+
+runtime/libpprof.a: $(go_runtime_pprof_files) bufio.gox fmt.gox io.gox os.gox \
+               runtime.gox
+       $(BUILDARCHIVE)
+runtime/libpprof.la: runtime/libpprof.a
+runtime/pprof/check: $(CHECK_DEPS)
+       @$(MKDIR_P) runtime/pprof
+       $(CHECK)
+.PHONY: runtime/pprof/check
+
+testing/libiotest.a: $(go_testing_iotest_files) io.gox log.gox os.gox
+       $(BUILDARCHIVE)
+testing/libiotest.la: testing/libiotest.a
+testing/iotest/check: $(CHECK_DEPS)
+       @$(MKDIR_P) testing/iotest
+       $(CHECK)
+.PHONY: testing/iotest/check
+
+testing/libquick.a: $(go_testing_quick_files) flag.gox fmt.gox math.gox \
+               os.gox rand.gox reflect.gox strings.gox
+       $(BUILDARCHIVE)
+testing/libquick.la: testing/libquick.a
+testing/quick/check: $(CHECK_DEPS)
+       @$(MKDIR_P) testing/quick
+       $(CHECK)
+.PHONY: testing/quick/check
+
+testing/libscript.a: $(go_testing_script_files) fmt.gox os.gox rand.gox \
+               reflect.gox strings.gox
+       $(BUILDARCHIVE)
+testing/libscript.la: testing/libscript.a
+testing/script/check: $(CHECK_DEPS)
+       @$(MKDIR_P) testing/script
+       $(CHECK)
+.PHONY: testing/script/check
+
+sysinfo.go: $(srcdir)/mksysinfo.sh config.h
+       $(SHELL) $(srcdir)/mksysinfo.sh
+syscalls/libsyscall.a: $(go_syscall_files) $(go_syscall_c_files) sync.gox
+       rm -f syscall.gox syscalls/libsyscall.a
+       test -d syscalls || $(MKDIR_P) syscalls
+       files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e's/[^ ]*\.c//g'`; \
+       $(LTGOCOMPILE) -c -fgo-prefix="libgo_syscalls" -o syscalls/syscall.$(OBJEXT) $$files
+       $(LTCOMPILE) -c -o syscalls/errno.$(OBJEXT) $(srcdir)/syscalls/errno.c
+       $(AR) rc syscalls/libsyscall.a syscalls/syscall.$(OBJEXT) syscalls/errno.$(OBJEXT)
+syscalls/libsyscall.la: syscalls/libsyscall.a
+       $(LINK) syscalls/syscall.lo syscalls/errno.lo
+
+asn1.gox: asn1/libasn1.a
+       $(BUILDGOX)
+big.gox: big/libbig.a
+       $(BUILDGOX)
+bufio.gox: bufio/libbufio.a
+       $(BUILDGOX)
+bytes.gox: bytes/libbytes.a
+       $(BUILDGOX)
+cmath.gox: cmath/libcmath.a
+       $(BUILDGOX)
+ebnf.gox: ebnf/libebnf.a
+       $(BUILDGOX)
+exec.gox: exec/libexec.a
+       $(BUILDGOX)
+expvar.gox: expvar/libexpvar.a
+       $(BUILDGOX)
+flag.gox: flag/libflag.a
+       $(BUILDGOX)
+fmt.gox: fmt/libfmt.a
+       $(BUILDGOX)
+gob.gox: gob/libgob.a
+       $(BUILDGOX)
+hash.gox: hash/libhash.a
+       $(BUILDGOX)
+html.gox: html/libhtml.a
+       $(BUILDGOX)
+http.gox: http/libhttp.a
+       $(BUILDGOX)
+image.gox: image/libimage.a
+       $(BUILDGOX)
+io.gox: io/libio.a
+       $(BUILDGOX)
+json.gox: json/libjson.a
+       $(BUILDGOX)
+log.gox: log/liblog.a
+       $(BUILDGOX)
+math.gox: math/libmath.a
+       $(BUILDGOX)
+mime.gox: mime/libmime.a
+       $(BUILDGOX)
+net.gox: net/libnet.a
+       $(BUILDGOX)
+netchan.gox: netchan/libnetchan.a
+       $(BUILDGOX)
+os.gox: os/libos.a
+       $(BUILDGOX)
+patch.gox: patch/libpatch.a
+       $(BUILDGOX)
+path.gox: path/libpath.a
+       $(BUILDGOX)
+rand.gox: rand/librand.a
+       $(BUILDGOX)
+reflect.gox: reflect/libreflect.a
+       $(BUILDGOX)
+regexp.gox: regexp/libregexp.a
+       $(BUILDGOX)
+rpc.gox: rpc/librpc.a
+       $(BUILDGOX)
+runtime.gox: runtime/libruntime.a
+       $(BUILDGOX)
+scanner.gox: scanner/libscanner.a
+       $(BUILDGOX)
+smtp.gox: smtp/libsmtp.a
+       $(BUILDGOX)
+sort.gox: sort/libsort.a
+       $(BUILDGOX)
+strconv.gox: strconv/libstrconv.a
+       $(BUILDGOX)
+strings.gox: strings/libstrings.a
+       $(BUILDGOX)
+sync.gox: sync/libsync.a
+       $(BUILDGOX)
+syslog.gox: syslog/libsyslog.a
+       $(BUILDGOX)
+syscall.gox: syscalls/libsyscall.a
+       $(BUILDGOX)
+tabwriter.gox: tabwriter/libtabwriter.a
+       $(BUILDGOX)
+template.gox: template/libtemplate.a
+       $(BUILDGOX)
+testing.gox: testing/libtesting.a
+       $(BUILDGOX)
+time.gox: time/libtime.a
+       $(BUILDGOX)
+try.gox: try/libtry.a
+       $(BUILDGOX)
+unicode.gox: unicode/libunicode.a
+       $(BUILDGOX)
+utf16.gox: utf16/libutf16.a
+       $(BUILDGOX)
+utf8.gox: utf8/libutf8.a
+       $(BUILDGOX)
+websocket.gox: websocket/libwebsocket.a
+       $(BUILDGOX)
+xml.gox: xml/libxml.a
+       $(BUILDGOX)
+
+archive/tar.gox: archive/libtar.a
+       $(BUILDGOX)
+archive/zip.gox: archive/libzip.a
+       $(BUILDGOX)
+
+compress/flate.gox: compress/libflate.a
+       $(BUILDGOX)
+compress/gzip.gox: compress/libgzip.a
+       $(BUILDGOX)
+compress/zlib.gox: compress/libzlib.a
+       $(BUILDGOX)
+
+container/heap.gox: container/libheap.a
+       $(BUILDGOX)
+container/list.gox: container/liblist.a
+       $(BUILDGOX)
+container/ring.gox: container/libring.a
+       $(BUILDGOX)
+container/vector.gox: container/libvector.a
+       $(BUILDGOX)
+
+crypto/aes.gox: crypto/libaes.a
+       $(BUILDGOX)
+crypto/block.gox: crypto/libblock.a
+       $(BUILDGOX)
+crypto/blowfish.gox: crypto/libblowfish.a
+       $(BUILDGOX)
+crypto/cast5.gox: crypto/libcast5.a
+       $(BUILDGOX)
+crypto/hmac.gox: crypto/libhmac.a
+       $(BUILDGOX)
+crypto/md4.gox: crypto/libmd4.a
+       $(BUILDGOX)
+crypto/md5.gox: crypto/libmd5.a
+       $(BUILDGOX)
+crypto/ocsp.gox: crypto/libocsp.a
+       $(BUILDGOX)
+crypto/rand.gox: crypto/librand.a
+       $(BUILDGOX)
+crypto/rc4.gox: crypto/librc4.a
+       $(BUILDGOX)
+crypto/ripemd160.gox: crypto/libripemd160.a
+       $(BUILDGOX)
+crypto/rsa.gox: crypto/librsa.a
+       $(BUILDGOX)
+crypto/sha1.gox: crypto/libsha1.a
+       $(BUILDGOX)
+crypto/sha256.gox: crypto/libsha256.a
+       $(BUILDGOX)
+crypto/sha512.gox: crypto/libsha512.a
+       $(BUILDGOX)
+crypto/subtle.gox: crypto/libsubtle.a
+       $(BUILDGOX)
+crypto/tls.gox: crypto/libtls.a
+       $(BUILDGOX)
+crypto/x509.gox: crypto/libx509.a
+       $(BUILDGOX)
+crypto/xtea.gox: crypto/libxtea.a
+       $(BUILDGOX)
+
+debug/dwarf.gox: debug/libdwarf.a
+       $(BUILDGOX)
+debug/elf.gox: debug/libelf.a
+       $(BUILDGOX)
+debug/gosym.gox: debug/libgosym.a
+       $(BUILDGOX)
+debug/macho.gox: debug/libmacho.a
+       $(BUILDGOX)
+debug/pe.gox: debug/libpe.a
+       $(BUILDGOX)
+debug/proc.gox: debug/libproc.a
+       $(BUILDGOX)
+
+encoding/ascii85.gox: encoding/libascii85.a
+       $(BUILDGOX)
+encoding/base64.gox: encoding/libbase64.a
+       $(BUILDGOX)
+encoding/binary.gox: encoding/libbinary.a
+       $(BUILDGOX)
+encoding/git85.gox: encoding/libgit85.a
+       $(BUILDGOX)
+encoding/hex.gox: encoding/libhex.a
+       $(BUILDGOX)
+encoding/pem.gox: encoding/libpem.a
+       $(BUILDGOX)
+
+exp/datafmt.gox: exp/libdatafmt.a
+       $(BUILDGOX)
+exp/draw.gox: exp/libdraw.a
+       $(BUILDGOX)
+exp/eval.gox: exp/libeval.a
+       $(BUILDGOX)
+
+go/ast.gox: go/libast.a
+       $(BUILDGOX)
+go/doc.gox: go/libdoc.a
+       $(BUILDGOX)
+go/parser.gox: go/libparser.a
+       $(BUILDGOX)
+go/printer.gox: go/libprinter.a
+       $(BUILDGOX)
+go/scanner.gox: go/libscanner.a
+       $(BUILDGOX)
+go/token.gox: go/libtoken.a
+       $(BUILDGOX)
+go/typechecker.gox: go/libtypechecker.a
+       $(BUILDGOX)
+
+hash/adler32.gox: hash/libadler32.a
+       $(BUILDGOX)
+hash/crc32.gox: hash/libcrc32.a
+       $(BUILDGOX)
+hash/crc64.gox: hash/libcrc64.a
+       $(BUILDGOX)
+
+http/pprof.gox: http/libpprof.a
+       $(BUILDGOX)
+
+image/jpeg.gox: image/libjpeg.a
+       $(BUILDGOX)
+image/png.gox: image/libpng.a
+       $(BUILDGOX)
+
+index/suffixarray.gox: index/libsuffixarray.a
+       $(BUILDGOX)
+
+io/ioutil.gox: io/libioutil.a
+       $(BUILDGOX)
+
+mime/multipart.gox: mime/libmultipart.a
+       $(BUILDGOX)
+
+net/dict.gox: net/libdict.a
+       $(BUILDGOX)
+net/textproto.gox: net/libtextproto.a
+       $(BUILDGOX)
+
+os/signal.gox: os/libsignal.a
+       $(BUILDGOX)
+
+rpc/jsonrpc.gox: rpc/libjsonrpc.a
+       $(BUILDGOX)
+
+runtime/pprof.gox: runtime/libpprof.a
+       $(BUILDGOX)
+
+testing/iotest.gox: testing/libiotest.a
+       $(BUILDGOX)
+testing/quick.gox: testing/libquick.a
+       $(BUILDGOX)
+testing/script.gox: testing/libscript.a
+       $(BUILDGOX)
+
+check-recursive: $(TEST_PACKAGES)
+
+mostlyclean-local:
+       find . -name '*.lo' -print | xargs $(LIBTOOL) --mode=clean rm -f
+       find . -name '*.$(OBJEXT)' -print | xargs rm -f
+
+clean-local:
+       find . -name '*.la' -print | xargs $(LIBTOOL) --mode=clean rm -f
+       find . -name '*.a' -print | xargs rm -f
+
+# 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/libgo/README b/libgo/README
new file mode 100644 (file)
index 0000000..3e7ce43
--- /dev/null
@@ -0,0 +1,47 @@
+See ../README.
+
+This is the runtime support library for the Go programming language.
+This library is intended for use with the Go frontend.
+
+The library has only been tested on GNU/Linux using glibc.  It should
+not be difficult to port to other operating systems.
+
+The library has only been tested on x86/x86_64 systems.  It should not
+be difficult to port to other architectures.
+
+Directories:
+
+go
+  A copy of the Go library from http://golang.org/, with a few
+  changes for gccgo.  Notably, the reflection interface is different.
+
+runtime
+  Runtime functions, written in C, which are called directly by the
+  compiler or by the library.
+
+syscalls
+  System call support.
+
+Contributing
+============
+
+To contribute patches to the files in this directory, please see
+http://golang.org/doc/gccgo_contribute.html .
+
+Changes to these files require a copyright assignment to Google.  This
+is required to permit the changes to be copied to the gcc repository,
+as Google has a copyright assignment with the Free Software
+Foundation.
+
+If you are the copyright holder, you will need to agree to the
+individual contributor license agreement at
+http://code.google.com/legal/individual-cla-v1.0.html.  This agreement
+can be completed online.
+
+If your organization is the copyright holder, the organization will
+need to agree to the corporate contributor license agreement at
+http://code.google.com/legal/corporate-cla-v1.0.html.
+
+If the copyright holder for your code has already completed the
+agreement in connection with another Google open source project, it
+does not need to be completed again.
diff --git a/libgo/README.gcc b/libgo/README.gcc
new file mode 100644 (file)
index 0000000..d8bda19
--- /dev/null
@@ -0,0 +1,3 @@
+The files in this directory are mirrored from the gofrontend project
+hosted at http://code.google.com/p/gofrontend.  These files are the
+ones in the libgo subdirectory of that project.
diff --git a/libgo/aclocal.m4 b/libgo/aclocal.m4
new file mode 100644 (file)
index 0000000..ca453c6
--- /dev/null
@@ -0,0 +1,981 @@
+# 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.64],,
+[m4_warning([this file was generated for autoconf 2.64.
+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'.])])
+
+# 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]))])
+
+# 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)])
+
+# 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
+])
+
+# 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 <conftest.tar])
+    grep GrepMe conftest.dir/file >/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([../config/depstand.m4])
+m4_include([../config/lead-dot.m4])
+m4_include([../config/multi.m4])
+m4_include([../config/override.m4])
+m4_include([../config/unwind_ipinfo.m4])
+m4_include([config/go.m4])
+m4_include([config/libtool.m4])
+m4_include([config/ltoptions.m4])
+m4_include([config/ltsugar.m4])
+m4_include([config/ltversion.m4])
+m4_include([config/lt~obsolete.m4])
diff --git a/libgo/config.h.in b/libgo/config.h.in
new file mode 100644 (file)
index 0000000..5422bda
--- /dev/null
@@ -0,0 +1,119 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define if _Unwind_GetIPInfo is available. */
+#undef HAVE_GETIPINFO
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if the system has the type `off64_t'. */
+#undef HAVE_OFF64_T
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have the `srandom' function. */
+#undef HAVE_SRANDOM
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strsignal' function. */
+#undef HAVE_STRSIGNAL
+
+/* Define to 1 if you have the <syscall.h> header file. */
+#undef HAVE_SYSCALL_H
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#undef HAVE_SYS_EPOLL_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/ptrace.h> header file. */
+#undef HAVE_SYS_PTRACE_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/user.h> header file. */
+#undef HAVE_SYS_USER_H
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#undef HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if the linker support split stack adjustments */
+#undef LINKER_SUPPORTS_SPLIT_STACK
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* 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
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if we're to use libffi. */
+#undef USE_LIBFFI
+
+/* Define if the compiler supports -fsplit-stack */
+#undef USING_SPLIT_STACK
+
+/* 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
diff --git a/libgo/config/README b/libgo/config/README
new file mode 100644 (file)
index 0000000..06e8bf5
--- /dev/null
@@ -0,0 +1,2 @@
+This directory holds files needed temporarily until Go support is
+added to autoconf and libtool.
diff --git a/libgo/config/go.m4 b/libgo/config/go.m4
new file mode 100644 (file)
index 0000000..65a27cb
--- /dev/null
@@ -0,0 +1,92 @@
+dnl acinclude.m4 -- configure macros
+
+dnl Copyright 2009 The Go Authors. All rights reserved.
+dnl Use of this source code is governed by a BSD-style
+dnl license that can be found in the LICENSE file.
+
+dnl Go support--this could be in autoconf.
+dnl This version is probably autoconf 2.64 specific.
+
+AC_LANG_DEFINE([Go], [go], [GO], [],
+[ac_ext=go
+ac_compile='$GOC -c $GOCFLAGS conftest.$ac_ext >&AS_MESSAGE_LOG_FD'
+ac_link='$GOC -o conftest$ac_exeext $GOCFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&AS_MESSAGE_LOG_FD'
+ac_compile_gnu=yes
+])
+
+AU_DEFUN([AC_LANG_GO], [AC_LANG(Go)])
+
+m4_define([AC_LANG_PROGRAM(Go)],
+[package main
+$1
+func main() {
+$2
+}])
+
+m4_define([AC_LANG_IO_PROGRAM(Go)],
+[AC_LANG_PROGRAM([import "os"],
+[if f, err := os.Open("conftest.out", os.O_WRONLY), err != nil {
+       os.Exit(1);
+ }
+ if err := f.Close(); err != nil {
+       os.Exit(1);
+ }
+ os.Exit(0);
+])])
+
+m4_define([AC_LANG_CALL(Go)],
+[AC_LANG_PROGRAM([$1
+m4_if([$2], [main], ,
+[func $2();])],[$2();])])
+
+m4_define([AC_LANG_FUNC_LINK_TRY(Go)],
+[AC_LANG_PROGRAM(
+[func $1() int;
+var f := $1;
+], [return f();])])
+
+m4_define([AC_LANG_BOOL_COMPILE_TRY(Go)],
+[AC_LANG_PROGRAM([$1], [var test_array @<:@1 - 2 * !($2)@:>@;
+test_array @<:@0@:>@ = 0
+])])
+
+m4_define([AC_LANG_INT_SAVE(Go)],
+[AC_LANG_PROGRAM([$1
+import os
+func longval() long { return $2 }
+func ulongval() ulong { return $2 }],
+[panic("unimplemented")])])
+
+AC_DEFUN([AC_LANG_COMPILER(Go)],
+[AC_REQUIRE([AC_PROG_GO])])
+
+AN_MAKEVAR([GOC], [AC_PROG_GO])
+AN_PROGRAM([gccgo], [AC_PROG_GO])
+AC_DEFUN([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC],   [Go compiler command])dnl
+AC_ARG_VAR([GOCFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+m4_ifval([$1],
+      [AC_CHECK_TOOLS(GOC, [$1])],
+[AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [$ac_tool_prefix}gccgo])
+  fi
+fi
+if test -z "$GOC"; then
+  AC_CHECK_PROG(GOC, gccgo, gccgo, , , gccgo)
+fi
+])
+
+# Provide some information about the compiler.
+_AS_ECHO_LOG([checking for _AC_LANG compiler version])
+set X $ac_compile
+ac_compiler=$[2]
+_AC_DO_LIMIT([$ac_compiler --version >&AS_MESSAGE_LOG_FD])
+m4_expand_once([_AC_COMPILER_EXEEXT])[]dnl
+m4_expand_once([_AC_COMPILER_OBJEXT])[]dnl
+GOCFLAGS="-g -O2"
+AC_LANG_POP(Go)dnl
+])# AC_PROG_GO
diff --git a/libgo/config/libtool.m4 b/libgo/config/libtool.m4
new file mode 100644 (file)
index 0000000..c4c9d18
--- /dev/null
@@ -0,0 +1,7511 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009 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, 2009 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_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+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
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+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 "$cc_temp" | $SED "s%.*/%%; 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
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])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
+
+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
+
+# 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_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify 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'
+])
+
+# _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 "$][$1" | $SED "$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:
+#
+#    <var>='`$ECHO "$<var>" | $SED "$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'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$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 \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_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])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+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 <bug-libtool@gnu.org>."
+
+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) 2009 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.
+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)
+])# 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)],
+  [Go],                        [_LT_LANG(GO)],
+  [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([AC_PROG_GO],
+  [LT_LANG(GO)],
+  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+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)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+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], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _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"
+    ])
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+       lt_cv_ld_force_load=yes
+      else
+       cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    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" != ":" && test "$lt_cv_ld_force_load" = "no"; 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
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _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=func_echo_all
+    _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],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*" 
+}
+
+case "$ECHO" in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects 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 '$LINENO' "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
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_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_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _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:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 "$_lt_linker_boilerplate" | $SED '/^$/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;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    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"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+                = "X$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 <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#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
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#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;
+          else puts (dlerror ());
+       }
+      /* 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:$LINENO: $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:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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
+m4_require([_LT_CHECK_SHELL_FEATURES])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
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # 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 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # 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; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+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<name>.so
+      # instead of lib<name>.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=`func_echo_all "$lib" | $SED '\''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}'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    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
+  ;;
+
+haiku*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  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=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib'
+  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'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+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 | kopensolaris*-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
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    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],
+        [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # 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
+
+  # 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;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $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([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_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
+m4_require([_LT_PROG_ECHO_BACKSLASH])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 </dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break
+       ;;
+      *)
+       test "$with_gnu_ld" != yes && break
+       ;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+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
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[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.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && 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
+  ;;
+
+haiku*)
+  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])(-bit)?( [LM]SB)? 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 | kopensolaris*-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.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  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:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $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:$LINENO: 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* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-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
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _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([AC_PROG_AWK])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)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $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 | kopensolaris*-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* | bgxl[[cC]]* | mpixl[[cC]]*)
+           # IBM XL 8.0, 9.0 on PPC and BlueGene
+           _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'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    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
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xcompiler -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 | kopensolaris*-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* | pgfortran*)
+        # 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* | bgxl* | bgf* | mpixl*)
+       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+       _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\ F* | *Sun*Fortran*)
+         # 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)=''
+         ;;
+       *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,'
+         ;;
+       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
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
+    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") || (\$ 2 == "W")) && ([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
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+       # The AIX port of GNU ld has always aspired to compatibility
+       # with the native linker.  However, as the warning in the GNU ld
+       # block says, versions before 2.19.5* couldn't really create working
+       # shared libraries, regardless of the interface used.
+       case `$LD -v 2>&1` in
+         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+         *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+         *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+         *)
+           lt_use_gnu_ld_interface=yes
+           ;;
+       esac
+       ;;
+      *)
+       lt_use_gnu_ld_interface=yes
+       ;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = 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
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[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.19, 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 install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_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 <jrb3@best.com> 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(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+      _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
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    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 | kopensolaris*-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; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag'
+         ;;
+       pgf77* | pgf90* | pgf95* | pgfortran*)
+                                       # 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; func_echo_all \"$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]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+         tmp_sharedflag='-qmkshrobj'
+         tmp_addflag= ;;
+       nvcc*)  # Cuda Compiler Driver 2.2
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         _LT_TAGVAR(compiler_needs_object, $1)=yes
+         ;;
+       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; func_echo_all \"$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* | bgf* | bgxlf* | mpixlf*)
+         # 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
+       # Also, AIX nm treats weak defined symbols like other global
+       # defined symbols, whereas GNU nm marks them as "W".
+       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") || (\$ 2 == "W")) && ([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 func_echo_all "${wl}${allow_undefined_flag}"; 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'
+         if test "$with_gnu_ld" = yes; then
+           # We only use this code for GNU lds that support --whole-archive.
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+         else
+           # Exported symbols can be pulled into shared objects from archives
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+         fi
+         _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 `func_echo_all "$deplibs" | $SED '\''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 && test "$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 && test "$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'
+         ;;
+       *)
+       m4_if($1, [], [
+         # Older versions of the 11.00 compiler do not understand -b yet
+         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+         _LT_LINKER_OPTION([if $CC understands -b],
+           _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+           [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+           [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -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 "-set_version $verstring"` -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_CACHE_CHECK([whether -lc should be explicitly linked in],
+       [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+       [$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_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+         else
+           lt_cv_[]_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*
+       ])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_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_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],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+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
+
+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(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_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 -v "^Configured with:" | $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 func_echo_all "${wl}${allow_undefined_flag}"; 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'
+           if test "$with_gnu_ld" = yes; then
+             # We only use this code for GNU lds that support --whole-archive.
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+           else
+             # Exported symbols can be pulled into shared objects from archives
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+           fi
+           _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 <jrb3@best.com> 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(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+        _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*)
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      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; func_echo_all "$list"'
+            ;;
+          *)
+            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; func_echo_all "$list"'
+           ;;
+          *)
+           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" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "${wl}-set_version ${wl}$verstring"` -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 | kopensolaris*-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; func_echo_all "$list"'
+
+           _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 and above 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; func_echo_all \"$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=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+           ;;
+         xl* | mpixl* | bgxl*)
+           # 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; func_echo_all \"$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='func_echo_all'
+
+             # 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=func_echo_all
+       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" && func_echo_all "${wl}-set_version $verstring"` -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" && func_echo_all "-set_version $verstring"` -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 "-set_version $verstring"` -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=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+           ;;
+         *)
+           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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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 -v "^Configured with:" | $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='func_echo_all'
+
+           # 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 -v "^Configured with:" | $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 -v "^Configured with:" | $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(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+             '"$_LT_TAGVAR(old_archive_cmds, $1)"
+           _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+             '"$_LT_TAGVAR(reload_cmds, $1)"
+           ;;
+         *)
+           _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
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() { }
+_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_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_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+
+_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(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_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_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_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
+
+_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(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_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
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_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_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# 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=${GOC-"gccgo"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go 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_GO_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_GO
+# -----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+# 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 "${1}" | $SED "$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 "${1}" | $SED "$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 "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+    *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; 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 "${1}" | $SED "$my_sed_long_opt"`
+  func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=`$ECHO "${1}" | $SED '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/libgo/config/ltmain.sh b/libgo/config/ltmain.sh
new file mode 100644 (file)
index 0000000..b73de52
--- /dev/null
@@ -0,0 +1,8636 @@
+# Generated from ltmain.m4sh.
+
+# libtool (GNU libtool 1.3134 2009-11-29) 2.2.7a
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009 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
+#       --no-finish          let install mode avoid finish commands
+#       --preserve-dup-deps  don't remove duplicate dependency libraries
+#       --quiet, --silent    don't print informational messages
+#       --no-quiet, --no-silent
+#                            print informational messages (default)
+#       --tag=TAG            use configuration variables from tag TAG
+#   -v, --verbose            print more informational messages than default
+#       --no-verbose         don't print the extra informational messages
+#       --version            print version information
+#   -h, --help, --help-all   print short, long, or detailed 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.  When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# 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 1.3134 2009-11-29) 2.2.7a
+#         automake:    $automake_version
+#         autoconf:    $autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.2.7a
+TIMESTAMP=" 1.3134 2009-11-29"
+package_revision=1.3134
+
+# 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
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# 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
+
+
+
+
+
+
+
+# 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"
+
+
+
+: ${CP="cp -f"}
+: ${ECHO=$as_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="/mount/endor/wildenhu/local-x86_64/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 "${1}" | $SED -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 "${1}" | $SED -e "$basename"`
+}
+
+# Generated shell functions inserted here.
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+               s@/\./@/@g
+               t dotsl
+               s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+#             value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+  # Start from root dir and reassemble the path.
+  func_normal_abspath_result=
+  func_normal_abspath_tpath=$1
+  func_normal_abspath_altnamespace=
+  case $func_normal_abspath_tpath in
+    "")
+      # Empty path, that just means $cwd.
+      func_stripname '' '/' "`pwd`"
+      func_normal_abspath_result=$func_stripname_result
+      return
+    ;;
+    # The next three entries are used to spot a run of precisely
+    # two leading slashes without using negated character classes;
+    # we take advantage of case's first-match behaviour.
+    ///*)
+      # Unusual form of absolute path, do nothing.
+    ;;
+    //*)
+      # Not necessarily an ordinary path; POSIX reserves leading '//'
+      # and for example Cygwin uses it to access remote file shares
+      # over CIFS/SMB, so we conserve a leading double slash if found.
+      func_normal_abspath_altnamespace=/
+    ;;
+    /*)
+      # Absolute path, do nothing.
+    ;;
+    *)
+      # Relative path, prepend $cwd.
+      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+    ;;
+  esac
+  # Cancel out all the simple stuff to save iterations.  We also want
+  # the path to end with a slash for ease of parsing, so make sure
+  # there is one (and only one) here.
+  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+  while :; do
+    # Processed it all yet?
+    if test "$func_normal_abspath_tpath" = / ; then
+      # If we ascended to the root using ".." the result may be empty now.
+      if test -z "$func_normal_abspath_result" ; then
+        func_normal_abspath_result=/
+      fi
+      break
+    fi
+    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcar"`
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcdr"`
+    # Figure out what to do with it
+    case $func_normal_abspath_tcomponent in
+      "")
+        # Trailing empty path component, ignore it.
+      ;;
+      ..)
+        # Parent dir; strip last assembled component from result.
+        func_dirname "$func_normal_abspath_result"
+        func_normal_abspath_result=$func_dirname_result
+      ;;
+      *)
+        # Actual path component, append it.
+        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+      ;;
+    esac
+  done
+  # Restore leading double-slash if one was found on entry.
+  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+#             value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+  func_relative_path_result=
+  func_normal_abspath "$1"
+  func_relative_path_tlibdir=$func_normal_abspath_result
+  func_normal_abspath "$2"
+  func_relative_path_tbindir=$func_normal_abspath_result
+
+  # Ascend the tree starting from libdir
+  while :; do
+    # check if we have found a prefix of bindir
+    case $func_relative_path_tbindir in
+      $func_relative_path_tlibdir)
+        # found an exact match
+        func_relative_path_tcancelled=
+        break
+        ;;
+      $func_relative_path_tlibdir*)
+        # found a matching prefix
+        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+        func_relative_path_tcancelled=$func_stripname_result
+        if test -z "$func_relative_path_result"; then
+          func_relative_path_result=.
+        fi
+        break
+        ;;
+      *)
+        func_dirname $func_relative_path_tlibdir
+        func_relative_path_tlibdir=${func_dirname_result}
+        if test "x$func_relative_path_tlibdir" = x ; then
+          # Have to descend all the way to the root!
+          func_relative_path_result=../$func_relative_path_result
+          func_relative_path_tcancelled=$func_relative_path_tbindir
+          break
+        fi
+        func_relative_path_result=../$func_relative_path_result
+        ;;
+    esac
+  done
+
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_stripname '' '/' "$func_relative_path_result"
+  func_relative_path_result=$func_stripname_result
+  func_stripname '/' '/' "$func_relative_path_tcancelled"
+  if test "x$func_stripname_result" != x ; then
+    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+  fi
+
+  # Normalisation. If bindir is libdir, return empty string,
+  # else relative path ending with a slash; either way, target
+  # file name can be directly appended.
+  if test ! -z "$func_relative_path_result"; then
+    func_stripname './' '' "$func_relative_path_result/"
+    func_relative_path_result=$func_stripname_result
+  fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# 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_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+# 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 "$my_directory_path" | $SED -e "$dirname"`
+      done
+      my_dir_list=`$ECHO "$my_dir_list" | $SED '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 "$my_tmpdir"
+}
+
+
+# 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 "$1" | $SED "$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 "$1" | $SED \
+           -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 '/(C)/!b go
+       :more
+       /\./!{
+         N
+         s/\n# //
+         b more
+       }
+       :go
+       /^# '$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 [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+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"
+    ret=$?
+    if test -z "$1"; then
+      exit $ret
+    fi
+}
+
+# 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=:
+
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+# $mode is unset
+nonopt=
+execute_dlfiles=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+opt_dry_run=false
+opt_finish=:
+opt_duplicate_deps=false
+opt_silent=false
+opt_debug=:
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func_error ${1+"$@"}
+    func_error "See the $PACKAGE documentation for more information."
+    func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+  # Global variable:
+  tagname="$1"
+
+  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+  # Validate tagname.
+  case $tagname in
+    *[!-_A-Za-z0-9,/]*)
+      func_fatal_error "invalid tag name: $tagname"
+      ;;
+  esac
+
+  # Don't test for the "default" C tag, as we know it's
+  # there but not specially marked.
+  case $tagname in
+    CC) ;;
+    *)
+      if $GREP "$re_begincf" "$progpath" >/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"                                   ;;
+      --no-finish)     opt_finish=false                                ;;
+
+      --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=:
+                       opt_verbose=false
+                       ;;
+
+      --no-quiet|--no-silent)
+                       preserve_args="$preserve_args $opt"
+                       opt_silent=false
+                       ;;
+
+      --verbose| -v)   preserve_args="$preserve_args $opt"
+                       opt_silent=false
+                       opt_verbose=:
+                       ;;
+
+      --no-verbose)    preserve_args="$preserve_args $opt"
+                       opt_verbose=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=:                                      ;;
+      --help-all)      opt_help=': help-all'                           ;;
+      --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
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      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 "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # 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
+           CC_expanded=`func_echo_all $CC`
+           CC_quoted_expanded=`func_echo_all $CC_quoted`
+           case "$@ " in
+           " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+           " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+             # 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 <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "${write_libobj}"
+    }
+}
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $opt_debug
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+       # do not "continue".  Instead, add this to base_compile
+       lastarg="$arg"
+       arg_mode=normal
+       ;;
+
+      target )
+       libobj="$arg"
+       arg_mode=normal
+       continue
+       ;;
+
+      normal )
+       # Accept any command-line options.
+       case $arg in
+       -o)
+         test -n "$libobj" && \
+           func_fatal_error "you cannot specify \`-o' more than once"
+         arg_mode=target
+         continue
+         ;;
+
+       -pie | -fpie | -fPIE)
+          pie_flag="$pie_flag $arg"
+         continue
+         ;;
+
+       -shared | -static | -prefer-pic | -prefer-non-pic)
+         later="$later $arg"
+         continue
+         ;;
+
+       -no-suppress)
+         suppress_opt=no
+         continue
+         ;;
+
+       -Xcompiler)
+         arg_mode=arg  #  the next one goes into the "base_compile" arg list
+         continue      #  The current "srcfile" will either be retained or
+         ;;            #  replaced later.  I would guess that would be a bug.
+
+       -Wc,*)
+         func_stripname '-Wc,' '' "$arg"
+         args=$func_stripname_result
+         lastarg=
+         save_ifs="$IFS"; IFS=','
+         for arg in $args; do
+           IFS="$save_ifs"
+           func_quote_for_eval "$arg"
+           lastarg="$lastarg $func_quote_for_eval_result"
+         done
+         IFS="$save_ifs"
+         func_stripname ' ' '' "$lastarg"
+         lastarg=$func_stripname_result
+
+         # Add the arguments to base_compile.
+         base_compile="$base_compile $lastarg"
+         continue
+         ;;
+
+       *)
+         # Accept the current argument as the source file.
+         # The previous "srcfile" becomes the current argument.
+         #
+         lastarg="$srcfile"
+         srcfile="$arg"
+         ;;
+       esac  #  case $arg
+       ;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_quote_for_eval "$lastarg"
+      base_compile="$base_compile $func_quote_for_eval_result"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with \`-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+       func_basename "$srcfile"
+       libobj="$func_basename_result"
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+       test "$build_libtool_libs" != yes && \
+         func_fatal_configuration "can not build a shared library"
+       build_old_libs=no
+       continue
+       ;;
+
+      -static)
+       build_libtool_libs=no
+       build_old_libs=yes
+       continue
+       ;;
+
+      -prefer-pic)
+       pic_mode=yes
+       continue
+       ;;
+
+      -prefer-non-pic)
+       pic_mode=no
+       continue
+       ;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'   &()|`$[]' \
+      && 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 "$srcfile" | $SED 's%^.*/%%; 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
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+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-dir 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
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -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
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+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."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test "$opt_help" = :; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for mode in compile link execute install finish uninstall clean; do
+       func_mode_help
+      done
+    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for mode in compile link execute install finish uninstall clean; do
+       echo
+       func_mode_help
+      done
+    } |
+    sed '1d
+      /^When reporting/,/^Report/{
+       H
+       d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# 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
+      -* | *.la | *.lo ) ;;
+      *)
+       # 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 "----------------------------------------------------------------------"
+    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 "----------------------------------------------------------------------"
+    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.
+       case $nonopt in *shtool*) :;; *) false;; esac; 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"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+       files="$files $dest"
+       dest=$arg
+       continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f)
+       if $install_cp; then :; else
+         prev=$arg
+       fi
+       ;;
+      -g | -m | -o)
+       prev=$arg
+       ;;
+      -s)
+       stripme=" -s"
+       continue
+       ;;
+      -*)
+       ;;
+      *)
+       # If the previous option needed an argument, then skip it.
+       if test -n "$prev"; then
+         if test "x$prev" = x-m && test -n "$install_override_mode"; then
+           arg2=$install_override_mode
+           no_mode=false
+         fi
+         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"
+      if test -n "$arg2"; then
+       func_quote_for_eval "$arg2"
+      fi
+      install_shared_prog="$install_shared_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 -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+       func_quote_for_eval "$install_override_mode"
+       install_shared_prog="$install_shared_prog -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    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 "$destdir" | $SED -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 "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+         else
+           relink_command=`$ECHO "$relink_command" | $SED "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_shared_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 "$lib" | $SED '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 "$relink_command" | $SED '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 "$file$stripped_ext" | $SED "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" && $opt_finish; 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
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#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 "$objs$old_deplibs" | $SP2NL | $SED "$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 || {
+             $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+             $MV "$nlist"T "$nlist"
+           }
+         fi
+
+         if test -n "$export_symbols_regex"; then
+           $opt_dry_run || {
+             $EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T
+             $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
+             ${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' < "$nlist" > "$export_symbols"
+             case $host in
+             *cygwin* | *mingw* | *cegcc* )
+                echo EXPORTS > "$output_objdir/$outputname.def"
+                cat "$export_symbols" >> "$output_objdir/$outputname.def"
+               ;;
+             esac
+           }
+         else
+           $opt_dry_run || {
+             ${SED} -e 's/\([].[*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/' < "$export_symbols" > "$output_objdir/$outputname.exp"
+             $GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T
+             $MV "$nlist"T "$nlist"
+             case $host in
+               *cygwin* | *mingw* | *cegcc* )
+                 echo EXPORTS > "$output_objdir/$outputname.def"
+                 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 || {
+           $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 >/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 "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+         else
+           compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+         fi
+         ;;
+       *)
+         compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+         finalize_command=`$ECHO "$finalize_command" | $SED "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 "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "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.
+# Despite the name, also deal with 64 bit binaries.
+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 $OBJDUMP -f "$1" | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pe-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      win32_nmres=`$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"
+    if test "$lock_old_archive_extraction" = yes; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+       func_echo "Waiting for $lockfile to be removed"
+       sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+                  'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test "$lock_old_archive_extraction" = yes; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    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 [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=${1-no}
+
+       $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.
+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
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi\
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED '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 \"\$file\" | $SED '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 \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_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 \"\$thisdir\" | $SED '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 \"\$$shlibpath_var\" | $SED '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\
+"
+}
+
+
+# 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
+            func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null |
+              $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+            ;;
+          *cygwin* )
+            func_to_host_path_result=`cygpath -w "$1" |
+             $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_stripname : : "$1"
+        func_to_host_pathlist_tmp1=$func_stripname_result
+        case $build in
+          *mingw* ) # Actually, msys.
+            # Awkward: cmd appends spaces to result.
+            func_to_host_pathlist_result=`
+             ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null |
+             $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+            ;;
+          *cygwin* )
+            func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" |
+              $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_append func_to_host_pathlist_result ";$func_to_host_path_result"
+                  fi
+                fi
+              fi
+            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_append 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 <<EOF
+
+/* $cwrappersource - temporary wrapper executable 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 executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+
+   Currently, it simply execs the wrapper *script* "$SHELL $output",
+   but could eventually absorb all of the scripts functionality and
+   exec $objdir/$outputname directly.
+*/
+EOF
+           cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+#  define _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#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
+
+/* path handling portability macros */
+#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 */
+
+#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 LT_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_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+           cat <<EOF
+const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+           if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_pathlist "$temp_rpath"
+             cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_pathlist_result";
+EOF
+           else
+             cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+           fi
+
+           if test -n "$dllsearchpath"; then
+              func_to_host_pathlist "$dllsearchpath:"
+             cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_pathlist_result";
+EOF
+           else
+             cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+           fi
+
+           if test "$fast_install" = yes; then
+             cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+           else
+             cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+           fi
+
+
+           cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+#define LTWRAPPER_OPTION_PREFIX_LENGTH  5
+
+static const size_t opt_prefix_len         = LTWRAPPER_OPTION_PREFIX_LENGTH;
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  intptr_t rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  LTWRAPPER_DEBUGPRINTF (("(main) argv[0]      : %s\n", argv[0]));
+  LTWRAPPER_DEBUGPRINTF (("(main) program_name : %s\n", program_name));
+
+  /* very simple arg parsing; don't want to rely on getopt */
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], dumpscript_opt) == 0)
+       {
+EOF
+           case "$host" in
+             *mingw* | *cygwin* )
+               # make stdout use "unix" line endings
+               echo "          setmode(1,_O_BINARY);"
+               ;;
+             esac
+
+           cat <<"EOF"
+         lt_dump_script (stdout);
+         return 0;
+       }
+    }
+
+  newargz = XMALLOC (char *, argc + 1);
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal ("Couldn't find %s", argv[0]);
+  LTWRAPPER_DEBUGPRINTF (("(main) found exe (before symlink chase) at : %s\n",
+                         tmp_pathspec));
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  LTWRAPPER_DEBUGPRINTF (("(main) found exe (after symlink chase) at : %s\n",
+                         actual_cwrapper_path));
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup( base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  LTWRAPPER_DEBUGPRINTF (("(main) libtool target name: %s\n",
+                         target_name));
+EOF
+
+           cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+                   strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+           cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+           case $host_os in
+             mingw*)
+           cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+       *p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+       *p = '/';
+      }
+  }
+EOF
+           ;;
+           esac
+
+           cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (strncmp (argv[i], ltwrapper_option_prefix, opt_prefix_len) == 0)
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal ("Unrecognized option in %s namespace: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+  LTWRAPPER_DEBUGPRINTF     (("(main) lt_argv_zero : %s\n", (lt_argv_zero ? lt_argv_zero : "<NULL>")));
+  for (i = 0; i < newargc; i++)
+    {
+      LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d]   : %s\n", i, (newargz[i] ? newargz[i] : "<NULL>")));
+    }
+
+EOF
+
+           case $host_os in
+             mingw*)
+               cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  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 : "<NULL>"),
+                          (value ? value : "<NULL>")));
+  {
+#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;
+}
+
+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 : "<NULL>"),
+                          (value ? value : "<NULL>")));
+
+  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 : "<NULL>"),
+                          (value ? value : "<NULL>")));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+           case $host_os in
+             mingw*)
+               cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+       new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+       {
+         int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+         size_t length;
+         unsigned int backslashes;
+         const char *s;
+         char *quoted_string;
+         char *p;
+
+         length = 0;
+         backslashes = 0;
+         if (quote_around)
+           length++;
+         for (s = string; *s != '\0'; s++)
+           {
+             char c = *s;
+             if (c == '"')
+               length += backslashes + 1;
+             length++;
+             if (c == '\\')
+               backslashes++;
+             else
+               backslashes = 0;
+           }
+         if (quote_around)
+           length += backslashes + 1;
+
+         quoted_string = XMALLOC (char, length + 1);
+
+         p = quoted_string;
+         backslashes = 0;
+         if (quote_around)
+           *p++ = '"';
+         for (s = string; *s != '\0'; s++)
+           {
+             char c = *s;
+             if (c == '"')
+               {
+                 unsigned int j;
+                 for (j = backslashes + 1; j > 0; j--)
+                   *p++ = '\\';
+               }
+             *p++ = c;
+             if (c == '\\')
+               backslashes++;
+             else
+               backslashes = 0;
+           }
+         if (quote_around)
+           {
+             unsigned int j;
+             for (j = backslashes; j > 0; j--)
+               *p++ = '\\';
+             *p++ = '"';
+           }
+         *p = '\0';
+
+         new_argv[i] = quoted_string;
+       }
+      else
+       new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+               ;;
+           esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+           func_emit_wrapper yes |
+              $SED -e 's/\([\\"]\)/\\\1/g' \
+                  -e 's/^/  fputs ("/' -e 's/$/\\n", f);/'
+
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $opt_debug
+    case `eval "$file_magic_cmd \"\$1\" 2>/dev/null" | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# 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
+    bindir=
+    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
+       bindir)
+         bindir="$arg"
+         prev=
+         continue
+         ;;
+       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
+       ;;
+
+      -bindir)
+       prev=bindir
+       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 "$dir" | $SED '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* | *-*-haiku*)
+           # 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
+           ;;
+         *-*-linux*)
+           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 $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
+      # -tp=* Portland pgcc target processor selection
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
+        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 \"\${$shlibpath_var}\" \| \$SED \'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
+           func_basename "$deplib"
+            deplib_base=$func_basename_result
+           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 \"$deplib\"" 2>/dev/null | $SED 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 "$inherited_linker_flags" | $SED '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 " $dependency_libs" | $SED '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
+           eval "libname=\"$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
+             path=
+             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=
+                 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
+                 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 " $new_inherited_linker_flags" | $SED '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|qnx|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 "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #        lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #        deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #        dependency_libs=`$ECHO "$dependency_libs " | $SED "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* | *-*-haiku*)
+           # 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 <<EOF
+         int main() { return 0; }
+EOF
+         $opt_dry_run || $RM conftest
+         if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+           ldd_output=`ldd conftest`
+           for i in $deplibs; do
+             case $i in
+             -l*)
+               func_stripname -l '' "$i"
+               name=$func_stripname_result
+               if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+                 case " $predeps $postdeps " in
+                 *" $i "*)
+                   newdeplibs="$newdeplibs $i"
+                   i=""
+                   ;;
+                 esac
+               fi
+               if test -n "$i" ; then
+                 eval "libname=\"$libname_spec\""
+                 eval "deplib_matches=\"$library_names_spec\""
+                 set dummy $deplib_matches; shift
+                 deplib_match=$1
+                 if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+                   newdeplibs="$newdeplibs $i"
+                 else
+                   droppeddeps=yes
+                   echo
+                   $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+                   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 I believe you do not have"
+                   echo "*** because a test_compile did reveal that the linker did not use it for"
+                   echo "*** its dynamic dependency list that programs get resolved with at runtime."
+                 fi
+               fi
+               ;;
+             *)
+               newdeplibs="$newdeplibs $i"
+               ;;
+             esac
+           done
+         else
+           # Error occurred in the first compile.  Let's try to salvage
+           # the situation: Compile a separate program for each library.
+           for i in $deplibs; do
+             case $i in
+             -l*)
+               func_stripname -l '' "$i"
+               name=$func_stripname_result
+               $opt_dry_run || $RM conftest
+               if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+                 ldd_output=`ldd conftest`
+                 if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+                   case " $predeps $postdeps " in
+                   *" $i "*)
+                     newdeplibs="$newdeplibs $i"
+                     i=""
+                     ;;
+                   esac
+                 fi
+                 if test -n "$i" ; then
+                   eval "libname=\"$libname_spec\""
+                   eval "deplib_matches=\"$library_names_spec\""
+                   set dummy $deplib_matches; shift
+                   deplib_match=$1
+                   if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+                     newdeplibs="$newdeplibs $i"
+                   else
+                     droppeddeps=yes
+                     echo
+                     $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+                     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 a test_compile did reveal that the linker did not use this one"
+                     echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+                   fi
+                 fi
+               else
+                 droppeddeps=yes
+                 echo
+                 $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+                 echo "*** make it link in!  You will probably need to install it or some"
+                 echo "*** library that it depends on before this library will be fully"
+                 echo "*** functional.  Installing it before continuing would be even better."
+               fi
+               ;;
+             *)
+               newdeplibs="$newdeplibs $i"
+               ;;
+             esac
+           done
+         fi
+         ;;
+       file_magic*)
+         set dummy $deplibs_check_method; shift
+         file_magic_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
+               eval "libname=\"$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
+                     # 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 "$potlib" | $SED '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
+               eval "libname=\"$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 \"$potent_lib\"" 2>/dev/null | $SED 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 " $deplibs" | $SED 's/ -lc$//; 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 " $tmp_deplibs" | $SED "s,$i,,"`
+           done
+         fi
+         case $tmp_deplibs in
+         *[!\  \ ]*)
+           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
+           ;;
+         esac
+         ;;
+       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 " $newdeplibs" | $SED '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 " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         deplibs=`$ECHO " $deplibs" | $SED '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 "$libobjs" | $SP2NL | $SED "$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 || $ECHO "$include_expsyms" | $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 || (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
+         func_basename "$output"
+         output_la=$func_basename_result
+
+         # 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.
+                   reload_objs=$objlist
+                   eval "concat_cmds=\"$reload_cmds\""
+                 else
+                   # All subsequent reloadable object files will link in
+                   # the last one created.
+                   reload_objs="$objlist $last_robj"
+                   eval "concat_cmds=\"\$concat_cmds~$reload_cmds~\$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~
+             reload_objs="$objlist $last_robj"
+             eval "concat_cmds=\"\${concat_cmds}$reload_cmds\""
+             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 || $ECHO "$include_expsyms" | $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 || (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 "$tmp_whole_archive_flags" | $SED '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 "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $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 || 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 " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED '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 " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED '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 "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+       finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$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
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
+      *cygwin* | *mingw* )
+        if test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      *)
+        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 "$compile_command" | $SED '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 "$link_command" | $SED '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 "$compile_var$compile_command$compile_rpath" | $SED '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 "$link_command" | $SED '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 "$relink_command" | $SED "$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 "$relink_command" | $SED "$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"
+               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"
+               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"
+               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
+         # In fact, it would be nice if we could use this code for all target
+         # systems that can't hard-code library paths into their executables
+         # and that have no shared library path variable independent of PATH,
+         # but it turns out we can't easily determine that from inspecting
+         # libtool variables, so we have to hard-code the OSs to which it
+         # applies here; at the moment, that means platforms that use the PE
+         # object format with DLL files.  See the long comment at the top of
+         # tests/bindir.at for full details.
+         tdlname=$dlname
+         case $host,$output,$installed,$module,$dlname in
+           *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+             # If a -bindir argument was supplied, place the dll there.
+             if test "x$bindir" != x ;
+             then
+               func_relative_path "$install_libdir" "$bindir"
+               tdlname=$func_relative_path_result$dlname
+             else
+               # Otherwise fall back on heuristic.
+               tdlname=../bin/$dlname
+             fi
+             ;;
+         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/libgo/config/ltoptions.m4 b/libgo/config/ltoptions.m4
new file mode 100644 (file)
index 0000000..5ef12ce
--- /dev/null
@@ -0,0 +1,369 @@
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2008, 2009 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],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [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/libgo/config/ltsugar.m4 b/libgo/config/ltsugar.m4
new file mode 100644 (file)
index 0000000..9000a05
--- /dev/null
@@ -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/libgo/config/ltversion.m4 b/libgo/config/ltversion.m4
new file mode 100644 (file)
index 0000000..bf87f77
--- /dev/null
@@ -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 3134 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.2.7a])
+m4_define([LT_PACKAGE_REVISION], [1.3134])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.2.7a'
+macro_revision='1.3134'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/libgo/config/lt~obsolete.m4 b/libgo/config/lt~obsolete.m4
new file mode 100644 (file)
index 0000000..bf92b5e
--- /dev/null
@@ -0,0 +1,98 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2009 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_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])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],        [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],                [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],        [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],   [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],              [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],               [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],              [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/libgo/configure b/libgo/configure
new file mode 100644 (file)
index 0000000..d741395
--- /dev/null
@@ -0,0 +1,16395 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.64 for package-unused version-unused.
+#
+# 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
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || 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 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'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+exec 7<&0 </dev/null 6>&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='package-unused'
+PACKAGE_TARNAME='libgo'
+PACKAGE_VERSION='version-unused'
+PACKAGE_STRING='package-unused version-unused'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+ac_unique_file="Makefile.am"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+STRINGOPS_FLAG
+HAVE_SYS_MMAN_H_FALSE
+HAVE_SYS_MMAN_H_TRUE
+USING_SPLIT_STACK_FALSE
+USING_SPLIT_STACK_TRUE
+SPLIT_STACK
+LIBGO_IS_ARM_FALSE
+LIBGO_IS_ARM_TRUE
+LIBGO_IS_X86_64_FALSE
+LIBGO_IS_X86_64_TRUE
+LIBGO_IS_386_FALSE
+LIBGO_IS_386_TRUE
+LIBGO_IS_RTEMS_FALSE
+LIBGO_IS_RTEMS_TRUE
+LIBGO_IS_LINUX_FALSE
+LIBGO_IS_LINUX_TRUE
+LIBGO_IS_FREEBSD_FALSE
+LIBGO_IS_FREEBSD_TRUE
+LIBGO_IS_DARWIN_FALSE
+LIBGO_IS_DARWIN_TRUE
+LIBFFIINCS
+LIBFFI
+glibgo_toolexeclibdir
+glibgo_toolexecdir
+glibgo_prefixdir
+WERROR
+WARN_FLAGS
+enable_static
+enable_shared
+CPP
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+AR
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LIBTOOL
+OBJCOPY
+RANLIB
+LD
+FGREP
+EGREP
+GREP
+SED
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+GOCFLAGS
+GOC
+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
+multi_basedir
+libtool_VERSION
+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_multilib
+enable_dependency_tracking
+enable_maintainer_mode
+with_gnu_ld
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+enable_libtool_lock
+enable_version_specific_runtime_libs
+with_libffi
+with_system_libunwind
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+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 package-unused version-unused 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/libgo]
+  --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 package-unused version-unused:";;
+   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]
+  --enable-multilib       build many library versions (default)
+  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors
+  --enable-maintainer-mode  enable make rules and dependencies not useful
+                         (and sometimes confusing) to the casual installer
+  --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-version-specific-runtime-libs
+                          Specify that runtime libraries should be installed
+                          in a compiler-specific directory
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-pic              try to use only PIC/non-PIC objects [default=use
+                          both]
+  --without-libffi        don't use libffi
+  --with-system-libunwind use installed libunwind
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  GOC         Go compiler command
+  GOCFLAGS    Go compiler flags
+  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 the package provider.
+_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
+package-unused configure version-unused
+generated by GNU Autoconf 2.64
+
+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;}
+  return $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;}
+  return $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;}
+  return $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;}
+  return $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 <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#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;}
+    ;;
+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_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  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
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+        return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+           return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  eval "$3=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
+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_type
+cat >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 package-unused $as_me version-unused, which was
+generated by GNU Autoconf 2.64.  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 -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.
+  if 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 config.h"
+
+
+libtool_VERSION=1:0:0
+
+
+# Default to --enable-multilib
+# Check whether --enable-multilib was given.
+if test "${enable_multilib+set}" = set; then :
+  enableval=$enable_multilib; case "$enableval" in
+  yes) multilib=yes ;;
+  no)  multilib=no ;;
+  *)   as_fn_error "bad value $enableval for multilib option" "$LINENO" 5 ;;
+ esac
+else
+  multilib=yes
+fi
+
+
+# We may get other options which we leave undocumented:
+# --with-target-subdir, --with-multisrctop, --with-multisubdir
+# See config-ml.in if you want the gory details.
+
+if test "$srcdir" = "."; then
+  if test "$with_target_subdir" != "."; then
+    multi_basedir="$srcdir/$with_multisrctop../.."
+  else
+    multi_basedir="$srcdir/$with_multisrctop.."
+  fi
+else
+  multi_basedir="$srcdir/.."
+fi
+
+
+# Even if the default multilib is not a cross compilation,
+# it may be that some of the other multilibs are.
+if test $cross_compiling = no && test $multilib = yes \
+   && test "x${with_multisubdir}" != x ; then
+   cross_compiling=maybe
+fi
+
+ac_config_commands="$ac_config_commands default-1"
+
+
+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}
+
+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
+
+  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.
+    test -d ./--version && rmdir ./--version
+    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='libgo'
+ VERSION='version-unused'
+
+
+# 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 -'
+
+
+
+
+
+
+
+
+
+
+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
+    rm -f conftest.er1 conftest.err
+  fi
+  $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 conftest.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 for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+if test -z "$ac_file"; then :
+  $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; }; }
+fi
+ac_exeext=$ac_cv_exeext
+
+# 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 the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { { 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: yes" >&5
+$as_echo "yes" >&6; }
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out
+ac_clean_files=$ac_clean_files_save
+# 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; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+{ $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$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
+{ $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 <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* 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
+
+
+ac_ext=go
+ac_compile='$GOC -c $GOCFLAGS conftest.$ac_ext >&5'
+ac_link='$GOC -o conftest$ac_exeext $GOCFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compile_gnu=yes
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gccgo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gccgo; 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_GOC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$GOC"; then
+  ac_cv_prog_GOC="$GOC" # 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_GOC="${ac_tool_prefix}gccgo"
+    $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
+GOC=$ac_cv_prog_GOC
+if test -n "$GOC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GOC" >&5
+$as_echo "$GOC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_GOC"; then
+  ac_ct_GOC=$GOC
+  # Extract the first word of "gccgo", so it can be a program name with args.
+set dummy gccgo; 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_GOC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_GOC"; then
+  ac_cv_prog_ac_ct_GOC="$ac_ct_GOC" # 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_GOC="gccgo"
+    $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_GOC=$ac_cv_prog_ac_ct_GOC
+if test -n "$ac_ct_GOC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GOC" >&5
+$as_echo "$ac_ct_GOC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_GOC" = x; then
+    GOC=""
+  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
+    GOC=$ac_ct_GOC
+  fi
+else
+  GOC="$ac_cv_prog_GOC"
+fi
+
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}gccgo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gccgo; 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_GOC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$GOC"; then
+  ac_cv_prog_GOC="$GOC" # 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_GOC="$ac_tool_prefix}gccgo"
+    $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
+GOC=$ac_cv_prog_GOC
+if test -n "$GOC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GOC" >&5
+$as_echo "$GOC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$GOC"; then
+  # Extract the first word of "gccgo", so it can be a program name with args.
+set dummy gccgo; 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_GOC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$GOC"; then
+  ac_cv_prog_GOC="$GOC" # 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" = "gccgo"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_GOC="gccgo"
+    $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_GOC
+  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 GOC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_GOC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+GOC=$ac_cv_prog_GOC
+if test -n "$GOC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GOC" >&5
+$as_echo "$GOC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for Go compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ { ac_try="$ac_compiler --version >&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 --version >&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
+    rm -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+GOCFLAGS="-g -O2"
+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 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
+
+
+
+{ $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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case "$ECHO" in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 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 </dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break
+       ;;
+      *)
+       test "$with_gnu_ld" != yes && break
+       ;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&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 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+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
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objcopy", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objcopy; 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_OBJCOPY+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJCOPY"; then
+  ac_cv_prog_OBJCOPY="$OBJCOPY" # 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_OBJCOPY="${ac_tool_prefix}objcopy"
+    $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
+OBJCOPY=$ac_cv_prog_OBJCOPY
+if test -n "$OBJCOPY"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJCOPY" >&5
+$as_echo "$OBJCOPY" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJCOPY"; then
+  ac_ct_OBJCOPY=$OBJCOPY
+  # Extract the first word of "objcopy", so it can be a program name with args.
+set dummy objcopy; 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_OBJCOPY+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJCOPY"; then
+  ac_cv_prog_ac_ct_OBJCOPY="$ac_ct_OBJCOPY" # 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_OBJCOPY="objcopy"
+    $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_OBJCOPY=$ac_cv_prog_ac_ct_OBJCOPY
+if test -n "$ac_ct_OBJCOPY"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJCOPY" >&5
+$as_echo "$ac_ct_OBJCOPY" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJCOPY" = x; then
+    OBJCOPY="missing-objcopy"
+  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
+    OBJCOPY=$ac_ct_OBJCOPY
+  fi
+else
+  OBJCOPY="$ac_cv_prog_OBJCOPY"
+fi
+
+
+enable_dlopen=yes
+
+
+
+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.7a'
+macro_revision='1.3134'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Backslashify 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'
+
+{ $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 "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  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 "link -dump"
+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
+
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  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:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: 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;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    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"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+                = "X$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.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && 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
+  ;;
+
+haiku*)
+  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])(-bit)?( [LM]SB)? 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 | kopensolaris*-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
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 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 '$LINENO' "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; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if test "${lt_cv_ld_force_load+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+       lt_cv_ld_force_load=yes
+      else
+       cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&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" != ":" && test "$lt_cv_ld_force_load" = "no"; 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 <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+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 <string.h>
+
+_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 <stdlib.h>
+
+_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 <ctype.h>
+#include <stdlib.h>
+#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
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gccgo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gccgo; 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_GOC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$GOC"; then
+  ac_cv_prog_GOC="$GOC" # 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_GOC="${ac_tool_prefix}gccgo"
+    $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
+GOC=$ac_cv_prog_GOC
+if test -n "$GOC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GOC" >&5
+$as_echo "$GOC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_GOC"; then
+  ac_ct_GOC=$GOC
+  # Extract the first word of "gccgo", so it can be a program name with args.
+set dummy gccgo; 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_GOC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_GOC"; then
+  ac_cv_prog_ac_ct_GOC="$ac_ct_GOC" # 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_GOC="gccgo"
+    $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_GOC=$ac_cv_prog_ac_ct_GOC
+if test -n "$ac_ct_GOC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GOC" >&5
+$as_echo "$ac_ct_GOC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_GOC" = x; then
+    GOC=""
+  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
+    GOC=$ac_ct_GOC
+  fi
+else
+  GOC="$ac_cv_prog_GOC"
+fi
+
+
+
+
+
+
+# Set options
+
+
+
+
+  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
+
+# 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 "$cc_temp" | $SED "s%.*/%%; 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*
+
+
+## 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_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
+
+  { $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:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
+    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
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      lt_prog_compiler_pic='-Xcompiler -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 | kopensolaris*-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* | pgfortran*)
+        # 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* | bgxl* | bgf* | mpixl*)
+       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+       lt_prog_compiler_wl='-Wl,'
+       lt_prog_compiler_pic='-qpic'
+       lt_prog_compiler_static='-qstaticlink'
+       ;;
+      *)
+       case `$CC -V 2>&1 | sed 5q` in
+       *Sun\ F* | *Sun*Fortran*)
+         # 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=''
+         ;;
+       *Sun\ C*)
+         # Sun C 5.9
+         lt_prog_compiler_pic='-KPIC'
+         lt_prog_compiler_static='-Bstatic'
+         lt_prog_compiler_wl='-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:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 "$_lt_linker_boilerplate" | $SED '/^$/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:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+       # The AIX port of GNU ld has always aspired to compatibility
+       # with the native linker.  However, as the warning in the GNU ld
+       # block says, versions before 2.19.5* couldn't really create working
+       # shared libraries, regardless of the interface used.
+       case `$LD -v 2>&1` in
+         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+         *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+         *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+         *)
+           lt_use_gnu_ld_interface=yes
+           ;;
+       esac
+       ;;
+      *)
+       lt_use_gnu_ld_interface=yes
+       ;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = 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
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [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.19, 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 install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_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 <jrb3@best.com> 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'
+      export_dynamic_flag_spec='${wl}--export-all-symbols'
+      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
+      ;;
+
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
+    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 | kopensolaris*-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; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag'
+         ;;
+       pgf77* | pgf90* | pgf95* | pgfortran*)
+                                       # 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; func_echo_all \"$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]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+         tmp_sharedflag='-qmkshrobj'
+         tmp_addflag= ;;
+       nvcc*)  # Cuda Compiler Driver 2.2
+         whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         compiler_needs_object=yes
+         ;;
+       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; func_echo_all \"$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* | bgf* | bgxlf* | mpixlf*)
+         # 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
+       # Also, AIX nm treats weak defined symbols like other global
+       # defined symbols, whereas GNU nm marks them as "W".
+       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") || (\$ 2 == "W")) && (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 func_echo_all "${wl}${allow_undefined_flag}"; 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'
+         if test "$with_gnu_ld" = yes; then
+           # We only use this code for GNU lds that support --whole-archive.
+           whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+         else
+           # Exported symbols can be pulled into shared objects from archives
+           whole_archive_flag_spec='$convenience'
+         fi
+         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 `func_echo_all "$deplibs" | $SED '\''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"`'
+      enable_shared_with_static_runtimes=yes
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  else
+    whole_archive_flag_spec=''
+  fi
+  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=func_echo_all
+    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 && test "$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 && test "$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'
+         ;;
+       *)
+
+         # Older versions of the 11.00 compiler do not understand -b yet
+         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+         { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if test "${lt_cv_prog_compiler__b+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -b"
+   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 "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+    archive_cmds='$CC -b ${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
+
+         ;;
+       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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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" && func_echo_all "-set_version $verstring"` -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 "-set_version $verstring"` -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; }
+if test "${lt_cv_archive_cmds_need_lc+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  $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
+           lt_cv_archive_cmds_need_lc=no
+         else
+           lt_cv_archive_cmds_need_lc=yes
+         fi
+         allow_undefined_flag=$lt_save_allow_undefined_flag
+       else
+         cat conftest.err 1>&5
+       fi
+       $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+      ;;
+    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
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # 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 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # 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; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+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<name>.so
+      # instead of lib<name>.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=`func_echo_all "$lib" | $SED '\''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="$sys_lib_search_path_spec /usr/lib/w32api"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    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
+  ;;
+
+haiku*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  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=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib'
+  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'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+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 | kopensolaris*-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
+  if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    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 :
+  lt_cv_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
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # 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
+
+  # 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;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $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 10869 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#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
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#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;
+          else puts (dlerror ());
+       }
+      /* 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 10975 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#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
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#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;
+          else puts (dlerror ());
+       }
+      /* 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"
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+objext_GO=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# 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 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*
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC="$GCC"
+GCC=yes
+CC=${GOC-"gccgo"}
+compiler=$CC
+compiler_GO=$CC
+LD_GO="$LD"
+for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+archive_cmds_need_lc_GO=no
+
+old_archive_cmds_GO=$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_prog_compiler_no_builtin_flag_GO=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag_GO=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag_GO=' -fno-builtin' ;;
+  esac
+
+  { $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:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_GO="$lt_prog_compiler_no_builtin_flag_GO -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+  lt_prog_compiler_wl_GO=
+lt_prog_compiler_pic_GO=
+lt_prog_compiler_static_GO=
+
+{ $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_GO='-Wl,'
+    lt_prog_compiler_static_GO='-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_GO='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic_GO='-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_GO='-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_GO='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic_GO='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static_GO=
+      ;;
+
+    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_GO='-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_GO=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_GO='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       lt_prog_compiler_pic_GO=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic_GO='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl_GO='-Xlinker '
+      lt_prog_compiler_pic_GO='-Xcompiler -fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl_GO='-Wl,'
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       lt_prog_compiler_static_GO='-Bstatic'
+      else
+       lt_prog_compiler_static_GO='-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_GO='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl_GO='-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_GO='+Z'
+       ;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static_GO='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl_GO='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static_GO='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+       lt_prog_compiler_wl_GO='-Wl,'
+       lt_prog_compiler_pic_GO='-KPIC'
+       lt_prog_compiler_static_GO='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+       lt_prog_compiler_wl_GO='-Wl,'
+       lt_prog_compiler_pic_GO='-fPIC'
+       lt_prog_compiler_static_GO='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+       lt_prog_compiler_wl_GO='-Wl,'
+       lt_prog_compiler_pic_GO='--shared'
+       lt_prog_compiler_static_GO='--static'
+       ;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+       # which looks to be a dead project)
+       lt_prog_compiler_wl_GO='-Wl,'
+       lt_prog_compiler_pic_GO='-fpic'
+       lt_prog_compiler_static_GO='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl_GO='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static_GO='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+       lt_prog_compiler_wl_GO='-Wl,'
+       lt_prog_compiler_pic_GO='-qpic'
+       lt_prog_compiler_static_GO='-qstaticlink'
+       ;;
+      *)
+       case `$CC -V 2>&1 | sed 5q` in
+       *Sun\ F* | *Sun*Fortran*)
+         # Sun Fortran 8.3 passes all unrecognized flags to the linker
+         lt_prog_compiler_pic_GO='-KPIC'
+         lt_prog_compiler_static_GO='-Bstatic'
+         lt_prog_compiler_wl_GO=''
+         ;;
+       *Sun\ C*)
+         # Sun C 5.9
+         lt_prog_compiler_pic_GO='-KPIC'
+         lt_prog_compiler_static_GO='-Bstatic'
+         lt_prog_compiler_wl_GO='-Wl,'
+         ;;
+       esac
+       ;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic_GO='-KPIC'
+      lt_prog_compiler_static_GO='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic_GO='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl_GO='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static_GO='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static_GO='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic_GO='-KPIC'
+      lt_prog_compiler_static_GO='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95*)
+       lt_prog_compiler_wl_GO='-Qoption ld ';;
+      *)
+       lt_prog_compiler_wl_GO='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl_GO='-Qoption ld '
+      lt_prog_compiler_pic_GO='-PIC'
+      lt_prog_compiler_static_GO='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl_GO='-Wl,'
+      lt_prog_compiler_pic_GO='-KPIC'
+      lt_prog_compiler_static_GO='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+       lt_prog_compiler_pic_GO='-Kconform_pic'
+       lt_prog_compiler_static_GO='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl_GO='-Wl,'
+      lt_prog_compiler_pic_GO='-KPIC'
+      lt_prog_compiler_static_GO='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl_GO='-Wl,'
+      lt_prog_compiler_can_build_shared_GO=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic_GO='-pic'
+      lt_prog_compiler_static_GO='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared_GO=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic_GO=
+    ;;
+  *)
+    lt_prog_compiler_pic_GO="$lt_prog_compiler_pic_GO"
+    ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_GO" >&5
+$as_echo "$lt_prog_compiler_pic_GO" >&6; }
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_GO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_GO works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_GO works... " >&6; }
+if test "${lt_cv_prog_compiler_pic_works_GO+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works_GO=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic_GO"
+   # 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:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_GO=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_GO" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_GO" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works_GO" = xyes; then
+    case $lt_prog_compiler_pic_GO in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic_GO=" $lt_prog_compiler_pic_GO" ;;
+     esac
+else
+    lt_prog_compiler_pic_GO=
+     lt_prog_compiler_can_build_shared_GO=no
+fi
+
+fi
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_GO eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GO\"
+{ $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_GO+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works_GO=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 "$_lt_linker_boilerplate" | $SED '/^$/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_GO=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works_GO=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_GO" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_GO" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works_GO" = xyes; then
+    :
+else
+    lt_prog_compiler_static_GO=
+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_GO+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_GO=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:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_GO=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_GO" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_GO" >&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_GO+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_GO=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:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_GO=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_GO" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_GO" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_GO" = 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_GO=
+  always_export_symbols_GO=no
+  archive_cmds_GO=
+  archive_expsym_cmds_GO=
+  compiler_needs_object_GO=no
+  enable_shared_with_static_runtimes_GO=no
+  export_dynamic_flag_spec_GO=
+  export_symbols_cmds_GO='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic_GO=no
+  hardcode_direct_GO=no
+  hardcode_direct_absolute_GO=no
+  hardcode_libdir_flag_spec_GO=
+  hardcode_libdir_flag_spec_ld_GO=
+  hardcode_libdir_separator_GO=
+  hardcode_minus_L_GO=no
+  hardcode_shlibpath_var_GO=unsupported
+  inherit_rpath_GO=no
+  link_all_deplibs_GO=unknown
+  module_cmds_GO=
+  module_expsym_cmds_GO=
+  old_archive_from_new_cmds_GO=
+  old_archive_from_expsyms_cmds_GO=
+  thread_safe_flag_spec_GO=
+  whole_archive_flag_spec_GO=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms_GO=
+  # 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_GO='_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_GO=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+       # The AIX port of GNU ld has always aspired to compatibility
+       # with the native linker.  However, as the warning in the GNU ld
+       # block says, versions before 2.19.5* couldn't really create working
+       # shared libraries, regardless of the interface used.
+       case `$LD -v 2>&1` in
+         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+         *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+         *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+         *)
+           lt_use_gnu_ld_interface=yes
+           ;;
+       esac
+       ;;
+      *)
+       lt_use_gnu_ld_interface=yes
+       ;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = 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_GO='${wl}-rpath ${wl}$libdir'
+    export_dynamic_flag_spec_GO='${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_GO="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec_GO=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [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_GO=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, 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 install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds_GO=''
+        ;;
+      m68k)
+            archive_cmds_GO='$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_GO='-L$libdir'
+            hardcode_minus_L_GO=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       allow_undefined_flag_GO=unsupported
+       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+       # support --undefined.  This deserves some investigation.  FIXME
+       archive_cmds_GO='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+       ld_shlibs_GO=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, GO) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec_GO='-L$libdir'
+      export_dynamic_flag_spec_GO='${wl}--export-all-symbols'
+      allow_undefined_flag_GO=unsupported
+      always_export_symbols_GO=no
+      enable_shared_with_static_runtimes_GO=yes
+      export_symbols_cmds_GO='$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_GO='$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_GO='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_GO=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs_GO=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct_GO=no
+      hardcode_shlibpath_var_GO=no
+      hardcode_libdir_flag_spec_GO='${wl}-rpath,$libdir'
+      export_dynamic_flag_spec_GO='${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_GO='$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_GO='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 | kopensolaris*-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_GO='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag'
+         ;;
+       pgf77* | pgf90* | pgf95* | pgfortran*)
+                                       # Portland Group f77 and f90 compilers
+         whole_archive_flag_spec_GO='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$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_GO=
+         tmp_sharedflag='--shared' ;;
+       xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+         tmp_sharedflag='-qmkshrobj'
+         tmp_addflag= ;;
+       nvcc*)  # Cuda Compiler Driver 2.2
+         whole_archive_flag_spec_GO='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         compiler_needs_object_GO=yes
+         ;;
+       esac
+       case `$CC -V 2>&1 | sed 5q` in
+       *Sun\ C*)                       # Sun C 5.9
+         whole_archive_flag_spec_GO='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         compiler_needs_object_GO=yes
+         tmp_sharedflag='-G' ;;
+       *Sun\ F*)                       # Sun Fortran 8.3
+         tmp_sharedflag='-G' ;;
+       esac
+       archive_cmds_GO='$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_GO='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* | bgf* | bgxlf* | mpixlf*)
+         # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+         whole_archive_flag_spec_GO='--whole-archive$convenience --no-whole-archive'
+         hardcode_libdir_flag_spec_GO=
+         hardcode_libdir_flag_spec_ld_GO='-rpath $libdir'
+         archive_cmds_GO='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+         if test "x$supports_anon_versioning" = xyes; then
+           archive_expsym_cmds_GO='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_GO=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+       archive_cmds_GO='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+       wlarc=
+      else
+       archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       archive_expsym_cmds_GO='$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_GO=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_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       ld_shlibs_GO=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+       ld_shlibs_GO=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_GO='${wl}-rpath ${wl}$libdir'
+           archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+           archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         else
+           ld_shlibs_GO=no
+         fi
+       ;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds_GO='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct_GO=yes
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       ld_shlibs_GO=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs_GO" = no; then
+      runpath_var=
+      hardcode_libdir_flag_spec_GO=
+      export_dynamic_flag_spec_GO=
+      whole_archive_flag_spec_GO=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag_GO=unsupported
+      always_export_symbols_GO=yes
+      archive_expsym_cmds_GO='$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_GO=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_GO=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
+       # Also, AIX nm treats weak defined symbols like other global
+       # defined symbols, whereas GNU nm marks them as "W".
+       if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+         export_symbols_cmds_GO='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+       else
+         export_symbols_cmds_GO='$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_GO=''
+      hardcode_direct_GO=yes
+      hardcode_direct_absolute_GO=yes
+      hardcode_libdir_separator_GO=':'
+      link_all_deplibs_GO=yes
+      file_list_spec_GO='${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_GO=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_GO=yes
+         hardcode_libdir_flag_spec_GO='-L$libdir'
+         hardcode_libdir_separator_GO=
+         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_GO='${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_GO=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_GO='-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_GO='${wl}-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds_GO='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+       if test "$host_cpu" = ia64; then
+         hardcode_libdir_flag_spec_GO='${wl}-R $libdir:/usr/lib:/lib'
+         allow_undefined_flag_GO="-z nodefs"
+         archive_expsym_cmds_GO="\$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_GO='${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_GO=' ${wl}-bernotok'
+         allow_undefined_flag_GO=' ${wl}-berok'
+         if test "$with_gnu_ld" = yes; then
+           # We only use this code for GNU lds that support --whole-archive.
+           whole_archive_flag_spec_GO='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+         else
+           # Exported symbols can be pulled into shared objects from archives
+           whole_archive_flag_spec_GO='$convenience'
+         fi
+         archive_cmds_need_lc_GO=yes
+         # This is similar to how AIX traditionally builds its shared libraries.
+         archive_expsym_cmds_GO="\$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_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds_GO=''
+        ;;
+      m68k)
+            archive_cmds_GO='$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_GO='-L$libdir'
+            hardcode_minus_L_GO=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec_GO=-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_GO=' '
+      allow_undefined_flag_GO=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_GO='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      old_archive_from_new_cmds_GO='true'
+      # FIXME: Should let the user specify the lib program.
+      old_archive_cmds_GO='lib -OUT:$oldlib$oldobjs$old_deplibs'
+      fix_srcfile_path_GO='`cygpath -w "$srcfile"`'
+      enable_shared_with_static_runtimes_GO=yes
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc_GO=no
+  hardcode_direct_GO=no
+  hardcode_automatic_GO=yes
+  hardcode_shlibpath_var_GO=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec_GO='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  else
+    whole_archive_flag_spec_GO=''
+  fi
+  link_all_deplibs_GO=yes
+  allow_undefined_flag_GO="$_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=func_echo_all
+    archive_cmds_GO="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds_GO="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds_GO="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_GO="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_GO=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec_GO='-L$libdir'
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    freebsd1*)
+      ld_shlibs_GO=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_GO='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec_GO='-R$libdir'
+      hardcode_direct_GO=yes
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      archive_cmds_GO='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_GO=yes
+      hardcode_minus_L_GO=yes
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds_GO='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec_GO='-R$libdir'
+      hardcode_direct_GO=yes
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+       archive_cmds_GO='$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_GO='$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_GO='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator_GO=:
+      hardcode_direct_GO=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L_GO=yes
+      export_dynamic_flag_spec_GO='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+       archive_cmds_GO='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       archive_cmds_GO='$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_GO='${wl}+b ${wl}$libdir'
+       hardcode_libdir_flag_spec_ld_GO='+b $libdir'
+       hardcode_libdir_separator_GO=:
+       hardcode_direct_GO=yes
+       hardcode_direct_absolute_GO=yes
+       export_dynamic_flag_spec_GO='${wl}-E'
+       # hardcode_minus_L: Not really in the search PATH,
+       # but as the default location of the library.
+       hardcode_minus_L_GO=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+       case $host_cpu in
+       hppa*64*)
+         archive_cmds_GO='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         archive_cmds_GO='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         archive_cmds_GO='$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_GO='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         archive_cmds_GO='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+       archive_cmds_GO='$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_GO='${wl}+b ${wl}$libdir'
+       hardcode_libdir_separator_GO=:
+
+       case $host_cpu in
+       hppa*64*|ia64*)
+         hardcode_direct_GO=no
+         hardcode_shlibpath_var_GO=no
+         ;;
+       *)
+         hardcode_direct_GO=yes
+         hardcode_direct_absolute_GO=yes
+         export_dynamic_flag_spec_GO='${wl}-E'
+
+         # hardcode_minus_L: Not really in the search PATH,
+         # but as the default location of the library.
+         hardcode_minus_L_GO=yes
+         ;;
+       esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+       archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${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_GO='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc_GO='no'
+      hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_GO=:
+      inherit_rpath_GO=yes
+      link_all_deplibs_GO=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+       archive_cmds_GO='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+       archive_cmds_GO='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec_GO='-R$libdir'
+      hardcode_direct_GO=yes
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    newsos6)
+      archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_GO=yes
+      hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_GO=:
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+       hardcode_direct_GO=yes
+       hardcode_shlibpath_var_GO=no
+       hardcode_direct_absolute_GO=yes
+       if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+         archive_cmds_GO='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+         archive_expsym_cmds_GO='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+         hardcode_libdir_flag_spec_GO='${wl}-rpath,$libdir'
+         export_dynamic_flag_spec_GO='${wl}-E'
+       else
+         case $host_os in
+          openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+            archive_cmds_GO='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+            hardcode_libdir_flag_spec_GO='-R$libdir'
+            ;;
+          *)
+            archive_cmds_GO='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+            hardcode_libdir_flag_spec_GO='${wl}-rpath,$libdir'
+            ;;
+         esac
+       fi
+      else
+       ld_shlibs_GO=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec_GO='-L$libdir'
+      hardcode_minus_L_GO=yes
+      allow_undefined_flag_GO=unsupported
+      archive_cmds_GO='$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_GO='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+       allow_undefined_flag_GO=' ${wl}-expect_unresolved ${wl}\*'
+       archive_cmds_GO='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       allow_undefined_flag_GO=' -expect_unresolved \*'
+       archive_cmds_GO='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc_GO='no'
+      hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_GO=:
+      ;;
+
+    osf4* | osf5*)     # as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+       allow_undefined_flag_GO=' ${wl}-expect_unresolved ${wl}\*'
+       archive_cmds_GO='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+      else
+       allow_undefined_flag_GO=' -expect_unresolved \*'
+       archive_cmds_GO='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       archive_expsym_cmds_GO='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 "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+       # Both c and cxx compiler support -rpath directly
+       hardcode_libdir_flag_spec_GO='-rpath $libdir'
+      fi
+      archive_cmds_need_lc_GO='no'
+      hardcode_libdir_separator_GO=:
+      ;;
+
+    solaris*)
+      no_undefined_flag_GO=' -z defs'
+      if test "$GCC" = yes; then
+       wlarc='${wl}'
+       archive_cmds_GO='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds_GO='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_GO='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         archive_expsym_cmds_GO='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_GO='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+         archive_expsym_cmds_GO='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_GO='-R$libdir'
+      hardcode_shlibpath_var_GO=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_GO='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+       else
+         whole_archive_flag_spec_GO='-z allextract$convenience -z defaultextract'
+       fi
+       ;;
+      esac
+      link_all_deplibs_GO=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_GO='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       archive_cmds_GO='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec_GO='-L$libdir'
+      hardcode_direct_GO=yes
+      hardcode_minus_L_GO=yes
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+       sni)
+         archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         hardcode_direct_GO=yes # is this really true???
+       ;;
+       siemens)
+         ## LD is ld it makes a PLAMLIB
+         ## CC just makes a GrossModule.
+         archive_cmds_GO='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+         reload_cmds_GO='$CC -r -o $output$reload_objs'
+         hardcode_direct_GO=no
+        ;;
+       motorola)
+         archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         hardcode_direct_GO=no #Motorola manual says yes, but my tests say they lie
+       ;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var_GO=no
+      export_dynamic_flag_spec_GO='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+       hardcode_shlibpath_var_GO=no
+       runpath_var=LD_RUN_PATH
+       hardcode_runpath_var=yes
+       ld_shlibs_GO=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag_GO='${wl}-z,text'
+      archive_cmds_need_lc_GO=no
+      hardcode_shlibpath_var_GO=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+       archive_cmds_GO='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds_GO='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       archive_cmds_GO='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds_GO='$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_GO='${wl}-z,text'
+      allow_undefined_flag_GO='${wl}-z,nodefs'
+      archive_cmds_need_lc_GO=no
+      hardcode_shlibpath_var_GO=no
+      hardcode_libdir_flag_spec_GO='${wl}-R,$libdir'
+      hardcode_libdir_separator_GO=':'
+      link_all_deplibs_GO=yes
+      export_dynamic_flag_spec_GO='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+       archive_cmds_GO='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds_GO='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       archive_cmds_GO='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds_GO='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec_GO='-L$libdir'
+      hardcode_shlibpath_var_GO=no
+      ;;
+
+    *)
+      ld_shlibs_GO=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+       export_dynamic_flag_spec_GO='${wl}-Blargedynsym'
+       ;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_GO" >&5
+$as_echo "$ld_shlibs_GO" >&6; }
+test "$ld_shlibs_GO" = no && can_build_shared=no
+
+with_gnu_ld_GO=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_GO" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc_GO=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds_GO 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; }
+if test "${lt_cv_archive_cmds_need_lc_GO+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  $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_GO
+         pic_flag=$lt_prog_compiler_pic_GO
+         compiler_flags=-v
+         linker_flags=-v
+         verstring=
+         output_objdir=.
+         libname=conftest
+         lt_save_allow_undefined_flag=$allow_undefined_flag_GO
+         allow_undefined_flag_GO=
+         if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_GO 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds_GO 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
+           lt_cv_archive_cmds_need_lc_GO=no
+         else
+           lt_cv_archive_cmds_need_lc_GO=yes
+         fi
+         allow_undefined_flag_GO=$lt_save_allow_undefined_flag
+       else
+         cat conftest.err 1>&5
+       fi
+       $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_GO" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc_GO" >&6; }
+      archive_cmds_need_lc_GO=$lt_cv_archive_cmds_need_lc_GO
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $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_GO=
+if test -n "$hardcode_libdir_flag_spec_GO" ||
+   test -n "$runpath_var_GO" ||
+   test "X$hardcode_automatic_GO" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct_GO" != 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, GO)" != no &&
+     test "$hardcode_minus_L_GO" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action_GO=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action_GO=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action_GO=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_GO" >&5
+$as_echo "$hardcode_action_GO" >&6; }
+
+if test "$hardcode_action_GO" = relink ||
+   test "$inherit_rpath_GO" = 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
+
+
+
+
+
+
+
+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
+
+
+GCC=$lt_save_GCC
+CC="$lt_save_CC"
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+
+
+WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual'
+
+
+WERROR="-Werror"
+
+
+glibgo_toolexecdir=no
+glibgo_toolexeclibdir=no
+glibgo_prefixdir=$prefix
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-version-specific-runtime-libs" >&5
+$as_echo_n "checking for --enable-version-specific-runtime-libs... " >&6; }
+# Check whether --enable-version-specific-runtime-libs was given.
+if test "${enable_version_specific_runtime_libs+set}" = set; then :
+  enableval=$enable_version_specific_runtime_libs; case "$enableval" in
+    yes) version_specific_libs=yes ;;
+    no)  version_specific_libs=no ;;
+    *)   as_fn_error "Unknown argument to enable/disable version-specific libs" "$LINENO" 5;;
+   esac
+else
+  version_specific_libs=no
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $version_specific_libs" >&5
+$as_echo "$version_specific_libs" >&6; }
+
+# Version-specific runtime libs processing.
+if test $version_specific_libs = yes; then
+  glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
+  glibgo_toolexeclibdir='${toolexecdir}/${gcc_version}$(MULTISUBDIR)'
+fi
+
+# Calculate glibgo_toolexecdir, glibgo_toolexeclibdir
+# Install a library built with a cross compiler in tooldir, not libdir.
+if test x"$glibgo_toolexecdir" = x"no"; then
+  if test -n "$with_cross_host" &&
+     test x"$with_cross_host" != x"no"; then
+    glibgo_toolexecdir='${exec_prefix}/${host_alias}'
+    glibgo_toolexeclibdir='${toolexecdir}/lib'
+  else
+    glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
+    glibgo_toolexeclibdir='${libdir}'
+  fi
+  multi_os_directory=`$CC -print-multi-os-directory`
+  case $multi_os_directory in
+    .) ;; # Avoid trailing /.
+    *) glibgo_toolexeclibdir=$glibgo_toolexeclibdir/$multi_os_directory ;;
+  esac
+fi
+
+
+
+
+
+# See if the user wants to configure without libffi.  Some
+# architectures don't support it.  FIXME: We should set a default
+# based on the host.
+
+# Check whether --with-libffi was given.
+if test "${with_libffi+set}" = set; then :
+  withval=$with_libffi; :
+else
+  with_libffi=${with_libffi_default-yes}
+fi
+
+
+LIBFFI=
+LIBFFIINCS=
+if test "$with_libffi" != no; then
+
+$as_echo "#define USE_LIBFFI 1" >>confdefs.h
+
+   LIBFFI=../libffi/libffi_convenience.la
+   LIBFFIINCS='-I$(top_srcdir)/../libffi/include -I../libffi/include'
+fi
+
+
+
+is_darwin=no
+is_freebsd=no
+is_linux=no
+is_rtems=no
+case ${host} in
+  *-*-darwin*) is_darwin=yes ;;
+  *-*-freebsd*) is_freebsd=yes ;;
+  *-*-linux*)  is_linux=yes  ;;
+  *-*-rtems*)  is_rtems=yes  ;;
+esac
+ if test $is_darwin = yes; then
+  LIBGO_IS_DARWIN_TRUE=
+  LIBGO_IS_DARWIN_FALSE='#'
+else
+  LIBGO_IS_DARWIN_TRUE='#'
+  LIBGO_IS_DARWIN_FALSE=
+fi
+
+ if test $is_freebsd = yes; then
+  LIBGO_IS_FREEBSD_TRUE=
+  LIBGO_IS_FREEBSD_FALSE='#'
+else
+  LIBGO_IS_FREEBSD_TRUE='#'
+  LIBGO_IS_FREEBSD_FALSE=
+fi
+
+ if test $is_linux = yes; then
+  LIBGO_IS_LINUX_TRUE=
+  LIBGO_IS_LINUX_FALSE='#'
+else
+  LIBGO_IS_LINUX_TRUE='#'
+  LIBGO_IS_LINUX_FALSE=
+fi
+
+ if test $is_rtems = yes; then
+  LIBGO_IS_RTEMS_TRUE=
+  LIBGO_IS_RTEMS_FALSE='#'
+else
+  LIBGO_IS_RTEMS_TRUE='#'
+  LIBGO_IS_RTEMS_FALSE=
+fi
+
+
+is_386=no
+is_x86_64=no
+is_arm=no
+case ${host} in
+  i[34567]86-*-*)
+    is_386=yes
+    ;;
+  x86_64-*-*)
+    if test "$with_multisubdir" = "32"; then
+      is_386=yes
+    else
+      is_x86_64=yes
+    fi
+    ;;
+  arm*-*-* | strongarm*-*-* | ep9312*-*-* | xscale-*-*)
+    is_arm=yes
+    ;;
+esac
+ if test $is_386 = yes; then
+  LIBGO_IS_386_TRUE=
+  LIBGO_IS_386_FALSE='#'
+else
+  LIBGO_IS_386_TRUE='#'
+  LIBGO_IS_386_FALSE=
+fi
+
+ if test $is_x86_64 = yes; then
+  LIBGO_IS_X86_64_TRUE=
+  LIBGO_IS_X86_64_FALSE='#'
+else
+  LIBGO_IS_X86_64_TRUE='#'
+  LIBGO_IS_X86_64_FALSE=
+fi
+
+ if test $is_arm = yes; then
+  LIBGO_IS_ARM_TRUE=
+  LIBGO_IS_ARM_FALSE='#'
+else
+  LIBGO_IS_ARM_TRUE='#'
+  LIBGO_IS_ARM_FALSE=
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -fsplit-stack is supported" >&5
+$as_echo_n "checking whether -fsplit-stack is supported... " >&6; }
+if test "${ac_cv_libgo_split_stack_supported+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -fsplit-stack"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int i;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_libgo_split_stack_supported=yes
+else
+  ac_cv_libgo_split_stack_supported=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS=$CFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libgo_split_stack_supported" >&5
+$as_echo "$ac_cv_libgo_split_stack_supported" >&6; }
+if test "$ac_cv_libgo_split_stack_supported" = yes; then
+  SPLIT_STACK=-fsplit-stack
+
+$as_echo "#define USING_SPLIT_STACK 1" >>confdefs.h
+
+else
+  SPLIT_STACK=
+fi
+
+ if test "$ac_cv_libgo_split_stack_supported" = yes; then
+  USING_SPLIT_STACK_TRUE=
+  USING_SPLIT_STACK_FALSE='#'
+else
+  USING_SPLIT_STACK_TRUE='#'
+  USING_SPLIT_STACK_FALSE=
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether linker supports split stack" >&5
+$as_echo_n "checking whether linker supports split stack... " >&6; }
+if test "${ac_cv_libgo_linker_supports_split_stack+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_libgo_linker_supports_split_stack=no
+if $LD --help 2>/dev/null | grep split-stack-adjust-size >/dev/null 2>&1; then
+  ac_cv_libgo_linker_supports_split_stack=yes
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libgo_linker_supports_split_stack" >&5
+$as_echo "$ac_cv_libgo_linker_supports_split_stack" >&6; }
+if test "$ac_cv_libgo_linker_supports_split_stack" = yes; then
+
+$as_echo "#define LINKER_SUPPORTS_SPLIT_STACK 1" >>confdefs.h
+
+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 <sys/types.h>
+            #include <sys/param.h>
+
+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 <sys/types.h>
+               #include <sys/param.h>
+
+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 <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+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 <limits.h>
+
+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
+
+
+
+
+# Check whether --with-system-libunwind was given.
+if test "${with_system_libunwind+set}" = set; then :
+  withval=$with_system_libunwind;
+fi
+
+  # If system-libunwind was not specifically set, pick a default setting.
+  if test x$with_system_libunwind = x; then
+    case ${target} in
+      ia64-*-hpux*) with_system_libunwind=yes ;;
+      *) with_system_libunwind=no ;;
+    esac
+  fi
+  # Based on system-libunwind and target, do we have ipinfo?
+  if  test x$with_system_libunwind = xyes; then
+    case ${target} in
+      ia64-*-*) have_unwind_getipinfo=no ;;
+      *) have_unwind_getipinfo=yes ;;
+    esac
+  else
+    # Darwin before version 9 does not have _Unwind_GetIPInfo.
+
+    case ${target} in
+      *-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;;
+      *) have_unwind_getipinfo=yes ;;
+    esac
+
+  fi
+
+  if test x$have_unwind_getipinfo = xyes; then
+
+$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h
+
+  fi
+
+
+for ac_header in sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/user.h sys/utsname.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$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
+
+ if test "$ac_cv_header_sys_mman_h" = yes; then
+  HAVE_SYS_MMAN_H_TRUE=
+  HAVE_SYS_MMAN_H_FALSE='#'
+else
+  HAVE_SYS_MMAN_H_TRUE='#'
+  HAVE_SYS_MMAN_H_FALSE=
+fi
+
+for ac_func in srandom random strsignal
+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 `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -minline-all-stringops" >&5
+$as_echo_n "checking whether compiler supports -minline-all-stringops... " >&6; }
+if test "${ac_cv_libgo_compiler_supports_inline_all_stringops+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -minline-all-stringops"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int i;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_libgo_compiler_supports_inline_all_stringops=yes
+else
+  ac_cv_libgo_compiler_supports_inline_all_stringops=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS=$CFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libgo_compiler_supports_inline_all_stringops" >&5
+$as_echo "$ac_cv_libgo_compiler_supports_inline_all_stringops" >&6; }
+STRINGOPS_FLAG=
+if test "$ac_cv_libgo_compiler_supports_inline_all_stringops" = yes; then
+  STRINGOPS_FLAG=-minline-all-stringops
+fi
+
+
+CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"
+ac_fn_c_check_type "$LINENO" "off64_t" "ac_cv_type_off64_t" "$ac_includes_default"
+if test "x$ac_cv_type_off64_t" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_OFF64_T 1
+_ACEOF
+
+
+fi
+
+CFLAGS=$CFLAGS_hold
+
+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
+
+if test ${multilib} = yes; then
+  multilib_arg="--enable-multilib"
+else
+  multilib_arg=
+fi
+
+ac_config_files="$ac_config_files Makefile testsuite/Makefile"
+
+
+ac_config_commands="$ac_config_commands default"
+
+
+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 "${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 "${LIBGO_IS_DARWIN_TRUE}" && test -z "${LIBGO_IS_DARWIN_FALSE}"; then
+  as_fn_error "conditional \"LIBGO_IS_DARWIN\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_FREEBSD_TRUE}" && test -z "${LIBGO_IS_FREEBSD_FALSE}"; then
+  as_fn_error "conditional \"LIBGO_IS_FREEBSD\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_LINUX_TRUE}" && test -z "${LIBGO_IS_LINUX_FALSE}"; then
+  as_fn_error "conditional \"LIBGO_IS_LINUX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_RTEMS_TRUE}" && test -z "${LIBGO_IS_RTEMS_FALSE}"; then
+  as_fn_error "conditional \"LIBGO_IS_RTEMS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_386_TRUE}" && test -z "${LIBGO_IS_386_FALSE}"; then
+  as_fn_error "conditional \"LIBGO_IS_386\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_X86_64_TRUE}" && test -z "${LIBGO_IS_X86_64_FALSE}"; then
+  as_fn_error "conditional \"LIBGO_IS_X86_64\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_ARM_TRUE}" && test -z "${LIBGO_IS_ARM_FALSE}"; then
+  as_fn_error "conditional \"LIBGO_IS_ARM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${USING_SPLIT_STACK_TRUE}" && test -z "${USING_SPLIT_STACK_FALSE}"; then
+  as_fn_error "conditional \"USING_SPLIT_STACK\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+if test -z "${HAVE_SYS_MMAN_H_TRUE}" && test -z "${HAVE_SYS_MMAN_H_FALSE}"; then
+  as_fn_error "conditional \"HAVE_SYS_MMAN_H\" 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 package-unused $as_me version-unused, which was
+generated by GNU Autoconf 2.64.  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_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
+  -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 commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_version="\\
+package-unused config.status version-unused
+configured by $0, generated by GNU Autoconf 2.64,
+  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+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 ;;
+  --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
+#
+
+srcdir="$srcdir"
+host="$host"
+target="$target"
+with_multisubdir="$with_multisubdir"
+with_multisrctop="$with_multisrctop"
+with_target_subdir="$with_target_subdir"
+ac_configure_args="${multilib_arg} ${ac_configure_args}"
+multi_basedir="$multi_basedir"
+CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+CC="$CC"
+CXX="$CXX"
+GFORTRAN="$GFORTRAN"
+GCJ="$GCJ"
+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'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+LD_GO='`$ECHO "$LD_GO" | $SED "$delay_single_quote_subst"`'
+reload_flag_GO='`$ECHO "$reload_flag_GO" | $SED "$delay_single_quote_subst"`'
+reload_cmds_GO='`$ECHO "$reload_cmds_GO" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds_GO='`$ECHO "$old_archive_cmds_GO" | $SED "$delay_single_quote_subst"`'
+compiler_GO='`$ECHO "$compiler_GO" | $SED "$delay_single_quote_subst"`'
+GCC_GO='`$ECHO "$GCC_GO" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_GO='`$ECHO "$lt_prog_compiler_no_builtin_flag_GO" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_GO='`$ECHO "$lt_prog_compiler_wl_GO" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_GO='`$ECHO "$lt_prog_compiler_pic_GO" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static_GO='`$ECHO "$lt_prog_compiler_static_GO" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_GO='`$ECHO "$lt_cv_prog_compiler_c_o_GO" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc_GO='`$ECHO "$archive_cmds_need_lc_GO" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_GO='`$ECHO "$enable_shared_with_static_runtimes_GO" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_GO='`$ECHO "$export_dynamic_flag_spec_GO" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec_GO='`$ECHO "$whole_archive_flag_spec_GO" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object_GO='`$ECHO "$compiler_needs_object_GO" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_GO='`$ECHO "$old_archive_from_new_cmds_GO" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_GO='`$ECHO "$old_archive_from_expsyms_cmds_GO" | $SED "$delay_single_quote_subst"`'
+archive_cmds_GO='`$ECHO "$archive_cmds_GO" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds_GO='`$ECHO "$archive_expsym_cmds_GO" | $SED "$delay_single_quote_subst"`'
+module_cmds_GO='`$ECHO "$module_cmds_GO" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds_GO='`$ECHO "$module_expsym_cmds_GO" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld_GO='`$ECHO "$with_gnu_ld_GO" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag_GO='`$ECHO "$allow_undefined_flag_GO" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag_GO='`$ECHO "$no_undefined_flag_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_GO='`$ECHO "$hardcode_libdir_flag_spec_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld_GO='`$ECHO "$hardcode_libdir_flag_spec_ld_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator_GO='`$ECHO "$hardcode_libdir_separator_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_GO='`$ECHO "$hardcode_direct_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute_GO='`$ECHO "$hardcode_direct_absolute_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L_GO='`$ECHO "$hardcode_minus_L_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_GO='`$ECHO "$hardcode_shlibpath_var_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic_GO='`$ECHO "$hardcode_automatic_GO" | $SED "$delay_single_quote_subst"`'
+inherit_rpath_GO='`$ECHO "$inherit_rpath_GO" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs_GO='`$ECHO "$link_all_deplibs_GO" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path_GO='`$ECHO "$fix_srcfile_path_GO" | $SED "$delay_single_quote_subst"`'
+always_export_symbols_GO='`$ECHO "$always_export_symbols_GO" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds_GO='`$ECHO "$export_symbols_cmds_GO" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms_GO='`$ECHO "$exclude_expsyms_GO" | $SED "$delay_single_quote_subst"`'
+include_expsyms_GO='`$ECHO "$include_expsyms_GO" | $SED "$delay_single_quote_subst"`'
+prelink_cmds_GO='`$ECHO "$prelink_cmds_GO" | $SED "$delay_single_quote_subst"`'
+file_list_spec_GO='`$ECHO "$file_list_spec_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_action_GO='`$ECHO "$hardcode_action_GO" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SED \
+GREP \
+EGREP \
+FGREP \
+SHELL \
+ECHO \
+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 \
+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 \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib \
+LD_GO \
+reload_flag_GO \
+compiler_GO \
+lt_prog_compiler_no_builtin_flag_GO \
+lt_prog_compiler_wl_GO \
+lt_prog_compiler_pic_GO \
+lt_prog_compiler_static_GO \
+lt_cv_prog_compiler_c_o_GO \
+export_dynamic_flag_spec_GO \
+whole_archive_flag_spec_GO \
+compiler_needs_object_GO \
+with_gnu_ld_GO \
+allow_undefined_flag_GO \
+no_undefined_flag_GO \
+hardcode_libdir_flag_spec_GO \
+hardcode_libdir_flag_spec_ld_GO \
+hardcode_libdir_separator_GO \
+fix_srcfile_path_GO \
+exclude_expsyms_GO \
+include_expsyms_GO \
+file_list_spec_GO; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$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 \
+reload_cmds_GO \
+old_archive_cmds_GO \
+old_archive_from_new_cmds_GO \
+old_archive_from_expsyms_cmds_GO \
+archive_cmds_GO \
+archive_expsym_cmds_GO \
+module_cmds_GO \
+module_expsym_cmds_GO \
+export_symbols_cmds_GO \
+prelink_cmds_GO; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+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'
+
+
+
+
+
+
+# Variables needed in config.status (file generation) which aren't already
+# passed by autoconf.
+SUBDIRS="$SUBDIRS"
+
+
+_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
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;;
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "testsuite/Makefile") CONFIG_FILES="$CONFIG_FILES testsuite/Makefile" ;;
+    "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
+
+  *) 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_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 2>/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
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$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 = "\a"
+
+}
+{
+  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
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = "\a"
+}
+/^[\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    :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
+ ;;
+
+  :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
+    "default-1":C)
+# Only add multilib support code if we just rebuilt the top-level
+# Makefile.
+case " $CONFIG_FILES " in
+ *" Makefile "*)
+   ac_file=Makefile . ${multi_basedir}/config-ml.in
+   ;;
+esac ;;
+    "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, 2009 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="GO "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# 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
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# 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 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
+
+# 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
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# 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
+
+# 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
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# 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
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# 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 "${1}" | $SED "$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 "${1}" | $SED "$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 "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+    *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; 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 "${1}" | $SED "$my_sed_long_opt"`
+  func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=`$ECHO "${1}" | $SED '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"
+
+
+    cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: GO
+
+# The linker used to build libraries.
+LD=$lt_LD_GO
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_GO
+reload_cmds=$lt_reload_cmds_GO
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_GO
+
+# A language specific compiler.
+CC=$lt_compiler_GO
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_GO
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GO
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_GO
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_GO
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_GO
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GO
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_GO
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GO
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GO
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_GO
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_GO
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GO
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GO
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_GO
+archive_expsym_cmds=$lt_archive_expsym_cmds_GO
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_GO
+module_expsym_cmds=$lt_module_expsym_cmds_GO
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_GO
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_GO
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_GO
+
+# 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_GO
+
+# 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_GO
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_GO
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_GO
+
+# 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_GO
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_GO
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_GO
+
+# 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_GO
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_GO
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_GO
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path_GO
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_GO
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_GO
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_GO
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_GO
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_GO
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_GO
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_GO
+
+# ### END LIBTOOL TAG CONFIG: GO
+_LT_EOF
+
+ ;;
+    "default":C) if test -n "$CONFIG_FILES"; then
+   # Multilibs need MULTISUBDIR defined correctly in certain makefiles so
+   # that multilib installs will end up installed in the correct place.
+   # The testsuite needs it for multilib-aware ABI baseline files.
+   # To work around this not being passed down from config-ml.in ->
+   # srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually
+   # append it here.  Only modify Makefiles that have just been created.
+   #
+   # Also, get rid of this simulated-VPATH thing that automake does.
+   cat > vpsed << \_EOF
+s!`test -f '$<' || echo '$(srcdir)/'`!!
+_EOF
+   for i in $SUBDIRS; do
+    case $CONFIG_FILES in
+     *${i}/Makefile*)
+       #echo "Adding MULTISUBDIR to $i/Makefile"
+       sed -f vpsed $i/Makefile > tmp
+       grep '^MULTISUBDIR =' Makefile >> tmp
+       mv tmp $i/Makefile
+       ;;
+    esac
+   done
+   rm vpsed
+ fi
+ ;;
+
+  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/libgo/configure.ac b/libgo/configure.ac
new file mode 100644 (file)
index 0000000..bb6be70
--- /dev/null
@@ -0,0 +1,261 @@
+# configure.ac -- Go library configure script.
+
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Process this file with autoreconf to produce configure.
+
+AC_PREREQ(2.64)
+AC_INIT(package-unused, version-unused,, libgo)
+AC_CONFIG_SRCDIR(Makefile.am)
+AC_CONFIG_HEADER(config.h)
+
+libtool_VERSION=1:0:0
+AC_SUBST(libtool_VERSION)
+
+AM_ENABLE_MULTILIB(, ..)
+
+AC_CANONICAL_SYSTEM
+target_alias=${target_alias-$host_alias}
+
+AM_INIT_AUTOMAKE([1.9.3 no-define foreign -Wall])
+AH_TEMPLATE(PACKAGE, [Name of package])
+AH_TEMPLATE(VERSION, [Version number of package])
+
+m4_rename([_AC_ARG_VAR_PRECIOUS],[glibgo_PRECIOUS])
+m4_define([_AC_ARG_VAR_PRECIOUS],[])
+AC_PROG_CC
+AC_PROG_GO
+m4_rename_force([glibgo_PRECIOUS],[_AC_ARG_VAR_PRECIOUS])
+
+AC_SUBST(CFLAGS)
+
+AM_MAINTAINER_MODE
+
+AC_PROG_LD
+AC_PROG_RANLIB
+AC_CHECK_TOOL(OBJCOPY, objcopy, missing-objcopy)
+
+AC_LIBTOOL_DLOPEN
+AM_PROG_LIBTOOL
+AC_SUBST(enable_shared)
+AC_SUBST(enable_static)
+
+WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual'
+AC_SUBST(WARN_FLAGS)
+
+dnl FIXME: This should be controlled by --enable-maintainer-mode.
+WERROR="-Werror"
+AC_SUBST(WERROR)
+
+glibgo_toolexecdir=no
+glibgo_toolexeclibdir=no
+glibgo_prefixdir=$prefix
+
+AC_MSG_CHECKING([for --enable-version-specific-runtime-libs])
+AC_ARG_ENABLE([version-specific-runtime-libs],
+  AC_HELP_STRING([--enable-version-specific-runtime-libs],
+                 [Specify that runtime libraries should be installed in a compiler-specific directory]),
+  [case "$enableval" in
+    yes) version_specific_libs=yes ;;
+    no)  version_specific_libs=no ;;
+    *)   AC_MSG_ERROR([Unknown argument to enable/disable version-specific libs]);;
+   esac],
+  [version_specific_libs=no])
+AC_MSG_RESULT($version_specific_libs)
+
+# Version-specific runtime libs processing.
+if test $version_specific_libs = yes; then
+  glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
+  glibgo_toolexeclibdir='${toolexecdir}/${gcc_version}$(MULTISUBDIR)'
+fi
+
+# Calculate glibgo_toolexecdir, glibgo_toolexeclibdir
+# Install a library built with a cross compiler in tooldir, not libdir.
+if test x"$glibgo_toolexecdir" = x"no"; then
+  if test -n "$with_cross_host" &&
+     test x"$with_cross_host" != x"no"; then
+    glibgo_toolexecdir='${exec_prefix}/${host_alias}'
+    glibgo_toolexeclibdir='${toolexecdir}/lib'
+  else
+    glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
+    glibgo_toolexeclibdir='${libdir}'
+  fi
+  multi_os_directory=`$CC -print-multi-os-directory`
+  case $multi_os_directory in
+    .) ;; # Avoid trailing /.
+    *) glibgo_toolexeclibdir=$glibgo_toolexeclibdir/$multi_os_directory ;;
+  esac
+fi
+
+AC_SUBST(glibgo_prefixdir)
+AC_SUBST(glibgo_toolexecdir)
+AC_SUBST(glibgo_toolexeclibdir)
+
+# See if the user wants to configure without libffi.  Some
+# architectures don't support it.  FIXME: We should set a default
+# based on the host.
+AC_ARG_WITH(libffi,
+  AS_HELP_STRING([--without-libffi],
+                 [don't use libffi]),
+  [:],
+  [with_libffi=${with_libffi_default-yes}])
+
+LIBFFI=
+LIBFFIINCS=
+if test "$with_libffi" != no; then
+   AC_DEFINE(USE_LIBFFI, 1, [Define if we're to use libffi.])
+   LIBFFI=../libffi/libffi_convenience.la
+   LIBFFIINCS='-I$(top_srcdir)/../libffi/include -I../libffi/include'
+fi
+AC_SUBST(LIBFFI)
+AC_SUBST(LIBFFIINCS)
+
+is_darwin=no
+is_freebsd=no
+is_linux=no
+is_rtems=no
+case ${host} in
+  *-*-darwin*) is_darwin=yes ;;
+  *-*-freebsd*) is_freebsd=yes ;;
+  *-*-linux*)  is_linux=yes  ;;
+  *-*-rtems*)  is_rtems=yes  ;;
+esac
+AM_CONDITIONAL(LIBGO_IS_DARWIN, test $is_darwin = yes)
+AM_CONDITIONAL(LIBGO_IS_FREEBSD, test $is_freebsd = yes)
+AM_CONDITIONAL(LIBGO_IS_LINUX, test $is_linux = yes)
+AM_CONDITIONAL(LIBGO_IS_RTEMS, test $is_rtems = yes)
+
+is_386=no
+is_x86_64=no
+is_arm=no
+case ${host} in
+changequote(,)dnl
+  i[34567]86-*-*)
+changequote([,])dnl
+    is_386=yes
+    ;;
+  x86_64-*-*)
+    if test "$with_multisubdir" = "32"; then
+      is_386=yes
+    else
+      is_x86_64=yes
+    fi
+    ;;
+  arm*-*-* | strongarm*-*-* | ep9312*-*-* | xscale-*-*)
+    is_arm=yes
+    ;;
+esac
+AM_CONDITIONAL(LIBGO_IS_386, test $is_386 = yes)
+AM_CONDITIONAL(LIBGO_IS_X86_64, test $is_x86_64 = yes)
+AM_CONDITIONAL(LIBGO_IS_ARM, test $is_arm = yes)
+
+dnl Use -fsplit-stack when compiling C code if available.
+AC_CACHE_CHECK([whether -fsplit-stack is supported],
+[ac_cv_libgo_split_stack_supported],
+[CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -fsplit-stack"
+AC_COMPILE_IFELSE([[int i;]],
+[ac_cv_libgo_split_stack_supported=yes],
+[ac_cv_libgo_split_stack_supported=no])
+CFLAGS=$CFLAGS_hold])
+if test "$ac_cv_libgo_split_stack_supported" = yes; then
+  SPLIT_STACK=-fsplit-stack
+  AC_DEFINE(USING_SPLIT_STACK, 1,
+               [Define if the compiler supports -fsplit-stack])
+else
+  SPLIT_STACK=
+fi
+AC_SUBST(SPLIT_STACK)
+AM_CONDITIONAL(USING_SPLIT_STACK,
+       test "$ac_cv_libgo_split_stack_supported" = yes)
+
+dnl Check whether the linker does stack munging when calling from
+dnl split-stack into non-split-stack code.  We check this by looking
+dnl at the --help output.  FIXME: This is only half right: it's
+dnl possible for the linker to support this for some targets but not
+dnl others.
+AC_CACHE_CHECK([whether linker supports split stack],
+[ac_cv_libgo_linker_supports_split_stack],
+ac_cv_libgo_linker_supports_split_stack=no
+if $LD --help 2>/dev/null | grep split-stack-adjust-size >/dev/null 2>&1; then
+  ac_cv_libgo_linker_supports_split_stack=yes
+fi)
+if test "$ac_cv_libgo_linker_supports_split_stack" = yes; then
+  AC_DEFINE(LINKER_SUPPORTS_SPLIT_STACK, 1,
+           [Define if the linker support split stack adjustments])
+fi
+
+AC_C_BIGENDIAN
+
+GCC_CHECK_UNWIND_GETIPINFO
+
+AC_CHECK_HEADERS(sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/user.h sys/utsname.h)
+AM_CONDITIONAL(HAVE_SYS_MMAN_H, test "$ac_cv_header_sys_mman_h" = yes)
+AC_CHECK_FUNCS(srandom random strsignal)
+
+dnl For x86 we want to use the -minline-all-stringops option to avoid
+dnl forcing a stack split when calling memcpy and friends.
+AC_CACHE_CHECK([whether compiler supports -minline-all-stringops],
+[ac_cv_libgo_compiler_supports_inline_all_stringops],
+[CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -minline-all-stringops"
+AC_COMPILE_IFELSE([int i;],
+[ac_cv_libgo_compiler_supports_inline_all_stringops=yes],
+[ac_cv_libgo_compiler_supports_inline_all_stringops=no])
+CFLAGS=$CFLAGS_hold])
+STRINGOPS_FLAG=
+if test "$ac_cv_libgo_compiler_supports_inline_all_stringops" = yes; then
+  STRINGOPS_FLAG=-minline-all-stringops
+fi
+AC_SUBST(STRINGOPS_FLAG)
+
+CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"
+AC_CHECK_TYPES(off64_t)
+CFLAGS=$CFLAGS_hold
+
+AC_CACHE_SAVE
+
+if test ${multilib} = yes; then
+  multilib_arg="--enable-multilib"
+else
+  multilib_arg=
+fi
+
+AC_CONFIG_FILES(Makefile testsuite/Makefile)
+
+AC_CONFIG_COMMANDS([default],
+[if test -n "$CONFIG_FILES"; then
+   # Multilibs need MULTISUBDIR defined correctly in certain makefiles so
+   # that multilib installs will end up installed in the correct place.
+   # The testsuite needs it for multilib-aware ABI baseline files.
+   # To work around this not being passed down from config-ml.in ->
+   # srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually
+   # append it here.  Only modify Makefiles that have just been created.
+   #
+   # Also, get rid of this simulated-VPATH thing that automake does.
+   cat > vpsed << \_EOF
+s!`test -f '$<' || echo '$(srcdir)/'`!!
+_EOF
+   for i in $SUBDIRS; do
+    case $CONFIG_FILES in
+     *${i}/Makefile*)
+       #echo "Adding MULTISUBDIR to $i/Makefile"
+       sed -f vpsed $i/Makefile > tmp
+       grep '^MULTISUBDIR =' Makefile >> tmp
+       mv tmp $i/Makefile
+       ;;
+    esac
+   done
+   rm vpsed
+ fi
+],
+[
+# Variables needed in config.status (file generation) which aren't already
+# passed by autoconf.
+SUBDIRS="$SUBDIRS"
+])
+
+AC_OUTPUT
diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go
new file mode 100644 (file)
index 0000000..5b781ff
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The tar package implements access to tar archives.
+// It aims to cover most of the variations, including those produced
+// by GNU and BSD tars.
+//
+// References:
+//   http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
+//   http://www.gnu.org/software/tar/manual/html_node/Standard.html
+package tar
+
+const (
+       blockSize = 512
+
+       // Types
+       TypeReg           = '0'
+       TypeRegA          = '\x00'
+       TypeLink          = '1'
+       TypeSymlink       = '2'
+       TypeChar          = '3'
+       TypeBlock         = '4'
+       TypeDir           = '5'
+       TypeFifo          = '6'
+       TypeCont          = '7'
+       TypeXHeader       = 'x'
+       TypeXGlobalHeader = 'g'
+)
+
+// A Header represents a single header in a tar archive.
+// Some fields may not be populated.
+type Header struct {
+       Name     string
+       Mode     int64
+       Uid      int
+       Gid      int
+       Size     int64
+       Mtime    int64
+       Typeflag byte
+       Linkname string
+       Uname    string
+       Gname    string
+       Devmajor int64
+       Devminor int64
+       Atime    int64
+       Ctime    int64
+}
+
+var zeroBlock = make([]byte, blockSize)
+
+// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
+// We compute and return both.
+func checksum(header []byte) (unsigned int64, signed int64) {
+       for i := 0; i < len(header); i++ {
+               if i == 148 {
+                       // The chksum field (header[148:156]) is special: it should be treated as space bytes.
+                       unsigned += ' ' * 8
+                       signed += ' ' * 8
+                       i += 7
+                       continue
+               }
+               unsigned += int64(header[i])
+               signed += int64(int8(header[i]))
+       }
+       return
+}
+
+type slicer []byte
+
+func (sp *slicer) next(n int) (b []byte) {
+       s := *sp
+       b, *sp = s[0:n], s[n:]
+       return
+}
diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go
new file mode 100644 (file)
index 0000000..35a15f7
--- /dev/null
@@ -0,0 +1,226 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// TODO(dsymonds):
+//   - pax extensions
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "strconv"
+)
+
+var (
+       HeaderError os.Error = os.ErrorString("invalid tar header")
+)
+
+// A Reader provides sequential access to the contents of a tar archive.
+// A tar archive consists of a sequence of files.
+// The Next method advances to the next file in the archive (including the first),
+// and then it can be treated as an io.Reader to access the file's data.
+//
+// Example:
+//     tr := tar.NewReader(r)
+//     for {
+//             hdr, err := tr.Next()
+//             if err != nil {
+//                     // handle error
+//             }
+//             if hdr == nil {
+//                     // end of tar archive
+//                     break
+//             }
+//             io.Copy(data, tr)
+//     }
+type Reader struct {
+       r   io.Reader
+       err os.Error
+       nb  int64 // number of unread bytes for current file entry
+       pad int64 // amount of padding (ignored) after current file entry
+}
+
+// NewReader creates a new Reader reading from r.
+func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
+
+// Next advances to the next entry in the tar archive.
+func (tr *Reader) Next() (*Header, os.Error) {
+       var hdr *Header
+       if tr.err == nil {
+               tr.skipUnread()
+       }
+       if tr.err == nil {
+               hdr = tr.readHeader()
+       }
+       return hdr, tr.err
+}
+
+// Parse bytes as a NUL-terminated C-style string.
+// If a NUL byte is not found then the whole slice is returned as a string.
+func cString(b []byte) string {
+       n := 0
+       for n < len(b) && b[n] != 0 {
+               n++
+       }
+       return string(b[0:n])
+}
+
+func (tr *Reader) octal(b []byte) int64 {
+       // Removing leading spaces.
+       for len(b) > 0 && b[0] == ' ' {
+               b = b[1:]
+       }
+       // Removing trailing NULs and spaces.
+       for len(b) > 0 && (b[len(b)-1] == ' ' || b[len(b)-1] == '\x00') {
+               b = b[0 : len(b)-1]
+       }
+       x, err := strconv.Btoui64(cString(b), 8)
+       if err != nil {
+               tr.err = err
+       }
+       return int64(x)
+}
+
+type ignoreWriter struct{}
+
+func (ignoreWriter) Write(b []byte) (n int, err os.Error) {
+       return len(b), nil
+}
+
+// Skip any unread bytes in the existing file entry, as well as any alignment padding.
+func (tr *Reader) skipUnread() {
+       nr := tr.nb + tr.pad // number of bytes to skip
+       tr.nb, tr.pad = 0, 0
+       if sr, ok := tr.r.(io.Seeker); ok {
+               if _, err := sr.Seek(nr, 1); err == nil {
+                       return
+               }
+       }
+       _, tr.err = io.Copyn(ignoreWriter{}, tr.r, nr)
+}
+
+func (tr *Reader) verifyChecksum(header []byte) bool {
+       if tr.err != nil {
+               return false
+       }
+
+       given := tr.octal(header[148:156])
+       unsigned, signed := checksum(header)
+       return given == unsigned || given == signed
+}
+
+func (tr *Reader) readHeader() *Header {
+       header := make([]byte, blockSize)
+       if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+               return nil
+       }
+
+       // Two blocks of zero bytes marks the end of the archive.
+       if bytes.Equal(header, zeroBlock[0:blockSize]) {
+               if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+                       return nil
+               }
+               if bytes.Equal(header, zeroBlock[0:blockSize]) {
+                       tr.err = os.EOF
+               } else {
+                       tr.err = HeaderError // zero block and then non-zero block
+               }
+               return nil
+       }
+
+       if !tr.verifyChecksum(header) {
+               tr.err = HeaderError
+               return nil
+       }
+
+       // Unpack
+       hdr := new(Header)
+       s := slicer(header)
+
+       hdr.Name = cString(s.next(100))
+       hdr.Mode = tr.octal(s.next(8))
+       hdr.Uid = int(tr.octal(s.next(8)))
+       hdr.Gid = int(tr.octal(s.next(8)))
+       hdr.Size = tr.octal(s.next(12))
+       hdr.Mtime = tr.octal(s.next(12))
+       s.next(8) // chksum
+       hdr.Typeflag = s.next(1)[0]
+       hdr.Linkname = cString(s.next(100))
+
+       // The remainder of the header depends on the value of magic.
+       // The original (v7) version of tar had no explicit magic field,
+       // so its magic bytes, like the rest of the block, are NULs.
+       magic := string(s.next(8)) // contains version field as well.
+       var format string
+       switch magic {
+       case "ustar\x0000": // POSIX tar (1003.1-1988)
+               if string(header[508:512]) == "tar\x00" {
+                       format = "star"
+               } else {
+                       format = "posix"
+               }
+       case "ustar  \x00": // old GNU tar
+               format = "gnu"
+       }
+
+       switch format {
+       case "posix", "gnu", "star":
+               hdr.Uname = cString(s.next(32))
+               hdr.Gname = cString(s.next(32))
+               devmajor := s.next(8)
+               devminor := s.next(8)
+               if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
+                       hdr.Devmajor = tr.octal(devmajor)
+                       hdr.Devminor = tr.octal(devminor)
+               }
+               var prefix string
+               switch format {
+               case "posix", "gnu":
+                       prefix = cString(s.next(155))
+               case "star":
+                       prefix = cString(s.next(131))
+                       hdr.Atime = tr.octal(s.next(12))
+                       hdr.Ctime = tr.octal(s.next(12))
+               }
+               if len(prefix) > 0 {
+                       hdr.Name = prefix + "/" + hdr.Name
+               }
+       }
+
+       if tr.err != nil {
+               tr.err = HeaderError
+               return nil
+       }
+
+       // Maximum value of hdr.Size is 64 GB (12 octal digits),
+       // so there's no risk of int64 overflowing.
+       tr.nb = int64(hdr.Size)
+       tr.pad = -tr.nb & (blockSize - 1) // blockSize is a power of two
+
+       return hdr
+}
+
+// Read reads from the current entry in the tar archive.
+// It returns 0, os.EOF when it reaches the end of that entry,
+// until Next is called to advance to the next entry.
+func (tr *Reader) Read(b []byte) (n int, err os.Error) {
+       if tr.nb == 0 {
+               // file consumed
+               return 0, os.EOF
+       }
+
+       if int64(len(b)) > tr.nb {
+               b = b[0:tr.nb]
+       }
+       n, err = tr.r.Read(b)
+       tr.nb -= int64(n)
+
+       if err == os.EOF && tr.nb > 0 {
+               err = io.ErrUnexpectedEOF
+       }
+       tr.err = err
+       return
+}
diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go
new file mode 100644 (file)
index 0000000..cfc2585
--- /dev/null
@@ -0,0 +1,274 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+import (
+       "bytes"
+       "crypto/md5"
+       "fmt"
+       "io"
+       "os"
+       "reflect"
+       "testing"
+)
+
+type untarTest struct {
+       file    string
+       headers []*Header
+       cksums  []string
+}
+
+var gnuTarTest = &untarTest{
+       file: "testdata/gnu.tar",
+       headers: []*Header{
+               &Header{
+                       Name:     "small.txt",
+                       Mode:     0640,
+                       Uid:      73025,
+                       Gid:      5000,
+                       Size:     5,
+                       Mtime:    1244428340,
+                       Typeflag: '0',
+                       Uname:    "dsymonds",
+                       Gname:    "eng",
+               },
+               &Header{
+                       Name:     "small2.txt",
+                       Mode:     0640,
+                       Uid:      73025,
+                       Gid:      5000,
+                       Size:     11,
+                       Mtime:    1244436044,
+                       Typeflag: '0',
+                       Uname:    "dsymonds",
+                       Gname:    "eng",
+               },
+       },
+       cksums: []string{
+               "e38b27eaccb4391bdec553a7f3ae6b2f",
+               "c65bd2e50a56a2138bf1716f2fd56fe9",
+       },
+}
+
+var untarTests = []*untarTest{
+       gnuTarTest,
+       &untarTest{
+               file: "testdata/star.tar",
+               headers: []*Header{
+                       &Header{
+                               Name:     "small.txt",
+                               Mode:     0640,
+                               Uid:      73025,
+                               Gid:      5000,
+                               Size:     5,
+                               Mtime:    1244592783,
+                               Typeflag: '0',
+                               Uname:    "dsymonds",
+                               Gname:    "eng",
+                               Atime:    1244592783,
+                               Ctime:    1244592783,
+                       },
+                       &Header{
+                               Name:     "small2.txt",
+                               Mode:     0640,
+                               Uid:      73025,
+                               Gid:      5000,
+                               Size:     11,
+                               Mtime:    1244592783,
+                               Typeflag: '0',
+                               Uname:    "dsymonds",
+                               Gname:    "eng",
+                               Atime:    1244592783,
+                               Ctime:    1244592783,
+                       },
+               },
+       },
+       &untarTest{
+               file: "testdata/v7.tar",
+               headers: []*Header{
+                       &Header{
+                               Name:     "small.txt",
+                               Mode:     0444,
+                               Uid:      73025,
+                               Gid:      5000,
+                               Size:     5,
+                               Mtime:    1244593104,
+                               Typeflag: '\x00',
+                       },
+                       &Header{
+                               Name:     "small2.txt",
+                               Mode:     0444,
+                               Uid:      73025,
+                               Gid:      5000,
+                               Size:     11,
+                               Mtime:    1244593104,
+                               Typeflag: '\x00',
+                       },
+               },
+       },
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+       for i, test := range untarTests {
+               f, err := os.Open(test.file, os.O_RDONLY, 0444)
+               if err != nil {
+                       t.Errorf("test %d: Unexpected error: %v", i, err)
+                       continue
+               }
+               tr := NewReader(f)
+               for j, header := range test.headers {
+                       hdr, err := tr.Next()
+                       if err != nil || hdr == nil {
+                               t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+                               f.Close()
+                               continue testLoop
+                       }
+                       if !reflect.DeepEqual(hdr, header) {
+                               t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+                                       i, j, *hdr, *header)
+                       }
+               }
+               hdr, err := tr.Next()
+               if err == os.EOF {
+                       break
+               }
+               if hdr != nil || err != nil {
+                       t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, err)
+               }
+               f.Close()
+       }
+}
+
+func TestPartialRead(t *testing.T) {
+       f, err := os.Open("testdata/gnu.tar", os.O_RDONLY, 0444)
+       if err != nil {
+               t.Fatalf("Unexpected error: %v", err)
+       }
+       defer f.Close()
+
+       tr := NewReader(f)
+
+       // Read the first four bytes; Next() should skip the last byte.
+       hdr, err := tr.Next()
+       if err != nil || hdr == nil {
+               t.Fatalf("Didn't get first file: %v", err)
+       }
+       buf := make([]byte, 4)
+       if _, err := io.ReadFull(tr, buf); err != nil {
+               t.Fatalf("Unexpected error: %v", err)
+       }
+       if expected := []byte("Kilt"); !bytes.Equal(buf, expected) {
+               t.Errorf("Contents = %v, want %v", buf, expected)
+       }
+
+       // Second file
+       hdr, err = tr.Next()
+       if err != nil || hdr == nil {
+               t.Fatalf("Didn't get second file: %v", err)
+       }
+       buf = make([]byte, 6)
+       if _, err := io.ReadFull(tr, buf); err != nil {
+               t.Fatalf("Unexpected error: %v", err)
+       }
+       if expected := []byte("Google"); !bytes.Equal(buf, expected) {
+               t.Errorf("Contents = %v, want %v", buf, expected)
+       }
+}
+
+
+func TestIncrementalRead(t *testing.T) {
+       test := gnuTarTest
+       f, err := os.Open(test.file, os.O_RDONLY, 0444)
+       if err != nil {
+               t.Fatalf("Unexpected error: %v", err)
+       }
+       defer f.Close()
+
+       tr := NewReader(f)
+
+       headers := test.headers
+       cksums := test.cksums
+       nread := 0
+
+       // loop over all files
+       for ; ; nread++ {
+               hdr, err := tr.Next()
+               if hdr == nil || err == os.EOF {
+                       break
+               }
+
+               // check the header
+               if !reflect.DeepEqual(hdr, headers[nread]) {
+                       t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
+                               *hdr, headers[nread])
+               }
+
+               // read file contents in little chunks EOF,
+               // checksumming all the way
+               h := md5.New()
+               rdbuf := make([]uint8, 8)
+               for {
+                       nr, err := tr.Read(rdbuf)
+                       if err == os.EOF {
+                               break
+                       }
+                       if err != nil {
+                               t.Errorf("Read: unexpected error %v\n", err)
+                               break
+                       }
+                       h.Write(rdbuf[0:nr])
+               }
+               // verify checksum
+               have := fmt.Sprintf("%x", h.Sum())
+               want := cksums[nread]
+               if want != have {
+                       t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
+               }
+       }
+       if nread != len(headers) {
+               t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread)
+       }
+}
+
+func TestNonSeekable(t *testing.T) {
+       test := gnuTarTest
+       f, err := os.Open(test.file, os.O_RDONLY, 0444)
+       if err != nil {
+               t.Fatalf("Unexpected error: %v", err)
+       }
+       defer f.Close()
+
+       // pipe the data in
+       r, w, err := os.Pipe()
+       if err != nil {
+               t.Fatalf("Unexpected error %s", err)
+       }
+       go func() {
+               rdbuf := make([]uint8, 1<<16)
+               for {
+                       nr, err := f.Read(rdbuf)
+                       w.Write(rdbuf[0:nr])
+                       if err == os.EOF {
+                               break
+                       }
+               }
+               w.Close()
+       }()
+
+       tr := NewReader(r)
+       nread := 0
+
+       for ; ; nread++ {
+               hdr, err := tr.Next()
+               if hdr == nil || err == os.EOF {
+                       break
+               }
+       }
+
+       if nread != len(test.headers) {
+               t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread)
+       }
+}
diff --git a/libgo/go/archive/tar/testdata/gnu.tar b/libgo/go/archive/tar/testdata/gnu.tar
new file mode 100644 (file)
index 0000000..fc899dc
Binary files /dev/null and b/libgo/go/archive/tar/testdata/gnu.tar differ
diff --git a/libgo/go/archive/tar/testdata/small.txt b/libgo/go/archive/tar/testdata/small.txt
new file mode 100644 (file)
index 0000000..b249bfc
--- /dev/null
@@ -0,0 +1 @@
+Kilts
\ No newline at end of file
diff --git a/libgo/go/archive/tar/testdata/small2.txt b/libgo/go/archive/tar/testdata/small2.txt
new file mode 100644 (file)
index 0000000..394ee3e
--- /dev/null
@@ -0,0 +1 @@
+Google.com
diff --git a/libgo/go/archive/tar/testdata/star.tar b/libgo/go/archive/tar/testdata/star.tar
new file mode 100644 (file)
index 0000000..59e2d4e
Binary files /dev/null and b/libgo/go/archive/tar/testdata/star.tar differ
diff --git a/libgo/go/archive/tar/testdata/v7.tar b/libgo/go/archive/tar/testdata/v7.tar
new file mode 100644 (file)
index 0000000..eb65fc9
Binary files /dev/null and b/libgo/go/archive/tar/testdata/v7.tar differ
diff --git a/libgo/go/archive/tar/testdata/writer-big.tar b/libgo/go/archive/tar/testdata/writer-big.tar
new file mode 100644 (file)
index 0000000..753e883
Binary files /dev/null and b/libgo/go/archive/tar/testdata/writer-big.tar differ
diff --git a/libgo/go/archive/tar/testdata/writer.tar b/libgo/go/archive/tar/testdata/writer.tar
new file mode 100644 (file)
index 0000000..0358f91
Binary files /dev/null and b/libgo/go/archive/tar/testdata/writer.tar differ
diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go
new file mode 100644 (file)
index 0000000..8673bad
--- /dev/null
@@ -0,0 +1,205 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// TODO(dsymonds):
+// - catch more errors (no first header, write after close, etc.)
+
+import (
+       "io"
+       "os"
+       "strconv"
+)
+
+var (
+       ErrWriteTooLong    = os.NewError("write too long")
+       ErrFieldTooLong    = os.NewError("header field too long")
+       ErrWriteAfterClose = os.NewError("write after close")
+)
+
+// A Writer provides sequential writing of a tar archive in POSIX.1 format.
+// A tar archive consists of a sequence of files.
+// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
+// writing at most hdr.Size bytes in total.
+//
+// Example:
+//     tw := tar.NewWriter(w)
+//     hdr := new(Header)
+//     hdr.Size = length of data in bytes
+//     // populate other hdr fields as desired
+//     if err := tw.WriteHeader(hdr); err != nil {
+//             // handle error
+//     }
+//     io.Copy(tw, data)
+//     tw.Close()
+type Writer struct {
+       w          io.Writer
+       err        os.Error
+       nb         int64 // number of unwritten bytes for current file entry
+       pad        int64 // amount of padding to write after current file entry
+       closed     bool
+       usedBinary bool // whether the binary numeric field extension was used
+}
+
+// NewWriter creates a new Writer writing to w.
+func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
+
+// Flush finishes writing the current file (optional).
+func (tw *Writer) Flush() os.Error {
+       n := tw.nb + tw.pad
+       for n > 0 && tw.err == nil {
+               nr := n
+               if nr > blockSize {
+                       nr = blockSize
+               }
+               var nw int
+               nw, tw.err = tw.w.Write(zeroBlock[0:nr])
+               n -= int64(nw)
+       }
+       tw.nb = 0
+       tw.pad = 0
+       return tw.err
+}
+
+// Write s into b, terminating it with a NUL if there is room.
+func (tw *Writer) cString(b []byte, s string) {
+       if len(s) > len(b) {
+               if tw.err == nil {
+                       tw.err = ErrFieldTooLong
+               }
+               return
+       }
+       copy(b, s)
+       if len(s) < len(b) {
+               b[len(s)] = 0
+       }
+}
+
+// Encode x as an octal ASCII string and write it into b with leading zeros.
+func (tw *Writer) octal(b []byte, x int64) {
+       s := strconv.Itob64(x, 8)
+       // leading zeros, but leave room for a NUL.
+       for len(s)+1 < len(b) {
+               s = "0" + s
+       }
+       tw.cString(b, s)
+}
+
+// Write x into b, either as octal or as binary (GNUtar/star extension).
+func (tw *Writer) numeric(b []byte, x int64) {
+       // Try octal first.
+       s := strconv.Itob64(x, 8)
+       if len(s) < len(b) {
+               tw.octal(b, x)
+               return
+       }
+       // Too big: use binary (big-endian).
+       tw.usedBinary = true
+       for i := len(b) - 1; x > 0 && i >= 0; i-- {
+               b[i] = byte(x)
+               x >>= 8
+       }
+       b[0] |= 0x80 // highest bit indicates binary format
+}
+
+// WriteHeader writes hdr and prepares to accept the file's contents.
+// WriteHeader calls Flush if it is not the first header.
+// Calling after a Close will return ErrWriteAfterClose.
+func (tw *Writer) WriteHeader(hdr *Header) os.Error {
+       if tw.closed {
+               return ErrWriteAfterClose
+       }
+       if tw.err == nil {
+               tw.Flush()
+       }
+       if tw.err != nil {
+               return tw.err
+       }
+
+       tw.nb = int64(hdr.Size)
+       tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
+
+       header := make([]byte, blockSize)
+       s := slicer(header)
+
+       // TODO(dsymonds): handle names longer than 100 chars
+       copy(s.next(100), []byte(hdr.Name))
+
+       tw.octal(s.next(8), hdr.Mode)          // 100:108
+       tw.numeric(s.next(8), int64(hdr.Uid))  // 108:116
+       tw.numeric(s.next(8), int64(hdr.Gid))  // 116:124
+       tw.numeric(s.next(12), hdr.Size)       // 124:136
+       tw.numeric(s.next(12), hdr.Mtime)      // 136:148
+       s.next(8)                              // chksum (148:156)
+       s.next(1)[0] = hdr.Typeflag            // 156:157
+       s.next(100)                            // linkname (157:257)
+       copy(s.next(8), []byte("ustar\x0000")) // 257:265
+       tw.cString(s.next(32), hdr.Uname)      // 265:297
+       tw.cString(s.next(32), hdr.Gname)      // 297:329
+       tw.numeric(s.next(8), hdr.Devmajor)    // 329:337
+       tw.numeric(s.next(8), hdr.Devminor)    // 337:345
+
+       // Use the GNU magic instead of POSIX magic if we used any GNU extensions.
+       if tw.usedBinary {
+               copy(header[257:265], []byte("ustar  \x00"))
+       }
+
+       // The chksum field is terminated by a NUL and a space.
+       // This is different from the other octal fields.
+       chksum, _ := checksum(header)
+       tw.octal(header[148:155], chksum)
+       header[155] = ' '
+
+       if tw.err != nil {
+               // problem with header; probably integer too big for a field.
+               return tw.err
+       }
+
+       _, tw.err = tw.w.Write(header)
+
+       return tw.err
+}
+
+// Write writes to the current entry in the tar archive.
+// Write returns the error ErrWriteTooLong if more than
+// hdr.Size bytes are written after WriteHeader.
+func (tw *Writer) Write(b []byte) (n int, err os.Error) {
+       if tw.closed {
+               err = ErrWriteTooLong
+               return
+       }
+       overwrite := false
+       if int64(len(b)) > tw.nb {
+               b = b[0:tw.nb]
+               overwrite = true
+       }
+       n, err = tw.w.Write(b)
+       tw.nb -= int64(n)
+       if err == nil && overwrite {
+               err = ErrWriteTooLong
+               return
+       }
+       tw.err = err
+       return
+}
+
+// Close closes the tar archive, flushing any unwritten
+// data to the underlying writer.
+func (tw *Writer) Close() os.Error {
+       if tw.err != nil || tw.closed {
+               return tw.err
+       }
+       tw.Flush()
+       tw.closed = true
+
+       // trailer: two zero blocks
+       for i := 0; i < 2; i++ {
+               _, tw.err = tw.w.Write(zeroBlock)
+               if tw.err != nil {
+                       break
+               }
+       }
+       return tw.err
+}
diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go
new file mode 100644 (file)
index 0000000..24db9b8
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "testing"
+       "testing/iotest"
+)
+
+type writerTestEntry struct {
+       header   *Header
+       contents string
+}
+
+type writerTest struct {
+       file    string // filename of expected output
+       entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+       &writerTest{
+               file: "testdata/writer.tar",
+               entries: []*writerTestEntry{
+                       &writerTestEntry{
+                               header: &Header{
+                                       Name:     "small.txt",
+                                       Mode:     0640,
+                                       Uid:      73025,
+                                       Gid:      5000,
+                                       Size:     5,
+                                       Mtime:    1246508266,
+                                       Typeflag: '0',
+                                       Uname:    "dsymonds",
+                                       Gname:    "eng",
+                               },
+                               contents: "Kilts",
+                       },
+                       &writerTestEntry{
+                               header: &Header{
+                                       Name:     "small2.txt",
+                                       Mode:     0640,
+                                       Uid:      73025,
+                                       Gid:      5000,
+                                       Size:     11,
+                                       Mtime:    1245217492,
+                                       Typeflag: '0',
+                                       Uname:    "dsymonds",
+                                       Gname:    "eng",
+                               },
+                               contents: "Google.com\n",
+                       },
+               },
+       },
+       // The truncated test file was produced using these commands:
+       //   dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+       //   tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+       &writerTest{
+               file: "testdata/writer-big.tar",
+               entries: []*writerTestEntry{
+                       &writerTestEntry{
+                               header: &Header{
+                                       Name:     "tmp/16gig.txt",
+                                       Mode:     0640,
+                                       Uid:      73025,
+                                       Gid:      5000,
+                                       Size:     16 << 30,
+                                       Mtime:    1254699560,
+                                       Typeflag: '0',
+                                       Uname:    "dsymonds",
+                                       Gname:    "eng",
+                               },
+                               // no contents
+                       },
+               },
+       },
+}
+
+// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
+func bytestr(offset int, b []byte) string {
+       const rowLen = 32
+       s := fmt.Sprintf("%04x ", offset)
+       for _, ch := range b {
+               switch {
+               case '0' <= ch && ch <= '9', 'A' <= ch && ch <= 'Z', 'a' <= ch && ch <= 'z':
+                       s += fmt.Sprintf("  %c", ch)
+               default:
+                       s += fmt.Sprintf(" %02x", ch)
+               }
+       }
+       return s
+}
+
+// Render a pseudo-diff between two blocks of bytes.
+func bytediff(a []byte, b []byte) string {
+       const rowLen = 32
+       s := fmt.Sprintf("(%d bytes vs. %d bytes)\n", len(a), len(b))
+       for offset := 0; len(a)+len(b) > 0; offset += rowLen {
+               na, nb := rowLen, rowLen
+               if na > len(a) {
+                       na = len(a)
+               }
+               if nb > len(b) {
+                       nb = len(b)
+               }
+               sa := bytestr(offset, a[0:na])
+               sb := bytestr(offset, b[0:nb])
+               if sa != sb {
+                       s += fmt.Sprintf("-%v\n+%v\n", sa, sb)
+               }
+               a = a[na:]
+               b = b[nb:]
+       }
+       return s
+}
+
+func TestWriter(t *testing.T) {
+testLoop:
+       for i, test := range writerTests {
+               expected, err := ioutil.ReadFile(test.file)
+               if err != nil {
+                       t.Errorf("test %d: Unexpected error: %v", i, err)
+                       continue
+               }
+
+               buf := new(bytes.Buffer)
+               tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
+               for j, entry := range test.entries {
+                       if err := tw.WriteHeader(entry.header); err != nil {
+                               t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
+                               continue testLoop
+                       }
+                       if _, err := io.WriteString(tw, entry.contents); err != nil {
+                               t.Errorf("test %d, entry %d: Failed writing contents: %v", i, j, err)
+                               continue testLoop
+                       }
+               }
+               if err := tw.Close(); err != nil {
+                       t.Errorf("test %d: Failed closing archive: %v", err)
+                       continue testLoop
+               }
+
+               actual := buf.Bytes()
+               if !bytes.Equal(expected, actual) {
+                       t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
+                               i, bytediff(expected, actual))
+               }
+       }
+}
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go
new file mode 100644 (file)
index 0000000..579ba16
--- /dev/null
@@ -0,0 +1,278 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The zip package provides support for reading ZIP archives.
+
+See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+
+This package does not support ZIP64 or disk spanning.
+*/
+package zip
+
+import (
+       "bufio"
+       "bytes"
+       "compress/flate"
+       "hash"
+       "hash/crc32"
+       "encoding/binary"
+       "io"
+       "os"
+)
+
+var (
+       FormatError       = os.NewError("not a valid zip file")
+       UnsupportedMethod = os.NewError("unsupported compression algorithm")
+       ChecksumError     = os.NewError("checksum error")
+)
+
+type Reader struct {
+       r       io.ReaderAt
+       File    []*File
+       Comment string
+}
+
+type File struct {
+       FileHeader
+       zipr         io.ReaderAt
+       zipsize      int64
+       headerOffset uint32
+       bodyOffset   int64
+}
+
+// OpenReader will open the Zip file specified by name and return a Reader.
+func OpenReader(name string) (*Reader, os.Error) {
+       f, err := os.Open(name, os.O_RDONLY, 0644)
+       if err != nil {
+               return nil, err
+       }
+       fi, err := f.Stat()
+       if err != nil {
+               return nil, err
+       }
+       return NewReader(f, fi.Size)
+}
+
+// NewReader returns a new Reader reading from r, which is assumed to
+// have the given size in bytes.
+func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
+       end, err := readDirectoryEnd(r, size)
+       if err != nil {
+               return nil, err
+       }
+       z := &Reader{
+               r:       r,
+               File:    make([]*File, end.directoryRecords),
+               Comment: end.comment,
+       }
+       rs := io.NewSectionReader(r, 0, size)
+       if _, err = rs.Seek(int64(end.directoryOffset), 0); err != nil {
+               return nil, err
+       }
+       buf := bufio.NewReader(rs)
+       for i := range z.File {
+               z.File[i] = &File{zipr: r, zipsize: size}
+               if err := readDirectoryHeader(z.File[i], buf); err != nil {
+                       return nil, err
+               }
+       }
+       return z, nil
+}
+
+// Open returns a ReadCloser that provides access to the File's contents.
+func (f *File) Open() (rc io.ReadCloser, err os.Error) {
+       off := int64(f.headerOffset)
+       if f.bodyOffset == 0 {
+               r := io.NewSectionReader(f.zipr, off, f.zipsize-off)
+               if err = readFileHeader(f, r); err != nil {
+                       return
+               }
+               if f.bodyOffset, err = r.Seek(0, 1); err != nil {
+                       return
+               }
+       }
+       r := io.NewSectionReader(f.zipr, off+f.bodyOffset, int64(f.CompressedSize))
+       switch f.Method {
+       case 0: // store (no compression)
+               rc = nopCloser{r}
+       case 8: // DEFLATE
+               rc = flate.NewReader(r)
+       default:
+               err = UnsupportedMethod
+       }
+       if rc != nil {
+               rc = &checksumReader{rc, crc32.NewIEEE(), f.CRC32}
+       }
+       return
+}
+
+type checksumReader struct {
+       rc   io.ReadCloser
+       hash hash.Hash32
+       sum  uint32
+}
+
+func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
+       n, err = r.rc.Read(b)
+       r.hash.Write(b[:n])
+       if err != os.EOF {
+               return
+       }
+       if r.hash.Sum32() != r.sum {
+               err = ChecksumError
+       }
+       return
+}
+
+func (r *checksumReader) Close() os.Error { return r.rc.Close() }
+
+type nopCloser struct {
+       io.Reader
+}
+
+func (f nopCloser) Close() os.Error { return nil }
+
+func readFileHeader(f *File, r io.Reader) (err os.Error) {
+       defer func() {
+               if rerr, ok := recover().(os.Error); ok {
+                       err = rerr
+               }
+       }()
+       var (
+               signature      uint32
+               filenameLength uint16
+               extraLength    uint16
+       )
+       read(r, &signature)
+       if signature != fileHeaderSignature {
+               return FormatError
+       }
+       read(r, &f.ReaderVersion)
+       read(r, &f.Flags)
+       read(r, &f.Method)
+       read(r, &f.ModifiedTime)
+       read(r, &f.ModifiedDate)
+       read(r, &f.CRC32)
+       read(r, &f.CompressedSize)
+       read(r, &f.UncompressedSize)
+       read(r, &filenameLength)
+       read(r, &extraLength)
+       f.Name = string(readByteSlice(r, filenameLength))
+       f.Extra = readByteSlice(r, extraLength)
+       return
+}
+
+func readDirectoryHeader(f *File, r io.Reader) (err os.Error) {
+       defer func() {
+               if rerr, ok := recover().(os.Error); ok {
+                       err = rerr
+               }
+       }()
+       var (
+               signature          uint32
+               filenameLength     uint16
+               extraLength        uint16
+               commentLength      uint16
+               startDiskNumber    uint16 // unused
+               internalAttributes uint16 // unused
+               externalAttributes uint32 // unused
+       )
+       read(r, &signature)
+       if signature != directoryHeaderSignature {
+               return FormatError
+       }
+       read(r, &f.CreatorVersion)
+       read(r, &f.ReaderVersion)
+       read(r, &f.Flags)
+       read(r, &f.Method)
+       read(r, &f.ModifiedTime)
+       read(r, &f.ModifiedDate)
+       read(r, &f.CRC32)
+       read(r, &f.CompressedSize)
+       read(r, &f.UncompressedSize)
+       read(r, &filenameLength)
+       read(r, &extraLength)
+       read(r, &commentLength)
+       read(r, &startDiskNumber)
+       read(r, &internalAttributes)
+       read(r, &externalAttributes)
+       read(r, &f.headerOffset)
+       f.Name = string(readByteSlice(r, filenameLength))
+       f.Extra = readByteSlice(r, extraLength)
+       f.Comment = string(readByteSlice(r, commentLength))
+       return
+}
+
+func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error) {
+       // look for directoryEndSignature in the last 1k, then in the last 65k
+       var b []byte
+       for i, bLen := range []int64{1024, 65 * 1024} {
+               if bLen > size {
+                       bLen = size
+               }
+               b = make([]byte, int(bLen))
+               if _, err := r.ReadAt(b, size-bLen); err != nil && err != os.EOF {
+                       return nil, err
+               }
+               if p := findSignatureInBlock(b); p >= 0 {
+                       b = b[p:]
+                       break
+               }
+               if i == 1 || bLen == size {
+                       return nil, FormatError
+               }
+       }
+
+       // read header into struct
+       defer func() {
+               if rerr, ok := recover().(os.Error); ok {
+                       err = rerr
+                       d = nil
+               }
+       }()
+       br := bytes.NewBuffer(b[4:]) // skip over signature
+       d = new(directoryEnd)
+       read(br, &d.diskNbr)
+       read(br, &d.dirDiskNbr)
+       read(br, &d.dirRecordsThisDisk)
+       read(br, &d.directoryRecords)
+       read(br, &d.directorySize)
+       read(br, &d.directoryOffset)
+       read(br, &d.commentLen)
+       d.comment = string(readByteSlice(br, d.commentLen))
+       return d, nil
+}
+
+func findSignatureInBlock(b []byte) int {
+       const minSize = 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 // fixed part of header
+       for i := len(b) - minSize; i >= 0; i-- {
+               // defined from directoryEndSignature in struct.go
+               if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
+                       // n is length of comment
+                       n := int(b[i+minSize-2]) | int(b[i+minSize-1])<<8
+                       if n+minSize+i == len(b) {
+                               return i
+                       }
+               }
+       }
+       return -1
+}
+
+func read(r io.Reader, data interface{}) {
+       if err := binary.Read(r, binary.LittleEndian, data); err != nil {
+               panic(err)
+       }
+}
+
+func readByteSlice(r io.Reader, l uint16) []byte {
+       b := make([]byte, l)
+       if l == 0 {
+               return b
+       }
+       if _, err := io.ReadFull(r, b); err != nil {
+               panic(err)
+       }
+       return b
+}
diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go
new file mode 100644 (file)
index 0000000..8e1fbbf
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zip
+
+import (
+       "bytes"
+       "encoding/binary"
+       "io"
+       "io/ioutil"
+       "os"
+       "testing"
+)
+
+type ZipTest struct {
+       Name    string
+       Comment string
+       File    []ZipTestFile
+       Error   os.Error // the error that Opening this file should return
+}
+
+type ZipTestFile struct {
+       Name    string
+       Content []byte // if blank, will attempt to compare against File
+       File    string // name of file to compare to (relative to testdata/)
+}
+
+var tests = []ZipTest{
+       {
+               Name:    "test.zip",
+               Comment: "This is a zipfile comment.",
+               File: []ZipTestFile{
+                       {
+                               Name:    "test.txt",
+                               Content: []byte("This is a test text file.\n"),
+                       },
+                       {
+                               Name: "gophercolor16x16.png",
+                               File: "gophercolor16x16.png",
+                       },
+               },
+       },
+       {
+               Name: "r.zip",
+               File: []ZipTestFile{
+                       {
+                               Name: "r/r.zip",
+                               File: "r.zip",
+                       },
+               },
+       },
+       {Name: "readme.zip"},
+       {Name: "readme.notzip", Error: FormatError},
+}
+
+func TestReader(t *testing.T) {
+       for _, zt := range tests {
+               readTestZip(t, zt)
+       }
+}
+
+func readTestZip(t *testing.T, zt ZipTest) {
+       z, err := OpenReader("testdata/" + zt.Name)
+       if err != zt.Error {
+               t.Errorf("error=%v, want %v", err, zt.Error)
+               return
+       }
+
+       // bail here if no Files expected to be tested
+       // (there may actually be files in the zip, but we don't care)
+       if zt.File == nil {
+               return
+       }
+
+       if z.Comment != zt.Comment {
+               t.Errorf("%s: comment=%q, want %q", zt.Name, z.Comment, zt.Comment)
+       }
+       if len(z.File) != len(zt.File) {
+               t.Errorf("%s: file count=%d, want %d", zt.Name, len(z.File), len(zt.File))
+       }
+
+       // test read of each file
+       for i, ft := range zt.File {
+               readTestFile(t, ft, z.File[i])
+       }
+
+       // test simultaneous reads
+       n := 0
+       done := make(chan bool)
+       for i := 0; i < 5; i++ {
+               for j, ft := range zt.File {
+                       go func() {
+                               readTestFile(t, ft, z.File[j])
+                               done <- true
+                       }()
+                       n++
+               }
+       }
+       for ; n > 0; n-- {
+               <-done
+       }
+
+       // test invalid checksum
+       z.File[0].CRC32++ // invalidate
+       r, err := z.File[0].Open()
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       var b bytes.Buffer
+       _, err = io.Copy(&b, r)
+       if err != ChecksumError {
+               t.Errorf("%s: copy error=%v, want %v", err, ChecksumError)
+       }
+}
+
+func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
+       if f.Name != ft.Name {
+               t.Errorf("name=%q, want %q", f.Name, ft.Name)
+       }
+       var b bytes.Buffer
+       r, err := f.Open()
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       _, err = io.Copy(&b, r)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       r.Close()
+       var c []byte
+       if len(ft.Content) != 0 {
+               c = ft.Content
+       } else if c, err = ioutil.ReadFile("testdata/" + ft.File); err != nil {
+               t.Error(err)
+               return
+       }
+       if b.Len() != len(c) {
+               t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c))
+               return
+       }
+       for i, b := range b.Bytes() {
+               if b != c[i] {
+                       t.Errorf("%s: content[%d]=%q want %q", i, b, c[i])
+                       return
+               }
+       }
+}
+
+func TestInvalidFiles(t *testing.T) {
+       const size = 1024 * 70 // 70kb
+       b := make([]byte, size)
+
+       // zeroes
+       _, err := NewReader(sliceReaderAt(b), size)
+       if err != FormatError {
+               t.Errorf("zeroes: error=%v, want %v", err, FormatError)
+       }
+
+       // repeated directoryEndSignatures
+       sig := make([]byte, 4)
+       binary.LittleEndian.PutUint32(sig, directoryEndSignature)
+       for i := 0; i < size-4; i += 4 {
+               copy(b[i:i+4], sig)
+       }
+       _, err = NewReader(sliceReaderAt(b), size)
+       if err != FormatError {
+               t.Errorf("sigs: error=%v, want %v", err, FormatError)
+       }
+}
+
+type sliceReaderAt []byte
+
+func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, os.Error) {
+       copy(b, r[int(off):int(off)+len(b)])
+       return len(b), nil
+}
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
new file mode 100644 (file)
index 0000000..8a8c727
--- /dev/null
@@ -0,0 +1,33 @@
+package zip
+
+const (
+       fileHeaderSignature      = 0x04034b50
+       directoryHeaderSignature = 0x02014b50
+       directoryEndSignature    = 0x06054b50
+)
+
+type FileHeader struct {
+       Name             string
+       CreatorVersion   uint16
+       ReaderVersion    uint16
+       Flags            uint16
+       Method           uint16
+       ModifiedTime     uint16
+       ModifiedDate     uint16
+       CRC32            uint32
+       CompressedSize   uint32
+       UncompressedSize uint32
+       Extra            []byte
+       Comment          string
+}
+
+type directoryEnd struct {
+       diskNbr            uint16 // unused
+       dirDiskNbr         uint16 // unused
+       dirRecordsThisDisk uint16 // unused
+       directoryRecords   uint16
+       directorySize      uint32
+       directoryOffset    uint32 // relative to file
+       commentLen         uint16
+       comment            string
+}
diff --git a/libgo/go/archive/zip/testdata/gophercolor16x16.png b/libgo/go/archive/zip/testdata/gophercolor16x16.png
new file mode 100644 (file)
index 0000000..48854ff
Binary files /dev/null and b/libgo/go/archive/zip/testdata/gophercolor16x16.png differ
diff --git a/libgo/go/archive/zip/testdata/r.zip b/libgo/go/archive/zip/testdata/r.zip
new file mode 100644 (file)
index 0000000..ea0fa2f
Binary files /dev/null and b/libgo/go/archive/zip/testdata/r.zip differ
diff --git a/libgo/go/archive/zip/testdata/readme.notzip b/libgo/go/archive/zip/testdata/readme.notzip
new file mode 100644 (file)
index 0000000..06668c4
Binary files /dev/null and b/libgo/go/archive/zip/testdata/readme.notzip differ
diff --git a/libgo/go/archive/zip/testdata/readme.zip b/libgo/go/archive/zip/testdata/readme.zip
new file mode 100644 (file)
index 0000000..db3bb90
Binary files /dev/null and b/libgo/go/archive/zip/testdata/readme.zip differ
diff --git a/libgo/go/archive/zip/testdata/test.zip b/libgo/go/archive/zip/testdata/test.zip
new file mode 100644 (file)
index 0000000..03890c0
Binary files /dev/null and b/libgo/go/archive/zip/testdata/test.zip differ
diff --git a/libgo/go/asn1/asn1.go b/libgo/go/asn1/asn1.go
new file mode 100644 (file)
index 0000000..b26eb09
--- /dev/null
@@ -0,0 +1,785 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The asn1 package implements parsing of DER-encoded ASN.1 data structures,
+// as defined in ITU-T Rec X.690.
+//
+// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
+// http://luca.ntop.org/Teaching/Appunti/asn1.html.
+package asn1
+
+// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
+// are different encoding formats for those objects. Here, we'll be dealing
+// with DER, the Distinguished Encoding Rules. DER is used in X.509 because
+// it's fast to parse and, unlike BER, has a unique encoding for every object.
+// When calculating hashes over objects, it's important that the resulting
+// bytes be the same at both ends and DER removes this margin of error.
+//
+// ASN.1 is very complex and this package doesn't attempt to implement
+// everything by any means.
+
+import (
+       "fmt"
+       "os"
+       "reflect"
+       "time"
+)
+
+// A StructuralError suggests that the ASN.1 data is valid, but the Go type
+// which is receiving it doesn't match.
+type StructuralError struct {
+       Msg string
+}
+
+func (e StructuralError) String() string { return "ASN.1 structure error: " + e.Msg }
+
+// A SyntaxError suggests that the ASN.1 data is invalid.
+type SyntaxError struct {
+       Msg string
+}
+
+func (e SyntaxError) String() string { return "ASN.1 syntax error: " + e.Msg }
+
+// We start by dealing with each of the primitive types in turn.
+
+// BOOLEAN
+
+func parseBool(bytes []byte) (ret bool, err os.Error) {
+       if len(bytes) != 1 {
+               err = SyntaxError{"invalid boolean"}
+               return
+       }
+
+       return bytes[0] != 0, nil
+}
+
+// INTEGER
+
+// parseInt64 treats the given bytes as a big-endian, signed integer and
+// returns the result.
+func parseInt64(bytes []byte) (ret int64, err os.Error) {
+       if len(bytes) > 8 {
+               // We'll overflow an int64 in this case.
+               err = StructuralError{"integer too large"}
+               return
+       }
+       for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
+               ret <<= 8
+               ret |= int64(bytes[bytesRead])
+       }
+
+       // Shift up and down in order to sign extend the result.
+       ret <<= 64 - uint8(len(bytes))*8
+       ret >>= 64 - uint8(len(bytes))*8
+       return
+}
+
+// parseInt treats the given bytes as a big-endian, signed integer and returns
+// the result.
+func parseInt(bytes []byte) (int, os.Error) {
+       ret64, err := parseInt64(bytes)
+       if err != nil {
+               return 0, err
+       }
+       if ret64 != int64(int(ret64)) {
+               return 0, StructuralError{"integer too large"}
+       }
+       return int(ret64), nil
+}
+
+// BIT STRING
+
+// BitString is the structure to use when you want an ASN.1 BIT STRING type. A
+// bit string is padded up to the nearest byte in memory and the number of
+// valid bits is recorded. Padding bits will be zero.
+type BitString struct {
+       Bytes     []byte // bits packed into bytes.
+       BitLength int    // length in bits.
+}
+
+// At returns the bit at the given index. If the index is out of range it
+// returns false.
+func (b BitString) At(i int) int {
+       if i < 0 || i >= b.BitLength {
+               return 0
+       }
+       x := i / 8
+       y := 7 - uint(i%8)
+       return int(b.Bytes[x]>>y) & 1
+}
+
+// RightAlign returns a slice where the padding bits are at the beginning. The
+// slice may share memory with the BitString.
+func (b BitString) RightAlign() []byte {
+       shift := uint(8 - (b.BitLength % 8))
+       if shift == 8 || len(b.Bytes) == 0 {
+               return b.Bytes
+       }
+
+       a := make([]byte, len(b.Bytes))
+       a[0] = b.Bytes[0] >> shift
+       for i := 1; i < len(b.Bytes); i++ {
+               a[i] = b.Bytes[i-1] << (8 - shift)
+               a[i] |= b.Bytes[i] >> shift
+       }
+
+       return a
+}
+
+// parseBitString parses an ASN.1 bit string from the given byte array and returns it.
+func parseBitString(bytes []byte) (ret BitString, err os.Error) {
+       if len(bytes) == 0 {
+               err = SyntaxError{"zero length BIT STRING"}
+               return
+       }
+       paddingBits := int(bytes[0])
+       if paddingBits > 7 ||
+               len(bytes) == 1 && paddingBits > 0 ||
+               bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
+               err = SyntaxError{"invalid padding bits in BIT STRING"}
+               return
+       }
+       ret.BitLength = (len(bytes)-1)*8 - paddingBits
+       ret.Bytes = bytes[1:]
+       return
+}
+
+// OBJECT IDENTIFIER
+
+// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
+type ObjectIdentifier []int
+
+// Equal returns true iff oi and other represent the same identifier.
+func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
+       if len(oi) != len(other) {
+               return false
+       }
+       for i := 0; i < len(oi); i++ {
+               if oi[i] != other[i] {
+                       return false
+               }
+       }
+
+       return true
+}
+
+// parseObjectIdentifier parses an OBJECT IDENTIFER from the given bytes and
+// returns it. An object identifer is a sequence of variable length integers
+// that are assigned in a hierarachy.
+func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
+       if len(bytes) == 0 {
+               err = SyntaxError{"zero length OBJECT IDENTIFIER"}
+               return
+       }
+
+       // In the worst case, we get two elements from the first byte (which is
+       // encoded differently) and then every varint is a single byte long.
+       s = make([]int, len(bytes)+1)
+
+       // The first byte is 40*value1 + value2:
+       s[0] = int(bytes[0]) / 40
+       s[1] = int(bytes[0]) % 40
+       i := 2
+       for offset := 1; offset < len(bytes); i++ {
+               var v int
+               v, offset, err = parseBase128Int(bytes, offset)
+               if err != nil {
+                       return
+               }
+               s[i] = v
+       }
+       s = s[0:i]
+       return
+}
+
+// ENUMERATED
+
+// An Enumerated is represented as a plain int.
+type Enumerated int
+
+
+// FLAG
+
+// A Flag accepts any data and is set to true if present.
+type Flag bool
+
+// parseBase128Int parses a base-128 encoded int from the given offset in the
+// given byte array. It returns the value and the new offset.
+func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
+       offset = initOffset
+       for shifted := 0; offset < len(bytes); shifted++ {
+               if shifted > 4 {
+                       err = StructuralError{"base 128 integer too large"}
+                       return
+               }
+               ret <<= 7
+               b := bytes[offset]
+               ret |= int(b & 0x7f)
+               offset++
+               if b&0x80 == 0 {
+                       return
+               }
+       }
+       err = SyntaxError{"truncated base 128 integer"}
+       return
+}
+
+// UTCTime
+
+func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
+       s := string(bytes)
+       ret, err = time.Parse("0601021504Z0700", s)
+       if err == nil {
+               return
+       }
+       ret, err = time.Parse("060102150405Z0700", s)
+       return
+}
+
+// parseGeneralizedTime parses the GeneralizedTime from the given byte array
+// and returns the resulting time.
+func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
+       return time.Parse("20060102150405Z0700", string(bytes))
+}
+
+// PrintableString
+
+// parsePrintableString parses a ASN.1 PrintableString from the given byte
+// array and returns it.
+func parsePrintableString(bytes []byte) (ret string, err os.Error) {
+       for _, b := range bytes {
+               if !isPrintable(b) {
+                       err = SyntaxError{"PrintableString contains invalid character"}
+                       return
+               }
+       }
+       ret = string(bytes)
+       return
+}
+
+// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
+func isPrintable(b byte) bool {
+       return 'a' <= b && b <= 'z' ||
+               'A' <= b && b <= 'Z' ||
+               '0' <= b && b <= '9' ||
+               '\'' <= b && b <= ')' ||
+               '+' <= b && b <= '/' ||
+               b == ' ' ||
+               b == ':' ||
+               b == '=' ||
+               b == '?' ||
+               // This is techincally not allowed in a PrintableString.
+               // However, x509 certificates with wildcard strings don't
+               // always use the correct string type so we permit it.
+               b == '*'
+}
+
+// IA5String
+
+// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
+// byte array and returns it.
+func parseIA5String(bytes []byte) (ret string, err os.Error) {
+       for _, b := range bytes {
+               if b >= 0x80 {
+                       err = SyntaxError{"IA5String contains invalid character"}
+                       return
+               }
+       }
+       ret = string(bytes)
+       return
+}
+
+// T61String
+
+// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
+// byte array and returns it.
+func parseT61String(bytes []byte) (ret string, err os.Error) {
+       return string(bytes), nil
+}
+
+// A RawValue represents an undecoded ASN.1 object.
+type RawValue struct {
+       Class, Tag int
+       IsCompound bool
+       Bytes      []byte
+       FullBytes  []byte // includes the tag and length
+}
+
+// RawContent is used to signal that the undecoded, DER data needs to be
+// preserved for a struct. To use it, the first field of the struct must have
+// this type. It's an error for any of the other fields to have this type.
+type RawContent []byte
+
+// Tagging
+
+// parseTagAndLength parses an ASN.1 tag and length pair from the given offset
+// into a byte array. It returns the parsed data and the new offset. SET and
+// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
+// don't distinguish between ordered and unordered objects in this code.
+func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err os.Error) {
+       offset = initOffset
+       b := bytes[offset]
+       offset++
+       ret.class = int(b >> 6)
+       ret.isCompound = b&0x20 == 0x20
+       ret.tag = int(b & 0x1f)
+
+       // If the bottom five bits are set, then the tag number is actually base 128
+       // encoded afterwards
+       if ret.tag == 0x1f {
+               ret.tag, offset, err = parseBase128Int(bytes, offset)
+               if err != nil {
+                       return
+               }
+       }
+       if offset >= len(bytes) {
+               err = SyntaxError{"truncated tag or length"}
+               return
+       }
+       b = bytes[offset]
+       offset++
+       if b&0x80 == 0 {
+               // The length is encoded in the bottom 7 bits.
+               ret.length = int(b & 0x7f)
+       } else {
+               // Bottom 7 bits give the number of length bytes to follow.
+               numBytes := int(b & 0x7f)
+               // We risk overflowing a signed 32-bit number if we accept more than 3 bytes.
+               if numBytes > 3 {
+                       err = StructuralError{"length too large"}
+                       return
+               }
+               if numBytes == 0 {
+                       err = SyntaxError{"indefinite length found (not DER)"}
+                       return
+               }
+               ret.length = 0
+               for i := 0; i < numBytes; i++ {
+                       if offset >= len(bytes) {
+                               err = SyntaxError{"truncated tag or length"}
+                               return
+                       }
+                       b = bytes[offset]
+                       offset++
+                       ret.length <<= 8
+                       ret.length |= int(b)
+               }
+       }
+
+       return
+}
+
+// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
+// a number of ASN.1 values from the given byte array and returns them as a
+// slice of Go values of the given type.
+func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflect.Type) (ret *reflect.SliceValue, err os.Error) {
+       expectedTag, compoundType, ok := getUniversalType(elemType)
+       if !ok {
+               err = StructuralError{"unknown Go type for slice"}
+               return
+       }
+
+       // First we iterate over the input and count the number of elements,
+       // checking that the types are correct in each case.
+       numElements := 0
+       for offset := 0; offset < len(bytes); {
+               var t tagAndLength
+               t, offset, err = parseTagAndLength(bytes, offset)
+               if err != nil {
+                       return
+               }
+               if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
+                       err = StructuralError{"sequence tag mismatch"}
+                       return
+               }
+               if invalidLength(offset, t.length, len(bytes)) {
+                       err = SyntaxError{"truncated sequence"}
+                       return
+               }
+               offset += t.length
+               numElements++
+       }
+       ret = reflect.MakeSlice(sliceType, numElements, numElements)
+       params := fieldParameters{}
+       offset := 0
+       for i := 0; i < numElements; i++ {
+               offset, err = parseField(ret.Elem(i), bytes, offset, params)
+               if err != nil {
+                       return
+               }
+       }
+       return
+}
+
+var (
+       bitStringType        = reflect.Typeof(BitString{})
+       objectIdentifierType = reflect.Typeof(ObjectIdentifier{})
+       enumeratedType       = reflect.Typeof(Enumerated(0))
+       flagType             = reflect.Typeof(Flag(false))
+       timeType             = reflect.Typeof(&time.Time{})
+       rawValueType         = reflect.Typeof(RawValue{})
+       rawContentsType      = reflect.Typeof(RawContent(nil))
+)
+
+// invalidLength returns true iff offset + length > sliceLength, or if the
+// addition would overflow.
+func invalidLength(offset, length, sliceLength int) bool {
+       return offset+length < offset || offset+length > sliceLength
+}
+
+// parseField is the main parsing function. Given a byte array and an offset
+// into the array, it will try to parse a suitable ASN.1 value out and store it
+// in the given Value.
+func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) {
+       offset = initOffset
+       fieldType := v.Type()
+
+       // If we have run out of data, it may be that there are optional elements at the end.
+       if offset == len(bytes) {
+               if !setDefaultValue(v, params) {
+                       err = SyntaxError{"sequence truncated"}
+               }
+               return
+       }
+
+       // Deal with raw values.
+       if fieldType == rawValueType {
+               var t tagAndLength
+               t, offset, err = parseTagAndLength(bytes, offset)
+               if err != nil {
+                       return
+               }
+               if invalidLength(offset, t.length, len(bytes)) {
+                       err = SyntaxError{"data truncated"}
+                       return
+               }
+               result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
+               offset += t.length
+               v.(*reflect.StructValue).Set(reflect.NewValue(result).(*reflect.StructValue))
+               return
+       }
+
+       // Deal with the ANY type.
+       if ifaceType, ok := fieldType.(*reflect.InterfaceType); ok && ifaceType.NumMethod() == 0 {
+               ifaceValue := v.(*reflect.InterfaceValue)
+               var t tagAndLength
+               t, offset, err = parseTagAndLength(bytes, offset)
+               if err != nil {
+                       return
+               }
+               if invalidLength(offset, t.length, len(bytes)) {
+                       err = SyntaxError{"data truncated"}
+                       return
+               }
+               var result interface{}
+               if !t.isCompound && t.class == classUniversal {
+                       innerBytes := bytes[offset : offset+t.length]
+                       switch t.tag {
+                       case tagPrintableString:
+                               result, err = parsePrintableString(innerBytes)
+                       case tagIA5String:
+                               result, err = parseIA5String(innerBytes)
+                       case tagT61String:
+                               result, err = parseT61String(innerBytes)
+                       case tagInteger:
+                               result, err = parseInt64(innerBytes)
+                       case tagBitString:
+                               result, err = parseBitString(innerBytes)
+                       case tagOID:
+                               result, err = parseObjectIdentifier(innerBytes)
+                       case tagUTCTime:
+                               result, err = parseUTCTime(innerBytes)
+                       case tagOctetString:
+                               result = innerBytes
+                       default:
+                               // If we don't know how to handle the type, we just leave Value as nil.
+                       }
+               }
+               offset += t.length
+               if err != nil {
+                       return
+               }
+               if result != nil {
+                       ifaceValue.Set(reflect.NewValue(result))
+               }
+               return
+       }
+       universalTag, compoundType, ok1 := getUniversalType(fieldType)
+       if !ok1 {
+               err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)}
+               return
+       }
+
+       t, offset, err := parseTagAndLength(bytes, offset)
+       if err != nil {
+               return
+       }
+       if params.explicit {
+               if t.class == classContextSpecific && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
+                       if t.length > 0 {
+                               t, offset, err = parseTagAndLength(bytes, offset)
+                               if err != nil {
+                                       return
+                               }
+                       } else {
+                               if fieldType != flagType {
+                                       err = StructuralError{"Zero length explicit tag was not an asn1.Flag"}
+                                       return
+                               }
+
+                               flagValue := v.(*reflect.BoolValue)
+                               flagValue.Set(true)
+                               return
+                       }
+               } else {
+                       // The tags didn't match, it might be an optional element.
+                       ok := setDefaultValue(v, params)
+                       if ok {
+                               offset = initOffset
+                       } else {
+                               err = StructuralError{"explicitly tagged member didn't match"}
+                       }
+                       return
+               }
+       }
+
+       // Special case for strings: PrintableString and IA5String both map to
+       // the Go type string. getUniversalType returns the tag for
+       // PrintableString when it sees a string so, if we see an IA5String on
+       // the wire, we change the universal type to match.
+       if universalTag == tagPrintableString && t.tag == tagIA5String {
+               universalTag = tagIA5String
+       }
+
+       // Special case for time: UTCTime and GeneralizedTime both map to the
+       // Go type time.Time.
+       if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
+               universalTag = tagGeneralizedTime
+       }
+
+       expectedClass := classUniversal
+       expectedTag := universalTag
+
+       if !params.explicit && params.tag != nil {
+               expectedClass = classContextSpecific
+               expectedTag = *params.tag
+       }
+
+       // We have unwrapped any explicit tagging at this point.
+       if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
+               // Tags don't match. Again, it could be an optional element.
+               ok := setDefaultValue(v, params)
+               if ok {
+                       offset = initOffset
+               } else {
+                       err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset)}
+               }
+               return
+       }
+       if invalidLength(offset, t.length, len(bytes)) {
+               err = SyntaxError{"data truncated"}
+               return
+       }
+       innerBytes := bytes[offset : offset+t.length]
+       offset += t.length
+
+       // We deal with the structures defined in this package first.
+       switch fieldType {
+       case objectIdentifierType:
+               newSlice, err1 := parseObjectIdentifier(innerBytes)
+               sliceValue := v.(*reflect.SliceValue)
+               sliceValue.Set(reflect.MakeSlice(sliceValue.Type().(*reflect.SliceType), len(newSlice), len(newSlice)))
+               if err1 == nil {
+                       reflect.ArrayCopy(sliceValue, reflect.NewValue(newSlice).(reflect.ArrayOrSliceValue))
+               }
+               err = err1
+               return
+       case bitStringType:
+               structValue := v.(*reflect.StructValue)
+               bs, err1 := parseBitString(innerBytes)
+               if err1 == nil {
+                       structValue.Set(reflect.NewValue(bs).(*reflect.StructValue))
+               }
+               err = err1
+               return
+       case timeType:
+               ptrValue := v.(*reflect.PtrValue)
+               var time *time.Time
+               var err1 os.Error
+               if universalTag == tagUTCTime {
+                       time, err1 = parseUTCTime(innerBytes)
+               } else {
+                       time, err1 = parseGeneralizedTime(innerBytes)
+               }
+               if err1 == nil {
+                       ptrValue.Set(reflect.NewValue(time).(*reflect.PtrValue))
+               }
+               err = err1
+               return
+       case enumeratedType:
+               parsedInt, err1 := parseInt(innerBytes)
+               enumValue := v.(*reflect.IntValue)
+               if err1 == nil {
+                       enumValue.Set(int64(parsedInt))
+               }
+               err = err1
+               return
+       case flagType:
+               flagValue := v.(*reflect.BoolValue)
+               flagValue.Set(true)
+               return
+       }
+       switch val := v.(type) {
+       case *reflect.BoolValue:
+               parsedBool, err1 := parseBool(innerBytes)
+               if err1 == nil {
+                       val.Set(parsedBool)
+               }
+               err = err1
+               return
+       case *reflect.IntValue:
+               switch val.Type().Kind() {
+               case reflect.Int:
+                       parsedInt, err1 := parseInt(innerBytes)
+                       if err1 == nil {
+                               val.Set(int64(parsedInt))
+                       }
+                       err = err1
+                       return
+               case reflect.Int64:
+                       parsedInt, err1 := parseInt64(innerBytes)
+                       if err1 == nil {
+                               val.Set(parsedInt)
+                       }
+                       err = err1
+                       return
+               }
+       case *reflect.StructValue:
+               structType := fieldType.(*reflect.StructType)
+
+               if structType.NumField() > 0 &&
+                       structType.Field(0).Type == rawContentsType {
+                       bytes := bytes[initOffset:offset]
+                       val.Field(0).SetValue(reflect.NewValue(RawContent(bytes)))
+               }
+
+               innerOffset := 0
+               for i := 0; i < structType.NumField(); i++ {
+                       field := structType.Field(i)
+                       if i == 0 && field.Type == rawContentsType {
+                               continue
+                       }
+                       innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag))
+                       if err != nil {
+                               return
+                       }
+               }
+               // We allow extra bytes at the end of the SEQUENCE because
+               // adding elements to the end has been used in X.509 as the
+               // version numbers have increased.
+               return
+       case *reflect.SliceValue:
+               sliceType := fieldType.(*reflect.SliceType)
+               if sliceType.Elem().Kind() == reflect.Uint8 {
+                       val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
+                       reflect.ArrayCopy(val, reflect.NewValue(innerBytes).(reflect.ArrayOrSliceValue))
+                       return
+               }
+               newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
+               if err1 == nil {
+                       val.Set(newSlice)
+               }
+               err = err1
+               return
+       case *reflect.StringValue:
+               var v string
+               switch universalTag {
+               case tagPrintableString:
+                       v, err = parsePrintableString(innerBytes)
+               case tagIA5String:
+                       v, err = parseIA5String(innerBytes)
+               case tagT61String:
+                       v, err = parseT61String(innerBytes)
+               default:
+                       err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
+               }
+               if err == nil {
+                       val.Set(v)
+               }
+               return
+       }
+       err = StructuralError{"unknown Go type"}
+       return
+}
+
+// setDefaultValue is used to install a default value, from a tag string, into
+// a Value. It is successful is the field was optional, even if a default value
+// wasn't provided or it failed to install it into the Value.
+func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
+       if !params.optional {
+               return
+       }
+       ok = true
+       if params.defaultValue == nil {
+               return
+       }
+       switch val := v.(type) {
+       case *reflect.IntValue:
+               val.Set(*params.defaultValue)
+       }
+       return
+}
+
+// Unmarshal parses the DER-encoded ASN.1 data structure b
+// and uses the reflect package to fill in an arbitrary value pointed at by val.
+// Because Unmarshal uses the reflect package, the structs
+// being written to must use upper case field names.
+//
+// An ASN.1 INTEGER can be written to an int or int64.
+// If the encoded value does not fit in the Go type,
+// Unmarshal returns a parse error.
+//
+// An ASN.1 BIT STRING can be written to a BitString.
+//
+// An ASN.1 OCTET STRING can be written to a []byte.
+//
+// An ASN.1 OBJECT IDENTIFIER can be written to an
+// ObjectIdentifier.
+//
+// An ASN.1 ENUMERATED can be written to an Enumerated.
+//
+// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
+//
+// An ASN.1 PrintableString or IA5String can be written to a string.
+//
+// Any of the above ASN.1 values can be written to an interface{}.
+// The value stored in the interface has the corresponding Go type.
+// For integers, that type is int64.
+//
+// An ASN.1 SEQUENCE OF x or SET OF x can be written
+// to a slice if an x can be written to the slice's element type.
+//
+// An ASN.1 SEQUENCE or SET can be written to a struct
+// if each of the elements in the sequence can be
+// written to the corresponding element in the struct.
+//
+// The following tags on struct fields have special meaning to Unmarshal:
+//
+//     optional                marks the field as ASN.1 OPTIONAL
+//     [explicit] tag:x        specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
+//     default:x               sets the default value for optional integer fields
+//
+// If the type of the first field of a structure is RawContent then the raw
+// ASN1 contents of the struct will be stored in it.
+//
+// Other ASN.1 types are not supported; if it encounters them,
+// Unmarshal returns a parse error.
+func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
+       v := reflect.NewValue(val).(*reflect.PtrValue).Elem()
+       offset, err := parseField(v, b, 0, fieldParameters{})
+       if err != nil {
+               return nil, err
+       }
+       return b[offset:], nil
+}
diff --git a/libgo/go/asn1/asn1_test.go b/libgo/go/asn1/asn1_test.go
new file mode 100644 (file)
index 0000000..34b5f1e
--- /dev/null
@@ -0,0 +1,634 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package asn1
+
+import (
+       "bytes"
+       "reflect"
+       "testing"
+       "time"
+)
+
+type int64Test struct {
+       in  []byte
+       ok  bool
+       out int64
+}
+
+var int64TestData = []int64Test{
+       {[]byte{0x00}, true, 0},
+       {[]byte{0x7f}, true, 127},
+       {[]byte{0x00, 0x80}, true, 128},
+       {[]byte{0x01, 0x00}, true, 256},
+       {[]byte{0x80}, true, -128},
+       {[]byte{0xff, 0x7f}, true, -129},
+       {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, true, -1},
+       {[]byte{0xff}, true, -1},
+       {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, true, -9223372036854775808},
+       {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, false, 0},
+}
+
+func TestParseInt64(t *testing.T) {
+       for i, test := range int64TestData {
+               ret, err := parseInt64(test.in)
+               if (err == nil) != test.ok {
+                       t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+               }
+               if test.ok && ret != test.out {
+                       t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+               }
+       }
+}
+
+type bitStringTest struct {
+       in        []byte
+       ok        bool
+       out       []byte
+       bitLength int
+}
+
+var bitStringTestData = []bitStringTest{
+       {[]byte{}, false, []byte{}, 0},
+       {[]byte{0x00}, true, []byte{}, 0},
+       {[]byte{0x07, 0x00}, true, []byte{0x00}, 1},
+       {[]byte{0x07, 0x01}, false, []byte{}, 0},
+       {[]byte{0x07, 0x40}, false, []byte{}, 0},
+       {[]byte{0x08, 0x00}, false, []byte{}, 0},
+}
+
+func TestBitString(t *testing.T) {
+       for i, test := range bitStringTestData {
+               ret, err := parseBitString(test.in)
+               if (err == nil) != test.ok {
+                       t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+               }
+               if err == nil {
+                       if test.bitLength != ret.BitLength || bytes.Compare(ret.Bytes, test.out) != 0 {
+                               t.Errorf("#%d: Bad result: %v (expected %v %v)", i, ret, test.out, test.bitLength)
+                       }
+               }
+       }
+}
+
+func TestBitStringAt(t *testing.T) {
+       bs := BitString{[]byte{0x82, 0x40}, 16}
+       if bs.At(0) != 1 {
+               t.Error("#1: Failed")
+       }
+       if bs.At(1) != 0 {
+               t.Error("#2: Failed")
+       }
+       if bs.At(6) != 1 {
+               t.Error("#3: Failed")
+       }
+       if bs.At(9) != 1 {
+               t.Error("#4: Failed")
+       }
+}
+
+type bitStringRightAlignTest struct {
+       in    []byte
+       inlen int
+       out   []byte
+}
+
+var bitStringRightAlignTests = []bitStringRightAlignTest{
+       {[]byte{0x80}, 1, []byte{0x01}},
+       {[]byte{0x80, 0x80}, 9, []byte{0x01, 0x01}},
+       {[]byte{}, 0, []byte{}},
+       {[]byte{0xce}, 8, []byte{0xce}},
+       {[]byte{0xce, 0x47}, 16, []byte{0xce, 0x47}},
+       {[]byte{0x34, 0x50}, 12, []byte{0x03, 0x45}},
+}
+
+func TestBitStringRightAlign(t *testing.T) {
+       for i, test := range bitStringRightAlignTests {
+               bs := BitString{test.in, test.inlen}
+               out := bs.RightAlign()
+               if bytes.Compare(out, test.out) != 0 {
+                       t.Errorf("#%d got: %x want: %x", i, out, test.out)
+               }
+       }
+}
+
+type objectIdentifierTest struct {
+       in  []byte
+       ok  bool
+       out []int
+}
+
+var objectIdentifierTestData = []objectIdentifierTest{
+       {[]byte{}, false, []int{}},
+       {[]byte{85}, true, []int{2, 5}},
+       {[]byte{85, 0x02}, true, []int{2, 5, 2}},
+       {[]byte{85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
+       {[]byte{85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
+}
+
+func TestObjectIdentifier(t *testing.T) {
+       for i, test := range objectIdentifierTestData {
+               ret, err := parseObjectIdentifier(test.in)
+               if (err == nil) != test.ok {
+                       t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+               }
+               if err == nil {
+                       if !reflect.DeepEqual(test.out, ret) {
+                               t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+                       }
+               }
+       }
+}
+
+type timeTest struct {
+       in  string
+       ok  bool
+       out *time.Time
+}
+
+var utcTestData = []timeTest{
+       {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, -7 * 60 * 60, ""}},
+       {"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 7*60*60 + 30*60, ""}},
+       {"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, "UTC"}},
+       {"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, "UTC"}},
+       {"a10506234540Z", false, nil},
+       {"91a506234540Z", false, nil},
+       {"9105a6234540Z", false, nil},
+       {"910506a34540Z", false, nil},
+       {"910506334a40Z", false, nil},
+       {"91050633444aZ", false, nil},
+       {"910506334461Z", false, nil},
+       {"910506334400Za", false, nil},
+}
+
+func TestUTCTime(t *testing.T) {
+       for i, test := range utcTestData {
+               ret, err := parseUTCTime([]byte(test.in))
+               if (err == nil) != test.ok {
+                       t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+               }
+               if err == nil {
+                       if !reflect.DeepEqual(test.out, ret) {
+                               t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+                       }
+               }
+       }
+}
+
+var generalizedTimeTestData = []timeTest{
+       {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, "UTC"}},
+       {"20100102030405", false, nil},
+       {"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 6*60*60 + 7*60, ""}},
+       {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, -6*60*60 - 7*60, ""}},
+}
+
+func TestGeneralizedTime(t *testing.T) {
+       for i, test := range generalizedTimeTestData {
+               ret, err := parseGeneralizedTime([]byte(test.in))
+               if (err == nil) != test.ok {
+                       t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+               }
+               if err == nil {
+                       if !reflect.DeepEqual(test.out, ret) {
+                               t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+                       }
+               }
+       }
+}
+
+type tagAndLengthTest struct {
+       in  []byte
+       ok  bool
+       out tagAndLength
+}
+
+var tagAndLengthData = []tagAndLengthTest{
+       {[]byte{0x80, 0x01}, true, tagAndLength{2, 0, 1, false}},
+       {[]byte{0xa0, 0x01}, true, tagAndLength{2, 0, 1, true}},
+       {[]byte{0x02, 0x00}, true, tagAndLength{0, 2, 0, false}},
+       {[]byte{0xfe, 0x00}, true, tagAndLength{3, 30, 0, true}},
+       {[]byte{0x1f, 0x01, 0x00}, true, tagAndLength{0, 1, 0, false}},
+       {[]byte{0x1f, 0x81, 0x00, 0x00}, true, tagAndLength{0, 128, 0, false}},
+       {[]byte{0x1f, 0x81, 0x80, 0x01, 0x00}, true, tagAndLength{0, 0x4001, 0, false}},
+       {[]byte{0x00, 0x81, 0x01}, true, tagAndLength{0, 0, 1, false}},
+       {[]byte{0x00, 0x82, 0x01, 0x00}, true, tagAndLength{0, 0, 256, false}},
+       {[]byte{0x00, 0x83, 0x01, 0x00}, false, tagAndLength{}},
+       {[]byte{0x1f, 0x85}, false, tagAndLength{}},
+       {[]byte{0x30, 0x80}, false, tagAndLength{}},
+}
+
+func TestParseTagAndLength(t *testing.T) {
+       for i, test := range tagAndLengthData {
+               tagAndLength, _, err := parseTagAndLength(test.in, 0)
+               if (err == nil) != test.ok {
+                       t.Errorf("#%d: Incorrect error result (did pass? %v, expected: %v)", i, err == nil, test.ok)
+               }
+               if err == nil && !reflect.DeepEqual(test.out, tagAndLength) {
+                       t.Errorf("#%d: Bad result: %v (expected %v)", i, tagAndLength, test.out)
+               }
+       }
+}
+
+type parseFieldParametersTest struct {
+       in  string
+       out fieldParameters
+}
+
+func newInt(n int) *int { return &n }
+
+func newInt64(n int64) *int64 { return &n }
+
+func newString(s string) *string { return &s }
+
+func newBool(b bool) *bool { return &b }
+
+var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{
+       {"", fieldParameters{}},
+       {"ia5", fieldParameters{stringType: tagIA5String}},
+       {"printable", fieldParameters{stringType: tagPrintableString}},
+       {"optional", fieldParameters{optional: true}},
+       {"explicit", fieldParameters{explicit: true, tag: new(int)}},
+       {"optional,explicit", fieldParameters{optional: true, explicit: true, tag: new(int)}},
+       {"default:42", fieldParameters{defaultValue: newInt64(42)}},
+       {"tag:17", fieldParameters{tag: newInt(17)}},
+       {"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
+       {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, newInt64(42), newInt(17), 0, false}},
+       {"set", fieldParameters{set: true}},
+}
+
+func TestParseFieldParameters(t *testing.T) {
+       for i, test := range parseFieldParametersTestData {
+               f := parseFieldParameters(test.in)
+               if !reflect.DeepEqual(f, test.out) {
+                       t.Errorf("#%d: Bad result: %v (expected %v)", i, f, test.out)
+               }
+       }
+}
+
+type unmarshalTest struct {
+       in  []byte
+       out interface{}
+}
+
+type TestObjectIdentifierStruct struct {
+       OID ObjectIdentifier
+}
+
+type TestContextSpecificTags struct {
+       A int "tag:1"
+}
+
+type TestContextSpecificTags2 struct {
+       A int "explicit,tag:1"
+       B int
+}
+
+type TestElementsAfterString struct {
+       S    string
+       A, B int
+}
+
+var unmarshalTestData []unmarshalTest = []unmarshalTest{
+       {[]byte{0x02, 0x01, 0x42}, newInt(0x42)},
+       {[]byte{0x30, 0x08, 0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d}, &TestObjectIdentifierStruct{[]int{1, 2, 840, 113549}}},
+       {[]byte{0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0}, &BitString{[]byte{110, 93, 192}, 18}},
+       {[]byte{0x30, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &[]int{1, 2, 3}},
+       {[]byte{0x02, 0x01, 0x10}, newInt(16)},
+       {[]byte{0x13, 0x04, 't', 'e', 's', 't'}, newString("test")},
+       {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, newString("test")},
+       {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, &RawValue{0, 22, false, []byte("test"), []byte("\x16\x04test")}},
+       {[]byte{0x04, 0x04, 1, 2, 3, 4}, &RawValue{0, 4, false, []byte{1, 2, 3, 4}, []byte{4, 4, 1, 2, 3, 4}}},
+       {[]byte{0x30, 0x03, 0x81, 0x01, 0x01}, &TestContextSpecificTags{1}},
+       {[]byte{0x30, 0x08, 0xa1, 0x03, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02}, &TestContextSpecificTags2{1, 2}},
+       {[]byte{0x01, 0x01, 0x00}, newBool(false)},
+       {[]byte{0x01, 0x01, 0x01}, newBool(true)},
+       {[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}},
+}
+
+func TestUnmarshal(t *testing.T) {
+       for i, test := range unmarshalTestData {
+               pv := reflect.MakeZero(reflect.NewValue(test.out).Type())
+               zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
+               pv.(*reflect.PtrValue).PointTo(zv)
+               val := pv.Interface()
+               _, err := Unmarshal(test.in, val)
+               if err != nil {
+                       t.Errorf("Unmarshal failed at index %d %v", i, err)
+               }
+               if !reflect.DeepEqual(val, test.out) {
+                       t.Errorf("#%d:\nhave %#v\nwant %#v", i, val, test.out)
+               }
+       }
+}
+
+type Certificate struct {
+       TBSCertificate     TBSCertificate
+       SignatureAlgorithm AlgorithmIdentifier
+       SignatureValue     BitString
+}
+
+type TBSCertificate struct {
+       Version            int "optional,explicit,default:0,tag:0"
+       SerialNumber       RawValue
+       SignatureAlgorithm AlgorithmIdentifier
+       Issuer             RDNSequence
+       Validity           Validity
+       Subject            RDNSequence
+       PublicKey          PublicKeyInfo
+}
+
+type AlgorithmIdentifier struct {
+       Algorithm ObjectIdentifier
+}
+
+type RDNSequence []RelativeDistinguishedNameSET
+
+type RelativeDistinguishedNameSET []AttributeTypeAndValue
+
+type AttributeTypeAndValue struct {
+       Type  ObjectIdentifier
+       Value interface{}
+}
+
+type Validity struct {
+       NotBefore, NotAfter *time.Time
+}
+
+type PublicKeyInfo struct {
+       Algorithm AlgorithmIdentifier
+       PublicKey BitString
+}
+
+func TestCertificate(t *testing.T) {
+       // This is a minimal, self-signed certificate that should parse correctly.
+       var cert Certificate
+       if _, err := Unmarshal(derEncodedSelfSignedCertBytes, &cert); err != nil {
+               t.Errorf("Unmarshal failed: %v", err)
+       }
+       if !reflect.DeepEqual(cert, derEncodedSelfSignedCert) {
+               t.Errorf("Bad result:\ngot: %+v\nwant: %+v", cert, derEncodedSelfSignedCert)
+       }
+}
+
+func TestCertificateWithNUL(t *testing.T) {
+       // This is the paypal NUL-hack certificate. It should fail to parse because
+       // NUL isn't a permitted character in a PrintableString.
+
+       var cert Certificate
+       if _, err := Unmarshal(derEncodedPaypalNULCertBytes, &cert); err == nil {
+               t.Error("Unmarshal succeeded, should not have")
+       }
+}
+
+type rawStructTest struct {
+       Raw RawContent
+       A   int
+}
+
+func TestRawStructs(t *testing.T) {
+       var s rawStructTest
+       input := []byte{0x30, 0x03, 0x02, 0x01, 0x50}
+
+       rest, err := Unmarshal(input, &s)
+       if len(rest) != 0 {
+               t.Errorf("incomplete parse: %x", rest)
+               return
+       }
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       if s.A != 0x50 {
+               t.Errorf("bad value for A: got %d want %d", s.A, 0x50)
+       }
+       if bytes.Compare([]byte(s.Raw), input) != 0 {
+               t.Errorf("bad value for Raw: got %x want %x", s.Raw, input)
+       }
+}
+
+var derEncodedSelfSignedCert = Certificate{
+       TBSCertificate: TBSCertificate{
+               Version:            0,
+               SerialNumber:       RawValue{Class: 0, Tag: 2, IsCompound: false, Bytes: []uint8{0x0, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c, 0x98}, FullBytes: []byte{2, 9, 0x0, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c, 0x98}},
+               SignatureAlgorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}},
+               Issuer: RDNSequence{
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 7}, Value: "City"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 10}, Value: "Internet Widgits Pty Ltd"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
+               },
+               Validity: Validity{NotBefore: &time.Time{Year: 2009, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}, NotAfter: &time.Time{Year: 2010, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}},
+               Subject: RDNSequence{
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 7}, Value: "City"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 10}, Value: "Internet Widgits Pty Ltd"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
+                       RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
+               },
+               PublicKey: PublicKeyInfo{
+                       Algorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}},
+                       PublicKey: BitString{
+                               Bytes: []uint8{
+                                       0x30, 0x48, 0x2, 0x41, 0x0, 0xcd, 0xb7,
+                                       0x63, 0x9c, 0x32, 0x78, 0xf0, 0x6, 0xaa, 0x27, 0x7f, 0x6e, 0xaf, 0x42,
+                                       0x90, 0x2b, 0x59, 0x2d, 0x8c, 0xbc, 0xbe, 0x38, 0xa1, 0xc9, 0x2b, 0xa4,
+                                       0x69, 0x5a, 0x33, 0x1b, 0x1d, 0xea, 0xde, 0xad, 0xd8, 0xe9, 0xa5, 0xc2,
+                                       0x7e, 0x8c, 0x4c, 0x2f, 0xd0, 0xa8, 0x88, 0x96, 0x57, 0x72, 0x2a, 0x4f,
+                                       0x2a, 0xf7, 0x58, 0x9c, 0xf2, 0xc7, 0x70, 0x45, 0xdc, 0x8f, 0xde, 0xec,
+                                       0x35, 0x7d, 0x2, 0x3, 0x1, 0x0, 0x1,
+                               },
+                               BitLength: 592,
+                       },
+               },
+       },
+       SignatureAlgorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}},
+       SignatureValue: BitString{
+               Bytes: []uint8{
+                       0xa6, 0x7b, 0x6, 0xec, 0x5e, 0xce,
+                       0x92, 0x77, 0x2c, 0xa4, 0x13, 0xcb, 0xa3, 0xca, 0x12, 0x56, 0x8f, 0xdc, 0x6c,
+                       0x7b, 0x45, 0x11, 0xcd, 0x40, 0xa7, 0xf6, 0x59, 0x98, 0x4, 0x2, 0xdf, 0x2b,
+                       0x99, 0x8b, 0xb9, 0xa4, 0xa8, 0xcb, 0xeb, 0x34, 0xc0, 0xf0, 0xa7, 0x8c, 0xf8,
+                       0xd9, 0x1e, 0xde, 0x14, 0xa5, 0xed, 0x76, 0xbf, 0x11, 0x6f, 0xe3, 0x60, 0xaa,
+                       0xfa, 0x88, 0x21, 0x49, 0x4, 0x35,
+               },
+               BitLength: 512,
+       },
+}
+
+var derEncodedSelfSignedCertBytes = []byte{
+       0x30, 0x82, 0x02, 0x18, 0x30,
+       0x82, 0x01, 0xc2, 0x02, 0x09, 0x00, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c,
+       0x98, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+       0x05, 0x05, 0x00, 0x30, 0x81, 0x92, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+       0x04, 0x06, 0x13, 0x02, 0x58, 0x58, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+       0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+       0x65, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x04, 0x43,
+       0x69, 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+       0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+       0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31,
+       0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x66, 0x61, 0x6c,
+       0x73, 0x65, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+       0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+       0x01, 0x09, 0x01, 0x16, 0x11, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x40, 0x65, 0x78,
+       0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d,
+       0x30, 0x39, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x32, 0x35, 0x35, 0x33, 0x5a,
+       0x17, 0x0d, 0x31, 0x30, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x32, 0x35, 0x35,
+       0x33, 0x5a, 0x30, 0x81, 0x92, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+       0x06, 0x13, 0x02, 0x58, 0x58, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+       0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+       0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x04, 0x43, 0x69,
+       0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
+       0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+       0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x1a,
+       0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x66, 0x61, 0x6c, 0x73,
+       0x65, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+       0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+       0x09, 0x01, 0x16, 0x11, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x40, 0x65, 0x78, 0x61,
+       0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06,
+       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+       0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xcd, 0xb7, 0x63, 0x9c, 0x32, 0x78,
+       0xf0, 0x06, 0xaa, 0x27, 0x7f, 0x6e, 0xaf, 0x42, 0x90, 0x2b, 0x59, 0x2d, 0x8c,
+       0xbc, 0xbe, 0x38, 0xa1, 0xc9, 0x2b, 0xa4, 0x69, 0x5a, 0x33, 0x1b, 0x1d, 0xea,
+       0xde, 0xad, 0xd8, 0xe9, 0xa5, 0xc2, 0x7e, 0x8c, 0x4c, 0x2f, 0xd0, 0xa8, 0x88,
+       0x96, 0x57, 0x72, 0x2a, 0x4f, 0x2a, 0xf7, 0x58, 0x9c, 0xf2, 0xc7, 0x70, 0x45,
+       0xdc, 0x8f, 0xde, 0xec, 0x35, 0x7d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d,
+       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+       0x03, 0x41, 0x00, 0xa6, 0x7b, 0x06, 0xec, 0x5e, 0xce, 0x92, 0x77, 0x2c, 0xa4,
+       0x13, 0xcb, 0xa3, 0xca, 0x12, 0x56, 0x8f, 0xdc, 0x6c, 0x7b, 0x45, 0x11, 0xcd,
+       0x40, 0xa7, 0xf6, 0x59, 0x98, 0x04, 0x02, 0xdf, 0x2b, 0x99, 0x8b, 0xb9, 0xa4,
+       0xa8, 0xcb, 0xeb, 0x34, 0xc0, 0xf0, 0xa7, 0x8c, 0xf8, 0xd9, 0x1e, 0xde, 0x14,
+       0xa5, 0xed, 0x76, 0xbf, 0x11, 0x6f, 0xe3, 0x60, 0xaa, 0xfa, 0x88, 0x21, 0x49,
+       0x04, 0x35,
+}
+
+var derEncodedPaypalNULCertBytes = []byte{
+       0x30, 0x82, 0x06, 0x44, 0x30,
+       0x82, 0x05, 0xad, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x00, 0xf0, 0x9b,
+       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+       0x05, 0x00, 0x30, 0x82, 0x01, 0x12, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+       0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+       0x04, 0x08, 0x13, 0x09, 0x42, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x6f, 0x6e, 0x61,
+       0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x42, 0x61,
+       0x72, 0x63, 0x65, 0x6c, 0x6f, 0x6e, 0x61, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03,
+       0x55, 0x04, 0x0a, 0x13, 0x20, 0x49, 0x50, 0x53, 0x20, 0x43, 0x65, 0x72, 0x74,
+       0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
+       0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x73, 0x2e, 0x6c, 0x2e, 0x31, 0x2e,
+       0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x14, 0x25, 0x67, 0x65, 0x6e, 0x65,
+       0x72, 0x61, 0x6c, 0x40, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d,
+       0x20, 0x43, 0x2e, 0x49, 0x2e, 0x46, 0x2e, 0x20, 0x20, 0x42, 0x2d, 0x42, 0x36,
+       0x32, 0x32, 0x31, 0x30, 0x36, 0x39, 0x35, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03,
+       0x55, 0x04, 0x0b, 0x13, 0x25, 0x69, 0x70, 0x73, 0x43, 0x41, 0x20, 0x43, 0x4c,
+       0x41, 0x53, 0x45, 0x41, 0x31, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+       0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+       0x69, 0x74, 0x79, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+       0x25, 0x69, 0x70, 0x73, 0x43, 0x41, 0x20, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41,
+       0x31, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+       0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
+       0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
+       0x01, 0x16, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x40, 0x69, 0x70,
+       0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39,
+       0x30, 0x32, 0x32, 0x34, 0x32, 0x33, 0x30, 0x34, 0x31, 0x37, 0x5a, 0x17, 0x0d,
+       0x31, 0x31, 0x30, 0x32, 0x32, 0x34, 0x32, 0x33, 0x30, 0x34, 0x31, 0x37, 0x5a,
+       0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+       0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+       0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16,
+       0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0d, 0x53, 0x61, 0x6e, 0x20,
+       0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x31, 0x11, 0x30, 0x0f,
+       0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69,
+       0x74, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0b,
+       0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x55, 0x6e, 0x69, 0x74, 0x31, 0x2f,
+       0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x77, 0x77, 0x77, 0x2e,
+       0x70, 0x61, 0x79, 0x70, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x73, 0x73,
+       0x6c, 0x2e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
+       0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x63, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+       0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xd2, 0x69,
+       0xfa, 0x6f, 0x3a, 0x00, 0xb4, 0x21, 0x1b, 0xc8, 0xb1, 0x02, 0xd7, 0x3f, 0x19,
+       0xb2, 0xc4, 0x6d, 0xb4, 0x54, 0xf8, 0x8b, 0x8a, 0xcc, 0xdb, 0x72, 0xc2, 0x9e,
+       0x3c, 0x60, 0xb9, 0xc6, 0x91, 0x3d, 0x82, 0xb7, 0x7d, 0x99, 0xff, 0xd1, 0x29,
+       0x84, 0xc1, 0x73, 0x53, 0x9c, 0x82, 0xdd, 0xfc, 0x24, 0x8c, 0x77, 0xd5, 0x41,
+       0xf3, 0xe8, 0x1e, 0x42, 0xa1, 0xad, 0x2d, 0x9e, 0xff, 0x5b, 0x10, 0x26, 0xce,
+       0x9d, 0x57, 0x17, 0x73, 0x16, 0x23, 0x38, 0xc8, 0xd6, 0xf1, 0xba, 0xa3, 0x96,
+       0x5b, 0x16, 0x67, 0x4a, 0x4f, 0x73, 0x97, 0x3a, 0x4d, 0x14, 0xa4, 0xf4, 0xe2,
+       0x3f, 0x8b, 0x05, 0x83, 0x42, 0xd1, 0xd0, 0xdc, 0x2f, 0x7a, 0xe5, 0xb6, 0x10,
+       0xb2, 0x11, 0xc0, 0xdc, 0x21, 0x2a, 0x90, 0xff, 0xae, 0x97, 0x71, 0x5a, 0x49,
+       0x81, 0xac, 0x40, 0xf3, 0x3b, 0xb8, 0x59, 0xb2, 0x4f, 0x02, 0x03, 0x01, 0x00,
+       0x01, 0xa3, 0x82, 0x03, 0x21, 0x30, 0x82, 0x03, 0x1d, 0x30, 0x09, 0x06, 0x03,
+       0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x11, 0x06, 0x09, 0x60, 0x86,
+       0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x06, 0x40,
+       0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x03, 0xf8,
+       0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08,
+       0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x1d, 0x06, 0x03, 0x55,
+       0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x61, 0x8f, 0x61, 0x34, 0x43, 0x55, 0x14,
+       0x7f, 0x27, 0x09, 0xce, 0x4c, 0x8b, 0xea, 0x9b, 0x7b, 0x19, 0x25, 0xbc, 0x6e,
+       0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+       0x0e, 0x07, 0x60, 0xd4, 0x39, 0xc9, 0x1b, 0x5b, 0x5d, 0x90, 0x7b, 0x23, 0xc8,
+       0xd2, 0x34, 0x9d, 0x4a, 0x9a, 0x46, 0x39, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d,
+       0x11, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x1d, 0x12, 0x04,
+       0x15, 0x30, 0x13, 0x81, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x40,
+       0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x72, 0x06, 0x09,
+       0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d, 0x04, 0x65, 0x16, 0x63,
+       0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+       0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4e,
+       0x4f, 0x54, 0x20, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x45, 0x44, 0x2e,
+       0x20, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x20, 0x53, 0x65, 0x72, 0x76,
+       0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+       0x65, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x68,
+       0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70,
+       0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x2f, 0x06, 0x09, 0x60,
+       0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x02, 0x04, 0x22, 0x16, 0x20, 0x68,
+       0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70,
+       0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61,
+       0x32, 0x30, 0x30, 0x32, 0x2f, 0x30, 0x43, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+       0x86, 0xf8, 0x42, 0x01, 0x04, 0x04, 0x36, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70,
+       0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61,
+       0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30,
+       0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x43, 0x4c,
+       0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x46, 0x06, 0x09,
+       0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x03, 0x04, 0x39, 0x16, 0x37,
+       0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69,
+       0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63,
+       0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74,
+       0x69, 0x6f, 0x6e, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x68, 0x74,
+       0x6d, 0x6c, 0x3f, 0x30, 0x43, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8,
+       0x42, 0x01, 0x07, 0x04, 0x36, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
+       0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63,
+       0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f,
+       0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x6c, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41,
+       0x31, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x3f, 0x30, 0x41, 0x06, 0x09, 0x60, 0x86,
+       0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x08, 0x04, 0x34, 0x16, 0x32, 0x68, 0x74,
+       0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73,
+       0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32,
+       0x30, 0x30, 0x32, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x4c, 0x41,
+       0x53, 0x45, 0x41, 0x31, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x30, 0x81, 0x83, 0x06,
+       0x03, 0x55, 0x1d, 0x1f, 0x04, 0x7c, 0x30, 0x7a, 0x30, 0x39, 0xa0, 0x37, 0xa0,
+       0x35, 0x86, 0x33, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+       0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70,
+       0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61,
+       0x32, 0x30, 0x30, 0x32, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63,
+       0x72, 0x6c, 0x30, 0x3d, 0xa0, 0x3b, 0xa0, 0x39, 0x86, 0x37, 0x68, 0x74, 0x74,
+       0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x69,
+       0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63,
+       0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30,
+       0x30, 0x32, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63, 0x72, 0x6c,
+       0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
+       0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+       0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63,
+       0x73, 0x70, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+       0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x68, 0xee, 0x79, 0x97, 0x97, 0xdd, 0x3b,
+       0xef, 0x16, 0x6a, 0x06, 0xf2, 0x14, 0x9a, 0x6e, 0xcd, 0x9e, 0x12, 0xf7, 0xaa,
+       0x83, 0x10, 0xbd, 0xd1, 0x7c, 0x98, 0xfa, 0xc7, 0xae, 0xd4, 0x0e, 0x2c, 0x9e,
+       0x38, 0x05, 0x9d, 0x52, 0x60, 0xa9, 0x99, 0x0a, 0x81, 0xb4, 0x98, 0x90, 0x1d,
+       0xae, 0xbb, 0x4a, 0xd7, 0xb9, 0xdc, 0x88, 0x9e, 0x37, 0x78, 0x41, 0x5b, 0xf7,
+       0x82, 0xa5, 0xf2, 0xba, 0x41, 0x25, 0x5a, 0x90, 0x1a, 0x1e, 0x45, 0x38, 0xa1,
+       0x52, 0x58, 0x75, 0x94, 0x26, 0x44, 0xfb, 0x20, 0x07, 0xba, 0x44, 0xcc, 0xe5,
+       0x4a, 0x2d, 0x72, 0x3f, 0x98, 0x47, 0xf6, 0x26, 0xdc, 0x05, 0x46, 0x05, 0x07,
+       0x63, 0x21, 0xab, 0x46, 0x9b, 0x9c, 0x78, 0xd5, 0x54, 0x5b, 0x3d, 0x0c, 0x1e,
+       0xc8, 0x64, 0x8c, 0xb5, 0x50, 0x23, 0x82, 0x6f, 0xdb, 0xb8, 0x22, 0x1c, 0x43,
+       0x96, 0x07, 0xa8, 0xbb,
+}
diff --git a/libgo/go/asn1/common.go b/libgo/go/asn1/common.go
new file mode 100644 (file)
index 0000000..4a5eca1
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package asn1
+
+import (
+       "reflect"
+       "strconv"
+       "strings"
+)
+
+// ASN.1 objects have metadata preceeding them:
+//   the tag: the type of the object
+//   a flag denoting if this object is compound or not
+//   the class type: the namespace of the tag
+//   the length of the object, in bytes
+
+// Here are some standard tags and classes
+
+const (
+       tagBoolean         = 1
+       tagInteger         = 2
+       tagBitString       = 3
+       tagOctetString     = 4
+       tagOID             = 6
+       tagEnum            = 10
+       tagSequence        = 16
+       tagSet             = 17
+       tagPrintableString = 19
+       tagT61String       = 20
+       tagIA5String       = 22
+       tagUTCTime         = 23
+       tagGeneralizedTime = 24
+)
+
+const (
+       classUniversal       = 0
+       classApplication     = 1
+       classContextSpecific = 2
+       classPrivate         = 3
+)
+
+type tagAndLength struct {
+       class, tag, length int
+       isCompound         bool
+}
+
+// ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead
+// of" and "in addition to". When not specified, every primitive type has a
+// default tag in the UNIVERSAL class.
+//
+// For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1
+// doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT
+// CONTEXT-SPECIFIC 42], that means that the tag is replaced by another.
+//
+// On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an
+// /additional/ tag would wrap the default tag. This explicit tag will have the
+// compound flag set.
+//
+// (This is used in order to remove ambiguity with optional elements.)
+//
+// You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we
+// don't support that here. We support a single layer of EXPLICIT or IMPLICIT
+// tagging with tag strings on the fields of a structure.
+
+// fieldParameters is the parsed representation of tag string from a structure field.
+type fieldParameters struct {
+       optional     bool   // true iff the field is OPTIONAL
+       explicit     bool   // true iff and EXPLICIT tag is in use.
+       defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
+       tag          *int   // the EXPLICIT or IMPLICIT tag (maybe nil).
+       stringType   int    // the string tag to use when marshaling.
+       set          bool   // true iff this should be encoded as a SET
+
+       // Invariants:
+       //   if explicit is set, tag is non-nil.
+}
+
+// Given a tag string with the format specified in the package comment,
+// parseFieldParameters will parse it into a fieldParameters structure,
+// ignoring unknown parts of the string.
+func parseFieldParameters(str string) (ret fieldParameters) {
+       for _, part := range strings.Split(str, ",", -1) {
+               switch {
+               case part == "optional":
+                       ret.optional = true
+               case part == "explicit":
+                       ret.explicit = true
+                       if ret.tag == nil {
+                               ret.tag = new(int)
+                               *ret.tag = 0
+                       }
+               case part == "ia5":
+                       ret.stringType = tagIA5String
+               case part == "printable":
+                       ret.stringType = tagPrintableString
+               case strings.HasPrefix(part, "default:"):
+                       i, err := strconv.Atoi64(part[8:])
+                       if err == nil {
+                               ret.defaultValue = new(int64)
+                               *ret.defaultValue = i
+                       }
+               case strings.HasPrefix(part, "tag:"):
+                       i, err := strconv.Atoi(part[4:])
+                       if err == nil {
+                               ret.tag = new(int)
+                               *ret.tag = i
+                       }
+               case part == "set":
+                       ret.set = true
+               }
+       }
+       return
+}
+
+// Given a reflected Go type, getUniversalType returns the default tag number
+// and expected compound flag.
+func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
+       switch t {
+       case objectIdentifierType:
+               return tagOID, false, true
+       case bitStringType:
+               return tagBitString, false, true
+       case timeType:
+               return tagUTCTime, false, true
+       case enumeratedType:
+               return tagEnum, false, true
+       }
+       switch t := t.(type) {
+       case *reflect.BoolType:
+               return tagBoolean, false, true
+       case *reflect.IntType:
+               return tagInteger, false, true
+       case *reflect.StructType:
+               return tagSequence, true, true
+       case *reflect.SliceType:
+               if t.Elem().Kind() == reflect.Uint8 {
+                       return tagOctetString, false, true
+               }
+               if strings.HasSuffix(t.Name(), "SET") {
+                       return tagSet, true, true
+               }
+               return tagSequence, true, true
+       case *reflect.StringType:
+               return tagPrintableString, false, true
+       }
+       return 0, false, false
+}
diff --git a/libgo/go/asn1/marshal.go b/libgo/go/asn1/marshal.go
new file mode 100644 (file)
index 0000000..2454871
--- /dev/null
@@ -0,0 +1,482 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package asn1
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "os"
+       "reflect"
+       "time"
+)
+
+// A forkableWriter is an in-memory buffer that can be
+// 'forked' to create new forkableWriters that bracket the
+// original.  After
+//    pre, post := w.fork();
+// the overall sequence of bytes represented is logically w+pre+post.
+type forkableWriter struct {
+       *bytes.Buffer
+       pre, post *forkableWriter
+}
+
+func newForkableWriter() *forkableWriter {
+       return &forkableWriter{bytes.NewBuffer(nil), nil, nil}
+}
+
+func (f *forkableWriter) fork() (pre, post *forkableWriter) {
+       if f.pre != nil || f.post != nil {
+               panic("have already forked")
+       }
+       f.pre = newForkableWriter()
+       f.post = newForkableWriter()
+       return f.pre, f.post
+}
+
+func (f *forkableWriter) Len() (l int) {
+       l += f.Buffer.Len()
+       if f.pre != nil {
+               l += f.pre.Len()
+       }
+       if f.post != nil {
+               l += f.post.Len()
+       }
+       return
+}
+
+func (f *forkableWriter) writeTo(out io.Writer) (n int, err os.Error) {
+       n, err = out.Write(f.Bytes())
+       if err != nil {
+               return
+       }
+
+       var nn int
+
+       if f.pre != nil {
+               nn, err = f.pre.writeTo(out)
+               n += nn
+               if err != nil {
+                       return
+               }
+       }
+
+       if f.post != nil {
+               nn, err = f.post.writeTo(out)
+               n += nn
+       }
+       return
+}
+
+func marshalBase128Int(out *forkableWriter, n int64) (err os.Error) {
+       if n == 0 {
+               err = out.WriteByte(0)
+               return
+       }
+
+       l := 0
+       for i := n; i > 0; i >>= 7 {
+               l++
+       }
+
+       for i := l - 1; i >= 0; i-- {
+               o := byte(n >> uint(i*7))
+               o &= 0x7f
+               if i != 0 {
+                       o |= 0x80
+               }
+               err = out.WriteByte(o)
+               if err != nil {
+                       return
+               }
+       }
+
+       return nil
+}
+
+func marshalInt64(out *forkableWriter, i int64) (err os.Error) {
+       n := int64Length(i)
+
+       for ; n > 0; n-- {
+               err = out.WriteByte(byte(i >> uint((n-1)*8)))
+               if err != nil {
+                       return
+               }
+       }
+
+       return nil
+}
+
+func int64Length(i int64) (numBytes int) {
+       numBytes = 1
+
+       for i > 127 {
+               numBytes++
+               i >>= 8
+       }
+
+       for i < -128 {
+               numBytes++
+               i >>= 8
+       }
+
+       return
+}
+
+func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err os.Error) {
+       b := uint8(t.class) << 6
+       if t.isCompound {
+               b |= 0x20
+       }
+       if t.tag >= 31 {
+               b |= 0x1f
+               err = out.WriteByte(b)
+               if err != nil {
+                       return
+               }
+               err = marshalBase128Int(out, int64(t.tag))
+               if err != nil {
+                       return
+               }
+       } else {
+               b |= uint8(t.tag)
+               err = out.WriteByte(b)
+               if err != nil {
+                       return
+               }
+       }
+
+       if t.length >= 128 {
+               l := int64Length(int64(t.length))
+               err = out.WriteByte(0x80 | byte(l))
+               if err != nil {
+                       return
+               }
+               err = marshalInt64(out, int64(t.length))
+               if err != nil {
+                       return
+               }
+       } else {
+               err = out.WriteByte(byte(t.length))
+               if err != nil {
+                       return
+               }
+       }
+
+       return nil
+}
+
+func marshalBitString(out *forkableWriter, b BitString) (err os.Error) {
+       paddingBits := byte((8 - b.BitLength%8) % 8)
+       err = out.WriteByte(paddingBits)
+       if err != nil {
+               return
+       }
+       _, err = out.Write(b.Bytes)
+       return
+}
+
+func marshalObjectIdentifier(out *forkableWriter, oid []int) (err os.Error) {
+       if len(oid) < 2 || oid[0] > 6 || oid[1] >= 40 {
+               return StructuralError{"invalid object identifier"}
+       }
+
+       err = out.WriteByte(byte(oid[0]*40 + oid[1]))
+       if err != nil {
+               return
+       }
+       for i := 2; i < len(oid); i++ {
+               err = marshalBase128Int(out, int64(oid[i]))
+               if err != nil {
+                       return
+               }
+       }
+
+       return
+}
+
+func marshalPrintableString(out *forkableWriter, s string) (err os.Error) {
+       b := []byte(s)
+       for _, c := range b {
+               if !isPrintable(c) {
+                       return StructuralError{"PrintableString contains invalid character"}
+               }
+       }
+
+       _, err = out.Write(b)
+       return
+}
+
+func marshalIA5String(out *forkableWriter, s string) (err os.Error) {
+       b := []byte(s)
+       for _, c := range b {
+               if c > 127 {
+                       return StructuralError{"IA5String contains invalid character"}
+               }
+       }
+
+       _, err = out.Write(b)
+       return
+}
+
+func marshalTwoDigits(out *forkableWriter, v int) (err os.Error) {
+       err = out.WriteByte(byte('0' + (v/10)%10))
+       if err != nil {
+               return
+       }
+       return out.WriteByte(byte('0' + v%10))
+}
+
+func marshalUTCTime(out *forkableWriter, t *time.Time) (err os.Error) {
+       switch {
+       case 1950 <= t.Year && t.Year < 2000:
+               err = marshalTwoDigits(out, int(t.Year-1900))
+       case 2000 <= t.Year && t.Year < 2050:
+               err = marshalTwoDigits(out, int(t.Year-2000))
+       default:
+               return StructuralError{"Cannot represent time as UTCTime"}
+       }
+
+       if err != nil {
+               return
+       }
+
+       err = marshalTwoDigits(out, t.Month)
+       if err != nil {
+               return
+       }
+
+       err = marshalTwoDigits(out, t.Day)
+       if err != nil {
+               return
+       }
+
+       err = marshalTwoDigits(out, t.Hour)
+       if err != nil {
+               return
+       }
+
+       err = marshalTwoDigits(out, t.Minute)
+       if err != nil {
+               return
+       }
+
+       err = marshalTwoDigits(out, t.Second)
+       if err != nil {
+               return
+       }
+
+       switch {
+       case t.ZoneOffset/60 == 0:
+               err = out.WriteByte('Z')
+               return
+       case t.ZoneOffset > 0:
+               err = out.WriteByte('+')
+       case t.ZoneOffset < 0:
+               err = out.WriteByte('-')
+       }
+
+       if err != nil {
+               return
+       }
+
+       offsetMinutes := t.ZoneOffset / 60
+       if offsetMinutes < 0 {
+               offsetMinutes = -offsetMinutes
+       }
+
+       err = marshalTwoDigits(out, offsetMinutes/60)
+       if err != nil {
+               return
+       }
+
+       err = marshalTwoDigits(out, offsetMinutes%60)
+       return
+}
+
+func stripTagAndLength(in []byte) []byte {
+       _, offset, err := parseTagAndLength(in, 0)
+       if err != nil {
+               return in
+       }
+       return in[offset:]
+}
+
+func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err os.Error) {
+       switch value.Type() {
+       case timeType:
+               return marshalUTCTime(out, value.Interface().(*time.Time))
+       case bitStringType:
+               return marshalBitString(out, value.Interface().(BitString))
+       case objectIdentifierType:
+               return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
+       }
+
+       switch v := value.(type) {
+       case *reflect.BoolValue:
+               if v.Get() {
+                       return out.WriteByte(1)
+               } else {
+                       return out.WriteByte(0)
+               }
+       case *reflect.IntValue:
+               return marshalInt64(out, int64(v.Get()))
+       case *reflect.StructValue:
+               t := v.Type().(*reflect.StructType)
+
+               startingField := 0
+
+               // If the first element of the structure is a non-empty
+               // RawContents, then we don't bother serialising the rest.
+               if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
+                       s := v.Field(0).(*reflect.SliceValue)
+                       if s.Len() > 0 {
+                               bytes := make([]byte, s.Len())
+                               for i := 0; i < s.Len(); i++ {
+                                       bytes[i] = uint8(s.Elem(i).(*reflect.UintValue).Get())
+                               }
+                               /* The RawContents will contain the tag and
+                                * length fields but we'll also be writing
+                                * those outselves, so we strip them out of
+                                * bytes */
+                               _, err = out.Write(stripTagAndLength(bytes))
+                               return
+                       } else {
+                               startingField = 1
+                       }
+               }
+
+               for i := startingField; i < t.NumField(); i++ {
+                       var pre *forkableWriter
+                       pre, out = out.fork()
+                       err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag))
+                       if err != nil {
+                               return
+                       }
+               }
+               return
+       case *reflect.SliceValue:
+               sliceType := v.Type().(*reflect.SliceType)
+               if sliceType.Elem().Kind() == reflect.Uint8 {
+                       bytes := make([]byte, v.Len())
+                       for i := 0; i < v.Len(); i++ {
+                               bytes[i] = uint8(v.Elem(i).(*reflect.UintValue).Get())
+                       }
+                       _, err = out.Write(bytes)
+                       return
+               }
+
+               var params fieldParameters
+               for i := 0; i < v.Len(); i++ {
+                       var pre *forkableWriter
+                       pre, out = out.fork()
+                       err = marshalField(pre, v.Elem(i), params)
+                       if err != nil {
+                               return
+                       }
+               }
+               return
+       case *reflect.StringValue:
+               if params.stringType == tagIA5String {
+                       return marshalIA5String(out, v.Get())
+               } else {
+                       return marshalPrintableString(out, v.Get())
+               }
+               return
+       }
+
+       return StructuralError{"unknown Go type"}
+}
+
+func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err os.Error) {
+       // If the field is an interface{} then recurse into it.
+       if v, ok := v.(*reflect.InterfaceValue); ok && v.Type().(*reflect.InterfaceType).NumMethod() == 0 {
+               return marshalField(out, v.Elem(), params)
+       }
+
+       if v.Type() == rawValueType {
+               rv := v.Interface().(RawValue)
+               err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
+               if err != nil {
+                       return
+               }
+               _, err = out.Write(rv.Bytes)
+               return
+       }
+
+       if params.optional && reflect.DeepEqual(v.Interface(), reflect.MakeZero(v.Type()).Interface()) {
+               return
+       }
+
+       tag, isCompound, ok := getUniversalType(v.Type())
+       if !ok {
+               err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
+               return
+       }
+       class := classUniversal
+
+       if params.stringType != 0 {
+               if tag != tagPrintableString {
+                       return StructuralError{"Explicit string type given to non-string member"}
+               }
+               tag = params.stringType
+       }
+
+       if params.set {
+               if tag != tagSequence {
+                       return StructuralError{"Non sequence tagged as set"}
+               }
+               tag = tagSet
+       }
+
+       tags, body := out.fork()
+
+       err = marshalBody(body, v, params)
+       if err != nil {
+               return
+       }
+
+       bodyLen := body.Len()
+
+       var explicitTag *forkableWriter
+       if params.explicit {
+               explicitTag, tags = tags.fork()
+       }
+
+       if !params.explicit && params.tag != nil {
+               // implicit tag.
+               tag = *params.tag
+               class = classContextSpecific
+       }
+
+       err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
+       if err != nil {
+               return
+       }
+
+       if params.explicit {
+               err = marshalTagAndLength(explicitTag, tagAndLength{
+                       class:      classContextSpecific,
+                       tag:        *params.tag,
+                       length:     bodyLen + tags.Len(),
+                       isCompound: true,
+               })
+       }
+
+       return nil
+}
+
+// Marshal returns the ASN.1 encoding of val.
+func Marshal(val interface{}) ([]byte, os.Error) {
+       var out bytes.Buffer
+       v := reflect.NewValue(val)
+       f := newForkableWriter()
+       err := marshalField(f, v, fieldParameters{})
+       if err != nil {
+               return nil, err
+       }
+       _, err = f.writeTo(&out)
+       return out.Bytes(), nil
+}
diff --git a/libgo/go/asn1/marshal_test.go b/libgo/go/asn1/marshal_test.go
new file mode 100644 (file)
index 0000000..85eafc9
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package asn1
+
+import (
+       "bytes"
+       "encoding/hex"
+       "testing"
+       "time"
+)
+
+type intStruct struct {
+       A int
+}
+
+type twoIntStruct struct {
+       A int
+       B int
+}
+
+type nestedStruct struct {
+       A intStruct
+}
+
+type rawContentsStruct struct {
+       Raw RawContent
+       A   int
+}
+
+type implicitTagTest struct {
+       A int "implicit,tag:5"
+}
+
+type explicitTagTest struct {
+       A int "explicit,tag:5"
+}
+
+type ia5StringTest struct {
+       A string "ia5"
+}
+
+type printableStringTest struct {
+       A string "printable"
+}
+
+type testSET []int
+
+func setPST(t *time.Time) *time.Time {
+       t.ZoneOffset = -28800
+       return t
+}
+
+type marshalTest struct {
+       in  interface{}
+       out string // hex encoded
+}
+
+var marshalTests = []marshalTest{
+       {10, "02010a"},
+       {127, "02017f"},
+       {128, "02020080"},
+       {-128, "020180"},
+       {-129, "0202ff7f"},
+       {intStruct{64}, "3003020140"},
+       {twoIntStruct{64, 65}, "3006020140020141"},
+       {nestedStruct{intStruct{127}}, "3005300302017f"},
+       {[]byte{1, 2, 3}, "0403010203"},
+       {implicitTagTest{64}, "3003850140"},
+       {explicitTagTest{64}, "3005a503020140"},
+       {time.SecondsToUTC(0), "170d3730303130313030303030305a"},
+       {time.SecondsToUTC(1258325776), "170d3039313131353232353631365a"},
+       {setPST(time.SecondsToUTC(1258325776)), "17113039313131353232353631362d30383030"},
+       {BitString{[]byte{0x80}, 1}, "03020780"},
+       {BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
+       {ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
+       {ObjectIdentifier([]int{1, 2, 840, 133549, 1, 1, 5}), "06092a864888932d010105"},
+       {"test", "130474657374"},
+       {ia5StringTest{"test"}, "3006160474657374"},
+       {printableStringTest{"test"}, "3006130474657374"},
+       {printableStringTest{"test*"}, "30071305746573742a"},
+       {rawContentsStruct{nil, 64}, "3003020140"},
+       {rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"},
+       {RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"},
+       {testSET([]int{10}), "310302010a"},
+}
+
+func TestMarshal(t *testing.T) {
+       for i, test := range marshalTests {
+               data, err := Marshal(test.in)
+               if err != nil {
+                       t.Errorf("#%d failed: %s", i, err)
+               }
+               out, _ := hex.DecodeString(test.out)
+               if bytes.Compare(out, data) != 0 {
+                       t.Errorf("#%d got: %x want %x", i, data, out)
+               }
+       }
+}
diff --git a/libgo/go/big/arith.go b/libgo/go/big/arith.go
new file mode 100644 (file)
index 0000000..a4048d6
--- /dev/null
@@ -0,0 +1,259 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides Go implementations of elementary multi-precision
+// arithmetic operations on word vectors. Needed for platforms without
+// assembly implementations of these routines.
+
+package big
+
+// TODO(gri) Decide if Word needs to remain exported.
+
+type Word uintptr
+
+const (
+       // Compute the size _S of a Word in bytes.
+       _m    = ^Word(0)
+       _logS = _m>>8&1 + _m>>16&1 + _m>>32&1
+       _S    = 1 << _logS
+
+       _W = _S << 3 // word size in bits
+       _B = 1 << _W // digit base
+       _M = _B - 1  // digit mask
+
+       _W2 = _W / 2   // half word size in bits
+       _B2 = 1 << _W2 // half digit base
+       _M2 = _B2 - 1  // half digit mask
+)
+
+
+// ----------------------------------------------------------------------------
+// Elementary operations on words
+//
+// These operations are used by the vector operations below.
+
+// z1<<_W + z0 = x+y+c, with c == 0 or 1
+func addWW_g(x, y, c Word) (z1, z0 Word) {
+       yc := y + c
+       z0 = x + yc
+       if z0 < x || yc < y {
+               z1 = 1
+       }
+       return
+}
+
+
+// z1<<_W + z0 = x-y-c, with c == 0 or 1
+func subWW_g(x, y, c Word) (z1, z0 Word) {
+       yc := y + c
+       z0 = x - yc
+       if z0 > x || yc < y {
+               z1 = 1
+       }
+       return
+}
+
+
+// z1<<_W + z0 = x*y
+func mulWW(x, y Word) (z1, z0 Word) { return mulWW_g(x, y) }
+// Adapted from Warren, Hacker's Delight, p. 132.
+func mulWW_g(x, y Word) (z1, z0 Word) {
+       x0 := x & _M2
+       x1 := x >> _W2
+       y0 := y & _M2
+       y1 := y >> _W2
+       w0 := x0 * y0
+       t := x1*y0 + w0>>_W2
+       w1 := t & _M2
+       w2 := t >> _W2
+       w1 += x0 * y1
+       z1 = x1*y1 + w2 + w1>>_W2
+       z0 = x * y
+       return
+}
+
+
+// z1<<_W + z0 = x*y + c
+func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
+       z1, zz0 := mulWW(x, y)
+       if z0 = zz0 + c; z0 < zz0 {
+               z1++
+       }
+       return
+}
+
+
+// Length of x in bits.
+func bitLen(x Word) (n int) {
+       for ; x >= 0x100; x >>= 8 {
+               n += 8
+       }
+       for ; x > 0; x >>= 1 {
+               n++
+       }
+       return
+}
+
+
+// log2 computes the integer binary logarithm of x.
+// The result is the integer n for which 2^n <= x < 2^(n+1).
+// If x == 0, the result is -1.
+func log2(x Word) int {
+       return bitLen(x) - 1
+}
+
+
+// Number of leading zeros in x.
+func leadingZeros(x Word) uint {
+       return uint(_W - bitLen(x))
+}
+
+
+// q = (u1<<_W + u0 - r)/y
+func divWW(x1, x0, y Word) (q, r Word) { return divWW_g(x1, x0, y) }
+// Adapted from Warren, Hacker's Delight, p. 152.
+func divWW_g(u1, u0, v Word) (q, r Word) {
+       if u1 >= v {
+               return 1<<_W - 1, 1<<_W - 1
+       }
+
+       s := leadingZeros(v)
+       v <<= s
+
+       vn1 := v >> _W2
+       vn0 := v & _M2
+       un32 := u1<<s | u0>>(_W-s)
+       un10 := u0 << s
+       un1 := un10 >> _W2
+       un0 := un10 & _M2
+       q1 := un32 / vn1
+       rhat := un32 - q1*vn1
+
+again1:
+       if q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
+               q1--
+               rhat += vn1
+               if rhat < _B2 {
+                       goto again1
+               }
+       }
+
+       un21 := un32*_B2 + un1 - q1*v
+       q0 := un21 / vn1
+       rhat = un21 - q0*vn1
+
+again2:
+       if q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
+               q0--
+               rhat += vn1
+               if rhat < _B2 {
+                       goto again2
+               }
+       }
+
+       return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
+}
+
+
+func addVV(z, x, y []Word) (c Word) { return addVV_g(z, x, y) }
+func addVV_g(z, x, y []Word) (c Word) {
+       for i := range z {
+               c, z[i] = addWW_g(x[i], y[i], c)
+       }
+       return
+}
+
+
+func subVV(z, x, y []Word) (c Word) { return subVV_g(z, x, y) }
+func subVV_g(z, x, y []Word) (c Word) {
+       for i := range z {
+               c, z[i] = subWW_g(x[i], y[i], c)
+       }
+       return
+}
+
+
+func addVW(z, x []Word, y Word) (c Word) { return addVW_g(z, x, y) }
+func addVW_g(z, x []Word, y Word) (c Word) {
+       c = y
+       for i := range z {
+               c, z[i] = addWW_g(x[i], c, 0)
+       }
+       return
+}
+
+
+func subVW(z, x []Word, y Word) (c Word) { return subVW_g(z, x, y) }
+func subVW_g(z, x []Word, y Word) (c Word) {
+       c = y
+       for i := range z {
+               c, z[i] = subWW_g(x[i], c, 0)
+       }
+       return
+}
+
+
+func shlVW(z, x []Word, s Word) (c Word) { return shlVW_g(z, x, s) }
+func shlVW_g(z, x []Word, s Word) (c Word) {
+       if n := len(z); n > 0 {
+               ŝ := _W - s
+               w1 := x[n-1]
+               c = w1 >> ŝ
+               for i := n - 1; i > 0; i-- {
+                       w := w1
+                       w1 = x[i-1]
+                       z[i] = w<<s | w1>>ŝ
+               }
+               z[0] = w1 << s
+       }
+       return
+}
+
+
+func shrVW(z, x []Word, s Word) (c Word) { return shrVW_g(z, x, s) }
+func shrVW_g(z, x []Word, s Word) (c Word) {
+       if n := len(z); n > 0 {
+               ŝ := _W - s
+               w1 := x[0]
+               c = w1 << ŝ
+               for i := 0; i < n-1; i++ {
+                       w := w1
+                       w1 = x[i+1]
+                       z[i] = w>>s | w1<<ŝ
+               }
+               z[n-1] = w1 >> s
+       }
+       return
+}
+
+
+func mulAddVWW(z, x []Word, y, r Word) (c Word) { return mulAddVWW_g(z, x, y, r) }
+func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
+       c = r
+       for i := range z {
+               c, z[i] = mulAddWWW_g(x[i], y, c)
+       }
+       return
+}
+
+
+func addMulVVW(z, x []Word, y Word) (c Word) { return addMulVVW_g(z, x, y) }
+func addMulVVW_g(z, x []Word, y Word) (c Word) {
+       for i := range z {
+               z1, z0 := mulAddWWW_g(x[i], y, z[i])
+               c, z[i] = addWW_g(z0, c, 0)
+               c += z1
+       }
+       return
+}
+
+
+func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) { return divWVW_g(z, xn, x, y) }
+func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
+       r = xn
+       for i := len(z) - 1; i >= 0; i-- {
+               z[i], r = divWW_g(r, x[i], y)
+       }
+       return
+}
diff --git a/libgo/go/big/arith_decl.go b/libgo/go/big/arith_decl.go
new file mode 100644 (file)
index 0000000..c456d5f
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+// implemented in arith_$GOARCH.s
+func mulWW(x, y Word) (z1, z0 Word)
+func divWW(x1, x0, y Word) (q, r Word)
+func addVV(z, x, y []Word) (c Word)
+func subVV(z, x, y []Word) (c Word)
+func addVW(z, x []Word, y Word) (c Word)
+func subVW(z, x []Word, y Word) (c Word)
+func shlVW(z, x []Word, s Word) (c Word)
+func shrVW(z, x []Word, s Word) (c Word)
+func mulAddVWW(z, x []Word, y, r Word) (c Word)
+func addMulVVW(z, x []Word, y Word) (c Word)
+func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
diff --git a/libgo/go/big/arith_test.go b/libgo/go/big/arith_test.go
new file mode 100644 (file)
index 0000000..934b302
--- /dev/null
@@ -0,0 +1,342 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import "testing"
+
+
+type funWW func(x, y, c Word) (z1, z0 Word)
+type argWW struct {
+       x, y, c, z1, z0 Word
+}
+
+var sumWW = []argWW{
+       {0, 0, 0, 0, 0},
+       {0, 1, 0, 0, 1},
+       {0, 0, 1, 0, 1},
+       {0, 1, 1, 0, 2},
+       {12345, 67890, 0, 0, 80235},
+       {12345, 67890, 1, 0, 80236},
+       {_M, 1, 0, 1, 0},
+       {_M, 0, 1, 1, 0},
+       {_M, 1, 1, 1, 1},
+       {_M, _M, 0, 1, _M - 1},
+       {_M, _M, 1, 1, _M},
+}
+
+
+func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
+       z1, z0 := f(a.x, a.y, a.c)
+       if z1 != a.z1 || z0 != a.z0 {
+               t.Errorf("%s%+v\n\tgot z1:z0 = %#x:%#x; want %#x:%#x", msg, a, z1, z0, a.z1, a.z0)
+       }
+}
+
+
+func TestFunWW(t *testing.T) {
+       for _, a := range sumWW {
+               arg := a
+               testFunWW(t, "addWW_g", addWW_g, arg)
+
+               arg = argWW{a.y, a.x, a.c, a.z1, a.z0}
+               testFunWW(t, "addWW_g symmetric", addWW_g, arg)
+
+               arg = argWW{a.z0, a.x, a.c, a.z1, a.y}
+               testFunWW(t, "subWW_g", subWW_g, arg)
+
+               arg = argWW{a.z0, a.y, a.c, a.z1, a.x}
+               testFunWW(t, "subWW_g symmetric", subWW_g, arg)
+       }
+}
+
+
+type funVV func(z, x, y []Word) (c Word)
+type argVV struct {
+       z, x, y nat
+       c       Word
+}
+
+var sumVV = []argVV{
+       {},
+       {nat{0}, nat{0}, nat{0}, 0},
+       {nat{1}, nat{1}, nat{0}, 0},
+       {nat{0}, nat{_M}, nat{1}, 1},
+       {nat{80235}, nat{12345}, nat{67890}, 0},
+       {nat{_M - 1}, nat{_M}, nat{_M}, 1},
+       {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
+       {nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
+       {nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
+}
+
+
+func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
+       z := make(nat, len(a.z))
+       c := f(z, a.x, a.y)
+       for i, zi := range z {
+               if zi != a.z[i] {
+                       t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+                       break
+               }
+       }
+       if c != a.c {
+               t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+       }
+}
+
+
+func TestFunVV(t *testing.T) {
+       for _, a := range sumVV {
+               arg := a
+               testFunVV(t, "addVV_g", addVV_g, arg)
+               testFunVV(t, "addVV", addVV, arg)
+
+               arg = argVV{a.z, a.y, a.x, a.c}
+               testFunVV(t, "addVV_g symmetric", addVV_g, arg)
+               testFunVV(t, "addVV symmetric", addVV, arg)
+
+               arg = argVV{a.x, a.z, a.y, a.c}
+               testFunVV(t, "subVV_g", subVV_g, arg)
+               testFunVV(t, "subVV", subVV, arg)
+
+               arg = argVV{a.y, a.z, a.x, a.c}
+               testFunVV(t, "subVV_g symmetric", subVV_g, arg)
+               testFunVV(t, "subVV symmetric", subVV, arg)
+       }
+}
+
+
+type funVW func(z, x []Word, y Word) (c Word)
+type argVW struct {
+       z, x nat
+       y    Word
+       c    Word
+}
+
+var sumVW = []argVW{
+       {},
+       {nil, nil, 2, 2},
+       {nat{0}, nat{0}, 0, 0},
+       {nat{1}, nat{0}, 1, 0},
+       {nat{1}, nat{1}, 0, 0},
+       {nat{0}, nat{_M}, 1, 1},
+       {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
+}
+
+var prodVW = []argVW{
+       {},
+       {nat{0}, nat{0}, 0, 0},
+       {nat{0}, nat{_M}, 0, 0},
+       {nat{0}, nat{0}, _M, 0},
+       {nat{1}, nat{1}, 1, 0},
+       {nat{22793}, nat{991}, 23, 0},
+       {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
+       {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
+       {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
+       {nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
+       {nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
+       {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
+}
+
+var lshVW = []argVW{
+       {},
+       {nat{0}, nat{0}, 0, 0},
+       {nat{0}, nat{0}, 1, 0},
+       {nat{0}, nat{0}, 20, 0},
+
+       {nat{_M}, nat{_M}, 0, 0},
+       {nat{_M << 1 & _M}, nat{_M}, 1, 1},
+       {nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
+
+       {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+       {nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
+       {nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
+}
+
+var rshVW = []argVW{
+       {},
+       {nat{0}, nat{0}, 0, 0},
+       {nat{0}, nat{0}, 1, 0},
+       {nat{0}, nat{0}, 20, 0},
+
+       {nat{_M}, nat{_M}, 0, 0},
+       {nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
+       {nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
+
+       {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+       {nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
+       {nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
+}
+
+
+func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
+       z := make(nat, len(a.z))
+       c := f(z, a.x, a.y)
+       for i, zi := range z {
+               if zi != a.z[i] {
+                       t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+                       break
+               }
+       }
+       if c != a.c {
+               t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+       }
+}
+
+
+func TestFunVW(t *testing.T) {
+       for _, a := range sumVW {
+               arg := a
+               testFunVW(t, "addVW_g", addVW_g, arg)
+               testFunVW(t, "addVW", addVW, arg)
+
+               arg = argVW{a.x, a.z, a.y, a.c}
+               testFunVW(t, "subVW_g", subVW_g, arg)
+               testFunVW(t, "subVW", subVW, arg)
+       }
+
+       for _, a := range lshVW {
+               arg := a
+               testFunVW(t, "shlVW_g", shlVW_g, arg)
+               testFunVW(t, "shlVW", shlVW, arg)
+       }
+
+       for _, a := range rshVW {
+               arg := a
+               testFunVW(t, "shrVW_g", shrVW_g, arg)
+               testFunVW(t, "shrVW", shrVW, arg)
+       }
+}
+
+
+type funVWW func(z, x []Word, y, r Word) (c Word)
+type argVWW struct {
+       z, x nat
+       y, r Word
+       c    Word
+}
+
+var prodVWW = []argVWW{
+       {},
+       {nat{0}, nat{0}, 0, 0, 0},
+       {nat{991}, nat{0}, 0, 991, 0},
+       {nat{0}, nat{_M}, 0, 0, 0},
+       {nat{991}, nat{_M}, 0, 991, 0},
+       {nat{0}, nat{0}, _M, 0, 0},
+       {nat{991}, nat{0}, _M, 991, 0},
+       {nat{1}, nat{1}, 1, 0, 0},
+       {nat{992}, nat{1}, 1, 991, 0},
+       {nat{22793}, nat{991}, 23, 0, 0},
+       {nat{22800}, nat{991}, 23, 7, 0},
+       {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
+       {nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
+       {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
+       {nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
+       {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
+       {nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
+       {nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
+       {nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
+       {nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
+       {nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+       {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
+       {nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+}
+
+
+func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
+       z := make(nat, len(a.z))
+       c := f(z, a.x, a.y, a.r)
+       for i, zi := range z {
+               if zi != a.z[i] {
+                       t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+                       break
+               }
+       }
+       if c != a.c {
+               t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+       }
+}
+
+
+// TODO(gri) mulAddVWW and divWVW are symmetric operations but
+//           their signature is not symmetric. Try to unify.
+
+type funWVW func(z []Word, xn Word, x []Word, y Word) (r Word)
+type argWVW struct {
+       z  nat
+       xn Word
+       x  nat
+       y  Word
+       r  Word
+}
+
+func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
+       z := make(nat, len(a.z))
+       r := f(z, a.xn, a.x, a.y)
+       for i, zi := range z {
+               if zi != a.z[i] {
+                       t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+                       break
+               }
+       }
+       if r != a.r {
+               t.Errorf("%s%+v\n\tgot r = %#x; want %#x", msg, a, r, a.r)
+       }
+}
+
+
+func TestFunVWW(t *testing.T) {
+       for _, a := range prodVWW {
+               arg := a
+               testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg)
+               testFunVWW(t, "mulAddVWW", mulAddVWW, arg)
+
+               if a.y != 0 && a.r < a.y {
+                       arg := argWVW{a.x, a.c, a.z, a.y, a.r}
+                       testFunWVW(t, "divWVW_g", divWVW_g, arg)
+                       testFunWVW(t, "divWVW", divWVW, arg)
+               }
+       }
+}
+
+
+var mulWWTests = []struct {
+       x, y Word
+       q, r Word
+}{
+       {_M, _M, _M - 1, 1},
+       // 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
+}
+
+
+func TestMulWW(t *testing.T) {
+       for i, test := range mulWWTests {
+               q, r := mulWW_g(test.x, test.y)
+               if q != test.q || r != test.r {
+                       t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+               }
+       }
+}
+
+
+var mulAddWWWTests = []struct {
+       x, y, c Word
+       q, r    Word
+}{
+       // TODO(agl): These will only work on 64-bit platforms.
+       // {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
+       // {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
+       {_M, _M, 0, _M - 1, 1},
+       {_M, _M, _M, _M, 0},
+}
+
+
+func TestMulAddWWW(t *testing.T) {
+       for i, test := range mulAddWWWTests {
+               q, r := mulAddWWW_g(test.x, test.y, test.c)
+               if q != test.q || r != test.r {
+                       t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+               }
+       }
+}
diff --git a/libgo/go/big/calibrate_test.go b/libgo/go/big/calibrate_test.go
new file mode 100644 (file)
index 0000000..c6cd2e6
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file prints execution times for the Mul benchmark
+// given different Karatsuba thresholds. The result may be
+// used to manually fine-tune the threshold constant. The
+// results are somewhat fragile; use repeated runs to get
+// a clear picture.
+
+// Usage: gotest -calibrate
+
+package big
+
+import (
+       "flag"
+       "fmt"
+       "testing"
+       "time"
+)
+
+
+var calibrate = flag.Bool("calibrate", false, "run calibration test")
+
+
+// measure returns the time to run f
+func measure(f func()) int64 {
+       const N = 100
+       start := time.Nanoseconds()
+       for i := N; i > 0; i-- {
+               f()
+       }
+       stop := time.Nanoseconds()
+       return (stop - start) / N
+}
+
+
+func computeThresholds() {
+       fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
+       fmt.Printf("(run repeatedly for good results)\n")
+
+       // determine Tk, the work load execution time using basic multiplication
+       karatsubaThreshold = 1e9 // disable karatsuba
+       Tb := measure(benchmarkMulLoad)
+       fmt.Printf("Tb = %dns\n", Tb)
+
+       // thresholds
+       n := 8 // any lower values for the threshold lead to very slow multiplies
+       th1 := -1
+       th2 := -1
+
+       var deltaOld int64
+       for count := -1; count != 0; count-- {
+               // determine Tk, the work load execution time using Karatsuba multiplication
+               karatsubaThreshold = n // enable karatsuba
+               Tk := measure(benchmarkMulLoad)
+
+               // improvement over Tb
+               delta := (Tb - Tk) * 100 / Tb
+
+               fmt.Printf("n = %3d  Tk = %8dns  %4d%%", n, Tk, delta)
+
+               // determine break-even point
+               if Tk < Tb && th1 < 0 {
+                       th1 = n
+                       fmt.Print("  break-even point")
+               }
+
+               // determine diminishing return
+               if 0 < delta && delta < deltaOld && th2 < 0 {
+                       th2 = n
+                       fmt.Print("  diminishing return")
+               }
+               deltaOld = delta
+
+               fmt.Println()
+
+               // trigger counter
+               if th1 >= 0 && th2 >= 0 && count < 0 {
+                       count = 20 // this many extra measurements after we got both thresholds
+               }
+
+               n++
+       }
+}
+
+
+func TestCalibrate(t *testing.T) {
+       if *calibrate {
+               computeThresholds()
+       }
+}
diff --git a/libgo/go/big/hilbert_test.go b/libgo/go/big/hilbert_test.go
new file mode 100644 (file)
index 0000000..66a2121
--- /dev/null
@@ -0,0 +1,173 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A little test program and benchmark for rational arithmetics.
+// Computes a Hilbert matrix, its inverse, multiplies them
+// and verifies that the product is the identity matrix.
+
+package big
+
+import (
+       "fmt"
+       "testing"
+)
+
+
+type matrix struct {
+       n, m int
+       a    []*Rat
+}
+
+
+func (a *matrix) at(i, j int) *Rat {
+       if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+               panic("index out of range")
+       }
+       return a.a[i*a.m+j]
+}
+
+
+func (a *matrix) set(i, j int, x *Rat) {
+       if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+               panic("index out of range")
+       }
+       a.a[i*a.m+j] = x
+}
+
+
+func newMatrix(n, m int) *matrix {
+       if !(0 <= n && 0 <= m) {
+               panic("illegal matrix")
+       }
+       a := new(matrix)
+       a.n = n
+       a.m = m
+       a.a = make([]*Rat, n*m)
+       return a
+}
+
+
+func newUnit(n int) *matrix {
+       a := newMatrix(n, n)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       x := NewRat(0, 1)
+                       if i == j {
+                               x.SetInt64(1)
+                       }
+                       a.set(i, j, x)
+               }
+       }
+       return a
+}
+
+
+func newHilbert(n int) *matrix {
+       a := newMatrix(n, n)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       a.set(i, j, NewRat(1, int64(i+j+1)))
+               }
+       }
+       return a
+}
+
+
+func newInverseHilbert(n int) *matrix {
+       a := newMatrix(n, n)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       x1 := new(Rat).SetInt64(int64(i + j + 1))
+                       x2 := new(Rat).SetInt(new(Int).Binomial(int64(n+i), int64(n-j-1)))
+                       x3 := new(Rat).SetInt(new(Int).Binomial(int64(n+j), int64(n-i-1)))
+                       x4 := new(Rat).SetInt(new(Int).Binomial(int64(i+j), int64(i)))
+
+                       x1.Mul(x1, x2)
+                       x1.Mul(x1, x3)
+                       x1.Mul(x1, x4)
+                       x1.Mul(x1, x4)
+
+                       if (i+j)&1 != 0 {
+                               x1.Neg(x1)
+                       }
+
+                       a.set(i, j, x1)
+               }
+       }
+       return a
+}
+
+
+func (a *matrix) mul(b *matrix) *matrix {
+       if a.m != b.n {
+               panic("illegal matrix multiply")
+       }
+       c := newMatrix(a.n, b.m)
+       for i := 0; i < c.n; i++ {
+               for j := 0; j < c.m; j++ {
+                       x := NewRat(0, 1)
+                       for k := 0; k < a.m; k++ {
+                               x.Add(x, new(Rat).Mul(a.at(i, k), b.at(k, j)))
+                       }
+                       c.set(i, j, x)
+               }
+       }
+       return c
+}
+
+
+func (a *matrix) eql(b *matrix) bool {
+       if a.n != b.n || a.m != b.m {
+               return false
+       }
+       for i := 0; i < a.n; i++ {
+               for j := 0; j < a.m; j++ {
+                       if a.at(i, j).Cmp(b.at(i, j)) != 0 {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
+
+func (a *matrix) String() string {
+       s := ""
+       for i := 0; i < a.n; i++ {
+               for j := 0; j < a.m; j++ {
+                       s += fmt.Sprintf("\t%s", a.at(i, j))
+               }
+               s += "\n"
+       }
+       return s
+}
+
+
+func doHilbert(t *testing.T, n int) {
+       a := newHilbert(n)
+       b := newInverseHilbert(n)
+       I := newUnit(n)
+       ab := a.mul(b)
+       if !ab.eql(I) {
+               if t == nil {
+                       panic("Hilbert failed")
+               }
+               t.Errorf("a   = %s\n", a)
+               t.Errorf("b   = %s\n", b)
+               t.Errorf("a*b = %s\n", ab)
+               t.Errorf("I   = %s\n", I)
+       }
+}
+
+
+func TestHilbert(t *testing.T) {
+       doHilbert(t, 10)
+}
+
+
+func BenchmarkHilbert(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               doHilbert(nil, 10)
+       }
+}
diff --git a/libgo/go/big/int.go b/libgo/go/big/int.go
new file mode 100644 (file)
index 0000000..46e0087
--- /dev/null
@@ -0,0 +1,741 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements signed multi-precision integers.
+
+package big
+
+import (
+       "fmt"
+       "rand"
+)
+
+// An Int represents a signed multi-precision integer.
+// The zero value for an Int represents the value 0.
+type Int struct {
+       neg bool // sign
+       abs nat  // absolute value of the integer
+}
+
+
+var intOne = &Int{false, natOne}
+
+
+// Sign returns:
+//
+//     -1 if x <  0
+//      0 if x == 0
+//     +1 if x >  0
+//
+func (x *Int) Sign() int {
+       if len(x.abs) == 0 {
+               return 0
+       }
+       if x.neg {
+               return -1
+       }
+       return 1
+}
+
+
+// SetInt64 sets z to x and returns z.
+func (z *Int) SetInt64(x int64) *Int {
+       neg := false
+       if x < 0 {
+               neg = true
+               x = -x
+       }
+       z.abs = z.abs.setUint64(uint64(x))
+       z.neg = neg
+       return z
+}
+
+
+// NewInt allocates and returns a new Int set to x.
+func NewInt(x int64) *Int {
+       return new(Int).SetInt64(x)
+}
+
+
+// Set sets z to x and returns z.
+func (z *Int) Set(x *Int) *Int {
+       z.abs = z.abs.set(x.abs)
+       z.neg = x.neg
+       return z
+}
+
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Int) Abs(x *Int) *Int {
+       z.abs = z.abs.set(x.abs)
+       z.neg = false
+       return z
+}
+
+
+// Neg sets z to -x and returns z.
+func (z *Int) Neg(x *Int) *Int {
+       z.abs = z.abs.set(x.abs)
+       z.neg = len(z.abs) > 0 && !x.neg // 0 has no sign
+       return z
+}
+
+
+// Add sets z to the sum x+y and returns z.
+func (z *Int) Add(x, y *Int) *Int {
+       neg := x.neg
+       if x.neg == y.neg {
+               // x + y == x + y
+               // (-x) + (-y) == -(x + y)
+               z.abs = z.abs.add(x.abs, y.abs)
+       } else {
+               // x + (-y) == x - y == -(y - x)
+               // (-x) + y == y - x == -(x - y)
+               if x.abs.cmp(y.abs) >= 0 {
+                       z.abs = z.abs.sub(x.abs, y.abs)
+               } else {
+                       neg = !neg
+                       z.abs = z.abs.sub(y.abs, x.abs)
+               }
+       }
+       z.neg = len(z.abs) > 0 && neg // 0 has no sign
+       return z
+}
+
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Int) Sub(x, y *Int) *Int {
+       neg := x.neg
+       if x.neg != y.neg {
+               // x - (-y) == x + y
+               // (-x) - y == -(x + y)
+               z.abs = z.abs.add(x.abs, y.abs)
+       } else {
+               // x - y == x - y == -(y - x)
+               // (-x) - (-y) == y - x == -(x - y)
+               if x.abs.cmp(y.abs) >= 0 {
+                       z.abs = z.abs.sub(x.abs, y.abs)
+               } else {
+                       neg = !neg
+                       z.abs = z.abs.sub(y.abs, x.abs)
+               }
+       }
+       z.neg = len(z.abs) > 0 && neg // 0 has no sign
+       return z
+}
+
+
+// Mul sets z to the product x*y and returns z.
+func (z *Int) Mul(x, y *Int) *Int {
+       // x * y == x * y
+       // x * (-y) == -(x * y)
+       // (-x) * y == -(x * y)
+       // (-x) * (-y) == x * y
+       z.abs = z.abs.mul(x.abs, y.abs)
+       z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+       return z
+}
+
+
+// MulRange sets z to the product of all integers
+// in the range [a, b] inclusively and returns z.
+// If a > b (empty range), the result is 1.
+func (z *Int) MulRange(a, b int64) *Int {
+       switch {
+       case a > b:
+               return z.SetInt64(1) // empty range
+       case a <= 0 && b >= 0:
+               return z.SetInt64(0) // range includes 0
+       }
+       // a <= b && (b < 0 || a > 0)
+
+       neg := false
+       if a < 0 {
+               neg = (b-a)&1 == 0
+               a, b = -b, -a
+       }
+
+       z.abs = z.abs.mulRange(uint64(a), uint64(b))
+       z.neg = neg
+       return z
+}
+
+
+// Binomial sets z to the binomial coefficient of (n, k) and returns z.
+func (z *Int) Binomial(n, k int64) *Int {
+       var a, b Int
+       a.MulRange(n-k+1, n)
+       b.MulRange(1, k)
+       return z.Quo(&a, &b)
+}
+
+
+// Quo sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See QuoRem for more details.
+func (z *Int) Quo(x, y *Int) *Int {
+       z.abs, _ = z.abs.div(nil, x.abs, y.abs)
+       z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+       return z
+}
+
+
+// Rem sets z to the remainder x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See QuoRem for more details.
+func (z *Int) Rem(x, y *Int) *Int {
+       _, z.abs = nat(nil).div(z.abs, x.abs, y.abs)
+       z.neg = len(z.abs) > 0 && x.neg // 0 has no sign
+       return z
+}
+
+
+// QuoRem sets z to the quotient x/y and r to the remainder x%y
+// and returns the pair (z, r) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// QuoRem implements T-division and modulus (like Go):
+//
+//     q = x/y      with the result truncated to zero
+//     r = x - y*q
+//
+// (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
+//
+func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
+       z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs)
+       z.neg, r.neg = len(z.abs) > 0 && x.neg != y.neg, len(r.abs) > 0 && x.neg // 0 has no sign
+       return z, r
+}
+
+
+// Div sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See DivMod for more details.
+func (z *Int) Div(x, y *Int) *Int {
+       y_neg := y.neg // z may be an alias for y
+       var r Int
+       z.QuoRem(x, y, &r)
+       if r.neg {
+               if y_neg {
+                       z.Add(z, intOne)
+               } else {
+                       z.Sub(z, intOne)
+               }
+       }
+       return z
+}
+
+
+// Mod sets z to the modulus x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See DivMod for more details.
+func (z *Int) Mod(x, y *Int) *Int {
+       y0 := y // save y
+       if z == y || alias(z.abs, y.abs) {
+               y0 = new(Int).Set(y)
+       }
+       var q Int
+       q.QuoRem(x, y, z)
+       if z.neg {
+               if y0.neg {
+                       z.Sub(z, y0)
+               } else {
+                       z.Add(z, y0)
+               }
+       }
+       return z
+}
+
+
+// DivMod sets z to the quotient x div y and m to the modulus x mod y
+// and returns the pair (z, m) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// DivMod implements Euclidean division and modulus (unlike Go):
+//
+//     q = x div y  such that
+//     m = x - y*q  with 0 <= m < |q|
+//
+// (See Raymond T. Boute, ``The Euclidean definition of the functions
+// div and mod''. ACM Transactions on Programming Languages and
+// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
+// ACM press.)
+//
+func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
+       y0 := y // save y
+       if z == y || alias(z.abs, y.abs) {
+               y0 = new(Int).Set(y)
+       }
+       z.QuoRem(x, y, m)
+       if m.neg {
+               if y0.neg {
+                       z.Add(z, intOne)
+                       m.Sub(m, y0)
+               } else {
+                       z.Sub(z, intOne)
+                       m.Add(m, y0)
+               }
+       }
+       return z, m
+}
+
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y
+//   +1 if x >  y
+//
+func (x *Int) Cmp(y *Int) (r int) {
+       // x cmp y == x cmp y
+       // x cmp (-y) == x
+       // (-x) cmp y == y
+       // (-x) cmp (-y) == -(x cmp y)
+       switch {
+       case x.neg == y.neg:
+               r = x.abs.cmp(y.abs)
+               if x.neg {
+                       r = -r
+               }
+       case x.neg:
+               r = -1
+       default:
+               r = 1
+       }
+       return
+}
+
+
+func (x *Int) String() string {
+       s := ""
+       if x.neg {
+               s = "-"
+       }
+       return s + x.abs.string(10)
+}
+
+
+func fmtbase(ch int) int {
+       switch ch {
+       case 'b':
+               return 2
+       case 'o':
+               return 8
+       case 'd':
+               return 10
+       case 'x':
+               return 16
+       }
+       return 10
+}
+
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal) and
+// 'x' (hexadecimal).
+//
+func (x *Int) Format(s fmt.State, ch int) {
+       if x.neg {
+               fmt.Fprint(s, "-")
+       }
+       fmt.Fprint(s, x.abs.string(fmtbase(ch)))
+}
+
+
+// Int64 returns the int64 representation of z.
+// If z cannot be represented in an int64, the result is undefined.
+func (x *Int) Int64() int64 {
+       if len(x.abs) == 0 {
+               return 0
+       }
+       v := int64(x.abs[0])
+       if _W == 32 && len(x.abs) > 1 {
+               v |= int64(x.abs[1]) << 32
+       }
+       if x.neg {
+               v = -v
+       }
+       return v
+}
+
+
+// SetString sets z to the value of s, interpreted in the given base,
+// and returns z and a boolean indicating success. If SetString fails,
+// the value of z is undefined.
+//
+// If the base argument is 0, the string prefix determines the actual
+// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
+// ``0'' prefix selects base 8, and a ``0b'' or ``0B'' prefix selects
+// base 2. Otherwise the selected base is 10.
+//
+func (z *Int) SetString(s string, base int) (*Int, bool) {
+       if len(s) == 0 || base < 0 || base == 1 || 16 < base {
+               return z, false
+       }
+
+       neg := s[0] == '-'
+       if neg || s[0] == '+' {
+               s = s[1:]
+               if len(s) == 0 {
+                       return z, false
+               }
+       }
+
+       var scanned int
+       z.abs, _, scanned = z.abs.scan(s, base)
+       if scanned != len(s) {
+               return z, false
+       }
+       z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+       return z, true
+}
+
+
+// SetBytes interprets b as the bytes of a big-endian, unsigned integer and
+// sets z to that value.
+func (z *Int) SetBytes(b []byte) *Int {
+       const s = _S
+       z.abs = z.abs.make((len(b) + s - 1) / s)
+
+       j := 0
+       for len(b) >= s {
+               var w Word
+
+               for i := s; i > 0; i-- {
+                       w <<= 8
+                       w |= Word(b[len(b)-i])
+               }
+
+               z.abs[j] = w
+               j++
+               b = b[0 : len(b)-s]
+       }
+
+       if len(b) > 0 {
+               var w Word
+
+               for i := len(b); i > 0; i-- {
+                       w <<= 8
+                       w |= Word(b[len(b)-i])
+               }
+
+               z.abs[j] = w
+       }
+
+       z.abs = z.abs.norm()
+       z.neg = false
+       return z
+}
+
+
+// Bytes returns the absolute value of x as a big-endian byte array.
+func (z *Int) Bytes() []byte {
+       const s = _S
+       b := make([]byte, len(z.abs)*s)
+
+       for i, w := range z.abs {
+               wordBytes := b[(len(z.abs)-i-1)*s : (len(z.abs)-i)*s]
+               for j := s - 1; j >= 0; j-- {
+                       wordBytes[j] = byte(w)
+                       w >>= 8
+               }
+       }
+
+       i := 0
+       for i < len(b) && b[i] == 0 {
+               i++
+       }
+
+       return b[i:]
+}
+
+
+// BitLen returns the length of the absolute value of z in bits.
+// The bit length of 0 is 0.
+func (z *Int) BitLen() int {
+       return z.abs.bitLen()
+}
+
+
+// Exp sets z = x**y mod m. If m is nil, z = x**y.
+// See Knuth, volume 2, section 4.6.3.
+func (z *Int) Exp(x, y, m *Int) *Int {
+       if y.neg || len(y.abs) == 0 {
+               neg := x.neg
+               z.SetInt64(1)
+               z.neg = neg
+               return z
+       }
+
+       var mWords nat
+       if m != nil {
+               mWords = m.abs
+       }
+
+       z.abs = z.abs.expNN(x.abs, y.abs, mWords)
+       z.neg = len(z.abs) > 0 && x.neg && y.abs[0]&1 == 1 // 0 has no sign
+       return z
+}
+
+
+// GcdInt sets d to the greatest common divisor of a and b, which must be
+// positive numbers.
+// If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y.
+// If either a or b is not positive, GcdInt sets d = x = y = 0.
+func GcdInt(d, x, y, a, b *Int) {
+       if a.neg || b.neg {
+               d.SetInt64(0)
+               if x != nil {
+                       x.SetInt64(0)
+               }
+               if y != nil {
+                       y.SetInt64(0)
+               }
+               return
+       }
+
+       A := new(Int).Set(a)
+       B := new(Int).Set(b)
+
+       X := new(Int)
+       Y := new(Int).SetInt64(1)
+
+       lastX := new(Int).SetInt64(1)
+       lastY := new(Int)
+
+       q := new(Int)
+       temp := new(Int)
+
+       for len(B.abs) > 0 {
+               r := new(Int)
+               q, r = q.QuoRem(A, B, r)
+
+               A, B = B, r
+
+               temp.Set(X)
+               X.Mul(X, q)
+               X.neg = !X.neg
+               X.Add(X, lastX)
+               lastX.Set(temp)
+
+               temp.Set(Y)
+               Y.Mul(Y, q)
+               Y.neg = !Y.neg
+               Y.Add(Y, lastY)
+               lastY.Set(temp)
+       }
+
+       if x != nil {
+               *x = *lastX
+       }
+
+       if y != nil {
+               *y = *lastY
+       }
+
+       *d = *A
+}
+
+
+// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.
+// If it returns true, z is prime with probability 1 - 1/4^n.
+// If it returns false, z is not prime.
+func ProbablyPrime(z *Int, n int) bool {
+       return !z.neg && z.abs.probablyPrime(n)
+}
+
+
+// Rand sets z to a pseudo-random number in [0, n) and returns z. 
+func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
+       z.neg = false
+       if n.neg == true || len(n.abs) == 0 {
+               z.abs = nil
+               return z
+       }
+       z.abs = z.abs.random(rnd, n.abs, n.abs.bitLen())
+       return z
+}
+
+
+// ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where
+// p is a prime) and returns z.
+func (z *Int) ModInverse(g, p *Int) *Int {
+       var d Int
+       GcdInt(&d, z, nil, g, p)
+       // x and y are such that g*x + p*y = d. Since p is prime, d = 1. Taking
+       // that modulo p results in g*x = 1, therefore x is the inverse element.
+       if z.neg {
+               z.Add(z, p)
+       }
+       return z
+}
+
+
+// Lsh sets z = x << n and returns z.
+func (z *Int) Lsh(x *Int, n uint) *Int {
+       z.abs = z.abs.shl(x.abs, n)
+       z.neg = x.neg
+       return z
+}
+
+
+// Rsh sets z = x >> n and returns z.
+func (z *Int) Rsh(x *Int, n uint) *Int {
+       if x.neg {
+               // (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
+               t := z.abs.sub(x.abs, natOne) // no underflow because |x| > 0
+               t = t.shr(t, n)
+               z.abs = t.add(t, natOne)
+               z.neg = true // z cannot be zero if x is negative
+               return z
+       }
+
+       z.abs = z.abs.shr(x.abs, n)
+       z.neg = false
+       return z
+}
+
+
+// And sets z = x & y and returns z.
+func (z *Int) And(x, y *Int) *Int {
+       if x.neg == y.neg {
+               if x.neg {
+                       // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
+                       x1 := nat{}.sub(x.abs, natOne)
+                       y1 := nat{}.sub(y.abs, natOne)
+                       z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
+                       z.neg = true // z cannot be zero if x and y are negative
+                       return z
+               }
+
+               // x & y == x & y
+               z.abs = z.abs.and(x.abs, y.abs)
+               z.neg = false
+               return z
+       }
+
+       // x.neg != y.neg
+       if x.neg {
+               x, y = y, x // & is symmetric
+       }
+
+       // x & (-y) == x & ^(y-1) == x &^ (y-1)
+       y1 := nat{}.sub(y.abs, natOne)
+       z.abs = z.abs.andNot(x.abs, y1)
+       z.neg = false
+       return z
+}
+
+
+// AndNot sets z = x &^ y and returns z.
+func (z *Int) AndNot(x, y *Int) *Int {
+       if x.neg == y.neg {
+               if x.neg {
+                       // (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
+                       x1 := nat{}.sub(x.abs, natOne)
+                       y1 := nat{}.sub(y.abs, natOne)
+                       z.abs = z.abs.andNot(y1, x1)
+                       z.neg = false
+                       return z
+               }
+
+               // x &^ y == x &^ y
+               z.abs = z.abs.andNot(x.abs, y.abs)
+               z.neg = false
+               return z
+       }
+
+       if x.neg {
+               // (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
+               x1 := nat{}.sub(x.abs, natOne)
+               z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
+               z.neg = true // z cannot be zero if x is negative and y is positive
+               return z
+       }
+
+       // x &^ (-y) == x &^ ^(y-1) == x & (y-1)
+       y1 := nat{}.add(y.abs, natOne)
+       z.abs = z.abs.and(x.abs, y1)
+       z.neg = false
+       return z
+}
+
+
+// Or sets z = x | y and returns z.
+func (z *Int) Or(x, y *Int) *Int {
+       if x.neg == y.neg {
+               if x.neg {
+                       // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
+                       x1 := nat{}.sub(x.abs, natOne)
+                       y1 := nat{}.sub(y.abs, natOne)
+                       z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
+                       z.neg = true // z cannot be zero if x and y are negative
+                       return z
+               }
+
+               // x | y == x | y
+               z.abs = z.abs.or(x.abs, y.abs)
+               z.neg = false
+               return z
+       }
+
+       // x.neg != y.neg
+       if x.neg {
+               x, y = y, x // | is symmetric
+       }
+
+       // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
+       y1 := nat{}.sub(y.abs, natOne)
+       z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
+       z.neg = true // z cannot be zero if one of x or y is negative
+       return z
+}
+
+
+// Xor sets z = x ^ y and returns z.
+func (z *Int) Xor(x, y *Int) *Int {
+       if x.neg == y.neg {
+               if x.neg {
+                       // (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
+                       x1 := nat{}.sub(x.abs, natOne)
+                       y1 := nat{}.sub(y.abs, natOne)
+                       z.abs = z.abs.xor(x1, y1)
+                       z.neg = false
+                       return z
+               }
+
+               // x ^ y == x ^ y
+               z.abs = z.abs.xor(x.abs, y.abs)
+               z.neg = false
+               return z
+       }
+
+       // x.neg != y.neg
+       if x.neg {
+               x, y = y, x // ^ is symmetric
+       }
+
+       // x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
+       y1 := nat{}.sub(y.abs, natOne)
+       z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
+       z.neg = true // z cannot be zero if only one of x or y is negative
+       return z
+}
+
+
+// Not sets z = ^x and returns z.
+func (z *Int) Not(x *Int) *Int {
+       if x.neg {
+               // ^(-x) == ^(^(x-1)) == x-1
+               z.abs = z.abs.sub(x.abs, natOne)
+               z.neg = false
+               return z
+       }
+
+       // ^x == -x-1 == -(x+1)
+       z.abs = z.abs.add(x.abs, natOne)
+       z.neg = true // z cannot be zero if x is positive
+       return z
+}
diff --git a/libgo/go/big/int_test.go b/libgo/go/big/int_test.go
new file mode 100644 (file)
index 0000000..818d0c6
--- /dev/null
@@ -0,0 +1,1055 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+       "bytes"
+       "encoding/hex"
+       "fmt"
+       "testing"
+       "testing/quick"
+)
+
+
+func isNormalized(x *Int) bool {
+       if len(x.abs) == 0 {
+               return !x.neg
+       }
+       // len(x.abs) > 0
+       return x.abs[len(x.abs)-1] != 0
+}
+
+
+type funZZ func(z, x, y *Int) *Int
+type argZZ struct {
+       z, x, y *Int
+}
+
+
+var sumZZ = []argZZ{
+       {NewInt(0), NewInt(0), NewInt(0)},
+       {NewInt(1), NewInt(1), NewInt(0)},
+       {NewInt(1111111110), NewInt(123456789), NewInt(987654321)},
+       {NewInt(-1), NewInt(-1), NewInt(0)},
+       {NewInt(864197532), NewInt(-123456789), NewInt(987654321)},
+       {NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
+}
+
+
+var prodZZ = []argZZ{
+       {NewInt(0), NewInt(0), NewInt(0)},
+       {NewInt(0), NewInt(1), NewInt(0)},
+       {NewInt(1), NewInt(1), NewInt(1)},
+       {NewInt(-991 * 991), NewInt(991), NewInt(-991)},
+       // TODO(gri) add larger products
+}
+
+
+func TestSignZ(t *testing.T) {
+       var zero Int
+       for _, a := range sumZZ {
+               s := a.z.Sign()
+               e := a.z.Cmp(&zero)
+               if s != e {
+                       t.Errorf("got %d; want %d for z = %v", s, e, a.z)
+               }
+       }
+}
+
+
+func TestSetZ(t *testing.T) {
+       for _, a := range sumZZ {
+               var z Int
+               z.Set(a.z)
+               if !isNormalized(&z) {
+                       t.Errorf("%v is not normalized", z)
+               }
+               if (&z).Cmp(a.z) != 0 {
+                       t.Errorf("got z = %v; want %v", z, a.z)
+               }
+       }
+}
+
+
+func TestAbsZ(t *testing.T) {
+       var zero Int
+       for _, a := range sumZZ {
+               var z Int
+               z.Abs(a.z)
+               var e Int
+               e.Set(a.z)
+               if e.Cmp(&zero) < 0 {
+                       e.Sub(&zero, &e)
+               }
+               if z.Cmp(&e) != 0 {
+                       t.Errorf("got z = %v; want %v", z, e)
+               }
+       }
+}
+
+
+func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
+       var z Int
+       f(&z, a.x, a.y)
+       if !isNormalized(&z) {
+               t.Errorf("msg: %v is not normalized", z, msg)
+       }
+       if (&z).Cmp(a.z) != 0 {
+               t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
+       }
+}
+
+
+func TestSumZZ(t *testing.T) {
+       AddZZ := func(z, x, y *Int) *Int { return z.Add(x, y) }
+       SubZZ := func(z, x, y *Int) *Int { return z.Sub(x, y) }
+       for _, a := range sumZZ {
+               arg := a
+               testFunZZ(t, "AddZZ", AddZZ, arg)
+
+               arg = argZZ{a.z, a.y, a.x}
+               testFunZZ(t, "AddZZ symmetric", AddZZ, arg)
+
+               arg = argZZ{a.x, a.z, a.y}
+               testFunZZ(t, "SubZZ", SubZZ, arg)
+
+               arg = argZZ{a.y, a.z, a.x}
+               testFunZZ(t, "SubZZ symmetric", SubZZ, arg)
+       }
+}
+
+
+func TestProdZZ(t *testing.T) {
+       MulZZ := func(z, x, y *Int) *Int { return z.Mul(x, y) }
+       for _, a := range prodZZ {
+               arg := a
+               testFunZZ(t, "MulZZ", MulZZ, arg)
+
+               arg = argZZ{a.z, a.y, a.x}
+               testFunZZ(t, "MulZZ symmetric", MulZZ, arg)
+       }
+}
+
+
+// mulBytes returns x*y via grade school multiplication. Both inputs
+// and the result are assumed to be in big-endian representation (to
+// match the semantics of Int.Bytes and Int.SetBytes).
+func mulBytes(x, y []byte) []byte {
+       z := make([]byte, len(x)+len(y))
+
+       // multiply
+       k0 := len(z) - 1
+       for j := len(y) - 1; j >= 0; j-- {
+               d := int(y[j])
+               if d != 0 {
+                       k := k0
+                       carry := 0
+                       for i := len(x) - 1; i >= 0; i-- {
+                               t := int(z[k]) + int(x[i])*d + carry
+                               z[k], carry = byte(t), t>>8
+                               k--
+                       }
+                       z[k] = byte(carry)
+               }
+               k0--
+       }
+
+       // normalize (remove leading 0's)
+       i := 0
+       for i < len(z) && z[i] == 0 {
+               i++
+       }
+
+       return z[i:]
+}
+
+
+func checkMul(a, b []byte) bool {
+       var x, y, z1 Int
+       x.SetBytes(a)
+       y.SetBytes(b)
+       z1.Mul(&x, &y)
+
+       var z2 Int
+       z2.SetBytes(mulBytes(a, b))
+
+       return z1.Cmp(&z2) == 0
+}
+
+
+func TestMul(t *testing.T) {
+       if err := quick.Check(checkMul, nil); err != nil {
+               t.Error(err)
+       }
+}
+
+
+var mulRangesZ = []struct {
+       a, b int64
+       prod string
+}{
+       // entirely positive ranges are covered by mulRangesN
+       {-1, 1, "0"},
+       {-2, -1, "2"},
+       {-3, -2, "6"},
+       {-3, -1, "-6"},
+       {1, 3, "6"},
+       {-10, -10, "-10"},
+       {0, -1, "1"},                      // empty range
+       {-1, -100, "1"},                   // empty range
+       {-1, 1, "0"},                      // range includes 0
+       {-1e9, 0, "0"},                    // range includes 0
+       {-1e9, 1e9, "0"},                  // range includes 0
+       {-10, -1, "3628800"},              // 10!
+       {-20, -2, "-2432902008176640000"}, // -20!
+       {-99, -1,
+               "-933262154439441526816992388562667004907159682643816214685929" +
+                       "638952175999932299156089414639761565182862536979208272237582" +
+                       "511852109168640000000000000000000000", // -99!
+       },
+}
+
+
+func TestMulRangeZ(t *testing.T) {
+       var tmp Int
+       // test entirely positive ranges
+       for i, r := range mulRangesN {
+               prod := tmp.MulRange(int64(r.a), int64(r.b)).String()
+               if prod != r.prod {
+                       t.Errorf("#%da: got %s; want %s", i, prod, r.prod)
+               }
+       }
+       // test other ranges
+       for i, r := range mulRangesZ {
+               prod := tmp.MulRange(r.a, r.b).String()
+               if prod != r.prod {
+                       t.Errorf("#%db: got %s; want %s", i, prod, r.prod)
+               }
+       }
+}
+
+
+var stringTests = []struct {
+       in   string
+       out  string
+       base int
+       val  int64
+       ok   bool
+}{
+       {in: "", ok: false},
+       {in: "a", ok: false},
+       {in: "z", ok: false},
+       {in: "+", ok: false},
+       {in: "-", ok: false},
+       {in: "0b", ok: false},
+       {in: "0x", ok: false},
+       {in: "2", base: 2, ok: false},
+       {in: "0b2", base: 0, ok: false},
+       {in: "08", ok: false},
+       {in: "8", base: 8, ok: false},
+       {in: "0xg", base: 0, ok: false},
+       {in: "g", base: 16, ok: false},
+       {"0", "0", 0, 0, true},
+       {"0", "0", 10, 0, true},
+       {"0", "0", 16, 0, true},
+       {"+0", "0", 0, 0, true},
+       {"-0", "0", 0, 0, true},
+       {"10", "10", 0, 10, true},
+       {"10", "10", 10, 10, true},
+       {"10", "10", 16, 16, true},
+       {"-10", "-10", 16, -16, true},
+       {"+10", "10", 16, 16, true},
+       {"0x10", "16", 0, 16, true},
+       {in: "0x10", base: 16, ok: false},
+       {"-0x10", "-16", 0, -16, true},
+       {"+0x10", "16", 0, 16, true},
+       {"00", "0", 0, 0, true},
+       {"0", "0", 8, 0, true},
+       {"07", "7", 0, 7, true},
+       {"7", "7", 8, 7, true},
+       {"023", "19", 0, 19, true},
+       {"23", "23", 8, 19, true},
+       {"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+       {"0b0", "0", 0, 0, true},
+       {"-111", "-111", 2, -7, true},
+       {"-0b111", "-7", 0, -7, true},
+       {"0b1001010111", "599", 0, 0x257, true},
+       {"1001010111", "1001010111", 2, 0x257, true},
+}
+
+
+func format(base int) string {
+       switch base {
+       case 2:
+               return "%b"
+       case 8:
+               return "%o"
+       case 16:
+               return "%x"
+       }
+       return "%d"
+}
+
+
+func TestGetString(t *testing.T) {
+       z := new(Int)
+       for i, test := range stringTests {
+               if !test.ok {
+                       continue
+               }
+               z.SetInt64(test.val)
+
+               if test.base == 10 {
+                       s := z.String()
+                       if s != test.out {
+                               t.Errorf("#%da got %s; want %s", i, s, test.out)
+                       }
+               }
+
+               s := fmt.Sprintf(format(test.base), z)
+               if s != test.out {
+                       t.Errorf("#%db got %s; want %s", i, s, test.out)
+               }
+       }
+}
+
+
+func TestSetString(t *testing.T) {
+       tmp := new(Int)
+       for i, test := range stringTests {
+               n1, ok1 := new(Int).SetString(test.in, test.base)
+               n2, ok2 := tmp.SetString(test.in, test.base)
+               expected := NewInt(test.val)
+               if ok1 != test.ok || ok2 != test.ok {
+                       t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
+                       continue
+               }
+               if !ok1 || !ok2 {
+                       continue
+               }
+
+               if ok1 && !isNormalized(n1) {
+                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
+               }
+               if ok2 && !isNormalized(n2) {
+                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
+               }
+
+               if n1.Cmp(expected) != 0 {
+                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
+               }
+               if n2.Cmp(expected) != 0 {
+                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
+               }
+       }
+}
+
+
+// Examples from the Go Language Spec, section "Arithmetic operators"
+var divisionSignsTests = []struct {
+       x, y int64
+       q, r int64 // T-division
+       d, m int64 // Euclidian division
+}{
+       {5, 3, 1, 2, 1, 2},
+       {-5, 3, -1, -2, -2, 1},
+       {5, -3, -1, 2, -1, 2},
+       {-5, -3, 1, -2, 2, 1},
+       {1, 2, 0, 1, 0, 1},
+       {8, 4, 2, 0, 2, 0},
+}
+
+
+func TestDivisionSigns(t *testing.T) {
+       for i, test := range divisionSignsTests {
+               x := NewInt(test.x)
+               y := NewInt(test.y)
+               q := NewInt(test.q)
+               r := NewInt(test.r)
+               d := NewInt(test.d)
+               m := NewInt(test.m)
+
+               q1 := new(Int).Quo(x, y)
+               r1 := new(Int).Rem(x, y)
+               if !isNormalized(q1) {
+                       t.Errorf("#%d Quo: %v is not normalized", i, *q1)
+               }
+               if !isNormalized(r1) {
+                       t.Errorf("#%d Rem: %v is not normalized", i, *r1)
+               }
+               if q1.Cmp(q) != 0 || r1.Cmp(r) != 0 {
+                       t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q1, r1, q, r)
+               }
+
+               q2, r2 := new(Int).QuoRem(x, y, new(Int))
+               if !isNormalized(q2) {
+                       t.Errorf("#%d Quo: %v is not normalized", i, *q2)
+               }
+               if !isNormalized(r2) {
+                       t.Errorf("#%d Rem: %v is not normalized", i, *r2)
+               }
+               if q2.Cmp(q) != 0 || r2.Cmp(r) != 0 {
+                       t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q2, r2, q, r)
+               }
+
+               d1 := new(Int).Div(x, y)
+               m1 := new(Int).Mod(x, y)
+               if !isNormalized(d1) {
+                       t.Errorf("#%d Div: %v is not normalized", i, *d1)
+               }
+               if !isNormalized(m1) {
+                       t.Errorf("#%d Mod: %v is not normalized", i, *m1)
+               }
+               if d1.Cmp(d) != 0 || m1.Cmp(m) != 0 {
+                       t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d1, m1, d, m)
+               }
+
+               d2, m2 := new(Int).DivMod(x, y, new(Int))
+               if !isNormalized(d2) {
+                       t.Errorf("#%d Div: %v is not normalized", i, *d2)
+               }
+               if !isNormalized(m2) {
+                       t.Errorf("#%d Mod: %v is not normalized", i, *m2)
+               }
+               if d2.Cmp(d) != 0 || m2.Cmp(m) != 0 {
+                       t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d2, m2, d, m)
+               }
+       }
+}
+
+
+func checkSetBytes(b []byte) bool {
+       hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
+       hex2 := hex.EncodeToString(b)
+
+       for len(hex1) < len(hex2) {
+               hex1 = "0" + hex1
+       }
+
+       for len(hex1) > len(hex2) {
+               hex2 = "0" + hex2
+       }
+
+       return hex1 == hex2
+}
+
+
+func TestSetBytes(t *testing.T) {
+       if err := quick.Check(checkSetBytes, nil); err != nil {
+               t.Error(err)
+       }
+}
+
+
+func checkBytes(b []byte) bool {
+       b2 := new(Int).SetBytes(b).Bytes()
+       return bytes.Compare(b, b2) == 0
+}
+
+
+func TestBytes(t *testing.T) {
+       if err := quick.Check(checkSetBytes, nil); err != nil {
+               t.Error(err)
+       }
+}
+
+
+func checkQuo(x, y []byte) bool {
+       u := new(Int).SetBytes(x)
+       v := new(Int).SetBytes(y)
+
+       if len(v.abs) == 0 {
+               return true
+       }
+
+       r := new(Int)
+       q, r := new(Int).QuoRem(u, v, r)
+
+       if r.Cmp(v) >= 0 {
+               return false
+       }
+
+       uprime := new(Int).Set(q)
+       uprime.Mul(uprime, v)
+       uprime.Add(uprime, r)
+
+       return uprime.Cmp(u) == 0
+}
+
+
+var quoTests = []struct {
+       x, y string
+       q, r string
+}{
+       {
+               "476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
+               "9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
+               "50911",
+               "1",
+       },
+       {
+               "11510768301994997771168",
+               "1328165573307167369775",
+               "8",
+               "885443715537658812968",
+       },
+}
+
+
+func TestQuo(t *testing.T) {
+       if err := quick.Check(checkQuo, nil); err != nil {
+               t.Error(err)
+       }
+
+       for i, test := range quoTests {
+               x, _ := new(Int).SetString(test.x, 10)
+               y, _ := new(Int).SetString(test.y, 10)
+               expectedQ, _ := new(Int).SetString(test.q, 10)
+               expectedR, _ := new(Int).SetString(test.r, 10)
+
+               r := new(Int)
+               q, r := new(Int).QuoRem(x, y, r)
+
+               if q.Cmp(expectedQ) != 0 || r.Cmp(expectedR) != 0 {
+                       t.Errorf("#%d got (%s, %s) want (%s, %s)", i, q, r, expectedQ, expectedR)
+               }
+       }
+}
+
+
+func TestQuoStepD6(t *testing.T) {
+       // See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises
+       // a code path which only triggers 1 in 10^{-19} cases.
+
+       u := &Int{false, nat{0, 0, 1 + 1<<(_W-1), _M ^ (1 << (_W - 1))}}
+       v := &Int{false, nat{5, 2 + 1<<(_W-1), 1 << (_W - 1)}}
+
+       r := new(Int)
+       q, r := new(Int).QuoRem(u, v, r)
+       const expectedQ64 = "18446744073709551613"
+       const expectedR64 = "3138550867693340382088035895064302439801311770021610913807"
+       const expectedQ32 = "4294967293"
+       const expectedR32 = "39614081266355540837921718287"
+       if q.String() != expectedQ64 && q.String() != expectedQ32 ||
+               r.String() != expectedR64 && r.String() != expectedR32 {
+               t.Errorf("got (%s, %s) want (%s, %s) or (%s, %s)", q, r, expectedQ64, expectedR64, expectedQ32, expectedR32)
+       }
+}
+
+
+var bitLenTests = []struct {
+       in  string
+       out int
+}{
+       {"-1", 1},
+       {"0", 0},
+       {"1", 1},
+       {"2", 2},
+       {"4", 3},
+       {"0xabc", 12},
+       {"0x8000", 16},
+       {"0x80000000", 32},
+       {"0x800000000000", 48},
+       {"0x8000000000000000", 64},
+       {"0x80000000000000000000", 80},
+       {"-0x4000000000000000000000", 87},
+}
+
+
+func TestBitLen(t *testing.T) {
+       for i, test := range bitLenTests {
+               x, ok := new(Int).SetString(test.in, 0)
+               if !ok {
+                       t.Errorf("#%d test input invalid: %s", i, test.in)
+                       continue
+               }
+
+               if n := x.BitLen(); n != test.out {
+                       t.Errorf("#%d got %d want %d", i, n, test.out)
+               }
+       }
+}
+
+
+var expTests = []struct {
+       x, y, m string
+       out     string
+}{
+       {"5", "0", "", "1"},
+       {"-5", "0", "", "-1"},
+       {"5", "1", "", "5"},
+       {"-5", "1", "", "-5"},
+       {"-2", "3", "2", "0"},
+       {"5", "2", "", "25"},
+       {"1", "65537", "2", "1"},
+       {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+       {"0x8000000000000000", "2", "6719", "4944"},
+       {"0x8000000000000000", "3", "6719", "5447"},
+       {"0x8000000000000000", "1000", "6719", "1603"},
+       {"0x8000000000000000", "1000000", "6719", "3199"},
+       {
+               "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+               "298472983472983471903246121093472394872319615612417471234712061",
+               "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+               "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+       },
+}
+
+
+func TestExp(t *testing.T) {
+       for i, test := range expTests {
+               x, ok1 := new(Int).SetString(test.x, 0)
+               y, ok2 := new(Int).SetString(test.y, 0)
+               out, ok3 := new(Int).SetString(test.out, 0)
+
+               var ok4 bool
+               var m *Int
+
+               if len(test.m) == 0 {
+                       m, ok4 = nil, true
+               } else {
+                       m, ok4 = new(Int).SetString(test.m, 0)
+               }
+
+               if !ok1 || !ok2 || !ok3 || !ok4 {
+                       t.Errorf("#%d: error in input", i)
+                       continue
+               }
+
+               z := y.Exp(x, y, m)
+               if !isNormalized(z) {
+                       t.Errorf("#%d: %v is not normalized", i, *z)
+               }
+               if z.Cmp(out) != 0 {
+                       t.Errorf("#%d: got %s want %s", i, z, out)
+               }
+       }
+}
+
+
+func checkGcd(aBytes, bBytes []byte) bool {
+       a := new(Int).SetBytes(aBytes)
+       b := new(Int).SetBytes(bBytes)
+
+       x := new(Int)
+       y := new(Int)
+       d := new(Int)
+
+       GcdInt(d, x, y, a, b)
+       x.Mul(x, a)
+       y.Mul(y, b)
+       x.Add(x, y)
+
+       return x.Cmp(d) == 0
+}
+
+
+var gcdTests = []struct {
+       a, b    int64
+       d, x, y int64
+}{
+       {120, 23, 1, -9, 47},
+}
+
+
+func TestGcd(t *testing.T) {
+       for i, test := range gcdTests {
+               a := NewInt(test.a)
+               b := NewInt(test.b)
+
+               x := new(Int)
+               y := new(Int)
+               d := new(Int)
+
+               expectedX := NewInt(test.x)
+               expectedY := NewInt(test.y)
+               expectedD := NewInt(test.d)
+
+               GcdInt(d, x, y, a, b)
+
+               if expectedX.Cmp(x) != 0 ||
+                       expectedY.Cmp(y) != 0 ||
+                       expectedD.Cmp(d) != 0 {
+                       t.Errorf("#%d got (%s %s %s) want (%s %s %s)", i, x, y, d, expectedX, expectedY, expectedD)
+               }
+       }
+
+       quick.Check(checkGcd, nil)
+}
+
+
+var primes = []string{
+       "2",
+       "3",
+       "5",
+       "7",
+       "11",
+
+       "13756265695458089029",
+       "13496181268022124907",
+       "10953742525620032441",
+       "17908251027575790097",
+
+       // http://code.google.com/p/go/issues/detail?id=638
+       "18699199384836356663",
+
+       "98920366548084643601728869055592650835572950932266967461790948584315647051443",
+       "94560208308847015747498523884063394671606671904944666360068158221458669711639",
+
+       // http://primes.utm.edu/lists/small/small3.html
+       "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
+       "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
+       "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
+       "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+}
+
+
+var composites = []string{
+       "21284175091214687912771199898307297748211672914763848041968395774954376176754",
+       "6084766654921918907427900243509372380954290099172559290432744450051395395951",
+       "84594350493221918389213352992032324280367711247940675652888030554255915464401",
+       "82793403787388584738507275144194252681",
+}
+
+
+func TestProbablyPrime(t *testing.T) {
+       for i, s := range primes {
+               p, _ := new(Int).SetString(s, 10)
+               if !ProbablyPrime(p, 20) {
+                       t.Errorf("#%d prime found to be non-prime (%s)", i, s)
+               }
+       }
+
+       for i, s := range composites {
+               c, _ := new(Int).SetString(s, 10)
+               if ProbablyPrime(c, 20) {
+                       t.Errorf("#%d composite found to be prime (%s)", i, s)
+               }
+       }
+}
+
+
+type intShiftTest struct {
+       in    string
+       shift uint
+       out   string
+}
+
+
+var rshTests = []intShiftTest{
+       {"0", 0, "0"},
+       {"-0", 0, "0"},
+       {"0", 1, "0"},
+       {"0", 2, "0"},
+       {"1", 0, "1"},
+       {"1", 1, "0"},
+       {"1", 2, "0"},
+       {"2", 0, "2"},
+       {"2", 1, "1"},
+       {"-1", 0, "-1"},
+       {"-1", 1, "-1"},
+       {"-1", 10, "-1"},
+       {"-100", 2, "-25"},
+       {"-100", 3, "-13"},
+       {"-100", 100, "-1"},
+       {"4294967296", 0, "4294967296"},
+       {"4294967296", 1, "2147483648"},
+       {"4294967296", 2, "1073741824"},
+       {"18446744073709551616", 0, "18446744073709551616"},
+       {"18446744073709551616", 1, "9223372036854775808"},
+       {"18446744073709551616", 2, "4611686018427387904"},
+       {"18446744073709551616", 64, "1"},
+       {"340282366920938463463374607431768211456", 64, "18446744073709551616"},
+       {"340282366920938463463374607431768211456", 128, "1"},
+}
+
+
+func TestRsh(t *testing.T) {
+       for i, test := range rshTests {
+               in, _ := new(Int).SetString(test.in, 10)
+               expected, _ := new(Int).SetString(test.out, 10)
+               out := new(Int).Rsh(in, test.shift)
+
+               if !isNormalized(out) {
+                       t.Errorf("#%d: %v is not normalized", i, *out)
+               }
+               if out.Cmp(expected) != 0 {
+                       t.Errorf("#%d: got %s want %s", i, out, expected)
+               }
+       }
+}
+
+
+func TestRshSelf(t *testing.T) {
+       for i, test := range rshTests {
+               z, _ := new(Int).SetString(test.in, 10)
+               expected, _ := new(Int).SetString(test.out, 10)
+               z.Rsh(z, test.shift)
+
+               if !isNormalized(z) {
+                       t.Errorf("#%d: %v is not normalized", i, *z)
+               }
+               if z.Cmp(expected) != 0 {
+                       t.Errorf("#%d: got %s want %s", i, z, expected)
+               }
+       }
+}
+
+
+var lshTests = []intShiftTest{
+       {"0", 0, "0"},
+       {"0", 1, "0"},
+       {"0", 2, "0"},
+       {"1", 0, "1"},
+       {"1", 1, "2"},
+       {"1", 2, "4"},
+       {"2", 0, "2"},
+       {"2", 1, "4"},
+       {"2", 2, "8"},
+       {"-87", 1, "-174"},
+       {"4294967296", 0, "4294967296"},
+       {"4294967296", 1, "8589934592"},
+       {"4294967296", 2, "17179869184"},
+       {"18446744073709551616", 0, "18446744073709551616"},
+       {"9223372036854775808", 1, "18446744073709551616"},
+       {"4611686018427387904", 2, "18446744073709551616"},
+       {"1", 64, "18446744073709551616"},
+       {"18446744073709551616", 64, "340282366920938463463374607431768211456"},
+       {"1", 128, "340282366920938463463374607431768211456"},
+}
+
+
+func TestLsh(t *testing.T) {
+       for i, test := range lshTests {
+               in, _ := new(Int).SetString(test.in, 10)
+               expected, _ := new(Int).SetString(test.out, 10)
+               out := new(Int).Lsh(in, test.shift)
+
+               if !isNormalized(out) {
+                       t.Errorf("#%d: %v is not normalized", i, *out)
+               }
+               if out.Cmp(expected) != 0 {
+                       t.Errorf("#%d: got %s want %s", i, out, expected)
+               }
+       }
+}
+
+
+func TestLshSelf(t *testing.T) {
+       for i, test := range lshTests {
+               z, _ := new(Int).SetString(test.in, 10)
+               expected, _ := new(Int).SetString(test.out, 10)
+               z.Lsh(z, test.shift)
+
+               if !isNormalized(z) {
+                       t.Errorf("#%d: %v is not normalized", i, *z)
+               }
+               if z.Cmp(expected) != 0 {
+                       t.Errorf("#%d: got %s want %s", i, z, expected)
+               }
+       }
+}
+
+
+func TestLshRsh(t *testing.T) {
+       for i, test := range rshTests {
+               in, _ := new(Int).SetString(test.in, 10)
+               out := new(Int).Lsh(in, test.shift)
+               out = out.Rsh(out, test.shift)
+
+               if !isNormalized(out) {
+                       t.Errorf("#%d: %v is not normalized", i, *out)
+               }
+               if in.Cmp(out) != 0 {
+                       t.Errorf("#%d: got %s want %s", i, out, in)
+               }
+       }
+       for i, test := range lshTests {
+               in, _ := new(Int).SetString(test.in, 10)
+               out := new(Int).Lsh(in, test.shift)
+               out.Rsh(out, test.shift)
+
+               if !isNormalized(out) {
+                       t.Errorf("#%d: %v is not normalized", i, *out)
+               }
+               if in.Cmp(out) != 0 {
+                       t.Errorf("#%d: got %s want %s", i, out, in)
+               }
+       }
+}
+
+
+var int64Tests = []int64{
+       0,
+       1,
+       -1,
+       4294967295,
+       -4294967295,
+       4294967296,
+       -4294967296,
+       9223372036854775807,
+       -9223372036854775807,
+       -9223372036854775808,
+}
+
+
+func TestInt64(t *testing.T) {
+       for i, testVal := range int64Tests {
+               in := NewInt(testVal)
+               out := in.Int64()
+
+               if out != testVal {
+                       t.Errorf("#%d got %d want %d", i, out, testVal)
+               }
+       }
+}
+
+
+var bitwiseTests = []struct {
+       x, y                 string
+       and, or, xor, andNot string
+}{
+       {"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
+       {"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
+       {"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
+       {"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
+       {"-0xaf", "-0x50", "-0xf0", "-0x0f", "0xe1", "0x41"},
+       {"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
+       {"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
+       {"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
+       {"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
+       {"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
+       {"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
+       {"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
+       {"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
+       {
+               "0x1000009dc6e3d9822cba04129bcbe3401",
+               "0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+               "0x1000001186210100001000009048c2001",
+               "0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+               "0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+               "0x8c40c2d8822caa04120b8321400",
+       },
+       {
+               "0x1000009dc6e3d9822cba04129bcbe3401",
+               "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+               "0x8c40c2d8822caa04120b8321401",
+               "-0xb9bd7d543685789d57ca918e82229142459020483cd2014001fd",
+               "-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe",
+               "0x1000001186210100001000009048c2000",
+       },
+       {
+               "-0x1000009dc6e3d9822cba04129bcbe3401",
+               "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+               "-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+               "-0x1000001186210100001000009048c2001",
+               "0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+               "0xb9bd7d543685789d57ca918e82229142459020483cd2014001fc",
+       },
+}
+
+
+type bitFun func(z, x, y *Int) *Int
+
+func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+       expected := new(Int)
+       expected.SetString(exp, 0)
+
+       out := f(new(Int), x, y)
+       if out.Cmp(expected) != 0 {
+               t.Errorf("%s: got %s want %s", msg, out, expected)
+       }
+}
+
+
+func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+       self := new(Int)
+       self.Set(x)
+       expected := new(Int)
+       expected.SetString(exp, 0)
+
+       self = f(self, self, y)
+       if self.Cmp(expected) != 0 {
+               t.Errorf("%s: got %s want %s", msg, self, expected)
+       }
+}
+
+
+func TestBitwise(t *testing.T) {
+       x := new(Int)
+       y := new(Int)
+       for _, test := range bitwiseTests {
+               x.SetString(test.x, 0)
+               y.SetString(test.y, 0)
+
+               testBitFun(t, "and", (*Int).And, x, y, test.and)
+               testBitFunSelf(t, "and", (*Int).And, x, y, test.and)
+               testBitFun(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+               testBitFunSelf(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+               testBitFun(t, "or", (*Int).Or, x, y, test.or)
+               testBitFunSelf(t, "or", (*Int).Or, x, y, test.or)
+               testBitFun(t, "xor", (*Int).Xor, x, y, test.xor)
+               testBitFunSelf(t, "xor", (*Int).Xor, x, y, test.xor)
+       }
+}
+
+
+var notTests = []struct {
+       in  string
+       out string
+}{
+       {"0", "-1"},
+       {"1", "-2"},
+       {"7", "-8"},
+       {"0", "-1"},
+       {"-81910", "81909"},
+       {
+               "298472983472983471903246121093472394872319615612417471234712061",
+               "-298472983472983471903246121093472394872319615612417471234712062",
+       },
+}
+
+func TestNot(t *testing.T) {
+       in := new(Int)
+       out := new(Int)
+       expected := new(Int)
+       for i, test := range notTests {
+               in.SetString(test.in, 10)
+               expected.SetString(test.out, 10)
+               out = out.Not(in)
+               if out.Cmp(expected) != 0 {
+                       t.Errorf("#%d: got %s want %s", i, out, expected)
+               }
+               out = out.Not(out)
+               if out.Cmp(in) != 0 {
+                       t.Errorf("#%d: got %s want %s", i, out, in)
+               }
+       }
+}
+
+
+var modInverseTests = []struct {
+       element string
+       prime   string
+}{
+       {"1", "7"},
+       {"1", "13"},
+       {"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
+}
+
+func TestModInverse(t *testing.T) {
+       var element, prime Int
+       one := NewInt(1)
+       for i, test := range modInverseTests {
+               (&element).SetString(test.element, 10)
+               (&prime).SetString(test.prime, 10)
+               inverse := new(Int).ModInverse(&element, &prime)
+               inverse.Mul(inverse, &element)
+               inverse.Mod(inverse, &prime)
+               if inverse.Cmp(one) != 0 {
+                       t.Errorf("#%d: failed (e·e^(-1)=%s)", i, inverse)
+               }
+       }
+}
diff --git a/libgo/go/big/nat.go b/libgo/go/big/nat.go
new file mode 100644 (file)
index 0000000..a308f69
--- /dev/null
@@ -0,0 +1,1067 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains operations on unsigned multi-precision integers.
+// These are the building blocks for the operations on signed integers
+// and rationals.
+
+// This package implements multi-precision arithmetic (big numbers).
+// The following numeric types are supported:
+//
+//     - Int   signed integers
+//     - Rat   rational numbers
+//
+// All methods on Int take the result as the receiver; if it is one
+// of the operands it may be overwritten (and its memory reused).
+// To enable chaining of operations, the result is also returned.
+//
+package big
+
+import "rand"
+
+// An unsigned integer x of the form
+//
+//   x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
+//
+// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
+// with the digits x[i] as the slice elements.
+//
+// A number is normalized if the slice contains no leading 0 digits.
+// During arithmetic operations, denormalized values may occur but are
+// always normalized before returning the final result. The normalized
+// representation of 0 is the empty or nil slice (length = 0).
+
+type nat []Word
+
+var (
+       natOne = nat{1}
+       natTwo = nat{2}
+       natTen = nat{10}
+)
+
+
+func (z nat) clear() {
+       for i := range z {
+               z[i] = 0
+       }
+}
+
+
+func (z nat) norm() nat {
+       i := len(z)
+       for i > 0 && z[i-1] == 0 {
+               i--
+       }
+       return z[0:i]
+}
+
+
+func (z nat) make(n int) nat {
+       if n <= cap(z) {
+               return z[0:n] // reuse z
+       }
+       // Choosing a good value for e has significant performance impact
+       // because it increases the chance that a value can be reused.
+       const e = 4 // extra capacity
+       return make(nat, n, n+e)
+}
+
+
+func (z nat) setWord(x Word) nat {
+       if x == 0 {
+               return z.make(0)
+       }
+       z = z.make(1)
+       z[0] = x
+       return z
+}
+
+
+func (z nat) setUint64(x uint64) nat {
+       // single-digit values
+       if w := Word(x); uint64(w) == x {
+               return z.setWord(w)
+       }
+
+       // compute number of words n required to represent x
+       n := 0
+       for t := x; t > 0; t >>= _W {
+               n++
+       }
+
+       // split x into n words
+       z = z.make(n)
+       for i := range z {
+               z[i] = Word(x & _M)
+               x >>= _W
+       }
+
+       return z
+}
+
+
+func (z nat) set(x nat) nat {
+       z = z.make(len(x))
+       copy(z, x)
+       return z
+}
+
+
+func (z nat) add(x, y nat) nat {
+       m := len(x)
+       n := len(y)
+
+       switch {
+       case m < n:
+               return z.add(y, x)
+       case m == 0:
+               // n == 0 because m >= n; result is 0
+               return z.make(0)
+       case n == 0:
+               // result is x
+               return z.set(x)
+       }
+       // m > 0
+
+       z = z.make(m + 1)
+       c := addVV(z[0:n], x, y)
+       if m > n {
+               c = addVW(z[n:m], x[n:], c)
+       }
+       z[m] = c
+
+       return z.norm()
+}
+
+
+func (z nat) sub(x, y nat) nat {
+       m := len(x)
+       n := len(y)
+
+       switch {
+       case m < n:
+               panic("underflow")
+       case m == 0:
+               // n == 0 because m >= n; result is 0
+               return z.make(0)
+       case n == 0:
+               // result is x
+               return z.set(x)
+       }
+       // m > 0
+
+       z = z.make(m)
+       c := subVV(z[0:n], x, y)
+       if m > n {
+               c = subVW(z[n:], x[n:], c)
+       }
+       if c != 0 {
+               panic("underflow")
+       }
+
+       return z.norm()
+}
+
+
+func (x nat) cmp(y nat) (r int) {
+       m := len(x)
+       n := len(y)
+       if m != n || m == 0 {
+               switch {
+               case m < n:
+                       r = -1
+               case m > n:
+                       r = 1
+               }
+               return
+       }
+
+       i := m - 1
+       for i > 0 && x[i] == y[i] {
+               i--
+       }
+
+       switch {
+       case x[i] < y[i]:
+               r = -1
+       case x[i] > y[i]:
+               r = 1
+       }
+       return
+}
+
+
+func (z nat) mulAddWW(x nat, y, r Word) nat {
+       m := len(x)
+       if m == 0 || y == 0 {
+               return z.setWord(r) // result is r
+       }
+       // m > 0
+
+       z = z.make(m + 1)
+       z[m] = mulAddVWW(z[0:m], x, y, r)
+
+       return z.norm()
+}
+
+
+// basicMul multiplies x and y and leaves the result in z.
+// The (non-normalized) result is placed in z[0 : len(x) + len(y)].
+func basicMul(z, x, y nat) {
+       z[0 : len(x)+len(y)].clear() // initialize z
+       for i, d := range y {
+               if d != 0 {
+                       z[len(x)+i] = addMulVVW(z[i:i+len(x)], x, d)
+               }
+       }
+}
+
+
+// Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
+// Factored out for readability - do not use outside karatsuba.
+func karatsubaAdd(z, x nat, n int) {
+       if c := addVV(z[0:n], z, x); c != 0 {
+               addVW(z[n:n+n>>1], z[n:], c)
+       }
+}
+
+
+// Like karatsubaAdd, but does subtract.
+func karatsubaSub(z, x nat, n int) {
+       if c := subVV(z[0:n], z, x); c != 0 {
+               subVW(z[n:n+n>>1], z[n:], c)
+       }
+}
+
+
+// Operands that are shorter than karatsubaThreshold are multiplied using
+// "grade school" multiplication; for longer operands the Karatsuba algorithm
+// is used.
+var karatsubaThreshold int = 32 // computed by calibrate.go
+
+// karatsuba multiplies x and y and leaves the result in z.
+// Both x and y must have the same length n and n must be a
+// power of 2. The result vector z must have len(z) >= 6*n.
+// The (non-normalized) result is placed in z[0 : 2*n].
+func karatsuba(z, x, y nat) {
+       n := len(y)
+
+       // Switch to basic multiplication if numbers are odd or small.
+       // (n is always even if karatsubaThreshold is even, but be
+       // conservative)
+       if n&1 != 0 || n < karatsubaThreshold || n < 2 {
+               basicMul(z, x, y)
+               return
+       }
+       // n&1 == 0 && n >= karatsubaThreshold && n >= 2
+
+       // Karatsuba multiplication is based on the observation that
+       // for two numbers x and y with:
+       //
+       //   x = x1*b + x0
+       //   y = y1*b + y0
+       //
+       // the product x*y can be obtained with 3 products z2, z1, z0
+       // instead of 4:
+       //
+       //   x*y = x1*y1*b*b + (x1*y0 + x0*y1)*b + x0*y0
+       //       =    z2*b*b +              z1*b +    z0
+       //
+       // with:
+       //
+       //   xd = x1 - x0
+       //   yd = y0 - y1
+       //
+       //   z1 =      xd*yd                    + z1 + z0
+       //      = (x1-x0)*(y0 - y1)             + z1 + z0
+       //      = x1*y0 - x1*y1 - x0*y0 + x0*y1 + z1 + z0
+       //      = x1*y0 -    z1 -    z0 + x0*y1 + z1 + z0
+       //      = x1*y0                 + x0*y1
+
+       // split x, y into "digits"
+       n2 := n >> 1              // n2 >= 1
+       x1, x0 := x[n2:], x[0:n2] // x = x1*b + y0
+       y1, y0 := y[n2:], y[0:n2] // y = y1*b + y0
+
+       // z is used for the result and temporary storage:
+       //
+       //   6*n     5*n     4*n     3*n     2*n     1*n     0*n
+       // z = [z2 copy|z0 copy| xd*yd | yd:xd | x1*y1 | x0*y0 ]
+       //
+       // For each recursive call of karatsuba, an unused slice of
+       // z is passed in that has (at least) half the length of the
+       // caller's z.
+
+       // compute z0 and z2 with the result "in place" in z
+       karatsuba(z, x0, y0)     // z0 = x0*y0
+       karatsuba(z[n:], x1, y1) // z2 = x1*y1
+
+       // compute xd (or the negative value if underflow occurs)
+       s := 1 // sign of product xd*yd
+       xd := z[2*n : 2*n+n2]
+       if subVV(xd, x1, x0) != 0 { // x1-x0
+               s = -s
+               subVV(xd, x0, x1) // x0-x1
+       }
+
+       // compute yd (or the negative value if underflow occurs)
+       yd := z[2*n+n2 : 3*n]
+       if subVV(yd, y0, y1) != 0 { // y0-y1
+               s = -s
+               subVV(yd, y1, y0) // y1-y0
+       }
+
+       // p = (x1-x0)*(y0-y1) == x1*y0 - x1*y1 - x0*y0 + x0*y1 for s > 0
+       // p = (x0-x1)*(y0-y1) == x0*y0 - x0*y1 - x1*y0 + x1*y1 for s < 0
+       p := z[n*3:]
+       karatsuba(p, xd, yd)
+
+       // save original z2:z0
+       // (ok to use upper half of z since we're done recursing)
+       r := z[n*4:]
+       copy(r, z)
+
+       // add up all partial products
+       //
+       //   2*n     n     0
+       // z = [ z2  | z0  ]
+       //   +    [ z0  ]
+       //   +    [ z2  ]
+       //   +    [  p  ]
+       //
+       karatsubaAdd(z[n2:], r, n)
+       karatsubaAdd(z[n2:], r[n:], n)
+       if s > 0 {
+               karatsubaAdd(z[n2:], p, n)
+       } else {
+               karatsubaSub(z[n2:], p, n)
+       }
+}
+
+
+// alias returns true if x and y share the same base array.
+func alias(x, y nat) bool {
+       return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
+}
+
+
+// addAt implements z += x*(1<<(_W*i)); z must be long enough.
+// (we don't use nat.add because we need z to stay the same
+// slice, and we don't need to normalize z after each addition)
+func addAt(z, x nat, i int) {
+       if n := len(x); n > 0 {
+               if c := addVV(z[i:i+n], z[i:], x); c != 0 {
+                       j := i + n
+                       if j < len(z) {
+                               addVW(z[j:], z[j:], c)
+                       }
+               }
+       }
+}
+
+
+func max(x, y int) int {
+       if x > y {
+               return x
+       }
+       return y
+}
+
+
+// karatsubaLen computes an approximation to the maximum k <= n such that
+// k = p<<i for a number p <= karatsubaThreshold and an i >= 0. Thus, the
+// result is the largest number that can be divided repeatedly by 2 before
+// becoming about the value of karatsubaThreshold.
+func karatsubaLen(n int) int {
+       i := uint(0)
+       for n > karatsubaThreshold {
+               n >>= 1
+               i++
+       }
+       return n << i
+}
+
+
+func (z nat) mul(x, y nat) nat {
+       m := len(x)
+       n := len(y)
+
+       switch {
+       case m < n:
+               return z.mul(y, x)
+       case m == 0 || n == 0:
+               return z.make(0)
+       case n == 1:
+               return z.mulAddWW(x, y[0], 0)
+       }
+       // m >= n > 1
+
+       // determine if z can be reused
+       if alias(z, x) || alias(z, y) {
+               z = nil // z is an alias for x or y - cannot reuse
+       }
+
+       // use basic multiplication if the numbers are small
+       if n < karatsubaThreshold || n < 2 {
+               z = z.make(m + n)
+               basicMul(z, x, y)
+               return z.norm()
+       }
+       // m >= n && n >= karatsubaThreshold && n >= 2
+
+       // determine Karatsuba length k such that
+       //
+       //   x = x1*b + x0
+       //   y = y1*b + y0  (and k <= len(y), which implies k <= len(x))
+       //   b = 1<<(_W*k)  ("base" of digits xi, yi)
+       //
+       k := karatsubaLen(n)
+       // k <= n
+
+       // multiply x0 and y0 via Karatsuba
+       x0 := x[0:k]              // x0 is not normalized
+       y0 := y[0:k]              // y0 is not normalized
+       z = z.make(max(6*k, m+n)) // enough space for karatsuba of x0*y0 and full result of x*y
+       karatsuba(z, x0, y0)
+       z = z[0 : m+n] // z has final length but may be incomplete, upper portion is garbage
+
+       // If x1 and/or y1 are not 0, add missing terms to z explicitly:
+       //
+       //     m+n       2*k       0
+       //   z = [   ...   | x0*y0 ]
+       //     +   [ x1*y1 ]
+       //     +   [ x1*y0 ]
+       //     +   [ x0*y1 ]
+       //
+       if k < n || m != n {
+               x1 := x[k:] // x1 is normalized because x is
+               y1 := y[k:] // y1 is normalized because y is
+               var t nat
+               t = t.mul(x1, y1)
+               copy(z[2*k:], t)
+               z[2*k+len(t):].clear() // upper portion of z is garbage
+               t = t.mul(x1, y0.norm())
+               addAt(z, t, k)
+               t = t.mul(x0.norm(), y1)
+               addAt(z, t, k)
+       }
+
+       return z.norm()
+}
+
+
+// mulRange computes the product of all the unsigned integers in the
+// range [a, b] inclusively. If a > b (empty range), the result is 1.
+func (z nat) mulRange(a, b uint64) nat {
+       switch {
+       case a == 0:
+               // cut long ranges short (optimization)
+               return z.setUint64(0)
+       case a > b:
+               return z.setUint64(1)
+       case a == b:
+               return z.setUint64(a)
+       case a+1 == b:
+               return z.mul(nat(nil).setUint64(a), nat(nil).setUint64(b))
+       }
+       m := (a + b) / 2
+       return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
+}
+
+
+// q = (x-r)/y, with 0 <= r < y
+func (z nat) divW(x nat, y Word) (q nat, r Word) {
+       m := len(x)
+       switch {
+       case y == 0:
+               panic("division by zero")
+       case y == 1:
+               q = z.set(x) // result is x
+               return
+       case m == 0:
+               q = z.make(0) // result is 0
+               return
+       }
+       // m > 0
+       z = z.make(m)
+       r = divWVW(z, 0, x, y)
+       q = z.norm()
+       return
+}
+
+
+func (z nat) div(z2, u, v nat) (q, r nat) {
+       if len(v) == 0 {
+               panic("division by zero")
+       }
+
+       if u.cmp(v) < 0 {
+               q = z.make(0)
+               r = z2.set(u)
+               return
+       }
+
+       if len(v) == 1 {
+               var rprime Word
+               q, rprime = z.divW(u, v[0])
+               if rprime > 0 {
+                       r = z2.make(1)
+                       r[0] = rprime
+               } else {
+                       r = z2.make(0)
+               }
+               return
+       }
+
+       q, r = z.divLarge(z2, u, v)
+       return
+}
+
+
+// q = (uIn-r)/v, with 0 <= r < y
+// Uses z as storage for q, and u as storage for r if possible.
+// See Knuth, Volume 2, section 4.3.1, Algorithm D.
+// Preconditions:
+//    len(v) >= 2
+//    len(uIn) >= len(v)
+func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
+       n := len(v)
+       m := len(uIn) - n
+
+       // determine if z can be reused
+       // TODO(gri) should find a better solution - this if statement
+       //           is very costly (see e.g. time pidigits -s -n 10000)
+       if alias(z, uIn) || alias(z, v) {
+               z = nil // z is an alias for uIn or v - cannot reuse
+       }
+       q = z.make(m + 1)
+
+       qhatv := make(nat, n+1)
+       if alias(u, uIn) || alias(u, v) {
+               u = nil // u is an alias for uIn or v - cannot reuse
+       }
+       u = u.make(len(uIn) + 1)
+       u.clear()
+
+       // D1.
+       shift := Word(leadingZeros(v[n-1]))
+       shlVW(v, v, shift)
+       u[len(uIn)] = shlVW(u[0:len(uIn)], uIn, shift)
+
+       // D2.
+       for j := m; j >= 0; j-- {
+               // D3.
+               qhat := Word(_M)
+               if u[j+n] != v[n-1] {
+                       var rhat Word
+                       qhat, rhat = divWW(u[j+n], u[j+n-1], v[n-1])
+
+                       // x1 | x2 = q̂v_{n-2}
+                       x1, x2 := mulWW(qhat, v[n-2])
+                       // test if q̂v_{n-2} > br̂ + u_{j+n-2}
+                       for greaterThan(x1, x2, rhat, u[j+n-2]) {
+                               qhat--
+                               prevRhat := rhat
+                               rhat += v[n-1]
+                               // v[n-1] >= 0, so this tests for overflow.
+                               if rhat < prevRhat {
+                                       break
+                               }
+                               x1, x2 = mulWW(qhat, v[n-2])
+                       }
+               }
+
+               // D4.
+               qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
+
+               c := subVV(u[j:j+len(qhatv)], u[j:], qhatv)
+               if c != 0 {
+                       c := addVV(u[j:j+n], u[j:], v)
+                       u[j+n] += c
+                       qhat--
+               }
+
+               q[j] = qhat
+       }
+
+       q = q.norm()
+       shrVW(u, u, shift)
+       shrVW(v, v, shift)
+       r = u.norm()
+
+       return q, r
+}
+
+
+// Length of x in bits. x must be normalized.
+func (x nat) bitLen() int {
+       if i := len(x) - 1; i >= 0 {
+               return i*_W + bitLen(x[i])
+       }
+       return 0
+}
+
+
+func hexValue(ch byte) int {
+       var d byte
+       switch {
+       case '0' <= ch && ch <= '9':
+               d = ch - '0'
+       case 'a' <= ch && ch <= 'f':
+               d = ch - 'a' + 10
+       case 'A' <= ch && ch <= 'F':
+               d = ch - 'A' + 10
+       default:
+               return -1
+       }
+       return int(d)
+}
+
+
+// scan returns the natural number corresponding to the
+// longest possible prefix of s representing a natural number in a
+// given conversion base, the actual conversion base used, and the
+// prefix length. The syntax of natural numbers follows the syntax
+// of unsigned integer literals in Go.
+//
+// If the base argument is 0, the string prefix determines the actual
+// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
+// ``0'' prefix selects base 8, and a ``0b'' or ``0B'' prefix selects
+// base 2. Otherwise the selected base is 10.
+//
+func (z nat) scan(s string, base int) (nat, int, int) {
+       // determine base if necessary
+       i, n := 0, len(s)
+       if base == 0 {
+               base = 10
+               if n > 0 && s[0] == '0' {
+                       base, i = 8, 1
+                       if n > 1 {
+                               switch s[1] {
+                               case 'x', 'X':
+                                       base, i = 16, 2
+                               case 'b', 'B':
+                                       base, i = 2, 2
+                               }
+                       }
+               }
+       }
+
+       // reject illegal bases or strings consisting only of prefix
+       if base < 2 || 16 < base || (base != 8 && i >= n) {
+               return z, 0, 0
+       }
+
+       // convert string
+       z = z.make(0)
+       for ; i < n; i++ {
+               d := hexValue(s[i])
+               if 0 <= d && d < base {
+                       z = z.mulAddWW(z, Word(base), Word(d))
+               } else {
+                       break
+               }
+       }
+
+       return z.norm(), base, i
+}
+
+
+// string converts x to a string for a given base, with 2 <= base <= 16.
+// TODO(gri) in the style of the other routines, perhaps this should take
+//           a []byte buffer and return it
+func (x nat) string(base int) string {
+       if base < 2 || 16 < base {
+               panic("illegal base")
+       }
+
+       if len(x) == 0 {
+               return "0"
+       }
+
+       // allocate buffer for conversion
+       i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+       s := make([]byte, i)
+
+       // don't destroy x
+       q := nat(nil).set(x)
+
+       // convert
+       for len(q) > 0 {
+               i--
+               var r Word
+               q, r = q.divW(q, Word(base))
+               s[i] = "0123456789abcdef"[r]
+       }
+
+       return string(s[i:])
+}
+
+
+const deBruijn32 = 0x077CB531
+
+var deBruijn32Lookup = []byte{
+       0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+       31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
+}
+
+const deBruijn64 = 0x03f79d71b4ca8b09
+
+var deBruijn64Lookup = []byte{
+       0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
+       62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
+       63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
+       54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
+}
+
+// trailingZeroBits returns the number of consecutive zero bits on the right
+// side of the given Word.
+// See Knuth, volume 4, section 7.3.1
+func trailingZeroBits(x Word) int {
+       // x & -x leaves only the right-most bit set in the word. Let k be the
+       // index of that bit. Since only a single bit is set, the value is two
+       // to the power of k. Multipling by a power of two is equivalent to
+       // left shifting, in this case by k bits.  The de Bruijn constant is
+       // such that all six bit, consecutive substrings are distinct.
+       // Therefore, if we have a left shifted version of this constant we can
+       // find by how many bits it was shifted by looking at which six bit
+       // substring ended up at the top of the word.
+       switch _W {
+       case 32:
+               return int(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
+       case 64:
+               return int(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
+       default:
+               panic("Unknown word size")
+       }
+
+       return 0
+}
+
+
+// z = x << s
+func (z nat) shl(x nat, s uint) nat {
+       m := len(x)
+       if m == 0 {
+               return z.make(0)
+       }
+       // m > 0
+
+       n := m + int(s/_W)
+       z = z.make(n + 1)
+       z[n] = shlVW(z[n-m:n], x, Word(s%_W))
+       z[0 : n-m].clear()
+
+       return z.norm()
+}
+
+
+// z = x >> s
+func (z nat) shr(x nat, s uint) nat {
+       m := len(x)
+       n := m - int(s/_W)
+       if n <= 0 {
+               return z.make(0)
+       }
+       // n > 0
+
+       z = z.make(n)
+       shrVW(z, x[m-n:], Word(s%_W))
+
+       return z.norm()
+}
+
+
+func (z nat) and(x, y nat) nat {
+       m := len(x)
+       n := len(y)
+       if m > n {
+               m = n
+       }
+       // m <= n
+
+       z = z.make(m)
+       for i := 0; i < m; i++ {
+               z[i] = x[i] & y[i]
+       }
+
+       return z.norm()
+}
+
+
+func (z nat) andNot(x, y nat) nat {
+       m := len(x)
+       n := len(y)
+       if n > m {
+               n = m
+       }
+       // m >= n
+
+       z = z.make(m)
+       for i := 0; i < n; i++ {
+               z[i] = x[i] &^ y[i]
+       }
+       copy(z[n:m], x[n:m])
+
+       return z.norm()
+}
+
+
+func (z nat) or(x, y nat) nat {
+       m := len(x)
+       n := len(y)
+       s := x
+       if m < n {
+               n, m = m, n
+               s = y
+       }
+       // m >= n
+
+       z = z.make(m)
+       for i := 0; i < n; i++ {
+               z[i] = x[i] | y[i]
+       }
+       copy(z[n:m], s[n:m])
+
+       return z.norm()
+}
+
+
+func (z nat) xor(x, y nat) nat {
+       m := len(x)
+       n := len(y)
+       s := x
+       if m < n {
+               n, m = m, n
+               s = y
+       }
+       // m >= n
+
+       z = z.make(m)
+       for i := 0; i < n; i++ {
+               z[i] = x[i] ^ y[i]
+       }
+       copy(z[n:m], s[n:m])
+
+       return z.norm()
+}
+
+
+// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
+func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 }
+
+
+// modW returns x % d.
+func (x nat) modW(d Word) (r Word) {
+       // TODO(agl): we don't actually need to store the q value.
+       var q nat
+       q = q.make(len(x))
+       return divWVW(q, 0, x, d)
+}
+
+
+// powersOfTwoDecompose finds q and k such that q * 1<<k = n and q is odd.
+func (n nat) powersOfTwoDecompose() (q nat, k Word) {
+       if len(n) == 0 {
+               return n, 0
+       }
+
+       zeroWords := 0
+       for n[zeroWords] == 0 {
+               zeroWords++
+       }
+       // One of the words must be non-zero by invariant, therefore
+       // zeroWords < len(n).
+       x := trailingZeroBits(n[zeroWords])
+
+       q = q.make(len(n) - zeroWords)
+       shrVW(q, n[zeroWords:], Word(x))
+       q = q.norm()
+
+       k = Word(_W*zeroWords + x)
+       return
+}
+
+
+// random creates a random integer in [0..limit), using the space in z if
+// possible. n is the bit length of limit.
+func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
+       bitLengthOfMSW := uint(n % _W)
+       if bitLengthOfMSW == 0 {
+               bitLengthOfMSW = _W
+       }
+       mask := Word((1 << bitLengthOfMSW) - 1)
+       z = z.make(len(limit))
+
+       for {
+               for i := range z {
+                       switch _W {
+                       case 32:
+                               z[i] = Word(rand.Uint32())
+                       case 64:
+                               z[i] = Word(rand.Uint32()) | Word(rand.Uint32())<<32
+                       }
+               }
+
+               z[len(limit)-1] &= mask
+
+               if z.cmp(limit) < 0 {
+                       break
+               }
+       }
+
+       return z.norm()
+}
+
+
+// If m != nil, expNN calculates x**y mod m. Otherwise it calculates x**y. It
+// reuses the storage of z if possible.
+func (z nat) expNN(x, y, m nat) nat {
+       if alias(z, x) || alias(z, y) {
+               // We cannot allow in place modification of x or y.
+               z = nil
+       }
+
+       if len(y) == 0 {
+               z = z.make(1)
+               z[0] = 1
+               return z
+       }
+
+       if m != nil {
+               // We likely end up being as long as the modulus.
+               z = z.make(len(m))
+       }
+       z = z.set(x)
+       v := y[len(y)-1]
+       // It's invalid for the most significant word to be zero, therefore we
+       // will find a one bit.
+       shift := leadingZeros(v) + 1
+       v <<= shift
+       var q nat
+
+       const mask = 1 << (_W - 1)
+
+       // We walk through the bits of the exponent one by one. Each time we
+       // see a bit, we square, thus doubling the power. If the bit is a one,
+       // we also multiply by x, thus adding one to the power.
+
+       w := _W - int(shift)
+       for j := 0; j < w; j++ {
+               z = z.mul(z, z)
+
+               if v&mask != 0 {
+                       z = z.mul(z, x)
+               }
+
+               if m != nil {
+                       q, z = q.div(z, z, m)
+               }
+
+               v <<= 1
+       }
+
+       for i := len(y) - 2; i >= 0; i-- {
+               v = y[i]
+
+               for j := 0; j < _W; j++ {
+                       z = z.mul(z, z)
+
+                       if v&mask != 0 {
+                               z = z.mul(z, x)
+                       }
+
+                       if m != nil {
+                               q, z = q.div(z, z, m)
+                       }
+
+                       v <<= 1
+               }
+       }
+
+       return z
+}
+
+
+// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
+// If it returns true, n is prime with probability 1 - 1/4^reps.
+// If it returns false, n is not prime.
+func (n nat) probablyPrime(reps int) bool {
+       if len(n) == 0 {
+               return false
+       }
+
+       if len(n) == 1 {
+               if n[0] < 2 {
+                       return false
+               }
+
+               if n[0]%2 == 0 {
+                       return n[0] == 2
+               }
+
+               // We have to exclude these cases because we reject all
+               // multiples of these numbers below.
+               switch n[0] {
+               case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
+                       return true
+               }
+       }
+
+       const primesProduct32 = 0xC0CFD797         // Π {p ∈ primes, 2 < p <= 29}
+       const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
+
+       var r Word
+       switch _W {
+       case 32:
+               r = n.modW(primesProduct32)
+       case 64:
+               r = n.modW(primesProduct64 & _M)
+       default:
+               panic("Unknown word size")
+       }
+
+       if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
+               r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
+               return false
+       }
+
+       if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
+               r%43 == 0 || r%47 == 0 || r%53 == 0) {
+               return false
+       }
+
+       nm1 := nat(nil).sub(n, natOne)
+       // 1<<k * q = nm1;
+       q, k := nm1.powersOfTwoDecompose()
+
+       nm3 := nat(nil).sub(nm1, natTwo)
+       rand := rand.New(rand.NewSource(int64(n[0])))
+
+       var x, y, quotient nat
+       nm3Len := nm3.bitLen()
+
+NextRandom:
+       for i := 0; i < reps; i++ {
+               x = x.random(rand, nm3, nm3Len)
+               x = x.add(x, natTwo)
+               y = y.expNN(x, q, n)
+               if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
+                       continue
+               }
+               for j := Word(1); j < k; j++ {
+                       y = y.mul(y, y)
+                       quotient, y = quotient.div(y, y, n)
+                       if y.cmp(nm1) == 0 {
+                               continue NextRandom
+                       }
+                       if y.cmp(natOne) == 0 {
+                               return false
+                       }
+               }
+               return false
+       }
+
+       return true
+}
diff --git a/libgo/go/big/nat_test.go b/libgo/go/big/nat_test.go
new file mode 100644 (file)
index 0000000..0bcb945
--- /dev/null
@@ -0,0 +1,358 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import "testing"
+
+var cmpTests = []struct {
+       x, y nat
+       r    int
+}{
+       {nil, nil, 0},
+       {nil, nat{}, 0},
+       {nat{}, nil, 0},
+       {nat{}, nat{}, 0},
+       {nat{0}, nat{0}, 0},
+       {nat{0}, nat{1}, -1},
+       {nat{1}, nat{0}, 1},
+       {nat{1}, nat{1}, 0},
+       {nat{0, _M}, nat{1}, 1},
+       {nat{1}, nat{0, _M}, -1},
+       {nat{1, _M}, nat{0, _M}, 1},
+       {nat{0, _M}, nat{1, _M}, -1},
+       {nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
+       {nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
+}
+
+
+func TestCmp(t *testing.T) {
+       for i, a := range cmpTests {
+               r := a.x.cmp(a.y)
+               if r != a.r {
+                       t.Errorf("#%d got r = %v; want %v", i, r, a.r)
+               }
+       }
+}
+
+
+type funNN func(z, x, y nat) nat
+type argNN struct {
+       z, x, y nat
+}
+
+
+var sumNN = []argNN{
+       {},
+       {nat{1}, nil, nat{1}},
+       {nat{1111111110}, nat{123456789}, nat{987654321}},
+       {nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
+       {nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
+       {nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
+}
+
+
+var prodNN = []argNN{
+       {},
+       {nil, nil, nil},
+       {nil, nat{991}, nil},
+       {nat{991}, nat{991}, nat{1}},
+       {nat{991 * 991}, nat{991}, nat{991}},
+       {nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
+       {nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
+       {nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
+}
+
+
+func TestSet(t *testing.T) {
+       for _, a := range sumNN {
+               z := nat(nil).set(a.z)
+               if z.cmp(a.z) != 0 {
+                       t.Errorf("got z = %v; want %v", z, a.z)
+               }
+       }
+}
+
+
+func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
+       z := f(nil, a.x, a.y)
+       if z.cmp(a.z) != 0 {
+               t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z)
+       }
+}
+
+
+func TestFunNN(t *testing.T) {
+       for _, a := range sumNN {
+               arg := a
+               testFunNN(t, "add", nat.add, arg)
+
+               arg = argNN{a.z, a.y, a.x}
+               testFunNN(t, "add symmetric", nat.add, arg)
+
+               arg = argNN{a.x, a.z, a.y}
+               testFunNN(t, "sub", nat.sub, arg)
+
+               arg = argNN{a.y, a.z, a.x}
+               testFunNN(t, "sub symmetric", nat.sub, arg)
+       }
+
+       for _, a := range prodNN {
+               arg := a
+               testFunNN(t, "mul", nat.mul, arg)
+
+               arg = argNN{a.z, a.y, a.x}
+               testFunNN(t, "mul symmetric", nat.mul, arg)
+       }
+}
+
+
+var mulRangesN = []struct {
+       a, b uint64
+       prod string
+}{
+       {0, 0, "0"},
+       {1, 1, "1"},
+       {1, 2, "2"},
+       {1, 3, "6"},
+       {10, 10, "10"},
+       {0, 100, "0"},
+       {0, 1e9, "0"},
+       {1, 0, "1"},                    // empty range
+       {100, 1, "1"},                  // empty range
+       {1, 10, "3628800"},             // 10!
+       {1, 20, "2432902008176640000"}, // 20!
+       {1, 100,
+               "933262154439441526816992388562667004907159682643816214685929" +
+                       "638952175999932299156089414639761565182862536979208272237582" +
+                       "51185210916864000000000000000000000000", // 100!
+       },
+}
+
+
+func TestMulRangeN(t *testing.T) {
+       for i, r := range mulRangesN {
+               prod := nat(nil).mulRange(r.a, r.b).string(10)
+               if prod != r.prod {
+                       t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
+               }
+       }
+}
+
+
+var mulArg, mulTmp nat
+
+func init() {
+       const n = 1000
+       mulArg = make(nat, n)
+       for i := 0; i < n; i++ {
+               mulArg[i] = _M
+       }
+}
+
+
+func benchmarkMulLoad() {
+       for j := 1; j <= 10; j++ {
+               x := mulArg[0 : j*100]
+               mulTmp.mul(x, x)
+       }
+}
+
+
+func BenchmarkMul(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               benchmarkMulLoad()
+       }
+}
+
+
+var tab = []struct {
+       x nat
+       b int
+       s string
+}{
+       {nil, 10, "0"},
+       {nat{1}, 10, "1"},
+       {nat{10}, 10, "10"},
+       {nat{1234567890}, 10, "1234567890"},
+}
+
+
+func TestString(t *testing.T) {
+       for _, a := range tab {
+               s := a.x.string(a.b)
+               if s != a.s {
+                       t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
+               }
+
+               x, b, n := nat(nil).scan(a.s, a.b)
+               if x.cmp(a.x) != 0 {
+                       t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+               }
+               if b != a.b {
+                       t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.b)
+               }
+               if n != len(a.s) {
+                       t.Errorf("scan%+v\n\tgot n = %d; want %d", a, n, len(a.s))
+               }
+       }
+}
+
+
+func TestLeadingZeros(t *testing.T) {
+       var x Word = _B >> 1
+       for i := 0; i <= _W; i++ {
+               if int(leadingZeros(x)) != i {
+                       t.Errorf("failed at %x: got %d want %d", x, leadingZeros(x), i)
+               }
+               x >>= 1
+       }
+}
+
+
+type shiftTest struct {
+       in    nat
+       shift uint
+       out   nat
+}
+
+
+var leftShiftTests = []shiftTest{
+       {nil, 0, nil},
+       {nil, 1, nil},
+       {natOne, 0, natOne},
+       {natOne, 1, natTwo},
+       {nat{1 << (_W - 1)}, 1, nat{0}},
+       {nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
+}
+
+
+func TestShiftLeft(t *testing.T) {
+       for i, test := range leftShiftTests {
+               var z nat
+               z = z.shl(test.in, test.shift)
+               for j, d := range test.out {
+                       if j >= len(z) || z[j] != d {
+                               t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+                               break
+                       }
+               }
+       }
+}
+
+
+var rightShiftTests = []shiftTest{
+       {nil, 0, nil},
+       {nil, 1, nil},
+       {natOne, 0, natOne},
+       {natOne, 1, nil},
+       {natTwo, 1, natOne},
+       {nat{0, 1}, 1, nat{1 << (_W - 1)}},
+       {nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
+}
+
+
+func TestShiftRight(t *testing.T) {
+       for i, test := range rightShiftTests {
+               var z nat
+               z = z.shr(test.in, test.shift)
+               for j, d := range test.out {
+                       if j >= len(z) || z[j] != d {
+                               t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+                               break
+                       }
+               }
+       }
+}
+
+
+type modWTest struct {
+       in       string
+       dividend string
+       out      string
+}
+
+
+var modWTests32 = []modWTest{
+       {"23492635982634928349238759823742", "252341", "220170"},
+}
+
+
+var modWTests64 = []modWTest{
+       {"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
+}
+
+
+func runModWTests(t *testing.T, tests []modWTest) {
+       for i, test := range tests {
+               in, _ := new(Int).SetString(test.in, 10)
+               d, _ := new(Int).SetString(test.dividend, 10)
+               out, _ := new(Int).SetString(test.out, 10)
+
+               r := in.abs.modW(d.abs[0])
+               if r != out.abs[0] {
+                       t.Errorf("#%d failed: got %s want %s", i, r, out)
+               }
+       }
+}
+
+
+func TestModW(t *testing.T) {
+       if _W >= 32 {
+               runModWTests(t, modWTests32)
+       }
+       if _W >= 64 {
+               runModWTests(t, modWTests64)
+       }
+}
+
+
+func TestTrailingZeroBits(t *testing.T) {
+       var x Word
+       x--
+       for i := 0; i < _W; i++ {
+               if trailingZeroBits(x) != i {
+                       t.Errorf("Failed at step %d: x: %x got: %d", i, x, trailingZeroBits(x))
+               }
+               x <<= 1
+       }
+}
+
+
+var expNNTests = []struct {
+       x, y, m string
+       out     string
+}{
+       {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+       {"0x8000000000000000", "2", "6719", "4944"},
+       {"0x8000000000000000", "3", "6719", "5447"},
+       {"0x8000000000000000", "1000", "6719", "1603"},
+       {"0x8000000000000000", "1000000", "6719", "3199"},
+       {
+               "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+               "298472983472983471903246121093472394872319615612417471234712061",
+               "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+               "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+       },
+}
+
+
+func TestExpNN(t *testing.T) {
+       for i, test := range expNNTests {
+               x, _, _ := nat(nil).scan(test.x, 0)
+               y, _, _ := nat(nil).scan(test.y, 0)
+               out, _, _ := nat(nil).scan(test.out, 0)
+
+               var m nat
+
+               if len(test.m) > 0 {
+                       m, _, _ = nat(nil).scan(test.m, 0)
+               }
+
+               z := nat(nil).expNN(x, y, m)
+               if z.cmp(out) != 0 {
+                       t.Errorf("#%d got %v want %v", i, z, out)
+               }
+       }
+}
diff --git a/libgo/go/big/rat.go b/libgo/go/big/rat.go
new file mode 100644 (file)
index 0000000..40c6ef5
--- /dev/null
@@ -0,0 +1,327 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements multi-precision rational numbers.
+
+package big
+
+import "strings"
+
+// A Rat represents a quotient a/b of arbitrary precision. The zero value for
+// a Rat, 0/0, is not a legal Rat.
+type Rat struct {
+       a Int
+       b nat
+}
+
+
+// NewRat creates a new Rat with numerator a and denominator b.
+func NewRat(a, b int64) *Rat {
+       return new(Rat).SetFrac64(a, b)
+}
+
+
+// SetFrac sets z to a/b and returns z.
+func (z *Rat) SetFrac(a, b *Int) *Rat {
+       z.a.Set(a)
+       z.a.neg = a.neg != b.neg
+       z.b = z.b.set(b.abs)
+       return z.norm()
+}
+
+
+// SetFrac64 sets z to a/b and returns z.
+func (z *Rat) SetFrac64(a, b int64) *Rat {
+       z.a.SetInt64(a)
+       if b < 0 {
+               z.b.setUint64(uint64(-b))
+               z.a.neg = !z.a.neg
+               return z.norm()
+       }
+       z.b = z.b.setUint64(uint64(b))
+       return z.norm()
+}
+
+
+// SetInt sets z to x (by making a copy of x) and returns z.
+func (z *Rat) SetInt(x *Int) *Rat {
+       z.a.Set(x)
+       z.b = z.b.setWord(1)
+       return z
+}
+
+
+// SetInt64 sets z to x and returns z.
+func (z *Rat) SetInt64(x int64) *Rat {
+       z.a.SetInt64(x)
+       z.b = z.b.setWord(1)
+       return z
+}
+
+
+// Sign returns:
+//
+//     -1 if x <  0
+//      0 if x == 0
+//     +1 if x >  0
+//
+func (x *Rat) Sign() int {
+       return x.a.Sign()
+}
+
+
+// IsInt returns true if the denominator of x is 1.
+func (x *Rat) IsInt() bool {
+       return len(x.b) == 1 && x.b[0] == 1
+}
+
+
+// Num returns the numerator of z; it may be <= 0.
+// The result is a reference to z's numerator; it
+// may change if a new value is assigned to z.
+func (z *Rat) Num() *Int {
+       return &z.a
+}
+
+
+// Demom returns the denominator of z; it is always > 0.
+// The result is a reference to z's denominator; it
+// may change if a new value is assigned to z.
+func (z *Rat) Denom() *Int {
+       return &Int{false, z.b}
+}
+
+
+func gcd(x, y nat) nat {
+       // Euclidean algorithm.
+       var a, b nat
+       a = a.set(x)
+       b = b.set(y)
+       for len(b) != 0 {
+               var q, r nat
+               _, r = q.div(r, a, b)
+               a = b
+               b = r
+       }
+       return a
+}
+
+
+func (z *Rat) norm() *Rat {
+       f := gcd(z.a.abs, z.b)
+       if len(z.a.abs) == 0 {
+               // z == 0
+               z.a.neg = false // normalize sign
+               z.b = z.b.setWord(1)
+               return z
+       }
+       if f.cmp(natOne) != 0 {
+               z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f)
+               z.b, _ = z.b.div(nil, z.b, f)
+       }
+       return z
+}
+
+
+func mulNat(x *Int, y nat) *Int {
+       var z Int
+       z.abs = z.abs.mul(x.abs, y)
+       z.neg = len(z.abs) > 0 && x.neg
+       return &z
+}
+
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y
+//   +1 if x >  y
+//
+func (x *Rat) Cmp(y *Rat) (r int) {
+       return mulNat(&x.a, y.b).Cmp(mulNat(&y.a, x.b))
+}
+
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Rat) Abs(x *Rat) *Rat {
+       z.a.Abs(&x.a)
+       z.b = z.b.set(x.b)
+       return z
+}
+
+
+// Add sets z to the sum x+y and returns z.
+func (z *Rat) Add(x, y *Rat) *Rat {
+       a1 := mulNat(&x.a, y.b)
+       a2 := mulNat(&y.a, x.b)
+       z.a.Add(a1, a2)
+       z.b = z.b.mul(x.b, y.b)
+       return z.norm()
+}
+
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Rat) Sub(x, y *Rat) *Rat {
+       a1 := mulNat(&x.a, y.b)
+       a2 := mulNat(&y.a, x.b)
+       z.a.Sub(a1, a2)
+       z.b = z.b.mul(x.b, y.b)
+       return z.norm()
+}
+
+
+// Mul sets z to the product x*y and returns z.
+func (z *Rat) Mul(x, y *Rat) *Rat {
+       z.a.Mul(&x.a, &y.a)
+       z.b = z.b.mul(x.b, y.b)
+       return z.norm()
+}
+
+
+// Quo sets z to the quotient x/y and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+func (z *Rat) Quo(x, y *Rat) *Rat {
+       if len(y.a.abs) == 0 {
+               panic("division by zero")
+       }
+       a := mulNat(&x.a, y.b)
+       b := mulNat(&y.a, x.b)
+       z.a.abs = a.abs
+       z.b = b.abs
+       z.a.neg = a.neg != b.neg
+       return z.norm()
+}
+
+
+// Neg sets z to -x (by making a copy of x if necessary) and returns z.
+func (z *Rat) Neg(x *Rat) *Rat {
+       z.a.Neg(&x.a)
+       z.b = z.b.set(x.b)
+       return z
+}
+
+
+// Set sets z to x (by making a copy of x if necessary) and returns z.
+func (z *Rat) Set(x *Rat) *Rat {
+       z.a.Set(&x.a)
+       z.b = z.b.set(x.b)
+       return z
+}
+
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s can be given as a fraction "a/b" or as a floating-point number
+// optionally followed by an exponent. If the operation failed, the value of z
+// is undefined.
+func (z *Rat) SetString(s string) (*Rat, bool) {
+       if len(s) == 0 {
+               return z, false
+       }
+
+       // check for a quotient
+       sep := strings.Index(s, "/")
+       if sep >= 0 {
+               if _, ok := z.a.SetString(s[0:sep], 10); !ok {
+                       return z, false
+               }
+               s = s[sep+1:]
+               var n int
+               if z.b, _, n = z.b.scan(s, 10); n != len(s) {
+                       return z, false
+               }
+               return z.norm(), true
+       }
+
+       // check for a decimal point
+       sep = strings.Index(s, ".")
+       // check for an exponent
+       e := strings.IndexAny(s, "eE")
+       var exp Int
+       if e >= 0 {
+               if e < sep {
+                       // The E must come after the decimal point.
+                       return z, false
+               }
+               if _, ok := exp.SetString(s[e+1:], 10); !ok {
+                       return z, false
+               }
+               s = s[0:e]
+       }
+       if sep >= 0 {
+               s = s[0:sep] + s[sep+1:]
+               exp.Sub(&exp, NewInt(int64(len(s)-sep)))
+       }
+
+       if _, ok := z.a.SetString(s, 10); !ok {
+               return z, false
+       }
+       powTen := nat{}.expNN(natTen, exp.abs, nil)
+       if exp.neg {
+               z.b = powTen
+               z.norm()
+       } else {
+               z.a.abs = z.a.abs.mul(z.a.abs, powTen)
+               z.b = z.b.setWord(1)
+       }
+
+       return z, true
+}
+
+
+// String returns a string representation of z in the form "a/b" (even if b == 1).
+func (z *Rat) String() string {
+       return z.a.String() + "/" + z.b.string(10)
+}
+
+
+// RatString returns a string representation of z in the form "a/b" if b != 1,
+// and in the form "a" if b == 1.
+func (z *Rat) RatString() string {
+       if z.IsInt() {
+               return z.a.String()
+       }
+       return z.String()
+}
+
+
+// FloatString returns a string representation of z in decimal form with prec
+// digits of precision after the decimal point and the last digit rounded.
+func (z *Rat) FloatString(prec int) string {
+       if z.IsInt() {
+               return z.a.String()
+       }
+
+       q, r := nat{}.div(nat{}, z.a.abs, z.b)
+
+       p := natOne
+       if prec > 0 {
+               p = nat{}.expNN(natTen, nat{}.setUint64(uint64(prec)), nil)
+       }
+
+       r = r.mul(r, p)
+       r, r2 := r.div(nat{}, r, z.b)
+
+       // see if we need to round up
+       r2 = r2.add(r2, r2)
+       if z.b.cmp(r2) <= 0 {
+               r = r.add(r, natOne)
+               if r.cmp(p) >= 0 {
+                       q = nat{}.add(q, natOne)
+                       r = nat{}.sub(r, p)
+               }
+       }
+
+       s := q.string(10)
+       if z.a.neg {
+               s = "-" + s
+       }
+
+       if prec > 0 {
+               rs := r.string(10)
+               leadingZeros := prec - len(rs)
+               s += "." + strings.Repeat("0", leadingZeros) + rs
+       }
+
+       return s
+}
diff --git a/libgo/go/big/rat_test.go b/libgo/go/big/rat_test.go
new file mode 100644 (file)
index 0000000..460ed40
--- /dev/null
@@ -0,0 +1,259 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import "testing"
+
+
+var setStringTests = []struct {
+       in, out string
+       ok      bool
+}{
+       {"0", "0", true},
+       {"-0", "0", true},
+       {"1", "1", true},
+       {"-1", "-1", true},
+       {"1.", "1", true},
+       {"1e0", "1", true},
+       {"1.e1", "10", true},
+       {in: "1e", ok: false},
+       {in: "1.e", ok: false},
+       {in: "1e+14e-5", ok: false},
+       {in: "1e4.5", ok: false},
+       {in: "r", ok: false},
+       {in: "a/b", ok: false},
+       {in: "a.b", ok: false},
+       {"-0.1", "-1/10", true},
+       {"-.1", "-1/10", true},
+       {"2/4", "1/2", true},
+       {".25", "1/4", true},
+       {"-1/5", "-1/5", true},
+       {"8129567.7690E14", "812956776900000000000", true},
+       {"78189e+4", "781890000", true},
+       {"553019.8935e+8", "55301989350000", true},
+       {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
+       {"9877861857500000E-7", "3951144743/4", true},
+       {"2169378.417e-3", "2169378417/1000000", true},
+       {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
+       {"53/70893980658822810696", "53/70893980658822810696", true},
+       {"106/141787961317645621392", "53/70893980658822810696", true},
+       {"204211327800791583.81095", "4084226556015831676219/20000", true},
+}
+
+func TestRatSetString(t *testing.T) {
+       for i, test := range setStringTests {
+               x, ok := new(Rat).SetString(test.in)
+
+               if ok != test.ok || ok && x.RatString() != test.out {
+                       t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+               }
+       }
+}
+
+
+var floatStringTests = []struct {
+       in   string
+       prec int
+       out  string
+}{
+       {"0", 0, "0"},
+       {"0", 4, "0"},
+       {"1", 0, "1"},
+       {"1", 2, "1"},
+       {"-1", 0, "-1"},
+       {".25", 2, "0.25"},
+       {".25", 1, "0.3"},
+       {"-1/3", 3, "-0.333"},
+       {"-2/3", 4, "-0.6667"},
+       {"0.96", 1, "1.0"},
+       {"0.999", 2, "1.00"},
+       {"0.9", 0, "1"},
+       {".25", -1, "0"},
+       {".55", -1, "1"},
+}
+
+func TestFloatString(t *testing.T) {
+       for i, test := range floatStringTests {
+               x, _ := new(Rat).SetString(test.in)
+
+               if x.FloatString(test.prec) != test.out {
+                       t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
+               }
+       }
+}
+
+
+func TestRatSign(t *testing.T) {
+       zero := NewRat(0, 1)
+       for _, a := range setStringTests {
+               var x Rat
+               x.SetString(a.in)
+               s := x.Sign()
+               e := x.Cmp(zero)
+               if s != e {
+                       t.Errorf("got %d; want %d for z = %v", s, e, &x)
+               }
+       }
+}
+
+
+var ratCmpTests = []struct {
+       rat1, rat2 string
+       out        int
+}{
+       {"0", "0/1", 0},
+       {"1/1", "1", 0},
+       {"-1", "-2/2", 0},
+       {"1", "0", 1},
+       {"0/1", "1/1", -1},
+       {"-5/1434770811533343057144", "-5/1434770811533343057145", -1},
+       {"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1},
+       {"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1},
+       {"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0},
+}
+
+func TestRatCmp(t *testing.T) {
+       for i, test := range ratCmpTests {
+               x, _ := new(Rat).SetString(test.rat1)
+               y, _ := new(Rat).SetString(test.rat2)
+
+               out := x.Cmp(y)
+               if out != test.out {
+                       t.Errorf("#%d got out = %v; want %v", i, out, test.out)
+               }
+       }
+}
+
+
+func TestIsInt(t *testing.T) {
+       one := NewInt(1)
+       for _, a := range setStringTests {
+               var x Rat
+               x.SetString(a.in)
+               i := x.IsInt()
+               e := x.Denom().Cmp(one) == 0
+               if i != e {
+                       t.Errorf("got %v; want %v for z = %v", i, e, &x)
+               }
+       }
+}
+
+
+func TestRatAbs(t *testing.T) {
+       zero := NewRat(0, 1)
+       for _, a := range setStringTests {
+               var z Rat
+               z.SetString(a.in)
+               var e Rat
+               e.Set(&z)
+               if e.Cmp(zero) < 0 {
+                       e.Sub(zero, &e)
+               }
+               z.Abs(&z)
+               if z.Cmp(&e) != 0 {
+                       t.Errorf("got z = %v; want %v", &z, &e)
+               }
+       }
+}
+
+
+type ratBinFun func(z, x, y *Rat) *Rat
+type ratBinArg struct {
+       x, y, z string
+}
+
+func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
+       x, _ := NewRat(0, 1).SetString(a.x)
+       y, _ := NewRat(0, 1).SetString(a.y)
+       z, _ := NewRat(0, 1).SetString(a.z)
+       out := f(NewRat(0, 1), x, y)
+
+       if out.Cmp(z) != 0 {
+               t.Errorf("%s #%d got %s want %s", name, i, out, z)
+       }
+}
+
+
+var ratBinTests = []struct {
+       x, y      string
+       sum, prod string
+}{
+       {"0", "0", "0", "0"},
+       {"0", "1", "1", "0"},
+       {"-1", "0", "-1", "0"},
+       {"-1", "1", "0", "-1"},
+       {"1", "1", "2", "1"},
+       {"1/2", "1/2", "1", "1/4"},
+       {"1/4", "1/3", "7/12", "1/12"},
+       {"2/5", "-14/3", "-64/15", "-28/15"},
+       {"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"},
+       {"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"},
+       {"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"},
+       {"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"},
+       {"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"},
+       {"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"},
+       {"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"},
+       {"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"},
+       {"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"},
+       {"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"},
+}
+
+func TestRatBin(t *testing.T) {
+       for i, test := range ratBinTests {
+               arg := ratBinArg{test.x, test.y, test.sum}
+               testRatBin(t, i, "Add", (*Rat).Add, arg)
+
+               arg = ratBinArg{test.y, test.x, test.sum}
+               testRatBin(t, i, "Add symmetric", (*Rat).Add, arg)
+
+               arg = ratBinArg{test.sum, test.x, test.y}
+               testRatBin(t, i, "Sub", (*Rat).Sub, arg)
+
+               arg = ratBinArg{test.sum, test.y, test.x}
+               testRatBin(t, i, "Sub symmetric", (*Rat).Sub, arg)
+
+               arg = ratBinArg{test.x, test.y, test.prod}
+               testRatBin(t, i, "Mul", (*Rat).Mul, arg)
+
+               arg = ratBinArg{test.y, test.x, test.prod}
+               testRatBin(t, i, "Mul symmetric", (*Rat).Mul, arg)
+
+               if test.x != "0" {
+                       arg = ratBinArg{test.prod, test.x, test.y}
+                       testRatBin(t, i, "Quo", (*Rat).Quo, arg)
+               }
+
+               if test.y != "0" {
+                       arg = ratBinArg{test.prod, test.y, test.x}
+                       testRatBin(t, i, "Quo symmetric", (*Rat).Quo, arg)
+               }
+       }
+}
+
+
+func TestIssue820(t *testing.T) {
+       x := NewRat(3, 1)
+       y := NewRat(2, 1)
+       z := y.Quo(x, y)
+       q := NewRat(3, 2)
+       if z.Cmp(q) != 0 {
+               t.Errorf("got %s want %s", z, q)
+       }
+
+       y = NewRat(3, 1)
+       x = NewRat(2, 1)
+       z = y.Quo(x, y)
+       q = NewRat(2, 3)
+       if z.Cmp(q) != 0 {
+               t.Errorf("got %s want %s", z, q)
+       }
+
+       x = NewRat(3, 1)
+       z = x.Quo(x, x)
+       q = NewRat(3, 3)
+       if z.Cmp(q) != 0 {
+               t.Errorf("got %s want %s", z, q)
+       }
+}
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go
new file mode 100644 (file)
index 0000000..7d59fb8
--- /dev/null
@@ -0,0 +1,527 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements buffered I/O.  It wraps an io.Reader or io.Writer
+// object, creating another object (Reader or Writer) that also implements
+// the interface but provides buffering and some help for textual I/O.
+package bufio
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "strconv"
+       "utf8"
+)
+
+
+const (
+       defaultBufSize = 4096
+)
+
+// Errors introduced by this package.
+type Error struct {
+       os.ErrorString
+}
+
+var (
+       ErrInvalidUnreadByte os.Error = &Error{"bufio: invalid use of UnreadByte"}
+       ErrInvalidUnreadRune os.Error = &Error{"bufio: invalid use of UnreadRune"}
+       ErrBufferFull        os.Error = &Error{"bufio: buffer full"}
+       ErrNegativeCount     os.Error = &Error{"bufio: negative count"}
+       errInternal          os.Error = &Error{"bufio: internal error"}
+)
+
+// BufSizeError is the error representing an invalid buffer size.
+type BufSizeError int
+
+func (b BufSizeError) String() string {
+       return "bufio: bad buffer size " + strconv.Itoa(int(b))
+}
+
+
+// Buffered input.
+
+// Reader implements buffering for an io.Reader object.
+type Reader struct {
+       buf          []byte
+       rd           io.Reader
+       r, w         int
+       err          os.Error
+       lastByte     int
+       lastRuneSize int
+}
+
+// NewReaderSize creates a new Reader whose buffer has the specified size,
+// which must be greater than zero.  If the argument io.Reader is already a
+// Reader with large enough size, it returns the underlying Reader.
+// It returns the Reader and any error.
+func NewReaderSize(rd io.Reader, size int) (*Reader, os.Error) {
+       if size <= 0 {
+               return nil, BufSizeError(size)
+       }
+       // Is it already a Reader?
+       b, ok := rd.(*Reader)
+       if ok && len(b.buf) >= size {
+               return b, nil
+       }
+       b = new(Reader)
+       b.buf = make([]byte, size)
+       b.rd = rd
+       b.lastByte = -1
+       b.lastRuneSize = -1
+       return b, nil
+}
+
+// NewReader returns a new Reader whose buffer has the default size.
+func NewReader(rd io.Reader) *Reader {
+       b, err := NewReaderSize(rd, defaultBufSize)
+       if err != nil {
+               // cannot happen - defaultBufSize is a valid size
+               panic(err)
+       }
+       return b
+}
+
+// fill reads a new chunk into the buffer.
+func (b *Reader) fill() {
+       // Slide existing data to beginning.
+       if b.r > 0 {
+               copy(b.buf, b.buf[b.r:b.w])
+               b.w -= b.r
+               b.r = 0
+       }
+
+       // Read new data.
+       n, e := b.rd.Read(b.buf[b.w:])
+       b.w += n
+       if e != nil {
+               b.err = e
+       }
+}
+
+// Peek returns the next n bytes without advancing the reader. The bytes stop
+// being valid at the next read call. If Peek returns fewer than n bytes, it
+// also returns an error explaining why the read is short. The error is
+// ErrBufferFull if n is larger than b's buffer size.
+func (b *Reader) Peek(n int) ([]byte, os.Error) {
+       if n < 0 {
+               return nil, ErrNegativeCount
+       }
+       if n > len(b.buf) {
+               return nil, ErrBufferFull
+       }
+       for b.w-b.r < n && b.err == nil {
+               b.fill()
+       }
+       m := b.w - b.r
+       if m > n {
+               m = n
+       }
+       err := b.err
+       if m < n && err == nil {
+               err = ErrBufferFull
+       }
+       return b.buf[b.r : b.r+m], err
+}
+
+// Read reads data into p.
+// It returns the number of bytes read into p.
+// If nn < len(p), also returns an error explaining
+// why the read is short.  At EOF, the count will be
+// zero and err will be os.EOF.
+func (b *Reader) Read(p []byte) (nn int, err os.Error) {
+       nn = 0
+       for len(p) > 0 {
+               n := len(p)
+               if b.w == b.r {
+                       if b.err != nil {
+                               return nn, b.err
+                       }
+                       if len(p) >= len(b.buf) {
+                               // Large read, empty buffer.
+                               // Read directly into p to avoid copy.
+                               n, b.err = b.rd.Read(p)
+                               if n > 0 {
+                                       b.lastByte = int(p[n-1])
+                                       b.lastRuneSize = -1
+                               }
+                               p = p[n:]
+                               nn += n
+                               continue
+                       }
+                       b.fill()
+                       continue
+               }
+               if n > b.w-b.r {
+                       n = b.w - b.r
+               }
+               copy(p[0:n], b.buf[b.r:])
+               p = p[n:]
+               b.r += n
+               b.lastByte = int(b.buf[b.r-1])
+               b.lastRuneSize = -1
+               nn += n
+       }
+       return nn, nil
+}
+
+// ReadByte reads and returns a single byte.
+// If no byte is available, returns an error.
+func (b *Reader) ReadByte() (c byte, err os.Error) {
+       b.lastRuneSize = -1
+       for b.w == b.r {
+               if b.err != nil {
+                       return 0, b.err
+               }
+               b.fill()
+       }
+       c = b.buf[b.r]
+       b.r++
+       b.lastByte = int(c)
+       return c, nil
+}
+
+// UnreadByte unreads the last byte.  Only the most recently read byte can be unread.
+func (b *Reader) UnreadByte() os.Error {
+       b.lastRuneSize = -1
+       if b.r == b.w && b.lastByte >= 0 {
+               b.w = 1
+               b.r = 0
+               b.buf[0] = byte(b.lastByte)
+               b.lastByte = -1
+               return nil
+       }
+       if b.r <= 0 {
+               return ErrInvalidUnreadByte
+       }
+       b.r--
+       b.lastByte = -1
+       return nil
+}
+
+// ReadRune reads a single UTF-8 encoded Unicode character and returns the
+// rune and its size in bytes.
+func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
+       for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil {
+               b.fill()
+       }
+       b.lastRuneSize = -1
+       if b.r == b.w {
+               return 0, 0, b.err
+       }
+       rune, size = int(b.buf[b.r]), 1
+       if rune >= 0x80 {
+               rune, size = utf8.DecodeRune(b.buf[b.r:b.w])
+       }
+       b.r += size
+       b.lastByte = int(b.buf[b.r-1])
+       b.lastRuneSize = size
+       return rune, size, nil
+}
+
+// UnreadRune unreads the last rune.  If the most recent read operation on
+// the buffer was not a ReadRune, UnreadRune returns an error.  (In this
+// regard it is stricter than UnreadByte, which will unread the last byte
+// from any read operation.)
+func (b *Reader) UnreadRune() os.Error {
+       if b.lastRuneSize < 0 || b.r == 0 {
+               return ErrInvalidUnreadRune
+       }
+       b.r -= b.lastRuneSize
+       b.lastByte = -1
+       b.lastRuneSize = -1
+       return nil
+}
+
+// Buffered returns the number of bytes that can be read from the current buffer.
+func (b *Reader) Buffered() int { return b.w - b.r }
+
+// ReadSlice reads until the first occurrence of delim in the input,
+// returning a slice pointing at the bytes in the buffer.
+// The bytes stop being valid at the next read call.
+// If ReadSlice encounters an error before finding a delimiter,
+// it returns all the data in the buffer and the error itself (often os.EOF).
+// ReadSlice fails with error ErrBufferFull if the buffer fills without a delim.
+// Because the data returned from ReadSlice will be overwritten
+// by the next I/O operation, most clients should use
+// ReadBytes or ReadString instead.
+// ReadSlice returns err != nil if and only if line does not end in delim.
+func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
+       // Look in buffer.
+       if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
+               line1 := b.buf[b.r : b.r+i+1]
+               b.r += i + 1
+               return line1, nil
+       }
+
+       // Read more into buffer, until buffer fills or we find delim.
+       for {
+               if b.err != nil {
+                       line := b.buf[b.r:b.w]
+                       b.r = b.w
+                       return line, b.err
+               }
+
+               n := b.Buffered()
+               b.fill()
+
+               // Search new part of buffer
+               if i := bytes.IndexByte(b.buf[n:b.w], delim); i >= 0 {
+                       line := b.buf[0 : n+i+1]
+                       b.r = n + i + 1
+                       return line, nil
+               }
+
+               // Buffer is full?
+               if b.Buffered() >= len(b.buf) {
+                       b.r = b.w
+                       return b.buf, ErrBufferFull
+               }
+       }
+       panic("not reached")
+}
+
+// ReadBytes reads until the first occurrence of delim in the input,
+// returning a slice containing the data up to and including the delimiter.
+// If ReadBytes encounters an error before finding a delimiter,
+// it returns the data read before the error and the error itself (often os.EOF).
+// ReadBytes returns err != nil if and only if line does not end in delim.
+func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
+       // Use ReadSlice to look for array,
+       // accumulating full buffers.
+       var frag []byte
+       var full [][]byte
+       err = nil
+
+       for {
+               var e os.Error
+               frag, e = b.ReadSlice(delim)
+               if e == nil { // got final fragment
+                       break
+               }
+               if e != ErrBufferFull { // unexpected error
+                       err = e
+                       break
+               }
+
+               // Make a copy of the buffer.
+               buf := make([]byte, len(frag))
+               copy(buf, frag)
+               full = append(full, buf)
+       }
+
+       // Allocate new buffer to hold the full pieces and the fragment.
+       n := 0
+       for i := range full {
+               n += len(full[i])
+       }
+       n += len(frag)
+
+       // Copy full pieces and fragment in.
+       buf := make([]byte, n)
+       n = 0
+       for i := range full {
+               n += copy(buf[n:], full[i])
+       }
+       copy(buf[n:], frag)
+       return buf, err
+}
+
+// ReadString reads until the first occurrence of delim in the input,
+// returning a string containing the data up to and including the delimiter.
+// If ReadString encounters an error before finding a delimiter,
+// it returns the data read before the error and the error itself (often os.EOF).
+// ReadString returns err != nil if and only if line does not end in delim.
+func (b *Reader) ReadString(delim byte) (line string, err os.Error) {
+       bytes, e := b.ReadBytes(delim)
+       return string(bytes), e
+}
+
+
+// buffered output
+
+// Writer implements buffering for an io.Writer object.
+type Writer struct {
+       err os.Error
+       buf []byte
+       n   int
+       wr  io.Writer
+}
+
+// NewWriterSize creates a new Writer whose buffer has the specified size,
+// which must be greater than zero. If the argument io.Writer is already a
+// Writer with large enough size, it returns the underlying Writer.
+// It returns the Writer and any error.
+func NewWriterSize(wr io.Writer, size int) (*Writer, os.Error) {
+       if size <= 0 {
+               return nil, BufSizeError(size)
+       }
+       // Is it already a Writer?
+       b, ok := wr.(*Writer)
+       if ok && len(b.buf) >= size {
+               return b, nil
+       }
+       b = new(Writer)
+       b.buf = make([]byte, size)
+       b.wr = wr
+       return b, nil
+}
+
+// NewWriter returns a new Writer whose buffer has the default size.
+func NewWriter(wr io.Writer) *Writer {
+       b, err := NewWriterSize(wr, defaultBufSize)
+       if err != nil {
+               // cannot happen - defaultBufSize is valid size
+               panic(err)
+       }
+       return b
+}
+
+// Flush writes any buffered data to the underlying io.Writer.
+func (b *Writer) Flush() os.Error {
+       if b.err != nil {
+               return b.err
+       }
+       n, e := b.wr.Write(b.buf[0:b.n])
+       if n < b.n && e == nil {
+               e = io.ErrShortWrite
+       }
+       if e != nil {
+               if n > 0 && n < b.n {
+                       copy(b.buf[0:b.n-n], b.buf[n:b.n])
+               }
+               b.n -= n
+               b.err = e
+               return e
+       }
+       b.n = 0
+       return nil
+}
+
+// Available returns how many bytes are unused in the buffer.
+func (b *Writer) Available() int { return len(b.buf) - b.n }
+
+// Buffered returns the number of bytes that have been written into the current buffer.
+func (b *Writer) Buffered() int { return b.n }
+
+// Write writes the contents of p into the buffer.
+// It returns the number of bytes written.
+// If nn < len(p), it also returns an error explaining
+// why the write is short.
+func (b *Writer) Write(p []byte) (nn int, err os.Error) {
+       if b.err != nil {
+               return 0, b.err
+       }
+       nn = 0
+       for len(p) > 0 {
+               n := b.Available()
+               if n <= 0 {
+                       if b.Flush(); b.err != nil {
+                               break
+                       }
+                       n = b.Available()
+               }
+               if b.Buffered() == 0 && len(p) >= len(b.buf) {
+                       // Large write, empty buffer.
+                       // Write directly from p to avoid copy.
+                       n, b.err = b.wr.Write(p)
+                       nn += n
+                       p = p[n:]
+                       if b.err != nil {
+                               break
+                       }
+                       continue
+               }
+               if n > len(p) {
+                       n = len(p)
+               }
+               copy(b.buf[b.n:b.n+n], p[0:n])
+               b.n += n
+               nn += n
+               p = p[n:]
+       }
+       return nn, b.err
+}
+
+// WriteByte writes a single byte.
+func (b *Writer) WriteByte(c byte) os.Error {
+       if b.err != nil {
+               return b.err
+       }
+       if b.Available() <= 0 && b.Flush() != nil {
+               return b.err
+       }
+       b.buf[b.n] = c
+       b.n++
+       return nil
+}
+
+// WriteRune writes a single Unicode code point, returning
+// the number of bytes written and any error.
+func (b *Writer) WriteRune(rune int) (size int, err os.Error) {
+       if rune < utf8.RuneSelf {
+               err = b.WriteByte(byte(rune))
+               if err != nil {
+                       return 0, err
+               }
+               return 1, nil
+       }
+       if b.err != nil {
+               return 0, b.err
+       }
+       n := b.Available()
+       if n < utf8.UTFMax {
+               if b.Flush(); b.err != nil {
+                       return 0, b.err
+               }
+               n = b.Available()
+               if n < utf8.UTFMax {
+                       // Can only happen if buffer is silly small.
+                       return b.WriteString(string(rune))
+               }
+       }
+       size = utf8.EncodeRune(rune, b.buf[b.n:])
+       b.n += size
+       return size, nil
+}
+
+// WriteString writes a string.
+// It returns the number of bytes written.
+// If the count is less than len(s), it also returns an error explaining
+// why the write is short.
+func (b *Writer) WriteString(s string) (int, os.Error) {
+       if b.err != nil {
+               return 0, b.err
+       }
+       // Common case, worth making fast.
+       if b.Available() >= len(s) || len(b.buf) >= len(s) && b.Flush() == nil {
+               for i := 0; i < len(s); i++ { // loop over bytes, not runes.
+                       b.buf[b.n] = s[i]
+                       b.n++
+               }
+               return len(s), nil
+       }
+       for i := 0; i < len(s); i++ { // loop over bytes, not runes.
+               b.WriteByte(s[i])
+               if b.err != nil {
+                       return i, b.err
+               }
+       }
+       return len(s), nil
+}
+
+// buffered input and output
+
+// ReadWriter stores pointers to a Reader and a Writer.
+// It implements io.ReadWriter.
+type ReadWriter struct {
+       *Reader
+       *Writer
+}
+
+// NewReadWriter allocates a new ReadWriter that dispatches to r and w.
+func NewReadWriter(r *Reader, w *Writer) *ReadWriter {
+       return &ReadWriter{r, w}
+}
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
new file mode 100644 (file)
index 0000000..ef91d94
--- /dev/null
@@ -0,0 +1,572 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bufio
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "os"
+       "strings"
+       "testing"
+       "testing/iotest"
+       "utf8"
+)
+
+// Reads from a reader and rot13s the result.
+type rot13Reader struct {
+       r io.Reader
+}
+
+func newRot13Reader(r io.Reader) *rot13Reader {
+       r13 := new(rot13Reader)
+       r13.r = r
+       return r13
+}
+
+func (r13 *rot13Reader) Read(p []byte) (int, os.Error) {
+       n, e := r13.r.Read(p)
+       if e != nil {
+               return n, e
+       }
+       for i := 0; i < n; i++ {
+               c := p[i] | 0x20 // lowercase byte
+               if 'a' <= c && c <= 'm' {
+                       p[i] += 13
+               } else if 'n' <= c && c <= 'z' {
+                       p[i] -= 13
+               }
+       }
+       return n, nil
+}
+
+// Call ReadByte to accumulate the text of a file
+func readBytes(buf *Reader) string {
+       var b [1000]byte
+       nb := 0
+       for {
+               c, e := buf.ReadByte()
+               if e == os.EOF {
+                       break
+               }
+               if e != nil {
+                       panic("Data: " + e.String())
+               }
+               b[nb] = c
+               nb++
+       }
+       return string(b[0:nb])
+}
+
+func TestReaderSimple(t *testing.T) {
+       data := "hello world"
+       b := NewReader(bytes.NewBufferString(data))
+       if s := readBytes(b); s != "hello world" {
+               t.Errorf("simple hello world test failed: got %q", s)
+       }
+
+       b = NewReader(newRot13Reader(bytes.NewBufferString(data)))
+       if s := readBytes(b); s != "uryyb jbeyq" {
+               t.Errorf("rot13 hello world test failed: got %q", s)
+       }
+}
+
+
+type readMaker struct {
+       name string
+       fn   func(io.Reader) io.Reader
+}
+
+var readMakers = []readMaker{
+       {"full", func(r io.Reader) io.Reader { return r }},
+       {"byte", iotest.OneByteReader},
+       {"half", iotest.HalfReader},
+       {"data+err", iotest.DataErrReader},
+}
+
+// Call ReadString (which ends up calling everything else)
+// to accumulate the text of a file.
+func readLines(b *Reader) string {
+       s := ""
+       for {
+               s1, e := b.ReadString('\n')
+               if e == os.EOF {
+                       break
+               }
+               if e != nil {
+                       panic("GetLines: " + e.String())
+               }
+               s += s1
+       }
+       return s
+}
+
+// Call Read to accumulate the text of a file
+func reads(buf *Reader, m int) string {
+       var b [1000]byte
+       nb := 0
+       for {
+               n, e := buf.Read(b[nb : nb+m])
+               nb += n
+               if e == os.EOF {
+                       break
+               }
+       }
+       return string(b[0:nb])
+}
+
+type bufReader struct {
+       name string
+       fn   func(*Reader) string
+}
+
+var bufreaders = []bufReader{
+       {"1", func(b *Reader) string { return reads(b, 1) }},
+       {"2", func(b *Reader) string { return reads(b, 2) }},
+       {"3", func(b *Reader) string { return reads(b, 3) }},
+       {"4", func(b *Reader) string { return reads(b, 4) }},
+       {"5", func(b *Reader) string { return reads(b, 5) }},
+       {"7", func(b *Reader) string { return reads(b, 7) }},
+       {"bytes", readBytes},
+       {"lines", readLines},
+}
+
+var bufsizes = []int{
+       1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+       23, 32, 46, 64, 93, 128, 1024, 4096,
+}
+
+func TestReader(t *testing.T) {
+       var texts [31]string
+       str := ""
+       all := ""
+       for i := 0; i < len(texts)-1; i++ {
+               texts[i] = str + "\n"
+               all += texts[i]
+               str += string(i%26 + 'a')
+       }
+       texts[len(texts)-1] = all
+
+       for h := 0; h < len(texts); h++ {
+               text := texts[h]
+               for i := 0; i < len(readMakers); i++ {
+                       for j := 0; j < len(bufreaders); j++ {
+                               for k := 0; k < len(bufsizes); k++ {
+                                       readmaker := readMakers[i]
+                                       bufreader := bufreaders[j]
+                                       bufsize := bufsizes[k]
+                                       read := readmaker.fn(bytes.NewBufferString(text))
+                                       buf, _ := NewReaderSize(read, bufsize)
+                                       s := bufreader.fn(buf)
+                                       if s != text {
+                                               t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q",
+                                                       readmaker.name, bufreader.name, bufsize, text, s)
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+// A StringReader delivers its data one string segment at a time via Read.
+type StringReader struct {
+       data []string
+       step int
+}
+
+func (r *StringReader) Read(p []byte) (n int, err os.Error) {
+       if r.step < len(r.data) {
+               s := r.data[r.step]
+               n = copy(p, s)
+               r.step++
+       } else {
+               err = os.EOF
+       }
+       return
+}
+
+func readRuneSegments(t *testing.T, segments []string) {
+       got := ""
+       want := strings.Join(segments, "")
+       r := NewReader(&StringReader{data: segments})
+       for {
+               rune, _, err := r.ReadRune()
+               if err != nil {
+                       if err != os.EOF {
+                               return
+                       }
+                       break
+               }
+               got += string(rune)
+       }
+       if got != want {
+               t.Errorf("segments=%v got=%s want=%s", segments, got, want)
+       }
+}
+
+var segmentList = [][]string{
+       {},
+       {""},
+       {"日", "本語"},
+       {"\u65e5", "\u672c", "\u8a9e"},
+       {"\U000065e5", "\U0000672c", "\U00008a9e"},
+       {"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
+       {"Hello", ", ", "World", "!"},
+       {"Hello", ", ", "", "World", "!"},
+}
+
+func TestReadRune(t *testing.T) {
+       for _, s := range segmentList {
+               readRuneSegments(t, s)
+       }
+}
+
+func TestUnreadRune(t *testing.T) {
+       got := ""
+       segments := []string{"Hello, world:", "日本語"}
+       data := strings.Join(segments, "")
+       r := NewReader(&StringReader{data: segments})
+       // Normal execution.
+       for {
+               rune, _, err := r.ReadRune()
+               if err != nil {
+                       if err != os.EOF {
+                               t.Error("unexpected EOF")
+                       }
+                       break
+               }
+               got += string(rune)
+               // Put it back and read it again
+               if err = r.UnreadRune(); err != nil {
+                       t.Error("unexpected error on UnreadRune:", err)
+               }
+               rune1, _, err := r.ReadRune()
+               if err != nil {
+                       t.Error("unexpected error reading after unreading:", err)
+               }
+               if rune != rune1 {
+                       t.Errorf("incorrect rune after unread: got %c wanted %c", rune1, rune)
+               }
+       }
+       if got != data {
+               t.Errorf("want=%q got=%q", data, got)
+       }
+}
+
+// Test that UnreadRune fails if the preceding operation was not a ReadRune.
+func TestUnreadRuneError(t *testing.T) {
+       buf := make([]byte, 3) // All runes in this test are 3 bytes long
+       r := NewReader(&StringReader{data: []string{"日本語日本語日本語"}})
+       if r.UnreadRune() == nil {
+               t.Error("expected error on UnreadRune from fresh buffer")
+       }
+       _, _, err := r.ReadRune()
+       if err != nil {
+               t.Error("unexpected error on ReadRune (1):", err)
+       }
+       if err = r.UnreadRune(); err != nil {
+               t.Error("unexpected error on UnreadRune (1):", err)
+       }
+       if r.UnreadRune() == nil {
+               t.Error("expected error after UnreadRune (1)")
+       }
+       // Test error after Read.
+       _, _, err = r.ReadRune() // reset state
+       if err != nil {
+               t.Error("unexpected error on ReadRune (2):", err)
+       }
+       _, err = r.Read(buf)
+       if err != nil {
+               t.Error("unexpected error on Read (2):", err)
+       }
+       if r.UnreadRune() == nil {
+               t.Error("expected error after Read (2)")
+       }
+       // Test error after ReadByte.
+       _, _, err = r.ReadRune() // reset state
+       if err != nil {
+               t.Error("unexpected error on ReadRune (2):", err)
+       }
+       for _ = range buf {
+               _, err = r.ReadByte()
+               if err != nil {
+                       t.Error("unexpected error on ReadByte (2):", err)
+               }
+       }
+       if r.UnreadRune() == nil {
+               t.Error("expected error after ReadByte")
+       }
+       // Test error after UnreadByte.
+       _, _, err = r.ReadRune() // reset state
+       if err != nil {
+               t.Error("unexpected error on ReadRune (3):", err)
+       }
+       _, err = r.ReadByte()
+       if err != nil {
+               t.Error("unexpected error on ReadByte (3):", err)
+       }
+       err = r.UnreadByte()
+       if err != nil {
+               t.Error("unexpected error on UnreadByte (3):", err)
+       }
+       if r.UnreadRune() == nil {
+               t.Error("expected error after UnreadByte (3)")
+       }
+}
+
+func TestUnreadRuneAtEOF(t *testing.T) {
+       // UnreadRune/ReadRune should error at EOF (was a bug; used to panic)
+       r := NewReader(strings.NewReader("x"))
+       r.ReadRune()
+       r.ReadRune()
+       r.UnreadRune()
+       _, _, err := r.ReadRune()
+       if err == nil {
+               t.Error("expected error at EOF")
+       } else if err != os.EOF {
+               t.Error("expected EOF; got", err)
+       }
+}
+
+func TestReadWriteRune(t *testing.T) {
+       const NRune = 1000
+       byteBuf := new(bytes.Buffer)
+       w := NewWriter(byteBuf)
+       // Write the runes out using WriteRune
+       buf := make([]byte, utf8.UTFMax)
+       for rune := 0; rune < NRune; rune++ {
+               size := utf8.EncodeRune(rune, buf)
+               nbytes, err := w.WriteRune(rune)
+               if err != nil {
+                       t.Fatalf("WriteRune(0x%x) error: %s", rune, err)
+               }
+               if nbytes != size {
+                       t.Fatalf("WriteRune(0x%x) expected %d, got %d", rune, size, nbytes)
+               }
+       }
+       w.Flush()
+
+       r := NewReader(byteBuf)
+       // Read them back with ReadRune
+       for rune := 0; rune < NRune; rune++ {
+               size := utf8.EncodeRune(rune, buf)
+               nr, nbytes, err := r.ReadRune()
+               if nr != rune || nbytes != size || err != nil {
+                       t.Fatalf("ReadRune(0x%x) got 0x%x,%d not 0x%x,%d (err=%s)", r, nr, nbytes, r, size, err)
+               }
+       }
+}
+
+func TestWriter(t *testing.T) {
+       var data [8192]byte
+
+       for i := 0; i < len(data); i++ {
+               data[i] = byte(' ' + i%('~'-' '))
+       }
+       w := new(bytes.Buffer)
+       for i := 0; i < len(bufsizes); i++ {
+               for j := 0; j < len(bufsizes); j++ {
+                       nwrite := bufsizes[i]
+                       bs := bufsizes[j]
+
+                       // Write nwrite bytes using buffer size bs.
+                       // Check that the right amount makes it out
+                       // and that the data is correct.
+
+                       w.Reset()
+                       buf, e := NewWriterSize(w, bs)
+                       context := fmt.Sprintf("nwrite=%d bufsize=%d", nwrite, bs)
+                       if e != nil {
+                               t.Errorf("%s: NewWriterSize %d: %v", context, bs, e)
+                               continue
+                       }
+                       n, e1 := buf.Write(data[0:nwrite])
+                       if e1 != nil || n != nwrite {
+                               t.Errorf("%s: buf.Write %d = %d, %v", context, nwrite, n, e1)
+                               continue
+                       }
+                       if e = buf.Flush(); e != nil {
+                               t.Errorf("%s: buf.Flush = %v", context, e)
+                       }
+
+                       written := w.Bytes()
+                       if len(written) != nwrite {
+                               t.Errorf("%s: %d bytes written", context, len(written))
+                       }
+                       for l := 0; l < len(written); l++ {
+                               if written[i] != data[i] {
+                                       t.Errorf("%s: wrong bytes written")
+                                       t.Errorf("want=%s", data[0:len(written)])
+                                       t.Errorf("have=%s", written)
+                               }
+                       }
+               }
+       }
+}
+
+// Check that write errors are returned properly.
+
+type errorWriterTest struct {
+       n, m   int
+       err    os.Error
+       expect os.Error
+}
+
+func (w errorWriterTest) Write(p []byte) (int, os.Error) {
+       return len(p) * w.n / w.m, w.err
+}
+
+var errorWriterTests = []errorWriterTest{
+       {0, 1, nil, io.ErrShortWrite},
+       {1, 2, nil, io.ErrShortWrite},
+       {1, 1, nil, nil},
+       {0, 1, os.EPIPE, os.EPIPE},
+       {1, 2, os.EPIPE, os.EPIPE},
+       {1, 1, os.EPIPE, os.EPIPE},
+}
+
+func TestWriteErrors(t *testing.T) {
+       for _, w := range errorWriterTests {
+               buf := NewWriter(w)
+               _, e := buf.Write([]byte("hello world"))
+               if e != nil {
+                       t.Errorf("Write hello to %v: %v", w, e)
+                       continue
+               }
+               e = buf.Flush()
+               if e != w.expect {
+                       t.Errorf("Flush %v: got %v, wanted %v", w, e, w.expect)
+               }
+       }
+}
+
+func TestNewReaderSizeIdempotent(t *testing.T) {
+       const BufSize = 1000
+       b, err := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
+       if err != nil {
+               t.Error("NewReaderSize create fail", err)
+       }
+       // Does it recognize itself?
+       b1, err2 := NewReaderSize(b, BufSize)
+       if err2 != nil {
+               t.Error("NewReaderSize #2 create fail", err2)
+       }
+       if b1 != b {
+               t.Error("NewReaderSize did not detect underlying Reader")
+       }
+       // Does it wrap if existing buffer is too small?
+       b2, err3 := NewReaderSize(b, 2*BufSize)
+       if err3 != nil {
+               t.Error("NewReaderSize #3 create fail", err3)
+       }
+       if b2 == b {
+               t.Error("NewReaderSize did not enlarge buffer")
+       }
+}
+
+func TestNewWriterSizeIdempotent(t *testing.T) {
+       const BufSize = 1000
+       b, err := NewWriterSize(new(bytes.Buffer), BufSize)
+       if err != nil {
+               t.Error("NewWriterSize create fail", err)
+       }
+       // Does it recognize itself?
+       b1, err2 := NewWriterSize(b, BufSize)
+       if err2 != nil {
+               t.Error("NewWriterSize #2 create fail", err2)
+       }
+       if b1 != b {
+               t.Error("NewWriterSize did not detect underlying Writer")
+       }
+       // Does it wrap if existing buffer is too small?
+       b2, err3 := NewWriterSize(b, 2*BufSize)
+       if err3 != nil {
+               t.Error("NewWriterSize #3 create fail", err3)
+       }
+       if b2 == b {
+               t.Error("NewWriterSize did not enlarge buffer")
+       }
+}
+
+func TestWriteString(t *testing.T) {
+       const BufSize = 8
+       buf := new(bytes.Buffer)
+       b, err := NewWriterSize(buf, BufSize)
+       if err != nil {
+               t.Error("NewWriterSize create fail", err)
+       }
+       b.WriteString("0")                         // easy
+       b.WriteString("123456")                    // still easy
+       b.WriteString("7890")                      // easy after flush
+       b.WriteString("abcdefghijklmnopqrstuvwxy") // hard
+       b.WriteString("z")
+       b.Flush()
+       if b.err != nil {
+               t.Error("WriteString", b.err)
+       }
+       s := "01234567890abcdefghijklmnopqrstuvwxyz"
+       if string(buf.Bytes()) != s {
+               t.Errorf("WriteString wants %q gets %q", s, string(buf.Bytes()))
+       }
+}
+
+func TestBufferFull(t *testing.T) {
+       buf, _ := NewReaderSize(strings.NewReader("hello, world"), 5)
+       line, err := buf.ReadSlice(',')
+       if string(line) != "hello" || err != ErrBufferFull {
+               t.Errorf("first ReadSlice(,) = %q, %v", line, err)
+       }
+       line, err = buf.ReadSlice(',')
+       if string(line) != "," || err != nil {
+               t.Errorf("second ReadSlice(,) = %q, %v", line, err)
+       }
+}
+
+func TestPeek(t *testing.T) {
+       p := make([]byte, 10)
+       buf, _ := NewReaderSize(strings.NewReader("abcdefghij"), 4)
+       if s, err := buf.Peek(1); string(s) != "a" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "a", string(s), err)
+       }
+       if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "abcd", string(s), err)
+       }
+       if _, err := buf.Peek(5); err != ErrBufferFull {
+               t.Fatalf("want ErrBufFull got %v", err)
+       }
+       if _, err := buf.Read(p[0:3]); string(p[0:3]) != "abc" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "abc", string(p[0:3]), err)
+       }
+       if s, err := buf.Peek(1); string(s) != "d" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "d", string(s), err)
+       }
+       if s, err := buf.Peek(2); string(s) != "de" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "de", string(s), err)
+       }
+       if _, err := buf.Read(p[0:3]); string(p[0:3]) != "def" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "def", string(p[0:3]), err)
+       }
+       if s, err := buf.Peek(4); string(s) != "ghij" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "ghij", string(s), err)
+       }
+       if _, err := buf.Read(p[0:4]); string(p[0:4]) != "ghij" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "ghij", string(p[0:3]), err)
+       }
+       if s, err := buf.Peek(0); string(s) != "" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "", string(s), err)
+       }
+       if _, err := buf.Peek(1); err != os.EOF {
+               t.Fatalf("want EOF got %v", err)
+       }
+}
+
+func TestPeekThenUnreadRune(t *testing.T) {
+       // This sequence used to cause a crash.
+       r := NewReader(strings.NewReader("x"))
+       r.ReadRune()
+       r.Peek(1)
+       r.UnreadRune()
+       r.ReadRune() // Used to panic here
+}
diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go
new file mode 100644 (file)
index 0000000..6f93869
--- /dev/null
@@ -0,0 +1,254 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+// Simple byte buffer for marshaling data.
+
+import (
+       "io"
+       "os"
+       "utf8"
+)
+
+// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
+// The zero value for Buffer is an empty buffer ready to use.
+type Buffer struct {
+       buf       []byte            // contents are the bytes buf[off : len(buf)]
+       off       int               // read at &buf[off], write at &buf[len(buf)]
+       runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
+       bootstrap [64]byte          // memory to hold first slice; helps small buffers (Printf) avoid allocation.
+}
+
+// Bytes returns a slice of the contents of the unread portion of the buffer;
+// len(b.Bytes()) == b.Len().  If the caller changes the contents of the
+// returned slice, the contents of the buffer will change provided there
+// are no intervening method calls on the Buffer.
+func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
+
+// String returns the contents of the unread portion of the buffer
+// as a string.  If the Buffer is a nil pointer, it returns "<nil>".
+func (b *Buffer) String() string {
+       if b == nil {
+               // Special case, useful in debugging.
+               return "<nil>"
+       }
+       return string(b.buf[b.off:])
+}
+
+// Len returns the number of bytes of the unread portion of the buffer;
+// b.Len() == len(b.Bytes()).
+func (b *Buffer) Len() int { return len(b.buf) - b.off }
+
+// Truncate discards all but the first n unread bytes from the buffer.
+// It is an error to call b.Truncate(n) with n > b.Len().
+func (b *Buffer) Truncate(n int) {
+       if n == 0 {
+               // Reuse buffer space.
+               b.off = 0
+       }
+       b.buf = b.buf[0 : b.off+n]
+}
+
+// Reset resets the buffer so it has no content.
+// b.Reset() is the same as b.Truncate(0).
+func (b *Buffer) Reset() { b.Truncate(0) }
+
+// Grow buffer to guarantee space for n more bytes.
+// Return index where bytes should be written.
+func (b *Buffer) grow(n int) int {
+       m := b.Len()
+       // If buffer is empty, reset to recover space.
+       if m == 0 && b.off != 0 {
+               b.Truncate(0)
+       }
+       if len(b.buf)+n > cap(b.buf) {
+               var buf []byte
+               if b.buf == nil && n <= len(b.bootstrap) {
+                       buf = b.bootstrap[0:]
+               } else {
+                       // not enough space anywhere
+                       buf = make([]byte, 2*cap(b.buf)+n)
+                       copy(buf, b.buf[b.off:])
+               }
+               b.buf = buf
+               b.off = 0
+       }
+       b.buf = b.buf[0 : b.off+m+n]
+       return b.off + m
+}
+
+// Write appends the contents of p to the buffer.  The return
+// value n is the length of p; err is always nil.
+func (b *Buffer) Write(p []byte) (n int, err os.Error) {
+       m := b.grow(len(p))
+       copy(b.buf[m:], p)
+       return len(p), nil
+}
+
+// WriteString appends the contents of s to the buffer.  The return
+// value n is the length of s; err is always nil.
+func (b *Buffer) WriteString(s string) (n int, err os.Error) {
+       m := b.grow(len(s))
+       return copy(b.buf[m:], s), nil
+}
+
+// MinRead is the minimum slice size passed to a Read call by
+// Buffer.ReadFrom.  As long as the Buffer has at least MinRead bytes beyond
+// what is required to hold the contents of r, ReadFrom will not grow the
+// underlying buffer.
+const MinRead = 512
+
+// ReadFrom reads data from r until EOF and appends it to the buffer.
+// The return value n is the number of bytes read.
+// Any error except os.EOF encountered during the read
+// is also returned.
+func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
+       // If buffer is empty, reset to recover space.
+       if b.off >= len(b.buf) {
+               b.Truncate(0)
+       }
+       for {
+               if cap(b.buf)-len(b.buf) < MinRead {
+                       var newBuf []byte
+                       // can we get space without allocation?
+                       if b.off+cap(b.buf)-len(b.buf) >= MinRead {
+                               // reuse beginning of buffer
+                               newBuf = b.buf[0 : len(b.buf)-b.off]
+                       } else {
+                               // not enough space at end; put space on end
+                               newBuf = make([]byte, len(b.buf)-b.off, 2*(cap(b.buf)-b.off)+MinRead)
+                       }
+                       copy(newBuf, b.buf[b.off:])
+                       b.buf = newBuf
+                       b.off = 0
+               }
+               m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
+               b.buf = b.buf[0 : len(b.buf)+m]
+               n += int64(m)
+               if e == os.EOF {
+                       break
+               }
+               if e != nil {
+                       return n, e
+               }
+       }
+       return n, nil // err is EOF, so return nil explicitly
+}
+
+// WriteTo writes data to w until the buffer is drained or an error
+// occurs. The return value n is the number of bytes written.
+// Any error encountered during the write is also returned.
+func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
+       for b.off < len(b.buf) {
+               m, e := w.Write(b.buf[b.off:])
+               n += int64(m)
+               b.off += m
+               if e != nil {
+                       return n, e
+               }
+       }
+       // Buffer is now empty; reset.
+       b.Truncate(0)
+       return
+}
+
+// WriteByte appends the byte c to the buffer.
+// The returned error is always nil, but is included
+// to match bufio.Writer's WriteByte.
+func (b *Buffer) WriteByte(c byte) os.Error {
+       m := b.grow(1)
+       b.buf[m] = c
+       return nil
+}
+
+// WriteRune appends the UTF-8 encoding of Unicode
+// code point r to the buffer, returning its length and
+// an error, which is always nil but is included
+// to match bufio.Writer's WriteRune.
+func (b *Buffer) WriteRune(r int) (n int, err os.Error) {
+       if r < utf8.RuneSelf {
+               b.WriteByte(byte(r))
+               return 1, nil
+       }
+       n = utf8.EncodeRune(r, b.runeBytes[0:])
+       b.Write(b.runeBytes[0:n])
+       return n, nil
+}
+
+// Read reads the next len(p) bytes from the buffer or until the buffer
+// is drained.  The return value n is the number of bytes read.  If the
+// buffer has no data to return, err is os.EOF even if len(p) is zero;
+// otherwise it is nil.
+func (b *Buffer) Read(p []byte) (n int, err os.Error) {
+       if b.off >= len(b.buf) {
+               // Buffer is empty, reset to recover space.
+               b.Truncate(0)
+               return 0, os.EOF
+       }
+       n = copy(p, b.buf[b.off:])
+       b.off += n
+       return
+}
+
+// Next returns a slice containing the next n bytes from the buffer,
+// advancing the buffer as if the bytes had been returned by Read.
+// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
+// The slice is only valid until the next call to a read or write method.
+func (b *Buffer) Next(n int) []byte {
+       m := b.Len()
+       if n > m {
+               n = m
+       }
+       data := b.buf[b.off : b.off+n]
+       b.off += n
+       return data
+}
+
+// ReadByte reads and returns the next byte from the buffer.
+// If no byte is available, it returns error os.EOF.
+func (b *Buffer) ReadByte() (c byte, err os.Error) {
+       if b.off >= len(b.buf) {
+               // Buffer is empty, reset to recover space.
+               b.Truncate(0)
+               return 0, os.EOF
+       }
+       c = b.buf[b.off]
+       b.off++
+       return c, nil
+}
+
+// ReadRune reads and returns the next UTF-8-encoded
+// Unicode code point from the buffer.
+// If no bytes are available, the error returned is os.EOF.
+// If the bytes are an erroneous UTF-8 encoding, it
+// consumes one byte and returns U+FFFD, 1.
+func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
+       if b.off >= len(b.buf) {
+               // Buffer is empty, reset to recover space.
+               b.Truncate(0)
+               return 0, 0, os.EOF
+       }
+       c := b.buf[b.off]
+       if c < utf8.RuneSelf {
+               b.off++
+               return int(c), 1, nil
+       }
+       r, n := utf8.DecodeRune(b.buf[b.off:])
+       b.off += n
+       return r, n, nil
+}
+
+// NewBuffer creates and initializes a new Buffer using buf as its initial
+// contents.  It is intended to prepare a Buffer to read existing data.  It
+// can also be used to to size the internal buffer for writing.  To do that,
+// buf should have the desired capacity but a length of zero.
+func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
+
+// NewBufferString creates and initializes a new Buffer using string s as its
+// initial contents.  It is intended to prepare a buffer to read an existing
+// string.
+func NewBufferString(s string) *Buffer {
+       return &Buffer{buf: []byte(s)}
+}
diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go
new file mode 100644 (file)
index 0000000..1ba7749
--- /dev/null
@@ -0,0 +1,334 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes_test
+
+import (
+       . "bytes"
+       "rand"
+       "testing"
+       "utf8"
+)
+
+
+const N = 10000  // make this bigger for a larger (and slower) test
+var data string  // test data for write tests
+var bytes []byte // test data; same as data but as a slice.
+
+
+func init() {
+       bytes = make([]byte, N)
+       for i := 0; i < N; i++ {
+               bytes[i] = 'a' + byte(i%26)
+       }
+       data = string(bytes)
+}
+
+// Verify that contents of buf match the string s.
+func check(t *testing.T, testname string, buf *Buffer, s string) {
+       bytes := buf.Bytes()
+       str := buf.String()
+       if buf.Len() != len(bytes) {
+               t.Errorf("%s: buf.Len() == %d, len(buf.Bytes()) == %d", testname, buf.Len(), len(bytes))
+       }
+
+       if buf.Len() != len(str) {
+               t.Errorf("%s: buf.Len() == %d, len(buf.String()) == %d", testname, buf.Len(), len(str))
+       }
+
+       if buf.Len() != len(s) {
+               t.Errorf("%s: buf.Len() == %d, len(s) == %d", testname, buf.Len(), len(s))
+       }
+
+       if string(bytes) != s {
+               t.Errorf("%s: string(buf.Bytes()) == %q, s == %q", testname, string(bytes), s)
+       }
+}
+
+
+// Fill buf through n writes of string fus.
+// The initial contents of buf corresponds to the string s;
+// the result is the final contents of buf returned as a string.
+func fillString(t *testing.T, testname string, buf *Buffer, s string, n int, fus string) string {
+       check(t, testname+" (fill 1)", buf, s)
+       for ; n > 0; n-- {
+               m, err := buf.WriteString(fus)
+               if m != len(fus) {
+                       t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fus))
+               }
+               if err != nil {
+                       t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
+               }
+               s += fus
+               check(t, testname+" (fill 4)", buf, s)
+       }
+       return s
+}
+
+
+// Fill buf through n writes of byte slice fub.
+// The initial contents of buf corresponds to the string s;
+// the result is the final contents of buf returned as a string.
+func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub []byte) string {
+       check(t, testname+" (fill 1)", buf, s)
+       for ; n > 0; n-- {
+               m, err := buf.Write(fub)
+               if m != len(fub) {
+                       t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fub))
+               }
+               if err != nil {
+                       t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
+               }
+               s += string(fub)
+               check(t, testname+" (fill 4)", buf, s)
+       }
+       return s
+}
+
+
+func TestNewBuffer(t *testing.T) {
+       buf := NewBuffer(bytes)
+       check(t, "NewBuffer", buf, data)
+}
+
+
+func TestNewBufferString(t *testing.T) {
+       buf := NewBufferString(data)
+       check(t, "NewBufferString", buf, data)
+}
+
+
+// Empty buf through repeated reads into fub.
+// The initial contents of buf corresponds to the string s.
+func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) {
+       check(t, testname+" (empty 1)", buf, s)
+
+       for {
+               n, err := buf.Read(fub)
+               if n == 0 {
+                       break
+               }
+               if err != nil {
+                       t.Errorf(testname+" (empty 2): err should always be nil, found err == %s", err)
+               }
+               s = s[n:]
+               check(t, testname+" (empty 3)", buf, s)
+       }
+
+       check(t, testname+" (empty 4)", buf, "")
+}
+
+
+func TestBasicOperations(t *testing.T) {
+       var buf Buffer
+
+       for i := 0; i < 5; i++ {
+               check(t, "TestBasicOperations (1)", &buf, "")
+
+               buf.Reset()
+               check(t, "TestBasicOperations (2)", &buf, "")
+
+               buf.Truncate(0)
+               check(t, "TestBasicOperations (3)", &buf, "")
+
+               n, err := buf.Write([]byte(data[0:1]))
+               if n != 1 {
+                       t.Errorf("wrote 1 byte, but n == %d", n)
+               }
+               if err != nil {
+                       t.Errorf("err should always be nil, but err == %s", err)
+               }
+               check(t, "TestBasicOperations (4)", &buf, "a")
+
+               buf.WriteByte(data[1])
+               check(t, "TestBasicOperations (5)", &buf, "ab")
+
+               n, err = buf.Write([]byte(data[2:26]))
+               if n != 24 {
+                       t.Errorf("wrote 25 bytes, but n == %d", n)
+               }
+               check(t, "TestBasicOperations (6)", &buf, string(data[0:26]))
+
+               buf.Truncate(26)
+               check(t, "TestBasicOperations (7)", &buf, string(data[0:26]))
+
+               buf.Truncate(20)
+               check(t, "TestBasicOperations (8)", &buf, string(data[0:20]))
+
+               empty(t, "TestBasicOperations (9)", &buf, string(data[0:20]), make([]byte, 5))
+               empty(t, "TestBasicOperations (10)", &buf, "", make([]byte, 100))
+
+               buf.WriteByte(data[1])
+               c, err := buf.ReadByte()
+               if err != nil {
+                       t.Error("ReadByte unexpected eof")
+               }
+               if c != data[1] {
+                       t.Error("ReadByte wrong value c=%v", c)
+               }
+               c, err = buf.ReadByte()
+               if err == nil {
+                       t.Error("ReadByte unexpected not eof")
+               }
+       }
+}
+
+
+func TestLargeStringWrites(t *testing.T) {
+       var buf Buffer
+       for i := 3; i < 30; i += 3 {
+               s := fillString(t, "TestLargeWrites (1)", &buf, "", 5, data)
+               empty(t, "TestLargeStringWrites (2)", &buf, s, make([]byte, len(data)/i))
+       }
+       check(t, "TestLargeStringWrites (3)", &buf, "")
+}
+
+
+func TestLargeByteWrites(t *testing.T) {
+       var buf Buffer
+       for i := 3; i < 30; i += 3 {
+               s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, bytes)
+               empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i))
+       }
+       check(t, "TestLargeByteWrites (3)", &buf, "")
+}
+
+
+func TestLargeStringReads(t *testing.T) {
+       var buf Buffer
+       for i := 3; i < 30; i += 3 {
+               s := fillString(t, "TestLargeReads (1)", &buf, "", 5, data[0:len(data)/i])
+               empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data)))
+       }
+       check(t, "TestLargeStringReads (3)", &buf, "")
+}
+
+
+func TestLargeByteReads(t *testing.T) {
+       var buf Buffer
+       for i := 3; i < 30; i += 3 {
+               s := fillBytes(t, "TestLargeReads (1)", &buf, "", 5, bytes[0:len(bytes)/i])
+               empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data)))
+       }
+       check(t, "TestLargeByteReads (3)", &buf, "")
+}
+
+
+func TestMixedReadsAndWrites(t *testing.T) {
+       var buf Buffer
+       s := ""
+       for i := 0; i < 50; i++ {
+               wlen := rand.Intn(len(data))
+               if i%2 == 0 {
+                       s = fillString(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, data[0:wlen])
+               } else {
+                       s = fillBytes(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, bytes[0:wlen])
+               }
+
+               rlen := rand.Intn(len(data))
+               fub := make([]byte, rlen)
+               n, _ := buf.Read(fub)
+               s = s[n:]
+       }
+       empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
+}
+
+
+func TestNil(t *testing.T) {
+       var b *Buffer
+       if b.String() != "<nil>" {
+               t.Errorf("expcted <nil>; got %q", b.String())
+       }
+}
+
+
+func TestReadFrom(t *testing.T) {
+       var buf Buffer
+       for i := 3; i < 30; i += 3 {
+               s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, bytes[0:len(bytes)/i])
+               var b Buffer
+               b.ReadFrom(&buf)
+               empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data)))
+       }
+}
+
+
+func TestWriteTo(t *testing.T) {
+       var buf Buffer
+       for i := 3; i < 30; i += 3 {
+               s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, bytes[0:len(bytes)/i])
+               var b Buffer
+               buf.WriteTo(&b)
+               empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data)))
+       }
+}
+
+
+func TestRuneIO(t *testing.T) {
+       const NRune = 1000
+       // Built a test array while we write the data
+       b := make([]byte, utf8.UTFMax*NRune)
+       var buf Buffer
+       n := 0
+       for r := 0; r < NRune; r++ {
+               size := utf8.EncodeRune(r, b[n:])
+               nbytes, err := buf.WriteRune(r)
+               if err != nil {
+                       t.Fatalf("WriteRune(0x%x) error: %s", r, err)
+               }
+               if nbytes != size {
+                       t.Fatalf("WriteRune(0x%x) expected %d, got %d", r, size, nbytes)
+               }
+               n += size
+       }
+       b = b[0:n]
+
+       // Check the resulting bytes
+       if !Equal(buf.Bytes(), b) {
+               t.Fatalf("incorrect result from WriteRune: %q not %q", buf.Bytes(), b)
+       }
+
+       // Read it back with ReadRune
+       for r := 0; r < NRune; r++ {
+               size := utf8.EncodeRune(r, b)
+               nr, nbytes, err := buf.ReadRune()
+               if nr != r || nbytes != size || err != nil {
+                       t.Fatalf("ReadRune(0x%x) got 0x%x,%d not 0x%x,%d (err=%s)", r, nr, nbytes, r, size, err)
+               }
+       }
+}
+
+
+func TestNext(t *testing.T) {
+       b := []byte{0, 1, 2, 3, 4}
+       tmp := make([]byte, 5)
+       for i := 0; i <= 5; i++ {
+               for j := i; j <= 5; j++ {
+                       for k := 0; k <= 6; k++ {
+                               // 0 <= i <= j <= 5; 0 <= k <= 6
+                               // Check that if we start with a buffer
+                               // of length j at offset i and ask for
+                               // Next(k), we get the right bytes.
+                               buf := NewBuffer(b[0:j])
+                               n, _ := buf.Read(tmp[0:i])
+                               if n != i {
+                                       t.Fatalf("Read %d returned %d", i, n)
+                               }
+                               bb := buf.Next(k)
+                               want := k
+                               if want > j-i {
+                                       want = j - i
+                               }
+                               if len(bb) != want {
+                                       t.Fatalf("in %d,%d: len(Next(%d)) == %d", i, j, k, len(bb))
+                               }
+                               for l, v := range bb {
+                                       if v != byte(l+i) {
+                                               t.Fatalf("in %d,%d: Next(%d)[%d] = %d, want %d", i, j, k, l, v, l+i)
+                                       }
+                               }
+                       }
+               }
+       }
+}
diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go
new file mode 100644 (file)
index 0000000..1939fd5
--- /dev/null
@@ -0,0 +1,625 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The bytes package implements functions for the manipulation of byte slices.
+// Analogous to the facilities of the strings package.
+package bytes
+
+import (
+       "unicode"
+       "utf8"
+)
+
+// Compare returns an integer comparing the two byte arrays lexicographically.
+// The result will be 0 if a==b, -1 if a < b, and +1 if a > b
+func Compare(a, b []byte) int {
+       m := len(a)
+       if m > len(b) {
+               m = len(b)
+       }
+       for i, ac := range a[0:m] {
+               bc := b[i]
+               switch {
+               case ac > bc:
+                       return 1
+               case ac < bc:
+                       return -1
+               }
+       }
+       switch {
+       case len(a) < len(b):
+               return -1
+       case len(a) > len(b):
+               return 1
+       }
+       return 0
+}
+
+// Equal returns a boolean reporting whether a == b.
+func Equal(a, b []byte) bool {
+       if len(a) != len(b) {
+               return false
+       }
+       for i, c := range a {
+               if c != b[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+// explode splits s into an array of UTF-8 sequences, one per Unicode character (still arrays of bytes),
+// up to a maximum of n byte arrays. Invalid UTF-8 sequences are chopped into individual bytes.
+func explode(s []byte, n int) [][]byte {
+       if n <= 0 {
+               n = len(s)
+       }
+       a := make([][]byte, n)
+       var size int
+       na := 0
+       for len(s) > 0 {
+               if na+1 >= n {
+                       a[na] = s
+                       na++
+                       break
+               }
+               _, size = utf8.DecodeRune(s)
+               a[na] = s[0:size]
+               s = s[size:]
+               na++
+       }
+       return a[0:na]
+}
+
+// Count counts the number of non-overlapping instances of sep in s.
+func Count(s, sep []byte) int {
+       if len(sep) == 0 {
+               return utf8.RuneCount(s) + 1
+       }
+       c := sep[0]
+       n := 0
+       for i := 0; i+len(sep) <= len(s); i++ {
+               if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) {
+                       n++
+                       i += len(sep) - 1
+               }
+       }
+       return n
+}
+
+// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
+func Index(s, sep []byte) int {
+       n := len(sep)
+       if n == 0 {
+               return 0
+       }
+       c := sep[0]
+       for i := 0; i+n <= len(s); i++ {
+               if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) {
+                       return i
+               }
+       }
+       return -1
+}
+
+func indexBytePortable(s []byte, c byte) int {
+       for i, b := range s {
+               if b == c {
+                       return i
+               }
+       }
+       return -1
+}
+
+// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
+func LastIndex(s, sep []byte) int {
+       n := len(sep)
+       if n == 0 {
+               return len(s)
+       }
+       c := sep[0]
+       for i := len(s) - n; i >= 0; i-- {
+               if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) {
+                       return i
+               }
+       }
+       return -1
+}
+
+// IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index of the first occurrence in s of the given rune.
+// It returns -1 if rune is not present in s.
+func IndexRune(s []byte, rune int) int {
+       for i := 0; i < len(s); {
+               r, size := utf8.DecodeRune(s[i:])
+               if r == rune {
+                       return i
+               }
+               i += size
+       }
+       return -1
+}
+
+// IndexAny interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index of the first occurrence in s of any of the Unicode
+// code points in chars.  It returns -1 if chars is empty or if there is no code
+// point in common.
+func IndexAny(s []byte, chars string) int {
+       if len(chars) > 0 {
+               var rune, width int
+               for i := 0; i < len(s); i += width {
+                       rune = int(s[i])
+                       if rune < utf8.RuneSelf {
+                               width = 1
+                       } else {
+                               rune, width = utf8.DecodeRune(s[i:])
+                       }
+                       for _, r := range chars {
+                               if rune == r {
+                                       return i
+                               }
+                       }
+               }
+       }
+       return -1
+}
+
+// Generic split: splits after each instance of sep,
+// including sepSave bytes of sep in the subarrays.
+func genSplit(s, sep []byte, sepSave, n int) [][]byte {
+       if n == 0 {
+               return nil
+       }
+       if len(sep) == 0 {
+               return explode(s, n)
+       }
+       if n < 0 {
+               n = Count(s, sep) + 1
+       }
+       c := sep[0]
+       start := 0
+       a := make([][]byte, n)
+       na := 0
+       for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
+               if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) {
+                       a[na] = s[start : i+sepSave]
+                       na++
+                       start = i + len(sep)
+                       i += len(sep) - 1
+               }
+       }
+       a[na] = s[start:]
+       return a[0 : na+1]
+}
+
+// Split slices s into subslices separated by sep and returns a slice of
+// the subslices between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of subslices to return:
+//   n > 0: at most n subslices; the last subslice will be the unsplit remainder.
+//   n == 0: the result is nil (zero subslices)
+//   n < 0: all subslices
+func Split(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
+
+// SplitAfter slices s into subslices after each instance of sep and
+// returns a slice of those subslices.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of subslices to return:
+//   n > 0: at most n subslices; the last subslice will be the unsplit remainder.
+//   n == 0: the result is nil (zero subslices)
+//   n < 0: all subslices
+func SplitAfter(s, sep []byte, n int) [][]byte {
+       return genSplit(s, sep, len(sep), n)
+}
+
+// Fields splits the array s around each instance of one or more consecutive white space
+// characters, returning a slice of subarrays of s or an empty list if s contains only white space.
+func Fields(s []byte) [][]byte {
+       return FieldsFunc(s, unicode.IsSpace)
+}
+
+// FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It splits the array s at each run of code points c satisfying f(c) and
+// returns a slice of subarrays of s.  If no code points in s satisfy f(c), an
+// empty slice is returned.
+func FieldsFunc(s []byte, f func(int) bool) [][]byte {
+       n := 0
+       inField := false
+       for i := 0; i < len(s); {
+               rune, size := utf8.DecodeRune(s[i:])
+               wasInField := inField
+               inField = !f(rune)
+               if inField && !wasInField {
+                       n++
+               }
+               i += size
+       }
+
+       a := make([][]byte, n)
+       na := 0
+       fieldStart := -1
+       for i := 0; i <= len(s) && na < n; {
+               rune, size := utf8.DecodeRune(s[i:])
+               if fieldStart < 0 && size > 0 && !f(rune) {
+                       fieldStart = i
+                       i += size
+                       continue
+               }
+               if fieldStart >= 0 && (size == 0 || f(rune)) {
+                       a[na] = s[fieldStart:i]
+                       na++
+                       fieldStart = -1
+               }
+               if size == 0 {
+                       break
+               }
+               i += size
+       }
+       return a[0:na]
+}
+
+// Join concatenates the elements of a to create a single byte array.   The separator
+// sep is placed between elements in the resulting array.
+func Join(a [][]byte, sep []byte) []byte {
+       if len(a) == 0 {
+               return []byte{}
+       }
+       if len(a) == 1 {
+               return a[0]
+       }
+       n := len(sep) * (len(a) - 1)
+       for i := 0; i < len(a); i++ {
+               n += len(a[i])
+       }
+
+       b := make([]byte, n)
+       bp := 0
+       for i := 0; i < len(a); i++ {
+               s := a[i]
+               for j := 0; j < len(s); j++ {
+                       b[bp] = s[j]
+                       bp++
+               }
+               if i+1 < len(a) {
+                       s = sep
+                       for j := 0; j < len(s); j++ {
+                               b[bp] = s[j]
+                               bp++
+                       }
+               }
+       }
+       return b
+}
+
+// HasPrefix tests whether the byte array s begins with prefix.
+func HasPrefix(s, prefix []byte) bool {
+       return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix)
+}
+
+// HasSuffix tests whether the byte array s ends with suffix.
+func HasSuffix(s, suffix []byte) bool {
+       return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):], suffix)
+}
+
+// Map returns a copy of the byte array s with all its characters modified
+// according to the mapping function. If mapping returns a negative value, the character is
+// dropped from the string with no replacement.  The characters in s and the
+// output are interpreted as UTF-8-encoded Unicode code points.
+func Map(mapping func(rune int) int, s []byte) []byte {
+       // In the worst case, the array can grow when mapped, making
+       // things unpleasant.  But it's so rare we barge in assuming it's
+       // fine.  It could also shrink but that falls out naturally.
+       maxbytes := len(s) // length of b
+       nbytes := 0        // number of bytes encoded in b
+       b := make([]byte, maxbytes)
+       for i := 0; i < len(s); {
+               wid := 1
+               rune := int(s[i])
+               if rune >= utf8.RuneSelf {
+                       rune, wid = utf8.DecodeRune(s[i:])
+               }
+               rune = mapping(rune)
+               if rune >= 0 {
+                       if nbytes+utf8.RuneLen(rune) > maxbytes {
+                               // Grow the buffer.
+                               maxbytes = maxbytes*2 + utf8.UTFMax
+                               nb := make([]byte, maxbytes)
+                               copy(nb, b[0:nbytes])
+                               b = nb
+                       }
+                       nbytes += utf8.EncodeRune(rune, b[nbytes:maxbytes])
+               }
+               i += wid
+       }
+       return b[0:nbytes]
+}
+
+// Repeat returns a new byte slice consisting of count copies of b.
+func Repeat(b []byte, count int) []byte {
+       nb := make([]byte, len(b)*count)
+       bp := 0
+       for i := 0; i < count; i++ {
+               for j := 0; j < len(b); j++ {
+                       nb[bp] = b[j]
+                       bp++
+               }
+       }
+       return nb
+}
+
+// ToUpper returns a copy of the byte array s with all Unicode letters mapped to their upper case.
+func ToUpper(s []byte) []byte { return Map(unicode.ToUpper, s) }
+
+// ToUpper returns a copy of the byte array s with all Unicode letters mapped to their lower case.
+func ToLower(s []byte) []byte { return Map(unicode.ToLower, s) }
+
+// ToTitle returns a copy of the byte array s with all Unicode letters mapped to their title case.
+func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) }
+
+// ToUpperSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// upper case, giving priority to the special casing rules.
+func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte {
+       return Map(func(r int) int { return _case.ToUpper(r) }, s)
+}
+
+// ToLowerSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// lower case, giving priority to the special casing rules.
+func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte {
+       return Map(func(r int) int { return _case.ToLower(r) }, s)
+}
+
+// ToTitleSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// title case, giving priority to the special casing rules.
+func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte {
+       return Map(func(r int) int { return _case.ToTitle(r) }, s)
+}
+
+
+// isSeparator reports whether the rune could mark a word boundary.
+// TODO: update when package unicode captures more of the properties.
+func isSeparator(rune int) bool {
+       // ASCII alphanumerics and underscore are not separators
+       if rune <= 0x7F {
+               switch {
+               case '0' <= rune && rune <= '9':
+                       return false
+               case 'a' <= rune && rune <= 'z':
+                       return false
+               case 'A' <= rune && rune <= 'Z':
+                       return false
+               case rune == '_':
+                       return false
+               }
+               return true
+       }
+       // Letters and digits are not separators
+       if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+               return false
+       }
+       // Otherwise, all we can do for now is treat spaces as separators.
+       return unicode.IsSpace(rune)
+}
+
+// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+
+// Title returns a copy of s with all Unicode letters that begin words
+// mapped to their title case.
+func Title(s []byte) []byte {
+       // Use a closure here to remember state.
+       // Hackish but effective. Depends on Map scanning in order and calling
+       // the closure once per rune.
+       prev := ' '
+       return Map(
+               func(r int) int {
+                       if isSeparator(prev) {
+                               prev = r
+                               return unicode.ToTitle(r)
+                       }
+                       prev = r
+                       return r
+               },
+               s)
+}
+
+// TrimLeftFunc returns a subslice of s by slicing off all leading UTF-8-encoded
+// Unicode code points c that satisfy f(c).
+func TrimLeftFunc(s []byte, f func(r int) bool) []byte {
+       i := indexFunc(s, f, false)
+       if i == -1 {
+               return nil
+       }
+       return s[i:]
+}
+
+// TrimRightFunc returns a subslice of s by slicing off all trailing UTF-8
+// encoded Unicode code points c that satisfy f(c).
+func TrimRightFunc(s []byte, f func(r int) bool) []byte {
+       i := lastIndexFunc(s, f, false)
+       if i >= 0 && s[i] >= utf8.RuneSelf {
+               _, wid := utf8.DecodeRune(s[i:])
+               i += wid
+       } else {
+               i++
+       }
+       return s[0:i]
+}
+
+// TrimFunc returns a subslice of s by slicing off all leading and trailing
+// UTF-8-encoded Unicode code points c that satisfy f(c).
+func TrimFunc(s []byte, f func(r int) bool) []byte {
+       return TrimRightFunc(TrimLeftFunc(s, f), f)
+}
+
+// IndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index in s of the first Unicode
+// code point satisfying f(c), or -1 if none do.
+func IndexFunc(s []byte, f func(r int) bool) int {
+       return indexFunc(s, f, true)
+}
+
+// LastIndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index in s of the last Unicode
+// code point satisfying f(c), or -1 if none do.
+func LastIndexFunc(s []byte, f func(r int) bool) int {
+       return lastIndexFunc(s, f, true)
+}
+
+// indexFunc is the same as IndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func indexFunc(s []byte, f func(r int) bool, truth bool) int {
+       start := 0
+       for start < len(s) {
+               wid := 1
+               rune := int(s[start])
+               if rune >= utf8.RuneSelf {
+                       rune, wid = utf8.DecodeRune(s[start:])
+               }
+               if f(rune) == truth {
+                       return start
+               }
+               start += wid
+       }
+       return -1
+}
+
+// lastIndexFunc is the same as LastIndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func lastIndexFunc(s []byte, f func(r int) bool, truth bool) int {
+       for i := len(s); i > 0; {
+               rune, size := utf8.DecodeLastRune(s[0:i])
+               i -= size
+               if f(rune) == truth {
+                       return i
+               }
+       }
+       return -1
+}
+
+func makeCutsetFunc(cutset string) func(rune int) bool {
+       return func(rune int) bool {
+               for _, c := range cutset {
+                       if c == rune {
+                               return true
+                       }
+               }
+               return false
+       }
+}
+
+// Trim returns a subslice of s by slicing off all leading and
+// trailing UTF-8-encoded Unicode code points contained in cutset.
+func Trim(s []byte, cutset string) []byte {
+       return TrimFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimLeft returns a subslice of s by slicing off all leading
+// UTF-8-encoded Unicode code points contained in cutset.
+func TrimLeft(s []byte, cutset string) []byte {
+       return TrimLeftFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimRight returns a subslice of s by slicing off all trailing
+// UTF-8-encoded Unicode code points that are contained in cutset.
+func TrimRight(s []byte, cutset string) []byte {
+       return TrimRightFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimSpace returns a subslice of s by slicing off all leading and
+// trailing white space, as as defined by Unicode.
+func TrimSpace(s []byte) []byte {
+       return TrimFunc(s, unicode.IsSpace)
+}
+
+// How big to make a byte array when growing.
+// Heuristic: Scale by 50% to give n log n time.
+func resize(n int) int {
+       if n < 16 {
+               n = 16
+       }
+       return n + n/2
+}
+
+// Add appends the contents of t to the end of s and returns the result.
+// If s has enough capacity, it is extended in place; otherwise a
+// new array is allocated and returned.
+func Add(s, t []byte) []byte { // TODO
+       lens := len(s)
+       lent := len(t)
+       if lens+lent <= cap(s) {
+               s = s[0 : lens+lent]
+       } else {
+               news := make([]byte, lens+lent, resize(lens+lent))
+               copy(news, s)
+               s = news
+       }
+       copy(s[lens:lens+lent], t)
+       return s
+}
+
+// AddByte appends byte t to the end of s and returns the result.
+// If s has enough capacity, it is extended in place; otherwise a
+// new array is allocated and returned.
+func AddByte(s []byte, t byte) []byte { // TODO
+       lens := len(s)
+       if lens+1 <= cap(s) {
+               s = s[0 : lens+1]
+       } else {
+               news := make([]byte, lens+1, resize(lens+1))
+               copy(news, s)
+               s = news
+       }
+       s[lens] = t
+       return s
+}
+
+// Runes returns a slice of runes (Unicode code points) equivalent to s.
+func Runes(s []byte) []int {
+       t := make([]int, utf8.RuneCount(s))
+       i := 0
+       for len(s) > 0 {
+               r, l := utf8.DecodeRune(s)
+               t[i] = r
+               i++
+               s = s[l:]
+       }
+       return t
+}
+
+// Replace returns a copy of the slice s with the first n
+// non-overlapping instances of old replaced by new.
+// If n < 0, there is no limit on the number of replacements.
+func Replace(s, old, new []byte, n int) []byte {
+       if n == 0 {
+               return s // avoid allocation
+       }
+       // Compute number of replacements.
+       if m := Count(s, old); m == 0 {
+               return s // avoid allocation
+       } else if n <= 0 || m < n {
+               n = m
+       }
+
+       // Apply replacements to buffer.
+       t := make([]byte, len(s)+n*(len(new)-len(old)))
+       w := 0
+       start := 0
+       for i := 0; i < n; i++ {
+               j := start
+               if len(old) == 0 {
+                       if i > 0 {
+                               _, wid := utf8.DecodeRune(s[start:])
+                               j += wid
+                       }
+               } else {
+                       j += Index(s[start:], old)
+               }
+               w += copy(t[w:], s[start:j])
+               w += copy(t[w:], new)
+               start = j + len(old)
+       }
+       w += copy(t[w:], s[start:])
+       return t[0:w]
+}
diff --git a/libgo/go/bytes/bytes_decl.go b/libgo/go/bytes/bytes_decl.go
new file mode 100644 (file)
index 0000000..5d2b9e6
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
+func IndexByte(s []byte, c byte) int // asm_$GOARCH.s
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go
new file mode 100644 (file)
index 0000000..f3ca371
--- /dev/null
@@ -0,0 +1,864 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes_test
+
+import (
+       . "bytes"
+       "testing"
+       "unicode"
+       "utf8"
+)
+
+func eq(a, b []string) bool {
+       if len(a) != len(b) {
+               return false
+       }
+       for i := 0; i < len(a); i++ {
+               if a[i] != b[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+func arrayOfString(a [][]byte) []string {
+       result := make([]string, len(a))
+       for j := 0; j < len(a); j++ {
+               result[j] = string(a[j])
+       }
+       return result
+}
+
+// For ease of reading, the test cases use strings that are converted to byte
+// arrays before invoking the functions.
+
+var abcd = "abcd"
+var faces = "☺☻☹"
+var commas = "1,2,3,4"
+var dots = "1....2....3....4"
+
+type BinOpTest struct {
+       a string
+       b string
+       i int
+}
+
+var comparetests = []BinOpTest{
+       {"", "", 0},
+       {"a", "", 1},
+       {"", "a", -1},
+       {"abc", "abc", 0},
+       {"ab", "abc", -1},
+       {"abc", "ab", 1},
+       {"x", "ab", 1},
+       {"ab", "x", -1},
+       {"x", "a", 1},
+       {"b", "x", -1},
+}
+
+func TestCompare(t *testing.T) {
+       for _, tt := range comparetests {
+               a := []byte(tt.a)
+               b := []byte(tt.b)
+               cmp := Compare(a, b)
+               eql := Equal(a, b)
+               if cmp != tt.i {
+                       t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
+               }
+               if eql != (tt.i == 0) {
+                       t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql)
+               }
+       }
+}
+
+var indexTests = []BinOpTest{
+       {"", "", 0},
+       {"", "a", -1},
+       {"", "foo", -1},
+       {"fo", "foo", -1},
+       {"foo", "foo", 0},
+       {"oofofoofooo", "f", 2},
+       {"oofofoofooo", "foo", 4},
+       {"barfoobarfoo", "foo", 3},
+       {"foo", "", 0},
+       {"foo", "o", 1},
+       {"abcABCabc", "A", 3},
+       // cases with one byte strings - test IndexByte and special case in Index()
+       {"", "a", -1},
+       {"x", "a", -1},
+       {"x", "x", 0},
+       {"abc", "a", 0},
+       {"abc", "b", 1},
+       {"abc", "c", 2},
+       {"abc", "x", -1},
+       {"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33},
+       {"foofyfoobarfoobar", "y", 4},
+       {"oooooooooooooooooooooo", "r", -1},
+}
+
+var lastIndexTests = []BinOpTest{
+       {"", "", 0},
+       {"", "a", -1},
+       {"", "foo", -1},
+       {"fo", "foo", -1},
+       {"foo", "foo", 0},
+       {"foo", "f", 0},
+       {"oofofoofooo", "f", 7},
+       {"oofofoofooo", "foo", 7},
+       {"barfoobarfoo", "foo", 9},
+       {"foo", "", 3},
+       {"foo", "o", 2},
+       {"abcABCabc", "A", 3},
+       {"abcABCabc", "a", 6},
+}
+
+var indexAnyTests = []BinOpTest{
+       {"", "", -1},
+       {"", "a", -1},
+       {"", "abc", -1},
+       {"a", "", -1},
+       {"a", "a", 0},
+       {"aaa", "a", 0},
+       {"abc", "xyz", -1},
+       {"abc", "xcz", 2},
+       {"ab☺c", "x☺yz", 2},
+       {"aRegExp*", ".(|)*+?^$[]", 7},
+       {dots + dots + dots, " ", -1},
+}
+
+var indexRuneTests = []BinOpTest{
+       {"", "a", -1},
+       {"", "☺", -1},
+       {"foo", "☹", -1},
+       {"foo", "o", 1},
+       {"foo☺bar", "☺", 3},
+       {"foo☺☻☹bar", "☹", 9},
+}
+
+// Execute f on each test case.  funcName should be the name of f; it's used
+// in failure reports.
+func runIndexTests(t *testing.T, f func(s, sep []byte) int, funcName string, testCases []BinOpTest) {
+       for _, test := range testCases {
+               a := []byte(test.a)
+               b := []byte(test.b)
+               actual := f(a, b)
+               if actual != test.i {
+                       t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, b, actual, test.i)
+               }
+       }
+}
+
+func TestIndex(t *testing.T)     { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T) {
+       for _, test := range indexAnyTests {
+               a := []byte(test.a)
+               actual := IndexAny(a, test.b)
+               if actual != test.i {
+                       t.Errorf("IndexAny(%q,%q) = %v; want %v", a, test.b, actual, test.i)
+               }
+       }
+}
+
+func TestIndexByte(t *testing.T) {
+       for _, tt := range indexTests {
+               if len(tt.b) != 1 {
+                       continue
+               }
+               a := []byte(tt.a)
+               b := tt.b[0]
+               pos := IndexByte(a, b)
+               if pos != tt.i {
+                       t.Errorf(`IndexByte(%q, '%c') = %v`, tt.a, b, pos)
+               }
+               posp := IndexBytePortable(a, b)
+               if posp != tt.i {
+                       t.Errorf(`indexBytePortable(%q, '%c') = %v`, tt.a, b, posp)
+               }
+       }
+}
+
+// test a larger buffer with different sizes and alignments
+func TestIndexByteBig(t *testing.T) {
+       const n = 1024
+       b := make([]byte, n)
+       for i := 0; i < n; i++ {
+               // different start alignments
+               b1 := b[i:]
+               for j := 0; j < len(b1); j++ {
+                       b1[j] = 'x'
+                       pos := IndexByte(b1, 'x')
+                       if pos != j {
+                               t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+                       }
+                       b1[j] = 0
+                       pos = IndexByte(b1, 'x')
+                       if pos != -1 {
+                               t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+                       }
+               }
+               // different end alignments
+               b1 = b[:i]
+               for j := 0; j < len(b1); j++ {
+                       b1[j] = 'x'
+                       pos := IndexByte(b1, 'x')
+                       if pos != j {
+                               t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+                       }
+                       b1[j] = 0
+                       pos = IndexByte(b1, 'x')
+                       if pos != -1 {
+                               t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+                       }
+               }
+               // different start and end alignments
+               b1 = b[i/2 : n-(i+1)/2]
+               for j := 0; j < len(b1); j++ {
+                       b1[j] = 'x'
+                       pos := IndexByte(b1, 'x')
+                       if pos != j {
+                               t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+                       }
+                       b1[j] = 0
+                       pos = IndexByte(b1, 'x')
+                       if pos != -1 {
+                               t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+                       }
+               }
+       }
+}
+
+func TestIndexRune(t *testing.T) {
+       for _, tt := range indexRuneTests {
+               a := []byte(tt.a)
+               r, _ := utf8.DecodeRuneInString(tt.b)
+               pos := IndexRune(a, r)
+               if pos != tt.i {
+                       t.Errorf(`IndexRune(%q, '%c') = %v`, tt.a, r, pos)
+               }
+       }
+}
+
+func BenchmarkIndexByte4K(b *testing.B) { bmIndex(b, IndexByte, 4<<10) }
+
+func BenchmarkIndexByte4M(b *testing.B) { bmIndex(b, IndexByte, 4<<20) }
+
+func BenchmarkIndexByte64M(b *testing.B) { bmIndex(b, IndexByte, 64<<20) }
+
+func BenchmarkIndexBytePortable4K(b *testing.B) {
+       bmIndex(b, IndexBytePortable, 4<<10)
+}
+
+func BenchmarkIndexBytePortable4M(b *testing.B) {
+       bmIndex(b, IndexBytePortable, 4<<20)
+}
+
+func BenchmarkIndexBytePortable64M(b *testing.B) {
+       bmIndex(b, IndexBytePortable, 64<<20)
+}
+
+var bmbuf []byte
+
+func bmIndex(b *testing.B, index func([]byte, byte) int, n int) {
+       if len(bmbuf) < n {
+               bmbuf = make([]byte, n)
+       }
+       b.SetBytes(int64(n))
+       buf := bmbuf[0:n]
+       buf[n-1] = 'x'
+       for i := 0; i < b.N; i++ {
+               j := index(buf, 'x')
+               if j != n-1 {
+                       println("bad index", j)
+                       panic("bad index")
+               }
+       }
+       buf[n-1] = '0'
+}
+
+type ExplodeTest struct {
+       s string
+       n int
+       a []string
+}
+
+var explodetests = []ExplodeTest{
+       {"", -1, []string{}},
+       {abcd, -1, []string{"a", "b", "c", "d"}},
+       {faces, -1, []string{"☺", "☻", "☹"}},
+       {abcd, 2, []string{"a", "bcd"}},
+}
+
+func TestExplode(t *testing.T) {
+       for _, tt := range explodetests {
+               a := Split([]byte(tt.s), nil, tt.n)
+               result := arrayOfString(a)
+               if !eq(result, tt.a) {
+                       t.Errorf(`Explode("%s", %d) = %v; want %v`, tt.s, tt.n, result, tt.a)
+                       continue
+               }
+               s := Join(a, []byte{})
+               if string(s) != tt.s {
+                       t.Errorf(`Join(Explode("%s", %d), "") = "%s"`, tt.s, tt.n, s)
+               }
+       }
+}
+
+
+type SplitTest struct {
+       s   string
+       sep string
+       n   int
+       a   []string
+}
+
+var splittests = []SplitTest{
+       {abcd, "a", 0, nil},
+       {abcd, "a", -1, []string{"", "bcd"}},
+       {abcd, "z", -1, []string{"abcd"}},
+       {abcd, "", -1, []string{"a", "b", "c", "d"}},
+       {commas, ",", -1, []string{"1", "2", "3", "4"}},
+       {dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
+       {faces, "☹", -1, []string{"☺☻", ""}},
+       {faces, "~", -1, []string{faces}},
+       {faces, "", -1, []string{"☺", "☻", "☹"}},
+       {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
+       {"1 2", " ", 3, []string{"1", "2"}},
+       {"123", "", 2, []string{"1", "23"}},
+       {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplit(t *testing.T) {
+       for _, tt := range splittests {
+               a := Split([]byte(tt.s), []byte(tt.sep), tt.n)
+               result := arrayOfString(a)
+               if !eq(result, tt.a) {
+                       t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
+                       continue
+               }
+               if tt.n == 0 {
+                       continue
+               }
+               s := Join(a, []byte(tt.sep))
+               if string(s) != tt.s {
+                       t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
+               }
+       }
+}
+
+var splitaftertests = []SplitTest{
+       {abcd, "a", -1, []string{"a", "bcd"}},
+       {abcd, "z", -1, []string{"abcd"}},
+       {abcd, "", -1, []string{"a", "b", "c", "d"}},
+       {commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
+       {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
+       {faces, "☹", -1, []string{"☺☻☹", ""}},
+       {faces, "~", -1, []string{faces}},
+       {faces, "", -1, []string{"☺", "☻", "☹"}},
+       {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
+       {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
+       {"1 2", " ", 3, []string{"1 ", "2"}},
+       {"123", "", 2, []string{"1", "23"}},
+       {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplitAfter(t *testing.T) {
+       for _, tt := range splitaftertests {
+               a := SplitAfter([]byte(tt.s), []byte(tt.sep), tt.n)
+               result := arrayOfString(a)
+               if !eq(result, tt.a) {
+                       t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
+                       continue
+               }
+               s := Join(a, nil)
+               if string(s) != tt.s {
+                       t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
+               }
+       }
+}
+
+type FieldsTest struct {
+       s string
+       a []string
+}
+
+var fieldstests = []FieldsTest{
+       {"", []string{}},
+       {" ", []string{}},
+       {" \t ", []string{}},
+       {"  abc  ", []string{"abc"}},
+       {"1 2 3 4", []string{"1", "2", "3", "4"}},
+       {"1  2  3  4", []string{"1", "2", "3", "4"}},
+       {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+       {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+       {"\u2000\u2001\u2002", []string{}},
+       {"\n™\t™\n", []string{"™", "™"}},
+       {faces, []string{faces}},
+}
+
+func TestFields(t *testing.T) {
+       for _, tt := range fieldstests {
+               a := Fields([]byte(tt.s))
+               result := arrayOfString(a)
+               if !eq(result, tt.a) {
+                       t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
+                       continue
+               }
+       }
+}
+
+func TestFieldsFunc(t *testing.T) {
+       pred := func(c int) bool { return c == 'X' }
+       var fieldsFuncTests = []FieldsTest{
+               {"", []string{}},
+               {"XX", []string{}},
+               {"XXhiXXX", []string{"hi"}},
+               {"aXXbXXXcX", []string{"a", "b", "c"}},
+       }
+       for _, tt := range fieldsFuncTests {
+               a := FieldsFunc([]byte(tt.s), pred)
+               result := arrayOfString(a)
+               if !eq(result, tt.a) {
+                       t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
+               }
+       }
+}
+
+// Test case for any function which accepts and returns a byte array.
+// For ease of creation, we write the byte arrays as strings.
+type StringTest struct {
+       in, out string
+}
+
+var upperTests = []StringTest{
+       {"", ""},
+       {"abc", "ABC"},
+       {"AbC123", "ABC123"},
+       {"azAZ09_", "AZAZ09_"},
+       {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
+}
+
+var lowerTests = []StringTest{
+       {"", ""},
+       {"abc", "abc"},
+       {"AbC123", "abc123"},
+       {"azAZ09_", "azaz09_"},
+       {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
+}
+
+const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
+
+var trimSpaceTests = []StringTest{
+       {"", ""},
+       {"abc", "abc"},
+       {space + "abc" + space, "abc"},
+       {" ", ""},
+       {" \t\r\n \t\t\r\r\n\n ", ""},
+       {" \t\r\n x\t\t\r\r\n\n ", "x"},
+       {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
+       {"1 \t\r\n2", "1 \t\r\n2"},
+       {" x\x80", "x\x80"},
+       {" x\xc0", "x\xc0"},
+       {"x \xc0\xc0 ", "x \xc0\xc0"},
+       {"x \xc0", "x \xc0"},
+       {"x \xc0 ", "x \xc0"},
+       {"x \xc0\xc0 ", "x \xc0\xc0"},
+       {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
+       {"x ☺ ", "x ☺"},
+}
+
+// Execute f on each test case.  funcName should be the name of f; it's used
+// in failure reports.
+func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) {
+       for _, tc := range testCases {
+               actual := string(f([]byte(tc.in)))
+               if actual != tc.out {
+                       t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)
+               }
+       }
+}
+
+func tenRunes(rune int) string {
+       r := make([]int, 10)
+       for i := range r {
+               r[i] = rune
+       }
+       return string(r)
+}
+
+// User-defined self-inverse mapping function
+func rot13(rune int) int {
+       step := 13
+       if rune >= 'a' && rune <= 'z' {
+               return ((rune - 'a' + step) % 26) + 'a'
+       }
+       if rune >= 'A' && rune <= 'Z' {
+               return ((rune - 'A' + step) % 26) + 'A'
+       }
+       return rune
+}
+
+func TestMap(t *testing.T) {
+       // Run a couple of awful growth/shrinkage tests
+       a := tenRunes('a')
+
+       // 1.  Grow.  This triggers two reallocations in Map.
+       maxRune := func(rune int) int { return unicode.MaxRune }
+       m := Map(maxRune, []byte(a))
+       expect := tenRunes(unicode.MaxRune)
+       if string(m) != expect {
+               t.Errorf("growing: expected %q got %q", expect, m)
+       }
+
+       // 2. Shrink
+       minRune := func(rune int) int { return 'a' }
+       m = Map(minRune, []byte(tenRunes(unicode.MaxRune)))
+       expect = a
+       if string(m) != expect {
+               t.Errorf("shrinking: expected %q got %q", expect, m)
+       }
+
+       // 3. Rot13
+       m = Map(rot13, []byte("a to zed"))
+       expect = "n gb mrq"
+       if string(m) != expect {
+               t.Errorf("rot13: expected %q got %q", expect, m)
+       }
+
+       // 4. Rot13^2
+       m = Map(rot13, Map(rot13, []byte("a to zed")))
+       expect = "a to zed"
+       if string(m) != expect {
+               t.Errorf("rot13: expected %q got %q", expect, m)
+       }
+
+       // 5. Drop
+       dropNotLatin := func(rune int) int {
+               if unicode.Is(unicode.Latin, rune) {
+                       return rune
+               }
+               return -1
+       }
+       m = Map(dropNotLatin, []byte("Hello, 세계"))
+       expect = "Hello"
+       if string(m) != expect {
+               t.Errorf("drop: expected %q got %q", expect, m)
+       }
+}
+
+func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
+
+func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
+
+func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
+
+type AddTest struct {
+       s, t string
+       cap  int
+}
+
+var addtests = []AddTest{
+       {"", "", 0},
+       {"a", "", 1},
+       {"a", "b", 1},
+       {"abc", "def", 100},
+}
+
+func TestAdd(t *testing.T) {
+       for _, test := range addtests {
+               b := make([]byte, len(test.s), test.cap)
+               copy(b, test.s)
+               b = Add(b, []byte(test.t))
+               if string(b) != test.s+test.t {
+                       t.Errorf("Add(%q,%q) = %q", test.s, test.t, string(b))
+               }
+       }
+}
+
+func TestAddByte(t *testing.T) {
+       const N = 2e5
+       b := make([]byte, 0)
+       for i := 0; i < N; i++ {
+               b = AddByte(b, byte(i))
+       }
+       if len(b) != N {
+               t.Errorf("AddByte: too small; expected %d got %d", N, len(b))
+       }
+       for i, c := range b {
+               if c != byte(i) {
+                       t.Fatalf("AddByte: b[%d] should be %d is %d", i, c, byte(i))
+               }
+       }
+}
+
+type RepeatTest struct {
+       in, out string
+       count   int
+}
+
+var RepeatTests = []RepeatTest{
+       {"", "", 0},
+       {"", "", 1},
+       {"", "", 2},
+       {"-", "", 0},
+       {"-", "-", 1},
+       {"-", "----------", 10},
+       {"abc ", "abc abc abc ", 3},
+}
+
+func TestRepeat(t *testing.T) {
+       for _, tt := range RepeatTests {
+               tin := []byte(tt.in)
+               tout := []byte(tt.out)
+               a := Repeat(tin, tt.count)
+               if !Equal(a, tout) {
+                       t.Errorf("Repeat(%q, %d) = %q; want %q", tin, tt.count, a, tout)
+                       continue
+               }
+       }
+}
+
+func runesEqual(a, b []int) bool {
+       if len(a) != len(b) {
+               return false
+       }
+       for i, r := range a {
+               if r != b[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+type RunesTest struct {
+       in    string
+       out   []int
+       lossy bool
+}
+
+var RunesTests = []RunesTest{
+       {"", []int{}, false},
+       {" ", []int{32}, false},
+       {"ABC", []int{65, 66, 67}, false},
+       {"abc", []int{97, 98, 99}, false},
+       {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
+       {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
+       {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+}
+
+func TestRunes(t *testing.T) {
+       for _, tt := range RunesTests {
+               tin := []byte(tt.in)
+               a := Runes(tin)
+               if !runesEqual(a, tt.out) {
+                       t.Errorf("Runes(%q) = %v; want %v", tin, a, tt.out)
+                       continue
+               }
+               if !tt.lossy {
+                       // can only test reassembly if we didn't lose information
+                       s := string(a)
+                       if s != tt.in {
+                               t.Errorf("string(Runes(%q)) = %x; want %x", tin, s, tin)
+                       }
+               }
+       }
+}
+
+
+type TrimTest struct {
+       f               func([]byte, string) []byte
+       in, cutset, out string
+}
+
+var trimTests = []TrimTest{
+       {Trim, "abba", "a", "bb"},
+       {Trim, "abba", "ab", ""},
+       {TrimLeft, "abba", "ab", ""},
+       {TrimRight, "abba", "ab", ""},
+       {TrimLeft, "abba", "a", "bba"},
+       {TrimRight, "abba", "a", "abb"},
+       {Trim, "<tag>", "<>", "tag"},
+       {Trim, "* listitem", " *", "listitem"},
+       {Trim, `"quote"`, `"`, "quote"},
+       {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+       //empty string tests
+       {Trim, "abba", "", "abba"},
+       {Trim, "", "123", ""},
+       {Trim, "", "", ""},
+       {TrimLeft, "abba", "", "abba"},
+       {TrimLeft, "", "123", ""},
+       {TrimLeft, "", "", ""},
+       {TrimRight, "abba", "", "abba"},
+       {TrimRight, "", "123", ""},
+       {TrimRight, "", "", ""},
+       {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+}
+
+func TestTrim(t *testing.T) {
+       for _, tc := range trimTests {
+               actual := string(tc.f([]byte(tc.in), tc.cutset))
+               var name string
+               switch tc.f {
+               case Trim:
+                       name = "Trim"
+               case TrimLeft:
+                       name = "TrimLeft"
+               case TrimRight:
+                       name = "TrimRight"
+               default:
+                       t.Error("Undefined trim function")
+               }
+               if actual != tc.out {
+                       t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
+               }
+       }
+}
+
+type predicate struct {
+       f    func(r int) bool
+       name string
+}
+
+var isSpace = predicate{unicode.IsSpace, "IsSpace"}
+var isDigit = predicate{unicode.IsDigit, "IsDigit"}
+var isUpper = predicate{unicode.IsUpper, "IsUpper"}
+var isValidRune = predicate{
+       func(r int) bool {
+               return r != utf8.RuneError
+       },
+       "IsValidRune",
+}
+
+type TrimFuncTest struct {
+       f       predicate
+       in, out string
+}
+
+func not(p predicate) predicate {
+       return predicate{
+               func(r int) bool {
+                       return !p.f(r)
+               },
+               "not " + p.name,
+       }
+}
+
+var trimFuncTests = []TrimFuncTest{
+       {isSpace, space + " hello " + space, "hello"},
+       {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
+       {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
+       {not(isSpace), "hello" + space + "hello", space},
+       {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
+       {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"},
+       {not(isValidRune), "\xc0a\xc0", "a"},
+}
+
+func TestTrimFunc(t *testing.T) {
+       for _, tc := range trimFuncTests {
+               actual := string(TrimFunc([]byte(tc.in), tc.f.f))
+               if actual != tc.out {
+                       t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out)
+               }
+       }
+}
+
+type IndexFuncTest struct {
+       in          string
+       f           predicate
+       first, last int
+}
+
+var indexFuncTests = []IndexFuncTest{
+       {"", isValidRune, -1, -1},
+       {"abc", isDigit, -1, -1},
+       {"0123", isDigit, 0, 3},
+       {"a1b", isDigit, 1, 1},
+       {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes
+       {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
+       {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
+       {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
+
+       // tests of invalid UTF-8
+       {"\x801", isDigit, 1, 1},
+       {"\x80abc", isDigit, -1, -1},
+       {"\xc0a\xc0", isValidRune, 1, 1},
+       {"\xc0a\xc0", not(isValidRune), 0, 2},
+       {"\xc0☺\xc0", not(isValidRune), 0, 4},
+       {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
+       {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
+       {"a\xe0\x80cd", not(isValidRune), 1, 2},
+}
+
+func TestIndexFunc(t *testing.T) {
+       for _, tc := range indexFuncTests {
+               first := IndexFunc([]byte(tc.in), tc.f.f)
+               if first != tc.first {
+                       t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)
+               }
+               last := LastIndexFunc([]byte(tc.in), tc.f.f)
+               if last != tc.last {
+                       t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)
+               }
+       }
+}
+
+type ReplaceTest struct {
+       in       string
+       old, new string
+       n        int
+       out      string
+}
+
+var ReplaceTests = []ReplaceTest{
+       {"hello", "l", "L", 0, "hello"},
+       {"hello", "l", "L", -1, "heLLo"},
+       {"hello", "x", "X", -1, "hello"},
+       {"", "x", "X", -1, ""},
+       {"radar", "r", "<r>", -1, "<r>ada<r>"},
+       {"", "", "<>", -1, "<>"},
+       {"banana", "a", "<>", -1, "b<>n<>n<>"},
+       {"banana", "a", "<>", 1, "b<>nana"},
+       {"banana", "a", "<>", 1000, "b<>n<>n<>"},
+       {"banana", "an", "<>", -1, "b<><>a"},
+       {"banana", "ana", "<>", -1, "b<>na"},
+       {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
+       {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
+       {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
+       {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
+       {"banana", "", "<>", 1, "<>banana"},
+       {"banana", "a", "a", -1, "banana"},
+       {"banana", "a", "a", 1, "banana"},
+       {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
+}
+
+func TestReplace(t *testing.T) {
+       for _, tt := range ReplaceTests {
+               if s := string(Replace([]byte(tt.in), []byte(tt.old), []byte(tt.new), tt.n)); s != tt.out {
+                       t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
+               }
+       }
+}
+
+type TitleTest struct {
+       in, out string
+}
+
+var TitleTests = []TitleTest{
+       {"", ""},
+       {"a", "A"},
+       {" aaa aaa aaa ", " Aaa Aaa Aaa "},
+       {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
+       {"123a456", "123a456"},
+       {"double-blind", "Double-Blind"},
+       {"ÿøû", "Ÿøû"},
+}
+
+func TestTitle(t *testing.T) {
+       for _, tt := range TitleTests {
+               if s := string(Title([]byte(tt.in))); s != tt.out {
+                       t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
+               }
+       }
+}
diff --git a/libgo/go/bytes/export_test.go b/libgo/go/bytes/export_test.go
new file mode 100644 (file)
index 0000000..b65428d
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+// Export func for testing
+var IndexBytePortable = indexBytePortable
diff --git a/libgo/go/bytes/indexbyte.c b/libgo/go/bytes/indexbyte.c
new file mode 100644 (file)
index 0000000..1e0fef9
--- /dev/null
@@ -0,0 +1,26 @@
+/* indexbyte.c -- implement bytes.IndexByte for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "array.h"
+
+/* This is in C so that the compiler can optimize it
+   appropriately.  */
+
+int IndexByte (struct __go_open_array, char)
+  asm ("libgo_bytes.bytes.IndexByte");
+
+int
+IndexByte (struct __go_open_array s, char b)
+{
+  char *p;
+
+  p = __builtin_memchr (s.__values, b, s.__count);
+  if (p == NULL)
+    return -1;
+  return p - (char *) s.__values;
+}
diff --git a/libgo/go/cmath/abs.go b/libgo/go/cmath/abs.go
new file mode 100644 (file)
index 0000000..725dc4e
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The cmath package provides basic constants
+// and mathematical functions for complex numbers.
+package cmath
+
+import "math"
+
+// Abs returns the absolute value (also called the modulus) of x.
+func Abs(x complex128) float64 { return math.Hypot(real(x), imag(x)) }
diff --git a/libgo/go/cmath/asin.go b/libgo/go/cmath/asin.go
new file mode 100644 (file)
index 0000000..eb87ba5
--- /dev/null
@@ -0,0 +1,170 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8:  June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+//    Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+//   The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+//   Stephen L. Moshier
+//   moshier@na-net.ornl.gov
+
+// Complex circular arc sine
+//
+// DESCRIPTION:
+//
+// Inverse complex sine:
+//                               2
+// w = -i clog( iz + csqrt( 1 - z ) ).
+//
+// casin(z) = -i casinh(iz)
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10     10100       2.1e-15     3.4e-16
+//    IEEE      -10,+10     30000       2.2e-14     2.7e-15
+// Larger relative error can be observed for z near zero.
+// Also tested by csin(casin(z)) = z.
+
+// Asin returns the inverse sine of x.
+func Asin(x complex128) complex128 {
+       if imag(x) == 0 {
+               if math.Fabs(real(x)) > 1 {
+                       return cmplx(math.Pi/2, 0) // DOMAIN error
+               }
+               return cmplx(math.Asin(real(x)), 0)
+       }
+       ct := cmplx(-imag(x), real(x)) // i * x
+       xx := x * x
+       x1 := cmplx(1-real(xx), -imag(xx)) // 1 - x*x
+       x2 := Sqrt(x1)                     // x2 = sqrt(1 - x*x)
+       w := Log(ct + x2)
+       return cmplx(imag(w), -real(w)) // -i * w
+}
+
+// Asinh returns the inverse hyperbolic sine of x.
+func Asinh(x complex128) complex128 {
+       // TODO check range
+       if imag(x) == 0 {
+               if math.Fabs(real(x)) > 1 {
+                       return cmplx(math.Pi/2, 0) // DOMAIN error
+               }
+               return cmplx(math.Asinh(real(x)), 0)
+       }
+       xx := x * x
+       x1 := cmplx(1+real(xx), imag(xx)) // 1 + x*x
+       return Log(x + Sqrt(x1))          // log(x + sqrt(1 + x*x))
+}
+
+// Complex circular arc cosine
+//
+// DESCRIPTION:
+//
+// w = arccos z  =  PI/2 - arcsin z.
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10      5200      1.6e-15      2.8e-16
+//    IEEE      -10,+10     30000      1.8e-14      2.2e-15
+
+// Acos returns the inverse cosine of x.
+func Acos(x complex128) complex128 {
+       w := Asin(x)
+       return cmplx(math.Pi/2-real(w), -imag(w))
+}
+
+// Acosh returns the inverse hyperbolic cosine of x.
+func Acosh(x complex128) complex128 {
+       w := Acos(x)
+       if imag(w) <= 0 {
+               return cmplx(-imag(w), real(w)) // i * w
+       }
+       return cmplx(imag(w), -real(w)) // -i * w
+}
+
+// Complex circular arc tangent
+//
+// DESCRIPTION:
+//
+// If
+//     z = x + iy,
+//
+// then
+//          1       (    2x     )
+// Re w  =  - arctan(-----------)  +  k PI
+//          2       (     2    2)
+//                  (1 - x  - y )
+//
+//               ( 2         2)
+//          1    (x  +  (y+1) )
+// Im w  =  - log(------------)
+//          4    ( 2         2)
+//               (x  +  (y-1) )
+//
+// Where k is an arbitrary integer.
+//
+// catan(z) = -i catanh(iz).
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10      5900       1.3e-16     7.8e-18
+//    IEEE      -10,+10     30000       2.3e-15     8.5e-17
+// The check catan( ctan(z) )  =  z, with |x| and |y| < PI/2,
+// had peak relative error 1.5e-16, rms relative error
+// 2.9e-17.  See also clog().
+
+// Atan returns the inverse tangent of x.
+func Atan(x complex128) complex128 {
+       if real(x) == 0 && imag(x) > 1 {
+               return NaN()
+       }
+
+       x2 := real(x) * real(x)
+       a := 1 - x2 - imag(x)*imag(x)
+       if a == 0 {
+               return NaN()
+       }
+       t := 0.5 * math.Atan2(2*real(x), a)
+       w := reducePi(t)
+
+       t = imag(x) - 1
+       b := x2 + t*t
+       if b == 0 {
+               return NaN()
+       }
+       t = imag(x) + 1
+       c := (x2 + t*t) / b
+       return cmplx(w, 0.25*math.Log(c))
+}
+
+// Atanh returns the inverse hyperbolic tangent of x.
+func Atanh(x complex128) complex128 {
+       z := cmplx(-imag(x), real(x)) // z = i * x
+       z = Atan(z)
+       return cmplx(imag(z), -real(z)) // z = -i * z
+}
diff --git a/libgo/go/cmath/cmath_test.go b/libgo/go/cmath/cmath_test.go
new file mode 100644 (file)
index 0000000..93fac4e
--- /dev/null
@@ -0,0 +1,853 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import (
+       "math"
+       "testing"
+)
+
+var vc26 = []complex128{
+       (4.97901192488367350108546816 + 7.73887247457810456552351752i),
+       (7.73887247457810456552351752 - 0.27688005719200159404635997i),
+       (-0.27688005719200159404635997 - 5.01060361827107492160848778i),
+       (-5.01060361827107492160848778 + 9.63629370719841737980004837i),
+       (9.63629370719841737980004837 + 2.92637723924396464525443662i),
+       (2.92637723924396464525443662 + 5.22908343145930665230025625i),
+       (5.22908343145930665230025625 + 2.72793991043601025126008608i),
+       (2.72793991043601025126008608 + 1.82530809168085506044576505i),
+       (1.82530809168085506044576505 - 8.68592476857560136238589621i),
+       (-8.68592476857560136238589621 + 4.97901192488367350108546816i),
+}
+var vc = []complex128{
+       (4.9790119248836735e+00 + 7.7388724745781045e+00i),
+       (7.7388724745781045e+00 - 2.7688005719200159e-01i),
+       (-2.7688005719200159e-01 - 5.0106036182710749e+00i),
+       (-5.0106036182710749e+00 + 9.6362937071984173e+00i),
+       (9.6362937071984173e+00 + 2.9263772392439646e+00i),
+       (2.9263772392439646e+00 + 5.2290834314593066e+00i),
+       (5.2290834314593066e+00 + 2.7279399104360102e+00i),
+       (2.7279399104360102e+00 + 1.8253080916808550e+00i),
+       (1.8253080916808550e+00 - 8.6859247685756013e+00i),
+       (-8.6859247685756013e+00 + 4.9790119248836735e+00i),
+}
+
+// The expected results below were computed by the high precision calculators
+// at http://keisan.casio.com/.  More exact input values (array vc[], above)
+// were obtained by printing them with "%.26f".  The answers were calculated
+// to 26 digits (by using the "Digit number" drop-down control of each
+// calculator).
+
+var abs = []float64{
+       9.2022120669932650313380972e+00,
+       7.7438239742296106616261394e+00,
+       5.0182478202557746902556648e+00,
+       1.0861137372799545160704002e+01,
+       1.0070841084922199607011905e+01,
+       5.9922447613166942183705192e+00,
+       5.8978784056736762299945176e+00,
+       3.2822866700678709020367184e+00,
+       8.8756430028990417290744307e+00,
+       1.0011785496777731986390856e+01,
+}
+
+var acos = []complex128{
+       (1.0017679804707456328694569 - 2.9138232718554953784519807i),
+       (0.03606427612041407369636057 + 2.7358584434576260925091256i),
+       (1.6249365462333796703711823 + 2.3159537454335901187730929i),
+       (2.0485650849650740120660391 - 3.0795576791204117911123886i),
+       (0.29621132089073067282488147 - 3.0007392508200622519398814i),
+       (1.0664555914934156601503632 - 2.4872865024796011364747111i),
+       (0.48681307452231387690013905 - 2.463655912283054555225301i),
+       (0.6116977071277574248407752 - 1.8734458851737055262693056i),
+       (1.3649311280370181331184214 + 2.8793528632328795424123832i),
+       (2.6189310485682988308904501 - 2.9956543302898767795858704i),
+}
+var acosh = []complex128{
+       (2.9138232718554953784519807 + 1.0017679804707456328694569i),
+       (2.7358584434576260925091256 - 0.03606427612041407369636057i),
+       (2.3159537454335901187730929 - 1.6249365462333796703711823i),
+       (3.0795576791204117911123886 + 2.0485650849650740120660391i),
+       (3.0007392508200622519398814 + 0.29621132089073067282488147i),
+       (2.4872865024796011364747111 + 1.0664555914934156601503632i),
+       (2.463655912283054555225301 + 0.48681307452231387690013905i),
+       (1.8734458851737055262693056 + 0.6116977071277574248407752i),
+       (2.8793528632328795424123832 - 1.3649311280370181331184214i),
+       (2.9956543302898767795858704 + 2.6189310485682988308904501i),
+}
+var asin = []complex128{
+       (0.56902834632415098636186476 + 2.9138232718554953784519807i),
+       (1.5347320506744825455349611 - 2.7358584434576260925091256i),
+       (-0.054140219438483051139860579 - 2.3159537454335901187730929i),
+       (-0.47776875817017739283471738 + 3.0795576791204117911123886i),
+       (1.2745850059041659464064402 + 3.0007392508200622519398814i),
+       (0.50434073530148095908095852 + 2.4872865024796011364747111i),
+       (1.0839832522725827423311826 + 2.463655912283054555225301i),
+       (0.9590986196671391943905465 + 1.8734458851737055262693056i),
+       (0.20586519875787848611290031 - 2.8793528632328795424123832i),
+       (-1.0481347217734022116591284 + 2.9956543302898767795858704i),
+}
+var asinh = []complex128{
+       (2.9113760469415295679342185 + 0.99639459545704326759805893i),
+       (2.7441755423994259061579029 - 0.035468308789000500601119392i),
+       (-2.2962136462520690506126678 - 1.5144663565690151885726707i),
+       (-3.0771233459295725965402455 + 1.0895577967194013849422294i),
+       (3.0048366100923647417557027 + 0.29346979169819220036454168i),
+       (2.4800059370795363157364643 + 1.0545868606049165710424232i),
+       (2.4718773838309585611141821 + 0.47502344364250803363708842i),
+       (1.8910743588080159144378396 + 0.56882925572563602341139174i),
+       (2.8735426423367341878069406 - 1.362376149648891420997548i),
+       (-2.9981750586172477217567878 + 0.5183571985225367505624207i),
+}
+var atan = []complex128{
+       (1.5115747079332741358607654 + 0.091324403603954494382276776i),
+       (1.4424504323482602560806727 - 0.0045416132642803911503770933i),
+       (-1.5593488703630532674484026 - 0.20163295409248362456446431i),
+       (-1.5280619472445889867794105 + 0.081721556230672003746956324i),
+       (1.4759909163240799678221039 + 0.028602969320691644358773586i),
+       (1.4877353772046548932715555 + 0.14566877153207281663773599i),
+       (1.4206983927779191889826 + 0.076830486127880702249439993i),
+       (1.3162236060498933364869556 + 0.16031313000467530644933363i),
+       (1.5473450684303703578810093 - 0.11064907507939082484935782i),
+       (-1.4841462340185253987375812 + 0.049341850305024399493142411i),
+}
+var atanh = []complex128{
+       (0.058375027938968509064640438 + 1.4793488495105334458167782i),
+       (0.12977343497790381229915667 - 1.5661009410463561327262499i),
+       (-0.010576456067347252072200088 - 1.3743698658402284549750563i),
+       (-0.042218595678688358882784918 + 1.4891433968166405606692604i),
+       (0.095218997991316722061828397 + 1.5416884098777110330499698i),
+       (0.079965459366890323857556487 + 1.4252510353873192700350435i),
+       (0.15051245471980726221708301 + 1.4907432533016303804884461i),
+       (0.25082072933993987714470373 + 1.392057665392187516442986i),
+       (0.022896108815797135846276662 - 1.4609224989282864208963021i),
+       (-0.08665624101841876130537396 + 1.5207902036935093480142159i),
+}
+var conj = []complex128{
+       (4.9790119248836735e+00 - 7.7388724745781045e+00i),
+       (7.7388724745781045e+00 + 2.7688005719200159e-01i),
+       (-2.7688005719200159e-01 + 5.0106036182710749e+00i),
+       (-5.0106036182710749e+00 - 9.6362937071984173e+00i),
+       (9.6362937071984173e+00 - 2.9263772392439646e+00i),
+       (2.9263772392439646e+00 - 5.2290834314593066e+00i),
+       (5.2290834314593066e+00 - 2.7279399104360102e+00i),
+       (2.7279399104360102e+00 - 1.8253080916808550e+00i),
+       (1.8253080916808550e+00 + 8.6859247685756013e+00i),
+       (-8.6859247685756013e+00 - 4.9790119248836735e+00i),
+}
+var cos = []complex128{
+       (3.024540920601483938336569e+02 + 1.1073797572517071650045357e+03i),
+       (1.192858682649064973252758e-01 + 2.7857554122333065540970207e-01i),
+       (7.2144394304528306603857962e+01 - 2.0500129667076044169954205e+01i),
+       (2.24921952538403984190541e+03 - 7.317363745602773587049329e+03i),
+       (-9.148222970032421760015498e+00 + 1.953124661113563541862227e+00i),
+       (-9.116081175857732248227078e+01 - 1.992669213569952232487371e+01i),
+       (3.795639179042704640002918e+00 + 6.623513350981458399309662e+00i),
+       (-2.9144840732498869560679084e+00 - 1.214620271628002917638748e+00i),
+       (-7.45123482501299743872481e+02 + 2.8641692314488080814066734e+03i),
+       (-5.371977967039319076416747e+01 + 4.893348341339375830564624e+01i),
+}
+var cosh = []complex128{
+       (8.34638383523018249366948e+00 + 7.2181057886425846415112064e+01i),
+       (1.10421967379919366952251e+03 - 3.1379638689277575379469861e+02i),
+       (3.051485206773701584738512e-01 - 2.6805384730105297848044485e-01i),
+       (-7.33294728684187933370938e+01 + 1.574445942284918251038144e+01i),
+       (-7.478643293945957535757355e+03 + 1.6348382209913353929473321e+03i),
+       (4.622316522966235701630926e+00 - 8.088695185566375256093098e+00i),
+       (-8.544333183278877406197712e+01 + 3.7505836120128166455231717e+01i),
+       (-1.934457815021493925115198e+00 + 7.3725859611767228178358673e+00i),
+       (-2.352958770061749348353548e+00 - 2.034982010440878358915409e+00i),
+       (7.79756457532134748165069e+02 + 2.8549350716819176560377717e+03i),
+}
+var exp = []complex128{
+       (1.669197736864670815125146e+01 + 1.4436895109507663689174096e+02i),
+       (2.2084389286252583447276212e+03 - 6.2759289284909211238261917e+02i),
+       (2.227538273122775173434327e-01 + 7.2468284028334191250470034e-01i),
+       (-6.5182985958153548997881627e-03 - 1.39965837915193860879044e-03i),
+       (-1.4957286524084015746110777e+04 + 3.269676455931135688988042e+03i),
+       (9.218158701983105935659273e+00 - 1.6223985291084956009304582e+01i),
+       (-1.7088175716853040841444505e+02 + 7.501382609870410713795546e+01i),
+       (-3.852461315830959613132505e+00 + 1.4808420423156073221970892e+01i),
+       (-4.586775503301407379786695e+00 - 4.178501081246873415144744e+00i),
+       (4.451337963005453491095747e-05 - 1.62977574205442915935263e-04i),
+}
+var log = []complex128{
+       (2.2194438972179194425697051e+00 + 9.9909115046919291062461269e-01i),
+       (2.0468956191154167256337289e+00 - 3.5762575021856971295156489e-02i),
+       (1.6130808329853860438751244e+00 - 1.6259990074019058442232221e+00i),
+       (2.3851910394823008710032651e+00 + 2.0502936359659111755031062e+00i),
+       (2.3096442270679923004800651e+00 + 2.9483213155446756211881774e-01i),
+       (1.7904660933974656106951860e+00 + 1.0605860367252556281902109e+00i),
+       (1.7745926939841751666177512e+00 + 4.8084556083358307819310911e-01i),
+       (1.1885403350045342425648780e+00 + 5.8969634164776659423195222e-01i),
+       (2.1833107837679082586772505e+00 - 1.3636647724582455028314573e+00i),
+       (2.3037629487273259170991671e+00 + 2.6210913895386013290915234e+00i),
+}
+var log10 = []complex128{
+       (9.6389223745559042474184943e-01 + 4.338997735671419492599631e-01i),
+       (8.8895547241376579493490892e-01 - 1.5531488990643548254864806e-02i),
+       (7.0055210462945412305244578e-01 - 7.0616239649481243222248404e-01i),
+       (1.0358753067322445311676952e+00 + 8.9043121238134980156490909e-01i),
+       (1.003065742975330237172029e+00 + 1.2804396782187887479857811e-01i),
+       (7.7758954439739162532085157e-01 + 4.6060666333341810869055108e-01i),
+       (7.7069581462315327037689152e-01 + 2.0882857371769952195512475e-01i),
+       (5.1617650901191156135137239e-01 + 2.5610186717615977620363299e-01i),
+       (9.4819982567026639742663212e-01 - 5.9223208584446952284914289e-01i),
+       (1.0005115362454417135973429e+00 + 1.1383255270407412817250921e+00i),
+}
+
+type ff struct {
+       r, theta float64
+}
+
+var polar = []ff{
+       {9.2022120669932650313380972e+00, 9.9909115046919291062461269e-01},
+       {7.7438239742296106616261394e+00, -3.5762575021856971295156489e-02},
+       {5.0182478202557746902556648e+00, -1.6259990074019058442232221e+00},
+       {1.0861137372799545160704002e+01, 2.0502936359659111755031062e+00},
+       {1.0070841084922199607011905e+01, 2.9483213155446756211881774e-01},
+       {5.9922447613166942183705192e+00, 1.0605860367252556281902109e+00},
+       {5.8978784056736762299945176e+00, 4.8084556083358307819310911e-01},
+       {3.2822866700678709020367184e+00, 5.8969634164776659423195222e-01},
+       {8.8756430028990417290744307e+00, -1.3636647724582455028314573e+00},
+       {1.0011785496777731986390856e+01, 2.6210913895386013290915234e+00},
+}
+var pow = []complex128{
+       (-2.499956739197529585028819e+00 + 1.759751724335650228957144e+00i),
+       (7.357094338218116311191939e+04 - 5.089973412479151648145882e+04i),
+       (1.320777296067768517259592e+01 - 3.165621914333901498921986e+01i),
+       (-3.123287828297300934072149e-07 - 1.9849567521490553032502223E-7i),
+       (8.0622651468477229614813e+04 - 7.80028727944573092944363e+04i),
+       (-1.0268824572103165858577141e+00 - 4.716844738244989776610672e-01i),
+       (-4.35953819012244175753187e+01 + 2.2036445974645306917648585e+02i),
+       (8.3556092283250594950239e-01 - 1.2261571947167240272593282e+01i),
+       (1.582292972120769306069625e+03 + 1.273564263524278244782512e+04i),
+       (6.592208301642122149025369e-08 + 2.584887236651661903526389e-08i),
+}
+var sin = []complex128{
+       (-1.1073801774240233539648544e+03 + 3.024539773002502192425231e+02i),
+       (1.0317037521400759359744682e+00 - 3.2208979799929570242818e-02i),
+       (-2.0501952097271429804261058e+01 - 7.2137981348240798841800967e+01i),
+       (7.3173638080346338642193078e+03 + 2.249219506193664342566248e+03i),
+       (-1.964375633631808177565226e+00 - 9.0958264713870404464159683e+00i),
+       (1.992783647158514838337674e+01 - 9.11555769410191350416942e+01i),
+       (-6.680335650741921444300349e+00 + 3.763353833142432513086117e+00i),
+       (1.2794028166657459148245993e+00 - 2.7669092099795781155109602e+00i),
+       (2.8641693949535259594188879e+03 + 7.451234399649871202841615e+02i),
+       (-4.893811726244659135553033e+01 - 5.371469305562194635957655e+01i),
+}
+var sinh = []complex128{
+       (8.34559353341652565758198e+00 + 7.2187893208650790476628899e+01i),
+       (1.1042192548260646752051112e+03 - 3.1379650595631635858792056e+02i),
+       (-8.239469336509264113041849e-02 + 9.9273668758439489098514519e-01i),
+       (7.332295456982297798219401e+01 - 1.574585908122833444899023e+01i),
+       (-7.4786432301380582103534216e+03 + 1.63483823493980029604071e+03i),
+       (4.595842179016870234028347e+00 - 8.135290105518580753211484e+00i),
+       (-8.543842533574163435246793e+01 + 3.750798997857594068272375e+01i),
+       (-1.918003500809465688017307e+00 + 7.4358344619793504041350251e+00i),
+       (-2.233816733239658031433147e+00 - 2.143519070805995056229335e+00i),
+       (-7.797564130187551181105341e+02 - 2.8549352346594918614806877e+03i),
+}
+var sqrt = []complex128{
+       (2.6628203086086130543813948e+00 + 1.4531345674282185229796902e+00i),
+       (2.7823278427251986247149295e+00 - 4.9756907317005224529115567e-02i),
+       (1.5397025302089642757361015e+00 - 1.6271336573016637535695727e+00i),
+       (1.7103411581506875260277898e+00 + 2.8170677122737589676157029e+00i),
+       (3.1390392472953103383607947e+00 + 4.6612625849858653248980849e-01i),
+       (2.1117080764822417640789287e+00 + 1.2381170223514273234967850e+00i),
+       (2.3587032281672256703926939e+00 + 5.7827111903257349935720172e-01i),
+       (1.7335262588873410476661577e+00 + 5.2647258220721269141550382e-01i),
+       (2.3131094974708716531499282e+00 - 1.8775429304303785570775490e+00i),
+       (8.1420535745048086240947359e-01 + 3.0575897587277248522656113e+00i),
+}
+var tan = []complex128{
+       (-1.928757919086441129134525e-07 + 1.0000003267499169073251826e+00i),
+       (1.242412685364183792138948e+00 - 3.17149693883133370106696e+00i),
+       (-4.6745126251587795225571826e-05 - 9.9992439225263959286114298e-01i),
+       (4.792363401193648192887116e-09 + 1.0000000070589333451557723e+00i),
+       (2.345740824080089140287315e-03 + 9.947733046570988661022763e-01i),
+       (-2.396030789494815566088809e-05 + 9.9994781345418591429826779e-01i),
+       (-7.370204836644931340905303e-03 + 1.0043553413417138987717748e+00i),
+       (-3.691803847992048527007457e-02 + 9.6475071993469548066328894e-01i),
+       (-2.781955256713729368401878e-08 - 1.000000049848910609006646e+00i),
+       (9.4281590064030478879791249e-05 + 9.9999119340863718183758545e-01i),
+}
+var tanh = []complex128{
+       (1.0000921981225144748819918e+00 + 2.160986245871518020231507e-05i),
+       (9.9999967727531993209562591e-01 - 1.9953763222959658873657676e-07i),
+       (-1.765485739548037260789686e+00 + 1.7024216325552852445168471e+00i),
+       (-9.999189442732736452807108e-01 + 3.64906070494473701938098e-05i),
+       (9.9999999224622333738729767e-01 - 3.560088949517914774813046e-09i),
+       (1.0029324933367326862499343e+00 - 4.948790309797102353137528e-03i),
+       (9.9996113064788012488693567e-01 - 4.226995742097032481451259e-05i),
+       (1.0074784189316340029873945e+00 - 4.194050814891697808029407e-03i),
+       (9.9385534229718327109131502e-01 + 5.144217985914355502713437e-02i),
+       (-1.0000000491604982429364892e+00 - 2.901873195374433112227349e-08i),
+}
+
+// special cases
+var vcAbsSC = []complex128{
+       NaN(),
+}
+var absSC = []float64{
+       math.NaN(),
+}
+var vcAcosSC = []complex128{
+       NaN(),
+}
+var acosSC = []complex128{
+       NaN(),
+}
+var vcAcoshSC = []complex128{
+       NaN(),
+}
+var acoshSC = []complex128{
+       NaN(),
+}
+var vcAsinSC = []complex128{
+       NaN(),
+}
+var asinSC = []complex128{
+       NaN(),
+}
+var vcAsinhSC = []complex128{
+       NaN(),
+}
+var asinhSC = []complex128{
+       NaN(),
+}
+var vcAtanSC = []complex128{
+       NaN(),
+}
+var atanSC = []complex128{
+       NaN(),
+}
+var vcAtanhSC = []complex128{
+       NaN(),
+}
+var atanhSC = []complex128{
+       NaN(),
+}
+var vcConjSC = []complex128{
+       NaN(),
+}
+var conjSC = []complex128{
+       NaN(),
+}
+var vcCosSC = []complex128{
+       NaN(),
+}
+var cosSC = []complex128{
+       NaN(),
+}
+var vcCoshSC = []complex128{
+       NaN(),
+}
+var coshSC = []complex128{
+       NaN(),
+}
+var vcExpSC = []complex128{
+       NaN(),
+}
+var expSC = []complex128{
+       NaN(),
+}
+var vcIsNaNSC = []complex128{
+       cmplx(math.Inf(-1), math.Inf(-1)),
+       cmplx(math.Inf(-1), math.NaN()),
+       cmplx(math.NaN(), math.Inf(-1)),
+       cmplx(0, math.NaN()),
+       cmplx(math.NaN(), 0),
+       cmplx(math.Inf(1), math.Inf(1)),
+       cmplx(math.Inf(1), math.NaN()),
+       cmplx(math.NaN(), math.Inf(1)),
+       cmplx(math.NaN(), math.NaN()),
+}
+var isNaNSC = []bool{
+       false,
+       false,
+       false,
+       true,
+       true,
+       false,
+       false,
+       false,
+       true,
+}
+var vcLogSC = []complex128{
+       NaN(),
+}
+var logSC = []complex128{
+       NaN(),
+}
+var vcLog10SC = []complex128{
+       NaN(),
+}
+var log10SC = []complex128{
+       NaN(),
+}
+var vcPolarSC = []complex128{
+       NaN(),
+}
+var polarSC = []ff{
+       {math.NaN(), math.NaN()},
+}
+var vcPowSC = [][2]complex128{
+       {NaN(), NaN()},
+}
+var powSC = []complex128{
+       NaN(),
+}
+var vcSinSC = []complex128{
+       NaN(),
+}
+var sinSC = []complex128{
+       NaN(),
+}
+var vcSinhSC = []complex128{
+       NaN(),
+}
+var sinhSC = []complex128{
+       NaN(),
+}
+var vcSqrtSC = []complex128{
+       NaN(),
+}
+var sqrtSC = []complex128{
+       NaN(),
+}
+var vcTanSC = []complex128{
+       NaN(),
+}
+var tanSC = []complex128{
+       NaN(),
+}
+var vcTanhSC = []complex128{
+       NaN(),
+}
+var tanhSC = []complex128{
+       NaN(),
+}
+
+// functions borrowed from pkg/math/all_test.go
+func tolerance(a, b, e float64) bool {
+       d := a - b
+       if d < 0 {
+               d = -d
+       }
+
+       if a != 0 {
+               e = e * a
+               if e < 0 {
+                       e = -e
+               }
+       }
+       return d < e
+}
+func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
+func veryclose(a, b float64) bool  { return tolerance(a, b, 4e-16) }
+func alike(a, b float64) bool {
+       switch {
+       case a != a && b != b: // math.IsNaN(a) && math.IsNaN(b):
+               return true
+       case a == b:
+               return math.Signbit(a) == math.Signbit(b)
+       }
+       return false
+}
+
+func cTolerance(a, b complex128, e float64) bool {
+       d := Abs(a - b)
+       if a != 0 {
+               e = e * Abs(a)
+               if e < 0 {
+                       e = -e
+               }
+       }
+       return d < e
+}
+func cSoclose(a, b complex128, e float64) bool { return cTolerance(a, b, e) }
+func cVeryclose(a, b complex128) bool          { return cTolerance(a, b, 4e-16) }
+func cAlike(a, b complex128) bool {
+       switch {
+       case IsNaN(a) && IsNaN(b):
+               return true
+       case a == b:
+               return math.Signbit(real(a)) == math.Signbit(real(b)) && math.Signbit(imag(a)) == math.Signbit(imag(b))
+       }
+       return false
+}
+
+func TestAbs(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Abs(vc[i]); !veryclose(abs[i], f) {
+                       t.Errorf("Abs(%g) = %g, want %g", vc[i], f, abs[i])
+               }
+       }
+       for i := 0; i < len(vcAbsSC); i++ {
+               if f := Abs(vcAbsSC[i]); !alike(absSC[i], f) {
+                       t.Errorf("Abs(%g) = %g, want %g", vcAbsSC[i], f, absSC[i])
+               }
+       }
+}
+func TestAcos(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Acos(vc[i]); !cSoclose(acos[i], f, 1e-14) {
+                       t.Errorf("Acos(%g) = %g, want %g", vc[i], f, acos[i])
+               }
+       }
+       for i := 0; i < len(vcAcosSC); i++ {
+               if f := Acos(vcAcosSC[i]); !cAlike(acosSC[i], f) {
+                       t.Errorf("Acos(%g) = %g, want %g", vcAcosSC[i], f, acosSC[i])
+               }
+       }
+}
+func TestAcosh(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Acosh(vc[i]); !cSoclose(acosh[i], f, 1e-14) {
+                       t.Errorf("Acosh(%g) = %g, want %g", vc[i], f, acosh[i])
+               }
+       }
+       for i := 0; i < len(vcAcoshSC); i++ {
+               if f := Acosh(vcAcoshSC[i]); !cAlike(acoshSC[i], f) {
+                       t.Errorf("Acosh(%g) = %g, want %g", vcAcoshSC[i], f, acoshSC[i])
+               }
+       }
+}
+func TestAsin(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Asin(vc[i]); !cSoclose(asin[i], f, 1e-14) {
+                       t.Errorf("Asin(%g) = %g, want %g", vc[i], f, asin[i])
+               }
+       }
+       for i := 0; i < len(vcAsinSC); i++ {
+               if f := Asin(vcAsinSC[i]); !cAlike(asinSC[i], f) {
+                       t.Errorf("Asin(%g) = %g, want %g", vcAsinSC[i], f, asinSC[i])
+               }
+       }
+}
+func TestAsinh(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Asinh(vc[i]); !cSoclose(asinh[i], f, 4e-15) {
+                       t.Errorf("Asinh(%g) = %g, want %g", vc[i], f, asinh[i])
+               }
+       }
+       for i := 0; i < len(vcAsinhSC); i++ {
+               if f := Asinh(vcAsinhSC[i]); !cAlike(asinhSC[i], f) {
+                       t.Errorf("Asinh(%g) = %g, want %g", vcAsinhSC[i], f, asinhSC[i])
+               }
+       }
+}
+func TestAtan(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Atan(vc[i]); !cVeryclose(atan[i], f) {
+                       t.Errorf("Atan(%g) = %g, want %g", vc[i], f, atan[i])
+               }
+       }
+       for i := 0; i < len(vcAtanSC); i++ {
+               if f := Atan(vcAtanSC[i]); !cAlike(atanSC[i], f) {
+                       t.Errorf("Atan(%g) = %g, want %g", vcAtanSC[i], f, atanSC[i])
+               }
+       }
+}
+func TestAtanh(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Atanh(vc[i]); !cVeryclose(atanh[i], f) {
+                       t.Errorf("Atanh(%g) = %g, want %g", vc[i], f, atanh[i])
+               }
+       }
+       for i := 0; i < len(vcAtanhSC); i++ {
+               if f := Atanh(vcAtanhSC[i]); !cAlike(atanhSC[i], f) {
+                       t.Errorf("Atanh(%g) = %g, want %g", vcAtanhSC[i], f, atanhSC[i])
+               }
+       }
+}
+func TestConj(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Conj(vc[i]); !cVeryclose(conj[i], f) {
+                       t.Errorf("Conj(%g) = %g, want %g", vc[i], f, conj[i])
+               }
+       }
+       for i := 0; i < len(vcConjSC); i++ {
+               if f := Conj(vcConjSC[i]); !cAlike(conjSC[i], f) {
+                       t.Errorf("Conj(%g) = %g, want %g", vcConjSC[i], f, conjSC[i])
+               }
+       }
+}
+func TestCos(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Cos(vc[i]); !cSoclose(cos[i], f, 3e-15) {
+                       t.Errorf("Cos(%g) = %g, want %g", vc[i], f, cos[i])
+               }
+       }
+       for i := 0; i < len(vcCosSC); i++ {
+               if f := Cos(vcCosSC[i]); !cAlike(cosSC[i], f) {
+                       t.Errorf("Cos(%g) = %g, want %g", vcCosSC[i], f, cosSC[i])
+               }
+       }
+}
+func TestCosh(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Cosh(vc[i]); !cSoclose(cosh[i], f, 2e-15) {
+                       t.Errorf("Cosh(%g) = %g, want %g", vc[i], f, cosh[i])
+               }
+       }
+       for i := 0; i < len(vcCoshSC); i++ {
+               if f := Cosh(vcCoshSC[i]); !cAlike(coshSC[i], f) {
+                       t.Errorf("Cosh(%g) = %g, want %g", vcCoshSC[i], f, coshSC[i])
+               }
+       }
+}
+func TestExp(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Exp(vc[i]); !cSoclose(exp[i], f, 1e-15) {
+                       t.Errorf("Exp(%g) = %g, want %g", vc[i], f, exp[i])
+               }
+       }
+       for i := 0; i < len(vcExpSC); i++ {
+               if f := Exp(vcExpSC[i]); !cAlike(expSC[i], f) {
+                       t.Errorf("Exp(%g) = %g, want %g", vcExpSC[i], f, expSC[i])
+               }
+       }
+}
+func TestIsNaN(t *testing.T) {
+       for i := 0; i < len(vcIsNaNSC); i++ {
+               if f := IsNaN(vcIsNaNSC[i]); isNaNSC[i] != f {
+                       t.Errorf("IsNaN(%g) = %g, want %g", vcIsNaNSC[i], f, isNaNSC[i])
+               }
+       }
+}
+func TestLog(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Log(vc[i]); !cVeryclose(log[i], f) {
+                       t.Errorf("Log(%g) = %g, want %g", vc[i], f, log[i])
+               }
+       }
+       for i := 0; i < len(vcLogSC); i++ {
+               if f := Log(vcLogSC[i]); !cAlike(logSC[i], f) {
+                       t.Errorf("Log(%g) = %g, want %g", vcLogSC[i], f, logSC[i])
+               }
+       }
+}
+func TestLog10(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Log10(vc[i]); !cVeryclose(log10[i], f) {
+                       t.Errorf("Log10(%g) = %g, want %g", vc[i], f, log10[i])
+               }
+       }
+       for i := 0; i < len(vcLog10SC); i++ {
+               if f := Log10(vcLog10SC[i]); !cAlike(log10SC[i], f) {
+                       t.Errorf("Log10(%g) = %g, want %g", vcLog10SC[i], f, log10SC[i])
+               }
+       }
+}
+func TestPolar(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if r, theta := Polar(vc[i]); !veryclose(polar[i].r, r) && !veryclose(polar[i].theta, theta) {
+                       t.Errorf("Polar(%g) = %g, %g want %g, %g", vc[i], r, theta, polar[i].r, polar[i].theta)
+               }
+       }
+       for i := 0; i < len(vcPolarSC); i++ {
+               if r, theta := Polar(vcPolarSC[i]); !alike(polarSC[i].r, r) && !alike(polarSC[i].theta, theta) {
+                       t.Errorf("Polar(%g) = %g, %g, want %g, %g", vcPolarSC[i], r, theta, polarSC[i].r, polarSC[i].theta)
+               }
+       }
+}
+func TestPow(t *testing.T) {
+       var a = cmplx(float64(3), float64(3))
+       for i := 0; i < len(vc); i++ {
+               if f := Pow(a, vc[i]); !cSoclose(pow[i], f, 4e-15) {
+                       t.Errorf("Pow(%g, %g) = %g, want %g", a, vc[i], f, pow[i])
+               }
+       }
+       for i := 0; i < len(vcPowSC); i++ {
+               if f := Pow(vcPowSC[i][0], vcPowSC[i][0]); !cAlike(powSC[i], f) {
+                       t.Errorf("Pow(%g, %g) = %g, want %g", vcPowSC[i][0], vcPowSC[i][0], f, powSC[i])
+               }
+       }
+}
+func TestRect(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Rect(polar[i].r, polar[i].theta); !cVeryclose(vc[i], f) {
+                       t.Errorf("Rect(%g, %g) = %g want %g", polar[i].r, polar[i].theta, f, vc[i])
+               }
+       }
+       for i := 0; i < len(vcPolarSC); i++ {
+               if f := Rect(polarSC[i].r, polarSC[i].theta); !cAlike(vcPolarSC[i], f) {
+                       t.Errorf("Rect(%g, %g) = %g, want %g", polarSC[i].r, polarSC[i].theta, f, vcPolarSC[i])
+               }
+       }
+}
+func TestSin(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Sin(vc[i]); !cSoclose(sin[i], f, 2e-15) {
+                       t.Errorf("Sin(%g) = %g, want %g", vc[i], f, sin[i])
+               }
+       }
+       for i := 0; i < len(vcSinSC); i++ {
+               if f := Sin(vcSinSC[i]); !cAlike(sinSC[i], f) {
+                       t.Errorf("Sin(%g) = %g, want %g", vcSinSC[i], f, sinSC[i])
+               }
+       }
+}
+func TestSinh(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Sinh(vc[i]); !cSoclose(sinh[i], f, 2e-15) {
+                       t.Errorf("Sinh(%g) = %g, want %g", vc[i], f, sinh[i])
+               }
+       }
+       for i := 0; i < len(vcSinhSC); i++ {
+               if f := Sinh(vcSinhSC[i]); !cAlike(sinhSC[i], f) {
+                       t.Errorf("Sinh(%g) = %g, want %g", vcSinhSC[i], f, sinhSC[i])
+               }
+       }
+}
+func TestSqrt(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Sqrt(vc[i]); !cVeryclose(sqrt[i], f) {
+                       t.Errorf("Sqrt(%g) = %g, want %g", vc[i], f, sqrt[i])
+               }
+       }
+       for i := 0; i < len(vcSqrtSC); i++ {
+               if f := Sqrt(vcSqrtSC[i]); !cAlike(sqrtSC[i], f) {
+                       t.Errorf("Sqrt(%g) = %g, want %g", vcSqrtSC[i], f, sqrtSC[i])
+               }
+       }
+}
+func TestTan(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Tan(vc[i]); !cSoclose(tan[i], f, 3e-15) {
+                       t.Errorf("Tan(%g) = %g, want %g", vc[i], f, tan[i])
+               }
+       }
+       for i := 0; i < len(vcTanSC); i++ {
+               if f := Tan(vcTanSC[i]); !cAlike(tanSC[i], f) {
+                       t.Errorf("Tan(%g) = %g, want %g", vcTanSC[i], f, tanSC[i])
+               }
+       }
+}
+func TestTanh(t *testing.T) {
+       for i := 0; i < len(vc); i++ {
+               if f := Tanh(vc[i]); !cSoclose(tanh[i], f, 2e-15) {
+                       t.Errorf("Tanh(%g) = %g, want %g", vc[i], f, tanh[i])
+               }
+       }
+       for i := 0; i < len(vcTanhSC); i++ {
+               if f := Tanh(vcTanhSC[i]); !cAlike(tanhSC[i], f) {
+                       t.Errorf("Tanh(%g) = %g, want %g", vcTanhSC[i], f, tanhSC[i])
+               }
+       }
+}
+
+func BenchmarkAbs(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Abs(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkAcos(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Acos(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkAcosh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Acosh(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkAsin(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Asin(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkAsinh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Asinh(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkAtan(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atan(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkAtanh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atanh(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkConj(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Conj(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkCos(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Cos(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkCosh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Cosh(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkExp(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Exp(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkLog(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Log(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkLog10(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Log10(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkPhase(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Phase(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkPolar(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Polar(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkPow(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Pow(cmplx(2.5, 3.5), cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkRect(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Rect(2.5, 1.5)
+       }
+}
+func BenchmarkSin(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sin(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkSinh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sinh(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkSqrt(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sqrt(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkTan(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Tan(cmplx(2.5, 3.5))
+       }
+}
+func BenchmarkTanh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Tanh(cmplx(2.5, 3.5))
+       }
+}
diff --git a/libgo/go/cmath/conj.go b/libgo/go/cmath/conj.go
new file mode 100644 (file)
index 0000000..7a19e86
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+// Conj returns the complex conjugate of x.
+func Conj(x complex128) complex128 { return cmplx(real(x), -imag(x)) }
diff --git a/libgo/go/cmath/exp.go b/libgo/go/cmath/exp.go
new file mode 100644 (file)
index 0000000..1a639c5
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8:  June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+//    Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+//   The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+//   Stephen L. Moshier
+//   moshier@na-net.ornl.gov
+
+// Complex exponential function
+//
+// DESCRIPTION:
+//
+// Returns the complex exponential of the complex argument z.
+//
+// If
+//     z = x + iy,
+//     r = exp(x),
+// then
+//     w = r cos y + i r sin y.
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10      8700       3.7e-17     1.1e-17
+//    IEEE      -10,+10     30000       3.0e-16     8.7e-17
+
+// Exp returns e**x, the base-e exponential of x.
+func Exp(x complex128) complex128 {
+       r := math.Exp(real(x))
+       s, c := math.Sincos(imag(x))
+       return cmplx(r*c, r*s)
+}
diff --git a/libgo/go/cmath/isinf.go b/libgo/go/cmath/isinf.go
new file mode 100644 (file)
index 0000000..f17a752
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// IsInf returns true if either real(x) or imag(x) is an infinity.
+func IsInf(x complex128) bool {
+       if math.IsInf(real(x), 0) || math.IsInf(imag(x), 0) {
+               return true
+       }
+       return false
+}
+
+// Inf returns a complex infinity, cmplx(+Inf, +Inf).
+func Inf() complex128 {
+       inf := math.Inf(1)
+       return cmplx(inf, inf)
+}
diff --git a/libgo/go/cmath/isnan.go b/libgo/go/cmath/isnan.go
new file mode 100644 (file)
index 0000000..8e971db
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// IsNaN returns true if either real(x) or imag(x) is NaN
+// and neither is an infinity.
+func IsNaN(x complex128) bool {
+       switch {
+       case math.IsInf(real(x), 0) || math.IsInf(imag(x), 0):
+               return false
+       case math.IsNaN(real(x)) || math.IsNaN(imag(x)):
+               return true
+       }
+       return false
+}
+
+// NaN returns a complex ``not-a-number'' value.
+func NaN() complex128 {
+       nan := math.NaN()
+       return cmplx(nan, nan)
+}
diff --git a/libgo/go/cmath/log.go b/libgo/go/cmath/log.go
new file mode 100644 (file)
index 0000000..b42062b
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8:  June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+//    Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+//   The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+//   Stephen L. Moshier
+//   moshier@na-net.ornl.gov
+
+// Complex natural logarithm
+//
+// DESCRIPTION:
+//
+// Returns complex logarithm to the base e (2.718...) of
+// the complex argument z.
+//
+// If
+//       z = x + iy, r = sqrt( x**2 + y**2 ),
+// then
+//       w = log(r) + i arctan(y/x).
+//
+// The arctangent ranges from -PI to +PI.
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10      7000       8.5e-17     1.9e-17
+//    IEEE      -10,+10     30000       5.0e-15     1.1e-16
+//
+// Larger relative error can be observed for z near 1 +i0.
+// In IEEE arithmetic the peak absolute error is 5.2e-16, rms
+// absolute error 1.0e-16.
+
+// Log returns the natural logarithm of x.
+func Log(x complex128) complex128 {
+       return cmplx(math.Log(Abs(x)), Phase(x))
+}
+
+// Log10 returns the decimal logarithm of x.
+func Log10(x complex128) complex128 {
+       return math.Log10E * Log(x)
+}
diff --git a/libgo/go/cmath/phase.go b/libgo/go/cmath/phase.go
new file mode 100644 (file)
index 0000000..2d67aa3
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// Phase returns the phase (also called the argument) of x.
+// The returned value is in the range [-Pi, Pi].
+func Phase(x complex128) float64 { return math.Atan2(imag(x), real(x)) }
diff --git a/libgo/go/cmath/polar.go b/libgo/go/cmath/polar.go
new file mode 100644 (file)
index 0000000..033676a
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+// Polar returns the absolute value r and phase θ of x,
+// such that x = r * e**θi.
+// The phase is in the range [-Pi, Pi].
+func Polar(x complex128) (r, θ float64) {
+       return Abs(x), Phase(x)
+}
diff --git a/libgo/go/cmath/pow.go b/libgo/go/cmath/pow.go
new file mode 100644 (file)
index 0000000..de2c4db
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8:  June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+//    Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+//   The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+//   Stephen L. Moshier
+//   moshier@na-net.ornl.gov
+
+// Complex power function
+//
+// DESCRIPTION:
+//
+// Raises complex A to the complex Zth power.
+// Definition is per AMS55 # 4.2.8,
+// analytically equivalent to cpow(a,z) = cexp(z clog(a)).
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    IEEE      -10,+10     30000       9.4e-15     1.5e-15
+
+// Pow returns x**y, the base-x exponential of y.
+func Pow(x, y complex128) complex128 {
+       modulus := Abs(x)
+       if modulus == 0 {
+               return cmplx(0, 0)
+       }
+       r := math.Pow(modulus, real(y))
+       arg := Phase(x)
+       theta := real(y) * arg
+       if imag(y) != 0 {
+               r *= math.Exp(-imag(y) * arg)
+               theta += imag(y) * math.Log(modulus)
+       }
+       s, c := math.Sincos(theta)
+       return cmplx(r*c, r*s)
+}
diff --git a/libgo/go/cmath/rect.go b/libgo/go/cmath/rect.go
new file mode 100644 (file)
index 0000000..1a88d86
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// Rect returns the complex number x with polar coordinates r, θ.
+func Rect(r, θ float64) complex128 {
+       s, c := math.Sincos(θ)
+       return cmplx(r*c, r*s)
+}
diff --git a/libgo/go/cmath/sin.go b/libgo/go/cmath/sin.go
new file mode 100644 (file)
index 0000000..1b79da4
--- /dev/null
@@ -0,0 +1,132 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8:  June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+//    Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+//   The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+//   Stephen L. Moshier
+//   moshier@na-net.ornl.gov
+
+// Complex circular sine
+//
+// DESCRIPTION:
+//
+// If
+//     z = x + iy,
+//
+// then
+//
+//     w = sin x  cosh y  +  i cos x sinh y.
+//
+// csin(z) = -i csinh(iz).
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10      8400       5.3e-17     1.3e-17
+//    IEEE      -10,+10     30000       3.8e-16     1.0e-16
+// Also tested by csin(casin(z)) = z.
+
+// Sin returns the sine of x.
+func Sin(x complex128) complex128 {
+       s, c := math.Sincos(real(x))
+       sh, ch := sinhcosh(imag(x))
+       return cmplx(s*ch, c*sh)
+}
+
+// Complex hyperbolic sine
+//
+// DESCRIPTION:
+//
+// csinh z = (cexp(z) - cexp(-z))/2
+//         = sinh x * cos y  +  i cosh x * sin y .
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    IEEE      -10,+10     30000       3.1e-16     8.2e-17
+
+// Sinh returns the hyperbolic sine of x.
+func Sinh(x complex128) complex128 {
+       s, c := math.Sincos(imag(x))
+       sh, ch := sinhcosh(real(x))
+       return cmplx(c*sh, s*ch)
+}
+
+// Complex circular cosine
+//
+// DESCRIPTION:
+//
+// If
+//     z = x + iy,
+//
+// then
+//
+//     w = cos x  cosh y  -  i sin x sinh y.
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10      8400       4.5e-17     1.3e-17
+//    IEEE      -10,+10     30000       3.8e-16     1.0e-16
+
+// Cos returns the cosine of x.
+func Cos(x complex128) complex128 {
+       s, c := math.Sincos(real(x))
+       sh, ch := sinhcosh(imag(x))
+       return cmplx(c*ch, -s*sh)
+}
+
+// Complex hyperbolic cosine
+//
+// DESCRIPTION:
+//
+// ccosh(z) = cosh x  cos y + i sinh x sin y .
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    IEEE      -10,+10     30000       2.9e-16     8.1e-17
+
+// Cosh returns the hyperbolic cosine of x.
+func Cosh(x complex128) complex128 {
+       s, c := math.Sincos(imag(x))
+       sh, ch := sinhcosh(real(x))
+       return cmplx(c*ch, s*sh)
+}
+
+// calculate sinh and cosh
+func sinhcosh(x float64) (sh, ch float64) {
+       if math.Fabs(x) <= 0.5 {
+               return math.Sinh(x), math.Cosh(x)
+       }
+       e := math.Exp(x)
+       ei := 0.5 / e
+       e *= 0.5
+       return e - ei, e + ei
+}
diff --git a/libgo/go/cmath/sqrt.go b/libgo/go/cmath/sqrt.go
new file mode 100644 (file)
index 0000000..58bc4b6
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8:  June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+//    Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+//   The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+//   Stephen L. Moshier
+//   moshier@na-net.ornl.gov
+
+// Complex square root
+//
+// DESCRIPTION:
+//
+// If z = x + iy,  r = |z|, then
+//
+//                       1/2
+// Re w  =  [ (r + x)/2 ]   ,
+//
+//                       1/2
+// Im w  =  [ (r - x)/2 ]   .
+//
+// Cancellation error in r-x or r+x is avoided by using the
+// identity  2 Re w Im w  =  y.
+//
+// Note that -w is also a square root of z.  The root chosen
+// is always in the right half plane and Im w has the same sign as y.
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10     25000       3.2e-17     9.6e-18
+//    IEEE      -10,+10   1,000,000     2.9e-16     6.1e-17
+
+// Sqrt returns the square root of x.
+func Sqrt(x complex128) complex128 {
+       if imag(x) == 0 {
+               if real(x) == 0 {
+                       return cmplx(0, 0)
+               }
+               if real(x) < 0 {
+                       return cmplx(0, math.Sqrt(-real(x)))
+               }
+               return cmplx(math.Sqrt(real(x)), 0)
+       }
+       if real(x) == 0 {
+               if imag(x) < 0 {
+                       r := math.Sqrt(-0.5 * imag(x))
+                       return cmplx(r, -r)
+               }
+               r := math.Sqrt(0.5 * imag(x))
+               return cmplx(r, r)
+       }
+       a := real(x)
+       b := imag(x)
+       var scale float64
+       // Rescale to avoid internal overflow or underflow.
+       if math.Fabs(a) > 4 || math.Fabs(b) > 4 {
+               a *= 0.25
+               b *= 0.25
+               scale = 2
+       } else {
+               a *= 1.8014398509481984e16 // 2**54
+               b *= 1.8014398509481984e16
+               scale = 7.450580596923828125e-9 // 2**-27
+       }
+       r := math.Hypot(a, b)
+       var t float64
+       if a > 0 {
+               t = math.Sqrt(0.5*r + 0.5*a)
+               r = scale * math.Fabs((0.5*b)/t)
+               t *= scale
+       } else {
+               r = math.Sqrt(0.5*r - 0.5*a)
+               t = scale * math.Fabs((0.5*b)/r)
+               r *= scale
+       }
+       if b < 0 {
+               return cmplx(t, -r)
+       }
+       return cmplx(t, r)
+}
diff --git a/libgo/go/cmath/tan.go b/libgo/go/cmath/tan.go
new file mode 100644 (file)
index 0000000..d1945cd
--- /dev/null
@@ -0,0 +1,184 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8:  June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+//    Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+//   The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+//   Stephen L. Moshier
+//   moshier@na-net.ornl.gov
+
+// Complex circular tangent
+//
+// DESCRIPTION:
+//
+// If
+//     z = x + iy,
+//
+// then
+//
+//           sin 2x  +  i sinh 2y
+//     w  =  --------------------.
+//            cos 2x  +  cosh 2y
+//
+// On the real axis the denominator is zero at odd multiples
+// of PI/2.  The denominator is evaluated by its Taylor
+// series near these points.
+//
+// ctan(z) = -i ctanh(iz).
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10      5200       7.1e-17     1.6e-17
+//    IEEE      -10,+10     30000       7.2e-16     1.2e-16
+// Also tested by ctan * ccot = 1 and catan(ctan(z))  =  z.
+
+// Tan returns the tangent of x.
+func Tan(x complex128) complex128 {
+       d := math.Cos(2*real(x)) + math.Cosh(2*imag(x))
+       if math.Fabs(d) < 0.25 {
+               d = tanSeries(x)
+       }
+       if d == 0 {
+               return Inf()
+       }
+       return cmplx(math.Sin(2*real(x))/d, math.Sinh(2*imag(x))/d)
+}
+
+// Complex hyperbolic tangent
+//
+// DESCRIPTION:
+//
+// tanh z = (sinh 2x  +  i sin 2y) / (cosh 2x + cos 2y) .
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    IEEE      -10,+10     30000       1.7e-14     2.4e-16
+
+// Tanh returns the hyperbolic tangent of x.
+func Tanh(x complex128) complex128 {
+       d := math.Cosh(2*real(x)) + math.Cos(2*imag(x))
+       if d == 0 {
+               return Inf()
+       }
+       return cmplx(math.Sinh(2*real(x))/d, math.Sin(2*imag(x))/d)
+}
+
+// Program to subtract nearest integer multiple of PI
+func reducePi(x float64) float64 {
+       const (
+               // extended precision value of PI:
+               DP1 = 3.14159265160560607910E0   // ?? 0x400921fb54000000
+               DP2 = 1.98418714791870343106E-9  // ?? 0x3e210b4610000000
+               DP3 = 1.14423774522196636802E-17 // ?? 0x3c6a62633145c06e
+       )
+       t := x / math.Pi
+       if t >= 0 {
+               t += 0.5
+       } else {
+               t -= 0.5
+       }
+       t = float64(int64(t)) // int64(t) = the multiple
+       return ((x - t*DP1) - t*DP2) - t*DP3
+}
+
+// Taylor series expansion for cosh(2y) - cos(2x)
+func tanSeries(z complex128) float64 {
+       const MACHEP = 1.0 / (1 << 53)
+       x := math.Fabs(2 * real(z))
+       y := math.Fabs(2 * imag(z))
+       x = reducePi(x)
+       x = x * x
+       y = y * y
+       x2 := float64(1)
+       y2 := float64(1)
+       f := float64(1)
+       rn := float64(0)
+       d := float64(0)
+       for {
+               rn += 1
+               f *= rn
+               rn += 1
+               f *= rn
+               x2 *= x
+               y2 *= y
+               t := y2 + x2
+               t /= f
+               d += t
+
+               rn += 1
+               f *= rn
+               rn += 1
+               f *= rn
+               x2 *= x
+               y2 *= y
+               t = y2 - x2
+               t /= f
+               d += t
+               if math.Fabs(t/d) <= MACHEP {
+                       break
+               }
+       }
+       return d
+}
+
+// Complex circular cotangent
+//
+// DESCRIPTION:
+//
+// If
+//     z = x + iy,
+//
+// then
+//
+//           sin 2x  -  i sinh 2y
+//     w  =  --------------------.
+//            cosh 2y  -  cos 2x
+//
+// On the real axis, the denominator has zeros at even
+// multiples of PI/2.  Near these points it is evaluated
+// by a Taylor series.
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC       -10,+10      3000       6.5e-17     1.6e-17
+//    IEEE      -10,+10     30000       9.2e-16     1.2e-16
+// Also tested by ctan * ccot = 1 + i0.
+
+// Cot returns the cotangent of x.
+func Cot(x complex128) complex128 {
+       d := math.Cosh(2*imag(x)) - math.Cos(2*real(x))
+       if math.Fabs(d) < 0.25 {
+               d = tanSeries(x)
+       }
+       if d == 0 {
+               return Inf()
+       }
+       return cmplx(math.Sin(2*real(x))/d, -math.Sinh(2*imag(x))/d)
+}
diff --git a/libgo/go/compress/flate/deflate.go b/libgo/go/compress/flate/deflate.go
new file mode 100644 (file)
index 0000000..509c8de
--- /dev/null
@@ -0,0 +1,441 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+       "io"
+       "math"
+       "os"
+)
+
+const (
+       NoCompression        = 0
+       BestSpeed            = 1
+       fastCompression      = 3
+       BestCompression      = 9
+       DefaultCompression   = -1
+       logMaxOffsetSize     = 15  // Standard DEFLATE
+       wideLogMaxOffsetSize = 22  // Wide DEFLATE
+       minMatchLength       = 3   // The smallest match that the compressor looks for
+       maxMatchLength       = 258 // The longest match for the compressor
+       minOffsetSize        = 1   // The shortest offset that makes any sence
+
+       // The maximum number of tokens we put into a single flat block, just too
+       // stop things from getting too large.
+       maxFlateBlockTokens = 1 << 14
+       maxStoreBlockSize   = 65535
+       hashBits            = 15
+       hashSize            = 1 << hashBits
+       hashMask            = (1 << hashBits) - 1
+       hashShift           = (hashBits + minMatchLength - 1) / minMatchLength
+)
+
+type syncPipeReader struct {
+       *io.PipeReader
+       closeChan chan bool
+}
+
+func (sr *syncPipeReader) CloseWithError(err os.Error) os.Error {
+       retErr := sr.PipeReader.CloseWithError(err)
+       sr.closeChan <- true // finish writer close
+       return retErr
+}
+
+type syncPipeWriter struct {
+       *io.PipeWriter
+       closeChan chan bool
+}
+
+type compressionLevel struct {
+       good, lazy, nice, chain, fastSkipHashing int
+}
+
+var levels = []compressionLevel{
+       {}, // 0
+       // For levels 1-3 we don't bother trying with lazy matches
+       {3, 0, 8, 4, 4},
+       {3, 0, 16, 8, 5},
+       {3, 0, 32, 32, 6},
+       // Levels 4-9 use increasingly more lazy matching
+       // and increasingly stringent conditions for "good enough".
+       {4, 4, 16, 16, math.MaxInt32},
+       {8, 16, 32, 32, math.MaxInt32},
+       {8, 16, 128, 128, math.MaxInt32},
+       {8, 32, 128, 256, math.MaxInt32},
+       {32, 128, 258, 1024, math.MaxInt32},
+       {32, 258, 258, 4096, math.MaxInt32},
+}
+
+func (sw *syncPipeWriter) Close() os.Error {
+       err := sw.PipeWriter.Close()
+       <-sw.closeChan // wait for reader close
+       return err
+}
+
+func syncPipe() (*syncPipeReader, *syncPipeWriter) {
+       r, w := io.Pipe()
+       sr := &syncPipeReader{r, make(chan bool, 1)}
+       sw := &syncPipeWriter{w, sr.closeChan}
+       return sr, sw
+}
+
+type compressor struct {
+       level         int
+       logWindowSize uint
+       w             *huffmanBitWriter
+       r             io.Reader
+       // (1 << logWindowSize) - 1.
+       windowMask int
+
+       // hashHead[hashValue] contains the largest inputIndex with the specified hash value
+       hashHead []int
+
+       // If hashHead[hashValue] is within the current window, then
+       // hashPrev[hashHead[hashValue] & windowMask] contains the previous index
+       // with the same hash value.
+       hashPrev []int
+
+       // If we find a match of length >= niceMatch, then we don't bother searching
+       // any further.
+       niceMatch int
+
+       // If we find a match of length >= goodMatch, we only do a half-hearted
+       // effort at doing lazy matching starting at the next character
+       goodMatch int
+
+       // The maximum number of chains we look at when finding a match
+       maxChainLength int
+
+       // The sliding window we use for matching
+       window []byte
+
+       // The index just past the last valid character
+       windowEnd int
+
+       // index in "window" at which current block starts
+       blockStart int
+}
+
+func (d *compressor) flush() os.Error {
+       d.w.flush()
+       return d.w.err
+}
+
+func (d *compressor) fillWindow(index int) (int, os.Error) {
+       wSize := d.windowMask + 1
+       if index >= wSize+wSize-(minMatchLength+maxMatchLength) {
+               // shift the window by wSize
+               copy(d.window, d.window[wSize:2*wSize])
+               index -= wSize
+               d.windowEnd -= wSize
+               if d.blockStart >= wSize {
+                       d.blockStart -= wSize
+               } else {
+                       d.blockStart = math.MaxInt32
+               }
+               for i, h := range d.hashHead {
+                       d.hashHead[i] = max(h-wSize, -1)
+               }
+               for i, h := range d.hashPrev {
+                       d.hashPrev[i] = max(h-wSize, -1)
+               }
+       }
+       var count int
+       var err os.Error
+       count, err = io.ReadAtLeast(d.r, d.window[d.windowEnd:], 1)
+       d.windowEnd += count
+       if err == os.EOF {
+               return index, nil
+       }
+       return index, err
+}
+
+func (d *compressor) writeBlock(tokens []token, index int, eof bool) os.Error {
+       if index > 0 || eof {
+               var window []byte
+               if d.blockStart <= index {
+                       window = d.window[d.blockStart:index]
+               }
+               d.blockStart = index
+               d.w.writeBlock(tokens, eof, window)
+               return d.w.err
+       }
+       return nil
+}
+
+// Try to find a match starting at index whose length is greater than prevSize.
+// We only look at chainCount possibilities before giving up.
+func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
+       win := d.window[0 : pos+min(maxMatchLength, lookahead)]
+
+       // We quit when we get a match that's at least nice long
+       nice := min(d.niceMatch, len(win)-pos)
+
+       // If we've got a match that's good enough, only look in 1/4 the chain.
+       tries := d.maxChainLength
+       length = prevLength
+       if length >= d.goodMatch {
+               tries >>= 2
+       }
+
+       w0 := win[pos]
+       w1 := win[pos+1]
+       wEnd := win[pos+length]
+       minIndex := pos - (d.windowMask + 1)
+
+       for i := prevHead; tries > 0; tries-- {
+               if w0 == win[i] && w1 == win[i+1] && wEnd == win[i+length] {
+                       // The hash function ensures that if win[i] and win[i+1] match, win[i+2] matches
+
+                       n := 3
+                       for pos+n < len(win) && win[i+n] == win[pos+n] {
+                               n++
+                       }
+                       if n > length && (n > 3 || pos-i <= 4096) {
+                               length = n
+                               offset = pos - i
+                               ok = true
+                               if n >= nice {
+                                       // The match is good enough that we don't try to find a better one.
+                                       break
+                               }
+                               wEnd = win[pos+n]
+                       }
+               }
+               if i == minIndex {
+                       // hashPrev[i & windowMask] has already been overwritten, so stop now.
+                       break
+               }
+               if i = d.hashPrev[i&d.windowMask]; i < minIndex || i < 0 {
+                       break
+               }
+       }
+       return
+}
+
+func (d *compressor) writeStoredBlock(buf []byte) os.Error {
+       if d.w.writeStoredHeader(len(buf), false); d.w.err != nil {
+               return d.w.err
+       }
+       d.w.writeBytes(buf)
+       return d.w.err
+}
+
+func (d *compressor) storedDeflate() os.Error {
+       buf := make([]byte, maxStoreBlockSize)
+       for {
+               n, err := d.r.Read(buf)
+               if n > 0 {
+                       if err := d.writeStoredBlock(buf[0:n]); err != nil {
+                               return err
+                       }
+               }
+               if err != nil {
+                       if err == os.EOF {
+                               break
+                       }
+                       return err
+               }
+       }
+       return nil
+}
+
+func (d *compressor) doDeflate() (err os.Error) {
+       // init
+       d.windowMask = 1<<d.logWindowSize - 1
+       d.hashHead = make([]int, hashSize)
+       d.hashPrev = make([]int, 1<<d.logWindowSize)
+       d.window = make([]byte, 2<<d.logWindowSize)
+       fillInts(d.hashHead, -1)
+       tokens := make([]token, maxFlateBlockTokens, maxFlateBlockTokens+1)
+       l := levels[d.level]
+       d.goodMatch = l.good
+       d.niceMatch = l.nice
+       d.maxChainLength = l.chain
+       lazyMatch := l.lazy
+       length := minMatchLength - 1
+       offset := 0
+       byteAvailable := false
+       isFastDeflate := l.fastSkipHashing != 0
+       index := 0
+       // run
+       if index, err = d.fillWindow(index); err != nil {
+               return
+       }
+       maxOffset := d.windowMask + 1 // (1 << logWindowSize);
+       // only need to change when you refill the window
+       windowEnd := d.windowEnd
+       maxInsertIndex := windowEnd - (minMatchLength - 1)
+       ti := 0
+
+       hash := int(0)
+       if index < maxInsertIndex {
+               hash = int(d.window[index])<<hashShift + int(d.window[index+1])
+       }
+       chainHead := -1
+       for {
+               if index > windowEnd {
+                       panic("index > windowEnd")
+               }
+               lookahead := windowEnd - index
+               if lookahead < minMatchLength+maxMatchLength {
+                       if index, err = d.fillWindow(index); err != nil {
+                               return
+                       }
+                       windowEnd = d.windowEnd
+                       if index > windowEnd {
+                               panic("index > windowEnd")
+                       }
+                       maxInsertIndex = windowEnd - (minMatchLength - 1)
+                       lookahead = windowEnd - index
+                       if lookahead == 0 {
+                               break
+                       }
+               }
+               if index < maxInsertIndex {
+                       // Update the hash
+                       hash = (hash<<hashShift + int(d.window[index+2])) & hashMask
+                       chainHead = d.hashHead[hash]
+                       d.hashPrev[index&d.windowMask] = chainHead
+                       d.hashHead[hash] = index
+               }
+               prevLength := length
+               prevOffset := offset
+               minIndex := max(index-maxOffset, 0)
+               length = minMatchLength - 1
+               offset = 0
+
+               if chainHead >= minIndex &&
+                       (isFastDeflate && lookahead > minMatchLength-1 ||
+                               !isFastDeflate && lookahead > prevLength && prevLength < lazyMatch) {
+                       if newLength, newOffset, ok := d.findMatch(index, chainHead, minMatchLength-1, lookahead); ok {
+                               length = newLength
+                               offset = newOffset
+                       }
+               }
+               if isFastDeflate && length >= minMatchLength ||
+                       !isFastDeflate && prevLength >= minMatchLength && length <= prevLength {
+                       // There was a match at the previous step, and the current match is
+                       // not better. Output the previous match.
+                       if isFastDeflate {
+                               tokens[ti] = matchToken(uint32(length-minMatchLength), uint32(offset-minOffsetSize))
+                       } else {
+                               tokens[ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize))
+                       }
+                       ti++
+                       // Insert in the hash table all strings up to the end of the match.
+                       // index and index-1 are already inserted. If there is not enough
+                       // lookahead, the last two strings are not inserted into the hash
+                       // table.
+                       if length <= l.fastSkipHashing {
+                               var newIndex int
+                               if isFastDeflate {
+                                       newIndex = index + length
+                               } else {
+                                       newIndex = prevLength - 1
+                               }
+                               for index++; index < newIndex; index++ {
+                                       if index < maxInsertIndex {
+                                               hash = (hash<<hashShift + int(d.window[index+2])) & hashMask
+                                               // Get previous value with the same hash.
+                                               // Our chain should point to the previous value.
+                                               d.hashPrev[index&d.windowMask] = d.hashHead[hash]
+                                               // Set the head of the hash chain to us.
+                                               d.hashHead[hash] = index
+                                       }
+                               }
+                               if !isFastDeflate {
+                                       byteAvailable = false
+                                       length = minMatchLength - 1
+                               }
+                       } else {
+                               // For matches this long, we don't bother inserting each individual
+                               // item into the table.
+                               index += length
+                               hash = (int(d.window[index])<<hashShift + int(d.window[index+1]))
+                       }
+                       if ti == maxFlateBlockTokens {
+                               // The block includes the current character
+                               if err = d.writeBlock(tokens, index, false); err != nil {
+                                       return
+                               }
+                               ti = 0
+                       }
+               } else {
+                       if isFastDeflate || byteAvailable {
+                               i := index - 1
+                               if isFastDeflate {
+                                       i = index
+                               }
+                               tokens[ti] = literalToken(uint32(d.window[i]) & 0xFF)
+                               ti++
+                               if ti == maxFlateBlockTokens {
+                                       if err = d.writeBlock(tokens, i+1, false); err != nil {
+                                               return
+                                       }
+                                       ti = 0
+                               }
+                       }
+                       index++
+                       if !isFastDeflate {
+                               byteAvailable = true
+                       }
+               }
+
+       }
+       if byteAvailable {
+               // There is still one pending token that needs to be flushed
+               tokens[ti] = literalToken(uint32(d.window[index-1]) & 0xFF)
+               ti++
+       }
+
+       if ti > 0 {
+               if err = d.writeBlock(tokens[0:ti], index, false); err != nil {
+                       return
+               }
+       }
+       return
+}
+
+func (d *compressor) compressor(r io.Reader, w io.Writer, level int, logWindowSize uint) (err os.Error) {
+       d.r = r
+       d.w = newHuffmanBitWriter(w)
+       d.level = level
+       d.logWindowSize = logWindowSize
+
+       switch {
+       case level == NoCompression:
+               err = d.storedDeflate()
+       case level == DefaultCompression:
+               d.level = 6
+               fallthrough
+       case 1 <= level && level <= 9:
+               err = d.doDeflate()
+       default:
+               return WrongValueError{"level", 0, 9, int32(level)}
+       }
+
+       if err != nil {
+               return err
+       }
+       if d.w.writeStoredHeader(0, true); d.w.err != nil {
+               return d.w.err
+       }
+       return d.flush()
+}
+
+func newCompressor(w io.Writer, level int, logWindowSize uint) io.WriteCloser {
+       var d compressor
+       pr, pw := syncPipe()
+       go func() {
+               err := d.compressor(pr, w, level, logWindowSize)
+               pr.CloseWithError(err)
+       }()
+       return pw
+}
+
+func NewWriter(w io.Writer, level int) io.WriteCloser {
+       return newCompressor(w, level, logMaxOffsetSize)
+}
diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go
new file mode 100644 (file)
index 0000000..9718d2f
--- /dev/null
@@ -0,0 +1,264 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+       "bytes"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "testing"
+)
+
+type deflateTest struct {
+       in    []byte
+       level int
+       out   []byte
+}
+
+type deflateInflateTest struct {
+       in []byte
+}
+
+type reverseBitsTest struct {
+       in       uint16
+       bitCount uint8
+       out      uint16
+}
+
+var deflateTests = []*deflateTest{
+       &deflateTest{[]byte{}, 0, []byte{1, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}},
+
+       &deflateTest{[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0,
+               []byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255},
+       },
+       &deflateTest{[]byte{}, 1, []byte{1, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11}, 1, []byte{18, 4, 4, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11, 0x12}, 1, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 1, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+       &deflateTest{[]byte{}, 9, []byte{1, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+       &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+}
+
+var deflateInflateTests = []*deflateInflateTest{
+       &deflateInflateTest{[]byte{}},
+       &deflateInflateTest{[]byte{0x11}},
+       &deflateInflateTest{[]byte{0x11, 0x12}},
+       &deflateInflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
+       &deflateInflateTest{[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}},
+       &deflateInflateTest{getLargeDataChunk()},
+}
+
+var reverseBitsTests = []*reverseBitsTest{
+       &reverseBitsTest{1, 1, 1},
+       &reverseBitsTest{1, 2, 2},
+       &reverseBitsTest{1, 3, 4},
+       &reverseBitsTest{1, 4, 8},
+       &reverseBitsTest{1, 5, 16},
+       &reverseBitsTest{17, 5, 17},
+       &reverseBitsTest{257, 9, 257},
+       &reverseBitsTest{29, 5, 23},
+}
+
+func getLargeDataChunk() []byte {
+       result := make([]byte, 100000)
+       for i := range result {
+               result[i] = byte(int64(i) * int64(i) & 0xFF)
+       }
+       return result
+}
+
+func TestDeflate(t *testing.T) {
+       for _, h := range deflateTests {
+               buffer := bytes.NewBuffer([]byte{})
+               w := NewWriter(buffer, h.level)
+               w.Write(h.in)
+               w.Close()
+               if bytes.Compare(buffer.Bytes(), h.out) != 0 {
+                       t.Errorf("buffer is wrong; level = %v, buffer.Bytes() = %v, expected output = %v",
+                               h.level, buffer.Bytes(), h.out)
+               }
+       }
+}
+
+func testToFromWithLevel(t *testing.T, level int, input []byte, name string) os.Error {
+       buffer := bytes.NewBuffer([]byte{})
+       w := NewWriter(buffer, level)
+       w.Write(input)
+       w.Close()
+       decompressor := NewReader(buffer)
+       decompressed, err := ioutil.ReadAll(decompressor)
+       if err != nil {
+               t.Errorf("reading decompressor: %s", err)
+               return err
+       }
+       decompressor.Close()
+       if bytes.Compare(input, decompressed) != 0 {
+               t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name)
+       }
+       return nil
+}
+
+func testToFrom(t *testing.T, input []byte, name string) {
+       for i := 0; i < 10; i++ {
+               testToFromWithLevel(t, i, input, name)
+       }
+}
+
+func TestDeflateInflate(t *testing.T) {
+       for i, h := range deflateInflateTests {
+               testToFrom(t, h.in, fmt.Sprintf("#%d", i))
+       }
+}
+
+func TestReverseBits(t *testing.T) {
+       for _, h := range reverseBitsTests {
+               if v := reverseBits(h.in, h.bitCount); v != h.out {
+                       t.Errorf("reverseBits(%v,%v) = %v, want %v",
+                               h.in, h.bitCount, v, h.out)
+               }
+       }
+}
+
+func TestDeflateInflateString(t *testing.T) {
+       gold := bytes.NewBufferString(getEdata()).Bytes()
+       testToFromWithLevel(t, 1, gold, "2.718281828...")
+}
+
+func getEdata() string {
+       return "2.718281828459045235360287471352662497757247093699959574966967627724076630353547" +
+               "59457138217852516642742746639193200305992181741359662904357290033429526059563073" +
+               "81323286279434907632338298807531952510190115738341879307021540891499348841675092" +
+               "44761460668082264800168477411853742345442437107539077744992069551702761838606261" +
+               "33138458300075204493382656029760673711320070932870912744374704723069697720931014" +
+               "16928368190255151086574637721112523897844250569536967707854499699679468644549059" +
+               "87931636889230098793127736178215424999229576351482208269895193668033182528869398" +
+               "49646510582093923982948879332036250944311730123819706841614039701983767932068328" +
+               "23764648042953118023287825098194558153017567173613320698112509961818815930416903" +
+               "51598888519345807273866738589422879228499892086805825749279610484198444363463244" +
+               "96848756023362482704197862320900216099023530436994184914631409343173814364054625" +
+               "31520961836908887070167683964243781405927145635490613031072085103837505101157477" +
+               "04171898610687396965521267154688957035035402123407849819334321068170121005627880" +
+               "23519303322474501585390473041995777709350366041699732972508868769664035557071622" +
+               "68447162560798826517871341951246652010305921236677194325278675398558944896970964" +
+               "09754591856956380236370162112047742722836489613422516445078182442352948636372141" +
+               "74023889344124796357437026375529444833799801612549227850925778256209262264832627" +
+               "79333865664816277251640191059004916449982893150566047258027786318641551956532442" +
+               "58698294695930801915298721172556347546396447910145904090586298496791287406870504" +
+               "89585867174798546677575732056812884592054133405392200011378630094556068816674001" +
+               "69842055804033637953764520304024322566135278369511778838638744396625322498506549" +
+               "95886234281899707733276171783928034946501434558897071942586398772754710962953741" +
+               "52111513683506275260232648472870392076431005958411661205452970302364725492966693" +
+               "81151373227536450988890313602057248176585118063036442812314965507047510254465011" +
+               "72721155519486685080036853228183152196003735625279449515828418829478761085263981" +
+               "39559900673764829224437528718462457803619298197139914756448826260390338144182326" +
+               "25150974827987779964373089970388867782271383605772978824125611907176639465070633" +
+               "04527954661855096666185664709711344474016070462621568071748187784437143698821855" +
+               "96709591025968620023537185887485696522000503117343920732113908032936344797273559" +
+               "55277349071783793421637012050054513263835440001863239914907054797780566978533580" +
+               "48966906295119432473099587655236812859041383241160722602998330535370876138939639" +
+               "17795745401613722361878936526053815584158718692553860616477983402543512843961294" +
+               "60352913325942794904337299085731580290958631382683291477116396337092400316894586" +
+               "36060645845925126994655724839186564209752685082307544254599376917041977780085362" +
+               "73094171016343490769642372229435236612557250881477922315197477806056967253801718" +
+               "07763603462459278778465850656050780844211529697521890874019660906651803516501792" +
+               "50461950136658543663271254963990854914420001457476081930221206602433009641270489" +
+               "43903971771951806990869986066365832322787093765022601492910115171776359446020232" +
+               "49300280401867723910288097866605651183260043688508817157238669842242201024950551" +
+               "88169480322100251542649463981287367765892768816359831247788652014117411091360116" +
+               "49950766290779436460058519419985601626479076153210387275571269925182756879893027" +
+               "61761146162549356495903798045838182323368612016243736569846703785853305275833337" +
+               "93990752166069238053369887956513728559388349989470741618155012539706464817194670" +
+               "83481972144888987906765037959036696724949925452790337296361626589760394985767413" +
+               "97359441023744329709355477982629614591442936451428617158587339746791897571211956" +
+               "18738578364475844842355558105002561149239151889309946342841393608038309166281881" +
+               "15037152849670597416256282360921680751501777253874025642534708790891372917228286" +
+               "11515915683725241630772254406337875931059826760944203261924285317018781772960235" +
+               "41306067213604600038966109364709514141718577701418060644363681546444005331608778" +
+               "31431744408119494229755993140118886833148328027065538330046932901157441475631399" +
+               "97221703804617092894579096271662260740718749975359212756084414737823303270330168" +
+               "23719364800217328573493594756433412994302485023573221459784328264142168487872167" +
+               "33670106150942434569844018733128101079451272237378861260581656680537143961278887" +
+               "32527373890392890506865324138062796025930387727697783792868409325365880733988457" +
+               "21874602100531148335132385004782716937621800490479559795929059165547050577751430" +
+               "81751126989851884087185640260353055837378324229241856256442550226721559802740126" +
+               "17971928047139600689163828665277009752767069777036439260224372841840883251848770" +
+               "47263844037953016690546593746161932384036389313136432713768884102681121989127522" +
+               "30562567562547017250863497653672886059667527408686274079128565769963137897530346" +
+               "60616669804218267724560530660773899624218340859882071864682623215080288286359746" +
+               "83965435885668550377313129658797581050121491620765676995065971534476347032085321" +
+               "56036748286083786568030730626576334697742956346437167093971930608769634953288468" +
+               "33613038829431040800296873869117066666146800015121143442256023874474325250769387" +
+               "07777519329994213727721125884360871583483562696166198057252661220679754062106208" +
+               "06498829184543953015299820925030054982570433905535701686531205264956148572492573" +
+               "86206917403695213533732531666345466588597286659451136441370331393672118569553952" +
+               "10845840724432383558606310680696492485123263269951460359603729725319836842336390" +
+               "46321367101161928217111502828016044880588023820319814930963695967358327420249882" +
+               "45684941273860566491352526706046234450549227581151709314921879592718001940968866" +
+               "98683703730220047531433818109270803001720593553052070070607223399946399057131158" +
+               "70996357773590271962850611465148375262095653467132900259943976631145459026858989" +
+               "79115837093419370441155121920117164880566945938131183843765620627846310490346293" +
+               "95002945834116482411496975832601180073169943739350696629571241027323913874175492" +
+               "30718624545432220395527352952402459038057445028922468862853365422138157221311632" +
+               "88112052146489805180092024719391710555390113943316681515828843687606961102505171" +
+               "00739276238555338627255353883096067164466237092264680967125406186950214317621166" +
+               "81400975952814939072226011126811531083873176173232352636058381731510345957365382" +
+               "23534992935822836851007810884634349983518404451704270189381994243410090575376257" +
+               "76757111809008816418331920196262341628816652137471732547772778348877436651882875" +
+               "21566857195063719365653903894493664217640031215278702223664636357555035655769488" +
+               "86549500270853923617105502131147413744106134445544192101336172996285694899193369" +
+               "18472947858072915608851039678195942983318648075608367955149663644896559294818785" +
+               "17840387733262470519450504198477420141839477312028158868457072905440575106012852" +
+               "58056594703046836344592652552137008068752009593453607316226118728173928074623094" +
+               "68536782310609792159936001994623799343421068781349734695924646975250624695861690" +
+               "91785739765951993929939955675427146549104568607020990126068187049841780791739240" +
+               "71945996323060254707901774527513186809982284730860766536866855516467702911336827" +
+               "56310722334672611370549079536583453863719623585631261838715677411873852772292259" +
+               "47433737856955384562468010139057278710165129666367644518724656537304024436841408" +
+               "14488732957847348490003019477888020460324660842875351848364959195082888323206522" +
+               "12810419044804724794929134228495197002260131043006241071797150279343326340799596" +
+               "05314460532304885289729176598760166678119379323724538572096075822771784833616135" +
+               "82612896226118129455927462767137794487586753657544861407611931125958512655759734" +
+               "57301533364263076798544338576171533346232527057200530398828949903425956623297578" +
+               "24887350292591668258944568946559926584547626945287805165017206747854178879822768" +
+               "06536650641910973434528878338621726156269582654478205672987756426325321594294418" +
+               "03994321700009054265076309558846589517170914760743713689331946909098190450129030" +
+               "70995662266203031826493657336984195557769637876249188528656866076005660256054457" +
+               "11337286840205574416030837052312242587223438854123179481388550075689381124935386" +
+               "31863528708379984569261998179452336408742959118074745341955142035172618420084550" +
+               "91708456823682008977394558426792142734775608796442792027083121501564063413416171" +
+               "66448069815483764491573900121217041547872591998943825364950514771379399147205219" +
+               "52907939613762110723849429061635760459623125350606853765142311534966568371511660" +
+               "42207963944666211632551577290709784731562782775987881364919512574833287937715714" +
+               "59091064841642678309949723674420175862269402159407924480541255360431317992696739" +
+               "15754241929660731239376354213923061787675395871143610408940996608947141834069836" +
+               "29936753626215452472984642137528910798843813060955526227208375186298370667872244" +
+               "30195793793786072107254277289071732854874374355781966511716618330881129120245204" +
+               "04868220007234403502544820283425418788465360259150644527165770004452109773558589" +
+               "76226554849416217149895323834216001140629507184904277892585527430352213968356790" +
+               "18076406042138307308774460170842688272261177180842664333651780002171903449234264" +
+               "26629226145600433738386833555534345300426481847398921562708609565062934040526494" +
+               "32442614456659212912256488935696550091543064261342526684725949143142393988454324" +
+               "86327461842846655985332312210466259890141712103446084271616619001257195870793217" +
+               "56969854401339762209674945418540711844643394699016269835160784892451405894094639" +
+               "52678073545797003070511636825194877011897640028276484141605872061841852971891540" +
+               "19688253289309149665345753571427318482016384644832499037886069008072709327673127" +
+               "58196656394114896171683298045513972950668760474091542042842999354102582911350224" +
+               "16907694316685742425225090269390348148564513030699251995904363840284292674125734" +
+               "22447765584177886171737265462085498294498946787350929581652632072258992368768457" +
+               "01782303809656788311228930580914057261086588484587310165815116753332767488701482" +
+               "91674197015125597825727074064318086014281490241467804723275976842696339357735429" +
+               "30186739439716388611764209004068663398856841681003872389214483176070116684503887" +
+               "21236436704331409115573328018297798873659091665961240202177855885487617616198937" +
+               "07943800566633648843650891448055710397652146960276625835990519870423001794655367" +
+               "9"
+}
diff --git a/libgo/go/compress/flate/flate_test.go b/libgo/go/compress/flate/flate_test.go
new file mode 100644 (file)
index 0000000..bfd3b83
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test tests some internals of the flate package.
+// The tests in package compress/gzip serve as the
+// end-to-end test of the decompressor.
+
+package flate
+
+import (
+       "bytes"
+       "reflect"
+       "testing"
+)
+
+// The Huffman code lengths used by the fixed-format Huffman blocks.
+var fixedHuffmanBits = [...]int{
+       // 0-143 length 8
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+
+       // 144-255 length 9
+       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+
+       // 256-279 length 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,
+
+       // 280-287 length 8
+       8, 8, 8, 8, 8, 8, 8, 8,
+}
+
+type InitDecoderTest struct {
+       in  []int
+       out huffmanDecoder
+       ok  bool
+}
+
+var initDecoderTests = []*InitDecoderTest{
+       // Example from Connell 1973,
+       &InitDecoderTest{
+               []int{3, 5, 2, 4, 3, 5, 5, 4, 4, 3, 4, 5},
+               huffmanDecoder{
+                       2, 5,
+                       [maxCodeLen + 1]int{2: 0, 4, 13, 31},
+                       [maxCodeLen + 1]int{2: 0, 1, 6, 20},
+                       // Paper used different code assignment:
+                       // 2, 9, 4, 0, 10, 8, 3, 7, 1, 5, 11, 6
+                       // Reordered here so that codes of same length
+                       // are assigned to increasing numbers.
+                       []int{2, 0, 4, 9, 3, 7, 8, 10, 1, 5, 6, 11},
+               },
+               true,
+       },
+
+       // Example from RFC 1951 section 3.2.2
+       &InitDecoderTest{
+               []int{2, 1, 3, 3},
+               huffmanDecoder{
+                       1, 3,
+                       [maxCodeLen + 1]int{1: 0, 2, 7},
+                       [maxCodeLen + 1]int{1: 0, 1, 4},
+                       []int{1, 0, 2, 3},
+               },
+               true,
+       },
+
+       // Second example from RFC 1951 section 3.2.2
+       &InitDecoderTest{
+               []int{3, 3, 3, 3, 3, 2, 4, 4},
+               huffmanDecoder{
+                       2, 4,
+                       [maxCodeLen + 1]int{2: 0, 6, 15},
+                       [maxCodeLen + 1]int{2: 0, 1, 8},
+                       []int{5, 0, 1, 2, 3, 4, 6, 7},
+               },
+               true,
+       },
+
+       // Static Huffman codes (RFC 1951 section 3.2.6)
+       &InitDecoderTest{
+               fixedHuffmanBits[0:],
+               fixedHuffmanDecoder,
+               true,
+       },
+
+       // Illegal input.
+       &InitDecoderTest{
+               []int{},
+               huffmanDecoder{},
+               false,
+       },
+
+       // Illegal input.
+       &InitDecoderTest{
+               []int{0, 0, 0, 0, 0, 0, 0},
+               huffmanDecoder{},
+               false,
+       },
+}
+
+func TestInitDecoder(t *testing.T) {
+       for i, tt := range initDecoderTests {
+               var h huffmanDecoder
+               if h.init(tt.in) != tt.ok {
+                       t.Errorf("test %d: init = %v", i, !tt.ok)
+                       continue
+               }
+               if !reflect.DeepEqual(&h, &tt.out) {
+                       t.Errorf("test %d:\nhave %v\nwant %v", i, h, tt.out)
+               }
+       }
+}
+
+func TestUncompressedSource(t *testing.T) {
+       decoder := NewReader(bytes.NewBuffer([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
+       output := make([]byte, 1)
+       n, error := decoder.Read(output)
+       if n != 1 || error != nil {
+               t.Fatalf("decoder.Read() = %d, %v, want 1, nil", n, error)
+       }
+       if output[0] != 0x11 {
+               t.Errorf("output[0] = %x, want 0x11", output[0])
+       }
+}
diff --git a/libgo/go/compress/flate/huffman_bit_writer.go b/libgo/go/compress/flate/huffman_bit_writer.go
new file mode 100644 (file)
index 0000000..abff82d
--- /dev/null
@@ -0,0 +1,506 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+       "io"
+       "math"
+       "os"
+       "strconv"
+)
+
+const (
+       // The largest offset code.
+       offsetCodeCount = 30
+
+       // The largest offset code in the extensions.
+       extendedOffsetCodeCount = 42
+
+       // The special code used to mark the end of a block.
+       endBlockMarker = 256
+
+       // The first length code.
+       lengthCodesStart = 257
+
+       // The number of codegen codes.
+       codegenCodeCount = 19
+       badCode          = 255
+)
+
+// The number of extra bits needed by length code X - LENGTH_CODES_START.
+var lengthExtraBits = []int8{
+       /* 257 */ 0, 0, 0,
+       /* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
+       /* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
+       /* 280 */ 4, 5, 5, 5, 5, 0,
+}
+
+// The length indicated by length code X - LENGTH_CODES_START.
+var lengthBase = []uint32{
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 10,
+       12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+       64, 80, 96, 112, 128, 160, 192, 224, 255,
+}
+
+// offset code word extra bits.
+var offsetExtraBits = []int8{
+       0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
+       4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
+       9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
+       /* extended window */
+       14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20,
+}
+
+var offsetBase = []uint32{
+       /* normal deflate */
+       0x000000, 0x000001, 0x000002, 0x000003, 0x000004,
+       0x000006, 0x000008, 0x00000c, 0x000010, 0x000018,
+       0x000020, 0x000030, 0x000040, 0x000060, 0x000080,
+       0x0000c0, 0x000100, 0x000180, 0x000200, 0x000300,
+       0x000400, 0x000600, 0x000800, 0x000c00, 0x001000,
+       0x001800, 0x002000, 0x003000, 0x004000, 0x006000,
+
+       /* extended window */
+       0x008000, 0x00c000, 0x010000, 0x018000, 0x020000,
+       0x030000, 0x040000, 0x060000, 0x080000, 0x0c0000,
+       0x100000, 0x180000, 0x200000, 0x300000,
+}
+
+// The odd order in which the codegen code sizes are written.
+var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+type huffmanBitWriter struct {
+       w io.Writer
+       // Data waiting to be written is bytes[0:nbytes]
+       // and then the low nbits of bits.
+       bits            uint32
+       nbits           uint32
+       bytes           [64]byte
+       nbytes          int
+       literalFreq     []int32
+       offsetFreq      []int32
+       codegen         []uint8
+       codegenFreq     []int32
+       literalEncoding *huffmanEncoder
+       offsetEncoding  *huffmanEncoder
+       codegenEncoding *huffmanEncoder
+       err             os.Error
+}
+
+type WrongValueError struct {
+       name  string
+       from  int32
+       to    int32
+       value int32
+}
+
+func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
+       return &huffmanBitWriter{
+               w:               w,
+               literalFreq:     make([]int32, maxLit),
+               offsetFreq:      make([]int32, extendedOffsetCodeCount),
+               codegen:         make([]uint8, maxLit+extendedOffsetCodeCount+1),
+               codegenFreq:     make([]int32, codegenCodeCount),
+               literalEncoding: newHuffmanEncoder(maxLit),
+               offsetEncoding:  newHuffmanEncoder(extendedOffsetCodeCount),
+               codegenEncoding: newHuffmanEncoder(codegenCodeCount),
+       }
+}
+
+func (err WrongValueError) String() string {
+       return "huffmanBitWriter: " + err.name + " should belong to [" + strconv.Itoa64(int64(err.from)) + ";" +
+               strconv.Itoa64(int64(err.to)) + "] but actual value is " + strconv.Itoa64(int64(err.value))
+}
+
+func (w *huffmanBitWriter) flushBits() {
+       if w.err != nil {
+               w.nbits = 0
+               return
+       }
+       bits := w.bits
+       w.bits >>= 16
+       w.nbits -= 16
+       n := w.nbytes
+       w.bytes[n] = byte(bits)
+       w.bytes[n+1] = byte(bits >> 8)
+       if n += 2; n >= len(w.bytes) {
+               _, w.err = w.w.Write(w.bytes[0:])
+               n = 0
+       }
+       w.nbytes = n
+}
+
+func (w *huffmanBitWriter) flush() {
+       if w.err != nil {
+               w.nbits = 0
+               return
+       }
+       n := w.nbytes
+       if w.nbits > 8 {
+               w.bytes[n] = byte(w.bits)
+               w.bits >>= 8
+               w.nbits -= 8
+               n++
+       }
+       if w.nbits > 0 {
+               w.bytes[n] = byte(w.bits)
+               w.nbits = 0
+               n++
+       }
+       w.bits = 0
+       _, w.err = w.w.Write(w.bytes[0:n])
+       w.nbytes = 0
+}
+
+func (w *huffmanBitWriter) writeBits(b, nb int32) {
+       w.bits |= uint32(b) << w.nbits
+       if w.nbits += uint32(nb); w.nbits >= 16 {
+               w.flushBits()
+       }
+}
+
+func (w *huffmanBitWriter) writeBytes(bytes []byte) {
+       if w.err != nil {
+               return
+       }
+       n := w.nbytes
+       if w.nbits == 8 {
+               w.bytes[n] = byte(w.bits)
+               w.nbits = 0
+               n++
+       }
+       if w.nbits != 0 {
+               w.err = InternalError("writeBytes with unfinished bits")
+               return
+       }
+       if n != 0 {
+               _, w.err = w.w.Write(w.bytes[0:n])
+               if w.err != nil {
+                       return
+               }
+       }
+       w.nbytes = 0
+       _, w.err = w.w.Write(bytes)
+}
+
+// RFC 1951 3.2.7 specifies a special run-length encoding for specifiying
+// the literal and offset lengths arrays (which are concatenated into a single
+// array).  This method generates that run-length encoding.
+//
+// The result is written into the codegen array, and the frequencies
+// of each code is written into the codegenFreq array.
+// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
+// information.  Code badCode is an end marker
+//
+//  numLiterals      The number of literals in literalEncoding
+//  numOffsets       The number of offsets in offsetEncoding
+func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
+       fillInt32s(w.codegenFreq, 0)
+       // Note that we are using codegen both as a temporary variable for holding
+       // a copy of the frequencies, and as the place where we put the result.
+       // This is fine because the output is always shorter than the input used
+       // so far.
+       codegen := w.codegen // cache
+       // Copy the concatenated code sizes to codegen.  Put a marker at the end.
+       copyUint8s(codegen[0:numLiterals], w.literalEncoding.codeBits)
+       copyUint8s(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits)
+       codegen[numLiterals+numOffsets] = badCode
+
+       size := codegen[0]
+       count := 1
+       outIndex := 0
+       for inIndex := 1; size != badCode; inIndex++ {
+               // INVARIANT: We have seen "count" copies of size that have not yet
+               // had output generated for them.
+               nextSize := codegen[inIndex]
+               if nextSize == size {
+                       count++
+                       continue
+               }
+               // We need to generate codegen indicating "count" of size.
+               if size != 0 {
+                       codegen[outIndex] = size
+                       outIndex++
+                       w.codegenFreq[size]++
+                       count--
+                       for count >= 3 {
+                               n := min(count, 6)
+                               codegen[outIndex] = 16
+                               outIndex++
+                               codegen[outIndex] = uint8(n - 3)
+                               outIndex++
+                               w.codegenFreq[16]++
+                               count -= n
+                       }
+               } else {
+                       for count >= 11 {
+                               n := min(count, 138)
+                               codegen[outIndex] = 18
+                               outIndex++
+                               codegen[outIndex] = uint8(n - 11)
+                               outIndex++
+                               w.codegenFreq[18]++
+                               count -= n
+                       }
+                       if count >= 3 {
+                               // count >= 3 && count <= 10
+                               codegen[outIndex] = 17
+                               outIndex++
+                               codegen[outIndex] = uint8(count - 3)
+                               outIndex++
+                               w.codegenFreq[17]++
+                               count = 0
+                       }
+               }
+               count--
+               for ; count >= 0; count-- {
+                       codegen[outIndex] = size
+                       outIndex++
+                       w.codegenFreq[size]++
+               }
+               // Set up invariant for next time through the loop.
+               size = nextSize
+               count = 1
+       }
+       // Marker indicating the end of the codegen.
+       codegen[outIndex] = badCode
+}
+
+func (w *huffmanBitWriter) writeCode(code *huffmanEncoder, literal uint32) {
+       if w.err != nil {
+               return
+       }
+       w.writeBits(int32(code.code[literal]), int32(code.codeBits[literal]))
+}
+
+// Write the header of a dynamic Huffman block to the output stream.
+//
+//  numLiterals  The number of literals specified in codegen
+//  numOffsets   The number of offsets specified in codegen
+//  numCodegens  Tne number of codegens used in codegen
+func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) {
+       if w.err != nil {
+               return
+       }
+       var firstBits int32 = 4
+       if isEof {
+               firstBits = 5
+       }
+       w.writeBits(firstBits, 3)
+       w.writeBits(int32(numLiterals-257), 5)
+       if numOffsets > offsetCodeCount {
+               // Extended version of decompressor
+               w.writeBits(int32(offsetCodeCount+((numOffsets-(1+offsetCodeCount))>>3)), 5)
+               w.writeBits(int32((numOffsets-(1+offsetCodeCount))&0x7), 3)
+       } else {
+               w.writeBits(int32(numOffsets-1), 5)
+       }
+       w.writeBits(int32(numCodegens-4), 4)
+
+       for i := 0; i < numCodegens; i++ {
+               value := w.codegenEncoding.codeBits[codegenOrder[i]]
+               w.writeBits(int32(value), 3)
+       }
+
+       i := 0
+       for {
+               var codeWord int = int(w.codegen[i])
+               i++
+               if codeWord == badCode {
+                       break
+               }
+               // The low byte contains the actual code to generate.
+               w.writeCode(w.codegenEncoding, uint32(codeWord))
+
+               switch codeWord {
+               case 16:
+                       w.writeBits(int32(w.codegen[i]), 2)
+                       i++
+                       break
+               case 17:
+                       w.writeBits(int32(w.codegen[i]), 3)
+                       i++
+                       break
+               case 18:
+                       w.writeBits(int32(w.codegen[i]), 7)
+                       i++
+                       break
+               }
+       }
+}
+
+func (w *huffmanBitWriter) writeStoredHeader(length int, isEof bool) {
+       if w.err != nil {
+               return
+       }
+       var flag int32
+       if isEof {
+               flag = 1
+       }
+       w.writeBits(flag, 3)
+       w.flush()
+       w.writeBits(int32(length), 16)
+       w.writeBits(int32(^uint16(length)), 16)
+}
+
+func (w *huffmanBitWriter) writeFixedHeader(isEof bool) {
+       if w.err != nil {
+               return
+       }
+       // Indicate that we are a fixed Huffman block
+       var value int32 = 2
+       if isEof {
+               value = 3
+       }
+       w.writeBits(value, 3)
+}
+
+func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
+       if w.err != nil {
+               return
+       }
+       fillInt32s(w.literalFreq, 0)
+       fillInt32s(w.offsetFreq, 0)
+
+       n := len(tokens)
+       tokens = tokens[0 : n+1]
+       tokens[n] = endBlockMarker
+
+       totalLength := -1 // Subtract 1 for endBlock.
+       for _, t := range tokens {
+               switch t.typ() {
+               case literalType:
+                       w.literalFreq[t.literal()]++
+                       totalLength++
+                       break
+               case matchType:
+                       length := t.length()
+                       offset := t.offset()
+                       totalLength += int(length + 3)
+                       w.literalFreq[lengthCodesStart+lengthCode(length)]++
+                       w.offsetFreq[offsetCode(offset)]++
+                       break
+               }
+       }
+       w.literalEncoding.generate(w.literalFreq, 15)
+       w.offsetEncoding.generate(w.offsetFreq, 15)
+
+       // get the number of literals
+       numLiterals := len(w.literalFreq)
+       for w.literalFreq[numLiterals-1] == 0 {
+               numLiterals--
+       }
+       // get the number of offsets
+       numOffsets := len(w.offsetFreq)
+       for numOffsets > 1 && w.offsetFreq[numOffsets-1] == 0 {
+               numOffsets--
+       }
+       storedBytes := 0
+       if input != nil {
+               storedBytes = len(input)
+       }
+       var extraBits int64
+       var storedSize int64
+       if storedBytes <= maxStoreBlockSize && input != nil {
+               storedSize = int64((storedBytes + 5) * 8)
+               // We only bother calculating the costs of the extra bits required by
+               // the length of offset fields (which will be the same for both fixed
+               // and dynamic encoding), if we need to compare those two encodings
+               // against stored encoding.
+               for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ {
+                       // First eight length codes have extra size = 0.
+                       extraBits += int64(w.literalFreq[lengthCode]) * int64(lengthExtraBits[lengthCode-lengthCodesStart])
+               }
+               for offsetCode := 4; offsetCode < numOffsets; offsetCode++ {
+                       // First four offset codes have extra size = 0.
+                       extraBits += int64(w.offsetFreq[offsetCode]) * int64(offsetExtraBits[offsetCode])
+               }
+       } else {
+               storedSize = math.MaxInt32
+       }
+
+       // Figure out which generates smaller code, fixed Huffman, dynamic
+       // Huffman, or just storing the data.
+       var fixedSize int64 = math.MaxInt64
+       if numOffsets <= offsetCodeCount {
+               fixedSize = int64(3) +
+                       fixedLiteralEncoding.bitLength(w.literalFreq) +
+                       fixedOffsetEncoding.bitLength(w.offsetFreq) +
+                       extraBits
+       }
+       // Generate codegen and codegenFrequencies, which indicates how to encode
+       // the literalEncoding and the offsetEncoding.
+       w.generateCodegen(numLiterals, numOffsets)
+       w.codegenEncoding.generate(w.codegenFreq, 7)
+       numCodegens := len(w.codegenFreq)
+       for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
+               numCodegens--
+       }
+       extensionSummand := 0
+       if numOffsets > offsetCodeCount {
+               extensionSummand = 3
+       }
+       dynamicHeader := int64(3+5+5+4+(3*numCodegens)) +
+               // Following line is an extension.
+               int64(extensionSummand) +
+               w.codegenEncoding.bitLength(w.codegenFreq) +
+               int64(extraBits) +
+               int64(w.codegenFreq[16]*2) +
+               int64(w.codegenFreq[17]*3) +
+               int64(w.codegenFreq[18]*7)
+       dynamicSize := dynamicHeader +
+               w.literalEncoding.bitLength(w.literalFreq) +
+               w.offsetEncoding.bitLength(w.offsetFreq)
+
+       if storedSize < fixedSize && storedSize < dynamicSize {
+               w.writeStoredHeader(storedBytes, eof)
+               w.writeBytes(input[0:storedBytes])
+               return
+       }
+       var literalEncoding *huffmanEncoder
+       var offsetEncoding *huffmanEncoder
+
+       if fixedSize <= dynamicSize {
+               w.writeFixedHeader(eof)
+               literalEncoding = fixedLiteralEncoding
+               offsetEncoding = fixedOffsetEncoding
+       } else {
+               // Write the header.
+               w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+               literalEncoding = w.literalEncoding
+               offsetEncoding = w.offsetEncoding
+       }
+
+       // Write the tokens.
+       for _, t := range tokens {
+               switch t.typ() {
+               case literalType:
+                       w.writeCode(literalEncoding, t.literal())
+                       break
+               case matchType:
+                       // Write the length
+                       length := t.length()
+                       lengthCode := lengthCode(length)
+                       w.writeCode(literalEncoding, lengthCode+lengthCodesStart)
+                       extraLengthBits := int32(lengthExtraBits[lengthCode])
+                       if extraLengthBits > 0 {
+                               extraLength := int32(length - lengthBase[lengthCode])
+                               w.writeBits(extraLength, extraLengthBits)
+                       }
+                       // Write the offset
+                       offset := t.offset()
+                       offsetCode := offsetCode(offset)
+                       w.writeCode(offsetEncoding, offsetCode)
+                       extraOffsetBits := int32(offsetExtraBits[offsetCode])
+                       if extraOffsetBits > 0 {
+                               extraOffset := int32(offset - offsetBase[offsetCode])
+                               w.writeBits(extraOffset, extraOffsetBits)
+                       }
+                       break
+               default:
+                       panic("unknown token type: " + string(t))
+               }
+       }
+}
diff --git a/libgo/go/compress/flate/huffman_code.go b/libgo/go/compress/flate/huffman_code.go
new file mode 100644 (file)
index 0000000..6be605f
--- /dev/null
@@ -0,0 +1,373 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+       "math"
+       "sort"
+)
+
+type huffmanEncoder struct {
+       codeBits []uint8
+       code     []uint16
+}
+
+type literalNode struct {
+       literal uint16
+       freq    int32
+}
+
+type chain struct {
+       // The sum of the leaves in this tree
+       freq int32
+
+       // The number of literals to the left of this item at this level
+       leafCount int32
+
+       // The right child of this chain in the previous level.
+       up *chain
+}
+
+type levelInfo struct {
+       // Our level.  for better printing
+       level int32
+
+       // The most recent chain generated for this level
+       lastChain *chain
+
+       // The frequency of the next character to add to this level
+       nextCharFreq int32
+
+       // The frequency of the next pair (from level below) to add to this level.
+       // Only valid if the "needed" value of the next lower level is 0.
+       nextPairFreq int32
+
+       // The number of chains remaining to generate for this level before moving
+       // up to the next level
+       needed int32
+
+       // The levelInfo for level+1
+       up *levelInfo
+
+       // The levelInfo for level-1
+       down *levelInfo
+}
+
+func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} }
+
+func newHuffmanEncoder(size int) *huffmanEncoder {
+       return &huffmanEncoder{make([]uint8, size), make([]uint16, size)}
+}
+
+// Generates a HuffmanCode corresponding to the fixed literal table
+func generateFixedLiteralEncoding() *huffmanEncoder {
+       h := newHuffmanEncoder(maxLit)
+       codeBits := h.codeBits
+       code := h.code
+       var ch uint16
+       for ch = 0; ch < maxLit; ch++ {
+               var bits uint16
+               var size uint8
+               switch {
+               case ch < 144:
+                       // size 8, 000110000  .. 10111111
+                       bits = ch + 48
+                       size = 8
+                       break
+               case ch < 256:
+                       // size 9, 110010000 .. 111111111
+                       bits = ch + 400 - 144
+                       size = 9
+                       break
+               case ch < 280:
+                       // size 7, 0000000 .. 0010111
+                       bits = ch - 256
+                       size = 7
+                       break
+               default:
+                       // size 8, 11000000 .. 11000111
+                       bits = ch + 192 - 280
+                       size = 8
+               }
+               codeBits[ch] = size
+               code[ch] = reverseBits(bits, size)
+       }
+       return h
+}
+
+func generateFixedOffsetEncoding() *huffmanEncoder {
+       h := newHuffmanEncoder(30)
+       codeBits := h.codeBits
+       code := h.code
+       for ch := uint16(0); ch < 30; ch++ {
+               codeBits[ch] = 5
+               code[ch] = reverseBits(ch, 5)
+       }
+       return h
+}
+
+var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding()
+var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding()
+
+func (h *huffmanEncoder) bitLength(freq []int32) int64 {
+       var total int64
+       for i, f := range freq {
+               if f != 0 {
+                       total += int64(f) * int64(h.codeBits[i])
+               }
+       }
+       return total
+}
+
+// Generate elements in the chain using an iterative algorithm.
+func (h *huffmanEncoder) generateChains(top *levelInfo, list []literalNode) {
+       n := len(list)
+       list = list[0 : n+1]
+       list[n] = maxNode()
+
+       l := top
+       for {
+               if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
+                       // We've run out of both leafs and pairs.
+                       // End all calculations for this level.
+                       // To m sure we never come back to this level or any lower level,
+                       // set nextPairFreq impossibly large.
+                       l.lastChain = nil
+                       l.needed = 0
+                       l = l.up
+                       l.nextPairFreq = math.MaxInt32
+                       continue
+               }
+
+               prevFreq := l.lastChain.freq
+               if l.nextCharFreq < l.nextPairFreq {
+                       // The next item on this row is a leaf node.
+                       n := l.lastChain.leafCount + 1
+                       l.lastChain = &chain{l.nextCharFreq, n, l.lastChain.up}
+                       l.nextCharFreq = list[n].freq
+               } else {
+                       // The next item on this row is a pair from the previous row.
+                       // nextPairFreq isn't valid until we generate two
+                       // more values in the level below
+                       l.lastChain = &chain{l.nextPairFreq, l.lastChain.leafCount, l.down.lastChain}
+                       l.down.needed = 2
+               }
+
+               if l.needed--; l.needed == 0 {
+                       // We've done everything we need to do for this level.
+                       // Continue calculating one level up.  Fill in nextPairFreq
+                       // of that level with the sum of the two nodes we've just calculated on
+                       // this level.
+                       up := l.up
+                       if up == nil {
+                               // All done!
+                               return
+                       }
+                       up.nextPairFreq = prevFreq + l.lastChain.freq
+                       l = up
+               } else {
+                       // If we stole from below, move down temporarily to replenish it.
+                       for l.down.needed > 0 {
+                               l = l.down
+                       }
+               }
+       }
+}
+
+// Return the number of literals assigned to each bit size in the Huffman encoding
+//
+// This method is only called when list.length >= 3
+// The cases of 0, 1, and 2 literals are handled by special case code.
+//
+// list  An array of the literals with non-zero frequencies
+//             and their associated frequencies.  The array is in order of increasing
+//             frequency, and has as its last element a special element with frequency
+//             MaxInt32
+// maxBits     The maximum number of bits that should be used to encode any literal.
+// return      An integer array in which array[i] indicates the number of literals
+//             that should be encoded in i bits.
+func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
+       n := int32(len(list))
+       list = list[0 : n+1]
+       list[n] = maxNode()
+
+       // The tree can't have greater depth than n - 1, no matter what.  This
+       // saves a little bit of work in some small cases
+       maxBits = minInt32(maxBits, n-1)
+
+       // Create information about each of the levels.
+       // A bogus "Level 0" whose sole purpose is so that
+       // level1.prev.needed==0.  This makes level1.nextPairFreq
+       // be a legitimate value that never gets chosen.
+       top := &levelInfo{needed: 0}
+       chain2 := &chain{list[1].freq, 2, new(chain)}
+       for level := int32(1); level <= maxBits; level++ {
+               // For every level, the first two items are the first two characters.
+               // We initialize the levels as if we had already figured this out.
+               top = &levelInfo{
+                       level:        level,
+                       lastChain:    chain2,
+                       nextCharFreq: list[2].freq,
+                       nextPairFreq: list[0].freq + list[1].freq,
+                       down:         top,
+               }
+               top.down.up = top
+               if level == 1 {
+                       top.nextPairFreq = math.MaxInt32
+               }
+       }
+
+       // We need a total of 2*n - 2 items at top level and have already generated 2.
+       top.needed = 2*n - 4
+
+       l := top
+       for {
+               if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
+                       // We've run out of both leafs and pairs.
+                       // End all calculations for this level.
+                       // To m sure we never come back to this level or any lower level,
+                       // set nextPairFreq impossibly large.
+                       l.lastChain = nil
+                       l.needed = 0
+                       l = l.up
+                       l.nextPairFreq = math.MaxInt32
+                       continue
+               }
+
+               prevFreq := l.lastChain.freq
+               if l.nextCharFreq < l.nextPairFreq {
+                       // The next item on this row is a leaf node.
+                       n := l.lastChain.leafCount + 1
+                       l.lastChain = &chain{l.nextCharFreq, n, l.lastChain.up}
+                       l.nextCharFreq = list[n].freq
+               } else {
+                       // The next item on this row is a pair from the previous row.
+                       // nextPairFreq isn't valid until we generate two
+                       // more values in the level below
+                       l.lastChain = &chain{l.nextPairFreq, l.lastChain.leafCount, l.down.lastChain}
+                       l.down.needed = 2
+               }
+
+               if l.needed--; l.needed == 0 {
+                       // We've done everything we need to do for this level.
+                       // Continue calculating one level up.  Fill in nextPairFreq
+                       // of that level with the sum of the two nodes we've just calculated on
+                       // this level.
+                       up := l.up
+                       if up == nil {
+                               // All done!
+                               break
+                       }
+                       up.nextPairFreq = prevFreq + l.lastChain.freq
+                       l = up
+               } else {
+                       // If we stole from below, move down temporarily to replenish it.
+                       for l.down.needed > 0 {
+                               l = l.down
+                       }
+               }
+       }
+
+       // Somethings is wrong if at the end, the top level is null or hasn't used
+       // all of the leaves.
+       if top.lastChain.leafCount != n {
+               panic("top.lastChain.leafCount != n")
+       }
+
+       bitCount := make([]int32, maxBits+1)
+       bits := 1
+       for chain := top.lastChain; chain.up != nil; chain = chain.up {
+               // chain.leafCount gives the number of literals requiring at least "bits"
+               // bits to encode.
+               bitCount[bits] = chain.leafCount - chain.up.leafCount
+               bits++
+       }
+       return bitCount
+}
+
+// Look at the leaves and assign them a bit count and an encoding as specified
+// in RFC 1951 3.2.2
+func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) {
+       code := uint16(0)
+       for n, bits := range bitCount {
+               code <<= 1
+               if n == 0 || bits == 0 {
+                       continue
+               }
+               // The literals list[len(list)-bits] .. list[len(list)-bits]
+               // are encoded using "bits" bits, and get the values
+               // code, code + 1, ....  The code values are
+               // assigned in literal order (not frequency order).
+               chunk := list[len(list)-int(bits):]
+               sortByLiteral(chunk)
+               for _, node := range chunk {
+                       h.codeBits[node.literal] = uint8(n)
+                       h.code[node.literal] = reverseBits(code, uint8(n))
+                       code++
+               }
+               list = list[0 : len(list)-int(bits)]
+       }
+}
+
+// Update this Huffman Code object to be the minimum code for the specified frequency count.
+//
+// freq  An array of frequencies, in which frequency[i] gives the frequency of literal i.
+// maxBits  The maximum number of bits to use for any literal.
+func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
+       list := make([]literalNode, len(freq)+1)
+       // Number of non-zero literals
+       count := 0
+       // Set list to be the set of all non-zero literals and their frequencies
+       for i, f := range freq {
+               if f != 0 {
+                       list[count] = literalNode{uint16(i), f}
+                       count++
+               } else {
+                       h.codeBits[i] = 0
+               }
+       }
+       // If freq[] is shorter than codeBits[], fill rest of codeBits[] with zeros
+       h.codeBits = h.codeBits[0:len(freq)]
+       list = list[0:count]
+       if count <= 2 {
+               // Handle the small cases here, because they are awkward for the general case code.  With
+               // two or fewer literals, everything has bit length 1.
+               for i, node := range list {
+                       // "list" is in order of increasing literal value.
+                       h.codeBits[node.literal] = 1
+                       h.code[node.literal] = uint16(i)
+               }
+               return
+       }
+       sortByFreq(list)
+
+       // Get the number of literals for each bit count
+       bitCount := h.bitCounts(list, maxBits)
+       // And do the assignment
+       h.assignEncodingAndSize(bitCount, list)
+}
+
+type literalNodeSorter struct {
+       a    []literalNode
+       less func(i, j int) bool
+}
+
+func (s literalNodeSorter) Len() int { return len(s.a) }
+
+func (s literalNodeSorter) Less(i, j int) bool {
+       return s.less(i, j)
+}
+
+func (s literalNodeSorter) Swap(i, j int) { s.a[i], s.a[j] = s.a[j], s.a[i] }
+
+func sortByFreq(a []literalNode) {
+       s := &literalNodeSorter{a, func(i, j int) bool { return a[i].freq < a[j].freq }}
+       sort.Sort(s)
+}
+
+func sortByLiteral(a []literalNode) {
+       s := &literalNodeSorter{a, func(i, j int) bool { return a[i].literal < a[j].literal }}
+       sort.Sort(s)
+}
diff --git a/libgo/go/compress/flate/inflate.go b/libgo/go/compress/flate/inflate.go
new file mode 100644 (file)
index 0000000..e46cbef
--- /dev/null
@@ -0,0 +1,610 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The flate package implements the DEFLATE compressed data
+// format, described in RFC 1951.  The gzip and zlib packages
+// implement access to DEFLATE-based file formats.
+package flate
+
+import (
+       "bufio"
+       "io"
+       "os"
+       "strconv"
+)
+
+const (
+       maxCodeLen = 16    // max length of Huffman code
+       maxHist    = 32768 // max history required
+       maxLit     = 286
+       maxDist    = 32
+       numCodes   = 19 // number of codes in Huffman meta-code
+)
+
+// A CorruptInputError reports the presence of corrupt input at a given offset.
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+       return "flate: corrupt input before offset " + strconv.Itoa64(int64(e))
+}
+
+// An InternalError reports an error in the flate code itself.
+type InternalError string
+
+func (e InternalError) String() string { return "flate: internal error: " + string(e) }
+
+// A ReadError reports an error encountered while reading input.
+type ReadError struct {
+       Offset int64    // byte offset where error occurred
+       Error  os.Error // error returned by underlying Read
+}
+
+func (e *ReadError) String() string {
+       return "flate: read error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String()
+}
+
+// A WriteError reports an error encountered while writing output.
+type WriteError struct {
+       Offset int64    // byte offset where error occurred
+       Error  os.Error // error returned by underlying Read
+}
+
+func (e *WriteError) String() string {
+       return "flate: write error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String()
+}
+
+// Huffman decoder is based on
+// J. Brian Connell, ``A Huffman-Shannon-Fano Code,''
+// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047.
+type huffmanDecoder struct {
+       // min, max code length
+       min, max int
+
+       // limit[i] = largest code word of length i
+       // Given code v of length n,
+       // need more bits if v > limit[n].
+       limit [maxCodeLen + 1]int
+
+       // base[i] = smallest code word of length i - seq number
+       base [maxCodeLen + 1]int
+
+       // codes[seq number] = output code.
+       // Given code v of length n, value is
+       // codes[v - base[n]].
+       codes []int
+}
+
+// Initialize Huffman decoding tables from array of code lengths.
+func (h *huffmanDecoder) init(bits []int) bool {
+       // TODO(rsc): Return false sometimes.
+
+       // Count number of codes of each length,
+       // compute min and max length.
+       var count [maxCodeLen + 1]int
+       var min, max int
+       for _, n := range bits {
+               if n == 0 {
+                       continue
+               }
+               if min == 0 || n < min {
+                       min = n
+               }
+               if n > max {
+                       max = n
+               }
+               count[n]++
+       }
+       if max == 0 {
+               return false
+       }
+
+       h.min = min
+       h.max = max
+
+       // For each code range, compute
+       // nextcode (first code of that length),
+       // limit (last code of that length), and
+       // base (offset from first code to sequence number).
+       code := 0
+       seq := 0
+       var nextcode [maxCodeLen]int
+       for i := min; i <= max; i++ {
+               n := count[i]
+               nextcode[i] = code
+               h.base[i] = code - seq
+               code += n
+               seq += n
+               h.limit[i] = code - 1
+               code <<= 1
+       }
+
+       // Make array mapping sequence numbers to codes.
+       if len(h.codes) < len(bits) {
+               h.codes = make([]int, len(bits))
+       }
+       for i, n := range bits {
+               if n == 0 {
+                       continue
+               }
+               code := nextcode[n]
+               nextcode[n]++
+               seq := code - h.base[n]
+               h.codes[seq] = i
+       }
+       return true
+}
+
+// Hard-coded Huffman tables for DEFLATE algorithm.
+// See RFC 1951, section 3.2.6.
+var fixedHuffmanDecoder = huffmanDecoder{
+       7, 9,
+       [maxCodeLen + 1]int{7: 23, 199, 511},
+       [maxCodeLen + 1]int{7: 0, 24, 224},
+       []int{
+               // length 7: 256-279
+               256, 257, 258, 259, 260, 261, 262,
+               263, 264, 265, 266, 267, 268, 269,
+               270, 271, 272, 273, 274, 275, 276,
+               277, 278, 279,
+
+               // length 8: 0-143
+               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, 84, 85, 86, 87, 88, 89, 90, 91,
+               92, 93, 94, 95, 96, 97, 98, 99, 100,
+               101, 102, 103, 104, 105, 106, 107, 108,
+               109, 110, 111, 112, 113, 114, 115, 116,
+               117, 118, 119, 120, 121, 122, 123, 124,
+               125, 126, 127, 128, 129, 130, 131, 132,
+               133, 134, 135, 136, 137, 138, 139, 140,
+               141, 142, 143,
+
+               // length 8: 280-287
+               280, 281, 282, 283, 284, 285, 286, 287,
+
+               // length 9: 144-255
+               144, 145, 146, 147, 148, 149, 150, 151,
+               152, 153, 154, 155, 156, 157, 158, 159,
+               160, 161, 162, 163, 164, 165, 166, 167,
+               168, 169, 170, 171, 172, 173, 174, 175,
+               176, 177, 178, 179, 180, 181, 182, 183,
+               184, 185, 186, 187, 188, 189, 190, 191,
+               192, 193, 194, 195, 196, 197, 198, 199,
+               200, 201, 202, 203, 204, 205, 206, 207,
+               208, 209, 210, 211, 212, 213, 214, 215,
+               216, 217, 218, 219, 220, 221, 222, 223,
+               224, 225, 226, 227, 228, 229, 230, 231,
+               232, 233, 234, 235, 236, 237, 238, 239,
+               240, 241, 242, 243, 244, 245, 246, 247,
+               248, 249, 250, 251, 252, 253, 254, 255,
+       },
+}
+
+// The actual read interface needed by NewReader.
+// If the passed in io.Reader does not also have ReadByte,
+// the NewReader will introduce its own buffering.
+type Reader interface {
+       io.Reader
+       ReadByte() (c byte, err os.Error)
+}
+
+// Decompress state.
+type decompressor struct {
+       // Input/output sources.
+       r       Reader
+       w       io.Writer
+       roffset int64
+       woffset int64
+
+       // Input bits, in top of b.
+       b  uint32
+       nb uint
+
+       // Huffman decoders for literal/length, distance.
+       h1, h2 huffmanDecoder
+
+       // Length arrays used to define Huffman codes.
+       bits     [maxLit + maxDist]int
+       codebits [numCodes]int
+
+       // Output history, buffer.
+       hist  [maxHist]byte
+       hp    int  // current output position in buffer
+       hfull bool // buffer has filled at least once
+
+       // Temporary buffer (avoids repeated allocation).
+       buf [4]byte
+}
+
+func (f *decompressor) inflate() (err os.Error) {
+       final := false
+       for err == nil && !final {
+               for f.nb < 1+2 {
+                       if err = f.moreBits(); err != nil {
+                               return
+                       }
+               }
+               final = f.b&1 == 1
+               f.b >>= 1
+               typ := f.b & 3
+               f.b >>= 2
+               f.nb -= 1 + 2
+               switch typ {
+               case 0:
+                       err = f.dataBlock()
+               case 1:
+                       // compressed, fixed Huffman tables
+                       err = f.decodeBlock(&fixedHuffmanDecoder, nil)
+               case 2:
+                       // compressed, dynamic Huffman tables
+                       if err = f.readHuffman(); err == nil {
+                               err = f.decodeBlock(&f.h1, &f.h2)
+                       }
+               default:
+                       // 3 is reserved.
+                       err = CorruptInputError(f.roffset)
+               }
+       }
+       return
+}
+
+// RFC 1951 section 3.2.7.
+// Compression with dynamic Huffman codes
+
+var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+func (f *decompressor) readHuffman() os.Error {
+       // HLIT[5], HDIST[5], HCLEN[4].
+       for f.nb < 5+5+4 {
+               if err := f.moreBits(); err != nil {
+                       return err
+               }
+       }
+       nlit := int(f.b&0x1F) + 257
+       f.b >>= 5
+       ndist := int(f.b&0x1F) + 1
+       f.b >>= 5
+       nclen := int(f.b&0xF) + 4
+       f.b >>= 4
+       f.nb -= 5 + 5 + 4
+
+       // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
+       for i := 0; i < nclen; i++ {
+               for f.nb < 3 {
+                       if err := f.moreBits(); err != nil {
+                               return err
+                       }
+               }
+               f.codebits[codeOrder[i]] = int(f.b & 0x7)
+               f.b >>= 3
+               f.nb -= 3
+       }
+       for i := nclen; i < len(codeOrder); i++ {
+               f.codebits[codeOrder[i]] = 0
+       }
+       if !f.h1.init(f.codebits[0:]) {
+               return CorruptInputError(f.roffset)
+       }
+
+       // HLIT + 257 code lengths, HDIST + 1 code lengths,
+       // using the code length Huffman code.
+       for i, n := 0, nlit+ndist; i < n; {
+               x, err := f.huffSym(&f.h1)
+               if err != nil {
+                       return err
+               }
+               if x < 16 {
+                       // Actual length.
+                       f.bits[i] = x
+                       i++
+                       continue
+               }
+               // Repeat previous length or zero.
+               var rep int
+               var nb uint
+               var b int
+               switch x {
+               default:
+                       return InternalError("unexpected length code")
+               case 16:
+                       rep = 3
+                       nb = 2
+                       if i == 0 {
+                               return CorruptInputError(f.roffset)
+                       }
+                       b = f.bits[i-1]
+               case 17:
+                       rep = 3
+                       nb = 3
+                       b = 0
+               case 18:
+                       rep = 11
+                       nb = 7
+                       b = 0
+               }
+               for f.nb < nb {
+                       if err := f.moreBits(); err != nil {
+                               return err
+                       }
+               }
+               rep += int(f.b & uint32(1<<nb-1))
+               f.b >>= nb
+               f.nb -= nb
+               if i+rep > n {
+                       return CorruptInputError(f.roffset)
+               }
+               for j := 0; j < rep; j++ {
+                       f.bits[i] = b
+                       i++
+               }
+       }
+
+       if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
+               return CorruptInputError(f.roffset)
+       }
+
+       return nil
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively.  If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error {
+       for {
+               v, err := f.huffSym(hl)
+               if err != nil {
+                       return err
+               }
+               var n uint // number of bits extra
+               var length int
+               switch {
+               case v < 256:
+                       f.hist[f.hp] = byte(v)
+                       f.hp++
+                       if f.hp == len(f.hist) {
+                               if err = f.flush(); err != nil {
+                                       return err
+                               }
+                       }
+                       continue
+               case v == 256:
+                       return nil
+               // otherwise, reference to older data
+               case v < 265:
+                       length = v - (257 - 3)
+                       n = 0
+               case v < 269:
+                       length = v*2 - (265*2 - 11)
+                       n = 1
+               case v < 273:
+                       length = v*4 - (269*4 - 19)
+                       n = 2
+               case v < 277:
+                       length = v*8 - (273*8 - 35)
+                       n = 3
+               case v < 281:
+                       length = v*16 - (277*16 - 67)
+                       n = 4
+               case v < 285:
+                       length = v*32 - (281*32 - 131)
+                       n = 5
+               default:
+                       length = 258
+                       n = 0
+               }
+               if n > 0 {
+                       for f.nb < n {
+                               if err = f.moreBits(); err != nil {
+                                       return err
+                               }
+                       }
+                       length += int(f.b & uint32(1<<n-1))
+                       f.b >>= n
+                       f.nb -= n
+               }
+
+               var dist int
+               if hd == nil {
+                       for f.nb < 5 {
+                               if err = f.moreBits(); err != nil {
+                                       return err
+                               }
+                       }
+                       dist = int(reverseByte[(f.b&0x1F)<<3])
+                       f.b >>= 5
+                       f.nb -= 5
+               } else {
+                       if dist, err = f.huffSym(hd); err != nil {
+                               return err
+                       }
+               }
+
+               switch {
+               case dist < 4:
+                       dist++
+               case dist >= 30:
+                       return CorruptInputError(f.roffset)
+               default:
+                       nb := uint(dist-2) >> 1
+                       // have 1 bit in bottom of dist, need nb more.
+                       extra := (dist & 1) << nb
+                       for f.nb < nb {
+                               if err = f.moreBits(); err != nil {
+                                       return err
+                               }
+                       }
+                       extra |= int(f.b & uint32(1<<nb-1))
+                       f.b >>= nb
+                       f.nb -= nb
+                       dist = 1<<(nb+1) + 1 + extra
+               }
+
+               // Copy history[-dist:-dist+length] into output.
+               if dist > len(f.hist) {
+                       return InternalError("bad history distance")
+               }
+
+               // No check on length; encoding can be prescient.
+               if !f.hfull && dist > f.hp {
+                       return CorruptInputError(f.roffset)
+               }
+
+               p := f.hp - dist
+               if p < 0 {
+                       p += len(f.hist)
+               }
+               for i := 0; i < length; i++ {
+                       f.hist[f.hp] = f.hist[p]
+                       f.hp++
+                       p++
+                       if f.hp == len(f.hist) {
+                               if err = f.flush(); err != nil {
+                                       return err
+                               }
+                       }
+                       if p == len(f.hist) {
+                               p = 0
+                       }
+               }
+       }
+       panic("unreached")
+}
+
+// Copy a single uncompressed data block from input to output.
+func (f *decompressor) dataBlock() os.Error {
+       // Uncompressed.
+       // Discard current half-byte.
+       f.nb = 0
+       f.b = 0
+
+       // Length then ones-complement of length.
+       nr, err := io.ReadFull(f.r, f.buf[0:4])
+       f.roffset += int64(nr)
+       if err != nil {
+               return &ReadError{f.roffset, err}
+       }
+       n := int(f.buf[0]) | int(f.buf[1])<<8
+       nn := int(f.buf[2]) | int(f.buf[3])<<8
+       if uint16(nn) != uint16(^n) {
+               return CorruptInputError(f.roffset)
+       }
+
+       // Read len bytes into history,
+       // writing as history fills.
+       for n > 0 {
+               m := len(f.hist) - f.hp
+               if m > n {
+                       m = n
+               }
+               m, err := io.ReadFull(f.r, f.hist[f.hp:f.hp+m])
+               f.roffset += int64(m)
+               if err != nil {
+                       return &ReadError{f.roffset, err}
+               }
+               n -= m
+               f.hp += m
+               if f.hp == len(f.hist) {
+                       if err = f.flush(); err != nil {
+                               return err
+                       }
+               }
+       }
+       return nil
+}
+
+func (f *decompressor) moreBits() os.Error {
+       c, err := f.r.ReadByte()
+       if err != nil {
+               if err == os.EOF {
+                       err = io.ErrUnexpectedEOF
+               }
+               return err
+       }
+       f.roffset++
+       f.b |= uint32(c) << f.nb
+       f.nb += 8
+       return nil
+}
+
+// Read the next Huffman-encoded symbol from f according to h.
+func (f *decompressor) huffSym(h *huffmanDecoder) (int, os.Error) {
+       for n := uint(h.min); n <= uint(h.max); n++ {
+               lim := h.limit[n]
+               if lim == -1 {
+                       continue
+               }
+               for f.nb < n {
+                       if err := f.moreBits(); err != nil {
+                               return 0, err
+                       }
+               }
+               v := int(f.b & uint32(1<<n-1))
+               v <<= 16 - n
+               v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8 // reverse bits
+               if v <= lim {
+                       f.b >>= n
+                       f.nb -= n
+                       return h.codes[v-h.base[n]], nil
+               }
+       }
+       return 0, CorruptInputError(f.roffset)
+}
+
+// Flush any buffered output to the underlying writer.
+func (f *decompressor) flush() os.Error {
+       if f.hp == 0 {
+               return nil
+       }
+       n, err := f.w.Write(f.hist[0:f.hp])
+       if n != f.hp && err == nil {
+               err = io.ErrShortWrite
+       }
+       if err != nil {
+               return &WriteError{f.woffset, err}
+       }
+       f.woffset += int64(f.hp)
+       f.hp = 0
+       f.hfull = true
+       return nil
+}
+
+func makeReader(r io.Reader) Reader {
+       if rr, ok := r.(Reader); ok {
+               return rr
+       }
+       return bufio.NewReader(r)
+}
+
+// Inflate reads DEFLATE-compressed data from r and writes
+// the uncompressed data to w.
+func (f *decompressor) decompressor(r io.Reader, w io.Writer) os.Error {
+       f.r = makeReader(r)
+       f.w = w
+       f.woffset = 0
+       if err := f.inflate(); err != nil {
+               return err
+       }
+       if err := f.flush(); err != nil {
+               return err
+       }
+       return nil
+}
+
+// NewReader returns a new ReadCloser that can be used
+// to read the uncompressed version of r.  It is the caller's
+// responsibility to call Close on the ReadCloser when
+// finished reading.
+func NewReader(r io.Reader) io.ReadCloser {
+       var f decompressor
+       pr, pw := io.Pipe()
+       go func() { pw.CloseWithError(f.decompressor(r, pw)) }()
+       return pr
+}
diff --git a/libgo/go/compress/flate/reverse_bits.go b/libgo/go/compress/flate/reverse_bits.go
new file mode 100644 (file)
index 0000000..c1a0272
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+var reverseByte = [256]byte{
+       0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+       0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+       0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+       0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+       0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+       0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+       0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+       0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+       0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+       0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+       0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+       0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+       0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+       0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+       0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+       0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+       0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+       0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+       0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+       0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+       0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+       0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+       0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+       0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+       0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+       0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+       0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+       0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+       0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+       0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+       0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+       0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+func reverseUint16(v uint16) uint16 {
+       return uint16(reverseByte[v>>8]) | uint16(reverseByte[v&0xFF])<<8
+}
+
+func reverseBits(number uint16, bitLength byte) uint16 {
+       return reverseUint16(number << uint8(16-bitLength))
+}
diff --git a/libgo/go/compress/flate/token.go b/libgo/go/compress/flate/token.go
new file mode 100644 (file)
index 0000000..38aea5f
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+const (
+       // 2 bits:   type   0 = literal  1=EOF  2=Match   3=Unused
+       // 8 bits:   xlength = length - MIN_MATCH_LENGTH
+       // 22 bits   xoffset = offset - MIN_OFFSET_SIZE, or literal
+       lengthShift = 22
+       offsetMask  = 1<<lengthShift - 1
+       typeMask    = 3 << 30
+       literalType = 0 << 30
+       matchType   = 1 << 30
+)
+
+// The length code for length X (MIN_MATCH_LENGTH <= X <= MAX_MATCH_LENGTH)
+// is lengthCodes[length - MIN_MATCH_LENGTH]
+var lengthCodes = [...]uint32{
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 8,
+       9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+       13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
+       15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+       17, 17, 17, 17, 17, 17, 17, 17, 18, 18,
+       18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+       19, 19, 19, 19, 20, 20, 20, 20, 20, 20,
+       20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+       21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+       21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+       22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+       22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+       23, 23, 23, 23, 23, 23, 23, 23, 24, 24,
+       24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+       24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+       24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+       25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+       25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+       25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+       25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+       26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+       26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+       26, 26, 26, 26, 27, 27, 27, 27, 27, 27,
+       27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+       27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+       27, 27, 27, 27, 27, 28,
+}
+
+var offsetCodes = [...]uint32{
+       0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+       8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+       10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+       11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+       12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+       12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+       13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+       13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+       14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+       14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+       14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+       14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+       15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+       15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+       15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+       15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+}
+
+type token uint32
+
+// Convert a literal into a literal token.
+func literalToken(literal uint32) token { return token(literalType + literal) }
+
+// Convert a < xlength, xoffset > pair into a match token.
+func matchToken(xlength uint32, xoffset uint32) token {
+       return token(matchType + xlength<<lengthShift + xoffset)
+}
+
+// Returns the type of a token
+func (t token) typ() uint32 { return uint32(t) & typeMask }
+
+// Returns the literal of a literal token
+func (t token) literal() uint32 { return uint32(t - literalType) }
+
+// Returns the extra offset of a match token
+func (t token) offset() uint32 { return uint32(t) & offsetMask }
+
+func (t token) length() uint32 { return uint32((t - matchType) >> lengthShift) }
+
+func lengthCode(len uint32) uint32 { return lengthCodes[len] }
+
+// Returns the offset code corresponding to a specific offset
+func offsetCode(off uint32) uint32 {
+       const n = uint32(len(offsetCodes))
+       switch {
+       case off < n:
+               return offsetCodes[off]
+       case off>>7 < n:
+               return offsetCodes[off>>7] + 14
+       default:
+               return offsetCodes[off>>14] + 28
+       }
+       panic("unreachable")
+}
diff --git a/libgo/go/compress/flate/util.go b/libgo/go/compress/flate/util.go
new file mode 100644 (file)
index 0000000..aca5c78
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+func min(left int, right int) int {
+       if left < right {
+               return left
+       }
+       return right
+}
+
+func minInt32(left int32, right int32) int32 {
+       if left < right {
+               return left
+       }
+       return right
+}
+
+func max(left int, right int) int {
+       if left > right {
+               return left
+       }
+       return right
+}
+
+func fillInts(a []int, value int) {
+       for i := range a {
+               a[i] = value
+       }
+}
+
+func fillInt32s(a []int32, value int32) {
+       for i := range a {
+               a[i] = value
+       }
+}
+
+func fillBytes(a []byte, value byte) {
+       for i := range a {
+               a[i] = value
+       }
+}
+
+func fillInt8s(a []int8, value int8) {
+       for i := range a {
+               a[i] = value
+       }
+}
+
+func fillUint8s(a []uint8, value uint8) {
+       for i := range a {
+               a[i] = value
+       }
+}
+
+func copyInt8s(dst []int8, src []int8) int {
+       cnt := min(len(dst), len(src))
+       for i := 0; i < cnt; i++ {
+               dst[i] = src[i]
+       }
+       return cnt
+}
+
+func copyUint8s(dst []uint8, src []uint8) int {
+       cnt := min(len(dst), len(src))
+       for i := 0; i < cnt; i++ {
+               dst[i] = src[i]
+       }
+       return cnt
+}
diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go
new file mode 100644 (file)
index 0000000..3c0b3c5
--- /dev/null
@@ -0,0 +1,230 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The gzip package implements reading and writing of
+// gzip format compressed files, as specified in RFC 1952.
+package gzip
+
+import (
+       "bufio"
+       "compress/flate"
+       "hash"
+       "hash/crc32"
+       "io"
+       "os"
+)
+
+// BUG(nigeltao): Comments and Names don't properly map UTF-8 character codes outside of
+// the 0x00-0x7f range to ISO 8859-1 (Latin-1).
+
+const (
+       gzipID1     = 0x1f
+       gzipID2     = 0x8b
+       gzipDeflate = 8
+       flagText    = 1 << 0
+       flagHdrCrc  = 1 << 1
+       flagExtra   = 1 << 2
+       flagName    = 1 << 3
+       flagComment = 1 << 4
+)
+
+func makeReader(r io.Reader) flate.Reader {
+       if rr, ok := r.(flate.Reader); ok {
+               return rr
+       }
+       return bufio.NewReader(r)
+}
+
+var HeaderError os.Error = os.ErrorString("invalid gzip header")
+var ChecksumError os.Error = os.ErrorString("gzip checksum error")
+
+// The gzip file stores a header giving metadata about the compressed file.
+// That header is exposed as the fields of the Compressor and Decompressor structs.
+type Header struct {
+       Comment string // comment
+       Extra   []byte // "extra data"
+       Mtime   uint32 // modification time (seconds since January 1, 1970)
+       Name    string // file name
+       OS      byte   // operating system type
+}
+
+// An Decompressor is an io.Reader that can be read to retrieve
+// uncompressed data from a gzip-format compressed file.
+//
+// In general, a gzip file can be a concatenation of gzip files,
+// each with its own header.  Reads from the Decompressor
+// return the concatenation of the uncompressed data of each.
+// Only the first header is recorded in the Decompressor fields.
+//
+// Gzip files store a length and checksum of the uncompressed data.
+// The Decompressor will return a ChecksumError when Read
+// reaches the end of the uncompressed data if it does not
+// have the expected length or checksum.  Clients should treat data
+// returned by Read as tentative until they receive the successful
+// (zero length, nil error) Read marking the end of the data.
+type Decompressor struct {
+       Header
+       r            flate.Reader
+       decompressor io.ReadCloser
+       digest       hash.Hash32
+       size         uint32
+       flg          byte
+       buf          [512]byte
+       err          os.Error
+}
+
+// NewReader creates a new Decompressor reading the given reader.
+// The implementation buffers input and may read more data than necessary from r.
+// It is the caller's responsibility to call Close on the Decompressor when done.
+func NewReader(r io.Reader) (*Decompressor, os.Error) {
+       z := new(Decompressor)
+       z.r = makeReader(r)
+       z.digest = crc32.NewIEEE()
+       if err := z.readHeader(true); err != nil {
+               z.err = err
+               return nil, err
+       }
+       return z, nil
+}
+
+// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
+func get4(p []byte) uint32 {
+       return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+}
+
+func (z *Decompressor) readString() (string, os.Error) {
+       var err os.Error
+       for i := 0; ; i++ {
+               if i >= len(z.buf) {
+                       return "", HeaderError
+               }
+               z.buf[i], err = z.r.ReadByte()
+               if err != nil {
+                       return "", err
+               }
+               if z.buf[i] == 0 {
+                       // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
+                       // TODO(nigeltao): Convert from ISO 8859-1 (Latin-1) to UTF-8.
+                       return string(z.buf[0:i]), nil
+               }
+       }
+       panic("not reached")
+}
+
+func (z *Decompressor) read2() (uint32, os.Error) {
+       _, err := io.ReadFull(z.r, z.buf[0:2])
+       if err != nil {
+               return 0, err
+       }
+       return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil
+}
+
+func (z *Decompressor) readHeader(save bool) os.Error {
+       _, err := io.ReadFull(z.r, z.buf[0:10])
+       if err != nil {
+               return err
+       }
+       if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
+               return HeaderError
+       }
+       z.flg = z.buf[3]
+       if save {
+               z.Mtime = get4(z.buf[4:8])
+               // z.buf[8] is xfl, ignored
+               z.OS = z.buf[9]
+       }
+       z.digest.Reset()
+       z.digest.Write(z.buf[0:10])
+
+       if z.flg&flagExtra != 0 {
+               n, err := z.read2()
+               if err != nil {
+                       return err
+               }
+               data := make([]byte, n)
+               if _, err = io.ReadFull(z.r, data); err != nil {
+                       return err
+               }
+               if save {
+                       z.Extra = data
+               }
+       }
+
+       var s string
+       if z.flg&flagName != 0 {
+               if s, err = z.readString(); err != nil {
+                       return err
+               }
+               if save {
+                       z.Name = s
+               }
+       }
+
+       if z.flg&flagComment != 0 {
+               if s, err = z.readString(); err != nil {
+                       return err
+               }
+               if save {
+                       z.Comment = s
+               }
+       }
+
+       if z.flg&flagHdrCrc != 0 {
+               n, err := z.read2()
+               if err != nil {
+                       return err
+               }
+               sum := z.digest.Sum32() & 0xFFFF
+               if n != sum {
+                       return HeaderError
+               }
+       }
+
+       z.digest.Reset()
+       z.decompressor = flate.NewReader(z.r)
+       return nil
+}
+
+func (z *Decompressor) Read(p []byte) (n int, err os.Error) {
+       if z.err != nil {
+               return 0, z.err
+       }
+       if len(p) == 0 {
+               return 0, nil
+       }
+
+       n, err = z.decompressor.Read(p)
+       z.digest.Write(p[0:n])
+       z.size += uint32(n)
+       if n != 0 || err != os.EOF {
+               z.err = err
+               return
+       }
+
+       // Finished file; check checksum + size.
+       if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil {
+               z.err = err
+               return 0, err
+       }
+       crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8])
+       sum := z.digest.Sum32()
+       if sum != crc32 || isize != z.size {
+               z.err = ChecksumError
+               return 0, z.err
+       }
+
+       // File is ok; is there another?
+       if err = z.readHeader(false); err != nil {
+               z.err = err
+               return
+       }
+
+       // Yes.  Reset and read from it.
+       z.digest.Reset()
+       z.size = 0
+       return z.Read(p)
+}
+
+// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
+func (z *Decompressor) Close() os.Error { return z.decompressor.Close() }
diff --git a/libgo/go/compress/gzip/gunzip_test.go b/libgo/go/compress/gzip/gunzip_test.go
new file mode 100644 (file)
index 0000000..1c08c73
--- /dev/null
@@ -0,0 +1,305 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gzip
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "testing"
+)
+
+type gunzipTest struct {
+       name string
+       desc string
+       raw  string
+       gzip []byte
+       err  os.Error
+}
+
+var gunzipTests = []gunzipTest{
+       { // has 1 empty fixed-huffman block
+               "empty.txt",
+               "empty.txt",
+               "",
+               []byte{
+                       0x1f, 0x8b, 0x08, 0x08, 0xf7, 0x5e, 0x14, 0x4a,
+                       0x00, 0x03, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e,
+                       0x74, 0x78, 0x74, 0x00, 0x03, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               },
+               nil,
+       },
+       { // has 1 non-empty fixed huffman block
+               "hello.txt",
+               "hello.txt",
+               "hello world\n",
+               []byte{
+                       0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+                       0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+                       0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+                       0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+                       0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+                       0x00, 0x00,
+               },
+               nil,
+       },
+       { // concatenation
+               "hello.txt",
+               "hello.txt x2",
+               "hello world\n" +
+                       "hello world\n",
+               []byte{
+                       0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+                       0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+                       0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+                       0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+                       0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+                       0x00, 0x00,
+                       0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+                       0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+                       0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+                       0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+                       0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+                       0x00, 0x00,
+               },
+               nil,
+       },
+       { // has a fixed huffman block with some length-distance pairs
+               "shesells.txt",
+               "shesells.txt",
+               "she sells seashells by the seashore\n",
+               []byte{
+                       0x1f, 0x8b, 0x08, 0x08, 0x72, 0x66, 0x8b, 0x4a,
+                       0x00, 0x03, 0x73, 0x68, 0x65, 0x73, 0x65, 0x6c,
+                       0x6c, 0x73, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x2b,
+                       0xce, 0x48, 0x55, 0x28, 0x4e, 0xcd, 0xc9, 0x29,
+                       0x06, 0x92, 0x89, 0xc5, 0x19, 0x60, 0x56, 0x52,
+                       0xa5, 0x42, 0x09, 0x58, 0x18, 0x28, 0x90, 0x5f,
+                       0x94, 0xca, 0x05, 0x00, 0x76, 0xb0, 0x3b, 0xeb,
+                       0x24, 0x00, 0x00, 0x00,
+               },
+               nil,
+       },
+       { // has dynamic huffman blocks
+               "gettysburg",
+               "gettysburg",
+               "  Four score and seven years ago our fathers brought forth on\n" +
+                       "this continent, a new nation, conceived in Liberty, and dedicated\n" +
+                       "to the proposition that all men are created equal.\n" +
+                       "  Now we are engaged in a great Civil War, testing whether that\n" +
+                       "nation, or any nation so conceived and so dedicated, can long\n" +
+                       "endure.\n" +
+                       "  We are met on a great battle-field of that war.\n" +
+                       "  We have come to dedicate a portion of that field, as a final\n" +
+                       "resting place for those who here gave their lives that that\n" +
+                       "nation might live.  It is altogether fitting and proper that\n" +
+                       "we should do this.\n" +
+                       "  But, in a larger sense, we can not dedicate — we can not\n" +
+                       "consecrate — we can not hallow — this ground.\n" +
+                       "  The brave men, living and dead, who struggled here, have\n" +
+                       "consecrated it, far above our poor power to add or detract.\n" +
+                       "The world will little note, nor long remember what we say here,\n" +
+                       "but it can never forget what they did here.\n" +
+                       "  It is for us the living, rather, to be dedicated here to the\n" +
+                       "unfinished work which they who fought here have thus far so\n" +
+                       "nobly advanced.  It is rather for us to be here dedicated to\n" +
+                       "the great task remaining before us — that from these honored\n" +
+                       "dead we take increased devotion to that cause for which they\n" +
+                       "gave the last full measure of devotion —\n" +
+                       "  that we here highly resolve that these dead shall not have\n" +
+                       "died in vain — that this nation, under God, shall have a new\n" +
+                       "birth of freedom — and that government of the people, by the\n" +
+                       "people, for the people, shall not perish from this earth.\n" +
+                       "\n" +
+                       "Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania\n",
+               []byte{
+                       0x1f, 0x8b, 0x08, 0x08, 0xd1, 0x12, 0x2b, 0x4a,
+                       0x00, 0x03, 0x67, 0x65, 0x74, 0x74, 0x79, 0x73,
+                       0x62, 0x75, 0x72, 0x67, 0x00, 0x65, 0x54, 0xcd,
+                       0x6e, 0xd4, 0x30, 0x10, 0xbe, 0xfb, 0x29, 0xe6,
+                       0x01, 0x42, 0xa5, 0x0a, 0x09, 0xc1, 0x11, 0x90,
+                       0x40, 0x48, 0xa8, 0xe2, 0x80, 0xd4, 0xf3, 0x24,
+                       0x9e, 0x24, 0x56, 0xbd, 0x9e, 0xc5, 0x76, 0x76,
+                       0x95, 0x1b, 0x0f, 0xc1, 0x13, 0xf2, 0x24, 0x7c,
+                       0x63, 0x77, 0x9b, 0x4a, 0x5c, 0xaa, 0x6e, 0x6c,
+                       0xcf, 0x7c, 0x7f, 0x33, 0x44, 0x5f, 0x74, 0xcb,
+                       0x54, 0x26, 0xcd, 0x42, 0x9c, 0x3c, 0x15, 0xb9,
+                       0x48, 0xa2, 0x5d, 0x38, 0x17, 0xe2, 0x45, 0xc9,
+                       0x4e, 0x67, 0xae, 0xab, 0xe0, 0xf7, 0x98, 0x75,
+                       0x5b, 0xd6, 0x4a, 0xb3, 0xe6, 0xba, 0x92, 0x26,
+                       0x57, 0xd7, 0x50, 0x68, 0xd2, 0x54, 0x43, 0x92,
+                       0x54, 0x07, 0x62, 0x4a, 0x72, 0xa5, 0xc4, 0x35,
+                       0x68, 0x1a, 0xec, 0x60, 0x92, 0x70, 0x11, 0x4f,
+                       0x21, 0xd1, 0xf7, 0x30, 0x4a, 0xae, 0xfb, 0xd0,
+                       0x9a, 0x78, 0xf1, 0x61, 0xe2, 0x2a, 0xde, 0x55,
+                       0x25, 0xd4, 0xa6, 0x73, 0xd6, 0xb3, 0x96, 0x60,
+                       0xef, 0xf0, 0x9b, 0x2b, 0x71, 0x8c, 0x74, 0x02,
+                       0x10, 0x06, 0xac, 0x29, 0x8b, 0xdd, 0x25, 0xf9,
+                       0xb5, 0x71, 0xbc, 0x73, 0x44, 0x0f, 0x7a, 0xa5,
+                       0xab, 0xb4, 0x33, 0x49, 0x0b, 0x2f, 0xbd, 0x03,
+                       0xd3, 0x62, 0x17, 0xe9, 0x73, 0xb8, 0x84, 0x48,
+                       0x8f, 0x9c, 0x07, 0xaa, 0x52, 0x00, 0x6d, 0xa1,
+                       0xeb, 0x2a, 0xc6, 0xa0, 0x95, 0x76, 0x37, 0x78,
+                       0x9a, 0x81, 0x65, 0x7f, 0x46, 0x4b, 0x45, 0x5f,
+                       0xe1, 0x6d, 0x42, 0xe8, 0x01, 0x13, 0x5c, 0x38,
+                       0x51, 0xd4, 0xb4, 0x38, 0x49, 0x7e, 0xcb, 0x62,
+                       0x28, 0x1e, 0x3b, 0x82, 0x93, 0x54, 0x48, 0xf1,
+                       0xd2, 0x7d, 0xe4, 0x5a, 0xa3, 0xbc, 0x99, 0x83,
+                       0x44, 0x4f, 0x3a, 0x77, 0x36, 0x57, 0xce, 0xcf,
+                       0x2f, 0x56, 0xbe, 0x80, 0x90, 0x9e, 0x84, 0xea,
+                       0x51, 0x1f, 0x8f, 0xcf, 0x90, 0xd4, 0x60, 0xdc,
+                       0x5e, 0xb4, 0xf7, 0x10, 0x0b, 0x26, 0xe0, 0xff,
+                       0xc4, 0xd1, 0xe5, 0x67, 0x2e, 0xe7, 0xc8, 0x93,
+                       0x98, 0x05, 0xb8, 0xa8, 0x45, 0xc0, 0x4d, 0x09,
+                       0xdc, 0x84, 0x16, 0x2b, 0x0d, 0x9a, 0x21, 0x53,
+                       0x04, 0x8b, 0xd2, 0x0b, 0xbd, 0xa2, 0x4c, 0xa7,
+                       0x60, 0xee, 0xd9, 0xe1, 0x1d, 0xd1, 0xb7, 0x4a,
+                       0x30, 0x8f, 0x63, 0xd5, 0xa5, 0x8b, 0x33, 0x87,
+                       0xda, 0x1a, 0x18, 0x79, 0xf3, 0xe3, 0xa6, 0x17,
+                       0x94, 0x2e, 0xab, 0x6e, 0xa0, 0xe3, 0xcd, 0xac,
+                       0x50, 0x8c, 0xca, 0xa7, 0x0d, 0x76, 0x37, 0xd1,
+                       0x23, 0xe7, 0x05, 0x57, 0x8b, 0xa4, 0x22, 0x83,
+                       0xd9, 0x62, 0x52, 0x25, 0xad, 0x07, 0xbb, 0xbf,
+                       0xbf, 0xff, 0xbc, 0xfa, 0xee, 0x20, 0x73, 0x91,
+                       0x29, 0xff, 0x7f, 0x02, 0x71, 0x62, 0x84, 0xb5,
+                       0xf6, 0xb5, 0x25, 0x6b, 0x41, 0xde, 0x92, 0xb7,
+                       0x76, 0x3f, 0x91, 0x91, 0x31, 0x1b, 0x41, 0x84,
+                       0x62, 0x30, 0x0a, 0x37, 0xa4, 0x5e, 0x18, 0x3a,
+                       0x99, 0x08, 0xa5, 0xe6, 0x6d, 0x59, 0x22, 0xec,
+                       0x33, 0x39, 0x86, 0x26, 0xf5, 0xab, 0x66, 0xc8,
+                       0x08, 0x20, 0xcf, 0x0c, 0xd7, 0x47, 0x45, 0x21,
+                       0x0b, 0xf6, 0x59, 0xd5, 0xfe, 0x5c, 0x8d, 0xaa,
+                       0x12, 0x7b, 0x6f, 0xa1, 0xf0, 0x52, 0x33, 0x4f,
+                       0xf5, 0xce, 0x59, 0xd3, 0xab, 0x66, 0x10, 0xbf,
+                       0x06, 0xc4, 0x31, 0x06, 0x73, 0xd6, 0x80, 0xa2,
+                       0x78, 0xc2, 0x45, 0xcb, 0x03, 0x65, 0x39, 0xc9,
+                       0x09, 0xd1, 0x06, 0x04, 0x33, 0x1a, 0x5a, 0xf1,
+                       0xde, 0x01, 0xb8, 0x71, 0x83, 0xc4, 0xb5, 0xb3,
+                       0xc3, 0x54, 0x65, 0x33, 0x0d, 0x5a, 0xf7, 0x9b,
+                       0x90, 0x7c, 0x27, 0x1f, 0x3a, 0x58, 0xa3, 0xd8,
+                       0xfd, 0x30, 0x5f, 0xb7, 0xd2, 0x66, 0xa2, 0x93,
+                       0x1c, 0x28, 0xb7, 0xe9, 0x1b, 0x0c, 0xe1, 0x28,
+                       0x47, 0x26, 0xbb, 0xe9, 0x7d, 0x7e, 0xdc, 0x96,
+                       0x10, 0x92, 0x50, 0x56, 0x7c, 0x06, 0xe2, 0x27,
+                       0xb4, 0x08, 0xd3, 0xda, 0x7b, 0x98, 0x34, 0x73,
+                       0x9f, 0xdb, 0xf6, 0x62, 0xed, 0x31, 0x41, 0x13,
+                       0xd3, 0xa2, 0xa8, 0x4b, 0x3a, 0xc6, 0x1d, 0xe4,
+                       0x2f, 0x8c, 0xf8, 0xfb, 0x97, 0x64, 0xf4, 0xb6,
+                       0x2f, 0x80, 0x5a, 0xf3, 0x56, 0xe0, 0x40, 0x50,
+                       0xd5, 0x19, 0xd0, 0x1e, 0xfc, 0xca, 0xe5, 0xc9,
+                       0xd4, 0x60, 0x00, 0x81, 0x2e, 0xa3, 0xcc, 0xb6,
+                       0x52, 0xf0, 0xb4, 0xdb, 0x69, 0x99, 0xce, 0x7a,
+                       0x32, 0x4c, 0x08, 0xed, 0xaa, 0x10, 0x10, 0xe3,
+                       0x6f, 0xee, 0x99, 0x68, 0x95, 0x9f, 0x04, 0x71,
+                       0xb2, 0x49, 0x2f, 0x62, 0xa6, 0x5e, 0xb4, 0xef,
+                       0x02, 0xed, 0x4f, 0x27, 0xde, 0x4a, 0x0f, 0xfd,
+                       0xc1, 0xcc, 0xdd, 0x02, 0x8f, 0x08, 0x16, 0x54,
+                       0xdf, 0xda, 0xca, 0xe0, 0x82, 0xf1, 0xb4, 0x31,
+                       0x7a, 0xa9, 0x81, 0xfe, 0x90, 0xb7, 0x3e, 0xdb,
+                       0xd3, 0x35, 0xc0, 0x20, 0x80, 0x33, 0x46, 0x4a,
+                       0x63, 0xab, 0xd1, 0x0d, 0x29, 0xd2, 0xe2, 0x84,
+                       0xb8, 0xdb, 0xfa, 0xe9, 0x89, 0x44, 0x86, 0x7c,
+                       0xe8, 0x0b, 0xe6, 0x02, 0x6a, 0x07, 0x9b, 0x96,
+                       0xd0, 0xdb, 0x2e, 0x41, 0x4c, 0xa1, 0xd5, 0x57,
+                       0x45, 0x14, 0xfb, 0xe3, 0xa6, 0x72, 0x5b, 0x87,
+                       0x6e, 0x0c, 0x6d, 0x5b, 0xce, 0xe0, 0x2f, 0xe2,
+                       0x21, 0x81, 0x95, 0xb0, 0xe8, 0xb6, 0x32, 0x0b,
+                       0xb2, 0x98, 0x13, 0x52, 0x5d, 0xfb, 0xec, 0x63,
+                       0x17, 0x8a, 0x9e, 0x23, 0x22, 0x36, 0xee, 0xcd,
+                       0xda, 0xdb, 0xcf, 0x3e, 0xf1, 0xc7, 0xf1, 0x01,
+                       0x12, 0x93, 0x0a, 0xeb, 0x6f, 0xf2, 0x02, 0x15,
+                       0x96, 0x77, 0x5d, 0xef, 0x9c, 0xfb, 0x88, 0x91,
+                       0x59, 0xf9, 0x84, 0xdd, 0x9b, 0x26, 0x8d, 0x80,
+                       0xf9, 0x80, 0x66, 0x2d, 0xac, 0xf7, 0x1f, 0x06,
+                       0xba, 0x7f, 0xff, 0xee, 0xed, 0x40, 0x5f, 0xa5,
+                       0xd6, 0xbd, 0x8c, 0x5b, 0x46, 0xd2, 0x7e, 0x48,
+                       0x4a, 0x65, 0x8f, 0x08, 0x42, 0x60, 0xf7, 0x0f,
+                       0xb9, 0x16, 0x0b, 0x0c, 0x1a, 0x06, 0x00, 0x00,
+               },
+               nil,
+       },
+       { // has 1 non-empty fixed huffman block then garbage
+               "hello.txt",
+               "hello.txt + garbage",
+               "hello world\n",
+               []byte{
+                       0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+                       0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+                       0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+                       0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+                       0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+                       0x00, 0x00, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', '!', '!',
+               },
+               HeaderError,
+       },
+       { // has 1 non-empty fixed huffman block not enough header
+               "hello.txt",
+               "hello.txt + garbage",
+               "hello world\n",
+               []byte{
+                       0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+                       0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+                       0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+                       0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+                       0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+                       0x00, 0x00, gzipID1,
+               },
+               io.ErrUnexpectedEOF,
+       },
+       { // has 1 non-empty fixed huffman block but corrupt checksum
+               "hello.txt",
+               "hello.txt + corrupt checksum",
+               "hello world\n",
+               []byte{
+                       0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+                       0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+                       0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+                       0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+                       0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00,
+                       0x00, 0x00,
+               },
+               ChecksumError,
+       },
+       { // has 1 non-empty fixed huffman block but corrupt size
+               "hello.txt",
+               "hello.txt + corrupt size",
+               "hello world\n",
+               []byte{
+                       0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+                       0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+                       0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+                       0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+                       0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0xff, 0x00,
+                       0x00, 0x00,
+               },
+               ChecksumError,
+       },
+}
+
+func TestDecompressor(t *testing.T) {
+       b := new(bytes.Buffer)
+       for _, tt := range gunzipTests {
+               in := bytes.NewBuffer(tt.gzip)
+               gzip, err := NewReader(in)
+               if err != nil {
+                       t.Errorf("%s: NewReader: %s", tt.name, err)
+                       continue
+               }
+               defer gzip.Close()
+               if tt.name != gzip.Name {
+                       t.Errorf("%s: got name %s", tt.name, gzip.Name)
+               }
+               b.Reset()
+               n, err := io.Copy(b, gzip)
+               if err != tt.err {
+                       t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+               }
+               s := b.String()
+               if s != tt.raw {
+                       t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+               }
+       }
+}
diff --git a/libgo/go/compress/gzip/gzip.go b/libgo/go/compress/gzip/gzip.go
new file mode 100644 (file)
index 0000000..8860d10
--- /dev/null
@@ -0,0 +1,187 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gzip
+
+import (
+       "compress/flate"
+       "hash"
+       "hash/crc32"
+       "io"
+       "os"
+)
+
+// These constants are copied from the flate package, so that code that imports
+// "compress/gzip" does not also have to import "compress/flate".
+const (
+       NoCompression      = flate.NoCompression
+       BestSpeed          = flate.BestSpeed
+       BestCompression    = flate.BestCompression
+       DefaultCompression = flate.DefaultCompression
+)
+
+// A Compressor is an io.WriteCloser that satisfies writes by compressing data written
+// to its wrapped io.Writer.
+type Compressor struct {
+       Header
+       w          io.Writer
+       level      int
+       compressor io.WriteCloser
+       digest     hash.Hash32
+       size       uint32
+       closed     bool
+       buf        [10]byte
+       err        os.Error
+}
+
+// NewWriter calls NewWriterLevel with the default compression level.
+func NewWriter(w io.Writer) (*Compressor, os.Error) {
+       return NewWriterLevel(w, DefaultCompression)
+}
+
+// NewWriterLevel creates a new Compressor writing to the given writer.
+// Writes may be buffered and not flushed until Close.
+// Callers that wish to set the fields in Compressor.Header must
+// do so before the first call to Write or Close.
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// level is the compression level, which can be DefaultCompression, NoCompression,
+// or any integer value between BestSpeed and BestCompression (inclusive).
+func NewWriterLevel(w io.Writer, level int) (*Compressor, os.Error) {
+       z := new(Compressor)
+       z.OS = 255 // unknown
+       z.w = w
+       z.level = level
+       z.digest = crc32.NewIEEE()
+       return z, nil
+}
+
+// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
+func put2(p []byte, v uint16) {
+       p[0] = uint8(v >> 0)
+       p[1] = uint8(v >> 8)
+}
+
+func put4(p []byte, v uint32) {
+       p[0] = uint8(v >> 0)
+       p[1] = uint8(v >> 8)
+       p[2] = uint8(v >> 16)
+       p[3] = uint8(v >> 24)
+}
+
+// writeBytes writes a length-prefixed byte slice to z.w.
+func (z *Compressor) writeBytes(b []byte) os.Error {
+       if len(b) > 0xffff {
+               return os.NewError("gzip.Write: Extra data is too large")
+       }
+       put2(z.buf[0:2], uint16(len(b)))
+       _, err := z.w.Write(z.buf[0:2])
+       if err != nil {
+               return err
+       }
+       _, err = z.w.Write(b)
+       return err
+}
+
+// writeString writes a string (in ISO 8859-1 (Latin-1) format) to z.w.
+func (z *Compressor) writeString(s string) os.Error {
+       // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
+       // TODO(nigeltao): Convert from UTF-8 to ISO 8859-1 (Latin-1).
+       for _, v := range s {
+               if v == 0 || v > 0x7f {
+                       return os.NewError("gzip.Write: non-ASCII header string")
+               }
+       }
+       _, err := io.WriteString(z.w, s)
+       if err != nil {
+               return err
+       }
+       // GZIP strings are NUL-terminated.
+       z.buf[0] = 0
+       _, err = z.w.Write(z.buf[0:1])
+       return err
+}
+
+func (z *Compressor) Write(p []byte) (int, os.Error) {
+       if z.err != nil {
+               return 0, z.err
+       }
+       var n int
+       // Write the GZIP header lazily.
+       if z.compressor == nil {
+               z.buf[0] = gzipID1
+               z.buf[1] = gzipID2
+               z.buf[2] = gzipDeflate
+               z.buf[3] = 0
+               if z.Extra != nil {
+                       z.buf[3] |= 0x04
+               }
+               if z.Name != "" {
+                       z.buf[3] |= 0x08
+               }
+               if z.Comment != "" {
+                       z.buf[3] |= 0x10
+               }
+               put4(z.buf[4:8], z.Mtime)
+               if z.level == BestCompression {
+                       z.buf[8] = 2
+               } else if z.level == BestSpeed {
+                       z.buf[8] = 4
+               } else {
+                       z.buf[8] = 0
+               }
+               z.buf[9] = z.OS
+               n, z.err = z.w.Write(z.buf[0:10])
+               if z.err != nil {
+                       return n, z.err
+               }
+               if z.Extra != nil {
+                       z.err = z.writeBytes(z.Extra)
+                       if z.err != nil {
+                               return n, z.err
+                       }
+               }
+               if z.Name != "" {
+                       z.err = z.writeString(z.Name)
+                       if z.err != nil {
+                               return n, z.err
+                       }
+               }
+               if z.Comment != "" {
+                       z.err = z.writeString(z.Comment)
+                       if z.err != nil {
+                               return n, z.err
+                       }
+               }
+               z.compressor = flate.NewWriter(z.w, z.level)
+       }
+       z.size += uint32(len(p))
+       z.digest.Write(p)
+       n, z.err = z.compressor.Write(p)
+       return n, z.err
+}
+
+// Calling Close does not close the wrapped io.Writer originally passed to NewWriter.
+func (z *Compressor) Close() os.Error {
+       if z.err != nil {
+               return z.err
+       }
+       if z.closed {
+               return nil
+       }
+       z.closed = true
+       if z.compressor == nil {
+               z.Write(nil)
+               if z.err != nil {
+                       return z.err
+               }
+       }
+       z.err = z.compressor.Close()
+       if z.err != nil {
+               return z.err
+       }
+       put4(z.buf[0:4], z.digest.Sum32())
+       put4(z.buf[4:8], z.size)
+       _, z.err = z.w.Write(z.buf[0:8])
+       return z.err
+}
diff --git a/libgo/go/compress/gzip/gzip_test.go b/libgo/go/compress/gzip/gzip_test.go
new file mode 100644 (file)
index 0000000..23f3514
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gzip
+
+import (
+       "io"
+       "io/ioutil"
+       "testing"
+)
+
+// pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the
+// writer end and ifunc at the reader end.
+func pipe(t *testing.T, dfunc func(*Compressor), cfunc func(*Decompressor)) {
+       piper, pipew := io.Pipe()
+       defer piper.Close()
+       go func() {
+               defer pipew.Close()
+               compressor, err := NewWriter(pipew)
+               if err != nil {
+                       t.Fatalf("%v", err)
+               }
+               defer compressor.Close()
+               dfunc(compressor)
+       }()
+       decompressor, err := NewReader(piper)
+       if err != nil {
+               t.Fatalf("%v", err)
+       }
+       defer decompressor.Close()
+       cfunc(decompressor)
+}
+
+// Tests that an empty payload still forms a valid GZIP stream.
+func TestEmpty(t *testing.T) {
+       pipe(t,
+               func(compressor *Compressor) {},
+               func(decompressor *Decompressor) {
+                       b, err := ioutil.ReadAll(decompressor)
+                       if err != nil {
+                               t.Fatalf("%v", err)
+                       }
+                       if len(b) != 0 {
+                               t.Fatalf("did not read an empty slice")
+                       }
+               })
+}
+
+// Tests that gzipping and then gunzipping is the identity function.
+func TestWriter(t *testing.T) {
+       pipe(t,
+               func(compressor *Compressor) {
+                       compressor.Comment = "comment"
+                       compressor.Extra = []byte("extra")
+                       compressor.Mtime = 1e8
+                       compressor.Name = "name"
+                       _, err := compressor.Write([]byte("payload"))
+                       if err != nil {
+                               t.Fatalf("%v", err)
+                       }
+               },
+               func(decompressor *Decompressor) {
+                       b, err := ioutil.ReadAll(decompressor)
+                       if err != nil {
+                               t.Fatalf("%v", err)
+                       }
+                       if string(b) != "payload" {
+                               t.Fatalf("payload is %q, want %q", string(b), "payload")
+                       }
+                       if decompressor.Comment != "comment" {
+                               t.Fatalf("comment is %q, want %q", decompressor.Comment, "comment")
+                       }
+                       if string(decompressor.Extra) != "extra" {
+                               t.Fatalf("extra is %q, want %q", decompressor.Extra, "extra")
+                       }
+                       if decompressor.Mtime != 1e8 {
+                               t.Fatalf("mtime is %d, want %d", decompressor.Mtime, uint32(1e8))
+                       }
+                       if decompressor.Name != "name" {
+                               t.Fatalf("name is %q, want %q", decompressor.Name, "name")
+                       }
+               })
+}
diff --git a/libgo/go/compress/zlib/reader.go b/libgo/go/compress/zlib/reader.go
new file mode 100644 (file)
index 0000000..721f6ec
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The zlib package implements reading and writing of zlib
+format compressed data, as specified in RFC 1950.
+
+The implementation provides filters that uncompress during reading
+and compress during writing.  For example, to write compressed data
+to a buffer:
+
+       var b bytes.Buffer
+       w, err := zlib.NewWriter(&b)
+       w.Write([]byte("hello, world\n"))
+       w.Close()
+
+and to read that data back:
+
+       r, err := zlib.NewReader(&b)
+       io.Copy(os.Stdout, r)
+       r.Close()
+*/
+package zlib
+
+import (
+       "bufio"
+       "compress/flate"
+       "hash"
+       "hash/adler32"
+       "io"
+       "os"
+)
+
+const zlibDeflate = 8
+
+var ChecksumError os.Error = os.ErrorString("zlib checksum error")
+var HeaderError os.Error = os.ErrorString("invalid zlib header")
+var UnsupportedError os.Error = os.ErrorString("unsupported zlib format")
+
+type reader struct {
+       r            flate.Reader
+       decompressor io.ReadCloser
+       digest       hash.Hash32
+       err          os.Error
+       scratch      [4]byte
+}
+
+// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
+// The implementation buffers input and may read more data than necessary from r.
+// It is the caller's responsibility to call Close on the ReadCloser when done.
+func NewReader(r io.Reader) (io.ReadCloser, os.Error) {
+       z := new(reader)
+       if fr, ok := r.(flate.Reader); ok {
+               z.r = fr
+       } else {
+               z.r = bufio.NewReader(r)
+       }
+       _, err := io.ReadFull(z.r, z.scratch[0:2])
+       if err != nil {
+               return nil, err
+       }
+       h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
+       if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
+               return nil, HeaderError
+       }
+       if z.scratch[1]&0x20 != 0 {
+               // BUG(nigeltao): The zlib package does not implement the FDICT flag.
+               return nil, UnsupportedError
+       }
+       z.digest = adler32.New()
+       z.decompressor = flate.NewReader(z.r)
+       return z, nil
+}
+
+func (z *reader) Read(p []byte) (n int, err os.Error) {
+       if z.err != nil {
+               return 0, z.err
+       }
+       if len(p) == 0 {
+               return 0, nil
+       }
+
+       n, err = z.decompressor.Read(p)
+       z.digest.Write(p[0:n])
+       if n != 0 || err != os.EOF {
+               z.err = err
+               return
+       }
+
+       // Finished file; check checksum.
+       if _, err := io.ReadFull(z.r, z.scratch[0:4]); err != nil {
+               z.err = err
+               return 0, err
+       }
+       // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
+       checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
+       if checksum != z.digest.Sum32() {
+               z.err = ChecksumError
+               return 0, z.err
+       }
+       return
+}
+
+// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
+func (z *reader) Close() os.Error {
+       if z.err != nil {
+               return z.err
+       }
+       z.err = z.decompressor.Close()
+       return z.err
+}
diff --git a/libgo/go/compress/zlib/reader_test.go b/libgo/go/compress/zlib/reader_test.go
new file mode 100644 (file)
index 0000000..eaefc3a
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zlib
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "testing"
+)
+
+type zlibTest struct {
+       desc       string
+       raw        string
+       compressed []byte
+       err        os.Error
+}
+
+// Compare-to-golden test data was generated by the ZLIB example program at
+// http://www.zlib.net/zpipe.c
+
+var zlibTests = []zlibTest{
+       {
+               "empty",
+               "",
+               []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
+               nil,
+       },
+       {
+               "goodbye",
+               "goodbye, world",
+               []byte{
+                       0x78, 0x9c, 0x4b, 0xcf, 0xcf, 0x4f, 0x49, 0xaa,
+                       0x4c, 0xd5, 0x51, 0x28, 0xcf, 0x2f, 0xca, 0x49,
+                       0x01, 0x00, 0x28, 0xa5, 0x05, 0x5e,
+               },
+               nil,
+       },
+       {
+               "bad header",
+               "",
+               []byte{0x78, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
+               HeaderError,
+       },
+       {
+               "bad checksum",
+               "",
+               []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff},
+               ChecksumError,
+       },
+       {
+               "not enough data",
+               "",
+               []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00},
+               io.ErrUnexpectedEOF,
+       },
+       {
+               "excess data is silently ignored",
+               "",
+               []byte{
+                       0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x78, 0x9c, 0xff,
+               },
+               nil,
+       },
+}
+
+func TestDecompressor(t *testing.T) {
+       b := new(bytes.Buffer)
+       for _, tt := range zlibTests {
+               in := bytes.NewBuffer(tt.compressed)
+               zlib, err := NewReader(in)
+               if err != nil {
+                       if err != tt.err {
+                               t.Errorf("%s: NewReader: %s", tt.desc, err)
+                       }
+                       continue
+               }
+               defer zlib.Close()
+               b.Reset()
+               n, err := io.Copy(b, zlib)
+               if err != nil {
+                       if err != tt.err {
+                               t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
+                       }
+                       continue
+               }
+               s := b.String()
+               if s != tt.raw {
+                       t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
+               }
+       }
+}
diff --git a/libgo/go/compress/zlib/testdata/e.txt b/libgo/go/compress/zlib/testdata/e.txt
new file mode 100644 (file)
index 0000000..76cf2a7
--- /dev/null
@@ -0,0 +1 @@
+2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907632338298807531952510190115738341879307021540891499348841675092447614606680822648001684774118537423454424371075390777449920695517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416928368190255151086574637721112523897844250569536967707854499699679468644549059879316368892300987931277361782154249992295763514822082698951936680331825288693984964651058209392398294887933203625094431173012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509961818815930416903515988885193458072738667385894228792284998920868058257492796104841984443634632449684875602336248270419786232090021609902353043699418491463140934317381436405462531520961836908887070167683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354021234078498193343210681701210056278802351930332247450158539047304199577770935036604169973297250886876966403555707162268447162560798826517871341951246652010305921236677194325278675398558944896970964097545918569563802363701621120477427228364896134225164450781824423529486363721417402388934412479635743702637552944483379980161254922785092577825620926226483262779333865664816277251640191059004916449982893150566047258027786318641551956532442586982946959308019152987211725563475463964479101459040905862984967912874068705048958586717479854667757573205681288459205413340539220001137863009455606881667400169842055804033637953764520304024322566135278369511778838638744396625322498506549958862342818997077332761717839280349465014345588970719425863987727547109629537415211151368350627526023264847287039207643100595841166120545297030236472549296669381151373227536450988890313602057248176585118063036442812314965507047510254465011727211555194866850800368532281831521960037356252794495158284188294787610852639813955990067376482922443752871846245780361929819713991475644882626039033814418232625150974827987779964373089970388867782271383605772978824125611907176639465070633045279546618550966661856647097113444740160704626215680717481877844371436988218559670959102596862002353718588748569652200050311734392073211390803293634479727355955277349071783793421637012050054513263835440001863239914907054797780566978533580489669062951194324730995876552368128590413832411607226029983305353708761389396391779574540161372236187893652605381558415871869255386061647798340254351284396129460352913325942794904337299085731580290958631382683291477116396337092400316894586360606458459251269946557248391865642097526850823075442545993769170419777800853627309417101634349076964237222943523661255725088147792231519747780605696725380171807763603462459278778465850656050780844211529697521890874019660906651803516501792504619501366585436632712549639908549144200014574760819302212066024330096412704894390397177195180699086998606636583232278709376502260149291011517177635944602023249300280401867723910288097866605651183260043688508817157238669842242201024950551881694803221002515426494639812873677658927688163598312477886520141174110913601164995076629077943646005851941998560162647907615321038727557126992518275687989302761761146162549356495903798045838182323368612016243736569846703785853305275833337939907521660692380533698879565137285593883499894707416181550125397064648171946708348197214488898790676503795903669672494992545279033729636162658976039498576741397359441023744329709355477982629614591442936451428617158587339746791897571211956187385783644758448423555581050025611492391518893099463428413936080383091662818811503715284967059741625628236092168075150177725387402564253470879089137291722828611515915683725241630772254406337875931059826760944203261924285317018781772960235413060672136046000389661093647095141417185777014180606443636815464440053316087783143174440811949422975599314011888683314832802706553833004693290115744147563139997221703804617092894579096271662260740718749975359212756084414737823303270330168237193648002173285734935947564334129943024850235732214597843282641421684878721673367010615094243456984401873312810107945127223737886126058165668053714396127888732527373890392890506865324138062796025930387727697783792868409325365880733988457218746021005311483351323850047827169376218004904795597959290591655470505777514308175112698985188408718564026035305583737832422924185625644255022672155980274012617971928047139600689163828665277009752767069777036439260224372841840883251848770472638440379530166905465937461619323840363893131364327137688841026811219891275223056256756254701725086349765367288605966752740868627407912856576996313789753034660616669804218267724560530660773899624218340859882071864682623215080288286359746839654358856685503773131296587975810501214916207656769950659715344763470320853215603674828608378656803073062657633469774295634643716709397193060876963495328846833613038829431040800296873869117066666146800015121143442256023874474325250769387077775193299942137277211258843608715834835626961661980572526612206797540621062080649882918454395301529982092503005498257043390553570168653120526495614857249257386206917403695213533732531666345466588597286659451136441370331393672118569553952108458407244323835586063106806964924851232632699514603596037297253198368423363904632136710116192821711150282801604488058802382031981493096369596735832742024988245684941273860566491352526706046234450549227581151709314921879592718001940968866986837037302200475314338181092708030017205935530520700706072233999463990571311587099635777359027196285061146514837526209565346713290025994397663114545902685898979115837093419370441155121920117164880566945938131183843765620627846310490346293950029458341164824114969758326011800731699437393506966295712410273239138741754923071862454543222039552735295240245903805744502892246886285336542213815722131163288112052146489805180092024719391710555390113943316681515828843687606961102505171007392762385553386272553538830960671644662370922646809671254061869502143176211668140097595281493907222601112681153108387317617323235263605838173151034595736538223534992935822836851007810884634349983518404451704270189381994243410090575376257767571118090088164183319201962623416288166521374717325477727783488774366518828752156685719506371936565390389449366421764003121527870222366463635755503565576948886549500270853923617105502131147413744106134445544192101336172996285694899193369184729478580729156088510396781959429833186480756083679551496636448965592948187851784038773326247051945050419847742014183947731202815886845707290544057510601285258056594703046836344592652552137008068752009593453607316226118728173928074623094685367823106097921599360019946237993434210687813497346959246469752506246958616909178573976595199392993995567542714654910456860702099012606818704984178079173924071945996323060254707901774527513186809982284730860766536866855516467702911336827563107223346726113705490795365834538637196235856312618387156774118738527722922594743373785695538456246801013905727871016512966636764451872465653730402443684140814488732957847348490003019477888020460324660842875351848364959195082888323206522128104190448047247949291342284951970022601310430062410717971502793433263407995960531446053230488528972917659876016667811937932372453857209607582277178483361613582612896226118129455927462767137794487586753657544861407611931125958512655759734573015333642630767985443385761715333462325270572005303988289499034259566232975782488735029259166825894456894655992658454762694528780516501720674785417887982276806536650641910973434528878338621726156269582654478205672987756426325321594294418039943217000090542650763095588465895171709147607437136893319469090981904501290307099566226620303182649365733698419555776963787624918852865686607600566025605445711337286840205574416030837052312242587223438854123179481388550075689381124935386318635287083799845692619981794523364087429591180747453419551420351726184200845509170845682368200897739455842679214273477560879644279202708312150156406341341617166448069815483764491573900121217041547872591998943825364950514771379399147205219529079396137621107238494290616357604596231253506068537651423115349665683715116604220796394466621163255157729070978473156278277598788136491951257483328793771571459091064841642678309949723674420175862269402159407924480541255360431317992696739157542419296607312393763542139230617876753958711436104089409966089471418340698362993675362621545247298464213752891079884381306095552622720837518629837066787224430195793793786072107254277289071732854874374355781966511716618330881129120245204048682200072344035025448202834254187884653602591506445271657700044521097735585897622655484941621714989532383421600114062950718490427789258552743035221396835679018076406042138307308774460170842688272261177180842664333651780002171903449234264266292261456004337383868335555343453004264818473989215627086095650629340405264943244261445665921291225648893569655009154306426134252668472594914314239398845432486327461842846655985332312210466259890141712103446084271616619001257195870793217569698544013397622096749454185407118446433946990162698351607848924514058940946395267807354579700307051163682519487701189764002827648414160587206184185297189154019688253289309149665345753571427318482016384644832499037886069008072709327673127581966563941148961716832980455139729506687604740915420428429993541025829113502241690769431668574242522509026939034814856451303069925199590436384028429267412573422447765584177886171737265462085498294498946787350929581652632072258992368768457017823038096567883112289305809140572610865884845873101658151167533327674887014829167419701512559782572707406431808601428149024146780472327597684269633935773542930186739439716388611764209004068663398856841681003872389214483176070116684503887212364367043314091155733280182977988736590916659612402021778558854876176161989370794380056663364884365089144805571039765214696027662583599051987042300179465536788
diff --git a/libgo/go/compress/zlib/testdata/pi.txt b/libgo/go/compress/zlib/testdata/pi.txt
new file mode 100644 (file)
index 0000000..58d8f3b
--- /dev/null
@@ -0,0 +1 @@
+3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275900994657640789512694683983525957098258226205224894077267194782684826014769909026401363944374553050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382686838689427741559918559252459539594310499725246808459872736446958486538367362226260991246080512438843904512441365497627807977156914359977001296160894416948685558484063534220722258284886481584560285060168427394522674676788952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288797108931456691368672287489405601015033086179286809208747609178249385890097149096759852613655497818931297848216829989487226588048575640142704775551323796414515237462343645428584447952658678210511413547357395231134271661021359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435064302184531910484810053706146806749192781911979399520614196634287544406437451237181921799983910159195618146751426912397489409071864942319615679452080951465502252316038819301420937621378559566389377870830390697920773467221825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539057962685610055081066587969981635747363840525714591028970641401109712062804390397595156771577004203378699360072305587631763594218731251471205329281918261861258673215791984148488291644706095752706957220917567116722910981690915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398315019701651511685171437657618351556508849099898599823873455283316355076479185358932261854896321329330898570642046752590709154814165498594616371802709819943099244889575712828905923233260972997120844335732654893823911932597463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100449293215160842444859637669838952286847831235526582131449576857262433441893039686426243410773226978028073189154411010446823252716201052652272111660396665573092547110557853763466820653109896526918620564769312570586356620185581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318586769751456614068007002378776591344017127494704205622305389945613140711270004078547332699390814546646458807972708266830634328587856983052358089330657574067954571637752542021149557615814002501262285941302164715509792592309907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111790429782856475032031986915140287080859904801094121472213179476477726224142548545403321571853061422881375850430633217518297986622371721591607716692547487389866549494501146540628433663937900397692656721463853067360965712091807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862947265473642523081770367515906735023507283540567040386743513622224771589150495309844489333096340878076932599397805419341447377441842631298608099888687413260472156951623965864573021631598193195167353812974167729478672422924654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001593776471651228935786015881617557829735233446042815126272037343146531977774160319906655418763979293344195215413418994854447345673831624993419131814809277771038638773431772075456545322077709212019051660962804909263601975988281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267945612753181340783303362542327839449753824372058353114771199260638133467768796959703098339130771098704085913374641442822772634659470474587847787201927715280731767907707157213444730605700733492436931138350493163128404251219256517980694113528013147013047816437885185290928545201165839341965621349143415956258658655705526904965209858033850722426482939728584783163057777560688876446248246857926039535277348030480290058760758251047470916439613626760449256274204208320856611906254543372131535958450687724602901618766795240616342522577195429162991930645537799140373404328752628889639958794757291746426357455254079091451357111369410911939325191076020825202618798531887705842972591677813149699009019211697173727847684726860849003377024242916513005005168323364350389517029893922334517220138128069650117844087451960121228599371623130171144484640903890644954440061986907548516026327505298349187407866808818338510228334508504860825039302133219715518430635455007668282949304137765527939751754613953984683393638304746119966538581538420568533862186725233402830871123282789212507712629463229563989898935821167456270102183564622013496715188190973038119800497340723961036854066431939509790190699639552453005450580685501956730229219139339185680344903982059551002263535361920419947455385938102343955449597783779023742161727111723643435439478221818528624085140066604433258885698670543154706965747458550332323342107301545940516553790686627333799585115625784322988273723198987571415957811196358330059408730681216028764962867446047746491599505497374256269010490377819868359381465741268049256487985561453723478673303904688383436346553794986419270563872931748723320837601123029911367938627089438799362016295154133714248928307220126901475466847653576164773794675200490757155527819653621323926406160136358155907422020203187277605277219005561484255518792530343513984425322341576233610642506390497500865627109535919465897514131034822769306247435363256916078154781811528436679570611086153315044521274739245449454236828860613408414863776700961207151249140430272538607648236341433462351897576645216413767969031495019108575984423919862916421939949072362346468441173940326591840443780513338945257423995082965912285085558215725031071257012668302402929525220118726767562204154205161841634847565169998116141010029960783869092916030288400269104140792886215078424516709087000699282120660418371806535567252532567532861291042487761825829765157959847035622262934860034158722980534989650226291748788202734209222245339856264766914905562842503912757710284027998066365825488926488025456610172967026640765590429099456815065265305371829412703369313785178609040708667114965583434347693385781711386455873678123014587687126603489139095620099393610310291616152881384379099042317473363948045759314931405297634757481193567091101377517210080315590248530906692037671922033229094334676851422144773793937517034436619910403375111735471918550464490263655128162288244625759163330391072253837421821408835086573917715096828874782656995995744906617583441375223970968340800535598491754173818839994469748676265516582765848358845314277568790029095170283529716344562129640435231176006651012412006597558512761785838292041974844236080071930457618932349229279650198751872127267507981255470958904556357921221033346697499235630254947802490114195212382815309114079073860251522742995818072471625916685451333123948049470791191532673430282441860414263639548000448002670496248201792896476697583183271314251702969234889627668440323260927524960357996469256504936818360900323809293459588970695365349406034021665443755890045632882250545255640564482465151875471196218443965825337543885690941130315095261793780029741207665147939425902989695946995565761218656196733786236256125216320862869222103274889218654364802296780705765615144632046927906821207388377814233562823608963208068222468012248261177185896381409183903673672220888321513755600372798394004152970028783076670944474560134556417254370906979396122571429894671543578468788614445812314593571984922528471605049221242470141214780573455105008019086996033027634787081081754501193071412233908663938339529425786905076431006383519834389341596131854347546495569781038293097164651438407007073604112373599843452251610507027056235266012764848308407611830130527932054274628654036036745328651057065874882256981579367897669742205750596834408697350201410206723585020072452256326513410559240190274216248439140359989535394590944070469120914093870012645600162374288021092764579310657922955249887275846101264836999892256959688159205600101655256375678
diff --git a/libgo/go/compress/zlib/writer.go b/libgo/go/compress/zlib/writer.go
new file mode 100644 (file)
index 0000000..031586c
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zlib
+
+import (
+       "compress/flate"
+       "hash"
+       "hash/adler32"
+       "io"
+       "os"
+)
+
+// These constants are copied from the flate package, so that code that imports
+// "compress/zlib" does not also have to import "compress/flate".
+const (
+       NoCompression      = flate.NoCompression
+       BestSpeed          = flate.BestSpeed
+       BestCompression    = flate.BestCompression
+       DefaultCompression = flate.DefaultCompression
+)
+
+type writer struct {
+       w          io.Writer
+       compressor io.WriteCloser
+       digest     hash.Hash32
+       err        os.Error
+       scratch    [4]byte
+}
+
+// NewWriter calls NewWriterLevel with the default compression level.
+func NewWriter(w io.Writer) (io.WriteCloser, os.Error) {
+       return NewWriterLevel(w, DefaultCompression)
+}
+
+// NewWriterLevel creates a new io.WriteCloser that satisfies writes by compressing data written to w.
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// level is the compression level, which can be DefaultCompression, NoCompression,
+// or any integer value between BestSpeed and BestCompression (inclusive).
+func NewWriterLevel(w io.Writer, level int) (io.WriteCloser, os.Error) {
+       z := new(writer)
+       // ZLIB has a two-byte header (as documented in RFC 1950).
+       // The first four bits is the CINFO (compression info), which is 7 for the default deflate window size.
+       // The next four bits is the CM (compression method), which is 8 for deflate.
+       z.scratch[0] = 0x78
+       // The next two bits is the FLEVEL (compression level). The four values are:
+       // 0=fastest, 1=fast, 2=default, 3=best.
+       // The next bit, FDICT, is unused, in this implementation.
+       // The final five FCHECK bits form a mod-31 checksum.
+       switch level {
+       case 0, 1:
+               z.scratch[1] = 0x01
+       case 2, 3, 4, 5:
+               z.scratch[1] = 0x5e
+       case 6, -1:
+               z.scratch[1] = 0x9c
+       case 7, 8, 9:
+               z.scratch[1] = 0xda
+       default:
+               return nil, os.NewError("level out of range")
+       }
+       _, err := w.Write(z.scratch[0:2])
+       if err != nil {
+               return nil, err
+       }
+       z.w = w
+       z.compressor = flate.NewWriter(w, level)
+       z.digest = adler32.New()
+       return z, nil
+}
+
+func (z *writer) Write(p []byte) (n int, err os.Error) {
+       if z.err != nil {
+               return 0, z.err
+       }
+       if len(p) == 0 {
+               return 0, nil
+       }
+       n, err = z.compressor.Write(p)
+       if err != nil {
+               z.err = err
+               return
+       }
+       z.digest.Write(p)
+       return
+}
+
+// Calling Close does not close the wrapped io.Writer originally passed to NewWriter.
+func (z *writer) Close() os.Error {
+       if z.err != nil {
+               return z.err
+       }
+       z.err = z.compressor.Close()
+       if z.err != nil {
+               return z.err
+       }
+       checksum := z.digest.Sum32()
+       // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
+       z.scratch[0] = uint8(checksum >> 24)
+       z.scratch[1] = uint8(checksum >> 16)
+       z.scratch[2] = uint8(checksum >> 8)
+       z.scratch[3] = uint8(checksum >> 0)
+       _, z.err = z.w.Write(z.scratch[0:4])
+       return z.err
+}
diff --git a/libgo/go/compress/zlib/writer_test.go b/libgo/go/compress/zlib/writer_test.go
new file mode 100644 (file)
index 0000000..fa9e78e
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zlib
+
+import (
+       "io"
+       "io/ioutil"
+       "os"
+       "testing"
+)
+
+var filenames = []string{
+       "testdata/e.txt",
+       "testdata/pi.txt",
+}
+
+// Tests that compressing and then decompressing the given file at the given compression level
+// yields equivalent bytes to the original file.
+func testFileLevel(t *testing.T, fn string, level int) {
+       // Read the file, as golden output.
+       golden, err := os.Open(fn, os.O_RDONLY, 0444)
+       if err != nil {
+               t.Errorf("%s (level=%d): %v", fn, level, err)
+               return
+       }
+       defer golden.Close()
+
+       // Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end.
+       raw, err := os.Open(fn, os.O_RDONLY, 0444)
+       if err != nil {
+               t.Errorf("%s (level=%d): %v", fn, level, err)
+               return
+       }
+       piper, pipew := io.Pipe()
+       defer piper.Close()
+       go func() {
+               defer raw.Close()
+               defer pipew.Close()
+               zlibw, err := NewWriterLevel(pipew, level)
+               if err != nil {
+                       t.Errorf("%s (level=%d): %v", fn, level, err)
+                       return
+               }
+               defer zlibw.Close()
+               var b [1024]byte
+               for {
+                       n, err0 := raw.Read(b[0:])
+                       if err0 != nil && err0 != os.EOF {
+                               t.Errorf("%s (level=%d): %v", fn, level, err0)
+                               return
+                       }
+                       _, err1 := zlibw.Write(b[0:n])
+                       if err1 == os.EPIPE {
+                               // Fail, but do not report the error, as some other (presumably reportable) error broke the pipe.
+                               return
+                       }
+                       if err1 != nil {
+                               t.Errorf("%s (level=%d): %v", fn, level, err1)
+                               return
+                       }
+                       if err0 == os.EOF {
+                               break
+                       }
+               }
+       }()
+       zlibr, err := NewReader(piper)
+       if err != nil {
+               t.Errorf("%s (level=%d): %v", fn, level, err)
+               return
+       }
+       defer zlibr.Close()
+
+       // Compare the two.
+       b0, err0 := ioutil.ReadAll(golden)
+       b1, err1 := ioutil.ReadAll(zlibr)
+       if err0 != nil {
+               t.Errorf("%s (level=%d): %v", fn, level, err0)
+               return
+       }
+       if err1 != nil {
+               t.Errorf("%s (level=%d): %v", fn, level, err1)
+               return
+       }
+       if len(b0) != len(b1) {
+               t.Errorf("%s (level=%d): length mismatch %d versus %d", fn, level, len(b0), len(b1))
+               return
+       }
+       for i := 0; i < len(b0); i++ {
+               if b0[i] != b1[i] {
+                       t.Errorf("%s (level=%d): mismatch at %d, 0x%02x versus 0x%02x\n", fn, level, i, b0[i], b1[i])
+                       return
+               }
+       }
+}
+
+func TestWriter(t *testing.T) {
+       for _, fn := range filenames {
+               testFileLevel(t, fn, DefaultCompression)
+               testFileLevel(t, fn, NoCompression)
+               for level := BestSpeed; level <= BestCompression; level++ {
+                       testFileLevel(t, fn, level)
+               }
+       }
+}
diff --git a/libgo/go/container/heap/heap.go b/libgo/go/container/heap/heap.go
new file mode 100644 (file)
index 0000000..4435a57
--- /dev/null
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package provides heap operations for any type that implements
+// heap.Interface.
+//
+package heap
+
+import "sort"
+
+// Any type that implements heap.Interface may be used as a
+// min-heap with the following invariants (established after
+// Init has been called):
+//
+//     !h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
+//
+type Interface interface {
+       sort.Interface
+       Push(x interface{})
+       Pop() interface{}
+}
+
+
+// A heaper must be initialized before any of the heap operations
+// can be used. Init is idempotent with respect to the heap invariants
+// and may be called whenever the heap invariants may have been invalidated.
+// Its complexity is O(n) where n = h.Len().
+//
+func Init(h Interface) {
+       // heapify
+       n := h.Len()
+       for i := n/2 - 1; i >= 0; i-- {
+               down(h, i, n)
+       }
+}
+
+
+// Push pushes the element x onto the heap. The complexity is
+// O(log(n)) where n = h.Len().
+//
+func Push(h Interface, x interface{}) {
+       h.Push(x)
+       up(h, h.Len()-1)
+}
+
+
+// Pop removes the minimum element (according to Less) from the heap
+// and returns it. The complexity is O(log(n)) where n = h.Len().
+// Same as Remove(h, 0).
+//
+func Pop(h Interface) interface{} {
+       n := h.Len() - 1
+       h.Swap(0, n)
+       down(h, 0, n)
+       return h.Pop()
+}
+
+
+// Remove removes the element at index i from the heap.
+// The complexity is O(log(n)) where n = h.Len().
+//
+func Remove(h Interface, i int) interface{} {
+       n := h.Len() - 1
+       if n != i {
+               h.Swap(i, n)
+               down(h, i, n)
+               up(h, i)
+       }
+       return h.Pop()
+}
+
+
+func up(h Interface, j int) {
+       for {
+               i := (j - 1) / 2 // parent
+               if i == j || h.Less(i, j) {
+                       break
+               }
+               h.Swap(i, j)
+               j = i
+       }
+}
+
+
+func down(h Interface, i, n int) {
+       for {
+               j1 := 2*i + 1
+               if j1 >= n {
+                       break
+               }
+               j := j1 // left child
+               if j2 := j1 + 1; j2 < n && !h.Less(j1, j2) {
+                       j = j2 // = 2*i + 2  // right child
+               }
+               if h.Less(i, j) {
+                       break
+               }
+               h.Swap(i, j)
+               i = j
+       }
+}
diff --git a/libgo/go/container/heap/heap_test.go b/libgo/go/container/heap/heap_test.go
new file mode 100644 (file)
index 0000000..89d444d
--- /dev/null
@@ -0,0 +1,166 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package heap
+
+import (
+       "testing"
+       "container/vector"
+)
+
+
+type myHeap struct {
+       // A vector.Vector implements sort.Interface except for Less,
+       // and it implements Push and Pop as required for heap.Interface.
+       vector.Vector
+}
+
+
+func (h *myHeap) Less(i, j int) bool { return h.At(i).(int) < h.At(j).(int) }
+
+
+func (h *myHeap) verify(t *testing.T, i int) {
+       n := h.Len()
+       j1 := 2*i + 1
+       j2 := 2*i + 2
+       if j1 < n {
+               if h.Less(j1, i) {
+                       t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h.At(i), j1, h.At(j1))
+                       return
+               }
+               h.verify(t, j1)
+       }
+       if j2 < n {
+               if h.Less(j2, i) {
+                       t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h.At(i), j1, h.At(j2))
+                       return
+               }
+               h.verify(t, j2)
+       }
+}
+
+
+func TestInit0(t *testing.T) {
+       h := new(myHeap)
+       for i := 20; i > 0; i-- {
+               h.Push(0) // all elements are the same
+       }
+       Init(h)
+       h.verify(t, 0)
+
+       for i := 1; h.Len() > 0; i++ {
+               x := Pop(h).(int)
+               h.verify(t, 0)
+               if x != 0 {
+                       t.Errorf("%d.th pop got %d; want %d", i, x, 0)
+               }
+       }
+}
+
+
+func TestInit1(t *testing.T) {
+       h := new(myHeap)
+       for i := 20; i > 0; i-- {
+               h.Push(i) // all elements are different
+       }
+       Init(h)
+       h.verify(t, 0)
+
+       for i := 1; h.Len() > 0; i++ {
+               x := Pop(h).(int)
+               h.verify(t, 0)
+               if x != i {
+                       t.Errorf("%d.th pop got %d; want %d", i, x, i)
+               }
+       }
+}
+
+
+func Test(t *testing.T) {
+       h := new(myHeap)
+       h.verify(t, 0)
+
+       for i := 20; i > 10; i-- {
+               h.Push(i)
+       }
+       Init(h)
+       h.verify(t, 0)
+
+       for i := 10; i > 0; i-- {
+               Push(h, i)
+               h.verify(t, 0)
+       }
+
+       for i := 1; h.Len() > 0; i++ {
+               x := Pop(h).(int)
+               if i < 20 {
+                       Push(h, 20+i)
+               }
+               h.verify(t, 0)
+               if x != i {
+                       t.Errorf("%d.th pop got %d; want %d", i, x, i)
+               }
+       }
+}
+
+
+func TestRemove0(t *testing.T) {
+       h := new(myHeap)
+       for i := 0; i < 10; i++ {
+               h.Push(i)
+       }
+       h.verify(t, 0)
+
+       for h.Len() > 0 {
+               i := h.Len() - 1
+               x := Remove(h, i).(int)
+               if x != i {
+                       t.Errorf("Remove(%d) got %d; want %d", i, x, i)
+               }
+               h.verify(t, 0)
+       }
+}
+
+
+func TestRemove1(t *testing.T) {
+       h := new(myHeap)
+       for i := 0; i < 10; i++ {
+               h.Push(i)
+       }
+       h.verify(t, 0)
+
+       for i := 0; h.Len() > 0; i++ {
+               x := Remove(h, 0).(int)
+               if x != i {
+                       t.Errorf("Remove(0) got %d; want %d", x, i)
+               }
+               h.verify(t, 0)
+       }
+}
+
+
+func TestRemove2(t *testing.T) {
+       N := 10
+
+       h := new(myHeap)
+       for i := 0; i < N; i++ {
+               h.Push(i)
+       }
+       h.verify(t, 0)
+
+       m := make(map[int]bool)
+       for h.Len() > 0 {
+               m[Remove(h, (h.Len()-1)/2).(int)] = true
+               h.verify(t, 0)
+       }
+
+       if len(m) != N {
+               t.Errorf("len(m) = %d; want %d", len(m), N)
+       }
+       for i := 0; i < len(m); i++ {
+               if !m[i] {
+                       t.Errorf("m[%d] doesn't exist", i)
+               }
+       }
+}
diff --git a/libgo/go/container/list/list.go b/libgo/go/container/list/list.go
new file mode 100755 (executable)
index 0000000..c1ebcdd
--- /dev/null
@@ -0,0 +1,211 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The list package implements a doubly linked list.
+//
+// To iterate over a list (where l is a *List):
+//     for e := l.Front(); e != nil; e = e.Next() {
+//             // do something with e.Value
+//     }
+//
+package list
+
+// Element is an element in the linked list.
+type Element struct {
+       // Next and previous pointers in the doubly-linked list of elements.
+       // The front of the list has prev = nil, and the back has next = nil.
+       next, prev *Element
+
+       // The list to which this element belongs.
+       list *List
+
+       // The contents of this list element.
+       Value interface{}
+}
+
+// Next returns the next list element or nil.
+func (e *Element) Next() *Element { return e.next }
+
+// Prev returns the previous list element or nil.
+func (e *Element) Prev() *Element { return e.prev }
+
+// List represents a doubly linked list.
+// The zero value for List is an empty list ready to use.
+type List struct {
+       front, back *Element
+       len         int
+}
+
+// Init initializes or clears a List.
+func (l *List) Init() *List {
+       l.front = nil
+       l.back = nil
+       l.len = 0
+       return l
+}
+
+// New returns an initialized list.
+func New() *List { return new(List) }
+
+// Front returns the first element in the list.
+func (l *List) Front() *Element { return l.front }
+
+// Back returns the last element in the list.
+func (l *List) Back() *Element { return l.back }
+
+// Remove removes the element from the list
+// and returns its Value.
+func (l *List) Remove(e *Element) interface{} {
+       l.remove(e)
+       e.list = nil // do what remove does not
+       return e.Value
+}
+
+// remove the element from the list, but do not clear the Element's list field.
+// This is so that other List methods may use remove when relocating Elements
+// without needing to restore the list field.
+func (l *List) remove(e *Element) {
+       if e.list != l {
+               return
+       }
+       if e.prev == nil {
+               l.front = e.next
+       } else {
+               e.prev.next = e.next
+       }
+       if e.next == nil {
+               l.back = e.prev
+       } else {
+               e.next.prev = e.prev
+       }
+
+       e.prev = nil
+       e.next = nil
+       l.len--
+}
+
+func (l *List) insertBefore(e *Element, mark *Element) {
+       if mark.prev == nil {
+               // new front of the list
+               l.front = e
+       } else {
+               mark.prev.next = e
+       }
+       e.prev = mark.prev
+       mark.prev = e
+       e.next = mark
+       l.len++
+}
+
+func (l *List) insertAfter(e *Element, mark *Element) {
+       if mark.next == nil {
+               // new back of the list
+               l.back = e
+       } else {
+               mark.next.prev = e
+       }
+       e.next = mark.next
+       mark.next = e
+       e.prev = mark
+       l.len++
+}
+
+func (l *List) insertFront(e *Element) {
+       if l.front == nil {
+               // empty list
+               l.front, l.back = e, e
+               e.prev, e.next = nil, nil
+               l.len = 1
+               return
+       }
+       l.insertBefore(e, l.front)
+}
+
+func (l *List) insertBack(e *Element) {
+       if l.back == nil {
+               // empty list
+               l.front, l.back = e, e
+               e.prev, e.next = nil, nil
+               l.len = 1
+               return
+       }
+       l.insertAfter(e, l.back)
+}
+
+// PushFront inserts the value at the front of the list and returns a new Element containing the value.
+func (l *List) PushFront(value interface{}) *Element {
+       e := &Element{nil, nil, l, value}
+       l.insertFront(e)
+       return e
+}
+
+// PushBack inserts the value at the back of the list and returns a new Element containing the value.
+func (l *List) PushBack(value interface{}) *Element {
+       e := &Element{nil, nil, l, value}
+       l.insertBack(e)
+       return e
+}
+
+// InsertBefore inserts the value immediately before mark and returns a new Element containing the value.
+func (l *List) InsertBefore(value interface{}, mark *Element) *Element {
+       if mark.list != l {
+               return nil
+       }
+       e := &Element{nil, nil, l, value}
+       l.insertBefore(e, mark)
+       return e
+}
+
+// InsertAfter inserts the value immediately after mark and returns a new Element containing the value.
+func (l *List) InsertAfter(value interface{}, mark *Element) *Element {
+       if mark.list != l {
+               return nil
+       }
+       e := &Element{nil, nil, l, value}
+       l.insertAfter(e, mark)
+       return e
+}
+
+// MoveToFront moves the element to the front of the list.
+func (l *List) MoveToFront(e *Element) {
+       if e.list != l || l.front == e {
+               return
+       }
+       l.remove(e)
+       l.insertFront(e)
+}
+
+// MoveToBack moves the element to the back of the list.
+func (l *List) MoveToBack(e *Element) {
+       if e.list != l || l.back == e {
+               return
+       }
+       l.remove(e)
+       l.insertBack(e)
+}
+
+// Len returns the number of elements in the list.
+func (l *List) Len() int { return l.len }
+
+// PushBackList inserts each element of ol at the back of the list.
+func (l *List) PushBackList(ol *List) {
+       last := ol.Back()
+       for e := ol.Front(); e != nil; e = e.Next() {
+               l.PushBack(e.Value)
+               if e == last {
+                       break
+               }
+       }
+}
+
+// PushFrontList inserts each element of ol at the front of the list. The ordering of the passed list is preserved.
+func (l *List) PushFrontList(ol *List) {
+       first := ol.Front()
+       for e := ol.Back(); e != nil; e = e.Prev() {
+               l.PushFront(e.Value)
+               if e == first {
+                       break
+               }
+       }
+}
diff --git a/libgo/go/container/list/list_test.go b/libgo/go/container/list/list_test.go
new file mode 100755 (executable)
index 0000000..1d44ff8
--- /dev/null
@@ -0,0 +1,209 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package list
+
+import (
+       "testing"
+)
+
+func checkListPointers(t *testing.T, l *List, es []*Element) {
+       if len(es) == 0 {
+               if l.front != nil || l.back != nil {
+                       t.Errorf("l.front/l.back = %v/%v should be nil/nil", l.front, l.back)
+               }
+               return
+       }
+
+       if l.front != es[0] {
+               t.Errorf("l.front = %v, want %v", l.front, es[0])
+       }
+       if last := es[len(es)-1]; l.back != last {
+               t.Errorf("l.back = %v, want %v", l.back, last)
+       }
+
+       for i, e := range es {
+               var e_prev, e_next *Element = nil, nil
+               if i > 0 {
+                       e_prev = es[i-1]
+               }
+               if i < len(es)-1 {
+                       e_next = es[i+1]
+               }
+               if e.prev != e_prev {
+                       t.Errorf("elt #%d (%v) has prev=%v, want %v", i, e, e.prev, e_prev)
+               }
+               if e.next != e_next {
+                       t.Errorf("elt #%d (%v) has next=%v, want %v", i, e, e.next, e_next)
+               }
+       }
+}
+
+func checkListLen(t *testing.T, l *List, n int) {
+       if an := l.Len(); an != n {
+               t.Errorf("l.Len() = %d, want %d", an, n)
+       }
+}
+
+func TestList(t *testing.T) {
+       l := New()
+       checkListPointers(t, l, []*Element{})
+       checkListLen(t, l, 0)
+
+       // Single element list
+       e := l.PushFront("a")
+       checkListLen(t, l, 1)
+       checkListPointers(t, l, []*Element{e})
+       l.MoveToFront(e)
+       checkListPointers(t, l, []*Element{e})
+       l.MoveToBack(e)
+       checkListPointers(t, l, []*Element{e})
+       checkListLen(t, l, 1)
+       l.Remove(e)
+       checkListPointers(t, l, []*Element{})
+       checkListLen(t, l, 0)
+
+       // Bigger list
+       e2 := l.PushFront(2)
+       e1 := l.PushFront(1)
+       e3 := l.PushBack(3)
+       e4 := l.PushBack("banana")
+       checkListPointers(t, l, []*Element{e1, e2, e3, e4})
+       checkListLen(t, l, 4)
+
+       l.Remove(e2)
+       checkListPointers(t, l, []*Element{e1, e3, e4})
+       checkListLen(t, l, 3)
+
+       l.MoveToFront(e3) // move from middle
+       checkListPointers(t, l, []*Element{e3, e1, e4})
+
+       l.MoveToFront(e1)
+       l.MoveToBack(e3) // move from middle
+       checkListPointers(t, l, []*Element{e1, e4, e3})
+
+       l.MoveToFront(e3) // move from back
+       checkListPointers(t, l, []*Element{e3, e1, e4})
+       l.MoveToFront(e3) // should be no-op
+       checkListPointers(t, l, []*Element{e3, e1, e4})
+
+       l.MoveToBack(e3) // move from front
+       checkListPointers(t, l, []*Element{e1, e4, e3})
+       l.MoveToBack(e3) // should be no-op
+       checkListPointers(t, l, []*Element{e1, e4, e3})
+
+       e2 = l.InsertBefore(2, e1) // insert before front
+       checkListPointers(t, l, []*Element{e2, e1, e4, e3})
+       l.Remove(e2)
+       e2 = l.InsertBefore(2, e4) // insert before middle
+       checkListPointers(t, l, []*Element{e1, e2, e4, e3})
+       l.Remove(e2)
+       e2 = l.InsertBefore(2, e3) // insert before back
+       checkListPointers(t, l, []*Element{e1, e4, e2, e3})
+       l.Remove(e2)
+
+       e2 = l.InsertAfter(2, e1) // insert after front
+       checkListPointers(t, l, []*Element{e1, e2, e4, e3})
+       l.Remove(e2)
+       e2 = l.InsertAfter(2, e4) // insert after middle
+       checkListPointers(t, l, []*Element{e1, e4, e2, e3})
+       l.Remove(e2)
+       e2 = l.InsertAfter(2, e3) // insert after back
+       checkListPointers(t, l, []*Element{e1, e4, e3, e2})
+       l.Remove(e2)
+
+       // Check standard iteration.
+       sum := 0
+       for e := l.Front(); e != nil; e = e.Next() {
+               if i, ok := e.Value.(int); ok {
+                       sum += i
+               }
+       }
+       if sum != 4 {
+               t.Errorf("sum over l.Iter() = %d, want 4", sum)
+       }
+
+       // Clear all elements by iterating
+       var next *Element
+       for e := l.Front(); e != nil; e = next {
+               next = e.Next()
+               l.Remove(e)
+       }
+       checkListPointers(t, l, []*Element{})
+       checkListLen(t, l, 0)
+}
+
+func checkList(t *testing.T, l *List, es []interface{}) {
+       if l.Len() != len(es) {
+               t.Errorf("list has len=%v, want %v", l.Len(), len(es))
+               return
+       }
+       i := 0
+       for e := l.Front(); e != nil; e = e.Next() {
+               le := e.Value.(int)
+               if le != es[i] {
+                       t.Errorf("elt #%d has value=%v, want %v", i, le, es[i])
+               }
+               i++
+       }
+}
+
+func TestExtending(t *testing.T) {
+       l1 := New()
+       l2 := New()
+
+       l1.PushBack(1)
+       l1.PushBack(2)
+       l1.PushBack(3)
+
+       l2.PushBack(4)
+       l2.PushBack(5)
+
+       l3 := New()
+       l3.PushBackList(l1)
+       checkList(t, l3, []interface{}{1, 2, 3})
+       l3.PushBackList(l2)
+       checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
+
+       l3 = New()
+       l3.PushFrontList(l2)
+       checkList(t, l3, []interface{}{4, 5})
+       l3.PushFrontList(l1)
+       checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
+
+       checkList(t, l1, []interface{}{1, 2, 3})
+       checkList(t, l2, []interface{}{4, 5})
+
+       l3 = New()
+       l3.PushBackList(l1)
+       checkList(t, l3, []interface{}{1, 2, 3})
+       l3.PushBackList(l3)
+       checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+       l3 = New()
+       l3.PushFrontList(l1)
+       checkList(t, l3, []interface{}{1, 2, 3})
+       l3.PushFrontList(l3)
+       checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+       l3 = New()
+       l1.PushBackList(l3)
+       checkList(t, l1, []interface{}{1, 2, 3})
+       l1.PushFrontList(l3)
+       checkList(t, l1, []interface{}{1, 2, 3})
+}
+
+func TestRemove(t *testing.T) {
+       l := New()
+       e1 := l.PushBack(1)
+       e2 := l.PushBack(2)
+       checkListPointers(t, l, []*Element{e1, e2})
+       e := l.Front()
+       l.Remove(e)
+       checkListPointers(t, l, []*Element{e2})
+       checkListLen(t, l, 1)
+       l.Remove(e)
+       checkListPointers(t, l, []*Element{e2})
+       checkListLen(t, l, 1)
+}
diff --git a/libgo/go/container/ring/ring.go b/libgo/go/container/ring/ring.go
new file mode 100644 (file)
index 0000000..335afbc
--- /dev/null
@@ -0,0 +1,153 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The ring package implements operations on circular lists.
+package ring
+
+// A Ring is an element of a circular list, or ring.
+// Rings do not have a beginning or end; a pointer to any ring element
+// serves as reference to the entire ring. Empty rings are represented
+// as nil Ring pointers. The zero value for a Ring is a one-element
+// ring with a nil Value.
+//
+type Ring struct {
+       next, prev *Ring
+       Value      interface{} // for use by client; untouched by this library
+}
+
+
+func (r *Ring) init() *Ring {
+       r.next = r
+       r.prev = r
+       return r
+}
+
+
+// Next returns the next ring element. r must not be empty.
+func (r *Ring) Next() *Ring {
+       if r.next == nil {
+               return r.init()
+       }
+       return r.next
+}
+
+
+// Prev returns the previous ring element. r must not be empty.
+func (r *Ring) Prev() *Ring {
+       if r.next == nil {
+               return r.init()
+       }
+       return r.prev
+}
+
+
+// Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0)
+// in the ring and returns that ring element. r must not be empty.
+//
+func (r *Ring) Move(n int) *Ring {
+       if r.next == nil {
+               return r.init()
+       }
+       switch {
+       case n < 0:
+               for ; n < 0; n++ {
+                       r = r.prev
+               }
+       case n > 0:
+               for ; n > 0; n-- {
+                       r = r.next
+               }
+       }
+       return r
+}
+
+
+// New creates a ring of n elements.
+func New(n int) *Ring {
+       if n <= 0 {
+               return nil
+       }
+       r := new(Ring)
+       p := r
+       for i := 1; i < n; i++ {
+               p.next = &Ring{prev: p}
+               p = p.next
+       }
+       p.next = r
+       r.prev = p
+       return r
+}
+
+
+// Link connects ring r with with ring s such that r.Next()
+// becomes s and returns the original value for r.Next().
+// r must not be empty.
+//
+// If r and s point to the same ring, linking
+// them removes the elements between r and s from the ring.
+// The removed elements form a subring and the result is a
+// reference to that subring (if no elements were removed,
+// the result is still the original value for r.Next(),
+// and not nil).
+//
+// If r and s point to different rings, linking
+// them creates a single ring with the elements of s inserted
+// after r. The result points to the element following the
+// last element of s after insertion.
+//
+func (r *Ring) Link(s *Ring) *Ring {
+       n := r.Next()
+       if s != nil {
+               p := s.Prev()
+               // Note: Cannot use multiple assignment because
+               // evaluation order of LHS is not specified.
+               r.next = s
+               s.prev = r
+               n.prev = p
+               p.next = n
+       }
+       return n
+}
+
+
+// Unlink removes n % r.Len() elements from the ring r, starting
+// at r.Next(). If n % r.Len() == 0, r remains unchanged.
+// The result is the removed subring. r must not be empty.
+//
+func (r *Ring) Unlink(n int) *Ring {
+       if n <= 0 {
+               return nil
+       }
+       return r.Link(r.Move(n + 1))
+}
+
+
+// Len computes the number of elements in ring r.
+// It executes in time proportional to the number of elements.
+//
+func (r *Ring) Len() int {
+       n := 0
+       if r != nil {
+               n = 1
+               for p := r.Next(); p != r; p = p.next {
+                       n++
+               }
+       }
+       return n
+}
+
+
+func (r *Ring) Iter() <-chan interface{} {
+       c := make(chan interface{})
+       go func() {
+               if r != nil {
+                       c <- r.Value
+                       for p := r.Next(); p != r; p = p.next {
+                               c <- p.Value
+                       }
+               }
+               close(c)
+       }()
+       return c
+}
diff --git a/libgo/go/container/ring/ring_test.go b/libgo/go/container/ring/ring_test.go
new file mode 100644 (file)
index 0000000..ee3c411
--- /dev/null
@@ -0,0 +1,240 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ring
+
+import (
+       "fmt"
+       "testing"
+)
+
+
+// For debugging - keep around.
+func dump(r *Ring) {
+       if r == nil {
+               fmt.Println("empty")
+               return
+       }
+       i, n := 0, r.Len()
+       for p := r; i < n; p = p.next {
+               fmt.Printf("%4d: %p = {<- %p | %p ->}\n", i, p, p.prev, p.next)
+               i++
+       }
+       fmt.Println()
+}
+
+
+func verify(t *testing.T, r *Ring, N int, sum int) {
+       // Len
+       n := r.Len()
+       if n != N {
+               t.Errorf("r.Len() == %d; expected %d", n, N)
+       }
+
+       // iteration
+       n = 0
+       s := 0
+       for p := range r.Iter() {
+               n++
+               if p != nil {
+                       s += p.(int)
+               }
+       }
+       if n != N {
+               t.Errorf("number of forward iterations == %d; expected %d", n, N)
+       }
+       if sum >= 0 && s != sum {
+               t.Errorf("forward ring sum = %d; expected %d", s, sum)
+       }
+
+       if r == nil {
+               return
+       }
+
+       // connections
+       if r.next != nil {
+               var p *Ring // previous element
+               for q := r; p == nil || q != r; q = q.next {
+                       if p != nil && p != q.prev {
+                               t.Errorf("prev = %p, expected q.prev = %p\n", p, q.prev)
+                       }
+                       p = q
+               }
+               if p != r.prev {
+                       t.Errorf("prev = %p, expected r.prev = %p\n", p, r.prev)
+               }
+       }
+
+       // Next, Prev
+       if r.Next() != r.next {
+               t.Errorf("r.Next() != r.next")
+       }
+       if r.Prev() != r.prev {
+               t.Errorf("r.Prev() != r.prev")
+       }
+
+       // Move
+       if r.Move(0) != r {
+               t.Errorf("r.Move(0) != r")
+       }
+       if r.Move(N) != r {
+               t.Errorf("r.Move(%d) != r", N)
+       }
+       if r.Move(-N) != r {
+               t.Errorf("r.Move(%d) != r", -N)
+       }
+       for i := 0; i < 10; i++ {
+               ni := N + i
+               mi := ni % N
+               if r.Move(ni) != r.Move(mi) {
+                       t.Errorf("r.Move(%d) != r.Move(%d)", ni, mi)
+               }
+               if r.Move(-ni) != r.Move(-mi) {
+                       t.Errorf("r.Move(%d) != r.Move(%d)", -ni, -mi)
+               }
+       }
+}
+
+
+func TestCornerCases(t *testing.T) {
+       var (
+               r0 *Ring
+               r1 Ring
+       )
+       // Basics
+       verify(t, r0, 0, 0)
+       verify(t, &r1, 1, 0)
+       // Insert
+       r1.Link(r0)
+       verify(t, r0, 0, 0)
+       verify(t, &r1, 1, 0)
+       // Insert
+       r1.Link(r0)
+       verify(t, r0, 0, 0)
+       verify(t, &r1, 1, 0)
+       // Unlink
+       r1.Unlink(0)
+       verify(t, &r1, 1, 0)
+}
+
+
+func makeN(n int) *Ring {
+       r := New(n)
+       for i := 1; i <= n; i++ {
+               r.Value = i
+               r = r.Next()
+       }
+       return r
+}
+
+
+func sum(r *Ring) int {
+       s := 0
+       for p := range r.Iter() {
+               s += p.(int)
+       }
+       return s
+}
+
+
+func sumN(n int) int { return (n*n + n) / 2 }
+
+
+func TestNew(t *testing.T) {
+       for i := 0; i < 10; i++ {
+               r := New(i)
+               verify(t, r, i, -1)
+       }
+       for i := 0; i < 10; i++ {
+               r := makeN(i)
+               verify(t, r, i, sumN(i))
+       }
+}
+
+
+func TestLink1(t *testing.T) {
+       r1a := makeN(1)
+       var r1b Ring
+       r2a := r1a.Link(&r1b)
+       verify(t, r2a, 2, 1)
+       if r2a != r1a {
+               t.Errorf("a) 2-element link failed")
+       }
+
+       r2b := r2a.Link(r2a.Next())
+       verify(t, r2b, 2, 1)
+       if r2b != r2a.Next() {
+               t.Errorf("b) 2-element link failed")
+       }
+
+       r1c := r2b.Link(r2b)
+       verify(t, r1c, 1, 1)
+       verify(t, r2b, 1, 0)
+}
+
+
+func TestLink2(t *testing.T) {
+       var r0 *Ring
+       r1a := &Ring{Value: 42}
+       r1b := &Ring{Value: 77}
+       r10 := makeN(10)
+
+       r1a.Link(r0)
+       verify(t, r1a, 1, 42)
+
+       r1a.Link(r1b)
+       verify(t, r1a, 2, 42+77)
+
+       r10.Link(r0)
+       verify(t, r10, 10, sumN(10))
+
+       r10.Link(r1a)
+       verify(t, r10, 12, sumN(10)+42+77)
+}
+
+
+func TestLink3(t *testing.T) {
+       var r Ring
+       n := 1
+       for i := 1; i < 100; i++ {
+               n += i
+               verify(t, r.Link(New(i)), n, -1)
+       }
+}
+
+
+func TestUnlink(t *testing.T) {
+       r10 := makeN(10)
+       s10 := r10.Move(6)
+
+       sum10 := sumN(10)
+
+       verify(t, r10, 10, sum10)
+       verify(t, s10, 10, sum10)
+
+       r0 := r10.Unlink(0)
+       verify(t, r0, 0, 0)
+
+       r1 := r10.Unlink(1)
+       verify(t, r1, 1, 2)
+       verify(t, r10, 9, sum10-2)
+
+       r9 := r10.Unlink(9)
+       verify(t, r9, 9, sum10-2)
+       verify(t, r10, 9, sum10-2)
+}
+
+
+func TestLinkUnlink(t *testing.T) {
+       for i := 1; i < 4; i++ {
+               ri := New(i)
+               for j := 0; j < i; j++ {
+                       rj := ri.Unlink(j)
+                       verify(t, rj, j, -1)
+                       verify(t, ri, i-j, -1)
+                       ri.Link(rj)
+                       verify(t, ri, i, -1)
+               }
+       }
+}
diff --git a/libgo/go/container/vector/defs.go b/libgo/go/container/vector/defs.go
new file mode 100644 (file)
index 0000000..a2febb6
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The vector package implements containers for managing sequences
+// of elements. Vectors grow and shrink dynamically as necessary.
+package vector
+
+
+// Vector is a container for numbered sequences of elements of type interface{}.
+// A vector's length and capacity adjusts automatically as necessary.
+// The zero value for Vector is an empty vector ready to use.
+type Vector []interface{}
+
+
+// IntVector is a container for numbered sequences of elements of type int.
+// A vector's length and capacity adjusts automatically as necessary.
+// The zero value for IntVector is an empty vector ready to use.
+type IntVector []int
+
+
+// StringVector is a container for numbered sequences of elements of type string.
+// A vector's length and capacity adjusts automatically as necessary.
+// The zero value for StringVector is an empty vector ready to use.
+type StringVector []string
+
+
+// Initial underlying array size
+const initialSize = 8
+
+
+// Partial sort.Interface support
+
+// LessInterface provides partial support of the sort.Interface.
+type LessInterface interface {
+       Less(y interface{}) bool
+}
+
+
+// Less returns a boolean denoting whether the i'th element is less than the j'th element.
+func (p *Vector) Less(i, j int) bool { return (*p)[i].(LessInterface).Less((*p)[j]) }
+
+
+// sort.Interface support
+
+// Less returns a boolean denoting whether the i'th element is less than the j'th element.
+func (p *IntVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
+
+
+// Less returns a boolean denoting whether the i'th element is less than the j'th element.
+func (p *StringVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
diff --git a/libgo/go/container/vector/intvector.go b/libgo/go/container/vector/intvector.go
new file mode 100644 (file)
index 0000000..5ad9e29
--- /dev/null
@@ -0,0 +1,208 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector.go, it was generated
+// automatically from vector.go - DO NOT EDIT in that case!
+
+package vector
+
+
+func (p *IntVector) realloc(length, capacity int) (b []int) {
+       if capacity < initialSize {
+               capacity = initialSize
+       }
+       if capacity < length {
+               capacity = length
+       }
+       b = make(IntVector, length, capacity)
+       copy(b, *p)
+       *p = b
+       return
+}
+
+
+// Insert n elements at position i.
+func (p *IntVector) Expand(i, n int) {
+       a := *p
+
+       // make sure we have enough space
+       len0 := len(a)
+       len1 := len0 + n
+       if len1 <= cap(a) {
+               // enough space - just expand
+               a = a[0:len1]
+       } else {
+               // not enough space - double capacity
+               capb := cap(a) * 2
+               if capb < len1 {
+                       // still not enough - use required length
+                       capb = len1
+               }
+               // capb >= len1
+               a = p.realloc(len1, capb)
+       }
+
+       // make a hole
+       for j := len0 - 1; j >= i; j-- {
+               a[j+n] = a[j]
+       }
+
+       *p = a
+}
+
+
+// Insert n elements at the end of a vector.
+func (p *IntVector) Extend(n int) { p.Expand(len(*p), n) }
+
+
+// Resize changes the length and capacity of a vector.
+// If the new length is shorter than the current length, Resize discards
+// trailing elements. If the new length is longer than the current length,
+// Resize adds the respective zero values for the additional elements. The capacity
+// parameter is ignored unless the new length or capacity is longer than the current
+// capacity. The resized vector's capacity may be larger than the requested capacity.
+func (p *IntVector) Resize(length, capacity int) *IntVector {
+       a := *p
+
+       if length > cap(a) || capacity > cap(a) {
+               // not enough space or larger capacity requested explicitly
+               a = p.realloc(length, capacity)
+       } else if length < len(a) {
+               // clear trailing elements
+               for i := range a[length:] {
+                       var zero int
+                       a[length+i] = zero
+               }
+       }
+
+       *p = a[0:length]
+       return p
+}
+
+
+// Len returns the number of elements in the vector.
+// Same as len(*p).
+func (p *IntVector) Len() int { return len(*p) }
+
+
+// Cap returns the capacity of the vector; that is, the
+// maximum length the vector can grow without resizing.
+// Same as cap(*p).
+func (p *IntVector) Cap() int { return cap(*p) }
+
+
+// At returns the i'th element of the vector.
+func (p *IntVector) At(i int) int { return (*p)[i] }
+
+
+// Set sets the i'th element of the vector to value x.
+func (p *IntVector) Set(i int, x int) { (*p)[i] = x }
+
+
+// Last returns the element in the vector of highest index.
+func (p *IntVector) Last() int { return (*p)[len(*p)-1] }
+
+
+// Copy makes a copy of the vector and returns it.
+func (p *IntVector) Copy() IntVector {
+       arr := make(IntVector, len(*p))
+       copy(arr, *p)
+       return arr
+}
+
+
+// Insert inserts into the vector an element of value x before
+// the current element at index i.
+func (p *IntVector) Insert(i int, x int) {
+       p.Expand(i, 1)
+       (*p)[i] = x
+}
+
+
+// Delete deletes the i'th element of the vector.  The gap is closed so the old
+// element at index i+1 has index i afterwards.
+func (p *IntVector) Delete(i int) {
+       a := *p
+       n := len(a)
+
+       copy(a[i:n-1], a[i+1:n])
+       var zero int
+       a[n-1] = zero // support GC, zero out entry
+       *p = a[0 : n-1]
+}
+
+
+// InsertVector inserts into the vector the contents of the vector
+// x such that the 0th element of x appears at index i after insertion.
+func (p *IntVector) InsertVector(i int, x *IntVector) {
+       b := *x
+
+       p.Expand(i, len(b))
+       copy((*p)[i:i+len(b)], b)
+}
+
+
+// Cut deletes elements i through j-1, inclusive.
+func (p *IntVector) Cut(i, j int) {
+       a := *p
+       n := len(a)
+       m := n - (j - i)
+
+       copy(a[i:m], a[j:n])
+       for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
+               var zero int
+               a[k] = zero // support GC, zero out entries
+       }
+
+       *p = a[0:m]
+}
+
+
+// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
+// The elements are copied. The original vector is unchanged.
+func (p *IntVector) Slice(i, j int) *IntVector {
+       var s IntVector
+       s.realloc(j-i, 0) // will fail in Init() if j < i
+       copy(s, (*p)[i:j])
+       return &s
+}
+
+
+// Convenience wrappers
+
+// Push appends x to the end of the vector.
+func (p *IntVector) Push(x int) { p.Insert(len(*p), x) }
+
+
+// Pop deletes the last element of the vector.
+func (p *IntVector) Pop() int {
+       a := *p
+
+       i := len(a) - 1
+       x := a[i]
+       var zero int
+       a[i] = zero // support GC, zero out entry
+       *p = a[0:i]
+       return x
+}
+
+
+// AppendVector appends the entire vector x to the end of this vector.
+func (p *IntVector) AppendVector(x *IntVector) { p.InsertVector(len(*p), x) }
+
+
+// Swap exchanges the elements at indexes i and j.
+func (p *IntVector) Swap(i, j int) {
+       a := *p
+       a[i], a[j] = a[j], a[i]
+}
+
+
+// Do calls function f for each element of the vector, in order.
+// The behavior of Do is undefined if f changes *p.
+func (p *IntVector) Do(f func(elem int)) {
+       for _, e := range *p {
+               f(e)
+       }
+}
diff --git a/libgo/go/container/vector/intvector_test.go b/libgo/go/container/vector/intvector_test.go
new file mode 100644 (file)
index 0000000..fcc7403
--- /dev/null
@@ -0,0 +1,344 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector_test.go, it was generated
+// automatically from vector_test.go - DO NOT EDIT in that case!
+
+package vector
+
+import "testing"
+
+
+func TestIntZeroLen(t *testing.T) {
+       a := new(IntVector)
+       if a.Len() != 0 {
+               t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
+       }
+       if len(*a) != 0 {
+               t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
+       }
+       var b IntVector
+       if b.Len() != 0 {
+               t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
+       }
+       if len(b) != 0 {
+               t.Errorf("%T: B4) expected 0, got %d", b, len(b))
+       }
+}
+
+
+func TestIntResize(t *testing.T) {
+       var a IntVector
+       checkSize(t, &a, 0, 0)
+       checkSize(t, a.Resize(0, 5), 0, 5)
+       checkSize(t, a.Resize(1, 0), 1, 5)
+       checkSize(t, a.Resize(10, 0), 10, 10)
+       checkSize(t, a.Resize(5, 0), 5, 10)
+       checkSize(t, a.Resize(3, 8), 3, 10)
+       checkSize(t, a.Resize(0, 100), 0, 100)
+       checkSize(t, a.Resize(11, 100), 11, 100)
+}
+
+
+func TestIntResize2(t *testing.T) {
+       var a IntVector
+       checkSize(t, &a, 0, 0)
+       a.Push(int2IntValue(1))
+       a.Push(int2IntValue(2))
+       a.Push(int2IntValue(3))
+       a.Push(int2IntValue(4))
+       checkSize(t, &a, 4, 4)
+       checkSize(t, a.Resize(10, 0), 10, 10)
+       for i := 4; i < a.Len(); i++ {
+               if a.At(i) != intzero {
+                       t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, intzero, a.At(i))
+               }
+       }
+       for i := 4; i < len(a); i++ {
+               if a[i] != intzero {
+                       t.Errorf("%T: expected a[%d] == %v; found %v", a, i, intzero, a[i])
+               }
+       }
+}
+
+
+func checkIntZero(t *testing.T, a *IntVector, i int) {
+       for j := 0; j < i; j++ {
+               if a.At(j) == intzero {
+                       t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
+               }
+               if (*a)[j] == intzero {
+                       t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
+               }
+       }
+       for ; i < a.Len(); i++ {
+               if a.At(i) != intzero {
+                       t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, intzero, a.At(i))
+               }
+               if (*a)[i] != intzero {
+                       t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, intzero, (*a)[i])
+               }
+       }
+}
+
+
+func TestIntTrailingElements(t *testing.T) {
+       var a IntVector
+       for i := 0; i < 10; i++ {
+               a.Push(int2IntValue(i + 1))
+       }
+       checkIntZero(t, &a, 10)
+       checkSize(t, &a, 10, 16)
+       checkSize(t, a.Resize(5, 0), 5, 16)
+       checkSize(t, a.Resize(10, 0), 10, 16)
+       checkIntZero(t, &a, 5)
+}
+
+
+func TestIntAccess(t *testing.T) {
+       const n = 100
+       var a IntVector
+       a.Resize(n, 0)
+       for i := 0; i < n; i++ {
+               a.Set(i, int2IntValue(val(i)))
+       }
+       for i := 0; i < n; i++ {
+               if elem2IntValue(a.At(i)) != int2IntValue(val(i)) {
+                       t.Error(i)
+               }
+       }
+       var b IntVector
+       b.Resize(n, 0)
+       for i := 0; i < n; i++ {
+               b[i] = int2IntValue(val(i))
+       }
+       for i := 0; i < n; i++ {
+               if elem2IntValue(b[i]) != int2IntValue(val(i)) {
+                       t.Error(i)
+               }
+       }
+}
+
+
+func TestIntInsertDeleteClear(t *testing.T) {
+       const n = 100
+       var a IntVector
+
+       for i := 0; i < n; i++ {
+               if a.Len() != i {
+                       t.Errorf("T%: A) wrong Len() %d (expected %d)", a, a.Len(), i)
+               }
+               if len(a) != i {
+                       t.Errorf("T%: A) wrong len() %d (expected %d)", a, len(a), i)
+               }
+               a.Insert(0, int2IntValue(val(i)))
+               if elem2IntValue(a.Last()) != int2IntValue(val(0)) {
+                       t.Error("T%: B", a)
+               }
+       }
+       for i := n - 1; i >= 0; i-- {
+               if elem2IntValue(a.Last()) != int2IntValue(val(0)) {
+                       t.Error("T%: C", a)
+               }
+               if elem2IntValue(a.At(0)) != int2IntValue(val(i)) {
+                       t.Error("T%: D", a)
+               }
+               if elem2IntValue(a[0]) != int2IntValue(val(i)) {
+                       t.Error("T%: D2", a)
+               }
+               a.Delete(0)
+               if a.Len() != i {
+                       t.Errorf("T%: E) wrong Len() %d (expected %d)", a, a.Len(), i)
+               }
+               if len(a) != i {
+                       t.Errorf("T%: E) wrong len() %d (expected %d)", a, len(a), i)
+               }
+       }
+
+       if a.Len() != 0 {
+               t.Errorf("T%: F) wrong Len() %d (expected 0)", a, a.Len())
+       }
+       if len(a) != 0 {
+               t.Errorf("T%: F) wrong len() %d (expected 0)", a, len(a))
+       }
+       for i := 0; i < n; i++ {
+               a.Push(int2IntValue(val(i)))
+               if a.Len() != i+1 {
+                       t.Errorf("T%: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
+               }
+               if len(a) != i+1 {
+                       t.Errorf("T%: G) wrong len() %d (expected %d)", a, len(a), i+1)
+               }
+               if elem2IntValue(a.Last()) != int2IntValue(val(i)) {
+                       t.Error("T%: H", a)
+               }
+       }
+       a.Resize(0, 0)
+       if a.Len() != 0 {
+               t.Errorf("T%: I wrong Len() %d (expected 0)", a, a.Len())
+       }
+       if len(a) != 0 {
+               t.Errorf("T%: I wrong len() %d (expected 0)", a, len(a))
+       }
+
+       const m = 5
+       for j := 0; j < m; j++ {
+               a.Push(int2IntValue(j))
+               for i := 0; i < n; i++ {
+                       x := val(i)
+                       a.Push(int2IntValue(x))
+                       if elem2IntValue(a.Pop()) != int2IntValue(x) {
+                               t.Error("T%: J", a)
+                       }
+                       if a.Len() != j+1 {
+                               t.Errorf("T%: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
+                       }
+                       if len(a) != j+1 {
+                               t.Errorf("T%: K) wrong len() %d (expected %d)", a, len(a), j+1)
+                       }
+               }
+       }
+       if a.Len() != m {
+               t.Errorf("T%: L) wrong Len() %d (expected %d)", a, a.Len(), m)
+       }
+       if len(a) != m {
+               t.Errorf("T%: L) wrong len() %d (expected %d)", a, len(a), m)
+       }
+}
+
+
+func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) {
+       for k := i; k < j; k++ {
+               if elem2IntValue(x.At(k)) != int2IntValue(elt) {
+                       t.Errorf("T%: M) wrong [%d] element %v (expected %v)", x, k, elem2IntValue(x.At(k)), int2IntValue(elt))
+               }
+       }
+
+       s := x.Slice(i, j)
+       for k, n := 0, j-i; k < n; k++ {
+               if elem2IntValue(s.At(k)) != int2IntValue(elt) {
+                       t.Errorf("T%: N) wrong [%d] element %v (expected %v)", x, k, elem2IntValue(x.At(k)), int2IntValue(elt))
+               }
+       }
+}
+
+
+func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) {
+       n := a + b + c
+       if x.Len() != n {
+               t.Errorf("T%: O) wrong Len() %d (expected %d)", x, x.Len(), n)
+       }
+       if len(*x) != n {
+               t.Errorf("T%: O) wrong len() %d (expected %d)", x, len(*x), n)
+       }
+       verify_sliceInt(t, x, 0, 0, a)
+       verify_sliceInt(t, x, 1, a, a+b)
+       verify_sliceInt(t, x, 0, a+b, n)
+}
+
+
+func make_vectorInt(elt, len int) *IntVector {
+       x := new(IntVector).Resize(len, 0)
+       for i := 0; i < len; i++ {
+               x.Set(i, int2IntValue(elt))
+       }
+       return x
+}
+
+
+func TestIntInsertVector(t *testing.T) {
+       // 1
+       a := make_vectorInt(0, 0)
+       b := make_vectorInt(1, 10)
+       a.InsertVector(0, b)
+       verify_patternInt(t, a, 0, 10, 0)
+       // 2
+       a = make_vectorInt(0, 10)
+       b = make_vectorInt(1, 0)
+       a.InsertVector(5, b)
+       verify_patternInt(t, a, 5, 0, 5)
+       // 3
+       a = make_vectorInt(0, 10)
+       b = make_vectorInt(1, 3)
+       a.InsertVector(3, b)
+       verify_patternInt(t, a, 3, 3, 7)
+       // 4
+       a = make_vectorInt(0, 10)
+       b = make_vectorInt(1, 1000)
+       a.InsertVector(8, b)
+       verify_patternInt(t, a, 8, 1000, 2)
+}
+
+
+func TestIntDo(t *testing.T) {
+       const n = 25
+       const salt = 17
+       a := new(IntVector).Resize(n, 0)
+       for i := 0; i < n; i++ {
+               a.Set(i, int2IntValue(salt*i))
+       }
+       count := 0
+       a.Do(func(e int) {
+               i := intf2IntValue(e)
+               if i != int2IntValue(count*salt) {
+                       t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
+               }
+               count++
+       })
+       if count != n {
+               t.Error(tname(a), "should visit", n, "values; did visit", count)
+       }
+
+       b := new(IntVector).Resize(n, 0)
+       for i := 0; i < n; i++ {
+               (*b)[i] = int2IntValue(salt * i)
+       }
+       count = 0
+       b.Do(func(e int) {
+               i := intf2IntValue(e)
+               if i != int2IntValue(count*salt) {
+                       t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
+               }
+               count++
+       })
+       if count != n {
+               t.Error(tname(b), "b) should visit", n, "values; did visit", count)
+       }
+
+       var c IntVector
+       c.Resize(n, 0)
+       for i := 0; i < n; i++ {
+               c[i] = int2IntValue(salt * i)
+       }
+       count = 0
+       c.Do(func(e int) {
+               i := intf2IntValue(e)
+               if i != int2IntValue(count*salt) {
+                       t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
+               }
+               count++
+       })
+       if count != n {
+               t.Error(tname(c), "c) should visit", n, "values; did visit", count)
+       }
+
+}
+
+
+func TestIntVectorCopy(t *testing.T) {
+       // verify Copy() returns a copy, not simply a slice of the original vector
+       const Len = 10
+       var src IntVector
+       for i := 0; i < Len; i++ {
+               src.Push(int2IntValue(i * i))
+       }
+       dest := src.Copy()
+       for i := 0; i < Len; i++ {
+               src[i] = int2IntValue(-1)
+               v := elem2IntValue(dest[i])
+               if v != int2IntValue(i*i) {
+                       t.Error(tname(src), "expected", i*i, "got", v)
+               }
+       }
+}
diff --git a/libgo/go/container/vector/nogen_test.go b/libgo/go/container/vector/nogen_test.go
new file mode 100644 (file)
index 0000000..790d374
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vector
+
+
+import (
+       "fmt"
+       "sort"
+       "testing"
+)
+
+var (
+       zero    interface{}
+       intzero int
+       strzero string
+)
+
+
+func int2Value(x int) int       { return x }
+func int2IntValue(x int) int    { return x }
+func int2StrValue(x int) string { return string(x) }
+
+
+func elem2Value(x interface{}) int  { return x.(int) }
+func elem2IntValue(x int) int       { return x }
+func elem2StrValue(x string) string { return x }
+
+
+func intf2Value(x interface{}) int       { return x.(int) }
+func intf2IntValue(x interface{}) int    { return x.(int) }
+func intf2StrValue(x interface{}) string { return x.(string) }
+
+
+type VectorInterface interface {
+       Len() int
+       Cap() int
+}
+
+
+func checkSize(t *testing.T, v VectorInterface, len, cap int) {
+       if v.Len() != len {
+               t.Errorf("%T expected len = %d; found %d", v, len, v.Len())
+       }
+       if v.Cap() < cap {
+               t.Errorf("%T expected cap >= %d; found %d", v, cap, v.Cap())
+       }
+}
+
+
+func val(i int) int { return i*991 - 1234 }
+
+
+func TestSorting(t *testing.T) {
+       const n = 100
+
+       a := new(IntVector).Resize(n, 0)
+       for i := n - 1; i >= 0; i-- {
+               a.Set(i, n-1-i)
+       }
+       if sort.IsSorted(a) {
+               t.Error("int vector not sorted")
+       }
+
+       b := new(StringVector).Resize(n, 0)
+       for i := n - 1; i >= 0; i-- {
+               b.Set(i, fmt.Sprint(n-1-i))
+       }
+       if sort.IsSorted(b) {
+               t.Error("string vector not sorted")
+       }
+}
+
+
+func tname(x interface{}) string { return fmt.Sprintf("%T: ", x) }
diff --git a/libgo/go/container/vector/numbers_test.go b/libgo/go/container/vector/numbers_test.go
new file mode 100644 (file)
index 0000000..a44242f
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vector
+
+import (
+       "fmt"
+       "runtime"
+       "strings"
+       "testing"
+)
+
+
+const memTestN = 1000000
+
+
+func s(n uint64) string {
+       str := fmt.Sprintf("%d", n)
+       lens := len(str)
+       a := make([]string, (lens+2)/3)
+       start := lens
+       for i, _ := range a {
+               start -= 3
+               if start < 0 {
+                       start = 0
+               }
+               a[len(a)-i-1] = str[start:lens]
+               lens -= 3
+       }
+       return strings.Join(a, " ")
+}
+
+
+func TestVectorNums(t *testing.T) {
+       var v Vector
+       c := int(0)
+       runtime.GC()
+       m0 := runtime.MemStats
+       v.Resize(memTestN, memTestN)
+       for i := 0; i < memTestN; i++ {
+               v.Set(i, c)
+       }
+       runtime.GC()
+       m := runtime.MemStats
+       v.Resize(0, 0)
+       runtime.GC()
+       n := m.Alloc - m0.Alloc
+       t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float(n)/memTestN)
+}
+
+
+func TestIntVectorNums(t *testing.T) {
+       var v IntVector
+       c := int(0)
+       runtime.GC()
+       m0 := runtime.MemStats
+       v.Resize(memTestN, memTestN)
+       for i := 0; i < memTestN; i++ {
+               v.Set(i, c)
+       }
+       runtime.GC()
+       m := runtime.MemStats
+       v.Resize(0, 0)
+       runtime.GC()
+       n := m.Alloc - m0.Alloc
+       t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float(n)/memTestN)
+}
+
+
+func TestStringVectorNums(t *testing.T) {
+       var v StringVector
+       c := ""
+       runtime.GC()
+       m0 := runtime.MemStats
+       v.Resize(memTestN, memTestN)
+       for i := 0; i < memTestN; i++ {
+               v.Set(i, c)
+       }
+       runtime.GC()
+       m := runtime.MemStats
+       v.Resize(0, 0)
+       runtime.GC()
+       n := m.Alloc - m0.Alloc
+       t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float(n)/memTestN)
+}
+
+
+func BenchmarkVectorNums(b *testing.B) {
+       c := int(0)
+       var v Vector
+       b.StopTimer()
+       runtime.GC()
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               v.Push(c)
+       }
+}
+
+
+func BenchmarkIntVectorNums(b *testing.B) {
+       c := int(0)
+       var v IntVector
+       b.StopTimer()
+       runtime.GC()
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               v.Push(c)
+       }
+}
+
+
+func BenchmarkStringVectorNums(b *testing.B) {
+       c := ""
+       var v StringVector
+       b.StopTimer()
+       runtime.GC()
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               v.Push(c)
+       }
+}
diff --git a/libgo/go/container/vector/stringvector.go b/libgo/go/container/vector/stringvector.go
new file mode 100644 (file)
index 0000000..852685f
--- /dev/null
@@ -0,0 +1,208 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector.go, it was generated
+// automatically from vector.go - DO NOT EDIT in that case!
+
+package vector
+
+
+func (p *StringVector) realloc(length, capacity int) (b []string) {
+       if capacity < initialSize {
+               capacity = initialSize
+       }
+       if capacity < length {
+               capacity = length
+       }
+       b = make(StringVector, length, capacity)
+       copy(b, *p)
+       *p = b
+       return
+}
+
+
+// Insert n elements at position i.
+func (p *StringVector) Expand(i, n int) {
+       a := *p
+
+       // make sure we have enough space
+       len0 := len(a)
+       len1 := len0 + n
+       if len1 <= cap(a) {
+               // enough space - just expand
+               a = a[0:len1]
+       } else {
+               // not enough space - double capacity
+               capb := cap(a) * 2
+               if capb < len1 {
+                       // still not enough - use required length
+                       capb = len1
+               }
+               // capb >= len1
+               a = p.realloc(len1, capb)
+       }
+
+       // make a hole
+       for j := len0 - 1; j >= i; j-- {
+               a[j+n] = a[j]
+       }
+
+       *p = a
+}
+
+
+// Insert n elements at the end of a vector.
+func (p *StringVector) Extend(n int) { p.Expand(len(*p), n) }
+
+
+// Resize changes the length and capacity of a vector.
+// If the new length is shorter than the current length, Resize discards
+// trailing elements. If the new length is longer than the current length,
+// Resize adds the respective zero values for the additional elements. The capacity
+// parameter is ignored unless the new length or capacity is longer than the current
+// capacity. The resized vector's capacity may be larger than the requested capacity.
+func (p *StringVector) Resize(length, capacity int) *StringVector {
+       a := *p
+
+       if length > cap(a) || capacity > cap(a) {
+               // not enough space or larger capacity requested explicitly
+               a = p.realloc(length, capacity)
+       } else if length < len(a) {
+               // clear trailing elements
+               for i := range a[length:] {
+                       var zero string
+                       a[length+i] = zero
+               }
+       }
+
+       *p = a[0:length]
+       return p
+}
+
+
+// Len returns the number of elements in the vector.
+// Same as len(*p).
+func (p *StringVector) Len() int { return len(*p) }
+
+
+// Cap returns the capacity of the vector; that is, the
+// maximum length the vector can grow without resizing.
+// Same as cap(*p).
+func (p *StringVector) Cap() int { return cap(*p) }
+
+
+// At returns the i'th element of the vector.
+func (p *StringVector) At(i int) string { return (*p)[i] }
+
+
+// Set sets the i'th element of the vector to value x.
+func (p *StringVector) Set(i int, x string) { (*p)[i] = x }
+
+
+// Last returns the element in the vector of highest index.
+func (p *StringVector) Last() string { return (*p)[len(*p)-1] }
+
+
+// Copy makes a copy of the vector and returns it.
+func (p *StringVector) Copy() StringVector {
+       arr := make(StringVector, len(*p))
+       copy(arr, *p)
+       return arr
+}
+
+
+// Insert inserts into the vector an element of value x before
+// the current element at index i.
+func (p *StringVector) Insert(i int, x string) {
+       p.Expand(i, 1)
+       (*p)[i] = x
+}
+
+
+// Delete deletes the i'th element of the vector.  The gap is closed so the old
+// element at index i+1 has index i afterwards.
+func (p *StringVector) Delete(i int) {
+       a := *p
+       n := len(a)
+
+       copy(a[i:n-1], a[i+1:n])
+       var zero string
+       a[n-1] = zero // support GC, zero out entry
+       *p = a[0 : n-1]
+}
+
+
+// InsertVector inserts into the vector the contents of the vector
+// x such that the 0th element of x appears at index i after insertion.
+func (p *StringVector) InsertVector(i int, x *StringVector) {
+       b := *x
+
+       p.Expand(i, len(b))
+       copy((*p)[i:i+len(b)], b)
+}
+
+
+// Cut deletes elements i through j-1, inclusive.
+func (p *StringVector) Cut(i, j int) {
+       a := *p
+       n := len(a)
+       m := n - (j - i)
+
+       copy(a[i:m], a[j:n])
+       for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
+               var zero string
+               a[k] = zero // support GC, zero out entries
+       }
+
+       *p = a[0:m]
+}
+
+
+// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
+// The elements are copied. The original vector is unchanged.
+func (p *StringVector) Slice(i, j int) *StringVector {
+       var s StringVector
+       s.realloc(j-i, 0) // will fail in Init() if j < i
+       copy(s, (*p)[i:j])
+       return &s
+}
+
+
+// Convenience wrappers
+
+// Push appends x to the end of the vector.
+func (p *StringVector) Push(x string) { p.Insert(len(*p), x) }
+
+
+// Pop deletes the last element of the vector.
+func (p *StringVector) Pop() string {
+       a := *p
+
+       i := len(a) - 1
+       x := a[i]
+       var zero string
+       a[i] = zero // support GC, zero out entry
+       *p = a[0:i]
+       return x
+}
+
+
+// AppendVector appends the entire vector x to the end of this vector.
+func (p *StringVector) AppendVector(x *StringVector) { p.InsertVector(len(*p), x) }
+
+
+// Swap exchanges the elements at indexes i and j.
+func (p *StringVector) Swap(i, j int) {
+       a := *p
+       a[i], a[j] = a[j], a[i]
+}
+
+
+// Do calls function f for each element of the vector, in order.
+// The behavior of Do is undefined if f changes *p.
+func (p *StringVector) Do(f func(elem string)) {
+       for _, e := range *p {
+               f(e)
+       }
+}
diff --git a/libgo/go/container/vector/stringvector_test.go b/libgo/go/container/vector/stringvector_test.go
new file mode 100644 (file)
index 0000000..2f3f082
--- /dev/null
@@ -0,0 +1,344 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector_test.go, it was generated
+// automatically from vector_test.go - DO NOT EDIT in that case!
+
+package vector
+
+import "testing"
+
+
+func TestStrZeroLen(t *testing.T) {
+       a := new(StringVector)
+       if a.Len() != 0 {
+               t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
+       }
+       if len(*a) != 0 {
+               t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
+       }
+       var b StringVector
+       if b.Len() != 0 {
+               t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
+       }
+       if len(b) != 0 {
+               t.Errorf("%T: B4) expected 0, got %d", b, len(b))
+       }
+}
+
+
+func TestStrResize(t *testing.T) {
+       var a StringVector
+       checkSize(t, &a, 0, 0)
+       checkSize(t, a.Resize(0, 5), 0, 5)
+       checkSize(t, a.Resize(1, 0), 1, 5)
+       checkSize(t, a.Resize(10, 0), 10, 10)
+       checkSize(t, a.Resize(5, 0), 5, 10)
+       checkSize(t, a.Resize(3, 8), 3, 10)
+       checkSize(t, a.Resize(0, 100), 0, 100)
+       checkSize(t, a.Resize(11, 100), 11, 100)
+}
+
+
+func TestStrResize2(t *testing.T) {
+       var a StringVector
+       checkSize(t, &a, 0, 0)
+       a.Push(int2StrValue(1))
+       a.Push(int2StrValue(2))
+       a.Push(int2StrValue(3))
+       a.Push(int2StrValue(4))
+       checkSize(t, &a, 4, 4)
+       checkSize(t, a.Resize(10, 0), 10, 10)
+       for i := 4; i < a.Len(); i++ {
+               if a.At(i) != strzero {
+                       t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, strzero, a.At(i))
+               }
+       }
+       for i := 4; i < len(a); i++ {
+               if a[i] != strzero {
+                       t.Errorf("%T: expected a[%d] == %v; found %v", a, i, strzero, a[i])
+               }
+       }
+}
+
+
+func checkStrZero(t *testing.T, a *StringVector, i int) {
+       for j := 0; j < i; j++ {
+               if a.At(j) == strzero {
+                       t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
+               }
+               if (*a)[j] == strzero {
+                       t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
+               }
+       }
+       for ; i < a.Len(); i++ {
+               if a.At(i) != strzero {
+                       t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, strzero, a.At(i))
+               }
+               if (*a)[i] != strzero {
+                       t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, strzero, (*a)[i])
+               }
+       }
+}
+
+
+func TestStrTrailingElements(t *testing.T) {
+       var a StringVector
+       for i := 0; i < 10; i++ {
+               a.Push(int2StrValue(i + 1))
+       }
+       checkStrZero(t, &a, 10)
+       checkSize(t, &a, 10, 16)
+       checkSize(t, a.Resize(5, 0), 5, 16)
+       checkSize(t, a.Resize(10, 0), 10, 16)
+       checkStrZero(t, &a, 5)
+}
+
+
+func TestStrAccess(t *testing.T) {
+       const n = 100
+       var a StringVector
+       a.Resize(n, 0)
+       for i := 0; i < n; i++ {
+               a.Set(i, int2StrValue(val(i)))
+       }
+       for i := 0; i < n; i++ {
+               if elem2StrValue(a.At(i)) != int2StrValue(val(i)) {
+                       t.Error(i)
+               }
+       }
+       var b StringVector
+       b.Resize(n, 0)
+       for i := 0; i < n; i++ {
+               b[i] = int2StrValue(val(i))
+       }
+       for i := 0; i < n; i++ {
+               if elem2StrValue(b[i]) != int2StrValue(val(i)) {
+                       t.Error(i)
+               }
+       }
+}
+
+
+func TestStrInsertDeleteClear(t *testing.T) {
+       const n = 100
+       var a StringVector
+
+       for i := 0; i < n; i++ {
+               if a.Len() != i {
+                       t.Errorf("T%: A) wrong Len() %d (expected %d)", a, a.Len(), i)
+               }
+               if len(a) != i {
+                       t.Errorf("T%: A) wrong len() %d (expected %d)", a, len(a), i)
+               }
+               a.Insert(0, int2StrValue(val(i)))
+               if elem2StrValue(a.Last()) != int2StrValue(val(0)) {
+                       t.Error("T%: B", a)
+               }
+       }
+       for i := n - 1; i >= 0; i-- {
+               if elem2StrValue(a.Last()) != int2StrValue(val(0)) {
+                       t.Error("T%: C", a)
+               }
+               if elem2StrValue(a.At(0)) != int2StrValue(val(i)) {
+                       t.Error("T%: D", a)
+               }
+               if elem2StrValue(a[0]) != int2StrValue(val(i)) {
+                       t.Error("T%: D2", a)
+               }
+               a.Delete(0)
+               if a.Len() != i {
+                       t.Errorf("T%: E) wrong Len() %d (expected %d)", a, a.Len(), i)
+               }
+               if len(a) != i {
+                       t.Errorf("T%: E) wrong len() %d (expected %d)", a, len(a), i)
+               }
+       }
+
+       if a.Len() != 0 {
+               t.Errorf("T%: F) wrong Len() %d (expected 0)", a, a.Len())
+       }
+       if len(a) != 0 {
+               t.Errorf("T%: F) wrong len() %d (expected 0)", a, len(a))
+       }
+       for i := 0; i < n; i++ {
+               a.Push(int2StrValue(val(i)))
+               if a.Len() != i+1 {
+                       t.Errorf("T%: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
+               }
+               if len(a) != i+1 {
+                       t.Errorf("T%: G) wrong len() %d (expected %d)", a, len(a), i+1)
+               }
+               if elem2StrValue(a.Last()) != int2StrValue(val(i)) {
+                       t.Error("T%: H", a)
+               }
+       }
+       a.Resize(0, 0)
+       if a.Len() != 0 {
+               t.Errorf("T%: I wrong Len() %d (expected 0)", a, a.Len())
+       }
+       if len(a) != 0 {
+               t.Errorf("T%: I wrong len() %d (expected 0)", a, len(a))
+       }
+
+       const m = 5
+       for j := 0; j < m; j++ {
+               a.Push(int2StrValue(j))
+               for i := 0; i < n; i++ {
+                       x := val(i)
+                       a.Push(int2StrValue(x))
+                       if elem2StrValue(a.Pop()) != int2StrValue(x) {
+                               t.Error("T%: J", a)
+                       }
+                       if a.Len() != j+1 {
+                               t.Errorf("T%: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
+                       }
+                       if len(a) != j+1 {
+                               t.Errorf("T%: K) wrong len() %d (expected %d)", a, len(a), j+1)
+                       }
+               }
+       }
+       if a.Len() != m {
+               t.Errorf("T%: L) wrong Len() %d (expected %d)", a, a.Len(), m)
+       }
+       if len(a) != m {
+               t.Errorf("T%: L) wrong len() %d (expected %d)", a, len(a), m)
+       }
+}
+
+
+func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) {
+       for k := i; k < j; k++ {
+               if elem2StrValue(x.At(k)) != int2StrValue(elt) {
+                       t.Errorf("T%: M) wrong [%d] element %v (expected %v)", x, k, elem2StrValue(x.At(k)), int2StrValue(elt))
+               }
+       }
+
+       s := x.Slice(i, j)
+       for k, n := 0, j-i; k < n; k++ {
+               if elem2StrValue(s.At(k)) != int2StrValue(elt) {
+                       t.Errorf("T%: N) wrong [%d] element %v (expected %v)", x, k, elem2StrValue(x.At(k)), int2StrValue(elt))
+               }
+       }
+}
+
+
+func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) {
+       n := a + b + c
+       if x.Len() != n {
+               t.Errorf("T%: O) wrong Len() %d (expected %d)", x, x.Len(), n)
+       }
+       if len(*x) != n {
+               t.Errorf("T%: O) wrong len() %d (expected %d)", x, len(*x), n)
+       }
+       verify_sliceStr(t, x, 0, 0, a)
+       verify_sliceStr(t, x, 1, a, a+b)
+       verify_sliceStr(t, x, 0, a+b, n)
+}
+
+
+func make_vectorStr(elt, len int) *StringVector {
+       x := new(StringVector).Resize(len, 0)
+       for i := 0; i < len; i++ {
+               x.Set(i, int2StrValue(elt))
+       }
+       return x
+}
+
+
+func TestStrInsertVector(t *testing.T) {
+       // 1
+       a := make_vectorStr(0, 0)
+       b := make_vectorStr(1, 10)
+       a.InsertVector(0, b)
+       verify_patternStr(t, a, 0, 10, 0)
+       // 2
+       a = make_vectorStr(0, 10)
+       b = make_vectorStr(1, 0)
+       a.InsertVector(5, b)
+       verify_patternStr(t, a, 5, 0, 5)
+       // 3
+       a = make_vectorStr(0, 10)
+       b = make_vectorStr(1, 3)
+       a.InsertVector(3, b)
+       verify_patternStr(t, a, 3, 3, 7)
+       // 4
+       a = make_vectorStr(0, 10)
+       b = make_vectorStr(1, 1000)
+       a.InsertVector(8, b)
+       verify_patternStr(t, a, 8, 1000, 2)
+}
+
+
+func TestStrDo(t *testing.T) {
+       const n = 25
+       const salt = 17
+       a := new(StringVector).Resize(n, 0)
+       for i := 0; i < n; i++ {
+               a.Set(i, int2StrValue(salt*i))
+       }
+       count := 0
+       a.Do(func(e string) {
+               i := intf2StrValue(e)
+               if i != int2StrValue(count*salt) {
+                       t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
+               }
+               count++
+       })
+       if count != n {
+               t.Error(tname(a), "should visit", n, "values; did visit", count)
+       }
+
+       b := new(StringVector).Resize(n, 0)
+       for i := 0; i < n; i++ {
+               (*b)[i] = int2StrValue(salt * i)
+       }
+       count = 0
+       b.Do(func(e string) {
+               i := intf2StrValue(e)
+               if i != int2StrValue(count*salt) {
+                       t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
+               }
+               count++
+       })
+       if count != n {
+               t.Error(tname(b), "b) should visit", n, "values; did visit", count)
+       }
+
+       var c StringVector
+       c.Resize(n, 0)
+       for i := 0; i < n; i++ {
+               c[i] = int2StrValue(salt * i)
+       }
+       count = 0
+       c.Do(func(e string) {
+               i := intf2StrValue(e)
+               if i != int2StrValue(count*salt) {
+                       t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
+               }
+               count++
+       })
+       if count != n {
+               t.Error(tname(c), "c) should visit", n, "values; did visit", count)
+       }
+
+}
+
+
+func TestStrVectorCopy(t *testing.T) {
+       // verify Copy() returns a copy, not simply a slice of the original vector
+       const Len = 10
+       var src StringVector
+       for i := 0; i < Len; i++ {
+               src.Push(int2StrValue(i * i))
+       }
+       dest := src.Copy()
+       for i := 0; i < Len; i++ {
+               src[i] = int2StrValue(-1)
+               v := elem2StrValue(dest[i])
+               if v != int2StrValue(i*i) {
+                       t.Error(tname(src), "expected", i*i, "got", v)
+               }
+       }
+}
diff --git a/libgo/go/container/vector/vector.go b/libgo/go/container/vector/vector.go
new file mode 100644 (file)
index 0000000..f43e4d2
--- /dev/null
@@ -0,0 +1,208 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector.go, it was generated
+// automatically from vector.go - DO NOT EDIT in that case!
+
+package vector
+
+
+func (p *Vector) realloc(length, capacity int) (b []interface{}) {
+       if capacity < initialSize {
+               capacity = initialSize
+       }
+       if capacity < length {
+               capacity = length
+       }
+       b = make(Vector, length, capacity)
+       copy(b, *p)
+       *p = b
+       return
+}
+
+
+// Insert n elements at position i.
+func (p *Vector) Expand(i, n int) {
+       a := *p
+
+       // make sure we have enough space
+       len0 := len(a)
+       len1 := len0 + n
+       if len1 <= cap(a) {
+               // enough space - just expand
+               a = a[0:len1]
+       } else {
+               // not enough space - double capacity
+               capb := cap(a) * 2
+               if capb < len1 {
+                       // still not enough - use required length
+                       capb = len1
+               }
+               // capb >= len1
+               a = p.realloc(len1, capb)
+       }
+
+       // make a hole
+       for j := len0 - 1; j >= i; j-- {
+               a[j+n] = a[j]
+       }
+
+       *p = a
+}
+
+
+// Insert n elements at the end of a vector.
+func (p *Vector) Extend(n int) { p.Expand(len(*p), n) }
+
+
+// Resize changes the length and capacity of a vector.
+// If the new length is shorter than the current length, Resize discards
+// trailing elements. If the new length is longer than the current length,
+// Resize adds the respective zero values for the additional elements. The capacity
+// parameter is ignored unless the new length or capacity is longer than the current
+// capacity. The resized vector's capacity may be larger than the requested capacity.
+func (p *Vector) Resize(length, capacity int) *Vector {
+       a := *p
+
+       if length > cap(a) || capacity > cap(a) {
+               // not enough space or larger capacity requested explicitly
+               a = p.realloc(length, capacity)
+       } else if length < len(a) {
+               // clear trailing elements
+               for i := range a[length:] {
+                       var zero interface{}
+                       a[length+i] = zero
+               }
+       }
+
+       *p = a[0:length]
+       return p
+}
+
+
+// Len returns the number of elements in the vector.
+// Same as len(*p).
+func (p *Vector) Len() int { return len(*p) }
+
+
+// Cap returns the capacity of the vector; that is, the
+// maximum length the vector can grow without resizing.
+// Same as cap(*p).
+func (p *Vector) Cap() int { return cap(*p) }
+
+
+// At returns the i'th element of the vector.
+func (p *Vector) At(i int) interface{} { return (*p)[i] }
+
+
+// Set sets the i'th element of the vector to value x.
+func (p *Vector) Set(i int, x interface{}) { (*p)[i] = x }
+
+
+// Last returns the element in the vector of highest index.
+func (p *Vector) Last() interface{} { return (*p)[len(*p)-1] }
+
+
+// Copy makes a copy of the vector and returns it.
+func (p *Vector) Copy() Vector {
+       arr := make(Vector, len(*p))
+       copy(arr, *p)
+       return arr
+}
+
+
+// Insert inserts into the vector an element of value x before
+// the current element at index i.
+func (p *Vector) Insert(i int, x interface{}) {
+       p.Expand(i, 1)
+       (*p)[i] = x
+}
+
+
+// Delete deletes the i'th element of the vector.  The gap is closed so the old
+// element at index i+1 has index i afterwards.
+func (p *Vector) Delete(i int) {
+       a := *p
+       n := len(a)
+
+       copy(a[i:n-1], a[i+1:n])
+       var zero interface{}
+       a[n-1] = zero // support GC, zero out entry
+       *p = a[0 : n-1]
+}
+
+
+// InsertVector inserts into the vector the contents of the vector
+// x such that the 0th element of x appears at index i after insertion.
+func (p *Vector) InsertVector(i int, x *Vector) {
+       b := *x
+
+       p.Expand(i, len(b))
+       copy((*p)[i:i+len(b)], b)
+}
+
+
+// Cut deletes elements i through j-1, inclusive.
+func (p *Vector) Cut(i, j int) {
+       a := *p
+       n := len(a)
+       m := n - (j - i)
+
+       copy(a[i:m], a[j:n])
+       for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
+               var zero interface{}
+               a[k] = zero // support GC, zero out entries
+       }
+
+       *p = a[0:m]
+}
+
+
+// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
+// The elements are copied. The original vector is unchanged.
+func (p *Vector) Slice(i, j int) *Vector {
+       var s Vector
+       s.realloc(j-i, 0) // will fail in Init() if j < i
+       copy(s, (*p)[i:j])
+       return &s
+}
+
+
+// Convenience wrappers
+
+// Push appends x to the end of the vector.
+func (p *Vector) Push(x interface{}) { p.Insert(len(*p), x) }
+
+
+// Pop deletes the last element of the vector.
+func (p *Vector) Pop() interface{} {
+       a := *p
+
+       i := len(a) - 1
+       x := a[i]
+       var zero interface{}
+       a[i] = zero // support GC, zero out entry
+       *p = a[0:i]
+       return x
+}
+
+
+// AppendVector appends the entire vector x to the end of this vector.
+func (p *Vector) AppendVector(x *Vector) { p.InsertVector(len(*p), x) }
+
+
+// Swap exchanges the elements at indexes i and j.
+func (p *Vector) Swap(i, j int) {
+       a := *p
+       a[i], a[j] = a[j], a[i]
+}
+
+
+// Do calls function f for each element of the vector, in order.
+// The behavior of Do is undefined if f changes *p.
+func (p *Vector) Do(f func(elem interface{})) {
+       for _, e := range *p {
+               f(e)
+       }
+}
diff --git a/libgo/go/container/vector/vector_test.go b/libgo/go/container/vector/vector_test.go
new file mode 100644 (file)
index 0000000..986dff2
--- /dev/null
@@ -0,0 +1,344 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector_test.go, it was generated
+// automatically from vector_test.go - DO NOT EDIT in that case!
+
+package vector
+
+import "testing"
+
+
+func TestZeroLen(t *testing.T) {
+       a := new(Vector)
+       if a.Len() != 0 {
+               t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
+       }
+       if len(*a) != 0 {
+               t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
+       }
+       var b Vector
+       if b.Len() != 0 {
+               t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
+       }
+       if len(b) != 0 {
+               t.Errorf("%T: B4) expected 0, got %d", b, len(b))
+       }
+}
+
+
+func TestResize(t *testing.T) {
+       var a Vector
+       checkSize(t, &a, 0, 0)
+       checkSize(t, a.Resize(0, 5), 0, 5)
+       checkSize(t, a.Resize(1, 0), 1, 5)
+       checkSize(t, a.Resize(10, 0), 10, 10)
+       checkSize(t, a.Resize(5, 0), 5, 10)
+       checkSize(t, a.Resize(3, 8), 3, 10)
+       checkSize(t, a.Resize(0, 100), 0, 100)
+       checkSize(t, a.Resize(11, 100), 11, 100)
+}
+
+
+func TestResize2(t *testing.T) {
+       var a Vector
+       checkSize(t, &a, 0, 0)
+       a.Push(int2Value(1))
+       a.Push(int2Value(2))
+       a.Push(int2Value(3))
+       a.Push(int2Value(4))
+       checkSize(t, &a, 4, 4)
+       checkSize(t, a.Resize(10, 0), 10, 10)
+       for i := 4; i < a.Len(); i++ {
+               if a.At(i) != zero {
+                       t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, zero, a.At(i))
+               }
+       }
+       for i := 4; i < len(a); i++ {
+               if a[i] != zero {
+                       t.Errorf("%T: expected a[%d] == %v; found %v", a, i, zero, a[i])
+               }
+       }
+}
+
+
+func checkZero(t *testing.T, a *Vector, i int) {
+       for j := 0; j < i; j++ {
+               if a.At(j) == zero {
+                       t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
+               }
+               if (*a)[j] == zero {
+                       t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
+               }
+       }
+       for ; i < a.Len(); i++ {
+               if a.At(i) != zero {
+                       t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, zero, a.At(i))
+               }
+               if (*a)[i] != zero {
+                       t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, zero, (*a)[i])
+               }
+       }
+}
+
+
+func TestTrailingElements(t *testing.T) {
+       var a Vector
+       for i := 0; i < 10; i++ {
+               a.Push(int2Value(i + 1))
+       }
+       checkZero(t, &a, 10)
+       checkSize(t, &a, 10, 16)
+       checkSize(t, a.Resize(5, 0), 5, 16)
+       checkSize(t, a.Resize(10, 0), 10, 16)
+       checkZero(t, &a, 5)
+}
+
+
+func TestAccess(t *testing.T) {
+       const n = 100
+       var a Vector
+       a.Resize(n, 0)
+       for i := 0; i < n; i++ {
+               a.Set(i, int2Value(val(i)))
+       }
+       for i := 0; i < n; i++ {
+               if elem2Value(a.At(i)) != int2Value(val(i)) {
+                       t.Error(i)
+               }
+       }
+       var b Vector
+       b.Resize(n, 0)
+       for i := 0; i < n; i++ {
+               b[i] = int2Value(val(i))
+       }
+       for i := 0; i < n; i++ {
+               if elem2Value(b[i]) != int2Value(val(i)) {
+                       t.Error(i)
+               }
+       }
+}
+
+
+func TestInsertDeleteClear(t *testing.T) {
+       const n = 100
+       var a Vector
+
+       for i := 0; i < n; i++ {
+               if a.Len() != i {
+                       t.Errorf("T%: A) wrong Len() %d (expected %d)", a, a.Len(), i)
+               }
+               if len(a) != i {
+                       t.Errorf("T%: A) wrong len() %d (expected %d)", a, len(a), i)
+               }
+               a.Insert(0, int2Value(val(i)))
+               if elem2Value(a.Last()) != int2Value(val(0)) {
+                       t.Error("T%: B", a)
+               }
+       }
+       for i := n - 1; i >= 0; i-- {
+               if elem2Value(a.Last()) != int2Value(val(0)) {
+                       t.Error("T%: C", a)
+               }
+               if elem2Value(a.At(0)) != int2Value(val(i)) {
+                       t.Error("T%: D", a)
+               }
+               if elem2Value(a[0]) != int2Value(val(i)) {
+                       t.Error("T%: D2", a)
+               }
+               a.Delete(0)
+               if a.Len() != i {
+                       t.Errorf("T%: E) wrong Len() %d (expected %d)", a, a.Len(), i)
+               }
+               if len(a) != i {
+                       t.Errorf("T%: E) wrong len() %d (expected %d)", a, len(a), i)
+               }
+       }
+
+       if a.Len() != 0 {
+               t.Errorf("T%: F) wrong Len() %d (expected 0)", a, a.Len())
+       }
+       if len(a) != 0 {
+               t.Errorf("T%: F) wrong len() %d (expected 0)", a, len(a))
+       }
+       for i := 0; i < n; i++ {
+               a.Push(int2Value(val(i)))
+               if a.Len() != i+1 {
+                       t.Errorf("T%: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
+               }
+               if len(a) != i+1 {
+                       t.Errorf("T%: G) wrong len() %d (expected %d)", a, len(a), i+1)
+               }
+               if elem2Value(a.Last()) != int2Value(val(i)) {
+                       t.Error("T%: H", a)
+               }
+       }
+       a.Resize(0, 0)
+       if a.Len() != 0 {
+               t.Errorf("T%: I wrong Len() %d (expected 0)", a, a.Len())
+       }
+       if len(a) != 0 {
+               t.Errorf("T%: I wrong len() %d (expected 0)", a, len(a))
+       }
+
+       const m = 5
+       for j := 0; j < m; j++ {
+               a.Push(int2Value(j))
+               for i := 0; i < n; i++ {
+                       x := val(i)
+                       a.Push(int2Value(x))
+                       if elem2Value(a.Pop()) != int2Value(x) {
+                               t.Error("T%: J", a)
+                       }
+                       if a.Len() != j+1 {
+                               t.Errorf("T%: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
+                       }
+                       if len(a) != j+1 {
+                               t.Errorf("T%: K) wrong len() %d (expected %d)", a, len(a), j+1)
+                       }
+               }
+       }
+       if a.Len() != m {
+               t.Errorf("T%: L) wrong Len() %d (expected %d)", a, a.Len(), m)
+       }
+       if len(a) != m {
+               t.Errorf("T%: L) wrong len() %d (expected %d)", a, len(a), m)
+       }
+}
+
+
+func verify_slice(t *testing.T, x *Vector, elt, i, j int) {
+       for k := i; k < j; k++ {
+               if elem2Value(x.At(k)) != int2Value(elt) {
+                       t.Errorf("T%: M) wrong [%d] element %v (expected %v)", x, k, elem2Value(x.At(k)), int2Value(elt))
+               }
+       }
+
+       s := x.Slice(i, j)
+       for k, n := 0, j-i; k < n; k++ {
+               if elem2Value(s.At(k)) != int2Value(elt) {
+                       t.Errorf("T%: N) wrong [%d] element %v (expected %v)", x, k, elem2Value(x.At(k)), int2Value(elt))
+               }
+       }
+}
+
+
+func verify_pattern(t *testing.T, x *Vector, a, b, c int) {
+       n := a + b + c
+       if x.Len() != n {
+               t.Errorf("T%: O) wrong Len() %d (expected %d)", x, x.Len(), n)
+       }
+       if len(*x) != n {
+               t.Errorf("T%: O) wrong len() %d (expected %d)", x, len(*x), n)
+       }
+       verify_slice(t, x, 0, 0, a)
+       verify_slice(t, x, 1, a, a+b)
+       verify_slice(t, x, 0, a+b, n)
+}
+
+
+func make_vector(elt, len int) *Vector {
+       x := new(Vector).Resize(len, 0)
+       for i := 0; i < len; i++ {
+               x.Set(i, int2Value(elt))
+       }
+       return x
+}
+
+
+func TestInsertVector(t *testing.T) {
+       // 1
+       a := make_vector(0, 0)
+       b := make_vector(1, 10)
+       a.InsertVector(0, b)
+       verify_pattern(t, a, 0, 10, 0)
+       // 2
+       a = make_vector(0, 10)
+       b = make_vector(1, 0)
+       a.InsertVector(5, b)
+       verify_pattern(t, a, 5, 0, 5)
+       // 3
+       a = make_vector(0, 10)
+       b = make_vector(1, 3)
+       a.InsertVector(3, b)
+       verify_pattern(t, a, 3, 3, 7)
+       // 4
+       a = make_vector(0, 10)
+       b = make_vector(1, 1000)
+       a.InsertVector(8, b)
+       verify_pattern(t, a, 8, 1000, 2)
+}
+
+
+func TestDo(t *testing.T) {
+       const n = 25
+       const salt = 17
+       a := new(Vector).Resize(n, 0)
+       for i := 0; i < n; i++ {
+               a.Set(i, int2Value(salt*i))
+       }
+       count := 0
+       a.Do(func(e interface{}) {
+               i := intf2Value(e)
+               if i != int2Value(count*salt) {
+                       t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
+               }
+               count++
+       })
+       if count != n {
+               t.Error(tname(a), "should visit", n, "values; did visit", count)
+       }
+
+       b := new(Vector).Resize(n, 0)
+       for i := 0; i < n; i++ {
+               (*b)[i] = int2Value(salt * i)
+       }
+       count = 0
+       b.Do(func(e interface{}) {
+               i := intf2Value(e)
+               if i != int2Value(count*salt) {
+                       t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
+               }
+               count++
+       })
+       if count != n {
+               t.Error(tname(b), "b) should visit", n, "values; did visit", count)
+       }
+
+       var c Vector
+       c.Resize(n, 0)
+       for i := 0; i < n; i++ {
+               c[i] = int2Value(salt * i)
+       }
+       count = 0
+       c.Do(func(e interface{}) {
+               i := intf2Value(e)
+               if i != int2Value(count*salt) {
+                       t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
+               }
+               count++
+       })
+       if count != n {
+               t.Error(tname(c), "c) should visit", n, "values; did visit", count)
+       }
+
+}
+
+
+func TestVectorCopy(t *testing.T) {
+       // verify Copy() returns a copy, not simply a slice of the original vector
+       const Len = 10
+       var src Vector
+       for i := 0; i < Len; i++ {
+               src.Push(int2Value(i * i))
+       }
+       dest := src.Copy()
+       for i := 0; i < Len; i++ {
+               src[i] = int2Value(-1)
+               v := elem2Value(dest[i])
+               if v != int2Value(i*i) {
+                       t.Error(tname(src), "expected", i*i, "got", v)
+               }
+       }
+}
diff --git a/libgo/go/crypto/aes/aes_test.go b/libgo/go/crypto/aes/aes_test.go
new file mode 100644 (file)
index 0000000..2136d44
--- /dev/null
@@ -0,0 +1,350 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+       "testing"
+)
+
+// See const.go for overview of math here.
+
+// Test that powx is initialized correctly.
+// (Can adapt this code to generate it too.)
+func TestPowx(t *testing.T) {
+       p := 1
+       for i := 0; i < len(powx); i++ {
+               if powx[i] != byte(p) {
+                       t.Errorf("powx[%d] = %#x, want %#x", i, powx[i], p)
+               }
+               p <<= 1
+               if p&0x100 != 0 {
+                       p ^= poly
+               }
+       }
+}
+
+// Multiply b and c as GF(2) polynomials modulo poly
+func mul(b, c uint32) uint32 {
+       i := b
+       j := c
+       s := uint32(0)
+       for k := uint32(1); k < 0x100 && j != 0; k <<= 1 {
+               // Invariant: k == 1<<n, i == b * xⁿ
+
+               if j&k != 0 {
+                       // s += i in GF(2); xor in binary
+                       s ^= i
+                       j ^= k // turn off bit to end loop early
+               }
+
+               // i *= x in GF(2) modulo the polynomial
+               i <<= 1
+               if i&0x100 != 0 {
+                       i ^= poly
+               }
+       }
+       return s
+}
+
+// Test all mul inputs against bit-by-bit n² algorithm.
+func TestMul(t *testing.T) {
+       for i := uint32(0); i < 256; i++ {
+               for j := uint32(0); j < 256; j++ {
+                       // Multiply i, j bit by bit.
+                       s := uint8(0)
+                       for k := uint(0); k < 8; k++ {
+                               for l := uint(0); l < 8; l++ {
+                                       if i&(1<<k) != 0 && j&(1<<l) != 0 {
+                                               s ^= powx[k+l]
+                                       }
+                               }
+                       }
+                       if x := mul(i, j); x != uint32(s) {
+                               t.Fatalf("mul(%#x, %#x) = %#x, want %#x", i, j, x, s)
+                       }
+               }
+       }
+}
+
+// Check that S-boxes are inverses of each other.
+// They have more structure that we could test,
+// but if this sanity check passes, we'll assume
+// the cut and paste from the FIPS PDF worked.
+func TestSboxes(t *testing.T) {
+       for i := 0; i < 256; i++ {
+               if j := sbox0[sbox1[i]]; j != byte(i) {
+                       t.Errorf("sbox0[sbox1[%#x]] = %#x", i, j)
+               }
+               if j := sbox1[sbox0[i]]; j != byte(i) {
+                       t.Errorf("sbox1[sbox0[%#x]] = %#x", i, j)
+               }
+       }
+}
+
+// Test that encryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTe(t *testing.T) {
+       for i := 0; i < 256; i++ {
+               s := uint32(sbox0[i])
+               s2 := mul(s, 2)
+               s3 := mul(s, 3)
+               w := s2<<24 | s<<16 | s<<8 | s3
+               for j := 0; j < 4; j++ {
+                       if x := te[j][i]; x != w {
+                               t.Fatalf("te[%d][%d] = %#x, want %#x", j, i, x, w)
+                       }
+                       w = w<<24 | w>>8
+               }
+       }
+}
+
+// Test that decryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTd(t *testing.T) {
+       for i := 0; i < 256; i++ {
+               s := uint32(sbox1[i])
+               s9 := mul(s, 0x9)
+               sb := mul(s, 0xb)
+               sd := mul(s, 0xd)
+               se := mul(s, 0xe)
+               w := se<<24 | s9<<16 | sd<<8 | sb
+               for j := 0; j < 4; j++ {
+                       if x := td[j][i]; x != w {
+                               t.Fatalf("td[%d][%d] = %#x, want %#x", j, i, x, w)
+                       }
+                       w = w<<24 | w>>8
+               }
+       }
+}
+
+// Test vectors are from FIPS 197:
+//     http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+// Appendix A of FIPS 197: Key expansion examples
+type KeyTest struct {
+       key []byte
+       enc []uint32
+       dec []uint32 // decryption expansion; not in FIPS 197, computed from C implementation.
+}
+
+var keyTests = []KeyTest{
+       {
+               // A.1.  Expansion of a 128-bit Cipher Key
+               []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
+               []uint32{
+                       0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c,
+                       0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605,
+                       0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f,
+                       0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b,
+                       0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00,
+                       0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc,
+                       0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd,
+                       0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f,
+                       0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f,
+                       0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e,
+                       0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
+               },
+               []uint32{
+                       0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
+                       0xc7b5a63, 0x1319eafe, 0xb0398890, 0x664cfbb4,
+                       0xdf7d925a, 0x1f62b09d, 0xa320626e, 0xd6757324,
+                       0x12c07647, 0xc01f22c7, 0xbc42d2f3, 0x7555114a,
+                       0x6efcd876, 0xd2df5480, 0x7c5df034, 0xc917c3b9,
+                       0x6ea30afc, 0xbc238cf6, 0xae82a4b4, 0xb54a338d,
+                       0x90884413, 0xd280860a, 0x12a12842, 0x1bc89739,
+                       0x7c1f13f7, 0x4208c219, 0xc021ae48, 0x969bf7b,
+                       0xcc7505eb, 0x3e17d1ee, 0x82296c51, 0xc9481133,
+                       0x2b3708a7, 0xf262d405, 0xbc3ebdbf, 0x4b617d62,
+                       0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x9cf4f3c,
+               },
+       },
+       {
+               // A.2.  Expansion of a 192-bit Cipher Key
+               []byte{
+                       0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+                       0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+               },
+               []uint32{
+                       0x8e73b0f7, 0xda0e6452, 0xc810f32b, 0x809079e5,
+                       0x62f8ead2, 0x522c6b7b, 0xfe0c91f7, 0x2402f5a5,
+                       0xec12068e, 0x6c827f6b, 0x0e7a95b9, 0x5c56fec2,
+                       0x4db7b4bd, 0x69b54118, 0x85a74796, 0xe92538fd,
+                       0xe75fad44, 0xbb095386, 0x485af057, 0x21efb14f,
+                       0xa448f6d9, 0x4d6dce24, 0xaa326360, 0x113b30e6,
+                       0xa25e7ed5, 0x83b1cf9a, 0x27f93943, 0x6a94f767,
+                       0xc0a69407, 0xd19da4e1, 0xec1786eb, 0x6fa64971,
+                       0x485f7032, 0x22cb8755, 0xe26d1352, 0x33f0b7b3,
+                       0x40beeb28, 0x2f18a259, 0x6747d26b, 0x458c553e,
+                       0xa7e1466c, 0x9411f1df, 0x821f750a, 0xad07d753,
+                       0xca400538, 0x8fcc5006, 0x282d166a, 0xbc3ce7b5,
+                       0xe98ba06f, 0x448c773c, 0x8ecc7204, 0x01002202,
+               },
+               nil,
+       },
+       {
+               // A.3.  Expansion of a 256-bit Cipher Key
+               []byte{
+                       0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+                       0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+               },
+               []uint32{
+                       0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781,
+                       0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4,
+                       0x9ba35411, 0x8e6925af, 0xa51a8b5f, 0x2067fcde,
+                       0xa8b09c1a, 0x93d194cd, 0xbe49846e, 0xb75d5b9a,
+                       0xd59aecb8, 0x5bf3c917, 0xfee94248, 0xde8ebe96,
+                       0xb5a9328a, 0x2678a647, 0x98312229, 0x2f6c79b3,
+                       0x812c81ad, 0xdadf48ba, 0x24360af2, 0xfab8b464,
+                       0x98c5bfc9, 0xbebd198e, 0x268c3ba7, 0x09e04214,
+                       0x68007bac, 0xb2df3316, 0x96e939e4, 0x6c518d80,
+                       0xc814e204, 0x76a9fb8a, 0x5025c02d, 0x59c58239,
+                       0xde136967, 0x6ccc5a71, 0xfa256395, 0x9674ee15,
+                       0x5886ca5d, 0x2e2f31d7, 0x7e0af1fa, 0x27cf73c3,
+                       0x749c47ab, 0x18501dda, 0xe2757e4f, 0x7401905a,
+                       0xcafaaae3, 0xe4d59b34, 0x9adf6ace, 0xbd10190d,
+                       0xfe4890d1, 0xe6188d0b, 0x046df344, 0x706c631e,
+               },
+               nil,
+       },
+}
+
+// Test key expansion against FIPS 197 examples.
+func TestExpandKey(t *testing.T) {
+L:
+       for i, tt := range keyTests {
+               enc := make([]uint32, len(tt.enc))
+               var dec []uint32
+               if tt.dec != nil {
+                       dec = make([]uint32, len(tt.dec))
+               }
+               expandKey(tt.key, enc, dec)
+               for j, v := range enc {
+                       if v != tt.enc[j] {
+                               t.Errorf("key %d: enc[%d] = %#x, want %#x", i, j, v, tt.enc[j])
+                               continue L
+                       }
+               }
+               if dec != nil {
+                       for j, v := range dec {
+                               if v != tt.dec[j] {
+                                       t.Errorf("key %d: dec[%d] = %#x, want %#x", i, j, v, tt.dec[j])
+                                       continue L
+                               }
+                       }
+               }
+       }
+}
+
+// Appendix B, C of FIPS 197: Cipher examples, Example vectors.
+type CryptTest struct {
+       key []byte
+       in  []byte
+       out []byte
+}
+
+var encryptTests = []CryptTest{
+       {
+               // Appendix B.
+               []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
+               []byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
+               []byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
+       },
+       {
+               // Appendix C.1.  AES-128
+               []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+               []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+               []byte{0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a},
+       },
+       {
+               // Appendix C.2.  AES-192
+               []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+               },
+               []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+               []byte{0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91},
+       },
+       {
+               // Appendix C.3.  AES-256
+               []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+               },
+               []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+               []byte{0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89},
+       },
+}
+
+// Test encryptBlock against FIPS 197 examples.
+func TestEncryptBlock(t *testing.T) {
+       for i, tt := range encryptTests {
+               n := len(tt.key) + 28
+               enc := make([]uint32, n)
+               dec := make([]uint32, n)
+               expandKey(tt.key, enc, dec)
+               out := make([]byte, len(tt.in))
+               encryptBlock(enc, out, tt.in)
+               for j, v := range out {
+                       if v != tt.out[j] {
+                               t.Errorf("encryptBlock %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
+                               break
+                       }
+               }
+       }
+}
+
+// Test decryptBlock against FIPS 197 examples.
+func TestDecryptBlock(t *testing.T) {
+       for i, tt := range encryptTests {
+               n := len(tt.key) + 28
+               enc := make([]uint32, n)
+               dec := make([]uint32, n)
+               expandKey(tt.key, enc, dec)
+               plain := make([]byte, len(tt.in))
+               decryptBlock(dec, plain, tt.out)
+               for j, v := range plain {
+                       if v != tt.in[j] {
+                               t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
+                               break
+                       }
+               }
+       }
+}
+
+// Test Cipher Encrypt method against FIPS 197 examples.
+func TestCipherEncrypt(t *testing.T) {
+       for i, tt := range encryptTests {
+               c, err := NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+                       continue
+               }
+               out := make([]byte, len(tt.in))
+               c.Encrypt(out, tt.in)
+               for j, v := range out {
+                       if v != tt.out[j] {
+                               t.Errorf("Cipher.Encrypt %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
+                               break
+                       }
+               }
+       }
+}
+
+// Test Cipher Decrypt against FIPS 197 examples.
+func TestCipherDecrypt(t *testing.T) {
+       for i, tt := range encryptTests {
+               c, err := NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+                       continue
+               }
+               plain := make([]byte, len(tt.in))
+               c.Decrypt(plain, tt.out)
+               for j, v := range plain {
+                       if v != tt.in[j] {
+                               t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
+                               break
+                       }
+               }
+       }
+}
diff --git a/libgo/go/crypto/aes/block.go b/libgo/go/crypto/aes/block.go
new file mode 100644 (file)
index 0000000..130cd01
--- /dev/null
@@ -0,0 +1,176 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This Go implementation is derived in part from the reference
+// ANSI C implementation, which carries the following notice:
+//
+//     rijndael-alg-fst.c
+//
+//     @version 3.0 (December 2000)
+//
+//     Optimised ANSI C code for the Rijndael cipher (now AES)
+//
+//     @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+//     @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+//     @author Paulo Barreto <paulo.barreto@terra.com.br>
+//
+//     This code is hereby placed in the public domain.
+//
+//     THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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.
+//
+// See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission
+// for implementation details.
+//     http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+//     http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf
+
+package aes
+
+// Encrypt one block from src into dst, using the expanded key xk.
+func encryptBlock(xk []uint32, dst, src []byte) {
+       var s0, s1, s2, s3, t0, t1, t2, t3 uint32
+
+       s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+       s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+       s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11])
+       s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15])
+
+       // First round just XORs input with key.
+       s0 ^= xk[0]
+       s1 ^= xk[1]
+       s2 ^= xk[2]
+       s3 ^= xk[3]
+
+       // Middle rounds shuffle using tables.
+       // Number of rounds is set by length of expanded key.
+       nr := len(xk)/4 - 2 // - 2: one above, one more below
+       k := 4
+       for r := 0; r < nr; r++ {
+               t0 = xk[k+0] ^ te[0][s0>>24] ^ te[1][s1>>16&0xff] ^ te[2][s2>>8&0xff] ^ te[3][s3&0xff]
+               t1 = xk[k+1] ^ te[0][s1>>24] ^ te[1][s2>>16&0xff] ^ te[2][s3>>8&0xff] ^ te[3][s0&0xff]
+               t2 = xk[k+2] ^ te[0][s2>>24] ^ te[1][s3>>16&0xff] ^ te[2][s0>>8&0xff] ^ te[3][s1&0xff]
+               t3 = xk[k+3] ^ te[0][s3>>24] ^ te[1][s0>>16&0xff] ^ te[2][s1>>8&0xff] ^ te[3][s2&0xff]
+               k += 4
+               s0, s1, s2, s3 = t0, t1, t2, t3
+       }
+
+       // Last round uses s-box directly and XORs to produce output.
+       s0 = uint32(sbox0[t0>>24])<<24 | uint32(sbox0[t1>>16&0xff])<<16 | uint32(sbox0[t2>>8&0xff])<<8 | uint32(sbox0[t3&0xff])
+       s1 = uint32(sbox0[t1>>24])<<24 | uint32(sbox0[t2>>16&0xff])<<16 | uint32(sbox0[t3>>8&0xff])<<8 | uint32(sbox0[t0&0xff])
+       s2 = uint32(sbox0[t2>>24])<<24 | uint32(sbox0[t3>>16&0xff])<<16 | uint32(sbox0[t0>>8&0xff])<<8 | uint32(sbox0[t1&0xff])
+       s3 = uint32(sbox0[t3>>24])<<24 | uint32(sbox0[t0>>16&0xff])<<16 | uint32(sbox0[t1>>8&0xff])<<8 | uint32(sbox0[t2&0xff])
+
+       s0 ^= xk[k+0]
+       s1 ^= xk[k+1]
+       s2 ^= xk[k+2]
+       s3 ^= xk[k+3]
+
+       dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0)
+       dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1)
+       dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2)
+       dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3)
+}
+
+// Decrypt one block from src into dst, using the expanded key xk.
+func decryptBlock(xk []uint32, dst, src []byte) {
+       var s0, s1, s2, s3, t0, t1, t2, t3 uint32
+
+       s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+       s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+       s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11])
+       s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15])
+
+       // First round just XORs input with key.
+       s0 ^= xk[0]
+       s1 ^= xk[1]
+       s2 ^= xk[2]
+       s3 ^= xk[3]
+
+       // Middle rounds shuffle using tables.
+       // Number of rounds is set by length of expanded key.
+       nr := len(xk)/4 - 2 // - 2: one above, one more below
+       k := 4
+       for r := 0; r < nr; r++ {
+               t0 = xk[k+0] ^ td[0][s0>>24] ^ td[1][s3>>16&0xff] ^ td[2][s2>>8&0xff] ^ td[3][s1&0xff]
+               t1 = xk[k+1] ^ td[0][s1>>24] ^ td[1][s0>>16&0xff] ^ td[2][s3>>8&0xff] ^ td[3][s2&0xff]
+               t2 = xk[k+2] ^ td[0][s2>>24] ^ td[1][s1>>16&0xff] ^ td[2][s0>>8&0xff] ^ td[3][s3&0xff]
+               t3 = xk[k+3] ^ td[0][s3>>24] ^ td[1][s2>>16&0xff] ^ td[2][s1>>8&0xff] ^ td[3][s0&0xff]
+               k += 4
+               s0, s1, s2, s3 = t0, t1, t2, t3
+       }
+
+       // Last round uses s-box directly and XORs to produce output.
+       s0 = uint32(sbox1[t0>>24])<<24 | uint32(sbox1[t3>>16&0xff])<<16 | uint32(sbox1[t2>>8&0xff])<<8 | uint32(sbox1[t1&0xff])
+       s1 = uint32(sbox1[t1>>24])<<24 | uint32(sbox1[t0>>16&0xff])<<16 | uint32(sbox1[t3>>8&0xff])<<8 | uint32(sbox1[t2&0xff])
+       s2 = uint32(sbox1[t2>>24])<<24 | uint32(sbox1[t1>>16&0xff])<<16 | uint32(sbox1[t0>>8&0xff])<<8 | uint32(sbox1[t3&0xff])
+       s3 = uint32(sbox1[t3>>24])<<24 | uint32(sbox1[t2>>16&0xff])<<16 | uint32(sbox1[t1>>8&0xff])<<8 | uint32(sbox1[t0&0xff])
+
+       s0 ^= xk[k+0]
+       s1 ^= xk[k+1]
+       s2 ^= xk[k+2]
+       s3 ^= xk[k+3]
+
+       dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0)
+       dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1)
+       dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2)
+       dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3)
+}
+
+// Apply sbox0 to each byte in w.
+func subw(w uint32) uint32 {
+       return uint32(sbox0[w>>24])<<24 |
+               uint32(sbox0[w>>16&0xff])<<16 |
+               uint32(sbox0[w>>8&0xff])<<8 |
+               uint32(sbox0[w&0xff])
+}
+
+// Rotate
+func rotw(w uint32) uint32 { return w<<8 | w>>24 }
+
+// Key expansion algorithm.  See FIPS-197, Figure 11.
+// Their rcon[i] is our powx[i-1] << 24.
+func expandKey(key []byte, enc, dec []uint32) {
+       // Encryption key setup.
+       var i int
+       nk := len(key) / 4
+       for i = 0; i < nk; i++ {
+               enc[i] = uint32(key[4*i])<<24 | uint32(key[4*i+1])<<16 | uint32(key[4*i+2])<<8 | uint32(key[4*i+3])
+       }
+       for ; i < len(enc); i++ {
+               t := enc[i-1]
+               if i%nk == 0 {
+                       t = subw(rotw(t)) ^ (uint32(powx[i/nk-1]) << 24)
+               } else if nk > 6 && i%nk == 4 {
+                       t = subw(t)
+               }
+               enc[i] = enc[i-nk] ^ t
+       }
+
+       // Derive decryption key from encryption key.
+       // Reverse the 4-word round key sets from enc to produce dec.
+       // All sets but the first and last get the MixColumn transform applied.
+       if dec == nil {
+               return
+       }
+       n := len(enc)
+       for i := 0; i < n; i += 4 {
+               ei := n - i - 4
+               for j := 0; j < 4; j++ {
+                       x := enc[ei+j]
+                       if i > 0 && i+4 < n {
+                               x = td[0][sbox0[x>>24]] ^ td[1][sbox0[x>>16&0xff]] ^ td[2][sbox0[x>>8&0xff]] ^ td[3][sbox0[x&0xff]]
+                       }
+                       dec[i+j] = x
+               }
+       }
+}
diff --git a/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go
new file mode 100644 (file)
index 0000000..3a9d023
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+       "os"
+       "strconv"
+)
+
+// The AES block size in bytes.
+const BlockSize = 16
+
+// A Cipher is an instance of AES encryption using a particular key.
+type Cipher struct {
+       enc []uint32
+       dec []uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+       return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher.
+// The key argument should be the AES key,
+// either 16, 24, or 32 bytes to select
+// AES-128, AES-192, or AES-256.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+       k := len(key)
+       switch k {
+       default:
+               return nil, KeySizeError(k)
+       case 16, 24, 32:
+               break
+       }
+
+       n := k + 28
+       c := &Cipher{make([]uint32, n), make([]uint32, n)}
+       expandKey(key, c.enc, c.dec)
+       return c, nil
+}
+
+// BlockSize returns the AES block size, 16 bytes.
+// It is necessary to satisfy the Cipher interface in the
+// package "crypto/block".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 16-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) }
+
+// Decrypt decrypts the 16-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c.dec, dst, src) }
+
+// Reset zeros the key data, so that it will no longer
+// appear in the process's memory.
+func (c *Cipher) Reset() {
+       for i := 0; i < len(c.enc); i++ {
+               c.enc[i] = 0
+       }
+       for i := 0; i < len(c.dec); i++ {
+               c.dec[i] = 0
+       }
+}
diff --git a/libgo/go/crypto/aes/const.go b/libgo/go/crypto/aes/const.go
new file mode 100644 (file)
index 0000000..97a5b64
--- /dev/null
@@ -0,0 +1,362 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// AES constants - 8720 bytes of initialized data.
+
+// This package implements AES encryption (formerly Rijndael),
+// as defined in U.S. Federal Information Processing Standards Publication 197.
+package aes
+
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+// AES is based on the mathematical behavior of binary polynomials
+// (polynomials over GF(2)) modulo the irreducible polynomial x⁸ + x⁴ + x² + x + 1.
+// Addition of these binary polynomials corresponds to binary xor.
+// Reducing mod poly corresponds to binary xor with poly every
+// time a 0x100 bit appears.
+const poly = 1<<8 | 1<<4 | 1<<3 | 1<<1 | 1<<0 // x⁸ + x⁴ + x² + x + 1
+
+// Powers of x mod poly in GF(2).
+var powx = [16]byte{
+       0x01,
+       0x02,
+       0x04,
+       0x08,
+       0x10,
+       0x20,
+       0x40,
+       0x80,
+       0x1b,
+       0x36,
+       0x6c,
+       0xd8,
+       0xab,
+       0x4d,
+       0x9a,
+       0x2f,
+}
+
+// FIPS-197 Figure 7. S-box substitution values in hexadecimal format.
+var sbox0 = [256]byte{
+       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,
+}
+
+// FIPS-197 Figure 14.  Inverse S-box substitution values in hexadecimal format.
+var sbox1 = [256]byte{
+       0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+       0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+       0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+       0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+       0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+       0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+       0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+       0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+       0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+       0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+       0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+       0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+       0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+       0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+       0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+       0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
+}
+
+// Lookup tables for encryption.
+// These can be recomputed by adapting the tests in aes_test.go.
+
+var te = [4][256]uint32{
+       {
+               0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
+               0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
+               0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
+               0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
+               0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
+               0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
+               0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
+               0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
+               0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
+               0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
+               0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
+               0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
+               0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
+               0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
+               0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
+               0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
+               0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
+               0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
+               0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
+               0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
+               0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
+               0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
+               0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
+               0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
+               0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
+               0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
+               0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
+               0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
+               0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
+               0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
+               0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
+               0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
+       },
+       {
+               0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
+               0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
+               0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
+               0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
+               0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
+               0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
+               0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
+               0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
+               0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
+               0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
+               0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
+               0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
+               0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
+               0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
+               0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
+               0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
+               0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
+               0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
+               0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
+               0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
+               0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
+               0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
+               0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
+               0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
+               0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
+               0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
+               0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
+               0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
+               0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
+               0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
+               0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
+               0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
+       },
+       {
+               0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
+               0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
+               0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
+               0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
+               0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
+               0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
+               0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
+               0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
+               0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
+               0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
+               0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
+               0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
+               0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
+               0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
+               0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
+               0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
+               0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
+               0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
+               0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
+               0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
+               0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
+               0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
+               0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
+               0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
+               0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
+               0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
+               0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
+               0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
+               0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
+               0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
+               0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
+               0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
+       },
+       {
+               0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
+               0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
+               0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
+               0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
+               0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
+               0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
+               0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
+               0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
+               0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
+               0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
+               0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
+               0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
+               0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
+               0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
+               0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
+               0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
+               0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
+               0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
+               0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
+               0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
+               0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
+               0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
+               0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
+               0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
+               0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
+               0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
+               0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
+               0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
+               0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
+               0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
+               0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
+               0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
+       },
+}
+
+// Lookup tables for decryption.
+// These can be recomputed by adapting the tests in aes_test.go.
+
+var td = [4][256]uint32{
+       {
+               0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
+               0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
+               0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
+               0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
+               0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
+               0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
+               0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
+               0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
+               0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
+               0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
+               0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
+               0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
+               0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
+               0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
+               0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
+               0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
+               0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
+               0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
+               0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
+               0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
+               0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
+               0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
+               0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
+               0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
+               0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
+               0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
+               0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
+               0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
+               0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
+               0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
+               0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
+               0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
+       },
+       {
+               0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
+               0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
+               0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
+               0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
+               0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
+               0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
+               0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
+               0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
+               0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
+               0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
+               0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
+               0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
+               0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
+               0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
+               0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
+               0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
+               0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
+               0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
+               0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
+               0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
+               0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
+               0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
+               0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
+               0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
+               0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
+               0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
+               0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
+               0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
+               0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
+               0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
+               0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
+               0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
+       },
+       {
+               0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
+               0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
+               0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
+               0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
+               0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
+               0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
+               0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
+               0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
+               0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
+               0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
+               0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
+               0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
+               0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
+               0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
+               0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
+               0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
+               0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
+               0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
+               0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
+               0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
+               0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
+               0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
+               0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
+               0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
+               0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
+               0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
+               0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
+               0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
+               0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
+               0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
+               0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
+               0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
+       },
+       {
+               0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
+               0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
+               0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
+               0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
+               0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
+               0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
+               0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
+               0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
+               0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
+               0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
+               0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
+               0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
+               0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
+               0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
+               0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
+               0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
+               0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
+               0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
+               0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
+               0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
+               0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
+               0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
+               0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
+               0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
+               0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
+               0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
+               0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
+               0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
+               0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
+               0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
+               0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
+               0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
+       },
+}
diff --git a/libgo/go/crypto/block/cbc.go b/libgo/go/crypto/block/cbc.go
new file mode 100644 (file)
index 0000000..23229c0
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Cipher block chaining (CBC) mode.
+
+// CBC provides confidentiality by xoring (chaining) each plaintext block
+// with the previous ciphertext block before applying the block cipher.
+
+// See NIST SP 800-38A, pp 10-11
+
+package block
+
+import (
+       "io"
+)
+
+type cbcCipher struct {
+       c         Cipher
+       blockSize int
+       iv        []byte
+       tmp       []byte
+}
+
+func newCBC(c Cipher, iv []byte) *cbcCipher {
+       n := c.BlockSize()
+       x := new(cbcCipher)
+       x.c = c
+       x.blockSize = n
+       x.iv = dup(iv)
+       x.tmp = make([]byte, n)
+       return x
+}
+
+func (x *cbcCipher) BlockSize() int { return x.blockSize }
+
+func (x *cbcCipher) Encrypt(dst, src []byte) {
+       for i := 0; i < x.blockSize; i++ {
+               x.iv[i] ^= src[i]
+       }
+       x.c.Encrypt(x.iv, x.iv)
+       for i := 0; i < x.blockSize; i++ {
+               dst[i] = x.iv[i]
+       }
+}
+
+func (x *cbcCipher) Decrypt(dst, src []byte) {
+       x.c.Decrypt(x.tmp, src)
+       for i := 0; i < x.blockSize; i++ {
+               x.tmp[i] ^= x.iv[i]
+               x.iv[i] = src[i]
+               dst[i] = x.tmp[i]
+       }
+}
+
+// NewCBCDecrypter returns a reader that reads data from r and decrypts it using c
+// in cipher block chaining (CBC) mode with the initialization vector iv.
+// The returned Reader does not buffer or read ahead except
+// as required by the cipher's block size.
+func NewCBCDecrypter(c Cipher, iv []byte, r io.Reader) io.Reader {
+       return NewECBDecrypter(newCBC(c, iv), r)
+}
+
+// NewCBCEncrypter returns a writer that encrypts data using c
+// in cipher block chaining (CBC) mode with the initialization vector iv
+// and writes the encrypted data to w.
+// The returned Writer does no buffering except as required
+// by the cipher's block size, so there is no need for a Flush method.
+func NewCBCEncrypter(c Cipher, iv []byte, w io.Writer) io.Writer {
+       return NewECBEncrypter(newCBC(c, iv), w)
+}
diff --git a/libgo/go/crypto/block/cbc_aes_test.go b/libgo/go/crypto/block/cbc_aes_test.go
new file mode 100644 (file)
index 0000000..5e8cb35
--- /dev/null
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CBC AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 24-29.
+
+package block
+
+import (
+       "bytes"
+       "crypto/aes"
+       "io"
+       "testing"
+)
+
+type cbcTest struct {
+       name string
+       key  []byte
+       iv   []byte
+       in   []byte
+       out  []byte
+}
+
+var cbcAESTests = []cbcTest{
+       // NIST SP 800-38A pp 27-29
+       {
+               "CBC-AES128",
+               commonKey128,
+               commonIV,
+               commonInput,
+               []byte{
+                       0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
+                       0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
+                       0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
+                       0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7,
+               },
+       },
+       {
+               "CBC-AES192",
+               commonKey192,
+               commonIV,
+               commonInput,
+               []byte{
+                       0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
+                       0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
+                       0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
+                       0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd,
+               },
+       },
+       {
+               "CBC-AES256",
+               commonKey256,
+               commonIV,
+               commonInput,
+               []byte{
+                       0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
+                       0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
+                       0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
+                       0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b,
+               },
+       },
+}
+
+func TestCBC_AES(t *testing.T) {
+       for _, tt := range cbcAESTests {
+               test := tt.name
+
+               c, err := aes.NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+                       continue
+               }
+
+               var crypt bytes.Buffer
+               w := NewCBCEncrypter(c, tt.iv, &crypt)
+               var r io.Reader = bytes.NewBuffer(tt.in)
+               n, err := io.Copy(w, r)
+               if n != int64(len(tt.in)) || err != nil {
+                       t.Errorf("%s: CBCEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
+               } else if d := crypt.Bytes(); !same(tt.out, d) {
+                       t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
+               }
+
+               var plain bytes.Buffer
+               r = NewCBCDecrypter(c, tt.iv, bytes.NewBuffer(tt.out))
+               w = &plain
+               n, err = io.Copy(w, r)
+               if n != int64(len(tt.out)) || err != nil {
+                       t.Errorf("%s: CBCDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
+               } else if d := plain.Bytes(); !same(tt.in, d) {
+                       t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in)
+               }
+
+               if t.Failed() {
+                       break
+               }
+       }
+}
diff --git a/libgo/go/crypto/block/cfb.go b/libgo/go/crypto/block/cfb.go
new file mode 100644 (file)
index 0000000..f20c0a0
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Cipher feedback (CFB) mode.
+
+// CFB provides confidentiality by feeding a fraction of
+// the previous ciphertext in as the plaintext for the next
+// block operation.
+
+// See NIST SP 800-38A, pp 11-13
+
+package block
+
+import (
+       "io"
+)
+
+type cfbCipher struct {
+       c          Cipher
+       blockSize  int // our block size (s/8)
+       cipherSize int // underlying cipher block size
+       iv         []byte
+       tmp        []byte
+}
+
+func newCFB(c Cipher, s int, iv []byte) *cfbCipher {
+       if s == 0 || s%8 != 0 {
+               panic("crypto/block: invalid CFB mode")
+       }
+       b := c.BlockSize()
+       x := new(cfbCipher)
+       x.c = c
+       x.blockSize = s / 8
+       x.cipherSize = b
+       x.iv = dup(iv)
+       x.tmp = make([]byte, b)
+       return x
+}
+
+func (x *cfbCipher) BlockSize() int { return x.blockSize }
+
+func (x *cfbCipher) Encrypt(dst, src []byte) {
+       // Encrypt old IV and xor prefix with src to make dst.
+       x.c.Encrypt(x.tmp, x.iv)
+       for i := 0; i < x.blockSize; i++ {
+               dst[i] = src[i] ^ x.tmp[i]
+       }
+
+       // Slide unused IV pieces down and insert dst at end.
+       for i := 0; i < x.cipherSize-x.blockSize; i++ {
+               x.iv[i] = x.iv[i+x.blockSize]
+       }
+       off := x.cipherSize - x.blockSize
+       for i := off; i < x.cipherSize; i++ {
+               x.iv[i] = dst[i-off]
+       }
+}
+
+func (x *cfbCipher) Decrypt(dst, src []byte) {
+       // Encrypt [sic] old IV and xor prefix with src to make dst.
+       x.c.Encrypt(x.tmp, x.iv)
+       for i := 0; i < x.blockSize; i++ {
+               dst[i] = src[i] ^ x.tmp[i]
+       }
+
+       // Slide unused IV pieces down and insert src at top.
+       for i := 0; i < x.cipherSize-x.blockSize; i++ {
+               x.iv[i] = x.iv[i+x.blockSize]
+       }
+       off := x.cipherSize - x.blockSize
+       for i := off; i < x.cipherSize; i++ {
+               // Reconstruct src = dst ^ x.tmp
+               // in case we overwrote src (src == dst).
+               x.iv[i] = dst[i-off] ^ x.tmp[i-off]
+       }
+}
+
+// NewCFBDecrypter returns a reader that reads data from r and decrypts it using c
+// in s-bit cipher feedback (CFB) mode with the initialization vector iv.
+// The returned Reader does not buffer or read ahead except
+// as required by the cipher's block size.
+// Modes for s not a multiple of 8 are unimplemented.
+func NewCFBDecrypter(c Cipher, s int, iv []byte, r io.Reader) io.Reader {
+       return NewECBDecrypter(newCFB(c, s, iv), r)
+}
+
+// NewCFBEncrypter returns a writer that encrypts data using c
+// in s-bit cipher feedback (CFB) mode with the initialization vector iv
+// and writes the encrypted data to w.
+// The returned Writer does no buffering except as required
+// by the cipher's block size, so there is no need for a Flush method.
+// Modes for s not a multiple of 8 are unimplemented.
+func NewCFBEncrypter(c Cipher, s int, iv []byte, w io.Writer) io.Writer {
+       return NewECBEncrypter(newCFB(c, s, iv), w)
+}
diff --git a/libgo/go/crypto/block/cfb_aes_test.go b/libgo/go/crypto/block/cfb_aes_test.go
new file mode 100644 (file)
index 0000000..e400c18
--- /dev/null
@@ -0,0 +1,311 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CFB AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 29-52.
+
+package block
+
+import (
+       "bytes"
+       "crypto/aes"
+       "io"
+       "testing"
+)
+
+type cfbTest struct {
+       name string
+       s    int
+       key  []byte
+       iv   []byte
+       in   []byte
+       out  []byte
+}
+
+var cfbAESTests = []cfbTest{
+       {
+               "CFB1-AES128",
+               1,
+               commonKey128,
+               commonIV,
+               []byte{
+                       0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
+                       1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
+               },
+               []byte{
+                       0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1,
+                       1<<7 | 0<<6 | 1<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1,
+               },
+       },
+       {
+               "CFB1-AES192",
+               1,
+               commonKey192,
+               commonIV,
+               []byte{
+                       0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
+                       1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
+               },
+               []byte{
+                       1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1,
+                       0<<7 | 1<<6 | 0<<5 | 1<<4 | 1<<3 | 0<<2 | 0<<1,
+               },
+       },
+       {
+               "CFB1-AES256",
+               1,
+               commonKey256,
+               commonIV,
+               []byte{
+                       0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
+                       1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
+               },
+               []byte{
+                       1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 0<<1,
+                       0<<7 | 0<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1,
+               },
+       },
+
+       {
+               "CFB8-AES128",
+               8,
+               commonKey128,
+               commonIV,
+               []byte{
+                       0x6b,
+                       0xc1,
+                       0xbe,
+                       0xe2,
+                       0x2e,
+                       0x40,
+                       0x9f,
+                       0x96,
+                       0xe9,
+                       0x3d,
+                       0x7e,
+                       0x11,
+                       0x73,
+                       0x93,
+                       0x17,
+                       0x2a,
+                       0xae,
+                       0x2d,
+               },
+               []byte{
+                       0x3b,
+                       0x79,
+                       0x42,
+                       0x4c,
+                       0x9c,
+                       0x0d,
+                       0xd4,
+                       0x36,
+                       0xba,
+                       0xce,
+                       0x9e,
+                       0x0e,
+                       0xd4,
+                       0x58,
+                       0x6a,
+                       0x4f,
+                       0x32,
+                       0xb9,
+               },
+       },
+
+       {
+               "CFB8-AES192",
+               8,
+               commonKey192,
+               commonIV,
+               []byte{
+                       0x6b,
+                       0xc1,
+                       0xbe,
+                       0xe2,
+                       0x2e,
+                       0x40,
+                       0x9f,
+                       0x96,
+                       0xe9,
+                       0x3d,
+                       0x7e,
+                       0x11,
+                       0x73,
+                       0x93,
+                       0x17,
+                       0x2a,
+                       0xae,
+                       0x2d,
+               },
+               []byte{
+                       0xcd,
+                       0xa2,
+                       0x52,
+                       0x1e,
+                       0xf0,
+                       0xa9,
+                       0x05,
+                       0xca,
+                       0x44,
+                       0xcd,
+                       0x05,
+                       0x7c,
+                       0xbf,
+                       0x0d,
+                       0x47,
+                       0xa0,
+                       0x67,
+                       0x8a,
+               },
+       },
+
+       {
+               "CFB8-AES256",
+               8,
+               commonKey256,
+               commonIV,
+               []byte{
+                       0x6b,
+                       0xc1,
+                       0xbe,
+                       0xe2,
+                       0x2e,
+                       0x40,
+                       0x9f,
+                       0x96,
+                       0xe9,
+                       0x3d,
+                       0x7e,
+                       0x11,
+                       0x73,
+                       0x93,
+                       0x17,
+                       0x2a,
+                       0xae,
+                       0x2d,
+               },
+               []byte{
+                       0xdc,
+                       0x1f,
+                       0x1a,
+                       0x85,
+                       0x20,
+                       0xa6,
+                       0x4d,
+                       0xb5,
+                       0x5f,
+                       0xcc,
+                       0x8a,
+                       0xc5,
+                       0x54,
+                       0x84,
+                       0x4e,
+                       0x88,
+                       0x97,
+                       0x00,
+               },
+       },
+
+       {
+               "CFB128-AES128",
+               128,
+               commonKey128,
+               commonIV,
+               []byte{
+                       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                       0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+               },
+               []byte{
+                       0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
+                       0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b,
+                       0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf,
+                       0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6,
+               },
+       },
+
+       {
+               "CFB128-AES192",
+               128,
+               commonKey192,
+               commonIV,
+               []byte{
+                       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                       0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+               },
+               []byte{
+                       0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
+                       0x67, 0xce, 0x7f, 0x7f, 0x81, 0x17, 0x36, 0x21, 0x96, 0x1a, 0x2b, 0x70, 0x17, 0x1d, 0x3d, 0x7a,
+                       0x2e, 0x1e, 0x8a, 0x1d, 0xd5, 0x9b, 0x88, 0xb1, 0xc8, 0xe6, 0x0f, 0xed, 0x1e, 0xfa, 0xc4, 0xc9,
+                       0xc0, 0x5f, 0x9f, 0x9c, 0xa9, 0x83, 0x4f, 0xa0, 0x42, 0xae, 0x8f, 0xba, 0x58, 0x4b, 0x09, 0xff,
+               },
+       },
+
+       {
+               "CFB128-AES256",
+               128,
+               commonKey256,
+               commonIV,
+               []byte{
+                       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                       0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+               },
+               []byte{
+                       0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
+                       0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b,
+                       0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9,
+                       0x75, 0xa3, 0x85, 0x74, 0x1a, 0xb9, 0xce, 0xf8, 0x20, 0x31, 0x62, 0x3d, 0x55, 0xb1, 0xe4, 0x71,
+               },
+       },
+}
+
+func TestCFB_AES(t *testing.T) {
+       for _, tt := range cfbAESTests {
+               test := tt.name
+
+               if tt.s == 1 {
+                       // 1-bit CFB not implemented
+                       continue
+               }
+
+               c, err := aes.NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+                       continue
+               }
+
+               var crypt bytes.Buffer
+               w := NewCFBEncrypter(c, tt.s, tt.iv, &crypt)
+               var r io.Reader = bytes.NewBuffer(tt.in)
+               n, err := io.Copy(w, r)
+               if n != int64(len(tt.in)) || err != nil {
+                       t.Errorf("%s: CFBEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
+               } else if d := crypt.Bytes(); !same(tt.out, d) {
+                       t.Errorf("%s: CFBEncrypter\nhave %x\nwant %x", test, d, tt.out)
+               }
+
+               var plain bytes.Buffer
+               r = NewCFBDecrypter(c, tt.s, tt.iv, bytes.NewBuffer(tt.out))
+               w = &plain
+               n, err = io.Copy(w, r)
+               if n != int64(len(tt.out)) || err != nil {
+                       t.Errorf("%s: CFBDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
+               } else if d := plain.Bytes(); !same(tt.in, d) {
+                       t.Errorf("%s: CFBDecrypter\nhave %x\nwant %x", test, d, tt.in)
+               }
+
+               if t.Failed() {
+                       break
+               }
+       }
+}
diff --git a/libgo/go/crypto/block/cipher.go b/libgo/go/crypto/block/cipher.go
new file mode 100644 (file)
index 0000000..a50d05c
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The block package implements standard block cipher modes
+// that can be wrapped around low-level block cipher implementations.
+// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html
+// and NIST Special Publication 800-38A.
+package block
+
+// A Cipher represents an implementation of block cipher
+// using a given key.  It provides the capability to encrypt
+// or decrypt individual blocks.  The mode implementations
+// extend that capability to streams of blocks.
+type Cipher interface {
+       // BlockSize returns the cipher's block size.
+       BlockSize() int
+
+       // Encrypt encrypts the first block in src into dst.
+       // Src and dst may point at the same memory.
+       Encrypt(dst, src []byte)
+
+       // Decrypt decrypts the first block in src into dst.
+       // Src and dst may point at the same memory.
+       Decrypt(dst, src []byte)
+}
+
+// Utility routines
+
+func shift1(dst, src []byte) byte {
+       var b byte
+       for i := len(src) - 1; i >= 0; i-- {
+               bb := src[i] >> 7
+               dst[i] = src[i]<<1 | b
+               b = bb
+       }
+       return b
+}
+
+func same(p, q []byte) bool {
+       if len(p) != len(q) {
+               return false
+       }
+       for i := 0; i < len(p); i++ {
+               if p[i] != q[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+func dup(p []byte) []byte {
+       q := make([]byte, len(p))
+       copy(q, p)
+       return q
+}
diff --git a/libgo/go/crypto/block/cmac.go b/libgo/go/crypto/block/cmac.go
new file mode 100644 (file)
index 0000000..b85cde7
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CMAC message authentication code, defined in
+// NIST Special Publication SP 800-38B.
+
+package block
+
+import (
+       "hash"
+       "os"
+)
+
+const (
+       // minimal irreducible polynomial of degree b
+       r64  = 0x1b
+       r128 = 0x87
+)
+
+type cmac struct {
+       k1, k2, ci, digest []byte
+       p                  int // position in ci
+       c                  Cipher
+}
+
+// TODO(rsc): Should this return an error instead of panic?
+
+// NewCMAC returns a new instance of a CMAC message authentication code
+// digest using the given Cipher.
+func NewCMAC(c Cipher) hash.Hash {
+       var r byte
+       n := c.BlockSize()
+       switch n {
+       case 64 / 8:
+               r = r64
+       case 128 / 8:
+               r = r128
+       default:
+               panic("crypto/block: NewCMAC: invalid cipher block size")
+       }
+
+       d := new(cmac)
+       d.c = c
+       d.k1 = make([]byte, n)
+       d.k2 = make([]byte, n)
+       d.ci = make([]byte, n)
+       d.digest = make([]byte, n)
+
+       // Subkey generation, p. 7
+       c.Encrypt(d.k1, d.k1)
+       if shift1(d.k1, d.k1) != 0 {
+               d.k1[n-1] ^= r
+       }
+       if shift1(d.k2, d.k1) != 0 {
+               d.k2[n-1] ^= r
+       }
+
+       return d
+}
+
+// Reset clears the digest state, starting a new digest.
+func (d *cmac) Reset() {
+       for i := range d.ci {
+               d.ci[i] = 0
+       }
+       d.p = 0
+}
+
+// Write adds the given data to the digest state.
+func (d *cmac) Write(p []byte) (n int, err os.Error) {
+       // Xor input into ci.
+       for _, c := range p {
+               // If ci is full, encrypt and start over.
+               if d.p >= len(d.ci) {
+                       d.c.Encrypt(d.ci, d.ci)
+                       d.p = 0
+               }
+               d.ci[d.p] ^= c
+               d.p++
+       }
+       return len(p), nil
+}
+
+// Sum returns the CMAC digest, one cipher block in length,
+// of the data written with Write.
+func (d *cmac) Sum() []byte {
+       // Finish last block, mix in key, encrypt.
+       // Don't edit ci, in case caller wants
+       // to keep digesting after call to Sum.
+       k := d.k1
+       if d.p < len(d.digest) {
+               k = d.k2
+       }
+       for i := 0; i < len(d.ci); i++ {
+               d.digest[i] = d.ci[i] ^ k[i]
+       }
+       if d.p < len(d.digest) {
+               d.digest[d.p] ^= 0x80
+       }
+       d.c.Encrypt(d.digest, d.digest)
+       return d.digest
+}
+
+func (d *cmac) Size() int { return len(d.digest) }
diff --git a/libgo/go/crypto/block/cmac_aes_test.go b/libgo/go/crypto/block/cmac_aes_test.go
new file mode 100644 (file)
index 0000000..0a4a1a4
--- /dev/null
@@ -0,0 +1,130 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CMAC test vectors.  See NIST SP 800-38B, Appendix D.
+
+package block
+
+import (
+       "crypto/aes"
+       "testing"
+)
+
+type cmacAESTest struct {
+       key    []byte
+       in     []byte
+       digest []byte
+}
+
+var cmacAESTests = []cmacAESTest{
+       {
+               commonKey128,
+               nil,
+               []byte{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46},
+       },
+       {
+               commonKey128,
+               []byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+               []byte{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c},
+       },
+       {
+               commonKey128,
+               []byte{
+                       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+               },
+               []byte{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27},
+       },
+       {
+               commonKey128,
+               []byte{
+                       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                       0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+               },
+               []byte{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe},
+       },
+       {
+               commonKey192,
+               nil,
+               []byte{0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67},
+       },
+       {
+               commonKey192,
+               []byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+               []byte{0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84},
+       },
+       {
+               commonKey192,
+               []byte{
+                       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+               },
+               []byte{0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e},
+       },
+       {
+               commonKey192,
+               []byte{
+                       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                       0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+               },
+               []byte{0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11},
+       },
+       {
+               commonKey256,
+               nil,
+               []byte{0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83},
+       },
+       {
+               commonKey256,
+               []byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+               []byte{0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c},
+       },
+       {
+               commonKey256,
+               []byte{
+                       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+               },
+               []byte{0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6},
+       },
+       {
+               commonKey256,
+               []byte{
+                       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+                       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+                       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+                       0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+               },
+               []byte{0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10},
+       },
+}
+
+func TestCMAC_AES(t *testing.T) {
+       for i, tt := range cmacAESTests {
+               c, err := aes.NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("test %d: NewCipher: %s", i, err)
+                       continue
+               }
+               d := NewCMAC(c)
+               n, err := d.Write(tt.in)
+               if err != nil || n != len(tt.in) {
+                       t.Errorf("test %d: Write %d: %d, %s", i, len(tt.in), n, err)
+                       continue
+               }
+               sum := d.Sum()
+               if !same(sum, tt.digest) {
+                       x := d.(*cmac)
+                       t.Errorf("test %d: digest mismatch\n\twant %x\n\thave %x\n\tk1 %x\n\tk2 %x", i, tt.digest, sum, x.k1, x.k2)
+                       continue
+               }
+       }
+}
diff --git a/libgo/go/crypto/block/ctr.go b/libgo/go/crypto/block/ctr.go
new file mode 100644 (file)
index 0000000..5d65c0c
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Counter (CTR) mode.
+
+// CTR converts a block cipher into a stream cipher by
+// repeatedly encrypting an incrementing counter and
+// xoring the resulting stream of data with the input.
+
+// See NIST SP 800-38A, pp 13-15
+
+package block
+
+import (
+       "io"
+)
+
+type ctrStream struct {
+       c   Cipher
+       ctr []byte
+       out []byte
+}
+
+func newCTRStream(c Cipher, ctr []byte) *ctrStream {
+       x := new(ctrStream)
+       x.c = c
+       x.ctr = dup(ctr)
+       x.out = make([]byte, len(ctr))
+       return x
+}
+
+func (x *ctrStream) Next() []byte {
+       // Next block is encryption of counter.
+       x.c.Encrypt(x.out, x.ctr)
+
+       // Increment counter
+       for i := len(x.ctr) - 1; i >= 0; i-- {
+               x.ctr[i]++
+               if x.ctr[i] != 0 {
+                       break
+               }
+       }
+
+       return x.out
+}
+
+// NewCTRReader returns a reader that reads data from r, decrypts (or encrypts)
+// it using c in counter (CTR) mode with the initialization vector iv.
+// The returned Reader does not buffer and has no block size.
+// In CTR mode, encryption and decryption are the same operation:
+// a CTR reader applied to an encrypted stream produces a decrypted
+// stream and vice versa.
+func NewCTRReader(c Cipher, iv []byte, r io.Reader) io.Reader {
+       return newXorReader(newCTRStream(c, iv), r)
+}
+
+// NewCTRWriter returns a writer that encrypts (or decrypts) data using c
+// in counter (CTR) mode with the initialization vector iv
+// and writes the encrypted data to w.
+// The returned Writer does not buffer and has no block size.
+// In CTR mode, encryption and decryption are the same operation:
+// a CTR writer applied to an decrypted stream produces an encrypted
+// stream and vice versa.
+func NewCTRWriter(c Cipher, iv []byte, w io.Writer) io.Writer {
+       return newXorWriter(newCTRStream(c, iv), w)
+}
diff --git a/libgo/go/crypto/block/ctr_aes_test.go b/libgo/go/crypto/block/ctr_aes_test.go
new file mode 100644 (file)
index 0000000..ce5fdd5
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CTR AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 55-58.
+
+package block
+
+import (
+       "bytes"
+       "crypto/aes"
+       "io"
+       "testing"
+)
+
+type ctrTest struct {
+       name string
+       key  []byte
+       iv   []byte
+       in   []byte
+       out  []byte
+}
+
+var commonCounter = []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}
+
+var ctrAESTests = []ctrTest{
+       // NIST SP 800-38A pp 55-58
+       {
+               "CTR-AES128",
+               commonKey128,
+               commonCounter,
+               commonInput,
+               []byte{
+                       0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+                       0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+                       0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+                       0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
+               },
+       },
+       {
+               "CTR-AES192",
+               commonKey192,
+               commonCounter,
+               commonInput,
+               []byte{
+                       0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
+                       0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef, 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
+                       0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70, 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
+                       0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58, 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50,
+               },
+       },
+       {
+               "CTR-AES256",
+               commonKey256,
+               commonCounter,
+               commonInput,
+               []byte{
+                       0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
+                       0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
+                       0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
+                       0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6,
+               },
+       },
+}
+
+func TestCTR_AES(t *testing.T) {
+       for _, tt := range ctrAESTests {
+               test := tt.name
+
+               c, err := aes.NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+                       continue
+               }
+
+               for j := 0; j <= 5; j += 5 {
+                       var crypt bytes.Buffer
+                       in := tt.in[0 : len(tt.in)-j]
+                       w := NewCTRWriter(c, tt.iv, &crypt)
+                       var r io.Reader = bytes.NewBuffer(in)
+                       n, err := io.Copy(w, r)
+                       if n != int64(len(in)) || err != nil {
+                               t.Errorf("%s/%d: CTRWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in))
+                       } else if d, out := crypt.Bytes(), tt.out[0:len(in)]; !same(out, d) {
+                               t.Errorf("%s/%d: CTRWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out)
+                       }
+               }
+
+               for j := 0; j <= 7; j += 7 {
+                       var plain bytes.Buffer
+                       out := tt.out[0 : len(tt.out)-j]
+                       r := NewCTRReader(c, tt.iv, bytes.NewBuffer(out))
+                       w := &plain
+                       n, err := io.Copy(w, r)
+                       if n != int64(len(out)) || err != nil {
+                               t.Errorf("%s/%d: CTRReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out))
+                       } else if d, in := plain.Bytes(), tt.in[0:len(out)]; !same(in, d) {
+                               t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), d, in)
+                       }
+               }
+
+               if t.Failed() {
+                       break
+               }
+       }
+}
diff --git a/libgo/go/crypto/block/eax.go b/libgo/go/crypto/block/eax.go
new file mode 100644 (file)
index 0000000..3f3b964
--- /dev/null
@@ -0,0 +1,253 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// EAX mode, not a NIST standard (yet).
+// EAX provides encryption and authentication.
+// EAX targets the same uses as NIST's CCM mode,
+// but EAX adds the ability to run in streaming mode.
+
+// See
+// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf
+// http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+// What those papers call OMAC is now called CMAC.
+
+package block
+
+import (
+       "fmt"
+       "hash"
+       "io"
+       "os"
+)
+
+// An EAXTagError is returned when the message has failed to authenticate,
+// because the tag at the end of the message stream (Read) does not match
+// the tag computed from the message itself (Computed).
+type EAXTagError struct {
+       Read     []byte
+       Computed []byte
+}
+
+func (e *EAXTagError) String() string {
+       return fmt.Sprintf("crypto/block: EAX tag mismatch: read %x but computed %x", e.Read, e.Computed)
+}
+
+func setupEAX(c Cipher, iv, hdr []byte, tagBytes int) (ctrIV, tag []byte, cmac hash.Hash) {
+       n := len(iv)
+       if n != c.BlockSize() {
+               panic(fmt.Sprintln("crypto/block: EAX: iv length", n, "!=", c.BlockSize()))
+       }
+       buf := make([]byte, n) // zeroed
+
+       // tag = CMAC(0 + iv) ^ CMAC(1 + hdr) ^ CMAC(2 + data)
+       cmac = NewCMAC(c)
+       cmac.Write(buf) // 0
+       cmac.Write(iv)
+       sum := cmac.Sum()
+       ctrIV = dup(sum)
+       tag = dup(sum[0:tagBytes])
+
+       cmac.Reset()
+       buf[n-1] = 1
+       cmac.Write(buf) // 1
+       cmac.Write(hdr)
+       sum = cmac.Sum()
+       for i := 0; i < tagBytes; i++ {
+               tag[i] ^= sum[i]
+       }
+
+       cmac.Reset()
+       buf[n-1] = 2 // 2
+       cmac.Write(buf)
+
+       return
+}
+
+func finishEAX(tag []byte, cmac hash.Hash) {
+       // Finish CMAC #2 and xor into tag.
+       sum := cmac.Sum()
+       for i := range tag {
+               tag[i] ^= sum[i]
+       }
+}
+
+// Writer adapter.  Tees writes into both w and cmac.
+// Knows that cmac never returns write errors.
+type cmacWriter struct {
+       w    io.Writer
+       cmac hash.Hash
+}
+
+func (cw *cmacWriter) Write(p []byte) (n int, err os.Error) {
+       n, err = cw.w.Write(p)
+       cw.cmac.Write(p[0:n])
+       return
+}
+
+// An eaxEncrypter implements the EAX encryption mode.
+type eaxEncrypter struct {
+       ctr io.Writer  // CTR encrypter
+       cw  cmacWriter // CTR's output stream
+       tag []byte
+}
+
+// NewEAXEncrypter creates and returns a new EAX encrypter
+// using the given cipher c, initialization vector iv, associated data hdr,
+// and tag length tagBytes.  The encrypter's Write method encrypts
+// the data it receives and writes that data to w.
+// The encrypter's Close method writes a final authenticating tag to w.
+func NewEAXEncrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, w io.Writer) io.WriteCloser {
+       x := new(eaxEncrypter)
+
+       // Create new CTR instance writing to both
+       // w for encrypted output and cmac for digesting.
+       x.cw.w = w
+       var ctrIV []byte
+       ctrIV, x.tag, x.cw.cmac = setupEAX(c, iv, hdr, tagBytes)
+       x.ctr = NewCTRWriter(c, ctrIV, &x.cw)
+       return x
+}
+
+func (x *eaxEncrypter) Write(p []byte) (n int, err os.Error) {
+       return x.ctr.Write(p)
+}
+
+func (x *eaxEncrypter) Close() os.Error {
+       x.ctr = nil // crash if Write is called again
+
+       // Write tag.
+       finishEAX(x.tag, x.cw.cmac)
+       n, err := x.cw.w.Write(x.tag)
+       if n != len(x.tag) && err == nil {
+               err = io.ErrShortWrite
+       }
+
+       return err
+}
+
+// Reader adapter.  Returns data read from r but hangs
+// on to the last len(tag) bytes for itself (returns EOF len(tag)
+// bytes early).  Also tees all data returned from Read into
+// the cmac digest.  The "don't return the last t bytes"
+// and the "tee into digest" functionality could be separated,
+// but the latter half is trivial.
+type cmacReader struct {
+       r    io.Reader
+       cmac hash.Hash
+       tag  []byte
+       tmp  []byte
+}
+
+func (cr *cmacReader) Read(p []byte) (n int, err os.Error) {
+       // TODO(rsc): Maybe fall back to simpler code if
+       // we recognize the underlying r as a ByteBuffer
+       // or ByteReader.  Then we can just take the last piece
+       // off at the start.
+
+       // First, read a tag-sized chunk.
+       // It's probably not the tag (unless there's no data).
+       tag := cr.tag
+       if len(tag) < cap(tag) {
+               nt := len(tag)
+               nn, err1 := io.ReadFull(cr.r, tag[nt:cap(tag)])
+               tag = tag[0 : nt+nn]
+               cr.tag = tag
+               if err1 != nil {
+                       return 0, err1
+               }
+       }
+
+       tagBytes := len(tag)
+       if len(p) > 4*tagBytes {
+               // If p is big, try to read directly into p to avoid a copy.
+               n, err = cr.r.Read(p[tagBytes:])
+               if n == 0 {
+                       goto out
+               }
+               // copy old tag into p
+               for i := 0; i < tagBytes; i++ {
+                       p[i] = tag[i]
+               }
+               // copy new tag out of p
+               for i := 0; i < tagBytes; i++ {
+                       tag[i] = p[n+i]
+               }
+               goto out
+       }
+
+       // Otherwise, read into p and then slide data
+       n, err = cr.r.Read(p)
+       if n == 0 {
+               goto out
+       }
+
+       // copy tag+p into p+tmp and then swap tmp, tag
+       tmp := cr.tmp
+       for i := n + tagBytes - 1; i >= 0; i-- {
+               var c byte
+               if i < tagBytes {
+                       c = tag[i]
+               } else {
+                       c = p[i-tagBytes]
+               }
+               if i < n {
+                       p[i] = c
+               } else {
+                       tmp[i] = c
+               }
+       }
+       cr.tmp, cr.tag = tag, tmp
+
+out:
+       cr.cmac.Write(p[0:n])
+       return
+}
+
+type eaxDecrypter struct {
+       ctr io.Reader
+       cr  cmacReader
+       tag []byte
+}
+
+// NewEAXDecrypter creates and returns a new EAX decrypter
+// using the given cipher c, initialization vector iv, associated data hdr,
+// and tag length tagBytes.  The encrypter's Read method decrypts and
+// returns data read from r.  At r's EOF, the encrypter checks the final
+// authenticating tag and returns an EAXTagError if the tag is invalid.
+// In that case, the message should be discarded.
+// Note that the data stream returned from Read cannot be
+// assumed to be valid, authenticated data until Read returns
+// 0, nil to signal the end of the data.
+func NewEAXDecrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, r io.Reader) io.Reader {
+       x := new(eaxDecrypter)
+
+       x.cr.r = r
+       x.cr.tag = make([]byte, 0, tagBytes)
+       x.cr.tmp = make([]byte, 0, tagBytes)
+       var ctrIV []byte
+       ctrIV, x.tag, x.cr.cmac = setupEAX(c, iv, hdr, tagBytes)
+       x.ctr = NewCTRReader(c, ctrIV, &x.cr)
+       return x
+}
+
+func (x *eaxDecrypter) checkTag() os.Error {
+       x.ctr = nil // crash if Read is called again
+
+       finishEAX(x.tag, x.cr.cmac)
+       if !same(x.tag, x.cr.tag) {
+               e := new(EAXTagError)
+               e.Computed = dup(x.tag)
+               e.Read = dup(x.cr.tag)
+               return e
+       }
+       return nil
+}
+
+func (x *eaxDecrypter) Read(p []byte) (n int, err os.Error) {
+       n, err = x.ctr.Read(p)
+       if n == 0 && err == nil {
+               err = x.checkTag()
+       }
+       return n, err
+}
diff --git a/libgo/go/crypto/block/eax_aes_test.go b/libgo/go/crypto/block/eax_aes_test.go
new file mode 100644 (file)
index 0000000..93aa771
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package block
+
+import (
+       "bytes"
+       "crypto/aes"
+       "fmt"
+       "io"
+       "testing"
+)
+
+// Test vectors from http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+
+type eaxAESTest struct {
+       msg    []byte
+       key    []byte
+       nonce  []byte
+       header []byte
+       cipher []byte
+}
+
+var eaxAESTests = []eaxAESTest{
+       {
+               []byte{},
+               []byte{0x23, 0x39, 0x52, 0xDE, 0xE4, 0xD5, 0xED, 0x5F, 0x9B, 0x9C, 0x6D, 0x6F, 0xF8, 0x0F, 0xF4, 0x78},
+               []byte{0x62, 0xEC, 0x67, 0xF9, 0xC3, 0xA4, 0xA4, 0x07, 0xFC, 0xB2, 0xA8, 0xC4, 0x90, 0x31, 0xA8, 0xB3},
+               []byte{0x6B, 0xFB, 0x91, 0x4F, 0xD0, 0x7E, 0xAE, 0x6B},
+               []byte{0xE0, 0x37, 0x83, 0x0E, 0x83, 0x89, 0xF2, 0x7B, 0x02, 0x5A, 0x2D, 0x65, 0x27, 0xE7, 0x9D, 0x01},
+       },
+       {
+               []byte{0xF7, 0xFB},
+               []byte{0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B, 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4},
+               []byte{0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84, 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD},
+               []byte{0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA},
+               []byte{0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D, 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79, 0x67, 0xE5},
+       },
+       {
+               []byte{0x1A, 0x47, 0xCB, 0x49, 0x33},
+               []byte{0x01, 0xF7, 0x4A, 0xD6, 0x40, 0x77, 0xF2, 0xE7, 0x04, 0xC0, 0xF6, 0x0A, 0xDA, 0x3D, 0xD5, 0x23},
+               []byte{0x70, 0xC3, 0xDB, 0x4F, 0x0D, 0x26, 0x36, 0x84, 0x00, 0xA1, 0x0E, 0xD0, 0x5D, 0x2B, 0xFF, 0x5E},
+               []byte{0x23, 0x4A, 0x34, 0x63, 0xC1, 0x26, 0x4A, 0xC6},
+               []byte{0xD8, 0x51, 0xD5, 0xBA, 0xE0, 0x3A, 0x59, 0xF2, 0x38, 0xA2, 0x3E, 0x39, 0x19, 0x9D, 0xC9, 0x26, 0x66, 0x26, 0xC4, 0x0F, 0x80},
+       },
+       {
+               []byte{0x48, 0x1C, 0x9E, 0x39, 0xB1},
+               []byte{0xD0, 0x7C, 0xF6, 0xCB, 0xB7, 0xF3, 0x13, 0xBD, 0xDE, 0x66, 0xB7, 0x27, 0xAF, 0xD3, 0xC5, 0xE8},
+               []byte{0x84, 0x08, 0xDF, 0xFF, 0x3C, 0x1A, 0x2B, 0x12, 0x92, 0xDC, 0x19, 0x9E, 0x46, 0xB7, 0xD6, 0x17},
+               []byte{0x33, 0xCC, 0xE2, 0xEA, 0xBF, 0xF5, 0xA7, 0x9D},
+               []byte{0x63, 0x2A, 0x9D, 0x13, 0x1A, 0xD4, 0xC1, 0x68, 0xA4, 0x22, 0x5D, 0x8E, 0x1F, 0xF7, 0x55, 0x93, 0x99, 0x74, 0xA7, 0xBE, 0xDE},
+       },
+       {
+               []byte{0x40, 0xD0, 0xC0, 0x7D, 0xA5, 0xE4},
+               []byte{0x35, 0xB6, 0xD0, 0x58, 0x00, 0x05, 0xBB, 0xC1, 0x2B, 0x05, 0x87, 0x12, 0x45, 0x57, 0xD2, 0xC2},
+               []byte{0xFD, 0xB6, 0xB0, 0x66, 0x76, 0xEE, 0xDC, 0x5C, 0x61, 0xD7, 0x42, 0x76, 0xE1, 0xF8, 0xE8, 0x16},
+               []byte{0xAE, 0xB9, 0x6E, 0xAE, 0xBE, 0x29, 0x70, 0xE9},
+               []byte{0x07, 0x1D, 0xFE, 0x16, 0xC6, 0x75, 0xCB, 0x06, 0x77, 0xE5, 0x36, 0xF7, 0x3A, 0xFE, 0x6A, 0x14, 0xB7, 0x4E, 0xE4, 0x98, 0x44, 0xDD},
+       },
+       {
+               []byte{0x4D, 0xE3, 0xB3, 0x5C, 0x3F, 0xC0, 0x39, 0x24, 0x5B, 0xD1, 0xFB, 0x7D},
+               []byte{0xBD, 0x8E, 0x6E, 0x11, 0x47, 0x5E, 0x60, 0xB2, 0x68, 0x78, 0x4C, 0x38, 0xC6, 0x2F, 0xEB, 0x22},
+               []byte{0x6E, 0xAC, 0x5C, 0x93, 0x07, 0x2D, 0x8E, 0x85, 0x13, 0xF7, 0x50, 0x93, 0x5E, 0x46, 0xDA, 0x1B},
+               []byte{0xD4, 0x48, 0x2D, 0x1C, 0xA7, 0x8D, 0xCE, 0x0F},
+               []byte{0x83, 0x5B, 0xB4, 0xF1, 0x5D, 0x74, 0x3E, 0x35, 0x0E, 0x72, 0x84, 0x14, 0xAB, 0xB8, 0x64, 0x4F, 0xD6, 0xCC, 0xB8, 0x69, 0x47, 0xC5, 0xE1, 0x05, 0x90, 0x21, 0x0A, 0x4F},
+       },
+       {
+               []byte{0x8B, 0x0A, 0x79, 0x30, 0x6C, 0x9C, 0xE7, 0xED, 0x99, 0xDA, 0xE4, 0xF8, 0x7F, 0x8D, 0xD6, 0x16, 0x36},
+               []byte{0x7C, 0x77, 0xD6, 0xE8, 0x13, 0xBE, 0xD5, 0xAC, 0x98, 0xBA, 0xA4, 0x17, 0x47, 0x7A, 0x2E, 0x7D},
+               []byte{0x1A, 0x8C, 0x98, 0xDC, 0xD7, 0x3D, 0x38, 0x39, 0x3B, 0x2B, 0xF1, 0x56, 0x9D, 0xEE, 0xFC, 0x19},
+               []byte{0x65, 0xD2, 0x01, 0x79, 0x90, 0xD6, 0x25, 0x28},
+               []byte{0x02, 0x08, 0x3E, 0x39, 0x79, 0xDA, 0x01, 0x48, 0x12, 0xF5, 0x9F, 0x11, 0xD5, 0x26, 0x30, 0xDA, 0x30, 0x13, 0x73, 0x27, 0xD1, 0x06, 0x49, 0xB0, 0xAA, 0x6E, 0x1C, 0x18, 0x1D, 0xB6, 0x17, 0xD7, 0xF2},
+       },
+       {
+               []byte{0x1B, 0xDA, 0x12, 0x2B, 0xCE, 0x8A, 0x8D, 0xBA, 0xF1, 0x87, 0x7D, 0x96, 0x2B, 0x85, 0x92, 0xDD, 0x2D, 0x56},
+               []byte{0x5F, 0xFF, 0x20, 0xCA, 0xFA, 0xB1, 0x19, 0xCA, 0x2F, 0xC7, 0x35, 0x49, 0xE2, 0x0F, 0x5B, 0x0D},
+               []byte{0xDD, 0xE5, 0x9B, 0x97, 0xD7, 0x22, 0x15, 0x6D, 0x4D, 0x9A, 0xFF, 0x2B, 0xC7, 0x55, 0x98, 0x26},
+               []byte{0x54, 0xB9, 0xF0, 0x4E, 0x6A, 0x09, 0x18, 0x9A},
+               []byte{0x2E, 0xC4, 0x7B, 0x2C, 0x49, 0x54, 0xA4, 0x89, 0xAF, 0xC7, 0xBA, 0x48, 0x97, 0xED, 0xCD, 0xAE, 0x8C, 0xC3, 0x3B, 0x60, 0x45, 0x05, 0x99, 0xBD, 0x02, 0xC9, 0x63, 0x82, 0x90, 0x2A, 0xEF, 0x7F, 0x83, 0x2A},
+       },
+       {
+               []byte{0x6C, 0xF3, 0x67, 0x20, 0x87, 0x2B, 0x85, 0x13, 0xF6, 0xEA, 0xB1, 0xA8, 0xA4, 0x44, 0x38, 0xD5, 0xEF, 0x11},
+               []byte{0xA4, 0xA4, 0x78, 0x2B, 0xCF, 0xFD, 0x3E, 0xC5, 0xE7, 0xEF, 0x6D, 0x8C, 0x34, 0xA5, 0x61, 0x23},
+               []byte{0xB7, 0x81, 0xFC, 0xF2, 0xF7, 0x5F, 0xA5, 0xA8, 0xDE, 0x97, 0xA9, 0xCA, 0x48, 0xE5, 0x22, 0xEC},
+               []byte{0x89, 0x9A, 0x17, 0x58, 0x97, 0x56, 0x1D, 0x7E},
+               []byte{0x0D, 0xE1, 0x8F, 0xD0, 0xFD, 0xD9, 0x1E, 0x7A, 0xF1, 0x9F, 0x1D, 0x8E, 0xE8, 0x73, 0x39, 0x38, 0xB1, 0xE8, 0xE7, 0xF6, 0xD2, 0x23, 0x16, 0x18, 0x10, 0x2F, 0xDB, 0x7F, 0xE5, 0x5F, 0xF1, 0x99, 0x17, 0x00},
+       },
+       {
+               []byte{0xCA, 0x40, 0xD7, 0x44, 0x6E, 0x54, 0x5F, 0xFA, 0xED, 0x3B, 0xD1, 0x2A, 0x74, 0x0A, 0x65, 0x9F, 0xFB, 0xBB, 0x3C, 0xEA, 0xB7},
+               []byte{0x83, 0x95, 0xFC, 0xF1, 0xE9, 0x5B, 0xEB, 0xD6, 0x97, 0xBD, 0x01, 0x0B, 0xC7, 0x66, 0xAA, 0xC3},
+               []byte{0x22, 0xE7, 0xAD, 0xD9, 0x3C, 0xFC, 0x63, 0x93, 0xC5, 0x7E, 0xC0, 0xB3, 0xC1, 0x7D, 0x6B, 0x44},
+               []byte{0x12, 0x67, 0x35, 0xFC, 0xC3, 0x20, 0xD2, 0x5A},
+               []byte{0xCB, 0x89, 0x20, 0xF8, 0x7A, 0x6C, 0x75, 0xCF, 0xF3, 0x96, 0x27, 0xB5, 0x6E, 0x3E, 0xD1, 0x97, 0xC5, 0x52, 0xD2, 0x95, 0xA7, 0xCF, 0xC4, 0x6A, 0xFC, 0x25, 0x3B, 0x46, 0x52, 0xB1, 0xAF, 0x37, 0x95, 0xB1, 0x24, 0xAB, 0x6E},
+       },
+}
+
+func TestEAXEncrypt_AES(t *testing.T) {
+       b := new(bytes.Buffer)
+       for i, tt := range eaxAESTests {
+               test := fmt.Sprintf("test %d", i)
+               c, err := aes.NewCipher(tt.key)
+               if err != nil {
+                       t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+               }
+               b.Reset()
+               enc := NewEAXEncrypter(c, tt.nonce, tt.header, 16, b)
+               n, err := io.Copy(enc, bytes.NewBuffer(tt.msg))
+               if n != int64(len(tt.msg)) || err != nil {
+                       t.Fatalf("%s: io.Copy into encrypter: %d, %s", test, n, err)
+               }
+               err = enc.Close()
+               if err != nil {
+                       t.Fatalf("%s: enc.Close: %s", test, err)
+               }
+               if d := b.Bytes(); !same(d, tt.cipher) {
+                       t.Fatalf("%s: got %x want %x", test, d, tt.cipher)
+               }
+       }
+}
+
+func TestEAXDecrypt_AES(t *testing.T) {
+       b := new(bytes.Buffer)
+       for i, tt := range eaxAESTests {
+               test := fmt.Sprintf("test %d", i)
+               c, err := aes.NewCipher(tt.key)
+               if err != nil {
+                       t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+               }
+               b.Reset()
+               dec := NewEAXDecrypter(c, tt.nonce, tt.header, 16, bytes.NewBuffer(tt.cipher))
+               n, err := io.Copy(b, dec)
+               if n != int64(len(tt.msg)) || err != nil {
+                       t.Fatalf("%s: io.Copy into decrypter: %d, %s", test, n, err)
+               }
+               if d := b.Bytes(); !same(d, tt.msg) {
+                       t.Fatalf("%s: got %x want %x", test, d, tt.msg)
+               }
+       }
+}
diff --git a/libgo/go/crypto/block/ecb.go b/libgo/go/crypto/block/ecb.go
new file mode 100644 (file)
index 0000000..cf09f7c
--- /dev/null
@@ -0,0 +1,270 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Electronic codebook (ECB) mode.
+// ECB is a fancy name for ``encrypt and decrypt each block separately.''
+// It's a pretty bad thing to do for any large amount of data (more than one block),
+// because the individual blocks can still be identified, duplicated, and reordered.
+// The ECB implementation exists mainly to provide buffering for
+// the other modes, which wrap it by providing modified Ciphers.
+
+// See NIST SP 800-38A, pp 9-10
+
+package block
+
+import (
+       "io"
+       "os"
+       "strconv"
+)
+
+type ecbDecrypter struct {
+       c         Cipher
+       r         io.Reader
+       blockSize int // block size
+
+       // Buffered data.
+       // The buffer buf is used as storage for both
+       // plain or crypt; at least one of those is nil at any given time.
+       buf   []byte
+       plain []byte // plain text waiting to be read
+       crypt []byte // ciphertext waiting to be decrypted
+}
+
+// Read into x.crypt until it has a full block or EOF or an error happens.
+func (x *ecbDecrypter) fillCrypt() os.Error {
+       var err os.Error
+       for len(x.crypt) < x.blockSize {
+               off := len(x.crypt)
+               var m int
+               m, err = x.r.Read(x.crypt[off:x.blockSize])
+               x.crypt = x.crypt[0 : off+m]
+               if m == 0 {
+                       break
+               }
+
+               // If an error happened but we got enough
+               // data to do some decryption, we can decrypt
+               // first and report the error (with some data) later.
+               // But if we don't have enough to decrypt,
+               // have to stop now.
+               if err != nil && len(x.crypt) < x.blockSize {
+                       break
+               }
+       }
+       return err
+}
+
+// Read from plain text buffer into p.
+func (x *ecbDecrypter) readPlain(p []byte) int {
+       n := len(x.plain)
+       if n > len(p) {
+               n = len(p)
+       }
+       for i := 0; i < n; i++ {
+               p[i] = x.plain[i]
+       }
+       if n < len(x.plain) {
+               x.plain = x.plain[n:]
+       } else {
+               x.plain = nil
+       }
+       return n
+}
+
+type ecbFragmentError int
+
+func (n ecbFragmentError) String() string {
+       return "crypto/block: " + strconv.Itoa(int(n)) + "-byte fragment at EOF"
+}
+
+func (x *ecbDecrypter) Read(p []byte) (n int, err os.Error) {
+       if len(p) == 0 {
+               return
+       }
+
+       // If there's no plaintext waiting and p is not big enough
+       // to hold a whole cipher block, we'll have to work in the
+       // cipher text buffer.  Set it to non-nil so that the
+       // code below will fill it.
+       if x.plain == nil && len(p) < x.blockSize && x.crypt == nil {
+               x.crypt = x.buf[0:0]
+       }
+
+       // If there is a leftover cipher text buffer,
+       // try to accumulate a full block.
+       if x.crypt != nil {
+               err = x.fillCrypt()
+               if err != nil || len(x.crypt) == 0 {
+                       return
+               }
+               x.c.Decrypt(x.crypt, x.crypt)
+               x.plain = x.crypt
+               x.crypt = nil
+       }
+
+       // If there is a leftover plain text buffer, read from it.
+       if x.plain != nil {
+               n = x.readPlain(p)
+               return
+       }
+
+       // Read and decrypt directly in caller's buffer.
+       n, err = io.ReadAtLeast(x.r, p, x.blockSize)
+       if err == os.EOF && n > 0 {
+               // EOF is only okay on block boundary
+               err = os.ErrorString("block fragment at EOF during decryption")
+               return
+       }
+       var i int
+       for i = 0; i+x.blockSize <= n; i += x.blockSize {
+               a := p[i : i+x.blockSize]
+               x.c.Decrypt(a, a)
+       }
+
+       // There might be an encrypted fringe remaining.
+       // Save it for next time.
+       if i < n {
+               p = p[i:n]
+               copy(x.buf, p)
+               x.crypt = x.buf[0:len(p)]
+               n = i
+       }
+
+       return
+}
+
+// NewECBDecrypter returns a reader that reads data from r and decrypts it using c.
+// It decrypts by calling c.Decrypt on each block in sequence;
+// this mode is known as electronic codebook mode, or ECB.
+// The returned Reader does not buffer or read ahead except
+// as required by the cipher's block size.
+func NewECBDecrypter(c Cipher, r io.Reader) io.Reader {
+       x := new(ecbDecrypter)
+       x.c = c
+       x.r = r
+       x.blockSize = c.BlockSize()
+       x.buf = make([]byte, x.blockSize)
+       return x
+}
+
+type ecbEncrypter struct {
+       c         Cipher
+       w         io.Writer
+       blockSize int
+
+       // Buffered data.
+       // The buffer buf is used as storage for both
+       // plain or crypt.  If both are non-nil, plain
+       // follows crypt in buf.
+       buf   []byte
+       plain []byte // plain text waiting to be encrypted
+       crypt []byte // encrypted text waiting to be written
+}
+
+// Flush the x.crypt buffer to x.w.
+func (x *ecbEncrypter) flushCrypt() os.Error {
+       if len(x.crypt) == 0 {
+               return nil
+       }
+       n, err := x.w.Write(x.crypt)
+       if n < len(x.crypt) {
+               x.crypt = x.crypt[n:]
+               if err == nil {
+                       err = io.ErrShortWrite
+               }
+       }
+       if err != nil {
+               return err
+       }
+       x.crypt = nil
+       return nil
+}
+
+// Slide x.plain down to the beginning of x.buf.
+// Plain is known to have less than one block of data,
+// so this is cheap enough.
+func (x *ecbEncrypter) slidePlain() {
+       if len(x.plain) == 0 {
+               x.plain = x.buf[0:0]
+       } else if cap(x.plain) < cap(x.buf) {
+               copy(x.buf, x.plain)
+               x.plain = x.buf[0:len(x.plain)]
+       }
+}
+
+// Fill x.plain from the data in p.
+// Return the number of bytes copied.
+func (x *ecbEncrypter) fillPlain(p []byte) int {
+       off := len(x.plain)
+       n := len(p)
+       if max := cap(x.plain) - off; n > max {
+               n = max
+       }
+       x.plain = x.plain[0 : off+n]
+       for i := 0; i < n; i++ {
+               x.plain[off+i] = p[i]
+       }
+       return n
+}
+
+// Encrypt x.plain; record encrypted range as x.crypt.
+func (x *ecbEncrypter) encrypt() {
+       var i int
+       n := len(x.plain)
+       for i = 0; i+x.blockSize <= n; i += x.blockSize {
+               a := x.plain[i : i+x.blockSize]
+               x.c.Encrypt(a, a)
+       }
+       x.crypt = x.plain[0:i]
+       x.plain = x.plain[i:n]
+}
+
+func (x *ecbEncrypter) Write(p []byte) (n int, err os.Error) {
+       for {
+               // If there is data waiting to be written, write it.
+               // This can happen on the first iteration
+               // if a write failed in an earlier call.
+               if err = x.flushCrypt(); err != nil {
+                       return
+               }
+
+               // Now that encrypted data is gone (flush ran),
+               // perhaps we need to slide the plaintext down.
+               x.slidePlain()
+
+               // Fill plaintext buffer from p.
+               m := x.fillPlain(p)
+               if m == 0 {
+                       break
+               }
+               n += m
+               p = p[m:]
+
+               // Encrypt, adjusting crypt and plain.
+               x.encrypt()
+
+               // Write x.crypt.
+               if err = x.flushCrypt(); err != nil {
+                       break
+               }
+       }
+       return
+}
+
+// NewECBEncrypter returns a writer that encrypts data using c and writes it to w.
+// It encrypts by calling c.Encrypt on each block in sequence;
+// this mode is known as electronic codebook mode, or ECB.
+// The returned Writer does no buffering except as required
+// by the cipher's block size, so there is no need for a Flush method.
+func NewECBEncrypter(c Cipher, w io.Writer) io.Writer {
+       x := new(ecbEncrypter)
+       x.c = c
+       x.w = w
+       x.blockSize = c.BlockSize()
+
+       // Create a buffer that is an integral number of blocks.
+       x.buf = make([]byte, 8192/x.blockSize*x.blockSize)
+       return x
+}
diff --git a/libgo/go/crypto/block/ecb_aes_test.go b/libgo/go/crypto/block/ecb_aes_test.go
new file mode 100644 (file)
index 0000000..14481d0
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// ECB AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 24-27.
+
+package block
+
+import (
+       "bytes"
+       "crypto/aes"
+       "io"
+       "testing"
+)
+
+type ecbTest struct {
+       name string
+       key  []byte
+       in   []byte
+       out  []byte
+}
+
+var commonInput = []byte{
+       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+       0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+}
+
+var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
+
+var commonKey192 = []byte{
+       0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+       0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+}
+
+var commonKey256 = []byte{
+       0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+       0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+}
+
+var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
+
+var ecbAESTests = []ecbTest{
+       // FIPS 197, Appendix B, C
+       {
+               "FIPS-197 Appendix B",
+               commonKey128,
+               []byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
+               []byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
+       },
+
+       // NIST SP 800-38A pp 24-27
+       {
+               "ECB-AES128",
+               commonKey128,
+               commonInput,
+               []byte{
+                       0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
+                       0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf,
+                       0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23, 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88,
+                       0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4,
+               },
+       },
+       {
+               "ECB-AES192",
+               commonKey192,
+               commonInput,
+               []byte{
+                       0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc,
+                       0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad, 0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef,
+                       0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a, 0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e,
+                       0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72, 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e,
+               },
+       },
+       {
+               "ECB-AES256",
+               commonKey256,
+               commonInput,
+               []byte{
+                       0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8,
+                       0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26, 0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70,
+                       0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9, 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d,
+                       0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff, 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7,
+               },
+       },
+}
+
+func TestECB_AES(t *testing.T) {
+       for _, tt := range ecbAESTests {
+               test := tt.name
+
+               c, err := aes.NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+                       continue
+               }
+
+               var crypt bytes.Buffer
+               w := NewECBEncrypter(c, &crypt)
+               var r io.Reader = bytes.NewBuffer(tt.in)
+               n, err := io.Copy(w, r)
+               if n != int64(len(tt.in)) || err != nil {
+                       t.Errorf("%s: ECBReader io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
+               } else if d := crypt.Bytes(); !same(tt.out, d) {
+                       t.Errorf("%s: ECBReader\nhave %x\nwant %x", test, d, tt.out)
+               }
+
+               var plain bytes.Buffer
+               r = NewECBDecrypter(c, bytes.NewBuffer(tt.out))
+               w = &plain
+               n, err = io.Copy(w, r)
+               if n != int64(len(tt.out)) || err != nil {
+                       t.Errorf("%s: ECBWriter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
+               } else if d := plain.Bytes(); !same(tt.in, d) {
+                       t.Errorf("%s: ECBWriter\nhave %x\nwant %x", test, d, tt.in)
+               }
+
+               if t.Failed() {
+                       break
+               }
+       }
+}
diff --git a/libgo/go/crypto/block/ecb_test.go b/libgo/go/crypto/block/ecb_test.go
new file mode 100644 (file)
index 0000000..6f79d92
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package block
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "testing"
+       "testing/iotest"
+)
+
+// Simple Cipher for testing: adds an incrementing amount
+// to each byte in each
+type IncCipher struct {
+       blockSize  int
+       delta      byte
+       encrypting bool
+}
+
+func (c *IncCipher) BlockSize() int { return c.blockSize }
+
+func (c *IncCipher) Encrypt(dst, src []byte) {
+       if !c.encrypting {
+               panic("encrypt: not encrypting")
+       }
+       if len(src) != c.blockSize || len(dst) != c.blockSize {
+               panic(fmt.Sprintln("encrypt: wrong block size", c.blockSize, len(src), len(dst)))
+       }
+       c.delta++
+       for i, b := range src {
+               dst[i] = b + c.delta
+       }
+}
+
+func (c *IncCipher) Decrypt(dst, src []byte) {
+       if c.encrypting {
+               panic("decrypt: not decrypting")
+       }
+       if len(src) != c.blockSize || len(dst) != c.blockSize {
+               panic(fmt.Sprintln("decrypt: wrong block size ", c.blockSize, " ", len(src), " ", len(dst)))
+       }
+       c.delta--
+       for i, b := range src {
+               dst[i] = b + c.delta
+       }
+}
+
+func TestECBEncrypter(t *testing.T) {
+       var plain, crypt [256]byte
+       for i := 0; i < len(plain); i++ {
+               plain[i] = byte(i)
+       }
+       b := new(bytes.Buffer)
+       for block := 1; block <= 64; block *= 2 {
+               // compute encrypted version
+               delta := byte(0)
+               for i := 0; i < len(crypt); i++ {
+                       if i%block == 0 {
+                               delta++
+                       }
+                       crypt[i] = plain[i] + delta
+               }
+
+               for frag := 0; frag < 2; frag++ {
+                       c := &IncCipher{block, 0, true}
+                       b.Reset()
+                       r := bytes.NewBuffer(plain[0:])
+                       w := NewECBEncrypter(c, b)
+
+                       // copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ...
+                       // if frag != 0, move the 1 to the end to cause fragmentation.
+                       if frag == 0 {
+                               _, err := io.Copyn(w, r, 1)
+                               if err != nil {
+                                       t.Errorf("block=%d frag=0: first Copyn: %s", block, err)
+                                       continue
+                               }
+                       }
+                       for n := 1; n <= len(plain)/2; n *= 2 {
+                               _, err := io.Copyn(w, r, int64(n))
+                               if err != nil {
+                                       t.Errorf("block=%d frag=%d: Copyn %d: %s", block, frag, n, err)
+                               }
+                       }
+                       if frag != 0 {
+                               _, err := io.Copyn(w, r, 1)
+                               if err != nil {
+                                       t.Errorf("block=%d frag=1: last Copyn: %s", block, err)
+                                       continue
+                               }
+                       }
+
+                       // check output
+                       data := b.Bytes()
+                       if len(data) != len(crypt) {
+                               t.Errorf("block=%d frag=%d: want %d bytes, got %d", block, frag, len(crypt), len(data))
+                               continue
+                       }
+
+                       if string(data) != string(crypt[0:]) {
+                               t.Errorf("block=%d frag=%d: want %x got %x", block, frag, data, crypt)
+                       }
+               }
+       }
+}
+
+func testECBDecrypter(t *testing.T, maxio int) {
+       var readers = []func(io.Reader) io.Reader{
+               func(r io.Reader) io.Reader { return r },
+               iotest.OneByteReader,
+               iotest.HalfReader,
+       }
+       var plain, crypt [256]byte
+       for i := 0; i < len(plain); i++ {
+               plain[i] = byte(255 - i)
+       }
+       b := new(bytes.Buffer)
+       for block := 1; block <= 64 && block <= maxio; block *= 2 {
+               // compute encrypted version
+               delta := byte(0)
+               for i := 0; i < len(crypt); i++ {
+                       if i%block == 0 {
+                               delta++
+                       }
+                       crypt[i] = plain[i] + delta
+               }
+
+               for mode := 0; mode < len(readers); mode++ {
+                       for frag := 0; frag < 2; frag++ {
+                               test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio)
+                               c := &IncCipher{block, 0, false}
+                               b.Reset()
+                               r := NewECBDecrypter(c, readers[mode](bytes.NewBuffer(crypt[0:maxio])))
+
+                               // read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ...
+                               // if frag == 1, move the 1 to the end to cause fragmentation.
+                               if frag == 0 {
+                                       _, err := io.Copyn(b, r, 1)
+                                       if err != nil {
+                                               t.Errorf("%s: first Copyn: %s", test, err)
+                                               continue
+                                       }
+                               }
+                               for n := 1; n <= maxio/2; n *= 2 {
+                                       _, err := io.Copyn(b, r, int64(n))
+                                       if err != nil {
+                                               t.Errorf("%s: Copyn %d: %s", test, n, err)
+                                       }
+                               }
+                               if frag != 0 {
+                                       _, err := io.Copyn(b, r, 1)
+                                       if err != nil {
+                                               t.Errorf("%s: last Copyn: %s", test, err)
+                                               continue
+                                       }
+                               }
+
+                               // check output
+                               data := b.Bytes()
+                               if len(data) != maxio {
+                                       t.Errorf("%s: want %d bytes, got %d", test, maxio, len(data))
+                                       continue
+                               }
+
+                               if string(data) != string(plain[0:maxio]) {
+                                       t.Errorf("%s: input=%x want %x got %x", test, crypt[0:maxio], plain[0:maxio], data)
+                               }
+                       }
+               }
+       }
+}
+
+func TestECBDecrypter(t *testing.T) {
+       // Do shorter I/O sizes first; they're easier to debug.
+       for n := 1; n <= 256 && !t.Failed(); n *= 2 {
+               testECBDecrypter(t, n)
+       }
+}
diff --git a/libgo/go/crypto/block/ofb.go b/libgo/go/crypto/block/ofb.go
new file mode 100644 (file)
index 0000000..11aaaa4
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Output feedback (OFB) mode.
+
+// OFB converts a block cipher into a stream cipher by
+// repeatedly encrypting an initialization vector and
+// xoring the resulting stream of data with the input.
+
+// See NIST SP 800-38A, pp 13-15
+
+package block
+
+import (
+       "fmt"
+       "io"
+)
+
+type ofbStream struct {
+       c  Cipher
+       iv []byte
+}
+
+func newOFBStream(c Cipher, iv []byte) *ofbStream {
+       x := new(ofbStream)
+       x.c = c
+       n := len(iv)
+       if n != c.BlockSize() {
+               panic(fmt.Sprintln("crypto/block: newOFBStream: invalid iv size", n, "!=", c.BlockSize()))
+       }
+       x.iv = dup(iv)
+       return x
+}
+
+func (x *ofbStream) Next() []byte {
+       x.c.Encrypt(x.iv, x.iv)
+       return x.iv
+}
+
+// NewOFBReader returns a reader that reads data from r, decrypts (or encrypts)
+// it using c in output feedback (OFB) mode with the initialization vector iv.
+// The returned Reader does not buffer and has no block size.
+// In OFB mode, encryption and decryption are the same operation:
+// an OFB reader applied to an encrypted stream produces a decrypted
+// stream and vice versa.
+func NewOFBReader(c Cipher, iv []byte, r io.Reader) io.Reader {
+       return newXorReader(newOFBStream(c, iv), r)
+}
+
+// NewOFBWriter returns a writer that encrypts (or decrypts) data using c
+// in cipher feedback (OFB) mode with the initialization vector iv
+// and writes the encrypted data to w.
+// The returned Writer does not buffer and has no block size.
+// In OFB mode, encryption and decryption are the same operation:
+// an OFB writer applied to an decrypted stream produces an encrypted
+// stream and vice versa.
+func NewOFBWriter(c Cipher, iv []byte, w io.Writer) io.Writer {
+       return newXorWriter(newOFBStream(c, iv), w)
+}
diff --git a/libgo/go/crypto/block/ofb_aes_test.go b/libgo/go/crypto/block/ofb_aes_test.go
new file mode 100644 (file)
index 0000000..9c527a6
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OFB AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 52-55.
+
+package block
+
+import (
+       "bytes"
+       "crypto/aes"
+       "io"
+       "testing"
+)
+
+type ofbTest struct {
+       name string
+       key  []byte
+       iv   []byte
+       in   []byte
+       out  []byte
+}
+
+var ofbAESTests = []ofbTest{
+       // NIST SP 800-38A pp 52-55
+       {
+               "OFB-AES128",
+               commonKey128,
+               commonIV,
+               commonInput,
+               []byte{
+                       0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
+                       0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25,
+                       0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc,
+                       0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e,
+               },
+       },
+       {
+               "OFB-AES192",
+               commonKey192,
+               commonIV,
+               commonInput,
+               []byte{
+                       0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
+                       0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01,
+                       0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2,
+                       0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a,
+               },
+       },
+       {
+               "OFB-AES256",
+               commonKey256,
+               commonIV,
+               commonInput,
+               []byte{
+                       0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
+                       0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d,
+                       0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08,
+                       0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84,
+               },
+       },
+}
+
+func TestOFB_AES(t *testing.T) {
+       for _, tt := range ofbAESTests {
+               test := tt.name
+
+               c, err := aes.NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+                       continue
+               }
+
+               for j := 0; j <= 5; j += 5 {
+                       var crypt bytes.Buffer
+                       in := tt.in[0 : len(tt.in)-j]
+                       w := NewOFBWriter(c, tt.iv, &crypt)
+                       var r io.Reader = bytes.NewBuffer(in)
+                       n, err := io.Copy(w, r)
+                       if n != int64(len(in)) || err != nil {
+                               t.Errorf("%s/%d: OFBWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in))
+                       } else if d, out := crypt.Bytes(), tt.out[0:len(in)]; !same(out, d) {
+                               t.Errorf("%s/%d: OFBWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out)
+                       }
+               }
+
+               for j := 0; j <= 7; j += 7 {
+                       var plain bytes.Buffer
+                       out := tt.out[0 : len(tt.out)-j]
+                       r := NewOFBReader(c, tt.iv, bytes.NewBuffer(out))
+                       w := &plain
+                       n, err := io.Copy(w, r)
+                       if n != int64(len(out)) || err != nil {
+                               t.Errorf("%s/%d: OFBReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out))
+                       } else if d, in := plain.Bytes(), tt.in[0:len(out)]; !same(in, d) {
+                               t.Errorf("%s/%d: OFBReader\nhave %x\nwant %x", test, len(out), d, in)
+                       }
+               }
+
+               if t.Failed() {
+                       break
+               }
+       }
+}
diff --git a/libgo/go/crypto/block/xor.go b/libgo/go/crypto/block/xor.go
new file mode 100644 (file)
index 0000000..9d8b172
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Encrypt/decrypt data by xor with a pseudo-random data stream.
+
+package block
+
+import (
+       "io"
+       "os"
+)
+
+// A dataStream is an interface to an unending stream of data,
+// used by XorReader and XorWriter to model a pseudo-random generator.
+// Calls to Next() return sequential blocks of data from the stream.
+// Each call must return at least one byte: there is no EOF.
+type dataStream interface {
+       Next() []byte
+}
+
+type xorReader struct {
+       r    io.Reader
+       rand dataStream // pseudo-random
+       buf  []byte     // data available from last call to rand
+}
+
+func newXorReader(rand dataStream, r io.Reader) io.Reader {
+       x := new(xorReader)
+       x.r = r
+       x.rand = rand
+       return x
+}
+
+func (x *xorReader) Read(p []byte) (n int, err os.Error) {
+       n, err = x.r.Read(p)
+
+       // xor input with stream.
+       bp := 0
+       buf := x.buf
+       for i := 0; i < n; i++ {
+               if bp >= len(buf) {
+                       buf = x.rand.Next()
+                       bp = 0
+               }
+               p[i] ^= buf[bp]
+               bp++
+       }
+       x.buf = buf[bp:]
+       return n, err
+}
+
+type xorWriter struct {
+       w     io.Writer
+       rand  dataStream // pseudo-random
+       buf   []byte     // last buffer returned by rand
+       extra []byte     // extra random data (use before buf)
+       work  []byte     // work space
+}
+
+func newXorWriter(rand dataStream, w io.Writer) io.Writer {
+       x := new(xorWriter)
+       x.w = w
+       x.rand = rand
+       x.work = make([]byte, 4096)
+       return x
+}
+
+func (x *xorWriter) Write(p []byte) (n int, err os.Error) {
+       for len(p) > 0 {
+               // Determine next chunk of random data
+               // and xor with p into x.work.
+               var chunk []byte
+               m := len(p)
+               if nn := len(x.extra); nn > 0 {
+                       // extra points into work, so edit directly
+                       if m > nn {
+                               m = nn
+                       }
+                       for i := 0; i < m; i++ {
+                               x.extra[i] ^= p[i]
+                       }
+                       chunk = x.extra[0:m]
+               } else {
+                       // xor p ^ buf into work, refreshing buf as needed
+                       if nn := len(x.work); m > nn {
+                               m = nn
+                       }
+                       bp := 0
+                       buf := x.buf
+                       for i := 0; i < m; i++ {
+                               if bp >= len(buf) {
+                                       buf = x.rand.Next()
+                                       bp = 0
+                               }
+                               x.work[i] = buf[bp] ^ p[i]
+                               bp++
+                       }
+                       x.buf = buf[bp:]
+                       chunk = x.work[0:m]
+               }
+
+               // Write chunk.
+               var nn int
+               nn, err = x.w.Write(chunk)
+               if nn != len(chunk) && err == nil {
+                       err = io.ErrShortWrite
+               }
+               if nn < len(chunk) {
+                       // Reconstruct the random bits from the unwritten
+                       // data and save them for next time.
+                       for i := nn; i < m; i++ {
+                               chunk[i] ^= p[i]
+                       }
+                       x.extra = chunk[nn:]
+               }
+               n += nn
+               if err != nil {
+                       return
+               }
+               p = p[m:]
+       }
+       return
+}
diff --git a/libgo/go/crypto/block/xor_test.go b/libgo/go/crypto/block/xor_test.go
new file mode 100644 (file)
index 0000000..50f6bb0
--- /dev/null
@@ -0,0 +1,168 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package block
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "testing"
+       "testing/iotest"
+)
+
+// Simple "pseudo-random" stream for testing.
+type incStream struct {
+       buf []byte
+       n   byte
+}
+
+func newIncStream(blockSize int) *incStream {
+       x := new(incStream)
+       x.buf = make([]byte, blockSize)
+       return x
+}
+
+func (x *incStream) Next() []byte {
+       x.n++
+       for i := range x.buf {
+               x.buf[i] = x.n
+               x.n++
+       }
+       return x.buf
+}
+
+func testXorWriter(t *testing.T, maxio int) {
+       var plain, crypt [256]byte
+       for i := 0; i < len(plain); i++ {
+               plain[i] = byte(i)
+       }
+       b := new(bytes.Buffer)
+       for block := 1; block <= 64 && block <= maxio; block *= 2 {
+               // compute encrypted version
+               n := byte(0)
+               for i := 0; i < len(crypt); i++ {
+                       if i%block == 0 {
+                               n++
+                       }
+                       crypt[i] = plain[i] ^ n
+                       n++
+               }
+
+               for frag := 0; frag < 2; frag++ {
+                       test := fmt.Sprintf("block=%d frag=%d maxio=%d", block, frag, maxio)
+                       b.Reset()
+                       r := bytes.NewBuffer(plain[0:])
+                       s := newIncStream(block)
+                       w := newXorWriter(s, b)
+
+                       // copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ...
+                       // if frag != 0, move the 1 to the end to cause fragmentation.
+                       if frag == 0 {
+                               _, err := io.Copyn(w, r, 1)
+                               if err != nil {
+                                       t.Errorf("%s: first Copyn: %s", test, err)
+                                       continue
+                               }
+                       }
+                       for n := 1; n <= len(plain)/2; n *= 2 {
+                               _, err := io.Copyn(w, r, int64(n))
+                               if err != nil {
+                                       t.Errorf("%s: Copyn %d: %s", test, n, err)
+                               }
+                       }
+
+                       // check output
+                       crypt := crypt[0 : len(crypt)-frag]
+                       data := b.Bytes()
+                       if len(data) != len(crypt) {
+                               t.Errorf("%s: want %d bytes, got %d", test, len(crypt), len(data))
+                               continue
+                       }
+
+                       if string(data) != string(crypt) {
+                               t.Errorf("%s: want %x got %x", test, data, crypt)
+                       }
+               }
+       }
+}
+
+
+func TestXorWriter(t *testing.T) {
+       // Do shorter I/O sizes first; they're easier to debug.
+       for n := 1; n <= 256 && !t.Failed(); n *= 2 {
+               testXorWriter(t, n)
+       }
+}
+
+func testXorReader(t *testing.T, maxio int) {
+       var readers = []func(io.Reader) io.Reader{
+               func(r io.Reader) io.Reader { return r },
+               iotest.OneByteReader,
+               iotest.HalfReader,
+       }
+       var plain, crypt [256]byte
+       for i := 0; i < len(plain); i++ {
+               plain[i] = byte(255 - i)
+       }
+       b := new(bytes.Buffer)
+       for block := 1; block <= 64 && block <= maxio; block *= 2 {
+               // compute encrypted version
+               n := byte(0)
+               for i := 0; i < len(crypt); i++ {
+                       if i%block == 0 {
+                               n++
+                       }
+                       crypt[i] = plain[i] ^ n
+                       n++
+               }
+
+               for mode := 0; mode < len(readers); mode++ {
+                       for frag := 0; frag < 2; frag++ {
+                               test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio)
+                               s := newIncStream(block)
+                               b.Reset()
+                               r := newXorReader(s, readers[mode](bytes.NewBuffer(crypt[0:maxio])))
+
+                               // read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ...
+                               // if frag == 1, move the 1 to the end to cause fragmentation.
+                               if frag == 0 {
+                                       _, err := io.Copyn(b, r, 1)
+                                       if err != nil {
+                                               t.Errorf("%s: first Copyn: %s", test, err)
+                                               continue
+                                       }
+                               }
+                               for n := 1; n <= maxio/2; n *= 2 {
+                                       _, err := io.Copyn(b, r, int64(n))
+                                       if err != nil {
+                                               t.Errorf("%s: Copyn %d: %s", test, n, err)
+                                       }
+                               }
+
+                               // check output
+                               data := b.Bytes()
+                               crypt := crypt[0 : maxio-frag]
+                               plain := plain[0 : maxio-frag]
+                               if len(data) != len(plain) {
+                                       t.Errorf("%s: want %d bytes, got %d", test, len(plain), len(data))
+                                       continue
+                               }
+
+                               if string(data) != string(plain) {
+                                       t.Errorf("%s: input=%x want %x got %x", test, crypt, plain, data)
+                               }
+                       }
+               }
+       }
+}
+
+func TestXorReader(t *testing.T) {
+       // Do shorter I/O sizes first; they're easier to debug.
+       for n := 1; n <= 256 && !t.Failed(); n *= 2 {
+               testXorReader(t, n)
+       }
+}
+
+// TODO(rsc): Test handling of writes after write errors.
diff --git a/libgo/go/crypto/blowfish/block.go b/libgo/go/crypto/blowfish/block.go
new file mode 100644 (file)
index 0000000..7fbe7ee
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+func expandKey(key []byte, c *Cipher) {
+       copy(c.p[0:], p[0:])
+       copy(c.s0[0:], s0[0:])
+       copy(c.s1[0:], s1[0:])
+       copy(c.s2[0:], s2[0:])
+       copy(c.s3[0:], s3[0:])
+
+       j := 0
+       for i := 0; i < 18; i++ {
+               var d uint32
+               for k := 0; k < 4; k++ {
+                       d = d<<8 | uint32(key[j])&0x000000FF
+                       j++
+                       if j >= len(key) {
+                               j = 0
+                       }
+               }
+               c.p[i] ^= d
+       }
+
+       var l, r uint32
+       for i := 0; i < 18; i += 2 {
+               l, r = encryptBlock(l, r, c)
+               c.p[i], c.p[i+1] = l, r
+       }
+
+       for i := 0; i < 256; i += 2 {
+               l, r = encryptBlock(l, r, c)
+               c.s0[i], c.s0[i+1] = l, r
+       }
+       for i := 0; i < 256; i += 2 {
+               l, r = encryptBlock(l, r, c)
+               c.s1[i], c.s1[i+1] = l, r
+       }
+       for i := 0; i < 256; i += 2 {
+               l, r = encryptBlock(l, r, c)
+               c.s2[i], c.s2[i+1] = l, r
+       }
+       for i := 0; i < 256; i += 2 {
+               l, r = encryptBlock(l, r, c)
+               c.s3[i], c.s3[i+1] = l, r
+       }
+}
+
+func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+       xl, xr := l, r
+       xl ^= c.p[0]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
+       xr ^= c.p[17]
+       return xr, xl
+}
+
+func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+       xl, xr := l, r
+       xl ^= c.p[17]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
+       xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
+       xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
+       xr ^= c.p[0]
+       return xr, xl
+}
+
+func zero(x []uint32) {
+       for i := range x {
+               x[i] = 0
+       }
+}
diff --git a/libgo/go/crypto/blowfish/blowfish_test.go b/libgo/go/crypto/blowfish/blowfish_test.go
new file mode 100644 (file)
index 0000000..3a7ab6c
--- /dev/null
@@ -0,0 +1,192 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+import (
+       "testing"
+)
+
+type CryptTest struct {
+       key []byte
+       in  []byte
+       out []byte
+}
+
+// Test vector values are from http://www.schneier.com/code/vectors.txt.
+var encryptTests = []CryptTest{
+       {
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+       {
+               []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+               []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+               []byte{0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A}},
+       {
+               []byte{0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+               []byte{0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2}},
+       {
+               []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+               []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+               []byte{0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D}},
+
+       {
+               []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+               []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+               []byte{0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96}},
+       {
+               []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+               []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+               []byte{0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7}},
+       {
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+       {
+               []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+               []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+               []byte{0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D}},
+       {
+               []byte{0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57},
+               []byte{0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42},
+               []byte{0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B}},
+       {
+               []byte{0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E},
+               []byte{0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA},
+               []byte{0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0}},
+       {
+               []byte{0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86},
+               []byte{0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72},
+               []byte{0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4}},
+       {
+               []byte{0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E},
+               []byte{0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A},
+               []byte{0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB}},
+       {
+               []byte{0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6},
+               []byte{0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2},
+               []byte{0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A}},
+       {
+               []byte{0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE},
+               []byte{0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A},
+               []byte{0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18}},
+       {
+               []byte{0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6},
+               []byte{0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2},
+               []byte{0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98}},
+       {
+               []byte{0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE},
+               []byte{0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A},
+               []byte{0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5}},
+       {
+               []byte{0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16},
+               []byte{0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
+               []byte{0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79}},
+       {
+               []byte{0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F},
+               []byte{0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A},
+               []byte{0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3}},
+       {
+               []byte{0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46},
+               []byte{0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32},
+               []byte{0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69}},
+       {
+               []byte{0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E},
+               []byte{0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA},
+               []byte{0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B}},
+       {
+               []byte{0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76},
+               []byte{0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62},
+               []byte{0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E}},
+       {
+               []byte{0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07},
+               []byte{0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2},
+               []byte{0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD}},
+       {
+               []byte{0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F},
+               []byte{0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA},
+               []byte{0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19}},
+       {
+               []byte{0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7},
+               []byte{0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92},
+               []byte{0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3}},
+       {
+               []byte{0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF},
+               []byte{0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A},
+               []byte{0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5}},
+       {
+               []byte{0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6},
+               []byte{0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2},
+               []byte{0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78}},
+       {
+               []byte{0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF},
+               []byte{0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A},
+               []byte{0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01}},
+       {
+               []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+               []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+               []byte{0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2}},
+       {
+               []byte{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
+               []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+               []byte{0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE}},
+       {
+               []byte{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
+               []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+               []byte{0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D}},
+       {
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+               []byte{0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4}},
+       {
+               []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC}},
+       {
+               []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A}},
+       {
+               []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+               []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+               []byte{0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A}},
+}
+
+func TestCipherEncrypt(t *testing.T) {
+       for i, tt := range encryptTests {
+               c, err := NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+                       continue
+               }
+               ct := make([]byte, len(tt.out))
+               c.Encrypt(ct, tt.in)
+               for j, v := range ct {
+                       if v != tt.out[j] {
+                               t.Errorf("Cipher.Encrypt, test vector #%d: cipher-text[%d] = %#x, expected %#x", i, j, v, tt.out[j])
+                               break
+                       }
+               }
+       }
+}
+
+func TestCipherDecrypt(t *testing.T) {
+       for i, tt := range encryptTests {
+               c, err := NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+                       continue
+               }
+               pt := make([]byte, len(tt.in))
+               c.Decrypt(pt, tt.out)
+               for j, v := range pt {
+                       if v != tt.in[j] {
+                               t.Errorf("Cipher.Decrypt, test vector #%d: plain-text[%d] = %#x, expected %#x", i, j, v, tt.in[j])
+                               break
+                       }
+               }
+       }
+}
diff --git a/libgo/go/crypto/blowfish/cipher.go b/libgo/go/crypto/blowfish/cipher.go
new file mode 100644 (file)
index 0000000..947f762
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements Bruce Schneier's Blowfish encryption algorithm.
+package blowfish
+
+// The code is a port of Bruce Schneier's C implementation.
+// See http://www.schneier.com/blowfish.html.
+
+import (
+       "os"
+       "strconv"
+)
+
+// The Blowfish block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of Blowfish encryption using a particular key.
+type Cipher struct {
+       p              [18]uint32
+       s0, s1, s2, s3 [256]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+       return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Blowfish key, 4 to 56 bytes.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+       k := len(key)
+       if k < 4 || k > 56 {
+               return nil, KeySizeError(k)
+       }
+       var result Cipher
+       expandKey(key, &result)
+       return &result, nil
+}
+
+// BlockSize returns the Blowfish block size, 8 bytes.
+// It is necessary to satisfy the Cipher interface in the
+// package "crypto/block".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+       l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+       r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+       l, r = encryptBlock(l, r, c)
+       dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+       dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Decrypt decrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) {
+       l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+       r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+       l, r = decryptBlock(l, r, c)
+       dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+       dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Reset zeros the key data, so that it will no longer
+// appear in the process's memory.
+func (c *Cipher) Reset() {
+       zero(c.p[0:])
+       zero(c.s0[0:])
+       zero(c.s1[0:])
+       zero(c.s2[0:])
+       zero(c.s3[0:])
+}
diff --git a/libgo/go/crypto/blowfish/const.go b/libgo/go/crypto/blowfish/const.go
new file mode 100644 (file)
index 0000000..8c5ee4c
--- /dev/null
@@ -0,0 +1,199 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The startup permutation array and substitution boxes.
+// They are the hexadecimal digits of PI; see:
+// http://www.schneier.com/code/constants.txt.
+
+package blowfish
+
+var s0 = [256]uint32{
+       0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+       0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+       0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+       0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+       0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+       0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+       0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+       0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+       0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+       0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+       0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+       0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+       0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+       0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+       0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+       0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+       0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+       0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+       0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+       0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+       0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+       0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+       0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+       0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+       0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+       0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+       0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+       0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+       0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+       0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+       0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+       0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+       0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+       0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+       0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+       0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+       0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+       0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+       0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+       0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+       0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+       0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+       0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+}
+
+var s1 = [256]uint32{
+       0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+       0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+       0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+       0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+       0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+       0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+       0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+       0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+       0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+       0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+       0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+       0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+       0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+       0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+       0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+       0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+       0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+       0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+       0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+       0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+       0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+       0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+       0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+       0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+       0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+       0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+       0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+       0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+       0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+       0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+       0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+       0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+       0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+       0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+       0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+       0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+       0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+       0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+       0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+       0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+       0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+       0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+       0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+}
+
+var s2 = [256]uint32{
+       0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+       0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+       0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+       0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+       0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+       0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+       0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+       0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+       0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+       0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+       0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+       0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+       0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+       0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+       0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+       0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+       0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+       0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+       0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+       0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+       0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+       0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+       0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+       0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+       0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+       0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+       0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+       0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+       0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+       0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+       0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+       0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+       0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+       0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+       0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+       0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+       0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+       0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+       0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+       0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+       0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+       0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+       0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+}
+
+var s3 = [256]uint32{
+       0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+       0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+       0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+       0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+       0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+       0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+       0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+       0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+       0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+       0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+       0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+       0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+       0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+       0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+       0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+       0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+       0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+       0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+       0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+       0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+       0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+       0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+       0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+       0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+       0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+       0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+       0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+       0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+       0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+       0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+       0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+       0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+       0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+       0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+       0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+       0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+       0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+       0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+       0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+       0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+       0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+       0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+       0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+}
+
+var p = [18]uint32{
+       0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+       0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+       0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
+}
diff --git a/libgo/go/crypto/cast5/cast5.go b/libgo/go/crypto/cast5/cast5.go
new file mode 100644 (file)
index 0000000..35f3e64
--- /dev/null
@@ -0,0 +1,536 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements CAST5, as defined in RFC 2144. CAST5 is a common
+// OpenPGP cipher.
+package cast5
+
+import (
+       "os"
+)
+
+const BlockSize = 8
+const KeySize = 16
+
+type Cipher struct {
+       masking [16]uint32
+       rotate  [16]uint8
+}
+
+func NewCipher(key []byte) (c *Cipher, err os.Error) {
+       if len(key) != KeySize {
+               return nil, os.ErrorString("CAST5: keys must be 16 bytes")
+       }
+
+       c = new(Cipher)
+       c.keySchedule(key)
+       return
+}
+
+func (c *Cipher) BlockSize() int {
+       return BlockSize
+}
+
+// Reset zeros the key material in memory.
+func (c *Cipher) Reset() {
+       for i := 0; i < 16; i++ {
+               c.masking[i] = 0
+               c.rotate[i] = 0
+       }
+}
+
+func (c *Cipher) Encrypt(dst, src []byte) {
+       l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+       r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+       l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+       l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+       l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+       l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+
+       l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+       l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+       l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+       l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+
+       l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+       l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+       l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+       l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+
+       l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+       l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+       l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+       l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+
+       dst[0] = uint8(r >> 24)
+       dst[1] = uint8(r >> 16)
+       dst[2] = uint8(r >> 8)
+       dst[3] = uint8(r)
+       dst[4] = uint8(l >> 24)
+       dst[5] = uint8(l >> 16)
+       dst[6] = uint8(l >> 8)
+       dst[7] = uint8(l)
+}
+
+func (c *Cipher) Decrypt(dst, src []byte) {
+       l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+       r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+       l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+       l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+       l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+       l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+
+       l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+       l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+       l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+       l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+
+       l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+       l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+       l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+       l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+
+       l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+       l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+       l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+       l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+
+       dst[0] = uint8(r >> 24)
+       dst[1] = uint8(r >> 16)
+       dst[2] = uint8(r >> 8)
+       dst[3] = uint8(r)
+       dst[4] = uint8(l >> 24)
+       dst[5] = uint8(l >> 16)
+       dst[6] = uint8(l >> 8)
+       dst[7] = uint8(l)
+}
+
+type keyScheduleA [4][7]uint8
+type keyScheduleB [4][5]uint8
+
+// keyScheduleRound contains the magic values for a round of the key schedule.
+// The keyScheduleA deals with the lines like:
+//   z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]
+// Conceptually, both x and z are in the same array, x first. The first
+// element describes which word of this array gets written to and the
+// second, which word gets read. So, for the line above, it's "4, 0", because
+// it's writing to the first word of z, which, being after x, is word 4, and
+// reading from the first word of x: word 0.
+//
+// Next are the indexes into the S-boxes. Now the array is treated as bytes. So
+// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear
+// that it's z that we're indexing.
+//
+// keyScheduleB deals with lines like:
+//   K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]
+// "K1" is ignored because key words are always written in order. So the five
+// elements are the S-box indexes. They use the same form as in keyScheduleA,
+// above.
+
+type keyScheduleRound struct{}
+type keySchedule []keyScheduleRound
+
+var schedule = []struct {
+       a keyScheduleA
+       b keyScheduleB
+}{
+       {
+               keyScheduleA{
+                       {4, 0, 0xd, 0xf, 0xc, 0xe, 0x8},
+                       {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+                       {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+                       {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+               },
+               keyScheduleB{
+                       {16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2},
+                       {16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6},
+                       {16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9},
+                       {16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc},
+               },
+       },
+       {
+               keyScheduleA{
+                       {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+                       {1, 4, 0, 2, 1, 3, 16 + 2},
+                       {2, 5, 7, 6, 5, 4, 16 + 1},
+                       {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+               },
+               keyScheduleB{
+                       {3, 2, 0xc, 0xd, 8},
+                       {1, 0, 0xe, 0xf, 0xd},
+                       {7, 6, 8, 9, 3},
+                       {5, 4, 0xa, 0xb, 7},
+               },
+       },
+       {
+               keyScheduleA{
+                       {4, 0, 0xd, 0xf, 0xc, 0xe, 8},
+                       {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+                       {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+                       {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+               },
+               keyScheduleB{
+                       {16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9},
+                       {16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc},
+                       {16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2},
+                       {16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6},
+               },
+       },
+       {
+               keyScheduleA{
+                       {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+                       {1, 4, 0, 2, 1, 3, 16 + 2},
+                       {2, 5, 7, 6, 5, 4, 16 + 1},
+                       {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+               },
+               keyScheduleB{
+                       {8, 9, 7, 6, 3},
+                       {0xa, 0xb, 5, 4, 7},
+                       {0xc, 0xd, 3, 2, 8},
+                       {0xe, 0xf, 1, 0, 0xd},
+               },
+       },
+}
+
+func (c *Cipher) keySchedule(in []byte) {
+       var t [8]uint32
+       var k [32]uint32
+
+       for i := 0; i < 4; i++ {
+               j := i * 4
+               t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3])
+       }
+
+       x := []byte{6, 7, 4, 5}
+       ki := 0
+
+       for half := 0; half < 2; half++ {
+               for _, round := range schedule {
+                       for j := 0; j < 4; j++ {
+                               var a [7]uint8
+                               copy(a[:], round.a[j][:])
+                               w := t[a[1]]
+                               w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff]
+                               w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff]
+                               w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff]
+                               w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff]
+                               w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff]
+                               t[a[0]] = w
+                       }
+
+                       for j := 0; j < 4; j++ {
+                               var b [5]uint8
+                               copy(b[:], round.b[j][:])
+                               w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff]
+                               w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff]
+                               w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff]
+                               w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff]
+                               w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff]
+                               k[ki] = w
+                               ki++
+                       }
+               }
+       }
+
+       for i := 0; i < 16; i++ {
+               c.masking[i] = k[i]
+               c.rotate[i] = uint8(k[16+i] & 0x1f)
+       }
+}
+
+// These are the three 'f' functions. See RFC 2144, section 2.2.
+func f1(d, m uint32, r uint8) uint32 {
+       t := m + d
+       I := (t << r) | (t >> (32 - r))
+       return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff]
+}
+
+func f2(d, m uint32, r uint8) uint32 {
+       t := m ^ d
+       I := (t << r) | (t >> (32 - r))
+       return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff]
+}
+
+func f3(d, m uint32, r uint8) uint32 {
+       t := m - d
+       I := (t << r) | (t >> (32 - r))
+       return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff]
+}
+
+var sBox = [8][256]uint32{
+       {
+               0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+               0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+               0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+               0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+               0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+               0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+               0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+               0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+               0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+               0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+               0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+               0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+               0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+               0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+               0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+               0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+               0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+               0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+               0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+               0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+               0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+               0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+               0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+               0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+               0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+               0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+               0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+               0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+               0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+               0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+               0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+               0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
+       },
+       {
+               0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+               0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+               0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+               0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+               0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+               0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+               0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+               0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+               0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+               0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+               0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+               0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+               0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+               0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+               0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+               0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+               0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+               0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+               0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+               0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+               0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+               0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+               0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+               0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+               0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+               0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+               0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+               0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+               0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+               0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+               0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+               0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
+       },
+       {
+               0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+               0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+               0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+               0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+               0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+               0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+               0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+               0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+               0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+               0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+               0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+               0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+               0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+               0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+               0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+               0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+               0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+               0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+               0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+               0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+               0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+               0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+               0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+               0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+               0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+               0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+               0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+               0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+               0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+               0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+               0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+               0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
+       },
+       {
+               0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+               0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+               0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+               0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+               0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+               0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+               0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+               0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+               0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+               0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+               0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+               0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+               0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+               0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+               0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+               0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+               0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+               0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+               0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+               0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+               0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+               0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+               0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+               0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+               0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+               0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+               0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+               0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+               0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+               0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+               0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+               0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
+       },
+       {
+               0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+               0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+               0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+               0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+               0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+               0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+               0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+               0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+               0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+               0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+               0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+               0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+               0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+               0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+               0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+               0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+               0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+               0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+               0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+               0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+               0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+               0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+               0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+               0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+               0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+               0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+               0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+               0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+               0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+               0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+               0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+               0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
+       },
+       {
+               0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+               0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+               0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+               0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+               0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+               0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+               0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+               0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+               0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+               0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+               0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+               0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+               0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+               0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+               0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+               0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+               0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+               0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+               0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+               0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+               0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+               0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+               0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+               0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+               0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+               0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+               0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+               0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+               0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+               0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+               0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+               0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
+       },
+       {
+               0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+               0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+               0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+               0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+               0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+               0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+               0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+               0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+               0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+               0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+               0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+               0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+               0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+               0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+               0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+               0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+               0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+               0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+               0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+               0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+               0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+               0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+               0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+               0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+               0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+               0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+               0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+               0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+               0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+               0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+               0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+               0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
+       },
+       {
+               0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+               0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+               0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+               0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+               0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+               0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+               0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+               0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+               0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+               0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+               0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+               0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+               0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+               0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+               0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+               0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+               0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+               0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+               0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+               0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+               0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+               0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+               0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+               0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+               0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+               0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+               0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+               0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+               0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+               0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+               0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+               0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
+       },
+}
diff --git a/libgo/go/crypto/cast5/cast5_test.go b/libgo/go/crypto/cast5/cast5_test.go
new file mode 100644 (file)
index 0000000..5f7025f
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cast5
+
+import (
+       "bytes"
+       "encoding/hex"
+       "testing"
+)
+
+// This test vector is taken from RFC 2144, App B.1.
+// Since the other two test vectors are for reduced-round variants, we can't
+// use them.
+var basicTests = []struct {
+       key, plainText, cipherText string
+}{
+       {
+               "0123456712345678234567893456789a",
+               "0123456789abcdef",
+               "238b4fe5847e44b2",
+       },
+}
+
+func TestBasic(t *testing.T) {
+       for i, test := range basicTests {
+               key, _ := hex.DecodeString(test.key)
+               plainText, _ := hex.DecodeString(test.plainText)
+               expected, _ := hex.DecodeString(test.cipherText)
+
+               c, err := NewCipher(key)
+               if err != nil {
+                       t.Errorf("#%d: failed to create Cipher: %s", i, err)
+                       continue
+               }
+               var cipherText [BlockSize]byte
+               c.Encrypt(cipherText[:], plainText)
+               if !bytes.Equal(cipherText[:], expected) {
+                       t.Errorf("#%d: got:%x want:%x", i, cipherText, expected)
+               }
+
+               var plainTextAgain [BlockSize]byte
+               c.Decrypt(plainTextAgain[:], cipherText[:])
+               if !bytes.Equal(plainTextAgain[:], plainText) {
+                       t.Errorf("#%d: got:%x want:%x", i, plainTextAgain, plainText)
+               }
+       }
+}
+
+// TestFull performs the test specified in RFC 2144, App B.2.
+// However, due to the length of time taken, it's disabled here and a more
+// limited version is included, below.
+func TestFull(t *testing.T) {
+       // This is too slow for normal testing
+       return
+
+       a, b := iterate(1000000)
+
+       const expectedA = "eea9d0a249fd3ba6b3436fb89d6dca92"
+       const expectedB = "b2c95eb00c31ad7180ac05b8e83d696e"
+
+       if hex.EncodeToString(a) != expectedA {
+               t.Errorf("a: got:%x want:%s", a, expectedA)
+       }
+       if hex.EncodeToString(b) != expectedB {
+               t.Errorf("b: got:%x want:%s", b, expectedB)
+       }
+}
+
+func iterate(iterations int) ([]byte, []byte) {
+       const initValueHex = "0123456712345678234567893456789a"
+
+       initValue, _ := hex.DecodeString(initValueHex)
+
+       var a, b [16]byte
+       copy(a[:], initValue)
+       copy(b[:], initValue)
+
+       for i := 0; i < iterations; i++ {
+               c, _ := NewCipher(b[:])
+               c.Encrypt(a[:8], a[:8])
+               c.Encrypt(a[8:], a[8:])
+               c, _ = NewCipher(a[:])
+               c.Encrypt(b[:8], b[:8])
+               c.Encrypt(b[8:], b[8:])
+       }
+
+       return a[:], b[:]
+}
+
+func TestLimited(t *testing.T) {
+       a, b := iterate(1000)
+
+       const expectedA = "23f73b14b02a2ad7dfb9f2c35644798d"
+       const expectedB = "e5bf37eff14c456a40b21ce369370a9f"
+
+       if hex.EncodeToString(a) != expectedA {
+               t.Errorf("a: got:%x want:%s", a, expectedA)
+       }
+       if hex.EncodeToString(b) != expectedB {
+               t.Errorf("b: got:%x want:%s", b, expectedB)
+       }
+}
diff --git a/libgo/go/crypto/hmac/hmac.go b/libgo/go/crypto/hmac/hmac.go
new file mode 100644 (file)
index 0000000..3b5aa13
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The hmac package implements the Keyed-Hash Message Authentication Code (HMAC)
+// as defined in U.S. Federal Information Processing Standards Publication 198.
+// An HMAC is a cryptographic hash that uses a key to sign a message.
+// The receiver verifies the hash by recomputing it using the same key.
+package hmac
+
+import (
+       "crypto/md5"
+       "crypto/sha1"
+       "hash"
+       "os"
+)
+
+// FIPS 198:
+// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
+
+// key is zero padded to 64 bytes
+// ipad = 0x36 byte repeated to 64 bytes
+// opad = 0x5c byte repeated to 64 bytes
+// hmac = H([key ^ opad] H([key ^ ipad] text))
+
+const (
+       // NOTE(rsc): This constant is actually the
+       // underlying hash function's block size.
+       // HMAC is only conventionally used with
+       // MD5 and SHA1, and both use 64-byte blocks.
+       // The hash.Hash interface doesn't provide a
+       // way to find out the block size.
+       padSize = 64
+)
+
+type hmac struct {
+       size         int
+       key, tmp     []byte
+       outer, inner hash.Hash
+}
+
+func (h *hmac) tmpPad(xor byte) {
+       for i, k := range h.key {
+               h.tmp[i] = xor ^ k
+       }
+       for i := len(h.key); i < padSize; i++ {
+               h.tmp[i] = xor
+       }
+}
+
+func (h *hmac) Sum() []byte {
+       sum := h.inner.Sum()
+       h.tmpPad(0x5c)
+       for i, b := range sum {
+               h.tmp[padSize+i] = b
+       }
+       h.outer.Reset()
+       h.outer.Write(h.tmp)
+       return h.outer.Sum()
+}
+
+func (h *hmac) Write(p []byte) (n int, err os.Error) {
+       return h.inner.Write(p)
+}
+
+func (h *hmac) Size() int { return h.size }
+
+func (h *hmac) Reset() {
+       h.inner.Reset()
+       h.tmpPad(0x36)
+       h.inner.Write(h.tmp[0:padSize])
+}
+
+// New returns a new HMAC hash using the given hash generator and key.
+func New(h func() hash.Hash, key []byte) hash.Hash {
+       hm := new(hmac)
+       hm.outer = h()
+       hm.inner = h()
+       hm.size = hm.inner.Size()
+       hm.tmp = make([]byte, padSize+hm.size)
+       if len(key) > padSize {
+               // If key is too big, hash it.
+               hm.outer.Write(key)
+               key = hm.outer.Sum()
+       }
+       hm.key = make([]byte, len(key))
+       copy(hm.key, key)
+       hm.Reset()
+       return hm
+}
+
+// NewMD5 returns a new HMAC-MD5 hash using the given key.
+func NewMD5(key []byte) hash.Hash { return New(md5.New, key) }
+
+// NewSHA1 returns a new HMAC-SHA1 hash using the given key.
+func NewSHA1(key []byte) hash.Hash { return New(sha1.New, key) }
diff --git a/libgo/go/crypto/hmac/hmac_test.go b/libgo/go/crypto/hmac/hmac_test.go
new file mode 100644 (file)
index 0000000..1a50fa3
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hmac
+
+import (
+       "hash"
+       "fmt"
+       "testing"
+)
+
+type hmacTest struct {
+       hash func([]byte) hash.Hash
+       key  []byte
+       in   []byte
+       out  string
+}
+
+// Tests from US FIPS 198
+// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
+var hmacTests = []hmacTest{
+       {
+               NewSHA1,
+               []byte{
+                       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+                       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+                       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+                       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+               },
+               []byte("Sample #1"),
+               "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a",
+       },
+       {
+               NewSHA1,
+               []byte{
+                       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+                       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+                       0x40, 0x41, 0x42, 0x43,
+               },
+               []byte("Sample #2"),
+               "0922d3405faa3d194f82a45830737d5cc6c75d24",
+       },
+       {
+               NewSHA1,
+               []byte{
+                       0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+                       0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+                       0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+                       0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+                       0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+                       0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+                       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+                       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+                       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+                       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+                       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+                       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+                       0xb0, 0xb1, 0xb2, 0xb3,
+               },
+               []byte("Sample #3"),
+               "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa",
+       },
+
+       // Test from Plan 9.
+       {
+               NewMD5,
+               []byte("Jefe"),
+               []byte("what do ya want for nothing?"),
+               "750c783e6ab0b503eaa86e310a5db738",
+       },
+}
+
+func TestHMAC(t *testing.T) {
+       for i, tt := range hmacTests {
+               h := tt.hash(tt.key)
+               for j := 0; j < 2; j++ {
+                       n, err := h.Write(tt.in)
+                       if n != len(tt.in) || err != nil {
+                               t.Errorf("test %d.%d: Write(%d) = %d, %v", i, j, len(tt.in), n, err)
+                               continue
+                       }
+
+                       // Repetive Sum() calls should return the same value
+                       for k := 0; k < 2; k++ {
+                               sum := fmt.Sprintf("%x", h.Sum())
+                               if sum != tt.out {
+                                       t.Errorf("test %d.%d.%d: have %s want %s\n", i, j, k, sum, tt.out)
+                               }
+                       }
+
+                       // Second iteration: make sure reset works.
+                       h.Reset()
+               }
+       }
+}
diff --git a/libgo/go/crypto/md4/md4.go b/libgo/go/crypto/md4/md4.go
new file mode 100644 (file)
index 0000000..e13c986
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the MD4 hash algorithm as defined in RFC 1320.
+package md4
+
+import (
+       "hash"
+       "os"
+)
+
+// The size of an MD4 checksum in bytes.
+const Size = 16
+
+const (
+       _Chunk = 64
+       _Init0 = 0x67452301
+       _Init1 = 0xEFCDAB89
+       _Init2 = 0x98BADCFE
+       _Init3 = 0x10325476
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+       s   [4]uint32
+       x   [_Chunk]byte
+       nx  int
+       len uint64
+}
+
+func (d *digest) Reset() {
+       d.s[0] = _Init0
+       d.s[1] = _Init1
+       d.s[2] = _Init2
+       d.s[3] = _Init3
+       d.nx = 0
+       d.len = 0
+}
+
+// New returns a new hash.Hash computing the MD4 checksum.
+func New() hash.Hash {
+       d := new(digest)
+       d.Reset()
+       return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+       nn = len(p)
+       d.len += uint64(nn)
+       if d.nx > 0 {
+               n := len(p)
+               if n > _Chunk-d.nx {
+                       n = _Chunk - d.nx
+               }
+               for i := 0; i < n; i++ {
+                       d.x[d.nx+i] = p[i]
+               }
+               d.nx += n
+               if d.nx == _Chunk {
+                       _Block(d, d.x[0:])
+                       d.nx = 0
+               }
+               p = p[n:]
+       }
+       n := _Block(d, p)
+       p = p[n:]
+       if len(p) > 0 {
+               d.nx = copy(d.x[:], p)
+       }
+       return
+}
+
+func (d0 *digest) Sum() []byte {
+       // Make a copy of d0, so that caller can keep writing and summing.
+       d := new(digest)
+       *d = *d0
+
+       // Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
+       len := d.len
+       var tmp [64]byte
+       tmp[0] = 0x80
+       if len%64 < 56 {
+               d.Write(tmp[0 : 56-len%64])
+       } else {
+               d.Write(tmp[0 : 64+56-len%64])
+       }
+
+       // Length in bits.
+       len <<= 3
+       for i := uint(0); i < 8; i++ {
+               tmp[i] = byte(len >> (8 * i))
+       }
+       d.Write(tmp[0:8])
+
+       if d.nx != 0 {
+               panic("d.nx != 0")
+       }
+
+       p := make([]byte, 16)
+       j := 0
+       for _, s := range d.s {
+               p[j+0] = byte(s >> 0)
+               p[j+1] = byte(s >> 8)
+               p[j+2] = byte(s >> 16)
+               p[j+3] = byte(s >> 24)
+               j += 4
+       }
+       return p
+}
diff --git a/libgo/go/crypto/md4/md4_test.go b/libgo/go/crypto/md4/md4_test.go
new file mode 100644 (file)
index 0000000..721bd4c
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package md4
+
+import (
+       "fmt"
+       "io"
+       "testing"
+)
+
+type md4Test struct {
+       out string
+       in  string
+}
+
+var golden = []md4Test{
+       {"31d6cfe0d16ae931b73c59d7e0c089c0", ""},
+       {"bde52cb31de33e46245e05fbdbd6fb24", "a"},
+       {"ec388dd78999dfc7cf4632465693b6bf", "ab"},
+       {"a448017aaf21d8525fc10ae87aa6729d", "abc"},
+       {"41decd8f579255c5200f86a4bb3ba740", "abcd"},
+       {"9803f4a34e8eb14f96adba49064a0c41", "abcde"},
+       {"804e7f1c2586e50b49ac65db5b645131", "abcdef"},
+       {"752f4adfe53d1da0241b5bc216d098fc", "abcdefg"},
+       {"ad9daf8d49d81988590a6f0e745d15dd", "abcdefgh"},
+       {"1e4e28b05464316b56402b3815ed2dfd", "abcdefghi"},
+       {"dc959c6f5d6f9e04e4380777cc964b3d", "abcdefghij"},
+       {"1b5701e265778898ef7de5623bbe7cc0", "Discard medicine more than two years old."},
+       {"d7f087e090fe7ad4a01cb59dacc9a572", "He who has a shady past knows that nice guys finish last."},
+       {"a6f8fd6df617c72837592fc3570595c9", "I wouldn't marry him with a ten foot pole."},
+       {"c92a84a9526da8abc240c05d6b1a1ce0", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {"f6013160c4dcb00847069fee3bb09803", "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {"2c3bb64f50b9107ed57640fe94bec09f", "Nepal premier won't resign."},
+       {"45b7d8a32c7806f2f7f897332774d6e4", "For every action there is an equal and opposite government program."},
+       {"b5b4f9026b175c62d7654bdc3a1cd438", "His money is twice tainted: 'taint yours and 'taint mine."},
+       {"caf44e80f2c20ce19b5ba1cab766e7bd", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {"191fae6707f496aa54a6bce9f2ecf74d", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {"9ddc753e7a4ccee6081cd1b45b23a834", "size:  a.out:  bad magic"},
+       {"8d050f55b1cadb9323474564be08a521", "The major problem is with sendmail.  -Mark Horton"},
+       {"ad6e2587f74c3e3cc19146f6127fa2e3", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {"1d616d60a5fabe85589c3f1566ca7fca", "If the enemy is within range, then so are you."},
+       {"aec3326a4f496a2ced65a1963f84577f", "It's well we cannot hear the screams/That we create in others' dreams."},
+       {"77b4fd762d6b9245e61c50bf6ebf118b", "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {"e8f48c726bae5e516f6ddb1a4fe62438", "C is as portable as Stonehedge!!"},
+       {"a3a84366e7219e887423b01f9be7166e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {"a6b7aa35157e984ef5d9b7f32e5fbb52", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {"75661f0545955f8f9abeeb17845f3fd6", "How can you write a big system without C++?  -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+       for i := 0; i < len(golden); i++ {
+               g := golden[i]
+               c := New()
+               for j := 0; j < 3; j++ {
+                       if j < 2 {
+                               io.WriteString(c, g.in)
+                       } else {
+                               io.WriteString(c, g.in[0:len(g.in)/2])
+                               c.Sum()
+                               io.WriteString(c, g.in[len(g.in)/2:])
+                       }
+                       s := fmt.Sprintf("%x", c.Sum())
+                       if s != g.out {
+                               t.Fatalf("md4[%d](%s) = %s want %s", j, g.in, s, g.out)
+                       }
+                       c.Reset()
+               }
+       }
+}
diff --git a/libgo/go/crypto/md4/md4block.go b/libgo/go/crypto/md4/md4block.go
new file mode 100644 (file)
index 0000000..3fed475
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// MD4 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package md4
+
+var shift1 = []uint{3, 7, 11, 19}
+var shift2 = []uint{3, 5, 9, 13}
+var shift3 = []uint{3, 9, 11, 15}
+
+var xIndex2 = []uint{0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}
+var xIndex3 = []uint{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}
+
+func _Block(dig *digest, p []byte) int {
+       a := dig.s[0]
+       b := dig.s[1]
+       c := dig.s[2]
+       d := dig.s[3]
+       n := 0
+       var X [16]uint32
+       for len(p) >= _Chunk {
+               aa, bb, cc, dd := a, b, c, d
+
+               j := 0
+               for i := 0; i < 16; i++ {
+                       X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+                       j += 4
+               }
+
+               // If this needs to be made faster in the future,
+               // the usual trick is to unroll each of these
+               // loops by a factor of 4; that lets you replace
+               // the shift[] lookups with constants and,
+               // with suitable variable renaming in each
+               // unrolled body, delete the a, b, c, d = d, a, b, c
+               // (or you can let the optimizer do the renaming).
+               //
+               // The index variables are uint so that % by a power
+               // of two can be optimized easily by a compiler.
+
+               // Round 1.
+               for i := uint(0); i < 16; i++ {
+                       x := i
+                       s := shift1[i%4]
+                       f := ((c ^ d) & b) ^ d
+                       a += f + X[x]
+                       a = a<<s | a>>(32-s)
+                       a, b, c, d = d, a, b, c
+               }
+
+               // Round 2.
+               for i := uint(0); i < 16; i++ {
+                       x := xIndex2[i]
+                       s := shift2[i%4]
+                       g := (b & c) | (b & d) | (c & d)
+                       a += g + X[x] + 0x5a827999
+                       a = a<<s | a>>(32-s)
+                       a, b, c, d = d, a, b, c
+               }
+
+               // Round 3.
+               for i := uint(0); i < 16; i++ {
+                       x := xIndex3[i]
+                       s := shift3[i%4]
+                       h := b ^ c ^ d
+                       a += h + X[x] + 0x6ed9eba1
+                       a = a<<s | a>>(32-s)
+                       a, b, c, d = d, a, b, c
+               }
+
+               a += aa
+               b += bb
+               c += cc
+               d += dd
+
+               p = p[_Chunk:]
+               n += _Chunk
+       }
+
+       dig.s[0] = a
+       dig.s[1] = b
+       dig.s[2] = c
+       dig.s[3] = d
+       return n
+}
diff --git a/libgo/go/crypto/md5/md5.go b/libgo/go/crypto/md5/md5.go
new file mode 100644 (file)
index 0000000..54fddb6
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the MD5 hash algorithm as defined in RFC 1321.
+package md5
+
+import (
+       "hash"
+       "os"
+)
+
+// The size of an MD5 checksum in bytes.
+const Size = 16
+
+const (
+       _Chunk = 64
+       _Init0 = 0x67452301
+       _Init1 = 0xEFCDAB89
+       _Init2 = 0x98BADCFE
+       _Init3 = 0x10325476
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+       s   [4]uint32
+       x   [_Chunk]byte
+       nx  int
+       len uint64
+}
+
+func (d *digest) Reset() {
+       d.s[0] = _Init0
+       d.s[1] = _Init1
+       d.s[2] = _Init2
+       d.s[3] = _Init3
+       d.nx = 0
+       d.len = 0
+}
+
+// New returns a new hash.Hash computing the MD5 checksum.
+func New() hash.Hash {
+       d := new(digest)
+       d.Reset()
+       return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+       nn = len(p)
+       d.len += uint64(nn)
+       if d.nx > 0 {
+               n := len(p)
+               if n > _Chunk-d.nx {
+                       n = _Chunk - d.nx
+               }
+               for i := 0; i < n; i++ {
+                       d.x[d.nx+i] = p[i]
+               }
+               d.nx += n
+               if d.nx == _Chunk {
+                       _Block(d, d.x[0:])
+                       d.nx = 0
+               }
+               p = p[n:]
+       }
+       n := _Block(d, p)
+       p = p[n:]
+       if len(p) > 0 {
+               d.nx = copy(d.x[:], p)
+       }
+       return
+}
+
+func (d0 *digest) Sum() []byte {
+       // Make a copy of d0 so that caller can keep writing and summing.
+       d := new(digest)
+       *d = *d0
+
+       // Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
+       len := d.len
+       var tmp [64]byte
+       tmp[0] = 0x80
+       if len%64 < 56 {
+               d.Write(tmp[0 : 56-len%64])
+       } else {
+               d.Write(tmp[0 : 64+56-len%64])
+       }
+
+       // Length in bits.
+       len <<= 3
+       for i := uint(0); i < 8; i++ {
+               tmp[i] = byte(len >> (8 * i))
+       }
+       d.Write(tmp[0:8])
+
+       if d.nx != 0 {
+               panic("d.nx != 0")
+       }
+
+       p := make([]byte, 16)
+       j := 0
+       for _, s := range d.s {
+               p[j+0] = byte(s >> 0)
+               p[j+1] = byte(s >> 8)
+               p[j+2] = byte(s >> 16)
+               p[j+3] = byte(s >> 24)
+               j += 4
+       }
+       return p
+}
diff --git a/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go
new file mode 100644 (file)
index 0000000..857002b
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package md5
+
+import (
+       "fmt"
+       "io"
+       "testing"
+)
+
+type md5Test struct {
+       out string
+       in  string
+}
+
+var golden = []md5Test{
+       {"d41d8cd98f00b204e9800998ecf8427e", ""},
+       {"0cc175b9c0f1b6a831c399e269772661", "a"},
+       {"187ef4436122d1cc2f40dc2b92f0eba0", "ab"},
+       {"900150983cd24fb0d6963f7d28e17f72", "abc"},
+       {"e2fc714c4727ee9395f324cd2e7f331f", "abcd"},
+       {"ab56b4d92b40713acc5af89985d4b786", "abcde"},
+       {"e80b5017098950fc58aad83c8c14978e", "abcdef"},
+       {"7ac66c0f148de9519b8bd264312c4d64", "abcdefg"},
+       {"e8dc4081b13434b45189a720b77b6818", "abcdefgh"},
+       {"8aa99b1f439ff71293e95357bac6fd94", "abcdefghi"},
+       {"a925576942e94b2ef57a066101b48876", "abcdefghij"},
+       {"d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old."},
+       {"bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last."},
+       {"0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole."},
+       {"9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {"a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {"e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign."},
+       {"637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program."},
+       {"834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine."},
+       {"de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {"acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {"e1c1384cb4d2221dfdd7c795a4222c9a", "size:  a.out:  bad magic"},
+       {"c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail.  -Mark Horton"},
+       {"cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {"83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you."},
+       {"277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams."},
+       {"fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {"469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!"},
+       {"63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {"72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {"132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++?  -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+       for i := 0; i < len(golden); i++ {
+               g := golden[i]
+               c := New()
+               for j := 0; j < 3; j++ {
+                       if j < 2 {
+                               io.WriteString(c, g.in)
+                       } else {
+                               io.WriteString(c, g.in[0:len(g.in)/2])
+                               c.Sum()
+                               io.WriteString(c, g.in[len(g.in)/2:])
+                       }
+                       s := fmt.Sprintf("%x", c.Sum())
+                       if s != g.out {
+                               t.Fatalf("md5[%d](%s) = %s want %s", j, g.in, s, g.out)
+                       }
+                       c.Reset()
+               }
+       }
+}
diff --git a/libgo/go/crypto/md5/md5block.go b/libgo/go/crypto/md5/md5block.go
new file mode 100644 (file)
index 0000000..a887e2e
--- /dev/null
@@ -0,0 +1,172 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// MD5 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package md5
+
+// table[i] = int((1<<32) * abs(sin(i+1 radians))).
+var table = []uint32{
+       // round 1
+       0xd76aa478,
+       0xe8c7b756,
+       0x242070db,
+       0xc1bdceee,
+       0xf57c0faf,
+       0x4787c62a,
+       0xa8304613,
+       0xfd469501,
+       0x698098d8,
+       0x8b44f7af,
+       0xffff5bb1,
+       0x895cd7be,
+       0x6b901122,
+       0xfd987193,
+       0xa679438e,
+       0x49b40821,
+
+       // round 2
+       0xf61e2562,
+       0xc040b340,
+       0x265e5a51,
+       0xe9b6c7aa,
+       0xd62f105d,
+       0x2441453,
+       0xd8a1e681,
+       0xe7d3fbc8,
+       0x21e1cde6,
+       0xc33707d6,
+       0xf4d50d87,
+       0x455a14ed,
+       0xa9e3e905,
+       0xfcefa3f8,
+       0x676f02d9,
+       0x8d2a4c8a,
+
+       // round3
+       0xfffa3942,
+       0x8771f681,
+       0x6d9d6122,
+       0xfde5380c,
+       0xa4beea44,
+       0x4bdecfa9,
+       0xf6bb4b60,
+       0xbebfbc70,
+       0x289b7ec6,
+       0xeaa127fa,
+       0xd4ef3085,
+       0x4881d05,
+       0xd9d4d039,
+       0xe6db99e5,
+       0x1fa27cf8,
+       0xc4ac5665,
+
+       // round 4
+       0xf4292244,
+       0x432aff97,
+       0xab9423a7,
+       0xfc93a039,
+       0x655b59c3,
+       0x8f0ccc92,
+       0xffeff47d,
+       0x85845dd1,
+       0x6fa87e4f,
+       0xfe2ce6e0,
+       0xa3014314,
+       0x4e0811a1,
+       0xf7537e82,
+       0xbd3af235,
+       0x2ad7d2bb,
+       0xeb86d391,
+}
+
+var shift1 = []uint{7, 12, 17, 22}
+var shift2 = []uint{5, 9, 14, 20}
+var shift3 = []uint{4, 11, 16, 23}
+var shift4 = []uint{6, 10, 15, 21}
+
+func _Block(dig *digest, p []byte) int {
+       a := dig.s[0]
+       b := dig.s[1]
+       c := dig.s[2]
+       d := dig.s[3]
+       n := 0
+       var X [16]uint32
+       for len(p) >= _Chunk {
+               aa, bb, cc, dd := a, b, c, d
+
+               j := 0
+               for i := 0; i < 16; i++ {
+                       X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+                       j += 4
+               }
+
+               // If this needs to be made faster in the future,
+               // the usual trick is to unroll each of these
+               // loops by a factor of 4; that lets you replace
+               // the shift[] lookups with constants and,
+               // with suitable variable renaming in each
+               // unrolled body, delete the a, b, c, d = d, a, b, c
+               // (or you can let the optimizer do the renaming).
+               //
+               // The index variables are uint so that % by a power
+               // of two can be optimized easily by a compiler.
+
+               // Round 1.
+               for i := uint(0); i < 16; i++ {
+                       x := i
+                       s := shift1[i%4]
+                       f := ((c ^ d) & b) ^ d
+                       a += f + X[x] + table[i]
+                       a = a<<s | a>>(32-s) + b
+                       a, b, c, d = d, a, b, c
+               }
+
+               // Round 2.
+               for i := uint(0); i < 16; i++ {
+                       x := (1 + 5*i) % 16
+                       s := shift2[i%4]
+                       g := ((b ^ c) & d) ^ c
+                       a += g + X[x] + table[i+16]
+                       a = a<<s | a>>(32-s) + b
+                       a, b, c, d = d, a, b, c
+               }
+
+               // Round 3.
+               for i := uint(0); i < 16; i++ {
+                       x := (5 + 3*i) % 16
+                       s := shift3[i%4]
+                       h := b ^ c ^ d
+                       a += h + X[x] + table[i+32]
+                       a = a<<s | a>>(32-s) + b
+                       a, b, c, d = d, a, b, c
+               }
+
+               // Round 4.
+               for i := uint(0); i < 16; i++ {
+                       x := (7 * i) % 16
+                       s := shift4[i%4]
+                       j := c ^ (b | ^d)
+                       a += j + X[x] + table[i+48]
+                       a = a<<s | a>>(32-s) + b
+                       a, b, c, d = d, a, b, c
+               }
+
+               a += aa
+               b += bb
+               c += cc
+               d += dd
+
+               p = p[_Chunk:]
+               n += _Chunk
+       }
+
+       dig.s[0] = a
+       dig.s[1] = b
+       dig.s[2] = c
+       dig.s[3] = d
+       return n
+}
diff --git a/libgo/go/crypto/ocsp/ocsp.go b/libgo/go/crypto/ocsp/ocsp.go
new file mode 100644 (file)
index 0000000..f3fa3bc
--- /dev/null
@@ -0,0 +1,203 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package parses OCSP responses as specified in RFC 2560. OCSP responses
+// are signed messages attesting to the validity of a certificate for a small
+// period of time. This is used to manage revocation for X.509 certificates.
+package ocsp
+
+import (
+       "asn1"
+       "crypto/rsa"
+       "crypto/sha1"
+       "crypto/x509"
+       "os"
+       "time"
+)
+
+var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
+var idSHA1WithRSA = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 1, 5})
+
+// These are internal structures that reflect the ASN.1 structure of an OCSP
+// response. See RFC 2560, section 4.2.
+
+const (
+       ocspSuccess       = 0
+       ocspMalformed     = 1
+       ocspInternalError = 2
+       ocspTryLater      = 3
+       ocspSigRequired   = 4
+       ocspUnauthorized  = 5
+)
+
+type rdnSequence []relativeDistinguishedNameSET
+
+type relativeDistinguishedNameSET []attributeTypeAndValue
+
+type attributeTypeAndValue struct {
+       Type  asn1.ObjectIdentifier
+       Value interface{}
+}
+
+type algorithmIdentifier struct {
+       Algorithm asn1.ObjectIdentifier
+}
+
+type certID struct {
+       HashAlgorithm algorithmIdentifier
+       NameHash      []byte
+       IssuerKeyHash []byte
+       SerialNumber  asn1.RawValue
+}
+
+type responseASN1 struct {
+       Status   asn1.Enumerated
+       Response responseBytes "explicit,tag:0"
+}
+
+type responseBytes struct {
+       ResponseType asn1.ObjectIdentifier
+       Response     []byte
+}
+
+type basicResponse struct {
+       TBSResponseData    responseData
+       SignatureAlgorithm algorithmIdentifier
+       Signature          asn1.BitString
+       Certificates       []asn1.RawValue "explicit,tag:0,optional"
+}
+
+type responseData struct {
+       Raw           asn1.RawContent
+       Version       int         "optional,default:1,explicit,tag:0"
+       RequestorName rdnSequence "optional,explicit,tag:1"
+       KeyHash       []byte      "optional,explicit,tag:2"
+       ProducedAt    *time.Time
+       Responses     []singleResponse
+}
+
+type singleResponse struct {
+       CertID     certID
+       Good       asn1.Flag   "explicit,tag:0,optional"
+       Revoked    revokedInfo "explicit,tag:1,optional"
+       Unknown    asn1.Flag   "explicit,tag:2,optional"
+       ThisUpdate *time.Time
+       NextUpdate *time.Time "explicit,tag:0,optional"
+}
+
+type revokedInfo struct {
+       RevocationTime *time.Time
+       Reason         int "explicit,tag:0,optional"
+}
+
+// This is the exposed reflection of the internal OCSP structures.
+
+const (
+       // Good means that the certificate is valid.
+       Good = iota
+       // Revoked means that the certificate has been deliberately revoked.
+       Revoked = iota
+       // Unknown means that the OCSP responder doesn't know about the certificate.
+       Unknown = iota
+       // ServerFailed means that the OCSP responder failed to process the request.
+       ServerFailed = iota
+)
+
+// Response represents an OCSP response. See RFC 2560.
+type Response struct {
+       // Status is one of {Good, Revoked, Unknown, ServerFailed}
+       Status                                        int
+       SerialNumber                                  []byte
+       ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time
+       RevocationReason                              int
+       Certificate                                   *x509.Certificate
+}
+
+// ParseError results from an invalid OCSP response.
+type ParseError string
+
+func (p ParseError) String() string {
+       return string(p)
+}
+
+// ParseResponse parses an OCSP response in DER form. It only supports
+// responses for a single certificate and only those using RSA signatures.
+// Non-RSA responses will result in an x509.UnsupportedAlgorithmError.
+// Signature errors or parse failures will result in a ParseError.
+func ParseResponse(bytes []byte) (*Response, os.Error) {
+       var resp responseASN1
+       rest, err := asn1.Unmarshal(bytes, &resp)
+       if err != nil {
+               return nil, err
+       }
+       if len(rest) > 0 {
+               return nil, ParseError("trailing data in OCSP response")
+       }
+
+       ret := new(Response)
+       if resp.Status != ocspSuccess {
+               ret.Status = ServerFailed
+               return ret, nil
+       }
+
+       if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
+               return nil, ParseError("bad OCSP response type")
+       }
+
+       var basicResp basicResponse
+       rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
+       if err != nil {
+               return nil, err
+       }
+
+       if len(basicResp.Certificates) != 1 {
+               return nil, ParseError("OCSP response contains bad number of certificates")
+       }
+
+       if len(basicResp.TBSResponseData.Responses) != 1 {
+               return nil, ParseError("OCSP response contains bad number of responses")
+       }
+
+       ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
+       if err != nil {
+               return nil, err
+       }
+
+       if ret.Certificate.PublicKeyAlgorithm != x509.RSA || !basicResp.SignatureAlgorithm.Algorithm.Equal(idSHA1WithRSA) {
+               return nil, x509.UnsupportedAlgorithmError{}
+       }
+
+       h := sha1.New()
+       hashType := rsa.HashSHA1
+
+       pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
+       h.Write(basicResp.TBSResponseData.Raw)
+       digest := h.Sum()
+       signature := basicResp.Signature.RightAlign()
+
+       if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
+               return nil, ParseError("bad OCSP signature")
+       }
+
+       r := basicResp.TBSResponseData.Responses[0]
+
+       ret.SerialNumber = r.CertID.SerialNumber.Bytes
+
+       switch {
+       case bool(r.Good):
+               ret.Status = Good
+       case bool(r.Unknown):
+               ret.Status = Unknown
+       default:
+               ret.Status = Revoked
+               ret.RevokedAt = r.Revoked.RevocationTime
+               ret.RevocationReason = r.Revoked.Reason
+       }
+
+       ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
+       ret.ThisUpdate = r.ThisUpdate
+       ret.NextUpdate = r.NextUpdate
+
+       return ret, nil
+}
diff --git a/libgo/go/crypto/ocsp/ocsp_test.go b/libgo/go/crypto/ocsp/ocsp_test.go
new file mode 100644 (file)
index 0000000..f988979
--- /dev/null
@@ -0,0 +1,97 @@
+package ocsp
+
+import (
+       "bytes"
+       "encoding/hex"
+       "reflect"
+       "testing"
+       "time"
+)
+
+func TestOCSPDecode(t *testing.T) {
+       responseBytes, _ := hex.DecodeString(ocspResponseHex)
+       resp, err := ParseResponse(responseBytes)
+       if err != nil {
+               t.Error(err)
+       }
+
+       expected := Response{Status: 0, SerialNumber: []byte{0x1, 0xd0, 0xfa}, RevocationReason: 0, ThisUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 15, Minute: 1, Second: 5, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}, NextUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 18, Minute: 35, Second: 17, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}}
+
+       if !reflect.DeepEqual(resp.ThisUpdate, resp.ThisUpdate) {
+               t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
+       }
+
+       if !reflect.DeepEqual(resp.NextUpdate, resp.NextUpdate) {
+               t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, expected.NextUpdate)
+       }
+
+       if resp.Status != expected.Status {
+               t.Errorf("resp.Status: got %d, want %d", resp.Status, expected.Status)
+       }
+
+       if !bytes.Equal(resp.SerialNumber, expected.SerialNumber) {
+               t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, expected.SerialNumber)
+       }
+
+       if resp.RevocationReason != expected.RevocationReason {
+               t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, expected.RevocationReason)
+       }
+}
+
+// This OCSP response was taken from Thawte's public OCSP responder.
+// To recreate:
+//   $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
+// Copy and paste the first certificate into /tmp/cert.crt and the second into
+// /tmp/intermediate.crt
+//   $ openssl ocsp -issuer /tmp/intermediate.crt -cert /tmp/cert.crt -url http://ocsp.thawte.com -resp_text -respout /tmp/ocsp.der
+// Then hex encode the result:
+//   $ python -c 'print file("/tmp/ocsp.der", "r").read().encode("hex")'
+
+const ocspResponseHex = "308206bc0a0100a08206b5308206b106092b0601050507300101048206a23082069e3081" +
+       "c9a14e304c310b300906035504061302494c31163014060355040a130d5374617274436f" +
+       "6d204c74642e312530230603550403131c5374617274436f6d20436c6173732031204f43" +
+       "5350205369676e6572180f32303130303730373137333531375a30663064303c30090605" +
+       "2b0e03021a050004146568874f40750f016a3475625e1f5c93e5a26d580414eb4234d098" +
+       "b0ab9ff41b6b08f7cc642eef0e2c45020301d0fa8000180f323031303037303731353031" +
+       "30355aa011180f32303130303730373138333531375a300d06092a864886f70d01010505" +
+       "000382010100ab557ff070d1d7cebbb5f0ec91a15c3fed22eb2e1b8244f1b84545f013a4" +
+       "fb46214c5e3fbfbebb8a56acc2b9db19f68fd3c3201046b3824d5ba689f99864328710cb" +
+       "467195eb37d84f539e49f859316b32964dc3e47e36814ce94d6c56dd02733b1d0802f7ff" +
+       "4eebdbbd2927dcf580f16cbc290f91e81b53cb365e7223f1d6e20a88ea064104875e0145" +
+       "672b20fc14829d51ca122f5f5d77d3ad6c83889c55c7dc43680ba2fe3cef8b05dbcabdc0" +
+       "d3e09aaf9725597f8c858c2fa38c0d6aed2e6318194420dd1a1137445d13e1c97ab47896" +
+       "17a4e08925f46f867b72e3a4dc1f08cb870b2b0717f7207faa0ac512e628a029aba7457a" +
+       "e63dcf3281e2162d9349a08204ba308204b6308204b23082039aa003020102020101300d" +
+       "06092a864886f70d010105050030818c310b300906035504061302494c31163014060355" +
+       "040a130d5374617274436f6d204c74642e312b3029060355040b13225365637572652044" +
+       "69676974616c204365727469666963617465205369676e696e6731383036060355040313" +
+       "2f5374617274436f6d20436c6173732031205072696d61727920496e7465726d65646961" +
+       "746520536572766572204341301e170d3037313032353030323330365a170d3132313032" +
+       "333030323330365a304c310b300906035504061302494c31163014060355040a130d5374" +
+       "617274436f6d204c74642e312530230603550403131c5374617274436f6d20436c617373" +
+       "2031204f435350205369676e657230820122300d06092a864886f70d0101010500038201" +
+       "0f003082010a0282010100b9561b4c45318717178084e96e178df2255e18ed8d8ecc7c2b" +
+       "7b51a6c1c2e6bf0aa3603066f132fe10ae97b50e99fa24b83fc53dd2777496387d14e1c3" +
+       "a9b6a4933e2ac12413d085570a95b8147414a0bc007c7bcf222446ef7f1a156d7ea1c577" +
+       "fc5f0facdfd42eb0f5974990cb2f5cefebceef4d1bdc7ae5c1075c5a99a93171f2b0845b" +
+       "4ff0864e973fcfe32f9d7511ff87a3e943410c90a4493a306b6944359340a9ca96f02b66" +
+       "ce67f028df2980a6aaee8d5d5d452b8b0eb93f923cc1e23fcccbdbe7ffcb114d08fa7a6a" +
+       "3c404f825d1a0e715935cf623a8c7b59670014ed0622f6089a9447a7a19010f7fe58f841" +
+       "29a2765ea367824d1c3bb2fda308530203010001a382015c30820158300c0603551d1301" +
+       "01ff04023000300b0603551d0f0404030203a8301e0603551d250417301506082b060105" +
+       "0507030906092b0601050507300105301d0603551d0e0416041445e0a36695414c5dd449" +
+       "bc00e33cdcdbd2343e173081a80603551d230481a030819d8014eb4234d098b0ab9ff41b" +
+       "6b08f7cc642eef0e2c45a18181a47f307d310b300906035504061302494c311630140603" +
+       "55040a130d5374617274436f6d204c74642e312b3029060355040b132253656375726520" +
+       "4469676974616c204365727469666963617465205369676e696e67312930270603550403" +
+       "13205374617274436f6d2043657274696669636174696f6e20417574686f726974798201" +
+       "0a30230603551d12041c301a8618687474703a2f2f7777772e737461727473736c2e636f" +
+       "6d2f302c06096086480186f842010d041f161d5374617274436f6d205265766f63617469" +
+       "6f6e20417574686f72697479300d06092a864886f70d01010505000382010100182d2215" +
+       "8f0fc0291324fa8574c49bb8ff2835085adcbf7b7fc4191c397ab6951328253fffe1e5ec" +
+       "2a7da0d50fca1a404e6968481366939e666c0a6209073eca57973e2fefa9ed1718e8176f" +
+       "1d85527ff522c08db702e3b2b180f1cbff05d98128252cf0f450f7dd2772f4188047f19d" +
+       "c85317366f94bc52d60f453a550af58e308aaab00ced33040b62bf37f5b1ab2a4f7f0f80" +
+       "f763bf4d707bc8841d7ad9385ee2a4244469260b6f2bf085977af9074796048ecc2f9d48" +
+       "a1d24ce16e41a9941568fec5b42771e118f16c106a54ccc339a4b02166445a167902e75e" +
+       "6d8620b0825dcd18a069b90fd851d10fa8effd409deec02860d26d8d833f304b10669b42"
diff --git a/libgo/go/crypto/rand/rand.go b/libgo/go/crypto/rand/rand.go
new file mode 100644 (file)
index 0000000..42d9da0
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rand implements a cryptographically secure
+// pseudorandom number generator.
+package rand
+
+import (
+       "io"
+       "os"
+)
+
+// Reader is a global, shared instance of a cryptographically
+// strong pseudo-random generator.
+// On Unix-like systems, Reader reads from /dev/urandom.
+// On Windows systems, Reader uses the CryptGenRandom API.
+var Reader io.Reader
+
+// Read is a helper function that calls Reader.Read.
+func Read(b []byte) (n int, err os.Error) { return Reader.Read(b) }
diff --git a/libgo/go/crypto/rand/rand_test.go b/libgo/go/crypto/rand/rand_test.go
new file mode 100644 (file)
index 0000000..f64ead4
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+       "bytes"
+       "compress/flate"
+       "testing"
+)
+
+func TestRead(t *testing.T) {
+       b := make([]byte, 4e6)
+       n, err := Read(b)
+       if n != len(b) || err != nil {
+               t.Fatalf("Read(buf) = %d, %s", n, err)
+       }
+
+       var z bytes.Buffer
+       f := flate.NewWriter(&z, 5)
+       f.Write(b)
+       f.Close()
+       if z.Len() < len(b)*99/100 {
+               t.Fatalf("Compressed %d -> %d", len(b), z.Len())
+       }
+}
diff --git a/libgo/go/crypto/rand/rand_unix.go b/libgo/go/crypto/rand/rand_unix.go
new file mode 100644 (file)
index 0000000..ff16f25
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unix cryptographically secure pseudorandom number
+// generator.
+
+package rand
+
+import (
+       "crypto/aes"
+       "io"
+       "os"
+       "sync"
+       "time"
+)
+
+// Easy implementation: read from /dev/urandom.
+// This is sufficient on Linux, OS X, and FreeBSD.
+
+func init() { Reader = &devReader{name: "/dev/urandom"} }
+
+// A devReader satisfies reads by reading the file named name.
+type devReader struct {
+       name string
+       f    *os.File
+       mu   sync.Mutex
+}
+
+func (r *devReader) Read(b []byte) (n int, err os.Error) {
+       r.mu.Lock()
+       if r.f == nil {
+               f, err := os.Open(r.name, os.O_RDONLY, 0)
+               if f == nil {
+                       r.mu.Unlock()
+                       return 0, err
+               }
+               r.f = f
+       }
+       r.mu.Unlock()
+       return r.f.Read(b)
+}
+
+// Alternate pseudo-random implementation for use on
+// systems without a reliable /dev/urandom.  So far we
+// haven't needed it.
+
+// newReader returns a new pseudorandom generator that
+// seeds itself by reading from entropy.  If entropy == nil,
+// the generator seeds itself by reading from the system's
+// random number generator, typically /dev/random.
+// The Read method on the returned reader always returns
+// the full amount asked for, or else it returns an error.
+//
+// The generator uses the X9.31 algorithm with AES-128,
+// reseeding after every 1 MB of generated data.
+func newReader(entropy io.Reader) io.Reader {
+       if entropy == nil {
+               entropy = &devReader{name: "/dev/random"}
+       }
+       return &reader{entropy: entropy}
+}
+
+type reader struct {
+       mu                   sync.Mutex
+       budget               int // number of bytes that can be generated
+       cipher               *aes.Cipher
+       entropy              io.Reader
+       time, seed, dst, key [aes.BlockSize]byte
+}
+
+func (r *reader) Read(b []byte) (n int, err os.Error) {
+       r.mu.Lock()
+       defer r.mu.Unlock()
+       n = len(b)
+
+       for len(b) > 0 {
+               if r.budget == 0 {
+                       _, err := io.ReadFull(r.entropy, r.seed[0:])
+                       if err != nil {
+                               return n - len(b), err
+                       }
+                       _, err = io.ReadFull(r.entropy, r.key[0:])
+                       if err != nil {
+                               return n - len(b), err
+                       }
+                       r.cipher, err = aes.NewCipher(r.key[0:])
+                       if err != nil {
+                               return n - len(b), err
+                       }
+                       r.budget = 1 << 20 // reseed after generating 1MB
+               }
+               r.budget -= aes.BlockSize
+
+               // ANSI X9.31 (== X9.17) algorithm, but using AES in place of 3DES.
+               //
+               // single block:
+               // t = encrypt(time)
+               // dst = encrypt(t^seed)
+               // seed = encrypt(t^dst)
+               ns := time.Nanoseconds()
+               r.time[0] = byte(ns >> 56)
+               r.time[1] = byte(ns >> 48)
+               r.time[2] = byte(ns >> 40)
+               r.time[3] = byte(ns >> 32)
+               r.time[4] = byte(ns >> 24)
+               r.time[5] = byte(ns >> 16)
+               r.time[6] = byte(ns >> 8)
+               r.time[7] = byte(ns)
+               r.cipher.Encrypt(r.time[0:], r.time[0:])
+               for i := 0; i < aes.BlockSize; i++ {
+                       r.dst[i] = r.time[i] ^ r.seed[i]
+               }
+               r.cipher.Encrypt(r.dst[0:], r.dst[0:])
+               for i := 0; i < aes.BlockSize; i++ {
+                       r.seed[i] = r.time[i] ^ r.dst[i]
+               }
+               r.cipher.Encrypt(r.seed[0:], r.seed[0:])
+
+               m := copy(b, r.dst[0:])
+               b = b[m:]
+       }
+
+       return n, nil
+}
diff --git a/libgo/go/crypto/rand/rand_windows.go b/libgo/go/crypto/rand/rand_windows.go
new file mode 100644 (file)
index 0000000..4b2b7a2
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Windows cryptographically secure pseudorandom number
+// generator.
+
+package rand
+
+import (
+       "os"
+       "sync"
+       "syscall"
+)
+
+// Implemented by using Windows CryptoAPI 2.0.
+
+func init() { Reader = &rngReader{} }
+
+// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
+type rngReader struct {
+       prov uint32
+       mu   sync.Mutex
+}
+
+func (r *rngReader) Read(b []byte) (n int, err os.Error) {
+       r.mu.Lock()
+       if r.prov == 0 {
+               const provType = syscall.PROV_RSA_FULL
+               const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT
+               ok, errno := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
+               if !ok {
+                       r.mu.Unlock()
+                       return 0, os.NewSyscallError("CryptAcquireContext", errno)
+               }
+       }
+       r.mu.Unlock()
+       ok, errno := syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
+       if !ok {
+               return 0, os.NewSyscallError("CryptGenRandom", errno)
+       }
+       return len(b), nil
+}
diff --git a/libgo/go/crypto/rc4/rc4.go b/libgo/go/crypto/rc4/rc4.go
new file mode 100644 (file)
index 0000000..e47a015
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements RC4 encryption, as defined in Bruce Schneier's
+// Applied Cryptography.
+package rc4
+
+// BUG(agl): RC4 is in common use but has design weaknesses that make
+// it a poor choice for new protocols.
+
+import (
+       "os"
+       "strconv"
+)
+
+// A Cipher is an instance of RC4 using a particular key.
+type Cipher struct {
+       s    [256]byte
+       i, j uint8
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+       return "crypto/rc4: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher.  The key argument should be the
+// RC4 key, at least 1 byte and at most 256 bytes.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+       k := len(key)
+       if k < 1 || k > 256 {
+               return nil, KeySizeError(k)
+       }
+       var c Cipher
+       for i := 0; i < 256; i++ {
+               c.s[i] = uint8(i)
+       }
+       var j uint8 = 0
+       for i := 0; i < 256; i++ {
+               j += c.s[i] + key[i%k]
+               c.s[i], c.s[j] = c.s[j], c.s[i]
+       }
+       return &c, nil
+}
+
+// XORKeyStream will XOR each byte of the given buffer with a byte of the
+// generated keystream.
+func (c *Cipher) XORKeyStream(buf []byte) {
+       for i := range buf {
+               c.i += 1
+               c.j += c.s[c.i]
+               c.s[c.i], c.s[c.j] = c.s[c.j], c.s[c.i]
+               buf[i] ^= c.s[c.s[c.i]+c.s[c.j]]
+       }
+}
+
+// Reset zeros the key data so that it will no longer appear in the
+// process's memory.
+func (c *Cipher) Reset() {
+       for i := range c.s {
+               c.s[i] = 0
+       }
+       c.i, c.j = 0, 0
+}
diff --git a/libgo/go/crypto/rc4/rc4_test.go b/libgo/go/crypto/rc4/rc4_test.go
new file mode 100644 (file)
index 0000000..73a52e7
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rc4
+
+import (
+       "testing"
+)
+
+type rc4Test struct {
+       key, keystream []byte
+}
+
+var golden = []rc4Test{
+       // Test vectors from the original cypherpunk posting of ARC4:
+       //   http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0?pli=1
+       {
+               []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+               []byte{0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79},
+       },
+       {
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a},
+       },
+       {
+               []byte{0xef, 0x01, 0x23, 0x45},
+               []byte{0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, 0xbd, 0x61},
+       },
+
+       // Test vectors from the Wikipedia page: http://en.wikipedia.org/wiki/RC4
+       {
+               []byte{0x4b, 0x65, 0x79},
+               []byte{0xeb, 0x9f, 0x77, 0x81, 0xb7, 0x34, 0xca, 0x72, 0xa7, 0x19},
+       },
+       {
+               []byte{0x57, 0x69, 0x6b, 0x69},
+               []byte{0x60, 0x44, 0xdb, 0x6d, 0x41, 0xb7},
+       },
+}
+
+func TestGolden(t *testing.T) {
+       for i := 0; i < len(golden); i++ {
+               g := golden[i]
+               c, err := NewCipher(g.key)
+               if err != nil {
+                       t.Errorf("Failed to create cipher at golden index %d", i)
+                       return
+               }
+               keystream := make([]byte, len(g.keystream))
+               c.XORKeyStream(keystream)
+               for j, v := range keystream {
+                       if g.keystream[j] != v {
+                               t.Errorf("Failed at golden index %d", i)
+                               break
+                       }
+               }
+       }
+}
diff --git a/libgo/go/crypto/ripemd160/ripemd160.go b/libgo/go/crypto/ripemd160/ripemd160.go
new file mode 100644 (file)
index 0000000..5614f13
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the RIPEMD-160 hash algorithm.
+package ripemd160
+
+// RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart
+// Preneel with specifications available at:
+// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf.
+
+import (
+       "hash"
+       "os"
+)
+
+// The size of the checksum in bytes.
+const Size = 20
+
+// The block size of the hash algorithm in bytes.
+const BlockSize = 64
+
+const (
+       _s0 = 0x67452301
+       _s1 = 0xefcdab89
+       _s2 = 0x98badcfe
+       _s3 = 0x10325476
+       _s4 = 0xc3d2e1f0
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+       s  [5]uint32       // running context
+       x  [BlockSize]byte // temporary buffer
+       nx int             // index into x
+       tc uint64          // total count of bytes processed
+}
+
+func (d *digest) Reset() {
+       d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4
+       d.nx = 0
+       d.tc = 0
+}
+
+// New returns a new hash.Hash computing the checksum.
+func New() hash.Hash {
+       result := new(digest)
+       result.Reset()
+       return result
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+       nn = len(p)
+       d.tc += uint64(nn)
+       if d.nx > 0 {
+               n := len(p)
+               if n > BlockSize-d.nx {
+                       n = BlockSize - d.nx
+               }
+               for i := 0; i < n; i++ {
+                       d.x[d.nx+i] = p[i]
+               }
+               d.nx += n
+               if d.nx == BlockSize {
+                       _Block(d, d.x[0:])
+                       d.nx = 0
+               }
+               p = p[n:]
+       }
+       n := _Block(d, p)
+       p = p[n:]
+       if len(p) > 0 {
+               d.nx = copy(d.x[:], p)
+       }
+       return
+}
+
+func (d0 *digest) Sum() []byte {
+       // Make a copy of d0 so that caller can keep writing and summing.
+       d := new(digest)
+       *d = *d0
+
+       // Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
+       tc := d.tc
+       var tmp [64]byte
+       tmp[0] = 0x80
+       if tc%64 < 56 {
+               d.Write(tmp[0 : 56-tc%64])
+       } else {
+               d.Write(tmp[0 : 64+56-tc%64])
+       }
+
+       // Length in bits.
+       tc <<= 3
+       for i := uint(0); i < 8; i++ {
+               tmp[i] = byte(tc >> (8 * i))
+       }
+       d.Write(tmp[0:8])
+
+       if d.nx != 0 {
+               panic("d.nx != 0")
+       }
+
+       p := make([]byte, 20)
+       j := 0
+       for _, s := range d.s {
+               p[j], p[j+1], p[j+2], p[j+3] = byte(s), byte(s>>8), byte(s>>16), byte(s>>24)
+               j += 4
+       }
+       return p
+}
diff --git a/libgo/go/crypto/ripemd160/ripemd160_test.go b/libgo/go/crypto/ripemd160/ripemd160_test.go
new file mode 100644 (file)
index 0000000..f4135f5
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ripemd160
+
+// Test vectors are from:
+// http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
+
+import (
+       "fmt"
+       "io"
+       "testing"
+)
+
+type mdTest struct {
+       out string
+       in  string
+}
+
+var vectors = [...]mdTest{
+       {"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""},
+       {"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"},
+       {"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"},
+       {"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"},
+       {"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"},
+       {"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
+       {"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
+       {"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
+}
+
+func TestVectors(t *testing.T) {
+       for i := 0; i < len(vectors); i++ {
+               tv := vectors[i]
+               md := New()
+               for j := 0; j < 3; j++ {
+                       if j < 2 {
+                               io.WriteString(md, tv.in)
+                       } else {
+                               io.WriteString(md, tv.in[0:len(tv.in)/2])
+                               md.Sum()
+                               io.WriteString(md, tv.in[len(tv.in)/2:])
+                       }
+                       s := fmt.Sprintf("%x", md.Sum())
+                       if s != tv.out {
+                               t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out)
+                       }
+                       md.Reset()
+               }
+       }
+}
+
+func TestMillionA(t *testing.T) {
+       md := New()
+       for i := 0; i < 100000; i++ {
+               io.WriteString(md, "aaaaaaaaaa")
+       }
+       out := "52783243c1697bdbe16d37f97f68f08325dc1528"
+       s := fmt.Sprintf("%x", md.Sum())
+       if s != out {
+               t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out)
+       }
+       md.Reset()
+}
diff --git a/libgo/go/crypto/ripemd160/ripemd160block.go b/libgo/go/crypto/ripemd160/ripemd160block.go
new file mode 100644 (file)
index 0000000..7bc8e6c
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// RIPEMD-160 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package ripemd160
+
+// work buffer indices and roll amounts for one line
+var _n = [80]uint{
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+       7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+       3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+       1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+       4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
+}
+
+var _r = [80]uint{
+       11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+       7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+       11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+       11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+       9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
+}
+
+// same for the other parallel one
+var n_ = [80]uint{
+       5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+       6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+       15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+       8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+       12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11,
+}
+
+var r_ = [80]uint{
+       8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+       9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+       9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+       15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+       8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11,
+}
+
+func _Block(md *digest, p []byte) int {
+       n := 0
+       var x [16]uint32
+       var alpha, beta uint32
+       for len(p) >= BlockSize {
+               a, b, c, d, e := md.s[0], md.s[1], md.s[2], md.s[3], md.s[4]
+               aa, bb, cc, dd, ee := a, b, c, d, e
+               j := 0
+               for i := 0; i < 16; i++ {
+                       x[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+                       j += 4
+               }
+
+               // round 1
+               i := 0
+               for i < 16 {
+                       alpha = a + (b ^ c ^ d) + x[_n[i]]
+                       s := _r[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + e
+                       beta = c<<10 | c>>22
+                       a, b, c, d, e = e, alpha, b, beta, d
+
+                       // parallel line
+                       alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6
+                       s = r_[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + ee
+                       beta = cc<<10 | cc>>22
+                       aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+                       i++
+               }
+
+               // round 2
+               for i < 32 {
+                       alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999
+                       s := _r[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + e
+                       beta = c<<10 | c>>22
+                       a, b, c, d, e = e, alpha, b, beta, d
+
+                       // parallel line
+                       alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124
+                       s = r_[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + ee
+                       beta = cc<<10 | cc>>22
+                       aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+                       i++
+               }
+
+               // round 3
+               for i < 48 {
+                       alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1
+                       s := _r[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + e
+                       beta = c<<10 | c>>22
+                       a, b, c, d, e = e, alpha, b, beta, d
+
+                       // parallel line
+                       alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3
+                       s = r_[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + ee
+                       beta = cc<<10 | cc>>22
+                       aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+                       i++
+               }
+
+               // round 4
+               for i < 64 {
+                       alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc
+                       s := _r[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + e
+                       beta = c<<10 | c>>22
+                       a, b, c, d, e = e, alpha, b, beta, d
+
+                       // parallel line
+                       alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9
+                       s = r_[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + ee
+                       beta = cc<<10 | cc>>22
+                       aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+                       i++
+               }
+
+               // round 5
+               for i < 80 {
+                       alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e
+                       s := _r[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + e
+                       beta = c<<10 | c>>22
+                       a, b, c, d, e = e, alpha, b, beta, d
+
+                       // parallel line
+                       alpha = aa + (bb ^ cc ^ dd) + x[n_[i]]
+                       s = r_[i]
+                       alpha = (alpha<<s | alpha>>(32-s)) + ee
+                       beta = cc<<10 | cc>>22
+                       aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+                       i++
+               }
+
+               // combine results
+               dd += c + md.s[1]
+               md.s[1] = md.s[2] + d + ee
+               md.s[2] = md.s[3] + e + aa
+               md.s[3] = md.s[4] + a + bb
+               md.s[4] = md.s[0] + b + cc
+               md.s[0] = dd
+
+               p = p[BlockSize:]
+               n += BlockSize
+       }
+       return n
+}
diff --git a/libgo/go/crypto/rsa/pkcs1v15.go b/libgo/go/crypto/rsa/pkcs1v15.go
new file mode 100644 (file)
index 0000000..f918d63
--- /dev/null
@@ -0,0 +1,270 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+import (
+       "big"
+       "crypto/subtle"
+       "io"
+       "os"
+)
+
+// This file implements encryption and decryption using PKCS#1 v1.5 padding.
+
+// EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5.
+// The message must be no longer than the length of the public modulus minus 11 bytes.
+// WARNING: use of this function to encrypt plaintexts other than session keys
+// is dangerous. Use RSA OAEP in new protocols.
+func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err os.Error) {
+       k := (pub.N.BitLen() + 7) / 8
+       if len(msg) > k-11 {
+               err = MessageTooLongError{}
+               return
+       }
+
+       // EM = 0x02 || PS || 0x00 || M
+       em := make([]byte, k-1)
+       em[0] = 2
+       ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
+       err = nonZeroRandomBytes(ps, rand)
+       if err != nil {
+               return
+       }
+       em[len(em)-len(msg)-1] = 0
+       copy(mm, msg)
+
+       m := new(big.Int).SetBytes(em)
+       c := encrypt(new(big.Int), pub, m)
+       out = c.Bytes()
+       return
+}
+
+// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
+// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
+func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err os.Error) {
+       valid, out, err := decryptPKCS1v15(rand, priv, ciphertext)
+       if err == nil && valid == 0 {
+               err = DecryptionError{}
+       }
+
+       return
+}
+
+// DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS#1 v1.5.
+// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
+// It returns an error if the ciphertext is the wrong length or if the
+// ciphertext is greater than the public modulus. Otherwise, no error is
+// returned. If the padding is valid, the resulting plaintext message is copied
+// into key. Otherwise, key is unchanged. These alternatives occur in constant
+// time. It is intended that the user of this function generate a random
+// session key beforehand and continue the protocol with the resulting value.
+// This will remove any possibility that an attacker can learn any information
+// about the plaintext.
+// See ``Chosen Ciphertext Attacks Against Protocols Based on the RSA
+// Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology
+// (Crypto '98),
+func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err os.Error) {
+       k := (priv.N.BitLen() + 7) / 8
+       if k-(len(key)+3+8) < 0 {
+               err = DecryptionError{}
+               return
+       }
+
+       valid, msg, err := decryptPKCS1v15(rand, priv, ciphertext)
+       if err != nil {
+               return
+       }
+
+       valid &= subtle.ConstantTimeEq(int32(len(msg)), int32(len(key)))
+       subtle.ConstantTimeCopy(valid, key, msg)
+       return
+}
+
+func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, msg []byte, err os.Error) {
+       k := (priv.N.BitLen() + 7) / 8
+       if k < 11 {
+               err = DecryptionError{}
+               return
+       }
+
+       c := new(big.Int).SetBytes(ciphertext)
+       m, err := decrypt(rand, priv, c)
+       if err != nil {
+               return
+       }
+
+       em := leftPad(m.Bytes(), k)
+       firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
+       secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2)
+
+       // The remainder of the plaintext must be a string of non-zero random
+       // octets, followed by a 0, followed by the message.
+       //   lookingForIndex: 1 iff we are still looking for the zero.
+       //   index: the offset of the first zero byte.
+       var lookingForIndex, index int
+       lookingForIndex = 1
+
+       for i := 2; i < len(em); i++ {
+               equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+               index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+               lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+       }
+
+       valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1)
+       msg = em[index+1:]
+       return
+}
+
+// nonZeroRandomBytes fills the given slice with non-zero random octets.
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
+       _, err = io.ReadFull(rand, s)
+       if err != nil {
+               return
+       }
+
+       for i := 0; i < len(s); i++ {
+               for s[i] == 0 {
+                       _, err = rand.Read(s[i : i+1])
+                       if err != nil {
+                               return
+                       }
+               }
+       }
+
+       return
+}
+
+// Due to the design of PKCS#1 v1.5, we need to know the exact hash function in
+// use. A generic hash.Hash will not do.
+type PKCS1v15Hash int
+
+const (
+       HashMD5 PKCS1v15Hash = iota
+       HashSHA1
+       HashSHA256
+       HashSHA384
+       HashSHA512
+       HashMD5SHA1 // combined MD5 and SHA1 hash used for RSA signing in TLS.
+)
+
+// These are ASN1 DER structures:
+//   DigestInfo ::= SEQUENCE {
+//     digestAlgorithm AlgorithmIdentifier,
+//     digest OCTET STRING
+//   }
+// For performance, we don't use the generic ASN1 encoder. Rather, we
+// precompute a prefix of the digest value that makes a valid ASN1 DER string
+// with the correct contents.
+var hashPrefixes = [][]byte{
+       // HashMD5
+       {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
+       // HashSHA1
+       {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
+       // HashSHA256
+       {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
+       // HashSHA384
+       {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
+       // HashSHA512
+       {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
+       // HashMD5SHA1
+       {}, // A special TLS case which doesn't use an ASN1 prefix.
+}
+
+// SignPKCS1v15 calcuates the signature of hashed using RSASSA-PSS-SIGN from RSA PKCS#1 v1.5.
+// Note that hashed must be the result of hashing the input message using the
+// given hash function.
+func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash PKCS1v15Hash, hashed []byte) (s []byte, err os.Error) {
+       hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
+       if err != nil {
+               return
+       }
+
+       tLen := len(prefix) + hashLen
+       k := (priv.N.BitLen() + 7) / 8
+       if k < tLen+11 {
+               return nil, MessageTooLongError{}
+       }
+
+       // EM = 0x00 || 0x01 || PS || 0x00 || T
+       em := make([]byte, k)
+       em[1] = 1
+       for i := 2; i < k-tLen-1; i++ {
+               em[i] = 0xff
+       }
+       copy(em[k-tLen:k-hashLen], prefix)
+       copy(em[k-hashLen:k], hashed)
+
+       m := new(big.Int).SetBytes(em)
+       c, err := decrypt(rand, priv, m)
+       if err == nil {
+               s = c.Bytes()
+       }
+       return
+}
+
+// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
+// hashed is the result of hashing the input message using the given hash
+// function and sig is the signature. A valid signature is indicated by
+// returning a nil error.
+func VerifyPKCS1v15(pub *PublicKey, hash PKCS1v15Hash, hashed []byte, sig []byte) (err os.Error) {
+       hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
+       if err != nil {
+               return
+       }
+
+       tLen := len(prefix) + hashLen
+       k := (pub.N.BitLen() + 7) / 8
+       if k < tLen+11 {
+               err = VerificationError{}
+               return
+       }
+
+       c := new(big.Int).SetBytes(sig)
+       m := encrypt(new(big.Int), pub, c)
+       em := leftPad(m.Bytes(), k)
+       // EM = 0x00 || 0x01 || PS || 0x00 || T
+
+       ok := subtle.ConstantTimeByteEq(em[0], 0)
+       ok &= subtle.ConstantTimeByteEq(em[1], 1)
+       ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed)
+       ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix)
+       ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0)
+
+       for i := 2; i < k-tLen-1; i++ {
+               ok &= subtle.ConstantTimeByteEq(em[i], 0xff)
+       }
+
+       if ok != 1 {
+               return VerificationError{}
+       }
+
+       return nil
+}
+
+func pkcs1v15HashInfo(hash PKCS1v15Hash, inLen int) (hashLen int, prefix []byte, err os.Error) {
+       switch hash {
+       case HashMD5:
+               hashLen = 16
+       case HashSHA1:
+               hashLen = 20
+       case HashSHA256:
+               hashLen = 32
+       case HashSHA384:
+               hashLen = 48
+       case HashSHA512:
+               hashLen = 64
+       case HashMD5SHA1:
+               hashLen = 36
+       default:
+               return 0, nil, os.ErrorString("unknown hash function")
+       }
+
+       if inLen != hashLen {
+               return 0, nil, os.ErrorString("input must be hashed message")
+       }
+
+       prefix = hashPrefixes[int(hash)]
+       return
+}
diff --git a/libgo/go/crypto/rsa/pkcs1v15_test.go b/libgo/go/crypto/rsa/pkcs1v15_test.go
new file mode 100644 (file)
index 0000000..bf6306d
--- /dev/null
@@ -0,0 +1,220 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+import (
+       "big"
+       "bytes"
+       "crypto/rand"
+       "crypto/sha1"
+       "encoding/base64"
+       "encoding/hex"
+       "io"
+       "testing"
+       "testing/quick"
+)
+
+func decodeBase64(in string) []byte {
+       out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+       n, err := base64.StdEncoding.Decode(out, []byte(in))
+       if err != nil {
+               return nil
+       }
+       return out[0:n]
+}
+
+type DecryptPKCS1v15Test struct {
+       in, out string
+}
+
+// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
+var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{
+       {
+               "gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
+               "x",
+       },
+       {
+               "Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
+               "testing.",
+       },
+       {
+               "arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
+               "testing.\n",
+       },
+       {
+               "WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
+               "01234567890123456789012345678901234567890123456789012",
+       },
+}
+
+func TestDecryptPKCS1v15(t *testing.T) {
+       for i, test := range decryptPKCS1v15Tests {
+               out, err := DecryptPKCS1v15(nil, rsaPrivateKey, decodeBase64(test.in))
+               if err != nil {
+                       t.Errorf("#%d error decrypting", i)
+               }
+               want := []byte(test.out)
+               if bytes.Compare(out, want) != 0 {
+                       t.Errorf("#%d got:%#v want:%#v", i, out, want)
+               }
+       }
+}
+
+func TestEncryptPKCS1v15(t *testing.T) {
+       random := rand.Reader
+       k := (rsaPrivateKey.N.BitLen() + 7) / 8
+
+       tryEncryptDecrypt := func(in []byte, blind bool) bool {
+               if len(in) > k-11 {
+                       in = in[0 : k-11]
+               }
+
+               ciphertext, err := EncryptPKCS1v15(random, &rsaPrivateKey.PublicKey, in)
+               if err != nil {
+                       t.Errorf("error encrypting: %s", err)
+                       return false
+               }
+
+               var rand io.Reader
+               if !blind {
+                       rand = nil
+               } else {
+                       rand = random
+               }
+               plaintext, err := DecryptPKCS1v15(rand, rsaPrivateKey, ciphertext)
+               if err != nil {
+                       t.Errorf("error decrypting: %s", err)
+                       return false
+               }
+
+               if bytes.Compare(plaintext, in) != 0 {
+                       t.Errorf("output mismatch: %#v %#v", plaintext, in)
+                       return false
+               }
+               return true
+       }
+
+       quick.Check(tryEncryptDecrypt, nil)
+}
+
+// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
+var decryptPKCS1v15SessionKeyTests = []DecryptPKCS1v15Test{
+       {
+               "e6ukkae6Gykq0fKzYwULpZehX+UPXYzMoB5mHQUDEiclRbOTqas4Y0E6nwns1BBpdvEJcilhl5zsox/6DtGsYg==",
+               "1234",
+       },
+       {
+               "Dtis4uk/q/LQGGqGk97P59K03hkCIVFMEFZRgVWOAAhxgYpCRG0MX2adptt92l67IqMki6iVQyyt0TtX3IdtEw==",
+               "FAIL",
+       },
+       {
+               "LIyFyCYCptPxrvTxpol8F3M7ZivlMsf53zs0vHRAv+rDIh2YsHS69ePMoPMe3TkOMZ3NupiL3takPxIs1sK+dw==",
+               "abcd",
+       },
+       {
+               "bafnobel46bKy76JzqU/RIVOH0uAYvzUtauKmIidKgM0sMlvobYVAVQPeUQ/oTGjbIZ1v/6Gyi5AO4DtHruGdw==",
+               "FAIL",
+       },
+}
+
+func TestEncryptPKCS1v15SessionKey(t *testing.T) {
+       for i, test := range decryptPKCS1v15SessionKeyTests {
+               key := []byte("FAIL")
+               err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, decodeBase64(test.in), key)
+               if err != nil {
+                       t.Errorf("#%d error decrypting", i)
+               }
+               want := []byte(test.out)
+               if bytes.Compare(key, want) != 0 {
+                       t.Errorf("#%d got:%#v want:%#v", i, key, want)
+               }
+       }
+}
+
+func TestNonZeroRandomBytes(t *testing.T) {
+       random := rand.Reader
+
+       b := make([]byte, 512)
+       err := nonZeroRandomBytes(b, random)
+       if err != nil {
+               t.Errorf("returned error: %s", err)
+       }
+       for _, b := range b {
+               if b == 0 {
+                       t.Errorf("Zero octet found")
+                       return
+               }
+       }
+}
+
+type signPKCS1v15Test struct {
+       in, out string
+}
+
+// These vectors have been tested with
+//   `openssl rsautl -verify -inkey pk -in signature | hexdump -C`
+var signPKCS1v15Tests = []signPKCS1v15Test{
+       {"Test.\n", "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e336ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"},
+}
+
+func TestSignPKCS1v15(t *testing.T) {
+       for i, test := range signPKCS1v15Tests {
+               h := sha1.New()
+               h.Write([]byte(test.in))
+               digest := h.Sum()
+
+               s, err := SignPKCS1v15(nil, rsaPrivateKey, HashSHA1, digest)
+               if err != nil {
+                       t.Errorf("#%d %s", i, err)
+               }
+
+               expected, _ := hex.DecodeString(test.out)
+               if bytes.Compare(s, expected) != 0 {
+                       t.Errorf("#%d got: %x want: %x", i, s, expected)
+               }
+       }
+}
+
+func TestVerifyPKCS1v15(t *testing.T) {
+       for i, test := range signPKCS1v15Tests {
+               h := sha1.New()
+               h.Write([]byte(test.in))
+               digest := h.Sum()
+
+               sig, _ := hex.DecodeString(test.out)
+
+               err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, HashSHA1, digest, sig)
+               if err != nil {
+                       t.Errorf("#%d %s", i, err)
+               }
+       }
+}
+
+func bigFromString(s string) *big.Int {
+       ret := new(big.Int)
+       ret.SetString(s, 10)
+       return ret
+}
+
+// In order to generate new test vectors you'll need the PEM form of this key:
+// -----BEGIN RSA PRIVATE KEY-----
+// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+// fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+// /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+// RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+// EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+// IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+// tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+// -----END RSA PRIVATE KEY-----
+
+var rsaPrivateKey = &PrivateKey{
+       PublicKey: PublicKey{
+               N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
+               E: 65537,
+       },
+       D: bigFromString("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"),
+       P: bigFromString("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
+       Q: bigFromString("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
+}
diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go
new file mode 100644 (file)
index 0000000..c7a8d20
--- /dev/null
@@ -0,0 +1,445 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements RSA encryption as specified in PKCS#1.
+package rsa
+
+// TODO(agl): Add support for PSS padding.
+
+import (
+       "big"
+       "crypto/subtle"
+       "hash"
+       "io"
+       "os"
+)
+
+var bigZero = big.NewInt(0)
+var bigOne = big.NewInt(1)
+
+// randomPrime returns a number, p, of the given size, such that p is prime
+// with high probability.
+func randomPrime(rand io.Reader, bits int) (p *big.Int, err os.Error) {
+       if bits < 1 {
+               err = os.EINVAL
+       }
+
+       bytes := make([]byte, (bits+7)/8)
+       p = new(big.Int)
+
+       for {
+               _, err = io.ReadFull(rand, bytes)
+               if err != nil {
+                       return
+               }
+
+               // Don't let the value be too small.
+               bytes[0] |= 0x80
+               // Make the value odd since an even number this large certainly isn't prime.
+               bytes[len(bytes)-1] |= 1
+
+               p.SetBytes(bytes)
+               if big.ProbablyPrime(p, 20) {
+                       return
+               }
+       }
+
+       return
+}
+
+// randomNumber returns a uniform random value in [0, max).
+func randomNumber(rand io.Reader, max *big.Int) (n *big.Int, err os.Error) {
+       k := (max.BitLen() + 7) / 8
+
+       // r is the number of bits in the used in the most significant byte of
+       // max.
+       r := uint(max.BitLen() % 8)
+       if r == 0 {
+               r = 8
+       }
+
+       bytes := make([]byte, k)
+       n = new(big.Int)
+
+       for {
+               _, err = io.ReadFull(rand, bytes)
+               if err != nil {
+                       return
+               }
+
+               // Clear bits in the first byte to increase the probability
+               // that the candidate is < max.
+               bytes[0] &= uint8(int(1<<r) - 1)
+
+               n.SetBytes(bytes)
+               if n.Cmp(max) < 0 {
+                       return
+               }
+       }
+
+       return
+}
+
+// A PublicKey represents the public part of an RSA key.
+type PublicKey struct {
+       N *big.Int // modulus
+       E int      // public exponent
+}
+
+// A PrivateKey represents an RSA key
+type PrivateKey struct {
+       PublicKey          // public part.
+       D         *big.Int // private exponent
+       P, Q      *big.Int // prime factors of N
+}
+
+// Validate performs basic sanity checks on the key.
+// It returns nil if the key is valid, or else an os.Error describing a problem.
+
+func (priv PrivateKey) Validate() os.Error {
+       // Check that p and q are prime. Note that this is just a sanity
+       // check. Since the random witnesses chosen by ProbablyPrime are
+       // deterministic, given the candidate number, it's easy for an attack
+       // to generate composites that pass this test.
+       if !big.ProbablyPrime(priv.P, 20) {
+               return os.ErrorString("P is composite")
+       }
+       if !big.ProbablyPrime(priv.Q, 20) {
+               return os.ErrorString("Q is composite")
+       }
+
+       // Check that p*q == n.
+       modulus := new(big.Int).Mul(priv.P, priv.Q)
+       if modulus.Cmp(priv.N) != 0 {
+               return os.ErrorString("invalid modulus")
+       }
+       // Check that e and totient(p, q) are coprime.
+       pminus1 := new(big.Int).Sub(priv.P, bigOne)
+       qminus1 := new(big.Int).Sub(priv.Q, bigOne)
+       totient := new(big.Int).Mul(pminus1, qminus1)
+       e := big.NewInt(int64(priv.E))
+       gcd := new(big.Int)
+       x := new(big.Int)
+       y := new(big.Int)
+       big.GcdInt(gcd, x, y, totient, e)
+       if gcd.Cmp(bigOne) != 0 {
+               return os.ErrorString("invalid public exponent E")
+       }
+       // Check that de ≡ 1 (mod totient(p, q))
+       de := new(big.Int).Mul(priv.D, e)
+       de.Mod(de, totient)
+       if de.Cmp(bigOne) != 0 {
+               return os.ErrorString("invalid private exponent D")
+       }
+       return nil
+}
+
+// GenerateKeyPair generates an RSA keypair of the given bit size.
+func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
+       priv = new(PrivateKey)
+       // Smaller public exponents lead to faster public key
+       // operations. Since the exponent must be coprime to
+       // (p-1)(q-1), the smallest possible value is 3. Some have
+       // suggested that a larger exponent (often 2**16+1) be used
+       // since previous implementation bugs[1] were avoided when this
+       // was the case. However, there are no current reasons not to use
+       // small exponents.
+       // [1] http://marc.info/?l=cryptography&m=115694833312008&w=2
+       priv.E = 3
+
+       pminus1 := new(big.Int)
+       qminus1 := new(big.Int)
+       totient := new(big.Int)
+
+       for {
+               p, err := randomPrime(rand, bits/2)
+               if err != nil {
+                       return nil, err
+               }
+
+               q, err := randomPrime(rand, bits/2)
+               if err != nil {
+                       return nil, err
+               }
+
+               if p.Cmp(q) == 0 {
+                       continue
+               }
+
+               n := new(big.Int).Mul(p, q)
+               pminus1.Sub(p, bigOne)
+               qminus1.Sub(q, bigOne)
+               totient.Mul(pminus1, qminus1)
+
+               g := new(big.Int)
+               priv.D = new(big.Int)
+               y := new(big.Int)
+               e := big.NewInt(int64(priv.E))
+               big.GcdInt(g, priv.D, y, e, totient)
+
+               if g.Cmp(bigOne) == 0 {
+                       priv.D.Add(priv.D, totient)
+                       priv.P = p
+                       priv.Q = q
+                       priv.N = n
+
+                       break
+               }
+       }
+
+       return
+}
+
+// incCounter increments a four byte, big-endian counter.
+func incCounter(c *[4]byte) {
+       if c[3]++; c[3] != 0 {
+               return
+       }
+       if c[2]++; c[2] != 0 {
+               return
+       }
+       if c[1]++; c[1] != 0 {
+               return
+       }
+       c[0]++
+}
+
+// mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function
+// specified in PKCS#1 v2.1.
+func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
+       var counter [4]byte
+
+       done := 0
+       for done < len(out) {
+               hash.Write(seed)
+               hash.Write(counter[0:4])
+               digest := hash.Sum()
+               hash.Reset()
+
+               for i := 0; i < len(digest) && done < len(out); i++ {
+                       out[done] ^= digest[i]
+                       done++
+               }
+               incCounter(&counter)
+       }
+}
+
+// MessageTooLongError is returned when attempting to encrypt a message which
+// is too large for the size of the public key.
+type MessageTooLongError struct{}
+
+func (MessageTooLongError) String() string {
+       return "message too long for RSA public key size"
+}
+
+func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
+       e := big.NewInt(int64(pub.E))
+       c.Exp(m, e, pub.N)
+       return c
+}
+
+// EncryptOAEP encrypts the given message with RSA-OAEP.
+// The message must be no longer than the length of the public modulus less
+// twice the hash length plus 2.
+func EncryptOAEP(hash hash.Hash, rand io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err os.Error) {
+       hash.Reset()
+       k := (pub.N.BitLen() + 7) / 8
+       if len(msg) > k-2*hash.Size()-2 {
+               err = MessageTooLongError{}
+               return
+       }
+
+       hash.Write(label)
+       lHash := hash.Sum()
+       hash.Reset()
+
+       em := make([]byte, k)
+       seed := em[1 : 1+hash.Size()]
+       db := em[1+hash.Size():]
+
+       copy(db[0:hash.Size()], lHash)
+       db[len(db)-len(msg)-1] = 1
+       copy(db[len(db)-len(msg):], msg)
+
+       _, err = io.ReadFull(rand, seed)
+       if err != nil {
+               return
+       }
+
+       mgf1XOR(db, hash, seed)
+       mgf1XOR(seed, hash, db)
+
+       m := new(big.Int)
+       m.SetBytes(em)
+       c := encrypt(new(big.Int), pub, m)
+       out = c.Bytes()
+       return
+}
+
+// A DecryptionError represents a failure to decrypt a message.
+// It is deliberately vague to avoid adaptive attacks.
+type DecryptionError struct{}
+
+func (DecryptionError) String() string { return "RSA decryption error" }
+
+// A VerificationError represents a failure to verify a signature.
+// It is deliberately vague to avoid adaptive attacks.
+type VerificationError struct{}
+
+func (VerificationError) String() string { return "RSA verification error" }
+
+// modInverse returns ia, the inverse of a in the multiplicative group of prime
+// order n. It requires that a be a member of the group (i.e. less than n).
+func modInverse(a, n *big.Int) (ia *big.Int, ok bool) {
+       g := new(big.Int)
+       x := new(big.Int)
+       y := new(big.Int)
+       big.GcdInt(g, x, y, a, n)
+       if g.Cmp(bigOne) != 0 {
+               // In this case, a and n aren't coprime and we cannot calculate
+               // the inverse. This happens because the values of n are nearly
+               // prime (being the product of two primes) rather than truly
+               // prime.
+               return
+       }
+
+       if x.Cmp(bigOne) < 0 {
+               // 0 is not the multiplicative inverse of any element so, if x
+               // < 1, then x is negative.
+               x.Add(x, n)
+       }
+
+       return x, true
+}
+
+// decrypt performs an RSA decryption, resulting in a plaintext integer. If a
+// random source is given, RSA blinding is used.
+func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) {
+       // TODO(agl): can we get away with reusing blinds?
+       if c.Cmp(priv.N) > 0 {
+               err = DecryptionError{}
+               return
+       }
+
+       var ir *big.Int
+       if rand != nil {
+               // Blinding enabled. Blinding involves multiplying c by r^e.
+               // Then the decryption operation performs (m^e * r^e)^d mod n
+               // which equals mr mod n. The factor of r can then be removed
+               // by multipling by the multiplicative inverse of r.
+
+               var r *big.Int
+
+               for {
+                       r, err = randomNumber(rand, priv.N)
+                       if err != nil {
+                               return
+                       }
+                       if r.Cmp(bigZero) == 0 {
+                               r = bigOne
+                       }
+                       var ok bool
+                       ir, ok = modInverse(r, priv.N)
+                       if ok {
+                               break
+                       }
+               }
+               bigE := big.NewInt(int64(priv.E))
+               rpowe := new(big.Int).Exp(r, bigE, priv.N)
+               c.Mul(c, rpowe)
+               c.Mod(c, priv.N)
+       }
+
+       m = new(big.Int).Exp(c, priv.D, priv.N)
+
+       if ir != nil {
+               // Unblind.
+               m.Mul(m, ir)
+               m.Mod(m, priv.N)
+       }
+
+       return
+}
+
+// DecryptOAEP decrypts ciphertext using RSA-OAEP.
+// If rand != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
+func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err os.Error) {
+       k := (priv.N.BitLen() + 7) / 8
+       if len(ciphertext) > k ||
+               k < hash.Size()*2+2 {
+               err = DecryptionError{}
+               return
+       }
+
+       c := new(big.Int).SetBytes(ciphertext)
+
+       m, err := decrypt(rand, priv, c)
+       if err != nil {
+               return
+       }
+
+       hash.Write(label)
+       lHash := hash.Sum()
+       hash.Reset()
+
+       // Converting the plaintext number to bytes will strip any
+       // leading zeros so we may have to left pad. We do this unconditionally
+       // to avoid leaking timing information. (Although we still probably
+       // leak the number of leading zeros. It's not clear that we can do
+       // anything about this.)
+       em := leftPad(m.Bytes(), k)
+
+       firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
+
+       seed := em[1 : hash.Size()+1]
+       db := em[hash.Size()+1:]
+
+       mgf1XOR(seed, hash, db)
+       mgf1XOR(db, hash, seed)
+
+       lHash2 := db[0:hash.Size()]
+
+       // We have to validate the plaintext in constant time in order to avoid
+       // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal
+       // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1
+       // v2.0. In J. Kilian, editor, Advances in Cryptology.
+       lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2)
+
+       // The remainder of the plaintext must be zero or more 0x00, followed
+       // by 0x01, followed by the message.
+       //   lookingForIndex: 1 iff we are still looking for the 0x01
+       //   index: the offset of the first 0x01 byte
+       //   invalid: 1 iff we saw a non-zero byte before the 0x01.
+       var lookingForIndex, index, invalid int
+       lookingForIndex = 1
+       rest := db[hash.Size():]
+
+       for i := 0; i < len(rest); i++ {
+               equals0 := subtle.ConstantTimeByteEq(rest[i], 0)
+               equals1 := subtle.ConstantTimeByteEq(rest[i], 1)
+               index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index)
+               lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex)
+               invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid)
+       }
+
+       if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 {
+               err = DecryptionError{}
+               return
+       }
+
+       msg = rest[index+1:]
+       return
+}
+
+// leftPad returns a new slice of length size. The contents of input are right
+// aligned in the new slice.
+func leftPad(input []byte, size int) (out []byte) {
+       n := len(input)
+       if n > size {
+               n = size
+       }
+       out = make([]byte, size)
+       copy(out[len(out)-n:], input)
+       return
+}
diff --git a/libgo/go/crypto/rsa/rsa_test.go b/libgo/go/crypto/rsa/rsa_test.go
new file mode 100644 (file)
index 0000000..df1f17f
--- /dev/null
@@ -0,0 +1,250 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+import (
+       "big"
+       "bytes"
+       "crypto/rand"
+       "crypto/sha1"
+       "testing"
+)
+
+func TestKeyGeneration(t *testing.T) {
+       random := rand.Reader
+
+       priv, err := GenerateKey(random, 1024)
+       if err != nil {
+               t.Errorf("failed to generate key")
+       }
+       pub := &priv.PublicKey
+       m := big.NewInt(42)
+       c := encrypt(new(big.Int), pub, m)
+       m2, err := decrypt(nil, priv, c)
+       if err != nil {
+               t.Errorf("error while decrypting: %s", err)
+       }
+       if m.Cmp(m2) != 0 {
+               t.Errorf("got:%v, want:%v (%s)", m2, m, priv)
+       }
+
+       m3, err := decrypt(random, priv, c)
+       if err != nil {
+               t.Errorf("error while decrypting (blind): %s", err)
+       }
+       if m.Cmp(m3) != 0 {
+               t.Errorf("(blind) got:%v, want:%v", m3, m)
+       }
+}
+
+type testEncryptOAEPMessage struct {
+       in   []byte
+       seed []byte
+       out  []byte
+}
+
+type testEncryptOAEPStruct struct {
+       modulus string
+       e       int
+       d       string
+       msgs    []testEncryptOAEPMessage
+}
+
+func TestEncryptOAEP(t *testing.T) {
+       sha1 := sha1.New()
+       n := new(big.Int)
+       for i, test := range testEncryptOAEPData {
+               n.SetString(test.modulus, 16)
+               public := PublicKey{n, test.e}
+
+               for j, message := range test.msgs {
+                       randomSource := bytes.NewBuffer(message.seed)
+                       out, err := EncryptOAEP(sha1, randomSource, &public, message.in, nil)
+                       if err != nil {
+                               t.Errorf("#%d,%d error: %s", i, j, err)
+                       }
+                       if bytes.Compare(out, message.out) != 0 {
+                               t.Errorf("#%d,%d bad result: %s (want %s)", i, j, out, message.out)
+                       }
+               }
+       }
+}
+
+func TestDecryptOAEP(t *testing.T) {
+       random := rand.Reader
+
+       sha1 := sha1.New()
+       n := new(big.Int)
+       d := new(big.Int)
+       for i, test := range testEncryptOAEPData {
+               n.SetString(test.modulus, 16)
+               d.SetString(test.d, 16)
+               private := PrivateKey{PublicKey{n, test.e}, d, nil, nil}
+
+               for j, message := range test.msgs {
+                       out, err := DecryptOAEP(sha1, nil, &private, message.out, nil)
+                       if err != nil {
+                               t.Errorf("#%d,%d error: %s", i, j, err)
+                       } else if bytes.Compare(out, message.in) != 0 {
+                               t.Errorf("#%d,%d bad result: %#v (want %#v)", i, j, out, message.in)
+                       }
+
+                       // Decrypt with blinding.
+                       out, err = DecryptOAEP(sha1, random, &private, message.out, nil)
+                       if err != nil {
+                               t.Errorf("#%d,%d (blind) error: %s", i, j, err)
+                       } else if bytes.Compare(out, message.in) != 0 {
+                               t.Errorf("#%d,%d (blind) bad result: %#v (want %#v)", i, j, out, message.in)
+                       }
+               }
+       }
+}
+
+// testEncryptOAEPData contains a subset of the vectors from RSA's "Test vectors for RSA-OAEP".
+var testEncryptOAEPData = []testEncryptOAEPStruct{
+       // Key 1
+       {"a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb",
+               65537,
+               "53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1",
+               []testEncryptOAEPMessage{
+                       // Example 1.1
+                       {
+                               []byte{0x66, 0x28, 0x19, 0x4e, 0x12, 0x07, 0x3d, 0xb0,
+                                       0x3b, 0xa9, 0x4c, 0xda, 0x9e, 0xf9, 0x53, 0x23, 0x97,
+                                       0xd5, 0x0d, 0xba, 0x79, 0xb9, 0x87, 0x00, 0x4a, 0xfe,
+                                       0xfe, 0x34,
+                               },
+                               []byte{0x18, 0xb7, 0x76, 0xea, 0x21, 0x06, 0x9d, 0x69,
+                                       0x77, 0x6a, 0x33, 0xe9, 0x6b, 0xad, 0x48, 0xe1, 0xdd,
+                                       0xa0, 0xa5, 0xef,
+                               },
+                               []byte{0x35, 0x4f, 0xe6, 0x7b, 0x4a, 0x12, 0x6d, 0x5d,
+                                       0x35, 0xfe, 0x36, 0xc7, 0x77, 0x79, 0x1a, 0x3f, 0x7b,
+                                       0xa1, 0x3d, 0xef, 0x48, 0x4e, 0x2d, 0x39, 0x08, 0xaf,
+                                       0xf7, 0x22, 0xfa, 0xd4, 0x68, 0xfb, 0x21, 0x69, 0x6d,
+                                       0xe9, 0x5d, 0x0b, 0xe9, 0x11, 0xc2, 0xd3, 0x17, 0x4f,
+                                       0x8a, 0xfc, 0xc2, 0x01, 0x03, 0x5f, 0x7b, 0x6d, 0x8e,
+                                       0x69, 0x40, 0x2d, 0xe5, 0x45, 0x16, 0x18, 0xc2, 0x1a,
+                                       0x53, 0x5f, 0xa9, 0xd7, 0xbf, 0xc5, 0xb8, 0xdd, 0x9f,
+                                       0xc2, 0x43, 0xf8, 0xcf, 0x92, 0x7d, 0xb3, 0x13, 0x22,
+                                       0xd6, 0xe8, 0x81, 0xea, 0xa9, 0x1a, 0x99, 0x61, 0x70,
+                                       0xe6, 0x57, 0xa0, 0x5a, 0x26, 0x64, 0x26, 0xd9, 0x8c,
+                                       0x88, 0x00, 0x3f, 0x84, 0x77, 0xc1, 0x22, 0x70, 0x94,
+                                       0xa0, 0xd9, 0xfa, 0x1e, 0x8c, 0x40, 0x24, 0x30, 0x9c,
+                                       0xe1, 0xec, 0xcc, 0xb5, 0x21, 0x00, 0x35, 0xd4, 0x7a,
+                                       0xc7, 0x2e, 0x8a,
+                               },
+                       },
+                       // Example 1.2
+                       {
+                               []byte{0x75, 0x0c, 0x40, 0x47, 0xf5, 0x47, 0xe8, 0xe4,
+                                       0x14, 0x11, 0x85, 0x65, 0x23, 0x29, 0x8a, 0xc9, 0xba,
+                                       0xe2, 0x45, 0xef, 0xaf, 0x13, 0x97, 0xfb, 0xe5, 0x6f,
+                                       0x9d, 0xd5,
+                               },
+                               []byte{0x0c, 0xc7, 0x42, 0xce, 0x4a, 0x9b, 0x7f, 0x32,
+                                       0xf9, 0x51, 0xbc, 0xb2, 0x51, 0xef, 0xd9, 0x25, 0xfe,
+                                       0x4f, 0xe3, 0x5f,
+                               },
+                               []byte{0x64, 0x0d, 0xb1, 0xac, 0xc5, 0x8e, 0x05, 0x68,
+                                       0xfe, 0x54, 0x07, 0xe5, 0xf9, 0xb7, 0x01, 0xdf, 0xf8,
+                                       0xc3, 0xc9, 0x1e, 0x71, 0x6c, 0x53, 0x6f, 0xc7, 0xfc,
+                                       0xec, 0x6c, 0xb5, 0xb7, 0x1c, 0x11, 0x65, 0x98, 0x8d,
+                                       0x4a, 0x27, 0x9e, 0x15, 0x77, 0xd7, 0x30, 0xfc, 0x7a,
+                                       0x29, 0x93, 0x2e, 0x3f, 0x00, 0xc8, 0x15, 0x15, 0x23,
+                                       0x6d, 0x8d, 0x8e, 0x31, 0x01, 0x7a, 0x7a, 0x09, 0xdf,
+                                       0x43, 0x52, 0xd9, 0x04, 0xcd, 0xeb, 0x79, 0xaa, 0x58,
+                                       0x3a, 0xdc, 0xc3, 0x1e, 0xa6, 0x98, 0xa4, 0xc0, 0x52,
+                                       0x83, 0xda, 0xba, 0x90, 0x89, 0xbe, 0x54, 0x91, 0xf6,
+                                       0x7c, 0x1a, 0x4e, 0xe4, 0x8d, 0xc7, 0x4b, 0xbb, 0xe6,
+                                       0x64, 0x3a, 0xef, 0x84, 0x66, 0x79, 0xb4, 0xcb, 0x39,
+                                       0x5a, 0x35, 0x2d, 0x5e, 0xd1, 0x15, 0x91, 0x2d, 0xf6,
+                                       0x96, 0xff, 0xe0, 0x70, 0x29, 0x32, 0x94, 0x6d, 0x71,
+                                       0x49, 0x2b, 0x44,
+                               },
+                       },
+                       // Example 1.3
+                       {
+                               []byte{0xd9, 0x4a, 0xe0, 0x83, 0x2e, 0x64, 0x45, 0xce,
+                                       0x42, 0x33, 0x1c, 0xb0, 0x6d, 0x53, 0x1a, 0x82, 0xb1,
+                                       0xdb, 0x4b, 0xaa, 0xd3, 0x0f, 0x74, 0x6d, 0xc9, 0x16,
+                                       0xdf, 0x24, 0xd4, 0xe3, 0xc2, 0x45, 0x1f, 0xff, 0x59,
+                                       0xa6, 0x42, 0x3e, 0xb0, 0xe1, 0xd0, 0x2d, 0x4f, 0xe6,
+                                       0x46, 0xcf, 0x69, 0x9d, 0xfd, 0x81, 0x8c, 0x6e, 0x97,
+                                       0xb0, 0x51,
+                               },
+                               []byte{0x25, 0x14, 0xdf, 0x46, 0x95, 0x75, 0x5a, 0x67,
+                                       0xb2, 0x88, 0xea, 0xf4, 0x90, 0x5c, 0x36, 0xee, 0xc6,
+                                       0x6f, 0xd2, 0xfd,
+                               },
+                               []byte{0x42, 0x37, 0x36, 0xed, 0x03, 0x5f, 0x60, 0x26,
+                                       0xaf, 0x27, 0x6c, 0x35, 0xc0, 0xb3, 0x74, 0x1b, 0x36,
+                                       0x5e, 0x5f, 0x76, 0xca, 0x09, 0x1b, 0x4e, 0x8c, 0x29,
+                                       0xe2, 0xf0, 0xbe, 0xfe, 0xe6, 0x03, 0x59, 0x5a, 0xa8,
+                                       0x32, 0x2d, 0x60, 0x2d, 0x2e, 0x62, 0x5e, 0x95, 0xeb,
+                                       0x81, 0xb2, 0xf1, 0xc9, 0x72, 0x4e, 0x82, 0x2e, 0xca,
+                                       0x76, 0xdb, 0x86, 0x18, 0xcf, 0x09, 0xc5, 0x34, 0x35,
+                                       0x03, 0xa4, 0x36, 0x08, 0x35, 0xb5, 0x90, 0x3b, 0xc6,
+                                       0x37, 0xe3, 0x87, 0x9f, 0xb0, 0x5e, 0x0e, 0xf3, 0x26,
+                                       0x85, 0xd5, 0xae, 0xc5, 0x06, 0x7c, 0xd7, 0xcc, 0x96,
+                                       0xfe, 0x4b, 0x26, 0x70, 0xb6, 0xea, 0xc3, 0x06, 0x6b,
+                                       0x1f, 0xcf, 0x56, 0x86, 0xb6, 0x85, 0x89, 0xaa, 0xfb,
+                                       0x7d, 0x62, 0x9b, 0x02, 0xd8, 0xf8, 0x62, 0x5c, 0xa3,
+                                       0x83, 0x36, 0x24, 0xd4, 0x80, 0x0f, 0xb0, 0x81, 0xb1,
+                                       0xcf, 0x94, 0xeb,
+                               },
+                       },
+               },
+       },
+       // Key 10
+       {"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb",
+               65537,
+               "056b04216fe5f354ac77250a4b6b0c8525a85c59b0bd80c56450a22d5f438e596a333aa875e291dd43f48cb88b9d5fc0d499f9fcd1c397f9afc070cd9e398c8d19e61db7c7410a6b2675dfbf5d345b804d201add502d5ce2dfcb091ce9997bbebe57306f383e4d588103f036f7e85d1934d152a323e4a8db451d6f4a5b1b0f102cc150e02feee2b88dea4ad4c1baccb24d84072d14e1d24a6771f7408ee30564fb86d4393a34bcf0b788501d193303f13a2284b001f0f649eaf79328d4ac5c430ab4414920a9460ed1b7bc40ec653e876d09abc509ae45b525190116a0c26101848298509c1c3bf3a483e7274054e15e97075036e989f60932807b5257751e79",
+               []testEncryptOAEPMessage{
+                       // Example 10.1
+                       {
+                               []byte{0x8b, 0xba, 0x6b, 0xf8, 0x2a, 0x6c, 0x0f, 0x86,
+                                       0xd5, 0xf1, 0x75, 0x6e, 0x97, 0x95, 0x68, 0x70, 0xb0,
+                                       0x89, 0x53, 0xb0, 0x6b, 0x4e, 0xb2, 0x05, 0xbc, 0x16,
+                                       0x94, 0xee,
+                               },
+                               []byte{0x47, 0xe1, 0xab, 0x71, 0x19, 0xfe, 0xe5, 0x6c,
+                                       0x95, 0xee, 0x5e, 0xaa, 0xd8, 0x6f, 0x40, 0xd0, 0xaa,
+                                       0x63, 0xbd, 0x33,
+                               },
+                               []byte{0x53, 0xea, 0x5d, 0xc0, 0x8c, 0xd2, 0x60, 0xfb,
+                                       0x3b, 0x85, 0x85, 0x67, 0x28, 0x7f, 0xa9, 0x15, 0x52,
+                                       0xc3, 0x0b, 0x2f, 0xeb, 0xfb, 0xa2, 0x13, 0xf0, 0xae,
+                                       0x87, 0x70, 0x2d, 0x06, 0x8d, 0x19, 0xba, 0xb0, 0x7f,
+                                       0xe5, 0x74, 0x52, 0x3d, 0xfb, 0x42, 0x13, 0x9d, 0x68,
+                                       0xc3, 0xc5, 0xaf, 0xee, 0xe0, 0xbf, 0xe4, 0xcb, 0x79,
+                                       0x69, 0xcb, 0xf3, 0x82, 0xb8, 0x04, 0xd6, 0xe6, 0x13,
+                                       0x96, 0x14, 0x4e, 0x2d, 0x0e, 0x60, 0x74, 0x1f, 0x89,
+                                       0x93, 0xc3, 0x01, 0x4b, 0x58, 0xb9, 0xb1, 0x95, 0x7a,
+                                       0x8b, 0xab, 0xcd, 0x23, 0xaf, 0x85, 0x4f, 0x4c, 0x35,
+                                       0x6f, 0xb1, 0x66, 0x2a, 0xa7, 0x2b, 0xfc, 0xc7, 0xe5,
+                                       0x86, 0x55, 0x9d, 0xc4, 0x28, 0x0d, 0x16, 0x0c, 0x12,
+                                       0x67, 0x85, 0xa7, 0x23, 0xeb, 0xee, 0xbe, 0xff, 0x71,
+                                       0xf1, 0x15, 0x94, 0x44, 0x0a, 0xae, 0xf8, 0x7d, 0x10,
+                                       0x79, 0x3a, 0x87, 0x74, 0xa2, 0x39, 0xd4, 0xa0, 0x4c,
+                                       0x87, 0xfe, 0x14, 0x67, 0xb9, 0xda, 0xf8, 0x52, 0x08,
+                                       0xec, 0x6c, 0x72, 0x55, 0x79, 0x4a, 0x96, 0xcc, 0x29,
+                                       0x14, 0x2f, 0x9a, 0x8b, 0xd4, 0x18, 0xe3, 0xc1, 0xfd,
+                                       0x67, 0x34, 0x4b, 0x0c, 0xd0, 0x82, 0x9d, 0xf3, 0xb2,
+                                       0xbe, 0xc6, 0x02, 0x53, 0x19, 0x62, 0x93, 0xc6, 0xb3,
+                                       0x4d, 0x3f, 0x75, 0xd3, 0x2f, 0x21, 0x3d, 0xd4, 0x5c,
+                                       0x62, 0x73, 0xd5, 0x05, 0xad, 0xf4, 0xcc, 0xed, 0x10,
+                                       0x57, 0xcb, 0x75, 0x8f, 0xc2, 0x6a, 0xee, 0xfa, 0x44,
+                                       0x12, 0x55, 0xed, 0x4e, 0x64, 0xc1, 0x99, 0xee, 0x07,
+                                       0x5e, 0x7f, 0x16, 0x64, 0x61, 0x82, 0xfd, 0xb4, 0x64,
+                                       0x73, 0x9b, 0x68, 0xab, 0x5d, 0xaf, 0xf0, 0xe6, 0x3e,
+                                       0x95, 0x52, 0x01, 0x68, 0x24, 0xf0, 0x54, 0xbf, 0x4d,
+                                       0x3c, 0x8c, 0x90, 0xa9, 0x7b, 0xb6, 0xb6, 0x55, 0x32,
+                                       0x84, 0xeb, 0x42, 0x9f, 0xcc,
+                               },
+                       },
+               },
+       },
+}
diff --git a/libgo/go/crypto/sha1/sha1.go b/libgo/go/crypto/sha1/sha1.go
new file mode 100644 (file)
index 0000000..8716c35
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the SHA1 hash algorithm as defined in RFC 3174.
+package sha1
+
+import (
+       "hash"
+       "os"
+)
+
+// The size of a SHA1 checksum in bytes.
+const Size = 20
+
+const (
+       _Chunk = 64
+       _Init0 = 0x67452301
+       _Init1 = 0xEFCDAB89
+       _Init2 = 0x98BADCFE
+       _Init3 = 0x10325476
+       _Init4 = 0xC3D2E1F0
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+       h   [5]uint32
+       x   [_Chunk]byte
+       nx  int
+       len uint64
+}
+
+func (d *digest) Reset() {
+       d.h[0] = _Init0
+       d.h[1] = _Init1
+       d.h[2] = _Init2
+       d.h[3] = _Init3
+       d.h[4] = _Init4
+       d.nx = 0
+       d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA1 checksum.
+func New() hash.Hash {
+       d := new(digest)
+       d.Reset()
+       return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+       nn = len(p)
+       d.len += uint64(nn)
+       if d.nx > 0 {
+               n := len(p)
+               if n > _Chunk-d.nx {
+                       n = _Chunk - d.nx
+               }
+               for i := 0; i < n; i++ {
+                       d.x[d.nx+i] = p[i]
+               }
+               d.nx += n
+               if d.nx == _Chunk {
+                       _Block(d, d.x[0:])
+                       d.nx = 0
+               }
+               p = p[n:]
+       }
+       n := _Block(d, p)
+       p = p[n:]
+       if len(p) > 0 {
+               d.nx = copy(d.x[:], p)
+       }
+       return
+}
+
+func (d0 *digest) Sum() []byte {
+       // Make a copy of d0 so that caller can keep writing and summing.
+       d := new(digest)
+       *d = *d0
+
+       // Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
+       len := d.len
+       var tmp [64]byte
+       tmp[0] = 0x80
+       if len%64 < 56 {
+               d.Write(tmp[0 : 56-len%64])
+       } else {
+               d.Write(tmp[0 : 64+56-len%64])
+       }
+
+       // Length in bits.
+       len <<= 3
+       for i := uint(0); i < 8; i++ {
+               tmp[i] = byte(len >> (56 - 8*i))
+       }
+       d.Write(tmp[0:8])
+
+       if d.nx != 0 {
+               panic("d.nx != 0")
+       }
+
+       p := make([]byte, 20)
+       j := 0
+       for _, s := range d.h {
+               p[j+0] = byte(s >> 24)
+               p[j+1] = byte(s >> 16)
+               p[j+2] = byte(s >> 8)
+               p[j+3] = byte(s >> 0)
+               j += 4
+       }
+       return p
+}
diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go
new file mode 100644 (file)
index 0000000..2712fe3
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA1 hash algorithm.  See RFC 3174.
+
+package sha1
+
+import (
+       "fmt"
+       "io"
+       "testing"
+)
+
+type sha1Test struct {
+       out string
+       in  string
+}
+
+var golden = []sha1Test{
+       {"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
+       {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"},
+       {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"},
+       {"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"},
+       {"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd"},
+       {"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde"},
+       {"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef"},
+       {"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg"},
+       {"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh"},
+       {"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi"},
+       {"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij"},
+       {"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old."},
+       {"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last."},
+       {"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole."},
+       {"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign."},
+       {"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program."},
+       {"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine."},
+       {"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size:  a.out:  bad magic"},
+       {"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail.  -Mark Horton"},
+       {"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you."},
+       {"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams."},
+       {"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!"},
+       {"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++?  -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+       for i := 0; i < len(golden); i++ {
+               g := golden[i]
+               c := New()
+               for j := 0; j < 3; j++ {
+                       if j < 2 {
+                               io.WriteString(c, g.in)
+                       } else {
+                               io.WriteString(c, g.in[0:len(g.in)/2])
+                               c.Sum()
+                               io.WriteString(c, g.in[len(g.in)/2:])
+                       }
+                       s := fmt.Sprintf("%x", c.Sum())
+                       if s != g.out {
+                               t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out)
+                       }
+                       c.Reset()
+               }
+       }
+}
diff --git a/libgo/go/crypto/sha1/sha1block.go b/libgo/go/crypto/sha1/sha1block.go
new file mode 100644 (file)
index 0000000..b5d32af
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA1 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha1
+
+const (
+       _K0 = 0x5A827999
+       _K1 = 0x6ED9EBA1
+       _K2 = 0x8F1BBCDC
+       _K3 = 0xCA62C1D6
+)
+
+func _Block(dig *digest, p []byte) int {
+       var w [80]uint32
+
+       n := 0
+       h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
+       for len(p) >= _Chunk {
+               // Can interlace the computation of w with the
+               // rounds below if needed for speed.
+               for i := 0; i < 16; i++ {
+                       j := i * 4
+                       w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
+               }
+               for i := 16; i < 80; i++ {
+                       tmp := w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]
+                       w[i] = tmp<<1 | tmp>>(32-1)
+               }
+
+               a, b, c, d, e := h0, h1, h2, h3, h4
+
+               // Each of the four 20-iteration rounds
+               // differs only in the computation of f and
+               // the choice of K (_K0, _K1, etc).
+               for i := 0; i < 20; i++ {
+                       f := b&c | (^b)&d
+                       a5 := a<<5 | a>>(32-5)
+                       b30 := b<<30 | b>>(32-30)
+                       t := a5 + f + e + w[i] + _K0
+                       a, b, c, d, e = t, a, b30, c, d
+               }
+               for i := 20; i < 40; i++ {
+                       f := b ^ c ^ d
+                       a5 := a<<5 | a>>(32-5)
+                       b30 := b<<30 | b>>(32-30)
+                       t := a5 + f + e + w[i] + _K1
+                       a, b, c, d, e = t, a, b30, c, d
+               }
+               for i := 40; i < 60; i++ {
+                       f := b&c | b&d | c&d
+                       a5 := a<<5 | a>>(32-5)
+                       b30 := b<<30 | b>>(32-30)
+                       t := a5 + f + e + w[i] + _K2
+                       a, b, c, d, e = t, a, b30, c, d
+               }
+               for i := 60; i < 80; i++ {
+                       f := b ^ c ^ d
+                       a5 := a<<5 | a>>(32-5)
+                       b30 := b<<30 | b>>(32-30)
+                       t := a5 + f + e + w[i] + _K3
+                       a, b, c, d, e = t, a, b30, c, d
+               }
+
+               h0 += a
+               h1 += b
+               h2 += c
+               h3 += d
+               h4 += e
+
+               p = p[_Chunk:]
+               n += _Chunk
+       }
+
+       dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] = h0, h1, h2, h3, h4
+       return n
+}
diff --git a/libgo/go/crypto/sha256/sha256.go b/libgo/go/crypto/sha256/sha256.go
new file mode 100644 (file)
index 0000000..57a8ffa
--- /dev/null
@@ -0,0 +1,159 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the SHA224 and SHA256 hash algorithms as defined in FIPS 180-2.
+package sha256
+
+import (
+       "hash"
+       "os"
+)
+
+// The size of a SHA256 checksum in bytes.
+const Size = 32
+
+// The size of a SHA224 checksum in bytes.
+const Size224 = 28
+
+const (
+       _Chunk     = 64
+       _Init0     = 0x6A09E667
+       _Init1     = 0xBB67AE85
+       _Init2     = 0x3C6EF372
+       _Init3     = 0xA54FF53A
+       _Init4     = 0x510E527F
+       _Init5     = 0x9B05688C
+       _Init6     = 0x1F83D9AB
+       _Init7     = 0x5BE0CD19
+       _Init0_224 = 0xC1059ED8
+       _Init1_224 = 0x367CD507
+       _Init2_224 = 0x3070DD17
+       _Init3_224 = 0xF70E5939
+       _Init4_224 = 0xFFC00B31
+       _Init5_224 = 0x68581511
+       _Init6_224 = 0x64F98FA7
+       _Init7_224 = 0xBEFA4FA4
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+       h     [8]uint32
+       x     [_Chunk]byte
+       nx    int
+       len   uint64
+       is224 bool // mark if this digest is SHA-224
+}
+
+func (d *digest) Reset() {
+       if !d.is224 {
+               d.h[0] = _Init0
+               d.h[1] = _Init1
+               d.h[2] = _Init2
+               d.h[3] = _Init3
+               d.h[4] = _Init4
+               d.h[5] = _Init5
+               d.h[6] = _Init6
+               d.h[7] = _Init7
+       } else {
+               d.h[0] = _Init0_224
+               d.h[1] = _Init1_224
+               d.h[2] = _Init2_224
+               d.h[3] = _Init3_224
+               d.h[4] = _Init4_224
+               d.h[5] = _Init5_224
+               d.h[6] = _Init6_224
+               d.h[7] = _Init7_224
+       }
+       d.nx = 0
+       d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA256 checksum.
+func New() hash.Hash {
+       d := new(digest)
+       d.Reset()
+       return d
+}
+
+// New224 returns a new hash.Hash computing the SHA224 checksum.
+func New224() hash.Hash {
+       d := new(digest)
+       d.is224 = true
+       d.Reset()
+       return d
+}
+
+func (d *digest) Size() int {
+       if !d.is224 {
+               return Size
+       }
+       return Size224
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+       nn = len(p)
+       d.len += uint64(nn)
+       if d.nx > 0 {
+               n := len(p)
+               if n > _Chunk-d.nx {
+                       n = _Chunk - d.nx
+               }
+               for i := 0; i < n; i++ {
+                       d.x[d.nx+i] = p[i]
+               }
+               d.nx += n
+               if d.nx == _Chunk {
+                       _Block(d, d.x[0:])
+                       d.nx = 0
+               }
+               p = p[n:]
+       }
+       n := _Block(d, p)
+       p = p[n:]
+       if len(p) > 0 {
+               d.nx = copy(d.x[:], p)
+       }
+       return
+}
+
+func (d0 *digest) Sum() []byte {
+       // Make a copy of d0 so that caller can keep writing and summing.
+       d := new(digest)
+       *d = *d0
+
+       // Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
+       len := d.len
+       var tmp [64]byte
+       tmp[0] = 0x80
+       if len%64 < 56 {
+               d.Write(tmp[0 : 56-len%64])
+       } else {
+               d.Write(tmp[0 : 64+56-len%64])
+       }
+
+       // Length in bits.
+       len <<= 3
+       for i := uint(0); i < 8; i++ {
+               tmp[i] = byte(len >> (56 - 8*i))
+       }
+       d.Write(tmp[0:8])
+
+       if d.nx != 0 {
+               panic("d.nx != 0")
+       }
+
+       p := make([]byte, 32)
+       j := 0
+       for _, s := range d.h {
+               p[j+0] = byte(s >> 24)
+               p[j+1] = byte(s >> 16)
+               p[j+2] = byte(s >> 8)
+               p[j+3] = byte(s >> 0)
+               j += 4
+       }
+       if d.is224 {
+               return p[0:28]
+       }
+       return p
+}
diff --git a/libgo/go/crypto/sha256/sha256_test.go b/libgo/go/crypto/sha256/sha256_test.go
new file mode 100644 (file)
index 0000000..42a3fa7
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA256 hash algorithm.  See FIPS 180-2.
+
+package sha256
+
+import (
+       "fmt"
+       "io"
+       "testing"
+)
+
+type sha256Test struct {
+       out string
+       in  string
+}
+
+var golden = []sha256Test{
+       {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""},
+       {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"},
+       {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"},
+       {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"},
+       {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"},
+       {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"},
+       {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"},
+       {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"},
+       {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"},
+       {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"},
+       {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"},
+       {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."},
+       {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."},
+       {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."},
+       {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."},
+       {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."},
+       {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."},
+       {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size:  a.out:  bad magic"},
+       {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail.  -Mark Horton"},
+       {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."},
+       {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."},
+       {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"},
+       {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++?  -Paul Glick"},
+}
+
+var golden224 = []sha256Test{
+       {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""},
+       {"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", "a"},
+       {"db3cda86d4429a1d39c148989566b38f7bda0156296bd364ba2f878b", "ab"},
+       {"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"},
+       {"a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601", "abcd"},
+       {"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6", "abcde"},
+       {"7043631cb415556a275a4ebecb802c74ee9f6153908e1792a90b6a98", "abcdef"},
+       {"d1884e711701ad81abe0c77a3b0ea12e19ba9af64077286c72fc602d", "abcdefg"},
+       {"17eb7d40f0356f8598e89eafad5f6c759b1f822975d9c9b737c8a517", "abcdefgh"},
+       {"aeb35915346c584db820d2de7af3929ffafef9222a9bcb26516c7334", "abcdefghi"},
+       {"d35e1e5af29ddb0d7e154357df4ad9842afee527c689ee547f753188", "abcdefghij"},
+       {"19297f1cef7ddc8a7e947f5c5a341e10f7245045e425db67043988d7", "Discard medicine more than two years old."},
+       {"0f10c2eb436251f777fbbd125e260d36aecf180411726c7c885f599a", "He who has a shady past knows that nice guys finish last."},
+       {"4d1842104919f314cad8a3cd20b3cba7e8ed3e7abed62b57441358f6", "I wouldn't marry him with a ten foot pole."},
+       {"a8ba85c6fe0c48fbffc72bbb2f03fcdbc87ae2dc7a56804d1590fb3b", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {"5543fbab26e67e8885b1a852d567d1cb8b9bfe42e0899584c50449a9", "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {"65ca107390f5da9efa05d28e57b221657edc7e43a9a18fb15b053ddb", "Nepal premier won't resign."},
+       {"84953962be366305a9cc9b5cd16ed019edc37ac96c0deb3e12cca116", "For every action there is an equal and opposite government program."},
+       {"35a189ce987151dfd00b3577583cc6a74b9869eecf894459cb52038d", "His money is twice tainted: 'taint yours and 'taint mine."},
+       {"2fc333713983edfd4ef2c0da6fb6d6415afb94987c91e4069eb063e6", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {"cbe32d38d577a1b355960a4bc3c659c2dc4670859a19777a875842c4", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {"a2dc118ce959e027576413a7b440c875cdc8d40df9141d6ef78a57e1", "size:  a.out:  bad magic"},
+       {"d10787e24052bcff26dc484787a54ed819e4e4511c54890ee977bf81", "The major problem is with sendmail.  -Mark Horton"},
+       {"62efcf16ab8a893acdf2f348aaf06b63039ff1bf55508c830532c9fb", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {"3e9b7e4613c59f58665104c5fa86c272db5d3a2ff30df5bb194a5c99", "If the enemy is within range, then so are you."},
+       {"5999c208b8bdf6d471bb7c359ac5b829e73a8211dff686143a4e7f18", "It's well we cannot hear the screams/That we create in others' dreams."},
+       {"3b2d67ff54eabc4ef737b14edf87c64280ef582bcdf2a6d56908b405", "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {"d0733595d20e4d3d6b5c565a445814d1bbb2fd08b9a3b8ffb97930c6", "C is as portable as Stonehedge!!"},
+       {"43fb8aeed8a833175c9295c1165415f98c866ef08a4922959d673507", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {"ec18e66e93afc4fb1604bc2baedbfd20b44c43d76e65c0996d7851c6", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {"86ed2eaa9c75ba98396e5c9fb2f679ecf0ea2ed1e0ee9ceecb4a9332", "How can you write a big system without C++?  -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+       for i := 0; i < len(golden); i++ {
+               g := golden[i]
+               c := New()
+               for j := 0; j < 3; j++ {
+                       if j < 2 {
+                               io.WriteString(c, g.in)
+                       } else {
+                               io.WriteString(c, g.in[0:len(g.in)/2])
+                               c.Sum()
+                               io.WriteString(c, g.in[len(g.in)/2:])
+                       }
+                       s := fmt.Sprintf("%x", c.Sum())
+                       if s != g.out {
+                               t.Fatalf("sha256[%d](%s) = %s want %s", j, g.in, s, g.out)
+                       }
+                       c.Reset()
+               }
+       }
+       for i := 0; i < len(golden224); i++ {
+               g := golden224[i]
+               c := New224()
+               for j := 0; j < 3; j++ {
+                       if j < 2 {
+                               io.WriteString(c, g.in)
+                       } else {
+                               io.WriteString(c, g.in[0:len(g.in)/2])
+                               c.Sum()
+                               io.WriteString(c, g.in[len(g.in)/2:])
+                       }
+                       s := fmt.Sprintf("%x", c.Sum())
+                       if s != g.out {
+                               t.Fatalf("sha224[%d](%s) = %s want %s", j, g.in, s, g.out)
+                       }
+                       c.Reset()
+               }
+       }
+}
diff --git a/libgo/go/crypto/sha256/sha256block.go b/libgo/go/crypto/sha256/sha256block.go
new file mode 100644 (file)
index 0000000..7b0f554
--- /dev/null
@@ -0,0 +1,129 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA256 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha256
+
+var _K = []uint32{
+       0x428a2f98,
+       0x71374491,
+       0xb5c0fbcf,
+       0xe9b5dba5,
+       0x3956c25b,
+       0x59f111f1,
+       0x923f82a4,
+       0xab1c5ed5,
+       0xd807aa98,
+       0x12835b01,
+       0x243185be,
+       0x550c7dc3,
+       0x72be5d74,
+       0x80deb1fe,
+       0x9bdc06a7,
+       0xc19bf174,
+       0xe49b69c1,
+       0xefbe4786,
+       0x0fc19dc6,
+       0x240ca1cc,
+       0x2de92c6f,
+       0x4a7484aa,
+       0x5cb0a9dc,
+       0x76f988da,
+       0x983e5152,
+       0xa831c66d,
+       0xb00327c8,
+       0xbf597fc7,
+       0xc6e00bf3,
+       0xd5a79147,
+       0x06ca6351,
+       0x14292967,
+       0x27b70a85,
+       0x2e1b2138,
+       0x4d2c6dfc,
+       0x53380d13,
+       0x650a7354,
+       0x766a0abb,
+       0x81c2c92e,
+       0x92722c85,
+       0xa2bfe8a1,
+       0xa81a664b,
+       0xc24b8b70,
+       0xc76c51a3,
+       0xd192e819,
+       0xd6990624,
+       0xf40e3585,
+       0x106aa070,
+       0x19a4c116,
+       0x1e376c08,
+       0x2748774c,
+       0x34b0bcb5,
+       0x391c0cb3,
+       0x4ed8aa4a,
+       0x5b9cca4f,
+       0x682e6ff3,
+       0x748f82ee,
+       0x78a5636f,
+       0x84c87814,
+       0x8cc70208,
+       0x90befffa,
+       0xa4506ceb,
+       0xbef9a3f7,
+       0xc67178f2,
+}
+
+func _Block(dig *digest, p []byte) int {
+       var w [64]uint32
+       n := 0
+       h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
+       for len(p) >= _Chunk {
+               // Can interlace the computation of w with the
+               // rounds below if needed for speed.
+               for i := 0; i < 16; i++ {
+                       j := i * 4
+                       w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
+               }
+               for i := 16; i < 64; i++ {
+                       t1 := (w[i-2]>>17 | w[i-2]<<(32-17)) ^ (w[i-2]>>19 | w[i-2]<<(32-19)) ^ (w[i-2] >> 10)
+
+                       t2 := (w[i-15]>>7 | w[i-15]<<(32-7)) ^ (w[i-15]>>18 | w[i-15]<<(32-18)) ^ (w[i-15] >> 3)
+
+                       w[i] = t1 + w[i-7] + t2 + w[i-16]
+               }
+
+               a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
+
+               for i := 0; i < 64; i++ {
+                       t1 := h + ((e>>6 | e<<(32-6)) ^ (e>>11 | e<<(32-11)) ^ (e>>25 | e<<(32-25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
+
+                       t2 := ((a>>2 | a<<(32-2)) ^ (a>>13 | a<<(32-13)) ^ (a>>22 | a<<(32-22))) + ((a & b) ^ (a & c) ^ (b & c))
+
+                       h = g
+                       g = f
+                       f = e
+                       e = d + t1
+                       d = c
+                       c = b
+                       b = a
+                       a = t1 + t2
+               }
+
+               h0 += a
+               h1 += b
+               h2 += c
+               h3 += d
+               h4 += e
+               h5 += f
+               h6 += g
+               h7 += h
+
+               p = p[_Chunk:]
+               n += _Chunk
+       }
+
+       dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
+       return n
+}
diff --git a/libgo/go/crypto/sha512/sha512.go b/libgo/go/crypto/sha512/sha512.go
new file mode 100644 (file)
index 0000000..c3cda97
--- /dev/null
@@ -0,0 +1,163 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the SHA384 and SHA512 hash algorithms as defined in FIPS 180-2.
+package sha512
+
+import (
+       "hash"
+       "os"
+)
+
+// The size of a SHA512 checksum in bytes.
+const Size = 64
+
+// The size of a SHA384 checksum in bytes.
+const Size384 = 48
+
+const (
+       _Chunk     = 128
+       _Init0     = 0x6a09e667f3bcc908
+       _Init1     = 0xbb67ae8584caa73b
+       _Init2     = 0x3c6ef372fe94f82b
+       _Init3     = 0xa54ff53a5f1d36f1
+       _Init4     = 0x510e527fade682d1
+       _Init5     = 0x9b05688c2b3e6c1f
+       _Init6     = 0x1f83d9abfb41bd6b
+       _Init7     = 0x5be0cd19137e2179
+       _Init0_384 = 0xcbbb9d5dc1059ed8
+       _Init1_384 = 0x629a292a367cd507
+       _Init2_384 = 0x9159015a3070dd17
+       _Init3_384 = 0x152fecd8f70e5939
+       _Init4_384 = 0x67332667ffc00b31
+       _Init5_384 = 0x8eb44a8768581511
+       _Init6_384 = 0xdb0c2e0d64f98fa7
+       _Init7_384 = 0x47b5481dbefa4fa4
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+       h     [8]uint64
+       x     [_Chunk]byte
+       nx    int
+       len   uint64
+       is384 bool // mark if this digest is SHA-384
+}
+
+func (d *digest) Reset() {
+       if !d.is384 {
+               d.h[0] = _Init0
+               d.h[1] = _Init1
+               d.h[2] = _Init2
+               d.h[3] = _Init3
+               d.h[4] = _Init4
+               d.h[5] = _Init5
+               d.h[6] = _Init6
+               d.h[7] = _Init7
+       } else {
+               d.h[0] = _Init0_384
+               d.h[1] = _Init1_384
+               d.h[2] = _Init2_384
+               d.h[3] = _Init3_384
+               d.h[4] = _Init4_384
+               d.h[5] = _Init5_384
+               d.h[6] = _Init6_384
+               d.h[7] = _Init7_384
+       }
+       d.nx = 0
+       d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA512 checksum.
+func New() hash.Hash {
+       d := new(digest)
+       d.Reset()
+       return d
+}
+
+// New384 returns a new hash.Hash computing the SHA384 checksum.
+func New384() hash.Hash {
+       d := new(digest)
+       d.is384 = true
+       d.Reset()
+       return d
+}
+
+func (d *digest) Size() int {
+       if !d.is384 {
+               return Size
+       }
+       return Size384
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+       nn = len(p)
+       d.len += uint64(nn)
+       if d.nx > 0 {
+               n := len(p)
+               if n > _Chunk-d.nx {
+                       n = _Chunk - d.nx
+               }
+               for i := 0; i < n; i++ {
+                       d.x[d.nx+i] = p[i]
+               }
+               d.nx += n
+               if d.nx == _Chunk {
+                       _Block(d, d.x[0:])
+                       d.nx = 0
+               }
+               p = p[n:]
+       }
+       n := _Block(d, p)
+       p = p[n:]
+       if len(p) > 0 {
+               d.nx = copy(d.x[:], p)
+       }
+       return
+}
+
+func (d0 *digest) Sum() []byte {
+       // Make a copy of d0 so that caller can keep writing and summing.
+       d := new(digest)
+       *d = *d0
+
+       // Padding.  Add a 1 bit and 0 bits until 112 bytes mod 128.
+       len := d.len
+       var tmp [128]byte
+       tmp[0] = 0x80
+       if len%128 < 112 {
+               d.Write(tmp[0 : 112-len%128])
+       } else {
+               d.Write(tmp[0 : 128+112-len%128])
+       }
+
+       // Length in bits.
+       len <<= 3
+       for i := uint(0); i < 16; i++ {
+               tmp[i] = byte(len >> (120 - 8*i))
+       }
+       d.Write(tmp[0:16])
+
+       if d.nx != 0 {
+               panic("d.nx != 0")
+       }
+
+       p := make([]byte, 64)
+       j := 0
+       for _, s := range d.h {
+               p[j+0] = byte(s >> 56)
+               p[j+1] = byte(s >> 48)
+               p[j+2] = byte(s >> 40)
+               p[j+3] = byte(s >> 32)
+               p[j+4] = byte(s >> 24)
+               p[j+5] = byte(s >> 16)
+               p[j+6] = byte(s >> 8)
+               p[j+7] = byte(s >> 0)
+               j += 8
+       }
+       if d.is384 {
+               return p[0:48]
+       }
+       return p
+}
diff --git a/libgo/go/crypto/sha512/sha512_test.go b/libgo/go/crypto/sha512/sha512_test.go
new file mode 100644 (file)
index 0000000..dd116dc
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA512 hash algorithm.  See FIPS 180-2.
+
+package sha512
+
+import (
+       "fmt"
+       "io"
+       "testing"
+)
+
+type sha512Test struct {
+       out string
+       in  string
+}
+
+var golden = []sha512Test{
+       {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""},
+       {"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", "a"},
+       {"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", "ab"},
+       {"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"},
+       {"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", "abcd"},
+       {"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", "abcde"},
+       {"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", "abcdef"},
+       {"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", "abcdefg"},
+       {"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", "abcdefgh"},
+       {"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", "abcdefghi"},
+       {"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", "abcdefghij"},
+       {"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", "Discard medicine more than two years old."},
+       {"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", "He who has a shady past knows that nice guys finish last."},
+       {"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", "I wouldn't marry him with a ten foot pole."},
+       {"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", "Nepal premier won't resign."},
+       {"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", "For every action there is an equal and opposite government program."},
+       {"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", "His money is twice tainted: 'taint yours and 'taint mine."},
+       {"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", "size:  a.out:  bad magic"},
+       {"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", "The major problem is with sendmail.  -Mark Horton"},
+       {"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", "If the enemy is within range, then so are you."},
+       {"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", "It's well we cannot hear the screams/That we create in others' dreams."},
+       {"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", "C is as portable as Stonehedge!!"},
+       {"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", "How can you write a big system without C++?  -Paul Glick"},
+}
+
+var golden384 = []sha512Test{
+       {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""},
+       {"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "a"},
+       {"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "ab"},
+       {"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"},
+       {"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "abcd"},
+       {"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "abcde"},
+       {"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "abcdef"},
+       {"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "abcdefg"},
+       {"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "abcdefgh"},
+       {"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "abcdefghi"},
+       {"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "abcdefghij"},
+       {"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "Discard medicine more than two years old."},
+       {"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "He who has a shady past knows that nice guys finish last."},
+       {"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "I wouldn't marry him with a ten foot pole."},
+       {"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "Nepal premier won't resign."},
+       {"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "For every action there is an equal and opposite government program."},
+       {"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "His money is twice tainted: 'taint yours and 'taint mine."},
+       {"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "size:  a.out:  bad magic"},
+       {"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "The major problem is with sendmail.  -Mark Horton"},
+       {"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "If the enemy is within range, then so are you."},
+       {"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "It's well we cannot hear the screams/That we create in others' dreams."},
+       {"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "C is as portable as Stonehedge!!"},
+       {"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "How can you write a big system without C++?  -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+       for i := 0; i < len(golden); i++ {
+               g := golden[i]
+               c := New()
+               for j := 0; j < 3; j++ {
+                       if j < 2 {
+                               io.WriteString(c, g.in)
+                       } else {
+                               io.WriteString(c, g.in[0:len(g.in)/2])
+                               c.Sum()
+                               io.WriteString(c, g.in[len(g.in)/2:])
+                       }
+                       s := fmt.Sprintf("%x", c.Sum())
+                       if s != g.out {
+                               t.Fatalf("sha512[%d](%s) = %s want %s", j, g.in, s, g.out)
+                       }
+                       c.Reset()
+               }
+       }
+       for i := 0; i < len(golden384); i++ {
+               g := golden384[i]
+               c := New384()
+               for j := 0; j < 3; j++ {
+                       if j < 2 {
+                               io.WriteString(c, g.in)
+                       } else {
+                               io.WriteString(c, g.in[0:len(g.in)/2])
+                               c.Sum()
+                               io.WriteString(c, g.in[len(g.in)/2:])
+                       }
+                       s := fmt.Sprintf("%x", c.Sum())
+                       if s != g.out {
+                               t.Fatalf("sha384[%d](%s) = %s want %s", j, g.in, s, g.out)
+                       }
+                       c.Reset()
+               }
+       }
+}
diff --git a/libgo/go/crypto/sha512/sha512block.go b/libgo/go/crypto/sha512/sha512block.go
new file mode 100644 (file)
index 0000000..6b75062
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA512 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha512
+
+var _K = []uint64{
+       0x428a2f98d728ae22,
+       0x7137449123ef65cd,
+       0xb5c0fbcfec4d3b2f,
+       0xe9b5dba58189dbbc,
+       0x3956c25bf348b538,
+       0x59f111f1b605d019,
+       0x923f82a4af194f9b,
+       0xab1c5ed5da6d8118,
+       0xd807aa98a3030242,
+       0x12835b0145706fbe,
+       0x243185be4ee4b28c,
+       0x550c7dc3d5ffb4e2,
+       0x72be5d74f27b896f,
+       0x80deb1fe3b1696b1,
+       0x9bdc06a725c71235,
+       0xc19bf174cf692694,
+       0xe49b69c19ef14ad2,
+       0xefbe4786384f25e3,
+       0x0fc19dc68b8cd5b5,
+       0x240ca1cc77ac9c65,
+       0x2de92c6f592b0275,
+       0x4a7484aa6ea6e483,
+       0x5cb0a9dcbd41fbd4,
+       0x76f988da831153b5,
+       0x983e5152ee66dfab,
+       0xa831c66d2db43210,
+       0xb00327c898fb213f,
+       0xbf597fc7beef0ee4,
+       0xc6e00bf33da88fc2,
+       0xd5a79147930aa725,
+       0x06ca6351e003826f,
+       0x142929670a0e6e70,
+       0x27b70a8546d22ffc,
+       0x2e1b21385c26c926,
+       0x4d2c6dfc5ac42aed,
+       0x53380d139d95b3df,
+       0x650a73548baf63de,
+       0x766a0abb3c77b2a8,
+       0x81c2c92e47edaee6,
+       0x92722c851482353b,
+       0xa2bfe8a14cf10364,
+       0xa81a664bbc423001,
+       0xc24b8b70d0f89791,
+       0xc76c51a30654be30,
+       0xd192e819d6ef5218,
+       0xd69906245565a910,
+       0xf40e35855771202a,
+       0x106aa07032bbd1b8,
+       0x19a4c116b8d2d0c8,
+       0x1e376c085141ab53,
+       0x2748774cdf8eeb99,
+       0x34b0bcb5e19b48a8,
+       0x391c0cb3c5c95a63,
+       0x4ed8aa4ae3418acb,
+       0x5b9cca4f7763e373,
+       0x682e6ff3d6b2b8a3,
+       0x748f82ee5defb2fc,
+       0x78a5636f43172f60,
+       0x84c87814a1f0ab72,
+       0x8cc702081a6439ec,
+       0x90befffa23631e28,
+       0xa4506cebde82bde9,
+       0xbef9a3f7b2c67915,
+       0xc67178f2e372532b,
+       0xca273eceea26619c,
+       0xd186b8c721c0c207,
+       0xeada7dd6cde0eb1e,
+       0xf57d4f7fee6ed178,
+       0x06f067aa72176fba,
+       0x0a637dc5a2c898a6,
+       0x113f9804bef90dae,
+       0x1b710b35131c471b,
+       0x28db77f523047d84,
+       0x32caab7b40c72493,
+       0x3c9ebe0a15c9bebc,
+       0x431d67c49c100d4c,
+       0x4cc5d4becb3e42b6,
+       0x597f299cfc657e2a,
+       0x5fcb6fab3ad6faec,
+       0x6c44198c4a475817,
+}
+
+func _Block(dig *digest, p []byte) int {
+       var w [80]uint64
+       n := 0
+       h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
+       for len(p) >= _Chunk {
+               for i := 0; i < 16; i++ {
+                       j := i * 8
+                       w[i] = uint64(p[j])<<56 | uint64(p[j+1])<<48 | uint64(p[j+2])<<40 | uint64(p[j+3])<<32 |
+                               uint64(p[j+4])<<24 | uint64(p[j+5])<<16 | uint64(p[j+6])<<8 | uint64(p[j+7])
+               }
+               for i := 16; i < 80; i++ {
+                       t1 := (w[i-2]>>19 | w[i-2]<<(64-19)) ^ (w[i-2]>>61 | w[i-2]<<(64-61)) ^ (w[i-2] >> 6)
+
+                       t2 := (w[i-15]>>1 | w[i-15]<<(64-1)) ^ (w[i-15]>>8 | w[i-15]<<(64-8)) ^ (w[i-15] >> 7)
+
+                       w[i] = t1 + w[i-7] + t2 + w[i-16]
+               }
+
+               a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
+
+               for i := 0; i < 80; i++ {
+                       t1 := h + ((e>>14 | e<<(64-14)) ^ (e>>18 | e<<(64-18)) ^ (e>>41 | e<<(64-41))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
+
+                       t2 := ((a>>28 | a<<(64-28)) ^ (a>>34 | a<<(64-34)) ^ (a>>39 | a<<(64-39))) + ((a & b) ^ (a & c) ^ (b & c))
+
+                       h = g
+                       g = f
+                       f = e
+                       e = d + t1
+                       d = c
+                       c = b
+                       b = a
+                       a = t1 + t2
+               }
+
+               h0 += a
+               h1 += b
+               h2 += c
+               h3 += d
+               h4 += e
+               h5 += f
+               h6 += g
+               h7 += h
+
+               p = p[_Chunk:]
+               n += _Chunk
+       }
+
+       dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
+       return n
+}
diff --git a/libgo/go/crypto/subtle/constant_time.go b/libgo/go/crypto/subtle/constant_time.go
new file mode 100644 (file)
index 0000000..a3d70b9
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+package subtle
+
+// ConstantTimeCompare returns 1 iff the two equal length slices, x
+// and y, have equal contents. The time taken is a function of the length of
+// the slices and is independent of the contents.
+func ConstantTimeCompare(x, y []byte) int {
+       var v byte
+
+       for i := 0; i < len(x); i++ {
+               v |= x[i] ^ y[i]
+       }
+
+       return ConstantTimeByteEq(v, 0)
+}
+
+// ConstantTimeSelect returns x if v is 1 and y if v is 0.
+// Its behavior is undefined if v takes any other value.
+func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y }
+
+// ConstantTimeByteEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeByteEq(x, y uint8) int {
+       z := ^(x ^ y)
+       z &= z >> 4
+       z &= z >> 2
+       z &= z >> 1
+
+       return int(z)
+}
+
+// ConstantTimeEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeEq(x, y int32) int {
+       z := ^(x ^ y)
+       z &= z >> 16
+       z &= z >> 8
+       z &= z >> 4
+       z &= z >> 2
+       z &= z >> 1
+
+       return int(z & 1)
+}
+
+// ConstantTimeCopy copies the contents of y into x iff v == 1. If v == 0, x is left unchanged.
+// Its behavior is undefined if v takes any other value.
+func ConstantTimeCopy(v int, x, y []byte) {
+       xmask := byte(v - 1)
+       ymask := byte(^(v - 1))
+       for i := 0; i < len(x); i++ {
+               x[i] = x[i]&xmask | y[i]&ymask
+       }
+       return
+}
diff --git a/libgo/go/crypto/subtle/constant_time_test.go b/libgo/go/crypto/subtle/constant_time_test.go
new file mode 100644 (file)
index 0000000..b28b735
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package subtle
+
+import (
+       "testing"
+       "testing/quick"
+)
+
+type TestConstantTimeCompareStruct struct {
+       a, b []byte
+       out  int
+}
+
+var testConstandTimeCompareData = []TestConstantTimeCompareStruct{
+       {[]byte{}, []byte{}, 1},
+       {[]byte{0x11}, []byte{0x11}, 1},
+       {[]byte{0x12}, []byte{0x11}, 0},
+}
+
+func TestConstantTimeCompare(t *testing.T) {
+       for i, test := range testConstandTimeCompareData {
+               if r := ConstantTimeCompare(test.a, test.b); r != test.out {
+                       t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
+               }
+       }
+}
+
+type TestConstantTimeByteEqStruct struct {
+       a, b uint8
+       out  int
+}
+
+var testConstandTimeByteEqData = []TestConstantTimeByteEqStruct{
+       {0, 0, 1},
+       {0, 1, 0},
+       {1, 0, 0},
+       {0xff, 0xff, 1},
+       {0xff, 0xfe, 0},
+}
+
+func byteEq(a, b uint8) int {
+       if a == b {
+               return 1
+       }
+       return 0
+}
+
+func TestConstantTimeByteEq(t *testing.T) {
+       for i, test := range testConstandTimeByteEqData {
+               if r := ConstantTimeByteEq(test.a, test.b); r != test.out {
+                       t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
+               }
+       }
+       err := quick.CheckEqual(ConstantTimeByteEq, byteEq, nil)
+       if err != nil {
+               t.Error(err)
+       }
+}
+
+func eq(a, b int32) int {
+       if a == b {
+               return 1
+       }
+       return 0
+}
+
+func TestConstantTimeEq(t *testing.T) {
+       err := quick.CheckEqual(ConstantTimeEq, eq, nil)
+       if err != nil {
+               t.Error(err)
+       }
+}
+
+func makeCopy(v int, x, y []byte) []byte {
+       if len(x) > len(y) {
+               x = x[0:len(y)]
+       } else {
+               y = y[0:len(x)]
+       }
+       if v == 1 {
+               copy(x, y)
+       }
+       return x
+}
+
+func constantTimeCopyWrapper(v int, x, y []byte) []byte {
+       if len(x) > len(y) {
+               x = x[0:len(y)]
+       } else {
+               y = y[0:len(x)]
+       }
+       v &= 1
+       ConstantTimeCopy(v, x, y)
+       return x
+}
+
+func TestConstantTimeCopy(t *testing.T) {
+       err := quick.CheckEqual(constantTimeCopyWrapper, makeCopy, nil)
+       if err != nil {
+               t.Error(err)
+       }
+}
diff --git a/libgo/go/crypto/tls/alert.go b/libgo/go/crypto/tls/alert.go
new file mode 100644 (file)
index 0000000..3b9e0e2
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import "strconv"
+
+type alert uint8
+
+const (
+       // alert level
+       alertLevelWarning = 1
+       alertLevelError   = 2
+)
+
+const (
+       alertCloseNotify            alert = 0
+       alertUnexpectedMessage      alert = 10
+       alertBadRecordMAC           alert = 20
+       alertDecryptionFailed       alert = 21
+       alertRecordOverflow         alert = 22
+       alertDecompressionFailure   alert = 30
+       alertHandshakeFailure       alert = 40
+       alertBadCertificate         alert = 42
+       alertUnsupportedCertificate alert = 43
+       alertCertificateRevoked     alert = 44
+       alertCertificateExpired     alert = 45
+       alertCertificateUnknown     alert = 46
+       alertIllegalParameter       alert = 47
+       alertUnknownCA              alert = 48
+       alertAccessDenied           alert = 49
+       alertDecodeError            alert = 50
+       alertDecryptError           alert = 51
+       alertProtocolVersion        alert = 70
+       alertInsufficientSecurity   alert = 71
+       alertInternalError          alert = 80
+       alertUserCanceled           alert = 90
+       alertNoRenegotiation        alert = 100
+)
+
+var alertText = map[alert]string{
+       alertCloseNotify:            "close notify",
+       alertUnexpectedMessage:      "unexpected message",
+       alertBadRecordMAC:           "bad record MAC",
+       alertDecryptionFailed:       "decryption failed",
+       alertRecordOverflow:         "record overflow",
+       alertDecompressionFailure:   "decompression failure",
+       alertHandshakeFailure:       "handshake failure",
+       alertBadCertificate:         "bad certificate",
+       alertUnsupportedCertificate: "unsupported certificate",
+       alertCertificateRevoked:     "revoked certificate",
+       alertCertificateExpired:     "expired certificate",
+       alertCertificateUnknown:     "unknown certificate",
+       alertIllegalParameter:       "illegal parameter",
+       alertUnknownCA:              "unknown certificate authority",
+       alertAccessDenied:           "access denied",
+       alertDecodeError:            "error decoding message",
+       alertDecryptError:           "error decrypting message",
+       alertProtocolVersion:        "protocol version not supported",
+       alertInsufficientSecurity:   "insufficient security level",
+       alertInternalError:          "internal error",
+       alertUserCanceled:           "user canceled",
+       alertNoRenegotiation:        "no renegotiation",
+}
+
+func (e alert) String() string {
+       s, ok := alertText[e]
+       if ok {
+               return s
+       }
+       return "alert(" + strconv.Itoa(int(e)) + ")"
+}
diff --git a/libgo/go/crypto/tls/ca_set.go b/libgo/go/crypto/tls/ca_set.go
new file mode 100644 (file)
index 0000000..fe2a540
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+       "crypto/x509"
+       "encoding/pem"
+       "strings"
+)
+
+// A CASet is a set of certificates.
+type CASet struct {
+       bySubjectKeyId map[string][]*x509.Certificate
+       byName         map[string][]*x509.Certificate
+}
+
+func NewCASet() *CASet {
+       return &CASet{
+               make(map[string][]*x509.Certificate),
+               make(map[string][]*x509.Certificate),
+       }
+}
+
+func nameToKey(name *x509.Name) string {
+       return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
+}
+
+// FindVerifiedParent attempts to find the certificate in s which has signed
+// the given certificate. If no such certificate can be found or the signature
+// doesn't match, it returns nil.
+func (s *CASet) FindVerifiedParent(cert *x509.Certificate) (parent *x509.Certificate) {
+       var candidates []*x509.Certificate
+
+       if len(cert.AuthorityKeyId) > 0 {
+               candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
+       }
+       if len(candidates) == 0 {
+               candidates = s.byName[nameToKey(&cert.Issuer)]
+       }
+
+       for _, c := range candidates {
+               if cert.CheckSignatureFrom(c) == nil {
+                       return c
+               }
+       }
+
+       return nil
+}
+
+// AddCert adds a certificate to the set
+func (s *CASet) AddCert(cert *x509.Certificate) {
+       if len(cert.SubjectKeyId) > 0 {
+               keyId := string(cert.SubjectKeyId)
+               s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], cert)
+       }
+       name := nameToKey(&cert.Subject)
+       s.byName[name] = append(s.byName[name], cert)
+}
+
+// SetFromPEM attempts to parse a series of PEM encoded root certificates. It
+// appends any certificates found to s and returns true if any certificates
+// were successfully parsed. On many Linux systems, /etc/ssl/cert.pem will
+// contains the system wide set of root CAs in a format suitable for this
+// function.
+func (s *CASet) SetFromPEM(pemCerts []byte) (ok bool) {
+       for len(pemCerts) > 0 {
+               var block *pem.Block
+               block, pemCerts = pem.Decode(pemCerts)
+               if block == nil {
+                       break
+               }
+               if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
+                       continue
+               }
+
+               cert, err := x509.ParseCertificate(block.Bytes)
+               if err != nil {
+                       continue
+               }
+
+               s.AddCert(cert)
+               ok = true
+       }
+
+       return
+}
diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go
new file mode 100644 (file)
index 0000000..a4f2b80
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+       "crypto/rand"
+       "crypto/rsa"
+       "io"
+       "io/ioutil"
+       "sync"
+       "time"
+)
+
+const (
+       maxPlaintext    = 16384        // maximum plaintext payload length
+       maxCiphertext   = 16384 + 2048 // maximum ciphertext payload length
+       recordHeaderLen = 5            // record header length
+       maxHandshake    = 65536        // maximum handshake we support (protocol max is 16 MB)
+
+       minVersion = 0x0301 // minimum supported version - TLS 1.0
+       maxVersion = 0x0302 // maximum supported version - TLS 1.1
+)
+
+// TLS record types.
+type recordType uint8
+
+const (
+       recordTypeChangeCipherSpec recordType = 20
+       recordTypeAlert            recordType = 21
+       recordTypeHandshake        recordType = 22
+       recordTypeApplicationData  recordType = 23
+)
+
+// TLS handshake message types.
+const (
+       typeClientHello        uint8 = 1
+       typeServerHello        uint8 = 2
+       typeCertificate        uint8 = 11
+       typeCertificateRequest uint8 = 13
+       typeServerHelloDone    uint8 = 14
+       typeCertificateVerify  uint8 = 15
+       typeClientKeyExchange  uint8 = 16
+       typeFinished           uint8 = 20
+       typeCertificateStatus  uint8 = 22
+       typeNextProtocol       uint8 = 67 // Not IANA assigned
+)
+
+// TLS cipher suites.
+const (
+       TLS_RSA_WITH_RC4_128_SHA uint16 = 5
+)
+
+// TLS compression types.
+const (
+       compressionNone uint8 = 0
+)
+
+// TLS extension numbers
+var (
+       extensionServerName    uint16 = 0
+       extensionStatusRequest uint16 = 5
+       extensionNextProtoNeg  uint16 = 13172 // not IANA assigned
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+       statusTypeOCSP uint8 = 1
+)
+
+// Certificate types (for certificateRequestMsg)
+const (
+       certTypeRSASign    = 1 // A certificate containing an RSA key
+       certTypeDSSSign    = 2 // A certificate containing a DSA key
+       certTypeRSAFixedDH = 3 // A certificate containing a static DH key
+       certTypeDSSFixedDH = 4 // A certficiate containing a static DH key
+       // Rest of these are reserved by the TLS spec
+)
+
+type ConnectionState struct {
+       HandshakeComplete  bool
+       CipherSuite        uint16
+       NegotiatedProtocol string
+}
+
+// A Config structure is used to configure a TLS client or server. After one
+// has been passed to a TLS function it must not be modified.
+type Config struct {
+       // Rand provides the source of entropy for nonces and RSA blinding.
+       Rand io.Reader
+       // Time returns the current time as the number of seconds since the epoch.
+       Time func() int64
+       // Certificates contains one or more certificate chains.
+       Certificates []Certificate
+       RootCAs      *CASet
+       // NextProtos is a list of supported, application level protocols.
+       // Currently only server-side handling is supported.
+       NextProtos []string
+       // ServerName is included in the client's handshake to support virtual
+       // hosting.
+       ServerName string
+       // AuthenticateClient determines if a server will request a certificate
+       // from the client. It does not require that the client send a
+       // certificate nor, if it does, that the certificate is anything more
+       // than self-signed.
+       AuthenticateClient bool
+}
+
+type Certificate struct {
+       // Certificate contains a chain of one or more certificates. Leaf
+       // certificate first.
+       Certificate [][]byte
+       PrivateKey  *rsa.PrivateKey
+}
+
+// A TLS record.
+type record struct {
+       contentType  recordType
+       major, minor uint8
+       payload      []byte
+}
+
+type handshakeMessage interface {
+       marshal() []byte
+       unmarshal([]byte) bool
+}
+
+type encryptor interface {
+       // XORKeyStream xors the contents of the slice with bytes from the key stream.
+       XORKeyStream(buf []byte)
+}
+
+// mutualVersion returns the protocol version to use given the advertised
+// version of the peer.
+func mutualVersion(vers uint16) (uint16, bool) {
+       if vers < minVersion {
+               return 0, false
+       }
+       if vers > maxVersion {
+               vers = maxVersion
+       }
+       return vers, true
+}
+
+// The defaultConfig is used in place of a nil *Config in the TLS server and client.
+var varDefaultConfig *Config
+
+var once sync.Once
+
+func defaultConfig() *Config {
+       once.Do(initDefaultConfig)
+       return varDefaultConfig
+}
+
+// Possible certificate files; stop after finding one.
+// On OS X we should really be using the Directory Services keychain
+// but that requires a lot of Mach goo to get at.  Instead we use
+// the same root set that curl uses.
+var certFiles = []string{
+       "/etc/ssl/certs/ca-certificates.crt", // Linux etc
+       "/usr/share/curl/curl-ca-bundle.crt", // OS X
+}
+
+func initDefaultConfig() {
+       roots := NewCASet()
+       for _, file := range certFiles {
+               data, err := ioutil.ReadFile(file)
+               if err == nil {
+                       roots.SetFromPEM(data)
+                       break
+               }
+       }
+
+       varDefaultConfig = &Config{
+               Rand:    rand.Reader,
+               Time:    time.Seconds,
+               RootCAs: roots,
+       }
+}
diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go
new file mode 100644 (file)
index 0000000..b18cda7
--- /dev/null
@@ -0,0 +1,690 @@
+// TLS low level connection and record layer
+
+package tls
+
+import (
+       "bytes"
+       "crypto/subtle"
+       "crypto/x509"
+       "hash"
+       "io"
+       "net"
+       "os"
+       "sync"
+)
+
+// A Conn represents a secured connection.
+// It implements the net.Conn interface.
+type Conn struct {
+       // constant
+       conn     net.Conn
+       isClient bool
+
+       // constant after handshake; protected by handshakeMutex
+       handshakeMutex    sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+       vers              uint16     // TLS version
+       haveVers          bool       // version has been negotiated
+       config            *Config    // configuration passed to constructor
+       handshakeComplete bool
+       cipherSuite       uint16
+       ocspResponse      []byte // stapled OCSP response
+       peerCertificates  []*x509.Certificate
+
+       clientProtocol string
+
+       // first permanent error
+       errMutex sync.Mutex
+       err      os.Error
+
+       // input/output
+       in, out  halfConn     // in.Mutex < out.Mutex
+       rawInput *block       // raw input, right off the wire
+       input    *block       // application data waiting to be read
+       hand     bytes.Buffer // handshake data waiting to be read
+
+       tmp [16]byte
+}
+
+func (c *Conn) setError(err os.Error) os.Error {
+       c.errMutex.Lock()
+       defer c.errMutex.Unlock()
+
+       if c.err == nil {
+               c.err = err
+       }
+       return err
+}
+
+func (c *Conn) error() os.Error {
+       c.errMutex.Lock()
+       defer c.errMutex.Unlock()
+
+       return c.err
+}
+
+// Access to net.Conn methods.
+// Cannot just embed net.Conn because that would
+// export the struct field too.
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+       return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+       return c.conn.RemoteAddr()
+}
+
+// SetTimeout sets the read deadline associated with the connection.
+// There is no write deadline.
+func (c *Conn) SetTimeout(nsec int64) os.Error {
+       return c.conn.SetTimeout(nsec)
+}
+
+// SetReadTimeout sets the time (in nanoseconds) that
+// Read will wait for data before returning os.EAGAIN.
+// Setting nsec == 0 (the default) disables the deadline.
+func (c *Conn) SetReadTimeout(nsec int64) os.Error {
+       return c.conn.SetReadTimeout(nsec)
+}
+
+// SetWriteTimeout exists to satisfy the net.Conn interface
+// but is not implemented by TLS.  It always returns an error.
+func (c *Conn) SetWriteTimeout(nsec int64) os.Error {
+       return os.NewError("TLS does not support SetWriteTimeout")
+}
+
+// A halfConn represents one direction of the record layer
+// connection, either sending or receiving.
+type halfConn struct {
+       sync.Mutex
+       crypt encryptor // encryption state
+       mac   hash.Hash // MAC algorithm
+       seq   [8]byte   // 64-bit sequence number
+       bfree *block    // list of free blocks
+
+       nextCrypt encryptor // next encryption state
+       nextMac   hash.Hash // next MAC algorithm
+}
+
+// prepareCipherSpec sets the encryption and MAC states
+// that a subsequent changeCipherSpec will use.
+func (hc *halfConn) prepareCipherSpec(crypt encryptor, mac hash.Hash) {
+       hc.nextCrypt = crypt
+       hc.nextMac = mac
+}
+
+// changeCipherSpec changes the encryption and MAC states
+// to the ones previously passed to prepareCipherSpec.
+func (hc *halfConn) changeCipherSpec() os.Error {
+       if hc.nextCrypt == nil {
+               return alertInternalError
+       }
+       hc.crypt = hc.nextCrypt
+       hc.mac = hc.nextMac
+       hc.nextCrypt = nil
+       hc.nextMac = nil
+       return nil
+}
+
+// incSeq increments the sequence number.
+func (hc *halfConn) incSeq() {
+       for i := 7; i >= 0; i-- {
+               hc.seq[i]++
+               if hc.seq[i] != 0 {
+                       return
+               }
+       }
+
+       // Not allowed to let sequence number wrap.
+       // Instead, must renegotiate before it does.
+       // Not likely enough to bother.
+       panic("TLS: sequence number wraparound")
+}
+
+// resetSeq resets the sequence number to zero.
+func (hc *halfConn) resetSeq() {
+       for i := range hc.seq {
+               hc.seq[i] = 0
+       }
+}
+
+// decrypt checks and strips the mac and decrypts the data in b.
+func (hc *halfConn) decrypt(b *block) (bool, alert) {
+       // pull out payload
+       payload := b.data[recordHeaderLen:]
+
+       // decrypt
+       if hc.crypt != nil {
+               hc.crypt.XORKeyStream(payload)
+       }
+
+       // check, strip mac
+       if hc.mac != nil {
+               if len(payload) < hc.mac.Size() {
+                       return false, alertBadRecordMAC
+               }
+
+               // strip mac off payload, b.data
+               n := len(payload) - hc.mac.Size()
+               b.data[3] = byte(n >> 8)
+               b.data[4] = byte(n)
+               b.data = b.data[0 : recordHeaderLen+n]
+               remoteMAC := payload[n:]
+
+               hc.mac.Reset()
+               hc.mac.Write(hc.seq[0:])
+               hc.incSeq()
+               hc.mac.Write(b.data)
+
+               if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 {
+                       return false, alertBadRecordMAC
+               }
+       }
+
+       return true, 0
+}
+
+// encrypt encrypts and macs the data in b.
+func (hc *halfConn) encrypt(b *block) (bool, alert) {
+       // mac
+       if hc.mac != nil {
+               hc.mac.Reset()
+               hc.mac.Write(hc.seq[0:])
+               hc.incSeq()
+               hc.mac.Write(b.data)
+               mac := hc.mac.Sum()
+               n := len(b.data)
+               b.resize(n + len(mac))
+               copy(b.data[n:], mac)
+
+               // update length to include mac
+               n = len(b.data) - recordHeaderLen
+               b.data[3] = byte(n >> 8)
+               b.data[4] = byte(n)
+       }
+
+       // encrypt
+       if hc.crypt != nil {
+               hc.crypt.XORKeyStream(b.data[recordHeaderLen:])
+       }
+
+       return true, 0
+}
+
+// A block is a simple data buffer.
+type block struct {
+       data []byte
+       off  int // index for Read
+       link *block
+}
+
+// resize resizes block to be n bytes, growing if necessary.
+func (b *block) resize(n int) {
+       if n > cap(b.data) {
+               b.reserve(n)
+       }
+       b.data = b.data[0:n]
+}
+
+// reserve makes sure that block contains a capacity of at least n bytes.
+func (b *block) reserve(n int) {
+       if cap(b.data) >= n {
+               return
+       }
+       m := cap(b.data)
+       if m == 0 {
+               m = 1024
+       }
+       for m < n {
+               m *= 2
+       }
+       data := make([]byte, len(b.data), m)
+       copy(data, b.data)
+       b.data = data
+}
+
+// readFromUntil reads from r into b until b contains at least n bytes
+// or else returns an error.
+func (b *block) readFromUntil(r io.Reader, n int) os.Error {
+       // quick case
+       if len(b.data) >= n {
+               return nil
+       }
+
+       // read until have enough.
+       b.reserve(n)
+       for {
+               m, err := r.Read(b.data[len(b.data):cap(b.data)])
+               b.data = b.data[0 : len(b.data)+m]
+               if len(b.data) >= n {
+                       break
+               }
+               if err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+func (b *block) Read(p []byte) (n int, err os.Error) {
+       n = copy(p, b.data[b.off:])
+       b.off += n
+       return
+}
+
+// newBlock allocates a new block, from hc's free list if possible.
+func (hc *halfConn) newBlock() *block {
+       b := hc.bfree
+       if b == nil {
+               return new(block)
+       }
+       hc.bfree = b.link
+       b.link = nil
+       b.resize(0)
+       return b
+}
+
+// freeBlock returns a block to hc's free list.
+// The protocol is such that each side only has a block or two on
+// its free list at a time, so there's no need to worry about
+// trimming the list, etc.
+func (hc *halfConn) freeBlock(b *block) {
+       b.link = hc.bfree
+       hc.bfree = b
+}
+
+// splitBlock splits a block after the first n bytes,
+// returning a block with those n bytes and a
+// block with the remaindec.  the latter may be nil.
+func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
+       if len(b.data) <= n {
+               return b, nil
+       }
+       bb := hc.newBlock()
+       bb.resize(len(b.data) - n)
+       copy(bb.data, b.data[n:])
+       b.data = b.data[0:n]
+       return b, bb
+}
+
+// readRecord reads the next TLS record from the connection
+// and updates the record layer state.
+// c.in.Mutex <= L; c.input == nil.
+func (c *Conn) readRecord(want recordType) os.Error {
+       // Caller must be in sync with connection:
+       // handshake data if handshake not yet completed,
+       // else application data.  (We don't support renegotiation.)
+       switch want {
+       default:
+               return c.sendAlert(alertInternalError)
+       case recordTypeHandshake, recordTypeChangeCipherSpec:
+               if c.handshakeComplete {
+                       return c.sendAlert(alertInternalError)
+               }
+       case recordTypeApplicationData:
+               if !c.handshakeComplete {
+                       return c.sendAlert(alertInternalError)
+               }
+       }
+
+Again:
+       if c.rawInput == nil {
+               c.rawInput = c.in.newBlock()
+       }
+       b := c.rawInput
+
+       // Read header, payload.
+       if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil {
+               // RFC suggests that EOF without an alertCloseNotify is
+               // an error, but popular web sites seem to do this,
+               // so we can't make it an error.
+               // if err == os.EOF {
+               //      err = io.ErrUnexpectedEOF
+               // }
+               if e, ok := err.(net.Error); !ok || !e.Temporary() {
+                       c.setError(err)
+               }
+               return err
+       }
+       typ := recordType(b.data[0])
+       vers := uint16(b.data[1])<<8 | uint16(b.data[2])
+       n := int(b.data[3])<<8 | int(b.data[4])
+       if c.haveVers && vers != c.vers {
+               return c.sendAlert(alertProtocolVersion)
+       }
+       if n > maxCiphertext {
+               return c.sendAlert(alertRecordOverflow)
+       }
+       if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
+               if err == os.EOF {
+                       err = io.ErrUnexpectedEOF
+               }
+               if e, ok := err.(net.Error); !ok || !e.Temporary() {
+                       c.setError(err)
+               }
+               return err
+       }
+
+       // Process message.
+       b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
+       b.off = recordHeaderLen
+       if ok, err := c.in.decrypt(b); !ok {
+               return c.sendAlert(err)
+       }
+       data := b.data[b.off:]
+       if len(data) > maxPlaintext {
+               c.sendAlert(alertRecordOverflow)
+               c.in.freeBlock(b)
+               return c.error()
+       }
+
+       switch typ {
+       default:
+               c.sendAlert(alertUnexpectedMessage)
+
+       case recordTypeAlert:
+               if len(data) != 2 {
+                       c.sendAlert(alertUnexpectedMessage)
+                       break
+               }
+               if alert(data[1]) == alertCloseNotify {
+                       c.setError(os.EOF)
+                       break
+               }
+               switch data[0] {
+               case alertLevelWarning:
+                       // drop on the floor
+                       c.in.freeBlock(b)
+                       goto Again
+               case alertLevelError:
+                       c.setError(&net.OpError{Op: "remote error", Error: alert(data[1])})
+               default:
+                       c.sendAlert(alertUnexpectedMessage)
+               }
+
+       case recordTypeChangeCipherSpec:
+               if typ != want || len(data) != 1 || data[0] != 1 {
+                       c.sendAlert(alertUnexpectedMessage)
+                       break
+               }
+               err := c.in.changeCipherSpec()
+               if err != nil {
+                       c.sendAlert(err.(alert))
+               }
+
+       case recordTypeApplicationData:
+               if typ != want {
+                       c.sendAlert(alertUnexpectedMessage)
+                       break
+               }
+               c.input = b
+               b = nil
+
+       case recordTypeHandshake:
+               // TODO(rsc): Should at least pick off connection close.
+               if typ != want {
+                       return c.sendAlert(alertNoRenegotiation)
+               }
+               c.hand.Write(data)
+       }
+
+       if b != nil {
+               c.in.freeBlock(b)
+       }
+       return c.error()
+}
+
+// sendAlert sends a TLS alert message.
+// c.out.Mutex <= L.
+func (c *Conn) sendAlertLocked(err alert) os.Error {
+       c.tmp[0] = alertLevelError
+       if err == alertNoRenegotiation {
+               c.tmp[0] = alertLevelWarning
+       }
+       c.tmp[1] = byte(err)
+       c.writeRecord(recordTypeAlert, c.tmp[0:2])
+       // closeNotify is a special case in that it isn't an error:
+       if err != alertCloseNotify {
+               return c.setError(&net.OpError{Op: "local error", Error: err})
+       }
+       return nil
+}
+
+// sendAlert sends a TLS alert message.
+// L < c.out.Mutex.
+func (c *Conn) sendAlert(err alert) os.Error {
+       c.out.Lock()
+       defer c.out.Unlock()
+       return c.sendAlertLocked(err)
+}
+
+// writeRecord writes a TLS record with the given type and payload
+// to the connection and updates the record layer state.
+// c.out.Mutex <= L.
+func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err os.Error) {
+       b := c.out.newBlock()
+       for len(data) > 0 {
+               m := len(data)
+               if m > maxPlaintext {
+                       m = maxPlaintext
+               }
+               b.resize(recordHeaderLen + m)
+               b.data[0] = byte(typ)
+               vers := c.vers
+               if vers == 0 {
+                       vers = maxVersion
+               }
+               b.data[1] = byte(vers >> 8)
+               b.data[2] = byte(vers)
+               b.data[3] = byte(m >> 8)
+               b.data[4] = byte(m)
+               copy(b.data[recordHeaderLen:], data)
+               c.out.encrypt(b)
+               _, err = c.conn.Write(b.data)
+               if err != nil {
+                       break
+               }
+               n += m
+               data = data[m:]
+       }
+       c.out.freeBlock(b)
+
+       if typ == recordTypeChangeCipherSpec {
+               err = c.out.changeCipherSpec()
+               if err != nil {
+                       // Cannot call sendAlert directly,
+                       // because we already hold c.out.Mutex.
+                       c.tmp[0] = alertLevelError
+                       c.tmp[1] = byte(err.(alert))
+                       c.writeRecord(recordTypeAlert, c.tmp[0:2])
+                       c.err = &net.OpError{Op: "local error", Error: err}
+                       return n, c.err
+               }
+       }
+       return
+}
+
+// readHandshake reads the next handshake message from
+// the record layer.
+// c.in.Mutex < L; c.out.Mutex < L.
+func (c *Conn) readHandshake() (interface{}, os.Error) {
+       for c.hand.Len() < 4 {
+               if c.err != nil {
+                       return nil, c.err
+               }
+               c.readRecord(recordTypeHandshake)
+       }
+
+       data := c.hand.Bytes()
+       n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+       if n > maxHandshake {
+               c.sendAlert(alertInternalError)
+               return nil, c.err
+       }
+       for c.hand.Len() < 4+n {
+               if c.err != nil {
+                       return nil, c.err
+               }
+               c.readRecord(recordTypeHandshake)
+       }
+       data = c.hand.Next(4 + n)
+       var m handshakeMessage
+       switch data[0] {
+       case typeClientHello:
+               m = new(clientHelloMsg)
+       case typeServerHello:
+               m = new(serverHelloMsg)
+       case typeCertificate:
+               m = new(certificateMsg)
+       case typeCertificateRequest:
+               m = new(certificateRequestMsg)
+       case typeCertificateStatus:
+               m = new(certificateStatusMsg)
+       case typeServerHelloDone:
+               m = new(serverHelloDoneMsg)
+       case typeClientKeyExchange:
+               m = new(clientKeyExchangeMsg)
+       case typeCertificateVerify:
+               m = new(certificateVerifyMsg)
+       case typeNextProtocol:
+               m = new(nextProtoMsg)
+       case typeFinished:
+               m = new(finishedMsg)
+       default:
+               c.sendAlert(alertUnexpectedMessage)
+               return nil, alertUnexpectedMessage
+       }
+
+       // The handshake message unmarshallers
+       // expect to be able to keep references to data,
+       // so pass in a fresh copy that won't be overwritten.
+       data = bytes.Add(nil, data)
+
+       if !m.unmarshal(data) {
+               c.sendAlert(alertUnexpectedMessage)
+               return nil, alertUnexpectedMessage
+       }
+       return m, nil
+}
+
+// Write writes data to the connection.
+func (c *Conn) Write(b []byte) (n int, err os.Error) {
+       if err = c.Handshake(); err != nil {
+               return
+       }
+
+       c.out.Lock()
+       defer c.out.Unlock()
+
+       if !c.handshakeComplete {
+               return 0, alertInternalError
+       }
+       if c.err != nil {
+               return 0, c.err
+       }
+       return c.writeRecord(recordTypeApplicationData, b)
+}
+
+// Read can be made to time out and return err == os.EAGAIN
+// after a fixed time limit; see SetTimeout and SetReadTimeout.
+func (c *Conn) Read(b []byte) (n int, err os.Error) {
+       if err = c.Handshake(); err != nil {
+               return
+       }
+
+       c.in.Lock()
+       defer c.in.Unlock()
+
+       for c.input == nil && c.err == nil {
+               if err := c.readRecord(recordTypeApplicationData); err != nil {
+                       // Soft error, like EAGAIN
+                       return 0, err
+               }
+       }
+       if c.err != nil {
+               return 0, c.err
+       }
+       n, err = c.input.Read(b)
+       if c.input.off >= len(c.input.data) {
+               c.in.freeBlock(c.input)
+               c.input = nil
+       }
+       return n, nil
+}
+
+// Close closes the connection.
+func (c *Conn) Close() os.Error {
+       if err := c.Handshake(); err != nil {
+               return err
+       }
+       return c.sendAlert(alertCloseNotify)
+}
+
+// Handshake runs the client or server handshake
+// protocol if it has not yet been run.
+// Most uses of this package need not call Handshake
+// explicitly: the first Read or Write will call it automatically.
+func (c *Conn) Handshake() os.Error {
+       c.handshakeMutex.Lock()
+       defer c.handshakeMutex.Unlock()
+       if err := c.error(); err != nil {
+               return err
+       }
+       if c.handshakeComplete {
+               return nil
+       }
+       if c.isClient {
+               return c.clientHandshake()
+       }
+       return c.serverHandshake()
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+       c.handshakeMutex.Lock()
+       defer c.handshakeMutex.Unlock()
+
+       var state ConnectionState
+       state.HandshakeComplete = c.handshakeComplete
+       if c.handshakeComplete {
+               state.NegotiatedProtocol = c.clientProtocol
+               state.CipherSuite = c.cipherSuite
+       }
+
+       return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
+       c.handshakeMutex.Lock()
+       defer c.handshakeMutex.Unlock()
+
+       return c.ocspResponse
+}
+
+// PeerCertificates returns the certificate chain that was presented by the
+// other side.
+func (c *Conn) PeerCertificates() []*x509.Certificate {
+       c.handshakeMutex.Lock()
+       defer c.handshakeMutex.Unlock()
+
+       return c.peerCertificates
+}
+
+// VerifyHostname checks that the peer certificate chain is valid for
+// connecting to host.  If so, it returns nil; if not, it returns an os.Error
+// describing the problem.
+func (c *Conn) VerifyHostname(host string) os.Error {
+       c.handshakeMutex.Lock()
+       defer c.handshakeMutex.Unlock()
+       if !c.isClient {
+               return os.ErrorString("VerifyHostname called on TLS server connection")
+       }
+       if !c.handshakeComplete {
+               return os.ErrorString("TLS handshake has not yet been performed")
+       }
+       return c.peerCertificates[0].VerifyHostname(host)
+}
diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go
new file mode 100644 (file)
index 0000000..bdc70f1
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate a self-signed X.509 certificate for a TLS server. Outputs to
+// 'cert.pem' and 'key.pem' and will overwrite existing files.
+
+package main
+
+import (
+       "crypto/rsa"
+       "crypto/x509"
+       "encoding/pem"
+       "flag"
+       "log"
+       "os"
+       "time"
+)
+
+var hostName *string = flag.String("host", "127.0.0.1", "Hostname to generate a certificate for")
+
+func main() {
+       flag.Parse()
+
+       urandom, err := os.Open("/dev/urandom", os.O_RDONLY, 0)
+       if err != nil {
+               log.Exitf("failed to open /dev/urandom: %s", err)
+               return
+       }
+
+       priv, err := rsa.GenerateKey(urandom, 1024)
+       if err != nil {
+               log.Exitf("failed to generate private key: %s", err)
+               return
+       }
+
+       now := time.Seconds()
+
+       template := x509.Certificate{
+               SerialNumber: []byte{0},
+               Subject: x509.Name{
+                       CommonName:   *hostName,
+                       Organization: "Acme Co",
+               },
+               NotBefore: time.SecondsToUTC(now - 300),
+               NotAfter:  time.SecondsToUTC(now + 60*60*24*365), // valid for 1 year.
+
+               SubjectKeyId: []byte{1, 2, 3, 4},
+               KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+       }
+
+       derBytes, err := x509.CreateCertificate(urandom, &template, &template, &priv.PublicKey, priv)
+       if err != nil {
+               log.Exitf("Failed to create certificate: %s", err)
+               return
+       }
+
+       certOut, err := os.Open("cert.pem", os.O_WRONLY|os.O_CREAT, 0644)
+       if err != nil {
+               log.Exitf("failed to open cert.pem for writing: %s", err)
+               return
+       }
+       pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+       certOut.Close()
+       log.Print("written cert.pem\n")
+
+       keyOut, err := os.Open("key.pem", os.O_WRONLY|os.O_CREAT, 0600)
+       if err != nil {
+               log.Print("failed to open key.pem for writing:", err)
+               return
+       }
+       pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
+       keyOut.Close()
+       log.Print("written key.pem\n")
+}
diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go
new file mode 100644 (file)
index 0000000..b6b0e0f
--- /dev/null
@@ -0,0 +1,287 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+       "crypto/hmac"
+       "crypto/rc4"
+       "crypto/rsa"
+       "crypto/subtle"
+       "crypto/x509"
+       "io"
+       "os"
+)
+
+func (c *Conn) clientHandshake() os.Error {
+       finishedHash := newFinishedHash()
+
+       if c.config == nil {
+               c.config = defaultConfig()
+       }
+
+       hello := &clientHelloMsg{
+               vers:               maxVersion,
+               cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+               compressionMethods: []uint8{compressionNone},
+               random:             make([]byte, 32),
+               ocspStapling:       true,
+               serverName:         c.config.ServerName,
+       }
+
+       t := uint32(c.config.Time())
+       hello.random[0] = byte(t >> 24)
+       hello.random[1] = byte(t >> 16)
+       hello.random[2] = byte(t >> 8)
+       hello.random[3] = byte(t)
+       _, err := io.ReadFull(c.config.Rand, hello.random[4:])
+       if err != nil {
+               c.sendAlert(alertInternalError)
+               return os.ErrorString("short read from Rand")
+       }
+
+       finishedHash.Write(hello.marshal())
+       c.writeRecord(recordTypeHandshake, hello.marshal())
+
+       msg, err := c.readHandshake()
+       if err != nil {
+               return err
+       }
+       serverHello, ok := msg.(*serverHelloMsg)
+       if !ok {
+               return c.sendAlert(alertUnexpectedMessage)
+       }
+       finishedHash.Write(serverHello.marshal())
+
+       vers, ok := mutualVersion(serverHello.vers)
+       if !ok {
+               c.sendAlert(alertProtocolVersion)
+       }
+       c.vers = vers
+       c.haveVers = true
+
+       if serverHello.cipherSuite != TLS_RSA_WITH_RC4_128_SHA ||
+               serverHello.compressionMethod != compressionNone {
+               return c.sendAlert(alertUnexpectedMessage)
+       }
+
+       msg, err = c.readHandshake()
+       if err != nil {
+               return err
+       }
+       certMsg, ok := msg.(*certificateMsg)
+       if !ok || len(certMsg.certificates) == 0 {
+               return c.sendAlert(alertUnexpectedMessage)
+       }
+       finishedHash.Write(certMsg.marshal())
+
+       certs := make([]*x509.Certificate, len(certMsg.certificates))
+       chain := NewCASet()
+       for i, asn1Data := range certMsg.certificates {
+               cert, err := x509.ParseCertificate(asn1Data)
+               if err != nil {
+                       c.sendAlert(alertBadCertificate)
+                       return os.ErrorString("failed to parse certificate from server: " + err.String())
+               }
+               certs[i] = cert
+               chain.AddCert(cert)
+       }
+
+       // If we don't have a root CA set configured then anything is accepted.
+       // TODO(rsc): Find certificates for OS X 10.6.
+       for cur := certs[0]; c.config.RootCAs != nil; {
+               parent := c.config.RootCAs.FindVerifiedParent(cur)
+               if parent != nil {
+                       break
+               }
+
+               parent = chain.FindVerifiedParent(cur)
+               if parent == nil {
+                       c.sendAlert(alertBadCertificate)
+                       return os.ErrorString("could not find root certificate for chain")
+               }
+
+               if !parent.BasicConstraintsValid || !parent.IsCA {
+                       c.sendAlert(alertBadCertificate)
+                       return os.ErrorString("intermediate certificate does not have CA bit set")
+               }
+               // KeyUsage status flags are ignored. From Engineering
+               // Security, Peter Gutmann: A European government CA marked its
+               // signing certificates as being valid for encryption only, but
+               // no-one noticed. Another European CA marked its signature
+               // keys as not being valid for signatures. A different CA
+               // marked its own trusted root certificate as being invalid for
+               // certificate signing.  Another national CA distributed a
+               // certificate to be used to encrypt data for the country’s tax
+               // authority that was marked as only being usable for digital
+               // signatures but not for encryption. Yet another CA reversed
+               // the order of the bit flags in the keyUsage due to confusion
+               // over encoding endianness, essentially setting a random
+               // keyUsage in certificates that it issued. Another CA created
+               // a self-invalidating certificate by adding a certificate
+               // policy statement stipulating that the certificate had to be
+               // used strictly as specified in the keyUsage, and a keyUsage
+               // containing a flag indicating that the RSA encryption key
+               // could only be used for Diffie-Hellman key agreement.
+
+               cur = parent
+       }
+
+       pub, ok := certs[0].PublicKey.(*rsa.PublicKey)
+       if !ok {
+               return c.sendAlert(alertUnsupportedCertificate)
+       }
+
+       c.peerCertificates = certs
+
+       if serverHello.certStatus {
+               msg, err = c.readHandshake()
+               if err != nil {
+                       return err
+               }
+               cs, ok := msg.(*certificateStatusMsg)
+               if !ok {
+                       return c.sendAlert(alertUnexpectedMessage)
+               }
+               finishedHash.Write(cs.marshal())
+
+               if cs.statusType == statusTypeOCSP {
+                       c.ocspResponse = cs.response
+               }
+       }
+
+       msg, err = c.readHandshake()
+       if err != nil {
+               return err
+       }
+
+       transmitCert := false
+       certReq, ok := msg.(*certificateRequestMsg)
+       if ok {
+               // We only accept certificates with RSA keys.
+               rsaAvail := false
+               for _, certType := range certReq.certificateTypes {
+                       if certType == certTypeRSASign {
+                               rsaAvail = true
+                               break
+                       }
+               }
+
+               // For now, only send a certificate back if the server gives us an
+               // empty list of certificateAuthorities.
+               //
+               // RFC 4346 on the certificateAuthorities field:
+               // A list of the distinguished names of acceptable certificate
+               // authorities.  These distinguished names may specify a desired
+               // distinguished name for a root CA or for a subordinate CA; thus,
+               // this message can be used to describe both known roots and a
+               // desired authorization space.  If the certificate_authorities
+               // list is empty then the client MAY send any certificate of the
+               // appropriate ClientCertificateType, unless there is some
+               // external arrangement to the contrary.
+               if rsaAvail && len(certReq.certificateAuthorities) == 0 {
+                       transmitCert = true
+               }
+
+               finishedHash.Write(certReq.marshal())
+
+               msg, err = c.readHandshake()
+               if err != nil {
+                       return err
+               }
+       }
+
+       shd, ok := msg.(*serverHelloDoneMsg)
+       if !ok {
+               return c.sendAlert(alertUnexpectedMessage)
+       }
+       finishedHash.Write(shd.marshal())
+
+       var cert *x509.Certificate
+       if transmitCert {
+               certMsg = new(certificateMsg)
+               if len(c.config.Certificates) > 0 {
+                       cert, err = x509.ParseCertificate(c.config.Certificates[0].Certificate[0])
+                       if err == nil && cert.PublicKeyAlgorithm == x509.RSA {
+                               certMsg.certificates = c.config.Certificates[0].Certificate
+                       } else {
+                               cert = nil
+                       }
+               }
+               finishedHash.Write(certMsg.marshal())
+               c.writeRecord(recordTypeHandshake, certMsg.marshal())
+       }
+
+       ckx := new(clientKeyExchangeMsg)
+       preMasterSecret := make([]byte, 48)
+       preMasterSecret[0] = byte(hello.vers >> 8)
+       preMasterSecret[1] = byte(hello.vers)
+       _, err = io.ReadFull(c.config.Rand, preMasterSecret[2:])
+       if err != nil {
+               return c.sendAlert(alertInternalError)
+       }
+
+       ckx.ciphertext, err = rsa.EncryptPKCS1v15(c.config.Rand, pub, preMasterSecret)
+       if err != nil {
+               return c.sendAlert(alertInternalError)
+       }
+
+       finishedHash.Write(ckx.marshal())
+       c.writeRecord(recordTypeHandshake, ckx.marshal())
+
+       if cert != nil {
+               certVerify := new(certificateVerifyMsg)
+               var digest [36]byte
+               copy(digest[0:16], finishedHash.serverMD5.Sum())
+               copy(digest[16:36], finishedHash.serverSHA1.Sum())
+               signed, err := rsa.SignPKCS1v15(c.config.Rand, c.config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, digest[0:])
+               if err != nil {
+                       return c.sendAlert(alertInternalError)
+               }
+               certVerify.signature = signed
+
+               finishedHash.Write(certVerify.marshal())
+               c.writeRecord(recordTypeHandshake, certVerify.marshal())
+       }
+
+       suite := cipherSuites[0]
+       masterSecret, clientMAC, serverMAC, clientKey, serverKey :=
+               keysFromPreMasterSecret11(preMasterSecret, hello.random, serverHello.random, suite.hashLength, suite.cipherKeyLength)
+
+       cipher, _ := rc4.NewCipher(clientKey)
+
+       c.out.prepareCipherSpec(cipher, hmac.NewSHA1(clientMAC))
+       c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+
+       finished := new(finishedMsg)
+       finished.verifyData = finishedHash.clientSum(masterSecret)
+       finishedHash.Write(finished.marshal())
+       c.writeRecord(recordTypeHandshake, finished.marshal())
+
+       cipher2, _ := rc4.NewCipher(serverKey)
+       c.in.prepareCipherSpec(cipher2, hmac.NewSHA1(serverMAC))
+       c.readRecord(recordTypeChangeCipherSpec)
+       if c.err != nil {
+               return c.err
+       }
+
+       msg, err = c.readHandshake()
+       if err != nil {
+               return err
+       }
+       serverFinished, ok := msg.(*finishedMsg)
+       if !ok {
+               return c.sendAlert(alertUnexpectedMessage)
+       }
+
+       verify := finishedHash.serverSum(masterSecret)
+       if len(verify) != len(serverFinished.verifyData) ||
+               subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+               return c.sendAlert(alertHandshakeFailure)
+       }
+
+       c.handshakeComplete = true
+       c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA
+       return nil
+}
diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go
new file mode 100644 (file)
index 0000000..91771ce
--- /dev/null
@@ -0,0 +1,807 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+type clientHelloMsg struct {
+       raw                []byte
+       vers               uint16
+       random             []byte
+       sessionId          []byte
+       cipherSuites       []uint16
+       compressionMethods []uint8
+       nextProtoNeg       bool
+       serverName         string
+       ocspStapling       bool
+}
+
+func (m *clientHelloMsg) marshal() []byte {
+       if m.raw != nil {
+               return m.raw
+       }
+
+       length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
+       numExtensions := 0
+       extensionsLength := 0
+       if m.nextProtoNeg {
+               numExtensions++
+       }
+       if m.ocspStapling {
+               extensionsLength += 1 + 2 + 2
+               numExtensions++
+       }
+       if len(m.serverName) > 0 {
+               extensionsLength += 5 + len(m.serverName)
+               numExtensions++
+       }
+       if numExtensions > 0 {
+               extensionsLength += 4 * numExtensions
+               length += 2 + extensionsLength
+       }
+
+       x := make([]byte, 4+length)
+       x[0] = typeClientHello
+       x[1] = uint8(length >> 16)
+       x[2] = uint8(length >> 8)
+       x[3] = uint8(length)
+       x[4] = uint8(m.vers >> 8)
+       x[5] = uint8(m.vers)
+       copy(x[6:38], m.random)
+       x[38] = uint8(len(m.sessionId))
+       copy(x[39:39+len(m.sessionId)], m.sessionId)
+       y := x[39+len(m.sessionId):]
+       y[0] = uint8(len(m.cipherSuites) >> 7)
+       y[1] = uint8(len(m.cipherSuites) << 1)
+       for i, suite := range m.cipherSuites {
+               y[2+i*2] = uint8(suite >> 8)
+               y[3+i*2] = uint8(suite)
+       }
+       z := y[2+len(m.cipherSuites)*2:]
+       z[0] = uint8(len(m.compressionMethods))
+       copy(z[1:], m.compressionMethods)
+
+       z = z[1+len(m.compressionMethods):]
+       if numExtensions > 0 {
+               z[0] = byte(extensionsLength >> 8)
+               z[1] = byte(extensionsLength)
+               z = z[2:]
+       }
+       if m.nextProtoNeg {
+               z[0] = byte(extensionNextProtoNeg >> 8)
+               z[1] = byte(extensionNextProtoNeg)
+               // The length is always 0
+               z = z[4:]
+       }
+       if len(m.serverName) > 0 {
+               z[0] = byte(extensionServerName >> 8)
+               z[1] = byte(extensionServerName)
+               l := len(m.serverName) + 5
+               z[2] = byte(l >> 8)
+               z[3] = byte(l)
+               z = z[4:]
+
+               // RFC 3546, section 3.1
+               //
+               // struct {
+               //     NameType name_type;
+               //     select (name_type) {
+               //         case host_name: HostName;
+               //     } name;
+               // } ServerName;
+               //
+               // enum {
+               //     host_name(0), (255)
+               // } NameType;
+               //
+               // opaque HostName<1..2^16-1>;
+               //
+               // struct {
+               //     ServerName server_name_list<1..2^16-1>
+               // } ServerNameList;
+
+               z[0] = byte((len(m.serverName) + 3) >> 8)
+               z[1] = byte(len(m.serverName) + 3)
+               z[3] = byte(len(m.serverName) >> 8)
+               z[4] = byte(len(m.serverName))
+               copy(z[5:], []byte(m.serverName))
+               z = z[l:]
+       }
+       if m.ocspStapling {
+               // RFC 4366, section 3.6
+               z[0] = byte(extensionStatusRequest >> 8)
+               z[1] = byte(extensionStatusRequest)
+               z[2] = 0
+               z[3] = 5
+               z[4] = 1 // OCSP type
+               // Two zero valued uint16s for the two lengths.
+               z = z[9:]
+       }
+
+       m.raw = x
+
+       return x
+}
+
+func (m *clientHelloMsg) unmarshal(data []byte) bool {
+       if len(data) < 42 {
+               return false
+       }
+       m.raw = data
+       m.vers = uint16(data[4])<<8 | uint16(data[5])
+       m.random = data[6:38]
+       sessionIdLen := int(data[38])
+       if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+               return false
+       }
+       m.sessionId = data[39 : 39+sessionIdLen]
+       data = data[39+sessionIdLen:]
+       if len(data) < 2 {
+               return false
+       }
+       // cipherSuiteLen is the number of bytes of cipher suite numbers. Since
+       // they are uint16s, the number must be even.
+       cipherSuiteLen := int(data[0])<<8 | int(data[1])
+       if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
+               return false
+       }
+       numCipherSuites := cipherSuiteLen / 2
+       m.cipherSuites = make([]uint16, numCipherSuites)
+       for i := 0; i < numCipherSuites; i++ {
+               m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+       }
+       data = data[2+cipherSuiteLen:]
+       if len(data) < 1 {
+               return false
+       }
+       compressionMethodsLen := int(data[0])
+       if len(data) < 1+compressionMethodsLen {
+               return false
+       }
+       m.compressionMethods = data[1 : 1+compressionMethodsLen]
+
+       data = data[1+compressionMethodsLen:]
+
+       m.nextProtoNeg = false
+       m.serverName = ""
+       m.ocspStapling = false
+
+       if len(data) == 0 {
+               // ClientHello is optionally followed by extension data
+               return true
+       }
+       if len(data) < 2 {
+               return false
+       }
+
+       extensionsLength := int(data[0])<<8 | int(data[1])
+       data = data[2:]
+       if extensionsLength != len(data) {
+               return false
+       }
+
+       for len(data) != 0 {
+               if len(data) < 4 {
+                       return false
+               }
+               extension := uint16(data[0])<<8 | uint16(data[1])
+               length := int(data[2])<<8 | int(data[3])
+               data = data[4:]
+               if len(data) < length {
+                       return false
+               }
+
+               switch extension {
+               case extensionServerName:
+                       if length < 2 {
+                               return false
+                       }
+                       numNames := int(data[0])<<8 | int(data[1])
+                       d := data[2:]
+                       for i := 0; i < numNames; i++ {
+                               if len(d) < 3 {
+                                       return false
+                               }
+                               nameType := d[0]
+                               nameLen := int(d[1])<<8 | int(d[2])
+                               d = d[3:]
+                               if len(d) < nameLen {
+                                       return false
+                               }
+                               if nameType == 0 {
+                                       m.serverName = string(d[0:nameLen])
+                                       break
+                               }
+                               d = d[nameLen:]
+                       }
+               case extensionNextProtoNeg:
+                       if length > 0 {
+                               return false
+                       }
+                       m.nextProtoNeg = true
+               case extensionStatusRequest:
+                       m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
+               }
+               data = data[length:]
+       }
+
+       return true
+}
+
+type serverHelloMsg struct {
+       raw               []byte
+       vers              uint16
+       random            []byte
+       sessionId         []byte
+       cipherSuite       uint16
+       compressionMethod uint8
+       nextProtoNeg      bool
+       nextProtos        []string
+       certStatus        bool
+}
+
+func (m *serverHelloMsg) marshal() []byte {
+       if m.raw != nil {
+               return m.raw
+       }
+
+       length := 38 + len(m.sessionId)
+       numExtensions := 0
+       extensionsLength := 0
+
+       nextProtoLen := 0
+       if m.nextProtoNeg {
+               numExtensions++
+               for _, v := range m.nextProtos {
+                       nextProtoLen += len(v)
+               }
+               nextProtoLen += len(m.nextProtos)
+               extensionsLength += nextProtoLen
+       }
+       if m.certStatus {
+               numExtensions++
+       }
+       if numExtensions > 0 {
+               extensionsLength += 4 * numExtensions
+               length += 2 + extensionsLength
+       }
+
+       x := make([]byte, 4+length)
+       x[0] = typeServerHello
+       x[1] = uint8(length >> 16)
+       x[2] = uint8(length >> 8)
+       x[3] = uint8(length)
+       x[4] = uint8(m.vers >> 8)
+       x[5] = uint8(m.vers)
+       copy(x[6:38], m.random)
+       x[38] = uint8(len(m.sessionId))
+       copy(x[39:39+len(m.sessionId)], m.sessionId)
+       z := x[39+len(m.sessionId):]
+       z[0] = uint8(m.cipherSuite >> 8)
+       z[1] = uint8(m.cipherSuite)
+       z[2] = uint8(m.compressionMethod)
+
+       z = z[3:]
+       if numExtensions > 0 {
+               z[0] = byte(extensionsLength >> 8)
+               z[1] = byte(extensionsLength)
+               z = z[2:]
+       }
+       if m.nextProtoNeg {
+               z[0] = byte(extensionNextProtoNeg >> 8)
+               z[1] = byte(extensionNextProtoNeg)
+               z[2] = byte(nextProtoLen >> 8)
+               z[3] = byte(nextProtoLen)
+               z = z[4:]
+
+               for _, v := range m.nextProtos {
+                       l := len(v)
+                       if l > 255 {
+                               l = 255
+                       }
+                       z[0] = byte(l)
+                       copy(z[1:], []byte(v[0:l]))
+                       z = z[1+l:]
+               }
+       }
+       if m.certStatus {
+               z[0] = byte(extensionStatusRequest >> 8)
+               z[1] = byte(extensionStatusRequest)
+               z = z[4:]
+       }
+
+       m.raw = x
+
+       return x
+}
+
+func (m *serverHelloMsg) unmarshal(data []byte) bool {
+       if len(data) < 42 {
+               return false
+       }
+       m.raw = data
+       m.vers = uint16(data[4])<<8 | uint16(data[5])
+       m.random = data[6:38]
+       sessionIdLen := int(data[38])
+       if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+               return false
+       }
+       m.sessionId = data[39 : 39+sessionIdLen]
+       data = data[39+sessionIdLen:]
+       if len(data) < 3 {
+               return false
+       }
+       m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
+       m.compressionMethod = data[2]
+       data = data[3:]
+
+       m.nextProtoNeg = false
+       m.nextProtos = nil
+       m.certStatus = false
+
+       if len(data) == 0 {
+               // ServerHello is optionally followed by extension data
+               return true
+       }
+       if len(data) < 2 {
+               return false
+       }
+
+       extensionsLength := int(data[0])<<8 | int(data[1])
+       data = data[2:]
+       if len(data) != extensionsLength {
+               return false
+       }
+
+       for len(data) != 0 {
+               if len(data) < 4 {
+                       return false
+               }
+               extension := uint16(data[0])<<8 | uint16(data[1])
+               length := int(data[2])<<8 | int(data[3])
+               data = data[4:]
+               if len(data) < length {
+                       return false
+               }
+
+               switch extension {
+               case extensionNextProtoNeg:
+                       m.nextProtoNeg = true
+                       d := data
+                       for len(d) > 0 {
+                               l := int(d[0])
+                               d = d[1:]
+                               if l == 0 || l > len(d) {
+                                       return false
+                               }
+                               m.nextProtos = append(m.nextProtos, string(d[0:l]))
+                               d = d[l:]
+                       }
+               case extensionStatusRequest:
+                       if length > 0 {
+                               return false
+                       }
+                       m.certStatus = true
+               }
+               data = data[length:]
+       }
+
+       return true
+}
+
+type certificateMsg struct {
+       raw          []byte
+       certificates [][]byte
+}
+
+func (m *certificateMsg) marshal() (x []byte) {
+       if m.raw != nil {
+               return m.raw
+       }
+
+       var i int
+       for _, slice := range m.certificates {
+               i += len(slice)
+       }
+
+       length := 3 + 3*len(m.certificates) + i
+       x = make([]byte, 4+length)
+       x[0] = typeCertificate
+       x[1] = uint8(length >> 16)
+       x[2] = uint8(length >> 8)
+       x[3] = uint8(length)
+
+       certificateOctets := length - 3
+       x[4] = uint8(certificateOctets >> 16)
+       x[5] = uint8(certificateOctets >> 8)
+       x[6] = uint8(certificateOctets)
+
+       y := x[7:]
+       for _, slice := range m.certificates {
+               y[0] = uint8(len(slice) >> 16)
+               y[1] = uint8(len(slice) >> 8)
+               y[2] = uint8(len(slice))
+               copy(y[3:], slice)
+               y = y[3+len(slice):]
+       }
+
+       m.raw = x
+       return
+}
+
+func (m *certificateMsg) unmarshal(data []byte) bool {
+       if len(data) < 7 {
+               return false
+       }
+
+       m.raw = data
+       certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
+       if uint32(len(data)) != certsLen+7 {
+               return false
+       }
+
+       numCerts := 0
+       d := data[7:]
+       for certsLen > 0 {
+               if len(d) < 4 {
+                       return false
+               }
+               certLen := uint32(d[0])<<24 | uint32(d[1])<<8 | uint32(d[2])
+               if uint32(len(d)) < 3+certLen {
+                       return false
+               }
+               d = d[3+certLen:]
+               certsLen -= 3 + certLen
+               numCerts++
+       }
+
+       m.certificates = make([][]byte, numCerts)
+       d = data[7:]
+       for i := 0; i < numCerts; i++ {
+               certLen := uint32(d[0])<<24 | uint32(d[1])<<8 | uint32(d[2])
+               m.certificates[i] = d[3 : 3+certLen]
+               d = d[3+certLen:]
+       }
+
+       return true
+}
+
+type certificateStatusMsg struct {
+       raw        []byte
+       statusType uint8
+       response   []byte
+}
+
+func (m *certificateStatusMsg) marshal() []byte {
+       if m.raw != nil {
+               return m.raw
+       }
+
+       var x []byte
+       if m.statusType == statusTypeOCSP {
+               x = make([]byte, 4+4+len(m.response))
+               x[0] = typeCertificateStatus
+               l := len(m.response) + 4
+               x[1] = byte(l >> 16)
+               x[2] = byte(l >> 8)
+               x[3] = byte(l)
+               x[4] = statusTypeOCSP
+
+               l -= 4
+               x[5] = byte(l >> 16)
+               x[6] = byte(l >> 8)
+               x[7] = byte(l)
+               copy(x[8:], m.response)
+       } else {
+               x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType}
+       }
+
+       m.raw = x
+       return x
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) bool {
+       m.raw = data
+       if len(data) < 5 {
+               return false
+       }
+       m.statusType = data[4]
+
+       m.response = nil
+       if m.statusType == statusTypeOCSP {
+               if len(data) < 8 {
+                       return false
+               }
+               respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
+               if uint32(len(data)) != 4+4+respLen {
+                       return false
+               }
+               m.response = data[8:]
+       }
+       return true
+}
+
+type serverHelloDoneMsg struct{}
+
+func (m *serverHelloDoneMsg) marshal() []byte {
+       x := make([]byte, 4)
+       x[0] = typeServerHelloDone
+       return x
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
+       return len(data) == 4
+}
+
+type clientKeyExchangeMsg struct {
+       raw        []byte
+       ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) marshal() []byte {
+       if m.raw != nil {
+               return m.raw
+       }
+       length := len(m.ciphertext) + 2
+       x := make([]byte, length+4)
+       x[0] = typeClientKeyExchange
+       x[1] = uint8(length >> 16)
+       x[2] = uint8(length >> 8)
+       x[3] = uint8(length)
+       x[4] = uint8(len(m.ciphertext) >> 8)
+       x[5] = uint8(len(m.ciphertext))
+       copy(x[6:], m.ciphertext)
+
+       m.raw = x
+       return x
+}
+
+func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
+       m.raw = data
+       if len(data) < 7 {
+               return false
+       }
+       cipherTextLen := int(data[4])<<8 | int(data[5])
+       if len(data) != 6+cipherTextLen {
+               return false
+       }
+       m.ciphertext = data[6:]
+       return true
+}
+
+type finishedMsg struct {
+       raw        []byte
+       verifyData []byte
+}
+
+func (m *finishedMsg) marshal() (x []byte) {
+       if m.raw != nil {
+               return m.raw
+       }
+
+       x = make([]byte, 16)
+       x[0] = typeFinished
+       x[3] = 12
+       copy(x[4:], m.verifyData)
+       m.raw = x
+       return
+}
+
+func (m *finishedMsg) unmarshal(data []byte) bool {
+       m.raw = data
+       if len(data) != 4+12 {
+               return false
+       }
+       m.verifyData = data[4:]
+       return true
+}
+
+type nextProtoMsg struct {
+       raw   []byte
+       proto string
+}
+
+func (m *nextProtoMsg) marshal() []byte {
+       if m.raw != nil {
+               return m.raw
+       }
+       l := len(m.proto)
+       if l > 255 {
+               l = 255
+       }
+
+       padding := 32 - (l+2)%32
+       length := l + padding + 2
+       x := make([]byte, length+4)
+       x[0] = typeNextProtocol
+       x[1] = uint8(length >> 16)
+       x[2] = uint8(length >> 8)
+       x[3] = uint8(length)
+
+       y := x[4:]
+       y[0] = byte(l)
+       copy(y[1:], []byte(m.proto[0:l]))
+       y = y[1+l:]
+       y[0] = byte(padding)
+
+       m.raw = x
+
+       return x
+}
+
+func (m *nextProtoMsg) unmarshal(data []byte) bool {
+       m.raw = data
+
+       if len(data) < 5 {
+               return false
+       }
+       data = data[4:]
+       protoLen := int(data[0])
+       data = data[1:]
+       if len(data) < protoLen {
+               return false
+       }
+       m.proto = string(data[0:protoLen])
+       data = data[protoLen:]
+
+       if len(data) < 1 {
+               return false
+       }
+       paddingLen := int(data[0])
+       data = data[1:]
+       if len(data) != paddingLen {
+               return false
+       }
+
+       return true
+}
+
+type certificateRequestMsg struct {
+       raw                    []byte
+       certificateTypes       []byte
+       certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsg) marshal() (x []byte) {
+       if m.raw != nil {
+               return m.raw
+       }
+
+       // See http://tools.ietf.org/html/rfc4346#section-7.4.4
+       length := 1 + len(m.certificateTypes) + 2
+       for _, ca := range m.certificateAuthorities {
+               length += 2 + len(ca)
+       }
+
+       x = make([]byte, 4+length)
+       x[0] = typeCertificateRequest
+       x[1] = uint8(length >> 16)
+       x[2] = uint8(length >> 8)
+       x[3] = uint8(length)
+
+       x[4] = uint8(len(m.certificateTypes))
+
+       copy(x[5:], m.certificateTypes)
+       y := x[5+len(m.certificateTypes):]
+
+       numCA := len(m.certificateAuthorities)
+       y[0] = uint8(numCA >> 8)
+       y[1] = uint8(numCA)
+       y = y[2:]
+       for _, ca := range m.certificateAuthorities {
+               y[0] = uint8(len(ca) >> 8)
+               y[1] = uint8(len(ca))
+               y = y[2:]
+               copy(y, ca)
+               y = y[len(ca):]
+       }
+
+       m.raw = x
+
+       return
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+       m.raw = data
+
+       if len(data) < 5 {
+               return false
+       }
+
+       length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+       if uint32(len(data))-4 != length {
+               return false
+       }
+
+       numCertTypes := int(data[4])
+       data = data[5:]
+       if numCertTypes == 0 || len(data) <= numCertTypes {
+               return false
+       }
+
+       m.certificateTypes = make([]byte, numCertTypes)
+       if copy(m.certificateTypes, data) != numCertTypes {
+               return false
+       }
+
+       data = data[numCertTypes:]
+       if len(data) < 2 {
+               return false
+       }
+
+       numCAs := uint16(data[0])<<16 | uint16(data[1])
+       data = data[2:]
+
+       m.certificateAuthorities = make([][]byte, numCAs)
+       for i := uint16(0); i < numCAs; i++ {
+               if len(data) < 2 {
+                       return false
+               }
+               caLen := uint16(data[0])<<16 | uint16(data[1])
+
+               data = data[2:]
+               if len(data) < int(caLen) {
+                       return false
+               }
+
+               ca := make([]byte, caLen)
+               copy(ca, data)
+               m.certificateAuthorities[i] = ca
+               data = data[caLen:]
+       }
+
+       if len(data) > 0 {
+               return false
+       }
+
+       return true
+}
+
+type certificateVerifyMsg struct {
+       raw       []byte
+       signature []byte
+}
+
+func (m *certificateVerifyMsg) marshal() (x []byte) {
+       if m.raw != nil {
+               return m.raw
+       }
+
+       // See http://tools.ietf.org/html/rfc4346#section-7.4.8
+       siglength := len(m.signature)
+       length := 2 + siglength
+       x = make([]byte, 4+length)
+       x[0] = typeCertificateVerify
+       x[1] = uint8(length >> 16)
+       x[2] = uint8(length >> 8)
+       x[3] = uint8(length)
+       x[4] = uint8(siglength >> 8)
+       x[5] = uint8(siglength)
+       copy(x[6:], m.signature)
+
+       m.raw = x
+
+       return
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
+       m.raw = data
+
+       if len(data) < 6 {
+               return false
+       }
+
+       length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+       if uint32(len(data))-4 != length {
+               return false
+       }
+
+       siglength := int(data[4])<<8 + int(data[5])
+       if len(data)-6 != siglength {
+               return false
+       }
+
+       m.signature = data[6:]
+
+       return true
+}
diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go
new file mode 100644 (file)
index 0000000..64d23e0
--- /dev/null
@@ -0,0 +1,197 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+       "rand"
+       "reflect"
+       "testing"
+       "testing/quick"
+)
+
+var tests = []interface{}{
+       &clientHelloMsg{},
+       &serverHelloMsg{},
+
+       &certificateMsg{},
+       &certificateRequestMsg{},
+       &certificateVerifyMsg{},
+       &certificateStatusMsg{},
+       &clientKeyExchangeMsg{},
+       &finishedMsg{},
+       &nextProtoMsg{},
+}
+
+type testMessage interface {
+       marshal() []byte
+       unmarshal([]byte) bool
+}
+
+func TestMarshalUnmarshal(t *testing.T) {
+       rand := rand.New(rand.NewSource(0))
+       for i, iface := range tests {
+               ty := reflect.NewValue(iface).Type()
+
+               for j := 0; j < 100; j++ {
+                       v, ok := quick.Value(ty, rand)
+                       if !ok {
+                               t.Errorf("#%d: failed to create value", i)
+                               break
+                       }
+
+                       m1 := v.Interface().(testMessage)
+                       marshaled := m1.marshal()
+                       m2 := iface.(testMessage)
+                       if !m2.unmarshal(marshaled) {
+                               t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled)
+                               break
+                       }
+                       m2.marshal() // to fill any marshal cache in the message
+
+                       if !reflect.DeepEqual(m1, m2) {
+                               t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled)
+                               break
+                       }
+
+                       if i >= 2 {
+                               // The first two message types (ClientHello and
+                               // ServerHello) are allowed to have parsable
+                               // prefixes because the extension data is
+                               // optional.
+                               for j := 0; j < len(marshaled); j++ {
+                                       if m2.unmarshal(marshaled[0:j]) {
+                                               t.Errorf("#%d unmarshaled a prefix of length %d of %#v", i, j, m1)
+                                               break
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+func TestFuzz(t *testing.T) {
+       rand := rand.New(rand.NewSource(0))
+       for _, iface := range tests {
+               m := iface.(testMessage)
+
+               for j := 0; j < 1000; j++ {
+                       len := rand.Intn(100)
+                       bytes := randomBytes(len, rand)
+                       // This just looks for crashes due to bounds errors etc.
+                       m.unmarshal(bytes)
+               }
+       }
+}
+
+func randomBytes(n int, rand *rand.Rand) []byte {
+       r := make([]byte, n)
+       for i := 0; i < n; i++ {
+               r[i] = byte(rand.Int31())
+       }
+       return r
+}
+
+func randomString(n int, rand *rand.Rand) string {
+       b := randomBytes(n, rand)
+       return string(b)
+}
+
+func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+       m := &clientHelloMsg{}
+       m.vers = uint16(rand.Intn(65536))
+       m.random = randomBytes(32, rand)
+       m.sessionId = randomBytes(rand.Intn(32), rand)
+       m.cipherSuites = make([]uint16, rand.Intn(63)+1)
+       for i := 0; i < len(m.cipherSuites); i++ {
+               m.cipherSuites[i] = uint16(rand.Int31())
+       }
+       m.compressionMethods = randomBytes(rand.Intn(63)+1, rand)
+       if rand.Intn(10) > 5 {
+               m.nextProtoNeg = true
+       }
+       if rand.Intn(10) > 5 {
+               m.serverName = randomString(rand.Intn(255), rand)
+       }
+       m.ocspStapling = rand.Intn(10) > 5
+
+       return reflect.NewValue(m)
+}
+
+func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+       m := &serverHelloMsg{}
+       m.vers = uint16(rand.Intn(65536))
+       m.random = randomBytes(32, rand)
+       m.sessionId = randomBytes(rand.Intn(32), rand)
+       m.cipherSuite = uint16(rand.Int31())
+       m.compressionMethod = uint8(rand.Intn(256))
+
+       if rand.Intn(10) > 5 {
+               m.nextProtoNeg = true
+
+               n := rand.Intn(10)
+               m.nextProtos = make([]string, n)
+               for i := 0; i < n; i++ {
+                       m.nextProtos[i] = randomString(20, rand)
+               }
+       }
+
+       return reflect.NewValue(m)
+}
+
+func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+       m := &certificateMsg{}
+       numCerts := rand.Intn(20)
+       m.certificates = make([][]byte, numCerts)
+       for i := 0; i < numCerts; i++ {
+               m.certificates[i] = randomBytes(rand.Intn(10)+1, rand)
+       }
+       return reflect.NewValue(m)
+}
+
+func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+       m := &certificateRequestMsg{}
+       m.certificateTypes = randomBytes(rand.Intn(5)+1, rand)
+       numCAs := rand.Intn(100)
+       m.certificateAuthorities = make([][]byte, numCAs)
+       for i := 0; i < numCAs; i++ {
+               m.certificateAuthorities[i] = randomBytes(rand.Intn(15)+1, rand)
+       }
+       return reflect.NewValue(m)
+}
+
+func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+       m := &certificateVerifyMsg{}
+       m.signature = randomBytes(rand.Intn(15)+1, rand)
+       return reflect.NewValue(m)
+}
+
+func (*certificateStatusMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+       m := &certificateStatusMsg{}
+       if rand.Intn(10) > 5 {
+               m.statusType = statusTypeOCSP
+               m.response = randomBytes(rand.Intn(10)+1, rand)
+       } else {
+               m.statusType = 42
+       }
+       return reflect.NewValue(m)
+}
+
+func (*clientKeyExchangeMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+       m := &clientKeyExchangeMsg{}
+       m.ciphertext = randomBytes(rand.Intn(1000)+1, rand)
+       return reflect.NewValue(m)
+}
+
+func (*finishedMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+       m := &finishedMsg{}
+       m.verifyData = randomBytes(12, rand)
+       return reflect.NewValue(m)
+}
+
+func (*nextProtoMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+       m := &nextProtoMsg{}
+       m.proto = randomString(rand.Intn(255), rand)
+       return reflect.NewValue(m)
+}
diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go
new file mode 100644 (file)
index 0000000..2255038
--- /dev/null
@@ -0,0 +1,280 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+// The handshake goroutine reads handshake messages from the record processor
+// and outputs messages to be written on another channel. It updates the record
+// processor with the state of the connection via the control channel. In the
+// case of handshake messages that need synchronous processing (because they
+// affect the handling of the next record) the record processor knows about
+// them and either waits for a control message (Finished) or includes a reply
+// channel in the message (ChangeCipherSpec).
+
+import (
+       "crypto/hmac"
+       "crypto/rc4"
+       "crypto/rsa"
+       "crypto/subtle"
+       "crypto/x509"
+       "io"
+       "os"
+)
+
+type cipherSuite struct {
+       id                          uint16 // The number of this suite on the wire.
+       hashLength, cipherKeyLength int
+       // TODO(agl): need a method to create the cipher and hash interfaces.
+}
+
+var cipherSuites = []cipherSuite{
+       {TLS_RSA_WITH_RC4_128_SHA, 20, 16},
+}
+
+func (c *Conn) serverHandshake() os.Error {
+       config := c.config
+       msg, err := c.readHandshake()
+       if err != nil {
+               return err
+       }
+       clientHello, ok := msg.(*clientHelloMsg)
+       if !ok {
+               return c.sendAlert(alertUnexpectedMessage)
+       }
+       vers, ok := mutualVersion(clientHello.vers)
+       if !ok {
+               return c.sendAlert(alertProtocolVersion)
+       }
+       c.vers = vers
+       c.haveVers = true
+
+       finishedHash := newFinishedHash()
+       finishedHash.Write(clientHello.marshal())
+
+       hello := new(serverHelloMsg)
+
+       // We only support a single ciphersuite so we look for it in the list
+       // of client supported suites.
+       //
+       // TODO(agl): Add additional cipher suites.
+       var suite *cipherSuite
+
+       for _, id := range clientHello.cipherSuites {
+               for _, supported := range cipherSuites {
+                       if supported.id == id {
+                               suite = &supported
+                               break
+                       }
+               }
+       }
+
+       foundCompression := false
+       // We only support null compression, so check that the client offered it.
+       for _, compression := range clientHello.compressionMethods {
+               if compression == compressionNone {
+                       foundCompression = true
+                       break
+               }
+       }
+
+       if suite == nil || !foundCompression {
+               return c.sendAlert(alertHandshakeFailure)
+       }
+
+       hello.vers = vers
+       hello.cipherSuite = suite.id
+       t := uint32(config.Time())
+       hello.random = make([]byte, 32)
+       hello.random[0] = byte(t >> 24)
+       hello.random[1] = byte(t >> 16)
+       hello.random[2] = byte(t >> 8)
+       hello.random[3] = byte(t)
+       _, err = io.ReadFull(config.Rand, hello.random[4:])
+       if err != nil {
+               return c.sendAlert(alertInternalError)
+       }
+       hello.compressionMethod = compressionNone
+       if clientHello.nextProtoNeg {
+               hello.nextProtoNeg = true
+               hello.nextProtos = config.NextProtos
+       }
+
+       finishedHash.Write(hello.marshal())
+       c.writeRecord(recordTypeHandshake, hello.marshal())
+
+       if len(config.Certificates) == 0 {
+               return c.sendAlert(alertInternalError)
+       }
+
+       certMsg := new(certificateMsg)
+       certMsg.certificates = config.Certificates[0].Certificate
+       finishedHash.Write(certMsg.marshal())
+       c.writeRecord(recordTypeHandshake, certMsg.marshal())
+
+       if config.AuthenticateClient {
+               // Request a client certificate
+               certReq := new(certificateRequestMsg)
+               certReq.certificateTypes = []byte{certTypeRSASign}
+               // An empty list of certificateAuthorities signals to
+               // the client that it may send any certificate in response
+               // to our request.
+
+               finishedHash.Write(certReq.marshal())
+               c.writeRecord(recordTypeHandshake, certReq.marshal())
+       }
+
+       helloDone := new(serverHelloDoneMsg)
+       finishedHash.Write(helloDone.marshal())
+       c.writeRecord(recordTypeHandshake, helloDone.marshal())
+
+       var pub *rsa.PublicKey
+       if config.AuthenticateClient {
+               // Get client certificate
+               msg, err = c.readHandshake()
+               if err != nil {
+                       return err
+               }
+               certMsg, ok = msg.(*certificateMsg)
+               if !ok {
+                       return c.sendAlert(alertUnexpectedMessage)
+               }
+               finishedHash.Write(certMsg.marshal())
+
+               certs := make([]*x509.Certificate, len(certMsg.certificates))
+               for i, asn1Data := range certMsg.certificates {
+                       cert, err := x509.ParseCertificate(asn1Data)
+                       if err != nil {
+                               c.sendAlert(alertBadCertificate)
+                               return os.ErrorString("could not parse client's certificate: " + err.String())
+                       }
+                       certs[i] = cert
+               }
+
+               // TODO(agl): do better validation of certs: max path length, name restrictions etc.
+               for i := 1; i < len(certs); i++ {
+                       if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
+                               c.sendAlert(alertBadCertificate)
+                               return os.ErrorString("could not validate certificate signature: " + err.String())
+                       }
+               }
+
+               if len(certs) > 0 {
+                       key, ok := certs[0].PublicKey.(*rsa.PublicKey)
+                       if !ok {
+                               return c.sendAlert(alertUnsupportedCertificate)
+                       }
+                       pub = key
+                       c.peerCertificates = certs
+               }
+       }
+
+       // Get client key exchange
+       msg, err = c.readHandshake()
+       if err != nil {
+               return err
+       }
+       ckx, ok := msg.(*clientKeyExchangeMsg)
+       if !ok {
+               return c.sendAlert(alertUnexpectedMessage)
+       }
+       finishedHash.Write(ckx.marshal())
+
+       // If we received a client cert in response to our certificate request message,
+       // the client will send us a certificateVerifyMsg immediately after the
+       // clientKeyExchangeMsg.  This message is a MD5SHA1 digest of all preceeding
+       // handshake-layer messages that is signed using the private key corresponding
+       // to the client's certificate. This allows us to verify that the client is in
+       // posession of the private key of the certificate.
+       if len(c.peerCertificates) > 0 {
+               msg, err = c.readHandshake()
+               if err != nil {
+                       return err
+               }
+               certVerify, ok := msg.(*certificateVerifyMsg)
+               if !ok {
+                       return c.sendAlert(alertUnexpectedMessage)
+               }
+
+               digest := make([]byte, 36)
+               copy(digest[0:16], finishedHash.serverMD5.Sum())
+               copy(digest[16:36], finishedHash.serverSHA1.Sum())
+               err = rsa.VerifyPKCS1v15(pub, rsa.HashMD5SHA1, digest, certVerify.signature)
+               if err != nil {
+                       c.sendAlert(alertBadCertificate)
+                       return os.ErrorString("could not validate signature of connection nonces: " + err.String())
+               }
+
+               finishedHash.Write(certVerify.marshal())
+       }
+
+       preMasterSecret := make([]byte, 48)
+       _, err = io.ReadFull(config.Rand, preMasterSecret[2:])
+       if err != nil {
+               return c.sendAlert(alertInternalError)
+       }
+
+       err = rsa.DecryptPKCS1v15SessionKey(config.Rand, config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret)
+       if err != nil {
+               return c.sendAlert(alertHandshakeFailure)
+       }
+       // We don't check the version number in the premaster secret. For one,
+       // by checking it, we would leak information about the validity of the
+       // encrypted pre-master secret. Secondly, it provides only a small
+       // benefit against a downgrade attack and some implementations send the
+       // wrong version anyway. See the discussion at the end of section
+       // 7.4.7.1 of RFC 4346.
+
+       masterSecret, clientMAC, serverMAC, clientKey, serverKey :=
+               keysFromPreMasterSecret11(preMasterSecret, clientHello.random, hello.random, suite.hashLength, suite.cipherKeyLength)
+
+       cipher, _ := rc4.NewCipher(clientKey)
+       c.in.prepareCipherSpec(cipher, hmac.NewSHA1(clientMAC))
+       c.readRecord(recordTypeChangeCipherSpec)
+       if err := c.error(); err != nil {
+               return err
+       }
+
+       if hello.nextProtoNeg {
+               msg, err = c.readHandshake()
+               if err != nil {
+                       return err
+               }
+               nextProto, ok := msg.(*nextProtoMsg)
+               if !ok {
+                       return c.sendAlert(alertUnexpectedMessage)
+               }
+               finishedHash.Write(nextProto.marshal())
+               c.clientProtocol = nextProto.proto
+       }
+
+       msg, err = c.readHandshake()
+       if err != nil {
+               return err
+       }
+       clientFinished, ok := msg.(*finishedMsg)
+       if !ok {
+               return c.sendAlert(alertUnexpectedMessage)
+       }
+
+       verify := finishedHash.clientSum(masterSecret)
+       if len(verify) != len(clientFinished.verifyData) ||
+               subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+               return c.sendAlert(alertHandshakeFailure)
+       }
+
+       finishedHash.Write(clientFinished.marshal())
+
+       cipher2, _ := rc4.NewCipher(serverKey)
+       c.out.prepareCipherSpec(cipher2, hmac.NewSHA1(serverMAC))
+       c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+
+       finished := new(finishedMsg)
+       finished.verifyData = finishedHash.serverSum(masterSecret)
+       c.writeRecord(recordTypeHandshake, finished.marshal())
+
+       c.handshakeComplete = true
+       c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA
+
+       return nil
+}
diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go
new file mode 100644 (file)
index 0000000..efdbb66
--- /dev/null
@@ -0,0 +1,293 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+       //      "bytes"
+       "big"
+       "crypto/rsa"
+       "encoding/hex"
+       "flag"
+       "io"
+       "net"
+       "os"
+       "testing"
+       //      "testing/script"
+)
+
+type zeroSource struct{}
+
+func (zeroSource) Read(b []byte) (n int, err os.Error) {
+       for i := range b {
+               b[i] = 0
+       }
+
+       return len(b), nil
+}
+
+var testConfig *Config
+
+func init() {
+       testConfig = new(Config)
+       testConfig.Time = func() int64 { return 0 }
+       testConfig.Rand = zeroSource{}
+       testConfig.Certificates = make([]Certificate, 1)
+       testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
+       testConfig.Certificates[0].PrivateKey = testPrivateKey
+}
+
+func testClientHelloFailure(t *testing.T, m handshakeMessage, expected os.Error) {
+       // Create in-memory network connection,
+       // send message to server.  Should return
+       // expected error.
+       c, s := net.Pipe()
+       go func() {
+               cli := Client(c, testConfig)
+               if ch, ok := m.(*clientHelloMsg); ok {
+                       cli.vers = ch.vers
+               }
+               cli.writeRecord(recordTypeHandshake, m.marshal())
+               c.Close()
+       }()
+       err := Server(s, testConfig).Handshake()
+       s.Close()
+       if e, ok := err.(*net.OpError); !ok || e.Error != expected {
+               t.Errorf("Got error: %s; expected: %s", err, expected)
+       }
+}
+
+func TestSimpleError(t *testing.T) {
+       testClientHelloFailure(t, &serverHelloDoneMsg{}, alertUnexpectedMessage)
+}
+
+var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205, 0x0300}
+
+func TestRejectBadProtocolVersion(t *testing.T) {
+       for _, v := range badProtocolVersions {
+               testClientHelloFailure(t, &clientHelloMsg{vers: v}, alertProtocolVersion)
+       }
+}
+
+func TestNoSuiteOverlap(t *testing.T) {
+       clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{0xff00}, []uint8{0}, false, "", false}
+       testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+
+}
+
+func TestNoCompressionOverlap(t *testing.T) {
+       clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{TLS_RSA_WITH_RC4_128_SHA}, []uint8{0xff}, false, "", false}
+       testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+}
+
+func TestAlertForwarding(t *testing.T) {
+       c, s := net.Pipe()
+       go func() {
+               Client(c, testConfig).sendAlert(alertUnknownCA)
+               c.Close()
+       }()
+
+       err := Server(s, testConfig).Handshake()
+       s.Close()
+       if e, ok := err.(*net.OpError); !ok || e.Error != os.Error(alertUnknownCA) {
+               t.Errorf("Got error: %s; expected: %s", err, alertUnknownCA)
+       }
+}
+
+func TestClose(t *testing.T) {
+       c, s := net.Pipe()
+       go c.Close()
+
+       err := Server(s, testConfig).Handshake()
+       s.Close()
+       if err != os.EOF {
+               t.Errorf("Got error: %s; expected: %s", err, os.EOF)
+       }
+}
+
+
+func TestHandshakeServer(t *testing.T) {
+       c, s := net.Pipe()
+       srv := Server(s, testConfig)
+       go func() {
+               srv.Write([]byte("hello, world\n"))
+               srv.Close()
+       }()
+
+       defer c.Close()
+       for i, b := range serverScript {
+               if i%2 == 0 {
+                       c.Write(b)
+                       continue
+               }
+               bb := make([]byte, len(b))
+               _, err := io.ReadFull(c, bb)
+               if err != nil {
+                       t.Fatalf("#%d: %s", i, err)
+               }
+       }
+
+       if !srv.haveVers || srv.vers != 0x0302 {
+               t.Errorf("server version incorrect: %v %v", srv.haveVers, srv.vers)
+       }
+
+       // TODO: check protocol
+}
+
+var serve = flag.Bool("serve", false, "run a TLS server on :10443")
+
+func TestRunServer(t *testing.T) {
+       if !*serve {
+               return
+       }
+
+       l, err := Listen("tcp", ":10443", testConfig)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       for {
+               c, err := l.Accept()
+               if err != nil {
+                       break
+               }
+               c.Write([]byte("hello, world\n"))
+               c.Close()
+       }
+}
+
+func bigFromString(s string) *big.Int {
+       ret := new(big.Int)
+       ret.SetString(s, 10)
+       return ret
+}
+
+func fromHex(s string) []byte {
+       b, _ := hex.DecodeString(s)
+       return b
+}
+
+var testCertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
+
+var testPrivateKey = &rsa.PrivateKey{
+       PublicKey: rsa.PublicKey{
+               N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
+               E: 65537,
+       },
+       D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
+       P: bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
+       Q: bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
+}
+
+// Script of interaction with gnutls implementation.
+// The values for this test are obtained by building a test binary (gotest)
+// and then running 6.out -serve to start a server and then
+// gnutls-cli --insecure --debug 100 -p 10443 localhost
+// to dump a session.
+var serverScript = [][]byte{
+       // Alternate write and read.
+       {
+               0x16, 0x03, 0x02, 0x00, 0x71, 0x01, 0x00, 0x00, 0x6d, 0x03, 0x02, 0x4b, 0xd4, 0xee, 0x6e, 0xab,
+               0x0b, 0xc3, 0x01, 0xd6, 0x8d, 0xe0, 0x72, 0x7e, 0x6c, 0x04, 0xbe, 0x9a, 0x3c, 0xa3, 0xd8, 0x95,
+               0x28, 0x00, 0xb2, 0xe8, 0x1f, 0xdd, 0xb0, 0xec, 0xca, 0x46, 0x1f, 0x00, 0x00, 0x28, 0x00, 0x33,
+               0x00, 0x39, 0x00, 0x16, 0x00, 0x32, 0x00, 0x38, 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+               0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x00, 0x8c,
+               0x00, 0x8d, 0x00, 0x8b, 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1c, 0x00, 0x09, 0x00, 0x03, 0x02, 0x00,
+               0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0f, 0x00, 0x00, 0x0c, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36,
+               0x38, 0x2e, 0x30, 0x2e, 0x31, 0x30,
+       },
+
+       {
+               0x16, 0x03, 0x02, 0x00, 0x2a,
+               0x02, 0x00, 0x00, 0x26, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
+
+               0x16, 0x03, 0x02, 0x02, 0xbe,
+               0x0b, 0x00, 0x02, 0xba, 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0, 0x30, 0x82,
+               0x02, 0x19, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f,
+               0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+               0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55,
+               0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d,
+               0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
+               0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73,
+               0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x34,
+               0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x34, 0x32,
+               0x34, 0x30, 0x39, 0x30, 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+               0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+               0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f,
+               0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20,
+               0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30,
+               0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+               0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79, 0xd6, 0xf5,
+               0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43, 0x5a, 0xd0,
+               0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c, 0x78, 0xb8,
+               0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c, 0xa5, 0x33,
+               0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26, 0x3f, 0xb5,
+               0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf, 0xef, 0x42,
+               0x71, 0x00, 0xfe, 0x18, 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39, 0xc4, 0xa2,
+               0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf, 0xb1, 0x1d,
+               0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03, 0x01, 0x00,
+               0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+               0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23, 0x69, 0xde,
+               0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x6e, 0x30,
+               0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23, 0x69,
+               0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30,
+               0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+               0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
+               0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
+               0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
+               0x74, 0x64, 0x82, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0c, 0x06,
+               0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+               0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x08, 0x6c,
+               0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7, 0x87, 0x9d,
+               0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66, 0x1f, 0xeb,
+               0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13, 0xb1, 0x18,
+               0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31, 0x59, 0xdb,
+               0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f, 0x33, 0xc4,
+               0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f, 0x89, 0x20,
+               0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70, 0xe8, 0x26,
+               0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
+               0x16, 0x03, 0x02, 0x00, 0x04,
+               0x0e, 0x00, 0x00, 0x00,
+       },
+
+       {
+               0x16, 0x03, 0x02, 0x00, 0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x3b, 0x7a, 0x9b, 0x05, 0xfd,
+               0x1b, 0x0d, 0x81, 0xf0, 0xac, 0x59, 0x57, 0x4e, 0xb6, 0xf5, 0x81, 0xed, 0x52, 0x78, 0xc5, 0xff,
+               0x36, 0x33, 0x9c, 0x94, 0x31, 0xc3, 0x14, 0x98, 0x5d, 0xa0, 0x49, 0x23, 0x11, 0x67, 0xdf, 0x73,
+               0x1b, 0x81, 0x0b, 0xdd, 0x10, 0xda, 0xee, 0xb5, 0x68, 0x61, 0xa9, 0xb6, 0x15, 0xae, 0x1a, 0x11,
+               0x31, 0x42, 0x2e, 0xde, 0x01, 0x4b, 0x81, 0x70, 0x03, 0xc8, 0x5b, 0xca, 0x21, 0x88, 0x25, 0xef,
+               0x89, 0xf0, 0xb7, 0xff, 0x24, 0x32, 0xd3, 0x14, 0x76, 0xe2, 0x50, 0x5c, 0x2e, 0x75, 0x9d, 0x5c,
+               0xa9, 0x80, 0x3d, 0x6f, 0xd5, 0x46, 0xd3, 0xdb, 0x42, 0x6e, 0x55, 0x81, 0x88, 0x42, 0x0e, 0x45,
+               0xfe, 0x9e, 0xe4, 0x41, 0x79, 0xcf, 0x71, 0x0e, 0xed, 0x27, 0xa8, 0x20, 0x05, 0xe9, 0x7a, 0x42,
+               0x4f, 0x05, 0x10, 0x2e, 0x52, 0x5d, 0x8c, 0x3c, 0x40, 0x49, 0x4c,
+
+               0x14, 0x03, 0x02, 0x00, 0x01, 0x01,
+
+               0x16, 0x03, 0x02, 0x00, 0x24, 0x8b, 0x12, 0x24, 0x06, 0xaa, 0x92, 0x74, 0xa1, 0x46, 0x6f, 0xc1,
+               0x4e, 0x4a, 0xf7, 0x16, 0xdd, 0xd6, 0xe1, 0x2d, 0x37, 0x0b, 0x44, 0xba, 0xeb, 0xc4, 0x6c, 0xc7,
+               0xa0, 0xb7, 0x8c, 0x9d, 0x24, 0xbd, 0x99, 0x33, 0x1e,
+       },
+
+       {
+               0x14, 0x03, 0x02, 0x00, 0x01,
+               0x01,
+
+               0x16, 0x03, 0x02, 0x00, 0x24,
+               0x6e, 0xd1, 0x3e, 0x49, 0x68, 0xc1, 0xa0, 0xa5, 0xb7, 0xaf, 0xb0, 0x7c, 0x52, 0x1f, 0xf7, 0x2d,
+               0x51, 0xf3, 0xa5, 0xb6, 0xf6, 0xd4, 0x18, 0x4b, 0x7a, 0xd5, 0x24, 0x1d, 0x09, 0xb6, 0x41, 0x1c,
+               0x1c, 0x98, 0xf6, 0x90,
+
+               0x17, 0x03, 0x02, 0x00, 0x21,
+               0x50, 0xb7, 0x92, 0x4f, 0xd8, 0x78, 0x29, 0xa2, 0xe7, 0xa5, 0xa6, 0xbd, 0x1a, 0x0c, 0xf1, 0x5a,
+               0x6e, 0x6c, 0xeb, 0x38, 0x99, 0x9b, 0x3c, 0xfd, 0xee, 0x53, 0xe8, 0x4d, 0x7b, 0xa5, 0x5b, 0x00,
+
+               0xb9,
+
+               0x15, 0x03, 0x02, 0x00, 0x16,
+               0xc7, 0xc9, 0x5a, 0x72, 0xfb, 0x02, 0xa5, 0x93, 0xdd, 0x69, 0xeb, 0x30, 0x68, 0x5e, 0xbc, 0xe0,
+               0x44, 0xb9, 0x59, 0x33, 0x68, 0xa9,
+       },
+}
diff --git a/libgo/go/crypto/tls/prf.go b/libgo/go/crypto/tls/prf.go
new file mode 100644 (file)
index 0000000..b206d26
--- /dev/null
@@ -0,0 +1,146 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+       "crypto/hmac"
+       "crypto/md5"
+       "crypto/sha1"
+       "hash"
+       "os"
+)
+
+// Split a premaster secret in two as specified in RFC 4346, section 5.
+func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
+       s1 = secret[0 : (len(secret)+1)/2]
+       s2 = secret[len(secret)/2:]
+       return
+}
+
+// pHash implements the P_hash function, as defined in RFC 4346, section 5.
+func pHash(result, secret, seed []byte, hash func() hash.Hash) {
+       h := hmac.New(hash, secret)
+       h.Write(seed)
+       a := h.Sum()
+
+       j := 0
+       for j < len(result) {
+               h.Reset()
+               h.Write(a)
+               h.Write(seed)
+               b := h.Sum()
+               todo := len(b)
+               if j+todo > len(result) {
+                       todo = len(result) - j
+               }
+               copy(result[j:j+todo], b)
+               j += todo
+
+               h.Reset()
+               h.Write(a)
+               a = h.Sum()
+       }
+}
+
+// pRF11 implements the TLS 1.1 pseudo-random function, as defined in RFC 4346, section 5.
+func pRF11(result, secret, label, seed []byte) {
+       hashSHA1 := sha1.New
+       hashMD5 := md5.New
+
+       labelAndSeed := make([]byte, len(label)+len(seed))
+       copy(labelAndSeed, label)
+       copy(labelAndSeed[len(label):], seed)
+
+       s1, s2 := splitPreMasterSecret(secret)
+       pHash(result, s1, labelAndSeed, hashMD5)
+       result2 := make([]byte, len(result))
+       pHash(result2, s2, labelAndSeed, hashSHA1)
+
+       for i, b := range result2 {
+               result[i] ^= b
+       }
+}
+
+const (
+       tlsRandomLength      = 32 // Length of a random nonce in TLS 1.1.
+       masterSecretLength   = 48 // Length of a master secret in TLS 1.1.
+       finishedVerifyLength = 12 // Length of verify_data in a Finished message.
+)
+
+var masterSecretLabel = []byte("master secret")
+var keyExpansionLabel = []byte("key expansion")
+var clientFinishedLabel = []byte("client finished")
+var serverFinishedLabel = []byte("server finished")
+
+// keysFromPreMasterSecret generates the connection keys from the pre master
+// secret, given the lengths of the MAC and cipher keys, as defined in RFC
+// 4346, section 6.3.
+func keysFromPreMasterSecret11(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey []byte) {
+       var seed [tlsRandomLength * 2]byte
+       copy(seed[0:len(clientRandom)], clientRandom)
+       copy(seed[len(clientRandom):], serverRandom)
+       masterSecret = make([]byte, masterSecretLength)
+       pRF11(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+
+       copy(seed[0:len(clientRandom)], serverRandom)
+       copy(seed[len(serverRandom):], clientRandom)
+
+       n := 2*macLen + 2*keyLen
+       keyMaterial := make([]byte, n)
+       pRF11(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+       clientMAC = keyMaterial[0:macLen]
+       serverMAC = keyMaterial[macLen : macLen*2]
+       clientKey = keyMaterial[macLen*2 : macLen*2+keyLen]
+       serverKey = keyMaterial[macLen*2+keyLen:]
+       return
+}
+
+// A finishedHash calculates the hash of a set of handshake messages suitable
+// for including in a Finished message.
+type finishedHash struct {
+       clientMD5  hash.Hash
+       clientSHA1 hash.Hash
+       serverMD5  hash.Hash
+       serverSHA1 hash.Hash
+}
+
+func newFinishedHash() finishedHash {
+       return finishedHash{md5.New(), sha1.New(), md5.New(), sha1.New()}
+}
+
+func (h finishedHash) Write(msg []byte) (n int, err os.Error) {
+       h.clientMD5.Write(msg)
+       h.clientSHA1.Write(msg)
+       h.serverMD5.Write(msg)
+       h.serverSHA1.Write(msg)
+       return len(msg), nil
+}
+
+// finishedSum calculates the contents of the verify_data member of a Finished
+// message given the MD5 and SHA1 hashes of a set of handshake messages.
+func finishedSum(md5, sha1, label, masterSecret []byte) []byte {
+       seed := make([]byte, len(md5)+len(sha1))
+       copy(seed, md5)
+       copy(seed[len(md5):], sha1)
+       out := make([]byte, finishedVerifyLength)
+       pRF11(out, masterSecret, label, seed)
+       return out
+}
+
+// clientSum returns the contents of the verify_data member of a client's
+// Finished message.
+func (h finishedHash) clientSum(masterSecret []byte) []byte {
+       md5 := h.clientMD5.Sum()
+       sha1 := h.clientSHA1.Sum()
+       return finishedSum(md5, sha1, clientFinishedLabel, masterSecret)
+}
+
+// serverSum returns the contents of the verify_data member of a server's
+// Finished message.
+func (h finishedHash) serverSum(masterSecret []byte) []byte {
+       md5 := h.serverMD5.Sum()
+       sha1 := h.serverSHA1.Sum()
+       return finishedSum(md5, sha1, serverFinishedLabel, masterSecret)
+}
diff --git a/libgo/go/crypto/tls/prf_test.go b/libgo/go/crypto/tls/prf_test.go
new file mode 100644 (file)
index 0000000..d99bab5
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+       "encoding/hex"
+       "testing"
+)
+
+type testSplitPreMasterSecretTest struct {
+       in, out1, out2 string
+}
+
+var testSplitPreMasterSecretTests = []testSplitPreMasterSecretTest{
+       {"", "", ""},
+       {"00", "00", "00"},
+       {"0011", "00", "11"},
+       {"001122", "0011", "1122"},
+       {"00112233", "0011", "2233"},
+}
+
+func TestSplitPreMasterSecret(t *testing.T) {
+       for i, test := range testSplitPreMasterSecretTests {
+               in, _ := hex.DecodeString(test.in)
+               out1, out2 := splitPreMasterSecret(in)
+               s1 := hex.EncodeToString(out1)
+               s2 := hex.EncodeToString(out2)
+               if s1 != test.out1 || s2 != test.out2 {
+                       t.Errorf("#%d: got: (%s, %s) want: (%s, %s)", i, s1, s2, test.out1, test.out2)
+               }
+       }
+}
+
+type testKeysFromTest struct {
+       preMasterSecret            string
+       clientRandom, serverRandom string
+       masterSecret               string
+       clientMAC, serverMAC       string
+       clientKey, serverKey       string
+       macLen, keyLen             int
+}
+
+func TestKeysFromPreMasterSecret(t *testing.T) {
+       for i, test := range testKeysFromTests {
+               in, _ := hex.DecodeString(test.preMasterSecret)
+               clientRandom, _ := hex.DecodeString(test.clientRandom)
+               serverRandom, _ := hex.DecodeString(test.serverRandom)
+               master, clientMAC, serverMAC, clientKey, serverKey := keysFromPreMasterSecret11(in, clientRandom, serverRandom, test.macLen, test.keyLen)
+               masterString := hex.EncodeToString(master)
+               clientMACString := hex.EncodeToString(clientMAC)
+               serverMACString := hex.EncodeToString(serverMAC)
+               clientKeyString := hex.EncodeToString(clientKey)
+               serverKeyString := hex.EncodeToString(serverKey)
+               if masterString != test.masterSecret ||
+                       clientMACString != test.clientMAC ||
+                       serverMACString != test.serverMAC ||
+                       clientKeyString != test.clientKey ||
+                       serverKeyString != test.serverKey {
+                       t.Errorf("#%d: got: (%s, %s, %s, %s, %s) want: (%s, %s, %s, %s %s)", i, masterString, clientMACString, serverMACString, clientKeyString, serverMACString, test.masterSecret, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey)
+               }
+       }
+}
+
+// These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
+var testKeysFromTests = []testKeysFromTest{
+       {
+               "0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
+               "4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
+               "4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
+               "3d851bab6e5556e959a16bc36d66cfae32f672bfa9ecdef6096cbb1b23472df1da63dbbd9827606413221d149ed08ceb",
+               "805aaa19b3d2c0a0759a4b6c9959890e08480119",
+               "2d22f9fe519c075c16448305ceee209fc24ad109",
+               "d50b5771244f850cd8117a9ccafe2cf1",
+               "e076e33206b30507a85c32855acd0919",
+               20,
+               16,
+       },
+       {
+               "03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
+               "4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
+               "4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
+               "7d64be7c80c59b740200b4b9c26d0baaa1c5ae56705acbcf2307fe62beb4728c19392c83f20483801cce022c77645460",
+               "97742ed60a0554ca13f04f97ee193177b971e3b0",
+               "37068751700400e03a8477a5c7eec0813ab9e0dc",
+               "207cddbc600d2a200abac6502053ee5c",
+               "df3f94f6e1eacc753b815fe16055cd43",
+               20,
+               16,
+       },
+       {
+               "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
+               "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
+               "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
+               "1aff2e7a2c4279d0126f57a65a77a8d9d0087cf2733366699bec27eb53d5740705a8574bb1acc2abbe90e44f0dd28d6c",
+               "3c7647c93c1379a31a609542aa44e7f117a70085",
+               "0d73102994be74a575a3ead8532590ca32a526d4",
+               "ac7581b0b6c10d85bbd905ffbf36c65e",
+               "ff07edde49682b45466bd2e39464b306",
+               20,
+               16,
+       },
+}
diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go
new file mode 100644 (file)
index 0000000..61f0a97
--- /dev/null
@@ -0,0 +1,137 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package partially implements the TLS 1.1 protocol, as specified in RFC 4346.
+package tls
+
+import (
+       "crypto/rsa"
+       "crypto/x509"
+       "encoding/pem"
+       "io/ioutil"
+       "net"
+       "os"
+       "strings"
+)
+
+func Server(conn net.Conn, config *Config) *Conn {
+       return &Conn{conn: conn, config: config}
+}
+
+func Client(conn net.Conn, config *Config) *Conn {
+       return &Conn{conn: conn, config: config, isClient: true}
+}
+
+type Listener struct {
+       listener net.Listener
+       config   *Config
+}
+
+func (l *Listener) Accept() (c net.Conn, err os.Error) {
+       c, err = l.listener.Accept()
+       if err != nil {
+               return
+       }
+       c = Server(c, l.config)
+       return
+}
+
+func (l *Listener) Close() os.Error { return l.listener.Close() }
+
+func (l *Listener) Addr() net.Addr { return l.listener.Addr() }
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with Server.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func NewListener(listener net.Listener, config *Config) (l *Listener) {
+       l = new(Listener)
+       l.listener = listener
+       l.config = config
+       return
+}
+
+func Listen(network, laddr string, config *Config) (net.Listener, os.Error) {
+       if config == nil || len(config.Certificates) == 0 {
+               return nil, os.NewError("tls.Listen: no certificates in configuration")
+       }
+       l, err := net.Listen(network, laddr)
+       if err != nil {
+               return nil, err
+       }
+       return NewListener(l, config), nil
+}
+
+func Dial(network, laddr, raddr string) (net.Conn, os.Error) {
+       c, err := net.Dial(network, laddr, raddr)
+       if err != nil {
+               return nil, err
+       }
+
+       colonPos := strings.LastIndex(raddr, ":")
+       if colonPos == -1 {
+               colonPos = len(raddr)
+       }
+       hostname := raddr[:colonPos]
+
+       config := defaultConfig()
+       config.ServerName = hostname
+       conn := Client(c, config)
+       err = conn.Handshake()
+       if err == nil {
+               return conn, nil
+       }
+       c.Close()
+       return nil, err
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair of
+// files. The files must contain PEM encoded data.
+func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.Error) {
+       certPEMBlock, err := ioutil.ReadFile(certFile)
+       if err != nil {
+               return
+       }
+
+       certDERBlock, _ := pem.Decode(certPEMBlock)
+       if certDERBlock == nil {
+               err = os.ErrorString("crypto/tls: failed to parse certificate PEM data")
+               return
+       }
+
+       cert.Certificate = [][]byte{certDERBlock.Bytes}
+
+       keyPEMBlock, err := ioutil.ReadFile(keyFile)
+       if err != nil {
+               return
+       }
+
+       keyDERBlock, _ := pem.Decode(keyPEMBlock)
+       if keyDERBlock == nil {
+               err = os.ErrorString("crypto/tls: failed to parse key PEM data")
+               return
+       }
+
+       key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
+       if err != nil {
+               err = os.ErrorString("crypto/tls: failed to parse key")
+               return
+       }
+
+       cert.PrivateKey = key
+
+       // We don't need to parse the public key for TLS, but we so do anyway
+       // to check that it looks sane and matches the private key.
+       x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes)
+       if err != nil {
+               return
+       }
+
+       if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 {
+               err = os.ErrorString("crypto/tls: private key does not match public key")
+               return
+       }
+
+       return
+}
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
new file mode 100644 (file)
index 0000000..b7a527c
--- /dev/null
@@ -0,0 +1,831 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package parses X.509-encoded keys and certificates.
+package x509
+
+import (
+       "asn1"
+       "big"
+       "container/vector"
+       "crypto/rsa"
+       "crypto/sha1"
+       "hash"
+       "io"
+       "os"
+       "strings"
+       "time"
+)
+
+// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
+type pkcs1PrivateKey struct {
+       Version int
+       N       asn1.RawValue
+       E       int
+       D       asn1.RawValue
+       P       asn1.RawValue
+       Q       asn1.RawValue
+}
+
+// rawValueIsInteger returns true iff the given ASN.1 RawValue is an INTEGER type.
+func rawValueIsInteger(raw *asn1.RawValue) bool {
+       return raw.Class == 0 && raw.Tag == 2 && raw.IsCompound == false
+}
+
+// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
+func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
+       var priv pkcs1PrivateKey
+       rest, err := asn1.Unmarshal(der, &priv)
+       if len(rest) > 0 {
+               err = asn1.SyntaxError{"trailing data"}
+               return
+       }
+       if err != nil {
+               return
+       }
+
+       if !rawValueIsInteger(&priv.N) ||
+               !rawValueIsInteger(&priv.D) ||
+               !rawValueIsInteger(&priv.P) ||
+               !rawValueIsInteger(&priv.Q) {
+               err = asn1.StructuralError{"tags don't match"}
+               return
+       }
+
+       key = &rsa.PrivateKey{
+               PublicKey: rsa.PublicKey{
+                       E: priv.E,
+                       N: new(big.Int).SetBytes(priv.N.Bytes),
+               },
+               D: new(big.Int).SetBytes(priv.D.Bytes),
+               P: new(big.Int).SetBytes(priv.P.Bytes),
+               Q: new(big.Int).SetBytes(priv.Q.Bytes),
+       }
+
+       err = key.Validate()
+       if err != nil {
+               return nil, err
+       }
+       return
+}
+
+// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
+func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
+       priv := pkcs1PrivateKey{
+               Version: 1,
+               N:       asn1.RawValue{Tag: 2, Bytes: key.PublicKey.N.Bytes()},
+               E:       key.PublicKey.E,
+               D:       asn1.RawValue{Tag: 2, Bytes: key.D.Bytes()},
+               P:       asn1.RawValue{Tag: 2, Bytes: key.P.Bytes()},
+               Q:       asn1.RawValue{Tag: 2, Bytes: key.Q.Bytes()},
+       }
+
+       b, _ := asn1.Marshal(priv)
+       return b
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificates.:
+
+type certificate struct {
+       TBSCertificate     tbsCertificate
+       SignatureAlgorithm algorithmIdentifier
+       SignatureValue     asn1.BitString
+}
+
+type tbsCertificate struct {
+       Raw                asn1.RawContent
+       Version            int "optional,explicit,default:1,tag:0"
+       SerialNumber       asn1.RawValue
+       SignatureAlgorithm algorithmIdentifier
+       Issuer             rdnSequence
+       Validity           validity
+       Subject            rdnSequence
+       PublicKey          publicKeyInfo
+       UniqueId           asn1.BitString "optional,tag:1"
+       SubjectUniqueId    asn1.BitString "optional,tag:2"
+       Extensions         []extension    "optional,explicit,tag:3"
+}
+
+type algorithmIdentifier struct {
+       Algorithm asn1.ObjectIdentifier
+}
+
+type rdnSequence []relativeDistinguishedNameSET
+
+type relativeDistinguishedNameSET []attributeTypeAndValue
+
+type attributeTypeAndValue struct {
+       Type  asn1.ObjectIdentifier
+       Value interface{}
+}
+
+type validity struct {
+       NotBefore, NotAfter *time.Time
+}
+
+type publicKeyInfo struct {
+       Algorithm algorithmIdentifier
+       PublicKey asn1.BitString
+}
+
+type extension struct {
+       Id       asn1.ObjectIdentifier
+       Critical bool "optional"
+       Value    []byte
+}
+
+// RFC 5280,  4.2.1.1
+type authKeyId struct {
+       Id []byte "optional,tag:0"
+}
+
+type SignatureAlgorithm int
+
+const (
+       UnknownSignatureAlgorithm SignatureAlgorithm = iota
+       MD2WithRSA
+       MD5WithRSA
+       SHA1WithRSA
+       SHA256WithRSA
+       SHA384WithRSA
+       SHA512WithRSA
+)
+
+type PublicKeyAlgorithm int
+
+const (
+       UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
+       RSA
+)
+
+// Name represents an X.509 distinguished name. This only includes the common
+// elements of a DN.  Additional elements in the name are ignored.
+type Name struct {
+       Country, Organization, OrganizationalUnit []string
+       Locality, Province                        []string
+       StreetAddress, PostalCode                 []string
+       SerialNumber, CommonName                  string
+}
+
+func (n *Name) fillFromRDNSequence(rdns *rdnSequence) {
+       for _, rdn := range *rdns {
+               if len(rdn) == 0 {
+                       continue
+               }
+               atv := rdn[0]
+               value, ok := atv.Value.(string)
+               if !ok {
+                       continue
+               }
+
+               t := atv.Type
+               if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+                       switch t[3] {
+                       case 3:
+                               n.CommonName = value
+                       case 5:
+                               n.SerialNumber = value
+                       case 6:
+                               n.Country = append(n.Country, value)
+                       case 7:
+                               n.Locality = append(n.Locality, value)
+                       case 8:
+                               n.Province = append(n.Province, value)
+                       case 9:
+                               n.StreetAddress = append(n.StreetAddress, value)
+                       case 10:
+                               n.Organization = append(n.Organization, value)
+                       case 11:
+                               n.OrganizationalUnit = append(n.OrganizationalUnit, value)
+                       case 17:
+                               n.PostalCode = append(n.PostalCode, value)
+                       }
+               }
+       }
+}
+
+var (
+       oidCountry            = []int{2, 5, 4, 6}
+       oidOrganization       = []int{2, 5, 4, 10}
+       oidOrganizationalUnit = []int{2, 5, 4, 11}
+       oidCommonName         = []int{2, 5, 4, 3}
+       oidSerialNumber       = []int{2, 5, 4, 5}
+       oidLocatity           = []int{2, 5, 4, 7}
+       oidProvince           = []int{2, 5, 4, 8}
+       oidStreetAddress      = []int{2, 5, 4, 9}
+       oidPostalCode         = []int{2, 5, 4, 17}
+)
+
+func (n Name) toRDNSequence() (ret rdnSequence) {
+       ret = make([]relativeDistinguishedNameSET, 9 /* maximum number of elements */ )
+       i := 0
+       if len(n.Country) > 0 {
+               ret[i] = []attributeTypeAndValue{{oidCountry, n.Country}}
+               i++
+       }
+       if len(n.Organization) > 0 {
+               ret[i] = []attributeTypeAndValue{{oidOrganization, n.Organization}}
+               i++
+       }
+       if len(n.OrganizationalUnit) > 0 {
+               ret[i] = []attributeTypeAndValue{{oidOrganizationalUnit, n.OrganizationalUnit}}
+               i++
+       }
+       if len(n.CommonName) > 0 {
+               ret[i] = []attributeTypeAndValue{{oidCommonName, n.CommonName}}
+               i++
+       }
+       if len(n.SerialNumber) > 0 {
+               ret[i] = []attributeTypeAndValue{{oidSerialNumber, n.SerialNumber}}
+               i++
+       }
+       if len(n.Locality) > 0 {
+               ret[i] = []attributeTypeAndValue{{oidLocatity, n.Locality}}
+               i++
+       }
+       if len(n.Province) > 0 {
+               ret[i] = []attributeTypeAndValue{{oidProvince, n.Province}}
+               i++
+       }
+       if len(n.StreetAddress) > 0 {
+               ret[i] = []attributeTypeAndValue{{oidStreetAddress, n.StreetAddress}}
+               i++
+       }
+       if len(n.PostalCode) > 0 {
+               ret[i] = []attributeTypeAndValue{{oidPostalCode, n.PostalCode}}
+               i++
+       }
+
+       // Adding another RDN here? Remember to update the maximum number of
+       // elements in the make() at the top of the function.
+
+       return ret[0:i]
+}
+
+func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm {
+       if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 &&
+               oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 {
+               switch oid[6] {
+               case 2:
+                       return MD2WithRSA
+               case 4:
+                       return MD5WithRSA
+               case 5:
+                       return SHA1WithRSA
+               case 11:
+                       return SHA256WithRSA
+               case 12:
+                       return SHA384WithRSA
+               case 13:
+                       return SHA512WithRSA
+               }
+       }
+
+       return UnknownSignatureAlgorithm
+}
+
+func getPublicKeyAlgorithmFromOID(oid []int) PublicKeyAlgorithm {
+       if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 &&
+               oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 {
+               switch oid[6] {
+               case 1:
+                       return RSA
+               }
+       }
+
+       return UnknownPublicKeyAlgorithm
+}
+
+// KeyUsage represents the set of actions that are valid for a given key. It's
+// a bitmap of the KeyUsage* constants.
+type KeyUsage int
+
+const (
+       KeyUsageDigitalSignature KeyUsage = 1 << iota
+       KeyUsageContentCommitment
+       KeyUsageKeyEncipherment
+       KeyUsageDataEncipherment
+       KeyUsageKeyAgreement
+       KeyUsageCertSign
+       KeyUsageCRLSign
+       KeyUsageEncipherOnly
+       KeyUsageDecipherOnly
+)
+
+// A Certificate represents an X.509 certificate.
+type Certificate struct {
+       Raw                []byte // Raw ASN.1 DER contents.
+       Signature          []byte
+       SignatureAlgorithm SignatureAlgorithm
+
+       PublicKeyAlgorithm PublicKeyAlgorithm
+       PublicKey          interface{}
+
+       Version             int
+       SerialNumber        []byte
+       Issuer              Name
+       Subject             Name
+       NotBefore, NotAfter *time.Time // Validity bounds.
+       KeyUsage            KeyUsage
+
+       BasicConstraintsValid bool // if true then the next two fields are valid.
+       IsCA                  bool
+       MaxPathLen            int
+
+       SubjectKeyId   []byte
+       AuthorityKeyId []byte
+
+       // Subject Alternate Name values
+       DNSNames       []string
+       EmailAddresses []string
+}
+
+// UnsupportedAlgorithmError results from attempting to perform an operation
+// that involves algorithms that are not currently implemented.
+type UnsupportedAlgorithmError struct{}
+
+func (UnsupportedAlgorithmError) String() string {
+       return "cannot verify signature: algorithm unimplemented"
+}
+
+// ConstraintViolationError results when a requested usage is not permitted by
+// a certificate. For example: checking a signature when the public key isn't a
+// certificate signing key.
+type ConstraintViolationError struct{}
+
+func (ConstraintViolationError) String() string {
+       return "invalid signature: parent certificate cannot sign this kind of certificate"
+}
+
+// CheckSignatureFrom verifies that the signature on c is a valid signature
+// from parent.
+func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) {
+       // RFC 5280, 4.2.1.9:
+       // "If the basic constraints extension is not present in a version 3
+       // certificate, or the extension is present but the cA boolean is not
+       // asserted, then the certified public key MUST NOT be used to verify
+       // certificate signatures."
+       if parent.Version == 3 && !parent.BasicConstraintsValid ||
+               parent.BasicConstraintsValid && !parent.IsCA {
+               return ConstraintViolationError{}
+       }
+
+       if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 {
+               return ConstraintViolationError{}
+       }
+
+       if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
+               return UnsupportedAlgorithmError{}
+       }
+
+       // TODO(agl): don't ignore the path length constraint.
+
+       var h hash.Hash
+       var hashType rsa.PKCS1v15Hash
+
+       switch c.SignatureAlgorithm {
+       case SHA1WithRSA:
+               h = sha1.New()
+               hashType = rsa.HashSHA1
+       default:
+               return UnsupportedAlgorithmError{}
+       }
+
+       pub, ok := parent.PublicKey.(*rsa.PublicKey)
+       if !ok {
+               return UnsupportedAlgorithmError{}
+       }
+
+       h.Write(c.Raw)
+       digest := h.Sum()
+
+       return rsa.VerifyPKCS1v15(pub, hashType, digest, c.Signature)
+}
+
+func matchHostnames(pattern, host string) bool {
+       if len(pattern) == 0 || len(host) == 0 {
+               return false
+       }
+
+       patternParts := strings.Split(pattern, ".", -1)
+       hostParts := strings.Split(host, ".", -1)
+
+       if len(patternParts) != len(hostParts) {
+               return false
+       }
+
+       for i, patternPart := range patternParts {
+               if patternPart == "*" {
+                       continue
+               }
+               if patternPart != hostParts[i] {
+                       return false
+               }
+       }
+
+       return true
+}
+
+type HostnameError struct {
+       Certificate *Certificate
+       Host        string
+}
+
+func (h *HostnameError) String() string {
+       var valid string
+       c := h.Certificate
+       if len(c.DNSNames) > 0 {
+               valid = strings.Join(c.DNSNames, ", ")
+       } else {
+               valid = c.Subject.CommonName
+       }
+       return "certificate is valid for " + valid + ", not " + h.Host
+}
+
+// VerifyHostname returns nil if c is a valid certificate for the named host.
+// Otherwise it returns an os.Error describing the mismatch.
+func (c *Certificate) VerifyHostname(h string) os.Error {
+       if len(c.DNSNames) > 0 {
+               for _, match := range c.DNSNames {
+                       if matchHostnames(match, h) {
+                               return nil
+                       }
+               }
+               // If Subject Alt Name is given, we ignore the common name.
+       } else if matchHostnames(c.Subject.CommonName, h) {
+               return nil
+       }
+
+       return &HostnameError{c, h}
+}
+
+type UnhandledCriticalExtension struct{}
+
+func (h UnhandledCriticalExtension) String() string {
+       return "unhandled critical extension"
+}
+
+type basicConstraints struct {
+       IsCA       bool "optional"
+       MaxPathLen int  "optional"
+}
+
+type rsaPublicKey struct {
+       N asn1.RawValue
+       E int
+}
+
+func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) {
+       switch algo {
+       case RSA:
+               p := new(rsaPublicKey)
+               _, err := asn1.Unmarshal(asn1Data, p)
+               if err != nil {
+                       return nil, err
+               }
+
+               if !rawValueIsInteger(&p.N) {
+                       return nil, asn1.StructuralError{"tags don't match"}
+               }
+
+               pub := &rsa.PublicKey{
+                       E: p.E,
+                       N: new(big.Int).SetBytes(p.N.Bytes),
+               }
+               return pub, nil
+       default:
+               return nil, nil
+       }
+
+       panic("unreachable")
+}
+
+func parseCertificate(in *certificate) (*Certificate, os.Error) {
+       out := new(Certificate)
+       out.Raw = in.TBSCertificate.Raw
+
+       out.Signature = in.SignatureValue.RightAlign()
+       out.SignatureAlgorithm =
+               getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm)
+
+       out.PublicKeyAlgorithm =
+               getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
+       var err os.Error
+       out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, in.TBSCertificate.PublicKey.PublicKey.RightAlign())
+       if err != nil {
+               return nil, err
+       }
+
+       out.Version = in.TBSCertificate.Version
+       out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes
+       out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer)
+       out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject)
+       out.NotBefore = in.TBSCertificate.Validity.NotBefore
+       out.NotAfter = in.TBSCertificate.Validity.NotAfter
+
+       for _, e := range in.TBSCertificate.Extensions {
+               if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
+                       switch e.Id[3] {
+                       case 15:
+                               // RFC 5280, 4.2.1.3
+                               var usageBits asn1.BitString
+                               _, err := asn1.Unmarshal(e.Value, &usageBits)
+
+                               if err == nil {
+                                       var usage int
+                                       for i := 0; i < 9; i++ {
+                                               if usageBits.At(i) != 0 {
+                                                       usage |= 1 << uint(i)
+                                               }
+                                       }
+                                       out.KeyUsage = KeyUsage(usage)
+                                       continue
+                               }
+                       case 19:
+                               // RFC 5280, 4.2.1.9
+                               var constriants basicConstraints
+                               _, err := asn1.Unmarshal(e.Value, &constriants)
+
+                               if err == nil {
+                                       out.BasicConstraintsValid = true
+                                       out.IsCA = constriants.IsCA
+                                       out.MaxPathLen = constriants.MaxPathLen
+                                       continue
+                               }
+                       case 17:
+                               // RFC 5280, 4.2.1.6
+
+                               // SubjectAltName ::= GeneralNames
+                               //
+                               // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+                               //
+                               // GeneralName ::= CHOICE {
+                               //      otherName                       [0]     OtherName,
+                               //      rfc822Name                      [1]     IA5String,
+                               //      dNSName                         [2]     IA5String,
+                               //      x400Address                     [3]     ORAddress,
+                               //      directoryName                   [4]     Name,
+                               //      ediPartyName                    [5]     EDIPartyName,
+                               //      uniformResourceIdentifier       [6]     IA5String,
+                               //      iPAddress                       [7]     OCTET STRING,
+                               //      registeredID                    [8]     OBJECT IDENTIFIER }
+                               var seq asn1.RawValue
+                               _, err := asn1.Unmarshal(e.Value, &seq)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
+                                       return nil, asn1.StructuralError{"bad SAN sequence"}
+                               }
+
+                               parsedName := false
+
+                               rest := seq.Bytes
+                               for len(rest) > 0 {
+                                       var v asn1.RawValue
+                                       rest, err = asn1.Unmarshal(rest, &v)
+                                       if err != nil {
+                                               return nil, err
+                                       }
+                                       switch v.Tag {
+                                       case 1:
+                                               out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes))
+                                               parsedName = true
+                                       case 2:
+                                               out.DNSNames = append(out.DNSNames, string(v.Bytes))
+                                               parsedName = true
+                                       }
+                               }
+
+                               if parsedName {
+                                       continue
+                               }
+                               // If we didn't parse any of the names then we
+                               // fall through to the critical check below.
+
+                       case 35:
+                               // RFC 5280, 4.2.1.1
+                               var a authKeyId
+                               _, err = asn1.Unmarshal(e.Value, &a)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               out.AuthorityKeyId = a.Id
+                               continue
+
+                       case 14:
+                               // RFC 5280, 4.2.1.2
+                               var keyid []byte
+                               _, err = asn1.Unmarshal(e.Value, &keyid)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               out.SubjectKeyId = keyid
+                               continue
+                       }
+               }
+
+               if e.Critical {
+                       return out, UnhandledCriticalExtension{}
+               }
+       }
+
+       return out, nil
+}
+
+// ParseCertificate parses a single certificate from the given ASN.1 DER data.
+func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) {
+       var cert certificate
+       rest, err := asn1.Unmarshal(asn1Data, &cert)
+       if err != nil {
+               return nil, err
+       }
+       if len(rest) > 0 {
+               return nil, asn1.SyntaxError{"trailing data"}
+       }
+
+       return parseCertificate(&cert)
+}
+
+// ParseCertificates parses one or more certificates from the given ASN.1 DER
+// data. The certificates must be concatenated with no intermediate padding.
+func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
+       v := new(vector.Vector)
+
+       for len(asn1Data) > 0 {
+               cert := new(certificate)
+               var err os.Error
+               asn1Data, err = asn1.Unmarshal(asn1Data, cert)
+               if err != nil {
+                       return nil, err
+               }
+               v.Push(cert)
+       }
+
+       ret := make([]*Certificate, v.Len())
+       for i := 0; i < v.Len(); i++ {
+               cert, err := parseCertificate(v.At(i).(*certificate))
+               if err != nil {
+                       return nil, err
+               }
+               ret[i] = cert
+       }
+
+       return ret, nil
+}
+
+func reverseBitsInAByte(in byte) byte {
+       b1 := in>>4 | in<<4
+       b2 := b1>>2&0x33 | b1<<2&0xcc
+       b3 := b2>>1&0x55 | b2<<1&0xaa
+       return b3
+}
+
+var (
+       oidExtensionSubjectKeyId     = []int{2, 5, 29, 14}
+       oidExtensionKeyUsage         = []int{2, 5, 29, 15}
+       oidExtensionAuthorityKeyId   = []int{2, 5, 29, 35}
+       oidExtensionBasicConstraints = []int{2, 5, 29, 19}
+       oidExtensionSubjectAltName   = []int{2, 5, 29, 17}
+)
+
+func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
+       ret = make([]extension, 5 /* maximum number of elements. */ )
+       n := 0
+
+       if template.KeyUsage != 0 {
+               ret[n].Id = oidExtensionKeyUsage
+               ret[n].Critical = true
+
+               var a [2]byte
+               a[0] = reverseBitsInAByte(byte(template.KeyUsage))
+               a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8))
+
+               l := 1
+               if a[1] != 0 {
+                       l = 2
+               }
+
+               ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8})
+               if err != nil {
+                       return
+               }
+               n++
+       }
+
+       if template.BasicConstraintsValid {
+               ret[n].Id = oidExtensionBasicConstraints
+               ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen})
+               ret[n].Critical = true
+               if err != nil {
+                       return
+               }
+               n++
+       }
+
+       if len(template.SubjectKeyId) > 0 {
+               ret[n].Id = oidExtensionSubjectKeyId
+               ret[n].Value, err = asn1.Marshal(template.SubjectKeyId)
+               if err != nil {
+                       return
+               }
+               n++
+       }
+
+       if len(template.AuthorityKeyId) > 0 {
+               ret[n].Id = oidExtensionAuthorityKeyId
+               ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId})
+               if err != nil {
+                       return
+               }
+               n++
+       }
+
+       if len(template.DNSNames) > 0 {
+               ret[n].Id = oidExtensionSubjectAltName
+               rawValues := make([]asn1.RawValue, len(template.DNSNames))
+               for i, name := range template.DNSNames {
+                       rawValues[i] = asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)}
+               }
+               ret[n].Value, err = asn1.Marshal(rawValues)
+               if err != nil {
+                       return
+               }
+               n++
+       }
+
+       // Adding another extension here? Remember to update the maximum number
+       // of elements in the make() at the top of the function.
+
+       return ret[0:n], nil
+}
+
+var (
+       oidSHA1WithRSA = []int{1, 2, 840, 113549, 1, 1, 5}
+       oidRSA         = []int{1, 2, 840, 113549, 1, 1, 1}
+)
+
+// CreateSelfSignedCertificate creates a new certificate based on
+// a template. The following members of template are used: SerialNumber,
+// Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA,
+// MaxPathLen, SubjectKeyId, DNSNames.
+//
+// The certificate is signed by parent. If parent is equal to template then the
+// certificate is self-signed. The parameter pub is the public key of the
+// signee and priv is the private key of the signer.
+//
+// The returned slice is the certificate in DER encoding.
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) {
+       asn1PublicKey, err := asn1.Marshal(rsaPublicKey{
+               N: asn1.RawValue{Tag: 2, Bytes: pub.N.Bytes()},
+               E: pub.E,
+       })
+       if err != nil {
+               return
+       }
+
+       if len(parent.SubjectKeyId) > 0 {
+               template.AuthorityKeyId = parent.SubjectKeyId
+       }
+
+       extensions, err := buildExtensions(template)
+       if err != nil {
+               return
+       }
+
+       encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
+       c := tbsCertificate{
+               Version:            3,
+               SerialNumber:       asn1.RawValue{Bytes: template.SerialNumber, Tag: 2},
+               SignatureAlgorithm: algorithmIdentifier{oidSHA1WithRSA},
+               Issuer:             parent.Subject.toRDNSequence(),
+               Validity:           validity{template.NotBefore, template.NotAfter},
+               Subject:            template.Subject.toRDNSequence(),
+               PublicKey:          publicKeyInfo{algorithmIdentifier{oidRSA}, encodedPublicKey},
+               Extensions:         extensions,
+       }
+
+       tbsCertContents, err := asn1.Marshal(c)
+       if err != nil {
+               return
+       }
+
+       c.Raw = tbsCertContents
+
+       h := sha1.New()
+       h.Write(tbsCertContents)
+       digest := h.Sum()
+
+       signature, err := rsa.SignPKCS1v15(rand, priv, rsa.HashSHA1, digest)
+       if err != nil {
+               return
+       }
+
+       cert, err = asn1.Marshal(certificate{
+               c,
+               algorithmIdentifier{oidSHA1WithRSA},
+               asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+       })
+       return
+}
diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go
new file mode 100644 (file)
index 0000000..f667741
--- /dev/null
@@ -0,0 +1,190 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+       "big"
+       "crypto/rand"
+       "crypto/rsa"
+       "encoding/hex"
+       "encoding/pem"
+       "reflect"
+       "testing"
+       "time"
+)
+
+func TestParsePKCS1PrivateKey(t *testing.T) {
+       block, _ := pem.Decode([]byte(pemPrivateKey))
+       priv, err := ParsePKCS1PrivateKey(block.Bytes)
+       if err != nil {
+               t.Errorf("Failed to parse private key: %s", err)
+       }
+       if !reflect.DeepEqual(priv, rsaPrivateKey) {
+               t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey)
+       }
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA PRIVATE KEY-----
+`
+
+func bigFromString(s string) *big.Int {
+       ret := new(big.Int)
+       ret.SetString(s, 10)
+       return ret
+}
+
+var rsaPrivateKey = &rsa.PrivateKey{
+       PublicKey: rsa.PublicKey{
+               N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
+               E: 65537,
+       },
+       D: bigFromString("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"),
+       P: bigFromString("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
+       Q: bigFromString("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
+}
+
+type matchHostnamesTest struct {
+       pattern, host string
+       ok            bool
+}
+
+var matchHostnamesTests = []matchHostnamesTest{
+       {"a.b.c", "a.b.c", true},
+       {"a.b.c", "b.b.c", false},
+       {"", "b.b.c", false},
+       {"a.b.c", "", false},
+       {"example.com", "example.com", true},
+       {"example.com", "www.example.com", false},
+       {"*.example.com", "www.example.com", true},
+       {"*.example.com", "xyz.www.example.com", false},
+       {"*.*.example.com", "xyz.www.example.com", true},
+       {"*.www.*.com", "xyz.www.example.com", true},
+}
+
+func TestMatchHostnames(t *testing.T) {
+       for i, test := range matchHostnamesTests {
+               r := matchHostnames(test.pattern, test.host)
+               if r != test.ok {
+                       t.Errorf("#%d mismatch got: %t want: %t", i, r, test.ok)
+               }
+       }
+}
+
+func TestCertificateParse(t *testing.T) {
+       s, _ := hex.DecodeString(certBytes)
+       certs, err := ParseCertificates(s)
+       if err != nil {
+               t.Error(err)
+       }
+       if len(certs) != 2 {
+               t.Errorf("Wrong number of certs: got %d want 2", len(certs))
+               return
+       }
+
+       err = certs[0].CheckSignatureFrom(certs[1])
+       if err != nil {
+               t.Error(err)
+       }
+
+       if err := certs[0].VerifyHostname("mail.google.com"); err != nil {
+               t.Error(err)
+       }
+}
+
+var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be1300d06092a864886" +
+       "f70d0101050500304c310b3009060355040613025a4131253023060355040a131c546861777465" +
+       "20436f6e73756c74696e67202850747929204c74642e311630140603550403130d546861777465" +
+       "20534743204341301e170d3039303332353136343932395a170d3130303332353136343932395a" +
+       "3069310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630" +
+       "140603550407130d4d6f756e7461696e205669657731133011060355040a130a476f6f676c6520" +
+       "496e63311830160603550403130f6d61696c2e676f6f676c652e636f6d30819f300d06092a8648" +
+       "86f70d010101050003818d0030818902818100c5d6f892fccaf5614b064149e80a2c9581a218ef" +
+       "41ec35bd7a58125ae76f9ea54ddc893abbeb029f6b73616bf0ffd868791fba7af9c4aebf3706ba" +
+       "3eeaeed27435b4ddcfb157c05f351d66aa87fee0de072d66d773affbd36ab78bef090e0cc861a9" +
+       "03ac90dd98b51c9c41566c017f0beec3bff391051ffba0f5cc6850ad2a590203010001a381e730" +
+       "81e430280603551d250421301f06082b0601050507030106082b06010505070302060960864801" +
+       "86f842040130360603551d1f042f302d302ba029a0278625687474703a2f2f63726c2e74686177" +
+       "74652e636f6d2f54686177746553474343412e63726c307206082b060105050701010466306430" +
+       "2206082b060105050730018616687474703a2f2f6f6373702e7468617774652e636f6d303e0608" +
+       "2b060105050730028632687474703a2f2f7777772e7468617774652e636f6d2f7265706f736974" +
+       "6f72792f5468617774655f5347435f43412e637274300c0603551d130101ff04023000300d0609" +
+       "2a864886f70d01010505000381810062f1f3050ebc105e497c7aedf87e24d2f4a986bb3b837bd1" +
+       "9b91ebcad98b065992f6bd2b49b7d6d3cb2e427a99d606c7b1d46352527fac39e6a8b6726de5bf" +
+       "70212a52cba07634a5e332011bd1868e78eb5e3c93cf03072276786f207494feaa0ed9d53b2110" +
+       "a76571f90209cdae884385c882587030ee15f33d761e2e45a6bc308203233082028ca003020102" +
+       "020430000002300d06092a864886f70d0101050500305f310b3009060355040613025553311730" +
+       "15060355040a130e566572695369676e2c20496e632e31373035060355040b132e436c61737320" +
+       "33205075626c6963205072696d6172792043657274696669636174696f6e20417574686f726974" +
+       "79301e170d3034303531333030303030305a170d3134303531323233353935395a304c310b3009" +
+       "060355040613025a4131253023060355040a131c54686177746520436f6e73756c74696e672028" +
+       "50747929204c74642e311630140603550403130d5468617774652053474320434130819f300d06" +
+       "092a864886f70d010101050003818d0030818902818100d4d367d08d157faecd31fe7d1d91a13f" +
+       "0b713cacccc864fb63fc324b0794bd6f80ba2fe10493c033fc093323e90b742b71c403c6d2cde2" +
+       "2ff50963cdff48a500bfe0e7f388b72d32de9836e60aad007bc4644a3b847503f270927d0e62f5" +
+       "21ab693684317590f8bfc76c881b06957cc9e5a8de75a12c7a68dfd5ca1c875860190203010001" +
+       "a381fe3081fb30120603551d130101ff040830060101ff020100300b0603551d0f040403020106" +
+       "301106096086480186f842010104040302010630280603551d110421301fa41d301b3119301706" +
+       "035504031310507269766174654c6162656c332d313530310603551d1f042a30283026a024a022" +
+       "8620687474703a2f2f63726c2e766572697369676e2e636f6d2f706361332e63726c303206082b" +
+       "0601050507010104263024302206082b060105050730018616687474703a2f2f6f6373702e7468" +
+       "617774652e636f6d30340603551d25042d302b06082b0601050507030106082b06010505070302" +
+       "06096086480186f8420401060a6086480186f845010801300d06092a864886f70d010105050003" +
+       "81810055ac63eadea1ddd2905f9f0bce76be13518f93d9052bc81b774bad6950a1eededcfddb07" +
+       "e9e83994dcab72792f06bfab8170c4a8edea5334edef1e53d906c7562bd15cf4d18a8eb42bb137" +
+       "9048084225c53e8acb7feb6f04d16dc574a2f7a27c7b603c77cd0ece48027f012fb69b37e02a2a" +
+       "36dcd585d6ace53f546f961e05af"
+
+func TestCreateSelfSignedCertificate(t *testing.T) {
+       random := rand.Reader
+
+       block, _ := pem.Decode([]byte(pemPrivateKey))
+       priv, err := ParsePKCS1PrivateKey(block.Bytes)
+       if err != nil {
+               t.Errorf("Failed to parse private key: %s", err)
+               return
+       }
+
+       template := Certificate{
+               SerialNumber: []byte{1},
+               Subject: Name{
+                       CommonName:   "test.example.com",
+                       Organization: []string{"Acme Co"},
+               },
+               NotBefore: time.SecondsToUTC(1000),
+               NotAfter:  time.SecondsToUTC(100000),
+
+               SubjectKeyId: []byte{1, 2, 3, 4},
+               KeyUsage:     KeyUsageCertSign,
+
+               BasicConstraintsValid: true,
+               IsCA:                  true,
+               DNSNames:              []string{"test.example.com"},
+       }
+
+       derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv)
+       if err != nil {
+               t.Errorf("Failed to create certificate: %s", err)
+               return
+       }
+
+       cert, err := ParseCertificate(derBytes)
+       if err != nil {
+               t.Errorf("Failed to parse certificate: %s", err)
+               return
+       }
+       err = cert.CheckSignatureFrom(cert)
+       if err != nil {
+               t.Errorf("Signature verification failed: %s", err)
+               return
+       }
+}
diff --git a/libgo/go/crypto/xtea/block.go b/libgo/go/crypto/xtea/block.go
new file mode 100644 (file)
index 0000000..3ac36d0
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+       Implementation adapted from Needham and Wheeler's paper:
+       http://www.cix.co.uk/~klockstone/xtea.pdf
+
+       A precalculated look up table is used during encryption/decryption for values that are based purely on the key.
+*/
+
+package xtea
+
+// XTEA is based on 64 rounds.
+const numRounds = 64
+
+// blockToUint32 reads an 8 byte slice into two uint32s.
+// The block is treated as big endian.
+func blockToUint32(src []byte) (uint32, uint32) {
+       r0 := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+       r1 := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+       return r0, r1
+}
+
+// uint32ToBlock writes two unint32s into an 8 byte data block.
+// Values are written as big endian.
+func uint32ToBlock(v0, v1 uint32, dst []byte) {
+       dst[0] = byte(v0 >> 24)
+       dst[1] = byte(v0 >> 16)
+       dst[2] = byte(v0 >> 8)
+       dst[3] = byte(v0)
+       dst[4] = byte(v1 >> 24)
+       dst[5] = byte(v1 >> 16)
+       dst[6] = byte(v1 >> 8)
+       dst[7] = byte(v1 >> 0)
+}
+
+// encryptBlock encrypts a single 8 byte block using XTEA.
+func encryptBlock(c *Cipher, dst, src []byte) {
+       v0, v1 := blockToUint32(src)
+
+       // Two rounds of XTEA applied per loop
+       for i := 0; i < numRounds; {
+               v0 += ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
+               i++
+               v1 += ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
+               i++
+       }
+
+       uint32ToBlock(v0, v1, dst)
+}
+
+// decryptBlock decrypt a single 8 byte block using XTEA.
+func decryptBlock(c *Cipher, dst, src []byte) {
+       v0, v1 := blockToUint32(src)
+
+       // Two rounds of XTEA applied per loop
+       for i := numRounds; i > 0; {
+               i--
+               v1 -= ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
+               i--
+               v0 -= ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
+       }
+
+       uint32ToBlock(v0, v1, dst)
+}
diff --git a/libgo/go/crypto/xtea/cipher.go b/libgo/go/crypto/xtea/cipher.go
new file mode 100644 (file)
index 0000000..b0fa2a1
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements XTEA encryption, as defined in Needham and
+// Wheeler's 1997 technical report, "Tea extensions."
+package xtea
+
+// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf
+
+import (
+       "os"
+       "strconv"
+)
+
+// The XTEA block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of an XTEA cipher using a particular key.
+// table contains a series of precalculated values that are used each round.
+type Cipher struct {
+       table [64]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+       return "crypto/xtea: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher.
+// The key argument should be the XTEA key.
+// XTEA only supports 128 bit (16 byte) keys.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+       k := len(key)
+       switch k {
+       default:
+               return nil, KeySizeError(k)
+       case 16:
+               break
+       }
+
+       c := new(Cipher)
+       initCipher(c, key)
+
+       return c, nil
+}
+
+// BlockSize returns the XTEA block size, 8 bytes.
+// It is necessary to satisfy the Cipher interface in the
+// package "crypto/block".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8 byte buffer src using the key and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c, dst, src) }
+
+// Decrypt decrypts the 8 byte buffer src using the key k and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c, dst, src) }
+
+// Reset zeros the table, so that it will no longer appear in the process's memory.
+func (c *Cipher) Reset() {
+       for i := 0; i < len(c.table); i++ {
+               c.table[i] = 0
+       }
+}
+
+// initCipher initializes the cipher context by creating a look up table
+// of precalculated values that are based on the key.
+func initCipher(c *Cipher, key []byte) {
+       // Load the key into four uint32s
+       var k [4]uint32
+       for i := 0; i < len(k); i++ {
+               j := i << 2 // Multiply by 4
+               k[i] = uint32(key[j+0])<<24 | uint32(key[j+1])<<16 | uint32(key[j+2])<<8 | uint32(key[j+3])
+       }
+
+       // Precalculate the table
+       const delta = 0x9E3779B9
+       var sum uint32 = 0
+
+       // Two rounds of XTEA applied per loop
+       for i := 0; i < numRounds; {
+               c.table[i] = sum + k[sum&3]
+               i++
+               sum += delta
+               c.table[i] = sum + k[(sum>>11)&3]
+               i++
+       }
+}
diff --git a/libgo/go/crypto/xtea/xtea_test.go b/libgo/go/crypto/xtea/xtea_test.go
new file mode 100644 (file)
index 0000000..03934f1
--- /dev/null
@@ -0,0 +1,246 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xtea
+
+import (
+       "testing"
+)
+
+// A sample test key for when we just want to initialise a cipher
+var testKey = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
+
+// Test that the block size for XTEA is correct
+func TestBlocksize(t *testing.T) {
+       if BlockSize != 8 {
+               t.Errorf("BlockSize constant - expected 8, got %d", BlockSize)
+               return
+       }
+
+       c, err := NewCipher(testKey)
+       if err != nil {
+               t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+               return
+       }
+
+       result := c.BlockSize()
+       if result != 8 {
+               t.Errorf("BlockSize function - expected 8, gotr %d", result)
+               return
+       }
+}
+
+// A series of test values to confirm that the Cipher.table array was initialised correctly
+var testTable = []uint32{
+       0x00112233, 0x6B1568B8, 0xE28CE030, 0xC5089E2D, 0xC5089E2D, 0x1EFBD3A2, 0xA7845C2A, 0x78EF0917,
+       0x78EF0917, 0x172682D0, 0x5B6AC714, 0x822AC955, 0x3DE68511, 0xDC1DFECA, 0x2062430E, 0x3611343F,
+       0xF1CCEFFB, 0x900469B4, 0xD448ADF8, 0x2E3BE36D, 0xB6C46BF5, 0x994029F2, 0x994029F2, 0xF3335F67,
+       0x6AAAD6DF, 0x4D2694DC, 0x4D2694DC, 0xEB5E0E95, 0x2FA252D9, 0x4551440A, 0x121E10D6, 0xB0558A8F,
+       0xE388BDC3, 0x0A48C004, 0xC6047BC0, 0x643BF579, 0xA88039BD, 0x02736F32, 0x8AFBF7BA, 0x5C66A4A7,
+       0x5C66A4A7, 0xC76AEB2C, 0x3EE262A4, 0x215E20A1, 0x215E20A1, 0x7B515616, 0x03D9DE9E, 0x1988CFCF,
+       0xD5448B8B, 0x737C0544, 0xB7C04988, 0xDE804BC9, 0x9A3C0785, 0x3873813E, 0x7CB7C582, 0xD6AAFAF7,
+       0x4E22726F, 0x309E306C, 0x309E306C, 0x8A9165E1, 0x1319EE69, 0xF595AC66, 0xF595AC66, 0x4F88E1DB,
+}
+
+// Test that the cipher context is initialised correctly
+func TestCipherInit(t *testing.T) {
+       c, err := NewCipher(testKey)
+       if err != nil {
+               t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+               return
+       }
+
+       for i := 0; i < len(c.table); i++ {
+               if c.table[i] != testTable[i] {
+                       t.Errorf("NewCipher() failed to initialise Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i])
+                       break
+               }
+       }
+}
+
+// Test that invalid key sizes return an error
+func TestInvalidKeySize(t *testing.T) {
+       // Test a long key
+       key := []byte{
+               0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+               0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+       }
+
+       _, err := NewCipher(key)
+       if err == nil {
+               t.Errorf("Invalid key size %d didn't result in an error.", len(key))
+       }
+
+       // Test a short key
+       key = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}
+
+       _, err = NewCipher(key)
+       if err == nil {
+               t.Errorf("Invalid key size %d didn't result in an error.", len(key))
+       }
+}
+
+// Test that we can correctly decode some bytes we have encoded
+func TestEncodeDecode(t *testing.T) {
+       original := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}
+       input := original
+       output := make([]byte, BlockSize)
+
+       c, err := NewCipher(testKey)
+       if err != nil {
+               t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+               return
+       }
+
+       // Encrypt the input block
+       c.Encrypt(output, input)
+
+       // Check that the output does not match the input
+       differs := false
+       for i := 0; i < len(input); i++ {
+               if output[i] != input[i] {
+                       differs = true
+                       break
+               }
+       }
+       if differs == false {
+               t.Error("Cipher.Encrypt: Failed to encrypt the input block.")
+               return
+       }
+
+       // Decrypt the block we just encrypted
+       input = output
+       output = make([]byte, BlockSize)
+       c.Decrypt(output, input)
+
+       // Check that the output from decrypt matches our initial input
+       for i := 0; i < len(input); i++ {
+               if output[i] != original[i] {
+                       t.Errorf("Decrypted byte %d differed. Expected %02X, got %02X\n", i, original[i], output[i])
+                       return
+               }
+       }
+}
+
+// Test Vectors
+type CryptTest struct {
+       key        []byte
+       plainText  []byte
+       cipherText []byte
+}
+
+var CryptTests = []CryptTest{
+       // These were sourced from http://www.freemedialibrary.com/index.php/XTEA_test_vectors
+       {
+               []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+               []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+               []byte{0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5},
+       },
+       {
+               []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+               []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+               []byte{0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8},
+       },
+       {
+               []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+               []byte{0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f},
+               []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+       },
+       {
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+               []byte{0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5},
+       },
+       {
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+               []byte{0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d},
+       },
+       {
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55},
+               []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+       },
+
+       // These vectors are from http://wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation#Bouncy_Castle_C.23_API
+       {
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0xDE, 0xE9, 0xD4, 0xD8, 0xF7, 0x13, 0x1E, 0xD9},
+       },
+       {
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
+               []byte{0x06, 0x5C, 0x1B, 0x89, 0x75, 0xC6, 0xA8, 0x16},
+       },
+       {
+               []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+               []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               []byte{0x1F, 0xF9, 0xA0, 0x26, 0x1A, 0xC6, 0x42, 0x64},
+       },
+       {
+               []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+               []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
+               []byte{0x8C, 0x67, 0x15, 0x5B, 0x2E, 0xF9, 0x1E, 0xAD},
+       },
+}
+
+// Test encryption
+func TestCipherEncrypt(t *testing.T) {
+       for i, tt := range CryptTests {
+               c, err := NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
+                       continue
+               }
+
+               out := make([]byte, len(tt.plainText))
+               c.Encrypt(out, tt.plainText)
+
+               for j := 0; j < len(out); j++ {
+                       if out[j] != tt.cipherText[j] {
+                               t.Errorf("Cipher.Encrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.cipherText[j])
+                               break
+                       }
+               }
+       }
+}
+
+// Test decryption
+func TestCipherDecrypt(t *testing.T) {
+       for i, tt := range CryptTests {
+               c, err := NewCipher(tt.key)
+               if err != nil {
+                       t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
+                       continue
+               }
+
+               out := make([]byte, len(tt.cipherText))
+               c.Decrypt(out, tt.cipherText)
+
+               for j := 0; j < len(out); j++ {
+                       if out[j] != tt.plainText[j] {
+                               t.Errorf("Cipher.Decrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.plainText[j])
+                               break
+                       }
+               }
+       }
+}
+
+// Test resetting the cipher context
+func TestReset(t *testing.T) {
+       c, err := NewCipher(testKey)
+       if err != nil {
+               t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+               return
+       }
+
+       c.Reset()
+       for i := 0; i < len(c.table); i++ {
+               if c.table[i] != 0 {
+                       t.Errorf("Cipher.Reset: Failed to clear Cipher.table[%d]. expected 0, got %08X", i, c.table[i])
+                       return
+               }
+       }
+}
diff --git a/libgo/go/debug/dwarf/buf.go b/libgo/go/debug/dwarf/buf.go
new file mode 100644 (file)
index 0000000..2d29ceb
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Buffered reading and decoding of DWARF data streams.
+
+package dwarf
+
+import (
+       "encoding/binary"
+       "os"
+       "strconv"
+)
+
+// Data buffer being decoded.
+type buf struct {
+       dwarf    *Data
+       order    binary.ByteOrder
+       name     string
+       off      Offset
+       data     []byte
+       addrsize int
+       err      os.Error
+}
+
+func makeBuf(d *Data, name string, off Offset, data []byte, addrsize int) buf {
+       return buf{d, d.order, name, off, data, addrsize, nil}
+}
+
+func (b *buf) uint8() uint8 {
+       if len(b.data) < 1 {
+               b.error("underflow")
+               return 0
+       }
+       val := b.data[0]
+       b.data = b.data[1:]
+       b.off++
+       return val
+}
+
+func (b *buf) bytes(n int) []byte {
+       if len(b.data) < n {
+               b.error("underflow")
+               return nil
+       }
+       data := b.data[0:n]
+       b.data = b.data[n:]
+       b.off += Offset(n)
+       return data
+}
+
+func (b *buf) skip(n int) { b.bytes(n) }
+
+func (b *buf) string() string {
+       for i := 0; i < len(b.data); i++ {
+               if b.data[i] == 0 {
+                       s := string(b.data[0:i])
+                       b.data = b.data[i+1:]
+                       b.off += Offset(i + 1)
+                       return s
+               }
+       }
+       b.error("underflow")
+       return ""
+}
+
+func (b *buf) uint16() uint16 {
+       a := b.bytes(2)
+       if a == nil {
+               return 0
+       }
+       return b.order.Uint16(a)
+}
+
+func (b *buf) uint32() uint32 {
+       a := b.bytes(4)
+       if a == nil {
+               return 0
+       }
+       return b.order.Uint32(a)
+}
+
+func (b *buf) uint64() uint64 {
+       a := b.bytes(8)
+       if a == nil {
+               return 0
+       }
+       return b.order.Uint64(a)
+}
+
+// Read a varint, which is 7 bits per byte, little endian.
+// the 0x80 bit means read another byte.
+func (b *buf) varint() (c uint64, bits uint) {
+       for i := 0; i < len(b.data); i++ {
+               byte := b.data[i]
+               c |= uint64(byte&0x7F) << bits
+               bits += 7
+               if byte&0x80 == 0 {
+                       b.off += Offset(i + 1)
+                       b.data = b.data[i+1:]
+                       return c, bits
+               }
+       }
+       return 0, 0
+}
+
+// Unsigned int is just a varint.
+func (b *buf) uint() uint64 {
+       x, _ := b.varint()
+       return x
+}
+
+// Signed int is a sign-extended varint.
+func (b *buf) int() int64 {
+       ux, bits := b.varint()
+       x := int64(ux)
+       if x&(1<<(bits-1)) != 0 {
+               x |= -1 << bits
+       }
+       return x
+}
+
+// Address-sized uint.
+func (b *buf) addr() uint64 {
+       switch b.addrsize {
+       case 1:
+               return uint64(b.uint8())
+       case 2:
+               return uint64(b.uint16())
+       case 4:
+               return uint64(b.uint32())
+       case 8:
+               return uint64(b.uint64())
+       }
+       b.error("unknown address size")
+       return 0
+}
+
+func (b *buf) error(s string) {
+       if b.err == nil {
+               b.data = nil
+               b.err = DecodeError{b.name, b.off, s}
+       }
+}
+
+type DecodeError struct {
+       Name   string
+       Offset Offset
+       Error  string
+}
+
+func (e DecodeError) String() string {
+       return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.Itob64(int64(e.Offset), 16) + ": " + e.Error
+}
diff --git a/libgo/go/debug/dwarf/const.go b/libgo/go/debug/dwarf/const.go
new file mode 100644 (file)
index 0000000..1a3fec1
--- /dev/null
@@ -0,0 +1,433 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Constants
+
+package dwarf
+
+import "strconv"
+
+// An Attr identifies the attribute type in a DWARF Entry's Field.
+type Attr uint32
+
+const (
+       AttrSibling        Attr = 0x01
+       AttrLocation       Attr = 0x02
+       AttrName           Attr = 0x03
+       AttrOrdering       Attr = 0x09
+       AttrByteSize       Attr = 0x0B
+       AttrBitOffset      Attr = 0x0C
+       AttrBitSize        Attr = 0x0D
+       AttrStmtList       Attr = 0x10
+       AttrLowpc          Attr = 0x11
+       AttrHighpc         Attr = 0x12
+       AttrLanguage       Attr = 0x13
+       AttrDiscr          Attr = 0x15
+       AttrDiscrValue     Attr = 0x16
+       AttrVisibility     Attr = 0x17
+       AttrImport         Attr = 0x18
+       AttrStringLength   Attr = 0x19
+       AttrCommonRef      Attr = 0x1A
+       AttrCompDir        Attr = 0x1B
+       AttrConstValue     Attr = 0x1C
+       AttrContainingType Attr = 0x1D
+       AttrDefaultValue   Attr = 0x1E
+       AttrInline         Attr = 0x20
+       AttrIsOptional     Attr = 0x21
+       AttrLowerBound     Attr = 0x22
+       AttrProducer       Attr = 0x25
+       AttrPrototyped     Attr = 0x27
+       AttrReturnAddr     Attr = 0x2A
+       AttrStartScope     Attr = 0x2C
+       AttrStrideSize     Attr = 0x2E
+       AttrUpperBound     Attr = 0x2F
+       AttrAbstractOrigin Attr = 0x31
+       AttrAccessibility  Attr = 0x32
+       AttrAddrClass      Attr = 0x33
+       AttrArtificial     Attr = 0x34
+       AttrBaseTypes      Attr = 0x35
+       AttrCalling        Attr = 0x36
+       AttrCount          Attr = 0x37
+       AttrDataMemberLoc  Attr = 0x38
+       AttrDeclColumn     Attr = 0x39
+       AttrDeclFile       Attr = 0x3A
+       AttrDeclLine       Attr = 0x3B
+       AttrDeclaration    Attr = 0x3C
+       AttrDiscrList      Attr = 0x3D
+       AttrEncoding       Attr = 0x3E
+       AttrExternal       Attr = 0x3F
+       AttrFrameBase      Attr = 0x40
+       AttrFriend         Attr = 0x41
+       AttrIdentifierCase Attr = 0x42
+       AttrMacroInfo      Attr = 0x43
+       AttrNamelistItem   Attr = 0x44
+       AttrPriority       Attr = 0x45
+       AttrSegment        Attr = 0x46
+       AttrSpecification  Attr = 0x47
+       AttrStaticLink     Attr = 0x48
+       AttrType           Attr = 0x49
+       AttrUseLocation    Attr = 0x4A
+       AttrVarParam       Attr = 0x4B
+       AttrVirtuality     Attr = 0x4C
+       AttrVtableElemLoc  Attr = 0x4D
+       AttrAllocated      Attr = 0x4E
+       AttrAssociated     Attr = 0x4F
+       AttrDataLocation   Attr = 0x50
+       AttrStride         Attr = 0x51
+       AttrEntrypc        Attr = 0x52
+       AttrUseUTF8        Attr = 0x53
+       AttrExtension      Attr = 0x54
+       AttrRanges         Attr = 0x55
+       AttrTrampoline     Attr = 0x56
+       AttrCallColumn     Attr = 0x57
+       AttrCallFile       Attr = 0x58
+       AttrCallLine       Attr = 0x59
+       AttrDescription    Attr = 0x5A
+)
+
+var attrNames = [...]string{
+       AttrSibling:        "Sibling",
+       AttrLocation:       "Location",
+       AttrName:           "Name",
+       AttrOrdering:       "Ordering",
+       AttrByteSize:       "ByteSize",
+       AttrBitOffset:      "BitOffset",
+       AttrBitSize:        "BitSize",
+       AttrStmtList:       "StmtList",
+       AttrLowpc:          "Lowpc",
+       AttrHighpc:         "Highpc",
+       AttrLanguage:       "Language",
+       AttrDiscr:          "Discr",
+       AttrDiscrValue:     "DiscrValue",
+       AttrVisibility:     "Visibility",
+       AttrImport:         "Import",
+       AttrStringLength:   "StringLength",
+       AttrCommonRef:      "CommonRef",
+       AttrCompDir:        "CompDir",
+       AttrConstValue:     "ConstValue",
+       AttrContainingType: "ContainingType",
+       AttrDefaultValue:   "DefaultValue",
+       AttrInline:         "Inline",
+       AttrIsOptional:     "IsOptional",
+       AttrLowerBound:     "LowerBound",
+       AttrProducer:       "Producer",
+       AttrPrototyped:     "Prototyped",
+       AttrReturnAddr:     "ReturnAddr",
+       AttrStartScope:     "StartScope",
+       AttrStrideSize:     "StrideSize",
+       AttrUpperBound:     "UpperBound",
+       AttrAbstractOrigin: "AbstractOrigin",
+       AttrAccessibility:  "Accessibility",
+       AttrAddrClass:      "AddrClass",
+       AttrArtificial:     "Artificial",
+       AttrBaseTypes:      "BaseTypes",
+       AttrCalling:        "Calling",
+       AttrCount:          "Count",
+       AttrDataMemberLoc:  "DataMemberLoc",
+       AttrDeclColumn:     "DeclColumn",
+       AttrDeclFile:       "DeclFile",
+       AttrDeclLine:       "DeclLine",
+       AttrDeclaration:    "Declaration",
+       AttrDiscrList:      "DiscrList",
+       AttrEncoding:       "Encoding",
+       AttrExternal:       "External",
+       AttrFrameBase:      "FrameBase",
+       AttrFriend:         "Friend",
+       AttrIdentifierCase: "IdentifierCase",
+       AttrMacroInfo:      "MacroInfo",
+       AttrNamelistItem:   "NamelistItem",
+       AttrPriority:       "Priority",
+       AttrSegment:        "Segment",
+       AttrSpecification:  "Specification",
+       AttrStaticLink:     "StaticLink",
+       AttrType:           "Type",
+       AttrUseLocation:    "UseLocation",
+       AttrVarParam:       "VarParam",
+       AttrVirtuality:     "Virtuality",
+       AttrVtableElemLoc:  "VtableElemLoc",
+       AttrAllocated:      "Allocated",
+       AttrAssociated:     "Associated",
+       AttrDataLocation:   "DataLocation",
+       AttrStride:         "Stride",
+       AttrEntrypc:        "Entrypc",
+       AttrUseUTF8:        "UseUTF8",
+       AttrExtension:      "Extension",
+       AttrRanges:         "Ranges",
+       AttrTrampoline:     "Trampoline",
+       AttrCallColumn:     "CallColumn",
+       AttrCallFile:       "CallFile",
+       AttrCallLine:       "CallLine",
+       AttrDescription:    "Description",
+}
+
+func (a Attr) String() string {
+       if int(a) < len(attrNames) {
+               s := attrNames[a]
+               if s != "" {
+                       return s
+               }
+       }
+       return strconv.Itoa(int(a))
+}
+
+func (a Attr) GoString() string {
+       if int(a) < len(attrNames) {
+               s := attrNames[a]
+               if s != "" {
+                       return "dwarf.Attr" + s
+               }
+       }
+       return "dwarf.Attr(" + strconv.Itoa64(int64(a)) + ")"
+}
+
+// A format is a DWARF data encoding format.
+type format uint32
+
+const (
+       // value formats
+       formAddr        format = 0x01
+       formDwarfBlock2 format = 0x03
+       formDwarfBlock4 format = 0x04
+       formData2       format = 0x05
+       formData4       format = 0x06
+       formData8       format = 0x07
+       formString      format = 0x08
+       formDwarfBlock  format = 0x09
+       formDwarfBlock1 format = 0x0A
+       formData1       format = 0x0B
+       formFlag        format = 0x0C
+       formSdata       format = 0x0D
+       formStrp        format = 0x0E
+       formUdata       format = 0x0F
+       formRefAddr     format = 0x10
+       formRef1        format = 0x11
+       formRef2        format = 0x12
+       formRef4        format = 0x13
+       formRef8        format = 0x14
+       formRefUdata    format = 0x15
+       formIndirect    format = 0x16
+)
+
+// A Tag is the classification (the type) of an Entry.
+type Tag uint32
+
+const (
+       TagArrayType              Tag = 0x01
+       TagClassType              Tag = 0x02
+       TagEntryPoint             Tag = 0x03
+       TagEnumerationType        Tag = 0x04
+       TagFormalParameter        Tag = 0x05
+       TagImportedDeclaration    Tag = 0x08
+       TagLabel                  Tag = 0x0A
+       TagLexDwarfBlock          Tag = 0x0B
+       TagMember                 Tag = 0x0D
+       TagPointerType            Tag = 0x0F
+       TagReferenceType          Tag = 0x10
+       TagCompileUnit            Tag = 0x11
+       TagStringType             Tag = 0x12
+       TagStructType             Tag = 0x13
+       TagSubroutineType         Tag = 0x15
+       TagTypedef                Tag = 0x16
+       TagUnionType              Tag = 0x17
+       TagUnspecifiedParameters  Tag = 0x18
+       TagVariant                Tag = 0x19
+       TagCommonDwarfBlock       Tag = 0x1A
+       TagCommonInclusion        Tag = 0x1B
+       TagInheritance            Tag = 0x1C
+       TagInlinedSubroutine      Tag = 0x1D
+       TagModule                 Tag = 0x1E
+       TagPtrToMemberType        Tag = 0x1F
+       TagSetType                Tag = 0x20
+       TagSubrangeType           Tag = 0x21
+       TagWithStmt               Tag = 0x22
+       TagAccessDeclaration      Tag = 0x23
+       TagBaseType               Tag = 0x24
+       TagCatchDwarfBlock        Tag = 0x25
+       TagConstType              Tag = 0x26
+       TagConstant               Tag = 0x27
+       TagEnumerator             Tag = 0x28
+       TagFileType               Tag = 0x29
+       TagFriend                 Tag = 0x2A
+       TagNamelist               Tag = 0x2B
+       TagNamelistItem           Tag = 0x2C
+       TagPackedType             Tag = 0x2D
+       TagSubprogram             Tag = 0x2E
+       TagTemplateTypeParameter  Tag = 0x2F
+       TagTemplateValueParameter Tag = 0x30
+       TagThrownType             Tag = 0x31
+       TagTryDwarfBlock          Tag = 0x32
+       TagVariantPart            Tag = 0x33
+       TagVariable               Tag = 0x34
+       TagVolatileType           Tag = 0x35
+       TagDwarfProcedure         Tag = 0x36
+       TagRestrictType           Tag = 0x37
+       TagInterfaceType          Tag = 0x38
+       TagNamespace              Tag = 0x39
+       TagImportedModule         Tag = 0x3A
+       TagUnspecifiedType        Tag = 0x3B
+       TagPartialUnit            Tag = 0x3C
+       TagImportedUnit           Tag = 0x3D
+       TagMutableType            Tag = 0x3E
+)
+
+var tagNames = [...]string{
+       TagArrayType:              "ArrayType",
+       TagClassType:              "ClassType",
+       TagEntryPoint:             "EntryPoint",
+       TagEnumerationType:        "EnumerationType",
+       TagFormalParameter:        "FormalParameter",
+       TagImportedDeclaration:    "ImportedDeclaration",
+       TagLabel:                  "Label",
+       TagLexDwarfBlock:          "LexDwarfBlock",
+       TagMember:                 "Member",
+       TagPointerType:            "PointerType",
+       TagReferenceType:          "ReferenceType",
+       TagCompileUnit:            "CompileUnit",
+       TagStringType:             "StringType",
+       TagStructType:             "StructType",
+       TagSubroutineType:         "SubroutineType",
+       TagTypedef:                "Typedef",
+       TagUnionType:              "UnionType",
+       TagUnspecifiedParameters:  "UnspecifiedParameters",
+       TagVariant:                "Variant",
+       TagCommonDwarfBlock:       "CommonDwarfBlock",
+       TagCommonInclusion:        "CommonInclusion",
+       TagInheritance:            "Inheritance",
+       TagInlinedSubroutine:      "InlinedSubroutine",
+       TagModule:                 "Module",
+       TagPtrToMemberType:        "PtrToMemberType",
+       TagSetType:                "SetType",
+       TagSubrangeType:           "SubrangeType",
+       TagWithStmt:               "WithStmt",
+       TagAccessDeclaration:      "AccessDeclaration",
+       TagBaseType:               "BaseType",
+       TagCatchDwarfBlock:        "CatchDwarfBlock",
+       TagConstType:              "ConstType",
+       TagConstant:               "Constant",
+       TagEnumerator:             "Enumerator",
+       TagFileType:               "FileType",
+       TagFriend:                 "Friend",
+       TagNamelist:               "Namelist",
+       TagNamelistItem:           "NamelistItem",
+       TagPackedType:             "PackedType",
+       TagSubprogram:             "Subprogram",
+       TagTemplateTypeParameter:  "TemplateTypeParameter",
+       TagTemplateValueParameter: "TemplateValueParameter",
+       TagThrownType:             "ThrownType",
+       TagTryDwarfBlock:          "TryDwarfBlock",
+       TagVariantPart:            "VariantPart",
+       TagVariable:               "Variable",
+       TagVolatileType:           "VolatileType",
+       TagDwarfProcedure:         "DwarfProcedure",
+       TagRestrictType:           "RestrictType",
+       TagInterfaceType:          "InterfaceType",
+       TagNamespace:              "Namespace",
+       TagImportedModule:         "ImportedModule",
+       TagUnspecifiedType:        "UnspecifiedType",
+       TagPartialUnit:            "PartialUnit",
+       TagImportedUnit:           "ImportedUnit",
+       TagMutableType:            "MutableType",
+}
+
+func (t Tag) String() string {
+       if int(t) < len(tagNames) {
+               s := tagNames[t]
+               if s != "" {
+                       return s
+               }
+       }
+       return strconv.Itoa(int(t))
+}
+
+func (t Tag) GoString() string {
+       if int(t) < len(tagNames) {
+               s := tagNames[t]
+               if s != "" {
+                       return "dwarf.Tag" + s
+               }
+       }
+       return "dwarf.Tag(" + strconv.Itoa64(int64(t)) + ")"
+}
+
+// Location expression operators.
+// The debug info encodes value locations like 8(R3)
+// as a sequence of these op codes.
+// This package does not implement full expressions;
+// the opPlusUconst operator is expected by the type parser.
+const (
+       opAddr       = 0x03 /* 1 op, const addr */
+       opDeref      = 0x06
+       opConst1u    = 0x08 /* 1 op, 1 byte const */
+       opConst1s    = 0x09 /*  " signed */
+       opConst2u    = 0x0A /* 1 op, 2 byte const  */
+       opConst2s    = 0x0B /*  " signed */
+       opConst4u    = 0x0C /* 1 op, 4 byte const */
+       opConst4s    = 0x0D /*  " signed */
+       opConst8u    = 0x0E /* 1 op, 8 byte const */
+       opConst8s    = 0x0F /*  " signed */
+       opConstu     = 0x10 /* 1 op, LEB128 const */
+       opConsts     = 0x11 /*  " signed */
+       opDup        = 0x12
+       opDrop       = 0x13
+       opOver       = 0x14
+       opPick       = 0x15 /* 1 op, 1 byte stack index */
+       opSwap       = 0x16
+       opRot        = 0x17
+       opXderef     = 0x18
+       opAbs        = 0x19
+       opAnd        = 0x1A
+       opDiv        = 0x1B
+       opMinus      = 0x1C
+       opMod        = 0x1D
+       opMul        = 0x1E
+       opNeg        = 0x1F
+       opNot        = 0x20
+       opOr         = 0x21
+       opPlus       = 0x22
+       opPlusUconst = 0x23 /* 1 op, ULEB128 addend */
+       opShl        = 0x24
+       opShr        = 0x25
+       opShra       = 0x26
+       opXor        = 0x27
+       opSkip       = 0x2F /* 1 op, signed 2-byte constant */
+       opBra        = 0x28 /* 1 op, signed 2-byte constant */
+       opEq         = 0x29
+       opGe         = 0x2A
+       opGt         = 0x2B
+       opLe         = 0x2C
+       opLt         = 0x2D
+       opNe         = 0x2E
+       opLit0       = 0x30
+       /* OpLitN = OpLit0 + N for N = 0..31 */
+       opReg0 = 0x50
+       /* OpRegN = OpReg0 + N for N = 0..31 */
+       opBreg0 = 0x70 /* 1 op, signed LEB128 constant */
+       /* OpBregN = OpBreg0 + N for N = 0..31 */
+       opRegx       = 0x90 /* 1 op, ULEB128 register */
+       opFbreg      = 0x91 /* 1 op, SLEB128 offset */
+       opBregx      = 0x92 /* 2 op, ULEB128 reg; SLEB128 off */
+       opPiece      = 0x93 /* 1 op, ULEB128 size of piece */
+       opDerefSize  = 0x94 /* 1-byte size of data retrieved */
+       opXderefSize = 0x95 /* 1-byte size of data retrieved */
+       opNop        = 0x96
+       /* next four new in Dwarf v3 */
+       opPushObjAddr = 0x97
+       opCall2       = 0x98 /* 2-byte offset of DIE */
+       opCall4       = 0x99 /* 4-byte offset of DIE */
+       opCallRef     = 0x9A /* 4- or 8- byte offset of DIE */
+       /* 0xE0-0xFF reserved for user-specific */
+)
+
+// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry.
+const (
+       encAddress        = 0x01
+       encBoolean        = 0x02
+       encComplexFloat   = 0x03
+       encFloat          = 0x04
+       encSigned         = 0x05
+       encSignedChar     = 0x06
+       encUnsigned       = 0x07
+       encUnsignedChar   = 0x08
+       encImaginaryFloat = 0x09
+)
diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go
new file mode 100644 (file)
index 0000000..549e5c2
--- /dev/null
@@ -0,0 +1,343 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DWARF debug information entry parser.
+// An entry is a sequence of data items of a given format.
+// The first word in the entry is an index into what DWARF
+// calls the ``abbreviation table.''  An abbreviation is really
+// just a type descriptor: it's an array of attribute tag/value format pairs.
+
+package dwarf
+
+import "os"
+
+// a single entry's description: a sequence of attributes
+type abbrev struct {
+       tag      Tag
+       children bool
+       field    []afield
+}
+
+type afield struct {
+       attr Attr
+       fmt  format
+}
+
+// a map from entry format ids to their descriptions
+type abbrevTable map[uint32]abbrev
+
+// ParseAbbrev returns the abbreviation table that starts at byte off
+// in the .debug_abbrev section.
+func (d *Data) parseAbbrev(off uint32) (abbrevTable, os.Error) {
+       if m, ok := d.abbrevCache[off]; ok {
+               return m, nil
+       }
+
+       data := d.abbrev
+       if off > uint32(len(data)) {
+               data = nil
+       } else {
+               data = data[off:]
+       }
+       b := makeBuf(d, "abbrev", 0, data, 0)
+
+       // Error handling is simplified by the buf getters
+       // returning an endless stream of 0s after an error.
+       m := make(abbrevTable)
+       for {
+               // Table ends with id == 0.
+               id := uint32(b.uint())
+               if id == 0 {
+                       break
+               }
+
+               // Walk over attributes, counting.
+               n := 0
+               b1 := b // Read from copy of b.
+               b1.uint()
+               b1.uint8()
+               for {
+                       tag := b1.uint()
+                       fmt := b1.uint()
+                       if tag == 0 && fmt == 0 {
+                               break
+                       }
+                       n++
+               }
+               if b1.err != nil {
+                       return nil, b1.err
+               }
+
+               // Walk over attributes again, this time writing them down.
+               var a abbrev
+               a.tag = Tag(b.uint())
+               a.children = b.uint8() != 0
+               a.field = make([]afield, n)
+               for i := range a.field {
+                       a.field[i].attr = Attr(b.uint())
+                       a.field[i].fmt = format(b.uint())
+               }
+               b.uint()
+               b.uint()
+
+               m[id] = a
+       }
+       if b.err != nil {
+               return nil, b.err
+       }
+       d.abbrevCache[off] = m
+       return m, nil
+}
+
+// An entry is a sequence of attribute/value pairs.
+type Entry struct {
+       Offset   Offset // offset of Entry in DWARF info
+       Tag      Tag    // tag (kind of Entry)
+       Children bool   // whether Entry is followed by children
+       Field    []Field
+}
+
+// A Field is a single attribute/value pair in an Entry.
+type Field struct {
+       Attr Attr
+       Val  interface{}
+}
+
+// Val returns the value associated with attribute Attr in Entry,
+// or nil if there is no such attribute.
+//
+// A common idiom is to merge the check for nil return with
+// the check that the value has the expected dynamic type, as in:
+//     v, ok := e.Val(AttrSibling).(int64);
+//
+func (e *Entry) Val(a Attr) interface{} {
+       for _, f := range e.Field {
+               if f.Attr == a {
+                       return f.Val
+               }
+       }
+       return nil
+}
+
+// An Offset represents the location of an Entry within the DWARF info.
+// (See Reader.Seek.)
+type Offset uint32
+
+// Entry reads a single entry from buf, decoding
+// according to the given abbreviation table.
+func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
+       off := b.off
+       id := uint32(b.uint())
+       if id == 0 {
+               return &Entry{}
+       }
+       a, ok := atab[id]
+       if !ok {
+               b.error("unknown abbreviation table index")
+               return nil
+       }
+       e := &Entry{
+               Offset:   off,
+               Tag:      a.tag,
+               Children: a.children,
+               Field:    make([]Field, len(a.field)),
+       }
+       for i := range e.Field {
+               e.Field[i].Attr = a.field[i].attr
+               fmt := a.field[i].fmt
+               if fmt == formIndirect {
+                       fmt = format(b.uint())
+               }
+               var val interface{}
+               switch fmt {
+               default:
+                       b.error("unknown entry attr format")
+
+               // address
+               case formAddr:
+                       val = b.addr()
+
+               // block
+               case formDwarfBlock1:
+                       val = b.bytes(int(b.uint8()))
+               case formDwarfBlock2:
+                       val = b.bytes(int(b.uint16()))
+               case formDwarfBlock4:
+                       val = b.bytes(int(b.uint32()))
+               case formDwarfBlock:
+                       val = b.bytes(int(b.uint()))
+
+               // constant
+               case formData1:
+                       val = int64(b.uint8())
+               case formData2:
+                       val = int64(b.uint16())
+               case formData4:
+                       val = int64(b.uint32())
+               case formData8:
+                       val = int64(b.uint64())
+               case formSdata:
+                       val = int64(b.int())
+               case formUdata:
+                       val = int64(b.uint())
+
+               // flag
+               case formFlag:
+                       val = b.uint8() == 1
+
+               // reference to other entry
+               case formRefAddr:
+                       val = Offset(b.addr())
+               case formRef1:
+                       val = Offset(b.uint8()) + ubase
+               case formRef2:
+                       val = Offset(b.uint16()) + ubase
+               case formRef4:
+                       val = Offset(b.uint32()) + ubase
+               case formRef8:
+                       val = Offset(b.uint64()) + ubase
+               case formRefUdata:
+                       val = Offset(b.uint()) + ubase
+
+               // string
+               case formString:
+                       val = b.string()
+               case formStrp:
+                       off := b.uint32() // offset into .debug_str
+                       if b.err != nil {
+                               return nil
+                       }
+                       b1 := makeBuf(b.dwarf, "str", 0, b.dwarf.str, 0)
+                       b1.skip(int(off))
+                       val = b1.string()
+                       if b1.err != nil {
+                               b.err = b1.err
+                               return nil
+                       }
+               }
+               e.Field[i].Val = val
+       }
+       if b.err != nil {
+               return nil
+       }
+       return e
+}
+
+// A Reader allows reading Entry structures from a DWARF ``info'' section.
+// The Entry structures are arranged in a tree.  The Reader's Next function
+// return successive entries from a pre-order traversal of the tree.
+// If an entry has children, its Children field will be true, and the children
+// follow, terminated by an Entry with Tag 0.
+type Reader struct {
+       b            buf
+       d            *Data
+       err          os.Error
+       unit         int
+       lastChildren bool   // .Children of last entry returned by Next
+       lastSibling  Offset // .Val(AttrSibling) of last entry returned by Next
+}
+
+// Reader returns a new Reader for Data.
+// The reader is positioned at byte offset 0 in the DWARF ``info'' section.
+func (d *Data) Reader() *Reader {
+       r := &Reader{d: d}
+       r.Seek(0)
+       return r
+}
+
+// Seek positions the Reader at offset off in the encoded entry stream.
+// Offset 0 can be used to denote the first entry.
+func (r *Reader) Seek(off Offset) {
+       d := r.d
+       r.err = nil
+       r.lastChildren = false
+       if off == 0 {
+               if len(d.unit) == 0 {
+                       return
+               }
+               u := &d.unit[0]
+               r.unit = 0
+               r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
+               return
+       }
+
+       // TODO(rsc): binary search (maybe a new package)
+       var i int
+       var u *unit
+       for i = range d.unit {
+               u = &d.unit[i]
+               if u.off <= off && off < u.off+Offset(len(u.data)) {
+                       r.unit = i
+                       r.b = makeBuf(r.d, "info", off, u.data[off-u.off:], u.addrsize)
+                       return
+               }
+       }
+       r.err = os.NewError("offset out of range")
+}
+
+// maybeNextUnit advances to the next unit if this one is finished.
+func (r *Reader) maybeNextUnit() {
+       for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
+               r.unit++
+               u := &r.d.unit[r.unit]
+               r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
+       }
+}
+
+// Next reads the next entry from the encoded entry stream.
+// It returns nil, nil when it reaches the end of the section.
+// It returns an error if the current offset is invalid or the data at the
+// offset cannot be decoded as a valid Entry.
+func (r *Reader) Next() (*Entry, os.Error) {
+       if r.err != nil {
+               return nil, r.err
+       }
+       r.maybeNextUnit()
+       if len(r.b.data) == 0 {
+               return nil, nil
+       }
+       u := &r.d.unit[r.unit]
+       e := r.b.entry(u.atable, u.base)
+       if r.b.err != nil {
+               r.err = r.b.err
+               return nil, r.err
+       }
+       if e != nil {
+               r.lastChildren = e.Children
+               if r.lastChildren {
+                       r.lastSibling, _ = e.Val(AttrSibling).(Offset)
+               }
+       } else {
+               r.lastChildren = false
+       }
+       return e, nil
+}
+
+// SkipChildren skips over the child entries associated with
+// the last Entry returned by Next.  If that Entry did not have
+// children or Next has not been called, SkipChildren is a no-op.
+func (r *Reader) SkipChildren() {
+       if r.err != nil || !r.lastChildren {
+               return
+       }
+
+       // If the last entry had a sibling attribute,
+       // that attribute gives the offset of the next
+       // sibling, so we can avoid decoding the
+       // child subtrees.
+       if r.lastSibling >= r.b.off {
+               r.Seek(r.lastSibling)
+               return
+       }
+
+       for {
+               e, err := r.Next()
+               if err != nil || e == nil || e.Tag == 0 {
+                       break
+               }
+               if e.Children {
+                       r.SkipChildren()
+               }
+       }
+}
diff --git a/libgo/go/debug/dwarf/open.go b/libgo/go/debug/dwarf/open.go
new file mode 100644 (file)
index 0000000..cb009e0
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package provides access to DWARF debugging information
+// loaded from executable files, as defined in the DWARF 2.0 Standard
+// at http://dwarfstd.org/doc/dwarf-2.0.0.pdf
+package dwarf
+
+import (
+       "encoding/binary"
+       "os"
+)
+
+// Data represents the DWARF debugging information
+// loaded from an executable file (for example, an ELF or Mach-O executable).
+type Data struct {
+       // raw data
+       abbrev   []byte
+       aranges  []byte
+       frame    []byte
+       info     []byte
+       line     []byte
+       pubnames []byte
+       ranges   []byte
+       str      []byte
+
+       // parsed data
+       abbrevCache map[uint32]abbrevTable
+       addrsize    int
+       order       binary.ByteOrder
+       typeCache   map[Offset]Type
+       unit        []unit
+}
+
+// New returns a new Data object initialized from the given parameters.
+// Clients should typically use [TODO(rsc): method to be named later] instead of calling
+// New directly.
+//
+// The []byte arguments are the data from the corresponding debug section
+// in the object file; for example, for an ELF object, abbrev is the contents of
+// the ".debug_abbrev" section.
+func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, os.Error) {
+       d := &Data{
+               abbrev:      abbrev,
+               aranges:     aranges,
+               frame:       frame,
+               info:        info,
+               line:        line,
+               pubnames:    pubnames,
+               ranges:      ranges,
+               str:         str,
+               abbrevCache: make(map[uint32]abbrevTable),
+               typeCache:   make(map[Offset]Type),
+       }
+
+       // Sniff .debug_info to figure out byte order.
+       // bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
+       if len(d.info) < 6 {
+               return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
+       }
+       x, y := d.info[4], d.info[5]
+       switch {
+       case x == 0 && y == 0:
+               return nil, DecodeError{"info", 4, "unsupported version 0"}
+       case x == 0:
+               d.order = binary.BigEndian
+       case y == 0:
+               d.order = binary.LittleEndian
+       default:
+               return nil, DecodeError{"info", 4, "cannot determine byte order"}
+       }
+
+       u, err := d.parseUnits()
+       if err != nil {
+               return nil, err
+       }
+       d.unit = u
+       return d, nil
+}
diff --git a/libgo/go/debug/dwarf/testdata/typedef.c b/libgo/go/debug/dwarf/testdata/typedef.c
new file mode 100644 (file)
index 0000000..2ceb00c
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Linux ELF:
+gcc -gdwarf-2 -m64 -c typedef.c && gcc -gdwarf-2 -m64 -o typedef.elf typedef.o
+
+OS X Mach-O:
+gcc -gdwarf-2 -m64 -c typedef.c -o typedef.macho
+*/
+
+typedef volatile int* t_ptr_volatile_int;
+typedef const char *t_ptr_const_char;
+typedef long t_long;
+typedef unsigned short t_ushort;
+typedef int t_func_int_of_float_double(float, double);
+typedef int (*t_ptr_func_int_of_float_double)(float, double);
+typedef int *t_func_ptr_int_of_char_schar_uchar(char, signed char, unsigned char);
+typedef void t_func_void_of_char(char);
+typedef void t_func_void_of_void(void);
+typedef void t_func_void_of_ptr_char_dots(char*, ...);
+typedef struct my_struct {
+       volatile int vi;
+       char x : 1;
+       int y : 4;
+       long long array[40];
+} t_my_struct;
+typedef union my_union {
+       volatile int vi;
+       char x : 1;
+       int y : 4;
+       long long array[40];
+} t_my_union;
+typedef enum my_enum {
+       e1 = 1,
+       e2 = 2,
+       e3 = -5,
+       e4 = 1000000000000000LL,
+} t_my_enum;
+
+typedef struct list t_my_list;
+struct list {
+       short val;
+       t_my_list *next;
+};
+
+typedef struct tree {
+       struct tree *left, *right;
+       unsigned long long val;
+} t_my_tree;
+
+t_ptr_volatile_int *a2;
+t_ptr_const_char **a3a;
+t_long *a4;
+t_ushort *a5;
+t_func_int_of_float_double *a6;
+t_ptr_func_int_of_float_double *a7;
+t_func_ptr_int_of_char_schar_uchar *a8;
+t_func_void_of_char *a9;
+t_func_void_of_void *a10;
+t_func_void_of_ptr_char_dots *a11;
+t_my_struct *a12;
+t_my_union *a12a;
+t_my_enum *a13;
+t_my_list *a14;
+t_my_tree *a15;
+
+int main()
+{
+       return 0;
+}
diff --git a/libgo/go/debug/dwarf/testdata/typedef.elf b/libgo/go/debug/dwarf/testdata/typedef.elf
new file mode 100755 (executable)
index 0000000..ea9291f
Binary files /dev/null and b/libgo/go/debug/dwarf/testdata/typedef.elf differ
diff --git a/libgo/go/debug/dwarf/testdata/typedef.macho b/libgo/go/debug/dwarf/testdata/typedef.macho
new file mode 100644 (file)
index 0000000..bf1dfd2
Binary files /dev/null and b/libgo/go/debug/dwarf/testdata/typedef.macho differ
diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go
new file mode 100644 (file)
index 0000000..902a545
--- /dev/null
@@ -0,0 +1,583 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DWARF type information structures.
+// The format is heavily biased toward C, but for simplicity
+// the String methods use a pseudo-Go syntax.
+
+package dwarf
+
+import (
+       "os"
+       "strconv"
+)
+
+// A Type conventionally represents a pointer to any of the
+// specific Type structures (CharType, StructType, etc.).
+type Type interface {
+       Common() *CommonType
+       String() string
+       Size() int64
+}
+
+// A CommonType holds fields common to multiple types.
+// If a field is not known or not applicable for a given type,
+// the zero value is used.
+type CommonType struct {
+       ByteSize int64  // size of value of this type, in bytes
+       Name     string // name that can be used to refer to type
+}
+
+func (c *CommonType) Common() *CommonType { return c }
+
+func (c *CommonType) Size() int64 { return c.ByteSize }
+
+// Basic types
+
+// A BasicType holds fields common to all basic types.
+type BasicType struct {
+       CommonType
+       BitSize   int64
+       BitOffset int64
+}
+
+func (b *BasicType) Basic() *BasicType { return b }
+
+func (t *BasicType) String() string {
+       if t.Name != "" {
+               return t.Name
+       }
+       return "?"
+}
+
+// A CharType represents a signed character type.
+type CharType struct {
+       BasicType
+}
+
+// A UcharType represents an unsigned character type.
+type UcharType struct {
+       BasicType
+}
+
+// An IntType represents a signed integer type.
+type IntType struct {
+       BasicType
+}
+
+// A UintType represents an unsigned integer type.
+type UintType struct {
+       BasicType
+}
+
+// A FloatType represents a floating point type.
+type FloatType struct {
+       BasicType
+}
+
+// A ComplexType represents a complex floating point type.
+type ComplexType struct {
+       BasicType
+}
+
+// A BoolType represents a boolean type.
+type BoolType struct {
+       BasicType
+}
+
+// An AddrType represents a machine address type.
+type AddrType struct {
+       BasicType
+}
+
+// qualifiers
+
+// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier.
+type QualType struct {
+       CommonType
+       Qual string
+       Type Type
+}
+
+func (t *QualType) String() string { return t.Qual + " " + t.Type.String() }
+
+func (t *QualType) Size() int64 { return t.Type.Size() }
+
+// An ArrayType represents a fixed size array type.
+type ArrayType struct {
+       CommonType
+       Type          Type
+       StrideBitSize int64 // if > 0, number of bits to hold each element
+       Count         int64 // if == -1, an incomplete array, like char x[].
+}
+
+func (t *ArrayType) String() string {
+       return "[" + strconv.Itoa64(t.Count) + "]" + t.Type.String()
+}
+
+func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() }
+
+// A VoidType represents the C void type.
+type VoidType struct {
+       CommonType
+}
+
+func (t *VoidType) String() string { return "void" }
+
+// A PtrType represents a pointer type.
+type PtrType struct {
+       CommonType
+       Type Type
+}
+
+func (t *PtrType) String() string { return "*" + t.Type.String() }
+
+// A StructType represents a struct, union, or C++ class type.
+type StructType struct {
+       CommonType
+       StructName string
+       Kind       string // "struct", "union", or "class".
+       Field      []*StructField
+       Incomplete bool // if true, struct, union, class is declared but not defined
+}
+
+// A StructField represents a field in a struct, union, or C++ class type.
+type StructField struct {
+       Name       string
+       Type       Type
+       ByteOffset int64
+       ByteSize   int64
+       BitOffset  int64 // within the ByteSize bytes at ByteOffset
+       BitSize    int64 // zero if not a bit field
+}
+
+func (t *StructType) String() string {
+       if t.StructName != "" {
+               return t.Kind + " " + t.StructName
+       }
+       return t.Defn()
+}
+
+func (t *StructType) Defn() string {
+       s := t.Kind
+       if t.StructName != "" {
+               s += " " + t.StructName
+       }
+       if t.Incomplete {
+               s += " /*incomplete*/"
+               return s
+       }
+       s += " {"
+       for i, f := range t.Field {
+               if i > 0 {
+                       s += "; "
+               }
+               s += f.Name + " " + f.Type.String()
+               s += "@" + strconv.Itoa64(f.ByteOffset)
+               if f.BitSize > 0 {
+                       s += " : " + strconv.Itoa64(f.BitSize)
+                       s += "@" + strconv.Itoa64(f.BitOffset)
+               }
+       }
+       s += "}"
+       return s
+}
+
+// An EnumType represents an enumerated type.
+// The only indication of its native integer type is its ByteSize
+// (inside CommonType).
+type EnumType struct {
+       CommonType
+       EnumName string
+       Val      []*EnumValue
+}
+
+// An EnumValue represents a single enumeration value.
+type EnumValue struct {
+       Name string
+       Val  int64
+}
+
+func (t *EnumType) String() string {
+       s := "enum"
+       if t.EnumName != "" {
+               s += " " + t.EnumName
+       }
+       s += " {"
+       for i, v := range t.Val {
+               if i > 0 {
+                       s += "; "
+               }
+               s += v.Name + "=" + strconv.Itoa64(v.Val)
+       }
+       s += "}"
+       return s
+}
+
+// A FuncType represents a function type.
+type FuncType struct {
+       CommonType
+       ReturnType Type
+       ParamType  []Type
+}
+
+func (t *FuncType) String() string {
+       s := "func("
+       for i, t := range t.ParamType {
+               if i > 0 {
+                       s += ", "
+               }
+               s += t.String()
+       }
+       s += ")"
+       if t.ReturnType != nil {
+               s += " " + t.ReturnType.String()
+       }
+       return s
+}
+
+// A DotDotDotType represents the variadic ... function parameter.
+type DotDotDotType struct {
+       CommonType
+}
+
+func (t *DotDotDotType) String() string { return "..." }
+
+// A TypedefType represents a named type.
+type TypedefType struct {
+       CommonType
+       Type Type
+}
+
+func (t *TypedefType) String() string { return t.Name }
+
+func (t *TypedefType) Size() int64 { return t.Type.Size() }
+
+func (d *Data) Type(off Offset) (Type, os.Error) {
+       if t, ok := d.typeCache[off]; ok {
+               return t, nil
+       }
+
+       r := d.Reader()
+       r.Seek(off)
+       e, err := r.Next()
+       if err != nil {
+               return nil, err
+       }
+       if e == nil || e.Offset != off {
+               return nil, DecodeError{"info", off, "no type at offset"}
+       }
+
+       // Parse type from Entry.
+       // Must always set d.typeCache[off] before calling
+       // d.Type recursively, to handle circular types correctly.
+       var typ Type
+
+       // Get next child; set err if error happens.
+       next := func() *Entry {
+               if !e.Children {
+                       return nil
+               }
+               kid, err1 := r.Next()
+               if err1 != nil {
+                       err = err1
+                       return nil
+               }
+               if kid == nil {
+                       err = DecodeError{"info", r.b.off, "unexpected end of DWARF entries"}
+                       return nil
+               }
+               if kid.Tag == 0 {
+                       return nil
+               }
+               return kid
+       }
+
+       // Get Type referred to by Entry's AttrType field.
+       // Set err if error happens.  Not having a type is an error.
+       typeOf := func(e *Entry) Type {
+               toff, ok := e.Val(AttrType).(Offset)
+               if !ok {
+                       // It appears that no Type means "void".
+                       return new(VoidType)
+               }
+               var t Type
+               if t, err = d.Type(toff); err != nil {
+                       return nil
+               }
+               return t
+       }
+
+       switch e.Tag {
+       case TagArrayType:
+               // Multi-dimensional array.  (DWARF v2 §5.4)
+               // Attributes:
+               //      AttrType:subtype [required]
+               //      AttrStrideSize: size in bits of each element of the array
+               //      AttrByteSize: size of entire array
+               // Children:
+               //      TagSubrangeType or TagEnumerationType giving one dimension.
+               //      dimensions are in left to right order.
+               t := new(ArrayType)
+               typ = t
+               d.typeCache[off] = t
+               if t.Type = typeOf(e); err != nil {
+                       goto Error
+               }
+               t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64)
+
+               // Accumulate dimensions,
+               ndim := 0
+               for kid := next(); kid != nil; kid = next() {
+                       // TODO(rsc): Can also be TagEnumerationType
+                       // but haven't seen that in the wild yet.
+                       switch kid.Tag {
+                       case TagSubrangeType:
+                               max, ok := kid.Val(AttrUpperBound).(int64)
+                               if !ok {
+                                       max = -2 // Count == -1, as in x[].
+                               }
+                               if ndim == 0 {
+                                       t.Count = max + 1
+                               } else {
+                                       // Multidimensional array.
+                                       // Create new array type underneath this one.
+                                       t.Type = &ArrayType{Type: t.Type, Count: max + 1}
+                               }
+                               ndim++
+                       case TagEnumerationType:
+                               err = DecodeError{"info", kid.Offset, "cannot handle enumeration type as array bound"}
+                               goto Error
+                       }
+               }
+               if ndim == 0 {
+                       err = DecodeError{"info", e.Offset, "missing dimension for array"}
+                       goto Error
+               }
+
+       case TagBaseType:
+               // Basic type.  (DWARF v2 §5.1)
+               // Attributes:
+               //      AttrName: name of base type in programming language of the compilation unit [required]
+               //      AttrEncoding: encoding value for type (encFloat etc) [required]
+               //      AttrByteSize: size of type in bytes [required]
+               //      AttrBitOffset: for sub-byte types, size in bits
+               //      AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes
+               name, _ := e.Val(AttrName).(string)
+               enc, ok := e.Val(AttrEncoding).(int64)
+               if !ok {
+                       err = DecodeError{"info", e.Offset, "missing encoding attribute for " + name}
+                       goto Error
+               }
+               switch enc {
+               default:
+                       err = DecodeError{"info", e.Offset, "unrecognized encoding attribute value"}
+                       goto Error
+
+               case encAddress:
+                       typ = new(AddrType)
+               case encBoolean:
+                       typ = new(BoolType)
+               case encComplexFloat:
+                       typ = new(ComplexType)
+               case encFloat:
+                       typ = new(FloatType)
+               case encSigned:
+                       typ = new(IntType)
+               case encUnsigned:
+                       typ = new(UintType)
+               case encSignedChar:
+                       typ = new(CharType)
+               case encUnsignedChar:
+                       typ = new(UcharType)
+               }
+               d.typeCache[off] = typ
+               t := typ.(interface {
+                       Basic() *BasicType
+               }).Basic()
+               t.Name = name
+               t.BitSize, _ = e.Val(AttrBitSize).(int64)
+               t.BitOffset, _ = e.Val(AttrBitOffset).(int64)
+
+       case TagClassType, TagStructType, TagUnionType:
+               // Structure, union, or class type.  (DWARF v2 §5.5)
+               // Attributes:
+               //      AttrName: name of struct, union, or class
+               //      AttrByteSize: byte size [required]
+               //      AttrDeclaration: if true, struct/union/class is incomplete
+               // Children:
+               //      TagMember to describe one member.
+               //              AttrName: name of member [required]
+               //              AttrType: type of member [required]
+               //              AttrByteSize: size in bytes
+               //              AttrBitOffset: bit offset within bytes for bit fields
+               //              AttrBitSize: bit size for bit fields
+               //              AttrDataMemberLoc: location within struct [required for struct, class]
+               // There is much more to handle C++, all ignored for now.
+               t := new(StructType)
+               typ = t
+               d.typeCache[off] = t
+               switch e.Tag {
+               case TagClassType:
+                       t.Kind = "class"
+               case TagStructType:
+                       t.Kind = "struct"
+               case TagUnionType:
+                       t.Kind = "union"
+               }
+               t.StructName, _ = e.Val(AttrName).(string)
+               t.Incomplete = e.Val(AttrDeclaration) != nil
+               t.Field = make([]*StructField, 0, 8)
+               for kid := next(); kid != nil; kid = next() {
+                       if kid.Tag == TagMember {
+                               f := new(StructField)
+                               if f.Type = typeOf(kid); err != nil {
+                                       goto Error
+                               }
+                               if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
+                                       b := makeBuf(d, "location", 0, loc, d.addrsize)
+                                       if b.uint8() != opPlusUconst {
+                                               err = DecodeError{"info", kid.Offset, "unexpected opcode"}
+                                               goto Error
+                                       }
+                                       f.ByteOffset = int64(b.uint())
+                                       if b.err != nil {
+                                               err = b.err
+                                               goto Error
+                                       }
+                               }
+                               f.Name, _ = kid.Val(AttrName).(string)
+                               f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
+                               f.BitOffset, _ = kid.Val(AttrBitOffset).(int64)
+                               f.BitSize, _ = kid.Val(AttrBitSize).(int64)
+                               t.Field = append(t.Field, f)
+                       }
+               }
+
+       case TagConstType, TagVolatileType, TagRestrictType:
+               // Type modifier (DWARF v2 §5.2)
+               // Attributes:
+               //      AttrType: subtype
+               t := new(QualType)
+               typ = t
+               d.typeCache[off] = t
+               if t.Type = typeOf(e); err != nil {
+                       goto Error
+               }
+               switch e.Tag {
+               case TagConstType:
+                       t.Qual = "const"
+               case TagRestrictType:
+                       t.Qual = "restrict"
+               case TagVolatileType:
+                       t.Qual = "volatile"
+               }
+
+       case TagEnumerationType:
+               // Enumeration type (DWARF v2 §5.6)
+               // Attributes:
+               //      AttrName: enum name if any
+               //      AttrByteSize: bytes required to represent largest value
+               // Children:
+               //      TagEnumerator:
+               //              AttrName: name of constant
+               //              AttrConstValue: value of constant
+               t := new(EnumType)
+               typ = t
+               d.typeCache[off] = t
+               t.EnumName, _ = e.Val(AttrName).(string)
+               t.Val = make([]*EnumValue, 0, 8)
+               for kid := next(); kid != nil; kid = next() {
+                       if kid.Tag == TagEnumerator {
+                               f := new(EnumValue)
+                               f.Name, _ = kid.Val(AttrName).(string)
+                               f.Val, _ = kid.Val(AttrConstValue).(int64)
+                               n := len(t.Val)
+                               if n >= cap(t.Val) {
+                                       val := make([]*EnumValue, n, n*2)
+                                       copy(val, t.Val)
+                                       t.Val = val
+                               }
+                               t.Val = t.Val[0 : n+1]
+                               t.Val[n] = f
+                       }
+               }
+
+       case TagPointerType:
+               // Type modifier (DWARF v2 §5.2)
+               // Attributes:
+               //      AttrType: subtype [not required!  void* has no AttrType]
+               //      AttrAddrClass: address class [ignored]
+               t := new(PtrType)
+               typ = t
+               d.typeCache[off] = t
+               if e.Val(AttrType) == nil {
+                       t.Type = &VoidType{}
+                       break
+               }
+               t.Type = typeOf(e)
+
+       case TagSubroutineType:
+               // Subroutine type.  (DWARF v2 §5.7)
+               // Attributes:
+               //      AttrType: type of return value if any
+               //      AttrName: possible name of type [ignored]
+               //      AttrPrototyped: whether used ANSI C prototye [ignored]
+               // Children:
+               //      TagFormalParameter: typed parameter
+               //              AttrType: type of parameter
+               //      TagUnspecifiedParameter: final ...
+               t := new(FuncType)
+               typ = t
+               d.typeCache[off] = t
+               if t.ReturnType = typeOf(e); err != nil {
+                       goto Error
+               }
+               t.ParamType = make([]Type, 0, 8)
+               for kid := next(); kid != nil; kid = next() {
+                       var tkid Type
+                       switch kid.Tag {
+                       default:
+                               continue
+                       case TagFormalParameter:
+                               if tkid = typeOf(kid); err != nil {
+                                       goto Error
+                               }
+                       case TagUnspecifiedParameters:
+                               tkid = &DotDotDotType{}
+                       }
+                       t.ParamType = append(t.ParamType, tkid)
+               }
+
+       case TagTypedef:
+               // Typedef (DWARF v2 §5.3)
+               // Attributes:
+               //      AttrName: name [required]
+               //      AttrType: type definition [required]
+               t := new(TypedefType)
+               typ = t
+               d.typeCache[off] = t
+               t.Name, _ = e.Val(AttrName).(string)
+               t.Type = typeOf(e)
+       }
+
+       if err != nil {
+               goto Error
+       }
+
+       b, ok := e.Val(AttrByteSize).(int64)
+       if !ok {
+               b = -1
+       }
+       typ.Common().ByteSize = b
+
+       return typ, nil
+
+Error:
+       // If the parse fails, take the type out of the cache
+       // so that the next call with this offset doesn't hit
+       // the cache and return success.
+       d.typeCache[off] = nil, false
+       return nil, err
+}
diff --git a/libgo/go/debug/dwarf/type_test.go b/libgo/go/debug/dwarf/type_test.go
new file mode 100644 (file)
index 0000000..6c2daaa
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf_test
+
+import (
+       . "debug/dwarf"
+       "debug/elf"
+       "debug/macho"
+       "testing"
+)
+
+var typedefTests = map[string]string{
+       "t_ptr_volatile_int":                 "*volatile int",
+       "t_ptr_const_char":                   "*const char",
+       "t_long":                             "long int",
+       "t_ushort":                           "short unsigned int",
+       "t_func_int_of_float_double":         "func(float, double) int",
+       "t_ptr_func_int_of_float_double":     "*func(float, double) int",
+       "t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int",
+       "t_func_void_of_char":                "func(char) void",
+       "t_func_void_of_void":                "func() void",
+       "t_func_void_of_ptr_char_dots":       "func(*char, ...) void",
+       "t_my_struct":                        "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; array [40]long long int@8}",
+       "t_my_union":                         "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
+       "t_my_enum":                          "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
+       "t_my_list":                          "struct list {val short int@0; next *t_my_list@8}",
+       "t_my_tree":                          "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}",
+}
+
+func elfData(t *testing.T, name string) *Data {
+       f, err := elf.Open(name)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       d, err := f.DWARF()
+       if err != nil {
+               t.Fatal(err)
+       }
+       return d
+}
+
+func machoData(t *testing.T, name string) *Data {
+       f, err := macho.Open(name)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       d, err := f.DWARF()
+       if err != nil {
+               t.Fatal(err)
+       }
+       return d
+}
+
+
+func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf")) }
+
+func TestTypedefsMachO(t *testing.T) {
+       testTypedefs(t, machoData(t, "testdata/typedef.macho"))
+}
+
+func testTypedefs(t *testing.T, d *Data) {
+       r := d.Reader()
+       seen := make(map[string]bool)
+       for {
+               e, err := r.Next()
+               if err != nil {
+                       t.Fatal("r.Next:", err)
+               }
+               if e == nil {
+                       break
+               }
+               if e.Tag == TagTypedef {
+                       typ, err := d.Type(e.Offset)
+                       if err != nil {
+                               t.Fatal("d.Type:", err)
+                       }
+                       t1 := typ.(*TypedefType)
+                       var typstr string
+                       if ts, ok := t1.Type.(*StructType); ok {
+                               typstr = ts.Defn()
+                       } else {
+                               typstr = t1.Type.String()
+                       }
+
+                       if want, ok := typedefTests[t1.Name]; ok {
+                               if seen[t1.Name] {
+                                       t.Errorf("multiple definitions for %s", t1.Name)
+                               }
+                               seen[t1.Name] = true
+                               if typstr != want {
+                                       t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want)
+                               }
+                       }
+               }
+               if e.Tag != TagCompileUnit {
+                       r.SkipChildren()
+               }
+       }
+
+       for k := range typedefTests {
+               if !seen[k] {
+                       t.Errorf("missing %s", k)
+               }
+       }
+}
diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go
new file mode 100644 (file)
index 0000000..02cb363
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf
+
+import (
+       "os"
+       "strconv"
+)
+
+// DWARF debug info is split into a sequence of compilation units.
+// Each unit has its own abbreviation table and address size.
+
+type unit struct {
+       base     Offset // byte offset of header within the aggregate info
+       off      Offset // byte offset of data within the aggregate info
+       data     []byte
+       atable   abbrevTable
+       addrsize int
+}
+
+func (d *Data) parseUnits() ([]unit, os.Error) {
+       // Count units.
+       nunit := 0
+       b := makeBuf(d, "info", 0, d.info, 0)
+       for len(b.data) > 0 {
+               b.skip(int(b.uint32()))
+               nunit++
+       }
+       if b.err != nil {
+               return nil, b.err
+       }
+
+       // Again, this time writing them down.
+       b = makeBuf(d, "info", 0, d.info, 0)
+       units := make([]unit, nunit)
+       for i := range units {
+               u := &units[i]
+               u.base = b.off
+               n := b.uint32()
+               if vers := b.uint16(); vers != 2 {
+                       b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+                       break
+               }
+               atable, err := d.parseAbbrev(b.uint32())
+               if err != nil {
+                       if b.err == nil {
+                               b.err = err
+                       }
+                       break
+               }
+               u.atable = atable
+               u.addrsize = int(b.uint8())
+               u.off = b.off
+               u.data = b.bytes(int(n - (2 + 4 + 1)))
+       }
+       if b.err != nil {
+               return nil, b.err
+       }
+       return units, nil
+}
diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go
new file mode 100644 (file)
index 0000000..46d618c
--- /dev/null
@@ -0,0 +1,1503 @@
+/*
+ * ELF constants and data structures
+ *
+ * Derived from:
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
+ * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
+ * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
+ * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
+ * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
+ * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
+ *
+ * Copyright (c) 1996-1998 John D. Polstra.  All rights reserved.
+ * Copyright (c) 2001 David E. O'Brien
+ * Portions Copyright 2009 The Go 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:
+ * 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 THE AUTHOR 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 AUTHOR 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.
+ */
+
+package elf
+
+import "strconv"
+
+/*
+ * Constants
+ */
+
+// Indexes into the Header.Ident array.
+const (
+       EI_CLASS      = 4  /* Class of machine. */
+       EI_DATA       = 5  /* Data format. */
+       EI_VERSION    = 6  /* ELF format version. */
+       EI_OSABI      = 7  /* Operating system / ABI identification */
+       EI_ABIVERSION = 8  /* ABI version */
+       EI_PAD        = 9  /* Start of padding (per SVR4 ABI). */
+       EI_NIDENT     = 16 /* Size of e_ident array. */
+)
+
+// Initial magic number for ELF files.
+const ELFMAG = "\177ELF"
+
+// Version is found in Header.Ident[EI_VERSION] and Header.Version.
+type Version byte
+
+const (
+       EV_NONE    Version = 0
+       EV_CURRENT Version = 1
+)
+
+var versionStrings = []intName{
+       {0, "EV_NONE"},
+       {1, "EV_CURRENT"},
+}
+
+func (i Version) String() string   { return stringName(uint32(i), versionStrings, false) }
+func (i Version) GoString() string { return stringName(uint32(i), versionStrings, true) }
+
+// Class is found in Header.Ident[EI_CLASS] and Header.Class.
+type Class byte
+
+const (
+       ELFCLASSNONE Class = 0 /* Unknown class. */
+       ELFCLASS32   Class = 1 /* 32-bit architecture. */
+       ELFCLASS64   Class = 2 /* 64-bit architecture. */
+)
+
+var classStrings = []intName{
+       {0, "ELFCLASSNONE"},
+       {1, "ELFCLASS32"},
+       {2, "ELFCLASS64"},
+}
+
+func (i Class) String() string   { return stringName(uint32(i), classStrings, false) }
+func (i Class) GoString() string { return stringName(uint32(i), classStrings, true) }
+
+// Data is found in Header.Ident[EI_DATA] and Header.Data.
+type Data byte
+
+const (
+       ELFDATANONE Data = 0 /* Unknown data format. */
+       ELFDATA2LSB Data = 1 /* 2's complement little-endian. */
+       ELFDATA2MSB Data = 2 /* 2's complement big-endian. */
+)
+
+var dataStrings = []intName{
+       {0, "ELFDATANONE"},
+       {1, "ELFDATA2LSB"},
+       {2, "ELFDATA2MSB"},
+}
+
+func (i Data) String() string   { return stringName(uint32(i), dataStrings, false) }
+func (i Data) GoString() string { return stringName(uint32(i), dataStrings, true) }
+
+// OSABI is found in Header.Ident[EI_OSABI] and Header.OSABI.
+type OSABI byte
+
+const (
+       ELFOSABI_NONE       OSABI = 0   /* UNIX System V ABI */
+       ELFOSABI_HPUX       OSABI = 1   /* HP-UX operating system */
+       ELFOSABI_NETBSD     OSABI = 2   /* NetBSD */
+       ELFOSABI_LINUX      OSABI = 3   /* GNU/Linux */
+       ELFOSABI_HURD       OSABI = 4   /* GNU/Hurd */
+       ELFOSABI_86OPEN     OSABI = 5   /* 86Open common IA32 ABI */
+       ELFOSABI_SOLARIS    OSABI = 6   /* Solaris */
+       ELFOSABI_AIX        OSABI = 7   /* AIX */
+       ELFOSABI_IRIX       OSABI = 8   /* IRIX */
+       ELFOSABI_FREEBSD    OSABI = 9   /* FreeBSD */
+       ELFOSABI_TRU64      OSABI = 10  /* TRU64 UNIX */
+       ELFOSABI_MODESTO    OSABI = 11  /* Novell Modesto */
+       ELFOSABI_OPENBSD    OSABI = 12  /* OpenBSD */
+       ELFOSABI_OPENVMS    OSABI = 13  /* Open VMS */
+       ELFOSABI_NSK        OSABI = 14  /* HP Non-Stop Kernel */
+       ELFOSABI_ARM        OSABI = 97  /* ARM */
+       ELFOSABI_STANDALONE OSABI = 255 /* Standalone (embedded) application */
+)
+
+var osabiStrings = []intName{
+       {0, "ELFOSABI_NONE"},
+       {1, "ELFOSABI_HPUX"},
+       {2, "ELFOSABI_NETBSD"},
+       {3, "ELFOSABI_LINUX"},
+       {4, "ELFOSABI_HURD"},
+       {5, "ELFOSABI_86OPEN"},
+       {6, "ELFOSABI_SOLARIS"},
+       {7, "ELFOSABI_AIX"},
+       {8, "ELFOSABI_IRIX"},
+       {9, "ELFOSABI_FREEBSD"},
+       {10, "ELFOSABI_TRU64"},
+       {11, "ELFOSABI_MODESTO"},
+       {12, "ELFOSABI_OPENBSD"},
+       {13, "ELFOSABI_OPENVMS"},
+       {14, "ELFOSABI_NSK"},
+       {97, "ELFOSABI_ARM"},
+       {255, "ELFOSABI_STANDALONE"},
+}
+
+func (i OSABI) String() string   { return stringName(uint32(i), osabiStrings, false) }
+func (i OSABI) GoString() string { return stringName(uint32(i), osabiStrings, true) }
+
+// Type is found in Header.Type.
+type Type uint16
+
+const (
+       ET_NONE   Type = 0      /* Unknown type. */
+       ET_REL    Type = 1      /* Relocatable. */
+       ET_EXEC   Type = 2      /* Executable. */
+       ET_DYN    Type = 3      /* Shared object. */
+       ET_CORE   Type = 4      /* Core file. */
+       ET_LOOS   Type = 0xfe00 /* First operating system specific. */
+       ET_HIOS   Type = 0xfeff /* Last operating system-specific. */
+       ET_LOPROC Type = 0xff00 /* First processor-specific. */
+       ET_HIPROC Type = 0xffff /* Last processor-specific. */
+)
+
+var typeStrings = []intName{
+       {0, "ET_NONE"},
+       {1, "ET_REL"},
+       {2, "ET_EXEC"},
+       {3, "ET_DYN"},
+       {4, "ET_CORE"},
+       {0xfe00, "ET_LOOS"},
+       {0xfeff, "ET_HIOS"},
+       {0xff00, "ET_LOPROC"},
+       {0xffff, "ET_HIPROC"},
+}
+
+func (i Type) String() string   { return stringName(uint32(i), typeStrings, false) }
+func (i Type) GoString() string { return stringName(uint32(i), typeStrings, true) }
+
+// Machine is found in Header.Machine.
+type Machine uint16
+
+const (
+       EM_NONE        Machine = 0  /* Unknown machine. */
+       EM_M32         Machine = 1  /* AT&T WE32100. */
+       EM_SPARC       Machine = 2  /* Sun SPARC. */
+       EM_386         Machine = 3  /* Intel i386. */
+       EM_68K         Machine = 4  /* Motorola 68000. */
+       EM_88K         Machine = 5  /* Motorola 88000. */
+       EM_860         Machine = 7  /* Intel i860. */
+       EM_MIPS        Machine = 8  /* MIPS R3000 Big-Endian only. */
+       EM_S370        Machine = 9  /* IBM System/370. */
+       EM_MIPS_RS3_LE Machine = 10 /* MIPS R3000 Little-Endian. */
+       EM_PARISC      Machine = 15 /* HP PA-RISC. */
+       EM_VPP500      Machine = 17 /* Fujitsu VPP500. */
+       EM_SPARC32PLUS Machine = 18 /* SPARC v8plus. */
+       EM_960         Machine = 19 /* Intel 80960. */
+       EM_PPC         Machine = 20 /* PowerPC 32-bit. */
+       EM_PPC64       Machine = 21 /* PowerPC 64-bit. */
+       EM_S390        Machine = 22 /* IBM System/390. */
+       EM_V800        Machine = 36 /* NEC V800. */
+       EM_FR20        Machine = 37 /* Fujitsu FR20. */
+       EM_RH32        Machine = 38 /* TRW RH-32. */
+       EM_RCE         Machine = 39 /* Motorola RCE. */
+       EM_ARM         Machine = 40 /* ARM. */
+       EM_SH          Machine = 42 /* Hitachi SH. */
+       EM_SPARCV9     Machine = 43 /* SPARC v9 64-bit. */
+       EM_TRICORE     Machine = 44 /* Siemens TriCore embedded processor. */
+       EM_ARC         Machine = 45 /* Argonaut RISC Core. */
+       EM_H8_300      Machine = 46 /* Hitachi H8/300. */
+       EM_H8_300H     Machine = 47 /* Hitachi H8/300H. */
+       EM_H8S         Machine = 48 /* Hitachi H8S. */
+       EM_H8_500      Machine = 49 /* Hitachi H8/500. */
+       EM_IA_64       Machine = 50 /* Intel IA-64 Processor. */
+       EM_MIPS_X      Machine = 51 /* Stanford MIPS-X. */
+       EM_COLDFIRE    Machine = 52 /* Motorola ColdFire. */
+       EM_68HC12      Machine = 53 /* Motorola M68HC12. */
+       EM_MMA         Machine = 54 /* Fujitsu MMA. */
+       EM_PCP         Machine = 55 /* Siemens PCP. */
+       EM_NCPU        Machine = 56 /* Sony nCPU. */
+       EM_NDR1        Machine = 57 /* Denso NDR1 microprocessor. */
+       EM_STARCORE    Machine = 58 /* Motorola Star*Core processor. */
+       EM_ME16        Machine = 59 /* Toyota ME16 processor. */
+       EM_ST100       Machine = 60 /* STMicroelectronics ST100 processor. */
+       EM_TINYJ       Machine = 61 /* Advanced Logic Corp. TinyJ processor. */
+       EM_X86_64      Machine = 62 /* Advanced Micro Devices x86-64 */
+
+       /* Non-standard or deprecated. */
+       EM_486         Machine = 6      /* Intel i486. */
+       EM_MIPS_RS4_BE Machine = 10     /* MIPS R4000 Big-Endian */
+       EM_ALPHA_STD   Machine = 41     /* Digital Alpha (standard value). */
+       EM_ALPHA       Machine = 0x9026 /* Alpha (written in the absence of an ABI) */
+)
+
+var machineStrings = []intName{
+       {0, "EM_NONE"},
+       {1, "EM_M32"},
+       {2, "EM_SPARC"},
+       {3, "EM_386"},
+       {4, "EM_68K"},
+       {5, "EM_88K"},
+       {7, "EM_860"},
+       {8, "EM_MIPS"},
+       {9, "EM_S370"},
+       {10, "EM_MIPS_RS3_LE"},
+       {15, "EM_PARISC"},
+       {17, "EM_VPP500"},
+       {18, "EM_SPARC32PLUS"},
+       {19, "EM_960"},
+       {20, "EM_PPC"},
+       {21, "EM_PPC64"},
+       {22, "EM_S390"},
+       {36, "EM_V800"},
+       {37, "EM_FR20"},
+       {38, "EM_RH32"},
+       {39, "EM_RCE"},
+       {40, "EM_ARM"},
+       {42, "EM_SH"},
+       {43, "EM_SPARCV9"},
+       {44, "EM_TRICORE"},
+       {45, "EM_ARC"},
+       {46, "EM_H8_300"},
+       {47, "EM_H8_300H"},
+       {48, "EM_H8S"},
+       {49, "EM_H8_500"},
+       {50, "EM_IA_64"},
+       {51, "EM_MIPS_X"},
+       {52, "EM_COLDFIRE"},
+       {53, "EM_68HC12"},
+       {54, "EM_MMA"},
+       {55, "EM_PCP"},
+       {56, "EM_NCPU"},
+       {57, "EM_NDR1"},
+       {58, "EM_STARCORE"},
+       {59, "EM_ME16"},
+       {60, "EM_ST100"},
+       {61, "EM_TINYJ"},
+       {62, "EM_X86_64"},
+
+       /* Non-standard or deprecated. */
+       {6, "EM_486"},
+       {10, "EM_MIPS_RS4_BE"},
+       {41, "EM_ALPHA_STD"},
+       {0x9026, "EM_ALPHA"},
+}
+
+func (i Machine) String() string   { return stringName(uint32(i), machineStrings, false) }
+func (i Machine) GoString() string { return stringName(uint32(i), machineStrings, true) }
+
+// Special section indices.
+type SectionIndex int
+
+const (
+       SHN_UNDEF     SectionIndex = 0      /* Undefined, missing, irrelevant. */
+       SHN_LORESERVE SectionIndex = 0xff00 /* First of reserved range. */
+       SHN_LOPROC    SectionIndex = 0xff00 /* First processor-specific. */
+       SHN_HIPROC    SectionIndex = 0xff1f /* Last processor-specific. */
+       SHN_LOOS      SectionIndex = 0xff20 /* First operating system-specific. */
+       SHN_HIOS      SectionIndex = 0xff3f /* Last operating system-specific. */
+       SHN_ABS       SectionIndex = 0xfff1 /* Absolute values. */
+       SHN_COMMON    SectionIndex = 0xfff2 /* Common data. */
+       SHN_XINDEX    SectionIndex = 0xffff /* Escape -- index stored elsewhere. */
+       SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */
+)
+
+var shnStrings = []intName{
+       {0, "SHN_UNDEF"},
+       {0xff00, "SHN_LOPROC"},
+       {0xff20, "SHN_LOOS"},
+       {0xfff1, "SHN_ABS"},
+       {0xfff2, "SHN_COMMON"},
+       {0xffff, "SHN_XINDEX"},
+}
+
+func (i SectionIndex) String() string   { return stringName(uint32(i), shnStrings, false) }
+func (i SectionIndex) GoString() string { return stringName(uint32(i), shnStrings, true) }
+
+// Section type.
+type SectionType uint32
+
+const (
+       SHT_NULL          SectionType = 0          /* inactive */
+       SHT_PROGBITS      SectionType = 1          /* program defined information */
+       SHT_SYMTAB        SectionType = 2          /* symbol table section */
+       SHT_STRTAB        SectionType = 3          /* string table section */
+       SHT_RELA          SectionType = 4          /* relocation section with addends */
+       SHT_HASH          SectionType = 5          /* symbol hash table section */
+       SHT_DYNAMIC       SectionType = 6          /* dynamic section */
+       SHT_NOTE          SectionType = 7          /* note section */
+       SHT_NOBITS        SectionType = 8          /* no space section */
+       SHT_REL           SectionType = 9          /* relocation section - no addends */
+       SHT_SHLIB         SectionType = 10         /* reserved - purpose unknown */
+       SHT_DYNSYM        SectionType = 11         /* dynamic symbol table section */
+       SHT_INIT_ARRAY    SectionType = 14         /* Initialization function pointers. */
+       SHT_FINI_ARRAY    SectionType = 15         /* Termination function pointers. */
+       SHT_PREINIT_ARRAY SectionType = 16         /* Pre-initialization function ptrs. */
+       SHT_GROUP         SectionType = 17         /* Section group. */
+       SHT_SYMTAB_SHNDX  SectionType = 18         /* Section indexes (see SHN_XINDEX). */
+       SHT_LOOS          SectionType = 0x60000000 /* First of OS specific semantics */
+       SHT_HIOS          SectionType = 0x6fffffff /* Last of OS specific semantics */
+       SHT_LOPROC        SectionType = 0x70000000 /* reserved range for processor */
+       SHT_HIPROC        SectionType = 0x7fffffff /* specific section header types */
+       SHT_LOUSER        SectionType = 0x80000000 /* reserved range for application */
+       SHT_HIUSER        SectionType = 0xffffffff /* specific indexes */
+)
+
+var shtStrings = []intName{
+       {0, "SHT_NULL"},
+       {1, "SHT_PROGBITS"},
+       {2, "SHT_SYMTAB"},
+       {3, "SHT_STRTAB"},
+       {4, "SHT_RELA"},
+       {5, "SHT_HASH"},
+       {6, "SHT_DYNAMIC"},
+       {7, "SHT_NOTE"},
+       {8, "SHT_NOBITS"},
+       {9, "SHT_REL"},
+       {10, "SHT_SHLIB"},
+       {11, "SHT_DYNSYM"},
+       {14, "SHT_INIT_ARRAY"},
+       {15, "SHT_FINI_ARRAY"},
+       {16, "SHT_PREINIT_ARRAY"},
+       {17, "SHT_GROUP"},
+       {18, "SHT_SYMTAB_SHNDX"},
+       {0x60000000, "SHT_LOOS"},
+       {0x6fffffff, "SHT_HIOS"},
+       {0x70000000, "SHT_LOPROC"},
+       {0x7fffffff, "SHT_HIPROC"},
+       {0x80000000, "SHT_LOUSER"},
+       {0xffffffff, "SHT_HIUSER"},
+}
+
+func (i SectionType) String() string   { return stringName(uint32(i), shtStrings, false) }
+func (i SectionType) GoString() string { return stringName(uint32(i), shtStrings, true) }
+
+// Section flags.
+type SectionFlag uint32
+
+const (
+       SHF_WRITE            SectionFlag = 0x1        /* Section contains writable data. */
+       SHF_ALLOC            SectionFlag = 0x2        /* Section occupies memory. */
+       SHF_EXECINSTR        SectionFlag = 0x4        /* Section contains instructions. */
+       SHF_MERGE            SectionFlag = 0x10       /* Section may be merged. */
+       SHF_STRINGS          SectionFlag = 0x20       /* Section contains strings. */
+       SHF_INFO_LINK        SectionFlag = 0x40       /* sh_info holds section index. */
+       SHF_LINK_ORDER       SectionFlag = 0x80       /* Special ordering requirements. */
+       SHF_OS_NONCONFORMING SectionFlag = 0x100      /* OS-specific processing required. */
+       SHF_GROUP            SectionFlag = 0x200      /* Member of section group. */
+       SHF_TLS              SectionFlag = 0x400      /* Section contains TLS data. */
+       SHF_MASKOS           SectionFlag = 0x0ff00000 /* OS-specific semantics. */
+       SHF_MASKPROC         SectionFlag = 0xf0000000 /* Processor-specific semantics. */
+)
+
+var shfStrings = []intName{
+       {0x1, "SHF_WRITE"},
+       {0x2, "SHF_ALLOC"},
+       {0x4, "SHF_EXECINSTR"},
+       {0x10, "SHF_MERGE"},
+       {0x20, "SHF_STRINGS"},
+       {0x40, "SHF_INFO_LINK"},
+       {0x80, "SHF_LINK_ORDER"},
+       {0x100, "SHF_OS_NONCONFORMING"},
+       {0x200, "SHF_GROUP"},
+       {0x400, "SHF_TLS"},
+}
+
+func (i SectionFlag) String() string   { return flagName(uint32(i), shfStrings, false) }
+func (i SectionFlag) GoString() string { return flagName(uint32(i), shfStrings, true) }
+
+// Prog.Type
+type ProgType int
+
+const (
+       PT_NULL    ProgType = 0          /* Unused entry. */
+       PT_LOAD    ProgType = 1          /* Loadable segment. */
+       PT_DYNAMIC ProgType = 2          /* Dynamic linking information segment. */
+       PT_INTERP  ProgType = 3          /* Pathname of interpreter. */
+       PT_NOTE    ProgType = 4          /* Auxiliary information. */
+       PT_SHLIB   ProgType = 5          /* Reserved (not used). */
+       PT_PHDR    ProgType = 6          /* Location of program header itself. */
+       PT_TLS     ProgType = 7          /* Thread local storage segment */
+       PT_LOOS    ProgType = 0x60000000 /* First OS-specific. */
+       PT_HIOS    ProgType = 0x6fffffff /* Last OS-specific. */
+       PT_LOPROC  ProgType = 0x70000000 /* First processor-specific type. */
+       PT_HIPROC  ProgType = 0x7fffffff /* Last processor-specific type. */
+)
+
+var ptStrings = []intName{
+       {0, "PT_NULL"},
+       {1, "PT_LOAD"},
+       {2, "PT_DYNAMIC"},
+       {3, "PT_INTERP"},
+       {4, "PT_NOTE"},
+       {5, "PT_SHLIB"},
+       {6, "PT_PHDR"},
+       {7, "PT_TLS"},
+       {0x60000000, "PT_LOOS"},
+       {0x6fffffff, "PT_HIOS"},
+       {0x70000000, "PT_LOPROC"},
+       {0x7fffffff, "PT_HIPROC"},
+}
+
+func (i ProgType) String() string   { return stringName(uint32(i), ptStrings, false) }
+func (i ProgType) GoString() string { return stringName(uint32(i), ptStrings, true) }
+
+// Prog.Flag
+type ProgFlag uint32
+
+const (
+       PF_X        ProgFlag = 0x1        /* Executable. */
+       PF_W        ProgFlag = 0x2        /* Writable. */
+       PF_R        ProgFlag = 0x4        /* Readable. */
+       PF_MASKOS   ProgFlag = 0x0ff00000 /* Operating system-specific. */
+       PF_MASKPROC ProgFlag = 0xf0000000 /* Processor-specific. */
+)
+
+var pfStrings = []intName{
+       {0x1, "PF_X"},
+       {0x2, "PF_W"},
+       {0x4, "PF_R"},
+}
+
+func (i ProgFlag) String() string   { return flagName(uint32(i), pfStrings, false) }
+func (i ProgFlag) GoString() string { return flagName(uint32(i), pfStrings, true) }
+
+// Dyn.Tag
+type DynTag int
+
+const (
+       DT_NULL         DynTag = 0  /* Terminating entry. */
+       DT_NEEDED       DynTag = 1  /* String table offset of a needed shared library. */
+       DT_PLTRELSZ     DynTag = 2  /* Total size in bytes of PLT relocations. */
+       DT_PLTGOT       DynTag = 3  /* Processor-dependent address. */
+       DT_HASH         DynTag = 4  /* Address of symbol hash table. */
+       DT_STRTAB       DynTag = 5  /* Address of string table. */
+       DT_SYMTAB       DynTag = 6  /* Address of symbol table. */
+       DT_RELA         DynTag = 7  /* Address of ElfNN_Rela relocations. */
+       DT_RELASZ       DynTag = 8  /* Total size of ElfNN_Rela relocations. */
+       DT_RELAENT      DynTag = 9  /* Size of each ElfNN_Rela relocation entry. */
+       DT_STRSZ        DynTag = 10 /* Size of string table. */
+       DT_SYMENT       DynTag = 11 /* Size of each symbol table entry. */
+       DT_INIT         DynTag = 12 /* Address of initialization function. */
+       DT_FINI         DynTag = 13 /* Address of finalization function. */
+       DT_SONAME       DynTag = 14 /* String table offset of shared object name. */
+       DT_RPATH        DynTag = 15 /* String table offset of library path. [sup] */
+       DT_SYMBOLIC     DynTag = 16 /* Indicates "symbolic" linking. [sup] */
+       DT_REL          DynTag = 17 /* Address of ElfNN_Rel relocations. */
+       DT_RELSZ        DynTag = 18 /* Total size of ElfNN_Rel relocations. */
+       DT_RELENT       DynTag = 19 /* Size of each ElfNN_Rel relocation. */
+       DT_PLTREL       DynTag = 20 /* Type of relocation used for PLT. */
+       DT_DEBUG        DynTag = 21 /* Reserved (not used). */
+       DT_TEXTREL      DynTag = 22 /* Indicates there may be relocations in non-writable segments. [sup] */
+       DT_JMPREL       DynTag = 23 /* Address of PLT relocations. */
+       DT_BIND_NOW     DynTag = 24 /* [sup] */
+       DT_INIT_ARRAY   DynTag = 25 /* Address of the array of pointers to initialization functions */
+       DT_FINI_ARRAY   DynTag = 26 /* Address of the array of pointers to termination functions */
+       DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */
+       DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of terminationfunctions. */
+       DT_RUNPATH      DynTag = 29 /* String table offset of a null-terminated library search path string. */
+       DT_FLAGS        DynTag = 30 /* Object specific flag values. */
+       DT_ENCODING     DynTag = 32 /* Values greater than or equal to DT_ENCODING
+          and less than DT_LOOS follow the rules for
+          the interpretation of the d_un union
+          as follows: even == 'd_ptr', even == 'd_val'
+          or none */
+       DT_PREINIT_ARRAY   DynTag = 32         /* Address of the array of pointers to pre-initialization functions. */
+       DT_PREINIT_ARRAYSZ DynTag = 33         /* Size in bytes of the array of pre-initialization functions. */
+       DT_LOOS            DynTag = 0x6000000d /* First OS-specific */
+       DT_HIOS            DynTag = 0x6ffff000 /* Last OS-specific */
+       DT_LOPROC          DynTag = 0x70000000 /* First processor-specific type. */
+       DT_HIPROC          DynTag = 0x7fffffff /* Last processor-specific type. */
+)
+
+var dtStrings = []intName{
+       {0, "DT_NULL"},
+       {1, "DT_NEEDED"},
+       {2, "DT_PLTRELSZ"},
+       {3, "DT_PLTGOT"},
+       {4, "DT_HASH"},
+       {5, "DT_STRTAB"},
+       {6, "DT_SYMTAB"},
+       {7, "DT_RELA"},
+       {8, "DT_RELASZ"},
+       {9, "DT_RELAENT"},
+       {10, "DT_STRSZ"},
+       {11, "DT_SYMENT"},
+       {12, "DT_INIT"},
+       {13, "DT_FINI"},
+       {14, "DT_SONAME"},
+       {15, "DT_RPATH"},
+       {16, "DT_SYMBOLIC"},
+       {17, "DT_REL"},
+       {18, "DT_RELSZ"},
+       {19, "DT_RELENT"},
+       {20, "DT_PLTREL"},
+       {21, "DT_DEBUG"},
+       {22, "DT_TEXTREL"},
+       {23, "DT_JMPREL"},
+       {24, "DT_BIND_NOW"},
+       {25, "DT_INIT_ARRAY"},
+       {26, "DT_FINI_ARRAY"},
+       {27, "DT_INIT_ARRAYSZ"},
+       {28, "DT_FINI_ARRAYSZ"},
+       {29, "DT_RUNPATH"},
+       {30, "DT_FLAGS"},
+       {32, "DT_ENCODING"},
+       {32, "DT_PREINIT_ARRAY"},
+       {33, "DT_PREINIT_ARRAYSZ"},
+       {0x6000000d, "DT_LOOS"},
+       {0x6ffff000, "DT_HIOS"},
+       {0x70000000, "DT_LOPROC"},
+       {0x7fffffff, "DT_HIPROC"},
+}
+
+func (i DynTag) String() string   { return stringName(uint32(i), dtStrings, false) }
+func (i DynTag) GoString() string { return stringName(uint32(i), dtStrings, true) }
+
+// DT_FLAGS values.
+type DynFlag int
+
+const (
+       DF_ORIGIN DynFlag = 0x0001 /* Indicates that the object being loaded may
+          make reference to the
+          $ORIGIN substitution string */
+       DF_SYMBOLIC DynFlag = 0x0002 /* Indicates "symbolic" linking. */
+       DF_TEXTREL  DynFlag = 0x0004 /* Indicates there may be relocations in non-writable segments. */
+       DF_BIND_NOW DynFlag = 0x0008 /* Indicates that the dynamic linker should
+          process all relocations for the object
+          containing this entry before transferring
+          control to the program. */
+       DF_STATIC_TLS DynFlag = 0x0010 /* Indicates that the shared object or
+          executable contains code using a static
+          thread-local storage scheme. */
+)
+
+var dflagStrings = []intName{
+       {0x0001, "DF_ORIGIN"},
+       {0x0002, "DF_SYMBOLIC"},
+       {0x0004, "DF_TEXTREL"},
+       {0x0008, "DF_BIND_NOW"},
+       {0x0010, "DF_STATIC_TLS"},
+}
+
+func (i DynFlag) String() string   { return flagName(uint32(i), dflagStrings, false) }
+func (i DynFlag) GoString() string { return flagName(uint32(i), dflagStrings, true) }
+
+// NType values; used in core files.
+type NType int
+
+const (
+       NT_PRSTATUS NType = 1 /* Process status. */
+       NT_FPREGSET NType = 2 /* Floating point registers. */
+       NT_PRPSINFO NType = 3 /* Process state info. */
+)
+
+var ntypeStrings = []intName{
+       {1, "NT_PRSTATUS"},
+       {2, "NT_FPREGSET"},
+       {3, "NT_PRPSINFO"},
+}
+
+func (i NType) String() string   { return stringName(uint32(i), ntypeStrings, false) }
+func (i NType) GoString() string { return stringName(uint32(i), ntypeStrings, true) }
+
+/* Symbol Binding - ELFNN_ST_BIND - st_info */
+type SymBind int
+
+const (
+       STB_LOCAL  SymBind = 0  /* Local symbol */
+       STB_GLOBAL SymBind = 1  /* Global symbol */
+       STB_WEAK   SymBind = 2  /* like global - lower precedence */
+       STB_LOOS   SymBind = 10 /* Reserved range for operating system */
+       STB_HIOS   SymBind = 12 /*   specific semantics. */
+       STB_LOPROC SymBind = 13 /* reserved range for processor */
+       STB_HIPROC SymBind = 15 /*   specific semantics. */
+)
+
+var stbStrings = []intName{
+       {0, "STB_LOCAL"},
+       {1, "STB_GLOBAL"},
+       {2, "STB_WEAK"},
+       {10, "STB_LOOS"},
+       {12, "STB_HIOS"},
+       {13, "STB_LOPROC"},
+       {15, "STB_HIPROC"},
+}
+
+func (i SymBind) String() string   { return stringName(uint32(i), stbStrings, false) }
+func (i SymBind) GoString() string { return stringName(uint32(i), stbStrings, true) }
+
+/* Symbol type - ELFNN_ST_TYPE - st_info */
+type SymType int
+
+const (
+       STT_NOTYPE  SymType = 0  /* Unspecified type. */
+       STT_OBJECT  SymType = 1  /* Data object. */
+       STT_FUNC    SymType = 2  /* Function. */
+       STT_SECTION SymType = 3  /* Section. */
+       STT_FILE    SymType = 4  /* Source file. */
+       STT_COMMON  SymType = 5  /* Uninitialized common block. */
+       STT_TLS     SymType = 6  /* TLS object. */
+       STT_LOOS    SymType = 10 /* Reserved range for operating system */
+       STT_HIOS    SymType = 12 /*   specific semantics. */
+       STT_LOPROC  SymType = 13 /* reserved range for processor */
+       STT_HIPROC  SymType = 15 /*   specific semantics. */
+)
+
+var sttStrings = []intName{
+       {0, "STT_NOTYPE"},
+       {1, "STT_OBJECT"},
+       {2, "STT_FUNC"},
+       {3, "STT_SECTION"},
+       {4, "STT_FILE"},
+       {5, "STT_COMMON"},
+       {6, "STT_TLS"},
+       {10, "STT_LOOS"},
+       {12, "STT_HIOS"},
+       {13, "STT_LOPROC"},
+       {15, "STT_HIPROC"},
+}
+
+func (i SymType) String() string   { return stringName(uint32(i), sttStrings, false) }
+func (i SymType) GoString() string { return stringName(uint32(i), sttStrings, true) }
+
+/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
+type SymVis int
+
+const (
+       STV_DEFAULT   SymVis = 0x0 /* Default visibility (see binding). */
+       STV_INTERNAL  SymVis = 0x1 /* Special meaning in relocatable objects. */
+       STV_HIDDEN    SymVis = 0x2 /* Not visible. */
+       STV_PROTECTED SymVis = 0x3 /* Visible but not preemptible. */
+)
+
+var stvStrings = []intName{
+       {0x0, "STV_DEFAULT"},
+       {0x1, "STV_INTERNAL"},
+       {0x2, "STV_HIDDEN"},
+       {0x3, "STV_PROTECTED"},
+}
+
+func (i SymVis) String() string   { return stringName(uint32(i), stvStrings, false) }
+func (i SymVis) GoString() string { return stringName(uint32(i), stvStrings, true) }
+
+/*
+ * Relocation types.
+ */
+
+// Relocation types for x86-64.
+type R_X86_64 int
+
+const (
+       R_X86_64_NONE     R_X86_64 = 0  /* No relocation. */
+       R_X86_64_64       R_X86_64 = 1  /* Add 64 bit symbol value. */
+       R_X86_64_PC32     R_X86_64 = 2  /* PC-relative 32 bit signed sym value. */
+       R_X86_64_GOT32    R_X86_64 = 3  /* PC-relative 32 bit GOT offset. */
+       R_X86_64_PLT32    R_X86_64 = 4  /* PC-relative 32 bit PLT offset. */
+       R_X86_64_COPY     R_X86_64 = 5  /* Copy data from shared object. */
+       R_X86_64_GLOB_DAT R_X86_64 = 6  /* Set GOT entry to data address. */
+       R_X86_64_JMP_SLOT R_X86_64 = 7  /* Set GOT entry to code address. */
+       R_X86_64_RELATIVE R_X86_64 = 8  /* Add load address of shared object. */
+       R_X86_64_GOTPCREL R_X86_64 = 9  /* Add 32 bit signed pcrel offset to GOT. */
+       R_X86_64_32       R_X86_64 = 10 /* Add 32 bit zero extended symbol value */
+       R_X86_64_32S      R_X86_64 = 11 /* Add 32 bit sign extended symbol value */
+       R_X86_64_16       R_X86_64 = 12 /* Add 16 bit zero extended symbol value */
+       R_X86_64_PC16     R_X86_64 = 13 /* Add 16 bit signed extended pc relative symbol value */
+       R_X86_64_8        R_X86_64 = 14 /* Add 8 bit zero extended symbol value */
+       R_X86_64_PC8      R_X86_64 = 15 /* Add 8 bit signed extended pc relative symbol value */
+       R_X86_64_DTPMOD64 R_X86_64 = 16 /* ID of module containing symbol */
+       R_X86_64_DTPOFF64 R_X86_64 = 17 /* Offset in TLS block */
+       R_X86_64_TPOFF64  R_X86_64 = 18 /* Offset in static TLS block */
+       R_X86_64_TLSGD    R_X86_64 = 19 /* PC relative offset to GD GOT entry */
+       R_X86_64_TLSLD    R_X86_64 = 20 /* PC relative offset to LD GOT entry */
+       R_X86_64_DTPOFF32 R_X86_64 = 21 /* Offset in TLS block */
+       R_X86_64_GOTTPOFF R_X86_64 = 22 /* PC relative offset to IE GOT entry */
+       R_X86_64_TPOFF32  R_X86_64 = 23 /* Offset in static TLS block */
+)
+
+var rx86_64Strings = []intName{
+       {0, "R_X86_64_NONE"},
+       {1, "R_X86_64_64"},
+       {2, "R_X86_64_PC32"},
+       {3, "R_X86_64_GOT32"},
+       {4, "R_X86_64_PLT32"},
+       {5, "R_X86_64_COPY"},
+       {6, "R_X86_64_GLOB_DAT"},
+       {7, "R_X86_64_JMP_SLOT"},
+       {8, "R_X86_64_RELATIVE"},
+       {9, "R_X86_64_GOTPCREL"},
+       {10, "R_X86_64_32"},
+       {11, "R_X86_64_32S"},
+       {12, "R_X86_64_16"},
+       {13, "R_X86_64_PC16"},
+       {14, "R_X86_64_8"},
+       {15, "R_X86_64_PC8"},
+       {16, "R_X86_64_DTPMOD64"},
+       {17, "R_X86_64_DTPOFF64"},
+       {18, "R_X86_64_TPOFF64"},
+       {19, "R_X86_64_TLSGD"},
+       {20, "R_X86_64_TLSLD"},
+       {21, "R_X86_64_DTPOFF32"},
+       {22, "R_X86_64_GOTTPOFF"},
+       {23, "R_X86_64_TPOFF32"},
+}
+
+func (i R_X86_64) String() string   { return stringName(uint32(i), rx86_64Strings, false) }
+func (i R_X86_64) GoString() string { return stringName(uint32(i), rx86_64Strings, true) }
+
+// Relocation types for Alpha.
+type R_ALPHA int
+
+const (
+       R_ALPHA_NONE           R_ALPHA = 0  /* No reloc */
+       R_ALPHA_REFLONG        R_ALPHA = 1  /* Direct 32 bit */
+       R_ALPHA_REFQUAD        R_ALPHA = 2  /* Direct 64 bit */
+       R_ALPHA_GPREL32        R_ALPHA = 3  /* GP relative 32 bit */
+       R_ALPHA_LITERAL        R_ALPHA = 4  /* GP relative 16 bit w/optimization */
+       R_ALPHA_LITUSE         R_ALPHA = 5  /* Optimization hint for LITERAL */
+       R_ALPHA_GPDISP         R_ALPHA = 6  /* Add displacement to GP */
+       R_ALPHA_BRADDR         R_ALPHA = 7  /* PC+4 relative 23 bit shifted */
+       R_ALPHA_HINT           R_ALPHA = 8  /* PC+4 relative 16 bit shifted */
+       R_ALPHA_SREL16         R_ALPHA = 9  /* PC relative 16 bit */
+       R_ALPHA_SREL32         R_ALPHA = 10 /* PC relative 32 bit */
+       R_ALPHA_SREL64         R_ALPHA = 11 /* PC relative 64 bit */
+       R_ALPHA_OP_PUSH        R_ALPHA = 12 /* OP stack push */
+       R_ALPHA_OP_STORE       R_ALPHA = 13 /* OP stack pop and store */
+       R_ALPHA_OP_PSUB        R_ALPHA = 14 /* OP stack subtract */
+       R_ALPHA_OP_PRSHIFT     R_ALPHA = 15 /* OP stack right shift */
+       R_ALPHA_GPVALUE        R_ALPHA = 16
+       R_ALPHA_GPRELHIGH      R_ALPHA = 17
+       R_ALPHA_GPRELLOW       R_ALPHA = 18
+       R_ALPHA_IMMED_GP_16    R_ALPHA = 19
+       R_ALPHA_IMMED_GP_HI32  R_ALPHA = 20
+       R_ALPHA_IMMED_SCN_HI32 R_ALPHA = 21
+       R_ALPHA_IMMED_BR_HI32  R_ALPHA = 22
+       R_ALPHA_IMMED_LO32     R_ALPHA = 23
+       R_ALPHA_COPY           R_ALPHA = 24 /* Copy symbol at runtime */
+       R_ALPHA_GLOB_DAT       R_ALPHA = 25 /* Create GOT entry */
+       R_ALPHA_JMP_SLOT       R_ALPHA = 26 /* Create PLT entry */
+       R_ALPHA_RELATIVE       R_ALPHA = 27 /* Adjust by program base */
+)
+
+var ralphaStrings = []intName{
+       {0, "R_ALPHA_NONE"},
+       {1, "R_ALPHA_REFLONG"},
+       {2, "R_ALPHA_REFQUAD"},
+       {3, "R_ALPHA_GPREL32"},
+       {4, "R_ALPHA_LITERAL"},
+       {5, "R_ALPHA_LITUSE"},
+       {6, "R_ALPHA_GPDISP"},
+       {7, "R_ALPHA_BRADDR"},
+       {8, "R_ALPHA_HINT"},
+       {9, "R_ALPHA_SREL16"},
+       {10, "R_ALPHA_SREL32"},
+       {11, "R_ALPHA_SREL64"},
+       {12, "R_ALPHA_OP_PUSH"},
+       {13, "R_ALPHA_OP_STORE"},
+       {14, "R_ALPHA_OP_PSUB"},
+       {15, "R_ALPHA_OP_PRSHIFT"},
+       {16, "R_ALPHA_GPVALUE"},
+       {17, "R_ALPHA_GPRELHIGH"},
+       {18, "R_ALPHA_GPRELLOW"},
+       {19, "R_ALPHA_IMMED_GP_16"},
+       {20, "R_ALPHA_IMMED_GP_HI32"},
+       {21, "R_ALPHA_IMMED_SCN_HI32"},
+       {22, "R_ALPHA_IMMED_BR_HI32"},
+       {23, "R_ALPHA_IMMED_LO32"},
+       {24, "R_ALPHA_COPY"},
+       {25, "R_ALPHA_GLOB_DAT"},
+       {26, "R_ALPHA_JMP_SLOT"},
+       {27, "R_ALPHA_RELATIVE"},
+}
+
+func (i R_ALPHA) String() string   { return stringName(uint32(i), ralphaStrings, false) }
+func (i R_ALPHA) GoString() string { return stringName(uint32(i), ralphaStrings, true) }
+
+// Relocation types for ARM.
+type R_ARM int
+
+const (
+       R_ARM_NONE          R_ARM = 0 /* No relocation. */
+       R_ARM_PC24          R_ARM = 1
+       R_ARM_ABS32         R_ARM = 2
+       R_ARM_REL32         R_ARM = 3
+       R_ARM_PC13          R_ARM = 4
+       R_ARM_ABS16         R_ARM = 5
+       R_ARM_ABS12         R_ARM = 6
+       R_ARM_THM_ABS5      R_ARM = 7
+       R_ARM_ABS8          R_ARM = 8
+       R_ARM_SBREL32       R_ARM = 9
+       R_ARM_THM_PC22      R_ARM = 10
+       R_ARM_THM_PC8       R_ARM = 11
+       R_ARM_AMP_VCALL9    R_ARM = 12
+       R_ARM_SWI24         R_ARM = 13
+       R_ARM_THM_SWI8      R_ARM = 14
+       R_ARM_XPC25         R_ARM = 15
+       R_ARM_THM_XPC22     R_ARM = 16
+       R_ARM_COPY          R_ARM = 20 /* Copy data from shared object. */
+       R_ARM_GLOB_DAT      R_ARM = 21 /* Set GOT entry to data address. */
+       R_ARM_JUMP_SLOT     R_ARM = 22 /* Set GOT entry to code address. */
+       R_ARM_RELATIVE      R_ARM = 23 /* Add load address of shared object. */
+       R_ARM_GOTOFF        R_ARM = 24 /* Add GOT-relative symbol address. */
+       R_ARM_GOTPC         R_ARM = 25 /* Add PC-relative GOT table address. */
+       R_ARM_GOT32         R_ARM = 26 /* Add PC-relative GOT offset. */
+       R_ARM_PLT32         R_ARM = 27 /* Add PC-relative PLT offset. */
+       R_ARM_GNU_VTENTRY   R_ARM = 100
+       R_ARM_GNU_VTINHERIT R_ARM = 101
+       R_ARM_RSBREL32      R_ARM = 250
+       R_ARM_THM_RPC22     R_ARM = 251
+       R_ARM_RREL32        R_ARM = 252
+       R_ARM_RABS32        R_ARM = 253
+       R_ARM_RPC24         R_ARM = 254
+       R_ARM_RBASE         R_ARM = 255
+)
+
+var rarmStrings = []intName{
+       {0, "R_ARM_NONE"},
+       {1, "R_ARM_PC24"},
+       {2, "R_ARM_ABS32"},
+       {3, "R_ARM_REL32"},
+       {4, "R_ARM_PC13"},
+       {5, "R_ARM_ABS16"},
+       {6, "R_ARM_ABS12"},
+       {7, "R_ARM_THM_ABS5"},
+       {8, "R_ARM_ABS8"},
+       {9, "R_ARM_SBREL32"},
+       {10, "R_ARM_THM_PC22"},
+       {11, "R_ARM_THM_PC8"},
+       {12, "R_ARM_AMP_VCALL9"},
+       {13, "R_ARM_SWI24"},
+       {14, "R_ARM_THM_SWI8"},
+       {15, "R_ARM_XPC25"},
+       {16, "R_ARM_THM_XPC22"},
+       {20, "R_ARM_COPY"},
+       {21, "R_ARM_GLOB_DAT"},
+       {22, "R_ARM_JUMP_SLOT"},
+       {23, "R_ARM_RELATIVE"},
+       {24, "R_ARM_GOTOFF"},
+       {25, "R_ARM_GOTPC"},
+       {26, "R_ARM_GOT32"},
+       {27, "R_ARM_PLT32"},
+       {100, "R_ARM_GNU_VTENTRY"},
+       {101, "R_ARM_GNU_VTINHERIT"},
+       {250, "R_ARM_RSBREL32"},
+       {251, "R_ARM_THM_RPC22"},
+       {252, "R_ARM_RREL32"},
+       {253, "R_ARM_RABS32"},
+       {254, "R_ARM_RPC24"},
+       {255, "R_ARM_RBASE"},
+}
+
+func (i R_ARM) String() string   { return stringName(uint32(i), rarmStrings, false) }
+func (i R_ARM) GoString() string { return stringName(uint32(i), rarmStrings, true) }
+
+// Relocation types for 386.
+type R_386 int
+
+const (
+       R_386_NONE         R_386 = 0  /* No relocation. */
+       R_386_32           R_386 = 1  /* Add symbol value. */
+       R_386_PC32         R_386 = 2  /* Add PC-relative symbol value. */
+       R_386_GOT32        R_386 = 3  /* Add PC-relative GOT offset. */
+       R_386_PLT32        R_386 = 4  /* Add PC-relative PLT offset. */
+       R_386_COPY         R_386 = 5  /* Copy data from shared object. */
+       R_386_GLOB_DAT     R_386 = 6  /* Set GOT entry to data address. */
+       R_386_JMP_SLOT     R_386 = 7  /* Set GOT entry to code address. */
+       R_386_RELATIVE     R_386 = 8  /* Add load address of shared object. */
+       R_386_GOTOFF       R_386 = 9  /* Add GOT-relative symbol address. */
+       R_386_GOTPC        R_386 = 10 /* Add PC-relative GOT table address. */
+       R_386_TLS_TPOFF    R_386 = 14 /* Negative offset in static TLS block */
+       R_386_TLS_IE       R_386 = 15 /* Absolute address of GOT for -ve static TLS */
+       R_386_TLS_GOTIE    R_386 = 16 /* GOT entry for negative static TLS block */
+       R_386_TLS_LE       R_386 = 17 /* Negative offset relative to static TLS */
+       R_386_TLS_GD       R_386 = 18 /* 32 bit offset to GOT (index,off) pair */
+       R_386_TLS_LDM      R_386 = 19 /* 32 bit offset to GOT (index,zero) pair */
+       R_386_TLS_GD_32    R_386 = 24 /* 32 bit offset to GOT (index,off) pair */
+       R_386_TLS_GD_PUSH  R_386 = 25 /* pushl instruction for Sun ABI GD sequence */
+       R_386_TLS_GD_CALL  R_386 = 26 /* call instruction for Sun ABI GD sequence */
+       R_386_TLS_GD_POP   R_386 = 27 /* popl instruction for Sun ABI GD sequence */
+       R_386_TLS_LDM_32   R_386 = 28 /* 32 bit offset to GOT (index,zero) pair */
+       R_386_TLS_LDM_PUSH R_386 = 29 /* pushl instruction for Sun ABI LD sequence */
+       R_386_TLS_LDM_CALL R_386 = 30 /* call instruction for Sun ABI LD sequence */
+       R_386_TLS_LDM_POP  R_386 = 31 /* popl instruction for Sun ABI LD sequence */
+       R_386_TLS_LDO_32   R_386 = 32 /* 32 bit offset from start of TLS block */
+       R_386_TLS_IE_32    R_386 = 33 /* 32 bit offset to GOT static TLS offset entry */
+       R_386_TLS_LE_32    R_386 = 34 /* 32 bit offset within static TLS block */
+       R_386_TLS_DTPMOD32 R_386 = 35 /* GOT entry containing TLS index */
+       R_386_TLS_DTPOFF32 R_386 = 36 /* GOT entry containing TLS offset */
+       R_386_TLS_TPOFF32  R_386 = 37 /* GOT entry of -ve static TLS offset */
+)
+
+var r386Strings = []intName{
+       {0, "R_386_NONE"},
+       {1, "R_386_32"},
+       {2, "R_386_PC32"},
+       {3, "R_386_GOT32"},
+       {4, "R_386_PLT32"},
+       {5, "R_386_COPY"},
+       {6, "R_386_GLOB_DAT"},
+       {7, "R_386_JMP_SLOT"},
+       {8, "R_386_RELATIVE"},
+       {9, "R_386_GOTOFF"},
+       {10, "R_386_GOTPC"},
+       {14, "R_386_TLS_TPOFF"},
+       {15, "R_386_TLS_IE"},
+       {16, "R_386_TLS_GOTIE"},
+       {17, "R_386_TLS_LE"},
+       {18, "R_386_TLS_GD"},
+       {19, "R_386_TLS_LDM"},
+       {24, "R_386_TLS_GD_32"},
+       {25, "R_386_TLS_GD_PUSH"},
+       {26, "R_386_TLS_GD_CALL"},
+       {27, "R_386_TLS_GD_POP"},
+       {28, "R_386_TLS_LDM_32"},
+       {29, "R_386_TLS_LDM_PUSH"},
+       {30, "R_386_TLS_LDM_CALL"},
+       {31, "R_386_TLS_LDM_POP"},
+       {32, "R_386_TLS_LDO_32"},
+       {33, "R_386_TLS_IE_32"},
+       {34, "R_386_TLS_LE_32"},
+       {35, "R_386_TLS_DTPMOD32"},
+       {36, "R_386_TLS_DTPOFF32"},
+       {37, "R_386_TLS_TPOFF32"},
+}
+
+func (i R_386) String() string   { return stringName(uint32(i), r386Strings, false) }
+func (i R_386) GoString() string { return stringName(uint32(i), r386Strings, true) }
+
+// Relocation types for PowerPC.
+type R_PPC int
+
+const (
+       R_PPC_NONE            R_PPC = 0 /* No relocation. */
+       R_PPC_ADDR32          R_PPC = 1
+       R_PPC_ADDR24          R_PPC = 2
+       R_PPC_ADDR16          R_PPC = 3
+       R_PPC_ADDR16_LO       R_PPC = 4
+       R_PPC_ADDR16_HI       R_PPC = 5
+       R_PPC_ADDR16_HA       R_PPC = 6
+       R_PPC_ADDR14          R_PPC = 7
+       R_PPC_ADDR14_BRTAKEN  R_PPC = 8
+       R_PPC_ADDR14_BRNTAKEN R_PPC = 9
+       R_PPC_REL24           R_PPC = 10
+       R_PPC_REL14           R_PPC = 11
+       R_PPC_REL14_BRTAKEN   R_PPC = 12
+       R_PPC_REL14_BRNTAKEN  R_PPC = 13
+       R_PPC_GOT16           R_PPC = 14
+       R_PPC_GOT16_LO        R_PPC = 15
+       R_PPC_GOT16_HI        R_PPC = 16
+       R_PPC_GOT16_HA        R_PPC = 17
+       R_PPC_PLTREL24        R_PPC = 18
+       R_PPC_COPY            R_PPC = 19
+       R_PPC_GLOB_DAT        R_PPC = 20
+       R_PPC_JMP_SLOT        R_PPC = 21
+       R_PPC_RELATIVE        R_PPC = 22
+       R_PPC_LOCAL24PC       R_PPC = 23
+       R_PPC_UADDR32         R_PPC = 24
+       R_PPC_UADDR16         R_PPC = 25
+       R_PPC_REL32           R_PPC = 26
+       R_PPC_PLT32           R_PPC = 27
+       R_PPC_PLTREL32        R_PPC = 28
+       R_PPC_PLT16_LO        R_PPC = 29
+       R_PPC_PLT16_HI        R_PPC = 30
+       R_PPC_PLT16_HA        R_PPC = 31
+       R_PPC_SDAREL16        R_PPC = 32
+       R_PPC_SECTOFF         R_PPC = 33
+       R_PPC_SECTOFF_LO      R_PPC = 34
+       R_PPC_SECTOFF_HI      R_PPC = 35
+       R_PPC_SECTOFF_HA      R_PPC = 36
+       R_PPC_TLS             R_PPC = 67
+       R_PPC_DTPMOD32        R_PPC = 68
+       R_PPC_TPREL16         R_PPC = 69
+       R_PPC_TPREL16_LO      R_PPC = 70
+       R_PPC_TPREL16_HI      R_PPC = 71
+       R_PPC_TPREL16_HA      R_PPC = 72
+       R_PPC_TPREL32         R_PPC = 73
+       R_PPC_DTPREL16        R_PPC = 74
+       R_PPC_DTPREL16_LO     R_PPC = 75
+       R_PPC_DTPREL16_HI     R_PPC = 76
+       R_PPC_DTPREL16_HA     R_PPC = 77
+       R_PPC_DTPREL32        R_PPC = 78
+       R_PPC_GOT_TLSGD16     R_PPC = 79
+       R_PPC_GOT_TLSGD16_LO  R_PPC = 80
+       R_PPC_GOT_TLSGD16_HI  R_PPC = 81
+       R_PPC_GOT_TLSGD16_HA  R_PPC = 82
+       R_PPC_GOT_TLSLD16     R_PPC = 83
+       R_PPC_GOT_TLSLD16_LO  R_PPC = 84
+       R_PPC_GOT_TLSLD16_HI  R_PPC = 85
+       R_PPC_GOT_TLSLD16_HA  R_PPC = 86
+       R_PPC_GOT_TPREL16     R_PPC = 87
+       R_PPC_GOT_TPREL16_LO  R_PPC = 88
+       R_PPC_GOT_TPREL16_HI  R_PPC = 89
+       R_PPC_GOT_TPREL16_HA  R_PPC = 90
+       R_PPC_EMB_NADDR32     R_PPC = 101
+       R_PPC_EMB_NADDR16     R_PPC = 102
+       R_PPC_EMB_NADDR16_LO  R_PPC = 103
+       R_PPC_EMB_NADDR16_HI  R_PPC = 104
+       R_PPC_EMB_NADDR16_HA  R_PPC = 105
+       R_PPC_EMB_SDAI16      R_PPC = 106
+       R_PPC_EMB_SDA2I16     R_PPC = 107
+       R_PPC_EMB_SDA2REL     R_PPC = 108
+       R_PPC_EMB_SDA21       R_PPC = 109
+       R_PPC_EMB_MRKREF      R_PPC = 110
+       R_PPC_EMB_RELSEC16    R_PPC = 111
+       R_PPC_EMB_RELST_LO    R_PPC = 112
+       R_PPC_EMB_RELST_HI    R_PPC = 113
+       R_PPC_EMB_RELST_HA    R_PPC = 114
+       R_PPC_EMB_BIT_FLD     R_PPC = 115
+       R_PPC_EMB_RELSDA      R_PPC = 116
+)
+
+var rppcStrings = []intName{
+       {0, "R_PPC_NONE"},
+       {1, "R_PPC_ADDR32"},
+       {2, "R_PPC_ADDR24"},
+       {3, "R_PPC_ADDR16"},
+       {4, "R_PPC_ADDR16_LO"},
+       {5, "R_PPC_ADDR16_HI"},
+       {6, "R_PPC_ADDR16_HA"},
+       {7, "R_PPC_ADDR14"},
+       {8, "R_PPC_ADDR14_BRTAKEN"},
+       {9, "R_PPC_ADDR14_BRNTAKEN"},
+       {10, "R_PPC_REL24"},
+       {11, "R_PPC_REL14"},
+       {12, "R_PPC_REL14_BRTAKEN"},
+       {13, "R_PPC_REL14_BRNTAKEN"},
+       {14, "R_PPC_GOT16"},
+       {15, "R_PPC_GOT16_LO"},
+       {16, "R_PPC_GOT16_HI"},
+       {17, "R_PPC_GOT16_HA"},
+       {18, "R_PPC_PLTREL24"},
+       {19, "R_PPC_COPY"},
+       {20, "R_PPC_GLOB_DAT"},
+       {21, "R_PPC_JMP_SLOT"},
+       {22, "R_PPC_RELATIVE"},
+       {23, "R_PPC_LOCAL24PC"},
+       {24, "R_PPC_UADDR32"},
+       {25, "R_PPC_UADDR16"},
+       {26, "R_PPC_REL32"},
+       {27, "R_PPC_PLT32"},
+       {28, "R_PPC_PLTREL32"},
+       {29, "R_PPC_PLT16_LO"},
+       {30, "R_PPC_PLT16_HI"},
+       {31, "R_PPC_PLT16_HA"},
+       {32, "R_PPC_SDAREL16"},
+       {33, "R_PPC_SECTOFF"},
+       {34, "R_PPC_SECTOFF_LO"},
+       {35, "R_PPC_SECTOFF_HI"},
+       {36, "R_PPC_SECTOFF_HA"},
+
+       {67, "R_PPC_TLS"},
+       {68, "R_PPC_DTPMOD32"},
+       {69, "R_PPC_TPREL16"},
+       {70, "R_PPC_TPREL16_LO"},
+       {71, "R_PPC_TPREL16_HI"},
+       {72, "R_PPC_TPREL16_HA"},
+       {73, "R_PPC_TPREL32"},
+       {74, "R_PPC_DTPREL16"},
+       {75, "R_PPC_DTPREL16_LO"},
+       {76, "R_PPC_DTPREL16_HI"},
+       {77, "R_PPC_DTPREL16_HA"},
+       {78, "R_PPC_DTPREL32"},
+       {79, "R_PPC_GOT_TLSGD16"},
+       {80, "R_PPC_GOT_TLSGD16_LO"},
+       {81, "R_PPC_GOT_TLSGD16_HI"},
+       {82, "R_PPC_GOT_TLSGD16_HA"},
+       {83, "R_PPC_GOT_TLSLD16"},
+       {84, "R_PPC_GOT_TLSLD16_LO"},
+       {85, "R_PPC_GOT_TLSLD16_HI"},
+       {86, "R_PPC_GOT_TLSLD16_HA"},
+       {87, "R_PPC_GOT_TPREL16"},
+       {88, "R_PPC_GOT_TPREL16_LO"},
+       {89, "R_PPC_GOT_TPREL16_HI"},
+       {90, "R_PPC_GOT_TPREL16_HA"},
+
+       {101, "R_PPC_EMB_NADDR32"},
+       {102, "R_PPC_EMB_NADDR16"},
+       {103, "R_PPC_EMB_NADDR16_LO"},
+       {104, "R_PPC_EMB_NADDR16_HI"},
+       {105, "R_PPC_EMB_NADDR16_HA"},
+       {106, "R_PPC_EMB_SDAI16"},
+       {107, "R_PPC_EMB_SDA2I16"},
+       {108, "R_PPC_EMB_SDA2REL"},
+       {109, "R_PPC_EMB_SDA21"},
+       {110, "R_PPC_EMB_MRKREF"},
+       {111, "R_PPC_EMB_RELSEC16"},
+       {112, "R_PPC_EMB_RELST_LO"},
+       {113, "R_PPC_EMB_RELST_HI"},
+       {114, "R_PPC_EMB_RELST_HA"},
+       {115, "R_PPC_EMB_BIT_FLD"},
+       {116, "R_PPC_EMB_RELSDA"},
+}
+
+func (i R_PPC) String() string   { return stringName(uint32(i), rppcStrings, false) }
+func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) }
+
+// Relocation types for SPARC.
+type R_SPARC int
+
+const (
+       R_SPARC_NONE     R_SPARC = 0
+       R_SPARC_8        R_SPARC = 1
+       R_SPARC_16       R_SPARC = 2
+       R_SPARC_32       R_SPARC = 3
+       R_SPARC_DISP8    R_SPARC = 4
+       R_SPARC_DISP16   R_SPARC = 5
+       R_SPARC_DISP32   R_SPARC = 6
+       R_SPARC_WDISP30  R_SPARC = 7
+       R_SPARC_WDISP22  R_SPARC = 8
+       R_SPARC_HI22     R_SPARC = 9
+       R_SPARC_22       R_SPARC = 10
+       R_SPARC_13       R_SPARC = 11
+       R_SPARC_LO10     R_SPARC = 12
+       R_SPARC_GOT10    R_SPARC = 13
+       R_SPARC_GOT13    R_SPARC = 14
+       R_SPARC_GOT22    R_SPARC = 15
+       R_SPARC_PC10     R_SPARC = 16
+       R_SPARC_PC22     R_SPARC = 17
+       R_SPARC_WPLT30   R_SPARC = 18
+       R_SPARC_COPY     R_SPARC = 19
+       R_SPARC_GLOB_DAT R_SPARC = 20
+       R_SPARC_JMP_SLOT R_SPARC = 21
+       R_SPARC_RELATIVE R_SPARC = 22
+       R_SPARC_UA32     R_SPARC = 23
+       R_SPARC_PLT32    R_SPARC = 24
+       R_SPARC_HIPLT22  R_SPARC = 25
+       R_SPARC_LOPLT10  R_SPARC = 26
+       R_SPARC_PCPLT32  R_SPARC = 27
+       R_SPARC_PCPLT22  R_SPARC = 28
+       R_SPARC_PCPLT10  R_SPARC = 29
+       R_SPARC_10       R_SPARC = 30
+       R_SPARC_11       R_SPARC = 31
+       R_SPARC_64       R_SPARC = 32
+       R_SPARC_OLO10    R_SPARC = 33
+       R_SPARC_HH22     R_SPARC = 34
+       R_SPARC_HM10     R_SPARC = 35
+       R_SPARC_LM22     R_SPARC = 36
+       R_SPARC_PC_HH22  R_SPARC = 37
+       R_SPARC_PC_HM10  R_SPARC = 38
+       R_SPARC_PC_LM22  R_SPARC = 39
+       R_SPARC_WDISP16  R_SPARC = 40
+       R_SPARC_WDISP19  R_SPARC = 41
+       R_SPARC_GLOB_JMP R_SPARC = 42
+       R_SPARC_7        R_SPARC = 43
+       R_SPARC_5        R_SPARC = 44
+       R_SPARC_6        R_SPARC = 45
+       R_SPARC_DISP64   R_SPARC = 46
+       R_SPARC_PLT64    R_SPARC = 47
+       R_SPARC_HIX22    R_SPARC = 48
+       R_SPARC_LOX10    R_SPARC = 49
+       R_SPARC_H44      R_SPARC = 50
+       R_SPARC_M44      R_SPARC = 51
+       R_SPARC_L44      R_SPARC = 52
+       R_SPARC_REGISTER R_SPARC = 53
+       R_SPARC_UA64     R_SPARC = 54
+       R_SPARC_UA16     R_SPARC = 55
+)
+
+var rsparcStrings = []intName{
+       {0, "R_SPARC_NONE"},
+       {1, "R_SPARC_8"},
+       {2, "R_SPARC_16"},
+       {3, "R_SPARC_32"},
+       {4, "R_SPARC_DISP8"},
+       {5, "R_SPARC_DISP16"},
+       {6, "R_SPARC_DISP32"},
+       {7, "R_SPARC_WDISP30"},
+       {8, "R_SPARC_WDISP22"},
+       {9, "R_SPARC_HI22"},
+       {10, "R_SPARC_22"},
+       {11, "R_SPARC_13"},
+       {12, "R_SPARC_LO10"},
+       {13, "R_SPARC_GOT10"},
+       {14, "R_SPARC_GOT13"},
+       {15, "R_SPARC_GOT22"},
+       {16, "R_SPARC_PC10"},
+       {17, "R_SPARC_PC22"},
+       {18, "R_SPARC_WPLT30"},
+       {19, "R_SPARC_COPY"},
+       {20, "R_SPARC_GLOB_DAT"},
+       {21, "R_SPARC_JMP_SLOT"},
+       {22, "R_SPARC_RELATIVE"},
+       {23, "R_SPARC_UA32"},
+       {24, "R_SPARC_PLT32"},
+       {25, "R_SPARC_HIPLT22"},
+       {26, "R_SPARC_LOPLT10"},
+       {27, "R_SPARC_PCPLT32"},
+       {28, "R_SPARC_PCPLT22"},
+       {29, "R_SPARC_PCPLT10"},
+       {30, "R_SPARC_10"},
+       {31, "R_SPARC_11"},
+       {32, "R_SPARC_64"},
+       {33, "R_SPARC_OLO10"},
+       {34, "R_SPARC_HH22"},
+       {35, "R_SPARC_HM10"},
+       {36, "R_SPARC_LM22"},
+       {37, "R_SPARC_PC_HH22"},
+       {38, "R_SPARC_PC_HM10"},
+       {39, "R_SPARC_PC_LM22"},
+       {40, "R_SPARC_WDISP16"},
+       {41, "R_SPARC_WDISP19"},
+       {42, "R_SPARC_GLOB_JMP"},
+       {43, "R_SPARC_7"},
+       {44, "R_SPARC_5"},
+       {45, "R_SPARC_6"},
+       {46, "R_SPARC_DISP64"},
+       {47, "R_SPARC_PLT64"},
+       {48, "R_SPARC_HIX22"},
+       {49, "R_SPARC_LOX10"},
+       {50, "R_SPARC_H44"},
+       {51, "R_SPARC_M44"},
+       {52, "R_SPARC_L44"},
+       {53, "R_SPARC_REGISTER"},
+       {54, "R_SPARC_UA64"},
+       {55, "R_SPARC_UA16"},
+}
+
+func (i R_SPARC) String() string   { return stringName(uint32(i), rsparcStrings, false) }
+func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings, true) }
+
+// Magic number for the elf trampoline, chosen wisely to be an immediate value.
+const ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
+
+
+// ELF32 File header.
+type Header32 struct {
+       Ident     [EI_NIDENT]byte /* File identification. */
+       Type      uint16          /* File type. */
+       Machine   uint16          /* Machine architecture. */
+       Version   uint32          /* ELF format version. */
+       Entry     uint32          /* Entry point. */
+       Phoff     uint32          /* Program header file offset. */
+       Shoff     uint32          /* Section header file offset. */
+       Flags     uint32          /* Architecture-specific flags. */
+       Ehsize    uint16          /* Size of ELF header in bytes. */
+       Phentsize uint16          /* Size of program header entry. */
+       Phnum     uint16          /* Number of program header entries. */
+       Shentsize uint16          /* Size of section header entry. */
+       Shnum     uint16          /* Number of section header entries. */
+       Shstrndx  uint16          /* Section name strings section. */
+}
+
+// ELF32 Section header.
+type Section32 struct {
+       Name      uint32 /* Section name (index into the section header string table). */
+       Type      uint32 /* Section type. */
+       Flags     uint32 /* Section flags. */
+       Addr      uint32 /* Address in memory image. */
+       Off       uint32 /* Offset in file. */
+       Size      uint32 /* Size in bytes. */
+       Link      uint32 /* Index of a related section. */
+       Info      uint32 /* Depends on section type. */
+       Addralign uint32 /* Alignment in bytes. */
+       Entsize   uint32 /* Size of each entry in section. */
+}
+
+// ELF32 Program header.
+type Prog32 struct {
+       Type   uint32 /* Entry type. */
+       Off    uint32 /* File offset of contents. */
+       Vaddr  uint32 /* Virtual address in memory image. */
+       Paddr  uint32 /* Physical address (not used). */
+       Filesz uint32 /* Size of contents in file. */
+       Memsz  uint32 /* Size of contents in memory. */
+       Flags  uint32 /* Access permission flags. */
+       Align  uint32 /* Alignment in memory and file. */
+}
+
+// ELF32 Dynamic structure.  The ".dynamic" section contains an array of them.
+type Dyn32 struct {
+       Tag int32  /* Entry type. */
+       Val uint32 /* Integer/Address value. */
+}
+
+/*
+ * Relocation entries.
+ */
+
+// ELF32 Relocations that don't need an addend field.
+type Rel32 struct {
+       Off  uint32 /* Location to be relocated. */
+       Info uint32 /* Relocation type and symbol index. */
+}
+
+// ELF32 Relocations that need an addend field.
+type Rela32 struct {
+       Off    uint32 /* Location to be relocated. */
+       Info   uint32 /* Relocation type and symbol index. */
+       Addend int32  /* Addend. */
+}
+
+func R_SYM32(info uint32) uint32      { return uint32(info >> 8) }
+func R_TYPE32(info uint32) uint32     { return uint32(info & 0xff) }
+func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ }
+
+// ELF32 Symbol.
+type Sym32 struct {
+       Name  uint32
+       Value uint32
+       Size  uint32
+       Info  uint8
+       Other uint8
+       Shndx uint16
+}
+
+const Sym32Size = 16
+
+func ST_BIND(info uint8) SymBind              { return SymBind(info >> 4) }
+func ST_TYPE(bind SymBind, typ SymType) uint8 { return uint8(bind)<<4 | uint8(typ)&0xf }
+func ST_VISIBILITY(other uint8) SymVis        { return SymVis(other & 3) }
+
+/*
+ * ELF64
+ */
+
+// ELF64 file header.
+type Header64 struct {
+       Ident     [EI_NIDENT]byte /* File identification. */
+       Type      uint16          /* File type. */
+       Machine   uint16          /* Machine architecture. */
+       Version   uint32          /* ELF format version. */
+       Entry     uint64          /* Entry point. */
+       Phoff     uint64          /* Program header file offset. */
+       Shoff     uint64          /* Section header file offset. */
+       Flags     uint32          /* Architecture-specific flags. */
+       Ehsize    uint16          /* Size of ELF header in bytes. */
+       Phentsize uint16          /* Size of program header entry. */
+       Phnum     uint16          /* Number of program header entries. */
+       Shentsize uint16          /* Size of section header entry. */
+       Shnum     uint16          /* Number of section header entries. */
+       Shstrndx  uint16          /* Section name strings section. */
+}
+
+// ELF64 Section header.
+type Section64 struct {
+       Name      uint32 /* Section name (index into the section header string table). */
+       Type      uint32 /* Section type. */
+       Flags     uint64 /* Section flags. */
+       Addr      uint64 /* Address in memory image. */
+       Off       uint64 /* Offset in file. */
+       Size      uint64 /* Size in bytes. */
+       Link      uint32 /* Index of a related section. */
+       Info      uint32 /* Depends on section type. */
+       Addralign uint64 /* Alignment in bytes. */
+       Entsize   uint64 /* Size of each entry in section. */
+}
+
+// ELF64 Program header.
+type Prog64 struct {
+       Type   uint32 /* Entry type. */
+       Flags  uint32 /* Access permission flags. */
+       Off    uint64 /* File offset of contents. */
+       Vaddr  uint64 /* Virtual address in memory image. */
+       Paddr  uint64 /* Physical address (not used). */
+       Filesz uint64 /* Size of contents in file. */
+       Memsz  uint64 /* Size of contents in memory. */
+       Align  uint64 /* Alignment in memory and file. */
+}
+
+// ELF64 Dynamic structure.  The ".dynamic" section contains an array of them.
+type Dyn64 struct {
+       Tag int64  /* Entry type. */
+       Val uint64 /* Integer/address value */
+}
+
+/*
+ * Relocation entries.
+ */
+
+/* ELF64 relocations that don't need an addend field. */
+type Rel64 struct {
+       Off  uint64 /* Location to be relocated. */
+       Info uint64 /* Relocation type and symbol index. */
+}
+
+/* ELF64 relocations that need an addend field. */
+type Rela64 struct {
+       Off    uint64 /* Location to be relocated. */
+       Info   uint64 /* Relocation type and symbol index. */
+       Addend int64  /* Addend. */
+}
+
+func R_SYM64(info uint64) uint32    { return uint32(info >> 32) }
+func R_TYPE64(info uint64) uint32   { return uint32(info) }
+func R_INFO(sym, typ uint32) uint64 { return uint64(sym)<<32 | uint64(typ) }
+
+
+// ELF64 symbol table entries.
+type Sym64 struct {
+       Name  uint32 /* String table index of name. */
+       Info  uint8  /* Type and binding information. */
+       Other uint8  /* Reserved (not used). */
+       Shndx uint16 /* Section index of symbol. */
+       Value uint64 /* Symbol value. */
+       Size  uint64 /* Size of associated object. */
+}
+
+const Sym64Size = 24
+
+type intName struct {
+       i uint32
+       s string
+}
+
+func stringName(i uint32, names []intName, goSyntax bool) string {
+       for _, n := range names {
+               if n.i == i {
+                       if goSyntax {
+                               return "elf." + n.s
+                       }
+                       return n.s
+               }
+       }
+
+       // second pass - look for smaller to add with.
+       // assume sorted already
+       for j := len(names) - 1; j >= 0; j-- {
+               n := names[j]
+               if n.i < i {
+                       s := n.s
+                       if goSyntax {
+                               s = "elf." + s
+                       }
+                       return s + "+" + strconv.Uitoa64(uint64(i-n.i))
+               }
+       }
+
+       return strconv.Uitoa64(uint64(i))
+}
+
+func flagName(i uint32, names []intName, goSyntax bool) string {
+       s := ""
+       for _, n := range names {
+               if n.i&i == n.i {
+                       if len(s) > 0 {
+                               s += "+"
+                       }
+                       if goSyntax {
+                               s += "elf."
+                       }
+                       s += n.s
+                       i -= n.i
+               }
+       }
+       if len(s) == 0 {
+               return "0x" + strconv.Uitob64(uint64(i), 16)
+       }
+       if i != 0 {
+               s += "+0x" + strconv.Uitob64(uint64(i), 16)
+       }
+       return s
+}
diff --git a/libgo/go/debug/elf/elf_test.go b/libgo/go/debug/elf/elf_test.go
new file mode 100644 (file)
index 0000000..67b961b
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elf
+
+import (
+       "fmt"
+       "testing"
+)
+
+type nameTest struct {
+       val interface{}
+       str string
+}
+
+var nameTests = []nameTest{
+       {ELFOSABI_LINUX, "ELFOSABI_LINUX"},
+       {ET_EXEC, "ET_EXEC"},
+       {EM_860, "EM_860"},
+       {SHN_LOPROC, "SHN_LOPROC"},
+       {SHT_PROGBITS, "SHT_PROGBITS"},
+       {SHF_MERGE + SHF_TLS, "SHF_MERGE+SHF_TLS"},
+       {PT_LOAD, "PT_LOAD"},
+       {PF_W + PF_R + 0x50, "PF_W+PF_R+0x50"},
+       {DT_SYMBOLIC, "DT_SYMBOLIC"},
+       {DF_BIND_NOW, "DF_BIND_NOW"},
+       {NT_FPREGSET, "NT_FPREGSET"},
+       {STB_GLOBAL, "STB_GLOBAL"},
+       {STT_COMMON, "STT_COMMON"},
+       {STV_HIDDEN, "STV_HIDDEN"},
+       {R_X86_64_PC32, "R_X86_64_PC32"},
+       {R_ALPHA_OP_PUSH, "R_ALPHA_OP_PUSH"},
+       {R_ARM_THM_ABS5, "R_ARM_THM_ABS5"},
+       {R_386_GOT32, "R_386_GOT32"},
+       {R_PPC_GOT16_HI, "R_PPC_GOT16_HI"},
+       {R_SPARC_GOT22, "R_SPARC_GOT22"},
+       {ET_LOOS + 5, "ET_LOOS+5"},
+       {ProgFlag(0x50), "0x50"},
+}
+
+func TestNames(t *testing.T) {
+       for i, tt := range nameTests {
+               s := fmt.Sprint(tt.val)
+               if s != tt.str {
+                       t.Errorf("#%d: want %q have %q", i, s, tt.str)
+               }
+       }
+}
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
new file mode 100644 (file)
index 0000000..568370b
--- /dev/null
@@ -0,0 +1,480 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package elf implements access to ELF object files.
+package elf
+
+import (
+       "bytes"
+       "debug/dwarf"
+       "encoding/binary"
+       "fmt"
+       "io"
+       "os"
+)
+
+// TODO: error reporting detail
+
+/*
+ * Internal ELF representation
+ */
+
+// A FileHeader represents an ELF file header.
+type FileHeader struct {
+       Class      Class
+       Data       Data
+       Version    Version
+       OSABI      OSABI
+       ABIVersion uint8
+       ByteOrder  binary.ByteOrder
+       Type       Type
+       Machine    Machine
+}
+
+// A File represents an open ELF file.
+type File struct {
+       FileHeader
+       Sections []*Section
+       Progs    []*Prog
+       closer   io.Closer
+}
+
+// A SectionHeader represents a single ELF section header.
+type SectionHeader struct {
+       Name      string
+       Type      SectionType
+       Flags     SectionFlag
+       Addr      uint64
+       Offset    uint64
+       Size      uint64
+       Link      uint32
+       Info      uint32
+       Addralign uint64
+       Entsize   uint64
+}
+
+// A Section represents a single section in an ELF file.
+type Section struct {
+       SectionHeader
+
+       // Embed ReaderAt for ReadAt method.
+       // Do not embed SectionReader directly
+       // to avoid having Read and Seek.
+       // If a client wants Read and Seek it must use
+       // Open() to avoid fighting over the seek offset
+       // with other clients.
+       io.ReaderAt
+       sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the ELF section.
+func (s *Section) Data() ([]byte, os.Error) {
+       dat := make([]byte, s.sr.Size())
+       n, err := s.sr.ReadAt(dat, 0)
+       return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the ELF section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+// A ProgHeader represents a single ELF program header.
+type ProgHeader struct {
+       Type   ProgType
+       Flags  ProgFlag
+       Vaddr  uint64
+       Paddr  uint64
+       Filesz uint64
+       Memsz  uint64
+       Align  uint64
+}
+
+// A Prog represents a single ELF program header in an ELF binary.
+type Prog struct {
+       ProgHeader
+
+       // Embed ReaderAt for ReadAt method.
+       // Do not embed SectionReader directly
+       // to avoid having Read and Seek.
+       // If a client wants Read and Seek it must use
+       // Open() to avoid fighting over the seek offset
+       // with other clients.
+       io.ReaderAt
+       sr *io.SectionReader
+}
+
+// Open returns a new ReadSeeker reading the ELF program body.
+func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
+
+// A Symbol represents an entry in an ELF symbol table section.
+type Symbol struct {
+       Name        uint32
+       Info, Other byte
+       Section     uint32
+       Value, Size uint64
+}
+
+/*
+ * ELF reader
+ */
+
+type FormatError struct {
+       off int64
+       msg string
+       val interface{}
+}
+
+func (e *FormatError) String() string {
+       msg := e.msg
+       if e.val != nil {
+               msg += fmt.Sprintf(" '%v' ", e.val)
+       }
+       msg += fmt.Sprintf("in record at byte %#x", e.off)
+       return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as an ELF binary.
+func Open(name string) (*File, os.Error) {
+       f, err := os.Open(name, os.O_RDONLY, 0)
+       if err != nil {
+               return nil, err
+       }
+       ff, err := NewFile(f)
+       if err != nil {
+               f.Close()
+               return nil, err
+       }
+       ff.closer = f
+       return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() os.Error {
+       var err os.Error
+       if f.closer != nil {
+               err = f.closer.Close()
+               f.closer = nil
+       }
+       return err
+}
+
+// NewFile creates a new File for accessing an ELF binary in an underlying reader.
+// The ELF binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+       sr := io.NewSectionReader(r, 0, 1<<63-1)
+       // Read and decode ELF identifier
+       var ident [16]uint8
+       if _, err := r.ReadAt(ident[0:], 0); err != nil {
+               return nil, err
+       }
+       if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
+               return nil, &FormatError{0, "bad magic number", ident[0:4]}
+       }
+
+       f := new(File)
+       f.Class = Class(ident[EI_CLASS])
+       switch f.Class {
+       case ELFCLASS32:
+       case ELFCLASS64:
+               // ok
+       default:
+               return nil, &FormatError{0, "unknown ELF class", f.Class}
+       }
+
+       f.Data = Data(ident[EI_DATA])
+       switch f.Data {
+       case ELFDATA2LSB:
+               f.ByteOrder = binary.LittleEndian
+       case ELFDATA2MSB:
+               f.ByteOrder = binary.BigEndian
+       default:
+               return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
+       }
+
+       f.Version = Version(ident[EI_VERSION])
+       if f.Version != EV_CURRENT {
+               return nil, &FormatError{0, "unknown ELF version", f.Version}
+       }
+
+       f.OSABI = OSABI(ident[EI_OSABI])
+       f.ABIVersion = ident[EI_ABIVERSION]
+
+       // Read ELF file header
+       var shoff int64
+       var shentsize, shnum, shstrndx int
+       shstrndx = -1
+       switch f.Class {
+       case ELFCLASS32:
+               hdr := new(Header32)
+               sr.Seek(0, 0)
+               if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
+                       return nil, err
+               }
+               f.Type = Type(hdr.Type)
+               f.Machine = Machine(hdr.Machine)
+               if v := Version(hdr.Version); v != f.Version {
+                       return nil, &FormatError{0, "mismatched ELF version", v}
+               }
+               shoff = int64(hdr.Shoff)
+               shentsize = int(hdr.Shentsize)
+               shnum = int(hdr.Shnum)
+               shstrndx = int(hdr.Shstrndx)
+       case ELFCLASS64:
+               hdr := new(Header64)
+               sr.Seek(0, 0)
+               if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
+                       return nil, err
+               }
+               f.Type = Type(hdr.Type)
+               f.Machine = Machine(hdr.Machine)
+               if v := Version(hdr.Version); v != f.Version {
+                       return nil, &FormatError{0, "mismatched ELF version", v}
+               }
+               shoff = int64(hdr.Shoff)
+               shentsize = int(hdr.Shentsize)
+               shnum = int(hdr.Shnum)
+               shstrndx = int(hdr.Shstrndx)
+       }
+       if shstrndx < 0 || shstrndx >= shnum {
+               return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
+       }
+
+       // Read program headers
+       // TODO
+
+       // Read section headers
+       f.Sections = make([]*Section, shnum)
+       names := make([]uint32, shnum)
+       for i := 0; i < shnum; i++ {
+               off := shoff + int64(i)*int64(shentsize)
+               sr.Seek(off, 0)
+               s := new(Section)
+               switch f.Class {
+               case ELFCLASS32:
+                       sh := new(Section32)
+                       if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
+                               return nil, err
+                       }
+                       names[i] = sh.Name
+                       s.SectionHeader = SectionHeader{
+                               Type:      SectionType(sh.Type),
+                               Flags:     SectionFlag(sh.Flags),
+                               Addr:      uint64(sh.Addr),
+                               Offset:    uint64(sh.Off),
+                               Size:      uint64(sh.Size),
+                               Link:      uint32(sh.Link),
+                               Info:      uint32(sh.Info),
+                               Addralign: uint64(sh.Addralign),
+                               Entsize:   uint64(sh.Entsize),
+                       }
+               case ELFCLASS64:
+                       sh := new(Section64)
+                       if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
+                               return nil, err
+                       }
+                       names[i] = sh.Name
+                       s.SectionHeader = SectionHeader{
+                               Type:      SectionType(sh.Type),
+                               Flags:     SectionFlag(sh.Flags),
+                               Offset:    uint64(sh.Off),
+                               Size:      uint64(sh.Size),
+                               Addr:      uint64(sh.Addr),
+                               Link:      uint32(sh.Link),
+                               Info:      uint32(sh.Info),
+                               Addralign: uint64(sh.Addralign),
+                               Entsize:   uint64(sh.Entsize),
+                       }
+               }
+               s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
+               s.ReaderAt = s.sr
+               f.Sections[i] = s
+       }
+
+       // Load section header string table.
+       s := f.Sections[shstrndx]
+       shstrtab := make([]byte, s.Size)
+       if _, err := r.ReadAt(shstrtab, int64(s.Offset)); err != nil {
+               return nil, err
+       }
+       for i, s := range f.Sections {
+               var ok bool
+               s.Name, ok = getString(shstrtab, int(names[i]))
+               if !ok {
+                       return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
+               }
+       }
+
+       return f, nil
+}
+
+func (f *File) getSymbols() ([]Symbol, os.Error) {
+       switch f.Class {
+       case ELFCLASS64:
+               return f.getSymbols64()
+       }
+
+       return nil, os.ErrorString("not implemented")
+}
+
+// GetSymbols returns a slice of Symbols from parsing the symbol table.
+func (f *File) getSymbols64() ([]Symbol, os.Error) {
+       var symtabSection *Section
+       for _, section := range f.Sections {
+               if section.Type == SHT_SYMTAB {
+                       symtabSection = section
+                       break
+               }
+       }
+
+       if symtabSection == nil {
+               return nil, os.ErrorString("no symbol section")
+       }
+
+       data, err := symtabSection.Data()
+       if err != nil {
+               return nil, os.ErrorString("cannot load symbol section")
+       }
+       symtab := bytes.NewBuffer(data)
+       if symtab.Len()%Sym64Size != 0 {
+               return nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size")
+       }
+
+       // The first entry is all zeros.
+       var skip [Sym64Size]byte
+       symtab.Read(skip[0:])
+
+       symbols := make([]Symbol, symtab.Len()/Sym64Size)
+
+       i := 0
+       var sym Sym64
+       for symtab.Len() > 0 {
+               binary.Read(symtab, f.ByteOrder, &sym)
+               symbols[i].Name = sym.Name
+               symbols[i].Info = sym.Info
+               symbols[i].Other = sym.Other
+               symbols[i].Section = uint32(sym.Shndx)
+               symbols[i].Value = sym.Value
+               symbols[i].Size = sym.Size
+               i++
+       }
+
+       return symbols, nil
+}
+
+// getString extracts a string from an ELF string table.
+func getString(section []byte, start int) (string, bool) {
+       if start < 0 || start >= len(section) {
+               return "", false
+       }
+
+       for end := start; end < len(section); end++ {
+               if section[end] == 0 {
+                       return string(section[start:end]), true
+               }
+       }
+       return "", false
+}
+
+// Section returns a section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+       for _, s := range f.Sections {
+               if s.Name == name {
+                       return s
+               }
+       }
+       return nil
+}
+
+// applyRelocations applies relocations to dst. rels is a relocations section
+// in RELA format.
+func (f *File) applyRelocations(dst []byte, rels []byte) os.Error {
+       if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
+               return f.applyRelocationsAMD64(dst, rels)
+       }
+
+       return os.ErrorString("not implemented")
+}
+
+func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
+       if len(rels)%Sym64Size != 0 {
+               return os.ErrorString("length of relocation section is not a multiple of Sym64Size")
+       }
+
+       symbols, err := f.getSymbols()
+       if err != nil {
+               return err
+       }
+
+       b := bytes.NewBuffer(rels)
+       var rela Rela64
+
+       for b.Len() > 0 {
+               binary.Read(b, f.ByteOrder, &rela)
+               symNo := rela.Info >> 32
+               t := R_X86_64(rela.Info & 0xffff)
+
+               if symNo >= uint64(len(symbols)) {
+                       continue
+               }
+               sym := &symbols[symNo]
+               if SymType(sym.Info&0xf) != STT_SECTION {
+                       // We don't handle non-section relocations for now.
+                       continue
+               }
+
+               switch t {
+               case R_X86_64_64:
+                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+                               continue
+                       }
+                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+               case R_X86_64_32:
+                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+                               continue
+                       }
+                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+               }
+       }
+
+       return nil
+}
+
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+       // There are many other DWARF sections, but these
+       // are the required ones, and the debug/dwarf package
+       // does not use the others, so don't bother loading them.
+       var names = [...]string{"abbrev", "info", "str"}
+       var dat [len(names)][]byte
+       for i, name := range names {
+               name = ".debug_" + name
+               s := f.Section(name)
+               if s == nil {
+                       continue
+               }
+               b, err := s.Data()
+               if err != nil && uint64(len(b)) < s.Size {
+                       return nil, err
+               }
+               dat[i] = b
+       }
+
+       // If there's a relocation table for .debug_info, we have to process it
+       // now otherwise the data in .debug_info is invalid for x86-64 objects.
+       rela := f.Section(".rela.debug_info")
+       if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
+               data, err := rela.Data()
+               if err != nil {
+                       return nil, err
+               }
+               err = f.applyRelocations(dat[1], data)
+               if err != nil {
+                       return nil, err
+               }
+       }
+
+       abbrev, info, str := dat[0], dat[1], dat[2]
+       return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go
new file mode 100644 (file)
index 0000000..84068ea
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elf
+
+import (
+       "debug/dwarf"
+       "encoding/binary"
+       "reflect"
+       "testing"
+)
+
+type fileTest struct {
+       file     string
+       hdr      FileHeader
+       sections []SectionHeader
+}
+
+var fileTests = []fileTest{
+       {
+               "testdata/gcc-386-freebsd-exec",
+               FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386},
+               []SectionHeader{
+                       {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+                       {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
+                       {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
+                       {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
+                       {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
+                       {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
+                       {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
+                       {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
+                       {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
+                       {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
+                       {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
+                       {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
+                       {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
+                       {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
+                       {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
+                       {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
+                       {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
+                       {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
+                       {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
+                       {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
+                       {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
+                       {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
+                       {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
+                       {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
+               },
+       },
+       {
+               "testdata/gcc-amd64-linux-exec",
+               FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64},
+               []SectionHeader{
+                       {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+                       {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
+                       {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
+                       {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
+                       {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
+                       {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
+                       {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
+                       {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
+                       {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
+                       {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
+                       {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
+                       {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
+                       {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
+                       {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
+                       {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
+                       {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
+                       {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
+                       {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
+                       {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
+                       {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
+                       {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
+                       {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
+                       {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
+                       {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
+                       {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
+                       {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
+                       {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
+                       {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
+                       {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
+                       {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
+                       {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
+                       {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
+                       {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
+               },
+       },
+}
+
+func TestOpen(t *testing.T) {
+       for i := range fileTests {
+               tt := &fileTests[i]
+
+               f, err := Open(tt.file)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+               if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+                       t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+                       continue
+               }
+               for i, s := range f.Sections {
+                       if i >= len(tt.sections) {
+                               break
+                       }
+                       sh := &tt.sections[i]
+                       if !reflect.DeepEqual(&s.SectionHeader, sh) {
+                               t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
+                       }
+               }
+               tn := len(tt.sections)
+               fn := len(f.Sections)
+               if tn != fn {
+                       t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+               }
+       }
+}
+
+type relocationTest struct {
+       file       string
+       firstEntry *dwarf.Entry
+}
+
+var relocationTests = []relocationTest{
+       {
+               "testdata/go-relocation-test-gcc441-x86-64.o",
+               &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+       },
+       {
+               "testdata/go-relocation-test-gcc441-x86.o",
+               &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+       },
+       {
+               "testdata/go-relocation-test-gcc424-x86-64.o",
+               &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+       },
+}
+
+func TestDWARFRelocations(t *testing.T) {
+       for i, test := range relocationTests {
+               f, err := Open(test.file)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+               dwarf, err := f.DWARF()
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+               reader := dwarf.Reader()
+               // Checking only the first entry is sufficient since it has
+               // many different strings. If the relocation had failed, all
+               // the string offsets would be zero and all the strings would
+               // end up being the same.
+               firstEntry, err := reader.Next()
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+
+               if !reflect.DeepEqual(test.firstEntry, firstEntry) {
+                       t.Errorf("#%d: mismatch: got:%#v want:%#v", i, firstEntry, test.firstEntry)
+                       continue
+               }
+       }
+}
diff --git a/libgo/go/debug/elf/testdata/gcc-386-freebsd-exec b/libgo/go/debug/elf/testdata/gcc-386-freebsd-exec
new file mode 100755 (executable)
index 0000000..7af9c58
Binary files /dev/null and b/libgo/go/debug/elf/testdata/gcc-386-freebsd-exec differ
diff --git a/libgo/go/debug/elf/testdata/gcc-amd64-linux-exec b/libgo/go/debug/elf/testdata/gcc-amd64-linux-exec
new file mode 100755 (executable)
index 0000000..c6cb1de
Binary files /dev/null and b/libgo/go/debug/elf/testdata/gcc-amd64-linux-exec differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o b/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o
new file mode 100644 (file)
index 0000000..a7c6d6e
Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o
new file mode 100644 (file)
index 0000000..2d37ab6
Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o
new file mode 100644 (file)
index 0000000..0d59fe3
Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o differ
diff --git a/libgo/go/debug/gosym/pclinetest.h b/libgo/go/debug/gosym/pclinetest.h
new file mode 100644 (file)
index 0000000..a6c40e7
--- /dev/null
@@ -0,0 +1,7 @@
+// Empty include file to generate z symbols
+
+
+
+
+
+// EOF
diff --git a/libgo/go/debug/gosym/pclinetest.s b/libgo/go/debug/gosym/pclinetest.s
new file mode 100644 (file)
index 0000000..519656b
--- /dev/null
@@ -0,0 +1,89 @@
+TEXT linefrompc(SB),7,$0       // Each byte stores its line delta
+BYTE $2;
+BYTE $1;
+BYTE $1; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1;
+BYTE $1;
+BYTE $1; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+#include "pclinetest.h"
+BYTE $2;
+#include "pclinetest.h"
+BYTE $2;
+
+TEXT pcfromline(SB),7,$0       // Each record stores its line delta, then n, then n more bytes
+BYTE $31; BYTE $0;
+BYTE $1; BYTE $1; BYTE $0;
+BYTE $1; BYTE $0;
+
+BYTE $2; BYTE $4; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+
+
+#include "pclinetest.h"
+BYTE $4; BYTE $0;
+
+
+BYTE $3; BYTE $3; BYTE $0; BYTE $0; BYTE $0;
+#include "pclinetest.h"
+
+
+BYTE $4; BYTE $3; BYTE $0; BYTE $0; BYTE $0;
+
+TEXT main(SB),7,$0
+       // Prevent GC of our test symbols
+       CALL linefrompc(SB)
+       CALL pcfromline(SB)
+
+// Keep the linker happy
+TEXT runtime·morestack(SB),7,$0
+       RET
+
+TEXT runtime·morestack00(SB),7,$0
+       RET
+
+TEXT runtime·morestack10(SB),7,$0
+       RET
+
+TEXT runtime·morestack01(SB),7,$0
+       RET
+
+TEXT runtime·morestack11(SB),7,$0
+       RET
+
+TEXT runtime·morestack8(SB),7,$0
+       RET
+
+TEXT runtime·morestack16(SB),7,$0
+       RET
+
+TEXT runtime·morestack24(SB),7,$0
+       RET
+
+TEXT runtime·morestack32(SB),7,$0
+       RET
+
+TEXT runtime·morestack40(SB),7,$0
+       RET
+
+TEXT runtime·morestack48(SB),7,$0
+       RET
+
+TEXT runtime·morestack8(SB),7,$0
+       RET
+
diff --git a/libgo/go/debug/gosym/pclntab.go b/libgo/go/debug/gosym/pclntab.go
new file mode 100644 (file)
index 0000000..9d7b0d1
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Line tables
+ */
+
+package gosym
+
+import "encoding/binary"
+
+type LineTable struct {
+       Data []byte
+       PC   uint64
+       Line int
+}
+
+// TODO(rsc): Need to pull in quantum from architecture definition.
+const quantum = 1
+
+func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) {
+       // The PC/line table can be thought of as a sequence of
+       //  <pc update>* <line update>
+       // batches.  Each update batch results in a (pc, line) pair,
+       // where line applies to every PC from pc up to but not
+       // including the pc of the next pair.
+       //
+       // Here we process each update individually, which simplifies
+       // the code, but makes the corner cases more confusing.
+       b, pc, line = t.Data, t.PC, t.Line
+       for pc <= targetPC && line != targetLine && len(b) > 0 {
+               code := b[0]
+               b = b[1:]
+               switch {
+               case code == 0:
+                       if len(b) < 4 {
+                               b = b[0:0]
+                               break
+                       }
+                       val := binary.BigEndian.Uint32(b)
+                       b = b[4:]
+                       line += int(val)
+               case code <= 64:
+                       line += int(code)
+               case code <= 128:
+                       line -= int(code - 64)
+               default:
+                       pc += quantum * uint64(code-128)
+                       continue
+               }
+               pc += quantum
+       }
+       return b, pc, line
+}
+
+func (t *LineTable) slice(pc uint64) *LineTable {
+       data, pc, line := t.parse(pc, -1)
+       return &LineTable{data, pc, line}
+}
+
+func (t *LineTable) PCToLine(pc uint64) int {
+       _, _, line := t.parse(pc, -1)
+       return line
+}
+
+func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 {
+       _, pc, line1 := t.parse(maxpc, line)
+       if line1 != line {
+               return 0
+       }
+       // Subtract quantum from PC to account for post-line increment
+       return pc - quantum
+}
+
+// NewLineTable returns a new PC/line table
+// corresponding to the encoded data.
+// Text must be the start address of the
+// corresponding text segment.
+func NewLineTable(data []byte, text uint64) *LineTable {
+       return &LineTable{data, text, 0}
+}
diff --git a/libgo/go/debug/gosym/pclntab_test.go b/libgo/go/debug/gosym/pclntab_test.go
new file mode 100644 (file)
index 0000000..9087021
--- /dev/null
@@ -0,0 +1,207 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gosym
+
+import (
+       "debug/elf"
+       "os"
+       "testing"
+       "syscall"
+)
+
+func dotest() bool {
+       // For now, only works on ELF platforms.
+       return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
+}
+
+func getTable(t *testing.T) *Table {
+       f, tab := crack(os.Args[0], t)
+       f.Close()
+       return tab
+}
+
+func crack(file string, t *testing.T) (*elf.File, *Table) {
+       // Open self
+       f, err := elf.Open(file)
+       if err != nil {
+               t.Fatal(err)
+       }
+       return parse(file, f, t)
+}
+
+func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
+       symdat, err := f.Section(".gosymtab").Data()
+       if err != nil {
+               f.Close()
+               t.Fatalf("reading %s gosymtab: %v", file, err)
+       }
+       pclndat, err := f.Section(".gopclntab").Data()
+       if err != nil {
+               f.Close()
+               t.Fatalf("reading %s gopclntab: %v", file, err)
+       }
+
+       pcln := NewLineTable(pclndat, f.Section(".text").Addr)
+       tab, err := NewTable(symdat, pcln)
+       if err != nil {
+               f.Close()
+               t.Fatalf("parsing %s gosymtab: %v", file, err)
+       }
+
+       return f, tab
+}
+
+var goarch = os.Getenv("O")
+
+func TestLineFromAline(t *testing.T) {
+       if !dotest() {
+               return
+       }
+
+       tab := getTable(t)
+
+       // Find the sym package
+       pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
+       if pkg == nil {
+               t.Fatalf("nil pkg")
+       }
+
+       // Walk every absolute line and ensure that we hit every
+       // source line monotonically
+       lastline := make(map[string]int)
+       final := -1
+       for i := 0; i < 10000; i++ {
+               path, line := pkg.lineFromAline(i)
+               // Check for end of object
+               if path == "" {
+                       if final == -1 {
+                               final = i - 1
+                       }
+                       continue
+               } else if final != -1 {
+                       t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
+               }
+               // It's okay to see files multiple times (e.g., sys.a)
+               if line == 1 {
+                       lastline[path] = 1
+                       continue
+               }
+               // Check that the is the next line in path
+               ll, ok := lastline[path]
+               if !ok {
+                       t.Errorf("file %s starts on line %d", path, line)
+               } else if line != ll+1 {
+                       t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
+               }
+               lastline[path] = line
+       }
+       if final == -1 {
+               t.Errorf("never reached end of object")
+       }
+}
+
+func TestLineAline(t *testing.T) {
+       if !dotest() {
+               return
+       }
+
+       tab := getTable(t)
+
+       for _, o := range tab.Files {
+               // A source file can appear multiple times in a
+               // object.  alineFromLine will always return alines in
+               // the first file, so track which lines we've seen.
+               found := make(map[string]int)
+               for i := 0; i < 1000; i++ {
+                       path, line := o.lineFromAline(i)
+                       if path == "" {
+                               break
+                       }
+
+                       // cgo files are full of 'Z' symbols, which we don't handle
+                       if len(path) > 4 && path[len(path)-4:] == ".cgo" {
+                               continue
+                       }
+
+                       if minline, ok := found[path]; path != "" && ok {
+                               if minline >= line {
+                                       // We've already covered this file
+                                       continue
+                               }
+                       }
+                       found[path] = line
+
+                       a, err := o.alineFromLine(path, line)
+                       if err != nil {
+                               t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
+                       } else if a != i {
+                               t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
+                       }
+               }
+       }
+}
+
+// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 -a "$GOARCH" = amd64 ]; then
+// gotest:    mkdir -p _test && $AS pclinetest.s && $LD -E main -o _test/pclinetest pclinetest.$O
+// gotest: fi
+func TestPCLine(t *testing.T) {
+       if !dotest() {
+               return
+       }
+
+       f, tab := crack("_test/pclinetest", t)
+       text := f.Section(".text")
+       textdat, err := text.Data()
+       if err != nil {
+               t.Fatalf("reading .text: %v", err)
+       }
+
+       // Test PCToLine
+       sym := tab.LookupFunc("linefrompc")
+       wantLine := 0
+       for pc := sym.Entry; pc < sym.End; pc++ {
+               file, line, fn := tab.PCToLine(pc)
+               off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
+               wantLine += int(textdat[off])
+               if fn == nil {
+                       t.Errorf("failed to get line of PC %#x", pc)
+               } else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
+                       t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
+               }
+       }
+
+       // Test LineToPC
+       sym = tab.LookupFunc("pcfromline")
+       lookupline := -1
+       wantLine = 0
+       off := uint64(0) // TODO(rsc): should not need off; bug in 8g
+       for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
+               file, line, fn := tab.PCToLine(pc)
+               off = pc - text.Addr
+               wantLine += int(textdat[off])
+               if line != wantLine {
+                       t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
+                       off = pc + 1 - text.Addr
+                       continue
+               }
+               if lookupline == -1 {
+                       lookupline = line
+               }
+               for ; lookupline <= line; lookupline++ {
+                       pc2, fn2, err := tab.LineToPC(file, lookupline)
+                       if lookupline != line {
+                               // Should be nothing on this line
+                               if err == nil {
+                                       t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
+                               }
+                       } else if err != nil {
+                               t.Errorf("failed to get PC of line %d: %s", lookupline, err)
+                       } else if pc != pc2 {
+                               t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
+                       }
+               }
+               off = pc + 1 - text.Addr
+       }
+}
diff --git a/libgo/go/debug/gosym/symtab.go b/libgo/go/debug/gosym/symtab.go
new file mode 100644 (file)
index 0000000..dea460d
--- /dev/null
@@ -0,0 +1,548 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package gosym implements access to the Go symbol
+// and line number tables embedded in Go binaries generated
+// by the gc compilers.
+package gosym
+
+// The table format is a variant of the format used in Plan 9's a.out
+// format, documented at http://plan9.bell-labs.com/magic/man2html/6/a.out.
+// The best reference for the differences between the Plan 9 format
+// and the Go format is the runtime source, specifically ../../runtime/symtab.c.
+
+import (
+       "encoding/binary"
+       "fmt"
+       "os"
+       "strconv"
+       "strings"
+)
+
+/*
+ * Symbols
+ */
+
+// A Sym represents a single symbol table entry.
+type Sym struct {
+       Value  uint64
+       Type   byte
+       Name   string
+       GoType uint64
+       // If this symbol if a function symbol, the corresponding Func
+       Func *Func
+}
+
+// Static returns whether this symbol is static (not visible outside its file).
+func (s *Sym) Static() bool { return s.Type >= 'a' }
+
+// PackageName returns the package part of the symbol name,
+// or the empty string if there is none.
+func (s *Sym) PackageName() string {
+       if i := strings.Index(s.Name, "."); i != -1 {
+               return s.Name[0:i]
+       }
+       return ""
+}
+
+// ReceiverName returns the receiver type name of this symbol,
+// or the empty string if there is none.
+func (s *Sym) ReceiverName() string {
+       l := strings.Index(s.Name, ".")
+       r := strings.LastIndex(s.Name, ".")
+       if l == -1 || r == -1 || l == r {
+               return ""
+       }
+       return s.Name[l+1 : r]
+}
+
+// BaseName returns the symbol name without the package or receiver name.
+func (s *Sym) BaseName() string {
+       if i := strings.LastIndex(s.Name, "."); i != -1 {
+               return s.Name[i+1:]
+       }
+       return s.Name
+}
+
+// A Func collects information about a single function.
+type Func struct {
+       Entry uint64
+       *Sym
+       End       uint64
+       Params    []*Sym
+       Locals    []*Sym
+       FrameSize int
+       LineTable *LineTable
+       Obj       *Obj
+}
+
+// An Obj represents a single object file.
+type Obj struct {
+       Funcs []Func
+       Paths []Sym
+}
+
+/*
+ * Symbol tables
+ */
+
+// Table represents a Go symbol table.  It stores all of the
+// symbols decoded from the program and provides methods to translate
+// between symbols, names, and addresses.
+type Table struct {
+       Syms  []Sym
+       Funcs []Func
+       Files map[string]*Obj
+       Objs  []Obj
+       //      textEnd uint64;
+}
+
+type sym struct {
+       value  uint32
+       gotype uint32
+       typ    byte
+       name   []byte
+}
+
+func walksymtab(data []byte, fn func(sym) os.Error) os.Error {
+       var s sym
+       p := data
+       for len(p) >= 6 {
+               s.value = binary.BigEndian.Uint32(p[0:4])
+               typ := p[4]
+               if typ&0x80 == 0 {
+                       return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
+               }
+               typ &^= 0x80
+               s.typ = typ
+               p = p[5:]
+               var i int
+               var nnul int
+               for i = 0; i < len(p); i++ {
+                       if p[i] == 0 {
+                               nnul = 1
+                               break
+                       }
+               }
+               switch typ {
+               case 'z', 'Z':
+                       p = p[i+nnul:]
+                       for i = 0; i+2 <= len(p); i += 2 {
+                               if p[i] == 0 && p[i+1] == 0 {
+                                       nnul = 2
+                                       break
+                               }
+                       }
+               }
+               if i+nnul+4 > len(p) {
+                       return &DecodingError{len(data), "unexpected EOF", nil}
+               }
+               s.name = p[0:i]
+               i += nnul
+               s.gotype = binary.BigEndian.Uint32(p[i : i+4])
+               p = p[i+4:]
+               fn(s)
+       }
+       return nil
+}
+
+// NewTable decodes the Go symbol table in data,
+// returning an in-memory representation.
+func NewTable(symtab []byte, pcln *LineTable) (*Table, os.Error) {
+       var n int
+       err := walksymtab(symtab, func(s sym) os.Error {
+               n++
+               return nil
+       })
+       if err != nil {
+               return nil, err
+       }
+
+       var t Table
+       fname := make(map[uint16]string)
+       t.Syms = make([]Sym, 0, n)
+       nf := 0
+       nz := 0
+       lasttyp := uint8(0)
+       err = walksymtab(symtab, func(s sym) os.Error {
+               n := len(t.Syms)
+               t.Syms = t.Syms[0 : n+1]
+               ts := &t.Syms[n]
+               ts.Type = s.typ
+               ts.Value = uint64(s.value)
+               ts.GoType = uint64(s.gotype)
+               switch s.typ {
+               default:
+                       // rewrite name to use . instead of · (c2 b7)
+                       w := 0
+                       b := s.name
+                       for i := 0; i < len(b); i++ {
+                               if b[i] == 0xc2 && i+1 < len(b) && b[i+1] == 0xb7 {
+                                       i++
+                                       b[i] = '.'
+                               }
+                               b[w] = b[i]
+                               w++
+                       }
+                       ts.Name = string(s.name[0:w])
+               case 'z', 'Z':
+                       if lasttyp != 'z' && lasttyp != 'Z' {
+                               nz++
+                       }
+                       for i := 0; i < len(s.name); i += 2 {
+                               eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
+                               elt, ok := fname[eltIdx]
+                               if !ok {
+                                       return &DecodingError{-1, "bad filename code", eltIdx}
+                               }
+                               if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
+                                       ts.Name += "/"
+                               }
+                               ts.Name += elt
+                       }
+               }
+               switch s.typ {
+               case 'T', 't', 'L', 'l':
+                       nf++
+               case 'f':
+                       fname[uint16(s.value)] = ts.Name
+               }
+               lasttyp = s.typ
+               return nil
+       })
+       if err != nil {
+               return nil, err
+       }
+
+       t.Funcs = make([]Func, 0, nf)
+       t.Objs = make([]Obj, 0, nz)
+       t.Files = make(map[string]*Obj)
+
+       // Count text symbols and attach frame sizes, parameters, and
+       // locals to them.  Also, find object file boundaries.
+       var obj *Obj
+       lastf := 0
+       for i := 0; i < len(t.Syms); i++ {
+               sym := &t.Syms[i]
+               switch sym.Type {
+               case 'Z', 'z': // path symbol
+                       // Finish the current object
+                       if obj != nil {
+                               obj.Funcs = t.Funcs[lastf:]
+                       }
+                       lastf = len(t.Funcs)
+
+                       // Start new object
+                       n := len(t.Objs)
+                       t.Objs = t.Objs[0 : n+1]
+                       obj = &t.Objs[n]
+
+                       // Count & copy path symbols
+                       var end int
+                       for end = i + 1; end < len(t.Syms); end++ {
+                               if c := t.Syms[end].Type; c != 'Z' && c != 'z' {
+                                       break
+                               }
+                       }
+                       obj.Paths = t.Syms[i:end]
+                       i = end - 1 // loop will i++
+
+                       // Record file names
+                       depth := 0
+                       for j := range obj.Paths {
+                               s := &obj.Paths[j]
+                               if s.Name == "" {
+                                       depth--
+                               } else {
+                                       if depth == 0 {
+                                               t.Files[s.Name] = obj
+                                       }
+                                       depth++
+                               }
+                       }
+
+               case 'T', 't', 'L', 'l': // text symbol
+                       if n := len(t.Funcs); n > 0 {
+                               t.Funcs[n-1].End = sym.Value
+                       }
+                       if sym.Name == "etext" {
+                               continue
+                       }
+
+                       // Count parameter and local (auto) syms
+                       var np, na int
+                       var end int
+               countloop:
+                       for end = i + 1; end < len(t.Syms); end++ {
+                               switch t.Syms[end].Type {
+                               case 'T', 't', 'L', 'l', 'Z', 'z':
+                                       break countloop
+                               case 'p':
+                                       np++
+                               case 'a':
+                                       na++
+                               }
+                       }
+
+                       // Fill in the function symbol
+                       n := len(t.Funcs)
+                       t.Funcs = t.Funcs[0 : n+1]
+                       fn := &t.Funcs[n]
+                       sym.Func = fn
+                       fn.Params = make([]*Sym, 0, np)
+                       fn.Locals = make([]*Sym, 0, na)
+                       fn.Sym = sym
+                       fn.Entry = sym.Value
+                       fn.Obj = obj
+                       if pcln != nil {
+                               fn.LineTable = pcln.slice(fn.Entry)
+                               pcln = fn.LineTable
+                       }
+                       for j := i; j < end; j++ {
+                               s := &t.Syms[j]
+                               switch s.Type {
+                               case 'm':
+                                       fn.FrameSize = int(s.Value)
+                               case 'p':
+                                       n := len(fn.Params)
+                                       fn.Params = fn.Params[0 : n+1]
+                                       fn.Params[n] = s
+                               case 'a':
+                                       n := len(fn.Locals)
+                                       fn.Locals = fn.Locals[0 : n+1]
+                                       fn.Locals[n] = s
+                               }
+                       }
+                       i = end - 1 // loop will i++
+               }
+       }
+       if obj != nil {
+               obj.Funcs = t.Funcs[lastf:]
+       }
+       return &t, nil
+}
+
+// PCToFunc returns the function containing the program counter pc,
+// or nil if there is no such function.
+func (t *Table) PCToFunc(pc uint64) *Func {
+       funcs := t.Funcs
+       for len(funcs) > 0 {
+               m := len(funcs) / 2
+               fn := &funcs[m]
+               switch {
+               case pc < fn.Entry:
+                       funcs = funcs[0:m]
+               case fn.Entry <= pc && pc < fn.End:
+                       return fn
+               default:
+                       funcs = funcs[m+1:]
+               }
+       }
+       return nil
+}
+
+// PCToLine looks up line number information for a program counter.
+// If there is no information, it returns fn == nil.
+func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) {
+       if fn = t.PCToFunc(pc); fn == nil {
+               return
+       }
+       file, line = fn.Obj.lineFromAline(fn.LineTable.PCToLine(pc))
+       return
+}
+
+// LineToPC looks up the first program counter on the given line in
+// the named file.  Returns UnknownPathError or UnknownLineError if
+// there is an error looking up this line.
+func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err os.Error) {
+       obj, ok := t.Files[file]
+       if !ok {
+               return 0, nil, UnknownFileError(file)
+       }
+       abs, err := obj.alineFromLine(file, line)
+       if err != nil {
+               return
+       }
+       for i := range obj.Funcs {
+               f := &obj.Funcs[i]
+               pc := f.LineTable.LineToPC(abs, f.End)
+               if pc != 0 {
+                       return pc, f, nil
+               }
+       }
+       return 0, nil, &UnknownLineError{file, line}
+}
+
+// LookupSym returns the text, data, or bss symbol with the given name,
+// or nil if no such symbol is found.
+func (t *Table) LookupSym(name string) *Sym {
+       // TODO(austin) Maybe make a map
+       for i := range t.Syms {
+               s := &t.Syms[i]
+               switch s.Type {
+               case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
+                       if s.Name == name {
+                               return s
+                       }
+               }
+       }
+       return nil
+}
+
+// LookupFunc returns the text, data, or bss symbol with the given name,
+// or nil if no such symbol is found.
+func (t *Table) LookupFunc(name string) *Func {
+       for i := range t.Funcs {
+               f := &t.Funcs[i]
+               if f.Sym.Name == name {
+                       return f
+               }
+       }
+       return nil
+}
+
+// SymByAddr returns the text, data, or bss symbol starting at the given address.
+// TODO(rsc): Allow lookup by any address within the symbol.
+func (t *Table) SymByAddr(addr uint64) *Sym {
+       // TODO(austin) Maybe make a map
+       for i := range t.Syms {
+               s := &t.Syms[i]
+               switch s.Type {
+               case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
+                       if s.Value == addr {
+                               return s
+                       }
+               }
+       }
+       return nil
+}
+
+/*
+ * Object files
+ */
+
+func (o *Obj) lineFromAline(aline int) (string, int) {
+       type stackEnt struct {
+               path   string
+               start  int
+               offset int
+               prev   *stackEnt
+       }
+
+       noPath := &stackEnt{"", 0, 0, nil}
+       tos := noPath
+
+       // TODO(austin) I have no idea how 'Z' symbols work, except
+       // that they pop the stack.
+pathloop:
+       for _, s := range o.Paths {
+               val := int(s.Value)
+               switch {
+               case val > aline:
+                       break pathloop
+
+               case val == 1:
+                       // Start a new stack
+                       tos = &stackEnt{s.Name, val, 0, noPath}
+
+               case s.Name == "":
+                       // Pop
+                       if tos == noPath {
+                               return "<malformed symbol table>", 0
+                       }
+                       tos.prev.offset += val - tos.start
+                       tos = tos.prev
+
+               default:
+                       // Push
+                       tos = &stackEnt{s.Name, val, 0, tos}
+               }
+       }
+
+       if tos == noPath {
+               return "", 0
+       }
+       return tos.path, aline - tos.start - tos.offset + 1
+}
+
+func (o *Obj) alineFromLine(path string, line int) (int, os.Error) {
+       if line < 1 {
+               return 0, &UnknownLineError{path, line}
+       }
+
+       for i, s := range o.Paths {
+               // Find this path
+               if s.Name != path {
+                       continue
+               }
+
+               // Find this line at this stack level
+               depth := 0
+               var incstart int
+               line += int(s.Value)
+       pathloop:
+               for _, s := range o.Paths[i:] {
+                       val := int(s.Value)
+                       switch {
+                       case depth == 1 && val >= line:
+                               return line - 1, nil
+
+                       case s.Name == "":
+                               depth--
+                               if depth == 0 {
+                                       break pathloop
+                               } else if depth == 1 {
+                                       line += val - incstart
+                               }
+
+                       default:
+                               if depth == 1 {
+                                       incstart = val
+                               }
+                               depth++
+                       }
+               }
+               return 0, &UnknownLineError{path, line}
+       }
+       return 0, UnknownFileError(path)
+}
+
+/*
+ * Errors
+ */
+
+// UnknownFileError represents a failure to find the specific file in
+// the symbol table.
+type UnknownFileError string
+
+func (e UnknownFileError) String() string { return "unknown file: " + string(e) }
+
+// UnknownLineError represents a failure to map a line to a program
+// counter, either because the line is beyond the bounds of the file
+// or because there is no code on the given line.
+type UnknownLineError struct {
+       File string
+       Line int
+}
+
+func (e *UnknownLineError) String() string {
+       return "no code at " + e.File + ":" + strconv.Itoa(e.Line)
+}
+
+// DecodingError represents an error during the decoding of
+// the symbol table.
+type DecodingError struct {
+       off int
+       msg string
+       val interface{}
+}
+
+func (e *DecodingError) String() string {
+       msg := e.msg
+       if e.val != nil {
+               msg += fmt.Sprintf(" '%v'", e.val)
+       }
+       msg += fmt.Sprintf(" at byte %#x", e.off)
+       return msg
+}
diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go
new file mode 100644 (file)
index 0000000..d280226
--- /dev/null
@@ -0,0 +1,360 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package macho implements access to Mach-O object files, as defined by
+// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html.
+package macho
+
+// High level access to low level data structures.
+
+import (
+       "bytes"
+       "debug/dwarf"
+       "encoding/binary"
+       "fmt"
+       "io"
+       "os"
+)
+
+// A File represents an open Mach-O file.
+type File struct {
+       FileHeader
+       ByteOrder binary.ByteOrder
+       Loads     []Load
+       Sections  []*Section
+
+       closer io.Closer
+}
+
+// A Load represents any Mach-O load command.
+type Load interface {
+       Raw() []byte
+}
+
+// A LoadBytes is the uninterpreted bytes of a Mach-O load command.
+type LoadBytes []byte
+
+func (b LoadBytes) Raw() []byte { return b }
+
+// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.
+type SegmentHeader struct {
+       Cmd     LoadCmd
+       Len     uint32
+       Name    string
+       Addr    uint64
+       Memsz   uint64
+       Offset  uint64
+       Filesz  uint64
+       Maxprot uint32
+       Prot    uint32
+       Nsect   uint32
+       Flag    uint32
+}
+
+// A Segment represents a Mach-O 32-bit or 64-bit load segment command.
+type Segment struct {
+       LoadBytes
+       SegmentHeader
+
+       // Embed ReaderAt for ReadAt method.
+       // Do not embed SectionReader directly
+       // to avoid having Read and Seek.
+       // If a client wants Read and Seek it must use
+       // Open() to avoid fighting over the seek offset
+       // with other clients.
+       io.ReaderAt
+       sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the segment.
+func (s *Segment) Data() ([]byte, os.Error) {
+       dat := make([]byte, s.sr.Size())
+       n, err := s.sr.ReadAt(dat, 0)
+       return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the segment.
+func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+type SectionHeader struct {
+       Name   string
+       Seg    string
+       Addr   uint64
+       Size   uint64
+       Offset uint32
+       Align  uint32
+       Reloff uint32
+       Nreloc uint32
+       Flags  uint32
+}
+
+type Section struct {
+       SectionHeader
+
+       // Embed ReaderAt for ReadAt method.
+       // Do not embed SectionReader directly
+       // to avoid having Read and Seek.
+       // If a client wants Read and Seek it must use
+       // Open() to avoid fighting over the seek offset
+       // with other clients.
+       io.ReaderAt
+       sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the Mach-O section.
+func (s *Section) Data() ([]byte, os.Error) {
+       dat := make([]byte, s.sr.Size())
+       n, err := s.sr.ReadAt(dat, 0)
+       return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the Mach-O section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+
+/*
+ * Mach-O reader
+ */
+
+type FormatError struct {
+       off int64
+       msg string
+       val interface{}
+}
+
+func (e *FormatError) String() string {
+       msg := e.msg
+       if e.val != nil {
+               msg += fmt.Sprintf(" '%v'", e.val)
+       }
+       msg += fmt.Sprintf(" in record at byte %#x", e.off)
+       return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
+func Open(name string) (*File, os.Error) {
+       f, err := os.Open(name, os.O_RDONLY, 0)
+       if err != nil {
+               return nil, err
+       }
+       ff, err := NewFile(f)
+       if err != nil {
+               f.Close()
+               return nil, err
+       }
+       ff.closer = f
+       return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() os.Error {
+       var err os.Error
+       if f.closer != nil {
+               err = f.closer.Close()
+               f.closer = nil
+       }
+       return err
+}
+
+// NewFile creates a new File for acecssing a Mach-O binary in an underlying reader.
+// The Mach-O binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+       f := new(File)
+       sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+       // Read and decode Mach magic to determine byte order, size.
+       // Magic32 and Magic64 differ only in the bottom bit.
+       var ident [4]byte
+       if _, err := r.ReadAt(ident[0:], 0); err != nil {
+               return nil, err
+       }
+       be := binary.BigEndian.Uint32(ident[0:])
+       le := binary.LittleEndian.Uint32(ident[0:])
+       switch Magic32 &^ 1 {
+       case be &^ 1:
+               f.ByteOrder = binary.BigEndian
+               f.Magic = be
+       case le &^ 1:
+               f.ByteOrder = binary.LittleEndian
+               f.Magic = le
+       default:
+               return nil, &FormatError{0, "invalid magic number", nil}
+       }
+
+       // Read entire file header.
+       if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {
+               return nil, err
+       }
+
+       // Then load commands.
+       offset := int64(fileHeaderSize32)
+       if f.Magic == Magic64 {
+               offset = fileHeaderSize64
+       }
+       dat := make([]byte, f.Cmdsz)
+       if _, err := r.ReadAt(dat, offset); err != nil {
+               return nil, err
+       }
+       f.Loads = make([]Load, f.Ncmd)
+       bo := f.ByteOrder
+       for i := range f.Loads {
+               // Each load command begins with uint32 command and length.
+               if len(dat) < 8 {
+                       return nil, &FormatError{offset, "command block too small", nil}
+               }
+               cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])
+               if siz < 8 || siz > uint32(len(dat)) {
+                       return nil, &FormatError{offset, "invalid command block size", nil}
+               }
+               var cmddat []byte
+               cmddat, dat = dat[0:siz], dat[siz:]
+               offset += int64(siz)
+               var s *Segment
+               switch cmd {
+               default:
+                       f.Loads[i] = LoadBytes(cmddat)
+
+               case LoadCmdSegment:
+                       var seg32 Segment32
+                       b := bytes.NewBuffer(cmddat)
+                       if err := binary.Read(b, bo, &seg32); err != nil {
+                               return nil, err
+                       }
+                       s = new(Segment)
+                       s.LoadBytes = cmddat
+                       s.Cmd = cmd
+                       s.Len = siz
+                       s.Name = cstring(seg32.Name[0:])
+                       s.Addr = uint64(seg32.Addr)
+                       s.Memsz = uint64(seg32.Memsz)
+                       s.Offset = uint64(seg32.Offset)
+                       s.Filesz = uint64(seg32.Filesz)
+                       s.Maxprot = seg32.Maxprot
+                       s.Prot = seg32.Prot
+                       s.Nsect = seg32.Nsect
+                       s.Flag = seg32.Flag
+                       f.Loads[i] = s
+                       for i := 0; i < int(s.Nsect); i++ {
+                               var sh32 Section32
+                               if err := binary.Read(b, bo, &sh32); err != nil {
+                                       return nil, err
+                               }
+                               sh := new(Section)
+                               sh.Name = cstring(sh32.Name[0:])
+                               sh.Seg = cstring(sh32.Seg[0:])
+                               sh.Addr = uint64(sh32.Addr)
+                               sh.Size = uint64(sh32.Size)
+                               sh.Offset = sh32.Offset
+                               sh.Align = sh32.Align
+                               sh.Reloff = sh32.Reloff
+                               sh.Nreloc = sh32.Nreloc
+                               sh.Flags = sh32.Flags
+                               f.pushSection(sh, r)
+                       }
+
+               case LoadCmdSegment64:
+                       var seg64 Segment64
+                       b := bytes.NewBuffer(cmddat)
+                       if err := binary.Read(b, bo, &seg64); err != nil {
+                               return nil, err
+                       }
+                       s = new(Segment)
+                       s.LoadBytes = cmddat
+                       s.Cmd = cmd
+                       s.Len = siz
+                       s.Name = cstring(seg64.Name[0:])
+                       s.Addr = seg64.Addr
+                       s.Memsz = seg64.Memsz
+                       s.Offset = seg64.Offset
+                       s.Filesz = seg64.Filesz
+                       s.Maxprot = seg64.Maxprot
+                       s.Prot = seg64.Prot
+                       s.Nsect = seg64.Nsect
+                       s.Flag = seg64.Flag
+                       f.Loads[i] = s
+                       for i := 0; i < int(s.Nsect); i++ {
+                               var sh64 Section64
+                               if err := binary.Read(b, bo, &sh64); err != nil {
+                                       return nil, err
+                               }
+                               sh := new(Section)
+                               sh.Name = cstring(sh64.Name[0:])
+                               sh.Seg = cstring(sh64.Seg[0:])
+                               sh.Addr = sh64.Addr
+                               sh.Size = sh64.Size
+                               sh.Offset = sh64.Offset
+                               sh.Align = sh64.Align
+                               sh.Reloff = sh64.Reloff
+                               sh.Nreloc = sh64.Nreloc
+                               sh.Flags = sh64.Flags
+                               f.pushSection(sh, r)
+                       }
+               }
+               if s != nil {
+                       s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
+                       s.ReaderAt = s.sr
+               }
+       }
+       return f, nil
+}
+
+func (f *File) pushSection(sh *Section, r io.ReaderAt) {
+       f.Sections = append(f.Sections, sh)
+       sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
+       sh.ReaderAt = sh.sr
+}
+
+func cstring(b []byte) string {
+       var i int
+       for i = 0; i < len(b) && b[i] != 0; i++ {
+       }
+       return string(b[0:i])
+}
+
+// Segment returns the first Segment with the given name, or nil if no such segment exists.
+func (f *File) Segment(name string) *Segment {
+       for _, l := range f.Loads {
+               if s, ok := l.(*Segment); ok && s.Name == name {
+                       return s
+               }
+       }
+       return nil
+}
+
+// Section returns the first section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+       for _, s := range f.Sections {
+               if s.Name == name {
+                       return s
+               }
+       }
+       return nil
+}
+
+// DWARF returns the DWARF debug information for the Mach-O file.
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+       // There are many other DWARF sections, but these
+       // are the required ones, and the debug/dwarf package
+       // does not use the others, so don't bother loading them.
+       var names = [...]string{"abbrev", "info", "str"}
+       var dat [len(names)][]byte
+       for i, name := range names {
+               name = "__debug_" + name
+               s := f.Section(name)
+               if s == nil {
+                       return nil, os.NewError("missing Mach-O section " + name)
+               }
+               b, err := s.Data()
+               if err != nil && uint64(len(b)) < s.Size {
+                       return nil, err
+               }
+               dat[i] = b
+       }
+
+       abbrev, info, str := dat[0], dat[1], dat[2]
+       return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
diff --git a/libgo/go/debug/macho/file_test.go b/libgo/go/debug/macho/file_test.go
new file mode 100644 (file)
index 0000000..56d8a20
--- /dev/null
@@ -0,0 +1,167 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package macho
+
+import (
+       "reflect"
+       "testing"
+)
+
+type fileTest struct {
+       file     string
+       hdr      FileHeader
+       segments []*SegmentHeader
+       sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+       {
+               "testdata/gcc-386-darwin-exec",
+               FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85},
+               []*SegmentHeader{
+                       &SegmentHeader{LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+                       &SegmentHeader{LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0},
+                       &SegmentHeader{LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0},
+                       &SegmentHeader{LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0},
+                       &SegmentHeader{LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0},
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+               },
+               []*SectionHeader{
+                       &SectionHeader{"__text", "__TEXT", 0x1f68, 0x88, 0xf68, 0x2, 0x0, 0x0, 0x80000400},
+                       &SectionHeader{"__cstring", "__TEXT", 0x1ff0, 0xd, 0xff0, 0x0, 0x0, 0x0, 0x2},
+                       &SectionHeader{"__data", "__DATA", 0x2000, 0x14, 0x1000, 0x2, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__dyld", "__DATA", 0x2014, 0x1c, 0x1014, 0x2, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008},
+               },
+       },
+       {
+               "testdata/gcc-amd64-darwin-exec",
+               FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85},
+               []*SegmentHeader{
+                       &SegmentHeader{LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+                       &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0},
+                       &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0},
+                       &SegmentHeader{LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0},
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+                       nil,
+               },
+               []*SectionHeader{
+                       &SectionHeader{"__text", "__TEXT", 0x100000f14, 0x6d, 0xf14, 0x2, 0x0, 0x0, 0x80000400},
+                       &SectionHeader{"__symbol_stub1", "__TEXT", 0x100000f81, 0xc, 0xf81, 0x0, 0x0, 0x0, 0x80000408},
+                       &SectionHeader{"__stub_helper", "__TEXT", 0x100000f90, 0x18, 0xf90, 0x2, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__cstring", "__TEXT", 0x100000fa8, 0xd, 0xfa8, 0x0, 0x0, 0x0, 0x2},
+                       &SectionHeader{"__eh_frame", "__TEXT", 0x100000fb8, 0x48, 0xfb8, 0x3, 0x0, 0x0, 0x6000000b},
+                       &SectionHeader{"__data", "__DATA", 0x100001000, 0x1c, 0x1000, 0x3, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__dyld", "__DATA", 0x100001020, 0x38, 0x1020, 0x3, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7},
+               },
+       },
+       {
+               "testdata/gcc-amd64-darwin-exec-debug",
+               FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0},
+               []*SegmentHeader{
+                       nil,
+                       &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0},
+                       &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0},
+                       &SegmentHeader{LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0},
+               },
+               []*SectionHeader{
+                       &SectionHeader{"__text", "__TEXT", 0x100000f14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80000400},
+                       &SectionHeader{"__symbol_stub1", "__TEXT", 0x100000f81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000408},
+                       &SectionHeader{"__stub_helper", "__TEXT", 0x100000f90, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__cstring", "__TEXT", 0x100000fa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
+                       &SectionHeader{"__eh_frame", "__TEXT", 0x100000fb8, 0x0, 0x0, 0x3, 0x0, 0x0, 0x6000000b},
+                       &SectionHeader{"__data", "__DATA", 0x100001000, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__dyld", "__DATA", 0x100001020, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x0, 0x0, 0x2, 0x0, 0x0, 0x7},
+                       &SectionHeader{"__debug_abbrev", "__DWARF", 0x100002000, 0x36, 0x1000, 0x0, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__debug_aranges", "__DWARF", 0x100002036, 0x30, 0x1036, 0x0, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__debug_frame", "__DWARF", 0x100002066, 0x40, 0x1066, 0x0, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__debug_info", "__DWARF", 0x1000020a6, 0x54, 0x10a6, 0x0, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__debug_line", "__DWARF", 0x1000020fa, 0x47, 0x10fa, 0x0, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__debug_pubnames", "__DWARF", 0x100002141, 0x1b, 0x1141, 0x0, 0x0, 0x0, 0x0},
+                       &SectionHeader{"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0},
+               },
+       },
+}
+
+func TestOpen(t *testing.T) {
+       for i := range fileTests {
+               tt := &fileTests[i]
+
+               f, err := Open(tt.file)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+               if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+                       t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+                       continue
+               }
+               for i, l := range f.Loads {
+                       if i >= len(tt.segments) {
+                               break
+                       }
+                       sh := tt.segments[i]
+                       s, ok := l.(*Segment)
+                       if sh == nil {
+                               if ok {
+                                       t.Errorf("open %s, section %d: skipping %#v\n", tt.file, i, &s.SegmentHeader)
+                               }
+                               continue
+                       }
+                       if !ok {
+                               t.Errorf("open %s, section %d: not *Segment\n", tt.file, i)
+                               continue
+                       }
+                       have := &s.SegmentHeader
+                       want := sh
+                       if !reflect.DeepEqual(have, want) {
+                               t.Errorf("open %s, segment %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+                       }
+               }
+               tn := len(tt.segments)
+               fn := len(f.Loads)
+               if tn != fn {
+                       t.Errorf("open %s: len(Loads) = %d, want %d", tt.file, fn, tn)
+               }
+
+               for i, sh := range f.Sections {
+                       if i >= len(tt.sections) {
+                               break
+                       }
+                       have := &sh.SectionHeader
+                       want := tt.sections[i]
+                       if !reflect.DeepEqual(have, want) {
+                               t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+                       }
+               }
+               tn = len(tt.sections)
+               fn = len(f.Sections)
+               if tn != fn {
+                       t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+               }
+
+       }
+}
+
+func TestOpenFailure(t *testing.T) {
+       filename := "file.go"    // not a Mach-O file
+       _, err := Open(filename) // don't crash
+       if err == nil {
+               t.Errorf("open %s: succeeded unexpectedly", filename)
+       }
+}
diff --git a/libgo/go/debug/macho/macho.go b/libgo/go/debug/macho/macho.go
new file mode 100644 (file)
index 0000000..a45d782
--- /dev/null
@@ -0,0 +1,229 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Mach-O header data structures
+// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
+
+package macho
+
+import "strconv"
+
+// A FileHeader represents a Mach-O file header.
+type FileHeader struct {
+       Magic  uint32
+       Cpu    Cpu
+       SubCpu uint32
+       Type   Type
+       Ncmd   uint32
+       Cmdsz  uint32
+       Flags  uint32
+}
+
+const (
+       fileHeaderSize32 = 7 * 4
+       fileHeaderSize64 = 8 * 4
+)
+
+const (
+       Magic32 uint32 = 0xfeedface
+       Magic64 uint32 = 0xfeedfacf
+)
+
+// A Type is a Mach-O file type, either an object or an executable.
+type Type uint32
+
+const (
+       TypeObj  Type = 1
+       TypeExec Type = 2
+)
+
+// A Cpu is a Mach-O cpu type.
+type Cpu uint32
+
+const (
+       Cpu386   Cpu = 7
+       CpuAmd64 Cpu = Cpu386 + 1<<24
+)
+
+var cpuStrings = []intName{
+       {uint32(Cpu386), "Cpu386"},
+       {uint32(CpuAmd64), "CpuAmd64"},
+}
+
+func (i Cpu) String() string   { return stringName(uint32(i), cpuStrings, false) }
+func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) }
+
+// A LoadCmd is a Mach-O load command.
+type LoadCmd uint32
+
+const (
+       LoadCmdSegment    LoadCmd = 1
+       LoadCmdSegment64  LoadCmd = 25
+       LoadCmdThread     LoadCmd = 4
+       LoadCmdUnixThread LoadCmd = 5 // thread+stack
+)
+
+var cmdStrings = []intName{
+       {uint32(LoadCmdSegment), "LoadCmdSegment"},
+       {uint32(LoadCmdSegment64), "LoadCmdSegment64"},
+       {uint32(LoadCmdThread), "LoadCmdThread"},
+       {uint32(LoadCmdUnixThread), "LoadCmdUnixThread"},
+}
+
+func (i LoadCmd) String() string   { return stringName(uint32(i), cmdStrings, false) }
+func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) }
+
+// A Segment64 is a 64-bit Mach-O segment load command.
+type Segment64 struct {
+       Cmd     LoadCmd
+       Len     uint32
+       Name    [16]byte
+       Addr    uint64
+       Memsz   uint64
+       Offset  uint64
+       Filesz  uint64
+       Maxprot uint32
+       Prot    uint32
+       Nsect   uint32
+       Flag    uint32
+}
+
+// A Segment32 is a 32-bit Mach-O segment load command.
+type Segment32 struct {
+       Cmd     LoadCmd
+       Len     uint32
+       Name    [16]byte
+       Addr    uint32
+       Memsz   uint32
+       Offset  uint32
+       Filesz  uint32
+       Maxprot uint32
+       Prot    uint32
+       Nsect   uint32
+       Flag    uint32
+}
+
+// A Section32 is a 32-bit Mach-O section header.
+type Section32 struct {
+       Name     [16]byte
+       Seg      [16]byte
+       Addr     uint32
+       Size     uint32
+       Offset   uint32
+       Align    uint32
+       Reloff   uint32
+       Nreloc   uint32
+       Flags    uint32
+       Reserve1 uint32
+       Reserve2 uint32
+}
+
+// A Section32 is a 64-bit Mach-O section header.
+type Section64 struct {
+       Name     [16]byte
+       Seg      [16]byte
+       Addr     uint64
+       Size     uint64
+       Offset   uint32
+       Align    uint32
+       Reloff   uint32
+       Nreloc   uint32
+       Flags    uint32
+       Reserve1 uint32
+       Reserve2 uint32
+       Reserve3 uint32
+}
+
+// A Thread is a Mach-O thread state command.
+type Thread struct {
+       Cmd  LoadCmd
+       Len  uint32
+       Type uint32
+       Data []uint32
+}
+
+// Regs386 is the Mach-O 386 register structure.
+type Regs386 struct {
+       AX    uint32
+       BX    uint32
+       CX    uint32
+       DX    uint32
+       DI    uint32
+       SI    uint32
+       BP    uint32
+       SP    uint32
+       SS    uint32
+       FLAGS uint32
+       IP    uint32
+       CS    uint32
+       DS    uint32
+       ES    uint32
+       FS    uint32
+       GS    uint32
+}
+
+// RegsAMD64 is the Mach-O AMD64 register structure.
+type RegsAMD64 struct {
+       AX    uint64
+       BX    uint64
+       CX    uint64
+       DX    uint64
+       DI    uint64
+       SI    uint64
+       BP    uint64
+       SP    uint64
+       R8    uint64
+       R9    uint64
+       R10   uint64
+       R11   uint64
+       R12   uint64
+       R13   uint64
+       R14   uint64
+       R15   uint64
+       IP    uint64
+       FLAGS uint64
+       CS    uint64
+       FS    uint64
+       GS    uint64
+}
+
+type intName struct {
+       i uint32
+       s string
+}
+
+func stringName(i uint32, names []intName, goSyntax bool) string {
+       for _, n := range names {
+               if n.i == i {
+                       if goSyntax {
+                               return "macho." + n.s
+                       }
+                       return n.s
+               }
+       }
+       return strconv.Uitoa64(uint64(i))
+}
+
+func flagName(i uint32, names []intName, goSyntax bool) string {
+       s := ""
+       for _, n := range names {
+               if n.i&i == n.i {
+                       if len(s) > 0 {
+                               s += "+"
+                       }
+                       if goSyntax {
+                               s += "macho."
+                       }
+                       s += n.s
+                       i -= n.i
+               }
+       }
+       if len(s) == 0 {
+               return "0x" + strconv.Uitob64(uint64(i), 16)
+       }
+       if i != 0 {
+               s += "+0x" + strconv.Uitob64(uint64(i), 16)
+       }
+       return s
+}
diff --git a/libgo/go/debug/macho/testdata/gcc-386-darwin-exec b/libgo/go/debug/macho/testdata/gcc-386-darwin-exec
new file mode 100755 (executable)
index 0000000..03ba1ba
Binary files /dev/null and b/libgo/go/debug/macho/testdata/gcc-386-darwin-exec differ
diff --git a/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec b/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec
new file mode 100755 (executable)
index 0000000..5155a5a
Binary files /dev/null and b/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec differ
diff --git a/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec-debug b/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec-debug
new file mode 100644 (file)
index 0000000..a47d3ae
Binary files /dev/null and b/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec-debug differ
diff --git a/libgo/go/debug/macho/testdata/hello.c b/libgo/go/debug/macho/testdata/hello.c
new file mode 100644 (file)
index 0000000..a689d36
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+main(void)
+{
+       printf("hello, world\n");
+       return 0;
+}
diff --git a/libgo/go/debug/pe/file.go b/libgo/go/debug/pe/file.go
new file mode 100644 (file)
index 0000000..904d2f8
--- /dev/null
@@ -0,0 +1,231 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pe implements access to PE (Microsoft Windows Portable Executable) files.
+package pe
+
+import (
+       "debug/dwarf"
+       "encoding/binary"
+       "fmt"
+       "io"
+       "os"
+       "strconv"
+)
+
+// A File represents an open PE file.
+type File struct {
+       FileHeader
+       Sections []*Section
+
+       closer io.Closer
+}
+
+type SectionHeader struct {
+       Name                 string
+       VirtualSize          uint32
+       VirtualAddress       uint32
+       Size                 uint32
+       Offset               uint32
+       PointerToRelocations uint32
+       PointerToLineNumbers uint32
+       NumberOfRelocations  uint16
+       NumberOfLineNumbers  uint16
+       Characteristics      uint32
+}
+
+
+type Section struct {
+       SectionHeader
+
+       // Embed ReaderAt for ReadAt method.
+       // Do not embed SectionReader directly
+       // to avoid having Read and Seek.
+       // If a client wants Read and Seek it must use
+       // Open() to avoid fighting over the seek offset
+       // with other clients.
+       io.ReaderAt
+       sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the PE section.
+func (s *Section) Data() ([]byte, os.Error) {
+       dat := make([]byte, s.sr.Size())
+       n, err := s.sr.ReadAt(dat, 0)
+       return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the PE section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+
+type FormatError struct {
+       off int64
+       msg string
+       val interface{}
+}
+
+func (e *FormatError) String() string {
+       msg := e.msg
+       if e.val != nil {
+               msg += fmt.Sprintf(" '%v'", e.val)
+       }
+       msg += fmt.Sprintf(" in record at byte %#x", e.off)
+       return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as a PE binary.
+func Open(name string) (*File, os.Error) {
+       f, err := os.Open(name, os.O_RDONLY, 0)
+       if err != nil {
+               return nil, err
+       }
+       ff, err := NewFile(f)
+       if err != nil {
+               f.Close()
+               return nil, err
+       }
+       ff.closer = f
+       return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() os.Error {
+       var err os.Error
+       if f.closer != nil {
+               err = f.closer.Close()
+               f.closer = nil
+       }
+       return err
+}
+
+// NewFile creates a new File for acecssing a PE binary in an underlying reader.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+       f := new(File)
+       sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+       var dosheader [96]byte
+       if _, err := r.ReadAt(dosheader[0:], 0); err != nil {
+               return nil, err
+       }
+       var base int64
+       if dosheader[0] == 'M' && dosheader[1] == 'Z' {
+               var sign [4]byte
+               r.ReadAt(sign[0:], int64(dosheader[0x3c]))
+               if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
+                       return nil, os.NewError("Invalid PE File Format.")
+               }
+               base = int64(dosheader[0x3c]) + 4
+       } else {
+               base = int64(0)
+       }
+       sr.Seek(base, 0)
+       if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
+               return nil, err
+       }
+       if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
+               return nil, os.NewError("Invalid PE File Format.")
+       }
+       // get symbol string table
+       sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), 0)
+       var l uint32
+       if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
+               return nil, err
+       }
+       ss := make([]byte, l)
+       if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols)); err != nil {
+               return nil, err
+       }
+       sr.Seek(base, 0)
+       binary.Read(sr, binary.LittleEndian, &f.FileHeader)
+       sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), 1) //Skip OptionalHeader
+       f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
+       for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
+               sh := new(SectionHeader32)
+               if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
+                       return nil, err
+               }
+               var name string
+               if sh.Name[0] == '\x2F' {
+                       si, _ := strconv.Atoi(cstring(sh.Name[1:]))
+                       name, _ = getString(ss, si)
+               } else {
+                       name = cstring(sh.Name[0:])
+               }
+               s := new(Section)
+               s.SectionHeader = SectionHeader{
+                       Name:                 name,
+                       VirtualSize:          uint32(sh.VirtualSize),
+                       VirtualAddress:       uint32(sh.VirtualAddress),
+                       Size:                 uint32(sh.SizeOfRawData),
+                       Offset:               uint32(sh.PointerToRawData),
+                       PointerToRelocations: uint32(sh.PointerToRelocations),
+                       PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
+                       NumberOfRelocations:  uint16(sh.NumberOfRelocations),
+                       NumberOfLineNumbers:  uint16(sh.NumberOfLineNumbers),
+                       Characteristics:      uint32(sh.Characteristics),
+               }
+               s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
+               s.ReaderAt = s.sr
+               f.Sections[i] = s
+       }
+       return f, nil
+}
+
+func cstring(b []byte) string {
+       var i int
+       for i = 0; i < len(b) && b[i] != 0; i++ {
+       }
+       return string(b[0:i])
+}
+
+// getString extracts a string from symbol string table.
+func getString(section []byte, start int) (string, bool) {
+       if start < 0 || start >= len(section) {
+               return "", false
+       }
+
+       for end := start; end < len(section); end++ {
+               if section[end] == 0 {
+                       return string(section[start:end]), true
+               }
+       }
+       return "", false
+}
+
+// Section returns the first section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+       for _, s := range f.Sections {
+               if s.Name == name {
+                       return s
+               }
+       }
+       return nil
+}
+
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+       // There are many other DWARF sections, but these
+       // are the required ones, and the debug/dwarf package
+       // does not use the others, so don't bother loading them.
+       var names = [...]string{"abbrev", "info", "str"}
+       var dat [len(names)][]byte
+       for i, name := range names {
+               name = ".debug_" + name
+               s := f.Section(name)
+               if s == nil {
+                       continue
+               }
+               b, err := s.Data()
+               if err != nil && uint32(len(b)) < s.Size {
+                       return nil, err
+               }
+               dat[i] = b
+       }
+
+       abbrev, info, str := dat[0], dat[1], dat[2]
+       return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
diff --git a/libgo/go/debug/pe/file_test.go b/libgo/go/debug/pe/file_test.go
new file mode 100644 (file)
index 0000000..c000c5f
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pe
+
+import (
+       "reflect"
+       "testing"
+)
+
+type fileTest struct {
+       file     string
+       hdr      FileHeader
+       sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+       fileTest{
+               "testdata/gcc-386-mingw-obj",
+               FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
+               []*SectionHeader{
+                       &SectionHeader{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
+                       &SectionHeader{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
+                       &SectionHeader{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
+                       &SectionHeader{".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
+                       &SectionHeader{".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
+                       &SectionHeader{".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
+                       &SectionHeader{".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
+                       &SectionHeader{".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
+                       &SectionHeader{".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
+                       &SectionHeader{".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
+                       &SectionHeader{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
+                       &SectionHeader{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
+               },
+       },
+       fileTest{
+               "testdata/gcc-386-mingw-exec",
+               FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
+               []*SectionHeader{
+                       &SectionHeader{Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
+                       &SectionHeader{Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+                       &SectionHeader{Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
+                       &SectionHeader{Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
+                       &SectionHeader{Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+                       &SectionHeader{Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+                       &SectionHeader{Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+                       &SectionHeader{Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+                       &SectionHeader{Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+                       &SectionHeader{Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+                       &SectionHeader{Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+                       &SectionHeader{Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+                       &SectionHeader{Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+                       &SectionHeader{Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
+                       &SectionHeader{Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+               },
+       },
+}
+
+func TestOpen(t *testing.T) {
+       for i := range fileTests {
+               tt := &fileTests[i]
+
+               f, err := Open(tt.file)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+               if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+                       t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+                       continue
+               }
+
+               for i, sh := range f.Sections {
+                       if i >= len(tt.sections) {
+                               break
+                       }
+                       have := &sh.SectionHeader
+                       want := tt.sections[i]
+                       if !reflect.DeepEqual(have, want) {
+                               t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+                       }
+               }
+               tn := len(tt.sections)
+               fn := len(f.Sections)
+               if tn != fn {
+                       t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+               }
+
+       }
+}
+
+func TestOpenFailure(t *testing.T) {
+       filename := "file.go"    // not a PE file
+       _, err := Open(filename) // don't crash
+       if err == nil {
+               t.Errorf("open %s: succeeded unexpectedly", filename)
+       }
+}
diff --git a/libgo/go/debug/pe/pe.go b/libgo/go/debug/pe/pe.go
new file mode 100644 (file)
index 0000000..b3dab73
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pe
+
+type FileHeader struct {
+       Machine              uint16
+       NumberOfSections     uint16
+       TimeDateStamp        uint32
+       PointerToSymbolTable uint32
+       NumberOfSymbols      uint32
+       SizeOfOptionalHeader uint16
+       Characteristics      uint16
+}
+
+type SectionHeader32 struct {
+       Name                 [8]uint8
+       VirtualSize          uint32
+       VirtualAddress       uint32
+       SizeOfRawData        uint32
+       PointerToRawData     uint32
+       PointerToRelocations uint32
+       PointerToLineNumbers uint32
+       NumberOfRelocations  uint16
+       NumberOfLineNumbers  uint16
+       Characteristics      uint32
+}
+
+const (
+       IMAGE_FILE_MACHINE_UNKNOWN   = 0x0
+       IMAGE_FILE_MACHINE_AM33      = 0x1d3
+       IMAGE_FILE_MACHINE_AMD64     = 0x8664
+       IMAGE_FILE_MACHINE_ARM       = 0x1c0
+       IMAGE_FILE_MACHINE_EBC       = 0xebc
+       IMAGE_FILE_MACHINE_I386      = 0x14c
+       IMAGE_FILE_MACHINE_IA64      = 0x200
+       IMAGE_FILE_MACHINE_M32R      = 0x9041
+       IMAGE_FILE_MACHINE_MIPS16    = 0x266
+       IMAGE_FILE_MACHINE_MIPSFPU   = 0x366
+       IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466
+       IMAGE_FILE_MACHINE_POWERPC   = 0x1f0
+       IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1
+       IMAGE_FILE_MACHINE_R4000     = 0x166
+       IMAGE_FILE_MACHINE_SH3       = 0x1a2
+       IMAGE_FILE_MACHINE_SH3DSP    = 0x1a3
+       IMAGE_FILE_MACHINE_SH4       = 0x1a6
+       IMAGE_FILE_MACHINE_SH5       = 0x1a8
+       IMAGE_FILE_MACHINE_THUMB     = 0x1c2
+       IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
+)
diff --git a/libgo/go/debug/pe/testdata/gcc-386-mingw-exec b/libgo/go/debug/pe/testdata/gcc-386-mingw-exec
new file mode 100644 (file)
index 0000000..4b808d0
Binary files /dev/null and b/libgo/go/debug/pe/testdata/gcc-386-mingw-exec differ
diff --git a/libgo/go/debug/pe/testdata/gcc-386-mingw-obj b/libgo/go/debug/pe/testdata/gcc-386-mingw-obj
new file mode 100644 (file)
index 0000000..0c84d89
Binary files /dev/null and b/libgo/go/debug/pe/testdata/gcc-386-mingw-obj differ
diff --git a/libgo/go/debug/pe/testdata/hello.c b/libgo/go/debug/pe/testdata/hello.c
new file mode 100644 (file)
index 0000000..a689d36
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+main(void)
+{
+       printf("hello, world\n");
+       return 0;
+}
diff --git a/libgo/go/debug/proc/proc.go b/libgo/go/debug/proc/proc.go
new file mode 100644 (file)
index 0000000..d89649c
--- /dev/null
@@ -0,0 +1,222 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package proc provides a platform-independent interface for
+// tracing and controlling running processes.  It supports
+// multi-threaded processes and provides typical low-level debugging
+// controls such as breakpoints, single stepping, and manipulating
+// memory and registers.
+package proc
+
+// TODO(rsc): Have to import everything that proc_linux.go
+// and proc_darwin.go do, because deps.bash only looks at
+// this file.
+import (
+       _ "container/vector"
+       _ "fmt"
+       _ "io"
+       "os"
+       _ "runtime"
+       "strconv"
+       _ "strings"
+       _ "sync"
+       _ "syscall"
+)
+
+type Word uint64
+
+// A Cause explains why a thread is stopped.
+type Cause interface {
+       String() string
+}
+
+// Regs is a set of named machine registers, including a program
+// counter, link register, and stack pointer.
+//
+// TODO(austin) There's quite a proliferation of methods here.  We
+// could make a Reg interface with Get and Set and make this just PC,
+// Link, SP, Names, and Reg.  We could also put Index in Reg and that
+// makes it easy to get the index of things like the PC (currently
+// there's just no way to know that).  This would also let us include
+// other per-register information like how to print it.
+type Regs interface {
+       // PC returns the value of the program counter.
+       PC() Word
+
+       // SetPC sets the program counter to val.
+       SetPC(val Word) os.Error
+
+       // Link returns the link register, if any.
+       Link() Word
+
+       // SetLink sets the link register to val.
+       SetLink(val Word) os.Error
+
+       // SP returns the value of the stack pointer.
+       SP() Word
+
+       // SetSP sets the stack pointer register to val.
+       SetSP(val Word) os.Error
+
+       // Names returns the names of all of the registers.
+       Names() []string
+
+       // Get returns the value of a register, where i corresponds to
+       // the index of the register's name in the array returned by
+       // Names.
+       Get(i int) Word
+
+       // Set sets the value of a register.
+       Set(i int, val Word) os.Error
+}
+
+// Thread is a thread in the process being traced.
+type Thread interface {
+       // Step steps this thread by a single instruction.  The thread
+       // must be stopped.  If the thread is currently stopped on a
+       // breakpoint, this will step over the breakpoint.
+       //
+       // XXX What if it's stopped because of a signal?
+       Step() os.Error
+
+       // Stopped returns the reason that this thread is stopped.  It
+       // is an error is the thread not stopped.
+       Stopped() (Cause, os.Error)
+
+       // Regs retrieves the current register values from this
+       // thread.  The thread must be stopped.
+       Regs() (Regs, os.Error)
+
+       // Peek reads len(out) bytes from the address addr in this
+       // thread into out.  The thread must be stopped.  It returns
+       // the number of bytes successfully read.  If an error occurs,
+       // such as attempting to read unmapped memory, this count
+       // could be short and an error will be returned.  If this does
+       // encounter unmapped memory, it will read up to the byte
+       // preceding the unmapped area.
+       Peek(addr Word, out []byte) (int, os.Error)
+
+       // Poke writes b to the address addr in this thread.  The
+       // thread must be stopped.  It returns the number of bytes
+       // successfully written.  If an error occurs, such as
+       // attempting to write to unmapped memory, this count could be
+       // short and an error will be returned.  If this does
+       // encounter unmapped memory, it will write up to the byte
+       // preceding the unmapped area.
+       Poke(addr Word, b []byte) (int, os.Error)
+}
+
+// Process is a process being traced.  It consists of a set of
+// threads.  A process can be running, stopped, or terminated.  The
+// process's state extends to all of its threads.
+type Process interface {
+       // Threads returns an array of all threads in this process.
+       Threads() []Thread
+
+       // AddBreakpoint creates a new breakpoint at program counter
+       // pc.  Breakpoints can only be created when the process is
+       // stopped.  It is an error if a breakpoint already exists at
+       // pc.
+       AddBreakpoint(pc Word) os.Error
+
+       // RemoveBreakpoint removes the breakpoint at the program
+       // counter pc.  It is an error if no breakpoint exists at pc.
+       RemoveBreakpoint(pc Word) os.Error
+
+       // Stop stops all running threads in this process before
+       // returning.
+       Stop() os.Error
+
+       // Continue resumes execution of all threads in this process.
+       // Any thread that is stopped on a breakpoint will be stepped
+       // over that breakpoint.  Any thread that is stopped because
+       // of a signal (other than SIGSTOP or SIGTRAP) will receive
+       // the pending signal.
+       Continue() os.Error
+
+       // WaitStop waits until all threads in process p are stopped
+       // as a result of some thread hitting a breakpoint, receiving
+       // a signal, creating a new thread, or exiting.
+       WaitStop() os.Error
+
+       // Detach detaches from this process.  All stopped threads
+       // will be resumed.
+       Detach() os.Error
+}
+
+// Stopped is a stop cause used for threads that are stopped either by
+// user request (e.g., from the Stop method or after single stepping),
+// or that are stopped because some other thread caused the program to
+// stop.
+type Stopped struct{}
+
+func (c Stopped) String() string { return "stopped" }
+
+// Breakpoint is a stop cause resulting from a thread reaching a set
+// breakpoint.
+type Breakpoint Word
+
+// PC returns the program counter that the program is stopped at.
+func (c Breakpoint) PC() Word { return Word(c) }
+
+func (c Breakpoint) String() string {
+       return "breakpoint at 0x" + strconv.Uitob64(uint64(c.PC()), 16)
+}
+
+// Signal is a stop cause resulting from a thread receiving a signal.
+// When the process is continued, the signal will be delivered.
+type Signal string
+
+// Signal returns the signal being delivered to the thread.
+func (c Signal) Name() string { return string(c) }
+
+func (c Signal) String() string { return c.Name() }
+
+// ThreadCreate is a stop cause returned from an existing thread when
+// it creates a new thread.  The new thread exists in a primordial
+// form at this point and will begin executing in earnest when the
+// process is continued.
+type ThreadCreate struct {
+       thread Thread
+}
+
+func (c *ThreadCreate) NewThread() Thread { return c.thread }
+
+func (c *ThreadCreate) String() string { return "thread create" }
+
+// ThreadExit is a stop cause resulting from a thread exiting.  When
+// this cause first arises, the thread will still be in the list of
+// process threads and its registers and memory will still be
+// accessible.
+type ThreadExit struct {
+       exitStatus int
+       signal     string
+}
+
+// Exited returns true if the thread exited normally.
+func (c *ThreadExit) Exited() bool { return c.exitStatus != -1 }
+
+// ExitStatus returns the exit status of the thread if it exited
+// normally or -1 otherwise.
+func (c *ThreadExit) ExitStatus() int { return c.exitStatus }
+
+// Signaled returns true if the thread was terminated by a signal.
+func (c *ThreadExit) Signaled() bool { return c.exitStatus == -1 }
+
+// StopSignal returns the signal that terminated the thread, or "" if
+// it was not terminated by a signal.
+func (c *ThreadExit) StopSignal() string { return c.signal }
+
+func (c *ThreadExit) String() string {
+       res := "thread exited "
+       switch {
+       case c.Exited():
+               res += "with status " + strconv.Itoa(c.ExitStatus())
+       case c.Signaled():
+               res += "from signal " + c.StopSignal()
+       default:
+               res += "from unknown cause"
+       }
+       return res
+}
diff --git a/libgo/go/debug/proc/proc_darwin.go b/libgo/go/debug/proc/proc_darwin.go
new file mode 100644 (file)
index 0000000..7caf3a2
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
+
+import "os"
+
+// Process tracing is not supported on OS X yet.
+
+func Attach(pid int) (Process, os.Error) {
+       return nil, os.NewError("debug/proc not implemented on OS X")
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+       return Attach(0)
+}
diff --git a/libgo/go/debug/proc/proc_freebsd.go b/libgo/go/debug/proc/proc_freebsd.go
new file mode 100644 (file)
index 0000000..f6474ce
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
+
+import "os"
+
+// Process tracing is not supported on FreeBSD yet.
+
+func Attach(pid int) (Process, os.Error) {
+       return nil, os.NewError("debug/proc not implemented on FreeBSD")
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+       return Attach(0)
+}
diff --git a/libgo/go/debug/proc/proc_linux.go b/libgo/go/debug/proc/proc_linux.go
new file mode 100644 (file)
index 0000000..f0cc43a
--- /dev/null
@@ -0,0 +1,1316 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
+
+// TODO(rsc): Imports here after to be in proc.go too in order
+// for deps.bash to get the right answer.
+import (
+       "container/vector"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "runtime"
+       "strconv"
+       "strings"
+       "sync"
+       "syscall"
+)
+
+// This is an implementation of the process tracing interface using
+// Linux's ptrace(2) interface.  The implementation is multi-threaded.
+// Each attached process has an associated monitor thread, and each
+// running attached thread has an associated "wait" thread.  The wait
+// thread calls wait4 on the thread's TID and reports any wait events
+// or errors via "debug events".  The monitor thread consumes these
+// wait events and updates the internally maintained state of each
+// thread.  All ptrace calls must run in the monitor thread, so the
+// monitor executes closures received on the debugReq channel.
+//
+// As ptrace's documentation is somewhat light, this is heavily based
+// on information gleaned from the implementation of ptrace found at
+//   http://lxr.linux.no/linux+v2.6.30/kernel/ptrace.c
+//   http://lxr.linux.no/linux+v2.6.30/arch/x86/kernel/ptrace.c#L854
+// as well as experimentation and examination of gdb's behavior.
+
+const (
+       trace    = false
+       traceIP  = false
+       traceMem = false
+)
+
+/*
+ * Thread state
+ */
+
+// Each thread can be in one of the following set of states.
+// Each state satisfies
+//  isRunning() || isStopped() || isZombie() || isTerminal().
+//
+// Running threads can be sent signals and must be waited on, but they
+// cannot be inspected using ptrace.
+//
+// Stopped threads can be inspected and continued, but cannot be
+// meaningfully waited on.  They can be sent signals, but the signals
+// will be queued until they are running again.
+//
+// Zombie threads cannot be inspected, continued, or sent signals (and
+// therefore they cannot be stopped), but they must be waited on.
+//
+// Terminal threads no longer exist in the OS and thus you can't do
+// anything with them.
+type threadState string
+
+const (
+       running             threadState = "Running"
+       singleStepping      threadState = "SingleStepping" // Transient
+       stopping            threadState = "Stopping"       // Transient
+       stopped             threadState = "Stopped"
+       stoppedBreakpoint   threadState = "StoppedBreakpoint"
+       stoppedSignal       threadState = "StoppedSignal"
+       stoppedThreadCreate threadState = "StoppedThreadCreate"
+       stoppedExiting      threadState = "StoppedExiting"
+       exiting             threadState = "Exiting" // Transient (except main thread)
+       exited              threadState = "Exited"
+       detached            threadState = "Detached"
+)
+
+func (ts threadState) isRunning() bool {
+       return ts == running || ts == singleStepping || ts == stopping
+}
+
+func (ts threadState) isStopped() bool {
+       return ts == stopped || ts == stoppedBreakpoint || ts == stoppedSignal || ts == stoppedThreadCreate || ts == stoppedExiting
+}
+
+func (ts threadState) isZombie() bool { return ts == exiting }
+
+func (ts threadState) isTerminal() bool { return ts == exited || ts == detached }
+
+func (ts threadState) String() string { return string(ts) }
+
+/*
+ * Basic types
+ */
+
+// A breakpoint stores information about a single breakpoint,
+// including its program counter, the overwritten text if the
+// breakpoint is installed.
+type breakpoint struct {
+       pc      uintptr
+       olddata []byte
+}
+
+func (bp *breakpoint) String() string {
+       if bp == nil {
+               return "<nil>"
+       }
+       return fmt.Sprintf("%#x", bp.pc)
+}
+
+// bpinst386 is the breakpoint instruction used on 386 and amd64.
+var bpinst386 = []byte{0xcc}
+
+// A debugEvent represents a reason a thread stopped or a wait error.
+type debugEvent struct {
+       *os.Waitmsg
+       t   *thread
+       err os.Error
+}
+
+// A debugReq is a request to execute a closure in the monitor thread.
+type debugReq struct {
+       f   func() os.Error
+       res chan os.Error
+}
+
+// A transitionHandler specifies a function to be called when a thread
+// changes state and a function to be called when an error occurs in
+// the monitor.  Both run in the monitor thread.  Before the monitor
+// invokes a handler, it removes the handler from the handler queue.
+// The handler should re-add itself if needed.
+type transitionHandler struct {
+       handle func(*thread, threadState, threadState)
+       onErr  func(os.Error)
+}
+
+// A process is a Linux process, which consists of a set of threads.
+// Each running process has one monitor thread, which processes
+// messages from the debugEvents, debugReqs, and stopReq channels and
+// calls transition handlers.
+//
+// To send a message to the monitor thread, first receive from the
+// ready channel.  If the ready channel returns true, the monitor is
+// still running and will accept a message.  If the ready channel
+// returns false, the monitor is not running (the ready channel has
+// been closed), and the reason it is not running will be stored in err.
+type process struct {
+       pid                int
+       threads            map[int]*thread
+       breakpoints        map[uintptr]*breakpoint
+       ready              chan bool
+       debugEvents        chan *debugEvent
+       debugReqs          chan *debugReq
+       stopReq            chan os.Error
+       transitionHandlers vector.Vector
+       err                os.Error
+}
+
+// A thread represents a Linux thread in another process that is being
+// debugged.  Each running thread has an associated goroutine that
+// waits for thread updates and sends them to the process monitor.
+type thread struct {
+       tid  int
+       proc *process
+       // Whether to ignore the next SIGSTOP received by wait.
+       ignoreNextSigstop bool
+
+       // Thread state.  Only modified via setState.
+       state threadState
+       // If state == StoppedBreakpoint
+       breakpoint *breakpoint
+       // If state == StoppedSignal or state == Exited
+       signal int
+       // If state == StoppedThreadCreate
+       newThread *thread
+       // If state == Exited
+       exitStatus int
+}
+
+/*
+ * Errors
+ */
+
+type badState struct {
+       thread  *thread
+       message string
+       state   threadState
+}
+
+func (e *badState) String() string {
+       return fmt.Sprintf("Thread %d %s from state %v", e.thread.tid, e.message, e.state)
+}
+
+type breakpointExistsError Word
+
+func (e breakpointExistsError) String() string {
+       return fmt.Sprintf("breakpoint already exists at PC %#x", e)
+}
+
+type noBreakpointError Word
+
+func (e noBreakpointError) String() string { return fmt.Sprintf("no breakpoint at PC %#x", e) }
+
+type newThreadError struct {
+       *os.Waitmsg
+       wantPid int
+       wantSig int
+}
+
+func (e *newThreadError) String() string {
+       return fmt.Sprintf("newThread wait wanted pid %v and signal %v, got %v and %v", e.Pid, e.StopSignal(), e.wantPid, e.wantSig)
+}
+
+type ProcessExited struct{}
+
+func (p ProcessExited) String() string { return "process exited" }
+
+/*
+ * Ptrace wrappers
+ */
+
+func (t *thread) ptracePeekText(addr uintptr, out []byte) (int, os.Error) {
+       c, err := syscall.PtracePeekText(t.tid, addr, out)
+       if traceMem {
+               fmt.Printf("peek(%#x) => %v, %v\n", addr, out, err)
+       }
+       return c, os.NewSyscallError("ptrace(PEEKTEXT)", err)
+}
+
+func (t *thread) ptracePokeText(addr uintptr, out []byte) (int, os.Error) {
+       c, err := syscall.PtracePokeText(t.tid, addr, out)
+       if traceMem {
+               fmt.Printf("poke(%#x, %v) => %v\n", addr, out, err)
+       }
+       return c, os.NewSyscallError("ptrace(POKETEXT)", err)
+}
+
+func (t *thread) ptraceGetRegs(regs *syscall.PtraceRegs) os.Error {
+       err := syscall.PtraceGetRegs(t.tid, regs)
+       return os.NewSyscallError("ptrace(GETREGS)", err)
+}
+
+func (t *thread) ptraceSetRegs(regs *syscall.PtraceRegs) os.Error {
+       err := syscall.PtraceSetRegs(t.tid, regs)
+       return os.NewSyscallError("ptrace(SETREGS)", err)
+}
+
+func (t *thread) ptraceSetOptions(options int) os.Error {
+       err := syscall.PtraceSetOptions(t.tid, options)
+       return os.NewSyscallError("ptrace(SETOPTIONS)", err)
+}
+
+func (t *thread) ptraceGetEventMsg() (uint, os.Error) {
+       msg, err := syscall.PtraceGetEventMsg(t.tid)
+       return msg, os.NewSyscallError("ptrace(GETEVENTMSG)", err)
+}
+
+func (t *thread) ptraceCont() os.Error {
+       err := syscall.PtraceCont(t.tid, 0)
+       return os.NewSyscallError("ptrace(CONT)", err)
+}
+
+func (t *thread) ptraceContWithSignal(sig int) os.Error {
+       err := syscall.PtraceCont(t.tid, sig)
+       return os.NewSyscallError("ptrace(CONT)", err)
+}
+
+func (t *thread) ptraceStep() os.Error {
+       err := syscall.PtraceSingleStep(t.tid)
+       return os.NewSyscallError("ptrace(SINGLESTEP)", err)
+}
+
+func (t *thread) ptraceDetach() os.Error {
+       err := syscall.PtraceDetach(t.tid)
+       return os.NewSyscallError("ptrace(DETACH)", err)
+}
+
+/*
+ * Logging utilties
+ */
+
+var logLock sync.Mutex
+
+func (t *thread) logTrace(format string, args ...interface{}) {
+       if !trace {
+               return
+       }
+       logLock.Lock()
+       defer logLock.Unlock()
+       fmt.Fprintf(os.Stderr, "Thread %d", t.tid)
+       if traceIP {
+               var regs syscall.PtraceRegs
+               err := t.ptraceGetRegs(&regs)
+               if err == nil {
+                       fmt.Fprintf(os.Stderr, "@%x", regs.PC())
+               }
+       }
+       fmt.Fprint(os.Stderr, ": ")
+       fmt.Fprintf(os.Stderr, format, args...)
+       fmt.Fprint(os.Stderr, "\n")
+}
+
+func (t *thread) warn(format string, args ...interface{}) {
+       logLock.Lock()
+       defer logLock.Unlock()
+       fmt.Fprintf(os.Stderr, "Thread %d: WARNING ", t.tid)
+       fmt.Fprintf(os.Stderr, format, args...)
+       fmt.Fprint(os.Stderr, "\n")
+}
+
+func (p *process) logTrace(format string, args ...interface{}) {
+       if !trace {
+               return
+       }
+       logLock.Lock()
+       defer logLock.Unlock()
+       fmt.Fprintf(os.Stderr, "Process %d: ", p.pid)
+       fmt.Fprintf(os.Stderr, format, args...)
+       fmt.Fprint(os.Stderr, "\n")
+}
+
+/*
+ * State utilities
+ */
+
+// someStoppedThread returns a stopped thread from the process.
+// Returns nil if no threads are stopped.
+//
+// Must be called from the monitor thread.
+func (p *process) someStoppedThread() *thread {
+       for _, t := range p.threads {
+               if t.state.isStopped() {
+                       return t
+               }
+       }
+       return nil
+}
+
+// someRunningThread returns a running thread from the process.
+// Returns nil if no threads are running.
+//
+// Must be called from the monitor thread.
+func (p *process) someRunningThread() *thread {
+       for _, t := range p.threads {
+               if t.state.isRunning() {
+                       return t
+               }
+       }
+       return nil
+}
+
+/*
+ * Breakpoint utilities
+ */
+
+// installBreakpoints adds breakpoints to the attached process.
+//
+// Must be called from the monitor thread.
+func (p *process) installBreakpoints() os.Error {
+       n := 0
+       main := p.someStoppedThread()
+       for _, b := range p.breakpoints {
+               if b.olddata != nil {
+                       continue
+               }
+
+               b.olddata = make([]byte, len(bpinst386))
+               _, err := main.ptracePeekText(uintptr(b.pc), b.olddata)
+               if err != nil {
+                       b.olddata = nil
+                       return err
+               }
+
+               _, err = main.ptracePokeText(uintptr(b.pc), bpinst386)
+               if err != nil {
+                       b.olddata = nil
+                       return err
+               }
+               n++
+       }
+       if n > 0 {
+               p.logTrace("installed %d/%d breakpoints", n, len(p.breakpoints))
+       }
+
+       return nil
+}
+
+// uninstallBreakpoints removes the installed breakpoints from p.
+//
+// Must be called from the monitor thread.
+func (p *process) uninstallBreakpoints() os.Error {
+       if len(p.threads) == 0 {
+               return nil
+       }
+       n := 0
+       main := p.someStoppedThread()
+       for _, b := range p.breakpoints {
+               if b.olddata == nil {
+                       continue
+               }
+
+               _, err := main.ptracePokeText(uintptr(b.pc), b.olddata)
+               if err != nil {
+                       return err
+               }
+               b.olddata = nil
+               n++
+       }
+       if n > 0 {
+               p.logTrace("uninstalled %d/%d breakpoints", n, len(p.breakpoints))
+       }
+
+       return nil
+}
+
+/*
+ * Debug event handling
+ */
+
+// wait waits for a wait event from this thread and sends it on the
+// debug events channel for this thread's process.  This should be
+// started in its own goroutine when the attached thread enters a
+// running state.  The goroutine will exit as soon as it sends a debug
+// event.
+func (t *thread) wait() {
+       for {
+               var ev debugEvent
+               ev.t = t
+               t.logTrace("beginning wait")
+               ev.Waitmsg, ev.err = os.Wait(t.tid, syscall.WALL)
+               if ev.err == nil && ev.Pid != t.tid {
+                       panic(fmt.Sprint("Wait returned pid ", ev.Pid, " wanted ", t.tid))
+               }
+               if ev.StopSignal() == syscall.SIGSTOP && t.ignoreNextSigstop {
+                       // Spurious SIGSTOP.  See Thread.Stop().
+                       t.ignoreNextSigstop = false
+                       err := t.ptraceCont()
+                       if err == nil {
+                               continue
+                       }
+                       // If we failed to continue, just let
+                       // the stop go through so we can
+                       // update the thread's state.
+               }
+               if !<-t.proc.ready {
+                       // The monitor exited
+                       break
+               }
+               t.proc.debugEvents <- &ev
+               break
+       }
+}
+
+// setState sets this thread's state, starts a wait thread if
+// necessary, and invokes state transition handlers.
+//
+// Must be called from the monitor thread.
+func (t *thread) setState(newState threadState) {
+       oldState := t.state
+       t.state = newState
+       t.logTrace("state %v -> %v", oldState, newState)
+
+       if !oldState.isRunning() && (newState.isRunning() || newState.isZombie()) {
+               // Start waiting on this thread
+               go t.wait()
+       }
+
+       // Invoke state change handlers
+       handlers := t.proc.transitionHandlers
+       if handlers.Len() == 0 {
+               return
+       }
+
+       t.proc.transitionHandlers = nil
+       for _, h := range handlers {
+               h := h.(*transitionHandler)
+               h.handle(t, oldState, newState)
+       }
+}
+
+// sendSigstop sends a SIGSTOP to this thread.
+func (t *thread) sendSigstop() os.Error {
+       t.logTrace("sending SIGSTOP")
+       err := syscall.Tgkill(t.proc.pid, t.tid, syscall.SIGSTOP)
+       return os.NewSyscallError("tgkill", err)
+}
+
+// stopAsync sends SIGSTOP to all threads in state 'running'.
+//
+// Must be called from the monitor thread.
+func (p *process) stopAsync() os.Error {
+       for _, t := range p.threads {
+               if t.state == running {
+                       err := t.sendSigstop()
+                       if err != nil {
+                               return err
+                       }
+                       t.setState(stopping)
+               }
+       }
+       return nil
+}
+
+// doTrap handles SIGTRAP debug events with a cause of 0.  These can
+// be caused either by an installed breakpoint, a breakpoint in the
+// program text, or by single stepping.
+//
+// TODO(austin) I think we also get this on an execve syscall.
+func (ev *debugEvent) doTrap() (threadState, os.Error) {
+       t := ev.t
+
+       if t.state == singleStepping {
+               return stopped, nil
+       }
+
+       // Hit a breakpoint.  Linux leaves the program counter after
+       // the breakpoint.  If this is an installed breakpoint, we
+       // need to back the PC up to the breakpoint PC.
+       var regs syscall.PtraceRegs
+       err := t.ptraceGetRegs(&regs)
+       if err != nil {
+               return stopped, err
+       }
+
+       b, ok := t.proc.breakpoints[uintptr(regs.PC())-uintptr(len(bpinst386))]
+       if !ok {
+               // We must have hit a breakpoint that was actually in
+               // the program.  Leave the IP where it is so we don't
+               // re-execute the breakpoint instruction.  Expose the
+               // fact that we stopped with a SIGTRAP.
+               return stoppedSignal, nil
+       }
+
+       t.breakpoint = b
+       t.logTrace("at breakpoint %v, backing up PC from %#x", b, regs.PC())
+
+       regs.SetPC(uint64(b.pc))
+       err = t.ptraceSetRegs(&regs)
+       if err != nil {
+               return stopped, err
+       }
+       return stoppedBreakpoint, nil
+}
+
+// doPtraceClone handles SIGTRAP debug events with a PTRACE_EVENT_CLONE
+// cause.  It initializes the new thread, adds it to the process, and
+// returns the appropriate thread state for the existing thread.
+func (ev *debugEvent) doPtraceClone() (threadState, os.Error) {
+       t := ev.t
+
+       // Get the TID of the new thread
+       tid, err := t.ptraceGetEventMsg()
+       if err != nil {
+               return stopped, err
+       }
+
+       nt, err := t.proc.newThread(int(tid), syscall.SIGSTOP, true)
+       if err != nil {
+               return stopped, err
+       }
+
+       // Remember the thread
+       t.newThread = nt
+
+       return stoppedThreadCreate, nil
+}
+
+// doPtraceExit handles SIGTRAP debug events with a PTRACE_EVENT_EXIT
+// cause.  It sets up the thread's state, but does not remove it from
+// the process.  A later WIFEXITED debug event will remove it from the
+// process.
+func (ev *debugEvent) doPtraceExit() (threadState, os.Error) {
+       t := ev.t
+
+       // Get exit status
+       exitStatus, err := t.ptraceGetEventMsg()
+       if err != nil {
+               return stopped, err
+       }
+       ws := syscall.WaitStatus(exitStatus)
+       t.logTrace("exited with %v", ws)
+       switch {
+       case ws.Exited():
+               t.exitStatus = ws.ExitStatus()
+       case ws.Signaled():
+               t.signal = ws.Signal()
+       }
+
+       // We still need to continue this thread and wait on this
+       // thread's WIFEXITED event.  We'll delete it then.
+       return stoppedExiting, nil
+}
+
+// process handles a debug event.  It modifies any thread or process
+// state as necessary, uninstalls breakpoints if necessary, and stops
+// any running threads.
+func (ev *debugEvent) process() os.Error {
+       if ev.err != nil {
+               return ev.err
+       }
+
+       t := ev.t
+       t.exitStatus = -1
+       t.signal = -1
+
+       // Decode wait status.
+       var state threadState
+       switch {
+       case ev.Stopped():
+               state = stoppedSignal
+               t.signal = ev.StopSignal()
+               t.logTrace("stopped with %v", ev)
+               if ev.StopSignal() == syscall.SIGTRAP {
+                       // What caused the debug trap?
+                       var err os.Error
+                       switch cause := ev.TrapCause(); cause {
+                       case 0:
+                               // Breakpoint or single stepping
+                               state, err = ev.doTrap()
+
+                       case syscall.PTRACE_EVENT_CLONE:
+                               state, err = ev.doPtraceClone()
+
+                       case syscall.PTRACE_EVENT_EXIT:
+                               state, err = ev.doPtraceExit()
+
+                       default:
+                               t.warn("Unknown trap cause %d", cause)
+                       }
+
+                       if err != nil {
+                               t.setState(stopped)
+                               t.warn("failed to handle trap %v: %v", ev, err)
+                       }
+               }
+
+       case ev.Exited():
+               state = exited
+               t.proc.threads[t.tid] = nil, false
+               t.logTrace("exited %v", ev)
+               // We should have gotten the exit status in
+               // PTRACE_EVENT_EXIT, but just in case.
+               t.exitStatus = ev.ExitStatus()
+
+       case ev.Signaled():
+               state = exited
+               t.proc.threads[t.tid] = nil, false
+               t.logTrace("signaled %v", ev)
+               // Again, this should be redundant.
+               t.signal = ev.Signal()
+
+       default:
+               panic(fmt.Sprintf("Unexpected wait status %v", ev.Waitmsg))
+       }
+
+       // If we sent a SIGSTOP to the thread (indicated by state
+       // Stopping), we might have raced with a different type of
+       // stop.  If we didn't get the stop we expected, then the
+       // SIGSTOP we sent is now queued up, so we should ignore the
+       // next one we get.
+       if t.state == stopping && ev.StopSignal() != syscall.SIGSTOP {
+               t.ignoreNextSigstop = true
+       }
+
+       // TODO(austin) If we're in state stopping and get a SIGSTOP,
+       // set state stopped instead of stoppedSignal.
+
+       t.setState(state)
+
+       if t.proc.someRunningThread() == nil {
+               // Nothing is running, uninstall breakpoints
+               return t.proc.uninstallBreakpoints()
+       }
+       // Stop any other running threads
+       return t.proc.stopAsync()
+}
+
+// onStop adds a handler for state transitions from running to
+// non-running states.  The handler will be called from the monitor
+// thread.
+//
+// Must be called from the monitor thread.
+func (t *thread) onStop(handle func(), onErr func(os.Error)) {
+       // TODO(austin) This is rather inefficient for things like
+       // stepping all threads during a continue.  Maybe move
+       // transitionHandlers to the thread, or have both per-thread
+       // and per-process transition handlers.
+       h := &transitionHandler{nil, onErr}
+       h.handle = func(st *thread, old, new threadState) {
+               if t == st && old.isRunning() && !new.isRunning() {
+                       handle()
+               } else {
+                       t.proc.transitionHandlers.Push(h)
+               }
+       }
+       t.proc.transitionHandlers.Push(h)
+}
+
+/*
+ * Event monitor
+ */
+
+// monitor handles debug events and debug requests for p, exiting when
+// there are no threads left in p.
+func (p *process) monitor() {
+       var err os.Error
+
+       // Linux requires that all ptrace calls come from the thread
+       // that originally attached.  Prevent the Go scheduler from
+       // migrating us to other OS threads.
+       runtime.LockOSThread()
+       defer runtime.UnlockOSThread()
+
+       hadThreads := false
+       for err == nil {
+               p.ready <- true
+               select {
+               case event := <-p.debugEvents:
+                       err = event.process()
+
+               case req := <-p.debugReqs:
+                       req.res <- req.f()
+
+               case err = <-p.stopReq:
+                       break
+               }
+
+               if len(p.threads) == 0 {
+                       if err == nil && hadThreads {
+                               p.logTrace("no more threads; monitor exiting")
+                               err = ProcessExited{}
+                       }
+               } else {
+                       hadThreads = true
+               }
+       }
+
+       // Abort waiting handlers
+       // TODO(austin) How do I stop the wait threads?
+       for _, h := range p.transitionHandlers {
+               h := h.(*transitionHandler)
+               h.onErr(err)
+       }
+
+       // Indicate that the monitor cannot receive any more messages
+       p.err = err
+       close(p.ready)
+}
+
+// do executes f in the monitor thread (and, thus, atomically with
+// respect to thread state changes).  f must not block.
+//
+// Must NOT be called from the monitor thread.
+func (p *process) do(f func() os.Error) os.Error {
+       if !<-p.ready {
+               return p.err
+       }
+       req := &debugReq{f, make(chan os.Error)}
+       p.debugReqs <- req
+       return <-req.res
+}
+
+// stopMonitor stops the monitor with the given error.  If the monitor
+// is already stopped, does nothing.
+func (p *process) stopMonitor(err os.Error) {
+       if err == nil {
+               panic("cannot stop the monitor with no error")
+       }
+       if <-p.ready {
+               p.stopReq <- err
+       }
+}
+
+/*
+ * Public thread interface
+ */
+
+func (t *thread) Regs() (Regs, os.Error) {
+       var regs syscall.PtraceRegs
+
+       err := t.proc.do(func() os.Error {
+               if !t.state.isStopped() {
+                       return &badState{t, "cannot get registers", t.state}
+               }
+               return t.ptraceGetRegs(&regs)
+       })
+       if err != nil {
+               return nil, err
+       }
+
+       setter := func(r *syscall.PtraceRegs) os.Error {
+               return t.proc.do(func() os.Error {
+                       if !t.state.isStopped() {
+                               return &badState{t, "cannot get registers", t.state}
+                       }
+                       return t.ptraceSetRegs(r)
+               })
+       }
+       return newRegs(&regs, setter), nil
+}
+
+func (t *thread) Peek(addr Word, out []byte) (int, os.Error) {
+       var c int
+
+       err := t.proc.do(func() os.Error {
+               if !t.state.isStopped() {
+                       return &badState{t, "cannot peek text", t.state}
+               }
+
+               var err os.Error
+               c, err = t.ptracePeekText(uintptr(addr), out)
+               return err
+       })
+
+       return c, err
+}
+
+func (t *thread) Poke(addr Word, out []byte) (int, os.Error) {
+       var c int
+
+       err := t.proc.do(func() os.Error {
+               if !t.state.isStopped() {
+                       return &badState{t, "cannot poke text", t.state}
+               }
+
+               var err os.Error
+               c, err = t.ptracePokeText(uintptr(addr), out)
+               return err
+       })
+
+       return c, err
+}
+
+// stepAsync starts this thread single stepping.  When the single step
+// is complete, it will send nil on the given channel.  If an error
+// occurs while setting up the single step, it returns that error.  If
+// an error occurs while waiting for the single step to complete, it
+// sends that error on the channel.
+func (t *thread) stepAsync(ready chan os.Error) os.Error {
+       if err := t.ptraceStep(); err != nil {
+               return err
+       }
+       t.setState(singleStepping)
+       t.onStop(func() { ready <- nil },
+               func(err os.Error) { ready <- err })
+       return nil
+}
+
+func (t *thread) Step() os.Error {
+       t.logTrace("Step {")
+       defer t.logTrace("}")
+
+       ready := make(chan os.Error)
+
+       err := t.proc.do(func() os.Error {
+               if !t.state.isStopped() {
+                       return &badState{t, "cannot single step", t.state}
+               }
+               return t.stepAsync(ready)
+       })
+       if err != nil {
+               return err
+       }
+
+       err = <-ready
+       return err
+}
+
+// TODO(austin) We should probably get this via C's strsignal.
+var sigNames = [...]string{
+       "SIGEXIT", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL",
+       "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL",
+       "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM",
+       "SIGTERM", "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP",
+       "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU",
+       "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGPOLL",
+       "SIGPWR", "SIGSYS",
+}
+
+// sigName returns the symbolic name for the given signal number.  If
+// the signal number is invalid, returns "<invalid>".
+func sigName(signal int) string {
+       if signal < 0 || signal >= len(sigNames) {
+               return "<invalid>"
+       }
+       return sigNames[signal]
+}
+
+func (t *thread) Stopped() (Cause, os.Error) {
+       var c Cause
+       err := t.proc.do(func() os.Error {
+               switch t.state {
+               case stopped:
+                       c = Stopped{}
+
+               case stoppedBreakpoint:
+                       c = Breakpoint(t.breakpoint.pc)
+
+               case stoppedSignal:
+                       c = Signal(sigName(t.signal))
+
+               case stoppedThreadCreate:
+                       c = &ThreadCreate{t.newThread}
+
+               case stoppedExiting, exiting, exited:
+                       if t.signal == -1 {
+                               c = &ThreadExit{t.exitStatus, ""}
+                       } else {
+                               c = &ThreadExit{t.exitStatus, sigName(t.signal)}
+                       }
+
+               default:
+                       return &badState{t, "cannot get stop cause", t.state}
+               }
+               return nil
+       })
+       if err != nil {
+               return nil, err
+       }
+
+       return c, nil
+}
+
+func (p *process) Threads() []Thread {
+       var res []Thread
+
+       p.do(func() os.Error {
+               res = make([]Thread, len(p.threads))
+               i := 0
+               for _, t := range p.threads {
+                       // Exclude zombie threads.
+                       st := t.state
+                       if st == exiting || st == exited || st == detached {
+                               continue
+                       }
+
+                       res[i] = t
+                       i++
+               }
+               res = res[0:i]
+               return nil
+       })
+       return res
+}
+
+func (p *process) AddBreakpoint(pc Word) os.Error {
+       return p.do(func() os.Error {
+               if t := p.someRunningThread(); t != nil {
+                       return &badState{t, "cannot add breakpoint", t.state}
+               }
+               if _, ok := p.breakpoints[uintptr(pc)]; ok {
+                       return breakpointExistsError(pc)
+               }
+               p.breakpoints[uintptr(pc)] = &breakpoint{pc: uintptr(pc)}
+               return nil
+       })
+}
+
+func (p *process) RemoveBreakpoint(pc Word) os.Error {
+       return p.do(func() os.Error {
+               if t := p.someRunningThread(); t != nil {
+                       return &badState{t, "cannot remove breakpoint", t.state}
+               }
+               if _, ok := p.breakpoints[uintptr(pc)]; !ok {
+                       return noBreakpointError(pc)
+               }
+               p.breakpoints[uintptr(pc)] = nil, false
+               return nil
+       })
+}
+
+func (p *process) Continue() os.Error {
+       // Single step any threads that are stopped at breakpoints so
+       // we can reinstall breakpoints.
+       var ready chan os.Error
+       count := 0
+
+       err := p.do(func() os.Error {
+               // We make the ready channel big enough to hold all
+               // ready message so we don't jam up the monitor if we
+               // stop listening (e.g., if there's an error).
+               ready = make(chan os.Error, len(p.threads))
+
+               for _, t := range p.threads {
+                       if !t.state.isStopped() {
+                               continue
+                       }
+
+                       // We use the breakpoint map directly here
+                       // instead of checking the stop cause because
+                       // it could have been stopped at a breakpoint
+                       // for some other reason, or the breakpoint
+                       // could have been added since it was stopped.
+                       var regs syscall.PtraceRegs
+                       err := t.ptraceGetRegs(&regs)
+                       if err != nil {
+                               return err
+                       }
+                       if b, ok := p.breakpoints[uintptr(regs.PC())]; ok {
+                               t.logTrace("stepping over breakpoint %v", b)
+                               if err := t.stepAsync(ready); err != nil {
+                                       return err
+                               }
+                               count++
+                       }
+               }
+               return nil
+       })
+       if err != nil {
+               p.stopMonitor(err)
+               return err
+       }
+
+       // Wait for single stepping threads
+       for count > 0 {
+               err = <-ready
+               if err != nil {
+                       p.stopMonitor(err)
+                       return err
+               }
+               count--
+       }
+
+       // Continue all threads
+       err = p.do(func() os.Error {
+               if err := p.installBreakpoints(); err != nil {
+                       return err
+               }
+
+               for _, t := range p.threads {
+                       var err os.Error
+                       switch {
+                       case !t.state.isStopped():
+                               continue
+
+                       case t.state == stoppedSignal && t.signal != syscall.SIGSTOP && t.signal != syscall.SIGTRAP:
+                               t.logTrace("continuing with signal %d", t.signal)
+                               err = t.ptraceContWithSignal(t.signal)
+
+                       default:
+                               t.logTrace("continuing")
+                               err = t.ptraceCont()
+                       }
+                       if err != nil {
+                               return err
+                       }
+                       if t.state == stoppedExiting {
+                               t.setState(exiting)
+                       } else {
+                               t.setState(running)
+                       }
+               }
+               return nil
+       })
+       if err != nil {
+               // TODO(austin) Do we need to stop the monitor with
+               // this error atomically with the do-routine above?
+               p.stopMonitor(err)
+               return err
+       }
+
+       return nil
+}
+
+func (p *process) WaitStop() os.Error {
+       // We need a non-blocking ready channel for the case where all
+       // threads are already stopped.
+       ready := make(chan os.Error, 1)
+
+       err := p.do(func() os.Error {
+               // Are all of the threads already stopped?
+               if p.someRunningThread() == nil {
+                       ready <- nil
+                       return nil
+               }
+
+               // Monitor state transitions
+               h := &transitionHandler{}
+               h.handle = func(st *thread, old, new threadState) {
+                       if !new.isRunning() {
+                               if p.someRunningThread() == nil {
+                                       ready <- nil
+                                       return
+                               }
+                       }
+                       p.transitionHandlers.Push(h)
+               }
+               h.onErr = func(err os.Error) { ready <- err }
+               p.transitionHandlers.Push(h)
+               return nil
+       })
+       if err != nil {
+               return err
+       }
+
+       return <-ready
+}
+
+func (p *process) Stop() os.Error {
+       err := p.do(func() os.Error { return p.stopAsync() })
+       if err != nil {
+               return err
+       }
+
+       return p.WaitStop()
+}
+
+func (p *process) Detach() os.Error {
+       if err := p.Stop(); err != nil {
+               return err
+       }
+
+       err := p.do(func() os.Error {
+               if err := p.uninstallBreakpoints(); err != nil {
+                       return err
+               }
+
+               for pid, t := range p.threads {
+                       if t.state.isStopped() {
+                               // We can't detach from zombies.
+                               if err := t.ptraceDetach(); err != nil {
+                                       return err
+                               }
+                       }
+                       t.setState(detached)
+                       p.threads[pid] = nil, false
+               }
+               return nil
+       })
+       // TODO(austin) Wait for monitor thread to exit?
+       return err
+}
+
+// newThread creates a new thread object and waits for its initial
+// signal.  If cloned is true, this thread was cloned from a thread we
+// are already attached to.
+//
+// Must be run from the monitor thread.
+func (p *process) newThread(tid int, signal int, cloned bool) (*thread, os.Error) {
+       t := &thread{tid: tid, proc: p, state: stopped}
+
+       // Get the signal from the thread
+       // TODO(austin) Thread might already be stopped if we're attaching.
+       w, err := os.Wait(tid, syscall.WALL)
+       if err != nil {
+               return nil, err
+       }
+       if w.Pid != tid || w.StopSignal() != signal {
+               return nil, &newThreadError{w, tid, signal}
+       }
+
+       if !cloned {
+               err = t.ptraceSetOptions(syscall.PTRACE_O_TRACECLONE | syscall.PTRACE_O_TRACEEXIT)
+               if err != nil {
+                       return nil, err
+               }
+       }
+
+       p.threads[tid] = t
+
+       return t, nil
+}
+
+// attachThread attaches a running thread to the process.
+//
+// Must NOT be run from the monitor thread.
+func (p *process) attachThread(tid int) (*thread, os.Error) {
+       p.logTrace("attaching to thread %d", tid)
+       var thr *thread
+       err := p.do(func() os.Error {
+               errno := syscall.PtraceAttach(tid)
+               if errno != 0 {
+                       return os.NewSyscallError("ptrace(ATTACH)", errno)
+               }
+
+               var err os.Error
+               thr, err = p.newThread(tid, syscall.SIGSTOP, false)
+               return err
+       })
+       return thr, err
+}
+
+// attachAllThreads attaches to all threads in a process.
+func (p *process) attachAllThreads() os.Error {
+       taskPath := "/proc/" + strconv.Itoa(p.pid) + "/task"
+       taskDir, err := os.Open(taskPath, os.O_RDONLY, 0)
+       if err != nil {
+               return err
+       }
+       defer taskDir.Close()
+
+       // We stop threads as we attach to them; however, because new
+       // threads can appear while we're looping over all of them, we
+       // have to repeatly scan until we know we're attached to all
+       // of them.
+       for again := true; again; {
+               again = false
+
+               tids, err := taskDir.Readdirnames(-1)
+               if err != nil {
+                       return err
+               }
+
+               for _, tidStr := range tids {
+                       tid, err := strconv.Atoi(tidStr)
+                       if err != nil {
+                               return err
+                       }
+                       if _, ok := p.threads[tid]; ok {
+                               continue
+                       }
+
+                       _, err = p.attachThread(tid)
+                       if err != nil {
+                               // There could have been a race, or
+                               // this process could be a zobmie.
+                               statFile, err2 := ioutil.ReadFile(taskPath + "/" + tidStr + "/stat")
+                               if err2 != nil {
+                                       switch err2 := err2.(type) {
+                                       case *os.PathError:
+                                               if err2.Error == os.ENOENT {
+                                                       // Raced with thread exit
+                                                       p.logTrace("raced with thread %d exit", tid)
+                                                       continue
+                                               }
+                                       }
+                                       // Return the original error
+                                       return err
+                               }
+
+                               statParts := strings.Split(string(statFile), " ", 4)
+                               if len(statParts) > 2 && statParts[2] == "Z" {
+                                       // tid is a zombie
+                                       p.logTrace("thread %d is a zombie", tid)
+                                       continue
+                               }
+
+                               // Return the original error
+                               return err
+                       }
+                       again = true
+               }
+       }
+
+       return nil
+}
+
+// newProcess creates a new process object and starts its monitor thread.
+func newProcess(pid int) *process {
+       p := &process{
+               pid:         pid,
+               threads:     make(map[int]*thread),
+               breakpoints: make(map[uintptr]*breakpoint),
+               ready:       make(chan bool, 1),
+               debugEvents: make(chan *debugEvent),
+               debugReqs:   make(chan *debugReq),
+               stopReq:     make(chan os.Error),
+       }
+
+       go p.monitor()
+
+       return p
+}
+
+// Attach attaches to process pid and stops all of its threads.
+func Attach(pid int) (Process, os.Error) {
+       p := newProcess(pid)
+
+       // Attach to all threads
+       err := p.attachAllThreads()
+       if err != nil {
+               p.Detach()
+               // TODO(austin) Detach stopped the monitor already
+               //p.stopMonitor(err);
+               return nil, err
+       }
+
+       return p, nil
+}
+
+// ForkExec forks the current process and execs argv0, stopping the
+// new process after the exec syscall.  See os.ForkExec for additional
+// details.
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+       p := newProcess(-1)
+
+       // Create array of integer (system) fds.
+       intfd := make([]int, len(fd))
+       for i, f := range fd {
+               if f == nil {
+                       intfd[i] = -1
+               } else {
+                       intfd[i] = f.Fd()
+               }
+       }
+
+       // Fork from the monitor thread so we get the right tracer pid.
+       err := p.do(func() os.Error {
+               pid, errno := syscall.PtraceForkExec(argv0, argv, envv, dir, intfd)
+               if errno != 0 {
+                       return &os.PathError{"fork/exec", argv0, os.Errno(errno)}
+               }
+               p.pid = pid
+
+               // The process will raise SIGTRAP when it reaches execve.
+               _, err := p.newThread(pid, syscall.SIGTRAP, false)
+               return err
+       })
+       if err != nil {
+               p.stopMonitor(err)
+               return nil, err
+       }
+
+       return p, nil
+}
diff --git a/libgo/go/debug/proc/proc_nacl.go b/libgo/go/debug/proc/proc_nacl.go
new file mode 100644 (file)
index 0000000..be26bbf
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
+
+import (
+       "os"
+       "syscall"
+)
+
+// Process tracing is not supported on Native Client.
+
+func Attach(pid int) (Process, os.Error) {
+       return nil, os.NewSyscallError("ptrace", syscall.ENACL)
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+       return nil, os.NewSyscallError("fork/exec", syscall.ENACL)
+}
diff --git a/libgo/go/debug/proc/proc_windows.go b/libgo/go/debug/proc/proc_windows.go
new file mode 100644 (file)
index 0000000..dc22fae
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
+
+import "os"
+
+// Process tracing is not supported on windows yet.
+
+func Attach(pid int) (Process, os.Error) {
+       return nil, os.NewError("debug/proc not implemented on windows")
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+       return Attach(0)
+}
diff --git a/libgo/go/debug/proc/ptrace-nptl.txt b/libgo/go/debug/proc/ptrace-nptl.txt
new file mode 100644 (file)
index 0000000..62cbf77
--- /dev/null
@@ -0,0 +1,132 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ptrace and NTPL, the missing manpage
+
+== Signals ==
+
+A signal sent to a ptrace'd process or thread causes only the thread
+that receives it to stop and report to the attached process.
+
+Use tgkill to target a signal (for example, SIGSTOP) at a particular
+thread.  If you use kill, the signal could be delivered to another
+thread in the same process.
+
+Note that SIGSTOP differs from its usual behavior when a process is
+being traced.  Usually, a SIGSTOP sent to any thread in a thread group
+will stop all threads in the thread group.  When a thread is traced,
+however, a SIGSTOP affects only the receiving thread (and any other
+threads in the thread group that are not traced).
+
+SIGKILL behaves like it does for non-traced processes.  It affects all
+threads in the process and terminates them without the WSTOPSIG event
+generated by other signals.  However, if PTRACE_O_TRACEEXIT is set,
+the attached process will still receive PTRACE_EVENT_EXIT events
+before receiving WIFSIGNALED events.
+
+See "Following thread death" for a caveat regarding signal delivery to
+zombie threads.
+
+== Waiting on threads ==
+
+Cloned threads in ptrace'd processes are treated similarly to cloned
+threads in your own process.  Thus, you must use the __WALL option in
+order to receive notifications from threads created by the child
+process.  Similarly, the __WCLONE option will wait only on
+notifications from threads created by the child process and *not* on
+notifications from the initial child thread.
+
+Even when waiting on a specific thread's PID using waitpid or similar,
+__WALL or __WCLONE is necessary or waitpid will return ECHILD.
+
+== Attaching to existing threads ==
+
+libthread_db (which gdb uses), attaches to existing threads by pulling
+the pthread data structures out of the traced process.  The much
+easier way is to traverse the /proc/PID/task directory, though it's
+unclear how the semantics of these two approaches differ.
+
+Unfortunately, if the main thread has exited (but the overall process
+has not), it sticks around as a zombie process.  This zombie will
+appear in the /proc/PID/task directory, but trying to attach to it
+will yield EPERM.  In this case, the third field of the
+/proc/PID/task/PID/stat file will be "Z".  Attempting to open the stat
+file is also a convenient way to detect races between listing the task
+directory and the thread exiting.  Coincidentally, gdb will simply
+fail to attach to a process whose main thread is a zombie.
+
+Because new threads may be created while the debugger is in the
+process of attaching to existing threads, the debugger must repeatedly
+re-list the task directory until it has attached to (and thus stopped)
+every thread listed.
+
+In order to follow new threads created by existing threads,
+PTRACE_O_TRACECLONE must be set on each thread attached to.
+
+== Following new threads ==
+
+With the child process stopped, use PTRACE_SETOPTIONS to set the
+PTRACE_O_TRACECLONE option.  This option is per-thread, and thus must
+be set on each existing thread individually.  When an existing thread
+with PTRACE_O_TRACECLONE set spawns a new thread, the existing thread
+will stop with (SIGTRAP | PTRACE_EVENT_CLONE << 8) and the PID of the
+new thread can be retrieved with PTRACE_GETEVENTMSG on the creating
+thread.  At this time, the new thread will exist, but will initially
+be stopped with a SIGSTOP.  The new thread will automatically be
+traced and will inherit the PTRACE_O_TRACECLONE option from its
+parent.  The attached process should wait on the new thread to receive
+the SIGSTOP notification.
+
+When using waitpid(-1, ...), don't rely on the parent thread reporting
+a SIGTRAP before receiving the SIGSTOP from the new child thread.
+
+Without PTRACE_O_TRACECLONE, newly cloned threads will not be
+ptrace'd.  As a result, signals received by new threads will be
+handled in the usual way, which may affect the parent and in turn
+appear to the attached process, but attributed to the parent (possibly
+in unexpected ways).
+
+== Following thread death ==
+
+If any thread with the PTRACE_O_TRACEEXIT option set exits (either by
+returning or pthread_exit'ing), the tracing process will receive an
+immediate PTRACE_EVENT_EXIT.  At this point, the thread will still
+exist.  The exit status, encoded as for wait, can be queried using
+PTRACE_GETEVENTMSG on the exiting thread's PID.  The thread should be
+continued so it can actually exit, after which its wait behavior is
+the same as for a thread without the PTRACE_O_TRACEEXIT option.
+
+If a non-main thread exits (either by returning or pthread_exit'ing),
+its corresponding process will also exit, producing a WIFEXITED event
+(after the process is continued from a possible PTRACE_EVENT_EXIT
+event).  It is *not* necessary for another thread to ptrace_join for
+this to happen.
+
+If the main thread exits by returning, then all threads will exit,
+first generating a PTRACE_EVENT_EXIT event for each thread if
+appropriate, then producing a WIFEXITED event for each thread.
+
+If the main thread exits using pthread_exit, then it enters a
+non-waitable zombie state.  It will still produce an immediate
+PTRACE_O_TRACEEXIT event, but the WIFEXITED event will be delayed
+until the entire process exits.  This state exists so that shells
+don't think the process is done until all of the threads have exited.
+Unfortunately, signals cannot be delivered to non-waitable zombies.
+Most notably, SIGSTOP cannot be delivered; as a result, when you
+broadcast SIGSTOP to all of the threads, you must not wait for
+non-waitable zombies to stop.  Furthermore, any ptrace command on a
+non-waitable zombie, including PTRACE_DETACH, will return ESRCH.
+
+== Multi-threaded debuggers ==
+
+If the debugger itself is multi-threaded, ptrace calls must come from
+the same thread that originally attached to the remote thread.  The
+kernel simply compares the PID of the caller of ptrace against the
+tracer PID of the process passed to ptrace.  Because each debugger
+thread has a different PID, calling ptrace from a different thread
+might as well be calling it from a different process and the kernel
+will return ESRCH.
+
+wait, on the other hand, does not have this restriction.  Any debugger
+thread can wait on any thread in the attached process.
diff --git a/libgo/go/debug/proc/regs_darwin_386.go b/libgo/go/debug/proc/regs_darwin_386.go
new file mode 100644 (file)
index 0000000..60c9ac7
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
diff --git a/libgo/go/debug/proc/regs_darwin_amd64.go b/libgo/go/debug/proc/regs_darwin_amd64.go
new file mode 100644 (file)
index 0000000..60c9ac7
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
diff --git a/libgo/go/debug/proc/regs_freebsd_386.go b/libgo/go/debug/proc/regs_freebsd_386.go
new file mode 100644 (file)
index 0000000..60c9ac7
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
diff --git a/libgo/go/debug/proc/regs_freebsd_amd64.go b/libgo/go/debug/proc/regs_freebsd_amd64.go
new file mode 100644 (file)
index 0000000..60c9ac7
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
diff --git a/libgo/go/debug/proc/regs_linux_386.go b/libgo/go/debug/proc/regs_linux_386.go
new file mode 100644 (file)
index 0000000..b4a9769
--- /dev/null
@@ -0,0 +1,143 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
+
+import (
+       "os"
+       "strconv"
+       "syscall"
+)
+
+type _386Regs struct {
+       syscall.PtraceRegs
+       setter func(*syscall.PtraceRegs) os.Error
+}
+
+var names = []string{
+       "eax",
+       "ebx",
+       "ecx",
+       "edx",
+       "esi",
+       "edi",
+       "ebp",
+       "esp",
+       "eip",
+       "eflags",
+       "cs",
+       "ss",
+       "ds",
+       "es",
+       "fs",
+       "gs",
+}
+
+func (r *_386Regs) PC() Word { return Word(r.Eip) }
+
+func (r *_386Regs) SetPC(val Word) os.Error {
+       r.Eip = int32(val)
+       return r.setter(&r.PtraceRegs)
+}
+
+func (r *_386Regs) Link() Word {
+       // TODO(austin)
+       panic("No link register")
+}
+
+func (r *_386Regs) SetLink(val Word) os.Error { panic("No link register") }
+
+func (r *_386Regs) SP() Word { return Word(r.Esp) }
+
+func (r *_386Regs) SetSP(val Word) os.Error {
+       r.Esp = int32(val)
+       return r.setter(&r.PtraceRegs)
+}
+
+func (r *_386Regs) Names() []string { return names }
+
+func (r *_386Regs) Get(i int) Word {
+       switch i {
+       case 0:
+               return Word(uint32(r.Eax))
+       case 1:
+               return Word(uint32(r.Ebx))
+       case 2:
+               return Word(uint32(r.Ecx))
+       case 3:
+               return Word(uint32(r.Edx))
+       case 4:
+               return Word(uint32(r.Esi))
+       case 5:
+               return Word(uint32(r.Edi))
+       case 6:
+               return Word(uint32(r.Ebp))
+       case 7:
+               return Word(uint32(r.Esp))
+       case 8:
+               return Word(uint32(r.Eip))
+       case 9:
+               return Word(uint32(r.Eflags))
+       case 10:
+               return Word(r.Xcs)
+       case 11:
+               return Word(r.Xss)
+       case 12:
+               return Word(r.Xds)
+       case 13:
+               return Word(r.Xes)
+       case 14:
+               return Word(r.Xfs)
+       case 15:
+               return Word(r.Xgs)
+       }
+       panic("invalid register index " + strconv.Itoa(i))
+}
+
+func (r *_386Regs) Set(i int, val Word) os.Error {
+       switch i {
+       case 0:
+               r.Eax = int32(val)
+       case 1:
+               r.Ebx = int32(val)
+       case 2:
+               r.Ecx = int32(val)
+       case 3:
+               r.Edx = int32(val)
+       case 4:
+               r.Esi = int32(val)
+       case 5:
+               r.Edi = int32(val)
+       case 6:
+               r.Ebp = int32(val)
+       case 7:
+               r.Esp = int32(val)
+       case 8:
+               r.Eip = int32(val)
+       case 9:
+               r.Eflags = int32(val)
+       case 10:
+               r.Xcs = int32(val)
+       case 11:
+               r.Xss = int32(val)
+       case 12:
+               r.Xds = int32(val)
+       case 13:
+               r.Xes = int32(val)
+       case 14:
+               r.Xfs = int32(val)
+       case 15:
+               r.Xgs = int32(val)
+       default:
+               panic("invalid register index " + strconv.Itoa(i))
+       }
+       return r.setter(&r.PtraceRegs)
+}
+
+func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs {
+       res := _386Regs{}
+       res.PtraceRegs = *regs
+       res.setter = setter
+       return &res
+}
diff --git a/libgo/go/debug/proc/regs_linux_amd64.go b/libgo/go/debug/proc/regs_linux_amd64.go
new file mode 100644 (file)
index 0000000..381be29
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
+
+import (
+       "os"
+       "strconv"
+       "syscall"
+)
+
+type amd64Regs struct {
+       syscall.PtraceRegs
+       setter func(*syscall.PtraceRegs) os.Error
+}
+
+var names = [...]string{
+       "rax",
+       "rbx",
+       "rcx",
+       "rdx",
+       "rsi",
+       "rdi",
+       "rbp",
+       "rsp",
+       "r8",
+       "r9",
+       "r10",
+       "r11",
+       "r12",
+       "r13",
+       "r14",
+       "r15",
+       "rip",
+       "eflags",
+       "cs",
+       "ss",
+       "ds",
+       "es",
+       "fs",
+       "gs",
+
+       // PtraceRegs contains these registers, but I don't think
+       // they're actually meaningful.
+       //"orig_rax",
+       //"fs_base",
+       //"gs_base",
+}
+
+func (r *amd64Regs) PC() Word { return Word(r.Rip) }
+
+func (r *amd64Regs) SetPC(val Word) os.Error {
+       r.Rip = uint64(val)
+       return r.setter(&r.PtraceRegs)
+}
+
+func (r *amd64Regs) Link() Word {
+       // TODO(austin)
+       panic("No link register")
+}
+
+func (r *amd64Regs) SetLink(val Word) os.Error {
+       panic("No link register")
+}
+
+func (r *amd64Regs) SP() Word { return Word(r.Rsp) }
+
+func (r *amd64Regs) SetSP(val Word) os.Error {
+       r.Rsp = uint64(val)
+       return r.setter(&r.PtraceRegs)
+}
+
+func (r *amd64Regs) Names() []string { return names[0:] }
+
+func (r *amd64Regs) Get(i int) Word {
+       switch i {
+       case 0:
+               return Word(r.Rax)
+       case 1:
+               return Word(r.Rbx)
+       case 2:
+               return Word(r.Rcx)
+       case 3:
+               return Word(r.Rdx)
+       case 4:
+               return Word(r.Rsi)
+       case 5:
+               return Word(r.Rdi)
+       case 6:
+               return Word(r.Rbp)
+       case 7:
+               return Word(r.Rsp)
+       case 8:
+               return Word(r.R8)
+       case 9:
+               return Word(r.R9)
+       case 10:
+               return Word(r.R10)
+       case 11:
+               return Word(r.R11)
+       case 12:
+               return Word(r.R12)
+       case 13:
+               return Word(r.R13)
+       case 14:
+               return Word(r.R14)
+       case 15:
+               return Word(r.R15)
+       case 16:
+               return Word(r.Rip)
+       case 17:
+               return Word(r.Eflags)
+       case 18:
+               return Word(r.Cs)
+       case 19:
+               return Word(r.Ss)
+       case 20:
+               return Word(r.Ds)
+       case 21:
+               return Word(r.Es)
+       case 22:
+               return Word(r.Fs)
+       case 23:
+               return Word(r.Gs)
+       }
+       panic("invalid register index " + strconv.Itoa(i))
+}
+
+func (r *amd64Regs) Set(i int, val Word) os.Error {
+       switch i {
+       case 0:
+               r.Rax = uint64(val)
+       case 1:
+               r.Rbx = uint64(val)
+       case 2:
+               r.Rcx = uint64(val)
+       case 3:
+               r.Rdx = uint64(val)
+       case 4:
+               r.Rsi = uint64(val)
+       case 5:
+               r.Rdi = uint64(val)
+       case 6:
+               r.Rbp = uint64(val)
+       case 7:
+               r.Rsp = uint64(val)
+       case 8:
+               r.R8 = uint64(val)
+       case 9:
+               r.R9 = uint64(val)
+       case 10:
+               r.R10 = uint64(val)
+       case 11:
+               r.R11 = uint64(val)
+       case 12:
+               r.R12 = uint64(val)
+       case 13:
+               r.R13 = uint64(val)
+       case 14:
+               r.R14 = uint64(val)
+       case 15:
+               r.R15 = uint64(val)
+       case 16:
+               r.Rip = uint64(val)
+       case 17:
+               r.Eflags = uint64(val)
+       case 18:
+               r.Cs = uint64(val)
+       case 19:
+               r.Ss = uint64(val)
+       case 20:
+               r.Ds = uint64(val)
+       case 21:
+               r.Es = uint64(val)
+       case 22:
+               r.Fs = uint64(val)
+       case 23:
+               r.Gs = uint64(val)
+       default:
+               panic("invalid register index " + strconv.Itoa(i))
+       }
+       return r.setter(&r.PtraceRegs)
+}
+
+func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs {
+       res := amd64Regs{}
+       res.PtraceRegs = *regs
+       res.setter = setter
+       return &res
+}
diff --git a/libgo/go/debug/proc/regs_linux_arm.go b/libgo/go/debug/proc/regs_linux_arm.go
new file mode 100644 (file)
index 0000000..ec78cbc
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
+
+import (
+       "os"
+       "syscall"
+)
+
+// TODO(kaib): add support
+
+type armRegs struct{}
+
+func (r *armRegs) PC() Word { return Word(0) }
+
+func (r *armRegs) SetPC(val Word) os.Error { return nil }
+
+func (r *armRegs) Link() Word { return Word(0) }
+
+func (r *armRegs) SetLink(val Word) os.Error { return nil }
+
+func (r *armRegs) SP() Word { return Word(0) }
+
+func (r *armRegs) SetSP(val Word) os.Error { return nil }
+
+func (r *armRegs) Names() []string { return nil }
+
+func (r *armRegs) Get(i int) Word { return Word(0) }
+
+func (r *armRegs) Set(i int, val Word) os.Error {
+       return nil
+}
+
+func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs {
+       res := armRegs{}
+       return &res
+}
diff --git a/libgo/go/debug/proc/regs_nacl_386.go b/libgo/go/debug/proc/regs_nacl_386.go
new file mode 100644 (file)
index 0000000..60c9ac7
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
diff --git a/libgo/go/debug/proc/regs_windows_386.go b/libgo/go/debug/proc/regs_windows_386.go
new file mode 100644 (file)
index 0000000..60c9ac7
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
diff --git a/libgo/go/debug/proc/regs_windows_amd64.go b/libgo/go/debug/proc/regs_windows_amd64.go
new file mode 100644 (file)
index 0000000..60c9ac7
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proc
diff --git a/libgo/go/ebnf/ebnf.go b/libgo/go/ebnf/ebnf.go
new file mode 100644 (file)
index 0000000..8333f58
--- /dev/null
@@ -0,0 +1,243 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A library for EBNF grammars. The input is text ([]byte) satisfying
+// the following grammar (represented itself in EBNF):
+//
+//     Production  = name "=" Expression "." .
+//     Expression  = Alternative { "|" Alternative } .
+//     Alternative = Term { Term } .
+//     Term        = name | token [ "..." token ] | Group | Option | Repetition .
+//     Group       = "(" Expression ")" .
+//     Option      = "[" Expression "]" .
+//     Repetition  = "{" Expression "}" .
+//
+// A name is a Go identifier, a token is a Go string, and comments
+// and white space follow the same rules as for the Go language.
+// Production names starting with an uppercase Unicode letter denote
+// non-terminal productions (i.e., productions which allow white-space
+// and comments between tokens); all other production names denote
+// lexical productions.
+//
+package ebnf
+
+import (
+       "go/scanner"
+       "go/token"
+       "os"
+       "unicode"
+       "utf8"
+)
+
+
+// ----------------------------------------------------------------------------
+// Internal representation
+
+type (
+       // An Expression node represents a production expression.
+       Expression interface {
+               // Pos is the position of the first character of the syntactic construct
+               Pos() token.Position
+       }
+
+       // An Alternative node represents a non-empty list of alternative expressions.
+       Alternative []Expression // x | y | z
+
+       // A Sequence node represents a non-empty list of sequential expressions.
+       Sequence []Expression // x y z
+
+       // A Name node represents a production name.
+       Name struct {
+               token.Position
+               String string
+       }
+
+       // A Token node represents a literal.
+       Token struct {
+               token.Position
+               String string
+       }
+
+       // A List node represents a range of characters.
+       Range struct {
+               Begin, End *Token // begin ... end
+       }
+
+       // A Group node represents a grouped expression.
+       Group struct {
+               token.Position
+               Body Expression // (body)
+       }
+
+       // An Option node represents an optional expression.
+       Option struct {
+               token.Position
+               Body Expression // [body]
+       }
+
+       // A Repetition node represents a repeated expression.
+       Repetition struct {
+               token.Position
+               Body Expression // {body}
+       }
+
+       // A Production node represents an EBNF production.
+       Production struct {
+               Name *Name
+               Expr Expression
+       }
+
+       // A Grammar is a set of EBNF productions. The map
+       // is indexed by production name.
+       //
+       Grammar map[string]*Production
+)
+
+
+func (x Alternative) Pos() token.Position {
+       return x[0].Pos() // the parser always generates non-empty Alternative
+}
+
+
+func (x Sequence) Pos() token.Position {
+       return x[0].Pos() // the parser always generates non-empty Sequences
+}
+
+
+func (x Range) Pos() token.Position { return x.Begin.Pos() }
+
+
+func (p *Production) Pos() token.Position { return p.Name.Pos() }
+
+
+// ----------------------------------------------------------------------------
+// Grammar verification
+
+func isLexical(name string) bool {
+       ch, _ := utf8.DecodeRuneInString(name)
+       return !unicode.IsUpper(ch)
+}
+
+
+type verifier struct {
+       scanner.ErrorVector
+       worklist []*Production
+       reached  Grammar // set of productions reached from (and including) the root production
+       grammar  Grammar
+}
+
+
+func (v *verifier) push(prod *Production) {
+       name := prod.Name.String
+       if _, found := v.reached[name]; !found {
+               v.worklist = append(v.worklist, prod)
+               v.reached[name] = prod
+       }
+}
+
+
+func (v *verifier) verifyChar(x *Token) int {
+       s := x.String
+       if utf8.RuneCountInString(s) != 1 {
+               v.Error(x.Pos(), "single char expected, found "+s)
+               return 0
+       }
+       ch, _ := utf8.DecodeRuneInString(s)
+       return ch
+}
+
+
+func (v *verifier) verifyExpr(expr Expression, lexical bool) {
+       switch x := expr.(type) {
+       case nil:
+               // empty expression
+       case Alternative:
+               for _, e := range x {
+                       v.verifyExpr(e, lexical)
+               }
+       case Sequence:
+               for _, e := range x {
+                       v.verifyExpr(e, lexical)
+               }
+       case *Name:
+               // a production with this name must exist;
+               // add it to the worklist if not yet processed
+               if prod, found := v.grammar[x.String]; found {
+                       v.push(prod)
+               } else {
+                       v.Error(x.Pos(), "missing production "+x.String)
+               }
+               // within a lexical production references
+               // to non-lexical productions are invalid
+               if lexical && !isLexical(x.String) {
+                       v.Error(x.Pos(), "reference to non-lexical production "+x.String)
+               }
+       case *Token:
+               // nothing to do for now
+       case *Range:
+               i := v.verifyChar(x.Begin)
+               j := v.verifyChar(x.End)
+               if i >= j {
+                       v.Error(x.Pos(), "decreasing character range")
+               }
+       case *Group:
+               v.verifyExpr(x.Body, lexical)
+       case *Option:
+               v.verifyExpr(x.Body, lexical)
+       case *Repetition:
+               v.verifyExpr(x.Body, lexical)
+       default:
+               panic("unreachable")
+       }
+}
+
+
+func (v *verifier) verify(grammar Grammar, start string) {
+       // find root production
+       root, found := grammar[start]
+       if !found {
+               var noPos token.Position
+               v.Error(noPos, "no start production "+start)
+               return
+       }
+
+       // initialize verifier
+       v.ErrorVector.Reset()
+       v.worklist = v.worklist[0:0]
+       v.reached = make(Grammar)
+       v.grammar = grammar
+
+       // work through the worklist
+       v.push(root)
+       for {
+               n := len(v.worklist) - 1
+               if n < 0 {
+                       break
+               }
+               prod := v.worklist[n]
+               v.worklist = v.worklist[0:n]
+               v.verifyExpr(prod.Expr, isLexical(prod.Name.String))
+       }
+
+       // check if all productions were reached
+       if len(v.reached) < len(v.grammar) {
+               for name, prod := range v.grammar {
+                       if _, found := v.reached[name]; !found {
+                               v.Error(prod.Pos(), name+" is unreachable")
+                       }
+               }
+       }
+}
+
+
+// Verify checks that:
+//     - all productions used are defined
+//     - all productions defined are used when beginning at start
+//     - lexical productions refer only to other lexical productions
+//
+func Verify(grammar Grammar, start string) os.Error {
+       var v verifier
+       v.verify(grammar, start)
+       return v.GetError(scanner.Sorted)
+}
diff --git a/libgo/go/ebnf/ebnf_test.go b/libgo/go/ebnf/ebnf_test.go
new file mode 100644 (file)
index 0000000..a88d19b
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ebnf
+
+import (
+       "io/ioutil"
+       "testing"
+)
+
+
+var grammars = []string{
+       `Program = .
+       `,
+
+       `Program = foo .
+       foo = "foo" .
+       `,
+
+       `Program = "a" | "b" "c" .
+       `,
+
+       `Program = "a" ... "z" .
+       `,
+
+       `Program = Song .
+        Song = { Note } .
+        Note = Do | (Re | Mi | Fa | So | La) | Ti .
+        Do = "c" .
+        Re = "d" .
+        Mi = "e" .
+        Fa = "f" .
+        So = "g" .
+        La = "a" .
+        Ti = ti .
+        ti = "b" .
+       `,
+}
+
+
+func check(t *testing.T, filename string, src []byte) {
+       grammar, err := Parse(filename, src)
+       if err != nil {
+               t.Errorf("Parse(%s) failed: %v", src, err)
+       }
+       if err = Verify(grammar, "Program"); err != nil {
+               t.Errorf("Verify(%s) failed: %v", src, err)
+       }
+}
+
+
+func TestGrammars(t *testing.T) {
+       for _, src := range grammars {
+               check(t, "", []byte(src))
+       }
+}
+
+
+var files = []string{
+// TODO(gri) add some test files
+}
+
+
+func TestFiles(t *testing.T) {
+       for _, filename := range files {
+               src, err := ioutil.ReadFile(filename)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               check(t, filename, src)
+       }
+}
diff --git a/libgo/go/ebnf/parser.go b/libgo/go/ebnf/parser.go
new file mode 100644 (file)
index 0000000..32edbac
--- /dev/null
@@ -0,0 +1,200 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ebnf
+
+import (
+       "go/scanner"
+       "go/token"
+       "os"
+       "strconv"
+)
+
+
+type parser struct {
+       scanner.ErrorVector
+       scanner scanner.Scanner
+       pos     token.Position // token position
+       tok     token.Token    // one token look-ahead
+       lit     []byte         // token literal
+}
+
+
+func (p *parser) next() {
+       p.pos, p.tok, p.lit = p.scanner.Scan()
+       if p.tok.IsKeyword() {
+               // TODO Should keyword mapping always happen outside scanner?
+               //      Or should there be a flag to scanner to enable keyword mapping?
+               p.tok = token.IDENT
+       }
+}
+
+
+func (p *parser) errorExpected(pos token.Position, msg string) {
+       msg = "expected " + msg
+       if pos.Offset == p.pos.Offset {
+               // the error happened at the current position;
+               // make the error message more specific
+               msg += ", found '" + p.tok.String() + "'"
+               if p.tok.IsLiteral() {
+                       msg += " " + string(p.lit)
+               }
+       }
+       p.Error(pos, msg)
+}
+
+
+func (p *parser) expect(tok token.Token) token.Position {
+       pos := p.pos
+       if p.tok != tok {
+               p.errorExpected(pos, "'"+tok.String()+"'")
+       }
+       p.next() // make progress in any case
+       return pos
+}
+
+
+func (p *parser) parseIdentifier() *Name {
+       pos := p.pos
+       name := string(p.lit)
+       p.expect(token.IDENT)
+       return &Name{pos, name}
+}
+
+
+func (p *parser) parseToken() *Token {
+       pos := p.pos
+       value := ""
+       if p.tok == token.STRING {
+               value, _ = strconv.Unquote(string(p.lit))
+               // Unquote may fail with an error, but only if the scanner found
+               // an illegal string in the first place. In this case the error
+               // has already been reported.
+               p.next()
+       } else {
+               p.expect(token.STRING)
+       }
+       return &Token{pos, value}
+}
+
+
+func (p *parser) parseTerm() (x Expression) {
+       pos := p.pos
+
+       switch p.tok {
+       case token.IDENT:
+               x = p.parseIdentifier()
+
+       case token.STRING:
+               tok := p.parseToken()
+               x = tok
+               if p.tok == token.ELLIPSIS {
+                       p.next()
+                       x = &Range{tok, p.parseToken()}
+               }
+
+       case token.LPAREN:
+               p.next()
+               x = &Group{pos, p.parseExpression()}
+               p.expect(token.RPAREN)
+
+       case token.LBRACK:
+               p.next()
+               x = &Option{pos, p.parseExpression()}
+               p.expect(token.RBRACK)
+
+       case token.LBRACE:
+               p.next()
+               x = &Repetition{pos, p.parseExpression()}
+               p.expect(token.RBRACE)
+       }
+
+       return x
+}
+
+
+func (p *parser) parseSequence() Expression {
+       var list Sequence
+
+       for x := p.parseTerm(); x != nil; x = p.parseTerm() {
+               list = append(list, x)
+       }
+
+       // no need for a sequence if list.Len() < 2
+       switch len(list) {
+       case 0:
+               return nil
+       case 1:
+               return list[0]
+       }
+
+       return list
+}
+
+
+func (p *parser) parseExpression() Expression {
+       var list Alternative
+
+       for {
+               if x := p.parseSequence(); x != nil {
+                       list = append(list, x)
+               }
+               if p.tok != token.OR {
+                       break
+               }
+               p.next()
+       }
+
+       // no need for an Alternative node if list.Len() < 2
+       switch len(list) {
+       case 0:
+               return nil
+       case 1:
+               return list[0]
+       }
+
+       return list
+}
+
+
+func (p *parser) parseProduction() *Production {
+       name := p.parseIdentifier()
+       p.expect(token.ASSIGN)
+       expr := p.parseExpression()
+       p.expect(token.PERIOD)
+       return &Production{name, expr}
+}
+
+
+func (p *parser) parse(filename string, src []byte) Grammar {
+       // initialize parser
+       p.ErrorVector.Reset()
+       p.scanner.Init(filename, src, p, 0)
+       p.next() // initializes pos, tok, lit
+
+       grammar := make(Grammar)
+       for p.tok != token.EOF {
+               prod := p.parseProduction()
+               name := prod.Name.String
+               if _, found := grammar[name]; !found {
+                       grammar[name] = prod
+               } else {
+                       p.Error(prod.Pos(), name+" declared already")
+               }
+       }
+
+       return grammar
+}
+
+
+// Parse parses a set of EBNF productions from source src.
+// It returns a set of productions. Errors are reported
+// for incorrect syntax and if a production is declared
+// more than once.
+//
+func Parse(filename string, src []byte) (Grammar, os.Error) {
+       var p parser
+       grammar := p.parse(filename, src)
+       return grammar, p.GetError(scanner.Sorted)
+}
diff --git a/libgo/go/encoding/ascii85/ascii85.go b/libgo/go/encoding/ascii85/ascii85.go
new file mode 100644 (file)
index 0000000..ead0c24
--- /dev/null
@@ -0,0 +1,300 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ascii85 implements the ascii85 data encoding
+// as used in the btoa tool and Adobe's PostScript and PDF document formats.
+package ascii85
+
+import (
+       "io"
+       "os"
+       "strconv"
+)
+
+/*
+ * Encoder
+ */
+
+// Encode encodes src into at most MaxEncodedLen(len(src))
+// bytes of dst, returning the actual number of bytes written.
+//
+// The encoding handles 4-byte chunks, using a special encoding
+// for the last fragment, so Encode is not appropriate for use on
+// individual blocks of a large data stream.  Use NewEncoder() instead.
+//
+// Often, ascii85-encoded data is wrapped in <~ and ~> symbols.
+// Encode does not add these.
+func Encode(dst, src []byte) int {
+       if len(src) == 0 {
+               return 0
+       }
+
+       n := 0
+       for len(src) > 0 {
+               dst[0] = 0
+               dst[1] = 0
+               dst[2] = 0
+               dst[3] = 0
+               dst[4] = 0
+
+               // Unpack 4 bytes into uint32 to repack into base 85 5-byte.
+               var v uint32
+               switch len(src) {
+               default:
+                       v |= uint32(src[3])
+                       fallthrough
+               case 3:
+                       v |= uint32(src[2]) << 8
+                       fallthrough
+               case 2:
+                       v |= uint32(src[1]) << 16
+                       fallthrough
+               case 1:
+                       v |= uint32(src[0]) << 24
+               }
+
+               // Special case: zero (!!!!!) shortens to z.
+               if v == 0 && len(src) >= 4 {
+                       dst[0] = 'z'
+                       dst = dst[1:]
+                       n++
+                       continue
+               }
+
+               // Otherwise, 5 base 85 digits starting at !.
+               for i := 4; i >= 0; i-- {
+                       dst[i] = '!' + byte(v%85)
+                       v /= 85
+               }
+
+               // If src was short, discard the low destination bytes.
+               m := 5
+               if len(src) < 4 {
+                       m -= 4 - len(src)
+                       src = nil
+               } else {
+                       src = src[4:]
+               }
+               dst = dst[m:]
+               n += m
+       }
+       return n
+}
+
+// MaxEncodedLen returns the maximum length of an encoding of n source bytes.
+func MaxEncodedLen(n int) int { return (n + 3) / 4 * 5 }
+
+// NewEncoder returns a new ascii85 stream encoder.  Data written to
+// the returned writer will be encoded and then written to w.
+// Ascii85 encodings operate in 32-bit blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// trailing partial block.
+func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} }
+
+type encoder struct {
+       err  os.Error
+       w    io.Writer
+       buf  [4]byte    // buffered data waiting to be encoded
+       nbuf int        // number of bytes in buf
+       out  [1024]byte // output buffer
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+       if e.err != nil {
+               return 0, e.err
+       }
+
+       // Leading fringe.
+       if e.nbuf > 0 {
+               var i int
+               for i = 0; i < len(p) && e.nbuf < 4; i++ {
+                       e.buf[e.nbuf] = p[i]
+                       e.nbuf++
+               }
+               n += i
+               p = p[i:]
+               if e.nbuf < 4 {
+                       return
+               }
+               nout := Encode(e.out[0:], e.buf[0:])
+               if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+                       return n, e.err
+               }
+               e.nbuf = 0
+       }
+
+       // Large interior chunks.
+       for len(p) >= 4 {
+               nn := len(e.out) / 5 * 4
+               if nn > len(p) {
+                       nn = len(p)
+               }
+               nn -= nn % 4
+               if nn > 0 {
+                       nout := Encode(e.out[0:], p[0:nn])
+                       if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+                               return n, e.err
+                       }
+               }
+               n += nn
+               p = p[nn:]
+       }
+
+       // Trailing fringe.
+       for i := 0; i < len(p); i++ {
+               e.buf[i] = p[i]
+       }
+       e.nbuf = len(p)
+       n += len(p)
+       return
+}
+
+// Close flushes any pending output from the encoder.
+// It is an error to call Write after calling Close.
+func (e *encoder) Close() os.Error {
+       // If there's anything left in the buffer, flush it out
+       if e.err == nil && e.nbuf > 0 {
+               nout := Encode(e.out[0:], e.buf[0:e.nbuf])
+               e.nbuf = 0
+               _, e.err = e.w.Write(e.out[0:nout])
+       }
+       return e.err
+}
+
+/*
+ * Decoder
+ */
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+       return "illegal ascii85 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+// Decode decodes src into dst, returning both the number
+// of bytes written to dst and the number consumed from src.
+// If src contains invalid ascii85 data, Decode will return the
+// number of bytes successfully written and a CorruptInputError.
+// Decode ignores space and control characters in src.
+// Often, ascii85-encoded data is wrapped in <~ and ~> symbols.
+// Decode expects these to have been stripped by the caller.
+//
+// If flush is true, Decode assumes that src represents the
+// end of the input stream and processes it completely rather
+// than wait for the completion of another 32-bit block.
+//
+// NewDecoder wraps an io.Reader interface around Decode.
+//
+func Decode(dst, src []byte, flush bool) (ndst, nsrc int, err os.Error) {
+       var v uint32
+       var nb int
+       for i, b := range src {
+               if len(dst)-ndst < 4 {
+                       return
+               }
+               switch {
+               case b <= ' ':
+                       continue
+               case b == 'z' && nb == 0:
+                       nb = 5
+                       v = 0
+               case '!' <= b && b <= 'u':
+                       v = v*85 + uint32(b-'!')
+                       nb++
+               default:
+                       return 0, 0, CorruptInputError(i)
+               }
+               if nb == 5 {
+                       nsrc = i + 1
+                       dst[ndst] = byte(v >> 24)
+                       dst[ndst+1] = byte(v >> 16)
+                       dst[ndst+2] = byte(v >> 8)
+                       dst[ndst+3] = byte(v)
+                       ndst += 4
+                       nb = 0
+                       v = 0
+               }
+       }
+       if flush {
+               nsrc = len(src)
+               if nb > 0 {
+                       // The number of output bytes in the last fragment
+                       // is the number of leftover input bytes - 1:
+                       // the extra byte provides enough bits to cover
+                       // the inefficiency of the encoding for the block.
+                       if nb == 1 {
+                               return 0, 0, CorruptInputError(len(src))
+                       }
+                       for i := nb; i < 5; i++ {
+                               // The short encoding truncated the output value.
+                               // We have to assume the worst case values (digit 84)
+                               // in order to ensure that the top bits are correct.
+                               v = v*85 + 84
+                       }
+                       for i := 0; i < nb-1; i++ {
+                               dst[ndst] = byte(v >> 24)
+                               v <<= 8
+                               ndst++
+                       }
+               }
+       }
+       return
+}
+
+// NewDecoder constructs a new ascii85 stream decoder.
+func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} }
+
+type decoder struct {
+       err     os.Error
+       readErr os.Error
+       r       io.Reader
+       end     bool       // saw end of message
+       buf     [1024]byte // leftover input
+       nbuf    int
+       out     []byte // leftover decoded output
+       outbuf  [1024]byte
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+       if len(p) == 0 {
+               return 0, nil
+       }
+       if d.err != nil {
+               return 0, d.err
+       }
+
+       for {
+               // Copy leftover output from last decode.
+               if len(d.out) > 0 {
+                       n = copy(p, d.out)
+                       d.out = d.out[n:]
+                       return
+               }
+
+               // Decode leftover input from last read.
+               var nn, nsrc, ndst int
+               if d.nbuf > 0 {
+                       ndst, nsrc, d.err = Decode(d.outbuf[0:], d.buf[0:d.nbuf], d.readErr != nil)
+                       if ndst > 0 {
+                               d.out = d.outbuf[0:ndst]
+                               d.nbuf = copy(d.buf[0:], d.buf[nsrc:d.nbuf])
+                               continue // copy out and return
+                       }
+               }
+
+               // Out of input, out of decoded output.  Check errors.
+               if d.err != nil {
+                       return 0, d.err
+               }
+               if d.readErr != nil {
+                       d.err = d.readErr
+                       return 0, d.err
+               }
+
+               // Read more data.
+               nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
+               d.nbuf += nn
+       }
+       panic("unreachable")
+}
diff --git a/libgo/go/encoding/ascii85/ascii85_test.go b/libgo/go/encoding/ascii85/ascii85_test.go
new file mode 100644 (file)
index 0000000..fdfeb88
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ascii85
+
+import (
+       "bytes"
+       "io/ioutil"
+       "os"
+       "testing"
+)
+
+type testpair struct {
+       decoded, encoded string
+}
+
+var pairs = []testpair{
+       // Wikipedia example
+       {
+               "Man is distinguished, not only by his reason, but by this singular passion from " +
+                       "other animals, which is a lust of the mind, that by a perseverance of delight in " +
+                       "the continued and indefatigable generation of knowledge, exceeds the short " +
+                       "vehemence of any carnal pleasure.",
+               "9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,\n" +
+                       "O<DJ+*.@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF\"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKY\n" +
+                       "i(DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIa\n" +
+                       "l(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G\n" +
+                       ">uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c\n",
+       },
+}
+
+var bigtest = pairs[len(pairs)-1]
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+       if args[len(args)-2] != args[len(args)-1] {
+               t.Errorf(msg, args...)
+               return false
+       }
+       return true
+}
+
+func strip85(s string) string {
+       t := make([]byte, len(s))
+       w := 0
+       for r := 0; r < len(s); r++ {
+               c := s[r]
+               if c > ' ' {
+                       t[w] = c
+                       w++
+               }
+       }
+       return string(t[0:w])
+}
+
+func TestEncode(t *testing.T) {
+       for _, p := range pairs {
+               buf := make([]byte, MaxEncodedLen(len(p.decoded)))
+               n := Encode(buf, []byte(p.decoded))
+               buf = buf[0:n]
+               testEqual(t, "Encode(%q) = %q, want %q", p.decoded, strip85(string(buf)), strip85(p.encoded))
+       }
+}
+
+func TestEncoder(t *testing.T) {
+       for _, p := range pairs {
+               bb := &bytes.Buffer{}
+               encoder := NewEncoder(bb)
+               encoder.Write([]byte(p.decoded))
+               encoder.Close()
+               testEqual(t, "Encode(%q) = %q, want %q", p.decoded, strip85(bb.String()), strip85(p.encoded))
+       }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+       input := []byte(bigtest.decoded)
+       for bs := 1; bs <= 12; bs++ {
+               bb := &bytes.Buffer{}
+               encoder := NewEncoder(bb)
+               for pos := 0; pos < len(input); pos += bs {
+                       end := pos + bs
+                       if end > len(input) {
+                               end = len(input)
+                       }
+                       n, err := encoder.Write(input[pos:end])
+                       testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+                       testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+               }
+               err := encoder.Close()
+               testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+               testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, strip85(bb.String()), strip85(bigtest.encoded))
+       }
+}
+
+func TestDecode(t *testing.T) {
+       for _, p := range pairs {
+               dbuf := make([]byte, 4*len(p.encoded))
+               ndst, nsrc, err := Decode(dbuf, []byte(p.encoded), true)
+               testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+               testEqual(t, "Decode(%q) = nsrc %v, want %v", p.encoded, nsrc, len(p.encoded))
+               testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded))
+               testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded)
+       }
+}
+
+func TestDecoder(t *testing.T) {
+       for _, p := range pairs {
+               decoder := NewDecoder(bytes.NewBufferString(p.encoded))
+               dbuf, err := ioutil.ReadAll(decoder)
+               if err != nil {
+                       t.Fatal("Read failed", err)
+               }
+               testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded))
+               testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded)
+               if err != nil {
+                       testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+               }
+       }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+       for bs := 1; bs <= 12; bs++ {
+               decoder := NewDecoder(bytes.NewBufferString(bigtest.encoded))
+               buf := make([]byte, len(bigtest.decoded)+12)
+               var total int
+               for total = 0; total < len(bigtest.decoded); {
+                       n, err := decoder.Read(buf[total : total+bs])
+                       testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+                       total += n
+               }
+               testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
+       }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+       type corrupt struct {
+               e string
+               p int
+       }
+       examples := []corrupt{
+               {"v", 0},
+               {"!z!!!!!!!!!", 1},
+       }
+
+       for _, e := range examples {
+               dbuf := make([]byte, 4*len(e.e))
+               _, _, err := Decode(dbuf, []byte(e.e), true)
+               switch err := err.(type) {
+               case CorruptInputError:
+                       testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+               default:
+                       t.Error("Decoder failed to detect corruption in", e)
+               }
+       }
+}
+
+func TestBig(t *testing.T) {
+       n := 3*1000 + 1
+       raw := make([]byte, n)
+       const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+       for i := 0; i < n; i++ {
+               raw[i] = alpha[i%len(alpha)]
+       }
+       encoded := new(bytes.Buffer)
+       w := NewEncoder(encoded)
+       nn, err := w.Write(raw)
+       if nn != n || err != nil {
+               t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+       }
+       err = w.Close()
+       if err != nil {
+               t.Fatalf("Encoder.Close() = %v want nil", err)
+       }
+       decoded, err := ioutil.ReadAll(NewDecoder(encoded))
+       if err != nil {
+               t.Fatalf("io.ReadAll(NewDecoder(...)): %v", err)
+       }
+
+       if !bytes.Equal(raw, decoded) {
+               var i int
+               for i = 0; i < len(decoded) && i < len(raw); i++ {
+                       if decoded[i] != raw[i] {
+                               break
+                       }
+               }
+               t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+       }
+}
diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go
new file mode 100644 (file)
index 0000000..4961297
--- /dev/null
@@ -0,0 +1,329 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package base64 implements base64 encoding as specified by RFC 4648.
+package base64
+
+import (
+       "io"
+       "os"
+       "strconv"
+)
+
+/*
+ * Encodings
+ */
+
+// An Encoding is a radix 64 encoding/decoding scheme, defined by a
+// 64-character alphabet.  The most common encoding is the "base64"
+// encoding defined in RFC 4648 and used in MIME (RFC 2045) and PEM
+// (RFC 1421).  RFC 4648 also defines an alternate encoding, which is
+// the standard encoding with - and _ substituted for + and /.
+type Encoding struct {
+       encode    string
+       decodeMap [256]byte
+}
+
+const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
+
+// NewEncoding returns a new Encoding defined by the given alphabet,
+// which must be a 64-byte string.
+func NewEncoding(encoder string) *Encoding {
+       e := new(Encoding)
+       e.encode = encoder
+       for i := 0; i < len(e.decodeMap); i++ {
+               e.decodeMap[i] = 0xFF
+       }
+       for i := 0; i < len(encoder); i++ {
+               e.decodeMap[encoder[i]] = byte(i)
+       }
+       return e
+}
+
+// StdEncoding is the standard base64 encoding, as defined in
+// RFC 4648.
+var StdEncoding = NewEncoding(encodeStd)
+
+// URLEncoding is the alternate base64 encoding defined in RFC 4648.
+// It is typically used in URLs and file names.
+var URLEncoding = NewEncoding(encodeURL)
+
+/*
+ * Encoder
+ */
+
+// Encode encodes src using the encoding enc, writing
+// EncodedLen(len(src)) bytes to dst.
+//
+// The encoding pads the output to a multiple of 4 bytes,
+// so Encode is not appropriate for use on individual blocks
+// of a large data stream.  Use NewEncoder() instead.
+func (enc *Encoding) Encode(dst, src []byte) {
+       if len(src) == 0 {
+               return
+       }
+
+       for len(src) > 0 {
+               dst[0] = 0
+               dst[1] = 0
+               dst[2] = 0
+               dst[3] = 0
+
+               // Unpack 4x 6-bit source blocks into a 4 byte
+               // destination quantum
+               switch len(src) {
+               default:
+                       dst[3] |= src[2] & 0x3F
+                       dst[2] |= src[2] >> 6
+                       fallthrough
+               case 2:
+                       dst[2] |= (src[1] << 2) & 0x3F
+                       dst[1] |= src[1] >> 4
+                       fallthrough
+               case 1:
+                       dst[1] |= (src[0] << 4) & 0x3F
+                       dst[0] |= src[0] >> 2
+               }
+
+               // Encode 6-bit blocks using the base64 alphabet
+               for j := 0; j < 4; j++ {
+                       dst[j] = enc.encode[dst[j]]
+               }
+
+               // Pad the final quantum
+               if len(src) < 3 {
+                       dst[3] = '='
+                       if len(src) < 2 {
+                               dst[2] = '='
+                       }
+                       break
+               }
+
+               src = src[3:]
+               dst = dst[4:]
+       }
+}
+
+type encoder struct {
+       err  os.Error
+       enc  *Encoding
+       w    io.Writer
+       buf  [3]byte    // buffered data waiting to be encoded
+       nbuf int        // number of bytes in buf
+       out  [1024]byte // output buffer
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+       if e.err != nil {
+               return 0, e.err
+       }
+
+       // Leading fringe.
+       if e.nbuf > 0 {
+               var i int
+               for i = 0; i < len(p) && e.nbuf < 3; i++ {
+                       e.buf[e.nbuf] = p[i]
+                       e.nbuf++
+               }
+               n += i
+               p = p[i:]
+               if e.nbuf < 3 {
+                       return
+               }
+               e.enc.Encode(e.out[0:], e.buf[0:])
+               if _, e.err = e.w.Write(e.out[0:4]); e.err != nil {
+                       return n, e.err
+               }
+               e.nbuf = 0
+       }
+
+       // Large interior chunks.
+       for len(p) >= 3 {
+               nn := len(e.out) / 4 * 3
+               if nn > len(p) {
+                       nn = len(p)
+               }
+               nn -= nn % 3
+               if nn > 0 {
+                       e.enc.Encode(e.out[0:], p[0:nn])
+                       if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
+                               return n, e.err
+                       }
+               }
+               n += nn
+               p = p[nn:]
+       }
+
+       // Trailing fringe.
+       for i := 0; i < len(p); i++ {
+               e.buf[i] = p[i]
+       }
+       e.nbuf = len(p)
+       n += len(p)
+       return
+}
+
+// Close flushes any pending output from the encoder.
+// It is an error to call Write after calling Close.
+func (e *encoder) Close() os.Error {
+       // If there's anything left in the buffer, flush it out
+       if e.err == nil && e.nbuf > 0 {
+               e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
+               e.nbuf = 0
+               _, e.err = e.w.Write(e.out[0:4])
+       }
+       return e.err
+}
+
+// NewEncoder returns a new base64 stream encoder.  Data written to
+// the returned writer will be encoded using enc and then written to w.
+// Base64 encodings operate in 4-byte blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// partially written blocks.
+func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
+       return &encoder{enc: enc, w: w}
+}
+
+// EncodedLen returns the length in bytes of the base64 encoding
+// of an input buffer of length n.
+func (enc *Encoding) EncodedLen(n int) int { return (n + 2) / 3 * 4 }
+
+/*
+ * Decoder
+ */
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+       return "illegal base64 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+// decode is like Decode but returns an additional 'end' value, which
+// indicates if end-of-message padding was encountered and thus any
+// additional data is an error.  decode also assumes len(src)%4==0,
+// since it is meant for internal use.
+func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
+       for i := 0; i < len(src)/4 && !end; i++ {
+               // Decode quantum using the base64 alphabet
+               var dbuf [4]byte
+               dlen := 4
+
+       dbufloop:
+               for j := 0; j < 4; j++ {
+                       in := src[i*4+j]
+                       if in == '=' && j >= 2 && i == len(src)/4-1 {
+                               // We've reached the end and there's
+                               // padding
+                               if src[i*4+3] != '=' {
+                                       return n, false, CorruptInputError(i*4 + 2)
+                               }
+                               dlen = j
+                               end = true
+                               break dbufloop
+                       }
+                       dbuf[j] = enc.decodeMap[in]
+                       if dbuf[j] == 0xFF {
+                               return n, false, CorruptInputError(i*4 + j)
+                       }
+               }
+
+               // Pack 4x 6-bit source blocks into 3 byte destination
+               // quantum
+               switch dlen {
+               case 4:
+                       dst[i*3+2] = dbuf[2]<<6 | dbuf[3]
+                       fallthrough
+               case 3:
+                       dst[i*3+1] = dbuf[1]<<4 | dbuf[2]>>2
+                       fallthrough
+               case 2:
+                       dst[i*3+0] = dbuf[0]<<2 | dbuf[1]>>4
+               }
+               n += dlen - 1
+       }
+
+       return n, end, nil
+}
+
+// Decode decodes src using the encoding enc.  It writes at most
+// DecodedLen(len(src)) bytes to dst and returns the number of bytes
+// written.  If src contains invalid base64 data, it will return the
+// number of bytes successfully written and CorruptInputError.
+func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) {
+       if len(src)%4 != 0 {
+               return 0, CorruptInputError(len(src) / 4 * 4)
+       }
+
+       n, _, err = enc.decode(dst, src)
+       return
+}
+
+type decoder struct {
+       err    os.Error
+       enc    *Encoding
+       r      io.Reader
+       end    bool       // saw end of message
+       buf    [1024]byte // leftover input
+       nbuf   int
+       out    []byte // leftover decoded output
+       outbuf [1024 / 4 * 3]byte
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+       if d.err != nil {
+               return 0, d.err
+       }
+
+       // Use leftover decoded output from last read.
+       if len(d.out) > 0 {
+               n = copy(p, d.out)
+               d.out = d.out[n:]
+               return n, nil
+       }
+
+       // Read a chunk.
+       nn := len(p) / 3 * 4
+       if nn < 4 {
+               nn = 4
+       }
+       if nn > len(d.buf) {
+               nn = len(d.buf)
+       }
+       nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 4-d.nbuf)
+       d.nbuf += nn
+       if d.nbuf < 4 {
+               return 0, d.err
+       }
+
+       // Decode chunk into p, or d.out and then p if p is too small.
+       nr := d.nbuf / 4 * 4
+       nw := d.nbuf / 4 * 3
+       if nw > len(p) {
+               nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
+               d.out = d.outbuf[0:nw]
+               n = copy(p, d.out)
+               d.out = d.out[n:]
+       } else {
+               n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
+       }
+       d.nbuf -= nr
+       for i := 0; i < d.nbuf; i++ {
+               d.buf[i] = d.buf[i+nr]
+       }
+
+       if d.err == nil {
+               d.err = err
+       }
+       return n, d.err
+}
+
+// NewDecoder constructs a new base64 stream decoder.
+func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
+       return &decoder{enc: enc, r: r}
+}
+
+// DecodedLen returns the maximum length in bytes of the decoded data
+// corresponding to n bytes of base64-encoded data.
+func (enc *Encoding) DecodedLen(n int) int { return n / 4 * 3 }
diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go
new file mode 100644 (file)
index 0000000..de41e70
--- /dev/null
@@ -0,0 +1,196 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base64
+
+import (
+       "bytes"
+       "io/ioutil"
+       "os"
+       "testing"
+)
+
+type testpair struct {
+       decoded, encoded string
+}
+
+var pairs = []testpair{
+       // RFC 3548 examples
+       {"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+"},
+       {"\x14\xfb\x9c\x03\xd9", "FPucA9k="},
+       {"\x14\xfb\x9c\x03", "FPucAw=="},
+
+       // RFC 4648 examples
+       {"", ""},
+       {"f", "Zg=="},
+       {"fo", "Zm8="},
+       {"foo", "Zm9v"},
+       {"foob", "Zm9vYg=="},
+       {"fooba", "Zm9vYmE="},
+       {"foobar", "Zm9vYmFy"},
+
+       // Wikipedia examples
+       {"sure.", "c3VyZS4="},
+       {"sure", "c3VyZQ=="},
+       {"sur", "c3Vy"},
+       {"su", "c3U="},
+       {"leasure.", "bGVhc3VyZS4="},
+       {"easure.", "ZWFzdXJlLg=="},
+       {"asure.", "YXN1cmUu"},
+       {"sure.", "c3VyZS4="},
+}
+
+var bigtest = testpair{
+       "Twas brillig, and the slithy toves",
+       "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==",
+}
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+       if args[len(args)-2] != args[len(args)-1] {
+               t.Errorf(msg, args...)
+               return false
+       }
+       return true
+}
+
+func TestEncode(t *testing.T) {
+       for _, p := range pairs {
+               buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded)))
+               StdEncoding.Encode(buf, []byte(p.decoded))
+               testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+       }
+}
+
+func TestEncoder(t *testing.T) {
+       for _, p := range pairs {
+               bb := &bytes.Buffer{}
+               encoder := NewEncoder(StdEncoding, bb)
+               encoder.Write([]byte(p.decoded))
+               encoder.Close()
+               testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
+       }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+       input := []byte(bigtest.decoded)
+       for bs := 1; bs <= 12; bs++ {
+               bb := &bytes.Buffer{}
+               encoder := NewEncoder(StdEncoding, bb)
+               for pos := 0; pos < len(input); pos += bs {
+                       end := pos + bs
+                       if end > len(input) {
+                               end = len(input)
+                       }
+                       n, err := encoder.Write(input[pos:end])
+                       testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+                       testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+               }
+               err := encoder.Close()
+               testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+               testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded)
+       }
+}
+
+func TestDecode(t *testing.T) {
+       for _, p := range pairs {
+               dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+               count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
+               testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+               testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
+               if len(p.encoded) > 0 {
+                       testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
+               }
+               testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+       }
+}
+
+func TestDecoder(t *testing.T) {
+       for _, p := range pairs {
+               decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+               dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+               count, err := decoder.Read(dbuf)
+               if err != nil && err != os.EOF {
+                       t.Fatal("Read failed", err)
+               }
+               testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded))
+               testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+               if err != os.EOF {
+                       count, err = decoder.Read(dbuf)
+               }
+               testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+       }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+       for bs := 1; bs <= 12; bs++ {
+               decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+               buf := make([]byte, len(bigtest.decoded)+12)
+               var total int
+               for total = 0; total < len(bigtest.decoded); {
+                       n, err := decoder.Read(buf[total : total+bs])
+                       testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+                       total += n
+               }
+               testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
+       }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+       type corrupt struct {
+               e string
+               p int
+       }
+       examples := []corrupt{
+               {"!!!!", 0},
+               {"x===", 1},
+               {"AA=A", 2},
+               {"AAA=AAAA", 3},
+               {"AAAAA", 4},
+               {"AAAAAA", 4},
+       }
+
+       for _, e := range examples {
+               dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
+               _, err := StdEncoding.Decode(dbuf, []byte(e.e))
+               switch err := err.(type) {
+               case CorruptInputError:
+                       testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+               default:
+                       t.Error("Decoder failed to detect corruption in", e)
+               }
+       }
+}
+
+func TestBig(t *testing.T) {
+       n := 3*1000 + 1
+       raw := make([]byte, n)
+       const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+       for i := 0; i < n; i++ {
+               raw[i] = alpha[i%len(alpha)]
+       }
+       encoded := new(bytes.Buffer)
+       w := NewEncoder(StdEncoding, encoded)
+       nn, err := w.Write(raw)
+       if nn != n || err != nil {
+               t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+       }
+       err = w.Close()
+       if err != nil {
+               t.Fatalf("Encoder.Close() = %v want nil", err)
+       }
+       decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded))
+       if err != nil {
+               t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
+       }
+
+       if !bytes.Equal(raw, decoded) {
+               var i int
+               for i = 0; i < len(decoded) && i < len(raw); i++ {
+                       if decoded[i] != raw[i] {
+                               break
+                       }
+               }
+               t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+       }
+}
diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go
new file mode 100644 (file)
index 0000000..ebc2ae8
--- /dev/null
@@ -0,0 +1,405 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements translation between
+// unsigned integer values and byte sequences.
+package binary
+
+import (
+       "math"
+       "io"
+       "os"
+       "reflect"
+)
+
+// A ByteOrder specifies how to convert byte sequences into
+// 16-, 32-, or 64-bit unsigned integers.
+type ByteOrder interface {
+       Uint16(b []byte) uint16
+       Uint32(b []byte) uint32
+       Uint64(b []byte) uint64
+       PutUint16([]byte, uint16)
+       PutUint32([]byte, uint32)
+       PutUint64([]byte, uint64)
+       String() string
+}
+
+// This is byte instead of struct{} so that it can be compared,
+// allowing, e.g., order == binary.LittleEndian.
+type unused byte
+
+// LittleEndian is the little-endian implementation of ByteOrder.
+var LittleEndian littleEndian
+
+// BigEndian is the big-endian implementation of ByteOrder.
+var BigEndian bigEndian
+
+type littleEndian unused
+
+func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
+
+func (littleEndian) PutUint16(b []byte, v uint16) {
+       b[0] = byte(v)
+       b[1] = byte(v >> 8)
+}
+
+func (littleEndian) Uint32(b []byte) uint32 {
+       return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func (littleEndian) PutUint32(b []byte, v uint32) {
+       b[0] = byte(v)
+       b[1] = byte(v >> 8)
+       b[2] = byte(v >> 16)
+       b[3] = byte(v >> 24)
+}
+
+func (littleEndian) Uint64(b []byte) uint64 {
+       return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+               uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+func (littleEndian) PutUint64(b []byte, v uint64) {
+       b[0] = byte(v)
+       b[1] = byte(v >> 8)
+       b[2] = byte(v >> 16)
+       b[3] = byte(v >> 24)
+       b[4] = byte(v >> 32)
+       b[5] = byte(v >> 40)
+       b[6] = byte(v >> 48)
+       b[7] = byte(v >> 56)
+}
+
+func (littleEndian) String() string { return "LittleEndian" }
+
+func (littleEndian) GoString() string { return "binary.LittleEndian" }
+
+type bigEndian unused
+
+func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
+
+func (bigEndian) PutUint16(b []byte, v uint16) {
+       b[0] = byte(v >> 8)
+       b[1] = byte(v)
+}
+
+func (bigEndian) Uint32(b []byte) uint32 {
+       return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+}
+
+func (bigEndian) PutUint32(b []byte, v uint32) {
+       b[0] = byte(v >> 24)
+       b[1] = byte(v >> 16)
+       b[2] = byte(v >> 8)
+       b[3] = byte(v)
+}
+
+func (bigEndian) Uint64(b []byte) uint64 {
+       return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+               uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+}
+
+func (bigEndian) PutUint64(b []byte, v uint64) {
+       b[0] = byte(v >> 56)
+       b[1] = byte(v >> 48)
+       b[2] = byte(v >> 40)
+       b[3] = byte(v >> 32)
+       b[4] = byte(v >> 24)
+       b[5] = byte(v >> 16)
+       b[6] = byte(v >> 8)
+       b[7] = byte(v)
+}
+
+func (bigEndian) String() string { return "BigEndian" }
+
+func (bigEndian) GoString() string { return "binary.BigEndian" }
+
+// Read reads structured binary data from r into data.
+// Data must be a pointer to a fixed-size value or a slice
+// of fixed-size values.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+// Bytes read from r are decoded using the specified byte order
+// and written to successive fields of the data.
+func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
+       var v reflect.Value
+       switch d := reflect.NewValue(data).(type) {
+       case *reflect.PtrValue:
+               v = d.Elem()
+       case *reflect.SliceValue:
+               v = d
+       default:
+               return os.NewError("binary.Read: invalid type " + d.Type().String())
+       }
+       size := TotalSize(v)
+       if size < 0 {
+               return os.NewError("binary.Read: invalid type " + v.Type().String())
+       }
+       d := &decoder{order: order, buf: make([]byte, size)}
+       if _, err := io.ReadFull(r, d.buf); err != nil {
+               return err
+       }
+       d.value(v)
+       return nil
+}
+
+// Write writes the binary representation of data into w.
+// Data must be a fixed-size value or a pointer to
+// a fixed-size value.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+// Bytes written to w are encoded using the specified byte order
+// and read from successive fields of the data.
+func Write(w io.Writer, order ByteOrder, data interface{}) os.Error {
+       v := reflect.Indirect(reflect.NewValue(data))
+       size := TotalSize(v)
+       if size < 0 {
+               return os.NewError("binary.Write: invalid type " + v.Type().String())
+       }
+       buf := make([]byte, size)
+       e := &encoder{order: order, buf: buf}
+       e.value(v)
+       _, err := w.Write(buf)
+       return err
+}
+
+func TotalSize(v reflect.Value) int {
+       if sv, ok := v.(*reflect.SliceValue); ok {
+               elem := sizeof(v.Type().(*reflect.SliceType).Elem())
+               if elem < 0 {
+                       return -1
+               }
+               return sv.Len() * elem
+       }
+       return sizeof(v.Type())
+}
+
+func sizeof(v reflect.Type) int {
+       switch t := v.(type) {
+       case *reflect.ArrayType:
+               n := sizeof(t.Elem())
+               if n < 0 {
+                       return -1
+               }
+               return t.Len() * n
+
+       case *reflect.StructType:
+               sum := 0
+               for i, n := 0, t.NumField(); i < n; i++ {
+                       s := sizeof(t.Field(i).Type)
+                       if s < 0 {
+                               return -1
+                       }
+                       sum += s
+               }
+               return sum
+
+       case *reflect.UintType, *reflect.IntType, *reflect.FloatType, *reflect.ComplexType:
+               return int(v.Size())
+       }
+       return -1
+}
+
+type decoder struct {
+       order ByteOrder
+       buf   []byte
+}
+
+type encoder struct {
+       order ByteOrder
+       buf   []byte
+}
+
+func (d *decoder) uint8() uint8 {
+       x := d.buf[0]
+       d.buf = d.buf[1:]
+       return x
+}
+
+func (e *encoder) uint8(x uint8) {
+       e.buf[0] = x
+       e.buf = e.buf[1:]
+}
+
+func (d *decoder) uint16() uint16 {
+       x := d.order.Uint16(d.buf[0:2])
+       d.buf = d.buf[2:]
+       return x
+}
+
+func (e *encoder) uint16(x uint16) {
+       e.order.PutUint16(e.buf[0:2], x)
+       e.buf = e.buf[2:]
+}
+
+func (d *decoder) uint32() uint32 {
+       x := d.order.Uint32(d.buf[0:4])
+       d.buf = d.buf[4:]
+       return x
+}
+
+func (e *encoder) uint32(x uint32) {
+       e.order.PutUint32(e.buf[0:4], x)
+       e.buf = e.buf[4:]
+}
+
+func (d *decoder) uint64() uint64 {
+       x := d.order.Uint64(d.buf[0:8])
+       d.buf = d.buf[8:]
+       return x
+}
+
+func (e *encoder) uint64(x uint64) {
+       e.order.PutUint64(e.buf[0:8], x)
+       e.buf = e.buf[8:]
+}
+
+func (d *decoder) int8() int8 { return int8(d.uint8()) }
+
+func (e *encoder) int8(x int8) { e.uint8(uint8(x)) }
+
+func (d *decoder) int16() int16 { return int16(d.uint16()) }
+
+func (e *encoder) int16(x int16) { e.uint16(uint16(x)) }
+
+func (d *decoder) int32() int32 { return int32(d.uint32()) }
+
+func (e *encoder) int32(x int32) { e.uint32(uint32(x)) }
+
+func (d *decoder) int64() int64 { return int64(d.uint64()) }
+
+func (e *encoder) int64(x int64) { e.uint64(uint64(x)) }
+
+func (d *decoder) value(v reflect.Value) {
+       switch v := v.(type) {
+       case *reflect.ArrayValue:
+               l := v.Len()
+               for i := 0; i < l; i++ {
+                       d.value(v.Elem(i))
+               }
+       case *reflect.StructValue:
+               l := v.NumField()
+               for i := 0; i < l; i++ {
+                       d.value(v.Field(i))
+               }
+
+       case *reflect.SliceValue:
+               l := v.Len()
+               for i := 0; i < l; i++ {
+                       d.value(v.Elem(i))
+               }
+
+       case *reflect.IntValue:
+               switch v.Type().Kind() {
+               case reflect.Int8:
+                       v.Set(int64(d.int8()))
+               case reflect.Int16:
+                       v.Set(int64(d.int16()))
+               case reflect.Int32:
+                       v.Set(int64(d.int32()))
+               case reflect.Int64:
+                       v.Set(d.int64())
+               }
+
+       case *reflect.UintValue:
+               switch v.Type().Kind() {
+               case reflect.Uint8:
+                       v.Set(uint64(d.uint8()))
+               case reflect.Uint16:
+                       v.Set(uint64(d.uint16()))
+               case reflect.Uint32:
+                       v.Set(uint64(d.uint32()))
+               case reflect.Uint64:
+                       v.Set(d.uint64())
+               }
+
+       case *reflect.FloatValue:
+               switch v.Type().Kind() {
+               case reflect.Float32:
+                       v.Set(float64(math.Float32frombits(d.uint32())))
+               case reflect.Float64:
+                       v.Set(math.Float64frombits(d.uint64()))
+               }
+
+       case *reflect.ComplexValue:
+               switch v.Type().Kind() {
+               case reflect.Complex64:
+                       v.Set(cmplx(
+                               float64(math.Float32frombits(d.uint32())),
+                               float64(math.Float32frombits(d.uint32())),
+                       ))
+               case reflect.Complex128:
+                       v.Set(cmplx(
+                               math.Float64frombits(d.uint64()),
+                               math.Float64frombits(d.uint64()),
+                       ))
+               }
+       }
+}
+
+func (e *encoder) value(v reflect.Value) {
+       switch v := v.(type) {
+       case *reflect.ArrayValue:
+               l := v.Len()
+               for i := 0; i < l; i++ {
+                       e.value(v.Elem(i))
+               }
+       case *reflect.StructValue:
+               l := v.NumField()
+               for i := 0; i < l; i++ {
+                       e.value(v.Field(i))
+               }
+       case *reflect.SliceValue:
+               l := v.Len()
+               for i := 0; i < l; i++ {
+                       e.value(v.Elem(i))
+               }
+
+       case *reflect.IntValue:
+               switch v.Type().Kind() {
+               case reflect.Int8:
+                       e.int8(int8(v.Get()))
+               case reflect.Int16:
+                       e.int16(int16(v.Get()))
+               case reflect.Int32:
+                       e.int32(int32(v.Get()))
+               case reflect.Int64:
+                       e.int64(v.Get())
+               }
+
+       case *reflect.UintValue:
+               switch v.Type().Kind() {
+               case reflect.Uint8:
+                       e.uint8(uint8(v.Get()))
+               case reflect.Uint16:
+                       e.uint16(uint16(v.Get()))
+               case reflect.Uint32:
+                       e.uint32(uint32(v.Get()))
+               case reflect.Uint64:
+                       e.uint64(v.Get())
+               }
+
+       case *reflect.FloatValue:
+               switch v.Type().Kind() {
+               case reflect.Float32:
+                       e.uint32(math.Float32bits(float32(v.Get())))
+               case reflect.Float64:
+                       e.uint64(math.Float64bits(v.Get()))
+               }
+
+       case *reflect.ComplexValue:
+               switch v.Type().Kind() {
+               case reflect.Complex64:
+                       x := v.Get()
+                       e.uint32(math.Float32bits(float32(real(x))))
+                       e.uint32(math.Float32bits(float32(imag(x))))
+               case reflect.Complex128:
+                       x := v.Get()
+                       e.uint64(math.Float64bits(real(x)))
+                       e.uint64(math.Float64bits(imag(x)))
+               }
+       }
+}
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go
new file mode 100644 (file)
index 0000000..d372d2d
--- /dev/null
@@ -0,0 +1,138 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package binary
+
+import (
+       "os"
+       "bytes"
+       "math"
+       "reflect"
+       "testing"
+)
+
+type Struct struct {
+       Int8       int8
+       Int16      int16
+       Int32      int32
+       Int64      int64
+       Uint8      uint8
+       Uint16     uint16
+       Uint32     uint32
+       Uint64     uint64
+       Float32    float32
+       Float64    float64
+       Complex64  complex64
+       Complex128 complex128
+       Array      [4]uint8
+}
+
+var s = Struct{
+       0x01,
+       0x0203,
+       0x04050607,
+       0x08090a0b0c0d0e0f,
+       0x10,
+       0x1112,
+       0x13141516,
+       0x1718191a1b1c1d1e,
+
+       math.Float32frombits(0x1f202122),
+       math.Float64frombits(0x232425262728292a),
+       cmplx(
+               math.Float32frombits(0x2b2c2d2e),
+               math.Float32frombits(0x2f303132),
+       ),
+       cmplx(
+               math.Float64frombits(0x333435363738393a),
+               math.Float64frombits(0x3b3c3d3e3f404142),
+       ),
+
+       [4]uint8{0x43, 0x44, 0x45, 0x46},
+}
+
+var big = []byte{
+       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,
+}
+
+var little = []byte{
+       1,
+       3, 2,
+       7, 6, 5, 4,
+       15, 14, 13, 12, 11, 10, 9, 8,
+       16,
+       18, 17,
+       22, 21, 20, 19,
+       30, 29, 28, 27, 26, 25, 24, 23,
+
+       34, 33, 32, 31,
+       42, 41, 40, 39, 38, 37, 36, 35,
+       46, 45, 44, 43, 50, 49, 48, 47,
+       58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
+
+       67, 68, 69, 70,
+}
+
+var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
+var res = []int32{0x01020304, 0x05060708}
+
+func checkResult(t *testing.T, dir string, order, err os.Error, have, want interface{}) {
+       if err != nil {
+               t.Errorf("%v %v: %v", dir, order, err)
+               return
+       }
+       if !reflect.DeepEqual(have, want) {
+               t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want)
+       }
+}
+
+func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
+       var s2 Struct
+       err := Read(bytes.NewBuffer(b), order, &s2)
+       checkResult(t, "Read", order, err, s2, s1)
+}
+
+func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
+       buf := new(bytes.Buffer)
+       err := Write(buf, order, s1)
+       checkResult(t, "Write", order, err, buf.Bytes(), b)
+}
+
+func TestBigEndianRead(t *testing.T) { testRead(t, BigEndian, big, s) }
+
+func TestLittleEndianRead(t *testing.T) { testRead(t, LittleEndian, little, s) }
+
+func TestBigEndianWrite(t *testing.T) { testWrite(t, BigEndian, big, s) }
+
+func TestLittleEndianWrite(t *testing.T) { testWrite(t, LittleEndian, little, s) }
+
+func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
+
+func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) }
+
+func TestReadSlice(t *testing.T) {
+       slice := make([]int32, 2)
+       err := Read(bytes.NewBuffer(src), BigEndian, slice)
+       checkResult(t, "ReadSlice", BigEndian, err, slice, res)
+}
+
+func TestWriteSlice(t *testing.T) {
+       buf := new(bytes.Buffer)
+       err := Write(buf, BigEndian, res)
+       checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)
+}
diff --git a/libgo/go/encoding/git85/git.go b/libgo/go/encoding/git85/git.go
new file mode 100644 (file)
index 0000000..09a45cd
--- /dev/null
@@ -0,0 +1,277 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package git85 implements the radix 85 data encoding
+// used in the Git version control system.
+package git85
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "strconv"
+)
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+       return "illegal git85 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+const encode = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
+
+// The decodings are 1+ the actual value, so that the
+// default zero value can be used to mean "not valid".
+var decode = [256]uint8{
+       '0': 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+       'A': 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,
+       'a': 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, 84, 85,
+}
+
+// Encode encodes src into EncodedLen(len(src))
+// bytes of dst.  As a convenience, it returns the number
+// of bytes written to dst, but this value is always EncodedLen(len(src)).
+// Encode implements the radix 85 encoding used in the
+// Git version control tool.
+//
+// The encoding splits src into chunks of at most 52 bytes
+// and encodes each chunk on its own line.
+func Encode(dst, src []byte) int {
+       ndst := 0
+       for len(src) > 0 {
+               n := len(src)
+               if n > 52 {
+                       n = 52
+               }
+               if n <= 27 {
+                       dst[ndst] = byte('A' + n - 1)
+               } else {
+                       dst[ndst] = byte('a' + n - 26 - 1)
+               }
+               ndst++
+               for i := 0; i < n; i += 4 {
+                       var v uint32
+                       for j := 0; j < 4 && i+j < n; j++ {
+                               v |= uint32(src[i+j]) << uint(24-j*8)
+                       }
+                       for j := 4; j >= 0; j-- {
+                               dst[ndst+j] = encode[v%85]
+                               v /= 85
+                       }
+                       ndst += 5
+               }
+               dst[ndst] = '\n'
+               ndst++
+               src = src[n:]
+       }
+       return ndst
+}
+
+// EncodedLen returns the length of an encoding of n source bytes.
+func EncodedLen(n int) int {
+       if n == 0 {
+               return 0
+       }
+       // 5 bytes per 4 bytes of input, rounded up.
+       // 2 extra bytes for each line of 52 src bytes, rounded up.
+       return (n+3)/4*5 + (n+51)/52*2
+}
+
+var newline = []byte{'\n'}
+
+// Decode decodes src into at most MaxDecodedLen(len(src))
+// bytes, returning the actual number of bytes written to dst.
+//
+// If Decode encounters invalid input, it returns a CorruptInputError.
+//
+func Decode(dst, src []byte) (n int, err os.Error) {
+       ndst := 0
+       nsrc := 0
+       for nsrc < len(src) {
+               var l int
+               switch ch := int(src[nsrc]); {
+               case 'A' <= ch && ch <= 'Z':
+                       l = ch - 'A' + 1
+               case 'a' <= ch && ch <= 'z':
+                       l = ch - 'a' + 26 + 1
+               default:
+                       return ndst, CorruptInputError(nsrc)
+               }
+               if nsrc+1+l > len(src) {
+                       return ndst, CorruptInputError(nsrc)
+               }
+               el := (l + 3) / 4 * 5 // encoded len
+               if nsrc+1+el+1 > len(src) || src[nsrc+1+el] != '\n' {
+                       return ndst, CorruptInputError(nsrc)
+               }
+               line := src[nsrc+1 : nsrc+1+el]
+               for i := 0; i < el; i += 5 {
+                       var v uint32
+                       for j := 0; j < 5; j++ {
+                               ch := decode[line[i+j]]
+                               if ch == 0 {
+                                       return ndst, CorruptInputError(nsrc + 1 + i + j)
+                               }
+                               v = v*85 + uint32(ch-1)
+                       }
+                       for j := 0; j < 4; j++ {
+                               dst[ndst] = byte(v >> 24)
+                               v <<= 8
+                               ndst++
+                       }
+               }
+               // Last fragment may have run too far (but there was room in dst).
+               // Back up.
+               if l%4 != 0 {
+                       ndst -= 4 - l%4
+               }
+               nsrc += 1 + el + 1
+       }
+       return ndst, nil
+}
+
+func MaxDecodedLen(n int) int { return n / 5 * 4 }
+
+// NewEncoder returns a new Git base85 stream encoder.  Data written to
+// the returned writer will be encoded and then written to w.
+// The Git encoding operates on 52-byte blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// partially written blocks.
+func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} }
+
+type encoder struct {
+       w    io.Writer
+       err  os.Error
+       buf  [52]byte
+       nbuf int
+       out  [1024]byte
+       nout int
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+       if e.err != nil {
+               return 0, e.err
+       }
+
+       // Leading fringe.
+       if e.nbuf > 0 {
+               var i int
+               for i = 0; i < len(p) && e.nbuf < 52; i++ {
+                       e.buf[e.nbuf] = p[i]
+                       e.nbuf++
+               }
+               n += i
+               p = p[i:]
+               if e.nbuf < 52 {
+                       return
+               }
+               nout := Encode(e.out[0:], e.buf[0:])
+               if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+                       return n, e.err
+               }
+               e.nbuf = 0
+       }
+
+       // Large interior chunks.
+       for len(p) >= 52 {
+               nn := len(e.out) / (1 + 52/4*5 + 1) * 52
+               if nn > len(p) {
+                       nn = len(p) / 52 * 52
+               }
+               if nn > 0 {
+                       nout := Encode(e.out[0:], p[0:nn])
+                       if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+                               return n, e.err
+                       }
+               }
+               n += nn
+               p = p[nn:]
+       }
+
+       // Trailing fringe.
+       for i := 0; i < len(p); i++ {
+               e.buf[i] = p[i]
+       }
+       e.nbuf = len(p)
+       n += len(p)
+       return
+}
+
+func (e *encoder) Close() os.Error {
+       // If there's anything left in the buffer, flush it out
+       if e.err == nil && e.nbuf > 0 {
+               nout := Encode(e.out[0:], e.buf[0:e.nbuf])
+               e.nbuf = 0
+               _, e.err = e.w.Write(e.out[0:nout])
+       }
+       return e.err
+}
+
+// NewDecoder returns a new Git base85 stream decoder.
+func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} }
+
+type decoder struct {
+       r       io.Reader
+       err     os.Error
+       readErr os.Error
+       buf     [1024]byte
+       nbuf    int
+       out     []byte
+       outbuf  [1024]byte
+       off     int64
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+       if len(p) == 0 {
+               return 0, nil
+       }
+
+       for {
+               // Copy leftover output from last decode.
+               if len(d.out) > 0 {
+                       n = copy(p, d.out)
+                       d.out = d.out[n:]
+                       return
+               }
+
+               // Out of decoded output.  Check errors.
+               if d.err != nil {
+                       return 0, d.err
+               }
+               if d.readErr != nil {
+                       d.err = d.readErr
+                       return 0, d.err
+               }
+
+               // Read and decode more input.
+               var nn int
+               nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
+               d.nbuf += nn
+
+               // Send complete lines to Decode.
+               nl := bytes.LastIndex(d.buf[0:d.nbuf], newline)
+               if nl < 0 {
+                       continue
+               }
+               nn, d.err = Decode(d.outbuf[0:], d.buf[0:nl+1])
+               if e, ok := d.err.(CorruptInputError); ok {
+                       d.err = CorruptInputError(int64(e) + d.off)
+               }
+               d.out = d.outbuf[0:nn]
+               d.nbuf = copy(d.buf[0:], d.buf[nl+1:d.nbuf])
+               d.off += int64(nl + 1)
+       }
+       panic("unreacahable")
+}
diff --git a/libgo/go/encoding/git85/git_test.go b/libgo/go/encoding/git85/git_test.go
new file mode 100644 (file)
index 0000000..c76385c
--- /dev/null
@@ -0,0 +1,194 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package git85
+
+import (
+       "bytes"
+       "io/ioutil"
+       "os"
+       "testing"
+)
+
+type testpair struct {
+       decoded, encoded string
+}
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+       if args[len(args)-2] != args[len(args)-1] {
+               t.Errorf(msg, args...)
+               return false
+       }
+       return true
+}
+
+func TestGitTable(t *testing.T) {
+       var saw [256]bool
+       for i, c := range encode {
+               if decode[c] != uint8(i+1) {
+                       t.Errorf("decode['%c'] = %d, want %d", c, decode[c], i+1)
+               }
+               saw[c] = true
+       }
+       for i, b := range saw {
+               if !b && decode[i] != 0 {
+                       t.Errorf("decode[%d] = %d, want 0", i, decode[i])
+               }
+       }
+}
+
+var gitPairs = []testpair{
+       // Wikipedia example, adapted.
+       {
+               "Man is distinguished, not only by his reason, but by this singular passion from " +
+                       "other animals, which is a lust of the mind, that by a perseverance of delight in " +
+                       "the continued and indefatigable generation of knowledge, exceeds the short " +
+                       "vehemence of any carnal pleasure.",
+
+               "zO<`^zX>%ZCX>)XGZfA9Ab7*B`EFf-gbRchTY<VDJc_3(Mb0BhMVRLV8EFfZabRc4R\n" +
+                       "zAarPHb0BkRZfA9DVR9gFVRLh7Z*CxFa&K)QZ**v7av))DX>DO_b1WctXlY|;AZc?T\n" +
+                       "zVIXXEb95kYW*~HEWgu;7Ze%PVbZB98AYyqSVIXj2a&u*NWpZI|V`U(3W*}r`Y-wj`\n" +
+                       "zbRcPNAarPDAY*TCbZKsNWn>^>Ze$>7Ze(R<VRUI{VPb4$AZKN6WpZJ3X>V>IZ)PBC\n" +
+                       "zZf|#NWn^b%EFfigV`XJzb0BnRWgv5CZ*p`Xc4cT~ZDnp_Wgu^6AYpEKAY);2ZeeU7\n" +
+                       "IaBO8^b9HiME&u=k\n",
+       },
+}
+
+var gitBigtest = gitPairs[len(gitPairs)-1]
+
+func TestEncode(t *testing.T) {
+       for _, p := range gitPairs {
+               buf := make([]byte, EncodedLen(len(p.decoded)))
+               n := Encode(buf, []byte(p.decoded))
+               if n != len(buf) {
+                       t.Errorf("EncodedLen does not agree with Encode")
+               }
+               buf = buf[0:n]
+               testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+       }
+}
+
+func TestEncoder(t *testing.T) {
+       for _, p := range gitPairs {
+               bb := &bytes.Buffer{}
+               encoder := NewEncoder(bb)
+               encoder.Write([]byte(p.decoded))
+               encoder.Close()
+               testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
+       }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+       input := []byte(gitBigtest.decoded)
+       for bs := 1; bs <= 12; bs++ {
+               bb := &bytes.Buffer{}
+               encoder := NewEncoder(bb)
+               for pos := 0; pos < len(input); pos += bs {
+                       end := pos + bs
+                       if end > len(input) {
+                               end = len(input)
+                       }
+                       n, err := encoder.Write(input[pos:end])
+                       testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+                       testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+               }
+               err := encoder.Close()
+               testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+               testEqual(t, "Encoding/%d of %q = %q, want %q", bs, gitBigtest.decoded, bb.String(), gitBigtest.encoded)
+       }
+}
+
+func TestDecode(t *testing.T) {
+       for _, p := range gitPairs {
+               dbuf := make([]byte, 4*len(p.encoded))
+               ndst, err := Decode(dbuf, []byte(p.encoded))
+               testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+               testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded))
+               testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded)
+       }
+}
+
+func TestDecoder(t *testing.T) {
+       for _, p := range gitPairs {
+               decoder := NewDecoder(bytes.NewBufferString(p.encoded))
+               dbuf, err := ioutil.ReadAll(decoder)
+               if err != nil {
+                       t.Fatal("Read failed", err)
+               }
+               testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded))
+               testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded)
+               if err != nil {
+                       testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+               }
+       }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+       for bs := 1; bs <= 12; bs++ {
+               decoder := NewDecoder(bytes.NewBufferString(gitBigtest.encoded))
+               buf := make([]byte, len(gitBigtest.decoded)+12)
+               var total int
+               for total = 0; total < len(gitBigtest.decoded); {
+                       n, err := decoder.Read(buf[total : total+bs])
+                       testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", gitBigtest.encoded, total, n, err, os.Error(nil))
+                       total += n
+               }
+               testEqual(t, "Decoding/%d of %q = %q, want %q", bs, gitBigtest.encoded, string(buf[0:total]), gitBigtest.decoded)
+       }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+       type corrupt struct {
+               e string
+               p int
+       }
+       examples := []corrupt{
+               {"v", 0},
+               {"!z!!!!!!!!!", 0},
+       }
+
+       for _, e := range examples {
+               dbuf := make([]byte, 2*len(e.e))
+               _, err := Decode(dbuf, []byte(e.e))
+               switch err := err.(type) {
+               case CorruptInputError:
+                       testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+               default:
+                       t.Error("Decoder failed to detect corruption in", e)
+               }
+       }
+}
+
+func TestGitBig(t *testing.T) {
+       n := 3*1000 + 1
+       raw := make([]byte, n)
+       const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+       for i := 0; i < n; i++ {
+               raw[i] = alpha[i%len(alpha)]
+       }
+       encoded := new(bytes.Buffer)
+       w := NewEncoder(encoded)
+       nn, err := w.Write(raw)
+       if nn != n || err != nil {
+               t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+       }
+       err = w.Close()
+       if err != nil {
+               t.Fatalf("Encoder.Close() = %v want nil", err)
+       }
+       decoded, err := ioutil.ReadAll(NewDecoder(encoded))
+       if err != nil {
+               t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
+       }
+
+       if !bytes.Equal(raw, decoded) {
+               var i int
+               for i = 0; i < len(decoded) && i < len(raw); i++ {
+                       if decoded[i] != raw[i] {
+                               break
+                       }
+               }
+               t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+       }
+}
diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go
new file mode 100644 (file)
index 0000000..292d917
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements hexadecimal encoding and decoding.
+package hex
+
+import (
+       "os"
+       "strconv"
+)
+
+const hextable = "0123456789abcdef"
+
+// EncodedLen returns the length of an encoding of n source bytes.
+func EncodedLen(n int) int { return n * 2 }
+
+// Encode encodes src into EncodedLen(len(src))
+// bytes of dst.  As a convenience, it returns the number
+// of bytes written to dst, but this value is always EncodedLen(len(src)).
+// Encode implements hexadecimal encoding.
+func Encode(dst, src []byte) int {
+       for i, v := range src {
+               dst[i*2] = hextable[v>>4]
+               dst[i*2+1] = hextable[v&0x0f]
+       }
+
+       return len(src) * 2
+}
+
+// OddLengthInputError results from decoding an odd length slice.
+type OddLengthInputError struct{}
+
+func (OddLengthInputError) String() string { return "odd length hex string" }
+
+// InvalidHexCharError results from finding an invalid character in a hex string.
+type InvalidHexCharError byte
+
+func (e InvalidHexCharError) String() string {
+       return "invalid hex char: " + strconv.Itoa(int(e))
+}
+
+
+func DecodedLen(x int) int { return x / 2 }
+
+// Decode decodes src into DecodedLen(len(src)) bytes, returning the actual
+// number of bytes written to dst.
+//
+// If Decode encounters invalid input, it returns an OddLengthInputError or an
+// InvalidHexCharError.
+func Decode(dst, src []byte) (int, os.Error) {
+       if len(src)%2 == 1 {
+               return 0, OddLengthInputError{}
+       }
+
+       for i := 0; i < len(src)/2; i++ {
+               a, ok := fromHexChar(src[i*2])
+               if !ok {
+                       return 0, InvalidHexCharError(src[i*2])
+               }
+               b, ok := fromHexChar(src[i*2+1])
+               if !ok {
+                       return 0, InvalidHexCharError(src[i*2+1])
+               }
+               dst[i] = (a << 4) | b
+       }
+
+       return len(src) / 2, nil
+}
+
+// fromHexChar converts a hex character into its value and a success flag.
+func fromHexChar(c byte) (byte, bool) {
+       switch {
+       case '0' <= c && c <= '9':
+               return c - '0', true
+       case 'a' <= c && c <= 'f':
+               return c - 'a' + 10, true
+       case 'A' <= c && c <= 'F':
+               return c - 'A' + 10, true
+       }
+
+       return 0, false
+}
+
+// EncodeToString returns the hexadecimal encoding of src.
+func EncodeToString(src []byte) string {
+       dst := make([]byte, EncodedLen(len(src)))
+       Encode(dst, src)
+       return string(dst)
+}
+
+// DecodeString returns the bytes represented by the hexadecimal string s.
+func DecodeString(s string) ([]byte, os.Error) {
+       src := []byte(s)
+       dst := make([]byte, DecodedLen(len(src)))
+       _, err := Decode(dst, src)
+       if err != nil {
+               return nil, err
+       }
+       return dst, nil
+}
diff --git a/libgo/go/encoding/hex/hex_test.go b/libgo/go/encoding/hex/hex_test.go
new file mode 100644 (file)
index 0000000..a14c9d4
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hex
+
+import (
+       "bytes"
+       "testing"
+)
+
+type encodeTest struct {
+       in, out []byte
+}
+
+var encodeTests = []encodeTest{
+       {[]byte{}, []byte{}},
+       {[]byte{0x01}, []byte{'0', '1'}},
+       {[]byte{0xff}, []byte{'f', 'f'}},
+       {[]byte{0xff, 00}, []byte{'f', 'f', '0', '0'}},
+       {[]byte{0}, []byte{'0', '0'}},
+       {[]byte{1}, []byte{'0', '1'}},
+       {[]byte{2}, []byte{'0', '2'}},
+       {[]byte{3}, []byte{'0', '3'}},
+       {[]byte{4}, []byte{'0', '4'}},
+       {[]byte{5}, []byte{'0', '5'}},
+       {[]byte{6}, []byte{'0', '6'}},
+       {[]byte{7}, []byte{'0', '7'}},
+       {[]byte{8}, []byte{'0', '8'}},
+       {[]byte{9}, []byte{'0', '9'}},
+       {[]byte{10}, []byte{'0', 'a'}},
+       {[]byte{11}, []byte{'0', 'b'}},
+       {[]byte{12}, []byte{'0', 'c'}},
+       {[]byte{13}, []byte{'0', 'd'}},
+       {[]byte{14}, []byte{'0', 'e'}},
+       {[]byte{15}, []byte{'0', 'f'}},
+}
+
+func TestEncode(t *testing.T) {
+       for i, test := range encodeTests {
+               dst := make([]byte, EncodedLen(len(test.in)))
+               n := Encode(dst, test.in)
+               if n != len(dst) {
+                       t.Errorf("#%d: bad return value: got: %d want: %d", i, n, len(dst))
+               }
+               if bytes.Compare(dst, test.out) != 0 {
+                       t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+               }
+       }
+}
+
+type decodeTest struct {
+       in, out []byte
+       ok      bool
+}
+
+var decodeTests = []decodeTest{
+       {[]byte{}, []byte{}, true},
+       {[]byte{'0'}, []byte{}, false},
+       {[]byte{'0', 'g'}, []byte{}, false},
+       {[]byte{'0', '\x01'}, []byte{}, false},
+       {[]byte{'0', '0'}, []byte{0}, true},
+       {[]byte{'0', '1'}, []byte{1}, true},
+       {[]byte{'0', '2'}, []byte{2}, true},
+       {[]byte{'0', '3'}, []byte{3}, true},
+       {[]byte{'0', '4'}, []byte{4}, true},
+       {[]byte{'0', '5'}, []byte{5}, true},
+       {[]byte{'0', '6'}, []byte{6}, true},
+       {[]byte{'0', '7'}, []byte{7}, true},
+       {[]byte{'0', '8'}, []byte{8}, true},
+       {[]byte{'0', '9'}, []byte{9}, true},
+       {[]byte{'0', 'a'}, []byte{10}, true},
+       {[]byte{'0', 'b'}, []byte{11}, true},
+       {[]byte{'0', 'c'}, []byte{12}, true},
+       {[]byte{'0', 'd'}, []byte{13}, true},
+       {[]byte{'0', 'e'}, []byte{14}, true},
+       {[]byte{'0', 'f'}, []byte{15}, true},
+       {[]byte{'0', 'A'}, []byte{10}, true},
+       {[]byte{'0', 'B'}, []byte{11}, true},
+       {[]byte{'0', 'C'}, []byte{12}, true},
+       {[]byte{'0', 'D'}, []byte{13}, true},
+       {[]byte{'0', 'E'}, []byte{14}, true},
+       {[]byte{'0', 'F'}, []byte{15}, true},
+}
+
+func TestDecode(t *testing.T) {
+       for i, test := range decodeTests {
+               dst := make([]byte, DecodedLen(len(test.in)))
+               n, err := Decode(dst, test.in)
+               if err == nil && n != len(dst) {
+                       t.Errorf("#%d: bad return value: got:%d want:%d", i, n, len(dst))
+               }
+               if test.ok != (err == nil) {
+                       t.Errorf("#%d: unexpected err value: %s", i, err)
+               }
+               if err == nil && bytes.Compare(dst, test.out) != 0 {
+                       t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+               }
+       }
+}
+
+type encodeStringTest struct {
+       in  []byte
+       out string
+}
+
+var encodeStringTests = []encodeStringTest{
+       {[]byte{}, ""},
+       {[]byte{0}, "00"},
+       {[]byte{0, 1}, "0001"},
+       {[]byte{0, 1, 255}, "0001ff"},
+}
+
+func TestEncodeToString(t *testing.T) {
+       for i, test := range encodeStringTests {
+               s := EncodeToString(test.in)
+               if s != test.out {
+                       t.Errorf("#%d got:%s want:%s", i, s, test.out)
+               }
+       }
+}
+
+type decodeStringTest struct {
+       in  string
+       out []byte
+       ok  bool
+}
+
+var decodeStringTests = []decodeStringTest{
+       {"", []byte{}, true},
+       {"0", []byte{}, false},
+       {"00", []byte{0}, true},
+       {"0\x01", []byte{}, false},
+       {"0g", []byte{}, false},
+       {"00ff00", []byte{0, 255, 0}, true},
+       {"0000ff", []byte{0, 0, 255}, true},
+}
+
+func TestDecodeString(t *testing.T) {
+       for i, test := range decodeStringTests {
+               dst, err := DecodeString(test.in)
+               if test.ok != (err == nil) {
+                       t.Errorf("#%d: unexpected err value: %s", i, err)
+               }
+               if err == nil && bytes.Compare(dst, test.out) != 0 {
+                       t.Errorf("#%d: got: %#v want: #%v", i, dst, test.out)
+               }
+       }
+}
diff --git a/libgo/go/encoding/pem/pem.go b/libgo/go/encoding/pem/pem.go
new file mode 100644 (file)
index 0000000..5653aeb
--- /dev/null
@@ -0,0 +1,257 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the PEM data encoding, which originated in Privacy
+// Enhanced Mail. The most common use of PEM encoding today is in TLS keys and
+// certificates. See RFC 1421.
+package pem
+
+import (
+       "bytes"
+       "encoding/base64"
+       "io"
+       "os"
+)
+
+// A Block represents a PEM encoded structure.
+//
+// The encoded form is:
+//    -----BEGIN Type-----
+//    Headers
+//    base64-encoded Bytes
+//    -----END Type-----
+// where Headers is a possibly empty sequence of Key: Value lines.
+type Block struct {
+       Type    string            // The type, taken from the preamble (i.e. "RSA PRIVATE KEY").
+       Headers map[string]string // Optional headers.
+       Bytes   []byte            // The decoded bytes of the contents. Typically a DER encoded ASN.1 structure.
+}
+
+// getLine results the first \r\n or \n delineated line from the given byte
+// array. The line does not include the \r\n or \n. The remainder of the byte
+// array (also not including the new line bytes) is also returned and this will
+// always be smaller than the original argument.
+func getLine(data []byte) (line, rest []byte) {
+       i := bytes.Index(data, []byte{'\n'})
+       var j int
+       if i < 0 {
+               i = len(data)
+               j = i
+       } else {
+               j = i + 1
+               if i > 0 && data[i-1] == '\r' {
+                       i--
+               }
+       }
+       return data[0:i], data[j:]
+}
+
+// removeWhitespace returns a copy of its input with all spaces, tab and
+// newline characters removed.
+func removeWhitespace(data []byte) []byte {
+       result := make([]byte, len(data))
+       n := 0
+
+       for _, b := range data {
+               if b == ' ' || b == '\t' || b == '\r' || b == '\n' {
+                       continue
+               }
+               result[n] = b
+               n++
+       }
+
+       return result[0:n]
+}
+
+var pemStart = []byte("\n-----BEGIN ")
+var pemEnd = []byte("\n-----END ")
+var pemEndOfLine = []byte("-----")
+
+// Decode will find the next PEM formatted block (certificate, private key
+// etc) in the input. It returns that block and the remainder of the input. If
+// no PEM data is found, p is nil and the whole of the input is returned in
+// rest.
+func Decode(data []byte) (p *Block, rest []byte) {
+       // pemStart begins with a newline. However, at the very beginning of
+       // the byte array, we'll accept the start string without it.
+       rest = data
+       if bytes.HasPrefix(data, pemStart[1:]) {
+               rest = rest[len(pemStart)-1 : len(data)]
+       } else if i := bytes.Index(data, pemStart); i >= 0 {
+               rest = rest[i+len(pemStart) : len(data)]
+       } else {
+               return nil, data
+       }
+
+       typeLine, rest := getLine(rest)
+       if !bytes.HasSuffix(typeLine, pemEndOfLine) {
+               goto Error
+       }
+       typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)]
+
+       p = &Block{
+               Headers: make(map[string]string),
+               Type:    string(typeLine),
+       }
+
+       for {
+               // This loop terminates because getLine's second result is
+               // always smaller than it's argument.
+               if len(rest) == 0 {
+                       return nil, data
+               }
+               line, next := getLine(rest)
+
+               i := bytes.Index(line, []byte{':'})
+               if i == -1 {
+                       break
+               }
+
+               // TODO(agl): need to cope with values that spread across lines.
+               key, val := line[0:i], line[i+1:]
+               key = bytes.TrimSpace(key)
+               val = bytes.TrimSpace(val)
+               p.Headers[string(key)] = string(val)
+               rest = next
+       }
+
+       i := bytes.Index(rest, pemEnd)
+       if i < 0 {
+               goto Error
+       }
+       base64Data := removeWhitespace(rest[0:i])
+
+       p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
+       n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
+       if err != nil {
+               goto Error
+       }
+       p.Bytes = p.Bytes[0:n]
+
+       _, rest = getLine(rest[i+len(pemEnd):])
+
+       return
+
+Error:
+       // If we get here then we have rejected a likely looking, but
+       // ultimately invalid PEM block. We need to start over from a new
+       // position.  We have consumed the preamble line and will have consumed
+       // any lines which could be header lines. However, a valid preamble
+       // line is not a valid header line, therefore we cannot have consumed
+       // the preamble line for the any subsequent block. Thus, we will always
+       // find any valid block, no matter what bytes preceed it.
+       //
+       // For example, if the input is
+       //
+       //    -----BEGIN MALFORMED BLOCK-----
+       //    junk that may look like header lines
+       //   or data lines, but no END line
+       //
+       //    -----BEGIN ACTUAL BLOCK-----
+       //    realdata
+       //    -----END ACTUAL BLOCK-----
+       //
+       // we've failed to parse using the first BEGIN line
+       // and now will try again, using the second BEGIN line.
+       p, rest = Decode(rest)
+       if p == nil {
+               rest = data
+       }
+       return
+}
+
+const pemLineLength = 64
+
+type lineBreaker struct {
+       line [pemLineLength]byte
+       used int
+       out  io.Writer
+}
+
+func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
+       if l.used+len(b) < pemLineLength {
+               copy(l.line[l.used:], b)
+               l.used += len(b)
+               return len(b), nil
+       }
+
+       n, err = l.out.Write(l.line[0:l.used])
+       if err != nil {
+               return
+       }
+       excess := pemLineLength - l.used
+       l.used = 0
+
+       n, err = l.out.Write(b[0:excess])
+       if err != nil {
+               return
+       }
+
+       n, err = l.out.Write([]byte{'\n'})
+       if err != nil {
+               return
+       }
+
+       return l.Write(b[excess:])
+}
+
+func (l *lineBreaker) Close() (err os.Error) {
+       if l.used > 0 {
+               _, err = l.out.Write(l.line[0:l.used])
+               if err != nil {
+                       return
+               }
+               _, err = l.out.Write([]byte{'\n'})
+       }
+
+       return
+}
+
+func Encode(out io.Writer, b *Block) (err os.Error) {
+       _, err = out.Write(pemStart[1:])
+       if err != nil {
+               return
+       }
+       _, err = out.Write([]byte(b.Type + "-----\n"))
+       if err != nil {
+               return
+       }
+
+       if len(b.Headers) > 0 {
+               for k, v := range b.Headers {
+                       _, err = out.Write([]byte(k + ": " + v + "\n"))
+                       if err != nil {
+                               return
+                       }
+               }
+               _, err = out.Write([]byte{'\n'})
+               if err != nil {
+                       return
+               }
+       }
+
+       var breaker lineBreaker
+       breaker.out = out
+
+       b64 := base64.NewEncoder(base64.StdEncoding, &breaker)
+       _, err = b64.Write(b.Bytes)
+       if err != nil {
+               return
+       }
+       b64.Close()
+       breaker.Close()
+
+       _, err = out.Write(pemEnd[1:])
+       if err != nil {
+               return
+       }
+       _, err = out.Write([]byte(b.Type + "-----\n"))
+       return
+}
+
+func EncodeToMemory(b *Block) []byte {
+       buf := bytes.NewBuffer(nil)
+       Encode(buf, b)
+       return buf.Bytes()
+}
diff --git a/libgo/go/encoding/pem/pem_test.go b/libgo/go/encoding/pem/pem_test.go
new file mode 100644 (file)
index 0000000..11efe55
--- /dev/null
@@ -0,0 +1,390 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pem
+
+import (
+       "bytes"
+       "reflect"
+       "testing"
+)
+
+type GetLineTest struct {
+       in, out1, out2 string
+}
+
+var getLineTests = []GetLineTest{
+       {"abc", "abc", ""},
+       {"abc\r", "abc\r", ""},
+       {"abc\n", "abc", ""},
+       {"abc\r\n", "abc", ""},
+       {"abc\nd", "abc", "d"},
+       {"abc\r\nd", "abc", "d"},
+       {"\nabc", "", "abc"},
+       {"\r\nabc", "", "abc"},
+}
+
+func TestGetLine(t *testing.T) {
+       for i, test := range getLineTests {
+               x, y := getLine([]byte(test.in))
+               if string(x) != test.out1 || string(y) != test.out2 {
+                       t.Errorf("#%d got:%+v,%+v want:%s,%s", i, x, y, test.out1, test.out2)
+               }
+       }
+}
+
+func TestDecode(t *testing.T) {
+       result, remainder := Decode([]byte(pemData))
+       if !reflect.DeepEqual(result, certificate) {
+               t.Errorf("#0 got:%#v want:%#v", result, certificate)
+       }
+       result, remainder = Decode(remainder)
+       if !reflect.DeepEqual(result, privateKey) {
+               t.Errorf("#1 got:%#v want:%#v", result, privateKey)
+       }
+       result, _ = Decode([]byte(pemPrivateKey))
+       if !reflect.DeepEqual(result, privateKey2) {
+               t.Errorf("#2 got:%#v want:%#v", result, privateKey2)
+       }
+}
+
+func TestEncode(t *testing.T) {
+       r := EncodeToMemory(privateKey2)
+       if string(r) != pemPrivateKey {
+               t.Errorf("got:%s want:%s", r, pemPrivateKey)
+       }
+}
+
+type lineBreakerTest struct {
+       in, out string
+}
+
+const sixtyFourCharString = "0123456789012345678901234567890123456789012345678901234567890123"
+
+var lineBreakerTests = []lineBreakerTest{
+       {"", ""},
+       {"a", "a\n"},
+       {"ab", "ab\n"},
+       {sixtyFourCharString, sixtyFourCharString + "\n"},
+       {sixtyFourCharString + "X", sixtyFourCharString + "\nX\n"},
+       {sixtyFourCharString + sixtyFourCharString, sixtyFourCharString + "\n" + sixtyFourCharString + "\n"},
+}
+
+func TestLineBreaker(t *testing.T) {
+       for i, test := range lineBreakerTests {
+               buf := bytes.NewBuffer(nil)
+               var breaker lineBreaker
+               breaker.out = buf
+               _, err := breaker.Write([]byte(test.in))
+               if err != nil {
+                       t.Errorf("#%d: error from Write: %s", i, err)
+                       continue
+               }
+               err = breaker.Close()
+               if err != nil {
+                       t.Errorf("#%d: error from Close: %s", i, err)
+                       continue
+               }
+
+               if string(buf.Bytes()) != test.out {
+                       t.Errorf("#%d: got:%s want:%s", i, string(buf.Bytes()), test.out)
+               }
+       }
+
+       for i, test := range lineBreakerTests {
+               buf := bytes.NewBuffer(nil)
+               var breaker lineBreaker
+               breaker.out = buf
+
+               for i := 0; i < len(test.in); i++ {
+                       _, err := breaker.Write([]byte(test.in[i : i+1]))
+                       if err != nil {
+                               t.Errorf("#%d: error from Write (byte by byte): %s", i, err)
+                               continue
+                       }
+               }
+               err := breaker.Close()
+               if err != nil {
+                       t.Errorf("#%d: error from Close (byte by byte): %s", i, err)
+                       continue
+               }
+
+               if string(buf.Bytes()) != test.out {
+                       t.Errorf("#%d: (byte by byte) got:%s want:%s", i, string(buf.Bytes()), test.out)
+               }
+       }
+}
+
+var pemData = `verify return:0
+-----BEGIN CERTIFICATE-----
+sdlfkjskldfj
+  -----BEGIN CERTIFICATE-----
+---
+Certificate chain
+ 0 s:/C=AU/ST=Somewhere/L=Someplace/O=Foo Bar/CN=foo.example.com
+   i:/C=ZA/O=CA Inc./CN=CA Inc
+-----BEGIN CERTIFICATE-----
+testing
+-----BEGIN CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID6TCCA1ICAQEwDQYJKoZIhvcNAQEFBQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYD
+VQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQK
+EwtHb29nbGUgSW5jLjEMMAoGA1UECxMDRW5nMQwwCgYDVQQDEwNhZ2wxHTAbBgkq
+hkiG9w0BCQEWDmFnbEBnb29nbGUuY29tMB4XDTA5MDkwOTIyMDU0M1oXDTEwMDkw
+OTIyMDU0M1owajELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAf
+BgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEjMCEGA1UEAxMaZXVyb3Bh
+LnNmby5jb3JwLmdvb2dsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQC6pgYt7/EibBDumASF+S0qvqdL/f+nouJw2T1Qc8GmXF/iiUcrsgzh/Fd8
+pDhz/T96Qg9IyR4ztuc2MXrmPra+zAuSf5bevFReSqvpIt8Duv0HbDbcqs/XKPfB
+uMDe+of7a9GCywvAZ4ZUJcp0thqD9fKTTjUWOBzHY1uNE4RitrhmJCrbBGXbJ249
+bvgmb7jgdInH2PU7PT55hujvOoIsQW2osXBFRur4pF1wmVh4W4lTLD6pjfIMUcML
+ICHEXEN73PDic8KS3EtNYCwoIld+tpIBjE1QOb1KOyuJBNW6Esw9ALZn7stWdYcE
+qAwvv20egN2tEXqj7Q4/1ccyPZc3PQgC3FJ8Be2mtllM+80qf4dAaQ/fWvCtOrQ5
+pnfe9juQvCo8Y0VGlFcrSys/MzSg9LJ/24jZVgzQved/Qupsp89wVidwIzjt+WdS
+fyWfH0/v1aQLvu5cMYuW//C0W2nlYziL5blETntM8My2ybNARy3ICHxCBv2RNtPI
+WQVm+E9/W5rwh2IJR4DHn2LHwUVmT/hHNTdBLl5Uhwr4Wc7JhE7AVqb14pVNz1lr
+5jxsp//ncIwftb7mZQ3DF03Yna+jJhpzx8CQoeLT6aQCHyzmH68MrHHT4MALPyUs
+Pomjn71GNTtDeWAXibjCgdL6iHACCF6Htbl0zGlG0OAK+bdn0QIDAQABMA0GCSqG
+SIb3DQEBBQUAA4GBAOKnQDtqBV24vVqvesL5dnmyFpFPXBn3WdFfwD6DzEb21UVG
+5krmJiu+ViipORJPGMkgoL6BjU21XI95VQbun5P8vvg8Z+FnFsvRFY3e1CCzAVQY
+ZsUkLw2I7zI/dNlWdB8Xp7v+3w9sX5N3J/WuJ1KOO5m26kRlHQo7EzT3974g
+-----END CERTIFICATE-----
+ 1 s:/C=ZA/O=Ca Inc./CN=CA Inc
+
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,80C7C7A09690757A
+
+eQp5ZkH6CyHBz7BZfUPxyLCCmftsBJ7HlqGb8Ld21cSwnzWZ4/SIlhyrUtsfw7VR
+2TTwA+odo9ex7GdxOTaH8oZFumIRoiEjHsk8U7Bhntp+ekkPP79xunnN7hb7hkhr
+yGDQZgA7s2cQHQ71v3gwT2BACAft26jCjbM1wgNzBnJ8M0Rzn68YWqaPtdBu8qb/
+zVR5JB1mnqvTSbFsfF5yMc6o2WQ9jJCl6KypnMl+BpL+dlvdjYVK4l9lYsB1Hs3d
++zDBbWxos818zzhS8/y6eIfiSG27cqrbhURbmgiSfDXjncK4m/pLcQ7mmBL6mFOr
+3Pj4jepzgOiFRL6MKE//h62fZvI1ErYr8VunHEykgKNhChDvb1RO6LEfqKBu+Ivw
+TB6fBhW3TCLMnVPYVoYwA+fHNTmZZm8BEonlIMfI+KktjWUg4Oia+NI6vKcPpFox
+hSnlGgCtvfEaq5/H4kHJp95eOpnFsLviw2seHNkz/LxJMRP1X428+DpYW/QD/0JU
+tJSuC/q9FUHL6RI3u/Asrv8pCb4+D7i1jW/AMIdJTtycOGsbPxQA7yHMWujHmeb1
+BTiHcL3s3KrJu1vDVrshvxfnz71KTeNnZH8UbOqT5i7fPGyXtY1XJddcbI/Q6tXf
+wHFsZc20TzSdsVLBtwksUacpbDogcEVMctnNrB8FIrB3vZEv9Q0Z1VeY7nmTpF+6
+a+z2P7acL7j6A6Pr3+q8P9CPiPC7zFonVzuVPyB8GchGR2hytyiOVpuD9+k8hcuw
+ZWAaUoVtWIQ52aKS0p19G99hhb+IVANC4akkdHV4SP8i7MVNZhfUmg==
+-----END RSA PRIVATE KEY-----`
+
+var certificate = &Block{Type: "CERTIFICATE",
+       Headers: map[string]string{},
+       Bytes: []uint8{0x30, 0x82, 0x3, 0xe9, 0x30, 0x82, 0x3, 0x52, 0x2, 0x1,
+               0x1, 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd,
+               0x1, 0x1, 0x5, 0x5, 0x0, 0x30, 0x81, 0x8b, 0x31, 0xb, 0x30,
+               0x9, 0x6, 0x3, 0x55, 0x4, 0x6, 0x13, 0x2, 0x55, 0x53, 0x31,
+               0x13, 0x30, 0x11, 0x6, 0x3, 0x55, 0x4, 0x8, 0x13, 0xa, 0x43,
+               0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31,
+               0x16, 0x30, 0x14, 0x6, 0x3, 0x55, 0x4, 0x7, 0x13, 0xd, 0x53,
+               0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73,
+               0x63, 0x6f, 0x31, 0x14, 0x30, 0x12, 0x6, 0x3, 0x55, 0x4, 0xa,
+               0x13, 0xb, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49,
+               0x6e, 0x63, 0x2e, 0x31, 0xc, 0x30, 0xa, 0x6, 0x3, 0x55, 0x4,
+               0xb, 0x13, 0x3, 0x45, 0x6e, 0x67, 0x31, 0xc, 0x30, 0xa, 0x6,
+               0x3, 0x55, 0x4, 0x3, 0x13, 0x3, 0x61, 0x67, 0x6c, 0x31, 0x1d,
+               0x30, 0x1b, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1,
+               0x9, 0x1, 0x16, 0xe, 0x61, 0x67, 0x6c, 0x40, 0x67, 0x6f, 0x6f,
+               0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17,
+               0xd, 0x30, 0x39, 0x30, 0x39, 0x30, 0x39, 0x32, 0x32, 0x30,
+               0x35, 0x34, 0x33, 0x5a, 0x17, 0xd, 0x31, 0x30, 0x30, 0x39,
+               0x30, 0x39, 0x32, 0x32, 0x30, 0x35, 0x34, 0x33, 0x5a, 0x30,
+               0x6a, 0x31, 0xb, 0x30, 0x9, 0x6, 0x3, 0x55, 0x4, 0x6, 0x13,
+               0x2, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x6, 0x3, 0x55, 0x4,
+               0x8, 0x13, 0xa, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
+               0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x6, 0x3, 0x55, 0x4, 0xa,
+               0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
+               0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+               0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30, 0x21,
+               0x6, 0x3, 0x55, 0x4, 0x3, 0x13, 0x1a, 0x65, 0x75, 0x72, 0x6f,
+               0x70, 0x61, 0x2e, 0x73, 0x66, 0x6f, 0x2e, 0x63, 0x6f, 0x72,
+               0x70, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63,
+               0x6f, 0x6d, 0x30, 0x82, 0x2, 0x22, 0x30, 0xd, 0x6, 0x9, 0x2a,
+               0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0x1, 0x5, 0x0, 0x3,
+               0x82, 0x2, 0xf, 0x0, 0x30, 0x82, 0x2, 0xa, 0x2, 0x82, 0x2, 0x1,
+               0x0, 0xba, 0xa6, 0x6, 0x2d, 0xef, 0xf1, 0x22, 0x6c, 0x10, 0xee,
+               0x98, 0x4, 0x85, 0xf9, 0x2d, 0x2a, 0xbe, 0xa7, 0x4b, 0xfd,
+               0xff, 0xa7, 0xa2, 0xe2, 0x70, 0xd9, 0x3d, 0x50, 0x73, 0xc1,
+               0xa6, 0x5c, 0x5f, 0xe2, 0x89, 0x47, 0x2b, 0xb2, 0xc, 0xe1,
+               0xfc, 0x57, 0x7c, 0xa4, 0x38, 0x73, 0xfd, 0x3f, 0x7a, 0x42,
+               0xf, 0x48, 0xc9, 0x1e, 0x33, 0xb6, 0xe7, 0x36, 0x31, 0x7a,
+               0xe6, 0x3e, 0xb6, 0xbe, 0xcc, 0xb, 0x92, 0x7f, 0x96, 0xde,
+               0xbc, 0x54, 0x5e, 0x4a, 0xab, 0xe9, 0x22, 0xdf, 0x3, 0xba,
+               0xfd, 0x7, 0x6c, 0x36, 0xdc, 0xaa, 0xcf, 0xd7, 0x28, 0xf7,
+               0xc1, 0xb8, 0xc0, 0xde, 0xfa, 0x87, 0xfb, 0x6b, 0xd1, 0x82,
+               0xcb, 0xb, 0xc0, 0x67, 0x86, 0x54, 0x25, 0xca, 0x74, 0xb6,
+               0x1a, 0x83, 0xf5, 0xf2, 0x93, 0x4e, 0x35, 0x16, 0x38, 0x1c,
+               0xc7, 0x63, 0x5b, 0x8d, 0x13, 0x84, 0x62, 0xb6, 0xb8, 0x66,
+               0x24, 0x2a, 0xdb, 0x4, 0x65, 0xdb, 0x27, 0x6e, 0x3d, 0x6e,
+               0xf8, 0x26, 0x6f, 0xb8, 0xe0, 0x74, 0x89, 0xc7, 0xd8, 0xf5,
+               0x3b, 0x3d, 0x3e, 0x79, 0x86, 0xe8, 0xef, 0x3a, 0x82, 0x2c,
+               0x41, 0x6d, 0xa8, 0xb1, 0x70, 0x45, 0x46, 0xea, 0xf8, 0xa4,
+               0x5d, 0x70, 0x99, 0x58, 0x78, 0x5b, 0x89, 0x53, 0x2c, 0x3e,
+               0xa9, 0x8d, 0xf2, 0xc, 0x51, 0xc3, 0xb, 0x20, 0x21, 0xc4, 0x5c,
+               0x43, 0x7b, 0xdc, 0xf0, 0xe2, 0x73, 0xc2, 0x92, 0xdc, 0x4b,
+               0x4d, 0x60, 0x2c, 0x28, 0x22, 0x57, 0x7e, 0xb6, 0x92, 0x1,
+               0x8c, 0x4d, 0x50, 0x39, 0xbd, 0x4a, 0x3b, 0x2b, 0x89, 0x4,
+               0xd5, 0xba, 0x12, 0xcc, 0x3d, 0x0, 0xb6, 0x67, 0xee, 0xcb,
+               0x56, 0x75, 0x87, 0x4, 0xa8, 0xc, 0x2f, 0xbf, 0x6d, 0x1e, 0x80,
+               0xdd, 0xad, 0x11, 0x7a, 0xa3, 0xed, 0xe, 0x3f, 0xd5, 0xc7,
+               0x32, 0x3d, 0x97, 0x37, 0x3d, 0x8, 0x2, 0xdc, 0x52, 0x7c, 0x5,
+               0xed, 0xa6, 0xb6, 0x59, 0x4c, 0xfb, 0xcd, 0x2a, 0x7f, 0x87,
+               0x40, 0x69, 0xf, 0xdf, 0x5a, 0xf0, 0xad, 0x3a, 0xb4, 0x39,
+               0xa6, 0x77, 0xde, 0xf6, 0x3b, 0x90, 0xbc, 0x2a, 0x3c, 0x63,
+               0x45, 0x46, 0x94, 0x57, 0x2b, 0x4b, 0x2b, 0x3f, 0x33, 0x34,
+               0xa0, 0xf4, 0xb2, 0x7f, 0xdb, 0x88, 0xd9, 0x56, 0xc, 0xd0,
+               0xbd, 0xe7, 0x7f, 0x42, 0xea, 0x6c, 0xa7, 0xcf, 0x70, 0x56,
+               0x27, 0x70, 0x23, 0x38, 0xed, 0xf9, 0x67, 0x52, 0x7f, 0x25,
+               0x9f, 0x1f, 0x4f, 0xef, 0xd5, 0xa4, 0xb, 0xbe, 0xee, 0x5c,
+               0x31, 0x8b, 0x96, 0xff, 0xf0, 0xb4, 0x5b, 0x69, 0xe5, 0x63,
+               0x38, 0x8b, 0xe5, 0xb9, 0x44, 0x4e, 0x7b, 0x4c, 0xf0, 0xcc,
+               0xb6, 0xc9, 0xb3, 0x40, 0x47, 0x2d, 0xc8, 0x8, 0x7c, 0x42, 0x6,
+               0xfd, 0x91, 0x36, 0xd3, 0xc8, 0x59, 0x5, 0x66, 0xf8, 0x4f,
+               0x7f, 0x5b, 0x9a, 0xf0, 0x87, 0x62, 0x9, 0x47, 0x80, 0xc7,
+               0x9f, 0x62, 0xc7, 0xc1, 0x45, 0x66, 0x4f, 0xf8, 0x47, 0x35,
+               0x37, 0x41, 0x2e, 0x5e, 0x54, 0x87, 0xa, 0xf8, 0x59, 0xce,
+               0xc9, 0x84, 0x4e, 0xc0, 0x56, 0xa6, 0xf5, 0xe2, 0x95, 0x4d,
+               0xcf, 0x59, 0x6b, 0xe6, 0x3c, 0x6c, 0xa7, 0xff, 0xe7, 0x70,
+               0x8c, 0x1f, 0xb5, 0xbe, 0xe6, 0x65, 0xd, 0xc3, 0x17, 0x4d,
+               0xd8, 0x9d, 0xaf, 0xa3, 0x26, 0x1a, 0x73, 0xc7, 0xc0, 0x90,
+               0xa1, 0xe2, 0xd3, 0xe9, 0xa4, 0x2, 0x1f, 0x2c, 0xe6, 0x1f,
+               0xaf, 0xc, 0xac, 0x71, 0xd3, 0xe0, 0xc0, 0xb, 0x3f, 0x25, 0x2c,
+               0x3e, 0x89, 0xa3, 0x9f, 0xbd, 0x46, 0x35, 0x3b, 0x43, 0x79,
+               0x60, 0x17, 0x89, 0xb8, 0xc2, 0x81, 0xd2, 0xfa, 0x88, 0x70,
+               0x2, 0x8, 0x5e, 0x87, 0xb5, 0xb9, 0x74, 0xcc, 0x69, 0x46, 0xd0,
+               0xe0, 0xa, 0xf9, 0xb7, 0x67, 0xd1, 0x2, 0x3, 0x1, 0x0, 0x1,
+               0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1,
+               0x1, 0x5, 0x5, 0x0, 0x3, 0x81, 0x81, 0x0, 0xe2, 0xa7, 0x40,
+               0x3b, 0x6a, 0x5, 0x5d, 0xb8, 0xbd, 0x5a, 0xaf, 0x7a, 0xc2,
+               0xf9, 0x76, 0x79, 0xb2, 0x16, 0x91, 0x4f, 0x5c, 0x19, 0xf7,
+               0x59, 0xd1, 0x5f, 0xc0, 0x3e, 0x83, 0xcc, 0x46, 0xf6, 0xd5,
+               0x45, 0x46, 0xe6, 0x4a, 0xe6, 0x26, 0x2b, 0xbe, 0x56, 0x28,
+               0xa9, 0x39, 0x12, 0x4f, 0x18, 0xc9, 0x20, 0xa0, 0xbe, 0x81,
+               0x8d, 0x4d, 0xb5, 0x5c, 0x8f, 0x79, 0x55, 0x6, 0xee, 0x9f,
+               0x93, 0xfc, 0xbe, 0xf8, 0x3c, 0x67, 0xe1, 0x67, 0x16, 0xcb,
+               0xd1, 0x15, 0x8d, 0xde, 0xd4, 0x20, 0xb3, 0x1, 0x54, 0x18,
+               0x66, 0xc5, 0x24, 0x2f, 0xd, 0x88, 0xef, 0x32, 0x3f, 0x74,
+               0xd9, 0x56, 0x74, 0x1f, 0x17, 0xa7, 0xbb, 0xfe, 0xdf, 0xf,
+               0x6c, 0x5f, 0x93, 0x77, 0x27, 0xf5, 0xae, 0x27, 0x52, 0x8e,
+               0x3b, 0x99, 0xb6, 0xea, 0x44, 0x65, 0x1d, 0xa, 0x3b, 0x13,
+               0x34, 0xf7, 0xf7, 0xbe, 0x20,
+       },
+}
+
+var privateKey = &Block{Type: "RSA PRIVATE KEY",
+       Headers: map[string]string{"DEK-Info": "DES-EDE3-CBC,80C7C7A09690757A", "Proc-Type": "4,ENCRYPTED"},
+       Bytes: []uint8{0x79, 0xa, 0x79, 0x66, 0x41, 0xfa, 0xb,
+               0x21, 0xc1, 0xcf, 0xb0, 0x59, 0x7d, 0x43, 0xf1, 0xc8, 0xb0,
+               0x82, 0x99, 0xfb, 0x6c, 0x4, 0x9e, 0xc7, 0x96, 0xa1, 0x9b,
+               0xf0, 0xb7, 0x76, 0xd5, 0xc4, 0xb0, 0x9f, 0x35, 0x99, 0xe3,
+               0xf4, 0x88, 0x96, 0x1c, 0xab, 0x52, 0xdb, 0x1f, 0xc3, 0xb5,
+               0x51, 0xd9, 0x34, 0xf0, 0x3, 0xea, 0x1d, 0xa3, 0xd7, 0xb1,
+               0xec, 0x67, 0x71, 0x39, 0x36, 0x87, 0xf2, 0x86, 0x45, 0xba,
+               0x62, 0x11, 0xa2, 0x21, 0x23, 0x1e, 0xc9, 0x3c, 0x53, 0xb0,
+               0x61, 0x9e, 0xda, 0x7e, 0x7a, 0x49, 0xf, 0x3f, 0xbf, 0x71,
+               0xba, 0x79, 0xcd, 0xee, 0x16, 0xfb, 0x86, 0x48, 0x6b, 0xc8,
+               0x60, 0xd0, 0x66, 0x0, 0x3b, 0xb3, 0x67, 0x10, 0x1d, 0xe,
+               0xf5, 0xbf, 0x78, 0x30, 0x4f, 0x60, 0x40, 0x8, 0x7, 0xed,
+               0xdb, 0xa8, 0xc2, 0x8d, 0xb3, 0x35, 0xc2, 0x3, 0x73, 0x6,
+               0x72, 0x7c, 0x33, 0x44, 0x73, 0x9f, 0xaf, 0x18, 0x5a, 0xa6,
+               0x8f, 0xb5, 0xd0, 0x6e, 0xf2, 0xa6, 0xff, 0xcd, 0x54, 0x79,
+               0x24, 0x1d, 0x66, 0x9e, 0xab, 0xd3, 0x49, 0xb1, 0x6c, 0x7c,
+               0x5e, 0x72, 0x31, 0xce, 0xa8, 0xd9, 0x64, 0x3d, 0x8c, 0x90,
+               0xa5, 0xe8, 0xac, 0xa9, 0x9c, 0xc9, 0x7e, 0x6, 0x92, 0xfe,
+               0x76, 0x5b, 0xdd, 0x8d, 0x85, 0x4a, 0xe2, 0x5f, 0x65, 0x62,
+               0xc0, 0x75, 0x1e, 0xcd, 0xdd, 0xfb, 0x30, 0xc1, 0x6d, 0x6c,
+               0x68, 0xb3, 0xcd, 0x7c, 0xcf, 0x38, 0x52, 0xf3, 0xfc, 0xba,
+               0x78, 0x87, 0xe2, 0x48, 0x6d, 0xbb, 0x72, 0xaa, 0xdb, 0x85,
+               0x44, 0x5b, 0x9a, 0x8, 0x92, 0x7c, 0x35, 0xe3, 0x9d, 0xc2,
+               0xb8, 0x9b, 0xfa, 0x4b, 0x71, 0xe, 0xe6, 0x98, 0x12, 0xfa,
+               0x98, 0x53, 0xab, 0xdc, 0xf8, 0xf8, 0x8d, 0xea, 0x73, 0x80,
+               0xe8, 0x85, 0x44, 0xbe, 0x8c, 0x28, 0x4f, 0xff, 0x87, 0xad,
+               0x9f, 0x66, 0xf2, 0x35, 0x12, 0xb6, 0x2b, 0xf1, 0x5b, 0xa7,
+               0x1c, 0x4c, 0xa4, 0x80, 0xa3, 0x61, 0xa, 0x10, 0xef, 0x6f,
+               0x54, 0x4e, 0xe8, 0xb1, 0x1f, 0xa8, 0xa0, 0x6e, 0xf8, 0x8b,
+               0xf0, 0x4c, 0x1e, 0x9f, 0x6, 0x15, 0xb7, 0x4c, 0x22, 0xcc,
+               0x9d, 0x53, 0xd8, 0x56, 0x86, 0x30, 0x3, 0xe7, 0xc7, 0x35,
+               0x39, 0x99, 0x66, 0x6f, 0x1, 0x12, 0x89, 0xe5, 0x20, 0xc7,
+               0xc8, 0xf8, 0xa9, 0x2d, 0x8d, 0x65, 0x20, 0xe0, 0xe8, 0x9a,
+               0xf8, 0xd2, 0x3a, 0xbc, 0xa7, 0xf, 0xa4, 0x5a, 0x31, 0x85,
+               0x29, 0xe5, 0x1a, 0x0, 0xad, 0xbd, 0xf1, 0x1a, 0xab, 0x9f,
+               0xc7, 0xe2, 0x41, 0xc9, 0xa7, 0xde, 0x5e, 0x3a, 0x99, 0xc5,
+               0xb0, 0xbb, 0xe2, 0xc3, 0x6b, 0x1e, 0x1c, 0xd9, 0x33, 0xfc,
+               0xbc, 0x49, 0x31, 0x13, 0xf5, 0x5f, 0x8d, 0xbc, 0xf8, 0x3a,
+               0x58, 0x5b, 0xf4, 0x3, 0xff, 0x42, 0x54, 0xb4, 0x94, 0xae,
+               0xb, 0xfa, 0xbd, 0x15, 0x41, 0xcb, 0xe9, 0x12, 0x37, 0xbb,
+               0xf0, 0x2c, 0xae, 0xff, 0x29, 0x9, 0xbe, 0x3e, 0xf, 0xb8,
+               0xb5, 0x8d, 0x6f, 0xc0, 0x30, 0x87, 0x49, 0x4e, 0xdc, 0x9c,
+               0x38, 0x6b, 0x1b, 0x3f, 0x14, 0x0, 0xef, 0x21, 0xcc, 0x5a,
+               0xe8, 0xc7, 0x99, 0xe6, 0xf5, 0x5, 0x38, 0x87, 0x70, 0xbd,
+               0xec, 0xdc, 0xaa, 0xc9, 0xbb, 0x5b, 0xc3, 0x56, 0xbb, 0x21,
+               0xbf, 0x17, 0xe7, 0xcf, 0xbd, 0x4a, 0x4d, 0xe3, 0x67, 0x64,
+               0x7f, 0x14, 0x6c, 0xea, 0x93, 0xe6, 0x2e, 0xdf, 0x3c, 0x6c,
+               0x97, 0xb5, 0x8d, 0x57, 0x25, 0xd7, 0x5c, 0x6c, 0x8f, 0xd0,
+               0xea, 0xd5, 0xdf, 0xc0, 0x71, 0x6c, 0x65, 0xcd, 0xb4, 0x4f,
+               0x34, 0x9d, 0xb1, 0x52, 0xc1, 0xb7, 0x9, 0x2c, 0x51, 0xa7,
+               0x29, 0x6c, 0x3a, 0x20, 0x70, 0x45, 0x4c, 0x72, 0xd9, 0xcd,
+               0xac, 0x1f, 0x5, 0x22, 0xb0, 0x77, 0xbd, 0x91, 0x2f, 0xf5,
+               0xd, 0x19, 0xd5, 0x57, 0x98, 0xee, 0x79, 0x93, 0xa4, 0x5f,
+               0xba, 0x6b, 0xec, 0xf6, 0x3f, 0xb6, 0x9c, 0x2f, 0xb8, 0xfa,
+               0x3, 0xa3, 0xeb, 0xdf, 0xea, 0xbc, 0x3f, 0xd0, 0x8f, 0x88,
+               0xf0, 0xbb, 0xcc, 0x5a, 0x27, 0x57, 0x3b, 0x95, 0x3f, 0x20,
+               0x7c, 0x19, 0xc8, 0x46, 0x47, 0x68, 0x72, 0xb7, 0x28, 0x8e,
+               0x56, 0x9b, 0x83, 0xf7, 0xe9, 0x3c, 0x85, 0xcb, 0xb0, 0x65,
+               0x60, 0x1a, 0x52, 0x85, 0x6d, 0x58, 0x84, 0x39, 0xd9, 0xa2,
+               0x92, 0xd2, 0x9d, 0x7d, 0x1b, 0xdf, 0x61, 0x85, 0xbf, 0x88,
+               0x54, 0x3, 0x42, 0xe1, 0xa9, 0x24, 0x74, 0x75, 0x78, 0x48,
+               0xff, 0x22, 0xec, 0xc5, 0x4d, 0x66, 0x17, 0xd4, 0x9a,
+       },
+}
+
+var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
+       Headers: map[string]string{},
+       Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
+               0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
+               0xd4, 0x0, 0xae, 0x6a, 0x4d, 0x1b, 0x8a, 0x3b, 0x6a, 0x13,
+               0x64, 0x2b, 0x23, 0xf2, 0x8b, 0x0, 0x3b, 0xfb, 0x97, 0x79,
+               0xa, 0xde, 0x9a, 0x4c, 0xc8, 0x2b, 0x8b, 0x2a, 0x81, 0x74,
+               0x7d, 0xde, 0xc0, 0x8b, 0x62, 0x96, 0xe5, 0x3a, 0x8, 0xc3,
+               0x31, 0x68, 0x7e, 0xf2, 0x5c, 0x4b, 0xf4, 0x93, 0x6b, 0xa1,
+               0xc0, 0xe6, 0x4, 0x1e, 0x9d, 0x15, 0x2, 0x3, 0x1, 0x0, 0x1,
+               0x2, 0x41, 0x0, 0x8a, 0xbd, 0x6a, 0x69, 0xf4, 0xd1, 0xa4,
+               0xb4, 0x87, 0xf0, 0xab, 0x8d, 0x7a, 0xae, 0xfd, 0x38, 0x60,
+               0x94, 0x5, 0xc9, 0x99, 0x98, 0x4e, 0x30, 0xf5, 0x67, 0xe1,
+               0xe8, 0xae, 0xef, 0xf4, 0x4e, 0x8b, 0x18, 0xbd, 0xb1, 0xec,
+               0x78, 0xdf, 0xa3, 0x1a, 0x55, 0xe3, 0x2a, 0x48, 0xd7, 0xfb,
+               0x13, 0x1f, 0x5a, 0xf1, 0xf4, 0x4d, 0x7d, 0x6b, 0x2c, 0xed,
+               0x2a, 0x9d, 0xf5, 0xe5, 0xae, 0x45, 0x35, 0x2, 0x21, 0x0,
+               0xda, 0xb2, 0xf1, 0x80, 0x48, 0xba, 0xa6, 0x8d, 0xe7, 0xdf,
+               0x4, 0xd2, 0xd3, 0x5d, 0x5d, 0x80, 0xe6, 0xe, 0x2d, 0xfa,
+               0x42, 0xd5, 0xa, 0x9b, 0x4, 0x21, 0x90, 0x32, 0x71, 0x5e,
+               0x46, 0xb3, 0x2, 0x21, 0x0, 0xd1, 0xf, 0x2e, 0x66, 0xb1,
+               0xd0, 0xc1, 0x3f, 0x10, 0xef, 0x99, 0x27, 0xbf, 0x53, 0x24,
+               0xa3, 0x79, 0xca, 0x21, 0x81, 0x46, 0xcb, 0xf9, 0xca, 0xfc,
+               0x79, 0x52, 0x21, 0xf1, 0x6a, 0x31, 0x17, 0x2, 0x20, 0x21,
+               0x2, 0x89, 0x79, 0x37, 0x81, 0x14, 0xca, 0xae, 0x88, 0xf7,
+               0xd, 0x6b, 0x61, 0xd8, 0x4f, 0x30, 0x6a, 0x4b, 0x7e, 0x4e,
+               0xc0, 0x21, 0x4d, 0xac, 0x9d, 0xf4, 0x49, 0xe8, 0xda, 0xb6,
+               0x9, 0x2, 0x20, 0x16, 0xb3, 0xec, 0x59, 0x10, 0xa4, 0x57,
+               0xe8, 0xe, 0x61, 0xc6, 0xa3, 0xf, 0x5e, 0xeb, 0x12, 0xa9,
+               0xae, 0x2e, 0xb7, 0x48, 0x45, 0xec, 0x69, 0x83, 0xc3, 0x75,
+               0xc, 0xe4, 0x97, 0xa0, 0x9f, 0x2, 0x20, 0x69, 0x52, 0xb4,
+               0x6, 0xe8, 0x50, 0x60, 0x71, 0x4c, 0x3a, 0xb7, 0x66, 0xba,
+               0xd, 0x8a, 0xc9, 0xb7, 0xd, 0xa3, 0x8, 0x6c, 0xa3, 0xf2,
+               0x62, 0xb0, 0x2a, 0x84, 0xaa, 0x2f, 0xd6, 0x1e, 0x55,
+       },
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA PRIVATE KEY-----
+`
diff --git a/libgo/go/exec/exec.go b/libgo/go/exec/exec.go
new file mode 100644 (file)
index 0000000..ba9bd24
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The exec package runs external commands.
+package exec
+
+import (
+       "os"
+)
+
+// Arguments to Run.
+const (
+       DevNull = iota
+       PassThrough
+       Pipe
+       MergeWithStdout
+)
+
+// A Cmd represents a running command.
+// Stdin, Stdout, and Stderr are Files representing pipes
+// connected to the running command's standard input, output, and error,
+// or else nil, depending on the arguments to Run.
+// Pid is the running command's operating system process ID.
+type Cmd struct {
+       Stdin  *os.File
+       Stdout *os.File
+       Stderr *os.File
+       Pid    int
+}
+
+// Given mode (DevNull, etc), return file for child
+// and file to record in Cmd structure.
+func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
+       switch mode {
+       case DevNull:
+               rw := os.O_WRONLY
+               if fd == 0 {
+                       rw = os.O_RDONLY
+               }
+               f, err := os.Open(os.DevNull, rw, 0)
+               return f, nil, err
+       case PassThrough:
+               switch fd {
+               case 0:
+                       return os.Stdin, nil, nil
+               case 1:
+                       return os.Stdout, nil, nil
+               case 2:
+                       return os.Stderr, nil, nil
+               }
+       case Pipe:
+               r, w, err := os.Pipe()
+               if err != nil {
+                       return nil, nil, err
+               }
+               if fd == 0 {
+                       return r, w, nil
+               }
+               return w, r, nil
+       }
+       return nil, nil, os.EINVAL
+}
+
+// Run starts the named binary running with
+// arguments argv and environment envv.
+// It returns a pointer to a new Cmd representing
+// the command or an error.
+//
+// The parameters stdin, stdout, and stderr
+// specify how to handle standard input, output, and error.
+// The choices are DevNull (connect to /dev/null),
+// PassThrough (connect to the current process's standard stream),
+// Pipe (connect to an operating system pipe), and
+// MergeWithStdout (only for standard error; use the same
+// file descriptor as was used for standard output).
+// If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
+// of the returned Cmd is the other end of the pipe.
+// Otherwise the field in Cmd is nil.
+func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
+       p = new(Cmd)
+       var fd [3]*os.File
+
+       if fd[0], p.Stdin, err = modeToFiles(stdin, 0); err != nil {
+               goto Error
+       }
+       if fd[1], p.Stdout, err = modeToFiles(stdout, 1); err != nil {
+               goto Error
+       }
+       if stderr == MergeWithStdout {
+               fd[2] = fd[1]
+       } else if fd[2], p.Stderr, err = modeToFiles(stderr, 2); err != nil {
+               goto Error
+       }
+
+       // Run command.
+       p.Pid, err = os.ForkExec(name, argv, envv, dir, fd[0:])
+       if err != nil {
+               goto Error
+       }
+       if fd[0] != os.Stdin {
+               fd[0].Close()
+       }
+       if fd[1] != os.Stdout {
+               fd[1].Close()
+       }
+       if fd[2] != os.Stderr && fd[2] != fd[1] {
+               fd[2].Close()
+       }
+       return p, nil
+
+Error:
+       if fd[0] != os.Stdin && fd[0] != nil {
+               fd[0].Close()
+       }
+       if fd[1] != os.Stdout && fd[1] != nil {
+               fd[1].Close()
+       }
+       if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] {
+               fd[2].Close()
+       }
+       if p.Stdin != nil {
+               p.Stdin.Close()
+       }
+       if p.Stdout != nil {
+               p.Stdout.Close()
+       }
+       if p.Stderr != nil {
+               p.Stderr.Close()
+       }
+       return nil, err
+}
+
+// Wait waits for the running command p,
+// returning the Waitmsg returned by os.Wait and an error.
+// The options are passed through to os.Wait.
+// Setting options to 0 waits for p to exit;
+// other options cause Wait to return for other
+// process events; see package os for details.
+func (p *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
+       if p.Pid <= 0 {
+               return nil, os.ErrorString("exec: invalid use of Cmd.Wait")
+       }
+       w, err := os.Wait(p.Pid, options)
+       if w != nil && (w.Exited() || w.Signaled()) {
+               p.Pid = -1
+       }
+       return w, err
+}
+
+// Close waits for the running command p to exit,
+// if it hasn't already, and then closes the non-nil file descriptors
+// p.Stdin, p.Stdout, and p.Stderr.
+func (p *Cmd) Close() os.Error {
+       if p.Pid > 0 {
+               // Loop on interrupt, but
+               // ignore other errors -- maybe
+               // caller has already waited for pid.
+               _, err := p.Wait(0)
+               for err == os.EINTR {
+                       _, err = p.Wait(0)
+               }
+       }
+
+       // Close the FDs that are still open.
+       var err os.Error
+       if p.Stdin != nil && p.Stdin.Fd() >= 0 {
+               if err1 := p.Stdin.Close(); err1 != nil {
+                       err = err1
+               }
+       }
+       if p.Stdout != nil && p.Stdout.Fd() >= 0 {
+               if err1 := p.Stdout.Close(); err1 != nil && err != nil {
+                       err = err1
+               }
+       }
+       if p.Stderr != nil && p.Stderr != p.Stdout && p.Stderr.Fd() >= 0 {
+               if err1 := p.Stderr.Close(); err1 != nil && err != nil {
+                       err = err1
+               }
+       }
+       return err
+}
diff --git a/libgo/go/exec/exec_test.go b/libgo/go/exec/exec_test.go
new file mode 100644 (file)
index 0000000..04f72cf
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+       "io"
+       "io/ioutil"
+       "testing"
+       "os"
+)
+
+func TestRunCat(t *testing.T) {
+       cat, err := LookPath("cat")
+       if err != nil {
+               t.Fatal("cat: ", err)
+       }
+       cmd, err := Run(cat, []string{"cat"}, nil, "",
+               Pipe, Pipe, DevNull)
+       if err != nil {
+               t.Fatal("run:", err)
+       }
+       io.WriteString(cmd.Stdin, "hello, world\n")
+       cmd.Stdin.Close()
+       buf, err := ioutil.ReadAll(cmd.Stdout)
+       if err != nil {
+               t.Fatal("read:", err)
+       }
+       if string(buf) != "hello, world\n" {
+               t.Fatalf("read: got %q", buf)
+       }
+       if err = cmd.Close(); err != nil {
+               t.Fatal("close:", err)
+       }
+}
+
+func TestRunEcho(t *testing.T) {
+       echo, err := LookPath("echo")
+       if err != nil {
+               t.Fatal("echo: ", err)
+       }
+       cmd, err := Run(echo, []string{"echo", "hello", "world"}, nil, "",
+               DevNull, Pipe, DevNull)
+       if err != nil {
+               t.Fatal("run:", err)
+       }
+       buf, err := ioutil.ReadAll(cmd.Stdout)
+       if err != nil {
+               t.Fatal("read:", err)
+       }
+       if string(buf) != "hello world\n" {
+               t.Fatalf("read: got %q", buf)
+       }
+       if err = cmd.Close(); err != nil {
+               t.Fatal("close:", err)
+       }
+}
+
+func TestStderr(t *testing.T) {
+       sh, err := LookPath("sh")
+       if err != nil {
+               t.Fatal("sh: ", err)
+       }
+       cmd, err := Run(sh, []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
+               DevNull, DevNull, Pipe)
+       if err != nil {
+               t.Fatal("run:", err)
+       }
+       buf, err := ioutil.ReadAll(cmd.Stderr)
+       if err != nil {
+               t.Fatal("read:", err)
+       }
+       if string(buf) != "hello world\n" {
+               t.Fatalf("read: got %q", buf)
+       }
+       if err = cmd.Close(); err != nil {
+               t.Fatal("close:", err)
+       }
+}
+
+func TestMergeWithStdout(t *testing.T) {
+       sh, err := LookPath("sh")
+       if err != nil {
+               t.Fatal("sh: ", err)
+       }
+       cmd, err := Run(sh, []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
+               DevNull, Pipe, MergeWithStdout)
+       if err != nil {
+               t.Fatal("run:", err)
+       }
+       buf, err := ioutil.ReadAll(cmd.Stdout)
+       if err != nil {
+               t.Fatal("read:", err)
+       }
+       if string(buf) != "hello world\n" {
+               t.Fatalf("read: got %q", buf)
+       }
+       if err = cmd.Close(); err != nil {
+               t.Fatal("close:", err)
+       }
+}
+
+func TestAddEnvVar(t *testing.T) {
+       err := os.Setenv("NEWVAR", "hello world")
+       if err != nil {
+               t.Fatal("setenv:", err)
+       }
+       sh, err := LookPath("sh")
+       if err != nil {
+               t.Fatal("sh: ", err)
+       }
+       cmd, err := Run(sh, []string{"sh", "-c", "echo $NEWVAR"}, nil, "",
+               DevNull, Pipe, DevNull)
+       if err != nil {
+               t.Fatal("run:", err)
+       }
+       buf, err := ioutil.ReadAll(cmd.Stdout)
+       if err != nil {
+               t.Fatal("read:", err)
+       }
+       if string(buf) != "hello world\n" {
+               t.Fatalf("read: got %q", buf)
+       }
+       if err = cmd.Close(); err != nil {
+               t.Fatal("close:", err)
+       }
+}
diff --git a/libgo/go/exec/lp_unix.go b/libgo/go/exec/lp_unix.go
new file mode 100644 (file)
index 0000000..b2feecd
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+       "os"
+       "strings"
+)
+
+func canExec(file string) bool {
+       d, err := os.Stat(file)
+       if err != nil {
+               return false
+       }
+       return d.IsRegular() && d.Permission()&0111 != 0
+}
+
+// LookPath searches for an executable binary named file
+// in the directories named by the PATH environment variable.
+// If file contains a slash, it is tried directly and the PATH is not consulted.
+func LookPath(file string) (string, os.Error) {
+       // NOTE(rsc): I wish we could use the Plan 9 behavior here
+       // (only bypass the path if file begins with / or ./ or ../)
+       // but that would not match all the Unix shells.
+
+       if strings.Contains(file, "/") {
+               if canExec(file) {
+                       return file, nil
+               }
+               return "", os.ENOENT
+       }
+       pathenv := os.Getenv("PATH")
+       for _, dir := range strings.Split(pathenv, ":", -1) {
+               if dir == "" {
+                       // Unix shell semantics: path element "" means "."
+                       dir = "."
+               }
+               if canExec(dir + "/" + file) {
+                       return dir + "/" + file, nil
+               }
+       }
+       return "", os.ENOENT
+}
diff --git a/libgo/go/exec/lp_windows.go b/libgo/go/exec/lp_windows.go
new file mode 100644 (file)
index 0000000..9d5dc1a
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+       "os"
+       "strings"
+)
+
+func chkStat(file string) bool {
+       d, err := os.Stat(file)
+       if err != nil {
+               return false
+       }
+       return d.IsRegular()
+}
+
+func canExec(file string, exts []string) (string, bool) {
+       if len(exts) == 0 {
+               return file, chkStat(file)
+       }
+       f := strings.ToLower(file)
+       for _, e := range exts {
+               if strings.HasSuffix(f, e) {
+                       return file, chkStat(file)
+               }
+       }
+       for _, e := range exts {
+               if f := file + e; chkStat(f) {
+                       return f, true
+               }
+       }
+       return ``, false
+}
+
+func LookPath(file string) (string, os.Error) {
+       exts := []string{}
+       if x := os.Getenv(`PATHEXT`); x != `` {
+               exts = strings.Split(strings.ToLower(x), `;`, -1)
+               for i, e := range exts {
+                       if e == `` || e[0] != '.' {
+                               exts[i] = `.` + e
+                       }
+               }
+       }
+       if strings.Contains(file, `\`) || strings.Contains(file, `/`) {
+               if f, ok := canExec(file, exts); ok {
+                       return f, nil
+               }
+               return ``, os.ENOENT
+       }
+       if pathenv := os.Getenv(`PATH`); pathenv == `` {
+               if f, ok := canExec(`.\`+file, exts); ok {
+                       return f, nil
+               }
+       } else {
+               for _, dir := range strings.Split(pathenv, `;`, -1) {
+                       if f, ok := canExec(dir+`\`+file, exts); ok {
+                               return f, nil
+                       }
+               }
+       }
+       return ``, os.ENOENT
+}
diff --git a/libgo/go/exp/4s/4s.go b/libgo/go/exp/4s/4s.go
new file mode 100644 (file)
index 0000000..ccc0d00
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a simple demo of Go running under Native Client.
+// It is a tetris clone built on top of the exp/nacl/av and exp/draw
+// packages.
+//
+// See ../nacl/README for how to run it.
+package main
+
+import (
+       "exp/nacl/av"
+       "exp/nacl/srpc"
+       "log"
+       "runtime"
+       "os"
+)
+
+var sndc chan []uint16
+
+func main() {
+       // Native Client requires that some calls are issued
+       // consistently by the same OS thread.
+       runtime.LockOSThread()
+
+       if srpc.Enabled() {
+               go srpc.ServeRuntime()
+       }
+
+       args := os.Args
+       p := pieces4
+       if len(args) > 1 && args[1] == "-5" {
+               p = pieces5
+       }
+       dx, dy := 500, 500
+       w, err := av.Init(av.SubsystemVideo|av.SubsystemAudio, dx, dy)
+       if err != nil {
+               log.Exit(err)
+       }
+
+       sndc = make(chan []uint16, 10)
+       go audioServer()
+       Play(p, w)
+}
+
+func audioServer() {
+       // Native Client requires that all audio calls
+       // original from a single OS thread.
+       runtime.LockOSThread()
+
+       n, err := av.AudioStream(nil)
+       if err != nil {
+               log.Exit(err)
+       }
+       for {
+               b := <-sndc
+               for len(b)*2 >= n {
+                       var a []uint16
+                       a, b = b[0:n/2], b[n/2:]
+                       n, err = av.AudioStream(a)
+                       if err != nil {
+                               log.Exit(err)
+                       }
+                       println(n, len(b)*2)
+               }
+               a := make([]uint16, n/2)
+               copy(a, b)
+               n, err = av.AudioStream(a)
+       }
+}
+
+func PlaySound(b []uint16) { sndc <- b }
+
+var whoosh = []uint16{
+// Insert your favorite sound samples here.
+}
diff --git a/libgo/go/exp/4s/5s.go b/libgo/go/exp/4s/5s.go
new file mode 100644 (file)
index 0000000..efeb6f1
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Hack to produce a binary that defaults to 5s.
+
+package main
+
+func init() { pieces4 = pieces5 }
diff --git a/libgo/go/exp/4s/data.go b/libgo/go/exp/4s/data.go
new file mode 100644 (file)
index 0000000..9e2a045
--- /dev/null
@@ -0,0 +1,142 @@
+// games/4s - a tetris clone
+//
+// Derived from Plan 9's /sys/src/games/xs.c
+// http://plan9.bell-labs.com/sources/plan9/sys/src/games/xs.c
+//
+// Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
+// Portions Copyright 2009 The Go Authors.  All Rights Reserved.
+// Distributed under the terms of the Lucent Public License Version 1.02
+// See http://plan9.bell-labs.com/plan9/license.html
+
+package main
+
+import . "image"
+
+var pieces4 = []Piece{
+       {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+       {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+       {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+
+       {0, 3, Point{2, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, nil, nil},
+       {1, 3, Point{2, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, nil, nil},
+       {2, 3, Point{2, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, nil, nil},
+       {3, 3, Point{2, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, nil, nil},
+
+       {0, 1, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
+       {1, 1, Point{2, 3}, []Point{{1, 0}, {0, 1}, {0, 1}, {-1, 0}}, nil, nil},
+       {2, 1, Point{3, 2}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 1, Point{2, 3}, []Point{{0, 0}, {1, 0}, {-1, 1}, {0, 1}}, nil, nil},
+
+       {0, 2, Point{3, 2}, []Point{{0, 1}, {1, 0}, {1, 0}, {0, -1}}, nil, nil},
+       {1, 2, Point{2, 3}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, 0}}, nil, nil},
+       {2, 2, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
+       {3, 2, Point{2, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {0, 1}}, nil, nil},
+
+       {0, 4, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
+       {1, 4, Point{2, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {0, 1}}, nil, nil},
+       {2, 4, Point{3, 2}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 4, Point{2, 3}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, -1}}, nil, nil},
+
+       {0, 5, Point{3, 2}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
+       {1, 5, Point{2, 3}, []Point{{1, 0}, {0, 1}, {-1, 0}, {0, 1}}, nil, nil},
+       {2, 5, Point{3, 2}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
+       {3, 5, Point{2, 3}, []Point{{1, 0}, {0, 1}, {-1, 0}, {0, 1}}, nil, nil},
+
+       {0, 6, Point{3, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {1, 0}}, nil, nil},
+       {1, 6, Point{2, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {0, 1}}, nil, nil},
+       {2, 6, Point{3, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {1, 0}}, nil, nil},
+       {3, 6, Point{2, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {0, 1}}, nil, nil},
+}
+
+var pieces5 = []Piece{
+       {0, 1, Point{5, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+       {1, 1, Point{1, 5}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+       {2, 1, Point{5, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 1, Point{1, 5}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+
+       {0, 0, Point{4, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
+       {1, 0, Point{2, 4}, []Point{{1, 0}, {0, 1}, {0, 1}, {0, 1}, {-1, 0}}, nil, nil},
+       {2, 0, Point{4, 2}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 0, Point{2, 4}, []Point{{0, 0}, {1, 0}, {-1, 1}, {0, 1}, {0, 1}}, nil, nil},
+
+       {0, 2, Point{4, 2}, []Point{{0, 0}, {0, 1}, {1, -1}, {1, 0}, {1, 0}}, nil, nil},
+       {1, 2, Point{2, 4}, []Point{{0, 0}, {1, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+       {2, 2, Point{4, 2}, []Point{{0, 1}, {1, 0}, {1, 0}, {1, 0}, {0, -1}}, nil, nil},
+       {3, 2, Point{2, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}, {1, 0}}, nil, nil},
+
+       {0, 7, Point{3, 3}, []Point{{0, 0}, {1, 0}, {1, 0}, {0, 1}, {0, 1}}, nil, nil},
+       {1, 7, Point{3, 3}, []Point{{0, 2}, {1, 0}, {1, 0}, {0, -1}, {0, -1}}, nil, nil},
+       {2, 7, Point{3, 3}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 7, Point{3, 3}, []Point{{0, 2}, {0, -1}, {0, -1}, {1, 0}, {1, 0}}, nil, nil},
+
+       {0, 3, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-2, 1}, {1, 0}}, nil, nil},
+       {1, 3, Point{2, 3}, []Point{{0, 0}, {1, 0}, {-1, 1}, {1, 0}, {0, 1}}, nil, nil},
+       {2, 3, Point{3, 2}, []Point{{1, 0}, {1, 0}, {-2, 1}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 3, Point{2, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {-1, 1}, {1, 0}}, nil, nil},
+
+       {0, 4, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-1, 1}, {1, 0}}, nil, nil},
+       {1, 4, Point{2, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {-1, 1}, {1, 0}}, nil, nil},
+       {2, 4, Point{3, 2}, []Point{{0, 0}, {1, 0}, {-1, 1}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 4, Point{2, 3}, []Point{{0, 0}, {1, 0}, {-1, 1}, {1, 0}, {-1, 1}}, nil, nil},
+
+       {0, 7, Point{3, 2}, []Point{{0, 0}, {2, 0}, {-2, 1}, {1, 0}, {1, 0}}, nil, nil},
+       {1, 7, Point{2, 3}, []Point{{0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 0}}, nil, nil},
+       {2, 7, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-2, 1}, {2, 0}}, nil, nil},
+       {3, 7, Point{2, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {-1, 1}, {1, 0}}, nil, nil},
+
+       {0, 5, Point{3, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}, {-1, 1}}, nil, nil},
+       {1, 5, Point{3, 3}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
+       {2, 5, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
+       {3, 5, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
+
+       {0, 6, Point{3, 3}, []Point{{1, 0}, {1, 0}, {-2, 1}, {1, 0}, {0, 1}}, nil, nil},
+       {1, 6, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
+       {2, 6, Point{3, 3}, []Point{{1, 0}, {0, 1}, {1, 0}, {-2, 1}, {1, 0}}, nil, nil},
+       {3, 6, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
+
+       {0, 0, Point{4, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
+       {1, 0, Point{2, 4}, []Point{{1, 0}, {-1, 1}, {1, 0}, {0, 1}, {0, 1}}, nil, nil},
+       {2, 0, Point{4, 2}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 0, Point{2, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, 0}, {-1, 1}}, nil, nil},
+
+       {0, 2, Point{4, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
+       {1, 2, Point{2, 4}, []Point{{1, 0}, {0, 1}, {-1, 1}, {1, 0}, {0, 1}}, nil, nil},
+       {2, 2, Point{4, 2}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 2, Point{2, 4}, []Point{{0, 0}, {0, 1}, {1, 0}, {-1, 1}, {0, 1}}, nil, nil},
+
+       {0, 1, Point{3, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}, {0, 1}}, nil, nil},
+       {1, 1, Point{3, 3}, []Point{{2, 0}, {-1, 1}, {1, 0}, {-2, 1}, {1, 0}}, nil, nil},
+       {2, 1, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
+       {3, 1, Point{3, 3}, []Point{{1, 0}, {1, 0}, {-2, 1}, {1, 0}, {-1, 1}}, nil, nil},
+
+       {0, 3, Point{3, 3}, []Point{{0, 0}, {1, 0}, {1, 0}, {-1, 1}, {0, 1}}, nil, nil},
+       {1, 3, Point{3, 3}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
+       {2, 3, Point{3, 3}, []Point{{1, 0}, {0, 1}, {-1, 1}, {1, 0}, {1, 0}}, nil, nil},
+       {3, 3, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
+
+       {0, 4, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
+       {1, 4, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
+       {2, 4, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
+       {3, 4, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
+
+       {0, 8, Point{4, 2}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}, {1, 0}}, nil, nil},
+       {1, 8, Point{2, 4}, []Point{{1, 0}, {-1, 1}, {1, 0}, {-1, 1}, {0, 1}}, nil, nil},
+       {2, 8, Point{4, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
+       {3, 8, Point{2, 4}, []Point{{1, 0}, {0, 1}, {-1, 1}, {1, 0}, {-1, 1}}, nil, nil},
+
+       {0, 9, Point{4, 2}, []Point{{2, 0}, {1, 0}, {-3, 1}, {1, 0}, {1, 0}}, nil, nil},
+       {1, 9, Point{2, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, 0}, {0, 1}}, nil, nil},
+       {2, 9, Point{4, 2}, []Point{{1, 0}, {1, 0}, {1, 0}, {-3, 1}, {1, 0}}, nil, nil},
+       {3, 9, Point{2, 4}, []Point{{0, 0}, {0, 1}, {1, 0}, {0, 1}, {0, 1}}, nil, nil},
+
+       {0, 5, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
+       {1, 5, Point{3, 3}, []Point{{1, 0}, {1, 0}, {-1, 1}, {-1, 1}, {1, 0}}, nil, nil},
+       {2, 5, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
+       {3, 5, Point{3, 3}, []Point{{1, 0}, {1, 0}, {-1, 1}, {-1, 1}, {1, 0}}, nil, nil},
+
+       {0, 6, Point{3, 3}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
+       {1, 6, Point{3, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {0, 1}, {1, 0}}, nil, nil},
+       {2, 6, Point{3, 3}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
+       {3, 6, Point{3, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {0, 1}, {1, 0}}, nil, nil},
+}
diff --git a/libgo/go/exp/4s/xs.go b/libgo/go/exp/4s/xs.go
new file mode 100644 (file)
index 0000000..c6806c0
--- /dev/null
@@ -0,0 +1,750 @@
+// games/4s - a tetris clone
+//
+// Derived from Plan 9's /sys/src/games/xs.c
+// http://plan9.bell-labs.com/sources/plan9/sys/src/games/xs.c
+//
+// Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
+// Portions Copyright 2009 The Go Authors.  All Rights Reserved.
+// Distributed under the terms of the Lucent Public License Version 1.02
+// See http://plan9.bell-labs.com/plan9/license.html
+
+/*
+ * engine for 4s, 5s, etc
+ */
+
+package main
+
+import (
+       "exp/draw"
+       "image"
+       "log"
+       "os"
+       "rand"
+       "time"
+)
+
+/*
+Cursor whitearrow = {
+       {0, 0},
+       {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
+        0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC,
+        0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
+        0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, },
+       {0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C,
+        0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C,
+        0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C,
+        0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }
+};
+*/
+
+const (
+       CNone   = 0
+       CBounds = 1
+       CPiece  = 2
+       NX      = 10
+       NY      = 20
+
+       NCOL = 10
+
+       MAXN = 5
+)
+
+var (
+       N                        int
+       display                  draw.Window
+       screen                   draw.Image
+       screenr                  image.Rectangle
+       board                    [NY][NX]byte
+       rboard                   image.Rectangle
+       pscore                   image.Point
+       scoresz                  image.Point
+       pcsz                     = 32
+       pos                      image.Point
+       bbr, bb2r                image.Rectangle
+       bb, bbmask, bb2, bb2mask *image.RGBA
+       whitemask                image.Image
+       br, br2                  image.Rectangle
+       points                   int
+       dt                       int
+       DY                       int
+       DMOUSE                   int
+       lastmx                   int
+       mouse                    draw.MouseEvent
+       newscreen                bool
+       timerc                   <-chan int64
+       suspc                    chan bool
+       mousec                   chan draw.MouseEvent
+       resizec                  chan bool
+       kbdc                     chan int
+       suspended                bool
+       tsleep                   int
+       piece                    *Piece
+       pieces                   []Piece
+)
+
+type Piece struct {
+       rot   int
+       tx    int
+       sz    image.Point
+       d     []image.Point
+       left  *Piece
+       right *Piece
+}
+
+var txbits = [NCOL][32]byte{
+       {0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF,
+               0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF,
+               0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF,
+               0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF,
+       },
+       {0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
+               0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
+               0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
+               0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
+       },
+       {0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
+               0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
+               0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
+               0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
+       },
+       {0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
+               0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
+               0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
+               0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
+       },
+       {0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88,
+               0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88,
+               0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88,
+               0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88,
+       },
+       {0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
+               0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
+               0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
+               0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
+       },
+       {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+               0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+               0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+               0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+       },
+       {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+               0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+               0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+               0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+       },
+       {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+               0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+               0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+               0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+       },
+       {0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33,
+               0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33,
+               0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33,
+               0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33,
+       },
+}
+
+var txpix = [NCOL]image.Image{
+       image.NewColorImage(image.RGBAColor{0xFF, 0xFF, 0x00, 0xFF}), /* yellow */
+       image.NewColorImage(image.RGBAColor{0x00, 0xFF, 0xFF, 0xFF}), /* cyan */
+       image.NewColorImage(image.RGBAColor{0x00, 0xFF, 0x00, 0xFF}), /* lime green */
+       image.NewColorImage(image.RGBAColor{0x00, 0x5D, 0xBB, 0xFF}), /* slate */
+       image.NewColorImage(image.RGBAColor{0xFF, 0x00, 0x00, 0xFF}), /* red */
+       image.NewColorImage(image.RGBAColor{0x55, 0xAA, 0xAA, 0xFF}), /* olive green */
+       image.NewColorImage(image.RGBAColor{0x00, 0x00, 0xFF, 0xFF}), /* blue */
+       image.NewColorImage(image.RGBAColor{0xFF, 0x55, 0xAA, 0xFF}), /* pink */
+       image.NewColorImage(image.RGBAColor{0xFF, 0xAA, 0xFF, 0xFF}), /* lavender */
+       image.NewColorImage(image.RGBAColor{0xBB, 0x00, 0x5D, 0xFF}), /* maroon */
+}
+
+func movemouse() int {
+       //mouse.image.Point = image.Pt(rboard.Min.X + rboard.Dx()/2, rboard.Min.Y + rboard.Dy()/2);
+       //moveto(mousectl, mouse.Xy);
+       return mouse.Loc.X
+}
+
+func warp(p image.Point, x int) int {
+       if !suspended && piece != nil {
+               x = pos.X + piece.sz.X*pcsz/2
+               if p.Y < rboard.Min.Y {
+                       p.Y = rboard.Min.Y
+               }
+               if p.Y >= rboard.Max.Y {
+                       p.Y = rboard.Max.Y - 1
+               }
+               //moveto(mousectl, image.Pt(x, p.Y));
+       }
+       return x
+}
+
+func initPieces() {
+       for i := range pieces {
+               p := &pieces[i]
+               if p.rot == 3 {
+                       p.right = &pieces[i-3]
+               } else {
+                       p.right = &pieces[i+1]
+               }
+               if p.rot == 0 {
+                       p.left = &pieces[i+3]
+               } else {
+                       p.left = &pieces[i-1]
+               }
+       }
+}
+
+func collide(pt image.Point, p *Piece) bool {
+       pt.X = (pt.X - rboard.Min.X) / pcsz
+       pt.Y = (pt.Y - rboard.Min.Y) / pcsz
+       for _, q := range p.d {
+               pt.X += q.X
+               pt.Y += q.Y
+               if pt.X < 0 || pt.X >= NX || pt.Y < 0 || pt.Y >= NY {
+                       return true
+                       continue
+               }
+               if board[pt.Y][pt.X] != 0 {
+                       return true
+               }
+       }
+       return false
+}
+
+func collider(pt, pmax image.Point) bool {
+       pi := (pt.X - rboard.Min.X) / pcsz
+       pj := (pt.Y - rboard.Min.Y) / pcsz
+       n := pmax.X / pcsz
+       m := pmax.Y/pcsz + 1
+       for i := pi; i < pi+n && i < NX; i++ {
+               for j := pj; j < pj+m && j < NY; j++ {
+                       if board[j][i] != 0 {
+                               return true
+                       }
+               }
+       }
+       return false
+}
+
+func setpiece(p *Piece) {
+       draw.Draw(bb, bbr, image.White, image.ZP)
+       draw.Draw(bbmask, bbr, image.Transparent, image.ZP)
+       br = image.Rect(0, 0, 0, 0)
+       br2 = br
+       piece = p
+       if p == nil {
+               return
+       }
+       var op image.Point
+       var r image.Rectangle
+       r.Min = bbr.Min
+       for i, pt := range p.d {
+               r.Min.X += pt.X * pcsz
+               r.Min.Y += pt.Y * pcsz
+               r.Max.X = r.Min.X + pcsz
+               r.Max.Y = r.Min.Y + pcsz
+               if i == 0 {
+                       draw.Draw(bb, r, image.Black, image.ZP)
+                       draw.Draw(bb, r.Inset(1), txpix[piece.tx], image.ZP)
+                       draw.Draw(bbmask, r, image.Opaque, image.ZP)
+                       op = r.Min
+               } else {
+                       draw.Draw(bb, r, bb, op)
+                       draw.Draw(bbmask, r, bbmask, op)
+               }
+               if br.Max.X < r.Max.X {
+                       br.Max.X = r.Max.X
+               }
+               if br.Max.Y < r.Max.Y {
+                       br.Max.Y = r.Max.Y
+               }
+       }
+       br.Max = br.Max.Sub(bbr.Min)
+       delta := image.Pt(0, DY)
+       br2.Max = br.Max.Add(delta)
+       r = br.Add(bb2r.Min)
+       r2 := br2.Add(bb2r.Min)
+       draw.Draw(bb2, r2, image.White, image.ZP)
+       draw.Draw(bb2, r.Add(delta), bb, bbr.Min)
+       draw.Draw(bb2mask, r2, image.Transparent, image.ZP)
+       draw.DrawMask(bb2mask, r, image.Opaque, bbr.Min, bbmask, image.ZP, draw.Over)
+       draw.DrawMask(bb2mask, r.Add(delta), image.Opaque, bbr.Min, bbmask, image.ZP, draw.Over)
+}
+
+func drawpiece() {
+       draw.DrawMask(screen, br.Add(pos), bb, bbr.Min, bbmask, image.ZP, draw.Over)
+       if suspended {
+               draw.DrawMask(screen, br.Add(pos), image.White, image.ZP, whitemask, image.ZP, draw.Over)
+       }
+}
+
+func undrawpiece() {
+       var mask image.Image
+       if collider(pos, br.Max) {
+               mask = bbmask
+       }
+       draw.DrawMask(screen, br.Add(pos), image.White, bbr.Min, mask, bbr.Min, draw.Over)
+}
+
+func rest() {
+       pt := pos.Sub(rboard.Min)
+       pt.X /= pcsz
+       pt.Y /= pcsz
+       for _, p := range piece.d {
+               pt.X += p.X
+               pt.Y += p.Y
+               board[pt.Y][pt.X] = byte(piece.tx + 16)
+       }
+}
+
+func canfit(p *Piece) bool {
+       var dx = [...]int{0, -1, 1, -2, 2, -3, 3, 4, -4}
+       j := N + 1
+       if j >= 4 {
+               j = p.sz.X
+               if j < p.sz.Y {
+                       j = p.sz.Y
+               }
+               j = 2*j - 1
+       }
+       for i := 0; i < j; i++ {
+               var z image.Point
+               z.X = pos.X + dx[i]*pcsz
+               z.Y = pos.Y
+               if !collide(z, p) {
+                       z.Y = pos.Y + pcsz - 1
+                       if !collide(z, p) {
+                               undrawpiece()
+                               pos.X = z.X
+                               return true
+                       }
+               }
+       }
+       return false
+}
+
+func score(p int) {
+       points += p
+       //      snprint(buf, sizeof(buf), "%.6ld", points);
+       //      draw.Draw(screen, draw.Rpt(pscore, pscore.Add(scoresz)), image.White, image.ZP);
+       //      string(screen, pscore, image.Black, image.ZP, font, buf);
+}
+
+func drawsq(b draw.Image, p image.Point, ptx int) {
+       var r image.Rectangle
+       r.Min = p
+       r.Max.X = r.Min.X + pcsz
+       r.Max.Y = r.Min.Y + pcsz
+       draw.Draw(b, r, image.Black, image.ZP)
+       draw.Draw(b, r.Inset(1), txpix[ptx], image.ZP)
+}
+
+func drawboard() {
+       draw.Border(screen, rboard.Inset(-2), 2, image.Black, image.ZP)
+       draw.Draw(screen, image.Rect(rboard.Min.X, rboard.Min.Y-2, rboard.Max.X, rboard.Min.Y),
+               image.White, image.ZP)
+       for i := 0; i < NY; i++ {
+               for j := 0; j < NX; j++ {
+                       if board[i][j] != 0 {
+                               drawsq(screen, image.Pt(rboard.Min.X+j*pcsz, rboard.Min.Y+i*pcsz), int(board[i][j]-16))
+                       }
+               }
+       }
+       score(0)
+       if suspended {
+               draw.DrawMask(screen, screenr, image.White, image.ZP, whitemask, image.ZP, draw.Over)
+       }
+}
+
+func choosepiece() {
+       for {
+               i := rand.Intn(len(pieces))
+               setpiece(&pieces[i])
+               pos = rboard.Min
+               pos.X += rand.Intn(NX) * pcsz
+               if !collide(image.Pt(pos.X, pos.Y+pcsz-DY), piece) {
+                       break
+               }
+       }
+       drawpiece()
+       display.FlushImage()
+}
+
+func movepiece() bool {
+       var mask image.Image
+       if collide(image.Pt(pos.X, pos.Y+pcsz), piece) {
+               return false
+       }
+       if collider(pos, br2.Max) {
+               mask = bb2mask
+       }
+       draw.DrawMask(screen, br2.Add(pos), bb2, bb2r.Min, mask, bb2r.Min, draw.Over)
+       pos.Y += DY
+       display.FlushImage()
+       return true
+}
+
+func suspend(s bool) {
+       suspended = s
+       /*
+               if suspended {
+                       setcursor(mousectl, &whitearrow);
+               } else {
+                       setcursor(mousectl, nil);
+               }
+       */
+       if !suspended {
+               drawpiece()
+       }
+       drawboard()
+       display.FlushImage()
+}
+
+func pause(t int) {
+       display.FlushImage()
+       for {
+               select {
+               case s := <-suspc:
+                       if !suspended && s {
+                               suspend(true)
+                       } else if suspended && !s {
+                               suspend(false)
+                               lastmx = warp(mouse.Loc, lastmx)
+                       }
+               case <-timerc:
+                       if suspended {
+                               break
+                       }
+                       t -= tsleep
+                       if t < 0 {
+                               return
+                       }
+               case <-resizec:
+                       //redraw(true);
+               case mouse = <-mousec:
+               case <-kbdc:
+               }
+       }
+}
+
+func horiz() bool {
+       var lev [MAXN]int
+       h := 0
+       for i := 0; i < NY; i++ {
+               for j := 0; board[i][j] != 0; j++ {
+                       if j == NX-1 {
+                               lev[h] = i
+                               h++
+                               break
+                       }
+               }
+       }
+       if h == 0 {
+               return false
+       }
+       r := rboard
+       newscreen = false
+       for j := 0; j < h; j++ {
+               r.Min.Y = rboard.Min.Y + lev[j]*pcsz
+               r.Max.Y = r.Min.Y + pcsz
+               draw.DrawMask(screen, r, image.White, image.ZP, whitemask, image.ZP, draw.Over)
+               display.FlushImage()
+       }
+       PlaySound(whoosh)
+       for i := 0; i < 3; i++ {
+               pause(250)
+               if newscreen {
+                       drawboard()
+                       break
+               }
+               for j := 0; j < h; j++ {
+                       r.Min.Y = rboard.Min.Y + lev[j]*pcsz
+                       r.Max.Y = r.Min.Y + pcsz
+                       draw.DrawMask(screen, r, image.White, image.ZP, whitemask, image.ZP, draw.Over)
+               }
+               display.FlushImage()
+       }
+       r = rboard
+       for j := 0; j < h; j++ {
+               i := NY - lev[j] - 1
+               score(250 + 10*i*i)
+               r.Min.Y = rboard.Min.Y
+               r.Max.Y = rboard.Min.Y + lev[j]*pcsz
+               draw.Draw(screen, r.Add(image.Pt(0, pcsz)), screen, r.Min)
+               r.Max.Y = rboard.Min.Y + pcsz
+               draw.Draw(screen, r, image.White, image.ZP)
+               for k := lev[j] - 1; k >= 0; k-- {
+                       board[k+1] = board[k]
+               }
+               board[0] = [NX]byte{}
+       }
+       display.FlushImage()
+       return true
+}
+
+func mright() {
+       if !collide(image.Pt(pos.X+pcsz, pos.Y), piece) &&
+               !collide(image.Pt(pos.X+pcsz, pos.Y+pcsz-DY), piece) {
+               undrawpiece()
+               pos.X += pcsz
+               drawpiece()
+               display.FlushImage()
+       }
+}
+
+func mleft() {
+       if !collide(image.Pt(pos.X-pcsz, pos.Y), piece) &&
+               !collide(image.Pt(pos.X-pcsz, pos.Y+pcsz-DY), piece) {
+               undrawpiece()
+               pos.X -= pcsz
+               drawpiece()
+               display.FlushImage()
+       }
+}
+
+func rright() {
+       if canfit(piece.right) {
+               setpiece(piece.right)
+               drawpiece()
+               display.FlushImage()
+       }
+}
+
+func rleft() {
+       if canfit(piece.left) {
+               setpiece(piece.left)
+               drawpiece()
+               display.FlushImage()
+       }
+}
+
+var fusst = 0
+
+func drop(f bool) bool {
+       if f {
+               score(5 * (rboard.Max.Y - pos.Y) / pcsz)
+               for movepiece() {
+               }
+       }
+       fusst = 0
+       rest()
+       if pos.Y == rboard.Min.Y && !horiz() {
+               return true
+       }
+       horiz()
+       setpiece(nil)
+       pause(1500)
+       choosepiece()
+       lastmx = warp(mouse.Loc, lastmx)
+       return false
+}
+
+func play() {
+       var om draw.MouseEvent
+       dt = 64
+       lastmx = -1
+       lastmx = movemouse()
+       choosepiece()
+       lastmx = warp(mouse.Loc, lastmx)
+       for {
+               select {
+               case mouse = <-mousec:
+                       if suspended {
+                               om = mouse
+                               break
+                       }
+                       if lastmx < 0 {
+                               lastmx = mouse.Loc.X
+                       }
+                       if mouse.Loc.X > lastmx+DMOUSE {
+                               mright()
+                               lastmx = mouse.Loc.X
+                       }
+                       if mouse.Loc.X < lastmx-DMOUSE {
+                               mleft()
+                               lastmx = mouse.Loc.X
+                       }
+                       if mouse.Buttons&^om.Buttons&1 == 1 {
+                               rleft()
+                       }
+                       if mouse.Buttons&^om.Buttons&2 == 2 {
+                               if drop(true) {
+                                       return
+                               }
+                       }
+                       if mouse.Buttons&^om.Buttons&4 == 4 {
+                               rright()
+                       }
+                       om = mouse
+
+               case s := <-suspc:
+                       if !suspended && s {
+                               suspend(true)
+                       } else if suspended && !s {
+                               suspend(false)
+                               lastmx = warp(mouse.Loc, lastmx)
+                       }
+
+               case <-resizec:
+                       //redraw(true);
+
+               case r := <-kbdc:
+                       if suspended {
+                               break
+                       }
+                       switch r {
+                       case 'f', ';':
+                               mright()
+                       case 'a', 'j':
+                               mleft()
+                       case 'd', 'l':
+                               rright()
+                       case 's', 'k':
+                               rleft()
+                       case ' ':
+                               if drop(true) {
+                                       return
+                               }
+                       }
+
+               case <-timerc:
+                       if suspended {
+                               break
+                       }
+                       dt -= tsleep
+                       if dt < 0 {
+                               i := 1
+                               dt = 16 * (points + rand.Intn(10000) - 5000) / 10000
+                               if dt >= 32 {
+                                       i += (dt - 32) / 16
+                                       dt = 32
+                               }
+                               dt = 52 - dt
+                               for ; i > 0; i-- {
+                                       if movepiece() {
+                                               continue
+                                       }
+                                       fusst++
+                                       if fusst == 40 {
+                                               if drop(false) {
+                                                       return
+                                               }
+                                               break
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+func suspproc() {
+       s := false
+       for {
+               select {
+               case mouse = <-mousec:
+                       mousec <- mouse
+               case r := <-kbdc:
+                       switch r {
+                       case 'q', 'Q', 0x04, 0x7F:
+                               os.Exit(0)
+                       default:
+                               if s {
+                                       s = false
+                                       suspc <- s
+                                       break
+                               }
+                               switch r {
+                               case 'z', 'Z', 'p', 'P', 0x1B:
+                                       s = true
+                                       suspc <- s
+                               default:
+                                       kbdc <- r
+                               }
+                       }
+               }
+       }
+}
+
+func redraw(new bool) {
+       //      if new && getwindow(display, Refmesg) < 0 {
+       //              sysfatal("can't reattach to window");
+       //      }
+       r := screen.Bounds()
+       pos.X = (pos.X - rboard.Min.X) / pcsz
+       pos.Y = (pos.Y - rboard.Min.Y) / pcsz
+       dx := r.Max.X - r.Min.X
+       dy := r.Max.Y - r.Min.Y - 2*32
+       DY = dx / NX
+       if DY > dy/NY {
+               DY = dy / NY
+       }
+       DY /= 8
+       if DY > 4 {
+               DY = 4
+       }
+       pcsz = DY * 8
+       DMOUSE = pcsz / 3
+       if pcsz < 8 {
+               log.Exitf("screen too small: %d", pcsz)
+       }
+       rboard = screenr
+       rboard.Min.X += (dx - pcsz*NX) / 2
+       rboard.Min.Y += (dy-pcsz*NY)/2 + 32
+       rboard.Max.X = rboard.Min.X + NX*pcsz
+       rboard.Max.Y = rboard.Min.Y + NY*pcsz
+       pscore.X = rboard.Min.X + 8
+       pscore.Y = rboard.Min.Y - 32
+       //      scoresz = stringsize(font, "000000");
+       pos.X = pos.X*pcsz + rboard.Min.X
+       pos.Y = pos.Y*pcsz + rboard.Min.Y
+       bbr = image.Rect(0, 0, N*pcsz, N*pcsz)
+       bb = image.NewRGBA(bbr.Max.X, bbr.Max.Y)
+       bbmask = image.NewRGBA(bbr.Max.X, bbr.Max.Y) // actually just a bitmap
+       bb2r = image.Rect(0, 0, N*pcsz, N*pcsz+DY)
+       bb2 = image.NewRGBA(bb2r.Dx(), bb2r.Dy())
+       bb2mask = image.NewRGBA(bb2r.Dx(), bb2r.Dy()) // actually just a bitmap
+       draw.Draw(screen, screenr, image.White, image.ZP)
+       drawboard()
+       setpiece(piece)
+       if piece != nil {
+               drawpiece()
+       }
+       lastmx = movemouse()
+       newscreen = true
+       display.FlushImage()
+}
+
+func demuxEvents(w draw.Window) {
+       for event := range w.EventChan() {
+               switch e := event.(type) {
+               case draw.MouseEvent:
+                       mousec <- e
+               case draw.ConfigEvent:
+                       resizec <- true
+               case draw.KeyEvent:
+                       kbdc <- e.Key
+               }
+       }
+       os.Exit(0)
+}
+
+func Play(pp []Piece, ctxt draw.Window) {
+       display = ctxt
+       screen = ctxt.Screen()
+       screenr = screen.Bounds()
+       pieces = pp
+       N = len(pieces[0].d)
+       initPieces()
+       rand.Seed(int64(time.Nanoseconds() % (1e9 - 1)))
+       whitemask = image.NewColorImage(image.AlphaColor{0x7F})
+       tsleep = 50
+       timerc = time.Tick(int64(tsleep/2) * 1e6)
+       suspc = make(chan bool)
+       mousec = make(chan draw.MouseEvent)
+       resizec = make(chan bool)
+       kbdc = make(chan int)
+       go demuxEvents(ctxt)
+       go suspproc()
+       points = 0
+       redraw(false)
+       play()
+}
diff --git a/libgo/go/exp/README b/libgo/go/exp/README
new file mode 100644 (file)
index 0000000..e602e3a
--- /dev/null
@@ -0,0 +1,3 @@
+This directory tree contains experimental packages and
+unfinished code that is subject to even more change than the
+rest of the Go tree.
diff --git a/libgo/go/exp/datafmt/datafmt.go b/libgo/go/exp/datafmt/datafmt.go
new file mode 100644 (file)
index 0000000..979dedd
--- /dev/null
@@ -0,0 +1,731 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*     The datafmt package implements syntax-directed, type-driven formatting
+       of arbitrary data structures. Formatting a data structure consists of
+       two phases: first, a parser reads a format specification and builds a
+       "compiled" format. Then, the format can be applied repeatedly to
+       arbitrary values. Applying a format to a value evaluates to a []byte
+       containing the formatted value bytes, or nil.
+
+       A format specification is a set of package declarations and format rules:
+
+               Format      = [ Entry { ";" Entry } [ ";" ] ] .
+               Entry       = PackageDecl | FormatRule .
+
+       (The syntax of a format specification is presented in the same EBNF
+       notation as used in the Go language specification. The syntax of white
+       space, comments, identifiers, and string literals is the same as in Go.)
+
+       A package declaration binds a package name (such as 'ast') to a
+       package import path (such as '"go/ast"'). Each package used (in
+       a type name, see below) must be declared once before use.
+
+               PackageDecl = PackageName ImportPath .
+               PackageName = identifier .
+               ImportPath  = string .
+
+       A format rule binds a rule name to a format expression. A rule name
+       may be a type name or one of the special names 'default' or '/'.
+       A type name may be the name of a predeclared type (for example, 'int',
+       'float32', etc.), the package-qualified name of a user-defined type
+       (for example, 'ast.MapType'), or an identifier indicating the structure
+       of unnamed composite types ('array', 'chan', 'func', 'interface', 'map',
+       or 'ptr'). Each rule must have a unique name; rules can be declared in
+       any order.
+
+               FormatRule  = RuleName "=" Expression .
+               RuleName    = TypeName | "default" | "/" .
+               TypeName    = [ PackageName "." ] identifier .
+
+       To format a value, the value's type name is used to select the format rule
+       (there is an override mechanism, see below). The format expression of the
+       selected rule specifies how the value is formatted. Each format expression,
+       when applied to a value, evaluates to a byte sequence or nil.
+
+       In its most general form, a format expression is a list of alternatives,
+       each of which is a sequence of operands:
+
+               Expression  = [ Sequence ] { "|" [ Sequence ] } .
+               Sequence    = Operand { Operand } .
+
+       The formatted result produced by an expression is the result of the first
+       alternative sequence that evaluates to a non-nil result; if there is no
+       such alternative, the expression evaluates to nil. The result produced by
+       an operand sequence is the concatenation of the results of its operands.
+       If any operand in the sequence evaluates to nil, the entire sequence
+       evaluates to nil.
+
+       There are five kinds of operands:
+
+               Operand     = Literal | Field | Group | Option | Repetition .
+
+       Literals evaluate to themselves, with two substitutions. First,
+       %-formats expand in the manner of fmt.Printf, with the current value
+       passed as the parameter. Second, the current indentation (see below)
+       is inserted after every newline or form feed character.
+
+               Literal     = string .
+
+       This table shows string literals applied to the value 42 and the
+       corresponding formatted result:
+
+               "foo"       foo
+               "%x"        2a
+               "x = %d"    x = 42
+               "%#x = %d"  0x2a = 42
+
+       A field operand is a field name optionally followed by an alternate
+       rule name. The field name may be an identifier or one of the special
+       names @ or *.
+
+               Field       = FieldName [ ":" RuleName ] .
+               FieldName   = identifier | "@" | "*" .
+
+       If the field name is an identifier, the current value must be a struct,
+       and there must be a field with that name in the struct. The same lookup
+       rules apply as in the Go language (for instance, the name of an anonymous
+       field is the unqualified type name). The field name denotes the field
+       value in the struct. If the field is not found, formatting is aborted
+       and an error message is returned. (TODO consider changing the semantics
+       such that if a field is not found, it evaluates to nil).
+
+       The special name '@' denotes the current value.
+
+       The meaning of the special name '*' depends on the type of the current
+       value:
+
+               array, slice types   array, slice element (inside {} only, see below)
+               interfaces           value stored in interface
+               pointers             value pointed to by pointer
+
+       (Implementation restriction: channel, function and map types are not
+       supported due to missing reflection support).
+
+       Fields are evaluated as follows: If the field value is nil, or an array
+       or slice element does not exist, the result is nil (see below for details
+       on array/slice elements). If the value is not nil the field value is
+       formatted (recursively) using the rule corresponding to its type name,
+       or the alternate rule name, if given.
+
+       The following example shows a complete format specification for a
+       struct 'myPackage.Point'. Assume the package
+
+               package myPackage  // in directory myDir/myPackage
+               type Point struct {
+                       name string;
+                       x, y int;
+               }
+
+       Applying the format specification
+
+               myPackage "myDir/myPackage";
+               int = "%d";
+               hexInt = "0x%x";
+               string = "---%s---";
+               myPackage.Point = name "{" x ", " y:hexInt "}";
+
+       to the value myPackage.Point{"foo", 3, 15} results in
+
+               ---foo---{3, 0xf}
+
+       Finally, an operand may be a grouped, optional, or repeated expression.
+       A grouped expression ("group") groups a more complex expression (body)
+       so that it can be used in place of a single operand:
+
+               Group       = "(" [ Indentation ">>" ] Body ")" .
+               Indentation = Expression .
+               Body        = Expression .
+
+       A group body may be prefixed by an indentation expression followed by '>>'.
+       The indentation expression is applied to the current value like any other
+       expression and the result, if not nil, is appended to the current indentation
+       during the evaluation of the body (see also formatting state, below).
+
+       An optional expression ("option") is enclosed in '[]' brackets.
+
+               Option      = "[" Body "]" .
+
+       An option evaluates to its body, except that if the body evaluates to nil,
+       the option expression evaluates to an empty []byte. Thus an option's purpose
+       is to protect the expression containing the option from a nil operand.
+
+       A repeated expression ("repetition") is enclosed in '{}' braces.
+
+               Repetition  = "{" Body [ "/" Separator ] "}" .
+               Separator   = Expression .
+
+       A repeated expression is evaluated as follows: The body is evaluated
+       repeatedly and its results are concatenated until the body evaluates
+       to nil. The result of the repetition is the (possibly empty) concatenation,
+       but it is never nil. An implicit index is supplied for the evaluation of
+       the body: that index is used to address elements of arrays or slices. If
+       the corresponding elements do not exist, the field denoting the element
+       evaluates to nil (which in turn may terminate the repetition).
+
+       The body of a repetition may be followed by a '/' and a "separator"
+       expression. If the separator is present, it is invoked between repetitions
+       of the body.
+
+       The following example shows a complete format specification for formatting
+       a slice of unnamed type. Applying the specification
+
+               int = "%b";
+               array = { * / ", " };  // array is the type name for an unnamed slice
+
+       to the value '[]int{2, 3, 5, 7}' results in
+
+               10, 11, 101, 111
+
+       Default rule: If a format rule named 'default' is present, it is used for
+       formatting a value if no other rule was found. A common default rule is
+
+               default = "%v"
+
+       to provide default formatting for basic types without having to specify
+       a specific rule for each basic type.
+
+       Global separator rule: If a format rule named '/' is present, it is
+       invoked with the current value between literals. If the separator
+       expression evaluates to nil, it is ignored.
+
+       For instance, a global separator rule may be used to punctuate a sequence
+       of values with commas. The rules:
+
+               default = "%v";
+               / = ", ";
+
+       will format an argument list by printing each one in its default format,
+       separated by a comma and a space.
+*/
+package datafmt
+
+import (
+       "bytes"
+       "fmt"
+       "go/token"
+       "io"
+       "os"
+       "reflect"
+       "runtime"
+)
+
+
+// ----------------------------------------------------------------------------
+// Format representation
+
+// Custom formatters implement the Formatter function type.
+// A formatter is invoked with the current formatting state, the
+// value to format, and the rule name under which the formatter
+// was installed (the same formatter function may be installed
+// under different names). The formatter may access the current state
+// to guide formatting and use State.Write to append to the state's
+// output.
+//
+// A formatter must return a boolean value indicating if it evaluated
+// to a non-nil value (true), or a nil value (false).
+//
+type Formatter func(state *State, value interface{}, ruleName string) bool
+
+
+// A FormatterMap is a set of custom formatters.
+// It maps a rule name to a formatter function.
+//
+type FormatterMap map[string]Formatter
+
+
+// A parsed format expression is built from the following nodes.
+//
+type (
+       expr interface{}
+
+       alternatives []expr // x | y | z
+
+       sequence []expr // x y z
+
+       literal [][]byte // a list of string segments, possibly starting with '%'
+
+       field struct {
+               fieldName string // including "@", "*"
+               ruleName  string // "" if no rule name specified
+       }
+
+       group struct {
+               indent, body expr // (indent >> body)
+       }
+
+       option struct {
+               body expr // [body]
+       }
+
+       repetition struct {
+               body, separator expr // {body / separator}
+       }
+
+       custom struct {
+               ruleName string
+               fun      Formatter
+       }
+)
+
+
+// A Format is the result of parsing a format specification.
+// The format may be applied repeatedly to format values.
+//
+type Format map[string]expr
+
+
+// ----------------------------------------------------------------------------
+// Formatting
+
+// An application-specific environment may be provided to Format.Apply;
+// the environment is available inside custom formatters via State.Env().
+// Environments must implement copying; the Copy method must return an
+// complete copy of the receiver. This is necessary so that the formatter
+// can save and restore an environment (in case of an absent expression).
+//
+// If the Environment doesn't change during formatting (this is under
+// control of the custom formatters), the Copy function can simply return
+// the receiver, and thus can be very light-weight.
+//
+type Environment interface {
+       Copy() Environment
+}
+
+
+// State represents the current formatting state.
+// It is provided as argument to custom formatters.
+//
+type State struct {
+       fmt       Format         // format in use
+       env       Environment    // user-supplied environment
+       errors    chan os.Error  // not chan *Error (errors <- nil would be wrong!)
+       hasOutput bool           // true after the first literal has been written
+       indent    bytes.Buffer   // current indentation
+       output    bytes.Buffer   // format output
+       linePos   token.Position // position of line beginning (Column == 0)
+       default_  expr           // possibly nil
+       separator expr           // possibly nil
+}
+
+
+func newState(fmt Format, env Environment, errors chan os.Error) *State {
+       s := new(State)
+       s.fmt = fmt
+       s.env = env
+       s.errors = errors
+       s.linePos = token.Position{Line: 1}
+
+       // if we have a default rule, cache it's expression for fast access
+       if x, found := fmt["default"]; found {
+               s.default_ = x
+       }
+
+       // if we have a global separator rule, cache it's expression for fast access
+       if x, found := fmt["/"]; found {
+               s.separator = x
+       }
+
+       return s
+}
+
+
+// Env returns the environment passed to Format.Apply.
+func (s *State) Env() interface{} { return s.env }
+
+
+// LinePos returns the position of the current line beginning
+// in the state's output buffer. Line numbers start at 1.
+//
+func (s *State) LinePos() token.Position { return s.linePos }
+
+
+// Pos returns the position of the next byte to be written to the
+// output buffer. Line numbers start at 1.
+//
+func (s *State) Pos() token.Position {
+       offs := s.output.Len()
+       return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
+}
+
+
+// Write writes data to the output buffer, inserting the indentation
+// string after each newline or form feed character. It cannot return an error.
+//
+func (s *State) Write(data []byte) (int, os.Error) {
+       n := 0
+       i0 := 0
+       for i, ch := range data {
+               if ch == '\n' || ch == '\f' {
+                       // write text segment and indentation
+                       n1, _ := s.output.Write(data[i0 : i+1])
+                       n2, _ := s.output.Write(s.indent.Bytes())
+                       n += n1 + n2
+                       i0 = i + 1
+                       s.linePos.Offset = s.output.Len()
+                       s.linePos.Line++
+               }
+       }
+       n3, _ := s.output.Write(data[i0:])
+       return n + n3, nil
+}
+
+
+type checkpoint struct {
+       env       Environment
+       hasOutput bool
+       outputLen int
+       linePos   token.Position
+}
+
+
+func (s *State) save() checkpoint {
+       saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
+       if s.env != nil {
+               saved.env = s.env.Copy()
+       }
+       return saved
+}
+
+
+func (s *State) restore(m checkpoint) {
+       s.env = m.env
+       s.output.Truncate(m.outputLen)
+}
+
+
+func (s *State) error(msg string) {
+       s.errors <- os.NewError(msg)
+       runtime.Goexit()
+}
+
+
+// TODO At the moment, unnamed types are simply mapped to the default
+//      names below. For instance, all unnamed arrays are mapped to
+//      'array' which is not really sufficient. Eventually one may want
+//      to be able to specify rules for say an unnamed slice of T.
+//
+
+func typename(typ reflect.Type) string {
+       switch typ.(type) {
+       case *reflect.ArrayType:
+               return "array"
+       case *reflect.SliceType:
+               return "array"
+       case *reflect.ChanType:
+               return "chan"
+       case *reflect.FuncType:
+               return "func"
+       case *reflect.InterfaceType:
+               return "interface"
+       case *reflect.MapType:
+               return "map"
+       case *reflect.PtrType:
+               return "ptr"
+       }
+       return typ.String()
+}
+
+func (s *State) getFormat(name string) expr {
+       if fexpr, found := s.fmt[name]; found {
+               return fexpr
+       }
+
+       if s.default_ != nil {
+               return s.default_
+       }
+
+       s.error(fmt.Sprintf("no format rule for type: '%s'", name))
+       return nil
+}
+
+
+// eval applies a format expression fexpr to a value. If the expression
+// evaluates internally to a non-nil []byte, that slice is appended to
+// the state's output buffer and eval returns true. Otherwise, eval
+// returns false and the state remains unchanged.
+//
+func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
+       // an empty format expression always evaluates
+       // to a non-nil (but empty) []byte
+       if fexpr == nil {
+               return true
+       }
+
+       switch t := fexpr.(type) {
+       case alternatives:
+               // append the result of the first alternative that evaluates to
+               // a non-nil []byte to the state's output
+               mark := s.save()
+               for _, x := range t {
+                       if s.eval(x, value, index) {
+                               return true
+                       }
+                       s.restore(mark)
+               }
+               return false
+
+       case sequence:
+               // append the result of all operands to the state's output
+               // unless a nil result is encountered
+               mark := s.save()
+               for _, x := range t {
+                       if !s.eval(x, value, index) {
+                               s.restore(mark)
+                               return false
+                       }
+               }
+               return true
+
+       case literal:
+               // write separator, if any
+               if s.hasOutput {
+                       // not the first literal
+                       if s.separator != nil {
+                               sep := s.separator // save current separator
+                               s.separator = nil  // and disable it (avoid recursion)
+                               mark := s.save()
+                               if !s.eval(sep, value, index) {
+                                       s.restore(mark)
+                               }
+                               s.separator = sep // enable it again
+                       }
+               }
+               s.hasOutput = true
+               // write literal segments
+               for _, lit := range t {
+                       if len(lit) > 1 && lit[0] == '%' {
+                               // segment contains a %-format at the beginning
+                               if lit[1] == '%' {
+                                       // "%%" is printed as a single "%"
+                                       s.Write(lit[1:])
+                               } else {
+                                       // use s instead of s.output to get indentation right
+                                       fmt.Fprintf(s, string(lit), value.Interface())
+                               }
+                       } else {
+                               // segment contains no %-formats
+                               s.Write(lit)
+                       }
+               }
+               return true // a literal never evaluates to nil
+
+       case *field:
+               // determine field value
+               switch t.fieldName {
+               case "@":
+                       // field value is current value
+
+               case "*":
+                       // indirection: operation is type-specific
+                       switch v := value.(type) {
+                       case *reflect.ArrayValue:
+                               if v.Len() <= index {
+                                       return false
+                               }
+                               value = v.Elem(index)
+
+                       case *reflect.SliceValue:
+                               if v.IsNil() || v.Len() <= index {
+                                       return false
+                               }
+                               value = v.Elem(index)
+
+                       case *reflect.MapValue:
+                               s.error("reflection support for maps incomplete")
+
+                       case *reflect.PtrValue:
+                               if v.IsNil() {
+                                       return false
+                               }
+                               value = v.Elem()
+
+                       case *reflect.InterfaceValue:
+                               if v.IsNil() {
+                                       return false
+                               }
+                               value = v.Elem()
+
+                       case *reflect.ChanValue:
+                               s.error("reflection support for chans incomplete")
+
+                       case *reflect.FuncValue:
+                               s.error("reflection support for funcs incomplete")
+
+                       default:
+                               s.error(fmt.Sprintf("error: * does not apply to `%s`", value.Type()))
+                       }
+
+               default:
+                       // value is value of named field
+                       var field reflect.Value
+                       if sval, ok := value.(*reflect.StructValue); ok {
+                               field = sval.FieldByName(t.fieldName)
+                               if field == nil {
+                                       // TODO consider just returning false in this case
+                                       s.error(fmt.Sprintf("error: no field `%s` in `%s`", t.fieldName, value.Type()))
+                               }
+                       }
+                       value = field
+               }
+
+               // determine rule
+               ruleName := t.ruleName
+               if ruleName == "" {
+                       // no alternate rule name, value type determines rule
+                       ruleName = typename(value.Type())
+               }
+               fexpr = s.getFormat(ruleName)
+
+               mark := s.save()
+               if !s.eval(fexpr, value, index) {
+                       s.restore(mark)
+                       return false
+               }
+               return true
+
+       case *group:
+               // remember current indentation
+               indentLen := s.indent.Len()
+
+               // update current indentation
+               mark := s.save()
+               s.eval(t.indent, value, index)
+               // if the indentation evaluates to nil, the state's output buffer
+               // didn't change - either way it's ok to append the difference to
+               // the current identation
+               s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()])
+               s.restore(mark)
+
+               // format group body
+               mark = s.save()
+               b := true
+               if !s.eval(t.body, value, index) {
+                       s.restore(mark)
+                       b = false
+               }
+
+               // reset indentation
+               s.indent.Truncate(indentLen)
+               return b
+
+       case *option:
+               // evaluate the body and append the result to the state's output
+               // buffer unless the result is nil
+               mark := s.save()
+               if !s.eval(t.body, value, 0) { // TODO is 0 index correct?
+                       s.restore(mark)
+               }
+               return true // an option never evaluates to nil
+
+       case *repetition:
+               // evaluate the body and append the result to the state's output
+               // buffer until a result is nil
+               for i := 0; ; i++ {
+                       mark := s.save()
+                       // write separator, if any
+                       if i > 0 && t.separator != nil {
+                               // nil result from separator is ignored
+                               mark := s.save()
+                               if !s.eval(t.separator, value, i) {
+                                       s.restore(mark)
+                               }
+                       }
+                       if !s.eval(t.body, value, i) {
+                               s.restore(mark)
+                               break
+                       }
+               }
+               return true // a repetition never evaluates to nil
+
+       case *custom:
+               // invoke the custom formatter to obtain the result
+               mark := s.save()
+               if !t.fun(s, value.Interface(), t.ruleName) {
+                       s.restore(mark)
+                       return false
+               }
+               return true
+       }
+
+       panic("unreachable")
+       return false
+}
+
+
+// Eval formats each argument according to the format
+// f and returns the resulting []byte and os.Error. If
+// an error occured, the []byte contains the partially
+// formatted result. An environment env may be passed
+// in which is available in custom formatters through
+// the state parameter.
+//
+func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
+       if f == nil {
+               return nil, os.NewError("format is nil")
+       }
+
+       errors := make(chan os.Error)
+       s := newState(f, env, errors)
+
+       go func() {
+               for _, v := range args {
+                       fld := reflect.NewValue(v)
+                       if fld == nil {
+                               errors <- os.NewError("nil argument")
+                               return
+                       }
+                       mark := s.save()
+                       if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct?
+                               s.restore(mark)
+                       }
+               }
+               errors <- nil // no errors
+       }()
+
+       err := <-errors
+       return s.output.Bytes(), err
+}
+
+
+// ----------------------------------------------------------------------------
+// Convenience functions
+
+// Fprint formats each argument according to the format f
+// and writes to w. The result is the total number of bytes
+// written and an os.Error, if any.
+//
+func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int, os.Error) {
+       data, err := f.Eval(env, args...)
+       if err != nil {
+               // TODO should we print partial result in case of error?
+               return 0, err
+       }
+       return w.Write(data)
+}
+
+
+// Print formats each argument according to the format f
+// and writes to standard output. The result is the total
+// number of bytes written and an os.Error, if any.
+//
+func (f Format) Print(args ...interface{}) (int, os.Error) {
+       return f.Fprint(os.Stdout, nil, args...)
+}
+
+
+// Sprint formats each argument according to the format f
+// and returns the resulting string. If an error occurs
+// during formatting, the result string contains the
+// partially formatted result followed by an error message.
+//
+func (f Format) Sprint(args ...interface{}) string {
+       var buf bytes.Buffer
+       _, err := f.Fprint(&buf, nil, args...)
+       if err != nil {
+               var i interface{} = args
+               fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(i), err)
+       }
+       return buf.String()
+}
diff --git a/libgo/go/exp/datafmt/datafmt_test.go b/libgo/go/exp/datafmt/datafmt_test.go
new file mode 100644 (file)
index 0000000..66794cf
--- /dev/null
@@ -0,0 +1,347 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package datafmt
+
+import (
+       "fmt"
+       "testing"
+)
+
+
+func parse(t *testing.T, form string, fmap FormatterMap) Format {
+       f, err := Parse("", []byte(form), fmap)
+       if err != nil {
+               t.Errorf("Parse(%s): %v", form, err)
+               return nil
+       }
+       return f
+}
+
+
+func verify(t *testing.T, f Format, expected string, args ...interface{}) {
+       if f == nil {
+               return // allow other tests to run
+       }
+       result := f.Sprint(args...)
+       if result != expected {
+               t.Errorf(
+                       "result  : `%s`\nexpected: `%s`\n\n",
+                       result, expected)
+       }
+}
+
+
+func formatter(s *State, value interface{}, rule_name string) bool {
+       switch rule_name {
+       case "/":
+               fmt.Fprintf(s, "%d %d %d", s.Pos().Line, s.LinePos().Column, s.Pos().Column)
+               return true
+       case "blank":
+               s.Write([]byte{' '})
+               return true
+       case "int":
+               if value.(int)&1 == 0 {
+                       fmt.Fprint(s, "even ")
+               } else {
+                       fmt.Fprint(s, "odd ")
+               }
+               return true
+       case "nil":
+               return false
+       case "testing.T":
+               s.Write([]byte("testing.T"))
+               return true
+       }
+       panic("unreachable")
+       return false
+}
+
+
+func TestCustomFormatters(t *testing.T) {
+       fmap0 := FormatterMap{"/": formatter}
+       fmap1 := FormatterMap{"int": formatter, "blank": formatter, "nil": formatter}
+       fmap2 := FormatterMap{"testing.T": formatter}
+
+       f := parse(t, `int=`, fmap0)
+       verify(t, f, ``, 1, 2, 3)
+
+       f = parse(t, `int="#"`, nil)
+       verify(t, f, `###`, 1, 2, 3)
+
+       f = parse(t, `int="#";string="%s"`, fmap0)
+       verify(t, f, "#1 0 1#1 0 7#1 0 13\n2 0 0foo2 0 8\n", 1, 2, 3, "\n", "foo", "\n")
+
+       f = parse(t, ``, fmap1)
+       verify(t, f, `even odd even odd `, 0, 1, 2, 3)
+
+       f = parse(t, `/ =@:blank; float="#"`, fmap1)
+       verify(t, f, `# # #`, 0.0, 1.0, 2.0)
+
+       f = parse(t, `float=@:nil`, fmap1)
+       verify(t, f, ``, 0.0, 1.0, 2.0)
+
+       f = parse(t, `testing "testing"; ptr=*`, fmap2)
+       verify(t, f, `testing.T`, t)
+
+       // TODO needs more tests
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting of basic and simple composite types
+
+func check(t *testing.T, form, expected string, args ...interface{}) {
+       f := parse(t, form, nil)
+       if f == nil {
+               return // allow other tests to run
+       }
+       result := f.Sprint(args...)
+       if result != expected {
+               t.Errorf(
+                       "format  : %s\nresult  : `%s`\nexpected: `%s`\n\n",
+                       form, result, expected)
+       }
+}
+
+
+func TestBasicTypes(t *testing.T) {
+       check(t, ``, ``)
+       check(t, `bool=":%v"`, `:true:false`, true, false)
+       check(t, `int="%b %d %o 0x%x"`, `101010 42 52 0x2a`, 42)
+
+       check(t, `int="%"`, `%`, 42)
+       check(t, `int="%%"`, `%`, 42)
+       check(t, `int="**%%**"`, `**%**`, 42)
+       check(t, `int="%%%%%%"`, `%%%`, 42)
+       check(t, `int="%%%d%%"`, `%42%`, 42)
+
+       const i = -42
+       const is = `-42`
+       check(t, `int  ="%d"`, is, i)
+       check(t, `int8 ="%d"`, is, int8(i))
+       check(t, `int16="%d"`, is, int16(i))
+       check(t, `int32="%d"`, is, int32(i))
+       check(t, `int64="%d"`, is, int64(i))
+
+       const u = 42
+       const us = `42`
+       check(t, `uint  ="%d"`, us, uint(u))
+       check(t, `uint8 ="%d"`, us, uint8(u))
+       check(t, `uint16="%d"`, us, uint16(u))
+       check(t, `uint32="%d"`, us, uint32(u))
+       check(t, `uint64="%d"`, us, uint64(u))
+
+       const f = 3.141592
+       const fs = `3.141592`
+       check(t, `float  ="%g"`, fs, f)
+       check(t, `float32="%g"`, fs, float32(f))
+       check(t, `float64="%g"`, fs, float64(f))
+}
+
+
+func TestArrayTypes(t *testing.T) {
+       var a0 [10]int
+       check(t, `array="array";`, `array`, a0)
+
+       a1 := [...]int{1, 2, 3}
+       check(t, `array="array";`, `array`, a1)
+       check(t, `array={*}; int="%d";`, `123`, a1)
+       check(t, `array={* / ", "}; int="%d";`, `1, 2, 3`, a1)
+       check(t, `array={* / *}; int="%d";`, `12233`, a1)
+
+       a2 := []interface{}{42, "foo", 3.14}
+       check(t, `array={* / ", "}; interface=*; string="bar"; default="%v";`, `42, bar, 3.14`, a2)
+}
+
+
+func TestChanTypes(t *testing.T) {
+       var c0 chan int
+       check(t, `chan="chan"`, `chan`, c0)
+
+       c1 := make(chan int)
+       go func() { c1 <- 42 }()
+       check(t, `chan="chan"`, `chan`, c1)
+       // check(t, `chan=*`, `42`, c1);  // reflection support for chans incomplete
+}
+
+
+func TestFuncTypes(t *testing.T) {
+       var f0 func() int
+       check(t, `func="func"`, `func`, f0)
+
+       f1 := func() int { return 42 }
+       check(t, `func="func"`, `func`, f1)
+       // check(t, `func=*`, `42`, f1);  // reflection support for funcs incomplete
+}
+
+
+func TestMapTypes(t *testing.T) {
+       var m0 map[string]int
+       check(t, `map="map"`, `map`, m0)
+
+       m1 := map[string]int{}
+       check(t, `map="map"`, `map`, m1)
+       // check(t, `map=*`, ``, m1);  // reflection support for maps incomplete
+}
+
+
+func TestPointerTypes(t *testing.T) {
+       var p0 *int
+       check(t, `ptr="ptr"`, `ptr`, p0)
+       check(t, `ptr=*`, ``, p0)
+       check(t, `ptr=*|"nil"`, `nil`, p0)
+
+       x := 99991
+       p1 := &x
+       check(t, `ptr="ptr"`, `ptr`, p1)
+       check(t, `ptr=*; int="%d"`, `99991`, p1)
+}
+
+
+func TestDefaultRule(t *testing.T) {
+       check(t, `default="%v"`, `42foo3.14`, 42, "foo", 3.14)
+       check(t, `default="%v"; int="%x"`, `abcdef`, 10, 11, 12, 13, 14, 15)
+       check(t, `default="%v"; int="%x"`, `ab**ef`, 10, 11, "**", 14, 15)
+       check(t, `default="%x"; int=@:default`, `abcdef`, 10, 11, 12, 13, 14, 15)
+}
+
+
+func TestGlobalSeparatorRule(t *testing.T) {
+       check(t, `int="%d"; / ="-"`, `1-2-3-4`, 1, 2, 3, 4)
+       check(t, `int="%x%x"; / ="*"`, `aa*aa`, 10, 10)
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct
+
+type T1 struct {
+       a int
+}
+
+const F1 = `datafmt "datafmt";` +
+       `int = "%d";` +
+       `datafmt.T1 = "<" a ">";`
+
+func TestStruct1(t *testing.T) { check(t, F1, "<42>", T1{42}) }
+
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct with an optional field (ptr)
+
+type T2 struct {
+       s string
+       p *T1
+}
+
+const F2a = F1 +
+       `string = "%s";` +
+       `ptr = *;` +
+       `datafmt.T2 = s ["-" p "-"];`
+
+const F2b = F1 +
+       `string = "%s";` +
+       `ptr = *;` +
+       `datafmt.T2 = s ("-" p "-" | "empty");`
+
+func TestStruct2(t *testing.T) {
+       check(t, F2a, "foo", T2{"foo", nil})
+       check(t, F2a, "bar-<17>-", T2{"bar", &T1{17}})
+       check(t, F2b, "fooempty", T2{"foo", nil})
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct with a repetitive field (slice)
+
+type T3 struct {
+       s string
+       a []int
+}
+
+const F3a = `datafmt "datafmt";` +
+       `default = "%v";` +
+       `array = *;` +
+       `datafmt.T3 = s  {" " a a / ","};`
+
+const F3b = `datafmt "datafmt";` +
+       `int = "%d";` +
+       `string = "%s";` +
+       `array = *;` +
+       `nil = ;` +
+       `empty = *:nil;` +
+       `datafmt.T3 = s [a:empty ": " {a / "-"}]`
+
+func TestStruct3(t *testing.T) {
+       check(t, F3a, "foo", T3{"foo", nil})
+       check(t, F3a, "foo 00, 11, 22", T3{"foo", []int{0, 1, 2}})
+       check(t, F3b, "bar", T3{"bar", nil})
+       check(t, F3b, "bal: 2-3-5", T3{"bal", []int{2, 3, 5}})
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct with alternative field
+
+type T4 struct {
+       x *int
+       a []int
+}
+
+const F4a = `datafmt "datafmt";` +
+       `int = "%d";` +
+       `ptr = *;` +
+       `array = *;` +
+       `nil = ;` +
+       `empty = *:nil;` +
+       `datafmt.T4 = "<" (x:empty x | "-") ">" `
+
+const F4b = `datafmt "datafmt";` +
+       `int = "%d";` +
+       `ptr = *;` +
+       `array = *;` +
+       `nil = ;` +
+       `empty = *:nil;` +
+       `datafmt.T4 = "<" (a:empty {a / ", "} | "-") ">" `
+
+func TestStruct4(t *testing.T) {
+       x := 7
+       check(t, F4a, "<->", T4{nil, nil})
+       check(t, F4a, "<7>", T4{&x, nil})
+       check(t, F4b, "<->", T4{nil, nil})
+       check(t, F4b, "<2, 3, 7>", T4{nil, []int{2, 3, 7}})
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting a struct (documentation example)
+
+type Point struct {
+       name string
+       x, y int
+}
+
+const FPoint = `datafmt "datafmt";` +
+       `int = "%d";` +
+       `hexInt = "0x%x";` +
+       `string = "---%s---";` +
+       `datafmt.Point = name "{" x ", " y:hexInt "}";`
+
+func TestStructPoint(t *testing.T) {
+       p := Point{"foo", 3, 15}
+       check(t, FPoint, "---foo---{3, 0xf}", p)
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting a slice (documentation example)
+
+const FSlice = `int = "%b";` +
+       `array = { * / ", " }`
+
+func TestSlice(t *testing.T) { check(t, FSlice, "10, 11, 101, 111", []int{2, 3, 5, 7}) }
+
+
+// TODO add more tests
diff --git a/libgo/go/exp/datafmt/parser.go b/libgo/go/exp/datafmt/parser.go
new file mode 100644 (file)
index 0000000..de1f1c2
--- /dev/null
@@ -0,0 +1,379 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package datafmt
+
+import (
+       "container/vector"
+       "go/scanner"
+       "go/token"
+       "os"
+       "strconv"
+       "strings"
+)
+
+// ----------------------------------------------------------------------------
+// Parsing
+
+type parser struct {
+       scanner.ErrorVector
+       scanner scanner.Scanner
+       pos     token.Position // token position
+       tok     token.Token    // one token look-ahead
+       lit     []byte         // token literal
+
+       packs map[string]string // PackageName -> ImportPath
+       rules map[string]expr   // RuleName -> Expression
+}
+
+
+func (p *parser) next() {
+       p.pos, p.tok, p.lit = p.scanner.Scan()
+       switch p.tok {
+       case token.CHAN, token.FUNC, token.INTERFACE, token.MAP, token.STRUCT:
+               // Go keywords for composite types are type names
+               // returned by reflect. Accept them as identifiers.
+               p.tok = token.IDENT // p.lit is already set correctly
+       }
+}
+
+
+func (p *parser) init(filename string, src []byte) {
+       p.ErrorVector.Reset()
+       p.scanner.Init(filename, src, p, scanner.AllowIllegalChars) // return '@' as token.ILLEGAL w/o error message
+       p.next()                                                    // initializes pos, tok, lit
+       p.packs = make(map[string]string)
+       p.rules = make(map[string]expr)
+}
+
+
+func (p *parser) errorExpected(pos token.Position, msg string) {
+       msg = "expected " + msg
+       if pos.Offset == p.pos.Offset {
+               // the error happened at the current position;
+               // make the error message more specific
+               msg += ", found '" + p.tok.String() + "'"
+               if p.tok.IsLiteral() {
+                       msg += " " + string(p.lit)
+               }
+       }
+       p.Error(pos, msg)
+}
+
+
+func (p *parser) expect(tok token.Token) token.Position {
+       pos := p.pos
+       if p.tok != tok {
+               p.errorExpected(pos, "'"+tok.String()+"'")
+       }
+       p.next() // make progress in any case
+       return pos
+}
+
+
+func (p *parser) parseIdentifier() string {
+       name := string(p.lit)
+       p.expect(token.IDENT)
+       return name
+}
+
+
+func (p *parser) parseTypeName() (string, bool) {
+       pos := p.pos
+       name, isIdent := p.parseIdentifier(), true
+       if p.tok == token.PERIOD {
+               // got a package name, lookup package
+               if importPath, found := p.packs[name]; found {
+                       name = importPath
+               } else {
+                       p.Error(pos, "package not declared: "+name)
+               }
+               p.next()
+               name, isIdent = name+"."+p.parseIdentifier(), false
+       }
+       return name, isIdent
+}
+
+
+// Parses a rule name and returns it. If the rule name is
+// a package-qualified type name, the package name is resolved.
+// The 2nd result value is true iff the rule name consists of a
+// single identifier only (and thus could be a package name).
+//
+func (p *parser) parseRuleName() (string, bool) {
+       name, isIdent := "", false
+       switch p.tok {
+       case token.IDENT:
+               name, isIdent = p.parseTypeName()
+       case token.DEFAULT:
+               name = "default"
+               p.next()
+       case token.QUO:
+               name = "/"
+               p.next()
+       default:
+               p.errorExpected(p.pos, "rule name")
+               p.next() // make progress in any case
+       }
+       return name, isIdent
+}
+
+
+func (p *parser) parseString() string {
+       s := ""
+       if p.tok == token.STRING {
+               s, _ = strconv.Unquote(string(p.lit))
+               // Unquote may fail with an error, but only if the scanner found
+               // an illegal string in the first place. In this case the error
+               // has already been reported.
+               p.next()
+               return s
+       } else {
+               p.expect(token.STRING)
+       }
+       return s
+}
+
+
+func (p *parser) parseLiteral() literal {
+       s := []byte(p.parseString())
+
+       // A string literal may contain %-format specifiers. To simplify
+       // and speed up printing of the literal, split it into segments
+       // that start with "%" possibly followed by a last segment that
+       // starts with some other character.
+       var list vector.Vector
+       i0 := 0
+       for i := 0; i < len(s); i++ {
+               if s[i] == '%' && i+1 < len(s) {
+                       // the next segment starts with a % format
+                       if i0 < i {
+                               // the current segment is not empty, split it off
+                               list.Push(s[i0:i])
+                               i0 = i
+                       }
+                       i++ // skip %; let loop skip over char after %
+               }
+       }
+       // the final segment may start with any character
+       // (it is empty iff the string is empty)
+       list.Push(s[i0:])
+
+       // convert list into a literal
+       lit := make(literal, list.Len())
+       for i := 0; i < list.Len(); i++ {
+               lit[i] = list.At(i).([]byte)
+       }
+
+       return lit
+}
+
+
+func (p *parser) parseField() expr {
+       var fname string
+       switch p.tok {
+       case token.ILLEGAL:
+               if string(p.lit) != "@" {
+                       return nil
+               }
+               fname = "@"
+               p.next()
+       case token.MUL:
+               fname = "*"
+               p.next()
+       case token.IDENT:
+               fname = p.parseIdentifier()
+       default:
+               return nil
+       }
+
+       var ruleName string
+       if p.tok == token.COLON {
+               p.next()
+               ruleName, _ = p.parseRuleName()
+       }
+
+       return &field{fname, ruleName}
+}
+
+
+func (p *parser) parseOperand() (x expr) {
+       switch p.tok {
+       case token.STRING:
+               x = p.parseLiteral()
+
+       case token.LPAREN:
+               p.next()
+               x = p.parseExpression()
+               if p.tok == token.SHR {
+                       p.next()
+                       x = &group{x, p.parseExpression()}
+               }
+               p.expect(token.RPAREN)
+
+       case token.LBRACK:
+               p.next()
+               x = &option{p.parseExpression()}
+               p.expect(token.RBRACK)
+
+       case token.LBRACE:
+               p.next()
+               x = p.parseExpression()
+               var div expr
+               if p.tok == token.QUO {
+                       p.next()
+                       div = p.parseExpression()
+               }
+               x = &repetition{x, div}
+               p.expect(token.RBRACE)
+
+       default:
+               x = p.parseField() // may be nil
+       }
+
+       return x
+}
+
+
+func (p *parser) parseSequence() expr {
+       var list vector.Vector
+
+       for x := p.parseOperand(); x != nil; x = p.parseOperand() {
+               list.Push(x)
+       }
+
+       // no need for a sequence if list.Len() < 2
+       switch list.Len() {
+       case 0:
+               return nil
+       case 1:
+               return list.At(0).(expr)
+       }
+
+       // convert list into a sequence
+       seq := make(sequence, list.Len())
+       for i := 0; i < list.Len(); i++ {
+               seq[i] = list.At(i).(expr)
+       }
+       return seq
+}
+
+
+func (p *parser) parseExpression() expr {
+       var list vector.Vector
+
+       for {
+               x := p.parseSequence()
+               if x != nil {
+                       list.Push(x)
+               }
+               if p.tok != token.OR {
+                       break
+               }
+               p.next()
+       }
+
+       // no need for an alternatives if list.Len() < 2
+       switch list.Len() {
+       case 0:
+               return nil
+       case 1:
+               return list.At(0).(expr)
+       }
+
+       // convert list into a alternatives
+       alt := make(alternatives, list.Len())
+       for i := 0; i < list.Len(); i++ {
+               alt[i] = list.At(i).(expr)
+       }
+       return alt
+}
+
+
+func (p *parser) parseFormat() {
+       for p.tok != token.EOF {
+               pos := p.pos
+
+               name, isIdent := p.parseRuleName()
+               switch p.tok {
+               case token.STRING:
+                       // package declaration
+                       importPath := p.parseString()
+
+                       // add package declaration
+                       if !isIdent {
+                               p.Error(pos, "illegal package name: "+name)
+                       } else if _, found := p.packs[name]; !found {
+                               p.packs[name] = importPath
+                       } else {
+                               p.Error(pos, "package already declared: "+name)
+                       }
+
+               case token.ASSIGN:
+                       // format rule
+                       p.next()
+                       x := p.parseExpression()
+
+                       // add rule
+                       if _, found := p.rules[name]; !found {
+                               p.rules[name] = x
+                       } else {
+                               p.Error(pos, "format rule already declared: "+name)
+                       }
+
+               default:
+                       p.errorExpected(p.pos, "package declaration or format rule")
+                       p.next() // make progress in any case
+               }
+
+               if p.tok == token.SEMICOLON {
+                       p.next()
+               } else {
+                       break
+               }
+       }
+       p.expect(token.EOF)
+}
+
+
+func remap(p *parser, name string) string {
+       i := strings.Index(name, ".")
+       if i >= 0 {
+               packageName, suffix := name[0:i], name[i:]
+               // lookup package
+               if importPath, found := p.packs[packageName]; found {
+                       name = importPath + suffix
+               } else {
+                       var invalidPos token.Position
+                       p.Error(invalidPos, "package not declared: "+packageName)
+               }
+       }
+       return name
+}
+
+
+// Parse parses a set of format productions from source src. Custom
+// formatters may be provided via a map of formatter functions. If
+// there are no errors, the result is a Format and the error is nil.
+// Otherwise the format is nil and a non-empty ErrorList is returned.
+//
+func Parse(filename string, src []byte, fmap FormatterMap) (Format, os.Error) {
+       // parse source
+       var p parser
+       p.init(filename, src)
+       p.parseFormat()
+
+       // add custom formatters, if any
+       for name, form := range fmap {
+               name = remap(&p, name)
+               if _, found := p.rules[name]; !found {
+                       p.rules[name] = &custom{name, form}
+               } else {
+                       var invalidPos token.Position
+                       p.Error(invalidPos, "formatter already declared: "+name)
+               }
+       }
+
+       return p.rules, p.GetError(scanner.NoMultiples)
+}
diff --git a/libgo/go/exp/draw/draw.go b/libgo/go/exp/draw/draw.go
new file mode 100644 (file)
index 0000000..2f3139d
--- /dev/null
@@ -0,0 +1,386 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package draw provides basic graphics and drawing primitives,
+// in the style of the Plan 9 graphics library
+// (see http://plan9.bell-labs.com/magic/man2html/2/draw)
+// and the X Render extension.
+package draw
+
+import "image"
+
+// m is the maximum color value returned by image.Color.RGBA.
+const m = 1<<16 - 1
+
+// A Porter-Duff compositing operator.
+type Op int
+
+const (
+       // Over specifies ``(src in mask) over dst''.
+       Over Op = iota
+       // Src specifies ``src in mask''.
+       Src
+)
+
+var zeroColor image.Color = image.AlphaColor{0}
+
+// A draw.Image is an image.Image with a Set method to change a single pixel.
+type Image interface {
+       image.Image
+       Set(x, y int, c image.Color)
+}
+
+// Draw calls DrawMask with a nil mask and an Over op.
+func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
+       DrawMask(dst, r, src, sp, nil, image.ZP, Over)
+}
+
+// DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
+// in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
+func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
+       sb := src.Bounds()
+       dx, dy := sb.Max.X-sp.X, sb.Max.Y-sp.Y
+       if mask != nil {
+               mb := mask.Bounds()
+               if dx > mb.Max.X-mp.X {
+                       dx = mb.Max.X - mp.X
+               }
+               if dy > mb.Max.Y-mp.Y {
+                       dy = mb.Max.Y - mp.Y
+               }
+       }
+       if r.Dx() > dx {
+               r.Max.X = r.Min.X + dx
+       }
+       if r.Dy() > dy {
+               r.Max.Y = r.Min.Y + dy
+       }
+       r = r.Intersect(dst.Bounds())
+       if r.Empty() {
+               return
+       }
+
+       // Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
+       if dst0, ok := dst.(*image.RGBA); ok {
+               if op == Over {
+                       if mask == nil {
+                               if src0, ok := src.(*image.ColorImage); ok {
+                                       drawFillOver(dst0, r, src0)
+                                       return
+                               }
+                               if src0, ok := src.(*image.RGBA); ok {
+                                       drawCopyOver(dst0, r, src0, sp)
+                                       return
+                               }
+                       } else if mask0, ok := mask.(*image.Alpha); ok {
+                               if src0, ok := src.(*image.ColorImage); ok {
+                                       drawGlyphOver(dst0, r, src0, mask0, mp)
+                                       return
+                               }
+                       }
+               } else {
+                       if mask == nil {
+                               if src0, ok := src.(*image.ColorImage); ok {
+                                       drawFillSrc(dst0, r, src0)
+                                       return
+                               }
+                               if src0, ok := src.(*image.RGBA); ok {
+                                       drawCopySrc(dst0, r, src0, sp)
+                                       return
+                               }
+                       }
+               }
+               drawRGBA(dst0, r, src, sp, mask, mp, op)
+               return
+       }
+
+       x0, x1, dx := r.Min.X, r.Max.X, 1
+       y0, y1, dy := r.Min.Y, r.Max.Y, 1
+       if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
+               // Rectangles overlap: process backward?
+               if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
+                       x0, x1, dx = x1-1, x0-1, -1
+                       y0, y1, dy = y1-1, y0-1, -1
+               }
+       }
+
+       var out *image.RGBA64Color
+       sy := sp.Y + y0 - r.Min.Y
+       my := mp.Y + y0 - r.Min.Y
+       for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+               sx := sp.X + x0 - r.Min.X
+               mx := mp.X + x0 - r.Min.X
+               for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+                       ma := uint32(m)
+                       if mask != nil {
+                               _, _, _, ma = mask.At(mx, my).RGBA()
+                       }
+                       switch {
+                       case ma == 0:
+                               if op == Over {
+                                       // No-op.
+                               } else {
+                                       dst.Set(x, y, zeroColor)
+                               }
+                       case ma == m && op == Src:
+                               dst.Set(x, y, src.At(sx, sy))
+                       default:
+                               sr, sg, sb, sa := src.At(sx, sy).RGBA()
+                               if out == nil {
+                                       out = new(image.RGBA64Color)
+                               }
+                               if op == Over {
+                                       dr, dg, db, da := dst.At(x, y).RGBA()
+                                       a := m - (sa * ma / m)
+                                       out.R = uint16((dr*a + sr*ma) / m)
+                                       out.G = uint16((dg*a + sg*ma) / m)
+                                       out.B = uint16((db*a + sb*ma) / m)
+                                       out.A = uint16((da*a + sa*ma) / m)
+                               } else {
+                                       out.R = uint16(sr * ma / m)
+                                       out.G = uint16(sg * ma / m)
+                                       out.B = uint16(sb * ma / m)
+                                       out.A = uint16(sa * ma / m)
+                               }
+                               dst.Set(x, y, out)
+                       }
+               }
+       }
+}
+
+func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
+       cr, cg, cb, ca := src.RGBA()
+       // The 0x101 is here for the same reason as in drawRGBA.
+       a := (m - ca) * 0x101
+       x0, x1 := r.Min.X, r.Max.X
+       y0, y1 := r.Min.Y, r.Max.Y
+       for y := y0; y != y1; y++ {
+               dbase := y * dst.Stride
+               dpix := dst.Pix[dbase+x0 : dbase+x1]
+               for i, rgba := range dpix {
+                       dr := (uint32(rgba.R)*a)/m + cr
+                       dg := (uint32(rgba.G)*a)/m + cg
+                       db := (uint32(rgba.B)*a)/m + cb
+                       da := (uint32(rgba.A)*a)/m + ca
+                       dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+               }
+       }
+}
+
+func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
+       dx0, dx1 := r.Min.X, r.Max.X
+       dy0, dy1 := r.Min.Y, r.Max.Y
+       nrows := dy1 - dy0
+       sx0, sx1 := sp.X, sp.X+dx1-dx0
+       d0 := dy0*dst.Stride + dx0
+       d1 := dy0*dst.Stride + dx1
+       s0 := sp.Y*src.Stride + sx0
+       s1 := sp.Y*src.Stride + sx1
+       var (
+               ddelta, sdelta int
+               i0, i1, idelta int
+       )
+       if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
+               ddelta = dst.Stride
+               sdelta = src.Stride
+               i0, i1, idelta = 0, d1-d0, +1
+       } else {
+               // If the source start point is higher than the destination start point, or equal height but to the left,
+               // then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
+               d0 += (nrows - 1) * dst.Stride
+               d1 += (nrows - 1) * dst.Stride
+               s0 += (nrows - 1) * src.Stride
+               s1 += (nrows - 1) * src.Stride
+               ddelta = -dst.Stride
+               sdelta = -src.Stride
+               i0, i1, idelta = d1-d0-1, -1, -1
+       }
+       for ; nrows > 0; nrows-- {
+               dpix := dst.Pix[d0:d1]
+               spix := src.Pix[s0:s1]
+               for i := i0; i != i1; i += idelta {
+                       // For unknown reasons, even though both dpix[i] and spix[i] are
+                       // image.RGBAColors, on an x86 CPU it seems fastest to call RGBA
+                       // for the source but to do it manually for the destination.
+                       sr, sg, sb, sa := spix[i].RGBA()
+                       rgba := dpix[i]
+                       dr := uint32(rgba.R)
+                       dg := uint32(rgba.G)
+                       db := uint32(rgba.B)
+                       da := uint32(rgba.A)
+                       // The 0x101 is here for the same reason as in drawRGBA.
+                       a := (m - sa) * 0x101
+                       dr = (dr*a)/m + sr
+                       dg = (dg*a)/m + sg
+                       db = (db*a)/m + sb
+                       da = (da*a)/m + sa
+                       dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+               }
+               d0 += ddelta
+               d1 += ddelta
+               s0 += sdelta
+               s1 += sdelta
+       }
+}
+
+func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
+       x0, x1 := r.Min.X, r.Max.X
+       y0, y1 := r.Min.Y, r.Max.Y
+       cr, cg, cb, ca := src.RGBA()
+       for y, my := y0, mp.Y; y != y1; y, my = y+1, my+1 {
+               dbase := y * dst.Stride
+               dpix := dst.Pix[dbase+x0 : dbase+x1]
+               mbase := my * mask.Stride
+               mpix := mask.Pix[mbase+mp.X:]
+               for i, rgba := range dpix {
+                       ma := uint32(mpix[i].A)
+                       if ma == 0 {
+                               continue
+                       }
+                       ma |= ma << 8
+                       dr := uint32(rgba.R)
+                       dg := uint32(rgba.G)
+                       db := uint32(rgba.B)
+                       da := uint32(rgba.A)
+                       // The 0x101 is here for the same reason as in drawRGBA.
+                       a := (m - (ca * ma / m)) * 0x101
+                       dr = (dr*a + cr*ma) / m
+                       dg = (dg*a + cg*ma) / m
+                       db = (db*a + cb*ma) / m
+                       da = (da*a + ca*ma) / m
+                       dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+               }
+       }
+}
+
+func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
+       if r.Dy() < 1 {
+               return
+       }
+       cr, cg, cb, ca := src.RGBA()
+       color := image.RGBAColor{uint8(cr >> 8), uint8(cg >> 8), uint8(cb >> 8), uint8(ca >> 8)}
+       // The built-in copy function is faster than a straightforward for loop to fill the destination with
+       // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
+       // then use the first row as the slice source for the remaining rows.
+       dx0, dx1 := r.Min.X, r.Max.X
+       dy0, dy1 := r.Min.Y, r.Max.Y
+       dbase := dy0 * dst.Stride
+       i0, i1 := dbase+dx0, dbase+dx1
+       firstRow := dst.Pix[i0:i1]
+       for i, _ := range firstRow {
+               firstRow[i] = color
+       }
+       for y := dy0 + 1; y < dy1; y++ {
+               i0 += dst.Stride
+               i1 += dst.Stride
+               copy(dst.Pix[i0:i1], firstRow)
+       }
+}
+
+func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
+       dx0, dx1 := r.Min.X, r.Max.X
+       dy0, dy1 := r.Min.Y, r.Max.Y
+       nrows := dy1 - dy0
+       sx0, sx1 := sp.X, sp.X+dx1-dx0
+       d0 := dy0*dst.Stride + dx0
+       d1 := dy0*dst.Stride + dx1
+       s0 := sp.Y*src.Stride + sx0
+       s1 := sp.Y*src.Stride + sx1
+       var ddelta, sdelta int
+       if r.Min.Y <= sp.Y {
+               ddelta = dst.Stride
+               sdelta = src.Stride
+       } else {
+               // If the source start point is higher than the destination start point, then we compose the rows
+               // in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
+               // check the x co-ordinates because the built-in copy function can handle overlapping slices.
+               d0 += (nrows - 1) * dst.Stride
+               d1 += (nrows - 1) * dst.Stride
+               s0 += (nrows - 1) * src.Stride
+               s1 += (nrows - 1) * src.Stride
+               ddelta = -dst.Stride
+               sdelta = -src.Stride
+       }
+       for ; nrows > 0; nrows-- {
+               copy(dst.Pix[d0:d1], src.Pix[s0:s1])
+               d0 += ddelta
+               d1 += ddelta
+               s0 += sdelta
+               s1 += sdelta
+       }
+}
+
+func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
+       x0, x1, dx := r.Min.X, r.Max.X, 1
+       y0, y1, dy := r.Min.Y, r.Max.Y, 1
+       if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
+               if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
+                       x0, x1, dx = x1-1, x0-1, -1
+                       y0, y1, dy = y1-1, y0-1, -1
+               }
+       }
+
+       sy := sp.Y + y0 - r.Min.Y
+       my := mp.Y + y0 - r.Min.Y
+       for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+               sx := sp.X + x0 - r.Min.X
+               mx := mp.X + x0 - r.Min.X
+               dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
+               for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+                       ma := uint32(m)
+                       if mask != nil {
+                               _, _, _, ma = mask.At(mx, my).RGBA()
+                       }
+                       sr, sg, sb, sa := src.At(sx, sy).RGBA()
+                       var dr, dg, db, da uint32
+                       if op == Over {
+                               rgba := dpix[x]
+                               dr = uint32(rgba.R)
+                               dg = uint32(rgba.G)
+                               db = uint32(rgba.B)
+                               da = uint32(rgba.A)
+                               // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
+                               // We work in 16-bit color, and so would normally do:
+                               // dr |= dr << 8
+                               // and similarly for dg, db and da, but instead we multiply a
+                               // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
+                               // This yields the same result, but is fewer arithmetic operations.
+                               a := (m - (sa * ma / m)) * 0x101
+                               dr = (dr*a + sr*ma) / m
+                               dg = (dg*a + sg*ma) / m
+                               db = (db*a + sb*ma) / m
+                               da = (da*a + sa*ma) / m
+                       } else {
+                               dr = sr * ma / m
+                               dg = sg * ma / m
+                               db = sb * ma / m
+                               da = sa * ma / m
+                       }
+                       dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+               }
+       }
+}
+
+// Border aligns r.Min in dst with sp in src and then replaces pixels
+// in a w-pixel border around r in dst with the result of the Porter-Duff compositing
+// operation ``src over dst.''  If w is positive, the border extends w pixels inside r.
+// If w is negative, the border extends w pixels outside r.
+func Border(dst Image, r image.Rectangle, w int, src image.Image, sp image.Point) {
+       i := w
+       if i > 0 {
+               // inside r
+               Draw(dst, image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+i), src, sp)                                // top
+               Draw(dst, image.Rect(r.Min.X, r.Min.Y+i, r.Min.X+i, r.Max.Y-i), src, sp.Add(image.Pt(0, i)))        // left
+               Draw(dst, image.Rect(r.Max.X-i, r.Min.Y+i, r.Max.X, r.Max.Y-i), src, sp.Add(image.Pt(r.Dx()-i, i))) // right
+               Draw(dst, image.Rect(r.Min.X, r.Max.Y-i, r.Max.X, r.Max.Y), src, sp.Add(image.Pt(0, r.Dy()-i)))     // bottom
+               return
+       }
+
+       // outside r;
+       i = -i
+       Draw(dst, image.Rect(r.Min.X-i, r.Min.Y-i, r.Max.X+i, r.Min.Y), src, sp.Add(image.Pt(-i, -i))) // top
+       Draw(dst, image.Rect(r.Min.X-i, r.Min.Y, r.Min.X, r.Max.Y), src, sp.Add(image.Pt(-i, 0)))      // left
+       Draw(dst, image.Rect(r.Max.X, r.Min.Y, r.Max.X+i, r.Max.Y), src, sp.Add(image.Pt(r.Dx(), 0)))  // right
+       Draw(dst, image.Rect(r.Min.X-i, r.Max.Y, r.Max.X+i, r.Max.Y+i), src, sp.Add(image.Pt(-i, 0)))  // bottom
+}
diff --git a/libgo/go/exp/draw/draw_test.go b/libgo/go/exp/draw/draw_test.go
new file mode 100644 (file)
index 0000000..90c9e82
--- /dev/null
@@ -0,0 +1,228 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import (
+       "image"
+       "testing"
+)
+
+func eq(c0, c1 image.Color) bool {
+       r0, g0, b0, a0 := c0.RGBA()
+       r1, g1, b1, a1 := c1.RGBA()
+       return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
+}
+
+func fillBlue(alpha int) image.Image {
+       return image.NewColorImage(image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)})
+}
+
+func fillAlpha(alpha int) image.Image {
+       return image.NewColorImage(image.AlphaColor{uint8(alpha)})
+}
+
+func vgradGreen(alpha int) image.Image {
+       m := image.NewRGBA(16, 16)
+       for y := 0; y < 16; y++ {
+               for x := 0; x < 16; x++ {
+                       m.Set(x, y, image.RGBAColor{0, uint8(y * alpha / 15), 0, uint8(alpha)})
+               }
+       }
+       return m
+}
+
+func vgradAlpha(alpha int) image.Image {
+       m := image.NewAlpha(16, 16)
+       for y := 0; y < 16; y++ {
+               for x := 0; x < 16; x++ {
+                       m.Set(x, y, image.AlphaColor{uint8(y * alpha / 15)})
+               }
+       }
+       return m
+}
+
+func hgradRed(alpha int) Image {
+       m := image.NewRGBA(16, 16)
+       for y := 0; y < 16; y++ {
+               for x := 0; x < 16; x++ {
+                       m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), 0, 0, uint8(alpha)})
+               }
+       }
+       return m
+}
+
+func gradYellow(alpha int) Image {
+       m := image.NewRGBA(16, 16)
+       for y := 0; y < 16; y++ {
+               for x := 0; x < 16; x++ {
+                       m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), uint8(y * alpha / 15), 0, uint8(alpha)})
+               }
+       }
+       return m
+}
+
+type drawTest struct {
+       desc     string
+       src      image.Image
+       mask     image.Image
+       op       Op
+       expected image.Color
+}
+
+var drawTests = []drawTest{
+       // Uniform mask (0% opaque).
+       {"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}},
+       {"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}},
+       // Uniform mask (100%, 75%, nil) and uniform source.
+       // At (x, y) == (8, 8):
+       // The destination pixel is {136, 0, 0, 255}.
+       // The source pixel is {0, 0, 90, 90}.
+       {"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}},
+       {"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}},
+       {"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}},
+       {"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}},
+       {"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}},
+       {"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}},
+       // Uniform mask (100%, 75%, nil) and variable source.
+       // At (x, y) == (8, 8):
+       // The destination pixel is {136, 0, 0, 255}.
+       // The source pixel is {0, 48, 0, 90}.
+       {"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}},
+       {"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}},
+       {"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}},
+       {"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}},
+       {"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}},
+       {"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}},
+       // Variable mask and variable source.
+       // At (x, y) == (8, 8):
+       // The destination pixel is {136, 0, 0, 255}.
+       // The source pixel is {0, 0, 255, 255}.
+       // The mask pixel's alpha is 102, or 40%.
+       {"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}},
+       {"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
+}
+
+func makeGolden(dst, src, mask image.Image, op Op) image.Image {
+       // Since golden is a newly allocated image, we don't have to check if the
+       // input source and mask images and the output golden image overlap.
+       b := dst.Bounds()
+       sx0 := src.Bounds().Min.X - b.Min.X
+       sy0 := src.Bounds().Min.Y - b.Min.Y
+       var mx0, my0 int
+       if mask != nil {
+               mx0 = mask.Bounds().Min.X - b.Min.X
+               my0 = mask.Bounds().Min.Y - b.Min.Y
+       }
+       golden := image.NewRGBA(b.Max.X, b.Max.Y)
+       for y := b.Min.Y; y < b.Max.Y; y++ {
+               my, sy := my0+y, sy0+y
+               for x := b.Min.X; x < b.Max.X; x++ {
+                       mx, sx := mx0+x, sx0+x
+                       const M = 1<<16 - 1
+                       var dr, dg, db, da uint32
+                       if op == Over {
+                               dr, dg, db, da = dst.At(x, y).RGBA()
+                       }
+                       sr, sg, sb, sa := src.At(sx, sy).RGBA()
+                       ma := uint32(M)
+                       if mask != nil {
+                               _, _, _, ma = mask.At(mx, my).RGBA()
+                       }
+                       a := M - (sa * ma / M)
+                       golden.Set(x, y, image.RGBA64Color{
+                               uint16((dr*a + sr*ma) / M),
+                               uint16((dg*a + sg*ma) / M),
+                               uint16((db*a + sb*ma) / M),
+                               uint16((da*a + sa*ma) / M),
+                       })
+               }
+       }
+       golden.Rect = b
+       return golden
+}
+
+func TestDraw(t *testing.T) {
+loop:
+       for _, test := range drawTests {
+               dst := hgradRed(255)
+               // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+               golden := makeGolden(dst, test.src, test.mask, test.op)
+               b := dst.Bounds()
+               if !b.Eq(golden.Bounds()) {
+                       t.Errorf("draw %s: bounds %v versus %v", test.desc, dst.Bounds(), golden.Bounds())
+                       continue
+               }
+               // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+               DrawMask(dst, b, test.src, image.ZP, test.mask, image.ZP, test.op)
+               // Check that the resultant pixel at (8, 8) matches what we expect
+               // (the expected value can be verified by hand).
+               if !eq(dst.At(8, 8), test.expected) {
+                       t.Errorf("draw %s: at (8, 8) %v versus %v", test.desc, dst.At(8, 8), test.expected)
+                       continue
+               }
+               // Check that the resultant dst image matches the golden output.
+               for y := b.Min.Y; y < b.Max.Y; y++ {
+                       for x := b.Min.X; x < b.Max.X; x++ {
+                               if !eq(dst.At(x, y), golden.At(x, y)) {
+                                       t.Errorf("draw %s: at (%d, %d), %v versus golden %v", test.desc, x, y, dst.At(x, y), golden.At(x, y))
+                                       continue loop
+                               }
+                       }
+               }
+       }
+}
+
+func TestDrawOverlap(t *testing.T) {
+       for _, op := range []Op{Over, Src} {
+               for yoff := -2; yoff <= 2; yoff++ {
+               loop:
+                       for xoff := -2; xoff <= 2; xoff++ {
+                               m := gradYellow(127).(*image.RGBA)
+                               dst := &image.RGBA{
+                                       Pix:    m.Pix,
+                                       Stride: m.Stride,
+                                       Rect:   image.Rect(5, 5, 10, 10),
+                               }
+                               src := &image.RGBA{
+                                       Pix:    m.Pix,
+                                       Stride: m.Stride,
+                                       Rect:   image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff),
+                               }
+                               // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+                               golden := makeGolden(dst, src, nil, op)
+                               b := dst.Bounds()
+                               if !b.Eq(golden.Bounds()) {
+                                       t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
+                                       continue
+                               }
+                               // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+                               DrawMask(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
+                               // Check that the resultant dst image matches the golden output.
+                               for y := b.Min.Y; y < b.Max.Y; y++ {
+                                       for x := b.Min.X; x < b.Max.X; x++ {
+                                               if !eq(dst.At(x, y), golden.At(x, y)) {
+                                                       t.Errorf("drawOverlap xoff=%d,yoff=%d: at (%d, %d), %v versus golden %v", xoff, yoff, x, y, dst.At(x, y), golden.At(x, y))
+                                                       continue loop
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+// TestIssue836 verifies http://code.google.com/p/go/issues/detail?id=836.
+func TestIssue836(t *testing.T) {
+       a := image.NewRGBA(1, 1)
+       b := image.NewRGBA(2, 2)
+       b.Set(0, 0, image.RGBAColor{0, 0, 0, 5})
+       b.Set(1, 0, image.RGBAColor{0, 0, 5, 5})
+       b.Set(0, 1, image.RGBAColor{0, 5, 0, 5})
+       b.Set(1, 1, image.RGBAColor{5, 0, 0, 5})
+       Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1))
+       if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
+               t.Errorf("Issue 836: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
+       }
+}
diff --git a/libgo/go/exp/draw/event.go b/libgo/go/exp/draw/event.go
new file mode 100644 (file)
index 0000000..b777d91
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import (
+       "image"
+       "os"
+)
+
+// A Window represents a single graphics window.
+type Window interface {
+       // Screen returns an editable Image for the window.
+       Screen() Image
+       // FlushImage flushes changes made to Screen() back to screen.
+       FlushImage()
+       // EventChan returns a channel carrying UI events such as key presses,
+       // mouse movements and window resizes.
+       EventChan() <-chan interface{}
+       // Close closes the window.
+       Close() os.Error
+}
+
+// A KeyEvent is sent for a key press or release.
+type KeyEvent struct {
+       // The value k represents key k being pressed.
+       // The value -k represents key k being released.
+       // The specific set of key values is not specified,
+       // but ordinary characters represent themselves.
+       Key int
+}
+
+// A MouseEvent is sent for a button press or release or for a mouse movement.
+type MouseEvent struct {
+       // Buttons is a bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right.
+       // It represents button state and not necessarily the state delta: bit 0
+       // being on means that the left mouse button is down, but does not imply
+       // that the same button was up in the previous MouseEvent.
+       Buttons int
+       // Loc is the location of the cursor.
+       Loc image.Point
+       // Nsec is the event's timestamp.
+       Nsec int64
+}
+
+// A ConfigEvent is sent each time the window's color model or size changes.
+// The client should respond by calling Window.Screen to obtain a new image.
+type ConfigEvent struct {
+       Config image.Config
+}
+
+// An ErrEvent is sent when an error occurs.
+type ErrEvent struct {
+       Err os.Error
+}
diff --git a/libgo/go/exp/draw/x11/auth.go b/libgo/go/exp/draw/x11/auth.go
new file mode 100644 (file)
index 0000000..896dedf
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x11
+
+import (
+       "bufio"
+       "io"
+       "os"
+)
+
+// readU16BE reads a big-endian uint16 from r, using b as a scratch buffer.
+func readU16BE(r io.Reader, b []byte) (uint16, os.Error) {
+       _, err := io.ReadFull(r, b[0:2])
+       if err != nil {
+               return 0, err
+       }
+       return uint16(b[0])<<8 + uint16(b[1]), nil
+}
+
+// readStr reads a length-prefixed string from r, using b as a scratch buffer.
+func readStr(r io.Reader, b []byte) (string, os.Error) {
+       n, err := readU16BE(r, b)
+       if err != nil {
+               return "", err
+       }
+       if int(n) > len(b) {
+               return "", os.NewError("Xauthority entry too long for buffer")
+       }
+       _, err = io.ReadFull(r, b[0:n])
+       if err != nil {
+               return "", err
+       }
+       return string(b[0:n]), nil
+}
+
+// readAuth reads the X authority file and returns the name/data pair for the display.
+// displayStr is the "12" out of a $DISPLAY like ":12.0".
+func readAuth(displayStr string) (name, data string, err os.Error) {
+       // b is a scratch buffer to use and should be at least 256 bytes long
+       // (i.e. it should be able to hold a hostname).
+       var b [256]byte
+       // As per /usr/include/X11/Xauth.h.
+       const familyLocal = 256
+
+       fn := os.Getenv("XAUTHORITY")
+       if fn == "" {
+               home := os.Getenv("HOME")
+               if home == "" {
+                       err = os.NewError("Xauthority not found: $XAUTHORITY, $HOME not set")
+                       return
+               }
+               fn = home + "/.Xauthority"
+       }
+       r, err := os.Open(fn, os.O_RDONLY, 0444)
+       if err != nil {
+               return
+       }
+       defer r.Close()
+       br := bufio.NewReader(r)
+
+       hostname, err := os.Hostname()
+       if err != nil {
+               return
+       }
+       for {
+               family, err := readU16BE(br, b[0:2])
+               if err != nil {
+                       return
+               }
+               addr, err := readStr(br, b[0:])
+               if err != nil {
+                       return
+               }
+               disp, err := readStr(br, b[0:])
+               if err != nil {
+                       return
+               }
+               name0, err := readStr(br, b[0:])
+               if err != nil {
+                       return
+               }
+               data0, err := readStr(br, b[0:])
+               if err != nil {
+                       return
+               }
+               if family == familyLocal && addr == hostname && disp == displayStr {
+                       return name0, data0, nil
+               }
+       }
+       panic("unreachable")
+}
diff --git a/libgo/go/exp/draw/x11/conn.go b/libgo/go/exp/draw/x11/conn.go
new file mode 100644 (file)
index 0000000..da21815
--- /dev/null
@@ -0,0 +1,622 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements an X11 backend for the exp/draw package.
+//
+// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf.
+// A summary of the wire format can be found in XCB's xproto.xml.
+package x11
+
+import (
+       "bufio"
+       "exp/draw"
+       "image"
+       "io"
+       "log"
+       "net"
+       "os"
+       "strconv"
+       "strings"
+       "time"
+)
+
+type resID uint32 // X resource IDs.
+
+// TODO(nigeltao): Handle window resizes.
+const (
+       windowHeight = 600
+       windowWidth  = 800
+)
+
+const (
+       keymapLo = 8
+       keymapHi = 255
+)
+
+type conn struct {
+       c io.Closer
+       r *bufio.Reader
+       w *bufio.Writer
+
+       gc, window, root, visual resID
+
+       img        *image.RGBA
+       eventc     chan interface{}
+       mouseState draw.MouseEvent
+
+       buf [256]byte // General purpose scratch buffer.
+
+       flush     chan bool
+       flushBuf0 [24]byte
+       flushBuf1 [4 * 1024]byte
+}
+
+// writeSocket runs in its own goroutine, serving both FlushImage calls
+// directly from the exp/draw client and indirectly from X expose events.
+// It paints c.img to the X server via PutImage requests.
+func (c *conn) writeSocket() {
+       defer c.c.Close()
+       for _ = range c.flush {
+               b := c.img.Bounds()
+               if b.Empty() {
+                       continue
+               }
+               // Each X request has a 16-bit length (in terms of 4-byte units). To avoid going over
+               // this limit, we send PutImage for each row of the image, rather than trying to paint
+               // the entire image in one X request. This approach could easily be optimized (or the
+               // X protocol may have an escape sequence to delimit very large requests).
+               // TODO(nigeltao): See what XCB's xcb_put_image does in this situation.
+               units := 6 + b.Dx()
+               if units > 0xffff || b.Dy() > 0xffff {
+                       log.Print("x11: window is too large for PutImage")
+                       return
+               }
+
+               c.flushBuf0[0] = 0x48 // PutImage opcode.
+               c.flushBuf0[1] = 0x02 // XCB_IMAGE_FORMAT_Z_PIXMAP.
+               c.flushBuf0[2] = uint8(units)
+               c.flushBuf0[3] = uint8(units >> 8)
+               setU32LE(c.flushBuf0[4:8], uint32(c.window))
+               setU32LE(c.flushBuf0[8:12], uint32(c.gc))
+               setU32LE(c.flushBuf0[12:16], 1<<16|uint32(b.Dx()))
+               c.flushBuf0[21] = 0x18 // depth = 24 bits.
+
+               for y := b.Min.Y; y < b.Max.Y; y++ {
+                       setU32LE(c.flushBuf0[16:20], uint32(y<<16))
+                       if _, err := c.w.Write(c.flushBuf0[0:24]); err != nil {
+                               if err != os.EOF {
+                                       log.Println("x11:", err.String())
+                               }
+                               return
+                       }
+                       p := c.img.Pix[y*c.img.Stride : (y+1)*c.img.Stride]
+                       for x := b.Min.X; x < b.Max.X; {
+                               nx := b.Max.X - x
+                               if nx > len(c.flushBuf1)/4 {
+                                       nx = len(c.flushBuf1) / 4
+                               }
+                               for i, rgba := range p[x : x+nx] {
+                                       c.flushBuf1[4*i+0] = rgba.B
+                                       c.flushBuf1[4*i+1] = rgba.G
+                                       c.flushBuf1[4*i+2] = rgba.R
+                               }
+                               x += nx
+                               if _, err := c.w.Write(c.flushBuf1[0 : 4*nx]); err != nil {
+                                       if err != os.EOF {
+                                               log.Println("x11:", err.String())
+                                       }
+                                       return
+                               }
+                       }
+               }
+               if err := c.w.Flush(); err != nil {
+                       if err != os.EOF {
+                               log.Println("x11:", err.String())
+                       }
+                       return
+               }
+       }
+}
+
+func (c *conn) Screen() draw.Image { return c.img }
+
+func (c *conn) FlushImage() {
+       // We do the send (the <- operator) in an expression context, rather than in
+       // a statement context, so that it does not block, and fails if the buffered
+       // channel is full (in which case there already is a flush request pending).
+       _ = c.flush <- false
+}
+
+func (c *conn) Close() os.Error {
+       // Shut down the writeSocket goroutine. This will close the socket to the
+       // X11 server, which will cause c.eventc to close.
+       close(c.flush)
+       for _ = range c.eventc {
+               // Drain the channel to allow the readSocket goroutine to shut down.
+       }
+       return nil
+}
+
+func (c *conn) EventChan() <-chan interface{} { return c.eventc }
+
+// readSocket runs in its own goroutine, reading X events and sending draw
+// events on c's EventChan.
+func (c *conn) readSocket() {
+       var (
+               keymap            [256][]int
+               keysymsPerKeycode int
+       )
+       defer close(c.eventc)
+       for {
+               // X events are always 32 bytes long.
+               if _, err := io.ReadFull(c.r, c.buf[0:32]); err != nil {
+                       if err != os.EOF {
+                               c.eventc <- draw.ErrEvent{err}
+                       }
+                       return
+               }
+               switch c.buf[0] {
+               case 0x01: // Reply from a request (e.g. GetKeyboardMapping).
+                       cookie := int(c.buf[3])<<8 | int(c.buf[2])
+                       if cookie != 1 {
+                               // We issued only one request (GetKeyboardMapping) with a cookie of 1,
+                               // so we shouldn't get any other reply from the X server.
+                               c.eventc <- draw.ErrEvent{os.NewError("x11: unexpected cookie")}
+                               return
+                       }
+                       keysymsPerKeycode = int(c.buf[1])
+                       b := make([]int, 256*keysymsPerKeycode)
+                       for i := range keymap {
+                               keymap[i] = b[i*keysymsPerKeycode : (i+1)*keysymsPerKeycode]
+                       }
+                       for i := keymapLo; i <= keymapHi; i++ {
+                               m := keymap[i]
+                               for j := range m {
+                                       u, err := readU32LE(c.r, c.buf[0:4])
+                                       if err != nil {
+                                               if err != os.EOF {
+                                                       c.eventc <- draw.ErrEvent{err}
+                                               }
+                                               return
+                                       }
+                                       m[j] = int(u)
+                               }
+                       }
+               case 0x02, 0x03: // Key press, key release.
+                       // X Keyboard Encoding is documented at http://tronche.com/gui/x/xlib/input/keyboard-encoding.html
+                       // TODO(nigeltao): Do we need to implement the "MODE SWITCH / group modifier" feature
+                       // or is that some no-longer-used X construct?
+                       if keysymsPerKeycode < 2 {
+                               // Either we haven't yet received the GetKeyboardMapping reply or
+                               // the X server has sent one that's too short.
+                               continue
+                       }
+                       keycode := int(c.buf[1])
+                       shift := int(c.buf[28]) & 0x01
+                       keysym := keymap[keycode][shift]
+                       if keysym == 0 {
+                               keysym = keymap[keycode][0]
+                       }
+                       // TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send
+                       // the same int down the channel as the sent on just the A key?
+                       // TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or
+                       // is that outside the scope of the draw.Window interface?
+                       if c.buf[0] == 0x03 {
+                               keysym = -keysym
+                       }
+                       c.eventc <- draw.KeyEvent{keysym}
+               case 0x04, 0x05: // Button press, button release.
+                       mask := 1 << (c.buf[1] - 1)
+                       if c.buf[0] == 0x04 {
+                               c.mouseState.Buttons |= mask
+                       } else {
+                               c.mouseState.Buttons &^= mask
+                       }
+                       c.mouseState.Nsec = time.Nanoseconds()
+                       c.eventc <- c.mouseState
+               case 0x06: // Motion notify.
+                       c.mouseState.Loc.X = int(int16(c.buf[25])<<8 | int16(c.buf[24]))
+                       c.mouseState.Loc.Y = int(int16(c.buf[27])<<8 | int16(c.buf[26]))
+                       c.mouseState.Nsec = time.Nanoseconds()
+                       c.eventc <- c.mouseState
+               case 0x0c: // Expose.
+                       // A single user action could trigger multiple expose events (e.g. if moving another
+                       // window with XShape'd rounded corners over our window). In that case, the X server will
+                       // send a uint16 count (in bytes 16-17) of the number of additional expose events coming.
+                       // We could parse each event for the (x, y, width, height) and maintain a minimal dirty
+                       // rectangle, but for now, the simplest approach is to paint the entire window, when
+                       // receiving the final event in the series.
+                       if c.buf[17] == 0 && c.buf[16] == 0 {
+                               // TODO(nigeltao): Should we ignore the very first expose event? A freshly mapped window
+                               // will trigger expose, but until the first c.FlushImage call, there's probably nothing to
+                               // paint but black. For an 800x600 window, at 4 bytes per pixel, each repaint writes about
+                               // 2MB over the socket.
+                               c.FlushImage()
+                       }
+                       // TODO(nigeltao): Should we listen to DestroyNotify (0x11) and ResizeRequest (0x19) events?
+                       // What about EnterNotify (0x07) and LeaveNotify (0x08)?
+               }
+       }
+}
+
+// connect connects to the X server given by the full X11 display name (e.g.
+// ":12.0") and returns the connection as well as the portion of the full name
+// that is the display number (e.g. "12").
+// Examples:
+//     connect(":1")                 // calls net.Dial("unix", "", "/tmp/.X11-unix/X1"), displayStr="1"
+//     connect("/tmp/launch-123/:0") // calls net.Dial("unix", "", "/tmp/launch-123/:0"), displayStr="0"
+//     connect("hostname:2.1")       // calls net.Dial("tcp", "", "hostname:6002"), displayStr="2"
+//     connect("tcp/hostname:1.0")   // calls net.Dial("tcp", "", "hostname:6001"), displayStr="1"
+func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
+       colonIdx := strings.LastIndex(display, ":")
+       if colonIdx < 0 {
+               return nil, "", os.NewError("bad display: " + display)
+       }
+       // Parse the section before the colon.
+       var protocol, host, socket string
+       if display[0] == '/' {
+               socket = display[0:colonIdx]
+       } else {
+               if i := strings.LastIndex(display, "/"); i < 0 {
+                       // The default protocol is TCP.
+                       protocol = "tcp"
+                       host = display[0:colonIdx]
+               } else {
+                       protocol = display[0:i]
+                       host = display[i+1 : colonIdx]
+               }
+       }
+       // Parse the section after the colon.
+       after := display[colonIdx+1:]
+       if after == "" {
+               return nil, "", os.NewError("bad display: " + display)
+       }
+       if i := strings.LastIndex(after, "."); i < 0 {
+               displayStr = after
+       } else {
+               displayStr = after[0:i]
+       }
+       displayInt, err := strconv.Atoi(displayStr)
+       if err != nil || displayInt < 0 {
+               return nil, "", os.NewError("bad display: " + display)
+       }
+       // Make the connection.
+       if socket != "" {
+               conn, err = net.Dial("unix", "", socket+":"+displayStr)
+       } else if host != "" {
+               conn, err = net.Dial(protocol, "", host+":"+strconv.Itoa(6000+displayInt))
+       } else {
+               conn, err = net.Dial("unix", "", "/tmp/.X11-unix/X"+displayStr)
+       }
+       if err != nil {
+               return nil, "", os.NewError("cannot connect to " + display + ": " + err.String())
+       }
+       return
+}
+
+// authenticate authenticates ourselves with the X server.
+// displayStr is the "12" out of ":12.0".
+func authenticate(w *bufio.Writer, displayStr string) os.Error {
+       key, value, err := readAuth(displayStr)
+       if err != nil {
+               return err
+       }
+       // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
+       if len(key) != 18 || len(value) != 16 {
+               return os.NewError("unsupported Xauth")
+       }
+       // 0x006c means little-endian. 0x000b, 0x0000 means X major version 11, minor version 0.
+       // 0x0012 and 0x0010 means the auth key and value have lenths 18 and 16.
+       // The final 0x0000 is padding, so that the string length is a multiple of 4.
+       _, err = io.WriteString(w, "\x6c\x00\x0b\x00\x00\x00\x12\x00\x10\x00\x00\x00")
+       if err != nil {
+               return err
+       }
+       _, err = io.WriteString(w, key)
+       if err != nil {
+               return err
+       }
+       // Again, the 0x0000 is padding.
+       _, err = io.WriteString(w, "\x00\x00")
+       if err != nil {
+               return err
+       }
+       _, err = io.WriteString(w, value)
+       if err != nil {
+               return err
+       }
+       err = w.Flush()
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+// readU8 reads a uint8 from r, using b as a scratch buffer.
+func readU8(r io.Reader, b []byte) (uint8, os.Error) {
+       _, err := io.ReadFull(r, b[0:1])
+       if err != nil {
+               return 0, err
+       }
+       return uint8(b[0]), nil
+}
+
+// readU16LE reads a little-endian uint16 from r, using b as a scratch buffer.
+func readU16LE(r io.Reader, b []byte) (uint16, os.Error) {
+       _, err := io.ReadFull(r, b[0:2])
+       if err != nil {
+               return 0, err
+       }
+       return uint16(b[0]) | uint16(b[1])<<8, nil
+}
+
+// readU32LE reads a little-endian uint32 from r, using b as a scratch buffer.
+func readU32LE(r io.Reader, b []byte) (uint32, os.Error) {
+       _, err := io.ReadFull(r, b[0:4])
+       if err != nil {
+               return 0, err
+       }
+       return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil
+}
+
+// setU32LE sets b[0:4] to be the little-endian representation of u.
+func setU32LE(b []byte, u uint32) {
+       b[0] = byte((u >> 0) & 0xff)
+       b[1] = byte((u >> 8) & 0xff)
+       b[2] = byte((u >> 16) & 0xff)
+       b[3] = byte((u >> 24) & 0xff)
+}
+
+// checkPixmapFormats checks that we have an agreeable X pixmap Format.
+func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err os.Error) {
+       for i := 0; i < n; i++ {
+               _, err = io.ReadFull(r, b[0:8])
+               if err != nil {
+                       return
+               }
+               // Byte 0 is depth, byte 1 is bits-per-pixel, byte 2 is scanline-pad, the rest (5) is padding.
+               if b[0] == 24 && b[1] == 32 {
+                       agree = true
+               }
+       }
+       return
+}
+
+// checkDepths checks that we have an agreeable X Depth (i.e. one that has an agreeable X VisualType).
+func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err os.Error) {
+       for i := 0; i < n; i++ {
+               depth, err := readU16LE(r, b)
+               if err != nil {
+                       return
+               }
+               depth &= 0xff
+               visualsLen, err := readU16LE(r, b)
+               if err != nil {
+                       return
+               }
+               // Ignore 4 bytes of padding.
+               _, err = io.ReadFull(r, b[0:4])
+               if err != nil {
+                       return
+               }
+               for j := 0; j < int(visualsLen); j++ {
+                       // Read 24 bytes: visual(4), class(1), bits per rgb value(1), colormap entries(2),
+                       // red mask(4), green mask(4), blue mask(4), padding(4).
+                       v, err := readU32LE(r, b)
+                       _, err = readU32LE(r, b)
+                       rm, err := readU32LE(r, b)
+                       gm, err := readU32LE(r, b)
+                       bm, err := readU32LE(r, b)
+                       _, err = readU32LE(r, b)
+                       if err != nil {
+                               return
+                       }
+                       if v == visual && rm == 0xff0000 && gm == 0xff00 && bm == 0xff && depth == 24 {
+                               agree = true
+                       }
+               }
+       }
+       return
+}
+
+// checkScreens checks that we have an agreeable X Screen.
+func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Error) {
+       for i := 0; i < n; i++ {
+               root0, err := readU32LE(r, b)
+               if err != nil {
+                       return
+               }
+               // Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks,
+               // width and height (pixels), width and height (mm), min and max installed maps.
+               _, err = io.ReadFull(r, b[0:28])
+               if err != nil {
+                       return
+               }
+               visual0, err := readU32LE(r, b)
+               if err != nil {
+                       return
+               }
+               // Next 4 bytes: backing stores, save unders, root depth, allowed depths length.
+               x, err := readU32LE(r, b)
+               if err != nil {
+                       return
+               }
+               nDepths := int(x >> 24)
+               agree, err := checkDepths(r, b, nDepths, visual0)
+               if err != nil {
+                       return
+               }
+               if agree && root == 0 {
+                       root = root0
+                       visual = visual0
+               }
+       }
+       return
+}
+
+// handshake performs the protocol handshake with the X server, and ensures
+// that the server provides a compatible Screen, Depth, etc.
+func (c *conn) handshake() os.Error {
+       _, err := io.ReadFull(c.r, c.buf[0:8])
+       if err != nil {
+               return err
+       }
+       // Byte 0:1 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
+       if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 {
+               return os.NewError("unsupported X version")
+       }
+       // Ignore the release number.
+       _, err = io.ReadFull(c.r, c.buf[0:4])
+       if err != nil {
+               return err
+       }
+       // Read the resource ID base.
+       resourceIdBase, err := readU32LE(c.r, c.buf[0:4])
+       if err != nil {
+               return err
+       }
+       // Read the resource ID mask.
+       resourceIdMask, err := readU32LE(c.r, c.buf[0:4])
+       if err != nil {
+               return err
+       }
+       if resourceIdMask < 256 {
+               return os.NewError("X resource ID mask is too small")
+       }
+       // Ignore the motion buffer size.
+       _, err = io.ReadFull(c.r, c.buf[0:4])
+       if err != nil {
+               return err
+       }
+       // Read the vendor length and round it up to a multiple of 4,
+       // for X11 protocol alignment reasons.
+       vendorLen, err := readU16LE(c.r, c.buf[0:2])
+       if err != nil {
+               return err
+       }
+       vendorLen = (vendorLen + 3) &^ 3
+       // Read the maximum request length.
+       maxReqLen, err := readU16LE(c.r, c.buf[0:2])
+       if err != nil {
+               return err
+       }
+       if maxReqLen != 0xffff {
+               return os.NewError("unsupported X maximum request length")
+       }
+       // Read the roots length.
+       rootsLen, err := readU8(c.r, c.buf[0:1])
+       if err != nil {
+               return err
+       }
+       // Read the pixmap formats length.
+       pixmapFormatsLen, err := readU8(c.r, c.buf[0:1])
+       if err != nil {
+               return err
+       }
+       // Ignore some things that we don't care about (totalling 10 + vendorLen bytes):
+       // imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1),
+       // minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen).
+       if 10+int(vendorLen) > cap(c.buf) {
+               return os.NewError("unsupported X vendor")
+       }
+       _, err = io.ReadFull(c.r, c.buf[0:10+int(vendorLen)])
+       if err != nil {
+               return err
+       }
+       // Check that we have an agreeable pixmap format.
+       agree, err := checkPixmapFormats(c.r, c.buf[0:8], int(pixmapFormatsLen))
+       if err != nil {
+               return err
+       }
+       if !agree {
+               return os.NewError("unsupported X pixmap formats")
+       }
+       // Check that we have an agreeable screen.
+       root, visual, err := checkScreens(c.r, c.buf[0:24], int(rootsLen))
+       if err != nil {
+               return err
+       }
+       if root == 0 || visual == 0 {
+               return os.NewError("unsupported X screen")
+       }
+       c.gc = resID(resourceIdBase)
+       c.window = resID(resourceIdBase + 1)
+       c.root = resID(root)
+       c.visual = resID(visual)
+       return nil
+}
+
+// NewWindow calls NewWindowDisplay with $DISPLAY.
+func NewWindow() (draw.Window, os.Error) {
+       display := os.Getenv("DISPLAY")
+       if len(display) == 0 {
+               return nil, os.NewError("$DISPLAY not set")
+       }
+       return NewWindowDisplay(display)
+}
+
+// NewWindowDisplay returns a new draw.Window, backed by a newly created and
+// mapped X11 window. The X server to connect to is specified by the display
+// string, such as ":1".
+func NewWindowDisplay(display string) (draw.Window, os.Error) {
+       socket, displayStr, err := connect(display)
+       if err != nil {
+               return nil, err
+       }
+       c := new(conn)
+       c.c = socket
+       c.r = bufio.NewReader(socket)
+       c.w = bufio.NewWriter(socket)
+       err = authenticate(c.w, displayStr)
+       if err != nil {
+               return nil, err
+       }
+       err = c.handshake()
+       if err != nil {
+               return nil, err
+       }
+
+       // Now that we're connected, show a window, via three X protocol messages.
+       // First, issue a GetKeyboardMapping request. This is the first request, and
+       // will be associated with a cookie of 1.
+       setU32LE(c.buf[0:4], 0x00020065) // 0x65 is the GetKeyboardMapping opcode, and the message is 2 x 4 bytes long.
+       setU32LE(c.buf[4:8], uint32((keymapHi-keymapLo+1)<<8|keymapLo))
+       // Second, create a graphics context (GC).
+       setU32LE(c.buf[8:12], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long.
+       setU32LE(c.buf[12:16], uint32(c.gc))
+       setU32LE(c.buf[16:20], uint32(c.root))
+       setU32LE(c.buf[20:24], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES.
+       setU32LE(c.buf[24:28], 0x00000000) // The Foreground is black.
+       setU32LE(c.buf[28:32], 0x00000000) // GraphicsExposures' value is unused.
+       // Third, create the window.
+       setU32LE(c.buf[32:36], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long.
+       setU32LE(c.buf[36:40], uint32(c.window))
+       setU32LE(c.buf[40:44], uint32(c.root))
+       setU32LE(c.buf[44:48], 0x00000000) // Initial (x, y) is (0, 0).
+       setU32LE(c.buf[48:52], windowHeight<<16|windowWidth)
+       setU32LE(c.buf[52:56], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1.
+       setU32LE(c.buf[56:60], uint32(c.visual))
+       setU32LE(c.buf[60:64], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK.
+       setU32LE(c.buf[64:68], 0x00000000) // The Back-Pixel is black.
+       setU32LE(c.buf[68:72], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks.
+       // Fourth, map the window.
+       setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long.
+       setU32LE(c.buf[76:80], uint32(c.window))
+       // Write the bytes.
+       _, err = c.w.Write(c.buf[0:80])
+       if err != nil {
+               return nil, err
+       }
+       err = c.w.Flush()
+       if err != nil {
+               return nil, err
+       }
+
+       c.img = image.NewRGBA(windowWidth, windowHeight)
+       c.eventc = make(chan interface{}, 16)
+       c.flush = make(chan bool, 1)
+       go c.readSocket()
+       go c.writeSocket()
+       return c, nil
+}
diff --git a/libgo/go/exp/eval/abort.go b/libgo/go/exp/eval/abort.go
new file mode 100644 (file)
index 0000000..22e17ce
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "fmt"
+       "os"
+       "runtime"
+)
+
+// Abort aborts the thread's current computation,
+// causing the innermost Try to return err.
+func (t *Thread) Abort(err os.Error) {
+       if t.abort == nil {
+               panic("abort: " + err.String())
+       }
+       t.abort <- err
+       runtime.Goexit()
+}
+
+// Try executes a computation; if the computation
+// Aborts, Try returns the error passed to abort.
+func (t *Thread) Try(f func(t *Thread)) os.Error {
+       oc := t.abort
+       c := make(chan os.Error)
+       t.abort = c
+       go func() {
+               f(t)
+               c <- nil
+       }()
+       err := <-c
+       t.abort = oc
+       return err
+}
+
+type DivByZeroError struct{}
+
+func (DivByZeroError) String() string { return "divide by zero" }
+
+type NilPointerError struct{}
+
+func (NilPointerError) String() string { return "nil pointer dereference" }
+
+type IndexError struct {
+       Idx, Len int64
+}
+
+func (e IndexError) String() string {
+       if e.Idx < 0 {
+               return fmt.Sprintf("negative index: %d", e.Idx)
+       }
+       return fmt.Sprintf("index %d exceeds length %d", e.Idx, e.Len)
+}
+
+type SliceError struct {
+       Lo, Hi, Cap int64
+}
+
+func (e SliceError) String() string {
+       return fmt.Sprintf("slice [%d:%d]; cap %d", e.Lo, e.Hi, e.Cap)
+}
+
+type KeyError struct {
+       Key interface{}
+}
+
+func (e KeyError) String() string { return fmt.Sprintf("key '%v' not found in map", e.Key) }
+
+type NegativeLengthError struct {
+       Len int64
+}
+
+func (e NegativeLengthError) String() string {
+       return fmt.Sprintf("negative length: %d", e.Len)
+}
+
+type NegativeCapacityError struct {
+       Len int64
+}
+
+func (e NegativeCapacityError) String() string {
+       return fmt.Sprintf("negative capacity: %d", e.Len)
+}
diff --git a/libgo/go/exp/eval/bridge.go b/libgo/go/exp/eval/bridge.go
new file mode 100644 (file)
index 0000000..84ff518
--- /dev/null
@@ -0,0 +1,171 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "log"
+       "go/token"
+       "reflect"
+)
+
+/*
+ * Type bridging
+ */
+
+var (
+       evalTypes   = make(map[reflect.Type]Type)
+       nativeTypes = make(map[Type]reflect.Type)
+)
+
+// TypeFromNative converts a regular Go type into a the corresponding
+// interpreter Type.
+func TypeFromNative(t reflect.Type) Type {
+       if et, ok := evalTypes[t]; ok {
+               return et
+       }
+
+       var nt *NamedType
+       if t.Name() != "" {
+               name := t.PkgPath() + "·" + t.Name()
+               nt = &NamedType{token.Position{}, name, nil, true, make(map[string]Method)}
+               evalTypes[t] = nt
+       }
+
+       var et Type
+       switch t := t.(type) {
+       case *reflect.BoolType:
+               et = BoolType
+       case *reflect.FloatType:
+               switch t.Kind() {
+               case reflect.Float32:
+                       et = Float32Type
+               case reflect.Float64:
+                       et = Float64Type
+               case reflect.Float:
+                       et = FloatType
+               }
+       case *reflect.IntType:
+               switch t.Kind() {
+               case reflect.Int16:
+                       et = Int16Type
+               case reflect.Int32:
+                       et = Int32Type
+               case reflect.Int64:
+                       et = Int64Type
+               case reflect.Int8:
+                       et = Int8Type
+               case reflect.Int:
+                       et = IntType
+               }
+       case *reflect.UintType:
+               switch t.Kind() {
+               case reflect.Uint16:
+                       et = Uint16Type
+               case reflect.Uint32:
+                       et = Uint32Type
+               case reflect.Uint64:
+                       et = Uint64Type
+               case reflect.Uint8:
+                       et = Uint8Type
+               case reflect.Uint:
+                       et = UintType
+               case reflect.Uintptr:
+                       et = UintptrType
+               }
+       case *reflect.StringType:
+               et = StringType
+       case *reflect.ArrayType:
+               et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem()))
+       case *reflect.ChanType:
+               log.Panicf("%T not implemented", t)
+       case *reflect.FuncType:
+               nin := t.NumIn()
+               // Variadic functions have DotDotDotType at the end
+               variadic := t.DotDotDot()
+               if variadic {
+                       nin--
+               }
+               in := make([]Type, nin)
+               for i := range in {
+                       in[i] = TypeFromNative(t.In(i))
+               }
+               out := make([]Type, t.NumOut())
+               for i := range out {
+                       out[i] = TypeFromNative(t.Out(i))
+               }
+               et = NewFuncType(in, variadic, out)
+       case *reflect.InterfaceType:
+               log.Panicf("%T not implemented", t)
+       case *reflect.MapType:
+               log.Panicf("%T not implemented", t)
+       case *reflect.PtrType:
+               et = NewPtrType(TypeFromNative(t.Elem()))
+       case *reflect.SliceType:
+               et = NewSliceType(TypeFromNative(t.Elem()))
+       case *reflect.StructType:
+               n := t.NumField()
+               fields := make([]StructField, n)
+               for i := 0; i < n; i++ {
+                       sf := t.Field(i)
+                       // TODO(austin) What to do about private fields?
+                       fields[i].Name = sf.Name
+                       fields[i].Type = TypeFromNative(sf.Type)
+                       fields[i].Anonymous = sf.Anonymous
+               }
+               et = NewStructType(fields)
+       case *reflect.UnsafePointerType:
+               log.Panicf("%T not implemented", t)
+       default:
+               log.Panicf("unexpected reflect.Type: %T", t)
+       }
+
+       if nt != nil {
+               if _, ok := et.(*NamedType); !ok {
+                       nt.Complete(et)
+                       et = nt
+               }
+       }
+
+       nativeTypes[et] = t
+       evalTypes[t] = et
+
+       return et
+}
+
+// TypeOfNative returns the interpreter Type of a regular Go value.
+func TypeOfNative(v interface{}) Type { return TypeFromNative(reflect.Typeof(v)) }
+
+/*
+ * Function bridging
+ */
+
+type nativeFunc struct {
+       fn      func(*Thread, []Value, []Value)
+       in, out int
+}
+
+func (f *nativeFunc) NewFrame() *Frame {
+       vars := make([]Value, f.in+f.out)
+       return &Frame{nil, vars}
+}
+
+func (f *nativeFunc) Call(t *Thread) { f.fn(t, t.f.Vars[0:f.in], t.f.Vars[f.in:f.in+f.out]) }
+
+// FuncFromNative creates an interpreter function from a native
+// function that takes its in and out arguments as slices of
+// interpreter Value's.  While somewhat inconvenient, this avoids
+// value marshalling.
+func FuncFromNative(fn func(*Thread, []Value, []Value), t *FuncType) FuncValue {
+       return &funcV{&nativeFunc{fn, len(t.In), len(t.Out)}}
+}
+
+// FuncFromNativeTyped is like FuncFromNative, but constructs the
+// function type from a function pointer using reflection.  Typically,
+// the type will be given as a nil pointer to a function with the
+// desired signature.
+func FuncFromNativeTyped(fn func(*Thread, []Value, []Value), t interface{}) (*FuncType, FuncValue) {
+       ft := TypeOfNative(t).(*FuncType)
+       return ft, FuncFromNative(fn, ft)
+}
diff --git a/libgo/go/exp/eval/compiler.go b/libgo/go/exp/eval/compiler.go
new file mode 100644 (file)
index 0000000..764df8e
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "fmt"
+       "go/scanner"
+       "go/token"
+)
+
+
+type positioned interface {
+       Pos() token.Position
+}
+
+
+// A compiler captures information used throughout an entire
+// compilation.  Currently it includes only the error handler.
+//
+// TODO(austin) This might actually represent package level, in which
+// case it should be package compiler.
+type compiler struct {
+       errors       scanner.ErrorHandler
+       numErrors    int
+       silentErrors int
+}
+
+func (a *compiler) diagAt(pos positioned, format string, args ...interface{}) {
+       a.errors.Error(pos.Pos(), fmt.Sprintf(format, args...))
+       a.numErrors++
+}
+
+func (a *compiler) numError() int { return a.numErrors + a.silentErrors }
+
+// The universal scope
+func newUniverse() *Scope {
+       sc := &Scope{nil, 0}
+       sc.block = &block{
+               offset: 0,
+               scope:  sc,
+               global: true,
+               defs:   make(map[string]Def),
+       }
+       return sc
+}
+
+var universe *Scope = newUniverse()
+
+
+// TODO(austin) These can all go in stmt.go now
+type label struct {
+       name string
+       desc string
+       // The PC goto statements should jump to, or nil if this label
+       // cannot be goto'd (such as an anonymous for loop label).
+       gotoPC *uint
+       // The PC break statements should jump to, or nil if a break
+       // statement is invalid.
+       breakPC *uint
+       // The PC continue statements should jump to, or nil if a
+       // continue statement is invalid.
+       continuePC *uint
+       // The position where this label was resolved.  If it has not
+       // been resolved yet, an invalid position.
+       resolved token.Position
+       // The position where this label was first jumped to.
+       used token.Position
+}
+
+// A funcCompiler captures information used throughout the compilation
+// of a single function body.
+type funcCompiler struct {
+       *compiler
+       fnType *FuncType
+       // Whether the out variables are named.  This affects what
+       // kinds of return statements are legal.
+       outVarsNamed bool
+       *codeBuf
+       flow   *flowBuf
+       labels map[string]*label
+}
+
+// A blockCompiler captures information used throughout the compilation
+// of a single block within a function.
+type blockCompiler struct {
+       *funcCompiler
+       block *block
+       // The label of this block, used for finding break and
+       // continue labels.
+       label *label
+       // The blockCompiler for the block enclosing this one, or nil
+       // for a function-level block.
+       parent *blockCompiler
+}
diff --git a/libgo/go/exp/eval/eval_test.go b/libgo/go/exp/eval/eval_test.go
new file mode 100644 (file)
index 0000000..d78242d
--- /dev/null
@@ -0,0 +1,255 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "big"
+       "flag"
+       "fmt"
+       "log"
+       "os"
+       "reflect"
+       "regexp"
+       "testing"
+)
+
+// Print each statement or expression before parsing it
+var noisy = false
+
+func init() { flag.BoolVar(&noisy, "noisy", false, "chatter during eval tests") }
+
+/*
+ * Generic statement/expression test framework
+ */
+
+type test []job
+
+type job struct {
+       code  string
+       cerr  string
+       rterr string
+       val   Value
+       noval bool
+}
+
+func runTests(t *testing.T, baseName string, tests []test) {
+       for i, test := range tests {
+               name := fmt.Sprintf("%s[%d]", baseName, i)
+               test.run(t, name)
+       }
+}
+
+func (a test) run(t *testing.T, name string) {
+       w := newTestWorld()
+       for _, j := range a {
+               src := j.code + ";" // trailing semicolon to finish statement
+               if noisy {
+                       println("code:", src)
+               }
+
+               code, err := w.Compile(src)
+               if err != nil {
+                       if j.cerr == "" {
+                               t.Errorf("%s: Compile %s: %v", name, src, err)
+                               break
+                       }
+                       if !match(t, err, j.cerr) {
+                               t.Errorf("%s: Compile %s = error %s; want %v", name, src, err, j.cerr)
+                               break
+                       }
+                       continue
+               }
+               if j.cerr != "" {
+                       t.Errorf("%s: Compile %s succeeded; want %s", name, src, j.cerr)
+                       break
+               }
+
+               val, err := code.Run()
+               if err != nil {
+                       if j.rterr == "" {
+                               t.Errorf("%s: Run %s: %v", name, src, err)
+                               break
+                       }
+                       if !match(t, err, j.rterr) {
+                               t.Errorf("%s: Run %s = error %s; want %v", name, src, err, j.rterr)
+                               break
+                       }
+                       continue
+               }
+               if j.rterr != "" {
+                       t.Errorf("%s: Run %s succeeded; want %s", name, src, j.rterr)
+                       break
+               }
+
+               if !j.noval && !reflect.DeepEqual(val, j.val) {
+                       t.Errorf("%s: Run %s = %T(%v) want %T(%v)", name, src, val, val, j.val, j.val)
+               }
+       }
+}
+
+func match(t *testing.T, err os.Error, pat string) bool {
+       ok, err1 := regexp.MatchString(pat, err.String())
+       if err1 != nil {
+               t.Fatalf("compile regexp %s: %v", pat, err1)
+       }
+       return ok
+}
+
+
+/*
+ * Test constructors
+ */
+
+// Expression compile error
+func CErr(expr string, cerr string) test { return test([]job{{code: expr, cerr: cerr}}) }
+
+// Expression runtime error
+func RErr(expr string, rterr string) test { return test([]job{{code: expr, rterr: rterr}}) }
+
+// Expression value
+func Val(expr string, val interface{}) test {
+       return test([]job{{code: expr, val: toValue(val)}})
+}
+
+// Statement runs without error
+func Run(stmts string) test { return test([]job{{code: stmts, noval: true}}) }
+
+// Two statements without error.
+// TODO(rsc): Should be possible with Run but the parser
+// won't let us do both top-level and non-top-level statements.
+func Run2(stmt1, stmt2 string) test {
+       return test([]job{{code: stmt1, noval: true}, {code: stmt2, noval: true}})
+}
+
+// Statement runs and test one expression's value
+func Val1(stmts string, expr1 string, val1 interface{}) test {
+       return test([]job{
+               {code: stmts, noval: true},
+               {code: expr1, val: toValue(val1)},
+       })
+}
+
+// Statement runs and test two expressions' values
+func Val2(stmts string, expr1 string, val1 interface{}, expr2 string, val2 interface{}) test {
+       return test([]job{
+               {code: stmts, noval: true},
+               {code: expr1, val: toValue(val1)},
+               {code: expr2, val: toValue(val2)},
+       })
+}
+
+/*
+ * Value constructors
+ */
+
+type vstruct []interface{}
+
+type varray []interface{}
+
+type vslice struct {
+       arr      varray
+       len, cap int
+}
+
+func toValue(val interface{}) Value {
+       switch val := val.(type) {
+       case bool:
+               r := boolV(val)
+               return &r
+       case uint8:
+               r := uint8V(val)
+               return &r
+       case uint:
+               r := uintV(val)
+               return &r
+       case int:
+               r := intV(val)
+               return &r
+       case *big.Int:
+               return &idealIntV{val}
+       case float:
+               r := floatV(val)
+               return &r
+       case *big.Rat:
+               return &idealFloatV{val}
+       case string:
+               r := stringV(val)
+               return &r
+       case vstruct:
+               elems := make([]Value, len(val))
+               for i, e := range val {
+                       elems[i] = toValue(e)
+               }
+               r := structV(elems)
+               return &r
+       case varray:
+               elems := make([]Value, len(val))
+               for i, e := range val {
+                       elems[i] = toValue(e)
+               }
+               r := arrayV(elems)
+               return &r
+       case vslice:
+               return &sliceV{Slice{toValue(val.arr).(ArrayValue), int64(val.len), int64(val.cap)}}
+       case Func:
+               return &funcV{val}
+       }
+       log.Panicf("toValue(%T) not implemented", val)
+       panic("unreachable")
+}
+
+/*
+ * Default test scope
+ */
+
+type testFunc struct{}
+
+func (*testFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
+
+func (*testFunc) Call(t *Thread) {
+       n := t.f.Vars[0].(IntValue).Get(t)
+
+       res := n + 1
+
+       t.f.Vars[1].(IntValue).Set(t, res)
+}
+
+type oneTwoFunc struct{}
+
+func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
+
+func (*oneTwoFunc) Call(t *Thread) {
+       t.f.Vars[0].(IntValue).Set(t, 1)
+       t.f.Vars[1].(IntValue).Set(t, 2)
+}
+
+type voidFunc struct{}
+
+func (*voidFunc) NewFrame() *Frame { return &Frame{nil, []Value{}} }
+
+func (*voidFunc) Call(t *Thread) {}
+
+func newTestWorld() *World {
+       w := NewWorld()
+
+       def := func(name string, t Type, val interface{}) { w.DefineVar(name, t, toValue(val)) }
+
+       w.DefineConst("c", IdealIntType, toValue(big.NewInt(1)))
+       def("i", IntType, 1)
+       def("i2", IntType, 2)
+       def("u", UintType, uint(1))
+       def("f", FloatType, 1.0)
+       def("s", StringType, "abc")
+       def("t", NewStructType([]StructField{{"a", IntType, false}}), vstruct{1})
+       def("ai", NewArrayType(2, IntType), varray{1, 2})
+       def("aai", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{1, 2}, varray{3, 4}})
+       def("aai2", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{5, 6}, varray{7, 8}})
+       def("fn", NewFuncType([]Type{IntType}, false, []Type{IntType}), &testFunc{})
+       def("oneTwo", NewFuncType([]Type{}, false, []Type{IntType, IntType}), &oneTwoFunc{})
+       def("void", NewFuncType([]Type{}, false, []Type{}), &voidFunc{})
+       def("sli", NewSliceType(IntType), vslice{varray{1, 2, 3}, 2, 3})
+
+       return w
+}
diff --git a/libgo/go/exp/eval/expr.go b/libgo/go/exp/eval/expr.go
new file mode 100644 (file)
index 0000000..823f240
--- /dev/null
@@ -0,0 +1,2009 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "big"
+       "fmt"
+       "go/ast"
+       "go/token"
+       "log"
+       "strconv"
+       "strings"
+       "os"
+)
+
+var (
+       idealZero = big.NewInt(0)
+       idealOne  = big.NewInt(1)
+)
+
+// An expr is the result of compiling an expression.  It stores the
+// type of the expression and its evaluator function.
+type expr struct {
+       *exprInfo
+       t Type
+
+       // Evaluate this node as the given type.
+       eval interface{}
+
+       // Map index expressions permit special forms of assignment,
+       // for which we need to know the Map and key.
+       evalMapValue func(t *Thread) (Map, interface{})
+
+       // Evaluate to the "address of" this value; that is, the
+       // settable Value object.  nil for expressions whose address
+       // cannot be taken.
+       evalAddr func(t *Thread) Value
+
+       // Execute this expression as a statement.  Only expressions
+       // that are valid expression statements should set this.
+       exec func(t *Thread)
+
+       // If this expression is a type, this is its compiled type.
+       // This is only permitted in the function position of a call
+       // expression.  In this case, t should be nil.
+       valType Type
+
+       // A short string describing this expression for error
+       // messages.
+       desc string
+}
+
+// exprInfo stores information needed to compile any expression node.
+// Each expr also stores its exprInfo so further expressions can be
+// compiled from it.
+type exprInfo struct {
+       *compiler
+       pos token.Position
+}
+
+func (a *exprInfo) newExpr(t Type, desc string) *expr {
+       return &expr{exprInfo: a, t: t, desc: desc}
+}
+
+func (a *exprInfo) diag(format string, args ...interface{}) {
+       a.diagAt(&a.pos, format, args...)
+}
+
+func (a *exprInfo) diagOpType(op token.Token, vt Type) {
+       a.diag("illegal operand type for '%v' operator\n\t%v", op, vt)
+}
+
+func (a *exprInfo) diagOpTypes(op token.Token, lt Type, rt Type) {
+       a.diag("illegal operand types for '%v' operator\n\t%v\n\t%v", op, lt, rt)
+}
+
+/*
+ * Common expression manipulations
+ */
+
+// a.convertTo(t) converts the value of the analyzed expression a,
+// which must be a constant, ideal number, to a new analyzed
+// expression with a constant value of type t.
+//
+// TODO(austin) Rename to resolveIdeal or something?
+func (a *expr) convertTo(t Type) *expr {
+       if !a.t.isIdeal() {
+               log.Panicf("attempted to convert from %v, expected ideal", a.t)
+       }
+
+       var rat *big.Rat
+
+       // XXX(Spec)  The spec says "It is erroneous".
+       //
+       // It is an error to assign a value with a non-zero fractional
+       // part to an integer, or if the assignment would overflow or
+       // underflow, or in general if the value cannot be represented
+       // by the type of the variable.
+       switch a.t {
+       case IdealFloatType:
+               rat = a.asIdealFloat()()
+               if t.isInteger() && !rat.IsInt() {
+                       a.diag("constant %v truncated to integer", rat.FloatString(6))
+                       return nil
+               }
+       case IdealIntType:
+               i := a.asIdealInt()()
+               rat = new(big.Rat).SetInt(i)
+       default:
+               log.Panicf("unexpected ideal type %v", a.t)
+       }
+
+       // Check bounds
+       if t, ok := t.lit().(BoundedType); ok {
+               if rat.Cmp(t.minVal()) < 0 {
+                       a.diag("constant %v underflows %v", rat.FloatString(6), t)
+                       return nil
+               }
+               if rat.Cmp(t.maxVal()) > 0 {
+                       a.diag("constant %v overflows %v", rat.FloatString(6), t)
+                       return nil
+               }
+       }
+
+       // Convert rat to type t.
+       res := a.newExpr(t, a.desc)
+       switch t := t.lit().(type) {
+       case *uintType:
+               n, d := rat.Num(), rat.Denom()
+               f := new(big.Int).Quo(n, d)
+               f = f.Abs(f)
+               v := uint64(f.Int64())
+               res.eval = func(*Thread) uint64 { return v }
+       case *intType:
+               n, d := rat.Num(), rat.Denom()
+               f := new(big.Int).Quo(n, d)
+               v := f.Int64()
+               res.eval = func(*Thread) int64 { return v }
+       case *idealIntType:
+               n, d := rat.Num(), rat.Denom()
+               f := new(big.Int).Quo(n, d)
+               res.eval = func() *big.Int { return f }
+       case *floatType:
+               n, d := rat.Num(), rat.Denom()
+               v := float64(n.Int64()) / float64(d.Int64())
+               res.eval = func(*Thread) float64 { return v }
+       case *idealFloatType:
+               res.eval = func() *big.Rat { return rat }
+       default:
+               log.Panicf("cannot convert to type %T", t)
+       }
+
+       return res
+}
+
+// convertToInt converts this expression to an integer, if possible,
+// or produces an error if not.  This accepts ideal ints, uints, and
+// ints.  If max is not -1, produces an error if possible if the value
+// exceeds max.  If negErr is not "", produces an error if possible if
+// the value is negative.
+func (a *expr) convertToInt(max int64, negErr string, errOp string) *expr {
+       switch a.t.lit().(type) {
+       case *idealIntType:
+               val := a.asIdealInt()()
+               if negErr != "" && val.Sign() < 0 {
+                       a.diag("negative %s: %s", negErr, val)
+                       return nil
+               }
+               bound := max
+               if negErr == "slice" {
+                       bound++
+               }
+               if max != -1 && val.Cmp(big.NewInt(bound)) >= 0 {
+                       a.diag("index %s exceeds length %d", val, max)
+                       return nil
+               }
+               return a.convertTo(IntType)
+
+       case *uintType:
+               // Convert to int
+               na := a.newExpr(IntType, a.desc)
+               af := a.asUint()
+               na.eval = func(t *Thread) int64 { return int64(af(t)) }
+               return na
+
+       case *intType:
+               // Good as is
+               return a
+       }
+
+       a.diag("illegal operand type for %s\n\t%v", errOp, a.t)
+       return nil
+}
+
+// derefArray returns an expression of array type if the given
+// expression is a *array type.  Otherwise, returns the given
+// expression.
+func (a *expr) derefArray() *expr {
+       if pt, ok := a.t.lit().(*PtrType); ok {
+               if _, ok := pt.Elem.lit().(*ArrayType); ok {
+                       deref := a.compileStarExpr(a)
+                       if deref == nil {
+                               log.Panicf("failed to dereference *array")
+                       }
+                       return deref
+               }
+       }
+       return a
+}
+
+/*
+ * Assignments
+ */
+
+// An assignCompiler compiles assignment operations.  Anything other
+// than short declarations should use the compileAssign wrapper.
+//
+// There are three valid types of assignment:
+// 1) T = T
+//    Assigning a single expression with single-valued type to a
+//    single-valued type.
+// 2) MT = T, T, ...
+//    Assigning multiple expressions with single-valued types to a
+//    multi-valued type.
+// 3) MT = MT
+//    Assigning a single expression with multi-valued type to a
+//    multi-valued type.
+type assignCompiler struct {
+       *compiler
+       pos token.Position
+       // The RHS expressions.  This may include nil's for
+       // expressions that failed to compile.
+       rs []*expr
+       // The (possibly unary) MultiType of the RHS.
+       rmt *MultiType
+       // Whether this is an unpack assignment (case 3).
+       isUnpack bool
+       // Whether map special assignment forms are allowed.
+       allowMap bool
+       // Whether this is a "r, ok = a[x]" assignment.
+       isMapUnpack bool
+       // The operation name to use in error messages, such as
+       // "assignment" or "function call".
+       errOp string
+       // The name to use for positions in error messages, such as
+       // "argument".
+       errPosName string
+}
+
+// Type check the RHS of an assignment, returning a new assignCompiler
+// and indicating if the type check succeeded.  This always returns an
+// assignCompiler with rmt set, but if type checking fails, slots in
+// the MultiType may be nil.  If rs contains nil's, type checking will
+// fail and these expressions given a nil type.
+func (a *compiler) checkAssign(pos token.Position, rs []*expr, errOp, errPosName string) (*assignCompiler, bool) {
+       c := &assignCompiler{
+               compiler:   a,
+               pos:        pos,
+               rs:         rs,
+               errOp:      errOp,
+               errPosName: errPosName,
+       }
+
+       // Is this an unpack?
+       if len(rs) == 1 && rs[0] != nil {
+               if rmt, isUnpack := rs[0].t.(*MultiType); isUnpack {
+                       c.rmt = rmt
+                       c.isUnpack = true
+                       return c, true
+               }
+       }
+
+       // Create MultiType for RHS and check that all RHS expressions
+       // are single-valued.
+       rts := make([]Type, len(rs))
+       ok := true
+       for i, r := range rs {
+               if r == nil {
+                       ok = false
+                       continue
+               }
+
+               if _, isMT := r.t.(*MultiType); isMT {
+                       r.diag("multi-valued expression not allowed in %s", errOp)
+                       ok = false
+                       continue
+               }
+
+               rts[i] = r.t
+       }
+
+       c.rmt = NewMultiType(rts)
+       return c, ok
+}
+
+func (a *assignCompiler) allowMapForms(nls int) {
+       a.allowMap = true
+
+       // Update unpacking info if this is r, ok = a[x]
+       if nls == 2 && len(a.rs) == 1 && a.rs[0] != nil && a.rs[0].evalMapValue != nil {
+               a.isUnpack = true
+               a.rmt = NewMultiType([]Type{a.rs[0].t, BoolType})
+               a.isMapUnpack = true
+       }
+}
+
+// compile type checks and compiles an assignment operation, returning
+// a function that expects an l-value and the frame in which to
+// evaluate the RHS expressions.  The l-value must have exactly the
+// type given by lt.  Returns nil if type checking fails.
+func (a *assignCompiler) compile(b *block, lt Type) func(Value, *Thread) {
+       lmt, isMT := lt.(*MultiType)
+       rmt, isUnpack := a.rmt, a.isUnpack
+
+       // Create unary MultiType for single LHS
+       if !isMT {
+               lmt = NewMultiType([]Type{lt})
+       }
+
+       // Check that the assignment count matches
+       lcount := len(lmt.Elems)
+       rcount := len(rmt.Elems)
+       if lcount != rcount {
+               msg := "not enough"
+               pos := a.pos
+               if rcount > lcount {
+                       msg = "too many"
+                       if lcount > 0 {
+                               pos = a.rs[lcount-1].pos
+                       }
+               }
+               a.diagAt(&pos, "%s %ss for %s\n\t%s\n\t%s", msg, a.errPosName, a.errOp, lt, rmt)
+               return nil
+       }
+
+       bad := false
+
+       // If this is an unpack, create a temporary to store the
+       // multi-value and replace the RHS with expressions to pull
+       // out values from the temporary.  Technically, this is only
+       // necessary when we need to perform assignment conversions.
+       var effect func(*Thread)
+       if isUnpack {
+               // This leaks a slot, but is definitely safe.
+               temp := b.DefineTemp(a.rmt)
+               tempIdx := temp.Index
+               if tempIdx < 0 {
+                       panic(fmt.Sprintln("tempidx", tempIdx))
+               }
+               if a.isMapUnpack {
+                       rf := a.rs[0].evalMapValue
+                       vt := a.rmt.Elems[0]
+                       effect = func(t *Thread) {
+                               m, k := rf(t)
+                               v := m.Elem(t, k)
+                               found := boolV(true)
+                               if v == nil {
+                                       found = boolV(false)
+                                       v = vt.Zero()
+                               }
+                               t.f.Vars[tempIdx] = multiV([]Value{v, &found})
+                       }
+               } else {
+                       rf := a.rs[0].asMulti()
+                       effect = func(t *Thread) { t.f.Vars[tempIdx] = multiV(rf(t)) }
+               }
+               orig := a.rs[0]
+               a.rs = make([]*expr, len(a.rmt.Elems))
+               for i, t := range a.rmt.Elems {
+                       if t.isIdeal() {
+                               log.Panicf("Right side of unpack contains ideal: %s", rmt)
+                       }
+                       a.rs[i] = orig.newExpr(t, orig.desc)
+                       index := i
+                       a.rs[i].genValue(func(t *Thread) Value { return t.f.Vars[tempIdx].(multiV)[index] })
+               }
+       }
+       // Now len(a.rs) == len(a.rmt) and we've reduced any unpacking
+       // to multi-assignment.
+
+       // TODO(austin) Deal with assignment special cases.
+
+       // Values of any type may always be assigned to variables of
+       // compatible static type.
+       for i, lt := range lmt.Elems {
+               rt := rmt.Elems[i]
+
+               // When [an ideal is] (used in an expression) assigned
+               // to a variable or typed constant, the destination
+               // must be able to represent the assigned value.
+               if rt.isIdeal() {
+                       a.rs[i] = a.rs[i].convertTo(lmt.Elems[i])
+                       if a.rs[i] == nil {
+                               bad = true
+                               continue
+                       }
+                       rt = a.rs[i].t
+               }
+
+               // A pointer p to an array can be assigned to a slice
+               // variable v with compatible element type if the type
+               // of p or v is unnamed.
+               if rpt, ok := rt.lit().(*PtrType); ok {
+                       if at, ok := rpt.Elem.lit().(*ArrayType); ok {
+                               if lst, ok := lt.lit().(*SliceType); ok {
+                                       if lst.Elem.compat(at.Elem, false) && (rt.lit() == Type(rt) || lt.lit() == Type(lt)) {
+                                               rf := a.rs[i].asPtr()
+                                               a.rs[i] = a.rs[i].newExpr(lt, a.rs[i].desc)
+                                               len := at.Len
+                                               a.rs[i].eval = func(t *Thread) Slice { return Slice{rf(t).(ArrayValue), len, len} }
+                                               rt = a.rs[i].t
+                                       }
+                               }
+                       }
+               }
+
+               if !lt.compat(rt, false) {
+                       if len(a.rs) == 1 {
+                               a.rs[0].diag("illegal operand types for %s\n\t%v\n\t%v", a.errOp, lt, rt)
+                       } else {
+                               a.rs[i].diag("illegal operand types in %s %d of %s\n\t%v\n\t%v", a.errPosName, i+1, a.errOp, lt, rt)
+                       }
+                       bad = true
+               }
+       }
+       if bad {
+               return nil
+       }
+
+       // Compile
+       if !isMT {
+               // Case 1
+               return genAssign(lt, a.rs[0])
+       }
+       // Case 2 or 3
+       as := make([]func(lv Value, t *Thread), len(a.rs))
+       for i, r := range a.rs {
+               as[i] = genAssign(lmt.Elems[i], r)
+       }
+       return func(lv Value, t *Thread) {
+               if effect != nil {
+                       effect(t)
+               }
+               lmv := lv.(multiV)
+               for i, a := range as {
+                       a(lmv[i], t)
+               }
+       }
+}
+
+// compileAssign compiles an assignment operation without the full
+// generality of an assignCompiler.  See assignCompiler for a
+// description of the arguments.
+func (a *compiler) compileAssign(pos token.Position, b *block, lt Type, rs []*expr, errOp, errPosName string) func(Value, *Thread) {
+       ac, ok := a.checkAssign(pos, rs, errOp, errPosName)
+       if !ok {
+               return nil
+       }
+       return ac.compile(b, lt)
+}
+
+/*
+ * Expression compiler
+ */
+
+// An exprCompiler stores information used throughout the compilation
+// of a single expression.  It does not embed funcCompiler because
+// expressions can appear at top level.
+type exprCompiler struct {
+       *compiler
+       // The block this expression is being compiled in.
+       block *block
+       // Whether this expression is used in a constant context.
+       constant bool
+}
+
+// compile compiles an expression AST.  callCtx should be true if this
+// AST is in the function position of a function call node; it allows
+// the returned expression to be a type or a built-in function (which
+// otherwise result in errors).
+func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
+       ei := &exprInfo{a.compiler, x.Pos()}
+
+       switch x := x.(type) {
+       // Literals
+       case *ast.BasicLit:
+               switch x.Kind {
+               case token.INT:
+                       return ei.compileIntLit(string(x.Value))
+               case token.FLOAT:
+                       return ei.compileFloatLit(string(x.Value))
+               case token.CHAR:
+                       return ei.compileCharLit(string(x.Value))
+               case token.STRING:
+                       return ei.compileStringLit(string(x.Value))
+               default:
+                       log.Panicf("unexpected basic literal type %v", x.Kind)
+               }
+
+       case *ast.CompositeLit:
+               goto notimpl
+
+       case *ast.FuncLit:
+               decl := ei.compileFuncType(a.block, x.Type)
+               if decl == nil {
+                       // TODO(austin) Try compiling the body,
+                       // perhaps with dummy argument definitions
+                       return nil
+               }
+               fn := ei.compileFunc(a.block, decl, x.Body)
+               if fn == nil {
+                       return nil
+               }
+               if a.constant {
+                       a.diagAt(x, "function literal used in constant expression")
+                       return nil
+               }
+               return ei.compileFuncLit(decl, fn)
+
+       // Types
+       case *ast.ArrayType:
+               // TODO(austin) Use a multi-type case
+               goto typeexpr
+
+       case *ast.ChanType:
+               goto typeexpr
+
+       case *ast.Ellipsis:
+               goto typeexpr
+
+       case *ast.FuncType:
+               goto typeexpr
+
+       case *ast.InterfaceType:
+               goto typeexpr
+
+       case *ast.MapType:
+               goto typeexpr
+
+       // Remaining expressions
+       case *ast.BadExpr:
+               // Error already reported by parser
+               a.silentErrors++
+               return nil
+
+       case *ast.BinaryExpr:
+               l, r := a.compile(x.X, false), a.compile(x.Y, false)
+               if l == nil || r == nil {
+                       return nil
+               }
+               return ei.compileBinaryExpr(x.Op, l, r)
+
+       case *ast.CallExpr:
+               l := a.compile(x.Fun, true)
+               args := make([]*expr, len(x.Args))
+               bad := false
+               for i, arg := range x.Args {
+                       if i == 0 && l != nil && (l.t == Type(makeType) || l.t == Type(newType)) {
+                               argei := &exprInfo{a.compiler, arg.Pos()}
+                               args[i] = argei.exprFromType(a.compileType(a.block, arg))
+                       } else {
+                               args[i] = a.compile(arg, false)
+                       }
+                       if args[i] == nil {
+                               bad = true
+                       }
+               }
+               if bad || l == nil {
+                       return nil
+               }
+               if a.constant {
+                       a.diagAt(x, "function call in constant context")
+                       return nil
+               }
+
+               if l.valType != nil {
+                       a.diagAt(x, "type conversions not implemented")
+                       return nil
+               } else if ft, ok := l.t.(*FuncType); ok && ft.builtin != "" {
+                       return ei.compileBuiltinCallExpr(a.block, ft, args)
+               } else {
+                       return ei.compileCallExpr(a.block, l, args)
+               }
+
+       case *ast.Ident:
+               return ei.compileIdent(a.block, a.constant, callCtx, x.Name)
+
+       case *ast.IndexExpr:
+               l, r := a.compile(x.X, false), a.compile(x.Index, false)
+               if l == nil || r == nil {
+                       return nil
+               }
+               return ei.compileIndexExpr(l, r)
+
+       case *ast.SliceExpr:
+               var hi *expr
+               arr := a.compile(x.X, false)
+               lo := a.compile(x.Index, false)
+               if x.End == nil {
+                       // End was omitted, so we need to compute len(x.X)
+                       ei := &exprInfo{a.compiler, x.Pos()}
+                       hi = ei.compileBuiltinCallExpr(a.block, lenType, []*expr{arr})
+               } else {
+                       hi = a.compile(x.End, false)
+               }
+               if arr == nil || lo == nil || hi == nil {
+                       return nil
+               }
+               return ei.compileSliceExpr(arr, lo, hi)
+
+       case *ast.KeyValueExpr:
+               goto notimpl
+
+       case *ast.ParenExpr:
+               return a.compile(x.X, callCtx)
+
+       case *ast.SelectorExpr:
+               v := a.compile(x.X, false)
+               if v == nil {
+                       return nil
+               }
+               return ei.compileSelectorExpr(v, x.Sel.Name)
+
+       case *ast.StarExpr:
+               // We pass down our call context because this could be
+               // a pointer type (and thus a type conversion)
+               v := a.compile(x.X, callCtx)
+               if v == nil {
+                       return nil
+               }
+               if v.valType != nil {
+                       // Turns out this was a pointer type, not a dereference
+                       return ei.exprFromType(NewPtrType(v.valType))
+               }
+               return ei.compileStarExpr(v)
+
+       case *ast.StructType:
+               goto notimpl
+
+       case *ast.TypeAssertExpr:
+               goto notimpl
+
+       case *ast.UnaryExpr:
+               v := a.compile(x.X, false)
+               if v == nil {
+                       return nil
+               }
+               return ei.compileUnaryExpr(x.Op, v)
+       }
+       log.Panicf("unexpected ast node type %T", x)
+       panic("unreachable")
+
+typeexpr:
+       if !callCtx {
+               a.diagAt(x, "type used as expression")
+               return nil
+       }
+       return ei.exprFromType(a.compileType(a.block, x))
+
+notimpl:
+       a.diagAt(x, "%T expression node not implemented", x)
+       return nil
+}
+
+func (a *exprInfo) exprFromType(t Type) *expr {
+       if t == nil {
+               return nil
+       }
+       expr := a.newExpr(nil, "type")
+       expr.valType = t
+       return expr
+}
+
+func (a *exprInfo) compileIdent(b *block, constant bool, callCtx bool, name string) *expr {
+       bl, level, def := b.Lookup(name)
+       if def == nil {
+               a.diag("%s: undefined", name)
+               return nil
+       }
+       switch def := def.(type) {
+       case *Constant:
+               expr := a.newExpr(def.Type, "constant")
+               if ft, ok := def.Type.(*FuncType); ok && ft.builtin != "" {
+                       // XXX(Spec) I don't think anything says that
+                       // built-in functions can't be used as values.
+                       if !callCtx {
+                               a.diag("built-in function %s cannot be used as a value", ft.builtin)
+                               return nil
+                       }
+                       // Otherwise, we leave the evaluators empty
+                       // because this is handled specially
+               } else {
+                       expr.genConstant(def.Value)
+               }
+               return expr
+       case *Variable:
+               if constant {
+                       a.diag("variable %s used in constant expression", name)
+                       return nil
+               }
+               if bl.global {
+                       return a.compileGlobalVariable(def)
+               }
+               return a.compileVariable(level, def)
+       case Type:
+               if callCtx {
+                       return a.exprFromType(def)
+               }
+               a.diag("type %v used as expression", name)
+               return nil
+       }
+       log.Panicf("name %s has unknown type %T", name, def)
+       panic("unreachable")
+}
+
+func (a *exprInfo) compileVariable(level int, v *Variable) *expr {
+       if v.Type == nil {
+               // Placeholder definition from an earlier error
+               a.silentErrors++
+               return nil
+       }
+       expr := a.newExpr(v.Type, "variable")
+       expr.genIdentOp(level, v.Index)
+       return expr
+}
+
+func (a *exprInfo) compileGlobalVariable(v *Variable) *expr {
+       if v.Type == nil {
+               // Placeholder definition from an earlier error
+               a.silentErrors++
+               return nil
+       }
+       if v.Init == nil {
+               v.Init = v.Type.Zero()
+       }
+       expr := a.newExpr(v.Type, "variable")
+       val := v.Init
+       expr.genValue(func(t *Thread) Value { return val })
+       return expr
+}
+
+func (a *exprInfo) compileIdealInt(i *big.Int, desc string) *expr {
+       expr := a.newExpr(IdealIntType, desc)
+       expr.eval = func() *big.Int { return i }
+       return expr
+}
+
+func (a *exprInfo) compileIntLit(lit string) *expr {
+       i, _ := new(big.Int).SetString(lit, 0)
+       return a.compileIdealInt(i, "integer literal")
+}
+
+func (a *exprInfo) compileCharLit(lit string) *expr {
+       if lit[0] != '\'' {
+               // Caught by parser
+               a.silentErrors++
+               return nil
+       }
+       v, _, tail, err := strconv.UnquoteChar(lit[1:], '\'')
+       if err != nil || tail != "'" {
+               // Caught by parser
+               a.silentErrors++
+               return nil
+       }
+       return a.compileIdealInt(big.NewInt(int64(v)), "character literal")
+}
+
+func (a *exprInfo) compileFloatLit(lit string) *expr {
+       f, ok := new(big.Rat).SetString(lit)
+       if !ok {
+               log.Panicf("malformed float literal %s at %v passed parser", lit, a.pos)
+       }
+       expr := a.newExpr(IdealFloatType, "float literal")
+       expr.eval = func() *big.Rat { return f }
+       return expr
+}
+
+func (a *exprInfo) compileString(s string) *expr {
+       // Ideal strings don't have a named type but they are
+       // compatible with type string.
+
+       // TODO(austin) Use unnamed string type.
+       expr := a.newExpr(StringType, "string literal")
+       expr.eval = func(*Thread) string { return s }
+       return expr
+}
+
+func (a *exprInfo) compileStringLit(lit string) *expr {
+       s, err := strconv.Unquote(lit)
+       if err != nil {
+               a.diag("illegal string literal, %v", err)
+               return nil
+       }
+       return a.compileString(s)
+}
+
+func (a *exprInfo) compileStringList(list []*expr) *expr {
+       ss := make([]string, len(list))
+       for i, s := range list {
+               ss[i] = s.asString()(nil)
+       }
+       return a.compileString(strings.Join(ss, ""))
+}
+
+func (a *exprInfo) compileFuncLit(decl *FuncDecl, fn func(*Thread) Func) *expr {
+       expr := a.newExpr(decl.Type, "function literal")
+       expr.eval = fn
+       return expr
+}
+
+func (a *exprInfo) compileSelectorExpr(v *expr, name string) *expr {
+       // mark marks a field that matches the selector name.  It
+       // tracks the best depth found so far and whether more than
+       // one field has been found at that depth.
+       bestDepth := -1
+       ambig := false
+       amberr := ""
+       mark := func(depth int, pathName string) {
+               switch {
+               case bestDepth == -1 || depth < bestDepth:
+                       bestDepth = depth
+                       ambig = false
+                       amberr = ""
+
+               case depth == bestDepth:
+                       ambig = true
+
+               default:
+                       log.Panicf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth)
+               }
+               amberr += "\n\t" + pathName[1:]
+       }
+
+       visited := make(map[Type]bool)
+
+       // find recursively searches for the named field, starting at
+       // type t.  If it finds the named field, it returns a function
+       // which takes an expr that represents a value of type 't' and
+       // returns an expr that retrieves the named field.  We delay
+       // expr construction to avoid producing lots of useless expr's
+       // as we search.
+       //
+       // TODO(austin) Now that the expression compiler works on
+       // semantic values instead of AST's, there should be a much
+       // better way of doing this.
+       var find func(Type, int, string) func(*expr) *expr
+       find = func(t Type, depth int, pathName string) func(*expr) *expr {
+               // Don't bother looking if we've found something shallower
+               if bestDepth != -1 && bestDepth < depth {
+                       return nil
+               }
+
+               // Don't check the same type twice and avoid loops
+               if visited[t] {
+                       return nil
+               }
+               visited[t] = true
+
+               // Implicit dereference
+               deref := false
+               if ti, ok := t.(*PtrType); ok {
+                       deref = true
+                       t = ti.Elem
+               }
+
+               // If it's a named type, look for methods
+               if ti, ok := t.(*NamedType); ok {
+                       _, ok := ti.methods[name]
+                       if ok {
+                               mark(depth, pathName+"."+name)
+                               log.Panic("Methods not implemented")
+                       }
+                       t = ti.Def
+               }
+
+               // If it's a struct type, check fields and embedded types
+               var builder func(*expr) *expr
+               if t, ok := t.(*StructType); ok {
+                       for i, f := range t.Elems {
+                               var sub func(*expr) *expr
+                               switch {
+                               case f.Name == name:
+                                       mark(depth, pathName+"."+name)
+                                       sub = func(e *expr) *expr { return e }
+
+                               case f.Anonymous:
+                                       sub = find(f.Type, depth+1, pathName+"."+f.Name)
+                                       if sub == nil {
+                                               continue
+                                       }
+
+                               default:
+                                       continue
+                               }
+
+                               // We found something.  Create a
+                               // builder for accessing this field.
+                               ft := f.Type
+                               index := i
+                               builder = func(parent *expr) *expr {
+                                       if deref {
+                                               parent = a.compileStarExpr(parent)
+                                       }
+                                       expr := a.newExpr(ft, "selector expression")
+                                       pf := parent.asStruct()
+                                       evalAddr := func(t *Thread) Value { return pf(t).Field(t, index) }
+                                       expr.genValue(evalAddr)
+                                       return sub(expr)
+                               }
+                       }
+               }
+
+               return builder
+       }
+
+       builder := find(v.t, 0, "")
+       if builder == nil {
+               a.diag("type %v has no field or method %s", v.t, name)
+               return nil
+       }
+       if ambig {
+               a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr)
+               return nil
+       }
+
+       return builder(v)
+}
+
+func (a *exprInfo) compileSliceExpr(arr, lo, hi *expr) *expr {
+       // Type check object
+       arr = arr.derefArray()
+
+       var at Type
+       var maxIndex int64 = -1
+
+       switch lt := arr.t.lit().(type) {
+       case *ArrayType:
+               at = NewSliceType(lt.Elem)
+               maxIndex = lt.Len
+
+       case *SliceType:
+               at = lt
+
+       case *stringType:
+               at = lt
+
+       default:
+               a.diag("cannot slice %v", arr.t)
+               return nil
+       }
+
+       // Type check index and convert to int
+       // XXX(Spec) It's unclear if ideal floats with no
+       // fractional part are allowed here.  6g allows it.  I
+       // believe that's wrong.
+       lo = lo.convertToInt(maxIndex, "slice", "slice")
+       hi = hi.convertToInt(maxIndex, "slice", "slice")
+       if lo == nil || hi == nil {
+               return nil
+       }
+
+       expr := a.newExpr(at, "slice expression")
+
+       // Compile
+       lof := lo.asInt()
+       hif := hi.asInt()
+       switch lt := arr.t.lit().(type) {
+       case *ArrayType:
+               arrf := arr.asArray()
+               bound := lt.Len
+               expr.eval = func(t *Thread) Slice {
+                       arr, lo, hi := arrf(t), lof(t), hif(t)
+                       if lo > hi || hi > bound || lo < 0 {
+                               t.Abort(SliceError{lo, hi, bound})
+                       }
+                       return Slice{arr.Sub(lo, bound-lo), hi - lo, bound - lo}
+               }
+
+       case *SliceType:
+               arrf := arr.asSlice()
+               expr.eval = func(t *Thread) Slice {
+                       arr, lo, hi := arrf(t), lof(t), hif(t)
+                       if lo > hi || hi > arr.Cap || lo < 0 {
+                               t.Abort(SliceError{lo, hi, arr.Cap})
+                       }
+                       return Slice{arr.Base.Sub(lo, arr.Cap-lo), hi - lo, arr.Cap - lo}
+               }
+
+       case *stringType:
+               arrf := arr.asString()
+               // TODO(austin) This pulls over the whole string in a
+               // remote setting, instead of creating a substring backed
+               // by remote memory.
+               expr.eval = func(t *Thread) string {
+                       arr, lo, hi := arrf(t), lof(t), hif(t)
+                       if lo > hi || hi > int64(len(arr)) || lo < 0 {
+                               t.Abort(SliceError{lo, hi, int64(len(arr))})
+                       }
+                       return arr[lo:hi]
+               }
+
+       default:
+               log.Panicf("unexpected left operand type %T", arr.t.lit())
+       }
+
+       return expr
+}
+
+func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
+       // Type check object
+       l = l.derefArray()
+
+       var at Type
+       intIndex := false
+       var maxIndex int64 = -1
+
+       switch lt := l.t.lit().(type) {
+       case *ArrayType:
+               at = lt.Elem
+               intIndex = true
+               maxIndex = lt.Len
+
+       case *SliceType:
+               at = lt.Elem
+               intIndex = true
+
+       case *stringType:
+               at = Uint8Type
+               intIndex = true
+
+       case *MapType:
+               at = lt.Elem
+               if r.t.isIdeal() {
+                       r = r.convertTo(lt.Key)
+                       if r == nil {
+                               return nil
+                       }
+               }
+               if !lt.Key.compat(r.t, false) {
+                       a.diag("cannot use %s as index into %s", r.t, lt)
+                       return nil
+               }
+
+       default:
+               a.diag("cannot index into %v", l.t)
+               return nil
+       }
+
+       // Type check index and convert to int if necessary
+       if intIndex {
+               // XXX(Spec) It's unclear if ideal floats with no
+               // fractional part are allowed here.  6g allows it.  I
+               // believe that's wrong.
+               r = r.convertToInt(maxIndex, "index", "index")
+               if r == nil {
+                       return nil
+               }
+       }
+
+       expr := a.newExpr(at, "index expression")
+
+       // Compile
+       switch lt := l.t.lit().(type) {
+       case *ArrayType:
+               lf := l.asArray()
+               rf := r.asInt()
+               bound := lt.Len
+               expr.genValue(func(t *Thread) Value {
+                       l, r := lf(t), rf(t)
+                       if r < 0 || r >= bound {
+                               t.Abort(IndexError{r, bound})
+                       }
+                       return l.Elem(t, r)
+               })
+
+       case *SliceType:
+               lf := l.asSlice()
+               rf := r.asInt()
+               expr.genValue(func(t *Thread) Value {
+                       l, r := lf(t), rf(t)
+                       if l.Base == nil {
+                               t.Abort(NilPointerError{})
+                       }
+                       if r < 0 || r >= l.Len {
+                               t.Abort(IndexError{r, l.Len})
+                       }
+                       return l.Base.Elem(t, r)
+               })
+
+       case *stringType:
+               lf := l.asString()
+               rf := r.asInt()
+               // TODO(austin) This pulls over the whole string in a
+               // remote setting, instead of just the one character.
+               expr.eval = func(t *Thread) uint64 {
+                       l, r := lf(t), rf(t)
+                       if r < 0 || r >= int64(len(l)) {
+                               t.Abort(IndexError{r, int64(len(l))})
+                       }
+                       return uint64(l[r])
+               }
+
+       case *MapType:
+               lf := l.asMap()
+               rf := r.asInterface()
+               expr.genValue(func(t *Thread) Value {
+                       m := lf(t)
+                       k := rf(t)
+                       if m == nil {
+                               t.Abort(NilPointerError{})
+                       }
+                       e := m.Elem(t, k)
+                       if e == nil {
+                               t.Abort(KeyError{k})
+                       }
+                       return e
+               })
+               // genValue makes things addressable, but map values
+               // aren't addressable.
+               expr.evalAddr = nil
+               expr.evalMapValue = func(t *Thread) (Map, interface{}) {
+                       // TODO(austin) Key check?  nil check?
+                       return lf(t), rf(t)
+               }
+
+       default:
+               log.Panicf("unexpected left operand type %T", l.t.lit())
+       }
+
+       return expr
+}
+
+func (a *exprInfo) compileCallExpr(b *block, l *expr, as []*expr) *expr {
+       // TODO(austin) Variadic functions.
+
+       // Type check
+
+       // XXX(Spec) Calling a named function type is okay.  I really
+       // think there needs to be a general discussion of named
+       // types.  A named type creates a new, distinct type, but the
+       // type of that type is still whatever it's defined to.  Thus,
+       // in "type Foo int", Foo is still an integer type and in
+       // "type Foo func()", Foo is a function type.
+       lt, ok := l.t.lit().(*FuncType)
+       if !ok {
+               a.diag("cannot call non-function type %v", l.t)
+               return nil
+       }
+
+       // The arguments must be single-valued expressions assignment
+       // compatible with the parameters of F.
+       //
+       // XXX(Spec) The spec is wrong.  It can also be a single
+       // multi-valued expression.
+       nin := len(lt.In)
+       assign := a.compileAssign(a.pos, b, NewMultiType(lt.In), as, "function call", "argument")
+       if assign == nil {
+               return nil
+       }
+
+       var t Type
+       nout := len(lt.Out)
+       switch nout {
+       case 0:
+               t = EmptyType
+       case 1:
+               t = lt.Out[0]
+       default:
+               t = NewMultiType(lt.Out)
+       }
+       expr := a.newExpr(t, "function call")
+
+       // Gather argument and out types to initialize frame variables
+       vts := make([]Type, nin+nout)
+       copy(vts, lt.In)
+       copy(vts[nin:], lt.Out)
+
+       // Compile
+       lf := l.asFunc()
+       call := func(t *Thread) []Value {
+               fun := lf(t)
+               fr := fun.NewFrame()
+               for i, t := range vts {
+                       fr.Vars[i] = t.Zero()
+               }
+               assign(multiV(fr.Vars[0:nin]), t)
+               oldf := t.f
+               t.f = fr
+               fun.Call(t)
+               t.f = oldf
+               return fr.Vars[nin : nin+nout]
+       }
+       expr.genFuncCall(call)
+
+       return expr
+}
+
+func (a *exprInfo) compileBuiltinCallExpr(b *block, ft *FuncType, as []*expr) *expr {
+       checkCount := func(min, max int) bool {
+               if len(as) < min {
+                       a.diag("not enough arguments to %s", ft.builtin)
+                       return false
+               } else if len(as) > max {
+                       a.diag("too many arguments to %s", ft.builtin)
+                       return false
+               }
+               return true
+       }
+
+       switch ft {
+       case capType:
+               if !checkCount(1, 1) {
+                       return nil
+               }
+               arg := as[0].derefArray()
+               expr := a.newExpr(IntType, "function call")
+               switch t := arg.t.lit().(type) {
+               case *ArrayType:
+                       // TODO(austin) It would be nice if this could
+                       // be a constant int.
+                       v := t.Len
+                       expr.eval = func(t *Thread) int64 { return v }
+
+               case *SliceType:
+                       vf := arg.asSlice()
+                       expr.eval = func(t *Thread) int64 { return vf(t).Cap }
+
+               //case *ChanType:
+
+               default:
+                       a.diag("illegal argument type for cap function\n\t%v", arg.t)
+                       return nil
+               }
+               return expr
+
+       case copyType:
+               if !checkCount(2, 2) {
+                       return nil
+               }
+               src := as[1]
+               dst := as[0]
+               if src.t != dst.t {
+                       a.diag("arguments to built-in function 'copy' must have same type\nsrc: %s\ndst: %s\n", src.t, dst.t)
+                       return nil
+               }
+               if _, ok := src.t.lit().(*SliceType); !ok {
+                       a.diag("src argument to 'copy' must be a slice (got: %s)", src.t)
+                       return nil
+               }
+               if _, ok := dst.t.lit().(*SliceType); !ok {
+                       a.diag("dst argument to 'copy' must be a slice (got: %s)", dst.t)
+                       return nil
+               }
+               expr := a.newExpr(IntType, "function call")
+               srcf := src.asSlice()
+               dstf := dst.asSlice()
+               expr.eval = func(t *Thread) int64 {
+                       src, dst := srcf(t), dstf(t)
+                       nelems := src.Len
+                       if nelems > dst.Len {
+                               nelems = dst.Len
+                       }
+                       dst.Base.Sub(0, nelems).Assign(t, src.Base.Sub(0, nelems))
+                       return nelems
+               }
+               return expr
+
+       case lenType:
+               if !checkCount(1, 1) {
+                       return nil
+               }
+               arg := as[0].derefArray()
+               expr := a.newExpr(IntType, "function call")
+               switch t := arg.t.lit().(type) {
+               case *stringType:
+                       vf := arg.asString()
+                       expr.eval = func(t *Thread) int64 { return int64(len(vf(t))) }
+
+               case *ArrayType:
+                       // TODO(austin) It would be nice if this could
+                       // be a constant int.
+                       v := t.Len
+                       expr.eval = func(t *Thread) int64 { return v }
+
+               case *SliceType:
+                       vf := arg.asSlice()
+                       expr.eval = func(t *Thread) int64 { return vf(t).Len }
+
+               case *MapType:
+                       vf := arg.asMap()
+                       expr.eval = func(t *Thread) int64 {
+                               // XXX(Spec) What's the len of an
+                               // uninitialized map?
+                               m := vf(t)
+                               if m == nil {
+                                       return 0
+                               }
+                               return m.Len(t)
+                       }
+
+               //case *ChanType:
+
+               default:
+                       a.diag("illegal argument type for len function\n\t%v", arg.t)
+                       return nil
+               }
+               return expr
+
+       case makeType:
+               if !checkCount(1, 3) {
+                       return nil
+               }
+               // XXX(Spec) What are the types of the
+               // arguments?  Do they have to be ints?  6g
+               // accepts any integral type.
+               var lenexpr, capexpr *expr
+               var lenf, capf func(*Thread) int64
+               if len(as) > 1 {
+                       lenexpr = as[1].convertToInt(-1, "length", "make function")
+                       if lenexpr == nil {
+                               return nil
+                       }
+                       lenf = lenexpr.asInt()
+               }
+               if len(as) > 2 {
+                       capexpr = as[2].convertToInt(-1, "capacity", "make function")
+                       if capexpr == nil {
+                               return nil
+                       }
+                       capf = capexpr.asInt()
+               }
+
+               switch t := as[0].valType.lit().(type) {
+               case *SliceType:
+                       // A new, initialized slice value for a given
+                       // element type T is made using the built-in
+                       // function make, which takes a slice type and
+                       // parameters specifying the length and
+                       // optionally the capacity.
+                       if !checkCount(2, 3) {
+                               return nil
+                       }
+                       et := t.Elem
+                       expr := a.newExpr(t, "function call")
+                       expr.eval = func(t *Thread) Slice {
+                               l := lenf(t)
+                               // XXX(Spec) What if len or cap is
+                               // negative?  The runtime panics.
+                               if l < 0 {
+                                       t.Abort(NegativeLengthError{l})
+                               }
+                               c := l
+                               if capf != nil {
+                                       c = capf(t)
+                                       if c < 0 {
+                                               t.Abort(NegativeCapacityError{c})
+                                       }
+                                       // XXX(Spec) What happens if
+                                       // len > cap?  The runtime
+                                       // sets cap to len.
+                                       if l > c {
+                                               c = l
+                                       }
+                               }
+                               base := arrayV(make([]Value, c))
+                               for i := int64(0); i < c; i++ {
+                                       base[i] = et.Zero()
+                               }
+                               return Slice{&base, l, c}
+                       }
+                       return expr
+
+               case *MapType:
+                       // A new, empty map value is made using the
+                       // built-in function make, which takes the map
+                       // type and an optional capacity hint as
+                       // arguments.
+                       if !checkCount(1, 2) {
+                               return nil
+                       }
+                       expr := a.newExpr(t, "function call")
+                       expr.eval = func(t *Thread) Map {
+                               if lenf == nil {
+                                       return make(evalMap)
+                               }
+                               l := lenf(t)
+                               return make(evalMap, l)
+                       }
+                       return expr
+
+               //case *ChanType:
+
+               default:
+                       a.diag("illegal argument type for make function\n\t%v", as[0].valType)
+                       return nil
+               }
+
+       case closeType, closedType:
+               a.diag("built-in function %s not implemented", ft.builtin)
+               return nil
+
+       case newType:
+               if !checkCount(1, 1) {
+                       return nil
+               }
+
+               t := as[0].valType
+               expr := a.newExpr(NewPtrType(t), "new")
+               expr.eval = func(*Thread) Value { return t.Zero() }
+               return expr
+
+       case panicType, printType, printlnType:
+               evals := make([]func(*Thread) interface{}, len(as))
+               for i, x := range as {
+                       evals[i] = x.asInterface()
+               }
+               spaces := ft == printlnType
+               newline := ft != printType
+               printer := func(t *Thread) {
+                       for i, eval := range evals {
+                               if i > 0 && spaces {
+                                       print(" ")
+                               }
+                               v := eval(t)
+                               type stringer interface {
+                                       String() string
+                               }
+                               switch v1 := v.(type) {
+                               case bool:
+                                       print(v1)
+                               case uint64:
+                                       print(v1)
+                               case int64:
+                                       print(v1)
+                               case float64:
+                                       print(v1)
+                               case string:
+                                       print(v1)
+                               case stringer:
+                                       print(v1.String())
+                               default:
+                                       print("???")
+                               }
+                       }
+                       if newline {
+                               print("\n")
+                       }
+               }
+               expr := a.newExpr(EmptyType, "print")
+               expr.exec = printer
+               if ft == panicType {
+                       expr.exec = func(t *Thread) {
+                               printer(t)
+                               t.Abort(os.NewError("panic"))
+                       }
+               }
+               return expr
+       }
+
+       log.Panicf("unexpected built-in function '%s'", ft.builtin)
+       panic("unreachable")
+}
+
+func (a *exprInfo) compileStarExpr(v *expr) *expr {
+       switch vt := v.t.lit().(type) {
+       case *PtrType:
+               expr := a.newExpr(vt.Elem, "indirect expression")
+               vf := v.asPtr()
+               expr.genValue(func(t *Thread) Value {
+                       v := vf(t)
+                       if v == nil {
+                               t.Abort(NilPointerError{})
+                       }
+                       return v
+               })
+               return expr
+       }
+
+       a.diagOpType(token.MUL, v.t)
+       return nil
+}
+
+var unaryOpDescs = make(map[token.Token]string)
+
+func (a *exprInfo) compileUnaryExpr(op token.Token, v *expr) *expr {
+       // Type check
+       var t Type
+       switch op {
+       case token.ADD, token.SUB:
+               if !v.t.isInteger() && !v.t.isFloat() {
+                       a.diagOpType(op, v.t)
+                       return nil
+               }
+               t = v.t
+
+       case token.NOT:
+               if !v.t.isBoolean() {
+                       a.diagOpType(op, v.t)
+                       return nil
+               }
+               t = BoolType
+
+       case token.XOR:
+               if !v.t.isInteger() {
+                       a.diagOpType(op, v.t)
+                       return nil
+               }
+               t = v.t
+
+       case token.AND:
+               // The unary prefix address-of operator & generates
+               // the address of its operand, which must be a
+               // variable, pointer indirection, field selector, or
+               // array or slice indexing operation.
+               if v.evalAddr == nil {
+                       a.diag("cannot take the address of %s", v.desc)
+                       return nil
+               }
+
+               // TODO(austin) Implement "It is illegal to take the
+               // address of a function result variable" once I have
+               // function result variables.
+
+               t = NewPtrType(v.t)
+
+       case token.ARROW:
+               log.Panicf("Unary op %v not implemented", op)
+
+       default:
+               log.Panicf("unknown unary operator %v", op)
+       }
+
+       desc, ok := unaryOpDescs[op]
+       if !ok {
+               desc = "unary " + op.String() + " expression"
+               unaryOpDescs[op] = desc
+       }
+
+       // Compile
+       expr := a.newExpr(t, desc)
+       switch op {
+       case token.ADD:
+               // Just compile it out
+               expr = v
+               expr.desc = desc
+
+       case token.SUB:
+               expr.genUnaryOpNeg(v)
+
+       case token.NOT:
+               expr.genUnaryOpNot(v)
+
+       case token.XOR:
+               expr.genUnaryOpXor(v)
+
+       case token.AND:
+               vf := v.evalAddr
+               expr.eval = func(t *Thread) Value { return vf(t) }
+
+       default:
+               log.Panicf("Compilation of unary op %v not implemented", op)
+       }
+
+       return expr
+}
+
+var binOpDescs = make(map[token.Token]string)
+
+func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
+       // Save the original types of l.t and r.t for error messages.
+       origlt := l.t
+       origrt := r.t
+
+       // XXX(Spec) What is the exact definition of a "named type"?
+
+       // XXX(Spec) Arithmetic operators: "Integer types" apparently
+       // means all types compatible with basic integer types, though
+       // this is never explained.  Likewise for float types, etc.
+       // This relates to the missing explanation of named types.
+
+       // XXX(Spec) Operators: "If both operands are ideal numbers,
+       // the conversion is to ideal floats if one of the operands is
+       // an ideal float (relevant for / and %)."  How is that
+       // relevant only for / and %?  If I add an ideal int and an
+       // ideal float, I get an ideal float.
+
+       if op != token.SHL && op != token.SHR {
+               // Except in shift expressions, if one operand has
+               // numeric type and the other operand is an ideal
+               // number, the ideal number is converted to match the
+               // type of the other operand.
+               if (l.t.isInteger() || l.t.isFloat()) && !l.t.isIdeal() && r.t.isIdeal() {
+                       r = r.convertTo(l.t)
+               } else if (r.t.isInteger() || r.t.isFloat()) && !r.t.isIdeal() && l.t.isIdeal() {
+                       l = l.convertTo(r.t)
+               }
+               if l == nil || r == nil {
+                       return nil
+               }
+
+               // Except in shift expressions, if both operands are
+               // ideal numbers and one is an ideal float, the other
+               // is converted to ideal float.
+               if l.t.isIdeal() && r.t.isIdeal() {
+                       if l.t.isInteger() && r.t.isFloat() {
+                               l = l.convertTo(r.t)
+                       } else if l.t.isFloat() && r.t.isInteger() {
+                               r = r.convertTo(l.t)
+                       }
+                       if l == nil || r == nil {
+                               return nil
+                       }
+               }
+       }
+
+       // Useful type predicates
+       // TODO(austin) CL 33668 mandates identical types except for comparisons.
+       compat := func() bool { return l.t.compat(r.t, false) }
+       integers := func() bool { return l.t.isInteger() && r.t.isInteger() }
+       floats := func() bool { return l.t.isFloat() && r.t.isFloat() }
+       strings := func() bool {
+               // TODO(austin) Deal with named types
+               return l.t == StringType && r.t == StringType
+       }
+       booleans := func() bool { return l.t.isBoolean() && r.t.isBoolean() }
+
+       // Type check
+       var t Type
+       switch op {
+       case token.ADD:
+               if !compat() || (!integers() && !floats() && !strings()) {
+                       a.diagOpTypes(op, origlt, origrt)
+                       return nil
+               }
+               t = l.t
+
+       case token.SUB, token.MUL, token.QUO:
+               if !compat() || (!integers() && !floats()) {
+                       a.diagOpTypes(op, origlt, origrt)
+                       return nil
+               }
+               t = l.t
+
+       case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
+               if !compat() || !integers() {
+                       a.diagOpTypes(op, origlt, origrt)
+                       return nil
+               }
+               t = l.t
+
+       case token.SHL, token.SHR:
+               // XXX(Spec) Is it okay for the right operand to be an
+               // ideal float with no fractional part?  "The right
+               // operand in a shift operation must be always be of
+               // unsigned integer type or an ideal number that can
+               // be safely converted into an unsigned integer type
+               // (§Arithmetic operators)" suggests so and 6g agrees.
+
+               if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) {
+                       a.diagOpTypes(op, origlt, origrt)
+                       return nil
+               }
+
+               // The right operand in a shift operation must be
+               // always be of unsigned integer type or an ideal
+               // number that can be safely converted into an
+               // unsigned integer type.
+               if r.t.isIdeal() {
+                       r2 := r.convertTo(UintType)
+                       if r2 == nil {
+                               return nil
+                       }
+
+                       // If the left operand is not ideal, convert
+                       // the right to not ideal.
+                       if !l.t.isIdeal() {
+                               r = r2
+                       }
+
+                       // If both are ideal, but the right side isn't
+                       // an ideal int, convert it to simplify things.
+                       if l.t.isIdeal() && !r.t.isInteger() {
+                               r = r.convertTo(IdealIntType)
+                               if r == nil {
+                                       log.Panicf("conversion to uintType succeeded, but conversion to idealIntType failed")
+                               }
+                       }
+               } else if _, ok := r.t.lit().(*uintType); !ok {
+                       a.diag("right operand of shift must be unsigned")
+                       return nil
+               }
+
+               if l.t.isIdeal() && !r.t.isIdeal() {
+                       // XXX(Spec) What is the meaning of "ideal >>
+                       // non-ideal"?  Russ says the ideal should be
+                       // converted to an int.  6g propagates the
+                       // type down from assignments as a hint.
+
+                       l = l.convertTo(IntType)
+                       if l == nil {
+                               return nil
+                       }
+               }
+
+               // At this point, we should have one of three cases:
+               // 1) uint SHIFT uint
+               // 2) int SHIFT uint
+               // 3) ideal int SHIFT ideal int
+
+               t = l.t
+
+       case token.LOR, token.LAND:
+               if !booleans() {
+                       return nil
+               }
+               // XXX(Spec) There's no mention of *which* boolean
+               // type the logical operators return.  From poking at
+               // 6g, it appears to be the named boolean type, NOT
+               // the type of the left operand, and NOT an unnamed
+               // boolean type.
+
+               t = BoolType
+
+       case token.ARROW:
+               // The operands in channel sends differ in type: one
+               // is always a channel and the other is a variable or
+               // value of the channel's element type.
+               log.Panic("Binary op <- not implemented")
+               t = BoolType
+
+       case token.LSS, token.GTR, token.LEQ, token.GEQ:
+               // XXX(Spec) It's really unclear what types which
+               // comparison operators apply to.  I feel like the
+               // text is trying to paint a Venn diagram for me,
+               // which it's really pretty simple: <, <=, >, >= apply
+               // only to numeric types and strings.  == and != apply
+               // to everything except arrays and structs, and there
+               // are some restrictions on when it applies to slices.
+
+               if !compat() || (!integers() && !floats() && !strings()) {
+                       a.diagOpTypes(op, origlt, origrt)
+                       return nil
+               }
+               t = BoolType
+
+       case token.EQL, token.NEQ:
+               // XXX(Spec) The rules for type checking comparison
+               // operators are spread across three places that all
+               // partially overlap with each other: the Comparison
+               // Compatibility section, the Operators section, and
+               // the Comparison Operators section.  The Operators
+               // section should just say that operators require
+               // identical types (as it does currently) except that
+               // there a few special cases for comparison, which are
+               // described in section X.  Currently it includes just
+               // one of the four special cases.  The Comparison
+               // Compatibility section and the Comparison Operators
+               // section should either be merged, or at least the
+               // Comparison Compatibility section should be
+               // exclusively about type checking and the Comparison
+               // Operators section should be exclusively about
+               // semantics.
+
+               // XXX(Spec) Comparison operators: "All comparison
+               // operators apply to basic types except bools."  This
+               // is very difficult to parse.  It's explained much
+               // better in the Comparison Compatibility section.
+
+               // XXX(Spec) Comparison compatibility: "Function
+               // values are equal if they refer to the same
+               // function." is rather vague.  It should probably be
+               // similar to the way the rule for map values is
+               // written: Function values are equal if they were
+               // created by the same execution of a function literal
+               // or refer to the same function declaration.  This is
+               // *almost* but not quite waht 6g implements.  If a
+               // function literals does not capture any variables,
+               // then multiple executions of it will result in the
+               // same closure.  Russ says he'll change that.
+
+               // TODO(austin) Deal with remaining special cases
+
+               if !compat() {
+                       a.diagOpTypes(op, origlt, origrt)
+                       return nil
+               }
+               // Arrays and structs may not be compared to anything.
+               switch l.t.(type) {
+               case *ArrayType, *StructType:
+                       a.diagOpTypes(op, origlt, origrt)
+                       return nil
+               }
+               t = BoolType
+
+       default:
+               log.Panicf("unknown binary operator %v", op)
+       }
+
+       desc, ok := binOpDescs[op]
+       if !ok {
+               desc = op.String() + " expression"
+               binOpDescs[op] = desc
+       }
+
+       // Check for ideal divide by zero
+       switch op {
+       case token.QUO, token.REM:
+               if r.t.isIdeal() {
+                       if (r.t.isInteger() && r.asIdealInt()().Sign() == 0) ||
+                               (r.t.isFloat() && r.asIdealFloat()().Sign() == 0) {
+                               a.diag("divide by zero")
+                               return nil
+                       }
+               }
+       }
+
+       // Compile
+       expr := a.newExpr(t, desc)
+       switch op {
+       case token.ADD:
+               expr.genBinOpAdd(l, r)
+
+       case token.SUB:
+               expr.genBinOpSub(l, r)
+
+       case token.MUL:
+               expr.genBinOpMul(l, r)
+
+       case token.QUO:
+               expr.genBinOpQuo(l, r)
+
+       case token.REM:
+               expr.genBinOpRem(l, r)
+
+       case token.AND:
+               expr.genBinOpAnd(l, r)
+
+       case token.OR:
+               expr.genBinOpOr(l, r)
+
+       case token.XOR:
+               expr.genBinOpXor(l, r)
+
+       case token.AND_NOT:
+               expr.genBinOpAndNot(l, r)
+
+       case token.SHL:
+               if l.t.isIdeal() {
+                       lv := l.asIdealInt()()
+                       rv := r.asIdealInt()()
+                       const maxShift = 99999
+                       if rv.Cmp(big.NewInt(maxShift)) > 0 {
+                               a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift)
+                               expr.t = nil
+                               return nil
+                       }
+                       val := new(big.Int).Lsh(lv, uint(rv.Int64()))
+                       expr.eval = func() *big.Int { return val }
+               } else {
+                       expr.genBinOpShl(l, r)
+               }
+
+       case token.SHR:
+               if l.t.isIdeal() {
+                       lv := l.asIdealInt()()
+                       rv := r.asIdealInt()()
+                       val := new(big.Int).Rsh(lv, uint(rv.Int64()))
+                       expr.eval = func() *big.Int { return val }
+               } else {
+                       expr.genBinOpShr(l, r)
+               }
+
+       case token.LSS:
+               expr.genBinOpLss(l, r)
+
+       case token.GTR:
+               expr.genBinOpGtr(l, r)
+
+       case token.LEQ:
+               expr.genBinOpLeq(l, r)
+
+       case token.GEQ:
+               expr.genBinOpGeq(l, r)
+
+       case token.EQL:
+               expr.genBinOpEql(l, r)
+
+       case token.NEQ:
+               expr.genBinOpNeq(l, r)
+
+       case token.LAND:
+               expr.genBinOpLogAnd(l, r)
+
+       case token.LOR:
+               expr.genBinOpLogOr(l, r)
+
+       default:
+               log.Panicf("Compilation of binary op %v not implemented", op)
+       }
+
+       return expr
+}
+
+// TODO(austin) This is a hack to eliminate a circular dependency
+// between type.go and expr.go
+func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
+       lenExpr := a.compileExpr(b, true, expr)
+       if lenExpr == nil {
+               return 0, false
+       }
+
+       // XXX(Spec) Are ideal floats with no fractional part okay?
+       if lenExpr.t.isIdeal() {
+               lenExpr = lenExpr.convertTo(IntType)
+               if lenExpr == nil {
+                       return 0, false
+               }
+       }
+
+       if !lenExpr.t.isInteger() {
+               a.diagAt(expr, "array size must be an integer")
+               return 0, false
+       }
+
+       switch lenExpr.t.lit().(type) {
+       case *intType:
+               return lenExpr.asInt()(nil), true
+       case *uintType:
+               return int64(lenExpr.asUint()(nil)), true
+       }
+       log.Panicf("unexpected integer type %T", lenExpr.t)
+       return 0, false
+}
+
+func (a *compiler) compileExpr(b *block, constant bool, expr ast.Expr) *expr {
+       ec := &exprCompiler{a, b, constant}
+       nerr := a.numError()
+       e := ec.compile(expr, false)
+       if e == nil && nerr == a.numError() {
+               log.Panicf("expression compilation failed without reporting errors")
+       }
+       return e
+}
+
+// extractEffect separates out any effects that the expression may
+// have, returning a function that will perform those effects and a
+// new exprCompiler that is guaranteed to be side-effect free.  These
+// are the moral equivalents of "temp := expr" and "temp" (or "temp :=
+// &expr" and "*temp" for addressable exprs).  Because this creates a
+// temporary variable, the caller should create a temporary block for
+// the compilation of this expression and the evaluation of the
+// results.
+func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) {
+       // Create "&a" if a is addressable
+       rhs := a
+       if a.evalAddr != nil {
+               rhs = a.compileUnaryExpr(token.AND, rhs)
+       }
+
+       // Create temp
+       ac, ok := a.checkAssign(a.pos, []*expr{rhs}, errOp, "")
+       if !ok {
+               return nil, nil
+       }
+       if len(ac.rmt.Elems) != 1 {
+               a.diag("multi-valued expression not allowed in %s", errOp)
+               return nil, nil
+       }
+       tempType := ac.rmt.Elems[0]
+       if tempType.isIdeal() {
+               // It's too bad we have to duplicate this rule.
+               switch {
+               case tempType.isInteger():
+                       tempType = IntType
+               case tempType.isFloat():
+                       tempType = FloatType
+               default:
+                       log.Panicf("unexpected ideal type %v", tempType)
+               }
+       }
+       temp := b.DefineTemp(tempType)
+       tempIdx := temp.Index
+
+       // Create "temp := rhs"
+       assign := ac.compile(b, tempType)
+       if assign == nil {
+               log.Panicf("compileAssign type check failed")
+       }
+
+       effect := func(t *Thread) {
+               tempVal := tempType.Zero()
+               t.f.Vars[tempIdx] = tempVal
+               assign(tempVal, t)
+       }
+
+       // Generate "temp" or "*temp"
+       getTemp := a.compileVariable(0, temp)
+       if a.evalAddr == nil {
+               return effect, getTemp
+       }
+
+       deref := a.compileStarExpr(getTemp)
+       if deref == nil {
+               return nil, nil
+       }
+       return effect, deref
+}
diff --git a/libgo/go/exp/eval/expr1.go b/libgo/go/exp/eval/expr1.go
new file mode 100644 (file)
index 0000000..ae0cfc7
--- /dev/null
@@ -0,0 +1,1905 @@
+// This file is machine generated by gen.go.
+// 6g gen.go && 6l gen.6 && ./6.out >expr1.go
+
+package eval
+
+import (
+       "big"
+       "log"
+)
+
+/*
+* "As" functions.  These retrieve evaluator functions from an
+* expr, panicking if the requested evaluator has the wrong type.
+ */
+func (a *expr) asBool() func(*Thread) bool {
+       return a.eval.(func(*Thread) bool)
+}
+func (a *expr) asUint() func(*Thread) uint64 {
+       return a.eval.(func(*Thread) uint64)
+}
+func (a *expr) asInt() func(*Thread) int64 {
+       return a.eval.(func(*Thread) int64)
+}
+func (a *expr) asIdealInt() func() *big.Int {
+       return a.eval.(func() *big.Int)
+}
+func (a *expr) asFloat() func(*Thread) float64 {
+       return a.eval.(func(*Thread) float64)
+}
+func (a *expr) asIdealFloat() func() *big.Rat {
+       return a.eval.(func() *big.Rat)
+}
+func (a *expr) asString() func(*Thread) string {
+       return a.eval.(func(*Thread) string)
+}
+func (a *expr) asArray() func(*Thread) ArrayValue {
+       return a.eval.(func(*Thread) ArrayValue)
+}
+func (a *expr) asStruct() func(*Thread) StructValue {
+       return a.eval.(func(*Thread) StructValue)
+}
+func (a *expr) asPtr() func(*Thread) Value {
+       return a.eval.(func(*Thread) Value)
+}
+func (a *expr) asFunc() func(*Thread) Func {
+       return a.eval.(func(*Thread) Func)
+}
+func (a *expr) asSlice() func(*Thread) Slice {
+       return a.eval.(func(*Thread) Slice)
+}
+func (a *expr) asMap() func(*Thread) Map {
+       return a.eval.(func(*Thread) Map)
+}
+func (a *expr) asMulti() func(*Thread) []Value {
+       return a.eval.(func(*Thread) []Value)
+}
+
+func (a *expr) asInterface() func(*Thread) interface{} {
+       switch sf := a.eval.(type) {
+       case func(t *Thread) bool:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func(t *Thread) uint64:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func(t *Thread) int64:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func() *big.Int:
+               return func(*Thread) interface{} { return sf() }
+       case func(t *Thread) float64:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func() *big.Rat:
+               return func(*Thread) interface{} { return sf() }
+       case func(t *Thread) string:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func(t *Thread) ArrayValue:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func(t *Thread) StructValue:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func(t *Thread) Value:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func(t *Thread) Func:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func(t *Thread) Slice:
+               return func(t *Thread) interface{} { return sf(t) }
+       case func(t *Thread) Map:
+               return func(t *Thread) interface{} { return sf(t) }
+       default:
+               log.Panicf("unexpected expression node type %T at %v", a.eval, a.pos)
+       }
+       panic("fail")
+}
+
+/*
+* Operator generators.
+ */
+
+func (a *expr) genConstant(v Value) {
+       switch a.t.lit().(type) {
+       case *boolType:
+               a.eval = func(t *Thread) bool { return v.(BoolValue).Get(t) }
+       case *uintType:
+               a.eval = func(t *Thread) uint64 { return v.(UintValue).Get(t) }
+       case *intType:
+               a.eval = func(t *Thread) int64 { return v.(IntValue).Get(t) }
+       case *idealIntType:
+               val := v.(IdealIntValue).Get()
+               a.eval = func() *big.Int { return val }
+       case *floatType:
+               a.eval = func(t *Thread) float64 { return v.(FloatValue).Get(t) }
+       case *idealFloatType:
+               val := v.(IdealFloatValue).Get()
+               a.eval = func() *big.Rat { return val }
+       case *stringType:
+               a.eval = func(t *Thread) string { return v.(StringValue).Get(t) }
+       case *ArrayType:
+               a.eval = func(t *Thread) ArrayValue { return v.(ArrayValue).Get(t) }
+       case *StructType:
+               a.eval = func(t *Thread) StructValue { return v.(StructValue).Get(t) }
+       case *PtrType:
+               a.eval = func(t *Thread) Value { return v.(PtrValue).Get(t) }
+       case *FuncType:
+               a.eval = func(t *Thread) Func { return v.(FuncValue).Get(t) }
+       case *SliceType:
+               a.eval = func(t *Thread) Slice { return v.(SliceValue).Get(t) }
+       case *MapType:
+               a.eval = func(t *Thread) Map { return v.(MapValue).Get(t) }
+       default:
+               log.Panicf("unexpected constant type %v at %v", a.t, a.pos)
+       }
+}
+
+func (a *expr) genIdentOp(level, index int) {
+       a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) }
+       switch a.t.lit().(type) {
+       case *boolType:
+               a.eval = func(t *Thread) bool { return t.f.Get(level, index).(BoolValue).Get(t) }
+       case *uintType:
+               a.eval = func(t *Thread) uint64 { return t.f.Get(level, index).(UintValue).Get(t) }
+       case *intType:
+               a.eval = func(t *Thread) int64 { return t.f.Get(level, index).(IntValue).Get(t) }
+       case *floatType:
+               a.eval = func(t *Thread) float64 { return t.f.Get(level, index).(FloatValue).Get(t) }
+       case *stringType:
+               a.eval = func(t *Thread) string { return t.f.Get(level, index).(StringValue).Get(t) }
+       case *ArrayType:
+               a.eval = func(t *Thread) ArrayValue { return t.f.Get(level, index).(ArrayValue).Get(t) }
+       case *StructType:
+               a.eval = func(t *Thread) StructValue { return t.f.Get(level, index).(StructValue).Get(t) }
+       case *PtrType:
+               a.eval = func(t *Thread) Value { return t.f.Get(level, index).(PtrValue).Get(t) }
+       case *FuncType:
+               a.eval = func(t *Thread) Func { return t.f.Get(level, index).(FuncValue).Get(t) }
+       case *SliceType:
+               a.eval = func(t *Thread) Slice { return t.f.Get(level, index).(SliceValue).Get(t) }
+       case *MapType:
+               a.eval = func(t *Thread) Map { return t.f.Get(level, index).(MapValue).Get(t) }
+       default:
+               log.Panicf("unexpected identifier type %v at %v", a.t, a.pos)
+       }
+}
+
+func (a *expr) genFuncCall(call func(t *Thread) []Value) {
+       a.exec = func(t *Thread) { call(t) }
+       switch a.t.lit().(type) {
+       case *boolType:
+               a.eval = func(t *Thread) bool { return call(t)[0].(BoolValue).Get(t) }
+       case *uintType:
+               a.eval = func(t *Thread) uint64 { return call(t)[0].(UintValue).Get(t) }
+       case *intType:
+               a.eval = func(t *Thread) int64 { return call(t)[0].(IntValue).Get(t) }
+       case *floatType:
+               a.eval = func(t *Thread) float64 { return call(t)[0].(FloatValue).Get(t) }
+       case *stringType:
+               a.eval = func(t *Thread) string { return call(t)[0].(StringValue).Get(t) }
+       case *ArrayType:
+               a.eval = func(t *Thread) ArrayValue { return call(t)[0].(ArrayValue).Get(t) }
+       case *StructType:
+               a.eval = func(t *Thread) StructValue { return call(t)[0].(StructValue).Get(t) }
+       case *PtrType:
+               a.eval = func(t *Thread) Value { return call(t)[0].(PtrValue).Get(t) }
+       case *FuncType:
+               a.eval = func(t *Thread) Func { return call(t)[0].(FuncValue).Get(t) }
+       case *SliceType:
+               a.eval = func(t *Thread) Slice { return call(t)[0].(SliceValue).Get(t) }
+       case *MapType:
+               a.eval = func(t *Thread) Map { return call(t)[0].(MapValue).Get(t) }
+       case *MultiType:
+               a.eval = func(t *Thread) []Value { return call(t) }
+       default:
+               log.Panicf("unexpected result type %v at %v", a.t, a.pos)
+       }
+}
+
+func (a *expr) genValue(vf func(*Thread) Value) {
+       a.evalAddr = vf
+       switch a.t.lit().(type) {
+       case *boolType:
+               a.eval = func(t *Thread) bool { return vf(t).(BoolValue).Get(t) }
+       case *uintType:
+               a.eval = func(t *Thread) uint64 { return vf(t).(UintValue).Get(t) }
+       case *intType:
+               a.eval = func(t *Thread) int64 { return vf(t).(IntValue).Get(t) }
+       case *floatType:
+               a.eval = func(t *Thread) float64 { return vf(t).(FloatValue).Get(t) }
+       case *stringType:
+               a.eval = func(t *Thread) string { return vf(t).(StringValue).Get(t) }
+       case *ArrayType:
+               a.eval = func(t *Thread) ArrayValue { return vf(t).(ArrayValue).Get(t) }
+       case *StructType:
+               a.eval = func(t *Thread) StructValue { return vf(t).(StructValue).Get(t) }
+       case *PtrType:
+               a.eval = func(t *Thread) Value { return vf(t).(PtrValue).Get(t) }
+       case *FuncType:
+               a.eval = func(t *Thread) Func { return vf(t).(FuncValue).Get(t) }
+       case *SliceType:
+               a.eval = func(t *Thread) Slice { return vf(t).(SliceValue).Get(t) }
+       case *MapType:
+               a.eval = func(t *Thread) Map { return vf(t).(MapValue).Get(t) }
+       default:
+               log.Panicf("unexpected result type %v at %v", a.t, a.pos)
+       }
+}
+
+func (a *expr) genUnaryOpNeg(v *expr) {
+       switch a.t.lit().(type) {
+       case *uintType:
+               vf := v.asUint()
+               a.eval = func(t *Thread) uint64 { v := vf(t); return -v }
+       case *intType:
+               vf := v.asInt()
+               a.eval = func(t *Thread) int64 { v := vf(t); return -v }
+       case *idealIntType:
+               val := v.asIdealInt()()
+               val.Neg(val)
+               a.eval = func() *big.Int { return val }
+       case *floatType:
+               vf := v.asFloat()
+               a.eval = func(t *Thread) float64 { v := vf(t); return -v }
+       case *idealFloatType:
+               val := v.asIdealFloat()()
+               val.Neg(val)
+               a.eval = func() *big.Rat { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", a.t, a.pos)
+       }
+}
+
+func (a *expr) genUnaryOpNot(v *expr) {
+       switch a.t.lit().(type) {
+       case *boolType:
+               vf := v.asBool()
+               a.eval = func(t *Thread) bool { v := vf(t); return !v }
+       default:
+               log.Panicf("unexpected type %v at %v", a.t, a.pos)
+       }
+}
+
+func (a *expr) genUnaryOpXor(v *expr) {
+       switch a.t.lit().(type) {
+       case *uintType:
+               vf := v.asUint()
+               a.eval = func(t *Thread) uint64 { v := vf(t); return ^v }
+       case *intType:
+               vf := v.asInt()
+               a.eval = func(t *Thread) int64 { v := vf(t); return ^v }
+       case *idealIntType:
+               val := v.asIdealInt()()
+               val.Not(val)
+               a.eval = func() *big.Int { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", a.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpLogAnd(l, r *expr) {
+       lf := l.asBool()
+       rf := r.asBool()
+       a.eval = func(t *Thread) bool { return lf(t) && rf(t) }
+}
+
+func (a *expr) genBinOpLogOr(l, r *expr) {
+       lf := l.asBool()
+       rf := r.asBool()
+       a.eval = func(t *Thread) bool { return lf(t) || rf(t) }
+}
+
+func (a *expr) genBinOpAdd(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l + r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l + r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l + r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l + r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l + r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l + r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l + r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l + r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l + r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l + r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Add(l, r)
+               a.eval = func() *big.Int { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               switch t.Bits {
+               case 32:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               ret = l + r
+                               return float64(float32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               ret = l + r
+                               return float64(float64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               ret = l + r
+                               return float64(float(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Add(l, r)
+               a.eval = func() *big.Rat { return val }
+       case *stringType:
+               lf := l.asString()
+               rf := r.asString()
+               a.eval = func(t *Thread) string {
+                       l, r := lf(t), rf(t)
+                       return l + r
+               }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpSub(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l - r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l - r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l - r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l - r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l - r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l - r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l - r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l - r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l - r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l - r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Sub(l, r)
+               a.eval = func() *big.Int { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               switch t.Bits {
+               case 32:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               ret = l - r
+                               return float64(float32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               ret = l - r
+                               return float64(float64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               ret = l - r
+                               return float64(float(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Sub(l, r)
+               a.eval = func() *big.Rat { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpMul(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l * r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l * r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l * r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l * r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l * r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l * r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l * r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l * r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l * r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l * r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Mul(l, r)
+               a.eval = func() *big.Int { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               switch t.Bits {
+               case 32:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               ret = l * r
+                               return float64(float32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               ret = l * r
+                               return float64(float64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               ret = l * r
+                               return float64(float(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Mul(l, r)
+               a.eval = func() *big.Rat { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpQuo(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Quo(l, r)
+               a.eval = func() *big.Int { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               switch t.Bits {
+               case 32:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return float64(float32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return float64(float64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) float64 {
+                               l, r := lf(t), rf(t)
+                               var ret float64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l / r
+                               return float64(float(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Quo(l, r)
+               a.eval = func() *big.Rat { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpRem(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               if r == 0 {
+                                       t.Abort(DivByZeroError{})
+                               }
+                               ret = l % r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Rem(l, r)
+               a.eval = func() *big.Int { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpAnd(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l & r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l & r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l & r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l & r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l & r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l & r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l & r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l & r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l & r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l & r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.And(l, r)
+               a.eval = func() *big.Int { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpOr(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l | r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l | r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l | r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l | r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l | r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l | r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l | r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l | r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l | r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l | r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Or(l, r)
+               a.eval = func() *big.Int { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpXor(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l ^ r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l ^ r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l ^ r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l ^ r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l ^ r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l ^ r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l ^ r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l ^ r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l ^ r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l ^ r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Xor(l, r)
+               a.eval = func() *big.Int { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpAndNot(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l &^ r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l &^ r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l &^ r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l &^ r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l &^ r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l &^ r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l &^ r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l &^ r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l &^ r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l &^ r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.AndNot(l, r)
+               a.eval = func() *big.Int { return val }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpShl(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l << r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l << r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l << r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l << r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l << r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l << r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l << r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l << r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l << r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l << r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpShr(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l >> r
+                               return uint64(uint8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l >> r
+                               return uint64(uint16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l >> r
+                               return uint64(uint32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l >> r
+                               return uint64(uint64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) uint64 {
+                               l, r := lf(t), rf(t)
+                               var ret uint64
+                               ret = l >> r
+                               return uint64(uint(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asUint()
+               switch t.Bits {
+               case 8:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l >> r
+                               return int64(int8(ret))
+                       }
+               case 16:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l >> r
+                               return int64(int16(ret))
+                       }
+               case 32:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l >> r
+                               return int64(int32(ret))
+                       }
+               case 64:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l >> r
+                               return int64(int64(ret))
+                       }
+               case 0:
+                       a.eval = func(t *Thread) int64 {
+                               l, r := lf(t), rf(t)
+                               var ret int64
+                               ret = l >> r
+                               return int64(int(ret))
+                       }
+               default:
+                       log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+               }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpLss(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l < r
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l < r
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Cmp(r) < 0
+               a.eval = func(t *Thread) bool { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l < r
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Cmp(r) < 0
+               a.eval = func(t *Thread) bool { return val }
+       case *stringType:
+               lf := l.asString()
+               rf := r.asString()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l < r
+               }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpGtr(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l > r
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l > r
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Cmp(r) > 0
+               a.eval = func(t *Thread) bool { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l > r
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Cmp(r) > 0
+               a.eval = func(t *Thread) bool { return val }
+       case *stringType:
+               lf := l.asString()
+               rf := r.asString()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l > r
+               }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpLeq(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l <= r
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l <= r
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Cmp(r) <= 0
+               a.eval = func(t *Thread) bool { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l <= r
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Cmp(r) <= 0
+               a.eval = func(t *Thread) bool { return val }
+       case *stringType:
+               lf := l.asString()
+               rf := r.asString()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l <= r
+               }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpGeq(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l >= r
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l >= r
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Cmp(r) >= 0
+               a.eval = func(t *Thread) bool { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l >= r
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Cmp(r) >= 0
+               a.eval = func(t *Thread) bool { return val }
+       case *stringType:
+               lf := l.asString()
+               rf := r.asString()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l >= r
+               }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpEql(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *boolType:
+               lf := l.asBool()
+               rf := r.asBool()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l == r
+               }
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l == r
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l == r
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Cmp(r) == 0
+               a.eval = func(t *Thread) bool { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l == r
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Cmp(r) == 0
+               a.eval = func(t *Thread) bool { return val }
+       case *stringType:
+               lf := l.asString()
+               rf := r.asString()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l == r
+               }
+       case *PtrType:
+               lf := l.asPtr()
+               rf := r.asPtr()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l == r
+               }
+       case *FuncType:
+               lf := l.asFunc()
+               rf := r.asFunc()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l == r
+               }
+       case *MapType:
+               lf := l.asMap()
+               rf := r.asMap()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l == r
+               }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func (a *expr) genBinOpNeq(l, r *expr) {
+       switch t := l.t.lit().(type) {
+       case *boolType:
+               lf := l.asBool()
+               rf := r.asBool()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l != r
+               }
+       case *uintType:
+               lf := l.asUint()
+               rf := r.asUint()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l != r
+               }
+       case *intType:
+               lf := l.asInt()
+               rf := r.asInt()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l != r
+               }
+       case *idealIntType:
+               l := l.asIdealInt()()
+               r := r.asIdealInt()()
+               val := l.Cmp(r) != 0
+               a.eval = func(t *Thread) bool { return val }
+       case *floatType:
+               lf := l.asFloat()
+               rf := r.asFloat()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l != r
+               }
+       case *idealFloatType:
+               l := l.asIdealFloat()()
+               r := r.asIdealFloat()()
+               val := l.Cmp(r) != 0
+               a.eval = func(t *Thread) bool { return val }
+       case *stringType:
+               lf := l.asString()
+               rf := r.asString()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l != r
+               }
+       case *PtrType:
+               lf := l.asPtr()
+               rf := r.asPtr()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l != r
+               }
+       case *FuncType:
+               lf := l.asFunc()
+               rf := r.asFunc()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l != r
+               }
+       case *MapType:
+               lf := l.asMap()
+               rf := r.asMap()
+               a.eval = func(t *Thread) bool {
+                       l, r := lf(t), rf(t)
+                       return l != r
+               }
+       default:
+               log.Panicf("unexpected type %v at %v", l.t, a.pos)
+       }
+}
+
+func genAssign(lt Type, r *expr) func(lv Value, t *Thread) {
+       switch lt.lit().(type) {
+       case *boolType:
+               rf := r.asBool()
+               return func(lv Value, t *Thread) { lv.(BoolValue).Set(t, rf(t)) }
+       case *uintType:
+               rf := r.asUint()
+               return func(lv Value, t *Thread) { lv.(UintValue).Set(t, rf(t)) }
+       case *intType:
+               rf := r.asInt()
+               return func(lv Value, t *Thread) { lv.(IntValue).Set(t, rf(t)) }
+       case *floatType:
+               rf := r.asFloat()
+               return func(lv Value, t *Thread) { lv.(FloatValue).Set(t, rf(t)) }
+       case *stringType:
+               rf := r.asString()
+               return func(lv Value, t *Thread) { lv.(StringValue).Set(t, rf(t)) }
+       case *ArrayType:
+               rf := r.asArray()
+               return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) }
+       case *StructType:
+               rf := r.asStruct()
+               return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) }
+       case *PtrType:
+               rf := r.asPtr()
+               return func(lv Value, t *Thread) { lv.(PtrValue).Set(t, rf(t)) }
+       case *FuncType:
+               rf := r.asFunc()
+               return func(lv Value, t *Thread) { lv.(FuncValue).Set(t, rf(t)) }
+       case *SliceType:
+               rf := r.asSlice()
+               return func(lv Value, t *Thread) { lv.(SliceValue).Set(t, rf(t)) }
+       case *MapType:
+               rf := r.asMap()
+               return func(lv Value, t *Thread) { lv.(MapValue).Set(t, rf(t)) }
+       default:
+               log.Panicf("unexpected left operand type %v at %v", lt, r.pos)
+       }
+       panic("fail")
+}
diff --git a/libgo/go/exp/eval/expr_test.go b/libgo/go/exp/eval/expr_test.go
new file mode 100644 (file)
index 0000000..0dbce43
--- /dev/null
@@ -0,0 +1,355 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "big"
+       "testing"
+)
+
+var undefined = "undefined"
+var typeAsExpr = "type .* used as expression"
+var badCharLit = "character literal"
+var unknownEscape = "unknown escape sequence"
+var opTypes = "illegal (operand|argument) type|cannot index into"
+var badAddrOf = "cannot take the address"
+var constantTruncated = "constant [^ ]* truncated"
+var constantUnderflows = "constant [^ ]* underflows"
+var constantOverflows = "constant [^ ]* overflows"
+var implLimit = "implementation limit"
+var mustBeUnsigned = "must be unsigned"
+var divByZero = "divide by zero"
+
+var hugeInteger = new(big.Int).Lsh(idealOne, 64)
+
+var exprTests = []test{
+       Val("i", 1),
+       CErr("zzz", undefined),
+       // TODO(austin) Test variable in constant context
+       //CErr("t", typeAsExpr),
+
+       Val("'a'", big.NewInt('a')),
+       Val("'\\uffff'", big.NewInt('\uffff')),
+       Val("'\\n'", big.NewInt('\n')),
+       CErr("''+x", badCharLit),
+       // Produces two parse errors
+       //CErr("'''", ""),
+       CErr("'\n'", badCharLit),
+       CErr("'\\z'", unknownEscape),
+       CErr("'ab'", badCharLit),
+
+       Val("1.0", big.NewRat(1, 1)),
+       Val("1.", big.NewRat(1, 1)),
+       Val(".1", big.NewRat(1, 10)),
+       Val("1e2", big.NewRat(100, 1)),
+
+       Val("\"abc\"", "abc"),
+       Val("\"\"", ""),
+       Val("\"\\n\\\"\"", "\n\""),
+       CErr("\"\\z\"", unknownEscape),
+       CErr("\"abc", "string not terminated"),
+
+       Val("(i)", 1),
+
+       Val("ai[0]", 1),
+       Val("(&ai)[0]", 1),
+       Val("ai[1]", 2),
+       Val("ai[i]", 2),
+       Val("ai[u]", 2),
+       CErr("ai[f]", opTypes),
+       CErr("ai[0][0]", opTypes),
+       CErr("ai[2]", "index 2 exceeds"),
+       CErr("ai[1+1]", "index 2 exceeds"),
+       CErr("ai[-1]", "negative index"),
+       RErr("ai[i+i]", "index 2 exceeds"),
+       RErr("ai[-i]", "negative index"),
+       CErr("i[0]", opTypes),
+       CErr("f[0]", opTypes),
+
+       Val("aai[0][0]", 1),
+       Val("aai[1][1]", 4),
+       CErr("aai[2][0]", "index 2 exceeds"),
+       CErr("aai[0][2]", "index 2 exceeds"),
+
+       Val("sli[0]", 1),
+       Val("sli[1]", 2),
+       CErr("sli[-1]", "negative index"),
+       RErr("sli[-i]", "negative index"),
+       RErr("sli[2]", "index 2 exceeds"),
+
+       Val("s[0]", uint8('a')),
+       Val("s[1]", uint8('b')),
+       CErr("s[-1]", "negative index"),
+       RErr("s[-i]", "negative index"),
+       RErr("s[3]", "index 3 exceeds"),
+
+       Val("ai[0:2]", vslice{varray{1, 2}, 2, 2}),
+       Val("ai[0:1]", vslice{varray{1, 2}, 1, 2}),
+       Val("ai[0:]", vslice{varray{1, 2}, 2, 2}),
+       Val("ai[i:]", vslice{varray{2}, 1, 1}),
+
+       Val("sli[0:2]", vslice{varray{1, 2, 3}, 2, 3}),
+       Val("sli[0:i]", vslice{varray{1, 2, 3}, 1, 3}),
+       Val("sli[1:]", vslice{varray{2, 3}, 1, 2}),
+
+       CErr("1(2)", "cannot call"),
+       CErr("fn(1,2)", "too many"),
+       CErr("fn()", "not enough"),
+       CErr("fn(true)", opTypes),
+       CErr("fn(true)", "function call"),
+       // Single argument functions don't say which argument.
+       //CErr("fn(true)", "argument 1"),
+       Val("fn(1)", 2),
+       Val("fn(1.0)", 2),
+       CErr("fn(1.5)", constantTruncated),
+       Val("fn(i)", 2),
+       CErr("fn(u)", opTypes),
+
+       CErr("void()+2", opTypes),
+       CErr("oneTwo()+2", opTypes),
+
+       Val("cap(ai)", 2),
+       Val("cap(&ai)", 2),
+       Val("cap(aai)", 2),
+       Val("cap(sli)", 3),
+       CErr("cap(0)", opTypes),
+       CErr("cap(i)", opTypes),
+       CErr("cap(s)", opTypes),
+
+       Val("len(s)", 3),
+       Val("len(ai)", 2),
+       Val("len(&ai)", 2),
+       Val("len(ai[0:])", 2),
+       Val("len(ai[1:])", 1),
+       Val("len(ai[2:])", 0),
+       Val("len(aai)", 2),
+       Val("len(sli)", 2),
+       Val("len(sli[0:])", 2),
+       Val("len(sli[1:])", 1),
+       Val("len(sli[2:])", 0),
+       // TODO(austin) Test len of map
+       CErr("len(0)", opTypes),
+       CErr("len(i)", opTypes),
+
+       CErr("*i", opTypes),
+       Val("*&i", 1),
+       Val("*&(i)", 1),
+       CErr("&1", badAddrOf),
+       CErr("&c", badAddrOf),
+       Val("*(&ai[0])", 1),
+
+       Val("+1", big.NewInt(+1)),
+       Val("+1.0", big.NewRat(1, 1)),
+       Val("01.5", big.NewRat(15, 10)),
+       CErr("+\"x\"", opTypes),
+
+       Val("-42", big.NewInt(-42)),
+       Val("-i", -1),
+       Val("-f", -1.0),
+       // 6g bug?
+       //Val("-(f-1)", -0.0),
+       CErr("-\"x\"", opTypes),
+
+       // TODO(austin) Test unary !
+
+       Val("^2", big.NewInt(^2)),
+       Val("^(-2)", big.NewInt(^(-2))),
+       CErr("^2.0", opTypes),
+       CErr("^2.5", opTypes),
+       Val("^i", ^1),
+       Val("^u", ^uint(1)),
+       CErr("^f", opTypes),
+
+       Val("1+i", 2),
+       Val("1+u", uint(2)),
+       Val("3.0+i", 4),
+       Val("1+1", big.NewInt(2)),
+       Val("f+f", 2.0),
+       Val("1+f", 2.0),
+       Val("1.0+1", big.NewRat(2, 1)),
+       Val("\"abc\" + \"def\"", "abcdef"),
+       CErr("i+u", opTypes),
+       CErr("-1+u", constantUnderflows),
+       // TODO(austin) Test named types
+
+       Val("2-1", big.NewInt(1)),
+       Val("2.0-1", big.NewRat(1, 1)),
+       Val("f-2", -1.0),
+       Val("-0.0", big.NewRat(0, 1)),
+       Val("2*2", big.NewInt(4)),
+       Val("2*i", 2),
+       Val("3/2", big.NewInt(1)),
+       Val("3/i", 3),
+       CErr("1/0", divByZero),
+       CErr("1.0/0", divByZero),
+       RErr("i/0", divByZero),
+       Val("3%2", big.NewInt(1)),
+       Val("i%2", 1),
+       CErr("3%0", divByZero),
+       CErr("3.0%0", opTypes),
+       RErr("i%0", divByZero),
+
+       // Examples from "Arithmetic operators"
+       Val("5/3", big.NewInt(1)),
+       Val("(i+4)/(i+2)", 1),
+       Val("5%3", big.NewInt(2)),
+       Val("(i+4)%(i+2)", 2),
+       Val("-5/3", big.NewInt(-1)),
+       Val("(i-6)/(i+2)", -1),
+       Val("-5%3", big.NewInt(-2)),
+       Val("(i-6)%(i+2)", -2),
+       Val("5/-3", big.NewInt(-1)),
+       Val("(i+4)/(i-4)", -1),
+       Val("5%-3", big.NewInt(2)),
+       Val("(i+4)%(i-4)", 2),
+       Val("-5/-3", big.NewInt(1)),
+       Val("(i-6)/(i-4)", 1),
+       Val("-5%-3", big.NewInt(-2)),
+       Val("(i-6)%(i-4)", -2),
+
+       // Examples from "Arithmetic operators"
+       Val("11/4", big.NewInt(2)),
+       Val("(i+10)/4", 2),
+       Val("11%4", big.NewInt(3)),
+       Val("(i+10)%4", 3),
+       Val("11>>2", big.NewInt(2)),
+       Val("(i+10)>>2", 2),
+       Val("11&3", big.NewInt(3)),
+       Val("(i+10)&3", 3),
+       Val("-11/4", big.NewInt(-2)),
+       Val("(i-12)/4", -2),
+       Val("-11%4", big.NewInt(-3)),
+       Val("(i-12)%4", -3),
+       Val("-11>>2", big.NewInt(-3)),
+       Val("(i-12)>>2", -3),
+       Val("-11&3", big.NewInt(1)),
+       Val("(i-12)&3", 1),
+
+       // TODO(austin) Test bit ops
+
+       // For shift, we try nearly every combination of positive
+       // ideal int, negative ideal int, big ideal int, ideal
+       // fractional float, ideal non-fractional float, int, uint,
+       // and float.
+       Val("2<<2", big.NewInt(2<<2)),
+       CErr("2<<(-1)", constantUnderflows),
+       CErr("2<<0x10000000000000000", constantOverflows),
+       CErr("2<<2.5", constantTruncated),
+       Val("2<<2.0", big.NewInt(2<<2.0)),
+       CErr("2<<i", mustBeUnsigned),
+       Val("2<<u", 2<<1),
+       CErr("2<<f", opTypes),
+
+       Val("-2<<2", big.NewInt(-2<<2)),
+       CErr("-2<<(-1)", constantUnderflows),
+       CErr("-2<<0x10000000000000000", constantOverflows),
+       CErr("-2<<2.5", constantTruncated),
+       Val("-2<<2.0", big.NewInt(-2<<2.0)),
+       CErr("-2<<i", mustBeUnsigned),
+       Val("-2<<u", -2<<1),
+       CErr("-2<<f", opTypes),
+
+       Val("0x10000000000000000<<2", new(big.Int).Lsh(hugeInteger, 2)),
+       CErr("0x10000000000000000<<(-1)", constantUnderflows),
+       CErr("0x10000000000000000<<0x10000000000000000", constantOverflows),
+       CErr("0x10000000000000000<<2.5", constantTruncated),
+       Val("0x10000000000000000<<2.0", new(big.Int).Lsh(hugeInteger, 2)),
+       CErr("0x10000000000000000<<i", mustBeUnsigned),
+       CErr("0x10000000000000000<<u", constantOverflows),
+       CErr("0x10000000000000000<<f", opTypes),
+
+       CErr("2.5<<2", opTypes),
+       CErr("2.0<<2", opTypes),
+
+       Val("i<<2", 1<<2),
+       CErr("i<<(-1)", constantUnderflows),
+       CErr("i<<0x10000000000000000", constantOverflows),
+       CErr("i<<2.5", constantTruncated),
+       Val("i<<2.0", 1<<2),
+       CErr("i<<i", mustBeUnsigned),
+       Val("i<<u", 1<<1),
+       CErr("i<<f", opTypes),
+       Val("i<<u", 1<<1),
+
+       Val("u<<2", uint(1<<2)),
+       CErr("u<<(-1)", constantUnderflows),
+       CErr("u<<0x10000000000000000", constantOverflows),
+       CErr("u<<2.5", constantTruncated),
+       Val("u<<2.0", uint(1<<2)),
+       CErr("u<<i", mustBeUnsigned),
+       Val("u<<u", uint(1<<1)),
+       CErr("u<<f", opTypes),
+       Val("u<<u", uint(1<<1)),
+
+       CErr("f<<2", opTypes),
+
+       // <, <=, >, >=
+       Val("1<2", 1 < 2),
+       Val("1<=2", 1 <= 2),
+       Val("2<=2", 2 <= 2),
+       Val("1>2", 1 > 2),
+       Val("1>=2", 1 >= 2),
+       Val("2>=2", 2 >= 2),
+
+       Val("i<2", 1 < 2),
+       Val("i<=2", 1 <= 2),
+       Val("i+1<=2", 2 <= 2),
+       Val("i>2", 1 > 2),
+       Val("i>=2", 1 >= 2),
+       Val("i+1>=2", 2 >= 2),
+
+       Val("u<2", 1 < 2),
+       Val("f<2", 1 < 2),
+
+       Val("s<\"b\"", true),
+       Val("s<\"a\"", false),
+       Val("s<=\"abc\"", true),
+       Val("s>\"aa\"", true),
+       Val("s>\"ac\"", false),
+       Val("s>=\"abc\"", true),
+
+       CErr("i<u", opTypes),
+       CErr("i<f", opTypes),
+       CErr("i<s", opTypes),
+       CErr("&i<&i", opTypes),
+       CErr("ai<ai", opTypes),
+
+       // ==, !=
+       Val("1==1", true),
+       Val("1!=1", false),
+       Val("1==2", false),
+       Val("1!=2", true),
+
+       Val("1.0==1", true),
+       Val("1.5==1", false),
+
+       Val("i==1", true),
+       Val("i!=1", false),
+       Val("i==2", false),
+       Val("i!=2", true),
+
+       Val("u==1", true),
+       Val("f==1", true),
+
+       Val("s==\"abc\"", true),
+       Val("s!=\"abc\"", false),
+       Val("s==\"abcd\"", false),
+       Val("s!=\"abcd\"", true),
+
+       Val("&i==&i", true),
+       Val("&i==&i2", false),
+
+       Val("fn==fn", true),
+       Val("fn==func(int)int{return 0}", false),
+
+       CErr("i==u", opTypes),
+       CErr("i==f", opTypes),
+       CErr("&i==&f", opTypes),
+       CErr("ai==ai", opTypes),
+       CErr("t==t", opTypes),
+       CErr("fn==oneTwo", opTypes),
+}
+
+func TestExpr(t *testing.T) { runTests(t, "exprTests", exprTests) }
diff --git a/libgo/go/exp/eval/func.go b/libgo/go/exp/eval/func.go
new file mode 100644 (file)
index 0000000..cb1b579
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import "os"
+
+/*
+ * Virtual machine
+ */
+
+type Thread struct {
+       abort chan os.Error
+       pc    uint
+       // The execution frame of this function.  This remains the
+       // same throughout a function invocation.
+       f *Frame
+}
+
+type code []func(*Thread)
+
+func (i code) exec(t *Thread) {
+       opc := t.pc
+       t.pc = 0
+       l := uint(len(i))
+       for t.pc < l {
+               pc := t.pc
+               t.pc++
+               i[pc](t)
+       }
+       t.pc = opc
+}
+
+/*
+ * Code buffer
+ */
+
+type codeBuf struct {
+       instrs code
+}
+
+func newCodeBuf() *codeBuf { return &codeBuf{make(code, 0, 16)} }
+
+func (b *codeBuf) push(instr func(*Thread)) {
+       b.instrs = append(b.instrs, instr)
+}
+
+func (b *codeBuf) nextPC() uint { return uint(len(b.instrs)) }
+
+func (b *codeBuf) get() code {
+       // Freeze this buffer into an array of exactly the right size
+       a := make(code, len(b.instrs))
+       copy(a, b.instrs)
+       return code(a)
+}
+
+/*
+ * User-defined functions
+ */
+
+type evalFunc struct {
+       outer     *Frame
+       frameSize int
+       code      code
+}
+
+func (f *evalFunc) NewFrame() *Frame { return f.outer.child(f.frameSize) }
+
+func (f *evalFunc) Call(t *Thread) { f.code.exec(t) }
diff --git a/libgo/go/exp/eval/scope.go b/libgo/go/exp/eval/scope.go
new file mode 100644 (file)
index 0000000..8eee38e
--- /dev/null
@@ -0,0 +1,199 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "go/token"
+       "log"
+)
+
+/*
+ * Blocks and scopes
+ */
+
+// A definition can be a *Variable, *Constant, or Type.
+type Def interface {
+       Pos() token.Position
+}
+
+type Variable struct {
+       token.Position
+       // Index of this variable in the Frame structure
+       Index int
+       // Static type of this variable
+       Type Type
+       // Value of this variable.  This is only used by Scope.NewFrame;
+       // therefore, it is useful for global scopes but cannot be used
+       // in function scopes.
+       Init Value
+}
+
+type Constant struct {
+       token.Position
+       Type  Type
+       Value Value
+}
+
+// A block represents a definition block in which a name may not be
+// defined more than once.
+type block struct {
+       // The block enclosing this one, including blocks in other
+       // scopes.
+       outer *block
+       // The nested block currently being compiled, or nil.
+       inner *block
+       // The Scope containing this block.
+       scope *Scope
+       // The Variables, Constants, and Types defined in this block.
+       defs map[string]Def
+       // The index of the first variable defined in this block.
+       // This must be greater than the index of any variable defined
+       // in any parent of this block within the same Scope at the
+       // time this block is entered.
+       offset int
+       // The number of Variables defined in this block.
+       numVars int
+       // If global, do not allocate new vars and consts in
+       // the frame; assume that the refs will be compiled in
+       // using defs[name].Init.
+       global bool
+}
+
+// A Scope is the compile-time analogue of a Frame, which captures
+// some subtree of blocks.
+type Scope struct {
+       // The root block of this scope.
+       *block
+       // The maximum number of variables required at any point in
+       // this Scope.  This determines the number of slots needed in
+       // Frame's created from this Scope at run-time.
+       maxVars int
+}
+
+func (b *block) enterChild() *block {
+       if b.inner != nil && b.inner.scope == b.scope {
+               log.Panic("Failed to exit child block before entering another child")
+       }
+       sub := &block{
+               outer:  b,
+               scope:  b.scope,
+               defs:   make(map[string]Def),
+               offset: b.offset + b.numVars,
+       }
+       b.inner = sub
+       return sub
+}
+
+func (b *block) exit() {
+       if b.outer == nil {
+               log.Panic("Cannot exit top-level block")
+       }
+       if b.outer.scope == b.scope {
+               if b.outer.inner != b {
+                       log.Panic("Already exited block")
+               }
+               if b.inner != nil && b.inner.scope == b.scope {
+                       log.Panic("Exit of parent block without exit of child block")
+               }
+       }
+       b.outer.inner = nil
+}
+
+func (b *block) ChildScope() *Scope {
+       if b.inner != nil && b.inner.scope == b.scope {
+               log.Panic("Failed to exit child block before entering a child scope")
+       }
+       sub := b.enterChild()
+       sub.offset = 0
+       sub.scope = &Scope{sub, 0}
+       return sub.scope
+}
+
+func (b *block) DefineVar(name string, pos token.Position, t Type) (*Variable, Def) {
+       if prev, ok := b.defs[name]; ok {
+               return nil, prev
+       }
+       v := b.defineSlot(t, false)
+       v.Position = pos
+       b.defs[name] = v
+       return v, nil
+}
+
+func (b *block) DefineTemp(t Type) *Variable { return b.defineSlot(t, true) }
+
+func (b *block) defineSlot(t Type, temp bool) *Variable {
+       if b.inner != nil && b.inner.scope == b.scope {
+               log.Panic("Failed to exit child block before defining variable")
+       }
+       index := -1
+       if !b.global || temp {
+               index = b.offset + b.numVars
+               b.numVars++
+               if index >= b.scope.maxVars {
+                       b.scope.maxVars = index + 1
+               }
+       }
+       v := &Variable{token.Position{}, index, t, nil}
+       return v
+}
+
+func (b *block) DefineConst(name string, pos token.Position, t Type, v Value) (*Constant, Def) {
+       if prev, ok := b.defs[name]; ok {
+               return nil, prev
+       }
+       c := &Constant{pos, t, v}
+       b.defs[name] = c
+       return c, nil
+}
+
+func (b *block) DefineType(name string, pos token.Position, t Type) Type {
+       if _, ok := b.defs[name]; ok {
+               return nil
+       }
+       nt := &NamedType{pos, name, nil, true, make(map[string]Method)}
+       if t != nil {
+               nt.Complete(t)
+       }
+       b.defs[name] = nt
+       return nt
+}
+
+func (b *block) Lookup(name string) (bl *block, level int, def Def) {
+       for b != nil {
+               if d, ok := b.defs[name]; ok {
+                       return b, level, d
+               }
+               if b.outer != nil && b.scope != b.outer.scope {
+                       level++
+               }
+               b = b.outer
+       }
+       return nil, 0, nil
+}
+
+func (s *Scope) NewFrame(outer *Frame) *Frame { return outer.child(s.maxVars) }
+
+/*
+ * Frames
+ */
+
+type Frame struct {
+       Outer *Frame
+       Vars  []Value
+}
+
+func (f *Frame) Get(level int, index int) Value {
+       for ; level > 0; level-- {
+               f = f.Outer
+       }
+       return f.Vars[index]
+}
+
+func (f *Frame) child(numVars int) *Frame {
+       // TODO(austin) This is probably rather expensive.  All values
+       // require heap allocation and zeroing them when we execute a
+       // definition typically requires some computation.
+       return &Frame{f, make([]Value, numVars)}
+}
diff --git a/libgo/go/exp/eval/stmt.go b/libgo/go/exp/eval/stmt.go
new file mode 100644 (file)
index 0000000..a665eb2
--- /dev/null
@@ -0,0 +1,1305 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "big"
+       "log"
+       "go/ast"
+       "go/token"
+)
+
+const (
+       returnPC = ^uint(0)
+       badPC    = ^uint(1)
+)
+
+/*
+ * Statement compiler
+ */
+
+type stmtCompiler struct {
+       *blockCompiler
+       pos token.Position
+       // This statement's label, or nil if it is not labeled.
+       stmtLabel *label
+}
+
+func (a *stmtCompiler) diag(format string, args ...interface{}) {
+       a.diagAt(&a.pos, format, args...)
+}
+
+/*
+ * Flow checker
+ */
+
+type flowEnt struct {
+       // Whether this flow entry is conditional.  If true, flow can
+       // continue to the next PC.
+       cond bool
+       // True if this will terminate flow (e.g., a return statement).
+       // cond must be false and jumps must be nil if this is true.
+       term bool
+       // PC's that can be reached from this flow entry.
+       jumps []*uint
+       // Whether this flow entry has been visited by reachesEnd.
+       visited bool
+}
+
+type flowBlock struct {
+       // If this is a goto, the target label.
+       target string
+       // The inner-most block containing definitions.
+       block *block
+       // The numVars from each block leading to the root of the
+       // scope, starting at block.
+       numVars []int
+}
+
+type flowBuf struct {
+       cb *codeBuf
+       // ents is a map from PC's to flow entries.  Any PC missing
+       // from this map is assumed to reach only PC+1.
+       ents map[uint]*flowEnt
+       // gotos is a map from goto positions to information on the
+       // block at the point of the goto.
+       gotos map[*token.Position]*flowBlock
+       // labels is a map from label name to information on the block
+       // at the point of the label.  labels are tracked by name,
+       // since mutliple labels at the same PC can have different
+       // blocks.
+       labels map[string]*flowBlock
+}
+
+func newFlowBuf(cb *codeBuf) *flowBuf {
+       return &flowBuf{cb, make(map[uint]*flowEnt), make(map[*token.Position]*flowBlock), make(map[string]*flowBlock)}
+}
+
+// put creates a flow control point for the next PC in the code buffer.
+// This should be done before pushing the instruction into the code buffer.
+func (f *flowBuf) put(cond bool, term bool, jumps []*uint) {
+       pc := f.cb.nextPC()
+       if ent, ok := f.ents[pc]; ok {
+               log.Panicf("Flow entry already exists at PC %d: %+v", pc, ent)
+       }
+       f.ents[pc] = &flowEnt{cond, term, jumps, false}
+}
+
+// putTerm creates a flow control point at the next PC that
+// unconditionally terminates execution.
+func (f *flowBuf) putTerm() { f.put(false, true, nil) }
+
+// put1 creates a flow control point at the next PC that jumps to one
+// PC and, if cond is true, can also continue to the PC following the
+// next PC.
+func (f *flowBuf) put1(cond bool, jumpPC *uint) {
+       f.put(cond, false, []*uint{jumpPC})
+}
+
+func newFlowBlock(target string, b *block) *flowBlock {
+       // Find the inner-most block containing definitions
+       for b.numVars == 0 && b.outer != nil && b.outer.scope == b.scope {
+               b = b.outer
+       }
+
+       // Count parents leading to the root of the scope
+       n := 0
+       for bp := b; bp.scope == b.scope; bp = bp.outer {
+               n++
+       }
+
+       // Capture numVars from each block to the root of the scope
+       numVars := make([]int, n)
+       i := 0
+       for bp := b; i < n; bp = bp.outer {
+               numVars[i] = bp.numVars
+               i++
+       }
+
+       return &flowBlock{target, b, numVars}
+}
+
+// putGoto captures the block at a goto statement.  This should be
+// called in addition to putting a flow control point.
+func (f *flowBuf) putGoto(pos token.Position, target string, b *block) {
+       f.gotos[&pos] = newFlowBlock(target, b)
+}
+
+// putLabel captures the block at a label.
+func (f *flowBuf) putLabel(name string, b *block) {
+       f.labels[name] = newFlowBlock("", b)
+}
+
+// reachesEnd returns true if the end of f's code buffer can be
+// reached from the given program counter.  Error reporting is the
+// caller's responsibility.
+func (f *flowBuf) reachesEnd(pc uint) bool {
+       endPC := f.cb.nextPC()
+       if pc > endPC {
+               log.Panicf("Reached bad PC %d past end PC %d", pc, endPC)
+       }
+
+       for ; pc < endPC; pc++ {
+               ent, ok := f.ents[pc]
+               if !ok {
+                       continue
+               }
+
+               if ent.visited {
+                       return false
+               }
+               ent.visited = true
+
+               if ent.term {
+                       return false
+               }
+
+               // If anything can reach the end, we can reach the end
+               // from pc.
+               for _, j := range ent.jumps {
+                       if f.reachesEnd(*j) {
+                               return true
+                       }
+               }
+               // If the jump was conditional, we can reach the next
+               // PC, so try reaching the end from it.
+               if ent.cond {
+                       continue
+               }
+               return false
+       }
+       return true
+}
+
+// gotosObeyScopes returns true if no goto statement causes any
+// variables to come into scope that were not in scope at the point of
+// the goto.  Reports any errors using the given compiler.
+func (f *flowBuf) gotosObeyScopes(a *compiler) {
+       for pos, src := range f.gotos {
+               tgt := f.labels[src.target]
+
+               // The target block must be a parent of this block
+               numVars := src.numVars
+               b := src.block
+               for len(numVars) > 0 && b != tgt.block {
+                       b = b.outer
+                       numVars = numVars[1:]
+               }
+               if b != tgt.block {
+                       // We jumped into a deeper block
+                       a.diagAt(pos, "goto causes variables to come into scope")
+                       return
+               }
+
+               // There must be no variables in the target block that
+               // did not exist at the jump
+               tgtNumVars := tgt.numVars
+               for i := range numVars {
+                       if tgtNumVars[i] > numVars[i] {
+                               a.diagAt(pos, "goto causes variables to come into scope")
+                               return
+                       }
+               }
+       }
+}
+
+/*
+ * Statement generation helpers
+ */
+
+func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
+       v, prev := a.block.DefineVar(ident.Name, ident.Pos(), t)
+       if prev != nil {
+               // TODO(austin) It's silly that we have to capture
+               // Pos() in a variable.
+               pos := prev.Pos()
+               if pos.IsValid() {
+                       a.diagAt(ident, "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Name, &pos)
+               } else {
+                       a.diagAt(ident, "variable %s redeclared in this block", ident.Name)
+               }
+               return nil
+       }
+
+       // Initialize the variable
+       index := v.Index
+       if v.Index >= 0 {
+               a.push(func(v *Thread) { v.f.Vars[index] = t.Zero() })
+       }
+       return v
+}
+
+// TODO(austin) Move doAssign to here
+
+/*
+ * Statement compiler
+ */
+
+func (a *stmtCompiler) compile(s ast.Stmt) {
+       if a.block.inner != nil {
+               log.Panic("Child scope still entered")
+       }
+
+       notimpl := false
+       switch s := s.(type) {
+       case *ast.BadStmt:
+               // Error already reported by parser.
+               a.silentErrors++
+
+       case *ast.DeclStmt:
+               a.compileDeclStmt(s)
+
+       case *ast.EmptyStmt:
+               // Do nothing.
+
+       case *ast.LabeledStmt:
+               a.compileLabeledStmt(s)
+
+       case *ast.ExprStmt:
+               a.compileExprStmt(s)
+
+       case *ast.IncDecStmt:
+               a.compileIncDecStmt(s)
+
+       case *ast.AssignStmt:
+               a.compileAssignStmt(s)
+
+       case *ast.GoStmt:
+               notimpl = true
+
+       case *ast.DeferStmt:
+               notimpl = true
+
+       case *ast.ReturnStmt:
+               a.compileReturnStmt(s)
+
+       case *ast.BranchStmt:
+               a.compileBranchStmt(s)
+
+       case *ast.BlockStmt:
+               a.compileBlockStmt(s)
+
+       case *ast.IfStmt:
+               a.compileIfStmt(s)
+
+       case *ast.CaseClause:
+               a.diag("case clause outside switch")
+
+       case *ast.SwitchStmt:
+               a.compileSwitchStmt(s)
+
+       case *ast.TypeCaseClause:
+               notimpl = true
+
+       case *ast.TypeSwitchStmt:
+               notimpl = true
+
+       case *ast.CommClause:
+               notimpl = true
+
+       case *ast.SelectStmt:
+               notimpl = true
+
+       case *ast.ForStmt:
+               a.compileForStmt(s)
+
+       case *ast.RangeStmt:
+               notimpl = true
+
+       default:
+               log.Panicf("unexpected ast node type %T", s)
+       }
+
+       if notimpl {
+               a.diag("%T statment node not implemented", s)
+       }
+
+       if a.block.inner != nil {
+               log.Panic("Forgot to exit child scope")
+       }
+}
+
+func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) {
+       switch decl := s.Decl.(type) {
+       case *ast.BadDecl:
+               // Do nothing.  Already reported by parser.
+               a.silentErrors++
+
+       case *ast.FuncDecl:
+               if !a.block.global {
+                       log.Panic("FuncDecl at statement level")
+               }
+
+       case *ast.GenDecl:
+               if decl.Tok == token.IMPORT && !a.block.global {
+                       log.Panic("import at statement level")
+               }
+
+       default:
+               log.Panicf("Unexpected Decl type %T", s.Decl)
+       }
+       a.compileDecl(s.Decl)
+}
+
+func (a *stmtCompiler) compileVarDecl(decl *ast.GenDecl) {
+       for _, spec := range decl.Specs {
+               spec := spec.(*ast.ValueSpec)
+               if spec.Values == nil {
+                       // Declaration without assignment
+                       if spec.Type == nil {
+                               // Parser should have caught
+                               log.Panic("Type and Values nil")
+                       }
+                       t := a.compileType(a.block, spec.Type)
+                       // Define placeholders even if type compile failed
+                       for _, n := range spec.Names {
+                               a.defineVar(n, t)
+                       }
+               } else {
+                       // Declaration with assignment
+                       lhs := make([]ast.Expr, len(spec.Names))
+                       for i, n := range spec.Names {
+                               lhs[i] = n
+                       }
+                       a.doAssign(lhs, spec.Values, decl.Tok, spec.Type)
+               }
+       }
+}
+
+func (a *stmtCompiler) compileDecl(decl ast.Decl) {
+       switch d := decl.(type) {
+       case *ast.BadDecl:
+               // Do nothing.  Already reported by parser.
+               a.silentErrors++
+
+       case *ast.FuncDecl:
+               decl := a.compileFuncType(a.block, d.Type)
+               if decl == nil {
+                       return
+               }
+               // Declare and initialize v before compiling func
+               // so that body can refer to itself.
+               c, prev := a.block.DefineConst(d.Name.Name, a.pos, decl.Type, decl.Type.Zero())
+               if prev != nil {
+                       pos := prev.Pos()
+                       if pos.IsValid() {
+                               a.diagAt(d.Name, "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Name, &pos)
+                       } else {
+                               a.diagAt(d.Name, "identifier %s redeclared in this block", d.Name.Name)
+                       }
+               }
+               fn := a.compileFunc(a.block, decl, d.Body)
+               if c == nil || fn == nil {
+                       return
+               }
+               var zeroThread Thread
+               c.Value.(FuncValue).Set(nil, fn(&zeroThread))
+
+       case *ast.GenDecl:
+               switch d.Tok {
+               case token.IMPORT:
+                       log.Panicf("%v not implemented", d.Tok)
+               case token.CONST:
+                       log.Panicf("%v not implemented", d.Tok)
+               case token.TYPE:
+                       a.compileTypeDecl(a.block, d)
+               case token.VAR:
+                       a.compileVarDecl(d)
+               }
+
+       default:
+               log.Panicf("Unexpected Decl type %T", decl)
+       }
+}
+
+func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) {
+       // Define label
+       l, ok := a.labels[s.Label.Name]
+       if ok {
+               if l.resolved.IsValid() {
+                       a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Name, &l.resolved)
+               }
+       } else {
+               pc := badPC
+               l = &label{name: s.Label.Name, gotoPC: &pc}
+               a.labels[l.name] = l
+       }
+       l.desc = "regular label"
+       l.resolved = s.Pos()
+
+       // Set goto PC
+       *l.gotoPC = a.nextPC()
+
+       // Define flow entry so we can check for jumps over declarations.
+       a.flow.putLabel(l.name, a.block)
+
+       // Compile the statement.  Reuse our stmtCompiler for simplicity.
+       sc := &stmtCompiler{a.blockCompiler, s.Stmt.Pos(), l}
+       sc.compile(s.Stmt)
+}
+
+func (a *stmtCompiler) compileExprStmt(s *ast.ExprStmt) {
+       bc := a.enterChild()
+       defer bc.exit()
+
+       e := a.compileExpr(bc.block, false, s.X)
+       if e == nil {
+               return
+       }
+
+       if e.exec == nil {
+               a.diag("%s cannot be used as expression statement", e.desc)
+               return
+       }
+
+       a.push(e.exec)
+}
+
+func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) {
+       // Create temporary block for extractEffect
+       bc := a.enterChild()
+       defer bc.exit()
+
+       l := a.compileExpr(bc.block, false, s.X)
+       if l == nil {
+               return
+       }
+
+       if l.evalAddr == nil {
+               l.diag("cannot assign to %s", l.desc)
+               return
+       }
+       if !(l.t.isInteger() || l.t.isFloat()) {
+               l.diagOpType(s.Tok, l.t)
+               return
+       }
+
+       var op token.Token
+       var desc string
+       switch s.Tok {
+       case token.INC:
+               op = token.ADD
+               desc = "increment statement"
+       case token.DEC:
+               op = token.SUB
+               desc = "decrement statement"
+       default:
+               log.Panicf("Unexpected IncDec token %v", s.Tok)
+       }
+
+       effect, l := l.extractEffect(bc.block, desc)
+
+       one := l.newExpr(IdealIntType, "constant")
+       one.pos = s.Pos()
+       one.eval = func() *big.Int { return big.NewInt(1) }
+
+       binop := l.compileBinaryExpr(op, l, one)
+       if binop == nil {
+               return
+       }
+
+       assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "")
+       if assign == nil {
+               log.Panicf("compileAssign type check failed")
+       }
+
+       lf := l.evalAddr
+       a.push(func(v *Thread) {
+               effect(v)
+               assign(lf(v), v)
+       })
+}
+
+func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr) {
+       nerr := a.numError()
+
+       // Compile right side first so we have the types when
+       // compiling the left side and so we don't see definitions
+       // made on the left side.
+       rs := make([]*expr, len(rhs))
+       for i, re := range rhs {
+               rs[i] = a.compileExpr(a.block, false, re)
+       }
+
+       errOp := "assignment"
+       if tok == token.DEFINE || tok == token.VAR {
+               errOp = "declaration"
+       }
+       ac, ok := a.checkAssign(a.pos, rs, errOp, "value")
+       ac.allowMapForms(len(lhs))
+
+       // If this is a definition and the LHS is too big, we won't be
+       // able to produce the usual error message because we can't
+       // begin to infer the types of the LHS.
+       if (tok == token.DEFINE || tok == token.VAR) && len(lhs) > len(ac.rmt.Elems) {
+               a.diag("not enough values for definition")
+       }
+
+       // Compile left type if there is one
+       var declType Type
+       if declTypeExpr != nil {
+               declType = a.compileType(a.block, declTypeExpr)
+       }
+
+       // Compile left side
+       ls := make([]*expr, len(lhs))
+       nDefs := 0
+       for i, le := range lhs {
+               // If this is a definition, get the identifier and its type
+               var ident *ast.Ident
+               var lt Type
+               switch tok {
+               case token.DEFINE:
+                       // Check that it's an identifier
+                       ident, ok = le.(*ast.Ident)
+                       if !ok {
+                               a.diagAt(le, "left side of := must be a name")
+                               // Suppress new defitions errors
+                               nDefs++
+                               continue
+                       }
+
+                       // Is this simply an assignment?
+                       if _, ok := a.block.defs[ident.Name]; ok {
+                               ident = nil
+                               break
+                       }
+                       nDefs++
+
+               case token.VAR:
+                       ident = le.(*ast.Ident)
+               }
+
+               // If it's a definition, get or infer its type.
+               if ident != nil {
+                       // Compute the identifier's type from the RHS
+                       // type.  We use the computed MultiType so we
+                       // don't have to worry about unpacking.
+                       switch {
+                       case declTypeExpr != nil:
+                               // We have a declaration type, use it.
+                               // If declType is nil, we gave an
+                               // error when we compiled it.
+                               lt = declType
+
+                       case i >= len(ac.rmt.Elems):
+                               // Define a placeholder.  We already
+                               // gave the "not enough" error above.
+                               lt = nil
+
+                       case ac.rmt.Elems[i] == nil:
+                               // We gave the error when we compiled
+                               // the RHS.
+                               lt = nil
+
+                       case ac.rmt.Elems[i].isIdeal():
+                               // If the type is absent and the
+                               // corresponding expression is a
+                               // constant expression of ideal
+                               // integer or ideal float type, the
+                               // type of the declared variable is
+                               // int or float respectively.
+                               switch {
+                               case ac.rmt.Elems[i].isInteger():
+                                       lt = IntType
+                               case ac.rmt.Elems[i].isFloat():
+                                       lt = FloatType
+                               default:
+                                       log.Panicf("unexpected ideal type %v", rs[i].t)
+                               }
+
+                       default:
+                               lt = ac.rmt.Elems[i]
+                       }
+               }
+
+               // If it's a definition, define the identifier
+               if ident != nil {
+                       if a.defineVar(ident, lt) == nil {
+                               continue
+                       }
+               }
+
+               // Compile LHS
+               ls[i] = a.compileExpr(a.block, false, le)
+               if ls[i] == nil {
+                       continue
+               }
+
+               if ls[i].evalMapValue != nil {
+                       // Map indexes are not generally addressable,
+                       // but they are assignable.
+                       //
+                       // TODO(austin) Now that the expression
+                       // compiler uses semantic values, this might
+                       // be easier to implement as a function call.
+                       sub := ls[i]
+                       ls[i] = ls[i].newExpr(sub.t, sub.desc)
+                       ls[i].evalMapValue = sub.evalMapValue
+                       mvf := sub.evalMapValue
+                       et := sub.t
+                       ls[i].evalAddr = func(t *Thread) Value {
+                               m, k := mvf(t)
+                               e := m.Elem(t, k)
+                               if e == nil {
+                                       e = et.Zero()
+                                       m.SetElem(t, k, e)
+                               }
+                               return e
+                       }
+               } else if ls[i].evalAddr == nil {
+                       ls[i].diag("cannot assign to %s", ls[i].desc)
+                       continue
+               }
+       }
+
+       // A short variable declaration may redeclare variables
+       // provided they were originally declared in the same block
+       // with the same type, and at least one of the variables is
+       // new.
+       if tok == token.DEFINE && nDefs == 0 {
+               a.diag("at least one new variable must be declared")
+               return
+       }
+
+       // If there have been errors, our arrays are full of nil's so
+       // get out of here now.
+       if nerr != a.numError() {
+               return
+       }
+
+       // Check for 'a[x] = r, ok'
+       if len(ls) == 1 && len(rs) == 2 && ls[0].evalMapValue != nil {
+               a.diag("a[x] = r, ok form not implemented")
+               return
+       }
+
+       // Create assigner
+       var lt Type
+       n := len(lhs)
+       if n == 1 {
+               lt = ls[0].t
+       } else {
+               lts := make([]Type, len(ls))
+               for i, l := range ls {
+                       if l != nil {
+                               lts[i] = l.t
+                       }
+               }
+               lt = NewMultiType(lts)
+       }
+       bc := a.enterChild()
+       defer bc.exit()
+       assign := ac.compile(bc.block, lt)
+       if assign == nil {
+               return
+       }
+
+       // Compile
+       if n == 1 {
+               // Don't need temporaries and can avoid []Value.
+               lf := ls[0].evalAddr
+               a.push(func(t *Thread) { assign(lf(t), t) })
+       } else if tok == token.VAR || (tok == token.DEFINE && nDefs == n) {
+               // Don't need temporaries
+               lfs := make([]func(*Thread) Value, n)
+               for i, l := range ls {
+                       lfs[i] = l.evalAddr
+               }
+               a.push(func(t *Thread) {
+                       dest := make([]Value, n)
+                       for i, lf := range lfs {
+                               dest[i] = lf(t)
+                       }
+                       assign(multiV(dest), t)
+               })
+       } else {
+               // Need temporaries
+               lmt := lt.(*MultiType)
+               lfs := make([]func(*Thread) Value, n)
+               for i, l := range ls {
+                       lfs[i] = l.evalAddr
+               }
+               a.push(func(t *Thread) {
+                       temp := lmt.Zero().(multiV)
+                       assign(temp, t)
+                       // Copy to destination
+                       for i := 0; i < n; i++ {
+                               // TODO(austin) Need to evaluate LHS
+                               // before RHS
+                               lfs[i](t).Assign(t, temp[i])
+                       }
+               })
+       }
+}
+
+var assignOpToOp = map[token.Token]token.Token{
+       token.ADD_ASSIGN: token.ADD,
+       token.SUB_ASSIGN: token.SUB,
+       token.MUL_ASSIGN: token.MUL,
+       token.QUO_ASSIGN: token.QUO,
+       token.REM_ASSIGN: token.REM,
+
+       token.AND_ASSIGN:     token.AND,
+       token.OR_ASSIGN:      token.OR,
+       token.XOR_ASSIGN:     token.XOR,
+       token.SHL_ASSIGN:     token.SHL,
+       token.SHR_ASSIGN:     token.SHR,
+       token.AND_NOT_ASSIGN: token.AND_NOT,
+}
+
+func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
+       if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
+               a.diag("tuple assignment cannot be combined with an arithmetic operation")
+               return
+       }
+
+       // Create temporary block for extractEffect
+       bc := a.enterChild()
+       defer bc.exit()
+
+       l := a.compileExpr(bc.block, false, s.Lhs[0])
+       r := a.compileExpr(bc.block, false, s.Rhs[0])
+       if l == nil || r == nil {
+               return
+       }
+
+       if l.evalAddr == nil {
+               l.diag("cannot assign to %s", l.desc)
+               return
+       }
+
+       effect, l := l.extractEffect(bc.block, "operator-assignment")
+
+       binop := r.compileBinaryExpr(assignOpToOp[s.Tok], l, r)
+       if binop == nil {
+               return
+       }
+
+       assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "assignment", "value")
+       if assign == nil {
+               log.Panicf("compileAssign type check failed")
+       }
+
+       lf := l.evalAddr
+       a.push(func(t *Thread) {
+               effect(t)
+               assign(lf(t), t)
+       })
+}
+
+func (a *stmtCompiler) compileAssignStmt(s *ast.AssignStmt) {
+       switch s.Tok {
+       case token.ASSIGN, token.DEFINE:
+               a.doAssign(s.Lhs, s.Rhs, s.Tok, nil)
+
+       default:
+               a.doAssignOp(s)
+       }
+}
+
+func (a *stmtCompiler) compileReturnStmt(s *ast.ReturnStmt) {
+       if a.fnType == nil {
+               a.diag("cannot return at the top level")
+               return
+       }
+
+       if len(s.Results) == 0 && (len(a.fnType.Out) == 0 || a.outVarsNamed) {
+               // Simple case.  Simply exit from the function.
+               a.flow.putTerm()
+               a.push(func(v *Thread) { v.pc = returnPC })
+               return
+       }
+
+       bc := a.enterChild()
+       defer bc.exit()
+
+       // Compile expressions
+       bad := false
+       rs := make([]*expr, len(s.Results))
+       for i, re := range s.Results {
+               rs[i] = a.compileExpr(bc.block, false, re)
+               if rs[i] == nil {
+                       bad = true
+               }
+       }
+       if bad {
+               return
+       }
+
+       // Create assigner
+
+       // However, if the expression list in the "return" statement
+       // is a single call to a multi-valued function, the values
+       // returned from the called function will be returned from
+       // this one.
+       assign := a.compileAssign(s.Pos(), bc.block, NewMultiType(a.fnType.Out), rs, "return", "value")
+
+       // XXX(Spec) "The result types of the current function and the
+       // called function must match."  Match is fuzzy.  It should
+       // say that they must be assignment compatible.
+
+       // Compile
+       start := len(a.fnType.In)
+       nout := len(a.fnType.Out)
+       a.flow.putTerm()
+       a.push(func(t *Thread) {
+               assign(multiV(t.f.Vars[start:start+nout]), t)
+               t.pc = returnPC
+       })
+}
+
+func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, errOp, errCtx string) *label {
+       bc := a.blockCompiler
+       for ; bc != nil; bc = bc.parent {
+               if bc.label == nil {
+                       continue
+               }
+               l := bc.label
+               if name == nil && pred(l) {
+                       return l
+               }
+               if name != nil && l.name == name.Name {
+                       if !pred(l) {
+                               a.diag("cannot %s to %s %s", errOp, l.desc, l.name)
+                               return nil
+                       }
+                       return l
+               }
+       }
+       if name == nil {
+               a.diag("%s outside %s", errOp, errCtx)
+       } else {
+               a.diag("%s label %s not defined", errOp, name.Name)
+       }
+       return nil
+}
+
+func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
+       var pc *uint
+
+       switch s.Tok {
+       case token.BREAK:
+               l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.breakPC != nil }, "break", "for loop, switch, or select")
+               if l == nil {
+                       return
+               }
+               pc = l.breakPC
+
+       case token.CONTINUE:
+               l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.continuePC != nil }, "continue", "for loop")
+               if l == nil {
+                       return
+               }
+               pc = l.continuePC
+
+       case token.GOTO:
+               l, ok := a.labels[s.Label.Name]
+               if !ok {
+                       pc := badPC
+                       l = &label{name: s.Label.Name, desc: "unresolved label", gotoPC: &pc, used: s.Pos()}
+                       a.labels[l.name] = l
+               }
+
+               pc = l.gotoPC
+               a.flow.putGoto(s.Pos(), l.name, a.block)
+
+       case token.FALLTHROUGH:
+               a.diag("fallthrough outside switch")
+               return
+
+       default:
+               log.Panic("Unexpected branch token %v", s.Tok)
+       }
+
+       a.flow.put1(false, pc)
+       a.push(func(v *Thread) { v.pc = *pc })
+}
+
+func (a *stmtCompiler) compileBlockStmt(s *ast.BlockStmt) {
+       bc := a.enterChild()
+       bc.compileStmts(s)
+       bc.exit()
+}
+
+func (a *stmtCompiler) compileIfStmt(s *ast.IfStmt) {
+       // The scope of any variables declared by [the init] statement
+       // extends to the end of the "if" statement and the variables
+       // are initialized once before the statement is entered.
+       //
+       // XXX(Spec) What this really wants to say is that there's an
+       // implicit scope wrapping every if, for, and switch
+       // statement.  This is subtly different from what it actually
+       // says when there's a non-block else clause, because that
+       // else claus has to execute in a scope that is *not* the
+       // surrounding scope.
+       bc := a.enterChild()
+       defer bc.exit()
+
+       // Compile init statement, if any
+       if s.Init != nil {
+               bc.compileStmt(s.Init)
+       }
+
+       elsePC := badPC
+       endPC := badPC
+
+       // Compile condition, if any.  If there is no condition, we
+       // fall through to the body.
+       if s.Cond != nil {
+               e := bc.compileExpr(bc.block, false, s.Cond)
+               switch {
+               case e == nil:
+                       // Error reported by compileExpr
+               case !e.t.isBoolean():
+                       e.diag("'if' condition must be boolean\n\t%v", e.t)
+               default:
+                       eval := e.asBool()
+                       a.flow.put1(true, &elsePC)
+                       a.push(func(t *Thread) {
+                               if !eval(t) {
+                                       t.pc = elsePC
+                               }
+                       })
+               }
+       }
+
+       // Compile body
+       body := bc.enterChild()
+       body.compileStmts(s.Body)
+       body.exit()
+
+       // Compile else
+       if s.Else != nil {
+               // Skip over else if we executed the body
+               a.flow.put1(false, &endPC)
+               a.push(func(v *Thread) { v.pc = endPC })
+               elsePC = a.nextPC()
+               bc.compileStmt(s.Else)
+       } else {
+               elsePC = a.nextPC()
+       }
+       endPC = a.nextPC()
+}
+
+func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
+       // Create implicit scope around switch
+       bc := a.enterChild()
+       defer bc.exit()
+
+       // Compile init statement, if any
+       if s.Init != nil {
+               bc.compileStmt(s.Init)
+       }
+
+       // Compile condition, if any, and extract its effects
+       var cond *expr
+       condbc := bc.enterChild()
+       if s.Tag != nil {
+               e := condbc.compileExpr(condbc.block, false, s.Tag)
+               if e != nil {
+                       var effect func(*Thread)
+                       effect, cond = e.extractEffect(condbc.block, "switch")
+                       a.push(effect)
+               }
+       }
+
+       // Count cases
+       ncases := 0
+       hasDefault := false
+       for _, c := range s.Body.List {
+               clause, ok := c.(*ast.CaseClause)
+               if !ok {
+                       a.diagAt(clause, "switch statement must contain case clauses")
+                       continue
+               }
+               if clause.Values == nil {
+                       if hasDefault {
+                               a.diagAt(clause, "switch statement contains more than one default case")
+                       }
+                       hasDefault = true
+               } else {
+                       ncases += len(clause.Values)
+               }
+       }
+
+       // Compile case expressions
+       cases := make([]func(*Thread) bool, ncases)
+       i := 0
+       for _, c := range s.Body.List {
+               clause, ok := c.(*ast.CaseClause)
+               if !ok {
+                       continue
+               }
+               for _, v := range clause.Values {
+                       e := condbc.compileExpr(condbc.block, false, v)
+                       switch {
+                       case e == nil:
+                               // Error reported by compileExpr
+                       case cond == nil && !e.t.isBoolean():
+                               a.diagAt(v, "'case' condition must be boolean")
+                       case cond == nil:
+                               cases[i] = e.asBool()
+                       case cond != nil:
+                               // Create comparison
+                               // TOOD(austin) This produces bad error messages
+                               compare := e.compileBinaryExpr(token.EQL, cond, e)
+                               if compare != nil {
+                                       cases[i] = compare.asBool()
+                               }
+                       }
+                       i++
+               }
+       }
+
+       // Emit condition
+       casePCs := make([]*uint, ncases+1)
+       endPC := badPC
+
+       a.flow.put(false, false, casePCs)
+       a.push(func(t *Thread) {
+               for i, c := range cases {
+                       if c(t) {
+                               t.pc = *casePCs[i]
+                               return
+                       }
+               }
+               t.pc = *casePCs[ncases]
+       })
+       condbc.exit()
+
+       // Compile cases
+       i = 0
+       for _, c := range s.Body.List {
+               clause, ok := c.(*ast.CaseClause)
+               if !ok {
+                       continue
+               }
+
+               // Save jump PC's
+               pc := a.nextPC()
+               if clause.Values != nil {
+                       for _ = range clause.Values {
+                               casePCs[i] = &pc
+                               i++
+                       }
+               } else {
+                       // Default clause
+                       casePCs[ncases] = &pc
+               }
+
+               // Compile body
+               fall := false
+               for j, s := range clause.Body {
+                       if br, ok := s.(*ast.BranchStmt); ok && br.Tok == token.FALLTHROUGH {
+                               // println("Found fallthrough");
+                               // It may be used only as the final
+                               // non-empty statement in a case or
+                               // default clause in an expression
+                               // "switch" statement.
+                               for _, s2 := range clause.Body[j+1:] {
+                                       // XXX(Spec) 6g also considers
+                                       // empty blocks to be empty
+                                       // statements.
+                                       if _, ok := s2.(*ast.EmptyStmt); !ok {
+                                               a.diagAt(s, "fallthrough statement must be final statement in case")
+                                               break
+                                       }
+                               }
+                               fall = true
+                       } else {
+                               bc.compileStmt(s)
+                       }
+               }
+               // Jump out of switch, unless there was a fallthrough
+               if !fall {
+                       a.flow.put1(false, &endPC)
+                       a.push(func(v *Thread) { v.pc = endPC })
+               }
+       }
+
+       // Get end PC
+       endPC = a.nextPC()
+       if !hasDefault {
+               casePCs[ncases] = &endPC
+       }
+}
+
+func (a *stmtCompiler) compileForStmt(s *ast.ForStmt) {
+       // Wrap the entire for in a block.
+       bc := a.enterChild()
+       defer bc.exit()
+
+       // Compile init statement, if any
+       if s.Init != nil {
+               bc.compileStmt(s.Init)
+       }
+
+       bodyPC := badPC
+       postPC := badPC
+       checkPC := badPC
+       endPC := badPC
+
+       // Jump to condition check.  We generate slightly less code by
+       // placing the condition check after the body.
+       a.flow.put1(false, &checkPC)
+       a.push(func(v *Thread) { v.pc = checkPC })
+
+       // Compile body
+       bodyPC = a.nextPC()
+       body := bc.enterChild()
+       if a.stmtLabel != nil {
+               body.label = a.stmtLabel
+       } else {
+               body.label = &label{resolved: s.Pos()}
+       }
+       body.label.desc = "for loop"
+       body.label.breakPC = &endPC
+       body.label.continuePC = &postPC
+       body.compileStmts(s.Body)
+       body.exit()
+
+       // Compile post, if any
+       postPC = a.nextPC()
+       if s.Post != nil {
+               // TODO(austin) Does the parser disallow short
+               // declarations in s.Post?
+               bc.compileStmt(s.Post)
+       }
+
+       // Compile condition check, if any
+       checkPC = a.nextPC()
+       if s.Cond == nil {
+               // If the condition is absent, it is equivalent to true.
+               a.flow.put1(false, &bodyPC)
+               a.push(func(v *Thread) { v.pc = bodyPC })
+       } else {
+               e := bc.compileExpr(bc.block, false, s.Cond)
+               switch {
+               case e == nil:
+                       // Error reported by compileExpr
+               case !e.t.isBoolean():
+                       a.diag("'for' condition must be boolean\n\t%v", e.t)
+               default:
+                       eval := e.asBool()
+                       a.flow.put1(true, &bodyPC)
+                       a.push(func(t *Thread) {
+                               if eval(t) {
+                                       t.pc = bodyPC
+                               }
+                       })
+               }
+       }
+
+       endPC = a.nextPC()
+}
+
+/*
+ * Block compiler
+ */
+
+func (a *blockCompiler) compileStmt(s ast.Stmt) {
+       sc := &stmtCompiler{a, s.Pos(), nil}
+       sc.compile(s)
+}
+
+func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
+       for _, sub := range block.List {
+               a.compileStmt(sub)
+       }
+}
+
+func (a *blockCompiler) enterChild() *blockCompiler {
+       block := a.block.enterChild()
+       return &blockCompiler{
+               funcCompiler: a.funcCompiler,
+               block:        block,
+               parent:       a,
+       }
+}
+
+func (a *blockCompiler) exit() { a.block.exit() }
+
+/*
+ * Function compiler
+ */
+
+func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) func(*Thread) Func {
+       // Create body scope
+       //
+       // The scope of a parameter or result is the body of the
+       // corresponding function.
+       bodyScope := b.ChildScope()
+       defer bodyScope.exit()
+       for i, t := range decl.Type.In {
+               if decl.InNames[i] != nil {
+                       bodyScope.DefineVar(decl.InNames[i].Name, decl.InNames[i].Pos(), t)
+               } else {
+                       bodyScope.DefineTemp(t)
+               }
+       }
+       for i, t := range decl.Type.Out {
+               if decl.OutNames[i] != nil {
+                       bodyScope.DefineVar(decl.OutNames[i].Name, decl.OutNames[i].Pos(), t)
+               } else {
+                       bodyScope.DefineTemp(t)
+               }
+       }
+
+       // Create block context
+       cb := newCodeBuf()
+       fc := &funcCompiler{
+               compiler:     a,
+               fnType:       decl.Type,
+               outVarsNamed: len(decl.OutNames) > 0 && decl.OutNames[0] != nil,
+               codeBuf:      cb,
+               flow:         newFlowBuf(cb),
+               labels:       make(map[string]*label),
+       }
+       bc := &blockCompiler{
+               funcCompiler: fc,
+               block:        bodyScope.block,
+       }
+
+       // Compile body
+       nerr := a.numError()
+       bc.compileStmts(body)
+       fc.checkLabels()
+       if nerr != a.numError() {
+               return nil
+       }
+
+       // Check that the body returned if necessary.  We only check
+       // this if there were no errors compiling the body.
+       if len(decl.Type.Out) > 0 && fc.flow.reachesEnd(0) {
+               // XXX(Spec) Not specified.
+               a.diagAt(&body.Rbrace, "function ends without a return statement")
+               return nil
+       }
+
+       code := fc.get()
+       maxVars := bodyScope.maxVars
+       return func(t *Thread) Func { return &evalFunc{t.f, maxVars, code} }
+}
+
+// Checks that labels were resolved and that all jumps obey scoping
+// rules.  Reports an error and set fc.err if any check fails.
+func (a *funcCompiler) checkLabels() {
+       nerr := a.numError()
+       for _, l := range a.labels {
+               if !l.resolved.IsValid() {
+                       a.diagAt(&l.used, "label %s not defined", l.name)
+               }
+       }
+       if nerr != a.numError() {
+               // Don't check scopes if we have unresolved labels
+               return
+       }
+
+       // Executing the "goto" statement must not cause any variables
+       // to come into scope that were not already in scope at the
+       // point of the goto.
+       a.flow.gotosObeyScopes(a.compiler)
+}
diff --git a/libgo/go/exp/eval/stmt_test.go b/libgo/go/exp/eval/stmt_test.go
new file mode 100644 (file)
index 0000000..a14a288
--- /dev/null
@@ -0,0 +1,343 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import "testing"
+
+var atLeastOneDecl = "at least one new variable must be declared"
+
+var stmtTests = []test{
+       // Short declarations
+       Val1("x := i", "x", 1),
+       Val1("x := f", "x", 1.0),
+       // Type defaulting
+       Val1("a := 42", "a", 42),
+       Val1("a := 1.0", "a", 1.0),
+       // Parallel assignment
+       Val2("a, b := 1, 2", "a", 1, "b", 2),
+       Val2("a, i := 1, 2", "a", 1, "i", 2),
+       CErr("a, i := 1, f", opTypes),
+       CErr("a, b := 1, 2, 3", "too many"),
+       CErr("a := 1, 2", "too many"),
+       CErr("a, b := 1", "not enough"),
+       // Mixed declarations
+       CErr("i := 1", atLeastOneDecl),
+       CErr("i, u := 1, 2", atLeastOneDecl),
+       Val2("i, x := 2, f", "i", 2, "x", 1.0),
+       // Various errors
+       CErr("1 := 2", "left side of := must be a name"),
+       CErr("c, a := 1, 1", "cannot assign"),
+       // Unpacking
+       Val2("x, y := oneTwo()", "x", 1, "y", 2),
+       CErr("x := oneTwo()", "too many"),
+       CErr("x, y, z := oneTwo()", "not enough"),
+       CErr("x, y := oneTwo(), 2", "multi-valued"),
+       CErr("x := oneTwo()+2", opTypes),
+       // TOOD(austin) This error message is weird
+       CErr("x := void()", "not enough"),
+       // Placeholders
+       CErr("x := 1+\"x\"; i=x+1", opTypes),
+
+       // Assignment
+       Val1("i = 2", "i", 2),
+       Val1("(i) = 2", "i", 2),
+       CErr("1 = 2", "cannot assign"),
+       CErr("1-1 = 2", "- expression"),
+       Val1("i = 2.0", "i", 2),
+       CErr("i = 2.2", constantTruncated),
+       CErr("u = -2", constantUnderflows),
+       CErr("i = f", opTypes),
+       CErr("i, u = 0, f", opTypes),
+       CErr("i, u = 0, f", "value 2"),
+       Val2("i, i2 = i2, i", "i", 2, "i2", 1),
+       CErr("c = 1", "cannot assign"),
+
+       Val1("x := &i; *x = 2", "i", 2),
+
+       Val1("ai[0] = 42", "ai", varray{42, 2}),
+       Val1("aai[1] = ai; ai[0] = 42", "aai", varray{varray{1, 2}, varray{1, 2}}),
+       Val1("aai = aai2", "aai", varray{varray{5, 6}, varray{7, 8}}),
+
+       // Assignment conversions
+       Run("var sl []int; sl = &ai"),
+       CErr("type ST []int; type AT *[2]int; var x AT = &ai; var y ST = x", opTypes),
+       Run("type ST []int; var y ST = &ai"),
+       Run("type AT *[2]int; var x AT = &ai; var y []int = x"),
+
+       // Op-assignment
+       Val1("i += 2", "i", 3),
+       Val("i", 1),
+       Val1("f += 2", "f", 3.0),
+       CErr("2 += 2", "cannot assign"),
+       CErr("i, j += 2", "cannot be combined"),
+       CErr("i += 2, 3", "cannot be combined"),
+       Val2("s2 := s; s += \"def\"", "s2", "abc", "s", "abcdef"),
+       CErr("s += 1", opTypes),
+       // Single evaluation
+       Val2("ai[func()int{i+=1;return 0}()] *= 3; i2 = ai[0]", "i", 2, "i2", 3),
+
+       // Type declarations
+       // Identifiers
+       Run("type T int"),
+       CErr("type T x", "undefined"),
+       CErr("type T c", "constant"),
+       CErr("type T i", "variable"),
+       CErr("type T T", "recursive"),
+       CErr("type T x; type U T; var v U; v = 1", "undefined"),
+       // Pointer types
+       Run("type T *int"),
+       Run("type T *T"),
+       // Array types
+       Run("type T [5]int"),
+       Run("type T [c+42/2]int"),
+       Run("type T [2.0]int"),
+       CErr("type T [i]int", "constant expression"),
+       CErr("type T [2.5]int", constantTruncated),
+       CErr("type T [-1]int", "negative"),
+       CErr("type T [2]T", "recursive"),
+       // Struct types
+       Run("type T struct { a int; b int }"),
+       Run("type T struct { a int; int }"),
+       Run("type T struct { x *T }"),
+       Run("type T int; type U struct { T }"),
+       CErr("type T *int; type U struct { T }", "embedded.*pointer"),
+       CErr("type T *struct { T }", "embedded.*pointer"),
+       CErr("type T struct { a int; a int }", " a .*redeclared.*:1:17"),
+       CErr("type T struct { int; int }", "int .*redeclared.*:1:17"),
+       CErr("type T struct { int int; int }", "int .*redeclared.*:1:17"),
+       Run("type T struct { x *struct { T } }"),
+       CErr("type T struct { x struct { T } }", "recursive"),
+       CErr("type T struct { x }; type U struct { T }", "undefined"),
+       // Function types
+       Run("type T func()"),
+       Run("type T func(a, b int) int"),
+       Run("type T func(a, b int) (x int, y int)"),
+       Run("type T func(a, a int) (a int, a int)"),
+       Run("type T func(a, b int) (x, y int)"),
+       Run("type T func(int, int) (int, int)"),
+       CErr("type T func(x); type U T", "undefined"),
+       CErr("type T func(a T)", "recursive"),
+       // Interface types
+       Run("type T interface {x(a, b int) int}"),
+       Run("type T interface {x(a, b int) int}; type U interface {T; y(c int)}"),
+       CErr("type T interface {x(a int); x()}", "method x redeclared"),
+       CErr("type T interface {x()}; type U interface {T; x()}", "method x redeclared"),
+       CErr("type T int; type U interface {T}", "embedded type"),
+       // Parens
+       Run("type T (int)"),
+
+       // Variable declarations
+       Val2("var x int", "i", 1, "x", 0),
+       Val1("var x = 1", "x", 1),
+       Val1("var x = 1.0", "x", 1.0),
+       Val1("var x int = 1.0", "x", 1),
+       // Placeholders
+       CErr("var x foo; x = 1", "undefined"),
+       CErr("var x foo = 1; x = 1", "undefined"),
+       // Redeclaration
+       CErr("var i, x int", " i .*redeclared"),
+       CErr("var x int; var x int", " x .*redeclared.*:1:5"),
+
+       // Expression statements
+       CErr("x := func(){ 1-1 }", "expression statement"),
+       CErr("x := func(){ 1-1 }", "- expression"),
+       Val1("fn(2)", "i", 1),
+
+       // IncDec statements
+       Val1("i++", "i", 2),
+       Val1("i--", "i", 0),
+       Val1("u++", "u", uint(2)),
+       Val1("u--", "u", uint(0)),
+       Val1("f++", "f", 2.0),
+       Val1("f--", "f", 0.0),
+       // Single evaluation
+       Val2("ai[func()int{i+=1;return 0}()]++; i2 = ai[0]", "i", 2, "i2", 2),
+       // Operand types
+       CErr("s++", opTypes),
+       CErr("s++", "'\\+\\+'"),
+       CErr("2++", "cannot assign"),
+       CErr("c++", "cannot assign"),
+
+       // Function scoping
+       Val1("fn1 := func() { i=2 }; fn1()", "i", 2),
+       Val1("fn1 := func() { i:=2 }; fn1()", "i", 1),
+       Val2("fn1 := func() int { i=2; i:=3; i=4; return i }; x := fn1()", "i", 2, "x", 4),
+
+       // Basic returns
+       CErr("fn1 := func() int {}", "return"),
+       Run("fn1 := func() {}"),
+       CErr("fn1 := func() (r int) {}", "return"),
+       Val1("fn1 := func() (r int) {return}; i = fn1()", "i", 0),
+       Val1("fn1 := func() (r int) {r = 2; return}; i = fn1()", "i", 2),
+       Val1("fn1 := func() (r int) {return 2}; i = fn1()", "i", 2),
+       Val1("fn1 := func(int) int {return 2}; i = fn1(1)", "i", 2),
+
+       // Multi-valued returns
+       Val2("fn1 := func() (bool, int) {return true, 2}; x, y := fn1()", "x", true, "y", 2),
+       CErr("fn1 := func() int {return}", "not enough values"),
+       CErr("fn1 := func() int {return 1,2}", "too many values"),
+       CErr("fn1 := func() {return 1}", "too many values"),
+       CErr("fn1 := func() (int,int,int) {return 1,2}", "not enough values"),
+       Val2("fn1 := func() (int, int) {return oneTwo()}; x, y := fn1()", "x", 1, "y", 2),
+       CErr("fn1 := func() int {return oneTwo()}", "too many values"),
+       CErr("fn1 := func() (int,int,int) {return oneTwo()}", "not enough values"),
+       Val1("fn1 := func(x,y int) int {return x+y}; x := fn1(oneTwo())", "x", 3),
+
+       // Return control flow
+       Val2("fn1 := func(x *int) bool { *x = 2; return true; *x = 3; }; x := fn1(&i)", "i", 2, "x", true),
+
+       // Break/continue/goto/fallthrough
+       CErr("break", "outside"),
+       CErr("break foo", "break.*foo.*not defined"),
+       CErr("continue", "outside"),
+       CErr("continue foo", "continue.*foo.*not defined"),
+       CErr("fallthrough", "outside"),
+       CErr("goto foo", "foo.*not defined"),
+       CErr(" foo: foo:;", "foo.*redeclared.*:1:2"),
+       Val1("i+=2; goto L; i+=4; L: i+=8", "i", 1+2+8),
+       // Return checking
+       CErr("fn1 := func() int { goto L; return 1; L: }", "return"),
+       Run("fn1 := func() int { L: goto L; i = 2 }"),
+       Run("fn1 := func() int { return 1; L: goto L }"),
+       // Scope checking
+       Run("fn1 := func() { { L: x:=1 }; goto L }"),
+       CErr("fn1 := func() { { x:=1; L: }; goto L }", "into scope"),
+       CErr("fn1 := func() { goto L; x:=1; L: }", "into scope"),
+       Run("fn1 := func() { goto L; { L: x:=1 } }"),
+       CErr("fn1 := func() { goto L; { x:=1; L: } }", "into scope"),
+
+       // Blocks
+       CErr("fn1 := func() int {{}}", "return"),
+       Val1("fn1 := func() bool { { return true } }; b := fn1()", "b", true),
+
+       // If
+       Val2("if true { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
+       Val2("if false { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
+       Val2("if i == i2 { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
+       // Omit optional parts
+       Val2("if { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
+       Val2("if true { i = 2 }; i2 = 4", "i", 2, "i2", 4),
+       Val2("if false { i = 2 }; i2 = 4", "i", 1, "i2", 4),
+       // Init
+       Val2("if x := true; x { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
+       Val2("if x := false; x { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
+       // Statement else
+       Val2("if true { i = 2 } else i = 3; i2 = 4", "i", 2, "i2", 4),
+       Val2("if false { i = 2 } else i = 3; i2 = 4", "i", 3, "i2", 4),
+       // Scoping
+       Val2("if true { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1),
+       Val2("if false { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1),
+       Val2("if false { i := 2 } else i := 3; i2 = i", "i", 1, "i2", 1),
+       CErr("if true { x := 2 }; x = 4", undefined),
+       Val2("if i := 2; true { i2 = i; i := 3 }", "i", 1, "i2", 2),
+       Val2("if i := 2; false {} else { i2 = i; i := 3 }", "i", 1, "i2", 2),
+       // Return checking
+       Run("fn1 := func() int { if true { return 1 } else { return 2 } }"),
+       Run("fn1 := func() int { if true { return 1 } else return 2 }"),
+       CErr("fn1 := func() int { if true { return 1 } else { } }", "return"),
+       CErr("fn1 := func() int { if true { } else { return 1 } }", "return"),
+       CErr("fn1 := func() int { if true { } else return 1 }", "return"),
+       CErr("fn1 := func() int { if true { } else { } }", "return"),
+       CErr("fn1 := func() int { if true { return 1 } }", "return"),
+       CErr("fn1 := func() int { if true { } }", "return"),
+       Run("fn1 := func() int { if true { }; return 1 }"),
+       CErr("fn1 := func() int { if { } }", "return"),
+       CErr("fn1 := func() int { if { } else { return 2 } }", "return"),
+       Run("fn1 := func() int { if { return 1 } }"),
+       Run("fn1 := func() int { if { return 1 } else { } }"),
+       Run("fn1 := func() int { if { return 1 } else { } }"),
+
+       // Switch
+       Val1("switch { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+4),
+       Val1("switch { default: i += 2; case false: i += 4; case true: i += 8 }", "i", 1+8),
+       CErr("switch { default: i += 2; default: i += 4 }", "more than one"),
+       Val1("switch false { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+2),
+       CErr("switch s { case 1: }", opTypes),
+       CErr("switch ai { case ai: i += 2 }", opTypes),
+       Val1("switch 1.0 { case 1: i += 2; case 2: i += 4 }", "i", 1+2),
+       Val1("switch 1.5 { case 1: i += 2; case 2: i += 4 }", "i", 1),
+       CErr("switch oneTwo() {}", "multi-valued expression"),
+       Val1("switch 2 { case 1: i += 2; fallthrough; case 2: i += 4; fallthrough; case 3: i += 8; fallthrough }", "i", 1+4+8),
+       Val1("switch 5 { case 1: i += 2; fallthrough; default: i += 4; fallthrough; case 2: i += 8; fallthrough; case 3: i += 16; fallthrough }", "i", 1+4+8+16),
+       CErr("switch { case true: fallthrough; i += 2 }", "final statement"),
+       Val1("switch { case true: i += 2; fallthrough; ; ; case false: i += 4 }", "i", 1+2+4),
+       Val1("switch 2 { case 0, 1: i += 2; case 2, 3: i += 4 }", "i", 1+4),
+       Val2("switch func()int{i2++;return 5}() { case 1, 2: i += 2; case 4, 5: i += 4 }", "i", 1+4, "i2", 3),
+       Run("switch i { case i: }"),
+       // TODO(austin) Why doesn't this fail?
+       //CErr("case 1:", "XXX"),
+
+       // For
+       Val2("for x := 1; x < 5; x++ { i+=x }; i2 = 4", "i", 11, "i2", 4),
+       Val2("for x := 1; x < 5; x++ { i+=x; break; i++ }; i2 = 4", "i", 2, "i2", 4),
+       Val2("for x := 1; x < 5; x++ { i+=x; continue; i++ }; i2 = 4", "i", 11, "i2", 4),
+       Val2("for i = 2; false; i = 3 { i = 4 }; i2 = 4", "i", 2, "i2", 4),
+       Val2("for i < 5 { i++ }; i2 = 4", "i", 5, "i2", 4),
+       Val2("for i < 0 { i++ }; i2 = 4", "i", 1, "i2", 4),
+       // Scoping
+       Val2("for i := 2; true; { i2 = i; i := 3; break }", "i", 1, "i2", 2),
+       // Labeled break/continue
+       Val1("L1: for { L2: for { i+=2; break L1; i+=4 }; i+=8 }", "i", 1+2),
+       Val1("L1: for { L2: for { i+=2; break L2; i+=4 }; i+=8; break; i+=16 }", "i", 1+2+8),
+       CErr("L1: { for { break L1 } }", "break.*not defined"),
+       CErr("L1: for {}; for { break L1 }", "break.*not defined"),
+       CErr("L1:; for { break L1 }", "break.*not defined"),
+       Val2("L1: for i = 0; i < 2; i++ { L2: for { i2++; continue L1; i2++ } }", "i", 2, "i2", 4),
+       CErr("L1: { for { continue L1 } }", "continue.*not defined"),
+       CErr("L1:; for { continue L1 }", "continue.*not defined"),
+       // Return checking
+       Run("fn1 := func() int{ for {} }"),
+       CErr("fn1 := func() int{ for true {} }", "return"),
+       CErr("fn1 := func() int{ for true {return 1} }", "return"),
+       CErr("fn1 := func() int{ for {break} }", "return"),
+       Run("fn1 := func() int{ for { for {break} } }"),
+       CErr("fn1 := func() int{ L1: for { for {break L1} } }", "return"),
+       Run("fn1 := func() int{ for true {}; return 1 }"),
+
+       // Selectors
+       Val1("var x struct { a int; b int }; x.a = 42; i = x.a", "i", 42),
+       Val1("type T struct { x int }; var y struct { T }; y.x = 42; i = y.x", "i", 42),
+       Val2("type T struct { x int }; var y struct { T; x int }; y.x = 42; i = y.x; i2 = y.T.x", "i", 42, "i2", 0),
+       Run("type T struct { x int }; var y struct { *T }; a := func(){i=y.x}"),
+       CErr("type T struct { x int }; var x T; x.y = 42", "no field"),
+       CErr("type T struct { x int }; type U struct { x int }; var y struct { T; U }; y.x = 42", "ambiguous.*\tT\\.x\n\tU\\.x"),
+       CErr("type T struct { *T }; var x T; x.foo", "no field"),
+
+       Val1("fib := func(int) int{return 0;}; fib = func(v int) int { if v < 2 { return 1 }; return fib(v-1)+fib(v-2) }; i = fib(20)", "i", 10946),
+
+       // Make slice
+       Val2("x := make([]int, 2); x[0] = 42; i, i2 = x[0], x[1]", "i", 42, "i2", 0),
+       Val2("x := make([]int, 2); x[1] = 42; i, i2 = x[0], x[1]", "i", 0, "i2", 42),
+       RErr("x := make([]int, 2); x[-i] = 42", "negative index"),
+       RErr("x := make([]int, 2); x[2] = 42", "index 2 exceeds"),
+       Val2("x := make([]int, 2, 3); i, i2 = len(x), cap(x)", "i", 2, "i2", 3),
+       Val2("x := make([]int, 3, 2); i, i2 = len(x), cap(x)", "i", 3, "i2", 3),
+       RErr("x := make([]int, -i)", "negative length"),
+       RErr("x := make([]int, 2, -i)", "negative capacity"),
+       RErr("x := make([]int, 2, 3); x[2] = 42", "index 2 exceeds"),
+       CErr("x := make([]int, 2, 3, 4)", "too many"),
+       CErr("x := make([]int)", "not enough"),
+
+       // TODO(austin) Test make map
+
+       // Maps
+       Val1("x := make(map[int] int); x[1] = 42; i = x[1]", "i", 42),
+       Val2("x := make(map[int] int); x[1] = 42; i, y := x[1]", "i", 42, "y", true),
+       Val2("x := make(map[int] int); x[1] = 42; i, y := x[2]", "i", 0, "y", false),
+       // Not implemented
+       //Val1("x := make(map[int] int); x[1] = 42, true; i = x[1]", "i", 42),
+       //Val2("x := make(map[int] int); x[1] = 42; x[1] = 42, false; i, y := x[1]", "i", 0, "y", false),
+       Run("var x int; a := make(map[int] int); a[0], x = 1, 2"),
+       CErr("x := make(map[int] int); (func(a,b int){})(x[0])", "not enough"),
+       CErr("x := make(map[int] int); x[1] = oneTwo()", "too many"),
+       RErr("x := make(map[int] int); i = x[1]", "key '1' not found"),
+
+       // Functions
+       Val2("func fib(n int) int { if n <= 2 { return n }; return fib(n-1) + fib(n-2) }", "fib(4)", 5, "fib(10)", 89),
+       Run("func f1(){}"),
+       Run2("func f1(){}", "f1()"),
+}
+
+func TestStmt(t *testing.T) { runTests(t, "stmtTests", stmtTests) }
diff --git a/libgo/go/exp/eval/type.go b/libgo/go/exp/eval/type.go
new file mode 100644 (file)
index 0000000..6c465dd
--- /dev/null
@@ -0,0 +1,1258 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "big"
+       "go/ast"
+       "go/token"
+       "log"
+       "reflect"
+       "sort"
+       "unsafe" // For Sizeof
+)
+
+
+// XXX(Spec) The type compatibility section is very confusing because
+// it makes it seem like there are three distinct types of
+// compatibility: plain compatibility, assignment compatibility, and
+// comparison compatibility.  As I understand it, there's really only
+// assignment compatibility and comparison and conversion have some
+// restrictions and have special meaning in some cases where the types
+// are not otherwise assignment compatible.  The comparison
+// compatibility section is almost all about the semantics of
+// comparison, not the type checking of it, so it would make much more
+// sense in the comparison operators section.  The compatibility and
+// assignment compatibility sections should be rolled into one.
+
+type Type interface {
+       // compat returns whether this type is compatible with another
+       // type.  If conv is false, this is normal compatibility,
+       // where two named types are compatible only if they are the
+       // same named type.  If conv if true, this is conversion
+       // compatibility, where two named types are conversion
+       // compatible if their definitions are conversion compatible.
+       //
+       // TODO(austin) Deal with recursive types
+       compat(o Type, conv bool) bool
+       // lit returns this type's literal.  If this is a named type,
+       // this is the unnamed underlying type.  Otherwise, this is an
+       // identity operation.
+       lit() Type
+       // isBoolean returns true if this is a boolean type.
+       isBoolean() bool
+       // isInteger returns true if this is an integer type.
+       isInteger() bool
+       // isFloat returns true if this is a floating type.
+       isFloat() bool
+       // isIdeal returns true if this is an ideal int or float.
+       isIdeal() bool
+       // Zero returns a new zero value of this type.
+       Zero() Value
+       // String returns the string representation of this type.
+       String() string
+       // The position where this type was defined, if any.
+       Pos() token.Position
+}
+
+type BoundedType interface {
+       Type
+       // minVal returns the smallest value of this type.
+       minVal() *big.Rat
+       // maxVal returns the largest value of this type.
+       maxVal() *big.Rat
+}
+
+var universePos = token.Position{"<universe>", 0, 0, 0}
+
+/*
+ * Type array maps.  These are used to memoize composite types.
+ */
+
+type typeArrayMapEntry struct {
+       key  []Type
+       v    interface{}
+       next *typeArrayMapEntry
+}
+
+type typeArrayMap map[uintptr]*typeArrayMapEntry
+
+func hashTypeArray(key []Type) uintptr {
+       hash := uintptr(0)
+       for _, t := range key {
+               hash = hash * 33
+               if t == nil {
+                       continue
+               }
+               addr := reflect.NewValue(t).(*reflect.PtrValue).Get()
+               hash ^= addr
+       }
+       return hash
+}
+
+func newTypeArrayMap() typeArrayMap { return make(map[uintptr]*typeArrayMapEntry) }
+
+func (m typeArrayMap) Get(key []Type) interface{} {
+       ent, ok := m[hashTypeArray(key)]
+       if !ok {
+               return nil
+       }
+
+nextEnt:
+       for ; ent != nil; ent = ent.next {
+               if len(key) != len(ent.key) {
+                       continue
+               }
+               for i := 0; i < len(key); i++ {
+                       if key[i] != ent.key[i] {
+                               continue nextEnt
+                       }
+               }
+               // Found it
+               return ent.v
+       }
+
+       return nil
+}
+
+func (m typeArrayMap) Put(key []Type, v interface{}) interface{} {
+       hash := hashTypeArray(key)
+       ent := m[hash]
+
+       new := &typeArrayMapEntry{key, v, ent}
+       m[hash] = new
+       return v
+}
+
+/*
+ * Common type
+ */
+
+type commonType struct{}
+
+func (commonType) isBoolean() bool { return false }
+
+func (commonType) isInteger() bool { return false }
+
+func (commonType) isFloat() bool { return false }
+
+func (commonType) isIdeal() bool { return false }
+
+func (commonType) Pos() token.Position { return token.Position{} }
+
+/*
+ * Bool
+ */
+
+type boolType struct {
+       commonType
+}
+
+var BoolType = universe.DefineType("bool", universePos, &boolType{})
+
+func (t *boolType) compat(o Type, conv bool) bool {
+       _, ok := o.lit().(*boolType)
+       return ok
+}
+
+func (t *boolType) lit() Type { return t }
+
+func (t *boolType) isBoolean() bool { return true }
+
+func (boolType) String() string {
+       // Use angle brackets as a convention for printing the
+       // underlying, unnamed type.  This should only show up in
+       // debug output.
+       return "<bool>"
+}
+
+func (t *boolType) Zero() Value {
+       res := boolV(false)
+       return &res
+}
+
+/*
+ * Uint
+ */
+
+type uintType struct {
+       commonType
+
+       // 0 for architecture-dependent types
+       Bits uint
+       // true for uintptr, false for all others
+       Ptr  bool
+       name string
+}
+
+var (
+       Uint8Type  = universe.DefineType("uint8", universePos, &uintType{commonType{}, 8, false, "uint8"})
+       Uint16Type = universe.DefineType("uint16", universePos, &uintType{commonType{}, 16, false, "uint16"})
+       Uint32Type = universe.DefineType("uint32", universePos, &uintType{commonType{}, 32, false, "uint32"})
+       Uint64Type = universe.DefineType("uint64", universePos, &uintType{commonType{}, 64, false, "uint64"})
+
+       UintType    = universe.DefineType("uint", universePos, &uintType{commonType{}, 0, false, "uint"})
+       UintptrType = universe.DefineType("uintptr", universePos, &uintType{commonType{}, 0, true, "uintptr"})
+)
+
+func (t *uintType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*uintType)
+       return ok && t == t2
+}
+
+func (t *uintType) lit() Type { return t }
+
+func (t *uintType) isInteger() bool { return true }
+
+func (t *uintType) String() string { return "<" + t.name + ">" }
+
+func (t *uintType) Zero() Value {
+       switch t.Bits {
+       case 0:
+               if t.Ptr {
+                       res := uintptrV(0)
+                       return &res
+               } else {
+                       res := uintV(0)
+                       return &res
+               }
+       case 8:
+               res := uint8V(0)
+               return &res
+       case 16:
+               res := uint16V(0)
+               return &res
+       case 32:
+               res := uint32V(0)
+               return &res
+       case 64:
+               res := uint64V(0)
+               return &res
+       }
+       panic("unexpected uint bit count")
+}
+
+func (t *uintType) minVal() *big.Rat { return big.NewRat(0, 1) }
+
+func (t *uintType) maxVal() *big.Rat {
+       bits := t.Bits
+       if bits == 0 {
+               if t.Ptr {
+                       bits = uint(8 * unsafe.Sizeof(uintptr(0)))
+               } else {
+                       bits = uint(8 * unsafe.Sizeof(uint(0)))
+               }
+       }
+       numer := big.NewInt(1)
+       numer.Lsh(numer, bits)
+       numer.Sub(numer, idealOne)
+       return new(big.Rat).SetInt(numer)
+}
+
+/*
+ * Int
+ */
+
+type intType struct {
+       commonType
+
+       // XXX(Spec) Numeric types: "There is also a set of
+       // architecture-independent basic numeric types whose size
+       // depends on the architecture."  Should that be
+       // architecture-dependent?
+
+       // 0 for architecture-dependent types
+       Bits uint
+       name string
+}
+
+var (
+       Int8Type  = universe.DefineType("int8", universePos, &intType{commonType{}, 8, "int8"})
+       Int16Type = universe.DefineType("int16", universePos, &intType{commonType{}, 16, "int16"})
+       Int32Type = universe.DefineType("int32", universePos, &intType{commonType{}, 32, "int32"})
+       Int64Type = universe.DefineType("int64", universePos, &intType{commonType{}, 64, "int64"})
+
+       IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"})
+)
+
+func (t *intType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*intType)
+       return ok && t == t2
+}
+
+func (t *intType) lit() Type { return t }
+
+func (t *intType) isInteger() bool { return true }
+
+func (t *intType) String() string { return "<" + t.name + ">" }
+
+func (t *intType) Zero() Value {
+       switch t.Bits {
+       case 8:
+               res := int8V(0)
+               return &res
+       case 16:
+               res := int16V(0)
+               return &res
+       case 32:
+               res := int32V(0)
+               return &res
+       case 64:
+               res := int64V(0)
+               return &res
+
+       case 0:
+               res := intV(0)
+               return &res
+       }
+       panic("unexpected int bit count")
+}
+
+func (t *intType) minVal() *big.Rat {
+       bits := t.Bits
+       if bits == 0 {
+               bits = uint(8 * unsafe.Sizeof(int(0)))
+       }
+       numer := big.NewInt(-1)
+       numer.Lsh(numer, bits-1)
+       return new(big.Rat).SetInt(numer)
+}
+
+func (t *intType) maxVal() *big.Rat {
+       bits := t.Bits
+       if bits == 0 {
+               bits = uint(8 * unsafe.Sizeof(int(0)))
+       }
+       numer := big.NewInt(1)
+       numer.Lsh(numer, bits-1)
+       numer.Sub(numer, idealOne)
+       return new(big.Rat).SetInt(numer)
+}
+
+/*
+ * Ideal int
+ */
+
+type idealIntType struct {
+       commonType
+}
+
+var IdealIntType Type = &idealIntType{}
+
+func (t *idealIntType) compat(o Type, conv bool) bool {
+       _, ok := o.lit().(*idealIntType)
+       return ok
+}
+
+func (t *idealIntType) lit() Type { return t }
+
+func (t *idealIntType) isInteger() bool { return true }
+
+func (t *idealIntType) isIdeal() bool { return true }
+
+func (t *idealIntType) String() string { return "ideal integer" }
+
+func (t *idealIntType) Zero() Value { return &idealIntV{idealZero} }
+
+/*
+ * Float
+ */
+
+type floatType struct {
+       commonType
+
+       // 0 for architecture-dependent type
+       Bits uint
+
+       name string
+}
+
+var (
+       Float32Type = universe.DefineType("float32", universePos, &floatType{commonType{}, 32, "float32"})
+       Float64Type = universe.DefineType("float64", universePos, &floatType{commonType{}, 64, "float64"})
+       FloatType   = universe.DefineType("float", universePos, &floatType{commonType{}, 0, "float"})
+)
+
+func (t *floatType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*floatType)
+       return ok && t == t2
+}
+
+func (t *floatType) lit() Type { return t }
+
+func (t *floatType) isFloat() bool { return true }
+
+func (t *floatType) String() string { return "<" + t.name + ">" }
+
+func (t *floatType) Zero() Value {
+       switch t.Bits {
+       case 32:
+               res := float32V(0)
+               return &res
+       case 64:
+               res := float64V(0)
+               return &res
+       case 0:
+               res := floatV(0)
+               return &res
+       }
+       panic("unexpected float bit count")
+}
+
+var maxFloat32Val *big.Rat
+var maxFloat64Val *big.Rat
+var minFloat32Val *big.Rat
+var minFloat64Val *big.Rat
+
+func (t *floatType) minVal() *big.Rat {
+       bits := t.Bits
+       if bits == 0 {
+               bits = uint(8 * unsafe.Sizeof(float(0)))
+       }
+       switch bits {
+       case 32:
+               return minFloat32Val
+       case 64:
+               return minFloat64Val
+       }
+       log.Panicf("unexpected floating point bit count: %d", bits)
+       panic("unreachable")
+}
+
+func (t *floatType) maxVal() *big.Rat {
+       bits := t.Bits
+       if bits == 0 {
+               bits = uint(8 * unsafe.Sizeof(float(0)))
+       }
+       switch bits {
+       case 32:
+               return maxFloat32Val
+       case 64:
+               return maxFloat64Val
+       }
+       log.Panicf("unexpected floating point bit count: %d", bits)
+       panic("unreachable")
+}
+
+/*
+ * Ideal float
+ */
+
+type idealFloatType struct {
+       commonType
+}
+
+var IdealFloatType Type = &idealFloatType{}
+
+func (t *idealFloatType) compat(o Type, conv bool) bool {
+       _, ok := o.lit().(*idealFloatType)
+       return ok
+}
+
+func (t *idealFloatType) lit() Type { return t }
+
+func (t *idealFloatType) isFloat() bool { return true }
+
+func (t *idealFloatType) isIdeal() bool { return true }
+
+func (t *idealFloatType) String() string { return "ideal float" }
+
+func (t *idealFloatType) Zero() Value { return &idealFloatV{big.NewRat(0, 1)} }
+
+/*
+ * String
+ */
+
+type stringType struct {
+       commonType
+}
+
+var StringType = universe.DefineType("string", universePos, &stringType{})
+
+func (t *stringType) compat(o Type, conv bool) bool {
+       _, ok := o.lit().(*stringType)
+       return ok
+}
+
+func (t *stringType) lit() Type { return t }
+
+func (t *stringType) String() string { return "<string>" }
+
+func (t *stringType) Zero() Value {
+       res := stringV("")
+       return &res
+}
+
+/*
+ * Array
+ */
+
+type ArrayType struct {
+       commonType
+       Len  int64
+       Elem Type
+}
+
+var arrayTypes = make(map[int64]map[Type]*ArrayType)
+
+// Two array types are identical if they have identical element types
+// and the same array length.
+
+func NewArrayType(len int64, elem Type) *ArrayType {
+       ts, ok := arrayTypes[len]
+       if !ok {
+               ts = make(map[Type]*ArrayType)
+               arrayTypes[len] = ts
+       }
+       t, ok := ts[elem]
+       if !ok {
+               t = &ArrayType{commonType{}, len, elem}
+               ts[elem] = t
+       }
+       return t
+}
+
+func (t *ArrayType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*ArrayType)
+       if !ok {
+               return false
+       }
+       return t.Len == t2.Len && t.Elem.compat(t2.Elem, conv)
+}
+
+func (t *ArrayType) lit() Type { return t }
+
+func (t *ArrayType) String() string { return "[]" + t.Elem.String() }
+
+func (t *ArrayType) Zero() Value {
+       res := arrayV(make([]Value, t.Len))
+       // TODO(austin) It's unfortunate that each element is
+       // separately heap allocated.  We could add ZeroArray to
+       // everything, though that doesn't help with multidimensional
+       // arrays.  Or we could do something unsafe.  We'll have this
+       // same problem with structs.
+       for i := int64(0); i < t.Len; i++ {
+               res[i] = t.Elem.Zero()
+       }
+       return &res
+}
+
+/*
+ * Struct
+ */
+
+type StructField struct {
+       Name      string
+       Type      Type
+       Anonymous bool
+}
+
+type StructType struct {
+       commonType
+       Elems []StructField
+}
+
+var structTypes = newTypeArrayMap()
+
+// Two struct types are identical if they have the same sequence of
+// fields, and if corresponding fields have the same names and
+// identical types. Two anonymous fields are considered to have the
+// same name.
+
+func NewStructType(fields []StructField) *StructType {
+       // Start by looking up just the types
+       fts := make([]Type, len(fields))
+       for i, f := range fields {
+               fts[i] = f.Type
+       }
+       tMapI := structTypes.Get(fts)
+       if tMapI == nil {
+               tMapI = structTypes.Put(fts, make(map[string]*StructType))
+       }
+       tMap := tMapI.(map[string]*StructType)
+
+       // Construct key for field names
+       key := ""
+       for _, f := range fields {
+               // XXX(Spec) It's not clear if struct { T } and struct
+               // { T T } are either identical or compatible.  The
+               // "Struct Types" section says that the name of that
+               // field is "T", which suggests that they are
+               // identical, but it really means that it's the name
+               // for the purpose of selector expressions and nothing
+               // else.  We decided that they should be neither
+               // identical or compatible.
+               if f.Anonymous {
+                       key += "!"
+               }
+               key += f.Name + " "
+       }
+
+       // XXX(Spec) Do the tags also have to be identical for the
+       // types to be identical?  I certainly hope so, because
+       // otherwise, this is the only case where two distinct type
+       // objects can represent identical types.
+
+       t, ok := tMap[key]
+       if !ok {
+               // Create new struct type
+               t = &StructType{commonType{}, fields}
+               tMap[key] = t
+       }
+       return t
+}
+
+func (t *StructType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*StructType)
+       if !ok {
+               return false
+       }
+       if len(t.Elems) != len(t2.Elems) {
+               return false
+       }
+       for i, e := range t.Elems {
+               e2 := t2.Elems[i]
+               // XXX(Spec) An anonymous and a non-anonymous field
+               // are neither identical nor compatible.
+               if e.Anonymous != e2.Anonymous ||
+                       (!e.Anonymous && e.Name != e2.Name) ||
+                       !e.Type.compat(e2.Type, conv) {
+                       return false
+               }
+       }
+       return true
+}
+
+func (t *StructType) lit() Type { return t }
+
+func (t *StructType) String() string {
+       s := "struct {"
+       for i, f := range t.Elems {
+               if i > 0 {
+                       s += "; "
+               }
+               if !f.Anonymous {
+                       s += f.Name + " "
+               }
+               s += f.Type.String()
+       }
+       return s + "}"
+}
+
+func (t *StructType) Zero() Value {
+       res := structV(make([]Value, len(t.Elems)))
+       for i, f := range t.Elems {
+               res[i] = f.Type.Zero()
+       }
+       return &res
+}
+
+/*
+ * Pointer
+ */
+
+type PtrType struct {
+       commonType
+       Elem Type
+}
+
+var ptrTypes = make(map[Type]*PtrType)
+
+// Two pointer types are identical if they have identical base types.
+
+func NewPtrType(elem Type) *PtrType {
+       t, ok := ptrTypes[elem]
+       if !ok {
+               t = &PtrType{commonType{}, elem}
+               ptrTypes[elem] = t
+       }
+       return t
+}
+
+func (t *PtrType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*PtrType)
+       if !ok {
+               return false
+       }
+       return t.Elem.compat(t2.Elem, conv)
+}
+
+func (t *PtrType) lit() Type { return t }
+
+func (t *PtrType) String() string { return "*" + t.Elem.String() }
+
+func (t *PtrType) Zero() Value { return &ptrV{nil} }
+
+/*
+ * Function
+ */
+
+type FuncType struct {
+       commonType
+       // TODO(austin) Separate receiver Type for methods?
+       In       []Type
+       Variadic bool
+       Out      []Type
+       builtin  string
+}
+
+var funcTypes = newTypeArrayMap()
+var variadicFuncTypes = newTypeArrayMap()
+
+// Create singleton function types for magic built-in functions
+var (
+       capType     = &FuncType{builtin: "cap"}
+       closeType   = &FuncType{builtin: "close"}
+       closedType  = &FuncType{builtin: "closed"}
+       lenType     = &FuncType{builtin: "len"}
+       makeType    = &FuncType{builtin: "make"}
+       newType     = &FuncType{builtin: "new"}
+       panicType   = &FuncType{builtin: "panic"}
+       printType   = &FuncType{builtin: "print"}
+       printlnType = &FuncType{builtin: "println"}
+       copyType    = &FuncType{builtin: "copy"}
+)
+
+// Two function types are identical if they have the same number of
+// parameters and result values and if corresponding parameter and
+// result types are identical. All "..." parameters have identical
+// type. Parameter and result names are not required to match.
+
+func NewFuncType(in []Type, variadic bool, out []Type) *FuncType {
+       inMap := funcTypes
+       if variadic {
+               inMap = variadicFuncTypes
+       }
+
+       outMapI := inMap.Get(in)
+       if outMapI == nil {
+               outMapI = inMap.Put(in, newTypeArrayMap())
+       }
+       outMap := outMapI.(typeArrayMap)
+
+       tI := outMap.Get(out)
+       if tI != nil {
+               return tI.(*FuncType)
+       }
+
+       t := &FuncType{commonType{}, in, variadic, out, ""}
+       outMap.Put(out, t)
+       return t
+}
+
+func (t *FuncType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*FuncType)
+       if !ok {
+               return false
+       }
+       if len(t.In) != len(t2.In) || t.Variadic != t2.Variadic || len(t.Out) != len(t2.Out) {
+               return false
+       }
+       for i := range t.In {
+               if !t.In[i].compat(t2.In[i], conv) {
+                       return false
+               }
+       }
+       for i := range t.Out {
+               if !t.Out[i].compat(t2.Out[i], conv) {
+                       return false
+               }
+       }
+       return true
+}
+
+func (t *FuncType) lit() Type { return t }
+
+func typeListString(ts []Type, ns []*ast.Ident) string {
+       s := ""
+       for i, t := range ts {
+               if i > 0 {
+                       s += ", "
+               }
+               if ns != nil && ns[i] != nil {
+                       s += ns[i].Name + " "
+               }
+               if t == nil {
+                       // Some places use nil types to represent errors
+                       s += "<none>"
+               } else {
+                       s += t.String()
+               }
+       }
+       return s
+}
+
+func (t *FuncType) String() string {
+       if t.builtin != "" {
+               return "built-in function " + t.builtin
+       }
+       args := typeListString(t.In, nil)
+       if t.Variadic {
+               if len(args) > 0 {
+                       args += ", "
+               }
+               args += "..."
+       }
+       s := "func(" + args + ")"
+       if len(t.Out) > 0 {
+               s += " (" + typeListString(t.Out, nil) + ")"
+       }
+       return s
+}
+
+func (t *FuncType) Zero() Value { return &funcV{nil} }
+
+type FuncDecl struct {
+       Type *FuncType
+       Name *ast.Ident // nil for function literals
+       // InNames will be one longer than Type.In if this function is
+       // variadic.
+       InNames  []*ast.Ident
+       OutNames []*ast.Ident
+}
+
+func (t *FuncDecl) String() string {
+       s := "func"
+       if t.Name != nil {
+               s += " " + t.Name.Name
+       }
+       s += funcTypeString(t.Type, t.InNames, t.OutNames)
+       return s
+}
+
+func funcTypeString(ft *FuncType, ins []*ast.Ident, outs []*ast.Ident) string {
+       s := "("
+       s += typeListString(ft.In, ins)
+       if ft.Variadic {
+               if len(ft.In) > 0 {
+                       s += ", "
+               }
+               s += "..."
+       }
+       s += ")"
+       if len(ft.Out) > 0 {
+               s += " (" + typeListString(ft.Out, outs) + ")"
+       }
+       return s
+}
+
+/*
+ * Interface
+ */
+
+// TODO(austin) Interface values, types, and type compilation are
+// implemented, but none of the type checking or semantics of
+// interfaces are.
+
+type InterfaceType struct {
+       commonType
+       // TODO(austin) This should be a map from names to
+       // *FuncType's.  We only need the sorted list for generating
+       // the type map key.  It's detrimental for everything else.
+       methods []IMethod
+}
+
+type IMethod struct {
+       Name string
+       Type *FuncType
+}
+
+var interfaceTypes = newTypeArrayMap()
+
+func NewInterfaceType(methods []IMethod, embeds []*InterfaceType) *InterfaceType {
+       // Count methods of embedded interfaces
+       nMethods := len(methods)
+       for _, e := range embeds {
+               nMethods += len(e.methods)
+       }
+
+       // Combine methods
+       allMethods := make([]IMethod, nMethods)
+       copy(allMethods, methods)
+       n := len(methods)
+       for _, e := range embeds {
+               for _, m := range e.methods {
+                       allMethods[n] = m
+                       n++
+               }
+       }
+
+       // Sort methods
+       sort.Sort(iMethodSorter(allMethods))
+
+       mts := make([]Type, len(allMethods))
+       for i, m := range methods {
+               mts[i] = m.Type
+       }
+       tMapI := interfaceTypes.Get(mts)
+       if tMapI == nil {
+               tMapI = interfaceTypes.Put(mts, make(map[string]*InterfaceType))
+       }
+       tMap := tMapI.(map[string]*InterfaceType)
+
+       key := ""
+       for _, m := range allMethods {
+               key += m.Name + " "
+       }
+
+       t, ok := tMap[key]
+       if !ok {
+               t = &InterfaceType{commonType{}, allMethods}
+               tMap[key] = t
+       }
+       return t
+}
+
+type iMethodSorter []IMethod
+
+func (s iMethodSorter) Less(a, b int) bool { return s[a].Name < s[b].Name }
+
+func (s iMethodSorter) Swap(a, b int) { s[a], s[b] = s[b], s[a] }
+
+func (s iMethodSorter) Len() int { return len(s) }
+
+func (t *InterfaceType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*InterfaceType)
+       if !ok {
+               return false
+       }
+       if len(t.methods) != len(t2.methods) {
+               return false
+       }
+       for i, e := range t.methods {
+               e2 := t2.methods[i]
+               if e.Name != e2.Name || !e.Type.compat(e2.Type, conv) {
+                       return false
+               }
+       }
+       return true
+}
+
+func (t *InterfaceType) lit() Type { return t }
+
+func (t *InterfaceType) String() string {
+       // TODO(austin) Instead of showing embedded interfaces, this
+       // shows their methods.
+       s := "interface {"
+       for i, m := range t.methods {
+               if i > 0 {
+                       s += "; "
+               }
+               s += m.Name + funcTypeString(m.Type, nil, nil)
+       }
+       return s + "}"
+}
+
+// implementedBy tests if o implements t, returning nil, true if it does.
+// Otherwise, it returns a method of t that o is missing and false.
+func (t *InterfaceType) implementedBy(o Type) (*IMethod, bool) {
+       if len(t.methods) == 0 {
+               return nil, true
+       }
+
+       // The methods of a named interface types are those of the
+       // underlying type.
+       if it, ok := o.lit().(*InterfaceType); ok {
+               o = it
+       }
+
+       // XXX(Spec) Interface types: "A type implements any interface
+       // comprising any subset of its methods" It's unclear if
+       // methods must have identical or compatible types.  6g
+       // requires identical types.
+
+       switch o := o.(type) {
+       case *NamedType:
+               for _, tm := range t.methods {
+                       sm, ok := o.methods[tm.Name]
+                       if !ok || sm.decl.Type != tm.Type {
+                               return &tm, false
+                       }
+               }
+               return nil, true
+
+       case *InterfaceType:
+               var ti, oi int
+               for ti < len(t.methods) && oi < len(o.methods) {
+                       tm, om := &t.methods[ti], &o.methods[oi]
+                       switch {
+                       case tm.Name == om.Name:
+                               if tm.Type != om.Type {
+                                       return tm, false
+                               }
+                               ti++
+                               oi++
+                       case tm.Name > om.Name:
+                               oi++
+                       default:
+                               return tm, false
+                       }
+               }
+               if ti < len(t.methods) {
+                       return &t.methods[ti], false
+               }
+               return nil, true
+       }
+
+       return &t.methods[0], false
+}
+
+func (t *InterfaceType) Zero() Value { return &interfaceV{} }
+
+/*
+ * Slice
+ */
+
+type SliceType struct {
+       commonType
+       Elem Type
+}
+
+var sliceTypes = make(map[Type]*SliceType)
+
+// Two slice types are identical if they have identical element types.
+
+func NewSliceType(elem Type) *SliceType {
+       t, ok := sliceTypes[elem]
+       if !ok {
+               t = &SliceType{commonType{}, elem}
+               sliceTypes[elem] = t
+       }
+       return t
+}
+
+func (t *SliceType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*SliceType)
+       if !ok {
+               return false
+       }
+       return t.Elem.compat(t2.Elem, conv)
+}
+
+func (t *SliceType) lit() Type { return t }
+
+func (t *SliceType) String() string { return "[]" + t.Elem.String() }
+
+func (t *SliceType) Zero() Value {
+       // The value of an uninitialized slice is nil. The length and
+       // capacity of a nil slice are 0.
+       return &sliceV{Slice{nil, 0, 0}}
+}
+
+/*
+ * Map type
+ */
+
+type MapType struct {
+       commonType
+       Key  Type
+       Elem Type
+}
+
+var mapTypes = make(map[Type]map[Type]*MapType)
+
+func NewMapType(key Type, elem Type) *MapType {
+       ts, ok := mapTypes[key]
+       if !ok {
+               ts = make(map[Type]*MapType)
+               mapTypes[key] = ts
+       }
+       t, ok := ts[elem]
+       if !ok {
+               t = &MapType{commonType{}, key, elem}
+               ts[elem] = t
+       }
+       return t
+}
+
+func (t *MapType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*MapType)
+       if !ok {
+               return false
+       }
+       return t.Elem.compat(t2.Elem, conv) && t.Key.compat(t2.Key, conv)
+}
+
+func (t *MapType) lit() Type { return t }
+
+func (t *MapType) String() string { return "map[" + t.Key.String() + "] " + t.Elem.String() }
+
+func (t *MapType) Zero() Value {
+       // The value of an uninitialized map is nil.
+       return &mapV{nil}
+}
+
+/*
+type ChanType struct {
+       // TODO(austin)
+}
+*/
+
+/*
+ * Named types
+ */
+
+type Method struct {
+       decl *FuncDecl
+       fn   Func
+}
+
+type NamedType struct {
+       token.Position
+       Name string
+       // Underlying type.  If incomplete is true, this will be nil.
+       // If incomplete is false and this is still nil, then this is
+       // a placeholder type representing an error.
+       Def Type
+       // True while this type is being defined.
+       incomplete bool
+       methods    map[string]Method
+}
+
+// TODO(austin) This is temporarily needed by the debugger's remote
+// type parser.  This should only be possible with block.DefineType.
+func NewNamedType(name string) *NamedType {
+       return &NamedType{token.Position{}, name, nil, true, make(map[string]Method)}
+}
+
+func (t *NamedType) Complete(def Type) {
+       if !t.incomplete {
+               log.Panicf("cannot complete already completed NamedType %+v", *t)
+       }
+       // We strip the name from def because multiple levels of
+       // naming are useless.
+       if ndef, ok := def.(*NamedType); ok {
+               def = ndef.Def
+       }
+       t.Def = def
+       t.incomplete = false
+}
+
+func (t *NamedType) compat(o Type, conv bool) bool {
+       t2, ok := o.(*NamedType)
+       if ok {
+               if conv {
+                       // Two named types are conversion compatible
+                       // if their literals are conversion
+                       // compatible.
+                       return t.Def.compat(t2.Def, conv)
+               } else {
+                       // Two named types are compatible if their
+                       // type names originate in the same type
+                       // declaration.
+                       return t == t2
+               }
+       }
+       // A named and an unnamed type are compatible if the
+       // respective type literals are compatible.
+       return o.compat(t.Def, conv)
+}
+
+func (t *NamedType) lit() Type { return t.Def.lit() }
+
+func (t *NamedType) isBoolean() bool { return t.Def.isBoolean() }
+
+func (t *NamedType) isInteger() bool { return t.Def.isInteger() }
+
+func (t *NamedType) isFloat() bool { return t.Def.isFloat() }
+
+func (t *NamedType) isIdeal() bool { return false }
+
+func (t *NamedType) String() string { return t.Name }
+
+func (t *NamedType) Zero() Value { return t.Def.Zero() }
+
+/*
+ * Multi-valued type
+ */
+
+// MultiType is a special type used for multi-valued expressions, akin
+// to a tuple type.  It's not generally accessible within the
+// language.
+type MultiType struct {
+       commonType
+       Elems []Type
+}
+
+var multiTypes = newTypeArrayMap()
+
+func NewMultiType(elems []Type) *MultiType {
+       if t := multiTypes.Get(elems); t != nil {
+               return t.(*MultiType)
+       }
+
+       t := &MultiType{commonType{}, elems}
+       multiTypes.Put(elems, t)
+       return t
+}
+
+func (t *MultiType) compat(o Type, conv bool) bool {
+       t2, ok := o.lit().(*MultiType)
+       if !ok {
+               return false
+       }
+       if len(t.Elems) != len(t2.Elems) {
+               return false
+       }
+       for i := range t.Elems {
+               if !t.Elems[i].compat(t2.Elems[i], conv) {
+                       return false
+               }
+       }
+       return true
+}
+
+var EmptyType Type = NewMultiType([]Type{})
+
+func (t *MultiType) lit() Type { return t }
+
+func (t *MultiType) String() string {
+       if len(t.Elems) == 0 {
+               return "<none>"
+       }
+       return typeListString(t.Elems, nil)
+}
+
+func (t *MultiType) Zero() Value {
+       res := make([]Value, len(t.Elems))
+       for i, t := range t.Elems {
+               res[i] = t.Zero()
+       }
+       return multiV(res)
+}
+
+/*
+ * Initialize the universe
+ */
+
+func init() {
+       numer := big.NewInt(0xffffff)
+       numer.Lsh(numer, 127-23)
+       maxFloat32Val = new(big.Rat).SetInt(numer)
+       numer.SetInt64(0x1fffffffffffff)
+       numer.Lsh(numer, 1023-52)
+       maxFloat64Val = new(big.Rat).SetInt(numer)
+       minFloat32Val = new(big.Rat).Neg(maxFloat32Val)
+       minFloat64Val = new(big.Rat).Neg(maxFloat64Val)
+
+       // To avoid portability issues all numeric types are distinct
+       // except byte, which is an alias for uint8.
+
+       // Make byte an alias for the named type uint8.  Type aliases
+       // are otherwise impossible in Go, so just hack it here.
+       universe.defs["byte"] = universe.defs["uint8"]
+
+       // Built-in functions
+       universe.DefineConst("cap", universePos, capType, nil)
+       universe.DefineConst("close", universePos, closeType, nil)
+       universe.DefineConst("closed", universePos, closedType, nil)
+       universe.DefineConst("copy", universePos, copyType, nil)
+       universe.DefineConst("len", universePos, lenType, nil)
+       universe.DefineConst("make", universePos, makeType, nil)
+       universe.DefineConst("new", universePos, newType, nil)
+       universe.DefineConst("panic", universePos, panicType, nil)
+       universe.DefineConst("print", universePos, printType, nil)
+       universe.DefineConst("println", universePos, printlnType, nil)
+}
diff --git a/libgo/go/exp/eval/typec.go b/libgo/go/exp/eval/typec.go
new file mode 100644 (file)
index 0000000..7ee323e
--- /dev/null
@@ -0,0 +1,409 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "go/ast"
+       "go/token"
+       "log"
+)
+
+
+/*
+ * Type compiler
+ */
+
+type typeCompiler struct {
+       *compiler
+       block *block
+       // Check to be performed after a type declaration is compiled.
+       //
+       // TODO(austin) This will probably have to change after we
+       // eliminate forward declarations.
+       lateCheck func() bool
+}
+
+func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
+       _, _, def := a.block.Lookup(x.Name)
+       if def == nil {
+               a.diagAt(x, "%s: undefined", x.Name)
+               return nil
+       }
+       switch def := def.(type) {
+       case *Constant:
+               a.diagAt(x, "constant %v used as type", x.Name)
+               return nil
+       case *Variable:
+               a.diagAt(x, "variable %v used as type", x.Name)
+               return nil
+       case *NamedType:
+               if !allowRec && def.incomplete {
+                       a.diagAt(x, "illegal recursive type")
+                       return nil
+               }
+               if !def.incomplete && def.Def == nil {
+                       // Placeholder type from an earlier error
+                       return nil
+               }
+               return def
+       case Type:
+               return def
+       }
+       log.Panicf("name %s has unknown type %T", x.Name, def)
+       return nil
+}
+
+func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
+       // Compile element type
+       elem := a.compileType(x.Elt, allowRec)
+
+       // Compile length expression
+       if x.Len == nil {
+               if elem == nil {
+                       return nil
+               }
+               return NewSliceType(elem)
+       }
+
+       if _, ok := x.Len.(*ast.Ellipsis); ok {
+               a.diagAt(x.Len, "... array initailizers not implemented")
+               return nil
+       }
+       l, ok := a.compileArrayLen(a.block, x.Len)
+       if !ok {
+               return nil
+       }
+       if l < 0 {
+               a.diagAt(x.Len, "array length must be non-negative")
+               return nil
+       }
+       if elem == nil {
+               return nil
+       }
+
+       return NewArrayType(l, elem)
+}
+
+func (a *typeCompiler) compileFields(fields *ast.FieldList, allowRec bool) ([]Type, []*ast.Ident, []token.Position, bool) {
+       n := fields.NumFields()
+       ts := make([]Type, n)
+       ns := make([]*ast.Ident, n)
+       ps := make([]token.Position, n)
+       bad := false
+
+       if fields != nil {
+               i := 0
+               for _, f := range fields.List {
+                       t := a.compileType(f.Type, allowRec)
+                       if t == nil {
+                               bad = true
+                       }
+                       if f.Names == nil {
+                               ns[i] = nil
+                               ts[i] = t
+                               ps[i] = f.Type.Pos()
+                               i++
+                               continue
+                       }
+                       for _, n := range f.Names {
+                               ns[i] = n
+                               ts[i] = t
+                               ps[i] = n.Pos()
+                               i++
+                       }
+               }
+       }
+
+       return ts, ns, ps, bad
+}
+
+func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type {
+       ts, names, poss, bad := a.compileFields(x.Fields, allowRec)
+
+       // XXX(Spec) The spec claims that field identifiers must be
+       // unique, but 6g only checks this when they are accessed.  I
+       // think the spec is better in this regard: if I write two
+       // fields with the same name in the same struct type, clearly
+       // that's a mistake.  This definition does *not* descend into
+       // anonymous fields, so it doesn't matter if those change.
+       // There's separate language in the spec about checking
+       // uniqueness of field names inherited from anonymous fields
+       // at use time.
+       fields := make([]StructField, len(ts))
+       nameSet := make(map[string]token.Position, len(ts))
+       for i := range fields {
+               // Compute field name and check anonymous fields
+               var name string
+               if names[i] != nil {
+                       name = names[i].Name
+               } else {
+                       if ts[i] == nil {
+                               continue
+                       }
+
+                       var nt *NamedType
+                       // [For anonymous fields,] the unqualified
+                       // type name acts as the field identifier.
+                       switch t := ts[i].(type) {
+                       case *NamedType:
+                               name = t.Name
+                               nt = t
+                       case *PtrType:
+                               switch t := t.Elem.(type) {
+                               case *NamedType:
+                                       name = t.Name
+                                       nt = t
+                               }
+                       }
+                       // [An anonymous field] must be specified as a
+                       // type name T or as a pointer to a type name
+                       // *T, and T itself, may not be a pointer or
+                       // interface type.
+                       if nt == nil {
+                               a.diagAt(&poss[i], "embedded type must T or *T, where T is a named type")
+                               bad = true
+                               continue
+                       }
+                       // The check for embedded pointer types must
+                       // be deferred because of things like
+                       //  type T *struct { T }
+                       lateCheck := a.lateCheck
+                       a.lateCheck = func() bool {
+                               if _, ok := nt.lit().(*PtrType); ok {
+                                       a.diagAt(&poss[i], "embedded type %v is a pointer type", nt)
+                                       return false
+                               }
+                               return lateCheck()
+                       }
+               }
+
+               // Check name uniqueness
+               if prev, ok := nameSet[name]; ok {
+                       a.diagAt(&poss[i], "field %s redeclared\n\tprevious declaration at %s", name, &prev)
+                       bad = true
+                       continue
+               }
+               nameSet[name] = poss[i]
+
+               // Create field
+               fields[i].Name = name
+               fields[i].Type = ts[i]
+               fields[i].Anonymous = (names[i] == nil)
+       }
+
+       if bad {
+               return nil
+       }
+
+       return NewStructType(fields)
+}
+
+func (a *typeCompiler) compilePtrType(x *ast.StarExpr) Type {
+       elem := a.compileType(x.X, true)
+       if elem == nil {
+               return nil
+       }
+       return NewPtrType(elem)
+}
+
+func (a *typeCompiler) compileFuncType(x *ast.FuncType, allowRec bool) *FuncDecl {
+       // TODO(austin) Variadic function types
+
+       // The types of parameters and results must be complete.
+       //
+       // TODO(austin) It's not clear they actually have to be complete.
+       in, inNames, _, inBad := a.compileFields(x.Params, allowRec)
+       out, outNames, _, outBad := a.compileFields(x.Results, allowRec)
+
+       if inBad || outBad {
+               return nil
+       }
+       return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames}
+}
+
+func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool) *InterfaceType {
+       ts, names, poss, bad := a.compileFields(x.Methods, allowRec)
+
+       methods := make([]IMethod, len(ts))
+       nameSet := make(map[string]token.Position, len(ts))
+       embeds := make([]*InterfaceType, len(ts))
+
+       var nm, ne int
+       for i := range ts {
+               if ts[i] == nil {
+                       continue
+               }
+
+               if names[i] != nil {
+                       name := names[i].Name
+                       methods[nm].Name = name
+                       methods[nm].Type = ts[i].(*FuncType)
+                       nm++
+                       if prev, ok := nameSet[name]; ok {
+                               a.diagAt(&poss[i], "method %s redeclared\n\tprevious declaration at %s", name, &prev)
+                               bad = true
+                               continue
+                       }
+                       nameSet[name] = poss[i]
+               } else {
+                       // Embedded interface
+                       it, ok := ts[i].lit().(*InterfaceType)
+                       if !ok {
+                               a.diagAt(&poss[i], "embedded type must be an interface")
+                               bad = true
+                               continue
+                       }
+                       embeds[ne] = it
+                       ne++
+                       for _, m := range it.methods {
+                               if prev, ok := nameSet[m.Name]; ok {
+                                       a.diagAt(&poss[i], "method %s redeclared\n\tprevious declaration at %s", m.Name, &prev)
+                                       bad = true
+                                       continue
+                               }
+                               nameSet[m.Name] = poss[i]
+                       }
+               }
+       }
+
+       if bad {
+               return nil
+       }
+
+       methods = methods[0:nm]
+       embeds = embeds[0:ne]
+
+       return NewInterfaceType(methods, embeds)
+}
+
+func (a *typeCompiler) compileMapType(x *ast.MapType) Type {
+       key := a.compileType(x.Key, true)
+       val := a.compileType(x.Value, true)
+       if key == nil || val == nil {
+               return nil
+       }
+       // XXX(Spec) The Map types section explicitly lists all types
+       // that can be map keys except for function types.
+       switch key.lit().(type) {
+       case *StructType:
+               a.diagAt(x, "map key cannot be a struct type")
+               return nil
+       case *ArrayType:
+               a.diagAt(x, "map key cannot be an array type")
+               return nil
+       case *SliceType:
+               a.diagAt(x, "map key cannot be a slice type")
+               return nil
+       }
+       return NewMapType(key, val)
+}
+
+func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type {
+       switch x := x.(type) {
+       case *ast.BadExpr:
+               // Error already reported by parser
+               a.silentErrors++
+               return nil
+
+       case *ast.Ident:
+               return a.compileIdent(x, allowRec)
+
+       case *ast.ArrayType:
+               return a.compileArrayType(x, allowRec)
+
+       case *ast.StructType:
+               return a.compileStructType(x, allowRec)
+
+       case *ast.StarExpr:
+               return a.compilePtrType(x)
+
+       case *ast.FuncType:
+               fd := a.compileFuncType(x, allowRec)
+               if fd == nil {
+                       return nil
+               }
+               return fd.Type
+
+       case *ast.InterfaceType:
+               return a.compileInterfaceType(x, allowRec)
+
+       case *ast.MapType:
+               return a.compileMapType(x)
+
+       case *ast.ChanType:
+               goto notimpl
+
+       case *ast.ParenExpr:
+               return a.compileType(x.X, allowRec)
+
+       case *ast.Ellipsis:
+               a.diagAt(x, "illegal use of ellipsis")
+               return nil
+       }
+       a.diagAt(x, "expression used as type")
+       return nil
+
+notimpl:
+       a.diagAt(x, "compileType: %T not implemented", x)
+       return nil
+}
+
+/*
+ * Type compiler interface
+ */
+
+func noLateCheck() bool { return true }
+
+func (a *compiler) compileType(b *block, typ ast.Expr) Type {
+       tc := &typeCompiler{a, b, noLateCheck}
+       t := tc.compileType(typ, false)
+       if !tc.lateCheck() {
+               t = nil
+       }
+       return t
+}
+
+func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool {
+       ok := true
+       for _, spec := range decl.Specs {
+               spec := spec.(*ast.TypeSpec)
+               // Create incomplete type for this type
+               nt := b.DefineType(spec.Name.Name, spec.Name.Pos(), nil)
+               if nt != nil {
+                       nt.(*NamedType).incomplete = true
+               }
+               // Compile type
+               tc := &typeCompiler{a, b, noLateCheck}
+               t := tc.compileType(spec.Type, false)
+               if t == nil {
+                       // Create a placeholder type
+                       ok = false
+               }
+               // Fill incomplete type
+               if nt != nil {
+                       nt.(*NamedType).Complete(t)
+               }
+               // Perform late type checking with complete type
+               if !tc.lateCheck() {
+                       ok = false
+                       if nt != nil {
+                               // Make the type a placeholder
+                               nt.(*NamedType).Def = nil
+                       }
+               }
+       }
+       return ok
+}
+
+func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
+       tc := &typeCompiler{a, b, noLateCheck}
+       res := tc.compileFuncType(typ, false)
+       if res != nil {
+               if !tc.lateCheck() {
+                       res = nil
+               }
+       }
+       return res
+}
diff --git a/libgo/go/exp/eval/value.go b/libgo/go/exp/eval/value.go
new file mode 100644 (file)
index 0000000..cace2fd
--- /dev/null
@@ -0,0 +1,596 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package eval
+
+import (
+       "big"
+       "fmt"
+)
+
+type Value interface {
+       String() string
+       // Assign copies another value into this one.  It should
+       // assume that the other value satisfies the same specific
+       // value interface (BoolValue, etc.), but must not assume
+       // anything about its specific type.
+       Assign(t *Thread, o Value)
+}
+
+type BoolValue interface {
+       Value
+       Get(*Thread) bool
+       Set(*Thread, bool)
+}
+
+type UintValue interface {
+       Value
+       Get(*Thread) uint64
+       Set(*Thread, uint64)
+}
+
+type IntValue interface {
+       Value
+       Get(*Thread) int64
+       Set(*Thread, int64)
+}
+
+// TODO(austin) IdealIntValue and IdealFloatValue should not exist
+// because ideals are not l-values.
+type IdealIntValue interface {
+       Value
+       Get() *big.Int
+}
+
+type FloatValue interface {
+       Value
+       Get(*Thread) float64
+       Set(*Thread, float64)
+}
+
+type IdealFloatValue interface {
+       Value
+       Get() *big.Rat
+}
+
+type StringValue interface {
+       Value
+       Get(*Thread) string
+       Set(*Thread, string)
+}
+
+type ArrayValue interface {
+       Value
+       // TODO(austin) Get() is here for uniformity, but is
+       // completely useless.  If a lot of other types have similarly
+       // useless Get methods, just special-case these uses.
+       Get(*Thread) ArrayValue
+       Elem(*Thread, int64) Value
+       // Sub returns an ArrayValue backed by the same array that
+       // starts from element i and has length len.
+       Sub(i int64, len int64) ArrayValue
+}
+
+type StructValue interface {
+       Value
+       // TODO(austin) This is another useless Get()
+       Get(*Thread) StructValue
+       Field(*Thread, int) Value
+}
+
+type PtrValue interface {
+       Value
+       Get(*Thread) Value
+       Set(*Thread, Value)
+}
+
+type Func interface {
+       NewFrame() *Frame
+       Call(*Thread)
+}
+
+type FuncValue interface {
+       Value
+       Get(*Thread) Func
+       Set(*Thread, Func)
+}
+
+type Interface struct {
+       Type  Type
+       Value Value
+}
+
+type InterfaceValue interface {
+       Value
+       Get(*Thread) Interface
+       Set(*Thread, Interface)
+}
+
+type Slice struct {
+       Base     ArrayValue
+       Len, Cap int64
+}
+
+type SliceValue interface {
+       Value
+       Get(*Thread) Slice
+       Set(*Thread, Slice)
+}
+
+type Map interface {
+       Len(*Thread) int64
+       // Retrieve an element from the map, returning nil if it does
+       // not exist.
+       Elem(t *Thread, key interface{}) Value
+       // Set an entry in the map.  If val is nil, delete the entry.
+       SetElem(t *Thread, key interface{}, val Value)
+       // TODO(austin)  Perhaps there should be an iterator interface instead.
+       Iter(func(key interface{}, val Value) bool)
+}
+
+type MapValue interface {
+       Value
+       Get(*Thread) Map
+       Set(*Thread, Map)
+}
+
+/*
+ * Bool
+ */
+
+type boolV bool
+
+func (v *boolV) String() string { return fmt.Sprint(*v) }
+
+func (v *boolV) Assign(t *Thread, o Value) { *v = boolV(o.(BoolValue).Get(t)) }
+
+func (v *boolV) Get(*Thread) bool { return bool(*v) }
+
+func (v *boolV) Set(t *Thread, x bool) { *v = boolV(x) }
+
+/*
+ * Uint
+ */
+
+type uint8V uint8
+
+func (v *uint8V) String() string { return fmt.Sprint(*v) }
+
+func (v *uint8V) Assign(t *Thread, o Value) { *v = uint8V(o.(UintValue).Get(t)) }
+
+func (v *uint8V) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uint8V) Set(t *Thread, x uint64) { *v = uint8V(x) }
+
+type uint16V uint16
+
+func (v *uint16V) String() string { return fmt.Sprint(*v) }
+
+func (v *uint16V) Assign(t *Thread, o Value) { *v = uint16V(o.(UintValue).Get(t)) }
+
+func (v *uint16V) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uint16V) Set(t *Thread, x uint64) { *v = uint16V(x) }
+
+type uint32V uint32
+
+func (v *uint32V) String() string { return fmt.Sprint(*v) }
+
+func (v *uint32V) Assign(t *Thread, o Value) { *v = uint32V(o.(UintValue).Get(t)) }
+
+func (v *uint32V) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uint32V) Set(t *Thread, x uint64) { *v = uint32V(x) }
+
+type uint64V uint64
+
+func (v *uint64V) String() string { return fmt.Sprint(*v) }
+
+func (v *uint64V) Assign(t *Thread, o Value) { *v = uint64V(o.(UintValue).Get(t)) }
+
+func (v *uint64V) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uint64V) Set(t *Thread, x uint64) { *v = uint64V(x) }
+
+type uintV uint
+
+func (v *uintV) String() string { return fmt.Sprint(*v) }
+
+func (v *uintV) Assign(t *Thread, o Value) { *v = uintV(o.(UintValue).Get(t)) }
+
+func (v *uintV) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uintV) Set(t *Thread, x uint64) { *v = uintV(x) }
+
+type uintptrV uintptr
+
+func (v *uintptrV) String() string { return fmt.Sprint(*v) }
+
+func (v *uintptrV) Assign(t *Thread, o Value) { *v = uintptrV(o.(UintValue).Get(t)) }
+
+func (v *uintptrV) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uintptrV) Set(t *Thread, x uint64) { *v = uintptrV(x) }
+
+/*
+ * Int
+ */
+
+type int8V int8
+
+func (v *int8V) String() string { return fmt.Sprint(*v) }
+
+func (v *int8V) Assign(t *Thread, o Value) { *v = int8V(o.(IntValue).Get(t)) }
+
+func (v *int8V) Get(*Thread) int64 { return int64(*v) }
+
+func (v *int8V) Set(t *Thread, x int64) { *v = int8V(x) }
+
+type int16V int16
+
+func (v *int16V) String() string { return fmt.Sprint(*v) }
+
+func (v *int16V) Assign(t *Thread, o Value) { *v = int16V(o.(IntValue).Get(t)) }
+
+func (v *int16V) Get(*Thread) int64 { return int64(*v) }
+
+func (v *int16V) Set(t *Thread, x int64) { *v = int16V(x) }
+
+type int32V int32
+
+func (v *int32V) String() string { return fmt.Sprint(*v) }
+
+func (v *int32V) Assign(t *Thread, o Value) { *v = int32V(o.(IntValue).Get(t)) }
+
+func (v *int32V) Get(*Thread) int64 { return int64(*v) }
+
+func (v *int32V) Set(t *Thread, x int64) { *v = int32V(x) }
+
+type int64V int64
+
+func (v *int64V) String() string { return fmt.Sprint(*v) }
+
+func (v *int64V) Assign(t *Thread, o Value) { *v = int64V(o.(IntValue).Get(t)) }
+
+func (v *int64V) Get(*Thread) int64 { return int64(*v) }
+
+func (v *int64V) Set(t *Thread, x int64) { *v = int64V(x) }
+
+type intV int
+
+func (v *intV) String() string { return fmt.Sprint(*v) }
+
+func (v *intV) Assign(t *Thread, o Value) { *v = intV(o.(IntValue).Get(t)) }
+
+func (v *intV) Get(*Thread) int64 { return int64(*v) }
+
+func (v *intV) Set(t *Thread, x int64) { *v = intV(x) }
+
+/*
+ * Ideal int
+ */
+
+type idealIntV struct {
+       V *big.Int
+}
+
+func (v *idealIntV) String() string { return v.V.String() }
+
+func (v *idealIntV) Assign(t *Thread, o Value) {
+       v.V = o.(IdealIntValue).Get()
+}
+
+func (v *idealIntV) Get() *big.Int { return v.V }
+
+/*
+ * Float
+ */
+
+type float32V float32
+
+func (v *float32V) String() string { return fmt.Sprint(*v) }
+
+func (v *float32V) Assign(t *Thread, o Value) { *v = float32V(o.(FloatValue).Get(t)) }
+
+func (v *float32V) Get(*Thread) float64 { return float64(*v) }
+
+func (v *float32V) Set(t *Thread, x float64) { *v = float32V(x) }
+
+type float64V float64
+
+func (v *float64V) String() string { return fmt.Sprint(*v) }
+
+func (v *float64V) Assign(t *Thread, o Value) { *v = float64V(o.(FloatValue).Get(t)) }
+
+func (v *float64V) Get(*Thread) float64 { return float64(*v) }
+
+func (v *float64V) Set(t *Thread, x float64) { *v = float64V(x) }
+
+type floatV float
+
+func (v *floatV) String() string { return fmt.Sprint(*v) }
+
+func (v *floatV) Assign(t *Thread, o Value) { *v = floatV(o.(FloatValue).Get(t)) }
+
+func (v *floatV) Get(*Thread) float64 { return float64(*v) }
+
+func (v *floatV) Set(t *Thread, x float64) { *v = floatV(x) }
+
+/*
+ * Ideal float
+ */
+
+type idealFloatV struct {
+       V *big.Rat
+}
+
+func (v *idealFloatV) String() string { return v.V.FloatString(6) }
+
+func (v *idealFloatV) Assign(t *Thread, o Value) {
+       v.V = o.(IdealFloatValue).Get()
+}
+
+func (v *idealFloatV) Get() *big.Rat { return v.V }
+
+/*
+ * String
+ */
+
+type stringV string
+
+func (v *stringV) String() string { return fmt.Sprint(*v) }
+
+func (v *stringV) Assign(t *Thread, o Value) { *v = stringV(o.(StringValue).Get(t)) }
+
+func (v *stringV) Get(*Thread) string { return string(*v) }
+
+func (v *stringV) Set(t *Thread, x string) { *v = stringV(x) }
+
+/*
+ * Array
+ */
+
+type arrayV []Value
+
+func (v *arrayV) String() string {
+       res := "{"
+       for i, e := range *v {
+               if i > 0 {
+                       res += ", "
+               }
+               res += e.String()
+       }
+       return res + "}"
+}
+
+func (v *arrayV) Assign(t *Thread, o Value) {
+       oa := o.(ArrayValue)
+       l := int64(len(*v))
+       for i := int64(0); i < l; i++ {
+               (*v)[i].Assign(t, oa.Elem(t, i))
+       }
+}
+
+func (v *arrayV) Get(*Thread) ArrayValue { return v }
+
+func (v *arrayV) Elem(t *Thread, i int64) Value {
+       return (*v)[i]
+}
+
+func (v *arrayV) Sub(i int64, len int64) ArrayValue {
+       res := (*v)[i : i+len]
+       return &res
+}
+
+/*
+ * Struct
+ */
+
+type structV []Value
+
+// TODO(austin) Should these methods (and arrayV's) be on structV
+// instead of *structV?
+func (v *structV) String() string {
+       res := "{"
+       for i, v := range *v {
+               if i > 0 {
+                       res += ", "
+               }
+               res += v.String()
+       }
+       return res + "}"
+}
+
+func (v *structV) Assign(t *Thread, o Value) {
+       oa := o.(StructValue)
+       l := len(*v)
+       for i := 0; i < l; i++ {
+               (*v)[i].Assign(t, oa.Field(t, i))
+       }
+}
+
+func (v *structV) Get(*Thread) StructValue { return v }
+
+func (v *structV) Field(t *Thread, i int) Value {
+       return (*v)[i]
+}
+
+/*
+ * Pointer
+ */
+
+type ptrV struct {
+       // nil if the pointer is nil
+       target Value
+}
+
+func (v *ptrV) String() string {
+       if v.target == nil {
+               return "<nil>"
+       }
+       return "&" + v.target.String()
+}
+
+func (v *ptrV) Assign(t *Thread, o Value) { v.target = o.(PtrValue).Get(t) }
+
+func (v *ptrV) Get(*Thread) Value { return v.target }
+
+func (v *ptrV) Set(t *Thread, x Value) { v.target = x }
+
+/*
+ * Functions
+ */
+
+type funcV struct {
+       target Func
+}
+
+func (v *funcV) String() string {
+       // TODO(austin) Rob wants to see the definition
+       return "func {...}"
+}
+
+func (v *funcV) Assign(t *Thread, o Value) { v.target = o.(FuncValue).Get(t) }
+
+func (v *funcV) Get(*Thread) Func { return v.target }
+
+func (v *funcV) Set(t *Thread, x Func) { v.target = x }
+
+/*
+ * Interfaces
+ */
+
+type interfaceV struct {
+       Interface
+}
+
+func (v *interfaceV) String() string {
+       if v.Type == nil || v.Value == nil {
+               return "<nil>"
+       }
+       return v.Value.String()
+}
+
+func (v *interfaceV) Assign(t *Thread, o Value) {
+       v.Interface = o.(InterfaceValue).Get(t)
+}
+
+func (v *interfaceV) Get(*Thread) Interface { return v.Interface }
+
+func (v *interfaceV) Set(t *Thread, x Interface) {
+       v.Interface = x
+}
+
+/*
+ * Slices
+ */
+
+type sliceV struct {
+       Slice
+}
+
+func (v *sliceV) String() string {
+       if v.Base == nil {
+               return "<nil>"
+       }
+       return v.Base.Sub(0, v.Len).String()
+}
+
+func (v *sliceV) Assign(t *Thread, o Value) { v.Slice = o.(SliceValue).Get(t) }
+
+func (v *sliceV) Get(*Thread) Slice { return v.Slice }
+
+func (v *sliceV) Set(t *Thread, x Slice) { v.Slice = x }
+
+/*
+ * Maps
+ */
+
+type mapV struct {
+       target Map
+}
+
+func (v *mapV) String() string {
+       if v.target == nil {
+               return "<nil>"
+       }
+       res := "map["
+       i := 0
+       v.target.Iter(func(key interface{}, val Value) bool {
+               if i > 0 {
+                       res += ", "
+               }
+               i++
+               res += fmt.Sprint(key) + ":" + val.String()
+               return true
+       })
+       return res + "]"
+}
+
+func (v *mapV) Assign(t *Thread, o Value) { v.target = o.(MapValue).Get(t) }
+
+func (v *mapV) Get(*Thread) Map { return v.target }
+
+func (v *mapV) Set(t *Thread, x Map) { v.target = x }
+
+type evalMap map[interface{}]Value
+
+func (m evalMap) Len(t *Thread) int64 { return int64(len(m)) }
+
+func (m evalMap) Elem(t *Thread, key interface{}) Value {
+       return m[key]
+}
+
+func (m evalMap) SetElem(t *Thread, key interface{}, val Value) {
+       if val == nil {
+               m[key] = nil, false
+       } else {
+               m[key] = val
+       }
+}
+
+func (m evalMap) Iter(cb func(key interface{}, val Value) bool) {
+       for k, v := range m {
+               if !cb(k, v) {
+                       break
+               }
+       }
+}
+
+/*
+ * Multi-values
+ */
+
+type multiV []Value
+
+func (v multiV) String() string {
+       res := "("
+       for i, v := range v {
+               if i > 0 {
+                       res += ", "
+               }
+               res += v.String()
+       }
+       return res + ")"
+}
+
+func (v multiV) Assign(t *Thread, o Value) {
+       omv := o.(multiV)
+       for i := range v {
+               v[i].Assign(t, omv[i])
+       }
+}
+
+/*
+ * Universal constants
+ */
+
+func init() {
+       s := universe
+
+       true := boolV(true)
+       s.DefineConst("true", universePos, BoolType, &true)
+       false := boolV(false)
+       s.DefineConst("false", universePos, BoolType, &false)
+}
diff --git a/libgo/go/exp/eval/world.go b/libgo/go/exp/eval/world.go
new file mode 100644 (file)
index 0000000..f55051c
--- /dev/null
@@ -0,0 +1,185 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package is the beginning of an interpreter for Go.
+// It can run simple Go programs but does not implement
+// interface values or packages.
+package eval
+
+import (
+       "go/ast"
+       "go/parser"
+       "go/scanner"
+       "go/token"
+       "os"
+)
+
+type World struct {
+       scope *Scope
+       frame *Frame
+}
+
+func NewWorld() *World {
+       w := new(World)
+       w.scope = universe.ChildScope()
+       w.scope.global = true // this block's vars allocate directly
+       return w
+}
+
+type Code interface {
+       // The type of the value Run returns, or nil if Run returns nil.
+       Type() Type
+
+       // Run runs the code; if the code is a single expression
+       // with a value, it returns the value; otherwise it returns nil.
+       Run() (Value, os.Error)
+}
+
+type stmtCode struct {
+       w    *World
+       code code
+}
+
+func (w *World) CompileStmtList(stmts []ast.Stmt) (Code, os.Error) {
+       if len(stmts) == 1 {
+               if s, ok := stmts[0].(*ast.ExprStmt); ok {
+                       return w.CompileExpr(s.X)
+               }
+       }
+       errors := new(scanner.ErrorVector)
+       cc := &compiler{errors, 0, 0}
+       cb := newCodeBuf()
+       fc := &funcCompiler{
+               compiler:     cc,
+               fnType:       nil,
+               outVarsNamed: false,
+               codeBuf:      cb,
+               flow:         newFlowBuf(cb),
+               labels:       make(map[string]*label),
+       }
+       bc := &blockCompiler{
+               funcCompiler: fc,
+               block:        w.scope.block,
+       }
+       nerr := cc.numError()
+       for _, stmt := range stmts {
+               bc.compileStmt(stmt)
+       }
+       fc.checkLabels()
+       if nerr != cc.numError() {
+               return nil, errors.GetError(scanner.Sorted)
+       }
+       return &stmtCode{w, fc.get()}, nil
+}
+
+func (w *World) CompileDeclList(decls []ast.Decl) (Code, os.Error) {
+       stmts := make([]ast.Stmt, len(decls))
+       for i, d := range decls {
+               stmts[i] = &ast.DeclStmt{d}
+       }
+       return w.CompileStmtList(stmts)
+}
+
+func (s *stmtCode) Type() Type { return nil }
+
+func (s *stmtCode) Run() (Value, os.Error) {
+       t := new(Thread)
+       t.f = s.w.scope.NewFrame(nil)
+       return nil, t.Try(func(t *Thread) { s.code.exec(t) })
+}
+
+type exprCode struct {
+       w    *World
+       e    *expr
+       eval func(Value, *Thread)
+}
+
+func (w *World) CompileExpr(e ast.Expr) (Code, os.Error) {
+       errors := new(scanner.ErrorVector)
+       cc := &compiler{errors, 0, 0}
+
+       ec := cc.compileExpr(w.scope.block, false, e)
+       if ec == nil {
+               return nil, errors.GetError(scanner.Sorted)
+       }
+       var eval func(Value, *Thread)
+       switch t := ec.t.(type) {
+       case *idealIntType:
+               // nothing
+       case *idealFloatType:
+               // nothing
+       default:
+               if tm, ok := t.(*MultiType); ok && len(tm.Elems) == 0 {
+                       return &stmtCode{w, code{ec.exec}}, nil
+               }
+               eval = genAssign(ec.t, ec)
+       }
+       return &exprCode{w, ec, eval}, nil
+}
+
+func (e *exprCode) Type() Type { return e.e.t }
+
+func (e *exprCode) Run() (Value, os.Error) {
+       t := new(Thread)
+       t.f = e.w.scope.NewFrame(nil)
+       switch e.e.t.(type) {
+       case *idealIntType:
+               return &idealIntV{e.e.asIdealInt()()}, nil
+       case *idealFloatType:
+               return &idealFloatV{e.e.asIdealFloat()()}, nil
+       }
+       v := e.e.t.Zero()
+       eval := e.eval
+       err := t.Try(func(t *Thread) { eval(v, t) })
+       return v, err
+}
+
+func (w *World) Compile(text string) (Code, os.Error) {
+       stmts, err := parser.ParseStmtList("input", text)
+       if err == nil {
+               return w.CompileStmtList(stmts)
+       }
+
+       // Otherwise try as DeclList.
+       decls, err1 := parser.ParseDeclList("input", text)
+       if err1 == nil {
+               return w.CompileDeclList(decls)
+       }
+
+       // Have to pick an error.
+       // Parsing as statement list admits more forms,
+       // its error is more likely to be useful.
+       return nil, err
+}
+
+type RedefinitionError struct {
+       Name string
+       Prev Def
+}
+
+func (e *RedefinitionError) String() string {
+       res := "identifier " + e.Name + " redeclared"
+       pos := e.Prev.Pos()
+       if pos.IsValid() {
+               res += "; previous declaration at " + pos.String()
+       }
+       return res
+}
+
+func (w *World) DefineConst(name string, t Type, val Value) os.Error {
+       _, prev := w.scope.DefineConst(name, token.Position{}, t, val)
+       if prev != nil {
+               return &RedefinitionError{name, prev}
+       }
+       return nil
+}
+
+func (w *World) DefineVar(name string, t Type, val Value) os.Error {
+       v, prev := w.scope.DefineVar(name, token.Position{}, t)
+       if prev != nil {
+               return &RedefinitionError{name, prev}
+       }
+       v.Init = val
+       return nil
+}
diff --git a/libgo/go/exp/nacl/av/av.go b/libgo/go/exp/nacl/av/av.go
new file mode 100644 (file)
index 0000000..2b980f5
--- /dev/null
@@ -0,0 +1,289 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Native Client audio/video
+
+// Package av implements audio and video access for Native Client
+// binaries running standalone or embedded in a web browser window.
+//
+// The C version of the API is documented at
+// http://nativeclient.googlecode.com/svn/data/docs_tarball/nacl/googleclient/native_client/scons-out/doc/html/group__audio__video.html
+package av
+
+import (
+       "exp/draw"
+       "exp/nacl/srpc"
+       "log"
+       "os"
+       "syscall"
+       "unsafe"
+)
+
+var srpcEnabled = srpc.Enabled()
+
+// native_client/src/trusted/service_runtime/include/sys/audio_video.h
+
+// Subsystem values for Init.
+const (
+       SubsystemVideo = 1 << iota
+       SubsystemAudio
+       SubsystemEmbed
+)
+//     SubsystemRawEvents;
+
+// Audio formats.
+const (
+       AudioFormatStereo44K = iota
+       AudioFormatStereo48K
+)
+
+// A Window represents a connection to the Native Client window.
+// It implements draw.Context.
+type Window struct {
+       Embedded bool // running as part of a web page?
+       *Image        // screen image
+       eventc   chan interface{}
+}
+
+// *Window implements draw.Window.
+var _ draw.Window = (*Window)(nil)
+
+func (w *Window) EventChan() <-chan interface{} { return w.eventc }
+
+func (w *Window) Close() os.Error {
+       // TODO(nigeltao): implement.
+       return nil
+}
+
+func (w *Window) Screen() draw.Image { return w.Image }
+
+// Init initializes the Native Client subsystems specified by subsys.
+// Init must be called before using any of the other functions
+// in this package, and it must be called only once.
+//
+// If the SubsystemVideo flag is set, Init requests a window of size dx×dy.
+// When embedded in a web page, the web page's window specification
+// overrides the parameters to Init, so the returned Window may have
+// a different size than requested.
+//
+// If the SubsystemAudio flag is set, Init requests a connection to the
+// audio device carrying 44 kHz 16-bit stereo PCM audio samples.
+func Init(subsys int, dx, dy int) (*Window, os.Error) {
+       xsubsys := subsys
+       if srpcEnabled {
+               waitBridge()
+               xsubsys &^= SubsystemVideo | SubsystemEmbed
+       }
+
+       if xsubsys&SubsystemEmbed != 0 {
+               return nil, os.NewError("not embedded")
+       }
+
+       w := new(Window)
+       err := multimediaInit(xsubsys)
+       if err != nil {
+               return nil, err
+       }
+
+       if subsys&SubsystemVideo != 0 {
+               if dx, dy, err = videoInit(dx, dy); err != nil {
+                       return nil, err
+               }
+               w.Image = newImage(dx, dy, bridge.pixel)
+               w.eventc = make(chan interface{}, 64)
+       }
+
+       if subsys&SubsystemAudio != 0 {
+               var n int
+               if n, err = audioInit(AudioFormatStereo44K, 2048); err != nil {
+                       return nil, err
+               }
+               println("audio", n)
+       }
+
+       if subsys&SubsystemVideo != 0 {
+               go w.readEvents()
+       }
+
+       return w, nil
+}
+
+func (w *Window) FlushImage() {
+       if w.Image == nil {
+               return
+       }
+       videoUpdate(w.Image.Linear)
+}
+
+func multimediaInit(subsys int) (err os.Error) {
+       return os.NewSyscallError("multimedia_init", syscall.MultimediaInit(subsys))
+}
+
+func videoInit(dx, dy int) (ndx, ndy int, err os.Error) {
+       if srpcEnabled {
+               bridge.share.ready = 1
+               return int(bridge.share.width), int(bridge.share.height), nil
+       }
+       if e := syscall.VideoInit(dx, dy); e != 0 {
+               return 0, 0, os.NewSyscallError("video_init", int(e))
+       }
+       return dx, dy, nil
+}
+
+func videoUpdate(data []Color) (err os.Error) {
+       if srpcEnabled {
+               bridge.flushRPC.Call("upcall", nil)
+               return
+       }
+       return os.NewSyscallError("video_update", syscall.VideoUpdate((*uint32)(&data[0])))
+}
+
+var noEvents = os.NewError("no events")
+
+func videoPollEvent(ev []byte) (err os.Error) {
+       if srpcEnabled {
+               r := bridge.share.eq.ri
+               if r == bridge.share.eq.wi {
+                       return noEvents
+               }
+               copy(ev, bridge.share.eq.event[r][0:])
+               bridge.share.eq.ri = (r + 1) % eqsize
+               return nil
+       }
+       return os.NewSyscallError("video_poll_event", syscall.VideoPollEvent(&ev[0]))
+}
+
+func audioInit(fmt int, want int) (got int, err os.Error) {
+       var x int
+       e := syscall.AudioInit(fmt, want, &x)
+       if e == 0 {
+               return x, nil
+       }
+       return 0, os.NewSyscallError("audio_init", e)
+}
+
+var audioSize uintptr
+
+// AudioStream provides access to the audio device.
+// Each call to AudioStream writes the given data,
+// which should be a slice of 16-bit stereo PCM audio samples,
+// and returns the number of samples required by the next
+// call to AudioStream.
+//
+// To find out the initial number of samples to write, call AudioStream(nil).
+//
+func AudioStream(data []uint16) (nextSize int, err os.Error) {
+       if audioSize == 0 {
+               e := os.NewSyscallError("audio_stream", syscall.AudioStream(nil, &audioSize))
+               return int(audioSize), e
+       }
+       if data == nil {
+               return int(audioSize), nil
+       }
+       if uintptr(len(data))*2 != audioSize {
+               log.Printf("invalid audio size want %d got %d", audioSize, len(data))
+       }
+       e := os.NewSyscallError("audio_stream", syscall.AudioStream(&data[0], &audioSize))
+       return int(audioSize), e
+}
+
+// Synchronization structure to wait for bridge to become ready.
+var bridge struct {
+       c         chan bool
+       displayFd int
+       rpcFd     int
+       share     *videoShare
+       pixel     []Color
+       client    *srpc.Client
+       flushRPC  *srpc.RPC
+}
+
+// Wait for bridge to become ready.
+// When chan is first created, there is nothing in it,
+// so this blocks.  Once the bridge is ready, multimediaBridge.Run
+// will drop a value into the channel.  Then any calls
+// to waitBridge will finish, taking the value out and immediately putting it back.
+func waitBridge() { bridge.c <- <-bridge.c }
+
+const eqsize = 64
+
+// Data structure shared with host via mmap.
+type videoShare struct {
+       revision int32 // definition below is rev 100 unless noted
+       mapSize  int32
+
+       // event queue
+       eq struct {
+               ri    uint32 // read index [0,eqsize)
+               wi    uint32 // write index [0,eqsize)
+               eof   int32
+               event [eqsize][64]byte
+       }
+
+       // now unused
+       _, _, _, _ int32
+
+       // video backing store information
+       width, height, _, size int32
+       ready                  int32 // rev 0x101
+}
+
+// The frame buffer data is videoShareSize bytes after
+// the videoShare begins.
+const videoShareSize = 16 * 1024
+
+type multimediaBridge struct{}
+
+// If using SRPC, the runtime will call this method to pass in two file descriptors,
+// one to mmap to get the display memory, and another to use for SRPCs back
+// to the main process.
+func (multimediaBridge) Run(arg, ret []interface{}, size []int) srpc.Errno {
+       bridge.displayFd = arg[0].(int)
+       bridge.rpcFd = arg[1].(int)
+
+       var st syscall.Stat_t
+       if errno := syscall.Fstat(bridge.displayFd, &st); errno != 0 {
+               log.Exitf("mmbridge stat display: %s", os.Errno(errno))
+       }
+
+       addr, _, errno := syscall.Syscall6(syscall.SYS_MMAP,
+               0,
+               uintptr(st.Size),
+               syscall.PROT_READ|syscall.PROT_WRITE,
+               syscall.MAP_SHARED,
+               uintptr(bridge.displayFd),
+               0)
+       if errno != 0 {
+               log.Exitf("mmap display: %s", os.Errno(errno))
+       }
+
+       bridge.share = (*videoShare)(unsafe.Pointer(addr))
+
+       // Overestimate frame buffer size
+       // (must use a compile-time constant)
+       // and then reslice.  256 megapixels (1 GB) should be enough.
+       fb := (*[256 * 1024 * 1024]Color)(unsafe.Pointer(addr + videoShareSize))
+       bridge.pixel = fb[0 : (st.Size-videoShareSize)/4]
+
+       // Configure RPC connection back to client.
+       var err os.Error
+       bridge.client, err = srpc.NewClient(bridge.rpcFd)
+       if err != nil {
+               log.Exitf("NewClient: %s", err)
+       }
+       bridge.flushRPC = bridge.client.NewRPC(nil)
+
+       // Notify waiters that the bridge is ready.
+       println("bridged", bridge.share.revision)
+       bridge.c <- true
+
+       return srpc.OK
+}
+
+func init() {
+       bridge.c = make(chan bool, 1)
+       if srpcEnabled {
+               srpc.Add("nacl_multimedia_bridge", "hh:", multimediaBridge{})
+       }
+}
diff --git a/libgo/go/exp/nacl/av/event.go b/libgo/go/exp/nacl/av/event.go
new file mode 100644 (file)
index 0000000..f8fe329
--- /dev/null
@@ -0,0 +1,473 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// NaCl GUI events.
+// Clients do not have raw access to the event stream
+// (only filtered through the lens of package draw)
+// but perhaps they will.
+
+package av
+
+import (
+       "encoding/binary"
+       "exp/draw"
+       "image"
+       "log"
+       "os"
+       "time"
+)
+
+// An eventType identifies the type of a Native Client Event.
+type eventType uint8
+
+const (
+       eventActive = 1 + iota
+       eventExpose
+       eventKeyDown
+       eventKeyUp
+       eventMouseMotion
+       eventMouseButtonDown
+       eventMouseButtonUp
+       eventQuit
+       eventUnsupported
+)
+
+// A key represents a key on a keyboard.
+type key uint16
+
+const (
+       keyUnknown      = 0
+       keyFirst        = 0
+       keyBackspace    = 8
+       keyTab          = 9
+       keyClear        = 12
+       keyReturn       = 13
+       keyPause        = 19
+       keyEscape       = 27
+       keySpace        = 32
+       keyExclaim      = 33
+       keyQuotedbl     = 34
+       keyHash         = 35
+       keyDollar       = 36
+       keyAmpersand    = 38
+       keyQuote        = 39
+       keyLeftparen    = 40
+       keyRightparen   = 41
+       keyAsterisk     = 42
+       keyPlus         = 43
+       keyComma        = 44
+       keyMinus        = 45
+       keyPeriod       = 46
+       keySlash        = 47
+       key0            = 48
+       key1            = 49
+       key2            = 50
+       key3            = 51
+       key4            = 52
+       key5            = 53
+       key6            = 54
+       key7            = 55
+       key8            = 56
+       key9            = 57
+       keyColon        = 58
+       keySemicolon    = 59
+       keyLess         = 60
+       keyEquals       = 61
+       keyGreater      = 62
+       keyQuestion     = 63
+       keyAt           = 64
+       keyLeftbracket  = 91
+       keyBackslash    = 92
+       keyRightbracket = 93
+       keyCaret        = 94
+       keyUnderscore   = 95
+       keyBackquote    = 96
+       keyA            = 97
+       keyB            = 98
+       keyC            = 99
+       keyD            = 100
+       keyE            = 101
+       keyF            = 102
+       keyG            = 103
+       keyH            = 104
+       keyI            = 105
+       keyJ            = 106
+       keyK            = 107
+       keyL            = 108
+       keyM            = 109
+       keyN            = 110
+       keyO            = 111
+       keyP            = 112
+       keyQ            = 113
+       keyR            = 114
+       keyS            = 115
+       keyT            = 116
+       keyU            = 117
+       keyV            = 118
+       keyW            = 119
+       keyX            = 120
+       keyY            = 121
+       keyZ            = 122
+       keyDelete       = 127
+       keyWorld0       = 160
+       keyWorld1       = 161
+       keyWorld2       = 162
+       keyWorld3       = 163
+       keyWorld4       = 164
+       keyWorld5       = 165
+       keyWorld6       = 166
+       keyWorld7       = 167
+       keyWorld8       = 168
+       keyWorld9       = 169
+       keyWorld10      = 170
+       keyWorld11      = 171
+       keyWorld12      = 172
+       keyWorld13      = 173
+       keyWorld14      = 174
+       keyWorld15      = 175
+       keyWorld16      = 176
+       keyWorld17      = 177
+       keyWorld18      = 178
+       keyWorld19      = 179
+       keyWorld20      = 180
+       keyWorld21      = 181
+       keyWorld22      = 182
+       keyWorld23      = 183
+       keyWorld24      = 184
+       keyWorld25      = 185
+       keyWorld26      = 186
+       keyWorld27      = 187
+       keyWorld28      = 188
+       keyWorld29      = 189
+       keyWorld30      = 190
+       keyWorld31      = 191
+       keyWorld32      = 192
+       keyWorld33      = 193
+       keyWorld34      = 194
+       keyWorld35      = 195
+       keyWorld36      = 196
+       keyWorld37      = 197
+       keyWorld38      = 198
+       keyWorld39      = 199
+       keyWorld40      = 200
+       keyWorld41      = 201
+       keyWorld42      = 202
+       keyWorld43      = 203
+       keyWorld44      = 204
+       keyWorld45      = 205
+       keyWorld46      = 206
+       keyWorld47      = 207
+       keyWorld48      = 208
+       keyWorld49      = 209
+       keyWorld50      = 210
+       keyWorld51      = 211
+       keyWorld52      = 212
+       keyWorld53      = 213
+       keyWorld54      = 214
+       keyWorld55      = 215
+       keyWorld56      = 216
+       keyWorld57      = 217
+       keyWorld58      = 218
+       keyWorld59      = 219
+       keyWorld60      = 220
+       keyWorld61      = 221
+       keyWorld62      = 222
+       keyWorld63      = 223
+       keyWorld64      = 224
+       keyWorld65      = 225
+       keyWorld66      = 226
+       keyWorld67      = 227
+       keyWorld68      = 228
+       keyWorld69      = 229
+       keyWorld70      = 230
+       keyWorld71      = 231
+       keyWorld72      = 232
+       keyWorld73      = 233
+       keyWorld74      = 234
+       keyWorld75      = 235
+       keyWorld76      = 236
+       keyWorld77      = 237
+       keyWorld78      = 238
+       keyWorld79      = 239
+       keyWorld80      = 240
+       keyWorld81      = 241
+       keyWorld82      = 242
+       keyWorld83      = 243
+       keyWorld84      = 244
+       keyWorld85      = 245
+       keyWorld86      = 246
+       keyWorld87      = 247
+       keyWorld88      = 248
+       keyWorld89      = 249
+       keyWorld90      = 250
+       keyWorld91      = 251
+       keyWorld92      = 252
+       keyWorld93      = 253
+       keyWorld94      = 254
+       keyWorld95      = 255
+
+       // Numeric keypad
+       keyKp0        = 256
+       keyKp1        = 257
+       keyKp2        = 258
+       keyKp3        = 259
+       keyKp4        = 260
+       keyKp5        = 261
+       keyKp6        = 262
+       keyKp7        = 263
+       keyKp8        = 264
+       keyKp9        = 265
+       keyKpPeriod   = 266
+       keyKpDivide   = 267
+       keyKpMultiply = 268
+       keyKpMinus    = 269
+       keyKpPlus     = 270
+       keyKpEnter    = 271
+       keyKpEquals   = 272
+
+       // Arrow & insert/delete pad
+       keyUp       = 273
+       keyDown     = 274
+       keyRight    = 275
+       keyLeft     = 276
+       keyInsert   = 277
+       keyHome     = 278
+       keyEnd      = 279
+       keyPageup   = 280
+       keyPagedown = 281
+
+       // Function keys
+       keyF1  = 282
+       keyF2  = 283
+       keyF3  = 284
+       keyF4  = 285
+       keyF5  = 286
+       keyF6  = 287
+       keyF7  = 288
+       keyF8  = 289
+       keyF9  = 290
+       keyF10 = 291
+       keyF11 = 292
+       keyF12 = 293
+       keyF13 = 294
+       keyF14 = 295
+       keyF15 = 296
+
+       // Modifier keys
+       keyNumlock   = 300
+       keyCapslock  = 301
+       keyScrollock = 302
+       keyRshift    = 303
+       keyLshift    = 304
+       keyRctrl     = 305
+       keyLctrl     = 306
+       keyRalt      = 307
+       keyLalt      = 308
+       keyRmeta     = 309
+       keyLmeta     = 310
+       keyLsuper    = 311
+       keyRsuper    = 312
+       keyMode      = 313
+       keyCompose   = 314
+
+       // Misc keys
+       keyHelp   = 315
+       keyPrint  = 316
+       keySysreq = 317
+       keyBreak  = 318
+       keyMenu   = 319
+       keyPower  = 320
+       keyEuro   = 321
+       keyUndo   = 322
+
+       // Add any other keys here
+       keyLast
+)
+
+// A keymod is a set of bit flags
+type keymod uint16
+
+const (
+       keymodNone     = 0x0000
+       keymodLshift   = 0x0001
+       keymodRshift   = 0x0002
+       keymodLctrl    = 0x0040
+       keymodRctrl    = 0x0080
+       keymodLalt     = 0x0100
+       keymodRalt     = 0x0200
+       keymodLmeta    = 0x0400
+       keymodRmeta    = 0x0800
+       keymodNum      = 0x1000
+       keymodCaps     = 0x2000
+       keymodMode     = 0x4000
+       keymodReserved = 0x8000
+)
+
+const (
+       mouseButtonLeft   = 1
+       mouseButtonMiddle = 2
+       mouseButtonRight  = 3
+       mouseScrollUp     = 4
+       mouseScrollDown   = 5
+)
+
+const (
+       mouseStateLeftButtonPressed   = 1
+       mouseStateMiddleButtonPressed = 2
+       mouseStateRightButtonPressed  = 4
+)
+
+const (
+       activeMouse       = 1 //  mouse leaving/entering
+       activeInputFocus  = 2 // input focus lost/restored
+       activeApplication = 4 // application minimized/restored
+)
+
+const maxEventBytes = 64
+
+type activeEvent struct {
+       EventType eventType
+       Gain      uint8
+       State     uint8
+}
+
+type exposeEvent struct {
+       EventType eventType
+}
+
+type keyboardEvent struct {
+       EventType eventType
+       Device    uint8
+       State     uint8
+       Pad       uint8
+       ScanCode  uint8
+       Pad1      uint8
+       Key       key
+       Mod       keymod
+       Unicode   uint16
+}
+
+type mouseMotionEvent struct {
+       EventType eventType
+       Device    uint8
+       Buttons   uint8
+       Pad       uint8
+       X         uint16
+       Y         uint16
+       Xrel      int16
+       Yrel      int16
+}
+
+type mouseButtonEvent struct {
+       EventType eventType
+       Device    uint8
+       Button    uint8
+       State     uint8
+       X         uint16
+       Y         uint16
+}
+
+type quitEvent struct {
+       EventType eventType
+}
+
+type syncEvent struct{}
+
+type event interface{}
+
+type reader []byte
+
+func (r *reader) Read(p []byte) (n int, err os.Error) {
+       b := *r
+       if len(b) == 0 && len(p) > 0 {
+               return 0, os.EOF
+       }
+       n = copy(p, b)
+       *r = b[n:]
+       return
+}
+
+func (w *Window) readEvents() {
+       buf := make([]byte, maxEventBytes)
+       clean := false
+       var (
+               ea  *activeEvent
+               ee  *exposeEvent
+               ke  *keyboardEvent
+               mme *mouseMotionEvent
+               mbe *mouseButtonEvent
+               qe  *quitEvent
+       )
+       var m draw.MouseEvent
+       for {
+               if err := videoPollEvent(buf); err != nil {
+                       if !clean {
+                               clean = w.eventc <- draw.ConfigEvent{image.Config{ColorModel, w.Image.Bounds().Dx(), w.Image.Bounds().Dy()}}
+                       }
+                       time.Sleep(10e6) // 10ms
+                       continue
+               }
+               clean = false
+               var e event
+               switch buf[0] {
+               default:
+                       log.Print("unsupported event type", buf[0])
+                       continue
+               case eventActive:
+                       ea = new(activeEvent)
+                       e = ea
+               case eventExpose:
+                       ee = new(exposeEvent)
+                       e = ee
+               case eventKeyDown, eventKeyUp:
+                       ke = new(keyboardEvent)
+                       e = ke
+               case eventMouseMotion:
+                       mme = new(mouseMotionEvent)
+                       e = mme
+               case eventMouseButtonDown, eventMouseButtonUp:
+                       mbe = new(mouseButtonEvent)
+                       e = mbe
+               case eventQuit:
+                       qe = new(quitEvent)
+                       e = qe
+               }
+               r := reader(buf)
+               if err := binary.Read(&r, binary.LittleEndian, e); err != nil {
+                       log.Print("unpacking %T event: %s", e, err)
+                       continue
+               }
+               // log.Printf("%#v\n", e);
+               switch buf[0] {
+               case eventExpose:
+                       w.eventc <- draw.ConfigEvent{image.Config{ColorModel, w.Image.Bounds().Dx(), w.Image.Bounds().Dy()}}
+               case eventKeyDown:
+                       w.eventc <- draw.KeyEvent{int(ke.Key)}
+               case eventKeyUp:
+                       w.eventc <- draw.KeyEvent{-int(ke.Key)}
+               case eventMouseMotion:
+                       m.Loc.X = int(mme.X)
+                       m.Loc.Y = int(mme.Y)
+                       m.Buttons = int(mme.Buttons)
+                       m.Nsec = time.Nanoseconds()
+                       _ = w.eventc <- m
+               case eventMouseButtonDown:
+                       m.Loc.X = int(mbe.X)
+                       m.Loc.Y = int(mbe.Y)
+                       // TODO(rsc): Remove uint cast once 8g bug is fixed.
+                       m.Buttons |= 1 << uint(mbe.Button-1)
+                       m.Nsec = time.Nanoseconds()
+                       _ = w.eventc <- m
+               case eventMouseButtonUp:
+                       m.Loc.X = int(mbe.X)
+                       m.Loc.Y = int(mbe.Y)
+                       // TODO(rsc): Remove uint cast once 8g bug is fixed.
+                       m.Buttons &^= 1 << uint(mbe.Button-1)
+                       m.Nsec = time.Nanoseconds()
+                       _ = w.eventc <- m
+               case eventQuit:
+                       close(w.eventc)
+               }
+       }
+}
diff --git a/libgo/go/exp/nacl/av/image.go b/libgo/go/exp/nacl/av/image.go
new file mode 100644 (file)
index 0000000..2ff4bb6
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package av
+
+import (
+       "image"
+)
+
+// Native Client image format:
+// a single linear array of 32-bit ARGB as packed uint32s.
+
+// An Image represents a Native Client frame buffer.
+// The pixels in the image can be accessed as a single
+// linear slice or as a two-dimensional slice of slices.
+// Image implements image.Image.
+type Image struct {
+       Linear []Color
+       Pixel  [][]Color
+}
+
+var _ image.Image = (*Image)(nil)
+
+func (m *Image) ColorModel() image.ColorModel { return ColorModel }
+
+func (m *Image) Bounds() image.Rectangle {
+       if len(m.Pixel) == 0 {
+               return image.ZR
+       }
+       return image.Rectangle{image.ZP, image.Point{len(m.Pixel[0]), len(m.Pixel)}}
+}
+
+func (m *Image) At(x, y int) image.Color { return m.Pixel[y][x] }
+
+func (m *Image) Set(x, y int, color image.Color) {
+       if c, ok := color.(Color); ok {
+               m.Pixel[y][x] = c
+               return
+       }
+       m.Pixel[y][x] = makeColor(color.RGBA())
+}
+
+func newImage(dx, dy int, linear []Color) *Image {
+       if linear == nil {
+               linear = make([]Color, dx*dy)
+       }
+       pix := make([][]Color, dy)
+       for i := range pix {
+               pix[i] = linear[dx*i : dx*(i+1)]
+       }
+       return &Image{linear, pix}
+}
+
+// A Color represents a Native Client color value,
+// a 32-bit R, G, B, A value packed as 0xAARRGGBB.
+type Color uint32
+
+func (p Color) RGBA() (r, g, b, a uint32) {
+       x := uint32(p)
+       a = x >> 24
+       a |= a << 8
+       r = (x >> 16) & 0xFF
+       r |= r << 8
+       g = (x >> 8) & 0xFF
+       g |= g << 8
+       b = x & 0xFF
+       b |= b << 8
+       return
+}
+
+func makeColor(r, g, b, a uint32) Color {
+       return Color(a>>8<<24 | r>>8<<16 | g>>8<<8 | b>>8)
+}
+
+func toColor(color image.Color) image.Color {
+       if c, ok := color.(Color); ok {
+               return c
+       }
+       return makeColor(color.RGBA())
+}
+
+// ColorModel is the color model corresponding to the Native Client Color.
+var ColorModel = image.ColorModelFunc(toColor)
diff --git a/libgo/go/exp/nacl/srpc/client.go b/libgo/go/exp/nacl/srpc/client.go
new file mode 100644 (file)
index 0000000..3e421e4
--- /dev/null
@@ -0,0 +1,210 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements Native Client's simple RPC (SRPC).
+package srpc
+
+import (
+       "bytes"
+       "log"
+       "os"
+       "sync"
+)
+
+// A Client represents the client side of an SRPC connection.
+type Client struct {
+       fd      int // fd to server
+       r       msgReceiver
+       s       msgSender
+       service map[string]srv // services by name
+       out     chan *msg      // send to out to write to connection
+
+       mu      sync.Mutex // protects pending, idGen
+       pending map[uint64]*RPC
+       idGen   uint64 // generator for request IDs
+}
+
+// A srv is a single method that the server offers.
+type srv struct {
+       num uint32 // method number
+       fmt string // argument format
+}
+
+// An RPC represents a single RPC issued by a client.
+type RPC struct {
+       Ret   []interface{} // Return values
+       Done  chan *RPC     // Channel where notification of done arrives
+       Errno Errno         // Status code
+       c     *Client
+       id    uint64 // request id
+}
+
+// NewClient allocates a new client using the file descriptor fd.
+func NewClient(fd int) (c *Client, err os.Error) {
+       c = new(Client)
+       c.fd = fd
+       c.r.fd = fd
+       c.s.fd = fd
+       c.service = make(map[string]srv)
+       c.pending = make(map[uint64]*RPC)
+
+       // service discovery request
+       m := &msg{
+               protocol: protocol,
+               isReq:    true,
+               Ret:      []interface{}{[]byte(nil)},
+               Size:     []int{4000},
+       }
+       m.packRequest()
+       c.s.send(m)
+       m, err = c.r.recv()
+       if err != nil {
+               return nil, err
+       }
+       m.unpackResponse()
+       if m.status != OK {
+               log.Printf("NewClient service_discovery: %s", m.status)
+               return nil, m.status
+       }
+       for n, line := range bytes.Split(m.Ret[0].([]byte), []byte{'\n'}, -1) {
+               i := bytes.Index(line, []byte{':'})
+               if i < 0 {
+                       continue
+               }
+               c.service[string(line[0:i])] = srv{uint32(n), string(line[i+1:])}
+       }
+
+       c.out = make(chan *msg)
+       go c.input()
+       go c.output()
+       return c, nil
+}
+
+func (c *Client) input() {
+       for {
+               m, err := c.r.recv()
+               if err != nil {
+                       log.Exitf("client recv: %s", err)
+               }
+               if m.unpackResponse(); m.status != OK {
+                       log.Printf("invalid message: %s", m.status)
+                       continue
+               }
+               c.mu.Lock()
+               rpc, ok := c.pending[m.requestId]
+               if ok {
+                       c.pending[m.requestId] = nil, false
+               }
+               c.mu.Unlock()
+               if !ok {
+                       log.Print("unexpected response")
+                       continue
+               }
+               rpc.Ret = m.Ret
+               rpc.Done <- rpc
+       }
+}
+
+func (c *Client) output() {
+       for m := range c.out {
+               c.s.send(m)
+       }
+}
+
+// NewRPC creates a new RPC on the client connection.
+func (c *Client) NewRPC(done chan *RPC) *RPC {
+       if done == nil {
+               done = make(chan *RPC)
+       }
+       c.mu.Lock()
+       id := c.idGen
+       c.idGen++
+       c.mu.Unlock()
+       return &RPC{nil, done, OK, c, id}
+}
+
+// Start issues an RPC request for method name with the given arguments.
+// The RPC r must not be in use for another pending request.
+// To wait for the RPC to finish, receive from r.Done and then
+// inspect r.Ret and r.Errno.
+func (r *RPC) Start(name string, arg []interface{}) {
+       var m msg
+
+       r.Errno = OK
+       r.c.mu.Lock()
+       srv, ok := r.c.service[name]
+       if !ok {
+               r.c.mu.Unlock()
+               r.Errno = ErrBadRPCNumber
+               r.Done <- r
+               return
+       }
+       r.c.pending[r.id] = r
+       r.c.mu.Unlock()
+
+       m.protocol = protocol
+       m.requestId = r.id
+       m.isReq = true
+       m.rpcNumber = srv.num
+       m.Arg = arg
+
+       // Fill in the return values and sizes to generate
+       // the right type chars.  We'll take most any size.
+
+       // Skip over input arguments.
+       // We could check them against arg, but the server
+       // will do that anyway.
+       i := 0
+       for srv.fmt[i] != ':' {
+               i++
+       }
+       fmt := srv.fmt[i+1:]
+
+       // Now the return prototypes.
+       m.Ret = make([]interface{}, len(fmt)-i)
+       m.Size = make([]int, len(fmt)-i)
+       for i := 0; i < len(fmt); i++ {
+               switch fmt[i] {
+               default:
+                       log.Exitf("unexpected service type %c", fmt[i])
+               case 'b':
+                       m.Ret[i] = false
+               case 'C':
+                       m.Ret[i] = []byte(nil)
+                       m.Size[i] = 1 << 30
+               case 'd':
+                       m.Ret[i] = float64(0)
+               case 'D':
+                       m.Ret[i] = []float64(nil)
+                       m.Size[i] = 1 << 30
+               case 'h':
+                       m.Ret[i] = int(-1)
+               case 'i':
+                       m.Ret[i] = int32(0)
+               case 'I':
+                       m.Ret[i] = []int32(nil)
+                       m.Size[i] = 1 << 30
+               case 's':
+                       m.Ret[i] = ""
+                       m.Size[i] = 1 << 30
+               }
+       }
+
+       m.packRequest()
+       r.c.out <- &m
+}
+
+// Call is a convenient wrapper that starts the RPC request,
+// waits for it to finish, and then returns the results.
+// Its implementation is:
+//
+//     r.Start(name, arg)
+//     <-r.Done
+//     return r.Ret, r.Errno
+//
+func (r *RPC) Call(name string, arg []interface{}) (ret []interface{}, err Errno) {
+       r.Start(name, arg)
+       <-r.Done
+       return r.Ret, r.Errno
+}
diff --git a/libgo/go/exp/nacl/srpc/msg.go b/libgo/go/exp/nacl/srpc/msg.go
new file mode 100644 (file)
index 0000000..92601ed
--- /dev/null
@@ -0,0 +1,522 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SRPC constants, data structures, and parsing.
+
+package srpc
+
+import (
+       "math"
+       "os"
+       "strconv"
+       "syscall"
+       "unsafe"
+)
+
+// An Errno is an SRPC status code.
+type Errno uint32
+
+const (
+       OK Errno = 256 + iota
+       ErrBreak
+       ErrMessageTruncated
+       ErrNoMemory
+       ErrProtocolMismatch
+       ErrBadRPCNumber
+       ErrBadArgType
+       ErrTooFewArgs
+       ErrTooManyArgs
+       ErrInArgTypeMismatch
+       ErrOutArgTypeMismatch
+       ErrInternalError
+       ErrAppError
+)
+
+var errstr = [...]string{
+       OK - OK:                    "ok",
+       ErrBreak - OK:              "break",
+       ErrMessageTruncated - OK:   "message truncated",
+       ErrNoMemory - OK:           "out of memory",
+       ErrProtocolMismatch - OK:   "protocol mismatch",
+       ErrBadRPCNumber - OK:       "invalid RPC method number",
+       ErrBadArgType - OK:         "unexpected argument type",
+       ErrTooFewArgs - OK:         "too few arguments",
+       ErrTooManyArgs - OK:        "too many arguments",
+       ErrInArgTypeMismatch - OK:  "input argument type mismatch",
+       ErrOutArgTypeMismatch - OK: "output argument type mismatch",
+       ErrInternalError - OK:      "internal error",
+       ErrAppError - OK:           "application error",
+}
+
+func (e Errno) String() string {
+       if e < OK || int(e-OK) >= len(errstr) {
+               return "Errno(" + strconv.Itoa64(int64(e)) + ")"
+       }
+       return errstr[e-OK]
+}
+
+// A *msgHdr is the data argument to the imc_recvmsg
+// and imc_sendmsg system calls.  Because it contains unchecked
+// counts trusted by the system calls, the data structure is unsafe
+// to expose to package clients.
+type msgHdr struct {
+       iov   *iov
+       niov  int32
+       desc  *int32
+       ndesc int32
+       flags uint32
+}
+
+// A single region for I/O.  Just as unsafe as msgHdr.
+type iov struct {
+       base *byte
+       len  int32
+}
+
+// A msg is the Go representation of a message.
+type msg struct {
+       rdata []byte  // data being consumed during message parsing
+       rdesc []int32 // file descriptors being consumed during message parsing
+       wdata []byte  // data being generated when replying
+
+       // parsed version of message
+       protocol  uint32
+       requestId uint64
+       isReq     bool
+       rpcNumber uint32
+       gotHeader bool
+       status    Errno         // error code sent in response
+       Arg       []interface{} // method arguments
+       Ret       []interface{} // method results
+       Size      []int         // max sizes for arrays in method results
+       fmt       string        // accumulated format string of arg+":"+ret
+}
+
+// A msgReceiver receives messages from a file descriptor.
+type msgReceiver struct {
+       fd   int
+       data [128 * 1024]byte
+       desc [8]int32
+       hdr  msgHdr
+       iov  iov
+}
+
+func (r *msgReceiver) recv() (*msg, os.Error) {
+       // Init pointers to buffers where syscall recvmsg can write.
+       r.iov.base = &r.data[0]
+       r.iov.len = int32(len(r.data))
+       r.hdr.iov = &r.iov
+       r.hdr.niov = 1
+       r.hdr.desc = &r.desc[0]
+       r.hdr.ndesc = int32(len(r.desc))
+       n, _, e := syscall.Syscall(syscall.SYS_IMC_RECVMSG, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
+       if e != 0 {
+               return nil, os.NewSyscallError("imc_recvmsg", int(e))
+       }
+
+       // Make a copy of the data so that the next recvmsg doesn't
+       // smash it.  The system call did not update r.iov.len.  Instead it
+       // returned the total byte count as n.
+       m := new(msg)
+       m.rdata = make([]byte, n)
+       copy(m.rdata, r.data[0:])
+
+       // Make a copy of the desc too.
+       // The system call *did* update r.hdr.ndesc.
+       if r.hdr.ndesc > 0 {
+               m.rdesc = make([]int32, r.hdr.ndesc)
+               copy(m.rdesc, r.desc)
+       }
+
+       return m, nil
+}
+
+// A msgSender sends messages on a file descriptor.
+type msgSender struct {
+       fd  int
+       hdr msgHdr
+       iov iov
+}
+
+func (s *msgSender) send(m *msg) os.Error {
+       if len(m.wdata) > 0 {
+               s.iov.base = &m.wdata[0]
+       }
+       s.iov.len = int32(len(m.wdata))
+       s.hdr.iov = &s.iov
+       s.hdr.niov = 1
+       s.hdr.desc = nil
+       s.hdr.ndesc = 0
+       _, _, e := syscall.Syscall(syscall.SYS_IMC_SENDMSG, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
+       if e != 0 {
+               return os.NewSyscallError("imc_sendmsg", int(e))
+       }
+       return nil
+}
+
+// Reading from msg.rdata.
+func (m *msg) uint8() uint8 {
+       if m.status != OK {
+               return 0
+       }
+       if len(m.rdata) < 1 {
+               m.status = ErrMessageTruncated
+               return 0
+       }
+       x := m.rdata[0]
+       m.rdata = m.rdata[1:]
+       return x
+}
+
+func (m *msg) uint32() uint32 {
+       if m.status != OK {
+               return 0
+       }
+       if len(m.rdata) < 4 {
+               m.status = ErrMessageTruncated
+               return 0
+       }
+       b := m.rdata[0:4]
+       x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+       m.rdata = m.rdata[4:]
+       return x
+}
+
+func (m *msg) uint64() uint64 {
+       if m.status != OK {
+               return 0
+       }
+       if len(m.rdata) < 8 {
+               m.status = ErrMessageTruncated
+               return 0
+       }
+       b := m.rdata[0:8]
+       x := uint64(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24)
+       x |= uint64(uint32(b[4])|uint32(b[5])<<8|uint32(b[6])<<16|uint32(b[7])<<24) << 32
+       m.rdata = m.rdata[8:]
+       return x
+}
+
+func (m *msg) bytes(n int) []byte {
+       if m.status != OK {
+               return nil
+       }
+       if len(m.rdata) < n {
+               m.status = ErrMessageTruncated
+               return nil
+       }
+       x := m.rdata[0:n]
+       m.rdata = m.rdata[n:]
+       return x
+}
+
+// Writing to msg.wdata.
+func (m *msg) grow(n int) []byte {
+       i := len(m.wdata)
+       if i+n > cap(m.wdata) {
+               a := make([]byte, i, (i+n)*2)
+               copy(a, m.wdata)
+               m.wdata = a
+       }
+       m.wdata = m.wdata[0 : i+n]
+       return m.wdata[i : i+n]
+}
+
+func (m *msg) wuint8(x uint8) { m.grow(1)[0] = x }
+
+func (m *msg) wuint32(x uint32) {
+       b := m.grow(4)
+       b[0] = byte(x)
+       b[1] = byte(x >> 8)
+       b[2] = byte(x >> 16)
+       b[3] = byte(x >> 24)
+}
+
+func (m *msg) wuint64(x uint64) {
+       b := m.grow(8)
+       lo := uint32(x)
+       b[0] = byte(lo)
+       b[1] = byte(lo >> 8)
+       b[2] = byte(lo >> 16)
+       b[3] = byte(lo >> 24)
+       hi := uint32(x >> 32)
+       b[4] = byte(hi)
+       b[5] = byte(hi >> 8)
+       b[6] = byte(hi >> 16)
+       b[7] = byte(hi >> 24)
+}
+
+func (m *msg) wbytes(p []byte) { copy(m.grow(len(p)), p) }
+
+func (m *msg) wstring(s string) {
+       b := m.grow(len(s))
+       copy(b, s)
+}
+
+// Parsing of RPC header and arguments.
+//
+// The header format is:
+//     protocol uint32;
+//     requestId uint64;
+//     isReq bool;
+//     rpcNumber uint32;
+//     status uint32;  // only for response
+//
+// Then a sequence of values follow, preceded by the length:
+//     nvalue uint32;
+//
+// Each value begins with a one-byte type followed by
+// type-specific data.
+//
+//     type uint8;
+//     'b':    x bool;
+//     'C':    len uint32; x [len]byte;
+//     'd':    x float64;
+//     'D':    len uint32; x [len]float64;
+//     'h':    x int;  // handle aka file descriptor
+//     'i':    x int32;
+//     'I':    len uint32; x [len]int32;
+//     's':    len uint32; x [len]byte;
+//
+// If this is a request, a sequence of pseudo-values follows,
+// preceded by its length (nvalue uint32).
+//
+// Each pseudo-value is a one-byte type as above,
+// followed by a maximum length (len uint32)
+// for the 'C', 'D', 'I', and 's' types.
+//
+// In the Go msg, we represent each argument by
+// an empty interface containing the type of x in the
+// corresponding case.
+
+// The current protocol number.
+const protocol = 0xc0da0002
+
+func (m *msg) unpackHeader() {
+       m.protocol = m.uint32()
+       m.requestId = m.uint64()
+       m.isReq = m.uint8() != 0
+       m.rpcNumber = m.uint32()
+       m.gotHeader = m.status == OK // signal that header parsed successfully
+       if m.gotHeader && !m.isReq {
+               status := Errno(m.uint32())
+               m.gotHeader = m.status == OK // still ok?
+               if m.gotHeader {
+                       m.status = status
+               }
+       }
+}
+
+func (m *msg) packHeader() {
+       m.wuint32(m.protocol)
+       m.wuint64(m.requestId)
+       if m.isReq {
+               m.wuint8(1)
+       } else {
+               m.wuint8(0)
+       }
+       m.wuint32(m.rpcNumber)
+       if !m.isReq {
+               m.wuint32(uint32(m.status))
+       }
+}
+
+func (m *msg) unpackValues(v []interface{}) {
+       for i := range v {
+               t := m.uint8()
+               m.fmt += string(t)
+               switch t {
+               default:
+                       if m.status == OK {
+                               m.status = ErrBadArgType
+                       }
+                       return
+               case 'b': // bool[1]
+                       v[i] = m.uint8() > 0
+               case 'C': // char array
+                       v[i] = m.bytes(int(m.uint32()))
+               case 'd': // double
+                       v[i] = math.Float64frombits(m.uint64())
+               case 'D': // double array
+                       a := make([]float64, int(m.uint32()))
+                       for j := range a {
+                               a[j] = math.Float64frombits(m.uint64())
+                       }
+                       v[i] = a
+               case 'h': // file descriptor (handle)
+                       if len(m.rdesc) == 0 {
+                               if m.status == OK {
+                                       m.status = ErrBadArgType
+                               }
+                               return
+                       }
+                       v[i] = int(m.rdesc[0])
+                       m.rdesc = m.rdesc[1:]
+               case 'i': // int
+                       v[i] = int32(m.uint32())
+               case 'I': // int array
+                       a := make([]int32, int(m.uint32()))
+                       for j := range a {
+                               a[j] = int32(m.uint32())
+                       }
+                       v[i] = a
+               case 's': // string
+                       v[i] = string(m.bytes(int(m.uint32())))
+               }
+       }
+}
+
+func (m *msg) packValues(v []interface{}) {
+       for i := range v {
+               switch x := v[i].(type) {
+               default:
+                       if m.status == OK {
+                               m.status = ErrInternalError
+                       }
+                       return
+               case bool:
+                       m.wuint8('b')
+                       if x {
+                               m.wuint8(1)
+                       } else {
+                               m.wuint8(0)
+                       }
+               case []byte:
+                       m.wuint8('C')
+                       m.wuint32(uint32(len(x)))
+                       m.wbytes(x)
+               case float64:
+                       m.wuint8('d')
+                       m.wuint64(math.Float64bits(x))
+               case []float64:
+                       m.wuint8('D')
+                       m.wuint32(uint32(len(x)))
+                       for _, f := range x {
+                               m.wuint64(math.Float64bits(f))
+                       }
+               case int32:
+                       m.wuint8('i')
+                       m.wuint32(uint32(x))
+               case []int32:
+                       m.wuint8('I')
+                       m.wuint32(uint32(len(x)))
+                       for _, i := range x {
+                               m.wuint32(uint32(i))
+                       }
+               case string:
+                       m.wuint8('s')
+                       m.wuint32(uint32(len(x)))
+                       m.wstring(x)
+               }
+       }
+}
+
+func (m *msg) unpackRequest() {
+       m.status = OK
+       if m.unpackHeader(); m.status != OK {
+               return
+       }
+       if m.protocol != protocol || !m.isReq {
+               m.status = ErrProtocolMismatch
+               return
+       }
+
+       // type-tagged argument values
+       m.Arg = make([]interface{}, m.uint32())
+       m.unpackValues(m.Arg)
+       if m.status != OK {
+               return
+       }
+
+       // type-tagged expected return sizes.
+       // fill in zero values for each return value
+       // and save sizes.
+       m.fmt += ":"
+       m.Ret = make([]interface{}, m.uint32())
+       m.Size = make([]int, len(m.Ret))
+       for i := range m.Ret {
+               t := m.uint8()
+               m.fmt += string(t)
+               switch t {
+               default:
+                       if m.status == OK {
+                               m.status = ErrBadArgType
+                       }
+                       return
+               case 'b': // bool[1]
+                       m.Ret[i] = false
+               case 'C': // char array
+                       m.Size[i] = int(m.uint32())
+                       m.Ret[i] = []byte(nil)
+               case 'd': // double
+                       m.Ret[i] = float64(0)
+               case 'D': // double array
+                       m.Size[i] = int(m.uint32())
+                       m.Ret[i] = []float64(nil)
+               case 'h': // file descriptor (handle)
+                       m.Ret[i] = int(-1)
+               case 'i': // int
+                       m.Ret[i] = int32(0)
+               case 'I': // int array
+                       m.Size[i] = int(m.uint32())
+                       m.Ret[i] = []int32(nil)
+               case 's': // string
+                       m.Size[i] = int(m.uint32())
+                       m.Ret[i] = ""
+               }
+       }
+}
+
+func (m *msg) packRequest() {
+       m.packHeader()
+       m.wuint32(uint32(len(m.Arg)))
+       m.packValues(m.Arg)
+       m.wuint32(uint32(len(m.Ret)))
+       for i, v := range m.Ret {
+               switch x := v.(type) {
+               case bool:
+                       m.wuint8('b')
+               case []byte:
+                       m.wuint8('C')
+                       m.wuint32(uint32(m.Size[i]))
+               case float64:
+                       m.wuint8('d')
+               case []float64:
+                       m.wuint8('D')
+                       m.wuint32(uint32(m.Size[i]))
+               case int:
+                       m.wuint8('h')
+               case int32:
+                       m.wuint8('i')
+               case []int32:
+                       m.wuint8('I')
+                       m.wuint32(uint32(m.Size[i]))
+               case string:
+                       m.wuint8('s')
+                       m.wuint32(uint32(m.Size[i]))
+               }
+       }
+}
+
+func (m *msg) unpackResponse() {
+       m.status = OK
+       if m.unpackHeader(); m.status != OK {
+               return
+       }
+       if m.protocol != protocol || m.isReq {
+               m.status = ErrProtocolMismatch
+               return
+       }
+
+       // type-tagged return values
+       m.fmt = ""
+       m.Ret = make([]interface{}, m.uint32())
+       m.unpackValues(m.Ret)
+}
+
+func (m *msg) packResponse() {
+       m.packHeader()
+       m.wuint32(uint32(len(m.Ret)))
+       m.packValues(m.Ret)
+}
diff --git a/libgo/go/exp/nacl/srpc/server.go b/libgo/go/exp/nacl/srpc/server.go
new file mode 100644 (file)
index 0000000..5d65ca1
--- /dev/null
@@ -0,0 +1,192 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SRPC server
+
+package srpc
+
+import (
+       "bytes"
+       "log"
+       "os"
+       "syscall"
+)
+
+// TODO(rsc): I'd prefer to make this
+//     type Handler func(m *msg) Errno
+// but NaCl can't use closures.
+// The explicit interface is a way to attach state.
+
+// A Handler is a handler for an SRPC method.
+// It reads arguments from arg, checks size for array limits,
+// writes return values to ret, and returns an Errno status code.
+type Handler interface {
+       Run(arg, ret []interface{}, size []int) Errno
+}
+
+type method struct {
+       name    string
+       fmt     string
+       handler Handler
+}
+
+var rpcMethod []method
+
+// BUG(rsc): Add's format string should be replaced by analyzing the
+// type of an arbitrary func passed in an interface{} using reflection.
+
+// Add registers a handler for the named method.
+// Fmt is a Native Client format string, a sequence of
+// alphabetic characters representing the types of the parameter values,
+// a colon, and then a sequence of alphabetic characters
+// representing the types of the returned values.
+// The format characters and corresponding dynamic types are:
+//
+//     b       bool
+//     C       []byte
+//     d       float64
+//     D       []float64
+//     h       int     // a file descriptor (aka handle)
+//     i       int32
+//     I       []int32
+//     s       string
+//
+func Add(name, fmt string, handler Handler) {
+       rpcMethod = append(rpcMethod, method{name, fmt, handler})
+}
+
+// Serve accepts new SRPC connections from the file descriptor fd
+// and answers RPCs issued on those connections.
+// It closes fd and returns an error if the imc_accept system call fails.
+func Serve(fd int) os.Error {
+       defer syscall.Close(fd)
+
+       for {
+               cfd, _, e := syscall.Syscall(syscall.SYS_IMC_ACCEPT, uintptr(fd), 0, 0)
+               if e != 0 {
+                       return os.NewSyscallError("imc_accept", int(e))
+               }
+               go serveLoop(int(cfd))
+       }
+       panic("unreachable")
+}
+
+func serveLoop(fd int) {
+       c := make(chan *msg)
+       go sendLoop(fd, c)
+
+       var r msgReceiver
+       r.fd = fd
+       for {
+               m, err := r.recv()
+               if err != nil {
+                       break
+               }
+               m.unpackRequest()
+               if !m.gotHeader {
+                       log.Printf("cannot unpack header: %s", m.status)
+                       continue
+               }
+               // log.Printf("<- %#v", m);
+               m.isReq = false // set up for response
+               go serveMsg(m, c)
+       }
+       close(c)
+}
+
+func sendLoop(fd int, c <-chan *msg) {
+       var s msgSender
+       s.fd = fd
+       for m := range c {
+               // log.Printf("-> %#v", m);
+               m.packResponse()
+               s.send(m)
+       }
+       syscall.Close(fd)
+}
+
+func serveMsg(m *msg, c chan<- *msg) {
+       if m.status != OK {
+               c <- m
+               return
+       }
+       if m.rpcNumber >= uint32(len(rpcMethod)) {
+               m.status = ErrBadRPCNumber
+               c <- m
+               return
+       }
+
+       meth := &rpcMethod[m.rpcNumber]
+       if meth.fmt != m.fmt {
+               switch {
+               case len(m.fmt) < len(meth.fmt):
+                       m.status = ErrTooFewArgs
+               case len(m.fmt) > len(meth.fmt):
+                       m.status = ErrTooManyArgs
+               default:
+                       // There's a type mismatch.
+                       // It's an in-arg mismatch if the mismatch happens
+                       // before the colon; otherwise it's an out-arg mismatch.
+                       m.status = ErrInArgTypeMismatch
+                       for i := 0; i < len(m.fmt) && m.fmt[i] == meth.fmt[i]; i++ {
+                               if m.fmt[i] == ':' {
+                                       m.status = ErrOutArgTypeMismatch
+                                       break
+                               }
+                       }
+               }
+               c <- m
+               return
+       }
+
+       m.status = meth.handler.Run(m.Arg, m.Ret, m.Size)
+       c <- m
+}
+
+// ServeRuntime serves RPCs issued by the Native Client embedded runtime.
+// This should be called by main once all methods have been registered using Add.
+func ServeRuntime() os.Error {
+       // Call getFd to check that we are running embedded.
+       if _, err := getFd(); err != nil {
+               return err
+       }
+
+       // We are running embedded.
+       // The fd returned by getFd is a red herring.
+       // Accept connections on magic fd 3.
+       return Serve(3)
+}
+
+// getFd runs the srpc_get_fd system call.
+func getFd() (fd int, err os.Error) {
+       r1, _, e := syscall.Syscall(syscall.SYS_SRPC_GET_FD, 0, 0, 0)
+       return int(r1), os.NewSyscallError("srpc_get_fd", int(e))
+}
+
+// Enabled returns true if SRPC is enabled in the Native Client runtime.
+func Enabled() bool {
+       _, err := getFd()
+       return err == nil
+}
+
+// Service #0, service_discovery, returns a list of the other services
+// and their argument formats.
+type serviceDiscovery struct{}
+
+func (serviceDiscovery) Run(arg, ret []interface{}, size []int) Errno {
+       var b bytes.Buffer
+       for _, m := range rpcMethod {
+               b.WriteString(m.name)
+               b.WriteByte(':')
+               b.WriteString(m.fmt)
+               b.WriteByte('\n')
+       }
+       if b.Len() > size[0] {
+               return ErrNoMemory
+       }
+       ret[0] = b.Bytes()
+       return OK
+}
+
+func init() { Add("service_discovery", ":C", serviceDiscovery{}) }
diff --git a/libgo/go/exp/ogle/abort.go b/libgo/go/exp/ogle/abort.go
new file mode 100644 (file)
index 0000000..311a7b3
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "os"
+       "runtime"
+)
+
+// An aborter aborts the thread's current computation, usually
+// passing the error to a waiting thread.
+type aborter interface {
+       Abort(err os.Error)
+}
+
+type ogleAborter chan os.Error
+
+func (a ogleAborter) Abort(err os.Error) {
+       a <- err
+       runtime.Goexit()
+}
+
+// try executes a computation; if the computation Aborts, try returns
+// the error passed to abort.
+func try(f func(a aborter)) os.Error {
+       a := make(ogleAborter)
+       go func() {
+               f(a)
+               a <- nil
+       }()
+       err := <-a
+       return err
+}
diff --git a/libgo/go/exp/ogle/arch.go b/libgo/go/exp/ogle/arch.go
new file mode 100644 (file)
index 0000000..52b1c97
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "debug/proc"
+       "math"
+)
+
+type Arch interface {
+       // ToWord converts an array of up to 8 bytes in memory order
+       // to a word.
+       ToWord(data []byte) proc.Word
+       // FromWord converts a word to an array of up to 8 bytes in
+       // memory order.
+       FromWord(v proc.Word, out []byte)
+       // ToFloat32 converts a word to a float.  The order of this
+       // word will be the order returned by ToWord on the memory
+       // representation of a float, and thus may require reversing.
+       ToFloat32(bits uint32) float32
+       // FromFloat32 converts a float to a word.  This should return
+       // a word that can be passed to FromWord to get the memory
+       // representation of a float on this architecture.
+       FromFloat32(f float32) uint32
+       // ToFloat64 is to float64 as ToFloat32 is to float32.
+       ToFloat64(bits uint64) float64
+       // FromFloat64 is to float64 as FromFloat32 is to float32.
+       FromFloat64(f float64) uint64
+
+       // IntSize returns the number of bytes in an 'int'.
+       IntSize() int
+       // PtrSize returns the number of bytes in a 'uintptr'.
+       PtrSize() int
+       // FloatSize returns the number of bytes in a 'float'.
+       FloatSize() int
+       // Align rounds offset up to the appropriate offset for a
+       // basic type with the given width.
+       Align(offset, width int) int
+
+       // G returns the current G pointer.
+       G(regs proc.Regs) proc.Word
+
+       // ClosureSize returns the number of bytes expected by
+       // ParseClosure.
+       ClosureSize() int
+       // ParseClosure takes ClosureSize bytes read from a return PC
+       // in a remote process, determines if the code is a closure,
+       // and returns the frame size of the closure if it is.
+       ParseClosure(data []byte) (frame int, ok bool)
+}
+
+type ArchLSB struct{}
+
+func (ArchLSB) ToWord(data []byte) proc.Word {
+       var v proc.Word
+       for i, b := range data {
+               v |= proc.Word(b) << (uint(i) * 8)
+       }
+       return v
+}
+
+func (ArchLSB) FromWord(v proc.Word, out []byte) {
+       for i := range out {
+               out[i] = byte(v)
+               v >>= 8
+       }
+}
+
+func (ArchLSB) ToFloat32(bits uint32) float32 {
+       // TODO(austin) Do these definitions depend on my current
+       // architecture?
+       return math.Float32frombits(bits)
+}
+
+func (ArchLSB) FromFloat32(f float32) uint32 { return math.Float32bits(f) }
+
+func (ArchLSB) ToFloat64(bits uint64) float64 { return math.Float64frombits(bits) }
+
+func (ArchLSB) FromFloat64(f float64) uint64 { return math.Float64bits(f) }
+
+type ArchAlignedMultiple struct{}
+
+func (ArchAlignedMultiple) Align(offset, width int) int {
+       return ((offset - 1) | (width - 1)) + 1
+}
+
+type amd64 struct {
+       ArchLSB
+       ArchAlignedMultiple
+       gReg int
+}
+
+func (a *amd64) IntSize() int { return 4 }
+
+func (a *amd64) PtrSize() int { return 8 }
+
+func (a *amd64) FloatSize() int { return 4 }
+
+func (a *amd64) G(regs proc.Regs) proc.Word {
+       // See src/pkg/runtime/mkasmh
+       if a.gReg == -1 {
+               ns := regs.Names()
+               for i, n := range ns {
+                       if n == "r15" {
+                               a.gReg = i
+                               break
+                       }
+               }
+       }
+
+       return regs.Get(a.gReg)
+}
+
+func (a *amd64) ClosureSize() int { return 8 }
+
+func (a *amd64) ParseClosure(data []byte) (int, bool) {
+       if data[0] == 0x48 && data[1] == 0x81 && data[2] == 0xc4 && data[7] == 0xc3 {
+               return int(a.ToWord(data[3:7]) + 8), true
+       }
+       return 0, false
+}
+
+var Amd64 = &amd64{gReg: -1}
diff --git a/libgo/go/exp/ogle/cmd.go b/libgo/go/exp/ogle/cmd.go
new file mode 100644 (file)
index 0000000..d3672c2
--- /dev/null
@@ -0,0 +1,372 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Ogle is the beginning of a debugger for Go.
+package ogle
+
+import (
+       "bufio"
+       "debug/elf"
+       "debug/proc"
+       "exp/eval"
+       "fmt"
+       "go/scanner"
+       "go/token"
+       "os"
+       "strconv"
+       "strings"
+)
+
+var world *eval.World
+var curProc *Process
+
+func Main() {
+       world = eval.NewWorld()
+       defineFuncs()
+       r := bufio.NewReader(os.Stdin)
+       for {
+               print("; ")
+               line, err := r.ReadSlice('\n')
+               if err != nil {
+                       break
+               }
+
+               // Try line as a command
+               cmd, rest := getCmd(line)
+               if cmd != nil {
+                       err := cmd.handler(rest)
+                       if err != nil {
+                               scanner.PrintError(os.Stderr, err)
+                       }
+                       continue
+               }
+
+               // Try line as code
+               code, err := world.Compile(string(line))
+               if err != nil {
+                       scanner.PrintError(os.Stderr, err)
+                       continue
+               }
+               v, err := code.Run()
+               if err != nil {
+                       fmt.Fprintf(os.Stderr, err.String())
+                       continue
+               }
+               if v != nil {
+                       println(v.String())
+               }
+       }
+}
+
+// newScanner creates a new scanner that scans that given input bytes.
+func newScanner(input []byte) (*scanner.Scanner, *scanner.ErrorVector) {
+       sc := new(scanner.Scanner)
+       ev := new(scanner.ErrorVector)
+       sc.Init("input", input, ev, 0)
+
+       return sc, ev
+}
+
+/*
+ * Commands
+ */
+
+// A UsageError occurs when a command is called with illegal arguments.
+type UsageError string
+
+func (e UsageError) String() string { return string(e) }
+
+// A cmd represents a single command with a handler.
+type cmd struct {
+       cmd     string
+       handler func([]byte) os.Error
+}
+
+var cmds = []cmd{
+       {"load", cmdLoad},
+       {"bt", cmdBt},
+}
+
+// getCmd attempts to parse an input line as a registered command.  If
+// successful, it returns the command and the bytes remaining after
+// the command, which should be passed to the command.
+func getCmd(line []byte) (*cmd, []byte) {
+       sc, _ := newScanner(line)
+       pos, tok, lit := sc.Scan()
+       if sc.ErrorCount != 0 || tok != token.IDENT {
+               return nil, nil
+       }
+
+       slit := string(lit)
+       for i := range cmds {
+               if cmds[i].cmd == slit {
+                       return &cmds[i], line[pos.Offset+len(lit):]
+               }
+       }
+       return nil, nil
+}
+
+// cmdLoad starts or attaches to a process.  Its form is similar to
+// import:
+//
+//  load [sym] "path" [;]
+//
+// sym specifies the name to give to the process.  If not given, the
+// name is derived from the path of the process.  If ".", then the
+// packages from the remote process are defined into the current
+// namespace.  If given, this symbol is defined as a package
+// containing the process' packages.
+//
+// path gives the path of the process to start or attach to.  If it is
+// "pid:<num>", then attach to the given PID.  Otherwise, treat it as
+// a file path and space-separated arguments and start a new process.
+//
+// load always sets the current process to the loaded process.
+func cmdLoad(args []byte) os.Error {
+       ident, path, err := parseLoad(args)
+       if err != nil {
+               return err
+       }
+       if curProc != nil {
+               return UsageError("multiple processes not implemented")
+       }
+       if ident != "." {
+               return UsageError("process identifiers not implemented")
+       }
+
+       // Parse argument and start or attach to process
+       var fname string
+       var tproc proc.Process
+       if len(path) >= 4 && path[0:4] == "pid:" {
+               pid, err := strconv.Atoi(path[4:])
+               if err != nil {
+                       return err
+               }
+               fname, err = os.Readlink(fmt.Sprintf("/proc/%d/exe", pid))
+               if err != nil {
+                       return err
+               }
+               tproc, err = proc.Attach(pid)
+               if err != nil {
+                       return err
+               }
+               println("Attached to", pid)
+       } else {
+               parts := strings.Split(path, " ", -1)
+               if len(parts) == 0 {
+                       fname = ""
+               } else {
+                       fname = parts[0]
+               }
+               tproc, err = proc.ForkExec(fname, parts, os.Environ(), "", []*os.File{os.Stdin, os.Stdout, os.Stderr})
+               if err != nil {
+                       return err
+               }
+               println("Started", path)
+               // TODO(austin) If we fail after this point, kill tproc
+               // before detaching.
+       }
+
+       // Get symbols
+       f, err := os.Open(fname, os.O_RDONLY, 0)
+       if err != nil {
+               tproc.Detach()
+               return err
+       }
+       defer f.Close()
+       elf, err := elf.NewFile(f)
+       if err != nil {
+               tproc.Detach()
+               return err
+       }
+       curProc, err = NewProcessElf(tproc, elf)
+       if err != nil {
+               tproc.Detach()
+               return err
+       }
+
+       // Prepare new process
+       curProc.OnGoroutineCreate().AddHandler(EventPrint)
+       curProc.OnGoroutineExit().AddHandler(EventPrint)
+
+       err = curProc.populateWorld(world)
+       if err != nil {
+               tproc.Detach()
+               return err
+       }
+
+       return nil
+}
+
+func parseLoad(args []byte) (ident string, path string, err os.Error) {
+       err = UsageError("Usage: load [sym] \"path\"")
+       sc, ev := newScanner(args)
+
+       var toks [4]token.Token
+       var lits [4][]byte
+       for i := range toks {
+               _, toks[i], lits[i] = sc.Scan()
+       }
+       if sc.ErrorCount != 0 {
+               err = ev.GetError(scanner.NoMultiples)
+               return
+       }
+
+       i := 0
+       switch toks[i] {
+       case token.PERIOD, token.IDENT:
+               ident = string(lits[i])
+               i++
+       }
+
+       if toks[i] != token.STRING {
+               return
+       }
+       path, uerr := strconv.Unquote(string(lits[i]))
+       if uerr != nil {
+               err = uerr
+               return
+       }
+       i++
+
+       if toks[i] == token.SEMICOLON {
+               i++
+       }
+       if toks[i] != token.EOF {
+               return
+       }
+
+       return ident, path, nil
+}
+
+// cmdBt prints a backtrace for the current goroutine.  It takes no
+// arguments.
+func cmdBt(args []byte) os.Error {
+       err := parseNoArgs(args, "Usage: bt")
+       if err != nil {
+               return err
+       }
+
+       if curProc == nil || curProc.curGoroutine == nil {
+               return NoCurrentGoroutine{}
+       }
+
+       f := curProc.curGoroutine.frame
+       if f == nil {
+               fmt.Println("No frames on stack")
+               return nil
+       }
+
+       for f.Inner() != nil {
+               f = f.Inner()
+       }
+
+       for i := 0; i < 100; i++ {
+               if f == curProc.curGoroutine.frame {
+                       fmt.Printf("=> ")
+               } else {
+                       fmt.Printf("   ")
+               }
+               fmt.Printf("%8x %v\n", f.pc, f)
+               f, err = f.Outer()
+               if err != nil {
+                       return err
+               }
+               if f == nil {
+                       return nil
+               }
+       }
+
+       fmt.Println("...")
+       return nil
+}
+
+func parseNoArgs(args []byte, usage string) os.Error {
+       sc, ev := newScanner(args)
+       _, tok, _ := sc.Scan()
+       if sc.ErrorCount != 0 {
+               return ev.GetError(scanner.NoMultiples)
+       }
+       if tok != token.EOF {
+               return UsageError(usage)
+       }
+       return nil
+}
+
+/*
+ * Functions
+ */
+
+// defineFuncs populates world with the built-in functions.
+func defineFuncs() {
+       t, v := eval.FuncFromNativeTyped(fnOut, fnOutSig)
+       world.DefineConst("Out", t, v)
+       t, v = eval.FuncFromNativeTyped(fnContWait, fnContWaitSig)
+       world.DefineConst("ContWait", t, v)
+       t, v = eval.FuncFromNativeTyped(fnBpSet, fnBpSetSig)
+       world.DefineConst("BpSet", t, v)
+}
+
+// printCurFrame prints the current stack frame, as it would appear in
+// a backtrace.
+func printCurFrame() {
+       if curProc == nil || curProc.curGoroutine == nil {
+               return
+       }
+       f := curProc.curGoroutine.frame
+       if f == nil {
+               return
+       }
+       fmt.Printf("=> %8x %v\n", f.pc, f)
+}
+
+// fnOut moves the current frame to the caller of the current frame.
+func fnOutSig() {}
+func fnOut(t *eval.Thread, args []eval.Value, res []eval.Value) {
+       if curProc == nil {
+               t.Abort(NoCurrentGoroutine{})
+       }
+       err := curProc.Out()
+       if err != nil {
+               t.Abort(err)
+       }
+       // TODO(austin) Only in the command form
+       printCurFrame()
+}
+
+// fnContWait continues the current process and waits for a stopping event.
+func fnContWaitSig() {}
+func fnContWait(t *eval.Thread, args []eval.Value, res []eval.Value) {
+       if curProc == nil {
+               t.Abort(NoCurrentGoroutine{})
+       }
+       err := curProc.ContWait()
+       if err != nil {
+               t.Abort(err)
+       }
+       // TODO(austin) Only in the command form
+       ev := curProc.Event()
+       if ev != nil {
+               fmt.Printf("%v\n", ev)
+       }
+       printCurFrame()
+}
+
+// fnBpSet sets a breakpoint at the entry to the named function.
+func fnBpSetSig(string) {}
+func fnBpSet(t *eval.Thread, args []eval.Value, res []eval.Value) {
+       // TODO(austin) This probably shouldn't take a symbol name.
+       // Perhaps it should take an interface that provides PC's.
+       // Functions and instructions can implement that interface and
+       // we can have something to translate file:line pairs.
+       if curProc == nil {
+               t.Abort(NoCurrentGoroutine{})
+       }
+       name := args[0].(eval.StringValue).Get(t)
+       fn := curProc.syms.LookupFunc(name)
+       if fn == nil {
+               t.Abort(UsageError("no such function " + name))
+       }
+       curProc.OnBreakpoint(proc.Word(fn.Entry)).AddHandler(EventStop)
+}
diff --git a/libgo/go/exp/ogle/event.go b/libgo/go/exp/ogle/event.go
new file mode 100644 (file)
index 0000000..d7092de
--- /dev/null
@@ -0,0 +1,280 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "debug/proc"
+       "fmt"
+       "os"
+)
+
+/*
+ * Hooks and events
+ */
+
+// An EventHandler is a function that takes an event and returns a
+// response to that event and possibly an error.  If an event handler
+// returns an error, the process stops and no other handlers for that
+// event are executed.
+type EventHandler func(e Event) (EventAction, os.Error)
+
+// An EventAction is an event handler's response to an event.  If all
+// of an event's handlers execute without returning errors, their
+// results are combined as follows: If any handler returned
+// EAContinue, then the process resumes (without returning from
+// WaitStop); otherwise, if any handler returned EAStop, the process
+// remains stopped; otherwise, if all handlers returned EADefault, the
+// process resumes.  A handler may return EARemoveSelf bit-wise or'd
+// with any other action to indicate that the handler should be
+// removed from the hook.
+type EventAction int
+
+const (
+       EARemoveSelf EventAction = 0x100
+       EADefault    EventAction = iota
+       EAStop
+       EAContinue
+)
+
+// A EventHook allows event handlers to be added and removed.
+type EventHook interface {
+       AddHandler(EventHandler)
+       RemoveHandler(EventHandler)
+       NumHandler() int
+       handle(e Event) (EventAction, os.Error)
+       String() string
+}
+
+// EventHook is almost, but not quite, suitable for user-defined
+// events.  If we want user-defined events, make EventHook a struct,
+// special-case adding and removing handlers in breakpoint hooks, and
+// provide a public interface for posting events to hooks.
+
+type Event interface {
+       Process() *Process
+       Goroutine() *Goroutine
+       String() string
+}
+
+type commonHook struct {
+       // Head of handler chain
+       head *handler
+       // Number of non-internal handlers
+       len int
+}
+
+type handler struct {
+       eh EventHandler
+       // True if this handler must be run before user-defined
+       // handlers in order to ensure correctness.
+       internal bool
+       // True if this handler has been removed from the chain.
+       removed bool
+       next    *handler
+}
+
+func (h *commonHook) AddHandler(eh EventHandler) {
+       h.addHandler(eh, false)
+}
+
+func (h *commonHook) addHandler(eh EventHandler, internal bool) {
+       // Ensure uniqueness of handlers
+       h.RemoveHandler(eh)
+
+       if !internal {
+               h.len++
+       }
+       // Add internal handlers to the beginning
+       if internal || h.head == nil {
+               h.head = &handler{eh, internal, false, h.head}
+               return
+       }
+       // Add handler after internal handlers
+       // TODO(austin) This should probably go on the end instead
+       prev := h.head
+       for prev.next != nil && prev.internal {
+               prev = prev.next
+       }
+       prev.next = &handler{eh, internal, false, prev.next}
+}
+
+func (h *commonHook) RemoveHandler(eh EventHandler) {
+       plink := &h.head
+       for l := *plink; l != nil; plink, l = &l.next, l.next {
+               if l.eh == eh {
+                       if !l.internal {
+                               h.len--
+                       }
+                       l.removed = true
+                       *plink = l.next
+                       break
+               }
+       }
+}
+
+func (h *commonHook) NumHandler() int { return h.len }
+
+func (h *commonHook) handle(e Event) (EventAction, os.Error) {
+       action := EADefault
+       plink := &h.head
+       for l := *plink; l != nil; plink, l = &l.next, l.next {
+               if l.removed {
+                       continue
+               }
+               a, err := l.eh(e)
+               if a&EARemoveSelf == EARemoveSelf {
+                       if !l.internal {
+                               h.len--
+                       }
+                       l.removed = true
+                       *plink = l.next
+                       a &^= EARemoveSelf
+               }
+               if err != nil {
+                       return EAStop, err
+               }
+               if a > action {
+                       action = a
+               }
+       }
+       return action, nil
+}
+
+type commonEvent struct {
+       // The process of this event
+       p *Process
+       // The goroutine of this event.
+       t *Goroutine
+}
+
+func (e *commonEvent) Process() *Process { return e.p }
+
+func (e *commonEvent) Goroutine() *Goroutine { return e.t }
+
+/*
+ * Standard event handlers
+ */
+
+// EventPrint is a standard event handler that prints events as they
+// occur.  It will not cause the process to stop.
+func EventPrint(ev Event) (EventAction, os.Error) {
+       // TODO(austin) Include process name here?
+       fmt.Fprintf(os.Stderr, "*** %v\n", ev.String())
+       return EADefault, nil
+}
+
+// EventStop is a standard event handler that causes the process to stop.
+func EventStop(ev Event) (EventAction, os.Error) {
+       return EAStop, nil
+}
+
+/*
+ * Breakpoints
+ */
+
+type breakpointHook struct {
+       commonHook
+       p  *Process
+       pc proc.Word
+}
+
+// A Breakpoint event occurs when a process reaches a particular
+// program counter.  When this event is handled, the current goroutine
+// will be the goroutine that reached the program counter.
+type Breakpoint struct {
+       commonEvent
+       osThread proc.Thread
+       pc       proc.Word
+}
+
+func (h *breakpointHook) AddHandler(eh EventHandler) {
+       h.addHandler(eh, false)
+}
+
+func (h *breakpointHook) addHandler(eh EventHandler, internal bool) {
+       // We register breakpoint events lazily to avoid holding
+       // references to breakpoints without handlers.  Be sure to use
+       // the "canonical" breakpoint if there is one.
+       if cur, ok := h.p.breakpointHooks[h.pc]; ok {
+               h = cur
+       }
+       oldhead := h.head
+       h.commonHook.addHandler(eh, internal)
+       if oldhead == nil && h.head != nil {
+               h.p.proc.AddBreakpoint(h.pc)
+               h.p.breakpointHooks[h.pc] = h
+       }
+}
+
+func (h *breakpointHook) RemoveHandler(eh EventHandler) {
+       oldhead := h.head
+       h.commonHook.RemoveHandler(eh)
+       if oldhead != nil && h.head == nil {
+               h.p.proc.RemoveBreakpoint(h.pc)
+               h.p.breakpointHooks[h.pc] = nil, false
+       }
+}
+
+func (h *breakpointHook) String() string {
+       // TODO(austin) Include process name?
+       // TODO(austin) Use line:pc or at least sym+%#x
+       return fmt.Sprintf("breakpoint at %#x", h.pc)
+}
+
+func (b *Breakpoint) PC() proc.Word { return b.pc }
+
+func (b *Breakpoint) String() string {
+       // TODO(austin) Include process name and goroutine
+       // TODO(austin) Use line:pc or at least sym+%#x
+       return fmt.Sprintf("breakpoint at %#x", b.pc)
+}
+
+/*
+ * Goroutine create/exit
+ */
+
+type goroutineCreateHook struct {
+       commonHook
+}
+
+func (h *goroutineCreateHook) String() string { return "goroutine create" }
+
+// A GoroutineCreate event occurs when a process creates a new
+// goroutine.  When this event is handled, the current goroutine will
+// be the newly created goroutine.
+type GoroutineCreate struct {
+       commonEvent
+       parent *Goroutine
+}
+
+// Parent returns the goroutine that created this goroutine.  May be
+// nil if this event is the creation of the first goroutine.
+func (e *GoroutineCreate) Parent() *Goroutine { return e.parent }
+
+func (e *GoroutineCreate) String() string {
+       // TODO(austin) Include process name
+       if e.parent == nil {
+               return fmt.Sprintf("%v created", e.t)
+       }
+       return fmt.Sprintf("%v created by %v", e.t, e.parent)
+}
+
+type goroutineExitHook struct {
+       commonHook
+}
+
+func (h *goroutineExitHook) String() string { return "goroutine exit" }
+
+// A GoroutineExit event occurs when a Go goroutine exits.
+type GoroutineExit struct {
+       commonEvent
+}
+
+func (e *GoroutineExit) String() string {
+       // TODO(austin) Include process name
+       //return fmt.Sprintf("%v exited", e.t);
+       // For debugging purposes
+       return fmt.Sprintf("goroutine %#x exited", e.t.g.addr().base)
+}
diff --git a/libgo/go/exp/ogle/frame.go b/libgo/go/exp/ogle/frame.go
new file mode 100644 (file)
index 0000000..1538362
--- /dev/null
@@ -0,0 +1,212 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "debug/gosym"
+       "debug/proc"
+       "fmt"
+       "os"
+)
+
+// A Frame represents a single frame on a remote call stack.
+type Frame struct {
+       // pc is the PC of the next instruction that will execute in
+       // this frame.  For lower frames, this is the instruction
+       // following the CALL instruction.
+       pc, sp, fp proc.Word
+       // The runtime.Stktop of the active stack segment
+       stk remoteStruct
+       // The function this stack frame is in
+       fn *gosym.Func
+       // The path and line of the CALL or current instruction.  Note
+       // that this differs slightly from the meaning of Frame.pc.
+       path string
+       line int
+       // The inner and outer frames of this frame.  outer is filled
+       // in lazily.
+       inner, outer *Frame
+}
+
+// newFrame returns the top-most Frame of the given g's thread.
+func newFrame(g remoteStruct) (*Frame, os.Error) {
+       var f *Frame
+       err := try(func(a aborter) { f = aNewFrame(a, g) })
+       return f, err
+}
+
+func aNewFrame(a aborter, g remoteStruct) *Frame {
+       p := g.r.p
+       var pc, sp proc.Word
+
+       // Is this G alive?
+       switch g.field(p.f.G.Status).(remoteInt).aGet(a) {
+       case p.runtime.Gidle, p.runtime.Gmoribund, p.runtime.Gdead:
+               return nil
+       }
+
+       // Find the OS thread for this G
+
+       // TODO(austin) Ideally, we could look at the G's state and
+       // figure out if it's on an OS thread or not.  However, this
+       // is difficult because the state isn't updated atomically
+       // with scheduling changes.
+       for _, t := range p.proc.Threads() {
+               regs, err := t.Regs()
+               if err != nil {
+                       // TODO(austin) What to do?
+                       continue
+               }
+               thisg := p.G(regs)
+               if thisg == g.addr().base {
+                       // Found this G's OS thread
+                       pc = regs.PC()
+                       sp = regs.SP()
+
+                       // If this thread crashed, try to recover it
+                       if pc == 0 {
+                               pc = p.peekUintptr(a, pc)
+                               sp += 8
+                       }
+
+                       break
+               }
+       }
+
+       if pc == 0 && sp == 0 {
+               // G is not mapped to an OS thread.  Use the
+               // scheduler's stored PC and SP.
+               sched := g.field(p.f.G.Sched).(remoteStruct)
+               pc = proc.Word(sched.field(p.f.Gobuf.Pc).(remoteUint).aGet(a))
+               sp = proc.Word(sched.field(p.f.Gobuf.Sp).(remoteUint).aGet(a))
+       }
+
+       // Get Stktop
+       stk := g.field(p.f.G.Stackbase).(remotePtr).aGet(a).(remoteStruct)
+
+       return prepareFrame(a, pc, sp, stk, nil)
+}
+
+// prepareFrame creates a Frame from the PC and SP within that frame,
+// as well as the active stack segment.  This function takes care of
+// traversing stack breaks and unwinding closures.
+func prepareFrame(a aborter, pc, sp proc.Word, stk remoteStruct, inner *Frame) *Frame {
+       // Based on src/pkg/runtime/amd64/traceback.c:traceback
+       p := stk.r.p
+       top := inner == nil
+
+       // Get function
+       var path string
+       var line int
+       var fn *gosym.Func
+
+       for i := 0; i < 100; i++ {
+               // Traverse segmented stack breaks
+               if p.sys.lessstack != nil && pc == proc.Word(p.sys.lessstack.Value) {
+                       // Get stk->gobuf.pc
+                       pc = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Pc).(remoteUint).aGet(a))
+                       // Get stk->gobuf.sp
+                       sp = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Sp).(remoteUint).aGet(a))
+                       // Get stk->stackbase
+                       stk = stk.field(p.f.Stktop.Stackbase).(remotePtr).aGet(a).(remoteStruct)
+                       continue
+               }
+
+               // Get the PC of the call instruction
+               callpc := pc
+               if !top && (p.sys.goexit == nil || pc != proc.Word(p.sys.goexit.Value)) {
+                       callpc--
+               }
+
+               // Look up function
+               path, line, fn = p.syms.PCToLine(uint64(callpc))
+               if fn != nil {
+                       break
+               }
+
+               // Closure?
+               var buf = make([]byte, p.ClosureSize())
+               if _, err := p.Peek(pc, buf); err != nil {
+                       break
+               }
+               spdelta, ok := p.ParseClosure(buf)
+               if ok {
+                       sp += proc.Word(spdelta)
+                       pc = p.peekUintptr(a, sp-proc.Word(p.PtrSize()))
+               }
+       }
+       if fn == nil {
+               return nil
+       }
+
+       // Compute frame pointer
+       var fp proc.Word
+       if fn.FrameSize < p.PtrSize() {
+               fp = sp + proc.Word(p.PtrSize())
+       } else {
+               fp = sp + proc.Word(fn.FrameSize)
+       }
+       // TODO(austin) To really figure out if we're in the prologue,
+       // we need to disassemble the function and look for the call
+       // to morestack.  For now, just special case the entry point.
+       //
+       // TODO(austin) What if we're in the call to morestack in the
+       // prologue?  Then top == false.
+       if top && pc == proc.Word(fn.Entry) {
+               // We're in the function prologue, before SP
+               // has been adjusted for the frame.
+               fp -= proc.Word(fn.FrameSize - p.PtrSize())
+       }
+
+       return &Frame{pc, sp, fp, stk, fn, path, line, inner, nil}
+}
+
+// Outer returns the Frame that called this Frame, or nil if this is
+// the outermost frame.
+func (f *Frame) Outer() (*Frame, os.Error) {
+       var fr *Frame
+       err := try(func(a aborter) { fr = f.aOuter(a) })
+       return fr, err
+}
+
+func (f *Frame) aOuter(a aborter) *Frame {
+       // Is there a cached outer frame
+       if f.outer != nil {
+               return f.outer
+       }
+
+       p := f.stk.r.p
+
+       sp := f.fp
+       if f.fn == p.sys.newproc && f.fn == p.sys.deferproc {
+               // TODO(rsc) The compiler inserts two push/pop's
+               // around calls to go and defer.  Russ says this
+               // should get fixed in the compiler, but we account
+               // for it for now.
+               sp += proc.Word(2 * p.PtrSize())
+       }
+
+       pc := p.peekUintptr(a, f.fp-proc.Word(p.PtrSize()))
+       if pc < 0x1000 {
+               return nil
+       }
+
+       // TODO(austin) Register this frame for shoot-down.
+
+       f.outer = prepareFrame(a, pc, sp, f.stk, f)
+       return f.outer
+}
+
+// Inner returns the Frame called by this Frame, or nil if this is the
+// innermost frame.
+func (f *Frame) Inner() *Frame { return f.inner }
+
+func (f *Frame) String() string {
+       res := f.fn.Name
+       if f.pc > proc.Word(f.fn.Value) {
+               res += fmt.Sprintf("+%#x", f.pc-proc.Word(f.fn.Entry))
+       }
+       return res + fmt.Sprintf(" %s:%d", f.path, f.line)
+}
diff --git a/libgo/go/exp/ogle/goroutine.go b/libgo/go/exp/ogle/goroutine.go
new file mode 100644 (file)
index 0000000..5104ec6
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "debug/proc"
+       "exp/eval"
+       "fmt"
+       "os"
+)
+
+// A Goroutine represents a goroutine in a remote process.
+type Goroutine struct {
+       g     remoteStruct
+       frame *Frame
+       dead  bool
+}
+
+func (t *Goroutine) String() string {
+       if t.dead {
+               return "<dead thread>"
+       }
+       // TODO(austin) Give threads friendly ID's, possibly including
+       // the name of the entry function.
+       return fmt.Sprintf("thread %#x", t.g.addr().base)
+}
+
+// isG0 returns true if this thread if the internal idle thread
+func (t *Goroutine) isG0() bool { return t.g.addr().base == t.g.r.p.sys.g0.addr().base }
+
+func (t *Goroutine) resetFrame() (err os.Error) {
+       // TODO(austin) Reuse any live part of the current frame stack
+       // so existing references to Frame's keep working.
+       t.frame, err = newFrame(t.g)
+       return
+}
+
+// Out selects the caller frame of the current frame.
+func (t *Goroutine) Out() os.Error {
+       f, err := t.frame.Outer()
+       if f != nil {
+               t.frame = f
+       }
+       return err
+}
+
+// In selects the frame called by the current frame.
+func (t *Goroutine) In() os.Error {
+       f := t.frame.Inner()
+       if f != nil {
+               t.frame = f
+       }
+       return nil
+}
+
+func readylockedBP(ev Event) (EventAction, os.Error) {
+       b := ev.(*Breakpoint)
+       p := b.Process()
+
+       // The new g is the only argument to this function, so the
+       // stack will have the return address, then the G*.
+       regs, err := b.osThread.Regs()
+       if err != nil {
+               return EAStop, err
+       }
+       sp := regs.SP()
+       addr := sp + proc.Word(p.PtrSize())
+       arg := remotePtr{remote{addr, p}, p.runtime.G}
+       var gp eval.Value
+       err = try(func(a aborter) { gp = arg.aGet(a) })
+       if err != nil {
+               return EAStop, err
+       }
+       if gp == nil {
+               return EAStop, UnknownGoroutine{b.osThread, 0}
+       }
+       gs := gp.(remoteStruct)
+       g := &Goroutine{gs, nil, false}
+       p.goroutines[gs.addr().base] = g
+
+       // Enqueue goroutine creation event
+       parent := b.Goroutine()
+       if parent.isG0() {
+               parent = nil
+       }
+       p.postEvent(&GoroutineCreate{commonEvent{p, g}, parent})
+
+       // If we don't have any thread selected, select this one
+       if p.curGoroutine == nil {
+               p.curGoroutine = g
+       }
+
+       return EADefault, nil
+}
+
+func goexitBP(ev Event) (EventAction, os.Error) {
+       b := ev.(*Breakpoint)
+       p := b.Process()
+
+       g := b.Goroutine()
+       g.dead = true
+
+       addr := g.g.addr().base
+       p.goroutines[addr] = nil, false
+
+       // Enqueue thread exit event
+       p.postEvent(&GoroutineExit{commonEvent{p, g}})
+
+       // If we just exited our selected goroutine, selected another
+       if p.curGoroutine == g {
+               p.selectSomeGoroutine()
+       }
+
+       return EADefault, nil
+}
diff --git a/libgo/go/exp/ogle/main.go b/libgo/go/exp/ogle/main.go
new file mode 100644 (file)
index 0000000..1999ecc
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "exp/ogle"
+
+func main() { ogle.Main() }
diff --git a/libgo/go/exp/ogle/process.go b/libgo/go/exp/ogle/process.go
new file mode 100644 (file)
index 0000000..58e830a
--- /dev/null
@@ -0,0 +1,521 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "debug/elf"
+       "debug/gosym"
+       "debug/proc"
+       "exp/eval"
+       "fmt"
+       "log"
+       "os"
+       "reflect"
+)
+
+// A FormatError indicates a failure to process information in or
+// about a remote process, such as unexpected or missing information
+// in the object file or runtime structures.
+type FormatError string
+
+func (e FormatError) String() string { return string(e) }
+
+// An UnknownArchitecture occurs when trying to load an object file
+// that indicates an architecture not supported by the debugger.
+type UnknownArchitecture elf.Machine
+
+func (e UnknownArchitecture) String() string {
+       return "unknown architecture: " + elf.Machine(e).String()
+}
+
+// A ProcessNotStopped error occurs when attempting to read or write
+// memory or registers of a process that is not stopped.
+type ProcessNotStopped struct{}
+
+func (e ProcessNotStopped) String() string { return "process not stopped" }
+
+// An UnknownGoroutine error is an internal error representing an
+// unrecognized G structure pointer.
+type UnknownGoroutine struct {
+       OSThread  proc.Thread
+       Goroutine proc.Word
+}
+
+func (e UnknownGoroutine) String() string {
+       return fmt.Sprintf("internal error: unknown goroutine (G %#x)", e.Goroutine)
+}
+
+// A NoCurrentGoroutine error occurs when no goroutine is currently
+// selected in a process (or when there are no goroutines in a
+// process).
+type NoCurrentGoroutine struct{}
+
+func (e NoCurrentGoroutine) String() string { return "no current goroutine" }
+
+// A Process represents a remote attached process.
+type Process struct {
+       Arch
+       proc proc.Process
+
+       // The symbol table of this process
+       syms *gosym.Table
+
+       // A possibly-stopped OS thread, or nil
+       threadCache proc.Thread
+
+       // Types parsed from the remote process
+       types map[proc.Word]*remoteType
+
+       // Types and values from the remote runtime package
+       runtime runtimeValues
+
+       // Runtime field indexes
+       f runtimeIndexes
+
+       // Globals from the sys package (or from no package)
+       sys struct {
+               lessstack, goexit, newproc, deferproc, newprocreadylocked *gosym.Func
+               allg                                                      remotePtr
+               g0                                                        remoteStruct
+       }
+
+       // Event queue
+       posted  []Event
+       pending []Event
+       event   Event
+
+       // Event hooks
+       breakpointHooks     map[proc.Word]*breakpointHook
+       goroutineCreateHook *goroutineCreateHook
+       goroutineExitHook   *goroutineExitHook
+
+       // Current goroutine, or nil if there are no goroutines
+       curGoroutine *Goroutine
+
+       // Goroutines by the address of their G structure
+       goroutines map[proc.Word]*Goroutine
+}
+
+/*
+ * Process creation
+ */
+
+// NewProcess constructs a new remote process around a traced
+// process, an architecture, and a symbol table.
+func NewProcess(tproc proc.Process, arch Arch, syms *gosym.Table) (*Process, os.Error) {
+       p := &Process{
+               Arch:                arch,
+               proc:                tproc,
+               syms:                syms,
+               types:               make(map[proc.Word]*remoteType),
+               breakpointHooks:     make(map[proc.Word]*breakpointHook),
+               goroutineCreateHook: new(goroutineCreateHook),
+               goroutineExitHook:   new(goroutineExitHook),
+               goroutines:          make(map[proc.Word]*Goroutine),
+       }
+
+       // Fill in remote runtime
+       p.bootstrap()
+
+       switch {
+       case p.sys.allg.addr().base == 0:
+               return nil, FormatError("failed to find runtime symbol 'allg'")
+       case p.sys.g0.addr().base == 0:
+               return nil, FormatError("failed to find runtime symbol 'g0'")
+       case p.sys.newprocreadylocked == nil:
+               return nil, FormatError("failed to find runtime symbol 'newprocreadylocked'")
+       case p.sys.goexit == nil:
+               return nil, FormatError("failed to find runtime symbol 'sys.goexit'")
+       }
+
+       // Get current goroutines
+       p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false}
+       err := try(func(a aborter) {
+               g := p.sys.allg.aGet(a)
+               for g != nil {
+                       gs := g.(remoteStruct)
+                       fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base)
+                       p.goroutines[gs.addr().base] = &Goroutine{gs, nil, false}
+                       g = gs.field(p.f.G.Alllink).(remotePtr).aGet(a)
+               }
+       })
+       if err != nil {
+               return nil, err
+       }
+
+       // Create internal breakpoints to catch new and exited goroutines
+       p.OnBreakpoint(proc.Word(p.sys.newprocreadylocked.Entry)).(*breakpointHook).addHandler(readylockedBP, true)
+       p.OnBreakpoint(proc.Word(p.sys.goexit.Entry)).(*breakpointHook).addHandler(goexitBP, true)
+
+       // Select current frames
+       for _, g := range p.goroutines {
+               g.resetFrame()
+       }
+
+       p.selectSomeGoroutine()
+
+       return p, nil
+}
+
+func elfGoSyms(f *elf.File) (*gosym.Table, os.Error) {
+       text := f.Section(".text")
+       symtab := f.Section(".gosymtab")
+       pclntab := f.Section(".gopclntab")
+       if text == nil || symtab == nil || pclntab == nil {
+               return nil, nil
+       }
+
+       symdat, err := symtab.Data()
+       if err != nil {
+               return nil, err
+       }
+       pclndat, err := pclntab.Data()
+       if err != nil {
+               return nil, err
+       }
+
+       pcln := gosym.NewLineTable(pclndat, text.Addr)
+       tab, err := gosym.NewTable(symdat, pcln)
+       if err != nil {
+               return nil, err
+       }
+
+       return tab, nil
+}
+
+// NewProcessElf constructs a new remote process around a traced
+// process and the process' ELF object.
+func NewProcessElf(tproc proc.Process, f *elf.File) (*Process, os.Error) {
+       syms, err := elfGoSyms(f)
+       if err != nil {
+               return nil, err
+       }
+       if syms == nil {
+               return nil, FormatError("Failed to find symbol table")
+       }
+       var arch Arch
+       switch f.Machine {
+       case elf.EM_X86_64:
+               arch = Amd64
+       default:
+               return nil, UnknownArchitecture(f.Machine)
+       }
+       return NewProcess(tproc, arch, syms)
+}
+
+// bootstrap constructs the runtime structure of a remote process.
+func (p *Process) bootstrap() {
+       // Manually construct runtime types
+       p.runtime.String = newManualType(eval.TypeOfNative(rt1String{}), p.Arch)
+       p.runtime.Slice = newManualType(eval.TypeOfNative(rt1Slice{}), p.Arch)
+       p.runtime.Eface = newManualType(eval.TypeOfNative(rt1Eface{}), p.Arch)
+
+       p.runtime.Type = newManualType(eval.TypeOfNative(rt1Type{}), p.Arch)
+       p.runtime.CommonType = newManualType(eval.TypeOfNative(rt1CommonType{}), p.Arch)
+       p.runtime.UncommonType = newManualType(eval.TypeOfNative(rt1UncommonType{}), p.Arch)
+       p.runtime.StructField = newManualType(eval.TypeOfNative(rt1StructField{}), p.Arch)
+       p.runtime.StructType = newManualType(eval.TypeOfNative(rt1StructType{}), p.Arch)
+       p.runtime.PtrType = newManualType(eval.TypeOfNative(rt1PtrType{}), p.Arch)
+       p.runtime.ArrayType = newManualType(eval.TypeOfNative(rt1ArrayType{}), p.Arch)
+       p.runtime.SliceType = newManualType(eval.TypeOfNative(rt1SliceType{}), p.Arch)
+
+       p.runtime.Stktop = newManualType(eval.TypeOfNative(rt1Stktop{}), p.Arch)
+       p.runtime.Gobuf = newManualType(eval.TypeOfNative(rt1Gobuf{}), p.Arch)
+       p.runtime.G = newManualType(eval.TypeOfNative(rt1G{}), p.Arch)
+
+       // Get addresses of type.*runtime.XType for discrimination.
+       rtv := reflect.Indirect(reflect.NewValue(&p.runtime)).(*reflect.StructValue)
+       rtvt := rtv.Type().(*reflect.StructType)
+       for i := 0; i < rtv.NumField(); i++ {
+               n := rtvt.Field(i).Name
+               if n[0] != 'P' || n[1] < 'A' || n[1] > 'Z' {
+                       continue
+               }
+               sym := p.syms.LookupSym("type.*runtime." + n[1:])
+               if sym == nil {
+                       continue
+               }
+               rtv.Field(i).(*reflect.UintValue).Set(sym.Value)
+       }
+
+       // Get runtime field indexes
+       fillRuntimeIndexes(&p.runtime, &p.f)
+
+       // Fill G status
+       p.runtime.runtimeGStatus = rt1GStatus
+
+       // Get globals
+       p.sys.lessstack = p.syms.LookupFunc("sys.lessstack")
+       p.sys.goexit = p.syms.LookupFunc("goexit")
+       p.sys.newproc = p.syms.LookupFunc("sys.newproc")
+       p.sys.deferproc = p.syms.LookupFunc("sys.deferproc")
+       p.sys.newprocreadylocked = p.syms.LookupFunc("newprocreadylocked")
+       if allg := p.syms.LookupSym("allg"); allg != nil {
+               p.sys.allg = remotePtr{remote{proc.Word(allg.Value), p}, p.runtime.G}
+       }
+       if g0 := p.syms.LookupSym("g0"); g0 != nil {
+               p.sys.g0 = p.runtime.G.mk(remote{proc.Word(g0.Value), p}).(remoteStruct)
+       }
+}
+
+func (p *Process) selectSomeGoroutine() {
+       // Once we have friendly goroutine ID's, there might be a more
+       // reasonable behavior for this.
+       p.curGoroutine = nil
+       for _, g := range p.goroutines {
+               if !g.isG0() && g.frame != nil {
+                       p.curGoroutine = g
+                       return
+               }
+       }
+}
+
+/*
+ * Process memory
+ */
+
+func (p *Process) someStoppedOSThread() proc.Thread {
+       if p.threadCache != nil {
+               if _, err := p.threadCache.Stopped(); err == nil {
+                       return p.threadCache
+               }
+       }
+
+       for _, t := range p.proc.Threads() {
+               if _, err := t.Stopped(); err == nil {
+                       p.threadCache = t
+                       return t
+               }
+       }
+       return nil
+}
+
+func (p *Process) Peek(addr proc.Word, out []byte) (int, os.Error) {
+       thr := p.someStoppedOSThread()
+       if thr == nil {
+               return 0, ProcessNotStopped{}
+       }
+       return thr.Peek(addr, out)
+}
+
+func (p *Process) Poke(addr proc.Word, b []byte) (int, os.Error) {
+       thr := p.someStoppedOSThread()
+       if thr == nil {
+               return 0, ProcessNotStopped{}
+       }
+       return thr.Poke(addr, b)
+}
+
+func (p *Process) peekUintptr(a aborter, addr proc.Word) proc.Word {
+       return proc.Word(mkUintptr(remote{addr, p}).(remoteUint).aGet(a))
+}
+
+/*
+ * Events
+ */
+
+// OnBreakpoint returns the hook that is run when the program reaches
+// the given program counter.
+func (p *Process) OnBreakpoint(pc proc.Word) EventHook {
+       if bp, ok := p.breakpointHooks[pc]; ok {
+               return bp
+       }
+       // The breakpoint will register itself when a handler is added
+       return &breakpointHook{commonHook{nil, 0}, p, pc}
+}
+
+// OnGoroutineCreate returns the hook that is run when a goroutine is created.
+func (p *Process) OnGoroutineCreate() EventHook {
+       return p.goroutineCreateHook
+}
+
+// OnGoroutineExit returns the hook that is run when a goroutine exits.
+func (p *Process) OnGoroutineExit() EventHook { return p.goroutineExitHook }
+
+// osThreadToGoroutine looks up the goroutine running on an OS thread.
+func (p *Process) osThreadToGoroutine(t proc.Thread) (*Goroutine, os.Error) {
+       regs, err := t.Regs()
+       if err != nil {
+               return nil, err
+       }
+       g := p.G(regs)
+       gt, ok := p.goroutines[g]
+       if !ok {
+               return nil, UnknownGoroutine{t, g}
+       }
+       return gt, nil
+}
+
+// causesToEvents translates the stop causes of the underlying process
+// into an event queue.
+func (p *Process) causesToEvents() ([]Event, os.Error) {
+       // Count causes we're interested in
+       nev := 0
+       for _, t := range p.proc.Threads() {
+               if c, err := t.Stopped(); err == nil {
+                       switch c := c.(type) {
+                       case proc.Breakpoint:
+                               nev++
+                       case proc.Signal:
+                               // TODO(austin)
+                               //nev++;
+                       }
+               }
+       }
+
+       // Translate causes to events
+       events := make([]Event, nev)
+       i := 0
+       for _, t := range p.proc.Threads() {
+               if c, err := t.Stopped(); err == nil {
+                       switch c := c.(type) {
+                       case proc.Breakpoint:
+                               gt, err := p.osThreadToGoroutine(t)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               events[i] = &Breakpoint{commonEvent{p, gt}, t, proc.Word(c)}
+                               i++
+                       case proc.Signal:
+                               // TODO(austin)
+                       }
+               }
+       }
+
+       return events, nil
+}
+
+// postEvent appends an event to the posted queue.  These events will
+// be processed before any currently pending events.
+func (p *Process) postEvent(ev Event) {
+       p.posted = append(p.posted, ev)
+}
+
+// processEvents processes events in the event queue until no events
+// remain, a handler returns EAStop, or a handler returns an error.
+// It returns either EAStop or EAContinue and possibly an error.
+func (p *Process) processEvents() (EventAction, os.Error) {
+       var ev Event
+       for len(p.posted) > 0 {
+               ev, p.posted = p.posted[0], p.posted[1:]
+               action, err := p.processEvent(ev)
+               if action == EAStop {
+                       return action, err
+               }
+       }
+
+       for len(p.pending) > 0 {
+               ev, p.pending = p.pending[0], p.pending[1:]
+               action, err := p.processEvent(ev)
+               if action == EAStop {
+                       return action, err
+               }
+       }
+
+       return EAContinue, nil
+}
+
+// processEvent processes a single event, without manipulating the
+// event queues.  It returns either EAStop or EAContinue and possibly
+// an error.
+func (p *Process) processEvent(ev Event) (EventAction, os.Error) {
+       p.event = ev
+
+       var action EventAction
+       var err os.Error
+       switch ev := p.event.(type) {
+       case *Breakpoint:
+               hook, ok := p.breakpointHooks[ev.pc]
+               if !ok {
+                       break
+               }
+               p.curGoroutine = ev.Goroutine()
+               action, err = hook.handle(ev)
+
+       case *GoroutineCreate:
+               p.curGoroutine = ev.Goroutine()
+               action, err = p.goroutineCreateHook.handle(ev)
+
+       case *GoroutineExit:
+               action, err = p.goroutineExitHook.handle(ev)
+
+       default:
+               log.Panicf("Unknown event type %T in queue", p.event)
+       }
+
+       if err != nil {
+               return EAStop, err
+       } else if action == EAStop {
+               return EAStop, nil
+       }
+       return EAContinue, nil
+}
+
+// Event returns the last event that caused the process to stop.  This
+// may return nil if the process has never been stopped by an event.
+//
+// TODO(austin) Return nil if the user calls p.Stop()?
+func (p *Process) Event() Event { return p.event }
+
+/*
+ * Process control
+ */
+
+// TODO(austin) Cont, WaitStop, and Stop.  Need to figure out how
+// event handling works with these.  Originally I did it only in
+// WaitStop, but if you Cont and there are pending events, then you
+// have to not actually continue and wait until a WaitStop to process
+// them, even if the event handlers will tell you to continue.  We
+// could handle them in both Cont and WaitStop to avoid this problem,
+// but it's still weird if an event happens after the Cont and before
+// the WaitStop that the handlers say to continue from.  Or we could
+// handle them on a separate thread.  Then obviously you get weird
+// asynchronous things, like prints while the user it typing a command,
+// but that's not necessarily a bad thing.
+
+// ContWait resumes process execution and waits for an event to occur
+// that stops the process.
+func (p *Process) ContWait() os.Error {
+       for {
+               a, err := p.processEvents()
+               if err != nil {
+                       return err
+               } else if a == EAStop {
+                       break
+               }
+               err = p.proc.Continue()
+               if err != nil {
+                       return err
+               }
+               err = p.proc.WaitStop()
+               if err != nil {
+                       return err
+               }
+               for _, g := range p.goroutines {
+                       g.resetFrame()
+               }
+               p.pending, err = p.causesToEvents()
+               if err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+// Out selects the caller frame of the current frame.
+func (p *Process) Out() os.Error {
+       if p.curGoroutine == nil {
+               return NoCurrentGoroutine{}
+       }
+       return p.curGoroutine.Out()
+}
+
+// In selects the frame called by the current frame.
+func (p *Process) In() os.Error {
+       if p.curGoroutine == nil {
+               return NoCurrentGoroutine{}
+       }
+       return p.curGoroutine.In()
+}
diff --git a/libgo/go/exp/ogle/rruntime.go b/libgo/go/exp/ogle/rruntime.go
new file mode 100644 (file)
index 0000000..33f1935
--- /dev/null
@@ -0,0 +1,271 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "debug/proc"
+       "exp/eval"
+       "reflect"
+)
+
+// This file contains remote runtime definitions.  Using reflection,
+// we convert all of these to interpreter types and layout their
+// remote representations using the architecture rules.
+//
+// We could get most of these definitions from our own runtime
+// package; however, some of them differ in convenient ways, some of
+// them are not defined or exported by the runtime, and having our own
+// definitions makes it easy to support multiple remote runtime
+// versions.  This may turn out to be overkill.
+//
+// All of these structures are prefixed with rt1 to indicate the
+// runtime version and to mark them as types used only as templates
+// for remote types.
+
+/*
+ * Runtime data headers
+ *
+ * See $GOROOT/src/pkg/runtime/runtime.h
+ */
+
+type rt1String struct {
+       str uintptr
+       len int
+}
+
+type rt1Slice struct {
+       array uintptr
+       len   int
+       cap   int
+}
+
+type rt1Eface struct {
+       typ uintptr
+       ptr uintptr
+}
+
+/*
+ * Runtime type structures
+ *
+ * See $GOROOT/src/pkg/runtime/type.h and $GOROOT/src/pkg/runtime/type.go
+ */
+
+type rt1UncommonType struct {
+       name    *string
+       pkgPath *string
+       //methods []method;
+}
+
+type rt1CommonType struct {
+       size                   uintptr
+       hash                   uint32
+       alg, align, fieldAlign uint8
+       string                 *string
+       uncommonType           *rt1UncommonType
+}
+
+type rt1Type struct {
+       // While Type is technically an Eface, treating the
+       // discriminator as an opaque pointer and taking advantage of
+       // the commonType prologue on all Type's makes type parsing
+       // much simpler.
+       typ uintptr
+       ptr *rt1CommonType
+}
+
+type rt1StructField struct {
+       name    *string
+       pkgPath *string
+       typ     *rt1Type
+       tag     *string
+       offset  uintptr
+}
+
+type rt1StructType struct {
+       rt1CommonType
+       fields []rt1StructField
+}
+
+type rt1PtrType struct {
+       rt1CommonType
+       elem *rt1Type
+}
+
+type rt1SliceType struct {
+       rt1CommonType
+       elem *rt1Type
+}
+
+type rt1ArrayType struct {
+       rt1CommonType
+       elem *rt1Type
+       len  uintptr
+}
+
+/*
+ * Runtime scheduler structures
+ *
+ * See $GOROOT/src/pkg/runtime/runtime.h
+ */
+
+// Fields beginning with _ are only for padding
+
+type rt1Stktop struct {
+       stackguard uintptr
+       stackbase  *rt1Stktop
+       gobuf      rt1Gobuf
+       _args      uint32
+       _fp        uintptr
+}
+
+type rt1Gobuf struct {
+       sp uintptr
+       pc uintptr
+       g  *rt1G
+       r0 uintptr
+}
+
+type rt1G struct {
+       _stackguard uintptr
+       stackbase   *rt1Stktop
+       _defer      uintptr
+       sched       rt1Gobuf
+       _stack0     uintptr
+       _entry      uintptr
+       alllink     *rt1G
+       _param      uintptr
+       status      int16
+       // Incomplete
+}
+
+var rt1GStatus = runtimeGStatus{
+       Gidle:     0,
+       Grunnable: 1,
+       Grunning:  2,
+       Gsyscall:  3,
+       Gwaiting:  4,
+       Gmoribund: 5,
+       Gdead:     6,
+}
+
+// runtimeIndexes stores the indexes of fields in the runtime
+// structures.  It is filled in using reflection, so the name of the
+// fields must match the names of the remoteType's in runtimeValues
+// exactly and the names of the index fields must be the capitalized
+// version of the names of the fields in the runtime structures above.
+type runtimeIndexes struct {
+       String struct {
+               Str, Len int
+       }
+       Slice struct {
+               Array, Len, Cap int
+       }
+       Eface struct {
+               Typ, Ptr int
+       }
+
+       UncommonType struct {
+               Name, PkgPath int
+       }
+       CommonType struct {
+               Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
+       }
+       Type struct {
+               Typ, Ptr int
+       }
+       StructField struct {
+               Name, PkgPath, Typ, Tag, Offset int
+       }
+       StructType struct {
+               Fields int
+       }
+       PtrType struct {
+               Elem int
+       }
+       SliceType struct {
+               Elem int
+       }
+       ArrayType struct {
+               Elem, Len int
+       }
+
+       Stktop struct {
+               Stackguard, Stackbase, Gobuf int
+       }
+       Gobuf struct {
+               Sp, Pc, G int
+       }
+       G struct {
+               Stackbase, Sched, Status, Alllink int
+       }
+}
+
+// Values of G status codes
+type runtimeGStatus struct {
+       Gidle, Grunnable, Grunning, Gsyscall, Gwaiting, Gmoribund, Gdead int64
+}
+
+// runtimeValues stores the types and values that correspond to those
+// in the remote runtime package.
+type runtimeValues struct {
+       // Runtime data headers
+       String, Slice, Eface *remoteType
+       // Runtime type structures
+       Type, CommonType, UncommonType, StructField, StructType, PtrType,
+       ArrayType, SliceType *remoteType
+       // Runtime scheduler structures
+       Stktop, Gobuf, G *remoteType
+       // Addresses of *runtime.XType types.  These are the
+       // discriminators on the runtime.Type interface.  We use local
+       // reflection to fill these in from the remote symbol table,
+       // so the names must match the runtime names.
+       PBoolType,
+       PUint8Type, PUint16Type, PUint32Type, PUint64Type, PUintType, PUintptrType,
+       PInt8Type, PInt16Type, PInt32Type, PInt64Type, PIntType,
+       PFloat32Type, PFloat64Type, PFloatType,
+       PArrayType, PStringType, PStructType, PPtrType, PFuncType,
+       PInterfaceType, PSliceType, PMapType, PChanType,
+       PDotDotDotType, PUnsafePointerType proc.Word
+       // G status values
+       runtimeGStatus
+}
+
+// fillRuntimeIndexes fills a runtimeIndexes structure will the field
+// indexes gathered from the remoteTypes recorded in a runtimeValues
+// structure.
+func fillRuntimeIndexes(runtime *runtimeValues, out *runtimeIndexes) {
+       outv := reflect.Indirect(reflect.NewValue(out)).(*reflect.StructValue)
+       outt := outv.Type().(*reflect.StructType)
+       runtimev := reflect.Indirect(reflect.NewValue(runtime)).(*reflect.StructValue)
+
+       // out contains fields corresponding to each runtime type
+       for i := 0; i < outt.NumField(); i++ {
+               // Find the interpreter type for this runtime type
+               name := outt.Field(i).Name
+               et := runtimev.FieldByName(name).Interface().(*remoteType).Type.(*eval.StructType)
+
+               // Get the field indexes of the interpreter struct type
+               indexes := make(map[string]int, len(et.Elems))
+               for j, f := range et.Elems {
+                       if f.Anonymous {
+                               continue
+                       }
+                       name := f.Name
+                       if name[0] >= 'a' && name[0] <= 'z' {
+                               name = string(name[0]+'A'-'a') + name[1:]
+                       }
+                       indexes[name] = j
+               }
+
+               // Fill this field of out
+               outStructv := outv.Field(i).(*reflect.StructValue)
+               outStructt := outStructv.Type().(*reflect.StructType)
+               for j := 0; j < outStructt.NumField(); j++ {
+                       f := outStructv.Field(j).(*reflect.IntValue)
+                       name := outStructt.Field(j).Name
+                       f.Set(int64(indexes[name]))
+               }
+       }
+}
diff --git a/libgo/go/exp/ogle/rtype.go b/libgo/go/exp/ogle/rtype.go
new file mode 100644 (file)
index 0000000..fd77f1b
--- /dev/null
@@ -0,0 +1,291 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "debug/proc"
+       "exp/eval"
+       "fmt"
+       "log"
+)
+
+const debugParseRemoteType = false
+
+// A remoteType is the local representation of a type in a remote process.
+type remoteType struct {
+       eval.Type
+       // The size of values of this type in bytes.
+       size int
+       // The field alignment of this type.  Only used for
+       // manually-constructed types.
+       fieldAlign int
+       // The maker function to turn a remote address of a value of
+       // this type into an interpreter Value.
+       mk maker
+}
+
+var manualTypes = make(map[Arch]map[eval.Type]*remoteType)
+
+// newManualType constructs a remote type from an interpreter Type
+// using the size and alignment properties of the given architecture.
+// Most types are parsed directly out of the remote process, but to do
+// so we need to layout the structures that describe those types ourselves.
+func newManualType(t eval.Type, arch Arch) *remoteType {
+       if nt, ok := t.(*eval.NamedType); ok {
+               t = nt.Def
+       }
+
+       // Get the type map for this architecture
+       typeMap := manualTypes[arch]
+       if typeMap == nil {
+               typeMap = make(map[eval.Type]*remoteType)
+               manualTypes[arch] = typeMap
+
+               // Construct basic types for this architecture
+               basicType := func(t eval.Type, mk maker, size int, fieldAlign int) {
+                       t = t.(*eval.NamedType).Def
+                       if fieldAlign == 0 {
+                               fieldAlign = size
+                       }
+                       typeMap[t] = &remoteType{t, size, fieldAlign, mk}
+               }
+               basicType(eval.Uint8Type, mkUint8, 1, 0)
+               basicType(eval.Uint32Type, mkUint32, 4, 0)
+               basicType(eval.UintptrType, mkUintptr, arch.PtrSize(), 0)
+               basicType(eval.Int16Type, mkInt16, 2, 0)
+               basicType(eval.Int32Type, mkInt32, 4, 0)
+               basicType(eval.IntType, mkInt, arch.IntSize(), 0)
+               basicType(eval.StringType, mkString, arch.PtrSize()+arch.IntSize(), arch.PtrSize())
+       }
+
+       if rt, ok := typeMap[t]; ok {
+               return rt
+       }
+
+       var rt *remoteType
+       switch t := t.(type) {
+       case *eval.PtrType:
+               var elem *remoteType
+               mk := func(r remote) eval.Value { return remotePtr{r, elem} }
+               rt = &remoteType{t, arch.PtrSize(), arch.PtrSize(), mk}
+               // Construct the element type after registering the
+               // type to break cycles.
+               typeMap[eval.Type(t)] = rt
+               elem = newManualType(t.Elem, arch)
+
+       case *eval.ArrayType:
+               elem := newManualType(t.Elem, arch)
+               mk := func(r remote) eval.Value { return remoteArray{r, t.Len, elem} }
+               rt = &remoteType{t, elem.size * int(t.Len), elem.fieldAlign, mk}
+
+       case *eval.SliceType:
+               elem := newManualType(t.Elem, arch)
+               mk := func(r remote) eval.Value { return remoteSlice{r, elem} }
+               rt = &remoteType{t, arch.PtrSize() + 2*arch.IntSize(), arch.PtrSize(), mk}
+
+       case *eval.StructType:
+               layout := make([]remoteStructField, len(t.Elems))
+               offset := 0
+               fieldAlign := 0
+               for i, f := range t.Elems {
+                       elem := newManualType(f.Type, arch)
+                       if fieldAlign == 0 {
+                               fieldAlign = elem.fieldAlign
+                       }
+                       offset = arch.Align(offset, elem.fieldAlign)
+                       layout[i].offset = offset
+                       layout[i].fieldType = elem
+                       offset += elem.size
+               }
+               mk := func(r remote) eval.Value { return remoteStruct{r, layout} }
+               rt = &remoteType{t, offset, fieldAlign, mk}
+
+       default:
+               log.Panicf("cannot manually construct type %T", t)
+       }
+
+       typeMap[t] = rt
+       return rt
+}
+
+var prtIndent = ""
+
+// parseRemoteType parses a Type structure in a remote process to
+// construct the corresponding interpreter type and remote type.
+func parseRemoteType(a aborter, rs remoteStruct) *remoteType {
+       addr := rs.addr().base
+       p := rs.addr().p
+
+       // We deal with circular types by discovering cycles at
+       // NamedTypes.  If a type cycles back to something other than
+       // a named type, we're guaranteed that there will be a named
+       // type somewhere in that cycle.  Thus, we continue down,
+       // re-parsing types until we reach the named type in the
+       // cycle.  In order to still create one remoteType per remote
+       // type, we insert an empty remoteType in the type map the
+       // first time we encounter the type and re-use that structure
+       // the second time we encounter it.
+
+       rt, ok := p.types[addr]
+       if ok && rt.Type != nil {
+               return rt
+       } else if !ok {
+               rt = &remoteType{}
+               p.types[addr] = rt
+       }
+
+       if debugParseRemoteType {
+               sym := p.syms.SymByAddr(uint64(addr))
+               name := "<unknown>"
+               if sym != nil {
+                       name = sym.Name
+               }
+               log.Printf("%sParsing type at %#x (%s)", prtIndent, addr, name)
+               prtIndent += " "
+               defer func() { prtIndent = prtIndent[0 : len(prtIndent)-1] }()
+       }
+
+       // Get Type header
+       itype := proc.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a))
+       typ := rs.field(p.f.Type.Ptr).(remotePtr).aGet(a).(remoteStruct)
+
+       // Is this a named type?
+       var nt *eval.NamedType
+       uncommon := typ.field(p.f.CommonType.UncommonType).(remotePtr).aGet(a)
+       if uncommon != nil {
+               name := uncommon.(remoteStruct).field(p.f.UncommonType.Name).(remotePtr).aGet(a)
+               if name != nil {
+                       // TODO(austin) Declare type in appropriate remote package
+                       nt = eval.NewNamedType(name.(remoteString).aGet(a))
+                       rt.Type = nt
+               }
+       }
+
+       // Create type
+       var t eval.Type
+       var mk maker
+       switch itype {
+       case p.runtime.PBoolType:
+               t = eval.BoolType
+               mk = mkBool
+       case p.runtime.PUint8Type:
+               t = eval.Uint8Type
+               mk = mkUint8
+       case p.runtime.PUint16Type:
+               t = eval.Uint16Type
+               mk = mkUint16
+       case p.runtime.PUint32Type:
+               t = eval.Uint32Type
+               mk = mkUint32
+       case p.runtime.PUint64Type:
+               t = eval.Uint64Type
+               mk = mkUint64
+       case p.runtime.PUintType:
+               t = eval.UintType
+               mk = mkUint
+       case p.runtime.PUintptrType:
+               t = eval.UintptrType
+               mk = mkUintptr
+       case p.runtime.PInt8Type:
+               t = eval.Int8Type
+               mk = mkInt8
+       case p.runtime.PInt16Type:
+               t = eval.Int16Type
+               mk = mkInt16
+       case p.runtime.PInt32Type:
+               t = eval.Int32Type
+               mk = mkInt32
+       case p.runtime.PInt64Type:
+               t = eval.Int64Type
+               mk = mkInt64
+       case p.runtime.PIntType:
+               t = eval.IntType
+               mk = mkInt
+       case p.runtime.PFloat32Type:
+               t = eval.Float32Type
+               mk = mkFloat32
+       case p.runtime.PFloat64Type:
+               t = eval.Float64Type
+               mk = mkFloat64
+       case p.runtime.PFloatType:
+               t = eval.FloatType
+               mk = mkFloat
+       case p.runtime.PStringType:
+               t = eval.StringType
+               mk = mkString
+
+       case p.runtime.PArrayType:
+               // Cast to an ArrayType
+               typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct)
+               len := int64(typ.field(p.f.ArrayType.Len).(remoteUint).aGet(a))
+               elem := parseRemoteType(a, typ.field(p.f.ArrayType.Elem).(remotePtr).aGet(a).(remoteStruct))
+               t = eval.NewArrayType(len, elem.Type)
+               mk = func(r remote) eval.Value { return remoteArray{r, len, elem} }
+
+       case p.runtime.PStructType:
+               // Cast to a StructType
+               typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct)
+               fs := typ.field(p.f.StructType.Fields).(remoteSlice).aGet(a)
+
+               fields := make([]eval.StructField, fs.Len)
+               layout := make([]remoteStructField, fs.Len)
+               for i := range fields {
+                       f := fs.Base.(remoteArray).elem(int64(i)).(remoteStruct)
+                       elemrs := f.field(p.f.StructField.Typ).(remotePtr).aGet(a).(remoteStruct)
+                       elem := parseRemoteType(a, elemrs)
+                       fields[i].Type = elem.Type
+                       name := f.field(p.f.StructField.Name).(remotePtr).aGet(a)
+                       if name == nil {
+                               fields[i].Anonymous = true
+                       } else {
+                               fields[i].Name = name.(remoteString).aGet(a)
+                       }
+                       layout[i].offset = int(f.field(p.f.StructField.Offset).(remoteUint).aGet(a))
+                       layout[i].fieldType = elem
+               }
+
+               t = eval.NewStructType(fields)
+               mk = func(r remote) eval.Value { return remoteStruct{r, layout} }
+
+       case p.runtime.PPtrType:
+               // Cast to a PtrType
+               typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct)
+               elem := parseRemoteType(a, typ.field(p.f.PtrType.Elem).(remotePtr).aGet(a).(remoteStruct))
+               t = eval.NewPtrType(elem.Type)
+               mk = func(r remote) eval.Value { return remotePtr{r, elem} }
+
+       case p.runtime.PSliceType:
+               // Cast to a SliceType
+               typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct)
+               elem := parseRemoteType(a, typ.field(p.f.SliceType.Elem).(remotePtr).aGet(a).(remoteStruct))
+               t = eval.NewSliceType(elem.Type)
+               mk = func(r remote) eval.Value { return remoteSlice{r, elem} }
+
+       case p.runtime.PMapType, p.runtime.PChanType, p.runtime.PFuncType, p.runtime.PInterfaceType, p.runtime.PUnsafePointerType, p.runtime.PDotDotDotType:
+               // TODO(austin)
+               t = eval.UintptrType
+               mk = mkUintptr
+
+       default:
+               sym := p.syms.SymByAddr(uint64(itype))
+               name := "<unknown symbol>"
+               if sym != nil {
+                       name = sym.Name
+               }
+               err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name)
+               a.Abort(FormatError(err))
+       }
+
+       // Fill in the remote type
+       if nt != nil {
+               nt.Complete(t)
+       } else {
+               rt.Type = t
+       }
+       rt.size = int(typ.field(p.f.CommonType.Size).(remoteUint).aGet(a))
+       rt.mk = mk
+
+       return rt
+}
diff --git a/libgo/go/exp/ogle/rvalue.go b/libgo/go/exp/ogle/rvalue.go
new file mode 100644 (file)
index 0000000..3d630f9
--- /dev/null
@@ -0,0 +1,515 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "debug/proc"
+       "exp/eval"
+       "fmt"
+)
+
+// A RemoteMismatchError occurs when an operation that requires two
+// identical remote processes is given different process.  For
+// example, this occurs when trying to set a pointer in one process to
+// point to something in another process.
+type RemoteMismatchError string
+
+func (e RemoteMismatchError) String() string { return string(e) }
+
+// A ReadOnlyError occurs when attempting to set or assign to a
+// read-only value.
+type ReadOnlyError string
+
+func (e ReadOnlyError) String() string { return string(e) }
+
+// A maker is a function that converts a remote address into an
+// interpreter Value.
+type maker func(remote) eval.Value
+
+type remoteValue interface {
+       addr() remote
+}
+
+// remote represents an address in a remote process.
+type remote struct {
+       base proc.Word
+       p    *Process
+}
+
+func (v remote) Get(a aborter, size int) uint64 {
+       // TODO(austin) This variable might temporarily be in a
+       // register.  We could trace the assembly back from the
+       // current PC, looking for the beginning of the function or a
+       // call (both of which guarantee that the variable is in
+       // memory), or an instruction that loads the variable into a
+       // register.
+       //
+       // TODO(austin) If this is a local variable, it might not be
+       // live at this PC.  In fact, because the compiler reuses
+       // slots, there might even be a different local variable at
+       // this location right now.  A simple solution to both
+       // problems is to include the range of PC's over which a local
+       // variable is live in the symbol table.
+       //
+       // TODO(austin) We need to prevent the remote garbage
+       // collector from collecting objects out from under us.
+       var arr [8]byte
+       buf := arr[0:size]
+       _, err := v.p.Peek(v.base, buf)
+       if err != nil {
+               a.Abort(err)
+       }
+       return uint64(v.p.ToWord(buf))
+}
+
+func (v remote) Set(a aborter, size int, x uint64) {
+       var arr [8]byte
+       buf := arr[0:size]
+       v.p.FromWord(proc.Word(x), buf)
+       _, err := v.p.Poke(v.base, buf)
+       if err != nil {
+               a.Abort(err)
+       }
+}
+
+func (v remote) plus(x proc.Word) remote { return remote{v.base + x, v.p} }
+
+func tryRVString(f func(a aborter) string) string {
+       var s string
+       err := try(func(a aborter) { s = f(a) })
+       if err != nil {
+               return fmt.Sprintf("<error: %v>", err)
+       }
+       return s
+}
+
+/*
+ * Bool
+ */
+
+type remoteBool struct {
+       r remote
+}
+
+func (v remoteBool) String() string {
+       return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
+}
+
+func (v remoteBool) Assign(t *eval.Thread, o eval.Value) {
+       v.Set(t, o.(eval.BoolValue).Get(t))
+}
+
+func (v remoteBool) Get(t *eval.Thread) bool { return v.aGet(t) }
+
+func (v remoteBool) aGet(a aborter) bool { return v.r.Get(a, 1) != 0 }
+
+func (v remoteBool) Set(t *eval.Thread, x bool) {
+       v.aSet(t, x)
+}
+
+func (v remoteBool) aSet(a aborter, x bool) {
+       if x {
+               v.r.Set(a, 1, 1)
+       } else {
+               v.r.Set(a, 1, 0)
+       }
+}
+
+func (v remoteBool) addr() remote { return v.r }
+
+func mkBool(r remote) eval.Value { return remoteBool{r} }
+
+/*
+ * Uint
+ */
+
+type remoteUint struct {
+       r    remote
+       size int
+}
+
+func (v remoteUint) String() string {
+       return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
+}
+
+func (v remoteUint) Assign(t *eval.Thread, o eval.Value) {
+       v.Set(t, o.(eval.UintValue).Get(t))
+}
+
+func (v remoteUint) Get(t *eval.Thread) uint64 {
+       return v.aGet(t)
+}
+
+func (v remoteUint) aGet(a aborter) uint64 { return v.r.Get(a, v.size) }
+
+func (v remoteUint) Set(t *eval.Thread, x uint64) {
+       v.aSet(t, x)
+}
+
+func (v remoteUint) aSet(a aborter, x uint64) { v.r.Set(a, v.size, x) }
+
+func (v remoteUint) addr() remote { return v.r }
+
+func mkUint8(r remote) eval.Value { return remoteUint{r, 1} }
+
+func mkUint16(r remote) eval.Value { return remoteUint{r, 2} }
+
+func mkUint32(r remote) eval.Value { return remoteUint{r, 4} }
+
+func mkUint64(r remote) eval.Value { return remoteUint{r, 8} }
+
+func mkUint(r remote) eval.Value { return remoteUint{r, r.p.IntSize()} }
+
+func mkUintptr(r remote) eval.Value { return remoteUint{r, r.p.PtrSize()} }
+
+/*
+ * Int
+ */
+
+type remoteInt struct {
+       r    remote
+       size int
+}
+
+func (v remoteInt) String() string {
+       return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
+}
+
+func (v remoteInt) Assign(t *eval.Thread, o eval.Value) {
+       v.Set(t, o.(eval.IntValue).Get(t))
+}
+
+func (v remoteInt) Get(t *eval.Thread) int64 { return v.aGet(t) }
+
+func (v remoteInt) aGet(a aborter) int64 { return int64(v.r.Get(a, v.size)) }
+
+func (v remoteInt) Set(t *eval.Thread, x int64) {
+       v.aSet(t, x)
+}
+
+func (v remoteInt) aSet(a aborter, x int64) { v.r.Set(a, v.size, uint64(x)) }
+
+func (v remoteInt) addr() remote { return v.r }
+
+func mkInt8(r remote) eval.Value { return remoteInt{r, 1} }
+
+func mkInt16(r remote) eval.Value { return remoteInt{r, 2} }
+
+func mkInt32(r remote) eval.Value { return remoteInt{r, 4} }
+
+func mkInt64(r remote) eval.Value { return remoteInt{r, 8} }
+
+func mkInt(r remote) eval.Value { return remoteInt{r, r.p.IntSize()} }
+
+/*
+ * Float
+ */
+
+type remoteFloat struct {
+       r    remote
+       size int
+}
+
+func (v remoteFloat) String() string {
+       return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
+}
+
+func (v remoteFloat) Assign(t *eval.Thread, o eval.Value) {
+       v.Set(t, o.(eval.FloatValue).Get(t))
+}
+
+func (v remoteFloat) Get(t *eval.Thread) float64 {
+       return v.aGet(t)
+}
+
+func (v remoteFloat) aGet(a aborter) float64 {
+       bits := v.r.Get(a, v.size)
+       switch v.size {
+       case 4:
+               return float64(v.r.p.ToFloat32(uint32(bits)))
+       case 8:
+               return v.r.p.ToFloat64(bits)
+       }
+       panic("Unexpected float size")
+}
+
+func (v remoteFloat) Set(t *eval.Thread, x float64) {
+       v.aSet(t, x)
+}
+
+func (v remoteFloat) aSet(a aborter, x float64) {
+       var bits uint64
+       switch v.size {
+       case 4:
+               bits = uint64(v.r.p.FromFloat32(float32(x)))
+       case 8:
+               bits = v.r.p.FromFloat64(x)
+       default:
+               panic("Unexpected float size")
+       }
+       v.r.Set(a, v.size, bits)
+}
+
+func (v remoteFloat) addr() remote { return v.r }
+
+func mkFloat32(r remote) eval.Value { return remoteFloat{r, 4} }
+
+func mkFloat64(r remote) eval.Value { return remoteFloat{r, 8} }
+
+func mkFloat(r remote) eval.Value { return remoteFloat{r, r.p.FloatSize()} }
+
+/*
+ * String
+ */
+
+type remoteString struct {
+       r remote
+}
+
+func (v remoteString) String() string {
+       return tryRVString(func(a aborter) string { return v.aGet(a) })
+}
+
+func (v remoteString) Assign(t *eval.Thread, o eval.Value) {
+       v.Set(t, o.(eval.StringValue).Get(t))
+}
+
+func (v remoteString) Get(t *eval.Thread) string {
+       return v.aGet(t)
+}
+
+func (v remoteString) aGet(a aborter) string {
+       rs := v.r.p.runtime.String.mk(v.r).(remoteStruct)
+       str := proc.Word(rs.field(v.r.p.f.String.Str).(remoteUint).aGet(a))
+       len := rs.field(v.r.p.f.String.Len).(remoteInt).aGet(a)
+
+       bytes := make([]uint8, len)
+       _, err := v.r.p.Peek(str, bytes)
+       if err != nil {
+               a.Abort(err)
+       }
+       return string(bytes)
+}
+
+func (v remoteString) Set(t *eval.Thread, x string) {
+       v.aSet(t, x)
+}
+
+func (v remoteString) aSet(a aborter, x string) {
+       // TODO(austin) This isn't generally possible without the
+       // ability to allocate remote memory.
+       a.Abort(ReadOnlyError("remote strings cannot be assigned to"))
+}
+
+func mkString(r remote) eval.Value { return remoteString{r} }
+
+/*
+ * Array
+ */
+
+type remoteArray struct {
+       r        remote
+       len      int64
+       elemType *remoteType
+}
+
+func (v remoteArray) String() string {
+       res := "{"
+       for i := int64(0); i < v.len; i++ {
+               if i > 0 {
+                       res += ", "
+               }
+               res += v.elem(i).String()
+       }
+       return res + "}"
+}
+
+func (v remoteArray) Assign(t *eval.Thread, o eval.Value) {
+       // TODO(austin) Could do a bigger memcpy if o is a
+       // remoteArray in the same Process.
+       oa := o.(eval.ArrayValue)
+       for i := int64(0); i < v.len; i++ {
+               v.Elem(t, i).Assign(t, oa.Elem(t, i))
+       }
+}
+
+func (v remoteArray) Get(t *eval.Thread) eval.ArrayValue {
+       return v
+}
+
+func (v remoteArray) Elem(t *eval.Thread, i int64) eval.Value {
+       return v.elem(i)
+}
+
+func (v remoteArray) elem(i int64) eval.Value {
+       return v.elemType.mk(v.r.plus(proc.Word(int64(v.elemType.size) * i)))
+}
+
+func (v remoteArray) Sub(i int64, len int64) eval.ArrayValue {
+       return remoteArray{v.r.plus(proc.Word(int64(v.elemType.size) * i)), len, v.elemType}
+}
+
+/*
+ * Struct
+ */
+
+type remoteStruct struct {
+       r      remote
+       layout []remoteStructField
+}
+
+type remoteStructField struct {
+       offset    int
+       fieldType *remoteType
+}
+
+func (v remoteStruct) String() string {
+       res := "{"
+       for i := range v.layout {
+               if i > 0 {
+                       res += ", "
+               }
+               res += v.field(i).String()
+       }
+       return res + "}"
+}
+
+func (v remoteStruct) Assign(t *eval.Thread, o eval.Value) {
+       // TODO(austin) Could do a bigger memcpy.
+       oa := o.(eval.StructValue)
+       l := len(v.layout)
+       for i := 0; i < l; i++ {
+               v.Field(t, i).Assign(t, oa.Field(t, i))
+       }
+}
+
+func (v remoteStruct) Get(t *eval.Thread) eval.StructValue {
+       return v
+}
+
+func (v remoteStruct) Field(t *eval.Thread, i int) eval.Value {
+       return v.field(i)
+}
+
+func (v remoteStruct) field(i int) eval.Value {
+       f := &v.layout[i]
+       return f.fieldType.mk(v.r.plus(proc.Word(f.offset)))
+}
+
+func (v remoteStruct) addr() remote { return v.r }
+
+/*
+ * Pointer
+ */
+
+// TODO(austin) Comparing two remote pointers for equality in the
+// interpreter will crash it because the Value's returned from
+// remotePtr.Get() will be structs.
+
+type remotePtr struct {
+       r        remote
+       elemType *remoteType
+}
+
+func (v remotePtr) String() string {
+       return tryRVString(func(a aborter) string {
+               e := v.aGet(a)
+               if e == nil {
+                       return "<nil>"
+               }
+               return "&" + e.String()
+       })
+}
+
+func (v remotePtr) Assign(t *eval.Thread, o eval.Value) {
+       v.Set(t, o.(eval.PtrValue).Get(t))
+}
+
+func (v remotePtr) Get(t *eval.Thread) eval.Value {
+       return v.aGet(t)
+}
+
+func (v remotePtr) aGet(a aborter) eval.Value {
+       addr := proc.Word(v.r.Get(a, v.r.p.PtrSize()))
+       if addr == 0 {
+               return nil
+       }
+       return v.elemType.mk(remote{addr, v.r.p})
+}
+
+func (v remotePtr) Set(t *eval.Thread, x eval.Value) {
+       v.aSet(t, x)
+}
+
+func (v remotePtr) aSet(a aborter, x eval.Value) {
+       if x == nil {
+               v.r.Set(a, v.r.p.PtrSize(), 0)
+               return
+       }
+       xr, ok := x.(remoteValue)
+       if !ok || v.r.p != xr.addr().p {
+               a.Abort(RemoteMismatchError("remote pointer must point within the same process"))
+       }
+       v.r.Set(a, v.r.p.PtrSize(), uint64(xr.addr().base))
+}
+
+func (v remotePtr) addr() remote { return v.r }
+
+/*
+ * Slice
+ */
+
+type remoteSlice struct {
+       r        remote
+       elemType *remoteType
+}
+
+func (v remoteSlice) String() string {
+       return tryRVString(func(a aborter) string {
+               b := v.aGet(a).Base
+               if b == nil {
+                       return "<nil>"
+               }
+               return b.String()
+       })
+}
+
+func (v remoteSlice) Assign(t *eval.Thread, o eval.Value) {
+       v.Set(t, o.(eval.SliceValue).Get(t))
+}
+
+func (v remoteSlice) Get(t *eval.Thread) eval.Slice {
+       return v.aGet(t)
+}
+
+func (v remoteSlice) aGet(a aborter) eval.Slice {
+       rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct)
+       base := proc.Word(rs.field(v.r.p.f.Slice.Array).(remoteUint).aGet(a))
+       nel := rs.field(v.r.p.f.Slice.Len).(remoteInt).aGet(a)
+       cap := rs.field(v.r.p.f.Slice.Cap).(remoteInt).aGet(a)
+       if base == 0 {
+               return eval.Slice{nil, nel, cap}
+       }
+       return eval.Slice{remoteArray{remote{base, v.r.p}, nel, v.elemType}, nel, cap}
+}
+
+func (v remoteSlice) Set(t *eval.Thread, x eval.Slice) {
+       v.aSet(t, x)
+}
+
+func (v remoteSlice) aSet(a aborter, x eval.Slice) {
+       rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct)
+       if x.Base == nil {
+               rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, 0)
+       } else {
+               ar, ok := x.Base.(remoteArray)
+               if !ok || v.r.p != ar.r.p {
+                       a.Abort(RemoteMismatchError("remote slice must point within the same process"))
+               }
+               rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, uint64(ar.r.base))
+       }
+       rs.field(v.r.p.f.Slice.Len).(remoteInt).aSet(a, x.Len)
+       rs.field(v.r.p.f.Slice.Cap).(remoteInt).aSet(a, x.Cap)
+}
diff --git a/libgo/go/exp/ogle/vars.go b/libgo/go/exp/ogle/vars.go
new file mode 100644 (file)
index 0000000..8a3a147
--- /dev/null
@@ -0,0 +1,272 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ogle
+
+import (
+       "debug/gosym"
+       "debug/proc"
+       "exp/eval"
+       "log"
+       "os"
+)
+
+/*
+ * Remote frame pointers
+ */
+
+// A NotOnStack error occurs when attempting to access a variable in a
+// remote frame where that remote frame is not on the current stack.
+type NotOnStack struct {
+       Fn        *gosym.Func
+       Goroutine *Goroutine
+}
+
+func (e NotOnStack) String() string {
+       return "function " + e.Fn.Name + " not on " + e.Goroutine.String() + "'s stack"
+}
+
+// A remoteFramePtr is an implementation of eval.PtrValue that
+// represents a pointer to a function frame in a remote process.  When
+// accessed, this locates the function on the current goroutine's
+// stack and returns a structure containing the local variables of
+// that function.
+type remoteFramePtr struct {
+       p  *Process
+       fn *gosym.Func
+       rt *remoteType
+}
+
+func (v remoteFramePtr) String() string {
+       // TODO(austin): This could be a really awesome string method
+       return "<remote frame>"
+}
+
+func (v remoteFramePtr) Assign(t *eval.Thread, o eval.Value) {
+       v.Set(t, o.(eval.PtrValue).Get(t))
+}
+
+func (v remoteFramePtr) Get(t *eval.Thread) eval.Value {
+       g := v.p.curGoroutine
+       if g == nil || g.frame == nil {
+               t.Abort(NoCurrentGoroutine{})
+       }
+
+       for f := g.frame; f != nil; f = f.aOuter(t) {
+               if f.fn != v.fn {
+                       continue
+               }
+
+               // TODO(austin): Register for shootdown with f
+               return v.rt.mk(remote{f.fp, v.p})
+       }
+
+       t.Abort(NotOnStack{v.fn, g})
+       panic("fail")
+}
+
+func (v remoteFramePtr) Set(t *eval.Thread, x eval.Value) {
+       // Theoretically this could be a static error.  If remote
+       // packages were packages, remote frames could just be defined
+       // as constants.
+       t.Abort(ReadOnlyError("remote frames cannot be assigned to"))
+}
+
+/*
+ * Remote packages
+ */
+
+// TODO(austin): Remote packages are implemented as structs right now,
+// which has some weird consequences.  You can attempt to assign to a
+// remote package.  It also produces terrible error messages.
+// Ideally, these would actually be packages, but somehow first-class
+// so they could be assigned to other names.
+
+// A remotePackage is an implementation of eval.StructValue that
+// represents a package in a remote process.  It's essentially a
+// regular struct, except it cannot be assigned to.
+type remotePackage struct {
+       defs []eval.Value
+}
+
+func (v remotePackage) String() string { return "<remote package>" }
+
+func (v remotePackage) Assign(t *eval.Thread, o eval.Value) {
+       t.Abort(ReadOnlyError("remote packages cannot be assigned to"))
+}
+
+func (v remotePackage) Get(t *eval.Thread) eval.StructValue {
+       return v
+}
+
+func (v remotePackage) Field(t *eval.Thread, i int) eval.Value {
+       return v.defs[i]
+}
+
+/*
+ * Remote variables
+ */
+
+// populateWorld defines constants in the given world for each package
+// in this process.  These packages are structs that, in turn, contain
+// fields for each global and function in that package.
+func (p *Process) populateWorld(w *eval.World) os.Error {
+       type def struct {
+               t eval.Type
+               v eval.Value
+       }
+       packages := make(map[string]map[string]def)
+
+       for _, s := range p.syms.Syms {
+               if s.ReceiverName() != "" {
+                       // TODO(austin)
+                       continue
+               }
+
+               // Package
+               pkgName := s.PackageName()
+               switch pkgName {
+               case "", "type", "extratype", "string", "go":
+                       // "go" is really "go.string"
+                       continue
+               }
+               pkg, ok := packages[pkgName]
+               if !ok {
+                       pkg = make(map[string]def)
+                       packages[pkgName] = pkg
+               }
+
+               // Symbol name
+               name := s.BaseName()
+               if _, ok := pkg[name]; ok {
+                       log.Printf("Multiple definitions of symbol %s", s.Name)
+                       continue
+               }
+
+               // Symbol type
+               rt, err := p.typeOfSym(&s)
+               if err != nil {
+                       return err
+               }
+
+               // Definition
+               switch s.Type {
+               case 'D', 'd', 'B', 'b':
+                       // Global variable
+                       if rt == nil {
+                               continue
+                       }
+                       pkg[name] = def{rt.Type, rt.mk(remote{proc.Word(s.Value), p})}
+
+               case 'T', 't', 'L', 'l':
+                       // Function
+                       s := s.Func
+                       // TODO(austin): Ideally, this would *also* be
+                       // callable.  How does that interact with type
+                       // conversion syntax?
+                       rt, err := p.makeFrameType(s)
+                       if err != nil {
+                               return err
+                       }
+                       pkg[name] = def{eval.NewPtrType(rt.Type), remoteFramePtr{p, s, rt}}
+               }
+       }
+
+       // TODO(austin): Define remote types
+
+       // Define packages
+       for pkgName, defs := range packages {
+               fields := make([]eval.StructField, len(defs))
+               vals := make([]eval.Value, len(defs))
+               i := 0
+               for name, def := range defs {
+                       fields[i].Name = name
+                       fields[i].Type = def.t
+                       vals[i] = def.v
+                       i++
+               }
+               pkgType := eval.NewStructType(fields)
+               pkgVal := remotePackage{vals}
+
+               err := w.DefineConst(pkgName, pkgType, pkgVal)
+               if err != nil {
+                       log.Printf("while defining package %s: %v", pkgName, err)
+               }
+       }
+
+       return nil
+}
+
+// typeOfSym returns the type associated with a symbol.  If the symbol
+// has no type, returns nil.
+func (p *Process) typeOfSym(s *gosym.Sym) (*remoteType, os.Error) {
+       if s.GoType == 0 {
+               return nil, nil
+       }
+       addr := proc.Word(s.GoType)
+       var rt *remoteType
+       err := try(func(a aborter) { rt = parseRemoteType(a, p.runtime.Type.mk(remote{addr, p}).(remoteStruct)) })
+       if err != nil {
+               return nil, err
+       }
+       return rt, nil
+}
+
+// makeFrameType constructs a struct type for the frame of a function.
+// The offsets in this struct type are such that the struct can be
+// instantiated at this function's frame pointer.
+func (p *Process) makeFrameType(s *gosym.Func) (*remoteType, os.Error) {
+       n := len(s.Params) + len(s.Locals)
+       fields := make([]eval.StructField, n)
+       layout := make([]remoteStructField, n)
+       i := 0
+
+       // TODO(austin): There can be multiple locals/parameters with
+       // the same name.  We probably need liveness information to do
+       // anything about this.  Once we have that, perhaps we give
+       // such fields interface{} type?  Or perhaps we disambiguate
+       // the names with numbers.  Disambiguation is annoying for
+       // things like "i", where there's an obvious right answer.
+
+       for _, param := range s.Params {
+               rt, err := p.typeOfSym(param)
+               if err != nil {
+                       return nil, err
+               }
+               if rt == nil {
+                       //fmt.Printf(" (no type)\n");
+                       continue
+               }
+               // TODO(austin): Why do local variables carry their
+               // package name?
+               fields[i].Name = param.BaseName()
+               fields[i].Type = rt.Type
+               // Parameters have positive offsets from FP
+               layout[i].offset = int(param.Value)
+               layout[i].fieldType = rt
+               i++
+       }
+
+       for _, local := range s.Locals {
+               rt, err := p.typeOfSym(local)
+               if err != nil {
+                       return nil, err
+               }
+               if rt == nil {
+                       continue
+               }
+               fields[i].Name = local.BaseName()
+               fields[i].Type = rt.Type
+               // Locals have negative offsets from FP - PtrSize
+               layout[i].offset = -int(local.Value) - p.PtrSize()
+               layout[i].fieldType = rt
+               i++
+       }
+
+       fields = fields[0:i]
+       layout = layout[0:i]
+       t := eval.NewStructType(fields)
+       mk := func(r remote) eval.Value { return remoteStruct{r, layout} }
+       return &remoteType{t, 0, 0, mk}, nil
+}
diff --git a/libgo/go/exp/spacewar/code.go b/libgo/go/exp/spacewar/code.go
new file mode 100644 (file)
index 0000000..6391b50
--- /dev/null
@@ -0,0 +1,7556 @@
+// This file contains the assembly language and machine code for
+// Spacewar!, the original PDP-1 video game.  It is downloaded from
+// http://spacewar.oversigma.com/sources/sources.zip which has
+// the following notice at http://spacewar.oversigma.com/:
+//
+//     Spacewar! was conceived in 1961 by Martin Graetz, Stephen Russell,
+//     and Wayne Wiitanen. It was first realized on the PDP-1 in 1962 by
+//     Stephen Russell, Peter Samson, Dan Edwards, and Martin Graetz,
+//     together with Alan Kotok, Steve Piner, and Robert A Saunders.
+//     Spacewar! is in the public domain, but this credit paragraph must
+//     accompany all distributed versions of the program.
+//
+//     This is the original version! Martin Graetz provided us with a
+//     printed version of the source. We typed in in again - it was about
+//     40 pages long - and re-assembled it with a PDP-1 assembler written
+//     in PERL. The resulting binary runs on a PDP-1 emulator written as
+//     a Java applet. The code is extremely faithful to the original. There
+//     are only two changes. 1)The spaceships have been made bigger and
+//     2) The overall timing has been special cased to deal with varying
+//     machine speeds.
+//
+//     The "a", "s", "d", "f" keys control one of the spaceships. The "k",
+//     "l", ";", "'" keys control the other. The controls are spin one
+//     way, spin the other, thrust, and fire.
+//
+//     Barry Silverman
+//     Brian Silverman
+//     Vadim Gerasimov
+//
+
+package main
+
+const spacewarCode = `
+-/macro fio-dec system, june 1963
+ 007652        640500          szm=sza sma-szf
+ 007652        650500          spq=szm i
+ 007652        761200          clc=cma+cla-opr
+-      define senseswitch A
+-      repeat 3, A=A+A
+-      szs A
+-      term
+-      define init A,B
+-      law B
+-      dap A
+-      term
+-      define index A,B,C
+-      idx A
+-      sas B
+-      jmp C
+-      term
+-      define listen
+-      cla+cli+clf 1-opr-opr
+-      szf i 1
+-      jmp .-1
+-      tyi
+-      term
+-      define swap
+-      rcl 9s
+-      rcl 9s
+-      term
+-      define load A,B
+-      lio (B
+-      dio A
+-      term
+-      define setup A,B
+-      law i B
+-      dac A
+-      term
+-      define count A,B
+-      isp A
+-      jmp B
+-      term
+-      define move A,B
+-      lio A
+-      dio B
+-      term
+-      define clear A,B
+-      init .+2, A
+-      dzm
+-      index .-1, (dzm B+1, .-1
+-      term
+-/spacewar 3.1  24 sep 62  p1. 1
+ 000003                        3/
+ 000003        600061          jmp sbf         / ignore seq. break
+ 000004        601561          jmp a40
+ 000005        601556          jmp a1          / use test word for control, note iot 11 00
+-/ interesting and often changed constants
+-/symb loc  usual value (all instructions are executed,
+-/ and may be replaced by jda or jsp)
+ 000006                tno,
+ 000006                6,
+ 000006        710041          law i 41        / number of torps + 1
+ 000007                tvl,
+ 000007                7,
+ 000007        675017          sar 4s          / torpedo velocity
+ 000010                rlt,
+ 000010                10,
+ 000010        710020          law i 20        / torpedo reload time
+ 000011                tlf,
+ 000011                11,
+ 000011        710140          law i 140       / torpedo life
+ 000012                foo,
+ 000012                12,
+ 000012        757777          -20000          / fuel supply
+ 000013                maa,
+ 000013                13,
+ 000013        000010          10              / spaceship angular acceleration
+ 000014                sac,
+ 000014                14,
+ 000014        675017          sar 4s          / spaceship acceleration
+ 000015                str,
+ 000015                15,
+ 000015        000001          1               / star capture radius
+ 000016                me1,
+ 000016                16,
+ 000016        006000          6000            / collision "radius"
+ 000017                me2,
+ 000017                17,
+ 000017        003000          3000            / above/2
+ 000020                ddd,
+ 000020                20,
+ 000020        777777          777777          / 0 to save space for ddt
+ 000021                the,
+ 000021                21,
+ 000021        675777          sar 9s          / amount of torpedo space warpage
+ 000022                mhs,
+ 000022                22,
+ 000022        710010          law i 10        / number of hyperspace shots
+ 000023                hd1,
+ 000023                23,
+ 000023        710040          law i 40        / time in hyperspace before breakout
+ 000024                hd2,
+ 000024                24,
+ 000024        710100          law i 100       / time in hyperspace breakout
+ 000025                hd3,
+ 000025                25,
+ 000025        710200          law i 200       / time to recharge hyperfield generator
+ 000026                hr1,
+ 000026                26,
+ 000026        667777          scl 9s          / scale on hyperspatial displacement
+ 000027                hr2,
+ 000027                27,
+ 000027        667017          scl 4s          / scale on hyperspatially induced velocity
+ 000030                hur,
+ 000030                30,
+ 000030        040000          40000           / hyperspatial uncertancy
+ 000031                ran,
+ 000031                31,
+ 000031        000000          0               / random number
+-/ place to build a private control word routine.
+-/ it should leave the control word in the io as follows.
+-/ high order 4 bits, rotate ccw, rotate cw, (both mean hyperspace)
+-/    fire rocket, and fire torpedo. low order 4 bits, same for
+-/    other ship. routine is entered by jsp cwg.
+ 000040                        40/
+ 000040                cwr,
+ 000040        601672          jmp mg1         / normally iot 11 control
+ 000061                        . 20/           / space
+-////
+-/ routine to flush sequence breaks, if they occur.
+ 000061                sbf,
+ 000061        720004          tyi
+ 000062        220002          lio 2
+ 000063        200000          lac 0
+ 000064        720054          lsm
+ 000065        610001          jmp i 1
+-      define xincr X,Y,INS
+-      lac Y
+-      INS ~ssn
+-      dac Y
+-      lac X
+-      INS ~scn
+-      dac X
+-      term
+-      define yincr X,Y,INS
+-      lac Y
+-      INS ~scn
+-      dac Y
+-      lac X
+-      -INS+add+sub ~ssn
+-      dac X
+-      term
+-////
+-      define dispatch
+-      add (a+r
+-      dap . 1
+-      jmp .
+-a,
+-      term
+-      define dispt A,Y,B
+-      repeat 6, B=B+B
+-      lio Y
+-      dpy-A+B
+-      term
+-      define scale A,B,C
+-      lac A
+-      sar B
+-      dac C
+-      term
+-      define diff V,S,QF
+-      add i V
+-      dac i V
+-      xct QF
+-      add i S
+-      dac i S
+-      term
+-      define random
+-      lac ran
+-      rar 1s
+-      xor (355760
+-      add (355670
+-      dac ran
+-      term
+-      define ranct S,X,C
+-      random
+-      S
+-      X
+-      sma
+-      cma
+-      dac C
+-      term
+-////
+-/sine-cosine subroutine. adams associates
+-/calling sequence= number in ac, jda jda sin or jdacos.
+-/argument is between q+2 pi, with binary point to right of bit 3.
+-/anser has binary point to right of bit 0. time = 2.35 ms.
+-      define mult Z
+-      jda mpy
+-      lac Z
+-      term
+ 000066                cos,
+ 000066        000000          0
+ 000067        260142          dap csx
+ 000070        202760          lac (62210
+ 000071        400066          add cos
+ 000072        240074          dac sin
+ 000073        600077          jmp .+4
+ 000074                sin,
+ 000074        000000          0
+ 000075        260142          dap csx
+ 000076        200074          lac sin
+ 000077        640200          spa
+ 000100                si1,
+ 000100        402761          add (311040
+ 000101        422760          sub (62210
+ 000102        640400          sma
+ 000103        600143          jmp si2
+ 000104        402760          add (62210
+ 000105                si3,
+ 000105        661003          ral 2s
+-      mult (242763
++000106        170171          jda mpy
++000107        202762          lac ZZ11
+ 000110        240074          dac sin
+-      mult sin
++000111        170171          jda mpy
++000112        200074          lac ZZ12
+ 000113        240066          dac cos
+-      mult (756103
++000114        170171          jda mpy
++000115        202763          lac ZZ13
+ 000116        402764          add (121312
+-      mult cos
++000117        170171          jda mpy
++000120        200066          lac ZZ14
+ 000121        402765          add (532511
+-      mult cos
++000122        170171          jda mpy
++000123        200066          lac ZZ15
+ 000124        402766          add (144417
+-      mult sin
++000125        170171          jda mpy
++000126        200074          lac ZZ16
+ 000127        667007          scl 3s
+ 000130        240066          dac cos
+ 000131        060074          xor sin
+ 000132        640400          sma
+ 000133        600141          jmp csx-1
+ 000134        202767          lac (377777
+ 000135        220074          lio sin
+ 000136        642000          spi
+ 000137        761000          cma
+ 000140        600142          jmp csx
+ 000141        200066          lac cos
+ 000142                csx,
+ 000142        600142          jmp .
+ 000143                si2,
+ 000143        761000          cma
+ 000144        402760          add (62210
+ 000145        640400          sma
+ 000146        600105          jmp si3
+ 000147        402760          add (62210
+ 000150        640200          spa
+ 000151        600154          jmp .+3
+ 000152        422760          sub (62210
+ 000153        600105          jmp si3
+ 000154        422760          sub (62210
+ 000155        600100          jmp si1
+-////
+-/bbn multiply subroutine
+-/call.. lac one factor, jdy mpy or imp, lac other factor.
+ 000156                imp,
+ 000156        000000          0                               /returns low 17 bits and sign in ac
+ 000157        260160          dap im1
+ 000160                im1,
+ 000160        100000          xct
+ 000161        170171          jda mpy
+ 000162        200156          lac imp
+ 000163        440160          idx im1
+ 000164        672001          rir 1s
+ 000165        673777          rcr 9s
+ 000166        673777          rcr 9s
+ 000167        610160          jmp i im1
+ 000170                mp2,
+ 000170        000000          0
+ 000171                mpy,
+ 000171        000000          0                               /return 34 bits and 2 signs
+ 000172        260200          dap mp1
+ 000173        200171          lac mpy
+ 000174        640200          spa
+ 000175        761000          cma
+ 000176        673777          rcr 9s
+ 000177        673777          rcr 9s
+ 000200                mp1,
+ 000200        100000          xct
+ 000201        640200          spa
+ 000202        761000          cma
+ 000203        240170          dac mp2
+ 000204        760200          cla
+ 000205        540170          mus mp2
++000206        540170          mus mp2
++000207        540170          mus mp2
++000210        540170          mus mp2
++000211        540170          mus mp2
++000212        540170          mus mp2
++000213        540170          mus mp2
++000214        540170          mus mp2
++000215        540170          mus mp2
++000216        540170          mus mp2
++000217        540170          mus mp2
++000220        540170          mus mp2
++000221        540170          mus mp2
++000222        540170          mus mp2
++000223        540170          mus mp2
++000224        540170          mus mp2
++000225        540170          mus mp2
+ 000226        240170          dac mp2
+ 000227        100200          xct mp1
+ 000230        060171          xor mpy
+ 000231        640400          sma
+ 000232        600243          jmp mp3
+ 000233        200170          lac mp2
+ 000234        761000          cma
+ 000235        673777          rcr 9s
+ 000236        673777          rcr 9s
+ 000237        761000          cma
+ 000240        673777          rcr 9s
+ 000241        673777          rcr 9s
+ 000242        240170          dac mp2
+ 000243                mp3,
+ 000243        440200          idx mp1
+ 000244        200170          lac mp2
+ 000245        610200          jmp i mp1
+-////
+-/integer square root
+-/input in ac, binary point to right of bit 17, jda sqt
+-/answer in ac with binary point between 8 and 9
+-/largest input number = 177777
+ 000246                sqt,
+ 000246        000000          0
+ 000247        260260          dap sqx
+ 000250        710023          law i 23
+ 000251        240304          dac sq1
+ 000252        340305          dzm sq2
+ 000253        220246          lio sqt
+ 000254        340246          dzm sqt
+ 000255                sq3,
+ 000255        460304          isp sq1
+ 000256        600261          jmp .+3
+ 000257        200305          lac sq2
+ 000260                sqx,
+ 000260        600260          jmp .
+ 000261        200305          lac sq2
+ 000262        665001          sal 1s
+ 000263        240305          dac sq2
+ 000264        200246          lac sqt
+ 000265        663003          rcl 2s
+ 000266        650100          sza i
+ 000267        600255          jmp sq3
+ 000270        240246          dac sqt
+ 000271        200305          lac sq2
+ 000272        665001          sal 1s
+ 000273        402770          add (1
+ 000274        420246          sub sqt
+ 000275        640500          sma+sza-skip
+ 000276        600255          jmp sq3
+ 000277        640200          spa
+ 000300        761000          cma
+ 000301        240246          dac sqt
+ 000302        440305          idx sq2
+ 000303        600255          jmp sq3
+ 000304                sq1,
+ 000304        000000          0
+ 000305                sq2,
+ 000305        000000          0
+-////
+-/bbn divide subroutine
+-/calling sequence.. lac hi-dividend, lio lo-dividend, jda dvd, lac divisor.
+-/returns quot in ac, rem in io.
+ 000306                idv,
+ 000306        000000          0               /integer divide, dividend in ac.
+ 000307        260317          dap dv1
+ 000310        200306          lac idv
+ 000311        677777          scr 9s
+ 000312        677377          scr 8s
+ 000313        240315          dac dvd
+ 000314        600317          jmp dv1
+ 000315                dvd,
+ 000315        000000          0
+ 000316        260317          dap dv1
+ 000317                dv1,
+ 000317        100000          xct
+ 000320        640200          spa
+ 000321        761000          cma
+ 000322        240306          dac idv
+ 000323        200315          lac dvd
+ 000324        640400          sma
+ 000325        600334          jmp dv2
+ 000326        761000          cma
+ 000327        673777          rcr 9s
+ 000330        673777          rcr 9s
+ 000331        761000          cma
+ 000332        673777          rcr 9s
+ 000333        673777          rcr 9s
+ 000334                dv2,
+ 000334        420306          sub idv
+ 000335        640400          sma
+ 000336        600376          jmp dve
+ 000337        560306          dis idv
++000340        560306          dis idv
++000341        560306          dis idv
++000342        560306          dis idv
++000343        560306          dis idv
++000344        560306          dis idv
++000345        560306          dis idv
++000346        560306          dis idv
++000347        560306          dis idv
++000350        560306          dis idv
++000351        560306          dis idv
++000352        560306          dis idv
++000353        560306          dis idv
++000354        560306          dis idv
++000355        560306          dis idv
++000356        560306          dis idv
++000357        560306          dis idv
++000360        560306          dis idv
+ 000361        400306          add idv
+ 000362        320306          dio idv
+ 000363        764000          cli
+ 000364        673001          rcr 1s
+ 000365        220315          lio dvd
+ 000366        642000          spi
+ 000367        761000          cma
+ 000370        240315          dac dvd
+ 000371        100317          xct dv1
+ 000372        060315          xor dvd
+ 000373        673777          rcr 9s
+ 000374        673777          rcr 9s
+ 000375        440317          idx dv1
+ 000376                dve,
+ 000376        440317          idx dv1
+ 000377        200306          lac idv
+ 000400        642000          spi
+ 000401        761000          cma
+ 000402        220315          lio dvd
+ 000403        610317          jmp i dv1
+-////
+-/outline compiler
+-/ac=where to compile to,  call oc
+-/ot=address of outline table
+-      define  plinst A
+-      lac A
+-      dac i oc
+-      idx oc
+-      terminate
+-      define comtab A, B
+-      plinst A
+-      jsp ocs
+-      lac B
+-      jmp oce
+-      terminate
+ 000404                ocs,
+ 000404        260411          dap ocz         /puts in swap
+ 000405        330412          dio i oc
+ 000406        440412          idx oc
+ 000407        330412          dio i oc
+ 000410        440412          idx oc
+ 000411                ocz,
+ 000411        600411          jmp .
+ 000412                oc,
+ 000412        000000          0
+ 000413        260554          dap ocx
+ 000414        210554          lac i ocx
+ 000415        260434          dap ocg
+-      plinst (stf 5
++000416        202771          lac ZZ17
++000417        250412          dac i oc
++000420        440412          idx oc
+ 000421        260555          dap ocm
+ 000422        440554          idx ocx
+ 000423                ock,
+-      plinst (lac ~sx1
++000423        202772          lac ZZ18
++000424        250412          dac i oc
++000425        440412          idx oc
+-      plinst (lio ~sy1
++000426        202773          lac ZZ19
++000427        250412          dac i oc
++000430        440412          idx oc
+ 000431        760006          clf 6
+ 000432                ocj,
+-      setup ~occ,6
++000432        710006          law i ZZ210
++000433        243112          dac ZZ110
+ 000434                ocg,
+ 000434        220434          lio .
+ 000435                och,
+ 000435        760200          cla
+ 000436        663007          rcl 3s
+ 000437        323113          dio ~oci
+ 000440        222774          lio (rcl 9s
+-      dispatch
++000441        402775          add (a11
++000442        260443          dap . 1
++000443        600443          jmp .
++000444                a11,
+ 000444        760000          opr
+ 000445        600557          jmp oc1
+ 000446                oco,
+ 000446        600602          jmp oc2
+ 000447                ocq,
+ 000447        600610          jmp oc3
+ 000450                ocp,
+ 000450        600616          jmp oc4
+ 000451                ocr,
+ 000451        600624          jmp oc5
+ 000452        600632          jmp oc6
+-////
+-      plinst (szf 5           //code
++000453        202776          lac ZZ112
++000454        250412          dac i oc
++000455        440412          idx oc
+ 000456        402777          add (4
+ 000457        260556          dap ocn
+-      plinst ocn
++000460        200556          lac ZZ113
++000461        250412          dac i oc
++000462        440412          idx oc
+-      plinst (dac ~sx1
++000463        203000          lac ZZ114
++000464        250412          dac i oc
++000465        440412          idx oc
+-      plinst (dio ~sy1
++000466        203001          lac ZZ115
++000467        250412          dac i oc
++000470        440412          idx oc
+-      plinst (jmp sq6
++000471        203002          lac ZZ116
++000472        250412          dac i oc
++000473        440412          idx oc
+-      plinst (clf 5
++000474        203003          lac ZZ117
++000475        250412          dac i oc
++000476        440412          idx oc
+-      plinst (lac ~scm
++000477        203004          lac ZZ118
++000500        250412          dac i oc
++000501        440412          idx oc
+-      plinst (cma
++000502        203005          lac ZZ119
++000503        250412          dac i oc
++000504        440412          idx oc
+-      plinst (dac ~scm
++000505        203006          lac ZZ120
++000506        250412          dac i oc
++000507        440412          idx oc
+-      plinst (lac ~ssm
++000510        203007          lac ZZ121
++000511        250412          dac i oc
++000512        440412          idx oc
+-      plinst (cma
++000513        203005          lac ZZ122
++000514        250412          dac i oc
++000515        440412          idx oc
+-      plinst (dac ~ssm
++000516        203010          lac ZZ123
++000517        250412          dac i oc
++000520        440412          idx oc
+-      plinst (lac ~csm
++000521        203011          lac ZZ124
++000522        250412          dac i oc
++000523        440412          idx oc
+-      plinst (lio ~ssd
++000524        203012          lac ZZ125
++000525        250412          dac i oc
++000526        440412          idx oc
+-      plinst (dac ~ssd
++000527        203013          lac ZZ126
++000530        250412          dac i oc
++000531        440412          idx oc
+-      plinst (dio ~csm
++000532        203014          lac ZZ127
++000533        250412          dac i oc
++000534        440412          idx oc
+-      plinst (lac ~ssc
++000535        203015          lac ZZ128
++000536        250412          dac i oc
++000537        440412          idx oc
+-      plinst (lio ~csn
++000540        203016          lac ZZ129
++000541        250412          dac i oc
++000542        440412          idx oc
+-      plinst (dac ~csn
++000543        203017          lac ZZ130
++000544        250412          dac i oc
++000545        440412          idx oc
+-      plinst (dio ~ssc
++000546        203020          lac ZZ131
++000547        250412          dac i oc
++000550        440412          idx oc
+-      plinst ocm
++000551        200555          lac ZZ132
++000552        250412          dac i oc
++000553        440412          idx oc
+ 000554                ocx,
+ 000554        600554          jmp .
+ 000555                ocm,
+ 000555        600555          jmp .
+ 000556                ocn,
+ 000556        600556          jmp .
+ 000557                oc1,
+-      plinst (add ~ssn
++000557        203021          lac ZZ133
++000560        250412          dac i oc
++000561        440412          idx oc
+ 000562        620404          jsp ocs
+ 000563        203022          lac (sub ~scn
+ 000564                oce,
+ 000564        250412          dac i oc
+ 000565        440412          idx oc
+ 000566        620404          jsp ocs
+-      plinst (ioh
++000567        203023          lac ZZ134
++000570        250412          dac i oc
++000571        440412          idx oc
+ 000572        203024          lac (dpy-4000
+ 000573                ocd,
+ 000573        250412          dac i oc
+ 000574        440412          idx oc
+ 000575        223113          lio ~oci
+-      count ~occ, och
++000576        463112          isp ZZ135
++000577        600435          jmp ZZ235
+ 000600        440434          idx ocg
+ 000601        600432          jmp ocj
+ 000602                oc2,
+-      comtab (add ~scm, (add ~ssm
+-      plinst ZZ136
++000602        203025          lac ZZ137
++000603        250412          dac i oc
++000604        440412          idx oc
++000605        620404          jsp ocs
++000606        203026          lac ZZ236
++000607        600564          jmp oce
+ 000610                oc3,
+-      comtab (add ~ssc, (sub ~csm
+-      plinst ZZ138
++000610        203027          lac ZZ139
++000611        250412          dac i oc
++000612        440412          idx oc
++000613        620404          jsp ocs
++000614        203030          lac ZZ238
++000615        600564          jmp oce
+ 000616                oc4,
+-      comtab (sub ~scm, (sub ~ssm
+-      plinst ZZ140
++000616        203031          lac ZZ141
++000617        250412          dac i oc
++000620        440412          idx oc
++000621        620404          jsp ocs
++000622        203032          lac ZZ240
++000623        600564          jmp oce
+ 000624                oc5,
+-      comtab (add ~csn, (sub ~ssd
+-      plinst ZZ142
++000624        203033          lac ZZ143
++000625        250412          dac i oc
++000626        440412          idx oc
++000627        620404          jsp ocs
++000630        203034          lac ZZ242
++000631        600564          jmp oce
+ 000632                oc6,
+ 000632        640006          szf 6
+ 000633        600642          jmp oc9
+ 000634        760016          stf 6
+-      plinst (dac ~ssa
++000635        203035          lac ZZ144
++000636        250412          dac i oc
++000637        440412          idx oc
+ 000640        203036          lac (dio ~ssi
+ 000641        600573          jmp ocd
+ 000642                oc9,
+ 000642        760006          clf 6
+-      plinst (lac ~ssa
++000643        203037          lac ZZ145
++000644        250412          dac i oc
++000645        440412          idx oc
+ 000646        203040          lac (lio ~ssi
+ 000647        600573          jmp ocd
+-////
+-/ display a star
+-      define starp
+-      add ~bx
+-      swap
+-      add ~by
+-      swap
+-      ioh
+-      dpy-4000
+-      terminate
+-                              /star
+ 000650                blp,
+ 000650        260675          dap blx
+ 000651        640060          szs 60
+ 000652        600675          jmp blx
+-      random
++000653        200031          lac ran
++000654        671001          rar 1s
++000655        063041          xor (355760
++000656        403042          add (355670
++000657        240031          dac ran
+ 000660        671777          rar 9s
+ 000661        023043          and (add 340
+ 000662        640200          spa
+ 000663        062767          xor (377777
+ 000664        243116          dac ~bx
+ 000665        200031          lac ran
+ 000666        661017          ral 4s
+ 000667        023043          and (add 340
+ 000670        640200          spa
+ 000671        062767          xor (377777
+ 000672        243117          dac ~by
+ 000673        620676          jsp bpt
+ 000674        730000          ioh
+ 000675                blx,
+ 000675        600675          jmp .
+ 000676                bpt,
+ 000676        261117          dap bpx
+-      random
++000677        200031          lac ran
++000700        671001          rar 1s
++000701        063041          xor (355760
++000702        403042          add (355670
++000703        240031          dac ran
+ 000704        675777          sar 9s
+ 000705        675037          sar 5s
+ 000706        640200          spa
+ 000707        761000          cma
+ 000710        665007          sal 3s
+ 000711        403044          add (bds
+ 000712        260715          dap bjm
+ 000713        764206          cla cli clf 6-opr-opr
+ 000714        724007          dpy-4000
+ 000715                bjm,
+ 000715        600715          jmp .
+ 000716                bds,
+-      starp
++000716        403116          add ~bx
+-      swap
++000717        663777          rcl 9s
++000720        663777          rcl 9s
++000721        403117          add ~by
+-      swap
++000722        663777          rcl 9s
++000723        663777          rcl 9s
++000724        730000          ioh
++000725        724007          dpy-4000
+-      starp
++000726        403116          add ~bx
+-      swap
++000727        663777          rcl 9s
++000730        663777          rcl 9s
++000731        403117          add ~by
+-      swap
++000732        663777          rcl 9s
++000733        663777          rcl 9s
++000734        730000          ioh
++000735        724007          dpy-4000
+-      starp
++000736        403116          add ~bx
+-      swap
++000737        663777          rcl 9s
++000740        663777          rcl 9s
++000741        403117          add ~by
+-      swap
++000742        663777          rcl 9s
++000743        663777          rcl 9s
++000744        730000          ioh
++000745        724007          dpy-4000
+-      starp
++000746        403116          add ~bx
+-      swap
++000747        663777          rcl 9s
++000750        663777          rcl 9s
++000751        403117          add ~by
+-      swap
++000752        663777          rcl 9s
++000753        663777          rcl 9s
++000754        730000          ioh
++000755        724007          dpy-4000
+-      starp
++000756        403116          add ~bx
+-      swap
++000757        663777          rcl 9s
++000760        663777          rcl 9s
++000761        403117          add ~by
+-      swap
++000762        663777          rcl 9s
++000763        663777          rcl 9s
++000764        730000          ioh
++000765        724007          dpy-4000
+-      starp
++000766        403116          add ~bx
+-      swap
++000767        663777          rcl 9s
++000770        663777          rcl 9s
++000771        403117          add ~by
+-      swap
++000772        663777          rcl 9s
++000773        663777          rcl 9s
++000774        730000          ioh
++000775        724007          dpy-4000
+-      starp
++000776        403116          add ~bx
+-      swap
++000777        663777          rcl 9s
++001000        663777          rcl 9s
++001001        403117          add ~by
+-      swap
++001002        663777          rcl 9s
++001003        663777          rcl 9s
++001004        730000          ioh
++001005        724007          dpy-4000
+-      starp
++001006        403116          add ~bx
+-      swap
++001007        663777          rcl 9s
++001010        663777          rcl 9s
++001011        403117          add ~by
+-      swap
++001012        663777          rcl 9s
++001013        663777          rcl 9s
++001014        730000          ioh
++001015        724007          dpy-4000
+-      starp
++001016        403116          add ~bx
+-      swap
++001017        663777          rcl 9s
++001020        663777          rcl 9s
++001021        403117          add ~by
+-      swap
++001022        663777          rcl 9s
++001023        663777          rcl 9s
++001024        730000          ioh
++001025        724007          dpy-4000
+-      starp
++001026        403116          add ~bx
+-      swap
++001027        663777          rcl 9s
++001030        663777          rcl 9s
++001031        403117          add ~by
+-      swap
++001032        663777          rcl 9s
++001033        663777          rcl 9s
++001034        730000          ioh
++001035        724007          dpy-4000
+-      starp
++001036        403116          add ~bx
+-      swap
++001037        663777          rcl 9s
++001040        663777          rcl 9s
++001041        403117          add ~by
+-      swap
++001042        663777          rcl 9s
++001043        663777          rcl 9s
++001044        730000          ioh
++001045        724007          dpy-4000
+-      starp
++001046        403116          add ~bx
+-      swap
++001047        663777          rcl 9s
++001050        663777          rcl 9s
++001051        403117          add ~by
+-      swap
++001052        663777          rcl 9s
++001053        663777          rcl 9s
++001054        730000          ioh
++001055        724007          dpy-4000
+-      starp
++001056        403116          add ~bx
+-      swap
++001057        663777          rcl 9s
++001060        663777          rcl 9s
++001061        403117          add ~by
+-      swap
++001062        663777          rcl 9s
++001063        663777          rcl 9s
++001064        730000          ioh
++001065        724007          dpy-4000
+-      starp
++001066        403116          add ~bx
+-      swap
++001067        663777          rcl 9s
++001070        663777          rcl 9s
++001071        403117          add ~by
+-      swap
++001072        663777          rcl 9s
++001073        663777          rcl 9s
++001074        730000          ioh
++001075        724007          dpy-4000
+-      starp
++001076        403116          add ~bx
+-      swap
++001077        663777          rcl 9s
++001100        663777          rcl 9s
++001101        403117          add ~by
+-      swap
++001102        663777          rcl 9s
++001103        663777          rcl 9s
++001104        730000          ioh
++001105        724007          dpy-4000
+-      starp
++001106        403116          add ~bx
+-      swap
++001107        663777          rcl 9s
++001110        663777          rcl 9s
++001111        403117          add ~by
+-      swap
++001112        663777          rcl 9s
++001113        663777          rcl 9s
++001114        730000          ioh
++001115        724007          dpy-4000
+ 001116        640006          szf 6
+ 001117                bpx,
+ 001117        601117          jmp .
+ 001120        760016          stf 6
+ 001121        761000          cma
+-      swap
++001122        663777          rcl 9s
++001123        663777          rcl 9s
+ 001124        761000          cma
+-      swap
++001125        663777          rcl 9s
++001126        663777          rcl 9s
+ 001127        600715          jmp bjm
+-////
+-/background display .  3/13/62, prs.
+-      define dislis J, Q, B
+-      repeat 6, B=B+B
+-      clf 5
+-      lac flo+r
+-      dap fpo+r
+-fs,
+-      dap fin+r
+-      dap fyn+r
+-      idx fyn+r
+-fin,
+-      lac                     /lac x
+-      sub fpr                 /right margin
+-      sma
+-      jmp fgr+r
+-      add (2000
+-frr,
+-      spq
+-fou,
+-      jmp fuu+r
+-fie,
+-      sub (1000
+-      sal 8s
+-fyn,
+-      lio                             /lio y
+-      dpy-i+B
+-      stf 5
+-fid,
+-      idx fyn+r
+-      sad (lio Q+2
+-      jmp flp+r
+-      sad fpo+r
+-      jmp fx+r
+-      dap fin+r
+-      idx fyn+r
+-      jmp fin+r
+-fgr,
+-      add (2000 -20000
+-      jmp frr+r
+-fuu,
+-      szf 5
+-fx,
+-      jmp flo+r+1             /return
+-      idx flo+r
+-      idx flo+r
+-      sas (Q+2
+-      jmp fid+r
+-      law J
+-      dac flo+r
+-      jmp fid+r
+-flp,
+-      lac (lio J
+-      sad fpo+r
+-      jmp fx+r
+-      dap fin+r
+-      law J+1
+-      dap fyn+r
+-      jmp fin+r
+-fpo,
+-      lio
+-flo,
+-      J
+-      terminate
+-////
+-      define background
+-      jsp bck
+-      termin
+ 001130                bck,
+ 001130        261134          dap bcx
+ 001131        640040          szs 40
+ 001132        601134          jmp bcx
+ 001133        461441          isp bcc
+ 001134                bcx,
+ 001134        601134          jmp .
+ 001135        710002          law i 2
+ 001136        241441          dac bcc
+-      dislis 1j,1q,3
++001137        000006          ZZ398=ZZ398+ZZ398
++001137        000014          ZZ398=ZZ398+ZZ398
++001137        000030          ZZ398=ZZ398+ZZ398
++001137        000060          ZZ398=ZZ398+ZZ398
++001137        000140          ZZ398=ZZ398+ZZ398
++001137        000300          ZZ398=ZZ398+ZZ398
++001137        760005          clf 5
++001140        201214          lac flo98
++001141        261213          dap fpo98
++001142                fs98,
++001142        261145          dap fin98
++001143        261156          dap fyn98
++001144        441156          idx fyn98
++001145                fin98,
++001145        200000          lac
++001146        421443          sub fpr
++001147        640400          sma
++001150        601171          jmp fgr98
++001151        403045          add (2000
++001152                frr98,
++001152        650500          spq
++001153                fou98,
++001153        601173          jmp fuu98
++001154                fie98,
++001154        423046          sub (1000
++001155        665377          sal 8s
++001156                fyn98,
++001156        220000          lio
++001157        720307          dpy-i+ZZ398
++001160        760015          stf 5
++001161                fid98,
++001161        441156          idx fyn98
++001162        503047          sad (lio ZZ298+2
++001163        601204          jmp flp98
++001164        501213          sad fpo98
++001165        601174          jmp fx98
++001166        261145          dap fin98
++001167        441156          idx fyn98
++001170        601145          jmp fin98
++001171                fgr98,
++001171        403050          add (2000 -20000
++001172        601152          jmp frr98
++001173                fuu98,
++001173        640005          szf 5
++001174                fx98,
++001174        601215          jmp flo98+1
++001175        441214          idx flo98
++001176        441214          idx flo98
++001177        523051          sas (ZZ298+2
++001200        601161          jmp fid98
++001201        706000          law ZZ198
++001202        241214          dac flo98
++001203        601161          jmp fid98
++001204                flp98,
++001204        203052          lac (lio ZZ198
++001205        501213          sad fpo98
++001206        601174          jmp fx98
++001207        261145          dap fin98
++001210        706001          law ZZ198+1
++001211        261156          dap fyn98
++001212        601145          jmp fin98
++001213                fpo98,
++001213        220000          lio
++001214                flo98,
++001214        006000          ZZ198
+-      dislis 2j,2q,2
++001215        000004          ZZ399=ZZ399+ZZ399
++001215        000010          ZZ399=ZZ399+ZZ399
++001215        000020          ZZ399=ZZ399+ZZ399
++001215        000040          ZZ399=ZZ399+ZZ399
++001215        000100          ZZ399=ZZ399+ZZ399
++001215        000200          ZZ399=ZZ399+ZZ399
++001215        760005          clf 5
++001216        201272          lac flo99
++001217        261271          dap fpo99
++001220                fs99,
++001220        261223          dap fin99
++001221        261234          dap fyn99
++001222        441234          idx fyn99
++001223                fin99,
++001223        200000          lac
++001224        421443          sub fpr
++001225        640400          sma
++001226        601247          jmp fgr99
++001227        403045          add (2000
++001230                frr99,
++001230        650500          spq
++001231                fou99,
++001231        601251          jmp fuu99
++001232                fie99,
++001232        423046          sub (1000
++001233        665377          sal 8s
++001234                fyn99,
++001234        220000          lio
++001235        720207          dpy-i+ZZ399
++001236        760015          stf 5
++001237                fid99,
++001237        441234          idx fyn99
++001240        503053          sad (lio ZZ299+2
++001241        601262          jmp flp99
++001242        501271          sad fpo99
++001243        601252          jmp fx99
++001244        261223          dap fin99
++001245        441234          idx fyn99
++001246        601223          jmp fin99
++001247                fgr99,
++001247        403050          add (2000 -20000
++001250        601230          jmp frr99
++001251                fuu99,
++001251        640005          szf 5
++001252                fx99,
++001252        601273          jmp flo99+1
++001253        441272          idx flo99
++001254        441272          idx flo99
++001255        523054          sas (ZZ299+2
++001256        601237          jmp fid99
++001257        706022          law ZZ199
++001260        241272          dac flo99
++001261        601237          jmp fid99
++001262                flp99,
++001262        203055          lac (lio ZZ199
++001263        501271          sad fpo99
++001264        601252          jmp fx99
++001265        261223          dap fin99
++001266        706023          law ZZ199+1
++001267        261234          dap fyn99
++001270        601223          jmp fin99
++001271                fpo99,
++001271        220000          lio
++001272                flo99,
++001272        006022          ZZ199
+-      dislis 3j,3q,1
++001273        000002          ZZ3100=ZZ3100+ZZ3100
++001273        000004          ZZ3100=ZZ3100+ZZ3100
++001273        000010          ZZ3100=ZZ3100+ZZ3100
++001273        000020          ZZ3100=ZZ3100+ZZ3100
++001273        000040          ZZ3100=ZZ3100+ZZ3100
++001273        000100          ZZ3100=ZZ3100+ZZ3100
++001273        760005          clf 5
++001274        201350          lac flo100
++001275        261347          dap fpo100
++001276                fs100,
++001276        261301          dap fin100
++001277        261312          dap fyn100
++001300        441312          idx fyn100
++001301                fin100,
++001301        200000          lac
++001302        421443          sub fpr
++001303        640400          sma
++001304        601325          jmp fgr100
++001305        403045          add (2000
++001306                frr100,
++001306        650500          spq
++001307                fou100,
++001307        601327          jmp fuu100
++001310                fie100,
++001310        423046          sub (1000
++001311        665377          sal 8s
++001312                fyn100,
++001312        220000          lio
++001313        720107          dpy-i+ZZ3100
++001314        760015          stf 5
++001315                fid100,
++001315        441312          idx fyn100
++001316        503056          sad (lio ZZ2100+2
++001317        601340          jmp flp100
++001320        501347          sad fpo100
++001321        601330          jmp fx100
++001322        261301          dap fin100
++001323        441312          idx fyn100
++001324        601301          jmp fin100
++001325                fgr100,
++001325        403050          add (2000 -20000
++001326        601306          jmp frr100
++001327                fuu100,
++001327        640005          szf 5
++001330                fx100,
++001330        601351          jmp flo100+1
++001331        441350          idx flo100
++001332        441350          idx flo100
++001333        523057          sas (ZZ2100+2
++001334        601315          jmp fid100
++001335        706044          law ZZ1100
++001336        241350          dac flo100
++001337        601315          jmp fid100
++001340                flp100,
++001340        203060          lac (lio ZZ1100
++001341        501347          sad fpo100
++001342        601330          jmp fx100
++001343        261301          dap fin100
++001344        706045          law ZZ1100+1
++001345        261312          dap fyn100
++001346        601301          jmp fin100
++001347                fpo100,
++001347        220000          lio
++001350                flo100,
++001350        006044          ZZ1100
+-      dislis 4j,4q,0
++001351        000000          ZZ3101=ZZ3101+ZZ3101
++001351        000000          ZZ3101=ZZ3101+ZZ3101
++001351        000000          ZZ3101=ZZ3101+ZZ3101
++001351        000000          ZZ3101=ZZ3101+ZZ3101
++001351        000000          ZZ3101=ZZ3101+ZZ3101
++001351        000000          ZZ3101=ZZ3101+ZZ3101
++001351        760005          clf 5
++001352        201426          lac flo101
++001353        261425          dap fpo101
++001354                fs101,
++001354        261357          dap fin101
++001355        261370          dap fyn101
++001356        441370          idx fyn101
++001357                fin101,
++001357        200000          lac
++001360        421443          sub fpr
++001361        640400          sma
++001362        601403          jmp fgr101
++001363        403045          add (2000
++001364                frr101,
++001364        650500          spq
++001365                fou101,
++001365        601405          jmp fuu101
++001366                fie101,
++001366        423046          sub (1000
++001367        665377          sal 8s
++001370                fyn101,
++001370        220000          lio
++001371        720007          dpy-i+ZZ3101
++001372        760015          stf 5
++001373                fid101,
++001373        441370          idx fyn101
++001374        503061          sad (lio ZZ2101+2
++001375        601416          jmp flp101
++001376        501425          sad fpo101
++001377        601406          jmp fx101
++001400        261357          dap fin101
++001401        441370          idx fyn101
++001402        601357          jmp fin101
++001403                fgr101,
++001403        403050          add (2000 -20000
++001404        601364          jmp frr101
++001405                fuu101,
++001405        640005          szf 5
++001406                fx101,
++001406        601427          jmp flo101+1
++001407        441426          idx flo101
++001410        441426          idx flo101
++001411        523062          sas (ZZ2101+2
++001412        601373          jmp fid101
++001413        706306          law ZZ1101
++001414        241426          dac flo101
++001415        601373          jmp fid101
++001416                flp101,
++001416        203063          lac (lio ZZ1101
++001417        501425          sad fpo101
++001420        601406          jmp fx101
++001421        261357          dap fin101
++001422        706307          law ZZ1101+1
++001423        261370          dap fyn101
++001424        601357          jmp fin101
++001425                fpo101,
++001425        220000          lio
++001426                flo101,
++001426        006306          ZZ1101
+ 001427        461442          isp bkc
+ 001430        601134          jmp bcx
+ 001431        710020          law i 20
+ 001432        241442          dac bkc
+ 001433        710001          law i 1
+ 001434        401443          add fpr
+ 001435        640200          spa
+ 001436        403064          add (20000
+ 001437        241443          dac fpr
+ 001440        601134          jmp bcx
+ 001441                bcc,
+ 001441        000000          0
+ 001442                bkc,
+ 001442        000000          0
+ 001443                fpr,
+ 001443        010000          10000
+-////
+-/spacewar 3.1  24 sep 62  pt. 2
+-/main control for spaceships
+ 001444        000030          nob=30                  /total number of colliding objects
+ 001444                ml0,
+-      load ~mtc, -4000        /delay for loop
++001444        223065          lio (ZZ2102
++001445        323120          dio ZZ1102
+-      init ml1, mtb           /loc of calc routines
++001446        703365          law ZZ2103
++001447        261703          dap ZZ1103
+ 001450        403066          add (nob
+ 001451        261737          dap mx1                 /x
+ 001452        003415          nx1=mtb nob
+ 001452        403066          add (nob
+ 001453        261747          dap my1                 /y
+ 001454        003445          ny1=nx1 nob
+ 001454        403066          add (nob
+ 001455        261772          dap ma1                 / count for length of explosion or torp
+ 001456        003475          na1=ny1 nob
+ 001456        403066          add (nob
+ 001457        262006          dap mb1                 / count of instructions taken by calc routine
+ 001460        003525          nb1=na1 nob
+ 001460        403066          add (nob
+ 001461        243121          dac ~mdx                / dx
+ 001462        003555          ndx=nb1 nob
+ 001462        403066          add (nob
+ 001463        243122          dac ~mdy                / dy
+ 001464        003605          ndy=ndx nob
+ 001464        403066          add (nob
+ 001465        262327          dap mom                 /angular velocity
+ 001466        003635          nom=ndy nob
+ 001466        403067          add (2
+ 001467        262343          dap mth                 / angle
+ 001470        003637          nth=nom 2
+ 001470        403067          add (2
+ 001471        243123          dac ~mfu                /fuel
+ 001472        003641          nfu=nth 2
+ 001472        403067          add (2
+ 001473        243124          dac ~mtr                / no torps remaining
+ 001474        003643          ntr=nfu 2
+ 001474        403067          add (2
+ 001475        261732          dap mot                 / outline of spaceship
+ 001476        003645          not=ntr 2
+ 001476        403067          add (2
+ 001477        262577          dap mco                 / old control word
+ 001500        003647          nco=not 2
+ 001500        403067          add (2
+ 001501        243125          dac ~mh1
+ 001502        003651          nh1=nco 2
+ 001502        403067          add (2
+ 001503        243126          dac ~mh2
+ 001504        003653          nh2=nh1 2
+ 001504        403067          add (2
+ 001505        243127          dac ~mh3
+ 001506        003655          nh3=nh2 2
+ 001506        403067          add (2
+ 001507        243130          dac ~mh4
+ 001510        003657          nh4=nh3 2
+ 001510        003661          nnn=nh4 2
+-////
+ 001510        702310          law ss1
+ 001511        063365          xor mtb
+ 001512        640100          sza
+ 001513        601534          jmp mdn
+ 001514        702314          law ss2
+ 001515        063366          xor mtb 1
+ 001516        640100          sza
+ 001517        601534          jmp mdn
+ 001520        700001          law 1                   / test if both ships out of torps
+ 001521        403643          add ntr
+ 001522        640200          spa
+ 001523        601530          jmp md1
+ 001524        700001          law 1
+ 001525        403644          add ntr 1
+ 001526        650200          spa i
+ 001527        601534          jmp mdn
+ 001530                md1,
+ 001530        100011          xct tlf                 / restart delay is 2x torpedo life
+ 001531        665001          sal 1s
+ 001532        243131          dac ~ntd
+ 001533        601703          jmp ml1
+ 001534                mdn,
+-      count ~ntd,ml1
++001534        463131          isp ZZ1104
++001535        601703          jmp ZZ2104
+ 001536        760011          stf 1
+ 001537        760012          stf 2
+ 001540        702310          law ss1
+ 001541        063365          xor mtb
+ 001542        640100          sza
+ 001543        760001          clf 1
+ 001544        650100          sza i
+ 001545        443132          idx ~1sc
+ 001546        702314          law ss2
+ 001547        063366          xor mtb 1
+ 001550        640100          sza
+ 001551        760002          clf 2
+ 001552        650100          sza i
+ 001553        443133          idx ~2sc
+ 001554        760002          clf 2
+ 001555        601564          jmp a
+-////
+ 001556                a1,
+ 001556        701676          law mg2                 / test word control
+ 001557        243134          dac ~cwg
+ 001560        601564          jmp a
+ 001561                a40,
+ 001561        700040          law cwr                 / here from start at 4
+ 001562        243134          dac ~cwg
+ 001563        601613          jmp a6
+ 001564                a,
+ 001564        203135          lac ~gct
+ 001565        640400          sma
+ 001566        601576          jmp a5
+-      count ~gct, a5
++001567        463135          isp ZZ1105
++001570        601576          jmp ZZ2105
+ 001571        203132          lac ~1sc
+ 001572        523133          sas ~2sc
+ 001573        601602          jmp a4
+ 001574        710001          law i 1
+ 001575        243135          dac ~gct
+ 001576                a5,
+ 001576        762200          lat
+ 001577        023070          and (40
+ 001600        650100          sza i
+ 001601        601621          jmp a2
+ 001602                a4,
+ 001602        203132          lac ~1sc
+ 001603        223133          lio ~2sc
+ 001604        760400          hlt
+ 001605        762200          lat
+ 001606        023070          and (40
+ 001607        640100          sza
+ 001610        601621          jmp a2
+ 001611        343132          dzm ~1sc
+ 001612        343133          dzm ~2sc
+ 001613                a6,
+ 001613        762200          lat
+ 001614        671077          rar 6s
+ 001615        023071          and (37
+ 001616        640100          sza
+ 001617        761000          cma
+ 001620        243135          dac ~gct
+ 001621                a2,
+-      clear mtb, nnn-1                / clear out all tables
+-      init .+2, ZZ1106
++001621        703365          law ZZ2107
++001622        261623          dap ZZ1107
++001623        340000          dzm
+-      index .-1, (dzm ZZ2106+1, .-1
++001624        441623          idx ZZ1108
++001625        523072          sas ZZ2108
++001626        601623          jmp ZZ3108
+ 001627        702310          law ss1
+ 001630        243365          dac mtb
+ 001631        702314          law ss2
+ 001632        243366          dac mtb 1
+ 001633        203073          lac (200000
+ 001634        243415          dac nx1
+ 001635        243445          dac ny1
+ 001636        761000          cma
+ 001637        243416          dac nx1 1
+ 001640        243446          dac ny1 1
+ 001641        203074          lac (144420
+ 001642        243637          dac nth
+-////
+ 001643        703661          law nnn                                 / start of outline problem
+ 001644        243645          dac not
+ 001645        220020          lio ddd
+ 001646        652000          spi i
+ 001647        601652          jmp a3
+ 001650        170412          jda oc
+ 001651        002735          ot1
+ 001652                a3,
+ 001652        243646          dac not 1
+ 001653        170412          jda oc
+ 001654        002746          ot2
+ 001655        100006          xct tno
+ 001656        243643          dac ntr
+ 001657        243644          dac ntr 1
+ 001660        200012          lac foo
+ 001661        243641          dac nfu
+ 001662        243642          dac nfu 1
+ 001663        702000          law 2000
+ 001664        243525          dac nb1
+ 001665        243526          dac nb1 1
+ 001666        100022          xct mhs
+ 001667        243653          dac nh2
+ 001670        243654          dac nh2 1
+ 001671        601444          jmp ml0
+-/ control word get routines
+ 001672                mg1,
+ 001672        261675          dap mg3
+ 001673        764000          cli
+ 001674        720011          iot 11
+ 001675                mg3,
+ 001675        601675          jmp .
+ 001676                mg2,
+ 001676        261702          dap mg4
+ 001677        762200          lat
+-      swap
++001700        663777          rcl 9s
++001701        663777          rcl 9s
+ 001702                mg4,
+ 001702        601702          jmp .
+-////
+ 001703                ml1,
+ 001703        201703          lac .                   / 1st control word
+ 001704        650100          sza i                   / zero if not active
+ 001705        602011          jmp mq1                 / not active
+-      swap
++001706        663777          rcl 9s
++001707        663777          rcl 9s
+ 001710        443136          idx ~moc
+ 001711        642000          spi
+ 001712        602003          jmp mq4
+ 001713        700001          law 1
+ 001714        401703          add ml1
+ 001715        261734          dap ml2
+ 001716        700001          law 1
+ 001717        401737          add mx1
+ 001720        261740          dap mx2
+ 001721        700001          law 1
+ 001722        401747          add my1
+ 001723        261750          dap my2
+ 001724        700001          law 1
+ 001725        401772          add ma1
+ 001726        261773          dap ma2
+ 001727        700001          law 1
+ 001730        402006          add mb1
+ 001731        261766          dap mb2
+ 001732                mot,
+ 001732        201732          lac .
+ 001733        262530          dap sp5
+ 001734                ml2,
+ 001734        201734          lac .                   / 2nd control word
+ 001735        650500          spq                     / can it collide?
+ 001736        601774          jmp mq2                 / no
+ 001737                mx1,
+ 001737        201737          lac .                   / calc if collision
+ 001740                mx2,
+ 001740        421740          sub .                   / delta x
+ 001741        640200          spa                     / take abs value
+ 001742        761000          cma
+ 001743        243137          dac ~mt1
+ 001744        420016          sub me1                 / < epsilon ?
+ 001745        640400          sma
+ 001746        601774          jmp mq2                 / no
+ 001747                my1,
+ 001747        201747          lac .
+ 001750                my2,
+ 001750        421750          sub .
+ 001751        640200          spa
+ 001752        761000          cma
+ 001753        420016          sub me1                 / < epsilon ?
+ 001754        640400          sma
+ 001755        601774          jmp mq2                 / no
+ 001756        403137          add ~mt1
+ 001757        420017          sub me2
+ 001760        640400          sma
+ 001761        601774          jmp mq2
+ 001762        203103          lac (mex 400000 / yes, explode
+ 001763        251703          dac i ml1               / replace calc routine with explosion
+ 001764        251734          dac i ml2
+ 001765        212006          lac i mb1               / duration of explosion
+ 001766                mb2,
+ 001766        401766          add .
+ 001767        761000          cma
+ 001770        675377          sar 8s
+ 001771        402770          add (1
+ 001772                ma1,
+ 001772        241772          dac .
+ 001773                ma2,
+ 001773        241773          dac .
+ 001774                mq2,
+ 001774        441740          idx mx2                 / end of comparion loop
+ 001775        441750          idx my2
+ 001776        441773          idx ma2
+ 001777        441766          idx mb2
+-      index ml2, (lac mtb nob, ml2
++002000        441734          idx ZZ1111
++002001        523075          sas ZZ2111
++002002        601734          jmp ZZ3111
+-////
+ 002003                mq4,
+ 002003        211703          lac i ml1               / routine for calculating spaceship
+ 002004        262005          dap . 1                 / or other object and displaying it
+ 002005        622005          jsp .
+ 002006                mb1,
+ 002006        202006          lac .                   / alter count of number of instructions
+ 002007        403120          add ~mtc
+ 002010        243120          dac ~mtc
+ 002011                mq1,
+ 002011        441737          idx mx1                 / end of comparison and display loop
+ 002012        441747          idx my1
+ 002013        441772          idx ma1
+ 002014        442006          idx mb1
+ 002015        443121          idx ~mdx
+ 002016        443122          idx ~mdy
+ 002017        442327          idx mom
+ 002020        442343          idx mth
+ 002021        443140          idx ~mas
+ 002022        443123          idx ~mfu
+ 002023        443124          idx ~mtr
+ 002024        441732          idx mot
+ 002025        442577          idx mco
+ 002026        443125          idx ~mh1
+ 002027        443126          idx ~mh2
+ 002030        443127          idx ~mh3
+ 002031        443130          idx ~mh4
+-      index ml1, (lac mtb nob-1, ml1
++002032        441703          idx ZZ1112
++002033        523076          sas ZZ2112
++002034        601703          jmp ZZ3112
+ 002035        211703          lac i ml1               / display and compute last point
+ 002036        650100          sza i                   / if active
+ 002037        602045          jmp mq3
+ 002040        262041          dap . 1
+ 002041        622041          jsp .
+ 002042        212006          lac i mb1
+ 002043        403120          add ~mtc
+ 002044        243120          dac ~mtc
+ 002045                mq3,
+-      background              / display stars of the heavens
++002045        621130          jsp bck
+ 002046        620650          jsp blp                 / display massive star
+-      count ~mtc, .   / use the rest of time of main loop
++002047        463120          isp ZZ1114
++002050        602047          jmp ZZ2114
+ 002051        601444          jmp ml0                 / repeat whole works
+-////
+-/ misc calculation routines
+-      / explosion
+ 002052                mex,
+ 002052        262133          dap mxr
+ 002053        760200          cla
+-      diff ~mdx, mx1, (sar 3s
++002054        413121          add i ZZ1115
++002055        253121          dac i ZZ1115
++002056        103077          xct ZZ3115
++002057        411737          add i ZZ2115
++002060        251737          dac i ZZ2115
+ 002061        760200          cla
+-      diff ~mdy, my1, (sar 3s
++002062        413122          add i ZZ1116
++002063        253122          dac i ZZ1116
++002064        103077          xct ZZ3116
++002065        411747          add i ZZ2116
++002066        251747          dac i ZZ2116
+ 002067        702134          law ms2
+ 002070        262117          dap msh
+ 002071        212006          lac i mb1               / time involved
+ 002072        765000          cma cli-opr
+ 002073        675007          sar 3s
+ 002074        243141          dac ~mxc
+ 002075                ms1,
+ 002075        423100          sub (140
+ 002076        640400          sma
+ 002077        442117          idx msh
+ 002100                mz1,
+-      random
++002100        200031          lac ran
++002101        671001          rar 1s
++002102        063041          xor (355760
++002103        403042          add (355670
++002104        240031          dac ran
+ 002105        023101          and (777
+ 002106        043102          ior (scl
+ 002107        242120          dac mi1
+-      random
++002110        200031          lac ran
++002111        671001          rar 1s
++002112        063041          xor (355760
++002113        403042          add (355670
++002114        240031          dac ran
+ 002115        677777          scr 9s
+ 002116        676777          sir 9s
+ 002117                msh,
+ 002117        102117          xct .
+ 002120                mi1,
+ 002120        760400          hlt
+ 002121        411747          add i my1
+-      swap
++002122        663777          rcl 9s
++002123        663777          rcl 9s
+ 002124        411737          add i mx1
+ 002125        720307          dpy-i 300
+-      count ~mxc, mz1
++002126        463141          isp ZZ1120
++002127        602100          jmp ZZ2120
+-      count i ma1, mxr
++002130        471772          isp ZZ1121
++002131        602133          jmp ZZ2121
+ 002132        351703          dzm i ml1
+ 002133                mxr,
+ 002133        602133          jmp .
+ 002134                ms2,
+ 002134        677001          scr 1s
+ 002135        677007          scr 3s
+-/ torpedo calc routine
+ 002136                tcr,
+ 002136        262167          dap trc
+-      count i ma1, tc1
++002137        471772          isp ZZ1122
++002140        602146          jmp ZZ2122
+ 002141        203103          lac (mex 400000
+ 002142        251703          dac i ml1
+ 002143        710002          law i 2
+ 002144        251772          dac i ma1
+ 002145        602167          jmp trc
+ 002146                tc1,
+ 002146        211737          lac i mx1
+ 002147        675777          sar 9s
+ 002150        100021          xct the
+-      diff ~mdy, my1, (sar 3s
++002151        413122          add i ZZ1123
++002152        253122          dac i ZZ1123
++002153        103077          xct ZZ3123
++002154        411747          add i ZZ2123
++002155        251747          dac i ZZ2123
+ 002156        675777          sar 9s
+ 002157        100021          xct the
+-      diff ~mdx, mx1, (sar 3s
++002160        413121          add i ZZ1124
++002161        253121          dac i ZZ1124
++002162        103077          xct ZZ3124
++002163        411737          add i ZZ2124
++002164        251737          dac i ZZ2124
+-      dispt i, i my1, 1
++002165        000002          ZZ3125=ZZ3125+ZZ3125
++002165        000004          ZZ3125=ZZ3125+ZZ3125
++002165        000010          ZZ3125=ZZ3125+ZZ3125
++002165        000020          ZZ3125=ZZ3125+ZZ3125
++002165        000040          ZZ3125=ZZ3125+ZZ3125
++002165        000100          ZZ3125=ZZ3125+ZZ3125
++002165        231747          lio ZZ2125
++002166        720107          dpy-ZZ1125+ZZ3125
+ 002167                trc,
+ 002167        602167          jmp .
+-////
+-/ hyperspace routines
+-/ this routine handles a non-colliding ship invisibly
+-/ in hyperspace
+ 002170                hp1,
+ 002170        262245          dap hp2
+-      count i ma1, hp2
++002171        471772          isp ZZ1126
++002172        602245          jmp ZZ2126
+ 002173        702246          law hp3                         / next step
+ 002174        251703          dac i ml1
+ 002175        700007          law 7
+ 002176        252006          dac i mb1
+-      random
++002177        200031          lac ran
++002200        671001          rar 1s
++002201        063041          xor (355760
++002202        403042          add (355670
++002203        240031          dac ran
+ 002204        677777          scr 9s
+ 002205        676777          sir 9s
+ 002206        100026          xct hr1
+ 002207        411737          add i mx1
+ 002210        251737          dac i mx1
+-      swap
++002211        663777          rcl 9s
++002212        663777          rcl 9s
+ 002213        411747          add i my1
+ 002214        251747          dac i my1
+-      random
++002215        200031          lac ran
++002216        671001          rar 1s
++002217        063041          xor (355760
++002220        403042          add (355670
++002221        240031          dac ran
+ 002222        677777          scr 9s
+ 002223        676777          sir 9s
+ 002224        100027          xct hr2
+ 002225        253122          dac i ~mdy
+ 002226        333121          dio i ~mdx
+-      setup ~hpt,3
++002227        710003          law i ZZ2130
++002230        243142          dac ZZ1130
+ 002231        200031          lac ran
+ 002232        252343          dac i mth
+ 002233                hp4,
+ 002233        212343          lac i mth
+ 002234        640400          sma
+ 002235        422761          sub (311040
+ 002236        640200          spa
+ 002237        402761          add (311040
+ 002240        252343          dac i mth
+-      count ~hpt,hp4
++002241        463142          isp ZZ1131
++002242        602233          jmp ZZ2131
+ 002243        100024          xct hd2
+ 002244        251772          dac i ma1
+ 002245                hp2,
+ 002245        602245          jmp .
+-/ this routine handles a ship breaking out of
+-/ hyperspace
+ 002246                hp3,
+ 002246        262307          dap hp5
+-      count i ma1,hp6
++002247        471772          isp ZZ1132
++002250        602304          jmp ZZ2132
+ 002251        213125          lac i ~mh1
+ 002252        251703          dac i ml1
+ 002253        702000          law 2000
+ 002254        252006          dac i mb1
+-      count i ~mh2,hp7
++002255        473126          isp ZZ1133
++002256        602260          jmp ZZ2133
+ 002257        353126          dzm i ~mh2
+-////
+ 002260                hp7,
+ 002260        100025          xct hd3
+ 002261        253127          dac i ~mh3
+ 002262        213130          lac i ~mh4
+ 002263        400030          add hur
+ 002264        253130          dac i ~mh4
+-      random
++002265        200031          lac ran
++002266        671001          rar 1s
++002267        063041          xor (355760
++002270        403042          add (355670
++002271        240031          dac ran
+ 002272        043104          ior (400000
+ 002273        413130          add i ~mh4
+ 002274        640200          spa
+ 002275        602307          jmp hp5
+ 002276        203103          lac (mex 400000
+ 002277        251703          dac i ml1
+ 002300        710010          law i 10
+ 002301        251772          dac i ma1
+ 002302        702000          law 2000
+ 002303        252006          dac i mb1
+ 002304                hp6,
+ 002304        211737          lac i mx1
+-      dispt i, i my1, 2
++002305        000004          ZZ3135=ZZ3135+ZZ3135
++002305        000010          ZZ3135=ZZ3135+ZZ3135
++002305        000020          ZZ3135=ZZ3135+ZZ3135
++002305        000040          ZZ3135=ZZ3135+ZZ3135
++002305        000100          ZZ3135=ZZ3135+ZZ3135
++002305        000200          ZZ3135=ZZ3135+ZZ3135
++002305        231747          lio ZZ2135
++002306        720207          dpy-ZZ1135+ZZ3135
+ 002307                hp5,
+ 002307        602307          jmp .
+-////
+-/ spaceship calc
+ 002310                ss1,
+ 002310        262713          dap srt                 / first spaceship
+ 002311        633134          jsp i ~cwg
+ 002312        323143          dio ~scw
+ 002313        602320          jmp sr0
+ 002314                ss2,
+ 002314        262713          dap srt
+ 002315        633134          jsp i ~cwg
+ 002316        672017          rir 4s
+ 002317        323143          dio ~scw
+ 002320                sr0,
+ 002320                sc1,
+ 002320        223143          lio ~scw                /control word
+ 002321        760206          clf 6 cla-opr           /update angle
+ 002322        642000          spi
+ 002323        400013          add maa
+ 002324        662001          ril 1s
+ 002325        642000          spi
+ 002326        420013          sub maa
+ 002327                mom,
+ 002327        402327          add .
+ 002330        252327          dac i mom
+ 002331        640010          szs 10
+ 002332        602335          jmp sr8
+ 002333        352327          dzm i mom
+ 002334        661177          ral 7s
+ 002335                sr8,
+ 002335        662001          ril 1s
+ 002336        642000          spi
+ 002337        760016          stf 6
+ 002340        233123          lio i ~mfu
+ 002341        652000          spi i
+ 002342        760006          clf 6
+ 002343                mth,
+ 002343        402343          add .
+ 002344        640400          sma
+ 002345        422761          sub (311040
+ 002346        640200          spa
+ 002347        402761          add (311040
+ 002350        252343          dac i mth
+ 002351        170074          jda sin
+ 002352        243144          dac ~sn
+ 002353        343116          dzm ~bx
+ 002354        343117          dzm ~by
+ 002355        640060          szs 60
+ 002356        602430          jmp bsg
+ 002357        211737          lac i mx1
+ 002360        675777          sar 9s
+ 002361        675003          sar 2s
+ 002362        243145          dac ~t1
+ 002363        170156          jda imp
+ 002364        203145          lac ~t1
+ 002365        243146          dac ~t2
+ 002366        211747          lac i my1
+-////
+ 002367        675777          sar 9s
+ 002370        675003          sar 2s
+ 002371        243145          dac ~t1
+ 002372        170156          jda imp
+ 002373        203145          lac ~t1
+ 002374        403146          add ~t2
+ 002375        420015          sub str
+ 002376        650500          sma i sza-skp
+ 002377        602714          jmp poh
+ 002400        400015          add str
+ 002401        243145          dac ~t1
+ 002402        170246          jda sqt
+ 002403        675777          sar 9s
+ 002404        170171          jda mpy
+ 002405        203145          lac ~t1
+ 002406        677003          scr 2s
+ 002407        650020          szs i 20                / switch 2 for light star
+ 002410        677003          scr 2s
+ 002411        640100          sza
+ 002412        602430          jmp bsg
+ 002413        323145          dio ~t1
+ 002414        211737          lac i mx1
+ 002415        761000          cma
+ 002416        170306          jda idv
+ 002417        203145          lac ~t1
+ 002420        760000          opr
+ 002421        243116          dac ~bx
+ 002422        211747          lac i my1
+ 002423        761000          cma
+ 002424        170306          jda idv
+ 002425        203145          lac ~t1
+ 002426        760000          opr
+ 002427        243117          dac ~by
+ 002430                bsg,
+ 002430        760200          cla
+ 002431        513123          sad i ~mfu
+ 002432        760006          clf 6
+ 002433        212343          lac i mth
+ 002434        170066          jda cos
+ 002435        243147          dac ~cs
+ 002436        675777          sar 9s
+ 002437        100014          xct sac
+ 002440        650006          szf i 6
+ 002441        760200          cla
+ 002442        403117          add ~by
+-      diff ~mdy, my1, (sar 3s
++002443        413122          add i ZZ1136
++002444        253122          dac i ZZ1136
++002445        103077          xct ZZ3136
++002446        411747          add i ZZ2136
++002447        251747          dac i ZZ2136
+ 002450        203144          lac ~sn
+ 002451        675777          sar 9s
+ 002452        100014          xct sac
+ 002453        761000          cma
+ 002454        650006          szf i 6
+ 002455        760200          cla
+ 002456        403116          add ~bx
+-      diff ~mdx, mx1, (sar 3s
++002457        413121          add i ZZ1137
++002460        253121          dac i ZZ1137
++002461        103077          xct ZZ3137
++002462        411737          add i ZZ2137
++002463        251737          dac i ZZ2137
+ 002464                sp1,
+-      scale ~sn, 5s, ~ssn
++002464        203144          lac ZZ1138
++002465        675037          sar ZZ2138
++002466        243150          dac ZZ3138
+ 002467                sp2,
+-      scale ~cs, 5s, ~scn
++002467        203147          lac ZZ1139
++002470        675037          sar ZZ2139
++002471        243114          dac ZZ3139
+ 002472        211737          lac i mx1
+-////
+ 002473        423150          sub ~ssn
+ 002474        243151          dac ~sx1
+ 002475        423150          sub ~ssn
+ 002476        243152          dac ~stx
+ 002477        211747          lac i my1
+ 002500        403114          add ~scn
+ 002501        243153          dac ~sy1
+ 002502        403114          add ~scn
+ 002503        243154          dac ~sty
+-/ Modified for Smaller Laptop screens - BDS
+-//    scale ~sn, 9s, ~ssn
+-//    scale ~cs, 9s, ~scn
+-      scale ~sn, 8s, ~ssn
++002504        203144          lac ZZ1140
++002505        675377          sar ZZ2140
++002506        243150          dac ZZ3140
+-      scale ~cs, 8s, ~scn
++002507        203147          lac ZZ1141
++002510        675377          sar ZZ2141
++002511        243114          dac ZZ3141
+ 002512        203150          lac ~ssn
+ 002513        243155          dac ~ssm
+ 002514        403114          add ~scn
+ 002515        243156          dac ~ssc
+ 002516        243157          dac ~ssd
+ 002517        203150          lac ~ssn
+ 002520        423114          sub ~scn
+ 002521        243160          dac ~csn
+ 002522        761000          cma
+ 002523        243161          dac ~csm
+ 002524        203114          lac ~scn
+ 002525        243162          dac ~scm
+ 002526        764200          cla cli-opr
+ 002527        724007          dpy-4000
+ 002530                sp5,
+ 002530        602530          jmp .
+ 002531                sq6,
+ 002531        730000          ioh
+-      ranct sar 9s, sar 4s, ~src
+-      random
++002532        200031          lac ran
++002533        671001          rar 1s
++002534        063041          xor (355760
++002535        403042          add (355670
++002536        240031          dac ran
++002537        675777          ZZ1142
++002540        675017          ZZ2142
++002541        640400          sma
++002542        761000          cma
++002543        243163          dac ZZ3142
+ 002544        223143          lio ~scw
+ 002545        662003          ril 2s
+ 002546        652000          spi i                           / not blasting
+ 002547        602574          jmp sq9                         / no tail
+ 002550                sq7,
+-      scale ~sn, 8s, ~ssn
++002550        203144          lac ZZ1144
++002551        675377          sar ZZ2144
++002552        243150          dac ZZ3144
+-      scale ~cs, 8s, ~scn
++002553        203147          lac ZZ1145
++002554        675377          sar ZZ2145
++002555        243114          dac ZZ3145
+-      count i ~mfu, st2
++002556        473123          isp ZZ1146
++002557        602562          jmp ZZ2146
+ 002560        353123          dzm i ~mfu
+ 002561        602574          jmp sq9
+ 002562                st2,
+-      yincr ~sx1, ~sy1, sub
++002562        203153          lac ZZ2147
++002563        423114          ZZ3147 ~scn
++002564        243153          dac ZZ2147
++002565        203151          lac ZZ1147
++002566        403150          -ZZ3147+add+sub ~ssn
++002567        243151          dac ZZ1147
+-      dispt i, ~sy1
++002570        000000          ZZ3148=ZZ3148+ZZ3148
++002570        000000          ZZ3148=ZZ3148+ZZ3148
++002570        000000          ZZ3148=ZZ3148+ZZ3148
++002570        000000          ZZ3148=ZZ3148+ZZ3148
++002570        000000          ZZ3148=ZZ3148+ZZ3148
++002570        000000          ZZ3148=ZZ3148+ZZ3148
++002570        223153          lio ZZ2148
++002571        720007          dpy-ZZ1148+ZZ3148
+-      count ~src,sq7
++002572        463163          isp ZZ1149
++002573        602550          jmp ZZ2149
+ 002574                sq9,
+-      count i ma1, sr5                / check if torp tube reloaded
++002574        471772          isp ZZ1150
++002575        602667          jmp ZZ2150
+ 002576        351772          dzm i ma1                       / prevent count around
+ 002577                mco,
+ 002577        202577          lac .                           / previous control word
+ 002600        761000          cma
+ 002601        650030          szs i 30
+ 002602        761200          clc
+ 002603        023143          and ~scw                        / present control word
+ 002604        661007          ral 3s                          / torpedo bit to bit 0
+ 002605        640400          sma
+ 002606        602667          jmp sr5                         / no launch
+-      count i ~mtr, st1               / check if torpedos exhausted
++002607        473124          isp ZZ1151
++002610        602613          jmp ZZ2151
+ 002611        353124          dzm i ~mtr                      / prevent count around
+ 002612        602667          jmp sr5
+ 002613                st1,
+-      init sr1, mtb                   / search for unused object
++002613        703365          law ZZ2152
++002614        262615          dap ZZ1152
+ 002615                sr1,
+ 002615        202615          lac .
+ 002616        650100          sza i                           / 0 if unused
+ 002617        602625          jmp sr2
+-      index sr1, (lac mtb+nob, sr1
++002620        442615          idx ZZ1153
++002621        523105          sas ZZ2153
++002622        602615          jmp ZZ3153
+ 002623        760400          hlt                             / no space for new objects
+ 002624        602623          jmp .-1
+-////
+ 002625                sr2,
+ 002625        203106          lac (tcr
+ 002626        252615          dac i sr1
+ 002627        700030          law nob
+ 002630        402615          add sr1
+ 002631        262633          dap ss3
+ 002632        223152          lio ~stx
+ 002633                ss3,
+ 002633        322633          dio .
+ 002634        403066          add (nob
+ 002635        262637          dap ss4
+ 002636        223154          lio ~sty
+ 002637                ss4,
+ 002637        322637          dio .
+ 002640        403066          add (nob
+ 002641        262664          dap sr6
+ 002642        403066          add (nob
+ 002643        262666          dap sr7
+ 002644        403066          add (nob
+ 002645        262654          dap sr3
+ 002646        403066          add (nob
+ 002647        262660          dap sr4
+ 002650        203144          lac ~sn
+ 002651        100007          xct tvl
+ 002652        761000          cma
+ 002653        413121          add i ~mdx
+ 002654                sr3,
+ 002654        242654          dac .
+ 002655        203147          lac ~cs
+ 002656        100007          xct tvl
+ 002657        413122          add i ~mdy
+ 002660                sr4,
+ 002660        242660          dac .
+ 002661        100010          xct rlt
+ 002662        251772          dac i ma1                       / permit torp tubes to cool
+ 002663                trp,
+ 002663        100011          xct tlf                         / life of torpedo
+ 002664                sr6,
+ 002664        242664          dac .
+ 002665        700020          law 20
+ 002666                sr7,
+ 002666        262666          dap .                           / length of torp calc
+ 002667                sr5,
+-      count i ~mh3, st3               / hyperbutton active?
++002667        473127          isp ZZ1154
++002670        602713          jmp ZZ2154
+ 002671        353127          dzm i ~mh3
+ 002672        213126          lac i ~mh2
+ 002673        650100          sza i
+ 002674        602713          jmp st3
+ 002675        203143          lac ~scw
+ 002676        761000          cma
+ 002677        052577          ior i mco
+ 002700        023107          and (600000
+ 002701        640100          sza
+ 002702        602713          jmp st3
+ 002703        211703          lac i ml1
+ 002704        253125          dac i ~mh1
+ 002705        203110          lac (hp1 400000
+ 002706        251703          dac i ml1
+ 002707        100023          xct hd1
+ 002710        251772          dac i ma1
+ 002711        700003          law 3
+ 002712        252006          dac i mb1
+ 002713                st3,
+ 002713                srt,
+ 002713        602713          jmp .
+-////
+-/ here to handle spaceships into star
+-/ spaceship in star
+ 002714                poh,
+ 002714        353121          dzm i ~mdx
+ 002715        353122          dzm i ~mdy
+ 002716        640050          szs 50
+ 002717        602730          jmp po1
+ 002720        202767          lac (377777
+ 002721        251737          dac i mx1
+ 002722        251747          dac i my1
+ 002723        212006          lac i mb1
+ 002724        243150          dac ~ssn
+-      count ~ssn, .
++002725        463150          isp ZZ1155
++002726        602725          jmp ZZ2155
+ 002727        602713          jmp srt
+ 002730                po1,
+ 002730        203103          lac (mex 400000 / now go bang
+ 002731        251703          dac i ml1
+ 002732        710010          law i 10
+ 002733        251772          dac i ma1
+ 002734        602713          jmp srt
+-////
+-/ outlines of spaceships
+ 002735                ot1,
+ 002735        111131          111131
+ 002736        111111          111111
+ 002737        111111          111111
+ 002740        111163          111163
+ 002741        311111          311111
+ 002742        146111          146111
+ 002743        111114          111114
+ 002744        700000          700000
+ 002745        000005  . 5/
+ 002746                ot2,
+ 002746        013113          013113
+ 002747        113111          113111
+ 002750        116313          116313
+ 002751        131111          131111
+ 002752        161151          161151
+ 002753        111633          111633
+ 002754        365114          365114
+ 002755        700000          700000
+ 002756        000005  . 5/
+ 002757        203164          lac ~ssa        / To fix assembler bug - ~ssa only referenced in lit
+ 002760                        constants
++002760        062210  62210
++002761        311040  311040
++002762        242763  242763
++002763        756103  756103
++002764        121312  121312
++002765        532511  532511
++002766        144417  144417
++002767        377777  377777
++002770        000001  1
++002771        760015  stf 5
++002772        203151  lac ~sx1
++002773        223153  lio ~sy1
++002774        663777  rcl 9s
++002775        000444  a11
++002776        640005  szf 5
++002777        000004  4
++003000        243151  dac ~sx1
++003001        323153  dio ~sy1
++003002        602531  jmp sq6
++003003        760005  clf 5
++003004        203162  lac ~scm
++003005        761000  cma
++003006        243162  dac ~scm
++003007        203155  lac ~ssm
++003010        243155  dac ~ssm
++003011        203161  lac ~csm
++003012        223157  lio ~ssd
++003013        243157  dac ~ssd
++003014        323161  dio ~csm
++003015        203156  lac ~ssc
++003016        223160  lio ~csn
++003017        243160  dac ~csn
++003020        323156  dio ~ssc
++003021        403150  add ~ssn
++003022        423114  sub ~scn
++003023        730000  ioh
++003024        724007  dpy-4000
++003025        403162  add ~scm
++003026        403155  add ~ssm
++003027        403156  add ~ssc
++003030        423161  sub ~csm
++003031        423162  sub ~scm
++003032        423155  sub ~ssm
++003033        403160  add ~csn
++003034        423157  sub ~ssd
++003035        243164  dac ~ssa
++003036        323115  dio ~ssi
++003037        203164  lac ~ssa
++003040        223115  lio ~ssi
++003041        355760  355760
++003042        355670  355670
++003043        400340  add 340
++003044        000716  bds
++003045        002000  2000
++003046        001000  1000
++003047        226022  lio ZZ298+2
++003050        761777  2000 -20000
++003051        006022  ZZ298+2
++003052        226000  lio ZZ198
++003053        226044  lio ZZ299+2
++003054        006044  ZZ299+2
++003055        226022  lio ZZ199
++003056        226306  lio ZZ2100+2
++003057        006306  ZZ2100+2
++003060        226044  lio ZZ1100
++003061        227652  lio ZZ2101+2
++003062        007652  ZZ2101+2
++003063        226306  lio ZZ1101
++003064        020000  20000
++003065        773777  ZZ2102
++003066        000030  nob
++003067        000002  2
++003070        000040  40
++003071        000037  37
++003072        343661  dzm ZZ2106+1
++003073        200000  200000
++003074        144420  144420
++003075        203415  lac mtb nob
++003076        203414  lac mtb nob-1
++003077        675007  sar 3s
++003100        000140  140
++003101        000777  777
++003102        667000  scl
++003103        402052  mex 400000
++003104        400000  400000
++003105        203415  lac mtb+nob
++003106        002136  tcr
++003107        600000  600000
++003110        402170  hp1 400000
+ 003111        000000          0
+ 003112                        variables
++003112        000000  occ
++003113        000000  oci
++003114        000000  scn
++003115        000000  ssi
++003116        000000  bx
++003117        000000  by
++003120        000000  mtc
++003121        000000  mdx
++003122        000000  mdy
++003123        000000  mfu
++003124        000000  mtr
++003125        000000  mh1
++003126        000000  mh2
++003127        000000  mh3
++003130        000000  mh4
++003131        000000  ntd
++003132        000000  1sc
++003133        000000  2sc
++003134        000000  cwg
++003135        000000  gct
++003136        000000  moc
++003137        000000  mt1
++003140        000000  mas
++003141        000000  mxc
++003142        000000  hpt
++003143        000000  scw
++003144        000000  sn
++003145        000000  t1
++003146        000000  t2
++003147        000000  cs
++003150        000000  ssn
++003151        000000  sx1
++003152        000000  stx
++003153        000000  sy1
++003154        000000  sty
++003155        000000  ssm
++003156        000000  ssc
++003157        000000  ssd
++003160        000000  csn
++003161        000000  csm
++003162        000000  scm
++003163        000000  src
++003164        000000  ssa
+ 003165                p,
+ 003365                        . 200/          / space for patches
+ 003365                mtb,
+-                              / table of objects and their properties
+ 006000                        6000/
+-/stars 1 3/13/62 prs.
+ 006000                        decimal
+-      define mark X, Y
+-      repeat 10, Y=Y+Y
+-      0 8192 -X
+-      0 Y
+-      terminate
+ 006000                1j,
+-       mark 1537, 371         /87 taur, aldebaran
++006000        001346          ZZ2156=ZZ2156+ZZ2156
++006000        002714          ZZ2156=ZZ2156+ZZ2156
++006000        005630          ZZ2156=ZZ2156+ZZ2156
++006000        013460          ZZ2156=ZZ2156+ZZ2156
++006000        027140          ZZ2156=ZZ2156+ZZ2156
++006000        056300          ZZ2156=ZZ2156+ZZ2156
++006000        134600          ZZ2156=ZZ2156+ZZ2156
++006000        271400          ZZ2156=ZZ2156+ZZ2156
++006000        014777          0 8192 -ZZ1156
++006001        271400          0 ZZ2156
+-       mark 1762, -189        /19 orio, rigel
++006002        777204          ZZ2157=ZZ2157+ZZ2157
++006002        776410          ZZ2157=ZZ2157+ZZ2157
++006002        775020          ZZ2157=ZZ2157+ZZ2157
++006002        772040          ZZ2157=ZZ2157+ZZ2157
++006002        764100          ZZ2157=ZZ2157+ZZ2157
++006002        750200          ZZ2157=ZZ2157+ZZ2157
++006002        720400          ZZ2157=ZZ2157+ZZ2157
++006002        641000          ZZ2157=ZZ2157+ZZ2157
++006002        014436          0 8192 -ZZ1157
++006003        641000          0 ZZ2157
+-       mark 1990, 168         /58 orio, betelgeuze
++006004        000520          ZZ2158=ZZ2158+ZZ2158
++006004        001240          ZZ2158=ZZ2158+ZZ2158
++006004        002500          ZZ2158=ZZ2158+ZZ2158
++006004        005200          ZZ2158=ZZ2158+ZZ2158
++006004        012400          ZZ2158=ZZ2158+ZZ2158
++006004        025000          ZZ2158=ZZ2158+ZZ2158
++006004        052000          ZZ2158=ZZ2158+ZZ2158
++006004        124000          ZZ2158=ZZ2158+ZZ2158
++006004        014072          0 8192 -ZZ1158
++006005        124000          0 ZZ2158
+-       mark 2280, -377        /9 cmaj, sirius
++006006        776414          ZZ2159=ZZ2159+ZZ2159
++006006        775030          ZZ2159=ZZ2159+ZZ2159
++006006        772060          ZZ2159=ZZ2159+ZZ2159
++006006        764140          ZZ2159=ZZ2159+ZZ2159
++006006        750300          ZZ2159=ZZ2159+ZZ2159
++006006        720600          ZZ2159=ZZ2159+ZZ2159
++006006        641400          ZZ2159=ZZ2159+ZZ2159
++006006        503000          ZZ2159=ZZ2159+ZZ2159
++006006        013430          0 8192 -ZZ1159
++006007        503000          0 ZZ2159
+-       mark 2583, 125         /25 cmin, procyon
++006010        000372          ZZ2160=ZZ2160+ZZ2160
++006010        000764          ZZ2160=ZZ2160+ZZ2160
++006010        001750          ZZ2160=ZZ2160+ZZ2160
++006010        003720          ZZ2160=ZZ2160+ZZ2160
++006010        007640          ZZ2160=ZZ2160+ZZ2160
++006010        017500          ZZ2160=ZZ2160+ZZ2160
++006010        037200          ZZ2160=ZZ2160+ZZ2160
++006010        076400          ZZ2160=ZZ2160+ZZ2160
++006010        012751          0 8192 -ZZ1160
++006011        076400          0 ZZ2160
+-       mark 3431, 283         /32 leon, regulus
++006012        001066          ZZ2161=ZZ2161+ZZ2161
++006012        002154          ZZ2161=ZZ2161+ZZ2161
++006012        004330          ZZ2161=ZZ2161+ZZ2161
++006012        010660          ZZ2161=ZZ2161+ZZ2161
++006012        021540          ZZ2161=ZZ2161+ZZ2161
++006012        043300          ZZ2161=ZZ2161+ZZ2161
++006012        106600          ZZ2161=ZZ2161+ZZ2161
++006012        215400          ZZ2161=ZZ2161+ZZ2161
++006012        011231          0 8192 -ZZ1161
++006013        215400          0 ZZ2161
+-       mark 4551, -242        /67 virg, spica
++006014        777032          ZZ2162=ZZ2162+ZZ2162
++006014        776064          ZZ2162=ZZ2162+ZZ2162
++006014        774150          ZZ2162=ZZ2162+ZZ2162
++006014        770320          ZZ2162=ZZ2162+ZZ2162
++006014        760640          ZZ2162=ZZ2162+ZZ2162
++006014        741500          ZZ2162=ZZ2162+ZZ2162
++006014        703200          ZZ2162=ZZ2162+ZZ2162
++006014        606400          ZZ2162=ZZ2162+ZZ2162
++006014        007071          0 8192 -ZZ1162
++006015        606400          0 ZZ2162
+-       mark 4842, 448         /16 boot, arcturus
++006016        001600          ZZ2163=ZZ2163+ZZ2163
++006016        003400          ZZ2163=ZZ2163+ZZ2163
++006016        007000          ZZ2163=ZZ2163+ZZ2163
++006016        016000          ZZ2163=ZZ2163+ZZ2163
++006016        034000          ZZ2163=ZZ2163+ZZ2163
++006016        070000          ZZ2163=ZZ2163+ZZ2163
++006016        160000          ZZ2163=ZZ2163+ZZ2163
++006016        340000          ZZ2163=ZZ2163+ZZ2163
++006016        006426          0 8192 -ZZ1163
++006017        340000          0 ZZ2163
+ 006020                1q,
+-       mark 6747, 196         /53 aqil, altair
++006020        000610          ZZ2164=ZZ2164+ZZ2164
++006020        001420          ZZ2164=ZZ2164+ZZ2164
++006020        003040          ZZ2164=ZZ2164+ZZ2164
++006020        006100          ZZ2164=ZZ2164+ZZ2164
++006020        014200          ZZ2164=ZZ2164+ZZ2164
++006020        030400          ZZ2164=ZZ2164+ZZ2164
++006020        061000          ZZ2164=ZZ2164+ZZ2164
++006020        142000          ZZ2164=ZZ2164+ZZ2164
++006020        002645          0 8192 -ZZ1164
++006021        142000          0 ZZ2164
+ 006022                2j,
+-       mark 1819, 143         /24 orio, bellatrix
++006022        000436          ZZ2165=ZZ2165+ZZ2165
++006022        001074          ZZ2165=ZZ2165+ZZ2165
++006022        002170          ZZ2165=ZZ2165+ZZ2165
++006022        004360          ZZ2165=ZZ2165+ZZ2165
++006022        010740          ZZ2165=ZZ2165+ZZ2165
++006022        021700          ZZ2165=ZZ2165+ZZ2165
++006022        043600          ZZ2165=ZZ2165+ZZ2165
++006022        107400          ZZ2165=ZZ2165+ZZ2165
++006022        014345          0 8192 -ZZ1165
++006023        107400          0 ZZ2165
+-       mark 1884, -29         /46 orio
++006024        777704          ZZ2166=ZZ2166+ZZ2166
++006024        777610          ZZ2166=ZZ2166+ZZ2166
++006024        777420          ZZ2166=ZZ2166+ZZ2166
++006024        777040          ZZ2166=ZZ2166+ZZ2166
++006024        776100          ZZ2166=ZZ2166+ZZ2166
++006024        774200          ZZ2166=ZZ2166+ZZ2166
++006024        770400          ZZ2166=ZZ2166+ZZ2166
++006024        761000          ZZ2166=ZZ2166+ZZ2166
++006024        014244          0 8192 -ZZ1166
++006025        761000          0 ZZ2166
+-       mark 1910, -46         /50 orio
++006026        777642          ZZ2167=ZZ2167+ZZ2167
++006026        777504          ZZ2167=ZZ2167+ZZ2167
++006026        777210          ZZ2167=ZZ2167+ZZ2167
++006026        776420          ZZ2167=ZZ2167+ZZ2167
++006026        775040          ZZ2167=ZZ2167+ZZ2167
++006026        772100          ZZ2167=ZZ2167+ZZ2167
++006026        764200          ZZ2167=ZZ2167+ZZ2167
++006026        750400          ZZ2167=ZZ2167+ZZ2167
++006026        014212          0 8192 -ZZ1167
++006027        750400          0 ZZ2167
+-       mark 1951, -221        /53 orio
++006030        777104          ZZ2168=ZZ2168+ZZ2168
++006030        776210          ZZ2168=ZZ2168+ZZ2168
++006030        774420          ZZ2168=ZZ2168+ZZ2168
++006030        771040          ZZ2168=ZZ2168+ZZ2168
++006030        762100          ZZ2168=ZZ2168+ZZ2168
++006030        744200          ZZ2168=ZZ2168+ZZ2168
++006030        710400          ZZ2168=ZZ2168+ZZ2168
++006030        621000          ZZ2168=ZZ2168+ZZ2168
++006030        014141          0 8192 -ZZ1168
++006031        621000          0 ZZ2168
+-       mark 2152, -407        / 2 cmaj
++006032        776320          ZZ2169=ZZ2169+ZZ2169
++006032        774640          ZZ2169=ZZ2169+ZZ2169
++006032        771500          ZZ2169=ZZ2169+ZZ2169
++006032        763200          ZZ2169=ZZ2169+ZZ2169
++006032        746400          ZZ2169=ZZ2169+ZZ2169
++006032        715000          ZZ2169=ZZ2169+ZZ2169
++006032        632000          ZZ2169=ZZ2169+ZZ2169
++006032        464000          ZZ2169=ZZ2169+ZZ2169
++006032        013630          0 8192 -ZZ1169
++006033        464000          0 ZZ2169
+-       mark 2230, 375         /24 gemi
++006034        001356          ZZ2170=ZZ2170+ZZ2170
++006034        002734          ZZ2170=ZZ2170+ZZ2170
++006034        005670          ZZ2170=ZZ2170+ZZ2170
++006034        013560          ZZ2170=ZZ2170+ZZ2170
++006034        027340          ZZ2170=ZZ2170+ZZ2170
++006034        056700          ZZ2170=ZZ2170+ZZ2170
++006034        135600          ZZ2170=ZZ2170+ZZ2170
++006034        273400          ZZ2170=ZZ2170+ZZ2170
++006034        013512          0 8192 -ZZ1170
++006035        273400          0 ZZ2170
+-       mark 3201, -187        /30 hyda, alphard
++006036        777210          ZZ2171=ZZ2171+ZZ2171
++006036        776420          ZZ2171=ZZ2171+ZZ2171
++006036        775040          ZZ2171=ZZ2171+ZZ2171
++006036        772100          ZZ2171=ZZ2171+ZZ2171
++006036        764200          ZZ2171=ZZ2171+ZZ2171
++006036        750400          ZZ2171=ZZ2171+ZZ2171
++006036        721000          ZZ2171=ZZ2171+ZZ2171
++006036        642000          ZZ2171=ZZ2171+ZZ2171
++006036        011577          0 8192 -ZZ1171
++006037        642000          0 ZZ2171
+-       mark 4005, 344         /94 leon, denebola
++006040        001260          ZZ2172=ZZ2172+ZZ2172
++006040        002540          ZZ2172=ZZ2172+ZZ2172
++006040        005300          ZZ2172=ZZ2172+ZZ2172
++006040        012600          ZZ2172=ZZ2172+ZZ2172
++006040        025400          ZZ2172=ZZ2172+ZZ2172
++006040        053000          ZZ2172=ZZ2172+ZZ2172
++006040        126000          ZZ2172=ZZ2172+ZZ2172
++006040        254000          ZZ2172=ZZ2172+ZZ2172
++006040        010133          0 8192 -ZZ1172
++006041        254000          0 ZZ2172
+ 006042                2q,
+-       mark 5975, 288         /55 ophi
++006042        001100          ZZ2173=ZZ2173+ZZ2173
++006042        002200          ZZ2173=ZZ2173+ZZ2173
++006042        004400          ZZ2173=ZZ2173+ZZ2173
++006042        011000          ZZ2173=ZZ2173+ZZ2173
++006042        022000          ZZ2173=ZZ2173+ZZ2173
++006042        044000          ZZ2173=ZZ2173+ZZ2173
++006042        110000          ZZ2173=ZZ2173+ZZ2173
++006042        220000          ZZ2173=ZZ2173+ZZ2173
++006042        004251          0 8192 -ZZ1173
++006043        220000          0 ZZ2173
+ 006044                3j,
+-       mark   46, 333         /88 pegs, algenib
++006044        001232          ZZ2174=ZZ2174+ZZ2174
++006044        002464          ZZ2174=ZZ2174+ZZ2174
++006044        005150          ZZ2174=ZZ2174+ZZ2174
++006044        012320          ZZ2174=ZZ2174+ZZ2174
++006044        024640          ZZ2174=ZZ2174+ZZ2174
++006044        051500          ZZ2174=ZZ2174+ZZ2174
++006044        123200          ZZ2174=ZZ2174+ZZ2174
++006044        246400          ZZ2174=ZZ2174+ZZ2174
++006044        017722          0 8192 -ZZ1174
++006045        246400          0 ZZ2174
+-       mark  362, -244        /31 ceti
++006046        777026          ZZ2175=ZZ2175+ZZ2175
++006046        776054          ZZ2175=ZZ2175+ZZ2175
++006046        774130          ZZ2175=ZZ2175+ZZ2175
++006046        770260          ZZ2175=ZZ2175+ZZ2175
++006046        760540          ZZ2175=ZZ2175+ZZ2175
++006046        741300          ZZ2175=ZZ2175+ZZ2175
++006046        702600          ZZ2175=ZZ2175+ZZ2175
++006046        605400          ZZ2175=ZZ2175+ZZ2175
++006046        017226          0 8192 -ZZ1175
++006047        605400          0 ZZ2175
+-       mark  490, 338         /99 pisc
++006050        001244          ZZ2176=ZZ2176+ZZ2176
++006050        002510          ZZ2176=ZZ2176+ZZ2176
++006050        005220          ZZ2176=ZZ2176+ZZ2176
++006050        012440          ZZ2176=ZZ2176+ZZ2176
++006050        025100          ZZ2176=ZZ2176+ZZ2176
++006050        052200          ZZ2176=ZZ2176+ZZ2176
++006050        124400          ZZ2176=ZZ2176+ZZ2176
++006050        251000          ZZ2176=ZZ2176+ZZ2176
++006050        017026          0 8192 -ZZ1176
++006051        251000          0 ZZ2176
+-       mark  566, -375        /52 ceti
++006052        776420          ZZ2177=ZZ2177+ZZ2177
++006052        775040          ZZ2177=ZZ2177+ZZ2177
++006052        772100          ZZ2177=ZZ2177+ZZ2177
++006052        764200          ZZ2177=ZZ2177+ZZ2177
++006052        750400          ZZ2177=ZZ2177+ZZ2177
++006052        721000          ZZ2177=ZZ2177+ZZ2177
++006052        642000          ZZ2177=ZZ2177+ZZ2177
++006052        504000          ZZ2177=ZZ2177+ZZ2177
++006052        016712          0 8192 -ZZ1177
++006053        504000          0 ZZ2177
+-       mark  621, 462         / 6 arie
++006054        001634          ZZ2178=ZZ2178+ZZ2178
++006054        003470          ZZ2178=ZZ2178+ZZ2178
++006054        007160          ZZ2178=ZZ2178+ZZ2178
++006054        016340          ZZ2178=ZZ2178+ZZ2178
++006054        034700          ZZ2178=ZZ2178+ZZ2178
++006054        071600          ZZ2178=ZZ2178+ZZ2178
++006054        163400          ZZ2178=ZZ2178+ZZ2178
++006054        347000          ZZ2178=ZZ2178+ZZ2178
++006054        016623          0 8192 -ZZ1178
++006055        347000          0 ZZ2178
+-       mark 764, -78          /68 ceti, mira
++006056        777542          ZZ2179=ZZ2179+ZZ2179
++006056        777304          ZZ2179=ZZ2179+ZZ2179
++006056        776610          ZZ2179=ZZ2179+ZZ2179
++006056        775420          ZZ2179=ZZ2179+ZZ2179
++006056        773040          ZZ2179=ZZ2179+ZZ2179
++006056        766100          ZZ2179=ZZ2179+ZZ2179
++006056        754200          ZZ2179=ZZ2179+ZZ2179
++006056        730400          ZZ2179=ZZ2179+ZZ2179
++006056        016404          0 8192 -ZZ1179
++006057        730400          0 ZZ2179
+-       mark  900, 64          /86 ceti
++006060        000200          ZZ2180=ZZ2180+ZZ2180
++006060        000400          ZZ2180=ZZ2180+ZZ2180
++006060        001000          ZZ2180=ZZ2180+ZZ2180
++006060        002000          ZZ2180=ZZ2180+ZZ2180
++006060        004000          ZZ2180=ZZ2180+ZZ2180
++006060        010000          ZZ2180=ZZ2180+ZZ2180
++006060        020000          ZZ2180=ZZ2180+ZZ2180
++006060        040000          ZZ2180=ZZ2180+ZZ2180
++006060        016174          0 8192 -ZZ1180
++006061        040000          0 ZZ2180
+-       mark 1007, 84          /92 ceti
++006062        000250          ZZ2181=ZZ2181+ZZ2181
++006062        000520          ZZ2181=ZZ2181+ZZ2181
++006062        001240          ZZ2181=ZZ2181+ZZ2181
++006062        002500          ZZ2181=ZZ2181+ZZ2181
++006062        005200          ZZ2181=ZZ2181+ZZ2181
++006062        012400          ZZ2181=ZZ2181+ZZ2181
++006062        025000          ZZ2181=ZZ2181+ZZ2181
++006062        052000          ZZ2181=ZZ2181+ZZ2181
++006062        016021          0 8192 -ZZ1181
++006063        052000          0 ZZ2181
+-       mark 1243, -230        /23 erid
++006064        777062          ZZ2182=ZZ2182+ZZ2182
++006064        776144          ZZ2182=ZZ2182+ZZ2182
++006064        774310          ZZ2182=ZZ2182+ZZ2182
++006064        770620          ZZ2182=ZZ2182+ZZ2182
++006064        761440          ZZ2182=ZZ2182+ZZ2182
++006064        743100          ZZ2182=ZZ2182+ZZ2182
++006064        706200          ZZ2182=ZZ2182+ZZ2182
++006064        614400          ZZ2182=ZZ2182+ZZ2182
++006064        015445          0 8192 -ZZ1182
++006065        614400          0 ZZ2182
+-       mark 1328, -314        /34 erid
++006066        776612          ZZ2183=ZZ2183+ZZ2183
++006066        775424          ZZ2183=ZZ2183+ZZ2183
++006066        773050          ZZ2183=ZZ2183+ZZ2183
++006066        766120          ZZ2183=ZZ2183+ZZ2183
++006066        754240          ZZ2183=ZZ2183+ZZ2183
++006066        730500          ZZ2183=ZZ2183+ZZ2183
++006066        661200          ZZ2183=ZZ2183+ZZ2183
++006066        542400          ZZ2183=ZZ2183+ZZ2183
++006066        015320          0 8192 -ZZ1183
++006067        542400          0 ZZ2183
+-       mark 1495, 432         /74 taur
++006070        001540          ZZ2184=ZZ2184+ZZ2184
++006070        003300          ZZ2184=ZZ2184+ZZ2184
++006070        006600          ZZ2184=ZZ2184+ZZ2184
++006070        015400          ZZ2184=ZZ2184+ZZ2184
++006070        033000          ZZ2184=ZZ2184+ZZ2184
++006070        066000          ZZ2184=ZZ2184+ZZ2184
++006070        154000          ZZ2184=ZZ2184+ZZ2184
++006070        330000          ZZ2184=ZZ2184+ZZ2184
++006070        015051          0 8192 -ZZ1184
++006071        330000          0 ZZ2184
+-       mark 1496, 356         /78 taur
++006072        001310          ZZ2185=ZZ2185+ZZ2185
++006072        002620          ZZ2185=ZZ2185+ZZ2185
++006072        005440          ZZ2185=ZZ2185+ZZ2185
++006072        013100          ZZ2185=ZZ2185+ZZ2185
++006072        026200          ZZ2185=ZZ2185+ZZ2185
++006072        054400          ZZ2185=ZZ2185+ZZ2185
++006072        131000          ZZ2185=ZZ2185+ZZ2185
++006072        262000          ZZ2185=ZZ2185+ZZ2185
++006072        015050          0 8192 -ZZ1185
++006073        262000          0 ZZ2185
+-       mark 1618, 154         / 1 orio
++006074        000464          ZZ2186=ZZ2186+ZZ2186
++006074        001150          ZZ2186=ZZ2186+ZZ2186
++006074        002320          ZZ2186=ZZ2186+ZZ2186
++006074        004640          ZZ2186=ZZ2186+ZZ2186
++006074        011500          ZZ2186=ZZ2186+ZZ2186
++006074        023200          ZZ2186=ZZ2186+ZZ2186
++006074        046400          ZZ2186=ZZ2186+ZZ2186
++006074        115000          ZZ2186=ZZ2186+ZZ2186
++006074        014656          0 8192 -ZZ1186
++006075        115000          0 ZZ2186
+-       mark 1644, 52          / 8 orio
++006076        000150          ZZ2187=ZZ2187+ZZ2187
++006076        000320          ZZ2187=ZZ2187+ZZ2187
++006076        000640          ZZ2187=ZZ2187+ZZ2187
++006076        001500          ZZ2187=ZZ2187+ZZ2187
++006076        003200          ZZ2187=ZZ2187+ZZ2187
++006076        006400          ZZ2187=ZZ2187+ZZ2187
++006076        015000          ZZ2187=ZZ2187+ZZ2187
++006076        032000          ZZ2187=ZZ2187+ZZ2187
++006076        014624          0 8192 -ZZ1187
++006077        032000          0 ZZ2187
+-       mark 1723, -119        /67 erid
++006100        777420          ZZ2188=ZZ2188+ZZ2188
++006100        777040          ZZ2188=ZZ2188+ZZ2188
++006100        776100          ZZ2188=ZZ2188+ZZ2188
++006100        774200          ZZ2188=ZZ2188+ZZ2188
++006100        770400          ZZ2188=ZZ2188+ZZ2188
++006100        761000          ZZ2188=ZZ2188+ZZ2188
++006100        742000          ZZ2188=ZZ2188+ZZ2188
++006100        704000          ZZ2188=ZZ2188+ZZ2188
++006100        014505          0 8192 -ZZ1188
++006101        704000          0 ZZ2188
+-       mark 1755, -371        / 5 leps
++006102        776430          ZZ2189=ZZ2189+ZZ2189
++006102        775060          ZZ2189=ZZ2189+ZZ2189
++006102        772140          ZZ2189=ZZ2189+ZZ2189
++006102        764300          ZZ2189=ZZ2189+ZZ2189
++006102        750600          ZZ2189=ZZ2189+ZZ2189
++006102        721400          ZZ2189=ZZ2189+ZZ2189
++006102        643000          ZZ2189=ZZ2189+ZZ2189
++006102        506000          ZZ2189=ZZ2189+ZZ2189
++006102        014445          0 8192 -ZZ1189
++006103        506000          0 ZZ2189
+-       mark 1779, -158        /20 orio
++006104        777302          ZZ2190=ZZ2190+ZZ2190
++006104        776604          ZZ2190=ZZ2190+ZZ2190
++006104        775410          ZZ2190=ZZ2190+ZZ2190
++006104        773020          ZZ2190=ZZ2190+ZZ2190
++006104        766040          ZZ2190=ZZ2190+ZZ2190
++006104        754100          ZZ2190=ZZ2190+ZZ2190
++006104        730200          ZZ2190=ZZ2190+ZZ2190
++006104        660400          ZZ2190=ZZ2190+ZZ2190
++006104        014415          0 8192 -ZZ1190
++006105        660400          0 ZZ2190
+-       mark 1817, -57         /28 orio
++006106        777614          ZZ2191=ZZ2191+ZZ2191
++006106        777430          ZZ2191=ZZ2191+ZZ2191
++006106        777060          ZZ2191=ZZ2191+ZZ2191
++006106        776140          ZZ2191=ZZ2191+ZZ2191
++006106        774300          ZZ2191=ZZ2191+ZZ2191
++006106        770600          ZZ2191=ZZ2191+ZZ2191
++006106        761400          ZZ2191=ZZ2191+ZZ2191
++006106        743000          ZZ2191=ZZ2191+ZZ2191
++006106        014347          0 8192 -ZZ1191
++006107        743000          0 ZZ2191
+-       mark 1843, -474        / 9 leps
++006110        776112          ZZ2192=ZZ2192+ZZ2192
++006110        774224          ZZ2192=ZZ2192+ZZ2192
++006110        770450          ZZ2192=ZZ2192+ZZ2192
++006110        761120          ZZ2192=ZZ2192+ZZ2192
++006110        742240          ZZ2192=ZZ2192+ZZ2192
++006110        704500          ZZ2192=ZZ2192+ZZ2192
++006110        611200          ZZ2192=ZZ2192+ZZ2192
++006110        422400          ZZ2192=ZZ2192+ZZ2192
++006110        014315          0 8192 -ZZ1192
++006111        422400          0 ZZ2192
+-       mark 1860, -8          /34 orio
++006112        777756          ZZ2193=ZZ2193+ZZ2193
++006112        777734          ZZ2193=ZZ2193+ZZ2193
++006112        777670          ZZ2193=ZZ2193+ZZ2193
++006112        777560          ZZ2193=ZZ2193+ZZ2193
++006112        777340          ZZ2193=ZZ2193+ZZ2193
++006112        776700          ZZ2193=ZZ2193+ZZ2193
++006112        775600          ZZ2193=ZZ2193+ZZ2193
++006112        773400          ZZ2193=ZZ2193+ZZ2193
++006112        014274          0 8192 -ZZ1193
++006113        773400          0 ZZ2193
+-       mark 1868, -407        /11 leps
++006114        776320          ZZ2194=ZZ2194+ZZ2194
++006114        774640          ZZ2194=ZZ2194+ZZ2194
++006114        771500          ZZ2194=ZZ2194+ZZ2194
++006114        763200          ZZ2194=ZZ2194+ZZ2194
++006114        746400          ZZ2194=ZZ2194+ZZ2194
++006114        715000          ZZ2194=ZZ2194+ZZ2194
++006114        632000          ZZ2194=ZZ2194+ZZ2194
++006114        464000          ZZ2194=ZZ2194+ZZ2194
++006114        014264          0 8192 -ZZ1194
++006115        464000          0 ZZ2194
+-       mark 1875, 225         /39 orio
++006116        000702          ZZ2195=ZZ2195+ZZ2195
++006116        001604          ZZ2195=ZZ2195+ZZ2195
++006116        003410          ZZ2195=ZZ2195+ZZ2195
++006116        007020          ZZ2195=ZZ2195+ZZ2195
++006116        016040          ZZ2195=ZZ2195+ZZ2195
++006116        034100          ZZ2195=ZZ2195+ZZ2195
++006116        070200          ZZ2195=ZZ2195+ZZ2195
++006116        160400          ZZ2195=ZZ2195+ZZ2195
++006116        014255          0 8192 -ZZ1195
++006117        160400          0 ZZ2195
+-       mark 1880, -136        /44 orio
++006120        777356          ZZ2196=ZZ2196+ZZ2196
++006120        776734          ZZ2196=ZZ2196+ZZ2196
++006120        775670          ZZ2196=ZZ2196+ZZ2196
++006120        773560          ZZ2196=ZZ2196+ZZ2196
++006120        767340          ZZ2196=ZZ2196+ZZ2196
++006120        756700          ZZ2196=ZZ2196+ZZ2196
++006120        735600          ZZ2196=ZZ2196+ZZ2196
++006120        673400          ZZ2196=ZZ2196+ZZ2196
++006120        014250          0 8192 -ZZ1196
++006121        673400          0 ZZ2196
+-       mark 1887, 480         /123 taur
++006122        001700          ZZ2197=ZZ2197+ZZ2197
++006122        003600          ZZ2197=ZZ2197+ZZ2197
++006122        007400          ZZ2197=ZZ2197+ZZ2197
++006122        017000          ZZ2197=ZZ2197+ZZ2197
++006122        036000          ZZ2197=ZZ2197+ZZ2197
++006122        074000          ZZ2197=ZZ2197+ZZ2197
++006122        170000          ZZ2197=ZZ2197+ZZ2197
++006122        360000          ZZ2197=ZZ2197+ZZ2197
++006122        014241          0 8192 -ZZ1197
++006123        360000          0 ZZ2197
+-       mark 1948, -338        /14 leps
++006124        776532          ZZ2198=ZZ2198+ZZ2198
++006124        775264          ZZ2198=ZZ2198+ZZ2198
++006124        772550          ZZ2198=ZZ2198+ZZ2198
++006124        765320          ZZ2198=ZZ2198+ZZ2198
++006124        752640          ZZ2198=ZZ2198+ZZ2198
++006124        725500          ZZ2198=ZZ2198+ZZ2198
++006124        653200          ZZ2198=ZZ2198+ZZ2198
++006124        526400          ZZ2198=ZZ2198+ZZ2198
++006124        014144          0 8192 -ZZ1198
++006125        526400          0 ZZ2198
+-       mark 2274, 296         /31 gemi
++006126        001120          ZZ2199=ZZ2199+ZZ2199
++006126        002240          ZZ2199=ZZ2199+ZZ2199
++006126        004500          ZZ2199=ZZ2199+ZZ2199
++006126        011200          ZZ2199=ZZ2199+ZZ2199
++006126        022400          ZZ2199=ZZ2199+ZZ2199
++006126        045000          ZZ2199=ZZ2199+ZZ2199
++006126        112000          ZZ2199=ZZ2199+ZZ2199
++006126        224000          ZZ2199=ZZ2199+ZZ2199
++006126        013436          0 8192 -ZZ1199
++006127        224000          0 ZZ2199
+-       mark 2460, 380         /54 gemi
++006130        001370          ZZ2200=ZZ2200+ZZ2200
++006130        002760          ZZ2200=ZZ2200+ZZ2200
++006130        005740          ZZ2200=ZZ2200+ZZ2200
++006130        013700          ZZ2200=ZZ2200+ZZ2200
++006130        027600          ZZ2200=ZZ2200+ZZ2200
++006130        057400          ZZ2200=ZZ2200+ZZ2200
++006130        137000          ZZ2200=ZZ2200+ZZ2200
++006130        276000          ZZ2200=ZZ2200+ZZ2200
++006130        013144          0 8192 -ZZ1200
++006131        276000          0 ZZ2200
+-       mark 2470, 504         /55 gemi
++006132        001760          ZZ2201=ZZ2201+ZZ2201
++006132        003740          ZZ2201=ZZ2201+ZZ2201
++006132        007700          ZZ2201=ZZ2201+ZZ2201
++006132        017600          ZZ2201=ZZ2201+ZZ2201
++006132        037400          ZZ2201=ZZ2201+ZZ2201
++006132        077000          ZZ2201=ZZ2201+ZZ2201
++006132        176000          ZZ2201=ZZ2201+ZZ2201
++006132        374000          ZZ2201=ZZ2201+ZZ2201
++006132        013132          0 8192 -ZZ1201
++006133        374000          0 ZZ2201
+-       mark 2513, 193         / 3 cmin
++006134        000602          ZZ2202=ZZ2202+ZZ2202
++006134        001404          ZZ2202=ZZ2202+ZZ2202
++006134        003010          ZZ2202=ZZ2202+ZZ2202
++006134        006020          ZZ2202=ZZ2202+ZZ2202
++006134        014040          ZZ2202=ZZ2202+ZZ2202
++006134        030100          ZZ2202=ZZ2202+ZZ2202
++006134        060200          ZZ2202=ZZ2202+ZZ2202
++006134        140400          ZZ2202=ZZ2202+ZZ2202
++006134        013057          0 8192 -ZZ1202
++006135        140400          0 ZZ2202
+-       mark 2967, 154         /11 hyda
++006136        000464          ZZ2203=ZZ2203+ZZ2203
++006136        001150          ZZ2203=ZZ2203+ZZ2203
++006136        002320          ZZ2203=ZZ2203+ZZ2203
++006136        004640          ZZ2203=ZZ2203+ZZ2203
++006136        011500          ZZ2203=ZZ2203+ZZ2203
++006136        023200          ZZ2203=ZZ2203+ZZ2203
++006136        046400          ZZ2203=ZZ2203+ZZ2203
++006136        115000          ZZ2203=ZZ2203+ZZ2203
++006136        012151          0 8192 -ZZ1203
++006137        115000          0 ZZ2203
+-       mark 3016, 144         /16 hyda
++006140        000440          ZZ2204=ZZ2204+ZZ2204
++006140        001100          ZZ2204=ZZ2204+ZZ2204
++006140        002200          ZZ2204=ZZ2204+ZZ2204
++006140        004400          ZZ2204=ZZ2204+ZZ2204
++006140        011000          ZZ2204=ZZ2204+ZZ2204
++006140        022000          ZZ2204=ZZ2204+ZZ2204
++006140        044000          ZZ2204=ZZ2204+ZZ2204
++006140        110000          ZZ2204=ZZ2204+ZZ2204
++006140        012070          0 8192 -ZZ1204
++006141        110000          0 ZZ2204
+-       mark 3424, 393         /30 leon
++006142        001422          ZZ2205=ZZ2205+ZZ2205
++006142        003044          ZZ2205=ZZ2205+ZZ2205
++006142        006110          ZZ2205=ZZ2205+ZZ2205
++006142        014220          ZZ2205=ZZ2205+ZZ2205
++006142        030440          ZZ2205=ZZ2205+ZZ2205
++006142        061100          ZZ2205=ZZ2205+ZZ2205
++006142        142200          ZZ2205=ZZ2205+ZZ2205
++006142        304400          ZZ2205=ZZ2205+ZZ2205
++006142        011240          0 8192 -ZZ1205
++006143        304400          0 ZZ2205
+-       mark 3496, 463         /41 leon, algieba
++006144        001636          ZZ2206=ZZ2206+ZZ2206
++006144        003474          ZZ2206=ZZ2206+ZZ2206
++006144        007170          ZZ2206=ZZ2206+ZZ2206
++006144        016360          ZZ2206=ZZ2206+ZZ2206
++006144        034740          ZZ2206=ZZ2206+ZZ2206
++006144        071700          ZZ2206=ZZ2206+ZZ2206
++006144        163600          ZZ2206=ZZ2206+ZZ2206
++006144        347400          ZZ2206=ZZ2206+ZZ2206
++006144        011130          0 8192 -ZZ1206
++006145        347400          0 ZZ2206
+-       mark 3668, -357        /nu hyda
++006146        776464          ZZ2207=ZZ2207+ZZ2207
++006146        775150          ZZ2207=ZZ2207+ZZ2207
++006146        772320          ZZ2207=ZZ2207+ZZ2207
++006146        764640          ZZ2207=ZZ2207+ZZ2207
++006146        751500          ZZ2207=ZZ2207+ZZ2207
++006146        723200          ZZ2207=ZZ2207+ZZ2207
++006146        646400          ZZ2207=ZZ2207+ZZ2207
++006146        515000          ZZ2207=ZZ2207+ZZ2207
++006146        010654          0 8192 -ZZ1207
++006147        515000          0 ZZ2207
+-       mark 3805, 479         /68 leon
++006150        001676          ZZ2208=ZZ2208+ZZ2208
++006150        003574          ZZ2208=ZZ2208+ZZ2208
++006150        007370          ZZ2208=ZZ2208+ZZ2208
++006150        016760          ZZ2208=ZZ2208+ZZ2208
++006150        035740          ZZ2208=ZZ2208+ZZ2208
++006150        073700          ZZ2208=ZZ2208+ZZ2208
++006150        167600          ZZ2208=ZZ2208+ZZ2208
++006150        357400          ZZ2208=ZZ2208+ZZ2208
++006150        010443          0 8192 -ZZ1208
++006151        357400          0 ZZ2208
+-       mark 3806, 364         /10 leon
++006152        001330          ZZ2209=ZZ2209+ZZ2209
++006152        002660          ZZ2209=ZZ2209+ZZ2209
++006152        005540          ZZ2209=ZZ2209+ZZ2209
++006152        013300          ZZ2209=ZZ2209+ZZ2209
++006152        026600          ZZ2209=ZZ2209+ZZ2209
++006152        055400          ZZ2209=ZZ2209+ZZ2209
++006152        133000          ZZ2209=ZZ2209+ZZ2209
++006152        266000          ZZ2209=ZZ2209+ZZ2209
++006152        010442          0 8192 -ZZ1209
++006153        266000          0 ZZ2209
+-       mark 4124, -502        / 2 corv
++006154        776022          ZZ2210=ZZ2210+ZZ2210
++006154        774044          ZZ2210=ZZ2210+ZZ2210
++006154        770110          ZZ2210=ZZ2210+ZZ2210
++006154        760220          ZZ2210=ZZ2210+ZZ2210
++006154        740440          ZZ2210=ZZ2210+ZZ2210
++006154        701100          ZZ2210=ZZ2210+ZZ2210
++006154        602200          ZZ2210=ZZ2210+ZZ2210
++006154        404400          ZZ2210=ZZ2210+ZZ2210
++006154        007744          0 8192 -ZZ1210
++006155        404400          0 ZZ2210
+-       mark 4157, -387        / 4 corv
++006156        776370          ZZ2211=ZZ2211+ZZ2211
++006156        774760          ZZ2211=ZZ2211+ZZ2211
++006156        771740          ZZ2211=ZZ2211+ZZ2211
++006156        763700          ZZ2211=ZZ2211+ZZ2211
++006156        747600          ZZ2211=ZZ2211+ZZ2211
++006156        717400          ZZ2211=ZZ2211+ZZ2211
++006156        637000          ZZ2211=ZZ2211+ZZ2211
++006156        476000          ZZ2211=ZZ2211+ZZ2211
++006156        007703          0 8192 -ZZ1211
++006157        476000          0 ZZ2211
+-       mark 4236, -363        / 7 corv
++006160        776450          ZZ2212=ZZ2212+ZZ2212
++006160        775120          ZZ2212=ZZ2212+ZZ2212
++006160        772240          ZZ2212=ZZ2212+ZZ2212
++006160        764500          ZZ2212=ZZ2212+ZZ2212
++006160        751200          ZZ2212=ZZ2212+ZZ2212
++006160        722400          ZZ2212=ZZ2212+ZZ2212
++006160        645000          ZZ2212=ZZ2212+ZZ2212
++006160        512000          ZZ2212=ZZ2212+ZZ2212
++006160        007564          0 8192 -ZZ1212
++006161        512000          0 ZZ2212
+-       mark 4304, -21         /29 virg
++006162        777724          ZZ2213=ZZ2213+ZZ2213
++006162        777650          ZZ2213=ZZ2213+ZZ2213
++006162        777520          ZZ2213=ZZ2213+ZZ2213
++006162        777240          ZZ2213=ZZ2213+ZZ2213
++006162        776500          ZZ2213=ZZ2213+ZZ2213
++006162        775200          ZZ2213=ZZ2213+ZZ2213
++006162        772400          ZZ2213=ZZ2213+ZZ2213
++006162        765000          ZZ2213=ZZ2213+ZZ2213
++006162        007460          0 8192 -ZZ1213
++006163        765000          0 ZZ2213
+-       mark 4384, 90          /43 virg
++006164        000264          ZZ2214=ZZ2214+ZZ2214
++006164        000550          ZZ2214=ZZ2214+ZZ2214
++006164        001320          ZZ2214=ZZ2214+ZZ2214
++006164        002640          ZZ2214=ZZ2214+ZZ2214
++006164        005500          ZZ2214=ZZ2214+ZZ2214
++006164        013200          ZZ2214=ZZ2214+ZZ2214
++006164        026400          ZZ2214=ZZ2214+ZZ2214
++006164        055000          ZZ2214=ZZ2214+ZZ2214
++006164        007340          0 8192 -ZZ1214
++006165        055000          0 ZZ2214
+-       mark 4421, 262         /47 virg
++006166        001014          ZZ2215=ZZ2215+ZZ2215
++006166        002030          ZZ2215=ZZ2215+ZZ2215
++006166        004060          ZZ2215=ZZ2215+ZZ2215
++006166        010140          ZZ2215=ZZ2215+ZZ2215
++006166        020300          ZZ2215=ZZ2215+ZZ2215
++006166        040600          ZZ2215=ZZ2215+ZZ2215
++006166        101400          ZZ2215=ZZ2215+ZZ2215
++006166        203000          ZZ2215=ZZ2215+ZZ2215
++006166        007273          0 8192 -ZZ1215
++006167        203000          0 ZZ2215
+-       mark 4606, -2          /79 virg
++006170        777772          ZZ2216=ZZ2216+ZZ2216
++006170        777764          ZZ2216=ZZ2216+ZZ2216
++006170        777750          ZZ2216=ZZ2216+ZZ2216
++006170        777720          ZZ2216=ZZ2216+ZZ2216
++006170        777640          ZZ2216=ZZ2216+ZZ2216
++006170        777500          ZZ2216=ZZ2216+ZZ2216
++006170        777200          ZZ2216=ZZ2216+ZZ2216
++006170        776400          ZZ2216=ZZ2216+ZZ2216
++006170        007002          0 8192 -ZZ1216
++006171        776400          0 ZZ2216
+-       mark 4721, 430         / 8 boot
++006172        001534          ZZ2217=ZZ2217+ZZ2217
++006172        003270          ZZ2217=ZZ2217+ZZ2217
++006172        006560          ZZ2217=ZZ2217+ZZ2217
++006172        015340          ZZ2217=ZZ2217+ZZ2217
++006172        032700          ZZ2217=ZZ2217+ZZ2217
++006172        065600          ZZ2217=ZZ2217+ZZ2217
++006172        153400          ZZ2217=ZZ2217+ZZ2217
++006172        327000          ZZ2217=ZZ2217+ZZ2217
++006172        006617          0 8192 -ZZ1217
++006173        327000          0 ZZ2217
+-       mark 5037, -356        / 9 libr
++006174        776466          ZZ2218=ZZ2218+ZZ2218
++006174        775154          ZZ2218=ZZ2218+ZZ2218
++006174        772330          ZZ2218=ZZ2218+ZZ2218
++006174        764660          ZZ2218=ZZ2218+ZZ2218
++006174        751540          ZZ2218=ZZ2218+ZZ2218
++006174        723300          ZZ2218=ZZ2218+ZZ2218
++006174        646600          ZZ2218=ZZ2218+ZZ2218
++006174        515400          ZZ2218=ZZ2218+ZZ2218
++006174        006123          0 8192 -ZZ1218
++006175        515400          0 ZZ2218
+-       mark 5186, -205        /27 libr
++006176        777144          ZZ2219=ZZ2219+ZZ2219
++006176        776310          ZZ2219=ZZ2219+ZZ2219
++006176        774620          ZZ2219=ZZ2219+ZZ2219
++006176        771440          ZZ2219=ZZ2219+ZZ2219
++006176        763100          ZZ2219=ZZ2219+ZZ2219
++006176        746200          ZZ2219=ZZ2219+ZZ2219
++006176        714400          ZZ2219=ZZ2219+ZZ2219
++006176        631000          ZZ2219=ZZ2219+ZZ2219
++006176        005676          0 8192 -ZZ1219
++006177        631000          0 ZZ2219
+-       mark 5344, 153         /24 serp
++006200        000462          ZZ2220=ZZ2220+ZZ2220
++006200        001144          ZZ2220=ZZ2220+ZZ2220
++006200        002310          ZZ2220=ZZ2220+ZZ2220
++006200        004620          ZZ2220=ZZ2220+ZZ2220
++006200        011440          ZZ2220=ZZ2220+ZZ2220
++006200        023100          ZZ2220=ZZ2220+ZZ2220
++006200        046200          ZZ2220=ZZ2220+ZZ2220
++006200        114400          ZZ2220=ZZ2220+ZZ2220
++006200        005440          0 8192 -ZZ1220
++006201        114400          0 ZZ2220
+-       mark 5357, 358         /28 serp
++006202        001314          ZZ2221=ZZ2221+ZZ2221
++006202        002630          ZZ2221=ZZ2221+ZZ2221
++006202        005460          ZZ2221=ZZ2221+ZZ2221
++006202        013140          ZZ2221=ZZ2221+ZZ2221
++006202        026300          ZZ2221=ZZ2221+ZZ2221
++006202        054600          ZZ2221=ZZ2221+ZZ2221
++006202        131400          ZZ2221=ZZ2221+ZZ2221
++006202        263000          ZZ2221=ZZ2221+ZZ2221
++006202        005423          0 8192 -ZZ1221
++006203        263000          0 ZZ2221
+-       mark 5373, -71         /32 serp
++006204        777560          ZZ2222=ZZ2222+ZZ2222
++006204        777340          ZZ2222=ZZ2222+ZZ2222
++006204        776700          ZZ2222=ZZ2222+ZZ2222
++006204        775600          ZZ2222=ZZ2222+ZZ2222
++006204        773400          ZZ2222=ZZ2222+ZZ2222
++006204        767000          ZZ2222=ZZ2222+ZZ2222
++006204        756000          ZZ2222=ZZ2222+ZZ2222
++006204        734000          ZZ2222=ZZ2222+ZZ2222
++006204        005403          0 8192 -ZZ1222
++006205        734000          0 ZZ2222
+-       mark 5430, -508        / 7 scor
++006206        776006          ZZ2223=ZZ2223+ZZ2223
++006206        774014          ZZ2223=ZZ2223+ZZ2223
++006206        770030          ZZ2223=ZZ2223+ZZ2223
++006206        760060          ZZ2223=ZZ2223+ZZ2223
++006206        740140          ZZ2223=ZZ2223+ZZ2223
++006206        700300          ZZ2223=ZZ2223+ZZ2223
++006206        600600          ZZ2223=ZZ2223+ZZ2223
++006206        401400          ZZ2223=ZZ2223+ZZ2223
++006206        005312          0 8192 -ZZ1223
++006207        401400          0 ZZ2223
+-       mark 5459, -445        / 8 scor
++006210        776204          ZZ2224=ZZ2224+ZZ2224
++006210        774410          ZZ2224=ZZ2224+ZZ2224
++006210        771020          ZZ2224=ZZ2224+ZZ2224
++006210        762040          ZZ2224=ZZ2224+ZZ2224
++006210        744100          ZZ2224=ZZ2224+ZZ2224
++006210        710200          ZZ2224=ZZ2224+ZZ2224
++006210        620400          ZZ2224=ZZ2224+ZZ2224
++006210        441000          ZZ2224=ZZ2224+ZZ2224
++006210        005255          0 8192 -ZZ1224
++006211        441000          0 ZZ2224
+-       mark 5513, -78         / 1 ophi
++006212        777542          ZZ2225=ZZ2225+ZZ2225
++006212        777304          ZZ2225=ZZ2225+ZZ2225
++006212        776610          ZZ2225=ZZ2225+ZZ2225
++006212        775420          ZZ2225=ZZ2225+ZZ2225
++006212        773040          ZZ2225=ZZ2225+ZZ2225
++006212        766100          ZZ2225=ZZ2225+ZZ2225
++006212        754200          ZZ2225=ZZ2225+ZZ2225
++006212        730400          ZZ2225=ZZ2225+ZZ2225
++006212        005167          0 8192 -ZZ1225
++006213        730400          0 ZZ2225
+-       mark 5536, -101        / 2 ophi
++006214        777464          ZZ2226=ZZ2226+ZZ2226
++006214        777150          ZZ2226=ZZ2226+ZZ2226
++006214        776320          ZZ2226=ZZ2226+ZZ2226
++006214        774640          ZZ2226=ZZ2226+ZZ2226
++006214        771500          ZZ2226=ZZ2226+ZZ2226
++006214        763200          ZZ2226=ZZ2226+ZZ2226
++006214        746400          ZZ2226=ZZ2226+ZZ2226
++006214        715000          ZZ2226=ZZ2226+ZZ2226
++006214        005140          0 8192 -ZZ1226
++006215        715000          0 ZZ2226
+-       mark 5609, 494         /27 herc
++006216        001734          ZZ2227=ZZ2227+ZZ2227
++006216        003670          ZZ2227=ZZ2227+ZZ2227
++006216        007560          ZZ2227=ZZ2227+ZZ2227
++006216        017340          ZZ2227=ZZ2227+ZZ2227
++006216        036700          ZZ2227=ZZ2227+ZZ2227
++006216        075600          ZZ2227=ZZ2227+ZZ2227
++006216        173400          ZZ2227=ZZ2227+ZZ2227
++006216        367000          ZZ2227=ZZ2227+ZZ2227
++006216        005027          0 8192 -ZZ1227
++006217        367000          0 ZZ2227
+-       mark 5641, -236        /13 ophi
++006220        777046          ZZ2228=ZZ2228+ZZ2228
++006220        776114          ZZ2228=ZZ2228+ZZ2228
++006220        774230          ZZ2228=ZZ2228+ZZ2228
++006220        770460          ZZ2228=ZZ2228+ZZ2228
++006220        761140          ZZ2228=ZZ2228+ZZ2228
++006220        742300          ZZ2228=ZZ2228+ZZ2228
++006220        704600          ZZ2228=ZZ2228+ZZ2228
++006220        611400          ZZ2228=ZZ2228+ZZ2228
++006220        004767          0 8192 -ZZ1228
++006221        611400          0 ZZ2228
+-       mark 5828, -355        /35 ophi
++006222        776470          ZZ2229=ZZ2229+ZZ2229
++006222        775160          ZZ2229=ZZ2229+ZZ2229
++006222        772340          ZZ2229=ZZ2229+ZZ2229
++006222        764700          ZZ2229=ZZ2229+ZZ2229
++006222        751600          ZZ2229=ZZ2229+ZZ2229
++006222        723400          ZZ2229=ZZ2229+ZZ2229
++006222        647000          ZZ2229=ZZ2229+ZZ2229
++006222        516000          ZZ2229=ZZ2229+ZZ2229
++006222        004474          0 8192 -ZZ1229
++006223        516000          0 ZZ2229
+-       mark 5860, 330         /64 herc
++006224        001224          ZZ2230=ZZ2230+ZZ2230
++006224        002450          ZZ2230=ZZ2230+ZZ2230
++006224        005120          ZZ2230=ZZ2230+ZZ2230
++006224        012240          ZZ2230=ZZ2230+ZZ2230
++006224        024500          ZZ2230=ZZ2230+ZZ2230
++006224        051200          ZZ2230=ZZ2230+ZZ2230
++006224        122400          ZZ2230=ZZ2230+ZZ2230
++006224        245000          ZZ2230=ZZ2230+ZZ2230
++006224        004434          0 8192 -ZZ1230
++006225        245000          0 ZZ2230
+-       mark 5984, -349        /55 serp
++006226        776504          ZZ2231=ZZ2231+ZZ2231
++006226        775210          ZZ2231=ZZ2231+ZZ2231
++006226        772420          ZZ2231=ZZ2231+ZZ2231
++006226        765040          ZZ2231=ZZ2231+ZZ2231
++006226        752100          ZZ2231=ZZ2231+ZZ2231
++006226        724200          ZZ2231=ZZ2231+ZZ2231
++006226        650400          ZZ2231=ZZ2231+ZZ2231
++006226        521000          ZZ2231=ZZ2231+ZZ2231
++006226        004240          0 8192 -ZZ1231
++006227        521000          0 ZZ2231
+-       mark 6047, 63          /62 ophi
++006230        000176          ZZ2232=ZZ2232+ZZ2232
++006230        000374          ZZ2232=ZZ2232+ZZ2232
++006230        000770          ZZ2232=ZZ2232+ZZ2232
++006230        001760          ZZ2232=ZZ2232+ZZ2232
++006230        003740          ZZ2232=ZZ2232+ZZ2232
++006230        007700          ZZ2232=ZZ2232+ZZ2232
++006230        017600          ZZ2232=ZZ2232+ZZ2232
++006230        037400          ZZ2232=ZZ2232+ZZ2232
++006230        004141          0 8192 -ZZ1232
++006231        037400          0 ZZ2232
+-       mark 6107, -222        /64 ophi
++006232        777102          ZZ2233=ZZ2233+ZZ2233
++006232        776204          ZZ2233=ZZ2233+ZZ2233
++006232        774410          ZZ2233=ZZ2233+ZZ2233
++006232        771020          ZZ2233=ZZ2233+ZZ2233
++006232        762040          ZZ2233=ZZ2233+ZZ2233
++006232        744100          ZZ2233=ZZ2233+ZZ2233
++006232        710200          ZZ2233=ZZ2233+ZZ2233
++006232        620400          ZZ2233=ZZ2233+ZZ2233
++006232        004045          0 8192 -ZZ1233
++006233        620400          0 ZZ2233
+-       mark 6159, 217         /72 ophi
++006234        000662          ZZ2234=ZZ2234+ZZ2234
++006234        001544          ZZ2234=ZZ2234+ZZ2234
++006234        003310          ZZ2234=ZZ2234+ZZ2234
++006234        006620          ZZ2234=ZZ2234+ZZ2234
++006234        015440          ZZ2234=ZZ2234+ZZ2234
++006234        033100          ZZ2234=ZZ2234+ZZ2234
++006234        066200          ZZ2234=ZZ2234+ZZ2234
++006234        154400          ZZ2234=ZZ2234+ZZ2234
++006234        003761          0 8192 -ZZ1234
++006235        154400          0 ZZ2234
+-       mark 6236, -66         /58 serp
++006236        777572          ZZ2235=ZZ2235+ZZ2235
++006236        777364          ZZ2235=ZZ2235+ZZ2235
++006236        776750          ZZ2235=ZZ2235+ZZ2235
++006236        775720          ZZ2235=ZZ2235+ZZ2235
++006236        773640          ZZ2235=ZZ2235+ZZ2235
++006236        767500          ZZ2235=ZZ2235+ZZ2235
++006236        757200          ZZ2235=ZZ2235+ZZ2235
++006236        736400          ZZ2235=ZZ2235+ZZ2235
++006236        003644          0 8192 -ZZ1235
++006237        736400          0 ZZ2235
+-       mark 6439, -483        /37 sgtr
++006240        776070          ZZ2236=ZZ2236+ZZ2236
++006240        774160          ZZ2236=ZZ2236+ZZ2236
++006240        770340          ZZ2236=ZZ2236+ZZ2236
++006240        760700          ZZ2236=ZZ2236+ZZ2236
++006240        741600          ZZ2236=ZZ2236+ZZ2236
++006240        703400          ZZ2236=ZZ2236+ZZ2236
++006240        607000          ZZ2236=ZZ2236+ZZ2236
++006240        416000          ZZ2236=ZZ2236+ZZ2236
++006240        003331          0 8192 -ZZ1236
++006241        416000          0 ZZ2236
+-       mark 6490, 312         /17 aqil
++006242        001160          ZZ2237=ZZ2237+ZZ2237
++006242        002340          ZZ2237=ZZ2237+ZZ2237
++006242        004700          ZZ2237=ZZ2237+ZZ2237
++006242        011600          ZZ2237=ZZ2237+ZZ2237
++006242        023400          ZZ2237=ZZ2237+ZZ2237
++006242        047000          ZZ2237=ZZ2237+ZZ2237
++006242        116000          ZZ2237=ZZ2237+ZZ2237
++006242        234000          ZZ2237=ZZ2237+ZZ2237
++006242        003246          0 8192 -ZZ1237
++006243        234000          0 ZZ2237
+-       mark 6491, -115        /16 aqil
++006244        777430          ZZ2238=ZZ2238+ZZ2238
++006244        777060          ZZ2238=ZZ2238+ZZ2238
++006244        776140          ZZ2238=ZZ2238+ZZ2238
++006244        774300          ZZ2238=ZZ2238+ZZ2238
++006244        770600          ZZ2238=ZZ2238+ZZ2238
++006244        761400          ZZ2238=ZZ2238+ZZ2238
++006244        743000          ZZ2238=ZZ2238+ZZ2238
++006244        706000          ZZ2238=ZZ2238+ZZ2238
++006244        003245          0 8192 -ZZ1238
++006245        706000          0 ZZ2238
+-       mark 6507, -482        /41 sgtr
++006246        776072          ZZ2239=ZZ2239+ZZ2239
++006246        774164          ZZ2239=ZZ2239+ZZ2239
++006246        770350          ZZ2239=ZZ2239+ZZ2239
++006246        760720          ZZ2239=ZZ2239+ZZ2239
++006246        741640          ZZ2239=ZZ2239+ZZ2239
++006246        703500          ZZ2239=ZZ2239+ZZ2239
++006246        607200          ZZ2239=ZZ2239+ZZ2239
++006246        416400          ZZ2239=ZZ2239+ZZ2239
++006246        003225          0 8192 -ZZ1239
++006247        416400          0 ZZ2239
+-       mark 6602, 66          /30 aqil
++006250        000204          ZZ2240=ZZ2240+ZZ2240
++006250        000410          ZZ2240=ZZ2240+ZZ2240
++006250        001020          ZZ2240=ZZ2240+ZZ2240
++006250        002040          ZZ2240=ZZ2240+ZZ2240
++006250        004100          ZZ2240=ZZ2240+ZZ2240
++006250        010200          ZZ2240=ZZ2240+ZZ2240
++006250        020400          ZZ2240=ZZ2240+ZZ2240
++006250        041000          ZZ2240=ZZ2240+ZZ2240
++006250        003066          0 8192 -ZZ1240
++006251        041000          0 ZZ2240
+-       mark 6721, 236         /50 aqil
++006252        000730          ZZ2241=ZZ2241+ZZ2241
++006252        001660          ZZ2241=ZZ2241+ZZ2241
++006252        003540          ZZ2241=ZZ2241+ZZ2241
++006252        007300          ZZ2241=ZZ2241+ZZ2241
++006252        016600          ZZ2241=ZZ2241+ZZ2241
++006252        035400          ZZ2241=ZZ2241+ZZ2241
++006252        073000          ZZ2241=ZZ2241+ZZ2241
++006252        166000          ZZ2241=ZZ2241+ZZ2241
++006252        002677          0 8192 -ZZ1241
++006253        166000          0 ZZ2241
+-       mark 6794, 437         /12 sgte
++006254        001552          ZZ2242=ZZ2242+ZZ2242
++006254        003324          ZZ2242=ZZ2242+ZZ2242
++006254        006650          ZZ2242=ZZ2242+ZZ2242
++006254        015520          ZZ2242=ZZ2242+ZZ2242
++006254        033240          ZZ2242=ZZ2242+ZZ2242
++006254        066500          ZZ2242=ZZ2242+ZZ2242
++006254        155200          ZZ2242=ZZ2242+ZZ2242
++006254        332400          ZZ2242=ZZ2242+ZZ2242
++006254        002566          0 8192 -ZZ1242
++006255        332400          0 ZZ2242
+-       mark 6862, -25         /65 aqil
++006256        777714          ZZ2243=ZZ2243+ZZ2243
++006256        777630          ZZ2243=ZZ2243+ZZ2243
++006256        777460          ZZ2243=ZZ2243+ZZ2243
++006256        777140          ZZ2243=ZZ2243+ZZ2243
++006256        776300          ZZ2243=ZZ2243+ZZ2243
++006256        774600          ZZ2243=ZZ2243+ZZ2243
++006256        771400          ZZ2243=ZZ2243+ZZ2243
++006256        763000          ZZ2243=ZZ2243+ZZ2243
++006256        002462          0 8192 -ZZ1243
++006257        763000          0 ZZ2243
+-       mark 6914, -344        / 9 capr
++006260        776516          ZZ2244=ZZ2244+ZZ2244
++006260        775234          ZZ2244=ZZ2244+ZZ2244
++006260        772470          ZZ2244=ZZ2244+ZZ2244
++006260        765160          ZZ2244=ZZ2244+ZZ2244
++006260        752340          ZZ2244=ZZ2244+ZZ2244
++006260        724700          ZZ2244=ZZ2244+ZZ2244
++006260        651600          ZZ2244=ZZ2244+ZZ2244
++006260        523400          ZZ2244=ZZ2244+ZZ2244
++006260        002376          0 8192 -ZZ1244
++006261        523400          0 ZZ2244
+-       mark 7014, 324         / 6 dlph
++006262        001210          ZZ2245=ZZ2245+ZZ2245
++006262        002420          ZZ2245=ZZ2245+ZZ2245
++006262        005040          ZZ2245=ZZ2245+ZZ2245
++006262        012100          ZZ2245=ZZ2245+ZZ2245
++006262        024200          ZZ2245=ZZ2245+ZZ2245
++006262        050400          ZZ2245=ZZ2245+ZZ2245
++006262        121000          ZZ2245=ZZ2245+ZZ2245
++006262        242000          ZZ2245=ZZ2245+ZZ2245
++006262        002232          0 8192 -ZZ1245
++006263        242000          0 ZZ2245
+-       mark 7318, -137        /22 aqar
++006264        777354          ZZ2246=ZZ2246+ZZ2246
++006264        776730          ZZ2246=ZZ2246+ZZ2246
++006264        775660          ZZ2246=ZZ2246+ZZ2246
++006264        773540          ZZ2246=ZZ2246+ZZ2246
++006264        767300          ZZ2246=ZZ2246+ZZ2246
++006264        756600          ZZ2246=ZZ2246+ZZ2246
++006264        735400          ZZ2246=ZZ2246+ZZ2246
++006264        673000          ZZ2246=ZZ2246+ZZ2246
++006264        001552          0 8192 -ZZ1246
++006265        673000          0 ZZ2246
+-       mark 7391, 214         / 8 pegs
++006266        000654          ZZ2247=ZZ2247+ZZ2247
++006266        001530          ZZ2247=ZZ2247+ZZ2247
++006266        003260          ZZ2247=ZZ2247+ZZ2247
++006266        006540          ZZ2247=ZZ2247+ZZ2247
++006266        015300          ZZ2247=ZZ2247+ZZ2247
++006266        032600          ZZ2247=ZZ2247+ZZ2247
++006266        065400          ZZ2247=ZZ2247+ZZ2247
++006266        153000          ZZ2247=ZZ2247+ZZ2247
++006266        001441          0 8192 -ZZ1247
++006267        153000          0 ZZ2247
+-       mark 7404, -377        /49 capr
++006270        776414          ZZ2248=ZZ2248+ZZ2248
++006270        775030          ZZ2248=ZZ2248+ZZ2248
++006270        772060          ZZ2248=ZZ2248+ZZ2248
++006270        764140          ZZ2248=ZZ2248+ZZ2248
++006270        750300          ZZ2248=ZZ2248+ZZ2248
++006270        720600          ZZ2248=ZZ2248+ZZ2248
++006270        641400          ZZ2248=ZZ2248+ZZ2248
++006270        503000          ZZ2248=ZZ2248+ZZ2248
++006270        001424          0 8192 -ZZ1248
++006271        503000          0 ZZ2248
+-       mark 7513, -18         /34 aqar
++006272        777732          ZZ2249=ZZ2249+ZZ2249
++006272        777664          ZZ2249=ZZ2249+ZZ2249
++006272        777550          ZZ2249=ZZ2249+ZZ2249
++006272        777320          ZZ2249=ZZ2249+ZZ2249
++006272        776640          ZZ2249=ZZ2249+ZZ2249
++006272        775500          ZZ2249=ZZ2249+ZZ2249
++006272        773200          ZZ2249=ZZ2249+ZZ2249
++006272        766400          ZZ2249=ZZ2249+ZZ2249
++006272        001247          0 8192 -ZZ1249
++006273        766400          0 ZZ2249
+-       mark 7539, 130         /26 pegs
++006274        000404          ZZ2250=ZZ2250+ZZ2250
++006274        001010          ZZ2250=ZZ2250+ZZ2250
++006274        002020          ZZ2250=ZZ2250+ZZ2250
++006274        004040          ZZ2250=ZZ2250+ZZ2250
++006274        010100          ZZ2250=ZZ2250+ZZ2250
++006274        020200          ZZ2250=ZZ2250+ZZ2250
++006274        040400          ZZ2250=ZZ2250+ZZ2250
++006274        101000          ZZ2250=ZZ2250+ZZ2250
++006274        001215          0 8192 -ZZ1250
++006275        101000          0 ZZ2250
+-       mark 7644, -12         /55 aqar
++006276        777746          ZZ2251=ZZ2251+ZZ2251
++006276        777714          ZZ2251=ZZ2251+ZZ2251
++006276        777630          ZZ2251=ZZ2251+ZZ2251
++006276        777460          ZZ2251=ZZ2251+ZZ2251
++006276        777140          ZZ2251=ZZ2251+ZZ2251
++006276        776300          ZZ2251=ZZ2251+ZZ2251
++006276        774600          ZZ2251=ZZ2251+ZZ2251
++006276        771400          ZZ2251=ZZ2251+ZZ2251
++006276        001044          0 8192 -ZZ1251
++006277        771400          0 ZZ2251
+-       mark 7717, 235         /42 pegs
++006300        000726          ZZ2252=ZZ2252+ZZ2252
++006300        001654          ZZ2252=ZZ2252+ZZ2252
++006300        003530          ZZ2252=ZZ2252+ZZ2252
++006300        007260          ZZ2252=ZZ2252+ZZ2252
++006300        016540          ZZ2252=ZZ2252+ZZ2252
++006300        035300          ZZ2252=ZZ2252+ZZ2252
++006300        072600          ZZ2252=ZZ2252+ZZ2252
++006300        165400          ZZ2252=ZZ2252+ZZ2252
++006300        000733          0 8192 -ZZ1252
++006301        165400          0 ZZ2252
+-       mark 7790, -372        /76 aqar
++006302        776426          ZZ2253=ZZ2253+ZZ2253
++006302        775054          ZZ2253=ZZ2253+ZZ2253
++006302        772130          ZZ2253=ZZ2253+ZZ2253
++006302        764260          ZZ2253=ZZ2253+ZZ2253
++006302        750540          ZZ2253=ZZ2253+ZZ2253
++006302        721300          ZZ2253=ZZ2253+ZZ2253
++006302        642600          ZZ2253=ZZ2253+ZZ2253
++006302        505400          ZZ2253=ZZ2253+ZZ2253
++006302        000622          0 8192 -ZZ1253
++006303        505400          0 ZZ2253
+ 006304                3q,
+-       mark 7849, 334         /54 pegs, markab
++006304        001234          ZZ2254=ZZ2254+ZZ2254
++006304        002470          ZZ2254=ZZ2254+ZZ2254
++006304        005160          ZZ2254=ZZ2254+ZZ2254
++006304        012340          ZZ2254=ZZ2254+ZZ2254
++006304        024700          ZZ2254=ZZ2254+ZZ2254
++006304        051600          ZZ2254=ZZ2254+ZZ2254
++006304        123400          ZZ2254=ZZ2254+ZZ2254
++006304        247000          ZZ2254=ZZ2254+ZZ2254
++006304        000527          0 8192 -ZZ1254
++006305        247000          0 ZZ2254
+ 006306                4j,
+-       mark 1, -143           /33 pisc
++006306        777340          ZZ2255=ZZ2255+ZZ2255
++006306        776700          ZZ2255=ZZ2255+ZZ2255
++006306        775600          ZZ2255=ZZ2255+ZZ2255
++006306        773400          ZZ2255=ZZ2255+ZZ2255
++006306        767000          ZZ2255=ZZ2255+ZZ2255
++006306        756000          ZZ2255=ZZ2255+ZZ2255
++006306        734000          ZZ2255=ZZ2255+ZZ2255
++006306        670000          ZZ2255=ZZ2255+ZZ2255
++006306        017777          0 8192 -ZZ1255
++006307        670000          0 ZZ2255
+-       mark 54, 447           /89 pegs
++006310        001576          ZZ2256=ZZ2256+ZZ2256
++006310        003374          ZZ2256=ZZ2256+ZZ2256
++006310        006770          ZZ2256=ZZ2256+ZZ2256
++006310        015760          ZZ2256=ZZ2256+ZZ2256
++006310        033740          ZZ2256=ZZ2256+ZZ2256
++006310        067700          ZZ2256=ZZ2256+ZZ2256
++006310        157600          ZZ2256=ZZ2256+ZZ2256
++006310        337400          ZZ2256=ZZ2256+ZZ2256
++006310        017712          0 8192 -ZZ1256
++006311        337400          0 ZZ2256
+-       mark 54, -443          /7 ceti
++006312        776210          ZZ2257=ZZ2257+ZZ2257
++006312        774420          ZZ2257=ZZ2257+ZZ2257
++006312        771040          ZZ2257=ZZ2257+ZZ2257
++006312        762100          ZZ2257=ZZ2257+ZZ2257
++006312        744200          ZZ2257=ZZ2257+ZZ2257
++006312        710400          ZZ2257=ZZ2257+ZZ2257
++006312        621000          ZZ2257=ZZ2257+ZZ2257
++006312        442000          ZZ2257=ZZ2257+ZZ2257
++006312        017712          0 8192 -ZZ1257
++006313        442000          0 ZZ2257
+-       mark 82, -214          /8 ceti
++006314        777122          ZZ2258=ZZ2258+ZZ2258
++006314        776244          ZZ2258=ZZ2258+ZZ2258
++006314        774510          ZZ2258=ZZ2258+ZZ2258
++006314        771220          ZZ2258=ZZ2258+ZZ2258
++006314        762440          ZZ2258=ZZ2258+ZZ2258
++006314        745100          ZZ2258=ZZ2258+ZZ2258
++006314        712200          ZZ2258=ZZ2258+ZZ2258
++006314        624400          ZZ2258=ZZ2258+ZZ2258
++006314        017656          0 8192 -ZZ1258
++006315        624400          0 ZZ2258
+-       mark 223, -254         /17 ceti
++006316        777002          ZZ2259=ZZ2259+ZZ2259
++006316        776004          ZZ2259=ZZ2259+ZZ2259
++006316        774010          ZZ2259=ZZ2259+ZZ2259
++006316        770020          ZZ2259=ZZ2259+ZZ2259
++006316        760040          ZZ2259=ZZ2259+ZZ2259
++006316        740100          ZZ2259=ZZ2259+ZZ2259
++006316        700200          ZZ2259=ZZ2259+ZZ2259
++006316        600400          ZZ2259=ZZ2259+ZZ2259
++006316        017441          0 8192 -ZZ1259
++006317        600400          0 ZZ2259
+-       mark 248, 160          /63 pisc
++006320        000500          ZZ2260=ZZ2260+ZZ2260
++006320        001200          ZZ2260=ZZ2260+ZZ2260
++006320        002400          ZZ2260=ZZ2260+ZZ2260
++006320        005000          ZZ2260=ZZ2260+ZZ2260
++006320        012000          ZZ2260=ZZ2260+ZZ2260
++006320        024000          ZZ2260=ZZ2260+ZZ2260
++006320        050000          ZZ2260=ZZ2260+ZZ2260
++006320        120000          ZZ2260=ZZ2260+ZZ2260
++006320        017410          0 8192 -ZZ1260
++006321        120000          0 ZZ2260
+-       mark 273, -38          /20 ceti
++006322        777662          ZZ2261=ZZ2261+ZZ2261
++006322        777544          ZZ2261=ZZ2261+ZZ2261
++006322        777310          ZZ2261=ZZ2261+ZZ2261
++006322        776620          ZZ2261=ZZ2261+ZZ2261
++006322        775440          ZZ2261=ZZ2261+ZZ2261
++006322        773100          ZZ2261=ZZ2261+ZZ2261
++006322        766200          ZZ2261=ZZ2261+ZZ2261
++006322        754400          ZZ2261=ZZ2261+ZZ2261
++006322        017357          0 8192 -ZZ1261
++006323        754400          0 ZZ2261
+-       mark 329, 167          /71 pisc
++006324        000516          ZZ2262=ZZ2262+ZZ2262
++006324        001234          ZZ2262=ZZ2262+ZZ2262
++006324        002470          ZZ2262=ZZ2262+ZZ2262
++006324        005160          ZZ2262=ZZ2262+ZZ2262
++006324        012340          ZZ2262=ZZ2262+ZZ2262
++006324        024700          ZZ2262=ZZ2262+ZZ2262
++006324        051600          ZZ2262=ZZ2262+ZZ2262
++006324        123400          ZZ2262=ZZ2262+ZZ2262
++006324        017267          0 8192 -ZZ1262
++006325        123400          0 ZZ2262
+-       mark 376, 467          /84 pisc
++006326        001646          ZZ2263=ZZ2263+ZZ2263
++006326        003514          ZZ2263=ZZ2263+ZZ2263
++006326        007230          ZZ2263=ZZ2263+ZZ2263
++006326        016460          ZZ2263=ZZ2263+ZZ2263
++006326        035140          ZZ2263=ZZ2263+ZZ2263
++006326        072300          ZZ2263=ZZ2263+ZZ2263
++006326        164600          ZZ2263=ZZ2263+ZZ2263
++006326        351400          ZZ2263=ZZ2263+ZZ2263
++006326        017210          0 8192 -ZZ1263
++006327        351400          0 ZZ2263
+-       mark 450, -198         /45 ceti
++006330        777162          ZZ2264=ZZ2264+ZZ2264
++006330        776344          ZZ2264=ZZ2264+ZZ2264
++006330        774710          ZZ2264=ZZ2264+ZZ2264
++006330        771620          ZZ2264=ZZ2264+ZZ2264
++006330        763440          ZZ2264=ZZ2264+ZZ2264
++006330        747100          ZZ2264=ZZ2264+ZZ2264
++006330        716200          ZZ2264=ZZ2264+ZZ2264
++006330        634400          ZZ2264=ZZ2264+ZZ2264
++006330        017076          0 8192 -ZZ1264
++006331        634400          0 ZZ2264
+-       mark 548, 113          /106 pisc
++006332        000342          ZZ2265=ZZ2265+ZZ2265
++006332        000704          ZZ2265=ZZ2265+ZZ2265
++006332        001610          ZZ2265=ZZ2265+ZZ2265
++006332        003420          ZZ2265=ZZ2265+ZZ2265
++006332        007040          ZZ2265=ZZ2265+ZZ2265
++006332        016100          ZZ2265=ZZ2265+ZZ2265
++006332        034200          ZZ2265=ZZ2265+ZZ2265
++006332        070400          ZZ2265=ZZ2265+ZZ2265
++006332        016734          0 8192 -ZZ1265
++006333        070400          0 ZZ2265
+-       mark 570, 197          /110 pisc
++006334        000612          ZZ2266=ZZ2266+ZZ2266
++006334        001424          ZZ2266=ZZ2266+ZZ2266
++006334        003050          ZZ2266=ZZ2266+ZZ2266
++006334        006120          ZZ2266=ZZ2266+ZZ2266
++006334        014240          ZZ2266=ZZ2266+ZZ2266
++006334        030500          ZZ2266=ZZ2266+ZZ2266
++006334        061200          ZZ2266=ZZ2266+ZZ2266
++006334        142400          ZZ2266=ZZ2266+ZZ2266
++006334        016706          0 8192 -ZZ1266
++006335        142400          0 ZZ2266
+-       mark 595, -255         /53 ceti
++006336        777000          ZZ2267=ZZ2267+ZZ2267
++006336        776000          ZZ2267=ZZ2267+ZZ2267
++006336        774000          ZZ2267=ZZ2267+ZZ2267
++006336        770000          ZZ2267=ZZ2267+ZZ2267
++006336        760000          ZZ2267=ZZ2267+ZZ2267
++006336        740000          ZZ2267=ZZ2267+ZZ2267
++006336        700000          ZZ2267=ZZ2267+ZZ2267
++006336        600000          ZZ2267=ZZ2267+ZZ2267
++006336        016655          0 8192 -ZZ1267
++006337        600000          0 ZZ2267
+-       mark 606, -247         /55 ceti
++006340        777020          ZZ2268=ZZ2268+ZZ2268
++006340        776040          ZZ2268=ZZ2268+ZZ2268
++006340        774100          ZZ2268=ZZ2268+ZZ2268
++006340        770200          ZZ2268=ZZ2268+ZZ2268
++006340        760400          ZZ2268=ZZ2268+ZZ2268
++006340        741000          ZZ2268=ZZ2268+ZZ2268
++006340        702000          ZZ2268=ZZ2268+ZZ2268
++006340        604000          ZZ2268=ZZ2268+ZZ2268
++006340        016642          0 8192 -ZZ1268
++006341        604000          0 ZZ2268
+-       mark 615, 428          / 5 arie
++006342        001530          ZZ2269=ZZ2269+ZZ2269
++006342        003260          ZZ2269=ZZ2269+ZZ2269
++006342        006540          ZZ2269=ZZ2269+ZZ2269
++006342        015300          ZZ2269=ZZ2269+ZZ2269
++006342        032600          ZZ2269=ZZ2269+ZZ2269
++006342        065400          ZZ2269=ZZ2269+ZZ2269
++006342        153000          ZZ2269=ZZ2269+ZZ2269
++006342        326000          ZZ2269=ZZ2269+ZZ2269
++006342        016631          0 8192 -ZZ1269
++006343        326000          0 ZZ2269
+-       mark 617, 61           /14 pisc
++006344        000172          ZZ2270=ZZ2270+ZZ2270
++006344        000364          ZZ2270=ZZ2270+ZZ2270
++006344        000750          ZZ2270=ZZ2270+ZZ2270
++006344        001720          ZZ2270=ZZ2270+ZZ2270
++006344        003640          ZZ2270=ZZ2270+ZZ2270
++006344        007500          ZZ2270=ZZ2270+ZZ2270
++006344        017200          ZZ2270=ZZ2270+ZZ2270
++006344        036400          ZZ2270=ZZ2270+ZZ2270
++006344        016627          0 8192 -ZZ1270
++006345        036400          0 ZZ2270
+-       mark 656,  -491        /59 ceti
++006346        776050          ZZ2271=ZZ2271+ZZ2271
++006346        774120          ZZ2271=ZZ2271+ZZ2271
++006346        770240          ZZ2271=ZZ2271+ZZ2271
++006346        760500          ZZ2271=ZZ2271+ZZ2271
++006346        741200          ZZ2271=ZZ2271+ZZ2271
++006346        702400          ZZ2271=ZZ2271+ZZ2271
++006346        605000          ZZ2271=ZZ2271+ZZ2271
++006346        412000          ZZ2271=ZZ2271+ZZ2271
++006346        016560          0 8192 -ZZ1271
++006347        412000          0 ZZ2271
+-       mark 665, 52           /113 pisc
++006350        000150          ZZ2272=ZZ2272+ZZ2272
++006350        000320          ZZ2272=ZZ2272+ZZ2272
++006350        000640          ZZ2272=ZZ2272+ZZ2272
++006350        001500          ZZ2272=ZZ2272+ZZ2272
++006350        003200          ZZ2272=ZZ2272+ZZ2272
++006350        006400          ZZ2272=ZZ2272+ZZ2272
++006350        015000          ZZ2272=ZZ2272+ZZ2272
++006350        032000          ZZ2272=ZZ2272+ZZ2272
++006350        016547          0 8192 -ZZ1272
++006351        032000          0 ZZ2272
+-       mark 727, 191          /65 ceti
++006352        000576          ZZ2273=ZZ2273+ZZ2273
++006352        001374          ZZ2273=ZZ2273+ZZ2273
++006352        002770          ZZ2273=ZZ2273+ZZ2273
++006352        005760          ZZ2273=ZZ2273+ZZ2273
++006352        013740          ZZ2273=ZZ2273+ZZ2273
++006352        027700          ZZ2273=ZZ2273+ZZ2273
++006352        057600          ZZ2273=ZZ2273+ZZ2273
++006352        137400          ZZ2273=ZZ2273+ZZ2273
++006352        016451          0 8192 -ZZ1273
++006353        137400          0 ZZ2273
+-       mark 803, -290         /72 ceti
++006354        776672          ZZ2274=ZZ2274+ZZ2274
++006354        775564          ZZ2274=ZZ2274+ZZ2274
++006354        773350          ZZ2274=ZZ2274+ZZ2274
++006354        766720          ZZ2274=ZZ2274+ZZ2274
++006354        755640          ZZ2274=ZZ2274+ZZ2274
++006354        733500          ZZ2274=ZZ2274+ZZ2274
++006354        667200          ZZ2274=ZZ2274+ZZ2274
++006354        556400          ZZ2274=ZZ2274+ZZ2274
++006354        016335          0 8192 -ZZ1274
++006355        556400          0 ZZ2274
+-       mark 813, 182          /73 ceti
++006356        000554          ZZ2275=ZZ2275+ZZ2275
++006356        001330          ZZ2275=ZZ2275+ZZ2275
++006356        002660          ZZ2275=ZZ2275+ZZ2275
++006356        005540          ZZ2275=ZZ2275+ZZ2275
++006356        013300          ZZ2275=ZZ2275+ZZ2275
++006356        026600          ZZ2275=ZZ2275+ZZ2275
++006356        055400          ZZ2275=ZZ2275+ZZ2275
++006356        133000          ZZ2275=ZZ2275+ZZ2275
++006356        016323          0 8192 -ZZ1275
++006357        133000          0 ZZ2275
+-       mark 838, -357         /76 ceti
++006360        776464          ZZ2276=ZZ2276+ZZ2276
++006360        775150          ZZ2276=ZZ2276+ZZ2276
++006360        772320          ZZ2276=ZZ2276+ZZ2276
++006360        764640          ZZ2276=ZZ2276+ZZ2276
++006360        751500          ZZ2276=ZZ2276+ZZ2276
++006360        723200          ZZ2276=ZZ2276+ZZ2276
++006360        646400          ZZ2276=ZZ2276+ZZ2276
++006360        515000          ZZ2276=ZZ2276+ZZ2276
++006360        016272          0 8192 -ZZ1276
++006361        515000          0 ZZ2276
+-       mark 878, -2           /82 ceti
++006362        777772          ZZ2277=ZZ2277+ZZ2277
++006362        777764          ZZ2277=ZZ2277+ZZ2277
++006362        777750          ZZ2277=ZZ2277+ZZ2277
++006362        777720          ZZ2277=ZZ2277+ZZ2277
++006362        777640          ZZ2277=ZZ2277+ZZ2277
++006362        777500          ZZ2277=ZZ2277+ZZ2277
++006362        777200          ZZ2277=ZZ2277+ZZ2277
++006362        776400          ZZ2277=ZZ2277+ZZ2277
++006362        016222          0 8192 -ZZ1277
++006363        776400          0 ZZ2277
+-       mark 907, -340         /89 ceti
++006364        776526          ZZ2278=ZZ2278+ZZ2278
++006364        775254          ZZ2278=ZZ2278+ZZ2278
++006364        772530          ZZ2278=ZZ2278+ZZ2278
++006364        765260          ZZ2278=ZZ2278+ZZ2278
++006364        752540          ZZ2278=ZZ2278+ZZ2278
++006364        725300          ZZ2278=ZZ2278+ZZ2278
++006364        652600          ZZ2278=ZZ2278+ZZ2278
++006364        525400          ZZ2278=ZZ2278+ZZ2278
++006364        016165          0 8192 -ZZ1278
++006365        525400          0 ZZ2278
+-       mark 908, 221          /87 ceti
++006366        000672          ZZ2279=ZZ2279+ZZ2279
++006366        001564          ZZ2279=ZZ2279+ZZ2279
++006366        003350          ZZ2279=ZZ2279+ZZ2279
++006366        006720          ZZ2279=ZZ2279+ZZ2279
++006366        015640          ZZ2279=ZZ2279+ZZ2279
++006366        033500          ZZ2279=ZZ2279+ZZ2279
++006366        067200          ZZ2279=ZZ2279+ZZ2279
++006366        156400          ZZ2279=ZZ2279+ZZ2279
++006366        016164          0 8192 -ZZ1279
++006367        156400          0 ZZ2279
+-       mark 913, -432         / 1 erid
++006370        776236          ZZ2280=ZZ2280+ZZ2280
++006370        774474          ZZ2280=ZZ2280+ZZ2280
++006370        771170          ZZ2280=ZZ2280+ZZ2280
++006370        762360          ZZ2280=ZZ2280+ZZ2280
++006370        744740          ZZ2280=ZZ2280+ZZ2280
++006370        711700          ZZ2280=ZZ2280+ZZ2280
++006370        623600          ZZ2280=ZZ2280+ZZ2280
++006370        447400          ZZ2280=ZZ2280+ZZ2280
++006370        016157          0 8192 -ZZ1280
++006371        447400          0 ZZ2280
+-       mark 947, -487         / 2 erid
++006372        776060          ZZ2281=ZZ2281+ZZ2281
++006372        774140          ZZ2281=ZZ2281+ZZ2281
++006372        770300          ZZ2281=ZZ2281+ZZ2281
++006372        760600          ZZ2281=ZZ2281+ZZ2281
++006372        741400          ZZ2281=ZZ2281+ZZ2281
++006372        703000          ZZ2281=ZZ2281+ZZ2281
++006372        606000          ZZ2281=ZZ2281+ZZ2281
++006372        414000          ZZ2281=ZZ2281+ZZ2281
++006372        016115          0 8192 -ZZ1281
++006373        414000          0 ZZ2281
+-       mark 976, -212         / 3 erid
++006374        777126          ZZ2282=ZZ2282+ZZ2282
++006374        776254          ZZ2282=ZZ2282+ZZ2282
++006374        774530          ZZ2282=ZZ2282+ZZ2282
++006374        771260          ZZ2282=ZZ2282+ZZ2282
++006374        762540          ZZ2282=ZZ2282+ZZ2282
++006374        745300          ZZ2282=ZZ2282+ZZ2282
++006374        712600          ZZ2282=ZZ2282+ZZ2282
++006374        625400          ZZ2282=ZZ2282+ZZ2282
++006374        016060          0 8192 -ZZ1282
++006375        625400          0 ZZ2282
+-       mark 992, 194          /91 ceti
++006376        000604          ZZ2283=ZZ2283+ZZ2283
++006376        001410          ZZ2283=ZZ2283+ZZ2283
++006376        003020          ZZ2283=ZZ2283+ZZ2283
++006376        006040          ZZ2283=ZZ2283+ZZ2283
++006376        014100          ZZ2283=ZZ2283+ZZ2283
++006376        030200          ZZ2283=ZZ2283+ZZ2283
++006376        060400          ZZ2283=ZZ2283+ZZ2283
++006376        141000          ZZ2283=ZZ2283+ZZ2283
++006376        016040          0 8192 -ZZ1283
++006377        141000          0 ZZ2283
+-       mark 1058, 440         /57 arie
++006400        001560          ZZ2284=ZZ2284+ZZ2284
++006400        003340          ZZ2284=ZZ2284+ZZ2284
++006400        006700          ZZ2284=ZZ2284+ZZ2284
++006400        015600          ZZ2284=ZZ2284+ZZ2284
++006400        033400          ZZ2284=ZZ2284+ZZ2284
++006400        067000          ZZ2284=ZZ2284+ZZ2284
++006400        156000          ZZ2284=ZZ2284+ZZ2284
++006400        334000          ZZ2284=ZZ2284+ZZ2284
++006400        015736          0 8192 -ZZ1284
++006401        334000          0 ZZ2284
+-       mark 1076, 470         /58 arie
++006402        001654          ZZ2285=ZZ2285+ZZ2285
++006402        003530          ZZ2285=ZZ2285+ZZ2285
++006402        007260          ZZ2285=ZZ2285+ZZ2285
++006402        016540          ZZ2285=ZZ2285+ZZ2285
++006402        035300          ZZ2285=ZZ2285+ZZ2285
++006402        072600          ZZ2285=ZZ2285+ZZ2285
++006402        165400          ZZ2285=ZZ2285+ZZ2285
++006402        353000          ZZ2285=ZZ2285+ZZ2285
++006402        015714          0 8192 -ZZ1285
++006403        353000          0 ZZ2285
+-       mark 1087,  -209       /13 erid
++006404        777134          ZZ2286=ZZ2286+ZZ2286
++006404        776270          ZZ2286=ZZ2286+ZZ2286
++006404        774560          ZZ2286=ZZ2286+ZZ2286
++006404        771340          ZZ2286=ZZ2286+ZZ2286
++006404        762700          ZZ2286=ZZ2286+ZZ2286
++006404        745600          ZZ2286=ZZ2286+ZZ2286
++006404        713400          ZZ2286=ZZ2286+ZZ2286
++006404        627000          ZZ2286=ZZ2286+ZZ2286
++006404        015701          0 8192 -ZZ1286
++006405        627000          0 ZZ2286
+-       mark 1104, 68          /96 ceti
++006406        000210          ZZ2287=ZZ2287+ZZ2287
++006406        000420          ZZ2287=ZZ2287+ZZ2287
++006406        001040          ZZ2287=ZZ2287+ZZ2287
++006406        002100          ZZ2287=ZZ2287+ZZ2287
++006406        004200          ZZ2287=ZZ2287+ZZ2287
++006406        010400          ZZ2287=ZZ2287+ZZ2287
++006406        021000          ZZ2287=ZZ2287+ZZ2287
++006406        042000          ZZ2287=ZZ2287+ZZ2287
++006406        015660          0 8192 -ZZ1287
++006407        042000          0 ZZ2287
+-       mark 1110, -503        /16 erid
++006410        776020          ZZ2288=ZZ2288+ZZ2288
++006410        774040          ZZ2288=ZZ2288+ZZ2288
++006410        770100          ZZ2288=ZZ2288+ZZ2288
++006410        760200          ZZ2288=ZZ2288+ZZ2288
++006410        740400          ZZ2288=ZZ2288+ZZ2288
++006410        701000          ZZ2288=ZZ2288+ZZ2288
++006410        602000          ZZ2288=ZZ2288+ZZ2288
++006410        404000          ZZ2288=ZZ2288+ZZ2288
++006410        015652          0 8192 -ZZ1288
++006411        404000          0 ZZ2288
+-       mark 1135, 198         / 1 taur
++006412        000614          ZZ2289=ZZ2289+ZZ2289
++006412        001430          ZZ2289=ZZ2289+ZZ2289
++006412        003060          ZZ2289=ZZ2289+ZZ2289
++006412        006140          ZZ2289=ZZ2289+ZZ2289
++006412        014300          ZZ2289=ZZ2289+ZZ2289
++006412        030600          ZZ2289=ZZ2289+ZZ2289
++006412        061400          ZZ2289=ZZ2289+ZZ2289
++006412        143000          ZZ2289=ZZ2289+ZZ2289
++006412        015621          0 8192 -ZZ1289
++006413        143000          0 ZZ2289
+-       mark 1148, 214         / 2 taur
++006414        000654          ZZ2290=ZZ2290+ZZ2290
++006414        001530          ZZ2290=ZZ2290+ZZ2290
++006414        003260          ZZ2290=ZZ2290+ZZ2290
++006414        006540          ZZ2290=ZZ2290+ZZ2290
++006414        015300          ZZ2290=ZZ2290+ZZ2290
++006414        032600          ZZ2290=ZZ2290+ZZ2290
++006414        065400          ZZ2290=ZZ2290+ZZ2290
++006414        153000          ZZ2290=ZZ2290+ZZ2290
++006414        015604          0 8192 -ZZ1290
++006415        153000          0 ZZ2290
+-       mark 1168, 287         / 5 taur
++006416        001076          ZZ2291=ZZ2291+ZZ2291
++006416        002174          ZZ2291=ZZ2291+ZZ2291
++006416        004370          ZZ2291=ZZ2291+ZZ2291
++006416        010760          ZZ2291=ZZ2291+ZZ2291
++006416        021740          ZZ2291=ZZ2291+ZZ2291
++006416        043700          ZZ2291=ZZ2291+ZZ2291
++006416        107600          ZZ2291=ZZ2291+ZZ2291
++006416        217400          ZZ2291=ZZ2291+ZZ2291
++006416        015560          0 8192 -ZZ1291
++006417        217400          0 ZZ2291
+-       mark 1170, -123        /17 erid
++006420        777410          ZZ2292=ZZ2292+ZZ2292
++006420        777020          ZZ2292=ZZ2292+ZZ2292
++006420        776040          ZZ2292=ZZ2292+ZZ2292
++006420        774100          ZZ2292=ZZ2292+ZZ2292
++006420        770200          ZZ2292=ZZ2292+ZZ2292
++006420        760400          ZZ2292=ZZ2292+ZZ2292
++006420        741000          ZZ2292=ZZ2292+ZZ2292
++006420        702000          ZZ2292=ZZ2292+ZZ2292
++006420        015556          0 8192 -ZZ1292
++006421        702000          0 ZZ2292
+-       mark 1185, -223        /18 erid
++006422        777100          ZZ2293=ZZ2293+ZZ2293
++006422        776200          ZZ2293=ZZ2293+ZZ2293
++006422        774400          ZZ2293=ZZ2293+ZZ2293
++006422        771000          ZZ2293=ZZ2293+ZZ2293
++006422        762000          ZZ2293=ZZ2293+ZZ2293
++006422        744000          ZZ2293=ZZ2293+ZZ2293
++006422        710000          ZZ2293=ZZ2293+ZZ2293
++006422        620000          ZZ2293=ZZ2293+ZZ2293
++006422        015537          0 8192 -ZZ1293
++006423        620000          0 ZZ2293
+-       mark 1191, -500        /19 erid
++006424        776026          ZZ2294=ZZ2294+ZZ2294
++006424        774054          ZZ2294=ZZ2294+ZZ2294
++006424        770130          ZZ2294=ZZ2294+ZZ2294
++006424        760260          ZZ2294=ZZ2294+ZZ2294
++006424        740540          ZZ2294=ZZ2294+ZZ2294
++006424        701300          ZZ2294=ZZ2294+ZZ2294
++006424        602600          ZZ2294=ZZ2294+ZZ2294
++006424        405400          ZZ2294=ZZ2294+ZZ2294
++006424        015531          0 8192 -ZZ1294
++006425        405400          0 ZZ2294
+-       mark 1205, 2           /10 taur
++006426        000004          ZZ2295=ZZ2295+ZZ2295
++006426        000010          ZZ2295=ZZ2295+ZZ2295
++006426        000020          ZZ2295=ZZ2295+ZZ2295
++006426        000040          ZZ2295=ZZ2295+ZZ2295
++006426        000100          ZZ2295=ZZ2295+ZZ2295
++006426        000200          ZZ2295=ZZ2295+ZZ2295
++006426        000400          ZZ2295=ZZ2295+ZZ2295
++006426        001000          ZZ2295=ZZ2295+ZZ2295
++006426        015513          0 8192 -ZZ1295
++006427        001000          0 ZZ2295
+-       mark 1260, -283        /26 erid
++006430        776710          ZZ2296=ZZ2296+ZZ2296
++006430        775620          ZZ2296=ZZ2296+ZZ2296
++006430        773440          ZZ2296=ZZ2296+ZZ2296
++006430        767100          ZZ2296=ZZ2296+ZZ2296
++006430        756200          ZZ2296=ZZ2296+ZZ2296
++006430        734400          ZZ2296=ZZ2296+ZZ2296
++006430        671000          ZZ2296=ZZ2296+ZZ2296
++006430        562000          ZZ2296=ZZ2296+ZZ2296
++006430        015424          0 8192 -ZZ1296
++006431        562000          0 ZZ2296
+-       mark 1304, -74         /32 erid
++006432        777552          ZZ2297=ZZ2297+ZZ2297
++006432        777324          ZZ2297=ZZ2297+ZZ2297
++006432        776650          ZZ2297=ZZ2297+ZZ2297
++006432        775520          ZZ2297=ZZ2297+ZZ2297
++006432        773240          ZZ2297=ZZ2297+ZZ2297
++006432        766500          ZZ2297=ZZ2297+ZZ2297
++006432        755200          ZZ2297=ZZ2297+ZZ2297
++006432        732400          ZZ2297=ZZ2297+ZZ2297
++006432        015350          0 8192 -ZZ1297
++006433        732400          0 ZZ2297
+-       mark 1338, 278         /35 taur
++006434        001054          ZZ2298=ZZ2298+ZZ2298
++006434        002130          ZZ2298=ZZ2298+ZZ2298
++006434        004260          ZZ2298=ZZ2298+ZZ2298
++006434        010540          ZZ2298=ZZ2298+ZZ2298
++006434        021300          ZZ2298=ZZ2298+ZZ2298
++006434        042600          ZZ2298=ZZ2298+ZZ2298
++006434        105400          ZZ2298=ZZ2298+ZZ2298
++006434        213000          ZZ2298=ZZ2298+ZZ2298
++006434        015306          0 8192 -ZZ1298
++006435        213000          0 ZZ2298
+-       mark 1353, 130         /38 taur
++006436        000404          ZZ2299=ZZ2299+ZZ2299
++006436        001010          ZZ2299=ZZ2299+ZZ2299
++006436        002020          ZZ2299=ZZ2299+ZZ2299
++006436        004040          ZZ2299=ZZ2299+ZZ2299
++006436        010100          ZZ2299=ZZ2299+ZZ2299
++006436        020200          ZZ2299=ZZ2299+ZZ2299
++006436        040400          ZZ2299=ZZ2299+ZZ2299
++006436        101000          ZZ2299=ZZ2299+ZZ2299
++006436        015267          0 8192 -ZZ1299
++006437        101000          0 ZZ2299
+-       mark 1358, 497         /37 taur
++006440        001742          ZZ2300=ZZ2300+ZZ2300
++006440        003704          ZZ2300=ZZ2300+ZZ2300
++006440        007610          ZZ2300=ZZ2300+ZZ2300
++006440        017420          ZZ2300=ZZ2300+ZZ2300
++006440        037040          ZZ2300=ZZ2300+ZZ2300
++006440        076100          ZZ2300=ZZ2300+ZZ2300
++006440        174200          ZZ2300=ZZ2300+ZZ2300
++006440        370400          ZZ2300=ZZ2300+ZZ2300
++006440        015262          0 8192 -ZZ1300
++006441        370400          0 ZZ2300
+-       mark 1405, -162        /38 erid
++006442        777272          ZZ2301=ZZ2301+ZZ2301
++006442        776564          ZZ2301=ZZ2301+ZZ2301
++006442        775350          ZZ2301=ZZ2301+ZZ2301
++006442        772720          ZZ2301=ZZ2301+ZZ2301
++006442        765640          ZZ2301=ZZ2301+ZZ2301
++006442        753500          ZZ2301=ZZ2301+ZZ2301
++006442        727200          ZZ2301=ZZ2301+ZZ2301
++006442        656400          ZZ2301=ZZ2301+ZZ2301
++006442        015203          0 8192 -ZZ1301
++006443        656400          0 ZZ2301
+-       mark 1414,  205        /47 taur
++006444        000632          ZZ2302=ZZ2302+ZZ2302
++006444        001464          ZZ2302=ZZ2302+ZZ2302
++006444        003150          ZZ2302=ZZ2302+ZZ2302
++006444        006320          ZZ2302=ZZ2302+ZZ2302
++006444        014640          ZZ2302=ZZ2302+ZZ2302
++006444        031500          ZZ2302=ZZ2302+ZZ2302
++006444        063200          ZZ2302=ZZ2302+ZZ2302
++006444        146400          ZZ2302=ZZ2302+ZZ2302
++006444        015172          0 8192 -ZZ1302
++006445        146400          0 ZZ2302
+-       mark 1423, 197         /49 taur
++006446        000612          ZZ2303=ZZ2303+ZZ2303
++006446        001424          ZZ2303=ZZ2303+ZZ2303
++006446        003050          ZZ2303=ZZ2303+ZZ2303
++006446        006120          ZZ2303=ZZ2303+ZZ2303
++006446        014240          ZZ2303=ZZ2303+ZZ2303
++006446        030500          ZZ2303=ZZ2303+ZZ2303
++006446        061200          ZZ2303=ZZ2303+ZZ2303
++006446        142400          ZZ2303=ZZ2303+ZZ2303
++006446        015161          0 8192 -ZZ1303
++006447        142400          0 ZZ2303
+-       mark 1426, -178        /40 erid
++006450        777232          ZZ2304=ZZ2304+ZZ2304
++006450        776464          ZZ2304=ZZ2304+ZZ2304
++006450        775150          ZZ2304=ZZ2304+ZZ2304
++006450        772320          ZZ2304=ZZ2304+ZZ2304
++006450        764640          ZZ2304=ZZ2304+ZZ2304
++006450        751500          ZZ2304=ZZ2304+ZZ2304
++006450        723200          ZZ2304=ZZ2304+ZZ2304
++006450        646400          ZZ2304=ZZ2304+ZZ2304
++006450        015156          0 8192 -ZZ1304
++006451        646400          0 ZZ2304
+-       mark 1430, 463         /50 taur
++006452        001636          ZZ2305=ZZ2305+ZZ2305
++006452        003474          ZZ2305=ZZ2305+ZZ2305
++006452        007170          ZZ2305=ZZ2305+ZZ2305
++006452        016360          ZZ2305=ZZ2305+ZZ2305
++006452        034740          ZZ2305=ZZ2305+ZZ2305
++006452        071700          ZZ2305=ZZ2305+ZZ2305
++006452        163600          ZZ2305=ZZ2305+ZZ2305
++006452        347400          ZZ2305=ZZ2305+ZZ2305
++006452        015152          0 8192 -ZZ1305
++006453        347400          0 ZZ2305
+-       mark 1446, 350         /54 taur
++006454        001274          ZZ2306=ZZ2306+ZZ2306
++006454        002570          ZZ2306=ZZ2306+ZZ2306
++006454        005360          ZZ2306=ZZ2306+ZZ2306
++006454        012740          ZZ2306=ZZ2306+ZZ2306
++006454        025700          ZZ2306=ZZ2306+ZZ2306
++006454        053600          ZZ2306=ZZ2306+ZZ2306
++006454        127400          ZZ2306=ZZ2306+ZZ2306
++006454        257000          ZZ2306=ZZ2306+ZZ2306
++006454        015132          0 8192 -ZZ1306
++006455        257000          0 ZZ2306
+-       mark 1463, 394         /61 taur
++006456        001424          ZZ2307=ZZ2307+ZZ2307
++006456        003050          ZZ2307=ZZ2307+ZZ2307
++006456        006120          ZZ2307=ZZ2307+ZZ2307
++006456        014240          ZZ2307=ZZ2307+ZZ2307
++006456        030500          ZZ2307=ZZ2307+ZZ2307
++006456        061200          ZZ2307=ZZ2307+ZZ2307
++006456        142400          ZZ2307=ZZ2307+ZZ2307
++006456        305000          ZZ2307=ZZ2307+ZZ2307
++006456        015111          0 8192 -ZZ1307
++006457        305000          0 ZZ2307
+-       mark 1470, 392         /64 taur
++006460        001420          ZZ2308=ZZ2308+ZZ2308
++006460        003040          ZZ2308=ZZ2308+ZZ2308
++006460        006100          ZZ2308=ZZ2308+ZZ2308
++006460        014200          ZZ2308=ZZ2308+ZZ2308
++006460        030400          ZZ2308=ZZ2308+ZZ2308
++006460        061000          ZZ2308=ZZ2308+ZZ2308
++006460        142000          ZZ2308=ZZ2308+ZZ2308
++006460        304000          ZZ2308=ZZ2308+ZZ2308
++006460        015102          0 8192 -ZZ1308
++006461        304000          0 ZZ2308
+-       mark 1476, 502         /65 taur
++006462        001754          ZZ2309=ZZ2309+ZZ2309
++006462        003730          ZZ2309=ZZ2309+ZZ2309
++006462        007660          ZZ2309=ZZ2309+ZZ2309
++006462        017540          ZZ2309=ZZ2309+ZZ2309
++006462        037300          ZZ2309=ZZ2309+ZZ2309
++006462        076600          ZZ2309=ZZ2309+ZZ2309
++006462        175400          ZZ2309=ZZ2309+ZZ2309
++006462        373000          ZZ2309=ZZ2309+ZZ2309
++006462        015074          0 8192 -ZZ1309
++006463        373000          0 ZZ2309
+-       mark 1477, 403         /68 taur
++006464        001446          ZZ2310=ZZ2310+ZZ2310
++006464        003114          ZZ2310=ZZ2310+ZZ2310
++006464        006230          ZZ2310=ZZ2310+ZZ2310
++006464        014460          ZZ2310=ZZ2310+ZZ2310
++006464        031140          ZZ2310=ZZ2310+ZZ2310
++006464        062300          ZZ2310=ZZ2310+ZZ2310
++006464        144600          ZZ2310=ZZ2310+ZZ2310
++006464        311400          ZZ2310=ZZ2310+ZZ2310
++006464        015073          0 8192 -ZZ1310
++006465        311400          0 ZZ2310
+-       mark 1483, 350         /71 taur
++006466        001274          ZZ2311=ZZ2311+ZZ2311
++006466        002570          ZZ2311=ZZ2311+ZZ2311
++006466        005360          ZZ2311=ZZ2311+ZZ2311
++006466        012740          ZZ2311=ZZ2311+ZZ2311
++006466        025700          ZZ2311=ZZ2311+ZZ2311
++006466        053600          ZZ2311=ZZ2311+ZZ2311
++006466        127400          ZZ2311=ZZ2311+ZZ2311
++006466        257000          ZZ2311=ZZ2311+ZZ2311
++006466        015065          0 8192 -ZZ1311
++006467        257000          0 ZZ2311
+-       mark 1485, 330         /73 taur
++006470        001224          ZZ2312=ZZ2312+ZZ2312
++006470        002450          ZZ2312=ZZ2312+ZZ2312
++006470        005120          ZZ2312=ZZ2312+ZZ2312
++006470        012240          ZZ2312=ZZ2312+ZZ2312
++006470        024500          ZZ2312=ZZ2312+ZZ2312
++006470        051200          ZZ2312=ZZ2312+ZZ2312
++006470        122400          ZZ2312=ZZ2312+ZZ2312
++006470        245000          ZZ2312=ZZ2312+ZZ2312
++006470        015063          0 8192 -ZZ1312
++006471        245000          0 ZZ2312
+-       mark 1495, 358         /77 taur
++006472        001314          ZZ2313=ZZ2313+ZZ2313
++006472        002630          ZZ2313=ZZ2313+ZZ2313
++006472        005460          ZZ2313=ZZ2313+ZZ2313
++006472        013140          ZZ2313=ZZ2313+ZZ2313
++006472        026300          ZZ2313=ZZ2313+ZZ2313
++006472        054600          ZZ2313=ZZ2313+ZZ2313
++006472        131400          ZZ2313=ZZ2313+ZZ2313
++006472        263000          ZZ2313=ZZ2313+ZZ2313
++006472        015051          0 8192 -ZZ1313
++006473        263000          0 ZZ2313
+-       mark 1507, 364         /
++006474        001330          ZZ2314=ZZ2314+ZZ2314
++006474        002660          ZZ2314=ZZ2314+ZZ2314
++006474        005540          ZZ2314=ZZ2314+ZZ2314
++006474        013300          ZZ2314=ZZ2314+ZZ2314
++006474        026600          ZZ2314=ZZ2314+ZZ2314
++006474        055400          ZZ2314=ZZ2314+ZZ2314
++006474        133000          ZZ2314=ZZ2314+ZZ2314
++006474        266000          ZZ2314=ZZ2314+ZZ2314
++006474        015035          0 8192 -ZZ1314
++006475        266000          0 ZZ2314
+-       mark 1518, -6          /45 erid
++006476        777762          ZZ2315=ZZ2315+ZZ2315
++006476        777744          ZZ2315=ZZ2315+ZZ2315
++006476        777710          ZZ2315=ZZ2315+ZZ2315
++006476        777620          ZZ2315=ZZ2315+ZZ2315
++006476        777440          ZZ2315=ZZ2315+ZZ2315
++006476        777100          ZZ2315=ZZ2315+ZZ2315
++006476        776200          ZZ2315=ZZ2315+ZZ2315
++006476        774400          ZZ2315=ZZ2315+ZZ2315
++006476        015022          0 8192 -ZZ1315
++006477        774400          0 ZZ2315
+-       mark 1526, 333         /86 taur
++006500        001232          ZZ2316=ZZ2316+ZZ2316
++006500        002464          ZZ2316=ZZ2316+ZZ2316
++006500        005150          ZZ2316=ZZ2316+ZZ2316
++006500        012320          ZZ2316=ZZ2316+ZZ2316
++006500        024640          ZZ2316=ZZ2316+ZZ2316
++006500        051500          ZZ2316=ZZ2316+ZZ2316
++006500        123200          ZZ2316=ZZ2316+ZZ2316
++006500        246400          ZZ2316=ZZ2316+ZZ2316
++006500        015012          0 8192 -ZZ1316
++006501        246400          0 ZZ2316
+-       mark 1537, 226         /88 taur
++006502        000704          ZZ2317=ZZ2317+ZZ2317
++006502        001610          ZZ2317=ZZ2317+ZZ2317
++006502        003420          ZZ2317=ZZ2317+ZZ2317
++006502        007040          ZZ2317=ZZ2317+ZZ2317
++006502        016100          ZZ2317=ZZ2317+ZZ2317
++006502        034200          ZZ2317=ZZ2317+ZZ2317
++006502        070400          ZZ2317=ZZ2317+ZZ2317
++006502        161000          ZZ2317=ZZ2317+ZZ2317
++006502        014777          0 8192 -ZZ1317
++006503        161000          0 ZZ2317
+-       mark 1544, -81         /48 erid
++006504        777534          ZZ2318=ZZ2318+ZZ2318
++006504        777270          ZZ2318=ZZ2318+ZZ2318
++006504        776560          ZZ2318=ZZ2318+ZZ2318
++006504        775340          ZZ2318=ZZ2318+ZZ2318
++006504        772700          ZZ2318=ZZ2318+ZZ2318
++006504        765600          ZZ2318=ZZ2318+ZZ2318
++006504        753400          ZZ2318=ZZ2318+ZZ2318
++006504        727000          ZZ2318=ZZ2318+ZZ2318
++006504        014770          0 8192 -ZZ1318
++006505        727000          0 ZZ2318
+-       mark 1551, 280         /90 taur
++006506        001060          ZZ2319=ZZ2319+ZZ2319
++006506        002140          ZZ2319=ZZ2319+ZZ2319
++006506        004300          ZZ2319=ZZ2319+ZZ2319
++006506        010600          ZZ2319=ZZ2319+ZZ2319
++006506        021400          ZZ2319=ZZ2319+ZZ2319
++006506        043000          ZZ2319=ZZ2319+ZZ2319
++006506        106000          ZZ2319=ZZ2319+ZZ2319
++006506        214000          ZZ2319=ZZ2319+ZZ2319
++006506        014761          0 8192 -ZZ1319
++006507        214000          0 ZZ2319
+-       mark 1556, 358         /92 taur
++006510        001314          ZZ2320=ZZ2320+ZZ2320
++006510        002630          ZZ2320=ZZ2320+ZZ2320
++006510        005460          ZZ2320=ZZ2320+ZZ2320
++006510        013140          ZZ2320=ZZ2320+ZZ2320
++006510        026300          ZZ2320=ZZ2320+ZZ2320
++006510        054600          ZZ2320=ZZ2320+ZZ2320
++006510        131400          ZZ2320=ZZ2320+ZZ2320
++006510        263000          ZZ2320=ZZ2320+ZZ2320
++006510        014754          0 8192 -ZZ1320
++006511        263000          0 ZZ2320
+-       mark 1557, -330        /53 erid
++006512        776552          ZZ2321=ZZ2321+ZZ2321
++006512        775324          ZZ2321=ZZ2321+ZZ2321
++006512        772650          ZZ2321=ZZ2321+ZZ2321
++006512        765520          ZZ2321=ZZ2321+ZZ2321
++006512        753240          ZZ2321=ZZ2321+ZZ2321
++006512        726500          ZZ2321=ZZ2321+ZZ2321
++006512        655200          ZZ2321=ZZ2321+ZZ2321
++006512        532400          ZZ2321=ZZ2321+ZZ2321
++006512        014753          0 8192 -ZZ1321
++006513        532400          0 ZZ2321
+-       mark 1571, -452        /54 erid
++006514        776166          ZZ2322=ZZ2322+ZZ2322
++006514        774354          ZZ2322=ZZ2322+ZZ2322
++006514        770730          ZZ2322=ZZ2322+ZZ2322
++006514        761660          ZZ2322=ZZ2322+ZZ2322
++006514        743540          ZZ2322=ZZ2322+ZZ2322
++006514        707300          ZZ2322=ZZ2322+ZZ2322
++006514        616600          ZZ2322=ZZ2322+ZZ2322
++006514        435400          ZZ2322=ZZ2322+ZZ2322
++006514        014735          0 8192 -ZZ1322
++006515        435400          0 ZZ2322
+-       mark 1596, -78         /57 erid
++006516        777542          ZZ2323=ZZ2323+ZZ2323
++006516        777304          ZZ2323=ZZ2323+ZZ2323
++006516        776610          ZZ2323=ZZ2323+ZZ2323
++006516        775420          ZZ2323=ZZ2323+ZZ2323
++006516        773040          ZZ2323=ZZ2323+ZZ2323
++006516        766100          ZZ2323=ZZ2323+ZZ2323
++006516        754200          ZZ2323=ZZ2323+ZZ2323
++006516        730400          ZZ2323=ZZ2323+ZZ2323
++006516        014704          0 8192 -ZZ1323
++006517        730400          0 ZZ2323
+-       mark 1622, 199         / 2 orio
++006520        000616          ZZ2324=ZZ2324+ZZ2324
++006520        001434          ZZ2324=ZZ2324+ZZ2324
++006520        003070          ZZ2324=ZZ2324+ZZ2324
++006520        006160          ZZ2324=ZZ2324+ZZ2324
++006520        014340          ZZ2324=ZZ2324+ZZ2324
++006520        030700          ZZ2324=ZZ2324+ZZ2324
++006520        061600          ZZ2324=ZZ2324+ZZ2324
++006520        143400          ZZ2324=ZZ2324+ZZ2324
++006520        014652          0 8192 -ZZ1324
++006521        143400          0 ZZ2324
+-       mark 1626, 124         / 3 orio
++006522        000370          ZZ2325=ZZ2325+ZZ2325
++006522        000760          ZZ2325=ZZ2325+ZZ2325
++006522        001740          ZZ2325=ZZ2325+ZZ2325
++006522        003700          ZZ2325=ZZ2325+ZZ2325
++006522        007600          ZZ2325=ZZ2325+ZZ2325
++006522        017400          ZZ2325=ZZ2325+ZZ2325
++006522        037000          ZZ2325=ZZ2325+ZZ2325
++006522        076000          ZZ2325=ZZ2325+ZZ2325
++006522        014646          0 8192 -ZZ1325
++006523        076000          0 ZZ2325
+-       mark 1638, -128        /61 erid
++006524        777376          ZZ2326=ZZ2326+ZZ2326
++006524        776774          ZZ2326=ZZ2326+ZZ2326
++006524        775770          ZZ2326=ZZ2326+ZZ2326
++006524        773760          ZZ2326=ZZ2326+ZZ2326
++006524        767740          ZZ2326=ZZ2326+ZZ2326
++006524        757700          ZZ2326=ZZ2326+ZZ2326
++006524        737600          ZZ2326=ZZ2326+ZZ2326
++006524        677400          ZZ2326=ZZ2326+ZZ2326
++006524        014632          0 8192 -ZZ1326
++006525        677400          0 ZZ2326
+-       mark 1646, 228         / 7 orio
++006526        000710          ZZ2327=ZZ2327+ZZ2327
++006526        001620          ZZ2327=ZZ2327+ZZ2327
++006526        003440          ZZ2327=ZZ2327+ZZ2327
++006526        007100          ZZ2327=ZZ2327+ZZ2327
++006526        016200          ZZ2327=ZZ2327+ZZ2327
++006526        034400          ZZ2327=ZZ2327+ZZ2327
++006526        071000          ZZ2327=ZZ2327+ZZ2327
++006526        162000          ZZ2327=ZZ2327+ZZ2327
++006526        014622          0 8192 -ZZ1327
++006527        162000          0 ZZ2327
+-       mark 1654, 304         / 9 orio
++006530        001140          ZZ2328=ZZ2328+ZZ2328
++006530        002300          ZZ2328=ZZ2328+ZZ2328
++006530        004600          ZZ2328=ZZ2328+ZZ2328
++006530        011400          ZZ2328=ZZ2328+ZZ2328
++006530        023000          ZZ2328=ZZ2328+ZZ2328
++006530        046000          ZZ2328=ZZ2328+ZZ2328
++006530        114000          ZZ2328=ZZ2328+ZZ2328
++006530        230000          ZZ2328=ZZ2328+ZZ2328
++006530        014612          0 8192 -ZZ1328
++006531        230000          0 ZZ2328
+-       mark 1669, 36          /10 orio
++006532        000110          ZZ2329=ZZ2329+ZZ2329
++006532        000220          ZZ2329=ZZ2329+ZZ2329
++006532        000440          ZZ2329=ZZ2329+ZZ2329
++006532        001100          ZZ2329=ZZ2329+ZZ2329
++006532        002200          ZZ2329=ZZ2329+ZZ2329
++006532        004400          ZZ2329=ZZ2329+ZZ2329
++006532        011000          ZZ2329=ZZ2329+ZZ2329
++006532        022000          ZZ2329=ZZ2329+ZZ2329
++006532        014573          0 8192 -ZZ1329
++006533        022000          0 ZZ2329
+-       mark 1680, -289        /64 erid
++006534        776674          ZZ2330=ZZ2330+ZZ2330
++006534        775570          ZZ2330=ZZ2330+ZZ2330
++006534        773360          ZZ2330=ZZ2330+ZZ2330
++006534        766740          ZZ2330=ZZ2330+ZZ2330
++006534        755700          ZZ2330=ZZ2330+ZZ2330
++006534        733600          ZZ2330=ZZ2330+ZZ2330
++006534        667400          ZZ2330=ZZ2330+ZZ2330
++006534        557000          ZZ2330=ZZ2330+ZZ2330
++006534        014560          0 8192 -ZZ1330
++006535        557000          0 ZZ2330
+-       mark 1687, -167        /65 erid
++006536        777260          ZZ2331=ZZ2331+ZZ2331
++006536        776540          ZZ2331=ZZ2331+ZZ2331
++006536        775300          ZZ2331=ZZ2331+ZZ2331
++006536        772600          ZZ2331=ZZ2331+ZZ2331
++006536        765400          ZZ2331=ZZ2331+ZZ2331
++006536        753000          ZZ2331=ZZ2331+ZZ2331
++006536        726000          ZZ2331=ZZ2331+ZZ2331
++006536        654000          ZZ2331=ZZ2331+ZZ2331
++006536        014551          0 8192 -ZZ1331
++006537        654000          0 ZZ2331
+-       mark 1690, -460        /
++006540        776146          ZZ2332=ZZ2332+ZZ2332
++006540        774314          ZZ2332=ZZ2332+ZZ2332
++006540        770630          ZZ2332=ZZ2332+ZZ2332
++006540        761460          ZZ2332=ZZ2332+ZZ2332
++006540        743140          ZZ2332=ZZ2332+ZZ2332
++006540        706300          ZZ2332=ZZ2332+ZZ2332
++006540        614600          ZZ2332=ZZ2332+ZZ2332
++006540        431400          ZZ2332=ZZ2332+ZZ2332
++006540        014546          0 8192 -ZZ1332
++006541        431400          0 ZZ2332
+-       mark 1690, 488         /102 taur
++006542        001720          ZZ2333=ZZ2333+ZZ2333
++006542        003640          ZZ2333=ZZ2333+ZZ2333
++006542        007500          ZZ2333=ZZ2333+ZZ2333
++006542        017200          ZZ2333=ZZ2333+ZZ2333
++006542        036400          ZZ2333=ZZ2333+ZZ2333
++006542        075000          ZZ2333=ZZ2333+ZZ2333
++006542        172000          ZZ2333=ZZ2333+ZZ2333
++006542        364000          ZZ2333=ZZ2333+ZZ2333
++006542        014546          0 8192 -ZZ1333
++006543        364000          0 ZZ2333
+-       mark 1700, 347         /11 orio
++006544        001266          ZZ2334=ZZ2334+ZZ2334
++006544        002554          ZZ2334=ZZ2334+ZZ2334
++006544        005330          ZZ2334=ZZ2334+ZZ2334
++006544        012660          ZZ2334=ZZ2334+ZZ2334
++006544        025540          ZZ2334=ZZ2334+ZZ2334
++006544        053300          ZZ2334=ZZ2334+ZZ2334
++006544        126600          ZZ2334=ZZ2334+ZZ2334
++006544        255400          ZZ2334=ZZ2334+ZZ2334
++006544        014534          0 8192 -ZZ1334
++006545        255400          0 ZZ2334
+-       mark 1729, 352         /15 orio
++006546        001300          ZZ2335=ZZ2335+ZZ2335
++006546        002600          ZZ2335=ZZ2335+ZZ2335
++006546        005400          ZZ2335=ZZ2335+ZZ2335
++006546        013000          ZZ2335=ZZ2335+ZZ2335
++006546        026000          ZZ2335=ZZ2335+ZZ2335
++006546        054000          ZZ2335=ZZ2335+ZZ2335
++006546        130000          ZZ2335=ZZ2335+ZZ2335
++006546        260000          ZZ2335=ZZ2335+ZZ2335
++006546        014477          0 8192 -ZZ1335
++006547        260000          0 ZZ2335
+-       mark 1732, -202        /69 erid
++006550        777152          ZZ2336=ZZ2336+ZZ2336
++006550        776324          ZZ2336=ZZ2336+ZZ2336
++006550        774650          ZZ2336=ZZ2336+ZZ2336
++006550        771520          ZZ2336=ZZ2336+ZZ2336
++006550        763240          ZZ2336=ZZ2336+ZZ2336
++006550        746500          ZZ2336=ZZ2336+ZZ2336
++006550        715200          ZZ2336=ZZ2336+ZZ2336
++006550        632400          ZZ2336=ZZ2336+ZZ2336
++006550        014474          0 8192 -ZZ1336
++006551        632400          0 ZZ2336
+-       mark 1750, -273        / 3 leps
++006552        776734          ZZ2337=ZZ2337+ZZ2337
++006552        775670          ZZ2337=ZZ2337+ZZ2337
++006552        773560          ZZ2337=ZZ2337+ZZ2337
++006552        767340          ZZ2337=ZZ2337+ZZ2337
++006552        756700          ZZ2337=ZZ2337+ZZ2337
++006552        735600          ZZ2337=ZZ2337+ZZ2337
++006552        673400          ZZ2337=ZZ2337+ZZ2337
++006552        567000          ZZ2337=ZZ2337+ZZ2337
++006552        014452          0 8192 -ZZ1337
++006553        567000          0 ZZ2337
+-       mark 1753, 63          /17 orio
++006554        000176          ZZ2338=ZZ2338+ZZ2338
++006554        000374          ZZ2338=ZZ2338+ZZ2338
++006554        000770          ZZ2338=ZZ2338+ZZ2338
++006554        001760          ZZ2338=ZZ2338+ZZ2338
++006554        003740          ZZ2338=ZZ2338+ZZ2338
++006554        007700          ZZ2338=ZZ2338+ZZ2338
++006554        017600          ZZ2338=ZZ2338+ZZ2338
++006554        037400          ZZ2338=ZZ2338+ZZ2338
++006554        014447          0 8192 -ZZ1338
++006555        037400          0 ZZ2338
+-       mark 1756, -297        / 4 leps
++006556        776654          ZZ2339=ZZ2339+ZZ2339
++006556        775530          ZZ2339=ZZ2339+ZZ2339
++006556        773260          ZZ2339=ZZ2339+ZZ2339
++006556        766540          ZZ2339=ZZ2339+ZZ2339
++006556        755300          ZZ2339=ZZ2339+ZZ2339
++006556        732600          ZZ2339=ZZ2339+ZZ2339
++006556        665400          ZZ2339=ZZ2339+ZZ2339
++006556        553000          ZZ2339=ZZ2339+ZZ2339
++006556        014444          0 8192 -ZZ1339
++006557        553000          0 ZZ2339
+-       mark 1792, -302        / 6 leps
++006560        776642          ZZ2340=ZZ2340+ZZ2340
++006560        775504          ZZ2340=ZZ2340+ZZ2340
++006560        773210          ZZ2340=ZZ2340+ZZ2340
++006560        766420          ZZ2340=ZZ2340+ZZ2340
++006560        755040          ZZ2340=ZZ2340+ZZ2340
++006560        732100          ZZ2340=ZZ2340+ZZ2340
++006560        664200          ZZ2340=ZZ2340+ZZ2340
++006560        550400          ZZ2340=ZZ2340+ZZ2340
++006560        014400          0 8192 -ZZ1340
++006561        550400          0 ZZ2340
+-       mark 1799, -486        /
++006562        776062          ZZ2341=ZZ2341+ZZ2341
++006562        774144          ZZ2341=ZZ2341+ZZ2341
++006562        770310          ZZ2341=ZZ2341+ZZ2341
++006562        760620          ZZ2341=ZZ2341+ZZ2341
++006562        741440          ZZ2341=ZZ2341+ZZ2341
++006562        703100          ZZ2341=ZZ2341+ZZ2341
++006562        606200          ZZ2341=ZZ2341+ZZ2341
++006562        414400          ZZ2341=ZZ2341+ZZ2341
++006562        014371          0 8192 -ZZ1341
++006563        414400          0 ZZ2341
+-       mark 1801, -11         /22 orio
++006564        777750          ZZ2342=ZZ2342+ZZ2342
++006564        777720          ZZ2342=ZZ2342+ZZ2342
++006564        777640          ZZ2342=ZZ2342+ZZ2342
++006564        777500          ZZ2342=ZZ2342+ZZ2342
++006564        777200          ZZ2342=ZZ2342+ZZ2342
++006564        776400          ZZ2342=ZZ2342+ZZ2342
++006564        775000          ZZ2342=ZZ2342+ZZ2342
++006564        772000          ZZ2342=ZZ2342+ZZ2342
++006564        014367          0 8192 -ZZ1342
++006565        772000          0 ZZ2342
+-       mark 1807, 79          /23 orio
++006566        000236          ZZ2343=ZZ2343+ZZ2343
++006566        000474          ZZ2343=ZZ2343+ZZ2343
++006566        001170          ZZ2343=ZZ2343+ZZ2343
++006566        002360          ZZ2343=ZZ2343+ZZ2343
++006566        004740          ZZ2343=ZZ2343+ZZ2343
++006566        011700          ZZ2343=ZZ2343+ZZ2343
++006566        023600          ZZ2343=ZZ2343+ZZ2343
++006566        047400          ZZ2343=ZZ2343+ZZ2343
++006566        014361          0 8192 -ZZ1343
++006567        047400          0 ZZ2343
+-       mark 1816, -180        /29 orio
++006570        777226          ZZ2344=ZZ2344+ZZ2344
++006570        776454          ZZ2344=ZZ2344+ZZ2344
++006570        775130          ZZ2344=ZZ2344+ZZ2344
++006570        772260          ZZ2344=ZZ2344+ZZ2344
++006570        764540          ZZ2344=ZZ2344+ZZ2344
++006570        751300          ZZ2344=ZZ2344+ZZ2344
++006570        722600          ZZ2344=ZZ2344+ZZ2344
++006570        645400          ZZ2344=ZZ2344+ZZ2344
++006570        014350          0 8192 -ZZ1344
++006571        645400          0 ZZ2344
+-       mark 1818, 40          /25 orio
++006572        000120          ZZ2345=ZZ2345+ZZ2345
++006572        000240          ZZ2345=ZZ2345+ZZ2345
++006572        000500          ZZ2345=ZZ2345+ZZ2345
++006572        001200          ZZ2345=ZZ2345+ZZ2345
++006572        002400          ZZ2345=ZZ2345+ZZ2345
++006572        005000          ZZ2345=ZZ2345+ZZ2345
++006572        012000          ZZ2345=ZZ2345+ZZ2345
++006572        024000          ZZ2345=ZZ2345+ZZ2345
++006572        014346          0 8192 -ZZ1345
++006573        024000          0 ZZ2345
+-       mark 1830, 497         /114 taur
++006574        001742          ZZ2346=ZZ2346+ZZ2346
++006574        003704          ZZ2346=ZZ2346+ZZ2346
++006574        007610          ZZ2346=ZZ2346+ZZ2346
++006574        017420          ZZ2346=ZZ2346+ZZ2346
++006574        037040          ZZ2346=ZZ2346+ZZ2346
++006574        076100          ZZ2346=ZZ2346+ZZ2346
++006574        174200          ZZ2346=ZZ2346+ZZ2346
++006574        370400          ZZ2346=ZZ2346+ZZ2346
++006574        014332          0 8192 -ZZ1346
++006575        370400          0 ZZ2346
+-       mark 1830, 69          /30 orio
++006576        000212          ZZ2347=ZZ2347+ZZ2347
++006576        000424          ZZ2347=ZZ2347+ZZ2347
++006576        001050          ZZ2347=ZZ2347+ZZ2347
++006576        002120          ZZ2347=ZZ2347+ZZ2347
++006576        004240          ZZ2347=ZZ2347+ZZ2347
++006576        010500          ZZ2347=ZZ2347+ZZ2347
++006576        021200          ZZ2347=ZZ2347+ZZ2347
++006576        042400          ZZ2347=ZZ2347+ZZ2347
++006576        014332          0 8192 -ZZ1347
++006577        042400          0 ZZ2347
+-       mark 1851, 134         /32 orio
++006600        000414          ZZ2348=ZZ2348+ZZ2348
++006600        001030          ZZ2348=ZZ2348+ZZ2348
++006600        002060          ZZ2348=ZZ2348+ZZ2348
++006600        004140          ZZ2348=ZZ2348+ZZ2348
++006600        010300          ZZ2348=ZZ2348+ZZ2348
++006600        020600          ZZ2348=ZZ2348+ZZ2348
++006600        041400          ZZ2348=ZZ2348+ZZ2348
++006600        103000          ZZ2348=ZZ2348+ZZ2348
++006600        014305          0 8192 -ZZ1348
++006601        103000          0 ZZ2348
+-       mark 1857, 421         /119 taur
++006602        001512          ZZ2349=ZZ2349+ZZ2349
++006602        003224          ZZ2349=ZZ2349+ZZ2349
++006602        006450          ZZ2349=ZZ2349+ZZ2349
++006602        015120          ZZ2349=ZZ2349+ZZ2349
++006602        032240          ZZ2349=ZZ2349+ZZ2349
++006602        064500          ZZ2349=ZZ2349+ZZ2349
++006602        151200          ZZ2349=ZZ2349+ZZ2349
++006602        322400          ZZ2349=ZZ2349+ZZ2349
++006602        014277          0 8192 -ZZ1349
++006603        322400          0 ZZ2349
+-       mark 1861, -168        /36 orio
++006604        777256          ZZ2350=ZZ2350+ZZ2350
++006604        776534          ZZ2350=ZZ2350+ZZ2350
++006604        775270          ZZ2350=ZZ2350+ZZ2350
++006604        772560          ZZ2350=ZZ2350+ZZ2350
++006604        765340          ZZ2350=ZZ2350+ZZ2350
++006604        752700          ZZ2350=ZZ2350+ZZ2350
++006604        725600          ZZ2350=ZZ2350+ZZ2350
++006604        653400          ZZ2350=ZZ2350+ZZ2350
++006604        014273          0 8192 -ZZ1350
++006605        653400          0 ZZ2350
+-       mark 1874, 214         /37 orio
++006606        000654          ZZ2351=ZZ2351+ZZ2351
++006606        001530          ZZ2351=ZZ2351+ZZ2351
++006606        003260          ZZ2351=ZZ2351+ZZ2351
++006606        006540          ZZ2351=ZZ2351+ZZ2351
++006606        015300          ZZ2351=ZZ2351+ZZ2351
++006606        032600          ZZ2351=ZZ2351+ZZ2351
++006606        065400          ZZ2351=ZZ2351+ZZ2351
++006606        153000          ZZ2351=ZZ2351+ZZ2351
++006606        014256          0 8192 -ZZ1351
++006607        153000          0 ZZ2351
+-       mark 1878, -132        /
++006610        777366          ZZ2352=ZZ2352+ZZ2352
++006610        776754          ZZ2352=ZZ2352+ZZ2352
++006610        775730          ZZ2352=ZZ2352+ZZ2352
++006610        773660          ZZ2352=ZZ2352+ZZ2352
++006610        767540          ZZ2352=ZZ2352+ZZ2352
++006610        757300          ZZ2352=ZZ2352+ZZ2352
++006610        736600          ZZ2352=ZZ2352+ZZ2352
++006610        675400          ZZ2352=ZZ2352+ZZ2352
++006610        014252          0 8192 -ZZ1352
++006611        675400          0 ZZ2352
+-       mark 1880, -112        /42 orio
++006612        777436          ZZ2353=ZZ2353+ZZ2353
++006612        777074          ZZ2353=ZZ2353+ZZ2353
++006612        776170          ZZ2353=ZZ2353+ZZ2353
++006612        774360          ZZ2353=ZZ2353+ZZ2353
++006612        770740          ZZ2353=ZZ2353+ZZ2353
++006612        761700          ZZ2353=ZZ2353+ZZ2353
++006612        743600          ZZ2353=ZZ2353+ZZ2353
++006612        707400          ZZ2353=ZZ2353+ZZ2353
++006612        014250          0 8192 -ZZ1353
++006613        707400          0 ZZ2353
+-       mark 1885, 210         /40 orio
++006614        000644          ZZ2354=ZZ2354+ZZ2354
++006614        001510          ZZ2354=ZZ2354+ZZ2354
++006614        003220          ZZ2354=ZZ2354+ZZ2354
++006614        006440          ZZ2354=ZZ2354+ZZ2354
++006614        015100          ZZ2354=ZZ2354+ZZ2354
++006614        032200          ZZ2354=ZZ2354+ZZ2354
++006614        064400          ZZ2354=ZZ2354+ZZ2354
++006614        151000          ZZ2354=ZZ2354+ZZ2354
++006614        014243          0 8192 -ZZ1354
++006615        151000          0 ZZ2354
+-       mark 1899,-60          /48 orio
++006616        777606          ZZ2355=ZZ2355+ZZ2355
++006616        777414          ZZ2355=ZZ2355+ZZ2355
++006616        777030          ZZ2355=ZZ2355+ZZ2355
++006616        776060          ZZ2355=ZZ2355+ZZ2355
++006616        774140          ZZ2355=ZZ2355+ZZ2355
++006616        770300          ZZ2355=ZZ2355+ZZ2355
++006616        760600          ZZ2355=ZZ2355+ZZ2355
++006616        741400          ZZ2355=ZZ2355+ZZ2355
++006616        014225          0 8192 -ZZ1355
++006617        741400          0 ZZ2355
+-       mark 1900, 93          /47 orio
++006620        000272          ZZ2356=ZZ2356+ZZ2356
++006620        000564          ZZ2356=ZZ2356+ZZ2356
++006620        001350          ZZ2356=ZZ2356+ZZ2356
++006620        002720          ZZ2356=ZZ2356+ZZ2356
++006620        005640          ZZ2356=ZZ2356+ZZ2356
++006620        013500          ZZ2356=ZZ2356+ZZ2356
++006620        027200          ZZ2356=ZZ2356+ZZ2356
++006620        056400          ZZ2356=ZZ2356+ZZ2356
++006620        014224          0 8192 -ZZ1356
++006621        056400          0 ZZ2356
+-       mark 1900, -165        /49 orio
++006622        777264          ZZ2357=ZZ2357+ZZ2357
++006622        776550          ZZ2357=ZZ2357+ZZ2357
++006622        775320          ZZ2357=ZZ2357+ZZ2357
++006622        772640          ZZ2357=ZZ2357+ZZ2357
++006622        765500          ZZ2357=ZZ2357+ZZ2357
++006622        753200          ZZ2357=ZZ2357+ZZ2357
++006622        726400          ZZ2357=ZZ2357+ZZ2357
++006622        655000          ZZ2357=ZZ2357+ZZ2357
++006622        014224          0 8192 -ZZ1357
++006623        655000          0 ZZ2357
+-       mark 1909, 375         /126 taur
++006624        001356          ZZ2358=ZZ2358+ZZ2358
++006624        002734          ZZ2358=ZZ2358+ZZ2358
++006624        005670          ZZ2358=ZZ2358+ZZ2358
++006624        013560          ZZ2358=ZZ2358+ZZ2358
++006624        027340          ZZ2358=ZZ2358+ZZ2358
++006624        056700          ZZ2358=ZZ2358+ZZ2358
++006624        135600          ZZ2358=ZZ2358+ZZ2358
++006624        273400          ZZ2358=ZZ2358+ZZ2358
++006624        014213          0 8192 -ZZ1358
++006625        273400          0 ZZ2358
+-       mark 1936, -511        /13 leps
++006626        776000          ZZ2359=ZZ2359+ZZ2359
++006626        774000          ZZ2359=ZZ2359+ZZ2359
++006626        770000          ZZ2359=ZZ2359+ZZ2359
++006626        760000          ZZ2359=ZZ2359+ZZ2359
++006626        740000          ZZ2359=ZZ2359+ZZ2359
++006626        700000          ZZ2359=ZZ2359+ZZ2359
++006626        600000          ZZ2359=ZZ2359+ZZ2359
++006626        400000          ZZ2359=ZZ2359+ZZ2359
++006626        014160          0 8192 -ZZ1359
++006627        400000          0 ZZ2359
+-       mark 1957, 287         /134 taur
++006630        001076          ZZ2360=ZZ2360+ZZ2360
++006630        002174          ZZ2360=ZZ2360+ZZ2360
++006630        004370          ZZ2360=ZZ2360+ZZ2360
++006630        010760          ZZ2360=ZZ2360+ZZ2360
++006630        021740          ZZ2360=ZZ2360+ZZ2360
++006630        043700          ZZ2360=ZZ2360+ZZ2360
++006630        107600          ZZ2360=ZZ2360+ZZ2360
++006630        217400          ZZ2360=ZZ2360+ZZ2360
++006630        014133          0 8192 -ZZ1360
++006631        217400          0 ZZ2360
+-       mark 1974, -475        /15 leps
++006632        776110          ZZ2361=ZZ2361+ZZ2361
++006632        774220          ZZ2361=ZZ2361+ZZ2361
++006632        770440          ZZ2361=ZZ2361+ZZ2361
++006632        761100          ZZ2361=ZZ2361+ZZ2361
++006632        742200          ZZ2361=ZZ2361+ZZ2361
++006632        704400          ZZ2361=ZZ2361+ZZ2361
++006632        611000          ZZ2361=ZZ2361+ZZ2361
++006632        422000          ZZ2361=ZZ2361+ZZ2361
++006632        014112          0 8192 -ZZ1361
++006633        422000          0 ZZ2361
+-       mark 1982, 461         /54 orio
++006634        001632          ZZ2362=ZZ2362+ZZ2362
++006634        003464          ZZ2362=ZZ2362+ZZ2362
++006634        007150          ZZ2362=ZZ2362+ZZ2362
++006634        016320          ZZ2362=ZZ2362+ZZ2362
++006634        034640          ZZ2362=ZZ2362+ZZ2362
++006634        071500          ZZ2362=ZZ2362+ZZ2362
++006634        163200          ZZ2362=ZZ2362+ZZ2362
++006634        346400          ZZ2362=ZZ2362+ZZ2362
++006634        014102          0 8192 -ZZ1362
++006635        346400          0 ZZ2362
+-       mark 2002, -323        /16 leps
++006636        776570          ZZ2363=ZZ2363+ZZ2363
++006636        775360          ZZ2363=ZZ2363+ZZ2363
++006636        772740          ZZ2363=ZZ2363+ZZ2363
++006636        765700          ZZ2363=ZZ2363+ZZ2363
++006636        753600          ZZ2363=ZZ2363+ZZ2363
++006636        727400          ZZ2363=ZZ2363+ZZ2363
++006636        657000          ZZ2363=ZZ2363+ZZ2363
++006636        536000          ZZ2363=ZZ2363+ZZ2363
++006636        014056          0 8192 -ZZ1363
++006637        536000          0 ZZ2363
+-       mark 2020, -70         /
++006640        777562          ZZ2364=ZZ2364+ZZ2364
++006640        777344          ZZ2364=ZZ2364+ZZ2364
++006640        776710          ZZ2364=ZZ2364+ZZ2364
++006640        775620          ZZ2364=ZZ2364+ZZ2364
++006640        773440          ZZ2364=ZZ2364+ZZ2364
++006640        767100          ZZ2364=ZZ2364+ZZ2364
++006640        756200          ZZ2364=ZZ2364+ZZ2364
++006640        734400          ZZ2364=ZZ2364+ZZ2364
++006640        014034          0 8192 -ZZ1364
++006641        734400          0 ZZ2364
+-       mark 2030, 220         /61 orio
++006642        000670          ZZ2365=ZZ2365+ZZ2365
++006642        001560          ZZ2365=ZZ2365+ZZ2365
++006642        003340          ZZ2365=ZZ2365+ZZ2365
++006642        006700          ZZ2365=ZZ2365+ZZ2365
++006642        015600          ZZ2365=ZZ2365+ZZ2365
++006642        033400          ZZ2365=ZZ2365+ZZ2365
++006642        067000          ZZ2365=ZZ2365+ZZ2365
++006642        156000          ZZ2365=ZZ2365+ZZ2365
++006642        014022          0 8192 -ZZ1365
++006643        156000          0 ZZ2365
+-       mark 2032, -241        / 3 mono
++006644        777034          ZZ2366=ZZ2366+ZZ2366
++006644        776070          ZZ2366=ZZ2366+ZZ2366
++006644        774160          ZZ2366=ZZ2366+ZZ2366
++006644        770340          ZZ2366=ZZ2366+ZZ2366
++006644        760700          ZZ2366=ZZ2366+ZZ2366
++006644        741600          ZZ2366=ZZ2366+ZZ2366
++006644        703400          ZZ2366=ZZ2366+ZZ2366
++006644        607000          ZZ2366=ZZ2366+ZZ2366
++006644        014020          0 8192 -ZZ1366
++006645        607000          0 ZZ2366
+-       mark 2037, 458         /62 orio
++006646        001624          ZZ2367=ZZ2367+ZZ2367
++006646        003450          ZZ2367=ZZ2367+ZZ2367
++006646        007120          ZZ2367=ZZ2367+ZZ2367
++006646        016240          ZZ2367=ZZ2367+ZZ2367
++006646        034500          ZZ2367=ZZ2367+ZZ2367
++006646        071200          ZZ2367=ZZ2367+ZZ2367
++006646        162400          ZZ2367=ZZ2367+ZZ2367
++006646        345000          ZZ2367=ZZ2367+ZZ2367
++006646        014013          0 8192 -ZZ1367
++006647        345000          0 ZZ2367
+-       mark 2057, -340        /18 leps
++006650        776526          ZZ2368=ZZ2368+ZZ2368
++006650        775254          ZZ2368=ZZ2368+ZZ2368
++006650        772530          ZZ2368=ZZ2368+ZZ2368
++006650        765260          ZZ2368=ZZ2368+ZZ2368
++006650        752540          ZZ2368=ZZ2368+ZZ2368
++006650        725300          ZZ2368=ZZ2368+ZZ2368
++006650        652600          ZZ2368=ZZ2368+ZZ2368
++006650        525400          ZZ2368=ZZ2368+ZZ2368
++006650        013767          0 8192 -ZZ1368
++006651        525400          0 ZZ2368
+-       mark 2059, 336         /67 orio
++006652        001240          ZZ2369=ZZ2369+ZZ2369
++006652        002500          ZZ2369=ZZ2369+ZZ2369
++006652        005200          ZZ2369=ZZ2369+ZZ2369
++006652        012400          ZZ2369=ZZ2369+ZZ2369
++006652        025000          ZZ2369=ZZ2369+ZZ2369
++006652        052000          ZZ2369=ZZ2369+ZZ2369
++006652        124000          ZZ2369=ZZ2369+ZZ2369
++006652        250000          ZZ2369=ZZ2369+ZZ2369
++006652        013765          0 8192 -ZZ1369
++006653        250000          0 ZZ2369
+-       mark 2084, 368         /69 orio
++006654        001340          ZZ2370=ZZ2370+ZZ2370
++006654        002700          ZZ2370=ZZ2370+ZZ2370
++006654        005600          ZZ2370=ZZ2370+ZZ2370
++006654        013400          ZZ2370=ZZ2370+ZZ2370
++006654        027000          ZZ2370=ZZ2370+ZZ2370
++006654        056000          ZZ2370=ZZ2370+ZZ2370
++006654        134000          ZZ2370=ZZ2370+ZZ2370
++006654        270000          ZZ2370=ZZ2370+ZZ2370
++006654        013734          0 8192 -ZZ1370
++006655        270000          0 ZZ2370
+-       mark 2084, 324         /70 orio
++006656        001210          ZZ2371=ZZ2371+ZZ2371
++006656        002420          ZZ2371=ZZ2371+ZZ2371
++006656        005040          ZZ2371=ZZ2371+ZZ2371
++006656        012100          ZZ2371=ZZ2371+ZZ2371
++006656        024200          ZZ2371=ZZ2371+ZZ2371
++006656        050400          ZZ2371=ZZ2371+ZZ2371
++006656        121000          ZZ2371=ZZ2371+ZZ2371
++006656        242000          ZZ2371=ZZ2371+ZZ2371
++006656        013734          0 8192 -ZZ1371
++006657        242000          0 ZZ2371
+-       mark 2105, -142        / 5 mono
++006660        777342          ZZ2372=ZZ2372+ZZ2372
++006660        776704          ZZ2372=ZZ2372+ZZ2372
++006660        775610          ZZ2372=ZZ2372+ZZ2372
++006660        773420          ZZ2372=ZZ2372+ZZ2372
++006660        767040          ZZ2372=ZZ2372+ZZ2372
++006660        756100          ZZ2372=ZZ2372+ZZ2372
++006660        734200          ZZ2372=ZZ2372+ZZ2372
++006660        670400          ZZ2372=ZZ2372+ZZ2372
++006660        013707          0 8192 -ZZ1372
++006661        670400          0 ZZ2372
+-       mark 2112, -311        /
++006662        776620          ZZ2373=ZZ2373+ZZ2373
++006662        775440          ZZ2373=ZZ2373+ZZ2373
++006662        773100          ZZ2373=ZZ2373+ZZ2373
++006662        766200          ZZ2373=ZZ2373+ZZ2373
++006662        754400          ZZ2373=ZZ2373+ZZ2373
++006662        731000          ZZ2373=ZZ2373+ZZ2373
++006662        662000          ZZ2373=ZZ2373+ZZ2373
++006662        544000          ZZ2373=ZZ2373+ZZ2373
++006662        013700          0 8192 -ZZ1373
++006663        544000          0 ZZ2373
+-       mark 2153, 106         / 8 mono
++006664        000324          ZZ2374=ZZ2374+ZZ2374
++006664        000650          ZZ2374=ZZ2374+ZZ2374
++006664        001520          ZZ2374=ZZ2374+ZZ2374
++006664        003240          ZZ2374=ZZ2374+ZZ2374
++006664        006500          ZZ2374=ZZ2374+ZZ2374
++006664        015200          ZZ2374=ZZ2374+ZZ2374
++006664        032400          ZZ2374=ZZ2374+ZZ2374
++006664        065000          ZZ2374=ZZ2374+ZZ2374
++006664        013627          0 8192 -ZZ1374
++006665        065000          0 ZZ2374
+-       mark 2179, 462         /18 gemi
++006666        001634          ZZ2375=ZZ2375+ZZ2375
++006666        003470          ZZ2375=ZZ2375+ZZ2375
++006666        007160          ZZ2375=ZZ2375+ZZ2375
++006666        016340          ZZ2375=ZZ2375+ZZ2375
++006666        034700          ZZ2375=ZZ2375+ZZ2375
++006666        071600          ZZ2375=ZZ2375+ZZ2375
++006666        163400          ZZ2375=ZZ2375+ZZ2375
++006666        347000          ZZ2375=ZZ2375+ZZ2375
++006666        013575          0 8192 -ZZ1375
++006667        347000          0 ZZ2375
+-       mark 2179, -107        /10 mono
++006670        777450          ZZ2376=ZZ2376+ZZ2376
++006670        777120          ZZ2376=ZZ2376+ZZ2376
++006670        776240          ZZ2376=ZZ2376+ZZ2376
++006670        774500          ZZ2376=ZZ2376+ZZ2376
++006670        771200          ZZ2376=ZZ2376+ZZ2376
++006670        762400          ZZ2376=ZZ2376+ZZ2376
++006670        745000          ZZ2376=ZZ2376+ZZ2376
++006670        712000          ZZ2376=ZZ2376+ZZ2376
++006670        013575          0 8192 -ZZ1376
++006671        712000          0 ZZ2376
+-       mark 2184, -159        /11 mono
++006672        777300          ZZ2377=ZZ2377+ZZ2377
++006672        776600          ZZ2377=ZZ2377+ZZ2377
++006672        775400          ZZ2377=ZZ2377+ZZ2377
++006672        773000          ZZ2377=ZZ2377+ZZ2377
++006672        766000          ZZ2377=ZZ2377+ZZ2377
++006672        754000          ZZ2377=ZZ2377+ZZ2377
++006672        730000          ZZ2377=ZZ2377+ZZ2377
++006672        660000          ZZ2377=ZZ2377+ZZ2377
++006672        013570          0 8192 -ZZ1377
++006673        660000          0 ZZ2377
+-       mark 2204, 168         /13 mono
++006674        000520          ZZ2378=ZZ2378+ZZ2378
++006674        001240          ZZ2378=ZZ2378+ZZ2378
++006674        002500          ZZ2378=ZZ2378+ZZ2378
++006674        005200          ZZ2378=ZZ2378+ZZ2378
++006674        012400          ZZ2378=ZZ2378+ZZ2378
++006674        025000          ZZ2378=ZZ2378+ZZ2378
++006674        052000          ZZ2378=ZZ2378+ZZ2378
++006674        124000          ZZ2378=ZZ2378+ZZ2378
++006674        013544          0 8192 -ZZ1378
++006675        124000          0 ZZ2378
+-       mark 2232, -436        / 7 cmaj
++006676        776226          ZZ2379=ZZ2379+ZZ2379
++006676        774454          ZZ2379=ZZ2379+ZZ2379
++006676        771130          ZZ2379=ZZ2379+ZZ2379
++006676        762260          ZZ2379=ZZ2379+ZZ2379
++006676        744540          ZZ2379=ZZ2379+ZZ2379
++006676        711300          ZZ2379=ZZ2379+ZZ2379
++006676        622600          ZZ2379=ZZ2379+ZZ2379
++006676        445400          ZZ2379=ZZ2379+ZZ2379
++006676        013510          0 8192 -ZZ1379
++006677        445400          0 ZZ2379
+-       mark 2239, -413        / 8 cmaj
++006700        776304          ZZ2380=ZZ2380+ZZ2380
++006700        774610          ZZ2380=ZZ2380+ZZ2380
++006700        771420          ZZ2380=ZZ2380+ZZ2380
++006700        763040          ZZ2380=ZZ2380+ZZ2380
++006700        746100          ZZ2380=ZZ2380+ZZ2380
++006700        714200          ZZ2380=ZZ2380+ZZ2380
++006700        630400          ZZ2380=ZZ2380+ZZ2380
++006700        461000          ZZ2380=ZZ2380+ZZ2380
++006700        013501          0 8192 -ZZ1380
++006701        461000          0 ZZ2380
+-       mark 2245, -320        /
++006702        776576          ZZ2381=ZZ2381+ZZ2381
++006702        775374          ZZ2381=ZZ2381+ZZ2381
++006702        772770          ZZ2381=ZZ2381+ZZ2381
++006702        765760          ZZ2381=ZZ2381+ZZ2381
++006702        753740          ZZ2381=ZZ2381+ZZ2381
++006702        727700          ZZ2381=ZZ2381+ZZ2381
++006702        657600          ZZ2381=ZZ2381+ZZ2381
++006702        537400          ZZ2381=ZZ2381+ZZ2381
++006702        013473          0 8192 -ZZ1381
++006703        537400          0 ZZ2381
+-       mark 2250, 227         /15 mono
++006704        000706          ZZ2382=ZZ2382+ZZ2382
++006704        001614          ZZ2382=ZZ2382+ZZ2382
++006704        003430          ZZ2382=ZZ2382+ZZ2382
++006704        007060          ZZ2382=ZZ2382+ZZ2382
++006704        016140          ZZ2382=ZZ2382+ZZ2382
++006704        034300          ZZ2382=ZZ2382+ZZ2382
++006704        070600          ZZ2382=ZZ2382+ZZ2382
++006704        161400          ZZ2382=ZZ2382+ZZ2382
++006704        013466          0 8192 -ZZ1382
++006705        161400          0 ZZ2382
+-       mark 2266, 303         /30 gemi
++006706        001136          ZZ2383=ZZ2383+ZZ2383
++006706        002274          ZZ2383=ZZ2383+ZZ2383
++006706        004570          ZZ2383=ZZ2383+ZZ2383
++006706        011360          ZZ2383=ZZ2383+ZZ2383
++006706        022740          ZZ2383=ZZ2383+ZZ2383
++006706        045700          ZZ2383=ZZ2383+ZZ2383
++006706        113600          ZZ2383=ZZ2383+ZZ2383
++006706        227400          ZZ2383=ZZ2383+ZZ2383
++006706        013446          0 8192 -ZZ1383
++006707        227400          0 ZZ2383
+-       mark 2291, 57          /18 mono
++006710        000162          ZZ2384=ZZ2384+ZZ2384
++006710        000344          ZZ2384=ZZ2384+ZZ2384
++006710        000710          ZZ2384=ZZ2384+ZZ2384
++006710        001620          ZZ2384=ZZ2384+ZZ2384
++006710        003440          ZZ2384=ZZ2384+ZZ2384
++006710        007100          ZZ2384=ZZ2384+ZZ2384
++006710        016200          ZZ2384=ZZ2384+ZZ2384
++006710        034400          ZZ2384=ZZ2384+ZZ2384
++006710        013415          0 8192 -ZZ1384
++006711        034400          0 ZZ2384
+-       mark 2327, 303         /38 gemi
++006712        001136          ZZ2385=ZZ2385+ZZ2385
++006712        002274          ZZ2385=ZZ2385+ZZ2385
++006712        004570          ZZ2385=ZZ2385+ZZ2385
++006712        011360          ZZ2385=ZZ2385+ZZ2385
++006712        022740          ZZ2385=ZZ2385+ZZ2385
++006712        045700          ZZ2385=ZZ2385+ZZ2385
++006712        113600          ZZ2385=ZZ2385+ZZ2385
++006712        227400          ZZ2385=ZZ2385+ZZ2385
++006712        013351          0 8192 -ZZ1385
++006713        227400          0 ZZ2385
+-       mark 2328, -457        /15 cmaj
++006714        776154          ZZ2386=ZZ2386+ZZ2386
++006714        774330          ZZ2386=ZZ2386+ZZ2386
++006714        770660          ZZ2386=ZZ2386+ZZ2386
++006714        761540          ZZ2386=ZZ2386+ZZ2386
++006714        743300          ZZ2386=ZZ2386+ZZ2386
++006714        706600          ZZ2386=ZZ2386+ZZ2386
++006714        615400          ZZ2386=ZZ2386+ZZ2386
++006714        433000          ZZ2386=ZZ2386+ZZ2386
++006714        013350          0 8192 -ZZ1386
++006715        433000          0 ZZ2386
+-       mark 2330, -271        /14 cmaj
++006716        776740          ZZ2387=ZZ2387+ZZ2387
++006716        775700          ZZ2387=ZZ2387+ZZ2387
++006716        773600          ZZ2387=ZZ2387+ZZ2387
++006716        767400          ZZ2387=ZZ2387+ZZ2387
++006716        757000          ZZ2387=ZZ2387+ZZ2387
++006716        736000          ZZ2387=ZZ2387+ZZ2387
++006716        674000          ZZ2387=ZZ2387+ZZ2387
++006716        570000          ZZ2387=ZZ2387+ZZ2387
++006716        013346          0 8192 -ZZ1387
++006717        570000          0 ZZ2387
+-       mark 2340, -456        /19 cmaj
++006720        776156          ZZ2388=ZZ2388+ZZ2388
++006720        774334          ZZ2388=ZZ2388+ZZ2388
++006720        770670          ZZ2388=ZZ2388+ZZ2388
++006720        761560          ZZ2388=ZZ2388+ZZ2388
++006720        743340          ZZ2388=ZZ2388+ZZ2388
++006720        706700          ZZ2388=ZZ2388+ZZ2388
++006720        615600          ZZ2388=ZZ2388+ZZ2388
++006720        433400          ZZ2388=ZZ2388+ZZ2388
++006720        013334          0 8192 -ZZ1388
++006721        433400          0 ZZ2388
+-       mark 2342, -385        /20 cmaj
++006722        776374          ZZ2389=ZZ2389+ZZ2389
++006722        774770          ZZ2389=ZZ2389+ZZ2389
++006722        771760          ZZ2389=ZZ2389+ZZ2389
++006722        763740          ZZ2389=ZZ2389+ZZ2389
++006722        747700          ZZ2389=ZZ2389+ZZ2389
++006722        717600          ZZ2389=ZZ2389+ZZ2389
++006722        637400          ZZ2389=ZZ2389+ZZ2389
++006722        477000          ZZ2389=ZZ2389+ZZ2389
++006722        013332          0 8192 -ZZ1389
++006723        477000          0 ZZ2389
+-       mark 2378, -93         /19 mono
++006724        777504          ZZ2390=ZZ2390+ZZ2390
++006724        777210          ZZ2390=ZZ2390+ZZ2390
++006724        776420          ZZ2390=ZZ2390+ZZ2390
++006724        775040          ZZ2390=ZZ2390+ZZ2390
++006724        772100          ZZ2390=ZZ2390+ZZ2390
++006724        764200          ZZ2390=ZZ2390+ZZ2390
++006724        750400          ZZ2390=ZZ2390+ZZ2390
++006724        721000          ZZ2390=ZZ2390+ZZ2390
++006724        013266          0 8192 -ZZ1390
++006725        721000          0 ZZ2390
+-       mark 2379, 471         /43 gemi
++006726        001656          ZZ2391=ZZ2391+ZZ2391
++006726        003534          ZZ2391=ZZ2391+ZZ2391
++006726        007270          ZZ2391=ZZ2391+ZZ2391
++006726        016560          ZZ2391=ZZ2391+ZZ2391
++006726        035340          ZZ2391=ZZ2391+ZZ2391
++006726        072700          ZZ2391=ZZ2391+ZZ2391
++006726        165600          ZZ2391=ZZ2391+ZZ2391
++006726        353400          ZZ2391=ZZ2391+ZZ2391
++006726        013265          0 8192 -ZZ1391
++006727        353400          0 ZZ2391
+-       mark 2385, -352        /23 cmaj
++006730        776476          ZZ2392=ZZ2392+ZZ2392
++006730        775174          ZZ2392=ZZ2392+ZZ2392
++006730        772370          ZZ2392=ZZ2392+ZZ2392
++006730        764760          ZZ2392=ZZ2392+ZZ2392
++006730        751740          ZZ2392=ZZ2392+ZZ2392
++006730        723700          ZZ2392=ZZ2392+ZZ2392
++006730        647600          ZZ2392=ZZ2392+ZZ2392
++006730        517400          ZZ2392=ZZ2392+ZZ2392
++006730        013257          0 8192 -ZZ1392
++006731        517400          0 ZZ2392
+-       mark 2428, -8          /22 mono
++006732        777756          ZZ2393=ZZ2393+ZZ2393
++006732        777734          ZZ2393=ZZ2393+ZZ2393
++006732        777670          ZZ2393=ZZ2393+ZZ2393
++006732        777560          ZZ2393=ZZ2393+ZZ2393
++006732        777340          ZZ2393=ZZ2393+ZZ2393
++006732        776700          ZZ2393=ZZ2393+ZZ2393
++006732        775600          ZZ2393=ZZ2393+ZZ2393
++006732        773400          ZZ2393=ZZ2393+ZZ2393
++006732        013204          0 8192 -ZZ1393
++006733        773400          0 ZZ2393
+-       mark 2491, -429        /
++006734        776244          ZZ2394=ZZ2394+ZZ2394
++006734        774510          ZZ2394=ZZ2394+ZZ2394
++006734        771220          ZZ2394=ZZ2394+ZZ2394
++006734        762440          ZZ2394=ZZ2394+ZZ2394
++006734        745100          ZZ2394=ZZ2394+ZZ2394
++006734        712200          ZZ2394=ZZ2394+ZZ2394
++006734        624400          ZZ2394=ZZ2394+ZZ2394
++006734        451000          ZZ2394=ZZ2394+ZZ2394
++006734        013105          0 8192 -ZZ1394
++006735        451000          0 ZZ2394
+-       mark 2519, 208         / 4 cmin
++006736        000640          ZZ2395=ZZ2395+ZZ2395
++006736        001500          ZZ2395=ZZ2395+ZZ2395
++006736        003200          ZZ2395=ZZ2395+ZZ2395
++006736        006400          ZZ2395=ZZ2395+ZZ2395
++006736        015000          ZZ2395=ZZ2395+ZZ2395
++006736        032000          ZZ2395=ZZ2395+ZZ2395
++006736        064000          ZZ2395=ZZ2395+ZZ2395
++006736        150000          ZZ2395=ZZ2395+ZZ2395
++006736        013051          0 8192 -ZZ1395
++006737        150000          0 ZZ2395
+-       mark 2527, 278         / 6 cmin
++006740        001054          ZZ2396=ZZ2396+ZZ2396
++006740        002130          ZZ2396=ZZ2396+ZZ2396
++006740        004260          ZZ2396=ZZ2396+ZZ2396
++006740        010540          ZZ2396=ZZ2396+ZZ2396
++006740        021300          ZZ2396=ZZ2396+ZZ2396
++006740        042600          ZZ2396=ZZ2396+ZZ2396
++006740        105400          ZZ2396=ZZ2396+ZZ2396
++006740        213000          ZZ2396=ZZ2396+ZZ2396
++006740        013041          0 8192 -ZZ1396
++006741        213000          0 ZZ2396
+-       mark 2559, -503        /
++006742        776020          ZZ2397=ZZ2397+ZZ2397
++006742        774040          ZZ2397=ZZ2397+ZZ2397
++006742        770100          ZZ2397=ZZ2397+ZZ2397
++006742        760200          ZZ2397=ZZ2397+ZZ2397
++006742        740400          ZZ2397=ZZ2397+ZZ2397
++006742        701000          ZZ2397=ZZ2397+ZZ2397
++006742        602000          ZZ2397=ZZ2397+ZZ2397
++006742        404000          ZZ2397=ZZ2397+ZZ2397
++006742        013001          0 8192 -ZZ1397
++006743        404000          0 ZZ2397
+-       mark 2597, -212        /26 mono
++006744        777126          ZZ2398=ZZ2398+ZZ2398
++006744        776254          ZZ2398=ZZ2398+ZZ2398
++006744        774530          ZZ2398=ZZ2398+ZZ2398
++006744        771260          ZZ2398=ZZ2398+ZZ2398
++006744        762540          ZZ2398=ZZ2398+ZZ2398
++006744        745300          ZZ2398=ZZ2398+ZZ2398
++006744        712600          ZZ2398=ZZ2398+ZZ2398
++006744        625400          ZZ2398=ZZ2398+ZZ2398
++006744        012733          0 8192 -ZZ1398
++006745        625400          0 ZZ2398
+-       mark 2704, -412        /
++006746        776306          ZZ2399=ZZ2399+ZZ2399
++006746        774614          ZZ2399=ZZ2399+ZZ2399
++006746        771430          ZZ2399=ZZ2399+ZZ2399
++006746        763060          ZZ2399=ZZ2399+ZZ2399
++006746        746140          ZZ2399=ZZ2399+ZZ2399
++006746        714300          ZZ2399=ZZ2399+ZZ2399
++006746        630600          ZZ2399=ZZ2399+ZZ2399
++006746        461400          ZZ2399=ZZ2399+ZZ2399
++006746        012560          0 8192 -ZZ1399
++006747        461400          0 ZZ2399
+-       mark 2709, -25         /28 mono
++006750        777714          ZZ2400=ZZ2400+ZZ2400
++006750        777630          ZZ2400=ZZ2400+ZZ2400
++006750        777460          ZZ2400=ZZ2400+ZZ2400
++006750        777140          ZZ2400=ZZ2400+ZZ2400
++006750        776300          ZZ2400=ZZ2400+ZZ2400
++006750        774600          ZZ2400=ZZ2400+ZZ2400
++006750        771400          ZZ2400=ZZ2400+ZZ2400
++006750        763000          ZZ2400=ZZ2400+ZZ2400
++006750        012553          0 8192 -ZZ1400
++006751        763000          0 ZZ2400
+-       mark 2714, 60          /
++006752        000170          ZZ2401=ZZ2401+ZZ2401
++006752        000360          ZZ2401=ZZ2401+ZZ2401
++006752        000740          ZZ2401=ZZ2401+ZZ2401
++006752        001700          ZZ2401=ZZ2401+ZZ2401
++006752        003600          ZZ2401=ZZ2401+ZZ2401
++006752        007400          ZZ2401=ZZ2401+ZZ2401
++006752        017000          ZZ2401=ZZ2401+ZZ2401
++006752        036000          ZZ2401=ZZ2401+ZZ2401
++006752        012546          0 8192 -ZZ1401
++006753        036000          0 ZZ2401
+-       mark 2751, -61         /29 mono
++006754        777604          ZZ2402=ZZ2402+ZZ2402
++006754        777410          ZZ2402=ZZ2402+ZZ2402
++006754        777020          ZZ2402=ZZ2402+ZZ2402
++006754        776040          ZZ2402=ZZ2402+ZZ2402
++006754        774100          ZZ2402=ZZ2402+ZZ2402
++006754        770200          ZZ2402=ZZ2402+ZZ2402
++006754        760400          ZZ2402=ZZ2402+ZZ2402
++006754        741000          ZZ2402=ZZ2402+ZZ2402
++006754        012501          0 8192 -ZZ1402
++006755        741000          0 ZZ2402
+-       mark 2757, -431        /16 pupp
++006756        776240          ZZ2403=ZZ2403+ZZ2403
++006756        774500          ZZ2403=ZZ2403+ZZ2403
++006756        771200          ZZ2403=ZZ2403+ZZ2403
++006756        762400          ZZ2403=ZZ2403+ZZ2403
++006756        745000          ZZ2403=ZZ2403+ZZ2403
++006756        712000          ZZ2403=ZZ2403+ZZ2403
++006756        624000          ZZ2403=ZZ2403+ZZ2403
++006756        450000          ZZ2403=ZZ2403+ZZ2403
++006756        012473          0 8192 -ZZ1403
++006757        450000          0 ZZ2403
+-       mark 2768, -288        /19 pupp
++006760        776676          ZZ2404=ZZ2404+ZZ2404
++006760        775574          ZZ2404=ZZ2404+ZZ2404
++006760        773370          ZZ2404=ZZ2404+ZZ2404
++006760        766760          ZZ2404=ZZ2404+ZZ2404
++006760        755740          ZZ2404=ZZ2404+ZZ2404
++006760        733700          ZZ2404=ZZ2404+ZZ2404
++006760        667600          ZZ2404=ZZ2404+ZZ2404
++006760        557400          ZZ2404=ZZ2404+ZZ2404
++006760        012460          0 8192 -ZZ1404
++006761        557400          0 ZZ2404
+-       mark 2794, 216         /17 canc
++006762        000660          ZZ2405=ZZ2405+ZZ2405
++006762        001540          ZZ2405=ZZ2405+ZZ2405
++006762        003300          ZZ2405=ZZ2405+ZZ2405
++006762        006600          ZZ2405=ZZ2405+ZZ2405
++006762        015400          ZZ2405=ZZ2405+ZZ2405
++006762        033000          ZZ2405=ZZ2405+ZZ2405
++006762        066000          ZZ2405=ZZ2405+ZZ2405
++006762        154000          ZZ2405=ZZ2405+ZZ2405
++006762        012426          0 8192 -ZZ1405
++006763        154000          0 ZZ2405
+-       mark 2848, -82         /
++006764        777532          ZZ2406=ZZ2406+ZZ2406
++006764        777264          ZZ2406=ZZ2406+ZZ2406
++006764        776550          ZZ2406=ZZ2406+ZZ2406
++006764        775320          ZZ2406=ZZ2406+ZZ2406
++006764        772640          ZZ2406=ZZ2406+ZZ2406
++006764        765500          ZZ2406=ZZ2406+ZZ2406
++006764        753200          ZZ2406=ZZ2406+ZZ2406
++006764        726400          ZZ2406=ZZ2406+ZZ2406
++006764        012340          0 8192 -ZZ1406
++006765        726400          0 ZZ2406
+-       mark 2915, 138         / 4 hyda
++006766        000424          ZZ2407=ZZ2407+ZZ2407
++006766        001050          ZZ2407=ZZ2407+ZZ2407
++006766        002120          ZZ2407=ZZ2407+ZZ2407
++006766        004240          ZZ2407=ZZ2407+ZZ2407
++006766        010500          ZZ2407=ZZ2407+ZZ2407
++006766        021200          ZZ2407=ZZ2407+ZZ2407
++006766        042400          ZZ2407=ZZ2407+ZZ2407
++006766        105000          ZZ2407=ZZ2407+ZZ2407
++006766        012235          0 8192 -ZZ1407
++006767        105000          0 ZZ2407
+-       mark 2921, 84          / 5 hyda
++006770        000250          ZZ2408=ZZ2408+ZZ2408
++006770        000520          ZZ2408=ZZ2408+ZZ2408
++006770        001240          ZZ2408=ZZ2408+ZZ2408
++006770        002500          ZZ2408=ZZ2408+ZZ2408
++006770        005200          ZZ2408=ZZ2408+ZZ2408
++006770        012400          ZZ2408=ZZ2408+ZZ2408
++006770        025000          ZZ2408=ZZ2408+ZZ2408
++006770        052000          ZZ2408=ZZ2408+ZZ2408
++006770        012227          0 8192 -ZZ1408
++006771        052000          0 ZZ2408
+-       mark 2942, -355        / 9 hyda
++006772        776470          ZZ2409=ZZ2409+ZZ2409
++006772        775160          ZZ2409=ZZ2409+ZZ2409
++006772        772340          ZZ2409=ZZ2409+ZZ2409
++006772        764700          ZZ2409=ZZ2409+ZZ2409
++006772        751600          ZZ2409=ZZ2409+ZZ2409
++006772        723400          ZZ2409=ZZ2409+ZZ2409
++006772        647000          ZZ2409=ZZ2409+ZZ2409
++006772        516000          ZZ2409=ZZ2409+ZZ2409
++006772        012202          0 8192 -ZZ1409
++006773        516000          0 ZZ2409
+-       mark 2944, 497         /43 canc
++006774        001742          ZZ2410=ZZ2410+ZZ2410
++006774        003704          ZZ2410=ZZ2410+ZZ2410
++006774        007610          ZZ2410=ZZ2410+ZZ2410
++006774        017420          ZZ2410=ZZ2410+ZZ2410
++006774        037040          ZZ2410=ZZ2410+ZZ2410
++006774        076100          ZZ2410=ZZ2410+ZZ2410
++006774        174200          ZZ2410=ZZ2410+ZZ2410
++006774        370400          ZZ2410=ZZ2410+ZZ2410
++006774        012200          0 8192 -ZZ1410
++006775        370400          0 ZZ2410
+-       mark 2947, 85          / 7 hyda
++006776        000252          ZZ2411=ZZ2411+ZZ2411
++006776        000524          ZZ2411=ZZ2411+ZZ2411
++006776        001250          ZZ2411=ZZ2411+ZZ2411
++006776        002520          ZZ2411=ZZ2411+ZZ2411
++006776        005240          ZZ2411=ZZ2411+ZZ2411
++006776        012500          ZZ2411=ZZ2411+ZZ2411
++006776        025200          ZZ2411=ZZ2411+ZZ2411
++006776        052400          ZZ2411=ZZ2411+ZZ2411
++006776        012175          0 8192 -ZZ1411
++006777        052400          0 ZZ2411
+-       mark 2951, -156        /
++007000        777306          ZZ2412=ZZ2412+ZZ2412
++007000        776614          ZZ2412=ZZ2412+ZZ2412
++007000        775430          ZZ2412=ZZ2412+ZZ2412
++007000        773060          ZZ2412=ZZ2412+ZZ2412
++007000        766140          ZZ2412=ZZ2412+ZZ2412
++007000        754300          ZZ2412=ZZ2412+ZZ2412
++007000        730600          ZZ2412=ZZ2412+ZZ2412
++007000        661400          ZZ2412=ZZ2412+ZZ2412
++007000        012171          0 8192 -ZZ1412
++007001        661400          0 ZZ2412
+-       mark 2953, 421         /47 canc
++007002        001512          ZZ2413=ZZ2413+ZZ2413
++007002        003224          ZZ2413=ZZ2413+ZZ2413
++007002        006450          ZZ2413=ZZ2413+ZZ2413
++007002        015120          ZZ2413=ZZ2413+ZZ2413
++007002        032240          ZZ2413=ZZ2413+ZZ2413
++007002        064500          ZZ2413=ZZ2413+ZZ2413
++007002        151200          ZZ2413=ZZ2413+ZZ2413
++007002        322400          ZZ2413=ZZ2413+ZZ2413
++007002        012167          0 8192 -ZZ1413
++007003        322400          0 ZZ2413
+-       mark 2968, -300        /12 hyda
++007004        776646          ZZ2414=ZZ2414+ZZ2414
++007004        775514          ZZ2414=ZZ2414+ZZ2414
++007004        773230          ZZ2414=ZZ2414+ZZ2414
++007004        766460          ZZ2414=ZZ2414+ZZ2414
++007004        755140          ZZ2414=ZZ2414+ZZ2414
++007004        732300          ZZ2414=ZZ2414+ZZ2414
++007004        664600          ZZ2414=ZZ2414+ZZ2414
++007004        551400          ZZ2414=ZZ2414+ZZ2414
++007004        012150          0 8192 -ZZ1414
++007005        551400          0 ZZ2414
+-       mark 2976, 141         /13 hyda
++007006        000432          ZZ2415=ZZ2415+ZZ2415
++007006        001064          ZZ2415=ZZ2415+ZZ2415
++007006        002150          ZZ2415=ZZ2415+ZZ2415
++007006        004320          ZZ2415=ZZ2415+ZZ2415
++007006        010640          ZZ2415=ZZ2415+ZZ2415
++007006        021500          ZZ2415=ZZ2415+ZZ2415
++007006        043200          ZZ2415=ZZ2415+ZZ2415
++007006        106400          ZZ2415=ZZ2415+ZZ2415
++007006        012140          0 8192 -ZZ1415
++007007        106400          0 ZZ2415
+-       mark 3032, 279         /65 canc
++007010        001056          ZZ2416=ZZ2416+ZZ2416
++007010        002134          ZZ2416=ZZ2416+ZZ2416
++007010        004270          ZZ2416=ZZ2416+ZZ2416
++007010        010560          ZZ2416=ZZ2416+ZZ2416
++007010        021340          ZZ2416=ZZ2416+ZZ2416
++007010        042700          ZZ2416=ZZ2416+ZZ2416
++007010        105600          ZZ2416=ZZ2416+ZZ2416
++007010        213400          ZZ2416=ZZ2416+ZZ2416
++007010        012050          0 8192 -ZZ1416
++007011        213400          0 ZZ2416
+-       mark 3124, 62          /22 hyda
++007012        000174          ZZ2417=ZZ2417+ZZ2417
++007012        000370          ZZ2417=ZZ2417+ZZ2417
++007012        000760          ZZ2417=ZZ2417+ZZ2417
++007012        001740          ZZ2417=ZZ2417+ZZ2417
++007012        003700          ZZ2417=ZZ2417+ZZ2417
++007012        007600          ZZ2417=ZZ2417+ZZ2417
++007012        017400          ZZ2417=ZZ2417+ZZ2417
++007012        037000          ZZ2417=ZZ2417+ZZ2417
++007012        011714          0 8192 -ZZ1417
++007013        037000          0 ZZ2417
+-       mark 3157, -263        /26 hyda
++007014        776760          ZZ2418=ZZ2418+ZZ2418
++007014        775740          ZZ2418=ZZ2418+ZZ2418
++007014        773700          ZZ2418=ZZ2418+ZZ2418
++007014        767600          ZZ2418=ZZ2418+ZZ2418
++007014        757400          ZZ2418=ZZ2418+ZZ2418
++007014        737000          ZZ2418=ZZ2418+ZZ2418
++007014        676000          ZZ2418=ZZ2418+ZZ2418
++007014        574000          ZZ2418=ZZ2418+ZZ2418
++007014        011653          0 8192 -ZZ1418
++007015        574000          0 ZZ2418
+-       mark 3161, -208        /27 hyda
++007016        777136          ZZ2419=ZZ2419+ZZ2419
++007016        776274          ZZ2419=ZZ2419+ZZ2419
++007016        774570          ZZ2419=ZZ2419+ZZ2419
++007016        771360          ZZ2419=ZZ2419+ZZ2419
++007016        762740          ZZ2419=ZZ2419+ZZ2419
++007016        745700          ZZ2419=ZZ2419+ZZ2419
++007016        713600          ZZ2419=ZZ2419+ZZ2419
++007016        627400          ZZ2419=ZZ2419+ZZ2419
++007016        011647          0 8192 -ZZ1419
++007017        627400          0 ZZ2419
+-       mark 3209, -53         /31 hyda
++007020        777624          ZZ2420=ZZ2420+ZZ2420
++007020        777450          ZZ2420=ZZ2420+ZZ2420
++007020        777120          ZZ2420=ZZ2420+ZZ2420
++007020        776240          ZZ2420=ZZ2420+ZZ2420
++007020        774500          ZZ2420=ZZ2420+ZZ2420
++007020        771200          ZZ2420=ZZ2420+ZZ2420
++007020        762400          ZZ2420=ZZ2420+ZZ2420
++007020        745000          ZZ2420=ZZ2420+ZZ2420
++007020        011567          0 8192 -ZZ1420
++007021        745000          0 ZZ2420
+-       mark 3225, -17         /32 hyda
++007022        777734          ZZ2421=ZZ2421+ZZ2421
++007022        777670          ZZ2421=ZZ2421+ZZ2421
++007022        777560          ZZ2421=ZZ2421+ZZ2421
++007022        777340          ZZ2421=ZZ2421+ZZ2421
++007022        776700          ZZ2421=ZZ2421+ZZ2421
++007022        775600          ZZ2421=ZZ2421+ZZ2421
++007022        773400          ZZ2421=ZZ2421+ZZ2421
++007022        767000          ZZ2421=ZZ2421+ZZ2421
++007022        011547          0 8192 -ZZ1421
++007023        767000          0 ZZ2421
+-       mark 3261, 116         /
++007024        000350          ZZ2422=ZZ2422+ZZ2422
++007024        000720          ZZ2422=ZZ2422+ZZ2422
++007024        001640          ZZ2422=ZZ2422+ZZ2422
++007024        003500          ZZ2422=ZZ2422+ZZ2422
++007024        007200          ZZ2422=ZZ2422+ZZ2422
++007024        016400          ZZ2422=ZZ2422+ZZ2422
++007024        035000          ZZ2422=ZZ2422+ZZ2422
++007024        072000          ZZ2422=ZZ2422+ZZ2422
++007024        011503          0 8192 -ZZ1422
++007025        072000          0 ZZ2422
+-       mark 3270, -16         /35 hyda
++007026        777736          ZZ2423=ZZ2423+ZZ2423
++007026        777674          ZZ2423=ZZ2423+ZZ2423
++007026        777570          ZZ2423=ZZ2423+ZZ2423
++007026        777360          ZZ2423=ZZ2423+ZZ2423
++007026        776740          ZZ2423=ZZ2423+ZZ2423
++007026        775700          ZZ2423=ZZ2423+ZZ2423
++007026        773600          ZZ2423=ZZ2423+ZZ2423
++007026        767400          ZZ2423=ZZ2423+ZZ2423
++007026        011472          0 8192 -ZZ1423
++007027        767400          0 ZZ2423
+-       mark 3274, -316        /38 hyda
++007030        776606          ZZ2424=ZZ2424+ZZ2424
++007030        775414          ZZ2424=ZZ2424+ZZ2424
++007030        773030          ZZ2424=ZZ2424+ZZ2424
++007030        766060          ZZ2424=ZZ2424+ZZ2424
++007030        754140          ZZ2424=ZZ2424+ZZ2424
++007030        730300          ZZ2424=ZZ2424+ZZ2424
++007030        660600          ZZ2424=ZZ2424+ZZ2424
++007030        541400          ZZ2424=ZZ2424+ZZ2424
++007030        011466          0 8192 -ZZ1424
++007031        541400          0 ZZ2424
+-       mark 3276, 236         /14 leon
++007032        000730          ZZ2425=ZZ2425+ZZ2425
++007032        001660          ZZ2425=ZZ2425+ZZ2425
++007032        003540          ZZ2425=ZZ2425+ZZ2425
++007032        007300          ZZ2425=ZZ2425+ZZ2425
++007032        016600          ZZ2425=ZZ2425+ZZ2425
++007032        035400          ZZ2425=ZZ2425+ZZ2425
++007032        073000          ZZ2425=ZZ2425+ZZ2425
++007032        166000          ZZ2425=ZZ2425+ZZ2425
++007032        011464          0 8192 -ZZ1425
++007033        166000          0 ZZ2425
+-       mark 3338, -327        /39 hyda
++007034        776560          ZZ2426=ZZ2426+ZZ2426
++007034        775340          ZZ2426=ZZ2426+ZZ2426
++007034        772700          ZZ2426=ZZ2426+ZZ2426
++007034        765600          ZZ2426=ZZ2426+ZZ2426
++007034        753400          ZZ2426=ZZ2426+ZZ2426
++007034        727000          ZZ2426=ZZ2426+ZZ2426
++007034        656000          ZZ2426=ZZ2426+ZZ2426
++007034        534000          ZZ2426=ZZ2426+ZZ2426
++007034        011366          0 8192 -ZZ1426
++007035        534000          0 ZZ2426
+-       mark 3385, 194         /29 leon
++007036        000604          ZZ2427=ZZ2427+ZZ2427
++007036        001410          ZZ2427=ZZ2427+ZZ2427
++007036        003020          ZZ2427=ZZ2427+ZZ2427
++007036        006040          ZZ2427=ZZ2427+ZZ2427
++007036        014100          ZZ2427=ZZ2427+ZZ2427
++007036        030200          ZZ2427=ZZ2427+ZZ2427
++007036        060400          ZZ2427=ZZ2427+ZZ2427
++007036        141000          ZZ2427=ZZ2427+ZZ2427
++007036        011307          0 8192 -ZZ1427
++007037        141000          0 ZZ2427
+-       mark 3415, -286        /40 hyda
++007040        776702          ZZ2428=ZZ2428+ZZ2428
++007040        775604          ZZ2428=ZZ2428+ZZ2428
++007040        773410          ZZ2428=ZZ2428+ZZ2428
++007040        767020          ZZ2428=ZZ2428+ZZ2428
++007040        756040          ZZ2428=ZZ2428+ZZ2428
++007040        734100          ZZ2428=ZZ2428+ZZ2428
++007040        670200          ZZ2428=ZZ2428+ZZ2428
++007040        560400          ZZ2428=ZZ2428+ZZ2428
++007040        011251          0 8192 -ZZ1428
++007041        560400          0 ZZ2428
+-       mark 3428, 239         /31 leon
++007042        000736          ZZ2429=ZZ2429+ZZ2429
++007042        001674          ZZ2429=ZZ2429+ZZ2429
++007042        003570          ZZ2429=ZZ2429+ZZ2429
++007042        007360          ZZ2429=ZZ2429+ZZ2429
++007042        016740          ZZ2429=ZZ2429+ZZ2429
++007042        035700          ZZ2429=ZZ2429+ZZ2429
++007042        073600          ZZ2429=ZZ2429+ZZ2429
++007042        167400          ZZ2429=ZZ2429+ZZ2429
++007042        011234          0 8192 -ZZ1429
++007043        167400          0 ZZ2429
+-       mark 3429, 3           /15 sext
++007044        000006          ZZ2430=ZZ2430+ZZ2430
++007044        000014          ZZ2430=ZZ2430+ZZ2430
++007044        000030          ZZ2430=ZZ2430+ZZ2430
++007044        000060          ZZ2430=ZZ2430+ZZ2430
++007044        000140          ZZ2430=ZZ2430+ZZ2430
++007044        000300          ZZ2430=ZZ2430+ZZ2430
++007044        000600          ZZ2430=ZZ2430+ZZ2430
++007044        001400          ZZ2430=ZZ2430+ZZ2430
++007044        011233          0 8192 -ZZ1430
++007045        001400          0 ZZ2430
+-       mark 3446, -270        /41 hyda
++007046        776742          ZZ2431=ZZ2431+ZZ2431
++007046        775704          ZZ2431=ZZ2431+ZZ2431
++007046        773610          ZZ2431=ZZ2431+ZZ2431
++007046        767420          ZZ2431=ZZ2431+ZZ2431
++007046        757040          ZZ2431=ZZ2431+ZZ2431
++007046        736100          ZZ2431=ZZ2431+ZZ2431
++007046        674200          ZZ2431=ZZ2431+ZZ2431
++007046        570400          ZZ2431=ZZ2431+ZZ2431
++007046        011212          0 8192 -ZZ1431
++007047        570400          0 ZZ2431
+-       mark 3495, 455         /40 leon
++007050        001616          ZZ2432=ZZ2432+ZZ2432
++007050        003434          ZZ2432=ZZ2432+ZZ2432
++007050        007070          ZZ2432=ZZ2432+ZZ2432
++007050        016160          ZZ2432=ZZ2432+ZZ2432
++007050        034340          ZZ2432=ZZ2432+ZZ2432
++007050        070700          ZZ2432=ZZ2432+ZZ2432
++007050        161600          ZZ2432=ZZ2432+ZZ2432
++007050        343400          ZZ2432=ZZ2432+ZZ2432
++007050        011131          0 8192 -ZZ1432
++007051        343400          0 ZZ2432
+-       mark 3534, -372        /42 hyda
++007052        776426          ZZ2433=ZZ2433+ZZ2433
++007052        775054          ZZ2433=ZZ2433+ZZ2433
++007052        772130          ZZ2433=ZZ2433+ZZ2433
++007052        764260          ZZ2433=ZZ2433+ZZ2433
++007052        750540          ZZ2433=ZZ2433+ZZ2433
++007052        721300          ZZ2433=ZZ2433+ZZ2433
++007052        642600          ZZ2433=ZZ2433+ZZ2433
++007052        505400          ZZ2433=ZZ2433+ZZ2433
++007052        011062          0 8192 -ZZ1433
++007053        505400          0 ZZ2433
+-       mark 3557, -3          /30 sext
++007054        777770          ZZ2434=ZZ2434+ZZ2434
++007054        777760          ZZ2434=ZZ2434+ZZ2434
++007054        777740          ZZ2434=ZZ2434+ZZ2434
++007054        777700          ZZ2434=ZZ2434+ZZ2434
++007054        777600          ZZ2434=ZZ2434+ZZ2434
++007054        777400          ZZ2434=ZZ2434+ZZ2434
++007054        777000          ZZ2434=ZZ2434+ZZ2434
++007054        776000          ZZ2434=ZZ2434+ZZ2434
++007054        011033          0 8192 -ZZ1434
++007055        776000          0 ZZ2434
+-       mark 3570, 223         /47 leon
++007056        000676          ZZ2435=ZZ2435+ZZ2435
++007056        001574          ZZ2435=ZZ2435+ZZ2435
++007056        003370          ZZ2435=ZZ2435+ZZ2435
++007056        006760          ZZ2435=ZZ2435+ZZ2435
++007056        015740          ZZ2435=ZZ2435+ZZ2435
++007056        033700          ZZ2435=ZZ2435+ZZ2435
++007056        067600          ZZ2435=ZZ2435+ZZ2435
++007056        157400          ZZ2435=ZZ2435+ZZ2435
++007056        011016          0 8192 -ZZ1435
++007057        157400          0 ZZ2435
+-       mark 3726, -404        /al crat
++007060        776326          ZZ2436=ZZ2436+ZZ2436
++007060        774654          ZZ2436=ZZ2436+ZZ2436
++007060        771530          ZZ2436=ZZ2436+ZZ2436
++007060        763260          ZZ2436=ZZ2436+ZZ2436
++007060        746540          ZZ2436=ZZ2436+ZZ2436
++007060        715300          ZZ2436=ZZ2436+ZZ2436
++007060        632600          ZZ2436=ZZ2436+ZZ2436
++007060        465400          ZZ2436=ZZ2436+ZZ2436
++007060        010562          0 8192 -ZZ1436
++007061        465400          0 ZZ2436
+-       mark 3736, -44         /61 leon
++007062        777646          ZZ2437=ZZ2437+ZZ2437
++007062        777514          ZZ2437=ZZ2437+ZZ2437
++007062        777230          ZZ2437=ZZ2437+ZZ2437
++007062        776460          ZZ2437=ZZ2437+ZZ2437
++007062        775140          ZZ2437=ZZ2437+ZZ2437
++007062        772300          ZZ2437=ZZ2437+ZZ2437
++007062        764600          ZZ2437=ZZ2437+ZZ2437
++007062        751400          ZZ2437=ZZ2437+ZZ2437
++007062        010550          0 8192 -ZZ1437
++007063        751400          0 ZZ2437
+-       mark 3738, 471         /60 leon
++007064        001656          ZZ2438=ZZ2438+ZZ2438
++007064        003534          ZZ2438=ZZ2438+ZZ2438
++007064        007270          ZZ2438=ZZ2438+ZZ2438
++007064        016560          ZZ2438=ZZ2438+ZZ2438
++007064        035340          ZZ2438=ZZ2438+ZZ2438
++007064        072700          ZZ2438=ZZ2438+ZZ2438
++007064        165600          ZZ2438=ZZ2438+ZZ2438
++007064        353400          ZZ2438=ZZ2438+ZZ2438
++007064        010546          0 8192 -ZZ1438
++007065        353400          0 ZZ2438
+-       mark 3754, 179         /63 leon
++007066        000546          ZZ2439=ZZ2439+ZZ2439
++007066        001314          ZZ2439=ZZ2439+ZZ2439
++007066        002630          ZZ2439=ZZ2439+ZZ2439
++007066        005460          ZZ2439=ZZ2439+ZZ2439
++007066        013140          ZZ2439=ZZ2439+ZZ2439
++007066        026300          ZZ2439=ZZ2439+ZZ2439
++007066        054600          ZZ2439=ZZ2439+ZZ2439
++007066        131400          ZZ2439=ZZ2439+ZZ2439
++007066        010526          0 8192 -ZZ1439
++007067        131400          0 ZZ2439
+-       mark 3793, -507        /11 crat
++007070        776010          ZZ2440=ZZ2440+ZZ2440
++007070        774020          ZZ2440=ZZ2440+ZZ2440
++007070        770040          ZZ2440=ZZ2440+ZZ2440
++007070        760100          ZZ2440=ZZ2440+ZZ2440
++007070        740200          ZZ2440=ZZ2440+ZZ2440
++007070        700400          ZZ2440=ZZ2440+ZZ2440
++007070        601000          ZZ2440=ZZ2440+ZZ2440
++007070        402000          ZZ2440=ZZ2440+ZZ2440
++007070        010457          0 8192 -ZZ1440
++007071        402000          0 ZZ2440
+-       mark 3821, -71         /74 leon
++007072        777560          ZZ2441=ZZ2441+ZZ2441
++007072        777340          ZZ2441=ZZ2441+ZZ2441
++007072        776700          ZZ2441=ZZ2441+ZZ2441
++007072        775600          ZZ2441=ZZ2441+ZZ2441
++007072        773400          ZZ2441=ZZ2441+ZZ2441
++007072        767000          ZZ2441=ZZ2441+ZZ2441
++007072        756000          ZZ2441=ZZ2441+ZZ2441
++007072        734000          ZZ2441=ZZ2441+ZZ2441
++007072        010423          0 8192 -ZZ1441
++007073        734000          0 ZZ2441
+-       mark 3836, -324        /12 crat
++007074        776566          ZZ2442=ZZ2442+ZZ2442
++007074        775354          ZZ2442=ZZ2442+ZZ2442
++007074        772730          ZZ2442=ZZ2442+ZZ2442
++007074        765660          ZZ2442=ZZ2442+ZZ2442
++007074        753540          ZZ2442=ZZ2442+ZZ2442
++007074        727300          ZZ2442=ZZ2442+ZZ2442
++007074        656600          ZZ2442=ZZ2442+ZZ2442
++007074        535400          ZZ2442=ZZ2442+ZZ2442
++007074        010404          0 8192 -ZZ1442
++007075        535400          0 ZZ2442
+-       mark 3846, 150         /77 leon
++007076        000454          ZZ2443=ZZ2443+ZZ2443
++007076        001130          ZZ2443=ZZ2443+ZZ2443
++007076        002260          ZZ2443=ZZ2443+ZZ2443
++007076        004540          ZZ2443=ZZ2443+ZZ2443
++007076        011300          ZZ2443=ZZ2443+ZZ2443
++007076        022600          ZZ2443=ZZ2443+ZZ2443
++007076        045400          ZZ2443=ZZ2443+ZZ2443
++007076        113000          ZZ2443=ZZ2443+ZZ2443
++007076        010372          0 8192 -ZZ1443
++007077        113000          0 ZZ2443
+-       mark 3861, 252         /78 leon
++007100        000770          ZZ2444=ZZ2444+ZZ2444
++007100        001760          ZZ2444=ZZ2444+ZZ2444
++007100        003740          ZZ2444=ZZ2444+ZZ2444
++007100        007700          ZZ2444=ZZ2444+ZZ2444
++007100        017600          ZZ2444=ZZ2444+ZZ2444
++007100        037400          ZZ2444=ZZ2444+ZZ2444
++007100        077000          ZZ2444=ZZ2444+ZZ2444
++007100        176000          ZZ2444=ZZ2444+ZZ2444
++007100        010353          0 8192 -ZZ1444
++007101        176000          0 ZZ2444
+-       mark 3868, -390        /15 crat
++007102        776362          ZZ2445=ZZ2445+ZZ2445
++007102        774744          ZZ2445=ZZ2445+ZZ2445
++007102        771710          ZZ2445=ZZ2445+ZZ2445
++007102        763620          ZZ2445=ZZ2445+ZZ2445
++007102        747440          ZZ2445=ZZ2445+ZZ2445
++007102        717100          ZZ2445=ZZ2445+ZZ2445
++007102        636200          ZZ2445=ZZ2445+ZZ2445
++007102        474400          ZZ2445=ZZ2445+ZZ2445
++007102        010344          0 8192 -ZZ1445
++007103        474400          0 ZZ2445
+-       mark 3935, -211        /21 crat
++007104        777130          ZZ2446=ZZ2446+ZZ2446
++007104        776260          ZZ2446=ZZ2446+ZZ2446
++007104        774540          ZZ2446=ZZ2446+ZZ2446
++007104        771300          ZZ2446=ZZ2446+ZZ2446
++007104        762600          ZZ2446=ZZ2446+ZZ2446
++007104        745400          ZZ2446=ZZ2446+ZZ2446
++007104        713000          ZZ2446=ZZ2446+ZZ2446
++007104        626000          ZZ2446=ZZ2446+ZZ2446
++007104        010241          0 8192 -ZZ1446
++007105        626000          0 ZZ2446
+-       mark 3936, -6          /91 leon
++007106        777762          ZZ2447=ZZ2447+ZZ2447
++007106        777744          ZZ2447=ZZ2447+ZZ2447
++007106        777710          ZZ2447=ZZ2447+ZZ2447
++007106        777620          ZZ2447=ZZ2447+ZZ2447
++007106        777440          ZZ2447=ZZ2447+ZZ2447
++007106        777100          ZZ2447=ZZ2447+ZZ2447
++007106        776200          ZZ2447=ZZ2447+ZZ2447
++007106        774400          ZZ2447=ZZ2447+ZZ2447
++007106        010240          0 8192 -ZZ1447
++007107        774400          0 ZZ2447
+-       mark 3981, -405        /27 crat
++007110        776324          ZZ2448=ZZ2448+ZZ2448
++007110        774650          ZZ2448=ZZ2448+ZZ2448
++007110        771520          ZZ2448=ZZ2448+ZZ2448
++007110        763240          ZZ2448=ZZ2448+ZZ2448
++007110        746500          ZZ2448=ZZ2448+ZZ2448
++007110        715200          ZZ2448=ZZ2448+ZZ2448
++007110        632400          ZZ2448=ZZ2448+ZZ2448
++007110        465000          ZZ2448=ZZ2448+ZZ2448
++007110        010163          0 8192 -ZZ1448
++007111        465000          0 ZZ2448
+-       mark 3986, 161         / 3 virg
++007112        000502          ZZ2449=ZZ2449+ZZ2449
++007112        001204          ZZ2449=ZZ2449+ZZ2449
++007112        002410          ZZ2449=ZZ2449+ZZ2449
++007112        005020          ZZ2449=ZZ2449+ZZ2449
++007112        012040          ZZ2449=ZZ2449+ZZ2449
++007112        024100          ZZ2449=ZZ2449+ZZ2449
++007112        050200          ZZ2449=ZZ2449+ZZ2449
++007112        120400          ZZ2449=ZZ2449+ZZ2449
++007112        010156          0 8192 -ZZ1449
++007113        120400          0 ZZ2449
+-       mark 3998, 473         /93 leon
++007114        001662          ZZ2450=ZZ2450+ZZ2450
++007114        003544          ZZ2450=ZZ2450+ZZ2450
++007114        007310          ZZ2450=ZZ2450+ZZ2450
++007114        016620          ZZ2450=ZZ2450+ZZ2450
++007114        035440          ZZ2450=ZZ2450+ZZ2450
++007114        073100          ZZ2450=ZZ2450+ZZ2450
++007114        166200          ZZ2450=ZZ2450+ZZ2450
++007114        354400          ZZ2450=ZZ2450+ZZ2450
++007114        010142          0 8192 -ZZ1450
++007115        354400          0 ZZ2450
+-       mark 4013, 53          / 5 virg
++007116        000152          ZZ2451=ZZ2451+ZZ2451
++007116        000324          ZZ2451=ZZ2451+ZZ2451
++007116        000650          ZZ2451=ZZ2451+ZZ2451
++007116        001520          ZZ2451=ZZ2451+ZZ2451
++007116        003240          ZZ2451=ZZ2451+ZZ2451
++007116        006500          ZZ2451=ZZ2451+ZZ2451
++007116        015200          ZZ2451=ZZ2451+ZZ2451
++007116        032400          ZZ2451=ZZ2451+ZZ2451
++007116        010123          0 8192 -ZZ1451
++007117        032400          0 ZZ2451
+-       mark 4072, 163         / 8 virg
++007120        000506          ZZ2452=ZZ2452+ZZ2452
++007120        001214          ZZ2452=ZZ2452+ZZ2452
++007120        002430          ZZ2452=ZZ2452+ZZ2452
++007120        005060          ZZ2452=ZZ2452+ZZ2452
++007120        012140          ZZ2452=ZZ2452+ZZ2452
++007120        024300          ZZ2452=ZZ2452+ZZ2452
++007120        050600          ZZ2452=ZZ2452+ZZ2452
++007120        121400          ZZ2452=ZZ2452+ZZ2452
++007120        010030          0 8192 -ZZ1452
++007121        121400          0 ZZ2452
+-       mark 4097, 211         / 9 virg
++007122        000646          ZZ2453=ZZ2453+ZZ2453
++007122        001514          ZZ2453=ZZ2453+ZZ2453
++007122        003230          ZZ2453=ZZ2453+ZZ2453
++007122        006460          ZZ2453=ZZ2453+ZZ2453
++007122        015140          ZZ2453=ZZ2453+ZZ2453
++007122        032300          ZZ2453=ZZ2453+ZZ2453
++007122        064600          ZZ2453=ZZ2453+ZZ2453
++007122        151400          ZZ2453=ZZ2453+ZZ2453
++007122        007777          0 8192 -ZZ1453
++007123        151400          0 ZZ2453
+-       mark 4180, -3          /15 virg
++007124        777770          ZZ2454=ZZ2454+ZZ2454
++007124        777760          ZZ2454=ZZ2454+ZZ2454
++007124        777740          ZZ2454=ZZ2454+ZZ2454
++007124        777700          ZZ2454=ZZ2454+ZZ2454
++007124        777600          ZZ2454=ZZ2454+ZZ2454
++007124        777400          ZZ2454=ZZ2454+ZZ2454
++007124        777000          ZZ2454=ZZ2454+ZZ2454
++007124        776000          ZZ2454=ZZ2454+ZZ2454
++007124        007654          0 8192 -ZZ1454
++007125        776000          0 ZZ2454
+-       mark 4185, 418         /11 coma
++007126        001504          ZZ2455=ZZ2455+ZZ2455
++007126        003210          ZZ2455=ZZ2455+ZZ2455
++007126        006420          ZZ2455=ZZ2455+ZZ2455
++007126        015040          ZZ2455=ZZ2455+ZZ2455
++007126        032100          ZZ2455=ZZ2455+ZZ2455
++007126        064200          ZZ2455=ZZ2455+ZZ2455
++007126        150400          ZZ2455=ZZ2455+ZZ2455
++007126        321000          ZZ2455=ZZ2455+ZZ2455
++007126        007647          0 8192 -ZZ1455
++007127        321000          0 ZZ2455
+-       mark 4249, -356        / 8 corv
++007130        776466          ZZ2456=ZZ2456+ZZ2456
++007130        775154          ZZ2456=ZZ2456+ZZ2456
++007130        772330          ZZ2456=ZZ2456+ZZ2456
++007130        764660          ZZ2456=ZZ2456+ZZ2456
++007130        751540          ZZ2456=ZZ2456+ZZ2456
++007130        723300          ZZ2456=ZZ2456+ZZ2456
++007130        646600          ZZ2456=ZZ2456+ZZ2456
++007130        515400          ZZ2456=ZZ2456+ZZ2456
++007130        007547          0 8192 -ZZ1456
++007131        515400          0 ZZ2456
+-       mark 4290, -170        /26 virg
++007132        777252          ZZ2457=ZZ2457+ZZ2457
++007132        776524          ZZ2457=ZZ2457+ZZ2457
++007132        775250          ZZ2457=ZZ2457+ZZ2457
++007132        772520          ZZ2457=ZZ2457+ZZ2457
++007132        765240          ZZ2457=ZZ2457+ZZ2457
++007132        752500          ZZ2457=ZZ2457+ZZ2457
++007132        725200          ZZ2457=ZZ2457+ZZ2457
++007132        652400          ZZ2457=ZZ2457+ZZ2457
++007132        007476          0 8192 -ZZ1457
++007133        652400          0 ZZ2457
+-       mark 4305, 245         /30 virg
++007134        000752          ZZ2458=ZZ2458+ZZ2458
++007134        001724          ZZ2458=ZZ2458+ZZ2458
++007134        003650          ZZ2458=ZZ2458+ZZ2458
++007134        007520          ZZ2458=ZZ2458+ZZ2458
++007134        017240          ZZ2458=ZZ2458+ZZ2458
++007134        036500          ZZ2458=ZZ2458+ZZ2458
++007134        075200          ZZ2458=ZZ2458+ZZ2458
++007134        172400          ZZ2458=ZZ2458+ZZ2458
++007134        007457          0 8192 -ZZ1458
++007135        172400          0 ZZ2458
+-       mark 4376, -205        /40 virg
++007136        777144          ZZ2459=ZZ2459+ZZ2459
++007136        776310          ZZ2459=ZZ2459+ZZ2459
++007136        774620          ZZ2459=ZZ2459+ZZ2459
++007136        771440          ZZ2459=ZZ2459+ZZ2459
++007136        763100          ZZ2459=ZZ2459+ZZ2459
++007136        746200          ZZ2459=ZZ2459+ZZ2459
++007136        714400          ZZ2459=ZZ2459+ZZ2459
++007136        631000          ZZ2459=ZZ2459+ZZ2459
++007136        007350          0 8192 -ZZ1459
++007137        631000          0 ZZ2459
+-       mark 4403, 409         /36 coma
++007140        001462          ZZ2460=ZZ2460+ZZ2460
++007140        003144          ZZ2460=ZZ2460+ZZ2460
++007140        006310          ZZ2460=ZZ2460+ZZ2460
++007140        014620          ZZ2460=ZZ2460+ZZ2460
++007140        031440          ZZ2460=ZZ2460+ZZ2460
++007140        063100          ZZ2460=ZZ2460+ZZ2460
++007140        146200          ZZ2460=ZZ2460+ZZ2460
++007140        314400          ZZ2460=ZZ2460+ZZ2460
++007140        007315          0 8192 -ZZ1460
++007141        314400          0 ZZ2460
+-       mark 4465, -114        /51 virg
++007142        777432          ZZ2461=ZZ2461+ZZ2461
++007142        777064          ZZ2461=ZZ2461+ZZ2461
++007142        776150          ZZ2461=ZZ2461+ZZ2461
++007142        774320          ZZ2461=ZZ2461+ZZ2461
++007142        770640          ZZ2461=ZZ2461+ZZ2461
++007142        761500          ZZ2461=ZZ2461+ZZ2461
++007142        743200          ZZ2461=ZZ2461+ZZ2461
++007142        706400          ZZ2461=ZZ2461+ZZ2461
++007142        007217          0 8192 -ZZ1461
++007143        706400          0 ZZ2461
+-       mark 4466, 411         /42 coma
++007144        001466          ZZ2462=ZZ2462+ZZ2462
++007144        003154          ZZ2462=ZZ2462+ZZ2462
++007144        006330          ZZ2462=ZZ2462+ZZ2462
++007144        014660          ZZ2462=ZZ2462+ZZ2462
++007144        031540          ZZ2462=ZZ2462+ZZ2462
++007144        063300          ZZ2462=ZZ2462+ZZ2462
++007144        146600          ZZ2462=ZZ2462+ZZ2462
++007144        315400          ZZ2462=ZZ2462+ZZ2462
++007144        007216          0 8192 -ZZ1462
++007145        315400          0 ZZ2462
+-       mark 4512, -404        /61 virg
++007146        776326          ZZ2463=ZZ2463+ZZ2463
++007146        774654          ZZ2463=ZZ2463+ZZ2463
++007146        771530          ZZ2463=ZZ2463+ZZ2463
++007146        763260          ZZ2463=ZZ2463+ZZ2463
++007146        746540          ZZ2463=ZZ2463+ZZ2463
++007146        715300          ZZ2463=ZZ2463+ZZ2463
++007146        632600          ZZ2463=ZZ2463+ZZ2463
++007146        465400          ZZ2463=ZZ2463+ZZ2463
++007146        007140          0 8192 -ZZ1463
++007147        465400          0 ZZ2463
+-       mark 4563, -352        /69 virg
++007150        776476          ZZ2464=ZZ2464+ZZ2464
++007150        775174          ZZ2464=ZZ2464+ZZ2464
++007150        772370          ZZ2464=ZZ2464+ZZ2464
++007150        764760          ZZ2464=ZZ2464+ZZ2464
++007150        751740          ZZ2464=ZZ2464+ZZ2464
++007150        723700          ZZ2464=ZZ2464+ZZ2464
++007150        647600          ZZ2464=ZZ2464+ZZ2464
++007150        517400          ZZ2464=ZZ2464+ZZ2464
++007150        007055          0 8192 -ZZ1464
++007151        517400          0 ZZ2464
+-       mark 4590, -131        /74 virg
++007152        777370          ZZ2465=ZZ2465+ZZ2465
++007152        776760          ZZ2465=ZZ2465+ZZ2465
++007152        775740          ZZ2465=ZZ2465+ZZ2465
++007152        773700          ZZ2465=ZZ2465+ZZ2465
++007152        767600          ZZ2465=ZZ2465+ZZ2465
++007152        757400          ZZ2465=ZZ2465+ZZ2465
++007152        737000          ZZ2465=ZZ2465+ZZ2465
++007152        676000          ZZ2465=ZZ2465+ZZ2465
++007152        007022          0 8192 -ZZ1465
++007153        676000          0 ZZ2465
+-       mark 4603, 95          /78 virg
++007154        000276          ZZ2466=ZZ2466+ZZ2466
++007154        000574          ZZ2466=ZZ2466+ZZ2466
++007154        001370          ZZ2466=ZZ2466+ZZ2466
++007154        002760          ZZ2466=ZZ2466+ZZ2466
++007154        005740          ZZ2466=ZZ2466+ZZ2466
++007154        013700          ZZ2466=ZZ2466+ZZ2466
++007154        027600          ZZ2466=ZZ2466+ZZ2466
++007154        057400          ZZ2466=ZZ2466+ZZ2466
++007154        007005          0 8192 -ZZ1466
++007155        057400          0 ZZ2466
+-       mark 4679, 409         / 4 boot
++007156        001462          ZZ2467=ZZ2467+ZZ2467
++007156        003144          ZZ2467=ZZ2467+ZZ2467
++007156        006310          ZZ2467=ZZ2467+ZZ2467
++007156        014620          ZZ2467=ZZ2467+ZZ2467
++007156        031440          ZZ2467=ZZ2467+ZZ2467
++007156        063100          ZZ2467=ZZ2467+ZZ2467
++007156        146200          ZZ2467=ZZ2467+ZZ2467
++007156        314400          ZZ2467=ZZ2467+ZZ2467
++007156        006671          0 8192 -ZZ1467
++007157        314400          0 ZZ2467
+-       mark 4691, 371         / 5 boot
++007160        001346          ZZ2468=ZZ2468+ZZ2468
++007160        002714          ZZ2468=ZZ2468+ZZ2468
++007160        005630          ZZ2468=ZZ2468+ZZ2468
++007160        013460          ZZ2468=ZZ2468+ZZ2468
++007160        027140          ZZ2468=ZZ2468+ZZ2468
++007160        056300          ZZ2468=ZZ2468+ZZ2468
++007160        134600          ZZ2468=ZZ2468+ZZ2468
++007160        271400          ZZ2468=ZZ2468+ZZ2468
++007160        006655          0 8192 -ZZ1468
++007161        271400          0 ZZ2468
+-       mark 4759, 46          /93 virg
++007162        000134          ZZ2469=ZZ2469+ZZ2469
++007162        000270          ZZ2469=ZZ2469+ZZ2469
++007162        000560          ZZ2469=ZZ2469+ZZ2469
++007162        001340          ZZ2469=ZZ2469+ZZ2469
++007162        002700          ZZ2469=ZZ2469+ZZ2469
++007162        005600          ZZ2469=ZZ2469+ZZ2469
++007162        013400          ZZ2469=ZZ2469+ZZ2469
++007162        027000          ZZ2469=ZZ2469+ZZ2469
++007162        006551          0 8192 -ZZ1469
++007163        027000          0 ZZ2469
+-       mark 4820, 66          /
++007164        000204          ZZ2470=ZZ2470+ZZ2470
++007164        000410          ZZ2470=ZZ2470+ZZ2470
++007164        001020          ZZ2470=ZZ2470+ZZ2470
++007164        002040          ZZ2470=ZZ2470+ZZ2470
++007164        004100          ZZ2470=ZZ2470+ZZ2470
++007164        010200          ZZ2470=ZZ2470+ZZ2470
++007164        020400          ZZ2470=ZZ2470+ZZ2470
++007164        041000          ZZ2470=ZZ2470+ZZ2470
++007164        006454          0 8192 -ZZ1470
++007165        041000          0 ZZ2470
+-       mark 4822, -223        /98 virg
++007166        777100          ZZ2471=ZZ2471+ZZ2471
++007166        776200          ZZ2471=ZZ2471+ZZ2471
++007166        774400          ZZ2471=ZZ2471+ZZ2471
++007166        771000          ZZ2471=ZZ2471+ZZ2471
++007166        762000          ZZ2471=ZZ2471+ZZ2471
++007166        744000          ZZ2471=ZZ2471+ZZ2471
++007166        710000          ZZ2471=ZZ2471+ZZ2471
++007166        620000          ZZ2471=ZZ2471+ZZ2471
++007166        006452          0 8192 -ZZ1471
++007167        620000          0 ZZ2471
+-       mark 4840, -126        /99 virg
++007170        777402          ZZ2472=ZZ2472+ZZ2472
++007170        777004          ZZ2472=ZZ2472+ZZ2472
++007170        776010          ZZ2472=ZZ2472+ZZ2472
++007170        774020          ZZ2472=ZZ2472+ZZ2472
++007170        770040          ZZ2472=ZZ2472+ZZ2472
++007170        760100          ZZ2472=ZZ2472+ZZ2472
++007170        740200          ZZ2472=ZZ2472+ZZ2472
++007170        700400          ZZ2472=ZZ2472+ZZ2472
++007170        006430          0 8192 -ZZ1472
++007171        700400          0 ZZ2472
+-       mark 4857, -294        /100 virg
++007172        776662          ZZ2473=ZZ2473+ZZ2473
++007172        775544          ZZ2473=ZZ2473+ZZ2473
++007172        773310          ZZ2473=ZZ2473+ZZ2473
++007172        766620          ZZ2473=ZZ2473+ZZ2473
++007172        755440          ZZ2473=ZZ2473+ZZ2473
++007172        733100          ZZ2473=ZZ2473+ZZ2473
++007172        666200          ZZ2473=ZZ2473+ZZ2473
++007172        554400          ZZ2473=ZZ2473+ZZ2473
++007172        006407          0 8192 -ZZ1473
++007173        554400          0 ZZ2473
+-       mark 4864, 382         /20 boot
++007174        001374          ZZ2474=ZZ2474+ZZ2474
++007174        002770          ZZ2474=ZZ2474+ZZ2474
++007174        005760          ZZ2474=ZZ2474+ZZ2474
++007174        013740          ZZ2474=ZZ2474+ZZ2474
++007174        027700          ZZ2474=ZZ2474+ZZ2474
++007174        057600          ZZ2474=ZZ2474+ZZ2474
++007174        137400          ZZ2474=ZZ2474+ZZ2474
++007174        277000          ZZ2474=ZZ2474+ZZ2474
++007174        006400          0 8192 -ZZ1474
++007175        277000          0 ZZ2474
+-       mark 4910, -41         /105 virg
++007176        777654          ZZ2475=ZZ2475+ZZ2475
++007176        777530          ZZ2475=ZZ2475+ZZ2475
++007176        777260          ZZ2475=ZZ2475+ZZ2475
++007176        776540          ZZ2475=ZZ2475+ZZ2475
++007176        775300          ZZ2475=ZZ2475+ZZ2475
++007176        772600          ZZ2475=ZZ2475+ZZ2475
++007176        765400          ZZ2475=ZZ2475+ZZ2475
++007176        753000          ZZ2475=ZZ2475+ZZ2475
++007176        006322          0 8192 -ZZ1475
++007177        753000          0 ZZ2475
+-       mark 4984, 383         /29 boot
++007200        001376          ZZ2476=ZZ2476+ZZ2476
++007200        002774          ZZ2476=ZZ2476+ZZ2476
++007200        005770          ZZ2476=ZZ2476+ZZ2476
++007200        013760          ZZ2476=ZZ2476+ZZ2476
++007200        027740          ZZ2476=ZZ2476+ZZ2476
++007200        057700          ZZ2476=ZZ2476+ZZ2476
++007200        137600          ZZ2476=ZZ2476+ZZ2476
++007200        277400          ZZ2476=ZZ2476+ZZ2476
++007200        006210          0 8192 -ZZ1476
++007201        277400          0 ZZ2476
+-       mark 4986, 322         /30 boot
++007202        001204          ZZ2477=ZZ2477+ZZ2477
++007202        002410          ZZ2477=ZZ2477+ZZ2477
++007202        005020          ZZ2477=ZZ2477+ZZ2477
++007202        012040          ZZ2477=ZZ2477+ZZ2477
++007202        024100          ZZ2477=ZZ2477+ZZ2477
++007202        050200          ZZ2477=ZZ2477+ZZ2477
++007202        120400          ZZ2477=ZZ2477+ZZ2477
++007202        241000          ZZ2477=ZZ2477+ZZ2477
++007202        006206          0 8192 -ZZ1477
++007203        241000          0 ZZ2477
+-       mark 4994, -119        /107 virg
++007204        777420          ZZ2478=ZZ2478+ZZ2478
++007204        777040          ZZ2478=ZZ2478+ZZ2478
++007204        776100          ZZ2478=ZZ2478+ZZ2478
++007204        774200          ZZ2478=ZZ2478+ZZ2478
++007204        770400          ZZ2478=ZZ2478+ZZ2478
++007204        761000          ZZ2478=ZZ2478+ZZ2478
++007204        742000          ZZ2478=ZZ2478+ZZ2478
++007204        704000          ZZ2478=ZZ2478+ZZ2478
++007204        006176          0 8192 -ZZ1478
++007205        704000          0 ZZ2478
+-       mark 5009, 396         /35 boot
++007206        001430          ZZ2479=ZZ2479+ZZ2479
++007206        003060          ZZ2479=ZZ2479+ZZ2479
++007206        006140          ZZ2479=ZZ2479+ZZ2479
++007206        014300          ZZ2479=ZZ2479+ZZ2479
++007206        030600          ZZ2479=ZZ2479+ZZ2479
++007206        061400          ZZ2479=ZZ2479+ZZ2479
++007206        143000          ZZ2479=ZZ2479+ZZ2479
++007206        306000          ZZ2479=ZZ2479+ZZ2479
++007206        006157          0 8192 -ZZ1479
++007207        306000          0 ZZ2479
+-       mark 5013, 53          /109 virg
++007210        000152          ZZ2480=ZZ2480+ZZ2480
++007210        000324          ZZ2480=ZZ2480+ZZ2480
++007210        000650          ZZ2480=ZZ2480+ZZ2480
++007210        001520          ZZ2480=ZZ2480+ZZ2480
++007210        003240          ZZ2480=ZZ2480+ZZ2480
++007210        006500          ZZ2480=ZZ2480+ZZ2480
++007210        015200          ZZ2480=ZZ2480+ZZ2480
++007210        032400          ZZ2480=ZZ2480+ZZ2480
++007210        006153          0 8192 -ZZ1480
++007211        032400          0 ZZ2480
+-       mark 5045, 444         /37 boot
++007212        001570          ZZ2481=ZZ2481+ZZ2481
++007212        003360          ZZ2481=ZZ2481+ZZ2481
++007212        006740          ZZ2481=ZZ2481+ZZ2481
++007212        015700          ZZ2481=ZZ2481+ZZ2481
++007212        033600          ZZ2481=ZZ2481+ZZ2481
++007212        067400          ZZ2481=ZZ2481+ZZ2481
++007212        157000          ZZ2481=ZZ2481+ZZ2481
++007212        336000          ZZ2481=ZZ2481+ZZ2481
++007212        006113          0 8192 -ZZ1481
++007213        336000          0 ZZ2481
+-       mark 5074, -90         /16 libr
++007214        777512          ZZ2482=ZZ2482+ZZ2482
++007214        777224          ZZ2482=ZZ2482+ZZ2482
++007214        776450          ZZ2482=ZZ2482+ZZ2482
++007214        775120          ZZ2482=ZZ2482+ZZ2482
++007214        772240          ZZ2482=ZZ2482+ZZ2482
++007214        764500          ZZ2482=ZZ2482+ZZ2482
++007214        751200          ZZ2482=ZZ2482+ZZ2482
++007214        722400          ZZ2482=ZZ2482+ZZ2482
++007214        006056          0 8192 -ZZ1482
++007215        722400          0 ZZ2482
+-       mark 5108, 57          /110 virg
++007216        000162          ZZ2483=ZZ2483+ZZ2483
++007216        000344          ZZ2483=ZZ2483+ZZ2483
++007216        000710          ZZ2483=ZZ2483+ZZ2483
++007216        001620          ZZ2483=ZZ2483+ZZ2483
++007216        003440          ZZ2483=ZZ2483+ZZ2483
++007216        007100          ZZ2483=ZZ2483+ZZ2483
++007216        016200          ZZ2483=ZZ2483+ZZ2483
++007216        034400          ZZ2483=ZZ2483+ZZ2483
++007216        006014          0 8192 -ZZ1483
++007217        034400          0 ZZ2483
+-       mark 5157, -442        /24 libr
++007220        776212          ZZ2484=ZZ2484+ZZ2484
++007220        774424          ZZ2484=ZZ2484+ZZ2484
++007220        771050          ZZ2484=ZZ2484+ZZ2484
++007220        762120          ZZ2484=ZZ2484+ZZ2484
++007220        744240          ZZ2484=ZZ2484+ZZ2484
++007220        710500          ZZ2484=ZZ2484+ZZ2484
++007220        621200          ZZ2484=ZZ2484+ZZ2484
++007220        442400          ZZ2484=ZZ2484+ZZ2484
++007220        005733          0 8192 -ZZ1484
++007221        442400          0 ZZ2484
+-       mark 5283, -221        /37 libr
++007222        777104          ZZ2485=ZZ2485+ZZ2485
++007222        776210          ZZ2485=ZZ2485+ZZ2485
++007222        774420          ZZ2485=ZZ2485+ZZ2485
++007222        771040          ZZ2485=ZZ2485+ZZ2485
++007222        762100          ZZ2485=ZZ2485+ZZ2485
++007222        744200          ZZ2485=ZZ2485+ZZ2485
++007222        710400          ZZ2485=ZZ2485+ZZ2485
++007222        621000          ZZ2485=ZZ2485+ZZ2485
++007222        005535          0 8192 -ZZ1485
++007223        621000          0 ZZ2485
+-       mark 5290, -329        /38 libr
++007224        776554          ZZ2486=ZZ2486+ZZ2486
++007224        775330          ZZ2486=ZZ2486+ZZ2486
++007224        772660          ZZ2486=ZZ2486+ZZ2486
++007224        765540          ZZ2486=ZZ2486+ZZ2486
++007224        753300          ZZ2486=ZZ2486+ZZ2486
++007224        726600          ZZ2486=ZZ2486+ZZ2486
++007224        655400          ZZ2486=ZZ2486+ZZ2486
++007224        533000          ZZ2486=ZZ2486+ZZ2486
++007224        005526          0 8192 -ZZ1486
++007225        533000          0 ZZ2486
+-       mark 5291, 247         /13 serp
++007226        000756          ZZ2487=ZZ2487+ZZ2487
++007226        001734          ZZ2487=ZZ2487+ZZ2487
++007226        003670          ZZ2487=ZZ2487+ZZ2487
++007226        007560          ZZ2487=ZZ2487+ZZ2487
++007226        017340          ZZ2487=ZZ2487+ZZ2487
++007226        036700          ZZ2487=ZZ2487+ZZ2487
++007226        075600          ZZ2487=ZZ2487+ZZ2487
++007226        173400          ZZ2487=ZZ2487+ZZ2487
++007226        005525          0 8192 -ZZ1487
++007227        173400          0 ZZ2487
+-       mark 5326, -440        /43 libr
++007230        776216          ZZ2488=ZZ2488+ZZ2488
++007230        774434          ZZ2488=ZZ2488+ZZ2488
++007230        771070          ZZ2488=ZZ2488+ZZ2488
++007230        762160          ZZ2488=ZZ2488+ZZ2488
++007230        744340          ZZ2488=ZZ2488+ZZ2488
++007230        710700          ZZ2488=ZZ2488+ZZ2488
++007230        621600          ZZ2488=ZZ2488+ZZ2488
++007230        443400          ZZ2488=ZZ2488+ZZ2488
++007230        005462          0 8192 -ZZ1488
++007231        443400          0 ZZ2488
+-       mark 5331, 455         /21 serp
++007232        001616          ZZ2489=ZZ2489+ZZ2489
++007232        003434          ZZ2489=ZZ2489+ZZ2489
++007232        007070          ZZ2489=ZZ2489+ZZ2489
++007232        016160          ZZ2489=ZZ2489+ZZ2489
++007232        034340          ZZ2489=ZZ2489+ZZ2489
++007232        070700          ZZ2489=ZZ2489+ZZ2489
++007232        161600          ZZ2489=ZZ2489+ZZ2489
++007232        343400          ZZ2489=ZZ2489+ZZ2489
++007232        005455          0 8192 -ZZ1489
++007233        343400          0 ZZ2489
+-       mark 5357, 175         /27 serp
++007234        000536          ZZ2490=ZZ2490+ZZ2490
++007234        001274          ZZ2490=ZZ2490+ZZ2490
++007234        002570          ZZ2490=ZZ2490+ZZ2490
++007234        005360          ZZ2490=ZZ2490+ZZ2490
++007234        012740          ZZ2490=ZZ2490+ZZ2490
++007234        025700          ZZ2490=ZZ2490+ZZ2490
++007234        053600          ZZ2490=ZZ2490+ZZ2490
++007234        127400          ZZ2490=ZZ2490+ZZ2490
++007234        005423          0 8192 -ZZ1490
++007235        127400          0 ZZ2490
+-       mark 5372, 420         /35 serp
++007236        001510          ZZ2491=ZZ2491+ZZ2491
++007236        003220          ZZ2491=ZZ2491+ZZ2491
++007236        006440          ZZ2491=ZZ2491+ZZ2491
++007236        015100          ZZ2491=ZZ2491+ZZ2491
++007236        032200          ZZ2491=ZZ2491+ZZ2491
++007236        064400          ZZ2491=ZZ2491+ZZ2491
++007236        151000          ZZ2491=ZZ2491+ZZ2491
++007236        322000          ZZ2491=ZZ2491+ZZ2491
++007236        005404          0 8192 -ZZ1491
++007237        322000          0 ZZ2491
+-       mark 5381, 109         /37 serp
++007240        000332          ZZ2492=ZZ2492+ZZ2492
++007240        000664          ZZ2492=ZZ2492+ZZ2492
++007240        001550          ZZ2492=ZZ2492+ZZ2492
++007240        003320          ZZ2492=ZZ2492+ZZ2492
++007240        006640          ZZ2492=ZZ2492+ZZ2492
++007240        015500          ZZ2492=ZZ2492+ZZ2492
++007240        033200          ZZ2492=ZZ2492+ZZ2492
++007240        066400          ZZ2492=ZZ2492+ZZ2492
++007240        005373          0 8192 -ZZ1492
++007241        066400          0 ZZ2492
+-       mark 5387, 484         /38 serp
++007242        001710          ZZ2493=ZZ2493+ZZ2493
++007242        003620          ZZ2493=ZZ2493+ZZ2493
++007242        007440          ZZ2493=ZZ2493+ZZ2493
++007242        017100          ZZ2493=ZZ2493+ZZ2493
++007242        036200          ZZ2493=ZZ2493+ZZ2493
++007242        074400          ZZ2493=ZZ2493+ZZ2493
++007242        171000          ZZ2493=ZZ2493+ZZ2493
++007242        362000          ZZ2493=ZZ2493+ZZ2493
++007242        005365          0 8192 -ZZ1493
++007243        362000          0 ZZ2493
+-       mark 5394, -374        /46 libr
++007244        776422          ZZ2494=ZZ2494+ZZ2494
++007244        775044          ZZ2494=ZZ2494+ZZ2494
++007244        772110          ZZ2494=ZZ2494+ZZ2494
++007244        764220          ZZ2494=ZZ2494+ZZ2494
++007244        750440          ZZ2494=ZZ2494+ZZ2494
++007244        721100          ZZ2494=ZZ2494+ZZ2494
++007244        642200          ZZ2494=ZZ2494+ZZ2494
++007244        504400          ZZ2494=ZZ2494+ZZ2494
++007244        005356          0 8192 -ZZ1494
++007245        504400          0 ZZ2494
+-       mark 5415, 364         /41 serp
++007246        001330          ZZ2495=ZZ2495+ZZ2495
++007246        002660          ZZ2495=ZZ2495+ZZ2495
++007246        005540          ZZ2495=ZZ2495+ZZ2495
++007246        013300          ZZ2495=ZZ2495+ZZ2495
++007246        026600          ZZ2495=ZZ2495+ZZ2495
++007246        055400          ZZ2495=ZZ2495+ZZ2495
++007246        133000          ZZ2495=ZZ2495+ZZ2495
++007246        266000          ZZ2495=ZZ2495+ZZ2495
++007246        005331          0 8192 -ZZ1495
++007247        266000          0 ZZ2495
+-       mark 5419, -318        /48 libr
++007250        776602          ZZ2496=ZZ2496+ZZ2496
++007250        775404          ZZ2496=ZZ2496+ZZ2496
++007250        773010          ZZ2496=ZZ2496+ZZ2496
++007250        766020          ZZ2496=ZZ2496+ZZ2496
++007250        754040          ZZ2496=ZZ2496+ZZ2496
++007250        730100          ZZ2496=ZZ2496+ZZ2496
++007250        660200          ZZ2496=ZZ2496+ZZ2496
++007250        540400          ZZ2496=ZZ2496+ZZ2496
++007250        005325          0 8192 -ZZ1496
++007251        540400          0 ZZ2496
+-       mark 5455, -253        /xi scor
++007252        777004          ZZ2497=ZZ2497+ZZ2497
++007252        776010          ZZ2497=ZZ2497+ZZ2497
++007252        774020          ZZ2497=ZZ2497+ZZ2497
++007252        770040          ZZ2497=ZZ2497+ZZ2497
++007252        760100          ZZ2497=ZZ2497+ZZ2497
++007252        740200          ZZ2497=ZZ2497+ZZ2497
++007252        700400          ZZ2497=ZZ2497+ZZ2497
++007252        601000          ZZ2497=ZZ2497+ZZ2497
++007252        005261          0 8192 -ZZ1497
++007253        601000          0 ZZ2497
+-       mark 5467, -464        / 9 scor
++007254        776136          ZZ2498=ZZ2498+ZZ2498
++007254        774274          ZZ2498=ZZ2498+ZZ2498
++007254        770570          ZZ2498=ZZ2498+ZZ2498
++007254        761360          ZZ2498=ZZ2498+ZZ2498
++007254        742740          ZZ2498=ZZ2498+ZZ2498
++007254        705700          ZZ2498=ZZ2498+ZZ2498
++007254        613600          ZZ2498=ZZ2498+ZZ2498
++007254        427400          ZZ2498=ZZ2498+ZZ2498
++007254        005245          0 8192 -ZZ1498
++007255        427400          0 ZZ2498
+-       mark 5470, -469        /10 scor
++007256        776124          ZZ2499=ZZ2499+ZZ2499
++007256        774250          ZZ2499=ZZ2499+ZZ2499
++007256        770520          ZZ2499=ZZ2499+ZZ2499
++007256        761240          ZZ2499=ZZ2499+ZZ2499
++007256        742500          ZZ2499=ZZ2499+ZZ2499
++007256        705200          ZZ2499=ZZ2499+ZZ2499
++007256        612400          ZZ2499=ZZ2499+ZZ2499
++007256        425000          ZZ2499=ZZ2499+ZZ2499
++007256        005242          0 8192 -ZZ1499
++007257        425000          0 ZZ2499
+-       mark 5497, -437        /14 scor
++007260        776224          ZZ2500=ZZ2500+ZZ2500
++007260        774450          ZZ2500=ZZ2500+ZZ2500
++007260        771120          ZZ2500=ZZ2500+ZZ2500
++007260        762240          ZZ2500=ZZ2500+ZZ2500
++007260        744500          ZZ2500=ZZ2500+ZZ2500
++007260        711200          ZZ2500=ZZ2500+ZZ2500
++007260        622400          ZZ2500=ZZ2500+ZZ2500
++007260        445000          ZZ2500=ZZ2500+ZZ2500
++007260        005207          0 8192 -ZZ1500
++007261        445000          0 ZZ2500
+-       mark 5499, -223        /15 scor
++007262        777100          ZZ2501=ZZ2501+ZZ2501
++007262        776200          ZZ2501=ZZ2501+ZZ2501
++007262        774400          ZZ2501=ZZ2501+ZZ2501
++007262        771000          ZZ2501=ZZ2501+ZZ2501
++007262        762000          ZZ2501=ZZ2501+ZZ2501
++007262        744000          ZZ2501=ZZ2501+ZZ2501
++007262        710000          ZZ2501=ZZ2501+ZZ2501
++007262        620000          ZZ2501=ZZ2501+ZZ2501
++007262        005205          0 8192 -ZZ1501
++007263        620000          0 ZZ2501
+-       mark 5558, 29          /50 serp
++007264        000072          ZZ2502=ZZ2502+ZZ2502
++007264        000164          ZZ2502=ZZ2502+ZZ2502
++007264        000350          ZZ2502=ZZ2502+ZZ2502
++007264        000720          ZZ2502=ZZ2502+ZZ2502
++007264        001640          ZZ2502=ZZ2502+ZZ2502
++007264        003500          ZZ2502=ZZ2502+ZZ2502
++007264        007200          ZZ2502=ZZ2502+ZZ2502
++007264        016400          ZZ2502=ZZ2502+ZZ2502
++007264        005112          0 8192 -ZZ1502
++007265        016400          0 ZZ2502
+-       mark 5561, 441         /20 herc
++007266        001562          ZZ2503=ZZ2503+ZZ2503
++007266        003344          ZZ2503=ZZ2503+ZZ2503
++007266        006710          ZZ2503=ZZ2503+ZZ2503
++007266        015620          ZZ2503=ZZ2503+ZZ2503
++007266        033440          ZZ2503=ZZ2503+ZZ2503
++007266        067100          ZZ2503=ZZ2503+ZZ2503
++007266        156200          ZZ2503=ZZ2503+ZZ2503
++007266        334400          ZZ2503=ZZ2503+ZZ2503
++007266        005107          0 8192 -ZZ1503
++007267        334400          0 ZZ2503
+-       mark 5565, -451        / 4 ophi
++007270        776170          ZZ2504=ZZ2504+ZZ2504
++007270        774360          ZZ2504=ZZ2504+ZZ2504
++007270        770740          ZZ2504=ZZ2504+ZZ2504
++007270        761700          ZZ2504=ZZ2504+ZZ2504
++007270        743600          ZZ2504=ZZ2504+ZZ2504
++007270        707400          ZZ2504=ZZ2504+ZZ2504
++007270        617000          ZZ2504=ZZ2504+ZZ2504
++007270        436000          ZZ2504=ZZ2504+ZZ2504
++007270        005103          0 8192 -ZZ1504
++007271        436000          0 ZZ2504
+-       mark 5580, 325         /24 herc
++007272        001212          ZZ2505=ZZ2505+ZZ2505
++007272        002424          ZZ2505=ZZ2505+ZZ2505
++007272        005050          ZZ2505=ZZ2505+ZZ2505
++007272        012120          ZZ2505=ZZ2505+ZZ2505
++007272        024240          ZZ2505=ZZ2505+ZZ2505
++007272        050500          ZZ2505=ZZ2505+ZZ2505
++007272        121200          ZZ2505=ZZ2505+ZZ2505
++007272        242400          ZZ2505=ZZ2505+ZZ2505
++007272        005064          0 8192 -ZZ1505
++007273        242400          0 ZZ2505
+-       mark 5582, -415        / 7 ophi
++007274        776300          ZZ2506=ZZ2506+ZZ2506
++007274        774600          ZZ2506=ZZ2506+ZZ2506
++007274        771400          ZZ2506=ZZ2506+ZZ2506
++007274        763000          ZZ2506=ZZ2506+ZZ2506
++007274        746000          ZZ2506=ZZ2506+ZZ2506
++007274        714000          ZZ2506=ZZ2506+ZZ2506
++007274        630000          ZZ2506=ZZ2506+ZZ2506
++007274        460000          ZZ2506=ZZ2506+ZZ2506
++007274        005062          0 8192 -ZZ1506
++007275        460000          0 ZZ2506
+-       mark 5589, -186        / 3 ophi
++007276        777212          ZZ2507=ZZ2507+ZZ2507
++007276        776424          ZZ2507=ZZ2507+ZZ2507
++007276        775050          ZZ2507=ZZ2507+ZZ2507
++007276        772120          ZZ2507=ZZ2507+ZZ2507
++007276        764240          ZZ2507=ZZ2507+ZZ2507
++007276        750500          ZZ2507=ZZ2507+ZZ2507
++007276        721200          ZZ2507=ZZ2507+ZZ2507
++007276        642400          ZZ2507=ZZ2507+ZZ2507
++007276        005053          0 8192 -ZZ1507
++007277        642400          0 ZZ2507
+-       mark 5606, -373        / 8 ophi
++007300        776424          ZZ2508=ZZ2508+ZZ2508
++007300        775050          ZZ2508=ZZ2508+ZZ2508
++007300        772120          ZZ2508=ZZ2508+ZZ2508
++007300        764240          ZZ2508=ZZ2508+ZZ2508
++007300        750500          ZZ2508=ZZ2508+ZZ2508
++007300        721200          ZZ2508=ZZ2508+ZZ2508
++007300        642400          ZZ2508=ZZ2508+ZZ2508
++007300        505000          ZZ2508=ZZ2508+ZZ2508
++007300        005032          0 8192 -ZZ1508
++007301        505000          0 ZZ2508
+-       mark 5609, 50          /10 ophi
++007302        000144          ZZ2509=ZZ2509+ZZ2509
++007302        000310          ZZ2509=ZZ2509+ZZ2509
++007302        000620          ZZ2509=ZZ2509+ZZ2509
++007302        001440          ZZ2509=ZZ2509+ZZ2509
++007302        003100          ZZ2509=ZZ2509+ZZ2509
++007302        006200          ZZ2509=ZZ2509+ZZ2509
++007302        014400          ZZ2509=ZZ2509+ZZ2509
++007302        031000          ZZ2509=ZZ2509+ZZ2509
++007302        005027          0 8192 -ZZ1509
++007303        031000          0 ZZ2509
+-       mark 5610, -484        / 9 ophi
++007304        776066          ZZ2510=ZZ2510+ZZ2510
++007304        774154          ZZ2510=ZZ2510+ZZ2510
++007304        770330          ZZ2510=ZZ2510+ZZ2510
++007304        760660          ZZ2510=ZZ2510+ZZ2510
++007304        741540          ZZ2510=ZZ2510+ZZ2510
++007304        703300          ZZ2510=ZZ2510+ZZ2510
++007304        606600          ZZ2510=ZZ2510+ZZ2510
++007304        415400          ZZ2510=ZZ2510+ZZ2510
++007304        005026          0 8192 -ZZ1510
++007305        415400          0 ZZ2510
+-       mark 5620, 266         /29 herc
++007306        001024          ZZ2511=ZZ2511+ZZ2511
++007306        002050          ZZ2511=ZZ2511+ZZ2511
++007306        004120          ZZ2511=ZZ2511+ZZ2511
++007306        010240          ZZ2511=ZZ2511+ZZ2511
++007306        020500          ZZ2511=ZZ2511+ZZ2511
++007306        041200          ZZ2511=ZZ2511+ZZ2511
++007306        102400          ZZ2511=ZZ2511+ZZ2511
++007306        205000          ZZ2511=ZZ2511+ZZ2511
++007306        005014          0 8192 -ZZ1511
++007307        205000          0 ZZ2511
+-       mark 5713, -241        /20 ophi
++007310        777034          ZZ2512=ZZ2512+ZZ2512
++007310        776070          ZZ2512=ZZ2512+ZZ2512
++007310        774160          ZZ2512=ZZ2512+ZZ2512
++007310        770340          ZZ2512=ZZ2512+ZZ2512
++007310        760700          ZZ2512=ZZ2512+ZZ2512
++007310        741600          ZZ2512=ZZ2512+ZZ2512
++007310        703400          ZZ2512=ZZ2512+ZZ2512
++007310        607000          ZZ2512=ZZ2512+ZZ2512
++007310        004657          0 8192 -ZZ1512
++007311        607000          0 ZZ2512
+-       mark 5742, 235         /25 ophi
++007312        000726          ZZ2513=ZZ2513+ZZ2513
++007312        001654          ZZ2513=ZZ2513+ZZ2513
++007312        003530          ZZ2513=ZZ2513+ZZ2513
++007312        007260          ZZ2513=ZZ2513+ZZ2513
++007312        016540          ZZ2513=ZZ2513+ZZ2513
++007312        035300          ZZ2513=ZZ2513+ZZ2513
++007312        072600          ZZ2513=ZZ2513+ZZ2513
++007312        165400          ZZ2513=ZZ2513+ZZ2513
++007312        004622          0 8192 -ZZ1513
++007313        165400          0 ZZ2513
+-       mark 5763, 217         /27 ophi
++007314        000662          ZZ2514=ZZ2514+ZZ2514
++007314        001544          ZZ2514=ZZ2514+ZZ2514
++007314        003310          ZZ2514=ZZ2514+ZZ2514
++007314        006620          ZZ2514=ZZ2514+ZZ2514
++007314        015440          ZZ2514=ZZ2514+ZZ2514
++007314        033100          ZZ2514=ZZ2514+ZZ2514
++007314        066200          ZZ2514=ZZ2514+ZZ2514
++007314        154400          ZZ2514=ZZ2514+ZZ2514
++007314        004575          0 8192 -ZZ1514
++007315        154400          0 ZZ2514
+-       mark 5807, 293         /60 herc
++007316        001112          ZZ2515=ZZ2515+ZZ2515
++007316        002224          ZZ2515=ZZ2515+ZZ2515
++007316        004450          ZZ2515=ZZ2515+ZZ2515
++007316        011120          ZZ2515=ZZ2515+ZZ2515
++007316        022240          ZZ2515=ZZ2515+ZZ2515
++007316        044500          ZZ2515=ZZ2515+ZZ2515
++007316        111200          ZZ2515=ZZ2515+ZZ2515
++007316        222400          ZZ2515=ZZ2515+ZZ2515
++007316        004521          0 8192 -ZZ1515
++007317        222400          0 ZZ2515
+-       mark 5868, -8          /41 ophi
++007320        777756          ZZ2516=ZZ2516+ZZ2516
++007320        777734          ZZ2516=ZZ2516+ZZ2516
++007320        777670          ZZ2516=ZZ2516+ZZ2516
++007320        777560          ZZ2516=ZZ2516+ZZ2516
++007320        777340          ZZ2516=ZZ2516+ZZ2516
++007320        776700          ZZ2516=ZZ2516+ZZ2516
++007320        775600          ZZ2516=ZZ2516+ZZ2516
++007320        773400          ZZ2516=ZZ2516+ZZ2516
++007320        004424          0 8192 -ZZ1516
++007321        773400          0 ZZ2516
+-       mark 5888, -478        /40 ophi
++007322        776102          ZZ2517=ZZ2517+ZZ2517
++007322        774204          ZZ2517=ZZ2517+ZZ2517
++007322        770410          ZZ2517=ZZ2517+ZZ2517
++007322        761020          ZZ2517=ZZ2517+ZZ2517
++007322        742040          ZZ2517=ZZ2517+ZZ2517
++007322        704100          ZZ2517=ZZ2517+ZZ2517
++007322        610200          ZZ2517=ZZ2517+ZZ2517
++007322        420400          ZZ2517=ZZ2517+ZZ2517
++007322        004400          0 8192 -ZZ1517
++007323        420400          0 ZZ2517
+-       mark 5889, -290        /53 serp
++007324        776672          ZZ2518=ZZ2518+ZZ2518
++007324        775564          ZZ2518=ZZ2518+ZZ2518
++007324        773350          ZZ2518=ZZ2518+ZZ2518
++007324        766720          ZZ2518=ZZ2518+ZZ2518
++007324        755640          ZZ2518=ZZ2518+ZZ2518
++007324        733500          ZZ2518=ZZ2518+ZZ2518
++007324        667200          ZZ2518=ZZ2518+ZZ2518
++007324        556400          ZZ2518=ZZ2518+ZZ2518
++007324        004377          0 8192 -ZZ1518
++007325        556400          0 ZZ2518
+-       mark 5924, -114        /
++007326        777432          ZZ2519=ZZ2519+ZZ2519
++007326        777064          ZZ2519=ZZ2519+ZZ2519
++007326        776150          ZZ2519=ZZ2519+ZZ2519
++007326        774320          ZZ2519=ZZ2519+ZZ2519
++007326        770640          ZZ2519=ZZ2519+ZZ2519
++007326        761500          ZZ2519=ZZ2519+ZZ2519
++007326        743200          ZZ2519=ZZ2519+ZZ2519
++007326        706400          ZZ2519=ZZ2519+ZZ2519
++007326        004334          0 8192 -ZZ1519
++007327        706400          0 ZZ2519
+-       mark 5925, 96          /49 ophi
++007330        000300          ZZ2520=ZZ2520+ZZ2520
++007330        000600          ZZ2520=ZZ2520+ZZ2520
++007330        001400          ZZ2520=ZZ2520+ZZ2520
++007330        003000          ZZ2520=ZZ2520+ZZ2520
++007330        006000          ZZ2520=ZZ2520+ZZ2520
++007330        014000          ZZ2520=ZZ2520+ZZ2520
++007330        030000          ZZ2520=ZZ2520+ZZ2520
++007330        060000          ZZ2520=ZZ2520+ZZ2520
++007330        004333          0 8192 -ZZ1520
++007331        060000          0 ZZ2520
+-       mark 5987, -183        /57 ophi
++007332        777220          ZZ2521=ZZ2521+ZZ2521
++007332        776440          ZZ2521=ZZ2521+ZZ2521
++007332        775100          ZZ2521=ZZ2521+ZZ2521
++007332        772200          ZZ2521=ZZ2521+ZZ2521
++007332        764400          ZZ2521=ZZ2521+ZZ2521
++007332        751000          ZZ2521=ZZ2521+ZZ2521
++007332        722000          ZZ2521=ZZ2521+ZZ2521
++007332        644000          ZZ2521=ZZ2521+ZZ2521
++007332        004235          0 8192 -ZZ1521
++007333        644000          0 ZZ2521
+-       mark 6006, -292        /56 serp
++007334        776666          ZZ2522=ZZ2522+ZZ2522
++007334        775554          ZZ2522=ZZ2522+ZZ2522
++007334        773330          ZZ2522=ZZ2522+ZZ2522
++007334        766660          ZZ2522=ZZ2522+ZZ2522
++007334        755540          ZZ2522=ZZ2522+ZZ2522
++007334        733300          ZZ2522=ZZ2522+ZZ2522
++007334        666600          ZZ2522=ZZ2522+ZZ2522
++007334        555400          ZZ2522=ZZ2522+ZZ2522
++007334        004212          0 8192 -ZZ1522
++007335        555400          0 ZZ2522
+-       mark 6016, -492        /58 ophi
++007336        776046          ZZ2523=ZZ2523+ZZ2523
++007336        774114          ZZ2523=ZZ2523+ZZ2523
++007336        770230          ZZ2523=ZZ2523+ZZ2523
++007336        760460          ZZ2523=ZZ2523+ZZ2523
++007336        741140          ZZ2523=ZZ2523+ZZ2523
++007336        702300          ZZ2523=ZZ2523+ZZ2523
++007336        604600          ZZ2523=ZZ2523+ZZ2523
++007336        411400          ZZ2523=ZZ2523+ZZ2523
++007336        004200          0 8192 -ZZ1523
++007337        411400          0 ZZ2523
+-       mark 6117, -84         /57 serp
++007340        777526          ZZ2524=ZZ2524+ZZ2524
++007340        777254          ZZ2524=ZZ2524+ZZ2524
++007340        776530          ZZ2524=ZZ2524+ZZ2524
++007340        775260          ZZ2524=ZZ2524+ZZ2524
++007340        772540          ZZ2524=ZZ2524+ZZ2524
++007340        765300          ZZ2524=ZZ2524+ZZ2524
++007340        752600          ZZ2524=ZZ2524+ZZ2524
++007340        725400          ZZ2524=ZZ2524+ZZ2524
++007340        004033          0 8192 -ZZ1524
++007341        725400          0 ZZ2524
+-       mark 6117, 99          /66 ophi
++007342        000306          ZZ2525=ZZ2525+ZZ2525
++007342        000614          ZZ2525=ZZ2525+ZZ2525
++007342        001430          ZZ2525=ZZ2525+ZZ2525
++007342        003060          ZZ2525=ZZ2525+ZZ2525
++007342        006140          ZZ2525=ZZ2525+ZZ2525
++007342        014300          ZZ2525=ZZ2525+ZZ2525
++007342        030600          ZZ2525=ZZ2525+ZZ2525
++007342        061400          ZZ2525=ZZ2525+ZZ2525
++007342        004033          0 8192 -ZZ1525
++007343        061400          0 ZZ2525
+-       mark 6119, 381         /93 herc
++007344        001372          ZZ2526=ZZ2526+ZZ2526
++007344        002764          ZZ2526=ZZ2526+ZZ2526
++007344        005750          ZZ2526=ZZ2526+ZZ2526
++007344        013720          ZZ2526=ZZ2526+ZZ2526
++007344        027640          ZZ2526=ZZ2526+ZZ2526
++007344        057500          ZZ2526=ZZ2526+ZZ2526
++007344        137200          ZZ2526=ZZ2526+ZZ2526
++007344        276400          ZZ2526=ZZ2526+ZZ2526
++007344        004031          0 8192 -ZZ1526
++007345        276400          0 ZZ2526
+-       mark 6119, 67          /67 ophi
++007346        000206          ZZ2527=ZZ2527+ZZ2527
++007346        000414          ZZ2527=ZZ2527+ZZ2527
++007346        001030          ZZ2527=ZZ2527+ZZ2527
++007346        002060          ZZ2527=ZZ2527+ZZ2527
++007346        004140          ZZ2527=ZZ2527+ZZ2527
++007346        010300          ZZ2527=ZZ2527+ZZ2527
++007346        020600          ZZ2527=ZZ2527+ZZ2527
++007346        041400          ZZ2527=ZZ2527+ZZ2527
++007346        004031          0 8192 -ZZ1527
++007347        041400          0 ZZ2527
+-       mark 6125, 30          /68 ophi
++007350        000074          ZZ2528=ZZ2528+ZZ2528
++007350        000170          ZZ2528=ZZ2528+ZZ2528
++007350        000360          ZZ2528=ZZ2528+ZZ2528
++007350        000740          ZZ2528=ZZ2528+ZZ2528
++007350        001700          ZZ2528=ZZ2528+ZZ2528
++007350        003600          ZZ2528=ZZ2528+ZZ2528
++007350        007400          ZZ2528=ZZ2528+ZZ2528
++007350        017000          ZZ2528=ZZ2528+ZZ2528
++007350        004023          0 8192 -ZZ1528
++007351        017000          0 ZZ2528
+-       mark 6146, 57          /70 ophi
++007352        000162          ZZ2529=ZZ2529+ZZ2529
++007352        000344          ZZ2529=ZZ2529+ZZ2529
++007352        000710          ZZ2529=ZZ2529+ZZ2529
++007352        001620          ZZ2529=ZZ2529+ZZ2529
++007352        003440          ZZ2529=ZZ2529+ZZ2529
++007352        007100          ZZ2529=ZZ2529+ZZ2529
++007352        016200          ZZ2529=ZZ2529+ZZ2529
++007352        034400          ZZ2529=ZZ2529+ZZ2529
++007352        003776          0 8192 -ZZ1529
++007353        034400          0 ZZ2529
+-       mark 6158, 198         /71 ophi
++007354        000614          ZZ2530=ZZ2530+ZZ2530
++007354        001430          ZZ2530=ZZ2530+ZZ2530
++007354        003060          ZZ2530=ZZ2530+ZZ2530
++007354        006140          ZZ2530=ZZ2530+ZZ2530
++007354        014300          ZZ2530=ZZ2530+ZZ2530
++007354        030600          ZZ2530=ZZ2530+ZZ2530
++007354        061400          ZZ2530=ZZ2530+ZZ2530
++007354        143000          ZZ2530=ZZ2530+ZZ2530
++007354        003762          0 8192 -ZZ1530
++007355        143000          0 ZZ2530
+-       mark 6170, 473         /102 herc
++007356        001662          ZZ2531=ZZ2531+ZZ2531
++007356        003544          ZZ2531=ZZ2531+ZZ2531
++007356        007310          ZZ2531=ZZ2531+ZZ2531
++007356        016620          ZZ2531=ZZ2531+ZZ2531
++007356        035440          ZZ2531=ZZ2531+ZZ2531
++007356        073100          ZZ2531=ZZ2531+ZZ2531
++007356        166200          ZZ2531=ZZ2531+ZZ2531
++007356        354400          ZZ2531=ZZ2531+ZZ2531
++007356        003746          0 8192 -ZZ1531
++007357        354400          0 ZZ2531
+-       mark 6188, -480        /13 sgtr
++007360        776076          ZZ2532=ZZ2532+ZZ2532
++007360        774174          ZZ2532=ZZ2532+ZZ2532
++007360        770370          ZZ2532=ZZ2532+ZZ2532
++007360        760760          ZZ2532=ZZ2532+ZZ2532
++007360        741740          ZZ2532=ZZ2532+ZZ2532
++007360        703700          ZZ2532=ZZ2532+ZZ2532
++007360        607600          ZZ2532=ZZ2532+ZZ2532
++007360        417400          ZZ2532=ZZ2532+ZZ2532
++007360        003724          0 8192 -ZZ1532
++007361        417400          0 ZZ2532
+-       mark 6234, 76          /74 ophi
++007362        000230          ZZ2533=ZZ2533+ZZ2533
++007362        000460          ZZ2533=ZZ2533+ZZ2533
++007362        001140          ZZ2533=ZZ2533+ZZ2533
++007362        002300          ZZ2533=ZZ2533+ZZ2533
++007362        004600          ZZ2533=ZZ2533+ZZ2533
++007362        011400          ZZ2533=ZZ2533+ZZ2533
++007362        023000          ZZ2533=ZZ2533+ZZ2533
++007362        046000          ZZ2533=ZZ2533+ZZ2533
++007362        003646          0 8192 -ZZ1533
++007363        046000          0 ZZ2533
+-       mark 6235, 499         /106 herc
++007364        001746          ZZ2534=ZZ2534+ZZ2534
++007364        003714          ZZ2534=ZZ2534+ZZ2534
++007364        007630          ZZ2534=ZZ2534+ZZ2534
++007364        017460          ZZ2534=ZZ2534+ZZ2534
++007364        037140          ZZ2534=ZZ2534+ZZ2534
++007364        076300          ZZ2534=ZZ2534+ZZ2534
++007364        174600          ZZ2534=ZZ2534+ZZ2534
++007364        371400          ZZ2534=ZZ2534+ZZ2534
++007364        003645          0 8192 -ZZ1534
++007365        371400          0 ZZ2534
+-       mark 6247, -204        /xi scut
++007366        777146          ZZ2535=ZZ2535+ZZ2535
++007366        776314          ZZ2535=ZZ2535+ZZ2535
++007366        774630          ZZ2535=ZZ2535+ZZ2535
++007366        771460          ZZ2535=ZZ2535+ZZ2535
++007366        763140          ZZ2535=ZZ2535+ZZ2535
++007366        746300          ZZ2535=ZZ2535+ZZ2535
++007366        714600          ZZ2535=ZZ2535+ZZ2535
++007366        631400          ZZ2535=ZZ2535+ZZ2535
++007366        003631          0 8192 -ZZ1535
++007367        631400          0 ZZ2535
+-       mark 6254, -469        /21 sgtr
++007370        776124          ZZ2536=ZZ2536+ZZ2536
++007370        774250          ZZ2536=ZZ2536+ZZ2536
++007370        770520          ZZ2536=ZZ2536+ZZ2536
++007370        761240          ZZ2536=ZZ2536+ZZ2536
++007370        742500          ZZ2536=ZZ2536+ZZ2536
++007370        705200          ZZ2536=ZZ2536+ZZ2536
++007370        612400          ZZ2536=ZZ2536+ZZ2536
++007370        425000          ZZ2536=ZZ2536+ZZ2536
++007370        003622          0 8192 -ZZ1536
++007371        425000          0 ZZ2536
+-       mark 6255, 494         /109 herc
++007372        001734          ZZ2537=ZZ2537+ZZ2537
++007372        003670          ZZ2537=ZZ2537+ZZ2537
++007372        007560          ZZ2537=ZZ2537+ZZ2537
++007372        017340          ZZ2537=ZZ2537+ZZ2537
++007372        036700          ZZ2537=ZZ2537+ZZ2537
++007372        075600          ZZ2537=ZZ2537+ZZ2537
++007372        173400          ZZ2537=ZZ2537+ZZ2537
++007372        367000          ZZ2537=ZZ2537+ZZ2537
++007372        003621          0 8192 -ZZ1537
++007373        367000          0 ZZ2537
+-       mark 6278, -333        /ga scut
++007374        776544          ZZ2538=ZZ2538+ZZ2538
++007374        775310          ZZ2538=ZZ2538+ZZ2538
++007374        772620          ZZ2538=ZZ2538+ZZ2538
++007374        765440          ZZ2538=ZZ2538+ZZ2538
++007374        753100          ZZ2538=ZZ2538+ZZ2538
++007374        726200          ZZ2538=ZZ2538+ZZ2538
++007374        654400          ZZ2538=ZZ2538+ZZ2538
++007374        531000          ZZ2538=ZZ2538+ZZ2538
++007374        003572          0 8192 -ZZ1538
++007375        531000          0 ZZ2538
+-       mark 6313, -189        /al scut
++007376        777204          ZZ2539=ZZ2539+ZZ2539
++007376        776410          ZZ2539=ZZ2539+ZZ2539
++007376        775020          ZZ2539=ZZ2539+ZZ2539
++007376        772040          ZZ2539=ZZ2539+ZZ2539
++007376        764100          ZZ2539=ZZ2539+ZZ2539
++007376        750200          ZZ2539=ZZ2539+ZZ2539
++007376        720400          ZZ2539=ZZ2539+ZZ2539
++007376        641000          ZZ2539=ZZ2539+ZZ2539
++007376        003527          0 8192 -ZZ1539
++007377        641000          0 ZZ2539
+-       mark 6379, 465         /110 herc
++007400        001642          ZZ2540=ZZ2540+ZZ2540
++007400        003504          ZZ2540=ZZ2540+ZZ2540
++007400        007210          ZZ2540=ZZ2540+ZZ2540
++007400        016420          ZZ2540=ZZ2540+ZZ2540
++007400        035040          ZZ2540=ZZ2540+ZZ2540
++007400        072100          ZZ2540=ZZ2540+ZZ2540
++007400        164200          ZZ2540=ZZ2540+ZZ2540
++007400        350400          ZZ2540=ZZ2540+ZZ2540
++007400        003425          0 8192 -ZZ1540
++007401        350400          0 ZZ2540
+-       mark 6382, -110        /be scut
++007402        777442          ZZ2541=ZZ2541+ZZ2541
++007402        777104          ZZ2541=ZZ2541+ZZ2541
++007402        776210          ZZ2541=ZZ2541+ZZ2541
++007402        774420          ZZ2541=ZZ2541+ZZ2541
++007402        771040          ZZ2541=ZZ2541+ZZ2541
++007402        762100          ZZ2541=ZZ2541+ZZ2541
++007402        744200          ZZ2541=ZZ2541+ZZ2541
++007402        710400          ZZ2541=ZZ2541+ZZ2541
++007402        003422          0 8192 -ZZ1541
++007403        710400          0 ZZ2541
+-       mark 6386, 411         /111 herc
++007404        001466          ZZ2542=ZZ2542+ZZ2542
++007404        003154          ZZ2542=ZZ2542+ZZ2542
++007404        006330          ZZ2542=ZZ2542+ZZ2542
++007404        014660          ZZ2542=ZZ2542+ZZ2542
++007404        031540          ZZ2542=ZZ2542+ZZ2542
++007404        063300          ZZ2542=ZZ2542+ZZ2542
++007404        146600          ZZ2542=ZZ2542+ZZ2542
++007404        315400          ZZ2542=ZZ2542+ZZ2542
++007404        003416          0 8192 -ZZ1542
++007405        315400          0 ZZ2542
+-       mark 6436, 93          /63 serp
++007406        000272          ZZ2543=ZZ2543+ZZ2543
++007406        000564          ZZ2543=ZZ2543+ZZ2543
++007406        001350          ZZ2543=ZZ2543+ZZ2543
++007406        002720          ZZ2543=ZZ2543+ZZ2543
++007406        005640          ZZ2543=ZZ2543+ZZ2543
++007406        013500          ZZ2543=ZZ2543+ZZ2543
++007406        027200          ZZ2543=ZZ2543+ZZ2543
++007406        056400          ZZ2543=ZZ2543+ZZ2543
++007406        003334          0 8192 -ZZ1543
++007407        056400          0 ZZ2543
+-       mark 6457, 340         /13 aqil
++007410        001250          ZZ2544=ZZ2544+ZZ2544
++007410        002520          ZZ2544=ZZ2544+ZZ2544
++007410        005240          ZZ2544=ZZ2544+ZZ2544
++007410        012500          ZZ2544=ZZ2544+ZZ2544
++007410        025200          ZZ2544=ZZ2544+ZZ2544
++007410        052400          ZZ2544=ZZ2544+ZZ2544
++007410        125000          ZZ2544=ZZ2544+ZZ2544
++007410        252000          ZZ2544=ZZ2544+ZZ2544
++007410        003307          0 8192 -ZZ1544
++007411        252000          0 ZZ2544
+-       mark 6465, -134        /12 aqil
++007412        777362          ZZ2545=ZZ2545+ZZ2545
++007412        776744          ZZ2545=ZZ2545+ZZ2545
++007412        775710          ZZ2545=ZZ2545+ZZ2545
++007412        773620          ZZ2545=ZZ2545+ZZ2545
++007412        767440          ZZ2545=ZZ2545+ZZ2545
++007412        757100          ZZ2545=ZZ2545+ZZ2545
++007412        736200          ZZ2545=ZZ2545+ZZ2545
++007412        674400          ZZ2545=ZZ2545+ZZ2545
++007412        003277          0 8192 -ZZ1545
++007413        674400          0 ZZ2545
+-       mark 6478, -498        /39 sgtr
++007414        776032          ZZ2546=ZZ2546+ZZ2546
++007414        774064          ZZ2546=ZZ2546+ZZ2546
++007414        770150          ZZ2546=ZZ2546+ZZ2546
++007414        760320          ZZ2546=ZZ2546+ZZ2546
++007414        740640          ZZ2546=ZZ2546+ZZ2546
++007414        701500          ZZ2546=ZZ2546+ZZ2546
++007414        603200          ZZ2546=ZZ2546+ZZ2546
++007414        406400          ZZ2546=ZZ2546+ZZ2546
++007414        003262          0 8192 -ZZ1546
++007415        406400          0 ZZ2546
+-       mark 6553, 483         / 1 vulp
++007416        001706          ZZ2547=ZZ2547+ZZ2547
++007416        003614          ZZ2547=ZZ2547+ZZ2547
++007416        007430          ZZ2547=ZZ2547+ZZ2547
++007416        017060          ZZ2547=ZZ2547+ZZ2547
++007416        036140          ZZ2547=ZZ2547+ZZ2547
++007416        074300          ZZ2547=ZZ2547+ZZ2547
++007416        170600          ZZ2547=ZZ2547+ZZ2547
++007416        361400          ZZ2547=ZZ2547+ZZ2547
++007416        003147          0 8192 -ZZ1547
++007417        361400          0 ZZ2547
+-       mark 6576, -410        /44 sgtr
++007420        776312          ZZ2548=ZZ2548+ZZ2548
++007420        774624          ZZ2548=ZZ2548+ZZ2548
++007420        771450          ZZ2548=ZZ2548+ZZ2548
++007420        763120          ZZ2548=ZZ2548+ZZ2548
++007420        746240          ZZ2548=ZZ2548+ZZ2548
++007420        714500          ZZ2548=ZZ2548+ZZ2548
++007420        631200          ZZ2548=ZZ2548+ZZ2548
++007420        462400          ZZ2548=ZZ2548+ZZ2548
++007420        003120          0 8192 -ZZ1548
++007421        462400          0 ZZ2548
+-       mark 6576, -368        /46 sgtr
++007422        776436          ZZ2549=ZZ2549+ZZ2549
++007422        775074          ZZ2549=ZZ2549+ZZ2549
++007422        772170          ZZ2549=ZZ2549+ZZ2549
++007422        764360          ZZ2549=ZZ2549+ZZ2549
++007422        750740          ZZ2549=ZZ2549+ZZ2549
++007422        721700          ZZ2549=ZZ2549+ZZ2549
++007422        643600          ZZ2549=ZZ2549+ZZ2549
++007422        507400          ZZ2549=ZZ2549+ZZ2549
++007422        003120          0 8192 -ZZ1549
++007423        507400          0 ZZ2549
+-       mark 6607, 3           /32 aqil
++007424        000006          ZZ2550=ZZ2550+ZZ2550
++007424        000014          ZZ2550=ZZ2550+ZZ2550
++007424        000030          ZZ2550=ZZ2550+ZZ2550
++007424        000060          ZZ2550=ZZ2550+ZZ2550
++007424        000140          ZZ2550=ZZ2550+ZZ2550
++007424        000300          ZZ2550=ZZ2550+ZZ2550
++007424        000600          ZZ2550=ZZ2550+ZZ2550
++007424        001400          ZZ2550=ZZ2550+ZZ2550
++007424        003061          0 8192 -ZZ1550
++007425        001400          0 ZZ2550
+-       mark 6651, 163         /38 aqil
++007426        000506          ZZ2551=ZZ2551+ZZ2551
++007426        001214          ZZ2551=ZZ2551+ZZ2551
++007426        002430          ZZ2551=ZZ2551+ZZ2551
++007426        005060          ZZ2551=ZZ2551+ZZ2551
++007426        012140          ZZ2551=ZZ2551+ZZ2551
++007426        024300          ZZ2551=ZZ2551+ZZ2551
++007426        050600          ZZ2551=ZZ2551+ZZ2551
++007426        121400          ZZ2551=ZZ2551+ZZ2551
++007426        003005          0 8192 -ZZ1551
++007427        121400          0 ZZ2551
+-       mark 6657, 445         / 9 vulp
++007430        001572          ZZ2552=ZZ2552+ZZ2552
++007430        003364          ZZ2552=ZZ2552+ZZ2552
++007430        006750          ZZ2552=ZZ2552+ZZ2552
++007430        015720          ZZ2552=ZZ2552+ZZ2552
++007430        033640          ZZ2552=ZZ2552+ZZ2552
++007430        067500          ZZ2552=ZZ2552+ZZ2552
++007430        157200          ZZ2552=ZZ2552+ZZ2552
++007430        336400          ZZ2552=ZZ2552+ZZ2552
++007430        002777          0 8192 -ZZ1552
++007431        336400          0 ZZ2552
+-       mark 6665, -35         /41 aqil
++007432        777670          ZZ2553=ZZ2553+ZZ2553
++007432        777560          ZZ2553=ZZ2553+ZZ2553
++007432        777340          ZZ2553=ZZ2553+ZZ2553
++007432        776700          ZZ2553=ZZ2553+ZZ2553
++007432        775600          ZZ2553=ZZ2553+ZZ2553
++007432        773400          ZZ2553=ZZ2553+ZZ2553
++007432        767000          ZZ2553=ZZ2553+ZZ2553
++007432        756000          ZZ2553=ZZ2553+ZZ2553
++007432        002767          0 8192 -ZZ1553
++007433        756000          0 ZZ2553
+-       mark 6688, 405         / 5 sgte
++007434        001452          ZZ2554=ZZ2554+ZZ2554
++007434        003124          ZZ2554=ZZ2554+ZZ2554
++007434        006250          ZZ2554=ZZ2554+ZZ2554
++007434        014520          ZZ2554=ZZ2554+ZZ2554
++007434        031240          ZZ2554=ZZ2554+ZZ2554
++007434        062500          ZZ2554=ZZ2554+ZZ2554
++007434        145200          ZZ2554=ZZ2554+ZZ2554
++007434        312400          ZZ2554=ZZ2554+ZZ2554
++007434        002740          0 8192 -ZZ1554
++007435        312400          0 ZZ2554
+-       mark 6693, 393         / 6 sgte
++007436        001422          ZZ2555=ZZ2555+ZZ2555
++007436        003044          ZZ2555=ZZ2555+ZZ2555
++007436        006110          ZZ2555=ZZ2555+ZZ2555
++007436        014220          ZZ2555=ZZ2555+ZZ2555
++007436        030440          ZZ2555=ZZ2555+ZZ2555
++007436        061100          ZZ2555=ZZ2555+ZZ2555
++007436        142200          ZZ2555=ZZ2555+ZZ2555
++007436        304400          ZZ2555=ZZ2555+ZZ2555
++007436        002733          0 8192 -ZZ1555
++007437        304400          0 ZZ2555
+-       mark 6730, 416         / 7 sgte
++007440        001500          ZZ2556=ZZ2556+ZZ2556
++007440        003200          ZZ2556=ZZ2556+ZZ2556
++007440        006400          ZZ2556=ZZ2556+ZZ2556
++007440        015000          ZZ2556=ZZ2556+ZZ2556
++007440        032000          ZZ2556=ZZ2556+ZZ2556
++007440        064000          ZZ2556=ZZ2556+ZZ2556
++007440        150000          ZZ2556=ZZ2556+ZZ2556
++007440        320000          ZZ2556=ZZ2556+ZZ2556
++007440        002666          0 8192 -ZZ1556
++007441        320000          0 ZZ2556
+-       mark 6739, 430         / 8 sgte
++007442        001534          ZZ2557=ZZ2557+ZZ2557
++007442        003270          ZZ2557=ZZ2557+ZZ2557
++007442        006560          ZZ2557=ZZ2557+ZZ2557
++007442        015340          ZZ2557=ZZ2557+ZZ2557
++007442        032700          ZZ2557=ZZ2557+ZZ2557
++007442        065600          ZZ2557=ZZ2557+ZZ2557
++007442        153400          ZZ2557=ZZ2557+ZZ2557
++007442        327000          ZZ2557=ZZ2557+ZZ2557
++007442        002655          0 8192 -ZZ1557
++007443        327000          0 ZZ2557
+-       mark 6755, 17          /55 aqil
++007444        000042          ZZ2558=ZZ2558+ZZ2558
++007444        000104          ZZ2558=ZZ2558+ZZ2558
++007444        000210          ZZ2558=ZZ2558+ZZ2558
++007444        000420          ZZ2558=ZZ2558+ZZ2558
++007444        001040          ZZ2558=ZZ2558+ZZ2558
++007444        002100          ZZ2558=ZZ2558+ZZ2558
++007444        004200          ZZ2558=ZZ2558+ZZ2558
++007444        010400          ZZ2558=ZZ2558+ZZ2558
++007444        002635          0 8192 -ZZ1558
++007445        010400          0 ZZ2558
+-       mark 6766, 187         /59 aqil
++007446        000566          ZZ2559=ZZ2559+ZZ2559
++007446        001354          ZZ2559=ZZ2559+ZZ2559
++007446        002730          ZZ2559=ZZ2559+ZZ2559
++007446        005660          ZZ2559=ZZ2559+ZZ2559
++007446        013540          ZZ2559=ZZ2559+ZZ2559
++007446        027300          ZZ2559=ZZ2559+ZZ2559
++007446        056600          ZZ2559=ZZ2559+ZZ2559
++007446        135400          ZZ2559=ZZ2559+ZZ2559
++007446        002622          0 8192 -ZZ1559
++007447        135400          0 ZZ2559
+-       mark 6772, 140         /60 aqil
++007450        000430          ZZ2560=ZZ2560+ZZ2560
++007450        001060          ZZ2560=ZZ2560+ZZ2560
++007450        002140          ZZ2560=ZZ2560+ZZ2560
++007450        004300          ZZ2560=ZZ2560+ZZ2560
++007450        010600          ZZ2560=ZZ2560+ZZ2560
++007450        021400          ZZ2560=ZZ2560+ZZ2560
++007450        043000          ZZ2560=ZZ2560+ZZ2560
++007450        106000          ZZ2560=ZZ2560+ZZ2560
++007450        002614          0 8192 -ZZ1560
++007451        106000          0 ZZ2560
+-       mark 6882, 339         /67 aqil
++007452        001246          ZZ2561=ZZ2561+ZZ2561
++007452        002514          ZZ2561=ZZ2561+ZZ2561
++007452        005230          ZZ2561=ZZ2561+ZZ2561
++007452        012460          ZZ2561=ZZ2561+ZZ2561
++007452        025140          ZZ2561=ZZ2561+ZZ2561
++007452        052300          ZZ2561=ZZ2561+ZZ2561
++007452        124600          ZZ2561=ZZ2561+ZZ2561
++007452        251400          ZZ2561=ZZ2561+ZZ2561
++007452        002436          0 8192 -ZZ1561
++007453        251400          0 ZZ2561
+-       mark 6896, -292        / 5 capr
++007454        776666          ZZ2562=ZZ2562+ZZ2562
++007454        775554          ZZ2562=ZZ2562+ZZ2562
++007454        773330          ZZ2562=ZZ2562+ZZ2562
++007454        766660          ZZ2562=ZZ2562+ZZ2562
++007454        755540          ZZ2562=ZZ2562+ZZ2562
++007454        733300          ZZ2562=ZZ2562+ZZ2562
++007454        666600          ZZ2562=ZZ2562+ZZ2562
++007454        555400          ZZ2562=ZZ2562+ZZ2562
++007454        002420          0 8192 -ZZ1562
++007455        555400          0 ZZ2562
+-       mark 6898, -292        / 6 capr
++007456        776666          ZZ2563=ZZ2563+ZZ2563
++007456        775554          ZZ2563=ZZ2563+ZZ2563
++007456        773330          ZZ2563=ZZ2563+ZZ2563
++007456        766660          ZZ2563=ZZ2563+ZZ2563
++007456        755540          ZZ2563=ZZ2563+ZZ2563
++007456        733300          ZZ2563=ZZ2563+ZZ2563
++007456        666600          ZZ2563=ZZ2563+ZZ2563
++007456        555400          ZZ2563=ZZ2563+ZZ2563
++007456        002416          0 8192 -ZZ1563
++007457        555400          0 ZZ2563
+-       mark 6913, -297        / 8 capr
++007460        776654          ZZ2564=ZZ2564+ZZ2564
++007460        775530          ZZ2564=ZZ2564+ZZ2564
++007460        773260          ZZ2564=ZZ2564+ZZ2564
++007460        766540          ZZ2564=ZZ2564+ZZ2564
++007460        755300          ZZ2564=ZZ2564+ZZ2564
++007460        732600          ZZ2564=ZZ2564+ZZ2564
++007460        665400          ZZ2564=ZZ2564+ZZ2564
++007460        553000          ZZ2564=ZZ2564+ZZ2564
++007460        002377          0 8192 -ZZ1564
++007461        553000          0 ZZ2564
+-       mark 6958, -413        /11 capr
++007462        776304          ZZ2565=ZZ2565+ZZ2565
++007462        774610          ZZ2565=ZZ2565+ZZ2565
++007462        771420          ZZ2565=ZZ2565+ZZ2565
++007462        763040          ZZ2565=ZZ2565+ZZ2565
++007462        746100          ZZ2565=ZZ2565+ZZ2565
++007462        714200          ZZ2565=ZZ2565+ZZ2565
++007462        630400          ZZ2565=ZZ2565+ZZ2565
++007462        461000          ZZ2565=ZZ2565+ZZ2565
++007462        002322          0 8192 -ZZ1565
++007463        461000          0 ZZ2565
+-       mark 6988, 250         / 2 dlph
++007464        000764          ZZ2566=ZZ2566+ZZ2566
++007464        001750          ZZ2566=ZZ2566+ZZ2566
++007464        003720          ZZ2566=ZZ2566+ZZ2566
++007464        007640          ZZ2566=ZZ2566+ZZ2566
++007464        017500          ZZ2566=ZZ2566+ZZ2566
++007464        037200          ZZ2566=ZZ2566+ZZ2566
++007464        076400          ZZ2566=ZZ2566+ZZ2566
++007464        175000          ZZ2566=ZZ2566+ZZ2566
++007464        002264          0 8192 -ZZ1566
++007465        175000          0 ZZ2566
+-       mark 7001, 326         / 4 dlph
++007466        001214          ZZ2567=ZZ2567+ZZ2567
++007466        002430          ZZ2567=ZZ2567+ZZ2567
++007466        005060          ZZ2567=ZZ2567+ZZ2567
++007466        012140          ZZ2567=ZZ2567+ZZ2567
++007466        024300          ZZ2567=ZZ2567+ZZ2567
++007466        050600          ZZ2567=ZZ2567+ZZ2567
++007466        121400          ZZ2567=ZZ2567+ZZ2567
++007466        243000          ZZ2567=ZZ2567+ZZ2567
++007466        002247          0 8192 -ZZ1567
++007467        243000          0 ZZ2567
+-       mark 7015, -33         /71 aqil
++007470        777674          ZZ2568=ZZ2568+ZZ2568
++007470        777570          ZZ2568=ZZ2568+ZZ2568
++007470        777360          ZZ2568=ZZ2568+ZZ2568
++007470        776740          ZZ2568=ZZ2568+ZZ2568
++007470        775700          ZZ2568=ZZ2568+ZZ2568
++007470        773600          ZZ2568=ZZ2568+ZZ2568
++007470        767400          ZZ2568=ZZ2568+ZZ2568
++007470        757000          ZZ2568=ZZ2568+ZZ2568
++007470        002231          0 8192 -ZZ1568
++007471        757000          0 ZZ2568
+-       mark 7020, 475         /29 vulp
++007472        001666          ZZ2569=ZZ2569+ZZ2569
++007472        003554          ZZ2569=ZZ2569+ZZ2569
++007472        007330          ZZ2569=ZZ2569+ZZ2569
++007472        016660          ZZ2569=ZZ2569+ZZ2569
++007472        035540          ZZ2569=ZZ2569+ZZ2569
++007472        073300          ZZ2569=ZZ2569+ZZ2569
++007472        166600          ZZ2569=ZZ2569+ZZ2569
++007472        355400          ZZ2569=ZZ2569+ZZ2569
++007472        002224          0 8192 -ZZ1569
++007473        355400          0 ZZ2569
+-       mark 7026, 354         / 9 dlph
++007474        001304          ZZ2570=ZZ2570+ZZ2570
++007474        002610          ZZ2570=ZZ2570+ZZ2570
++007474        005420          ZZ2570=ZZ2570+ZZ2570
++007474        013040          ZZ2570=ZZ2570+ZZ2570
++007474        026100          ZZ2570=ZZ2570+ZZ2570
++007474        054200          ZZ2570=ZZ2570+ZZ2570
++007474        130400          ZZ2570=ZZ2570+ZZ2570
++007474        261000          ZZ2570=ZZ2570+ZZ2570
++007474        002216          0 8192 -ZZ1570
++007475        261000          0 ZZ2570
+-       mark 7047, 335         /11 dlph
++007476        001236          ZZ2571=ZZ2571+ZZ2571
++007476        002474          ZZ2571=ZZ2571+ZZ2571
++007476        005170          ZZ2571=ZZ2571+ZZ2571
++007476        012360          ZZ2571=ZZ2571+ZZ2571
++007476        024740          ZZ2571=ZZ2571+ZZ2571
++007476        051700          ZZ2571=ZZ2571+ZZ2571
++007476        123600          ZZ2571=ZZ2571+ZZ2571
++007476        247400          ZZ2571=ZZ2571+ZZ2571
++007476        002171          0 8192 -ZZ1571
++007477        247400          0 ZZ2571
+-       mark 7066, 359         /12 dlph
++007500        001316          ZZ2572=ZZ2572+ZZ2572
++007500        002634          ZZ2572=ZZ2572+ZZ2572
++007500        005470          ZZ2572=ZZ2572+ZZ2572
++007500        013160          ZZ2572=ZZ2572+ZZ2572
++007500        026340          ZZ2572=ZZ2572+ZZ2572
++007500        054700          ZZ2572=ZZ2572+ZZ2572
++007500        131600          ZZ2572=ZZ2572+ZZ2572
++007500        263400          ZZ2572=ZZ2572+ZZ2572
++007500        002146          0 8192 -ZZ1572
++007501        263400          0 ZZ2572
+-       mark 7067, -225        / 2 aqar
++007502        777074          ZZ2573=ZZ2573+ZZ2573
++007502        776170          ZZ2573=ZZ2573+ZZ2573
++007502        774360          ZZ2573=ZZ2573+ZZ2573
++007502        770740          ZZ2573=ZZ2573+ZZ2573
++007502        761700          ZZ2573=ZZ2573+ZZ2573
++007502        743600          ZZ2573=ZZ2573+ZZ2573
++007502        707400          ZZ2573=ZZ2573+ZZ2573
++007502        617000          ZZ2573=ZZ2573+ZZ2573
++007502        002145          0 8192 -ZZ1573
++007503        617000          0 ZZ2573
+-       mark 7068, -123        / 3 aqar
++007504        777410          ZZ2574=ZZ2574+ZZ2574
++007504        777020          ZZ2574=ZZ2574+ZZ2574
++007504        776040          ZZ2574=ZZ2574+ZZ2574
++007504        774100          ZZ2574=ZZ2574+ZZ2574
++007504        770200          ZZ2574=ZZ2574+ZZ2574
++007504        760400          ZZ2574=ZZ2574+ZZ2574
++007504        741000          ZZ2574=ZZ2574+ZZ2574
++007504        702000          ZZ2574=ZZ2574+ZZ2574
++007504        002144          0 8192 -ZZ1574
++007505        702000          0 ZZ2574
+-       mark 7096, -213        / 6 aqar
++007506        777124          ZZ2575=ZZ2575+ZZ2575
++007506        776250          ZZ2575=ZZ2575+ZZ2575
++007506        774520          ZZ2575=ZZ2575+ZZ2575
++007506        771240          ZZ2575=ZZ2575+ZZ2575
++007506        762500          ZZ2575=ZZ2575+ZZ2575
++007506        745200          ZZ2575=ZZ2575+ZZ2575
++007506        712400          ZZ2575=ZZ2575+ZZ2575
++007506        625000          ZZ2575=ZZ2575+ZZ2575
++007506        002110          0 8192 -ZZ1575
++007507        625000          0 ZZ2575
+-       mark 7161, -461        /22 capr
++007510        776144          ZZ2576=ZZ2576+ZZ2576
++007510        774310          ZZ2576=ZZ2576+ZZ2576
++007510        770620          ZZ2576=ZZ2576+ZZ2576
++007510        761440          ZZ2576=ZZ2576+ZZ2576
++007510        743100          ZZ2576=ZZ2576+ZZ2576
++007510        706200          ZZ2576=ZZ2576+ZZ2576
++007510        614400          ZZ2576=ZZ2576+ZZ2576
++007510        431000          ZZ2576=ZZ2576+ZZ2576
++007510        002007          0 8192 -ZZ1576
++007511        431000          0 ZZ2576
+-       mark 7170, -401        /23 capr
++007512        776334          ZZ2577=ZZ2577+ZZ2577
++007512        774670          ZZ2577=ZZ2577+ZZ2577
++007512        771560          ZZ2577=ZZ2577+ZZ2577
++007512        763340          ZZ2577=ZZ2577+ZZ2577
++007512        746700          ZZ2577=ZZ2577+ZZ2577
++007512        715600          ZZ2577=ZZ2577+ZZ2577
++007512        633400          ZZ2577=ZZ2577+ZZ2577
++007512        467000          ZZ2577=ZZ2577+ZZ2577
++007512        001776          0 8192 -ZZ1577
++007513        467000          0 ZZ2577
+-       mark 7192, -268        /13 capr
++007514        776746          ZZ2578=ZZ2578+ZZ2578
++007514        775714          ZZ2578=ZZ2578+ZZ2578
++007514        773630          ZZ2578=ZZ2578+ZZ2578
++007514        767460          ZZ2578=ZZ2578+ZZ2578
++007514        757140          ZZ2578=ZZ2578+ZZ2578
++007514        736300          ZZ2578=ZZ2578+ZZ2578
++007514        674600          ZZ2578=ZZ2578+ZZ2578
++007514        571400          ZZ2578=ZZ2578+ZZ2578
++007514        001750          0 8192 -ZZ1578
++007515        571400          0 ZZ2578
+-       mark 7199, 222         / 5 equl
++007516        000674          ZZ2579=ZZ2579+ZZ2579
++007516        001570          ZZ2579=ZZ2579+ZZ2579
++007516        003360          ZZ2579=ZZ2579+ZZ2579
++007516        006740          ZZ2579=ZZ2579+ZZ2579
++007516        015700          ZZ2579=ZZ2579+ZZ2579
++007516        033600          ZZ2579=ZZ2579+ZZ2579
++007516        067400          ZZ2579=ZZ2579+ZZ2579
++007516        157000          ZZ2579=ZZ2579+ZZ2579
++007516        001741          0 8192 -ZZ1579
++007517        157000          0 ZZ2579
+-       mark 7223, 219         / 7 equl
++007520        000666          ZZ2580=ZZ2580+ZZ2580
++007520        001554          ZZ2580=ZZ2580+ZZ2580
++007520        003330          ZZ2580=ZZ2580+ZZ2580
++007520        006660          ZZ2580=ZZ2580+ZZ2580
++007520        015540          ZZ2580=ZZ2580+ZZ2580
++007520        033300          ZZ2580=ZZ2580+ZZ2580
++007520        066600          ZZ2580=ZZ2580+ZZ2580
++007520        155400          ZZ2580=ZZ2580+ZZ2580
++007520        001711          0 8192 -ZZ1580
++007521        155400          0 ZZ2580
+-       mark 7230, 110         / 8 equl
++007522        000334          ZZ2581=ZZ2581+ZZ2581
++007522        000670          ZZ2581=ZZ2581+ZZ2581
++007522        001560          ZZ2581=ZZ2581+ZZ2581
++007522        003340          ZZ2581=ZZ2581+ZZ2581
++007522        006700          ZZ2581=ZZ2581+ZZ2581
++007522        015600          ZZ2581=ZZ2581+ZZ2581
++007522        033400          ZZ2581=ZZ2581+ZZ2581
++007522        067000          ZZ2581=ZZ2581+ZZ2581
++007522        001702          0 8192 -ZZ1581
++007523        067000          0 ZZ2581
+-       mark 7263, -393        /32 capr
++007524        776354          ZZ2582=ZZ2582+ZZ2582
++007524        774730          ZZ2582=ZZ2582+ZZ2582
++007524        771660          ZZ2582=ZZ2582+ZZ2582
++007524        763540          ZZ2582=ZZ2582+ZZ2582
++007524        747300          ZZ2582=ZZ2582+ZZ2582
++007524        716600          ZZ2582=ZZ2582+ZZ2582
++007524        635400          ZZ2582=ZZ2582+ZZ2582
++007524        473000          ZZ2582=ZZ2582+ZZ2582
++007524        001641          0 8192 -ZZ1582
++007525        473000          0 ZZ2582
+-       mark 7267, 441         / 1 pegs
++007526        001562          ZZ2583=ZZ2583+ZZ2583
++007526        003344          ZZ2583=ZZ2583+ZZ2583
++007526        006710          ZZ2583=ZZ2583+ZZ2583
++007526        015620          ZZ2583=ZZ2583+ZZ2583
++007526        033440          ZZ2583=ZZ2583+ZZ2583
++007526        067100          ZZ2583=ZZ2583+ZZ2583
++007526        156200          ZZ2583=ZZ2583+ZZ2583
++007526        334400          ZZ2583=ZZ2583+ZZ2583
++007526        001635          0 8192 -ZZ1583
++007527        334400          0 ZZ2583
+-       mark 7299, -506        /36 capr
++007530        776012          ZZ2584=ZZ2584+ZZ2584
++007530        774024          ZZ2584=ZZ2584+ZZ2584
++007530        770050          ZZ2584=ZZ2584+ZZ2584
++007530        760120          ZZ2584=ZZ2584+ZZ2584
++007530        740240          ZZ2584=ZZ2584+ZZ2584
++007530        700500          ZZ2584=ZZ2584+ZZ2584
++007530        601200          ZZ2584=ZZ2584+ZZ2584
++007530        402400          ZZ2584=ZZ2584+ZZ2584
++007530        001575          0 8192 -ZZ1584
++007531        402400          0 ZZ2584
+-       mark 7347, -453        /39 capr
++007532        776164          ZZ2585=ZZ2585+ZZ2585
++007532        774350          ZZ2585=ZZ2585+ZZ2585
++007532        770720          ZZ2585=ZZ2585+ZZ2585
++007532        761640          ZZ2585=ZZ2585+ZZ2585
++007532        743500          ZZ2585=ZZ2585+ZZ2585
++007532        707200          ZZ2585=ZZ2585+ZZ2585
++007532        616400          ZZ2585=ZZ2585+ZZ2585
++007532        435000          ZZ2585=ZZ2585+ZZ2585
++007532        001515          0 8192 -ZZ1585
++007533        435000          0 ZZ2585
+-       mark 7353, -189        /23 aqar
++007534        777204          ZZ2586=ZZ2586+ZZ2586
++007534        776410          ZZ2586=ZZ2586+ZZ2586
++007534        775020          ZZ2586=ZZ2586+ZZ2586
++007534        772040          ZZ2586=ZZ2586+ZZ2586
++007534        764100          ZZ2586=ZZ2586+ZZ2586
++007534        750200          ZZ2586=ZZ2586+ZZ2586
++007534        720400          ZZ2586=ZZ2586+ZZ2586
++007534        641000          ZZ2586=ZZ2586+ZZ2586
++007534        001507          0 8192 -ZZ1586
++007535        641000          0 ZZ2586
+-       mark 7365, -390        /40 capr
++007536        776362          ZZ2587=ZZ2587+ZZ2587
++007536        774744          ZZ2587=ZZ2587+ZZ2587
++007536        771710          ZZ2587=ZZ2587+ZZ2587
++007536        763620          ZZ2587=ZZ2587+ZZ2587
++007536        747440          ZZ2587=ZZ2587+ZZ2587
++007536        717100          ZZ2587=ZZ2587+ZZ2587
++007536        636200          ZZ2587=ZZ2587+ZZ2587
++007536        474400          ZZ2587=ZZ2587+ZZ2587
++007536        001473          0 8192 -ZZ1587
++007537        474400          0 ZZ2587
+-       mark 7379, -440        /43 capr
++007540        776216          ZZ2588=ZZ2588+ZZ2588
++007540        774434          ZZ2588=ZZ2588+ZZ2588
++007540        771070          ZZ2588=ZZ2588+ZZ2588
++007540        762160          ZZ2588=ZZ2588+ZZ2588
++007540        744340          ZZ2588=ZZ2588+ZZ2588
++007540        710700          ZZ2588=ZZ2588+ZZ2588
++007540        621600          ZZ2588=ZZ2588+ZZ2588
++007540        443400          ZZ2588=ZZ2588+ZZ2588
++007540        001455          0 8192 -ZZ1588
++007541        443400          0 ZZ2588
+-       mark 7394, 384         / 9 pegs
++007542        001400          ZZ2589=ZZ2589+ZZ2589
++007542        003000          ZZ2589=ZZ2589+ZZ2589
++007542        006000          ZZ2589=ZZ2589+ZZ2589
++007542        014000          ZZ2589=ZZ2589+ZZ2589
++007542        030000          ZZ2589=ZZ2589+ZZ2589
++007542        060000          ZZ2589=ZZ2589+ZZ2589
++007542        140000          ZZ2589=ZZ2589+ZZ2589
++007542        300000          ZZ2589=ZZ2589+ZZ2589
++007542        001436          0 8192 -ZZ1589
++007543        300000          0 ZZ2589
+-       mark 7499, -60         /31 aquar
++007544        777606          ZZ2590=ZZ2590+ZZ2590
++007544        777414          ZZ2590=ZZ2590+ZZ2590
++007544        777030          ZZ2590=ZZ2590+ZZ2590
++007544        776060          ZZ2590=ZZ2590+ZZ2590
++007544        774140          ZZ2590=ZZ2590+ZZ2590
++007544        770300          ZZ2590=ZZ2590+ZZ2590
++007544        760600          ZZ2590=ZZ2590+ZZ2590
++007544        741400          ZZ2590=ZZ2590+ZZ2590
++007544        001265          0 8192 -ZZ1590
++007545        741400          0 ZZ2590
+-       mark 7513, 104         /22 pegs
++007546        000320          ZZ2591=ZZ2591+ZZ2591
++007546        000640          ZZ2591=ZZ2591+ZZ2591
++007546        001500          ZZ2591=ZZ2591+ZZ2591
++007546        003200          ZZ2591=ZZ2591+ZZ2591
++007546        006400          ZZ2591=ZZ2591+ZZ2591
++007546        015000          ZZ2591=ZZ2591+ZZ2591
++007546        032000          ZZ2591=ZZ2591+ZZ2591
++007546        064000          ZZ2591=ZZ2591+ZZ2591
++007546        001247          0 8192 -ZZ1591
++007547        064000          0 ZZ2591
+-       mark 7515, -327        /33 aqar
++007550        776560          ZZ2592=ZZ2592+ZZ2592
++007550        775340          ZZ2592=ZZ2592+ZZ2592
++007550        772700          ZZ2592=ZZ2592+ZZ2592
++007550        765600          ZZ2592=ZZ2592+ZZ2592
++007550        753400          ZZ2592=ZZ2592+ZZ2592
++007550        727000          ZZ2592=ZZ2592+ZZ2592
++007550        656000          ZZ2592=ZZ2592+ZZ2592
++007550        534000          ZZ2592=ZZ2592+ZZ2592
++007550        001245          0 8192 -ZZ1592
++007551        534000          0 ZZ2592
+-       mark 7575, -189        /43 aqar
++007552        777204          ZZ2593=ZZ2593+ZZ2593
++007552        776410          ZZ2593=ZZ2593+ZZ2593
++007552        775020          ZZ2593=ZZ2593+ZZ2593
++007552        772040          ZZ2593=ZZ2593+ZZ2593
++007552        764100          ZZ2593=ZZ2593+ZZ2593
++007552        750200          ZZ2593=ZZ2593+ZZ2593
++007552        720400          ZZ2593=ZZ2593+ZZ2593
++007552        641000          ZZ2593=ZZ2593+ZZ2593
++007552        001151          0 8192 -ZZ1593
++007553        641000          0 ZZ2593
+-       mark 7603, -43         /48 aqar
++007554        777650          ZZ2594=ZZ2594+ZZ2594
++007554        777520          ZZ2594=ZZ2594+ZZ2594
++007554        777240          ZZ2594=ZZ2594+ZZ2594
++007554        776500          ZZ2594=ZZ2594+ZZ2594
++007554        775200          ZZ2594=ZZ2594+ZZ2594
++007554        772400          ZZ2594=ZZ2594+ZZ2594
++007554        765000          ZZ2594=ZZ2594+ZZ2594
++007554        752000          ZZ2594=ZZ2594+ZZ2594
++007554        001115          0 8192 -ZZ1594
++007555        752000          0 ZZ2594
+-       mark 7604, 266         /31 pegs
++007556        001024          ZZ2595=ZZ2595+ZZ2595
++007556        002050          ZZ2595=ZZ2595+ZZ2595
++007556        004120          ZZ2595=ZZ2595+ZZ2595
++007556        010240          ZZ2595=ZZ2595+ZZ2595
++007556        020500          ZZ2595=ZZ2595+ZZ2595
++007556        041200          ZZ2595=ZZ2595+ZZ2595
++007556        102400          ZZ2595=ZZ2595+ZZ2595
++007556        205000          ZZ2595=ZZ2595+ZZ2595
++007556        001114          0 8192 -ZZ1595
++007557        205000          0 ZZ2595
+-       mark 7624, 20          /52 aquar
++007560        000050          ZZ2596=ZZ2596+ZZ2596
++007560        000120          ZZ2596=ZZ2596+ZZ2596
++007560        000240          ZZ2596=ZZ2596+ZZ2596
++007560        000500          ZZ2596=ZZ2596+ZZ2596
++007560        001200          ZZ2596=ZZ2596+ZZ2596
++007560        002400          ZZ2596=ZZ2596+ZZ2596
++007560        005000          ZZ2596=ZZ2596+ZZ2596
++007560        012000          ZZ2596=ZZ2596+ZZ2596
++007560        001070          0 8192 -ZZ1596
++007561        012000          0 ZZ2596
+-       mark 7639, 96          /35 pegs
++007562        000300          ZZ2597=ZZ2597+ZZ2597
++007562        000600          ZZ2597=ZZ2597+ZZ2597
++007562        001400          ZZ2597=ZZ2597+ZZ2597
++007562        003000          ZZ2597=ZZ2597+ZZ2597
++007562        006000          ZZ2597=ZZ2597+ZZ2597
++007562        014000          ZZ2597=ZZ2597+ZZ2597
++007562        030000          ZZ2597=ZZ2597+ZZ2597
++007562        060000          ZZ2597=ZZ2597+ZZ2597
++007562        001051          0 8192 -ZZ1597
++007563        060000          0 ZZ2597
+-       mark 7654, -255        /57 aqar
++007564        777000          ZZ2598=ZZ2598+ZZ2598
++007564        776000          ZZ2598=ZZ2598+ZZ2598
++007564        774000          ZZ2598=ZZ2598+ZZ2598
++007564        770000          ZZ2598=ZZ2598+ZZ2598
++007564        760000          ZZ2598=ZZ2598+ZZ2598
++007564        740000          ZZ2598=ZZ2598+ZZ2598
++007564        700000          ZZ2598=ZZ2598+ZZ2598
++007564        600000          ZZ2598=ZZ2598+ZZ2598
++007564        001032          0 8192 -ZZ1598
++007565        600000          0 ZZ2598
+-       mark 7681, -14         /62 aqar
++007566        777742          ZZ2599=ZZ2599+ZZ2599
++007566        777704          ZZ2599=ZZ2599+ZZ2599
++007566        777610          ZZ2599=ZZ2599+ZZ2599
++007566        777420          ZZ2599=ZZ2599+ZZ2599
++007566        777040          ZZ2599=ZZ2599+ZZ2599
++007566        776100          ZZ2599=ZZ2599+ZZ2599
++007566        774200          ZZ2599=ZZ2599+ZZ2599
++007566        770400          ZZ2599=ZZ2599+ZZ2599
++007566        000777          0 8192 -ZZ1599
++007567        770400          0 ZZ2599
+-       mark 7727, -440        /66 aqar
++007570        776216          ZZ2600=ZZ2600+ZZ2600
++007570        774434          ZZ2600=ZZ2600+ZZ2600
++007570        771070          ZZ2600=ZZ2600+ZZ2600
++007570        762160          ZZ2600=ZZ2600+ZZ2600
++007570        744340          ZZ2600=ZZ2600+ZZ2600
++007570        710700          ZZ2600=ZZ2600+ZZ2600
++007570        621600          ZZ2600=ZZ2600+ZZ2600
++007570        443400          ZZ2600=ZZ2600+ZZ2600
++007570        000721          0 8192 -ZZ1600
++007571        443400          0 ZZ2600
+-       mark 7747, 266         /46 pegs
++007572        001024          ZZ2601=ZZ2601+ZZ2601
++007572        002050          ZZ2601=ZZ2601+ZZ2601
++007572        004120          ZZ2601=ZZ2601+ZZ2601
++007572        010240          ZZ2601=ZZ2601+ZZ2601
++007572        020500          ZZ2601=ZZ2601+ZZ2601
++007572        041200          ZZ2601=ZZ2601+ZZ2601
++007572        102400          ZZ2601=ZZ2601+ZZ2601
++007572        205000          ZZ2601=ZZ2601+ZZ2601
++007572        000675          0 8192 -ZZ1601
++007573        205000          0 ZZ2601
+-       mark 7761, -321        /71 aqar
++007574        776574          ZZ2602=ZZ2602+ZZ2602
++007574        775370          ZZ2602=ZZ2602+ZZ2602
++007574        772760          ZZ2602=ZZ2602+ZZ2602
++007574        765740          ZZ2602=ZZ2602+ZZ2602
++007574        753700          ZZ2602=ZZ2602+ZZ2602
++007574        727600          ZZ2602=ZZ2602+ZZ2602
++007574        657400          ZZ2602=ZZ2602+ZZ2602
++007574        537000          ZZ2602=ZZ2602+ZZ2602
++007574        000657          0 8192 -ZZ1602
++007575        537000          0 ZZ2602
+-       mark 7779, -185        /73 aqar
++007576        777214          ZZ2603=ZZ2603+ZZ2603
++007576        776430          ZZ2603=ZZ2603+ZZ2603
++007576        775060          ZZ2603=ZZ2603+ZZ2603
++007576        772140          ZZ2603=ZZ2603+ZZ2603
++007576        764300          ZZ2603=ZZ2603+ZZ2603
++007576        750600          ZZ2603=ZZ2603+ZZ2603
++007576        721400          ZZ2603=ZZ2603+ZZ2603
++007576        643000          ZZ2603=ZZ2603+ZZ2603
++007576        000635          0 8192 -ZZ1603
++007577        643000          0 ZZ2603
+-       mark 7795, 189         /50 pegs
++007600        000572          ZZ2604=ZZ2604+ZZ2604
++007600        001364          ZZ2604=ZZ2604+ZZ2604
++007600        002750          ZZ2604=ZZ2604+ZZ2604
++007600        005720          ZZ2604=ZZ2604+ZZ2604
++007600        013640          ZZ2604=ZZ2604+ZZ2604
++007600        027500          ZZ2604=ZZ2604+ZZ2604
++007600        057200          ZZ2604=ZZ2604+ZZ2604
++007600        136400          ZZ2604=ZZ2604+ZZ2604
++007600        000615          0 8192 -ZZ1604
++007601        136400          0 ZZ2604
+-       mark 7844, 75          / 4 pisc
++007602        000226          ZZ2605=ZZ2605+ZZ2605
++007602        000454          ZZ2605=ZZ2605+ZZ2605
++007602        001130          ZZ2605=ZZ2605+ZZ2605
++007602        002260          ZZ2605=ZZ2605+ZZ2605
++007602        004540          ZZ2605=ZZ2605+ZZ2605
++007602        011300          ZZ2605=ZZ2605+ZZ2605
++007602        022600          ZZ2605=ZZ2605+ZZ2605
++007602        045400          ZZ2605=ZZ2605+ZZ2605
++007602        000534          0 8192 -ZZ1605
++007603        045400          0 ZZ2605
+-       mark 7862, 202         /55 pegs
++007604        000624          ZZ2606=ZZ2606+ZZ2606
++007604        001450          ZZ2606=ZZ2606+ZZ2606
++007604        003120          ZZ2606=ZZ2606+ZZ2606
++007604        006240          ZZ2606=ZZ2606+ZZ2606
++007604        014500          ZZ2606=ZZ2606+ZZ2606
++007604        031200          ZZ2606=ZZ2606+ZZ2606
++007604        062400          ZZ2606=ZZ2606+ZZ2606
++007604        145000          ZZ2606=ZZ2606+ZZ2606
++007604        000512          0 8192 -ZZ1606
++007605        145000          0 ZZ2606
+-       mark 7874, -494        /88 aqar
++007606        776042          ZZ2607=ZZ2607+ZZ2607
++007606        774104          ZZ2607=ZZ2607+ZZ2607
++007606        770210          ZZ2607=ZZ2607+ZZ2607
++007606        760420          ZZ2607=ZZ2607+ZZ2607
++007606        741040          ZZ2607=ZZ2607+ZZ2607
++007606        702100          ZZ2607=ZZ2607+ZZ2607
++007606        604200          ZZ2607=ZZ2607+ZZ2607
++007606        410400          ZZ2607=ZZ2607+ZZ2607
++007606        000476          0 8192 -ZZ1607
++007607        410400          0 ZZ2607
+-       mark 7903, -150        /90 aqar
++007610        777322          ZZ2608=ZZ2608+ZZ2608
++007610        776644          ZZ2608=ZZ2608+ZZ2608
++007610        775510          ZZ2608=ZZ2608+ZZ2608
++007610        773220          ZZ2608=ZZ2608+ZZ2608
++007610        766440          ZZ2608=ZZ2608+ZZ2608
++007610        755100          ZZ2608=ZZ2608+ZZ2608
++007610        732200          ZZ2608=ZZ2608+ZZ2608
++007610        664400          ZZ2608=ZZ2608+ZZ2608
++007610        000441          0 8192 -ZZ1608
++007611        664400          0 ZZ2608
+-       mark 7911, -219        /91 aqar
++007612        777110          ZZ2609=ZZ2609+ZZ2609
++007612        776220          ZZ2609=ZZ2609+ZZ2609
++007612        774440          ZZ2609=ZZ2609+ZZ2609
++007612        771100          ZZ2609=ZZ2609+ZZ2609
++007612        762200          ZZ2609=ZZ2609+ZZ2609
++007612        744400          ZZ2609=ZZ2609+ZZ2609
++007612        711000          ZZ2609=ZZ2609+ZZ2609
++007612        622000          ZZ2609=ZZ2609+ZZ2609
++007612        000431          0 8192 -ZZ1609
++007613        622000          0 ZZ2609
+-       mark 7919, 62          / 6 pisc
++007614        000174          ZZ2610=ZZ2610+ZZ2610
++007614        000370          ZZ2610=ZZ2610+ZZ2610
++007614        000760          ZZ2610=ZZ2610+ZZ2610
++007614        001740          ZZ2610=ZZ2610+ZZ2610
++007614        003700          ZZ2610=ZZ2610+ZZ2610
++007614        007600          ZZ2610=ZZ2610+ZZ2610
++007614        017400          ZZ2610=ZZ2610+ZZ2610
++007614        037000          ZZ2610=ZZ2610+ZZ2610
++007614        000421          0 8192 -ZZ1610
++007615        037000          0 ZZ2610
+-       mark 7923, -222        /93 aqar
++007616        777102          ZZ2611=ZZ2611+ZZ2611
++007616        776204          ZZ2611=ZZ2611+ZZ2611
++007616        774410          ZZ2611=ZZ2611+ZZ2611
++007616        771020          ZZ2611=ZZ2611+ZZ2611
++007616        762040          ZZ2611=ZZ2611+ZZ2611
++007616        744100          ZZ2611=ZZ2611+ZZ2611
++007616        710200          ZZ2611=ZZ2611+ZZ2611
++007616        620400          ZZ2611=ZZ2611+ZZ2611
++007616        000415          0 8192 -ZZ1611
++007617        620400          0 ZZ2611
+-       mark 7952, -470        /98 aqar
++007620        776122          ZZ2612=ZZ2612+ZZ2612
++007620        774244          ZZ2612=ZZ2612+ZZ2612
++007620        770510          ZZ2612=ZZ2612+ZZ2612
++007620        761220          ZZ2612=ZZ2612+ZZ2612
++007620        742440          ZZ2612=ZZ2612+ZZ2612
++007620        705100          ZZ2612=ZZ2612+ZZ2612
++007620        612200          ZZ2612=ZZ2612+ZZ2612
++007620        424400          ZZ2612=ZZ2612+ZZ2612
++007620        000360          0 8192 -ZZ1612
++007621        424400          0 ZZ2612
+-       mark 7969, -482        /99 aqar
++007622        776072          ZZ2613=ZZ2613+ZZ2613
++007622        774164          ZZ2613=ZZ2613+ZZ2613
++007622        770350          ZZ2613=ZZ2613+ZZ2613
++007622        760720          ZZ2613=ZZ2613+ZZ2613
++007622        741640          ZZ2613=ZZ2613+ZZ2613
++007622        703500          ZZ2613=ZZ2613+ZZ2613
++007622        607200          ZZ2613=ZZ2613+ZZ2613
++007622        416400          ZZ2613=ZZ2613+ZZ2613
++007622        000337          0 8192 -ZZ1613
++007623        416400          0 ZZ2613
+-       mark 7975, 16          / 8 pisc
++007624        000040          ZZ2614=ZZ2614+ZZ2614
++007624        000100          ZZ2614=ZZ2614+ZZ2614
++007624        000200          ZZ2614=ZZ2614+ZZ2614
++007624        000400          ZZ2614=ZZ2614+ZZ2614
++007624        001000          ZZ2614=ZZ2614+ZZ2614
++007624        002000          ZZ2614=ZZ2614+ZZ2614
++007624        004000          ZZ2614=ZZ2614+ZZ2614
++007624        010000          ZZ2614=ZZ2614+ZZ2614
++007624        000331          0 8192 -ZZ1614
++007625        010000          0 ZZ2614
+-       mark 7981, 133         /10 pisc
++007626        000412          ZZ2615=ZZ2615+ZZ2615
++007626        001024          ZZ2615=ZZ2615+ZZ2615
++007626        002050          ZZ2615=ZZ2615+ZZ2615
++007626        004120          ZZ2615=ZZ2615+ZZ2615
++007626        010240          ZZ2615=ZZ2615+ZZ2615
++007626        020500          ZZ2615=ZZ2615+ZZ2615
++007626        041200          ZZ2615=ZZ2615+ZZ2615
++007626        102400          ZZ2615=ZZ2615+ZZ2615
++007626        000323          0 8192 -ZZ1615
++007627        102400          0 ZZ2615
+-       mark 7988, 278         /70 pegs
++007630        001054          ZZ2616=ZZ2616+ZZ2616
++007630        002130          ZZ2616=ZZ2616+ZZ2616
++007630        004260          ZZ2616=ZZ2616+ZZ2616
++007630        010540          ZZ2616=ZZ2616+ZZ2616
++007630        021300          ZZ2616=ZZ2616+ZZ2616
++007630        042600          ZZ2616=ZZ2616+ZZ2616
++007630        105400          ZZ2616=ZZ2616+ZZ2616
++007630        213000          ZZ2616=ZZ2616+ZZ2616
++007630        000314          0 8192 -ZZ1616
++007631        213000          0 ZZ2616
+-       mark 8010, -489        /101 aqar
++007632        776054          ZZ2617=ZZ2617+ZZ2617
++007632        774130          ZZ2617=ZZ2617+ZZ2617
++007632        770260          ZZ2617=ZZ2617+ZZ2617
++007632        760540          ZZ2617=ZZ2617+ZZ2617
++007632        741300          ZZ2617=ZZ2617+ZZ2617
++007632        702600          ZZ2617=ZZ2617+ZZ2617
++007632        605400          ZZ2617=ZZ2617+ZZ2617
++007632        413000          ZZ2617=ZZ2617+ZZ2617
++007632        000266          0 8192 -ZZ1617
++007633        413000          0 ZZ2617
+-       mark 8049, 116         /17 pisc
++007634        000350          ZZ2618=ZZ2618+ZZ2618
++007634        000720          ZZ2618=ZZ2618+ZZ2618
++007634        001640          ZZ2618=ZZ2618+ZZ2618
++007634        003500          ZZ2618=ZZ2618+ZZ2618
++007634        007200          ZZ2618=ZZ2618+ZZ2618
++007634        016400          ZZ2618=ZZ2618+ZZ2618
++007634        035000          ZZ2618=ZZ2618+ZZ2618
++007634        072000          ZZ2618=ZZ2618+ZZ2618
++007634        000217          0 8192 -ZZ1618
++007635        072000          0 ZZ2618
+-       mark 8059, -418        /104 aqar
++007636        776272          ZZ2619=ZZ2619+ZZ2619
++007636        774564          ZZ2619=ZZ2619+ZZ2619
++007636        771350          ZZ2619=ZZ2619+ZZ2619
++007636        762720          ZZ2619=ZZ2619+ZZ2619
++007636        745640          ZZ2619=ZZ2619+ZZ2619
++007636        713500          ZZ2619=ZZ2619+ZZ2619
++007636        627200          ZZ2619=ZZ2619+ZZ2619
++007636        456400          ZZ2619=ZZ2619+ZZ2619
++007636        000205          0 8192 -ZZ1619
++007637        456400          0 ZZ2619
+-       mark 8061, 28          /18 pisc
++007640        000070          ZZ2620=ZZ2620+ZZ2620
++007640        000160          ZZ2620=ZZ2620+ZZ2620
++007640        000340          ZZ2620=ZZ2620+ZZ2620
++007640        000700          ZZ2620=ZZ2620+ZZ2620
++007640        001600          ZZ2620=ZZ2620+ZZ2620
++007640        003400          ZZ2620=ZZ2620+ZZ2620
++007640        007000          ZZ2620=ZZ2620+ZZ2620
++007640        016000          ZZ2620=ZZ2620+ZZ2620
++007640        000203          0 8192 -ZZ1620
++007641        016000          0 ZZ2620
+-       mark 8064, -344        /105 aqar
++007642        776516          ZZ2621=ZZ2621+ZZ2621
++007642        775234          ZZ2621=ZZ2621+ZZ2621
++007642        772470          ZZ2621=ZZ2621+ZZ2621
++007642        765160          ZZ2621=ZZ2621+ZZ2621
++007642        752340          ZZ2621=ZZ2621+ZZ2621
++007642        724700          ZZ2621=ZZ2621+ZZ2621
++007642        651600          ZZ2621=ZZ2621+ZZ2621
++007642        523400          ZZ2621=ZZ2621+ZZ2621
++007642        000200          0 8192 -ZZ1621
++007643        523400          0 ZZ2621
+-       mark 8159, 144         /28 pisc
++007644        000440          ZZ2622=ZZ2622+ZZ2622
++007644        001100          ZZ2622=ZZ2622+ZZ2622
++007644        002200          ZZ2622=ZZ2622+ZZ2622
++007644        004400          ZZ2622=ZZ2622+ZZ2622
++007644        011000          ZZ2622=ZZ2622+ZZ2622
++007644        022000          ZZ2622=ZZ2622+ZZ2622
++007644        044000          ZZ2622=ZZ2622+ZZ2622
++007644        110000          ZZ2622=ZZ2622+ZZ2622
++007644        000041          0 8192 -ZZ1622
++007645        110000          0 ZZ2622
+-       mark 8174, -149        /30 pisc
++007646        777324          ZZ2623=ZZ2623+ZZ2623
++007646        776650          ZZ2623=ZZ2623+ZZ2623
++007646        775520          ZZ2623=ZZ2623+ZZ2623
++007646        773240          ZZ2623=ZZ2623+ZZ2623
++007646        766500          ZZ2623=ZZ2623+ZZ2623
++007646        755200          ZZ2623=ZZ2623+ZZ2623
++007646        732400          ZZ2623=ZZ2623+ZZ2623
++007646        665000          ZZ2623=ZZ2623+ZZ2623
++007646        000022          0 8192 -ZZ1623
++007647        665000          0 ZZ2623
+ 007650                4q,
+-       mark 8188, -407        / 2 ceti
++007650        776320          ZZ2624=ZZ2624+ZZ2624
++007650        774640          ZZ2624=ZZ2624+ZZ2624
++007650        771500          ZZ2624=ZZ2624+ZZ2624
++007650        763200          ZZ2624=ZZ2624+ZZ2624
++007650        746400          ZZ2624=ZZ2624+ZZ2624
++007650        715000          ZZ2624=ZZ2624+ZZ2624
++007650        632000          ZZ2624=ZZ2624+ZZ2624
++007650        464000          ZZ2624=ZZ2624+ZZ2624
++007650        000004          0 8192 -ZZ1624
++007651        464000          0 ZZ2624
+ 007652                         start 4
+`
diff --git a/libgo/go/exp/spacewar/pdp1.go b/libgo/go/exp/spacewar/pdp1.go
new file mode 100644 (file)
index 0000000..e3abd68
--- /dev/null
@@ -0,0 +1,389 @@
+// Copyright (c) 1996 Barry Silverman, Brian Silverman, Vadim Gerasimov.
+// Portions Copyright (c) 2009 The Go Authors.
+//
+// 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 package and spacewar.go implement a simple PDP-1 emulator
+// complete enough to run the original PDP-1 video game Spacewar!
+// See ../../nacl/README for details on running them.
+//
+// They are a translation of the Java emulator pdp1.java in
+// http://spacewar.oversigma.com/sources/sources.zip.
+//
+// See also the PDP-1 handbook at http://www.dbit.com/~greeng3/pdp1/pdp1.html
+//
+// http://spacewar.oversigma.com/readme.html reads:
+//
+//     Spacewar! was conceived in 1961 by Martin Graetz, Stephen Russell,
+//     and Wayne Wiitanen. It was first realized on the PDP-1 in 1962 by
+//     Stephen Russell, Peter Samson, Dan Edwards, and Martin Graetz,
+//     together with Alan Kotok, Steve Piner, and Robert A Saunders.
+//     Spacewar! is in the public domain, but this credit paragraph must
+//     accompany all distributed versions of the program.
+//
+//     This is the original version! Martin Graetz provided us with a
+//     printed version of the source. We typed in in again - it was about
+//     40 pages long - and re-assembled it with a PDP-1 assembler written
+//     in PERL. The resulting binary runs on a PDP-1 emulator written as
+//     a Java applet. The code is extremely faithful to the original. There
+//     are only two changes. 1)The spaceships have been made bigger and
+//     2) The overall timing has been special cased to deal with varying
+//     machine speeds.
+//
+//     The "a", "s", "d", "f" keys control one of the spaceships. The "k",
+//     "l", ";", "'" keys control the other. The controls are spin one
+//     way, spin the other, thrust, and fire.
+//
+//     Barry Silverman
+//     Brian Silverman
+//     Vadim Gerasimov
+//
+package pdp1
+
+import (
+       "bufio"
+       "fmt"
+       "os"
+       "io"
+)
+
+type Word uint32
+
+const mask = 0777777
+const sign = 0400000
+
+const (
+       _ = iota // 00
+       opAND
+       opIOR
+       opXOR
+       opXCT
+       _
+       _
+       opCALJDA
+
+       opLAC // 10
+       opLIO
+       opDAC
+       opDAP
+       _
+       opDIO
+       opDZM
+       _
+
+       opADD // 20
+       opSUB
+       opIDX
+       opISP
+       opSAD
+       opSAS
+       opMUS
+       opDIS
+
+       opJMP // 30
+       opJSP
+       opSKP
+       opSFT
+       opLAW
+       opIOT
+       _
+       opOPR
+)
+
+// A Trapper represents an object with a Trap method.
+// The machine calls the Trap method to implement the
+// PDP-1 IOT instruction.
+type Trapper interface {
+       Trap(y Word)
+}
+
+// An M represents the machine state of a PDP-1.
+// Clients can set Display to install an output device.
+type M struct {
+       AC, IO, PC, OV Word
+       Mem            [010000]Word
+       Flag           [7]bool
+       Sense          [7]bool
+       Halt           bool
+}
+
+
+// Step runs a single machine instruction.
+func (m *M) Step(t Trapper) os.Error {
+       inst := m.Mem[m.PC]
+       m.PC++
+       return m.run(inst, t)
+}
+
+// Normalize actual 32-bit integer i to 18-bit ones-complement integer.
+// Interpret mod 0777777, because 0777777 == -0 == +0 == 0000000.
+func norm(i Word) Word {
+       i += i >> 18
+       i &= mask
+       if i == mask {
+               i = 0
+       }
+       return i
+}
+
+type UnknownInstrError struct {
+       Inst Word
+       PC   Word
+}
+
+func (e UnknownInstrError) String() string {
+       return fmt.Sprintf("unknown instruction %06o at %06o", e.Inst, e.PC)
+}
+
+type HaltError Word
+
+func (e HaltError) String() string {
+       return fmt.Sprintf("executed HLT instruction at %06o", e)
+}
+
+type LoopError Word
+
+func (e LoopError) String() string { return fmt.Sprintf("indirect load looping at %06o", e) }
+
+func (m *M) run(inst Word, t Trapper) os.Error {
+       ib, y := (inst>>12)&1, inst&07777
+       op := inst >> 13
+       if op < opSKP && op != opCALJDA {
+               for n := 0; ib != 0; n++ {
+                       if n > 07777 {
+                               return LoopError(m.PC - 1)
+                       }
+                       ib = (m.Mem[y] >> 12) & 1
+                       y = m.Mem[y] & 07777
+               }
+       }
+
+       switch op {
+       case opAND:
+               m.AC &= m.Mem[y]
+       case opIOR:
+               m.AC |= m.Mem[y]
+       case opXOR:
+               m.AC ^= m.Mem[y]
+       case opXCT:
+               m.run(m.Mem[y], t)
+       case opCALJDA:
+               a := y
+               if ib == 0 {
+                       a = 64
+               }
+               m.Mem[a] = m.AC
+               m.AC = (m.OV << 17) + m.PC
+               m.PC = a + 1
+       case opLAC:
+               m.AC = m.Mem[y]
+       case opLIO:
+               m.IO = m.Mem[y]
+       case opDAC:
+               m.Mem[y] = m.AC
+       case opDAP:
+               m.Mem[y] = m.Mem[y]&0770000 | m.AC&07777
+       case opDIO:
+               m.Mem[y] = m.IO
+       case opDZM:
+               m.Mem[y] = 0
+       case opADD:
+               m.AC += m.Mem[y]
+               m.OV = m.AC >> 18
+               m.AC = norm(m.AC)
+       case opSUB:
+               diffSigns := (m.AC^m.Mem[y])>>17 == 1
+               m.AC += m.Mem[y] ^ mask
+               m.AC = norm(m.AC)
+               if diffSigns && m.Mem[y]>>17 == m.AC>>17 {
+                       m.OV = 1
+               }
+       case opIDX:
+               m.AC = norm(m.Mem[y] + 1)
+               m.Mem[y] = m.AC
+       case opISP:
+               m.AC = norm(m.Mem[y] + 1)
+               m.Mem[y] = m.AC
+               if m.AC&sign == 0 {
+                       m.PC++
+               }
+       case opSAD:
+               if m.AC != m.Mem[y] {
+                       m.PC++
+               }
+       case opSAS:
+               if m.AC == m.Mem[y] {
+                       m.PC++
+               }
+       case opMUS:
+               if m.IO&1 == 1 {
+                       m.AC += m.Mem[y]
+                       m.AC = norm(m.AC)
+               }
+               m.IO = (m.IO>>1 | m.AC<<17) & mask
+               m.AC >>= 1
+       case opDIS:
+               m.AC, m.IO = (m.AC<<1|m.IO>>17)&mask,
+                       ((m.IO<<1|m.AC>>17)&mask)^1
+               if m.IO&1 == 1 {
+                       m.AC = m.AC + (m.Mem[y] ^ mask)
+               } else {
+                       m.AC = m.AC + 1 + m.Mem[y]
+               }
+               m.AC = norm(m.AC)
+       case opJMP:
+               m.PC = y
+       case opJSP:
+               m.AC = (m.OV << 17) + m.PC
+               m.PC = y
+       case opSKP:
+               cond := y&0100 == 0100 && m.AC == 0 ||
+                       y&0200 == 0200 && m.AC>>17 == 0 ||
+                       y&0400 == 0400 && m.AC>>17 == 1 ||
+                       y&01000 == 01000 && m.OV == 0 ||
+                       y&02000 == 02000 && m.IO>>17 == 0 ||
+                       y&7 != 0 && !m.Flag[y&7] ||
+                       y&070 != 0 && !m.Sense[(y&070)>>3] ||
+                       y&070 == 010
+               if (ib == 0) == cond {
+                       m.PC++
+               }
+               if y&01000 == 01000 {
+                       m.OV = 0
+               }
+       case opSFT:
+               for count := inst & 0777; count != 0; count >>= 1 {
+                       if count&1 == 0 {
+                               continue
+                       }
+                       switch (inst >> 9) & 017 {
+                       case 001: // rotate AC left
+                               m.AC = (m.AC<<1 | m.AC>>17) & mask
+                       case 002: // rotate IO left
+                               m.IO = (m.IO<<1 | m.IO>>17) & mask
+                       case 003: // rotate AC and IO left.
+                               w := uint64(m.AC)<<18 | uint64(m.IO)
+                               w = w<<1 | w>>35
+                               m.AC = Word(w>>18) & mask
+                               m.IO = Word(w) & mask
+                       case 005: // shift AC left (excluding sign bit)
+                               m.AC = (m.AC<<1|m.AC>>17)&mask&^sign | m.AC&sign
+                       case 006: // shift IO left (excluding sign bit)
+                               m.IO = (m.IO<<1|m.IO>>17)&mask&^sign | m.IO&sign
+                       case 007: // shift AC and IO left (excluding AC's sign bit)
+                               w := uint64(m.AC)<<18 | uint64(m.IO)
+                               w = w<<1 | w>>35
+                               m.AC = Word(w>>18)&mask&^sign | m.AC&sign
+                               m.IO = Word(w)&mask&^sign | m.AC&sign
+                       case 011: // rotate AC right
+                               m.AC = (m.AC>>1 | m.AC<<17) & mask
+                       case 012: // rotate IO right
+                               m.IO = (m.IO>>1 | m.IO<<17) & mask
+                       case 013: // rotate AC and IO right
+                               w := uint64(m.AC)<<18 | uint64(m.IO)
+                               w = w>>1 | w<<35
+                               m.AC = Word(w>>18) & mask
+                               m.IO = Word(w) & mask
+                       case 015: // shift AC right (excluding sign bit)
+                               m.AC = m.AC>>1 | m.AC&sign
+                       case 016: // shift IO right (excluding sign bit)
+                               m.IO = m.IO>>1 | m.IO&sign
+                       case 017: // shift AC and IO right (excluding AC's sign bit)
+                               w := uint64(m.AC)<<18 | uint64(m.IO)
+                               w = w >> 1
+                               m.AC = Word(w>>18) | m.AC&sign
+                               m.IO = Word(w) & mask
+                       default:
+                               goto Unknown
+                       }
+               }
+       case opLAW:
+               if ib == 0 {
+                       m.AC = y
+               } else {
+                       m.AC = y ^ mask
+               }
+       case opIOT:
+               t.Trap(y)
+       case opOPR:
+               if y&0200 == 0200 {
+                       m.AC = 0
+               }
+               if y&04000 == 04000 {
+                       m.IO = 0
+               }
+               if y&01000 == 01000 {
+                       m.AC ^= mask
+               }
+               if y&0400 == 0400 {
+                       m.PC--
+                       return HaltError(m.PC)
+               }
+               switch i, f := y&7, y&010 == 010; {
+               case i == 7:
+                       for i := 2; i < 7; i++ {
+                               m.Flag[i] = f
+                       }
+               case i >= 2:
+                       m.Flag[i] = f
+               }
+       default:
+       Unknown:
+               return UnknownInstrError{inst, m.PC - 1}
+       }
+       return nil
+}
+
+// Load loads the machine's memory from a text input file
+// listing octal address-value pairs, one per line, matching the
+// regular expression ^[ +]([0-7]+)\t([0-7]+).
+func (m *M) Load(r io.Reader) os.Error {
+       b := bufio.NewReader(r)
+       for {
+               line, err := b.ReadString('\n')
+               if err != nil {
+                       if err != os.EOF {
+                               return err
+                       }
+                       break
+               }
+               // look for ^[ +]([0-9]+)\t([0-9]+)
+               if line[0] != ' ' && line[0] != '+' {
+                       continue
+               }
+               i := 1
+               a := Word(0)
+               for ; i < len(line) && '0' <= line[i] && line[i] <= '7'; i++ {
+                       a = a*8 + Word(line[i]-'0')
+               }
+               if i >= len(line) || line[i] != '\t' || i == 1 {
+                       continue
+               }
+               v := Word(0)
+               j := i
+               for i++; i < len(line) && '0' <= line[i] && line[i] <= '7'; i++ {
+                       v = v*8 + Word(line[i]-'0')
+               }
+               if i == j {
+                       continue
+               }
+               m.Mem[a] = v
+       }
+       return nil
+}
diff --git a/libgo/go/exp/spacewar/spacewar.go b/libgo/go/exp/spacewar/spacewar.go
new file mode 100644 (file)
index 0000000..4eb6249
--- /dev/null
@@ -0,0 +1,202 @@
+// Copyright (c) 1996 Barry Silverman, Brian Silverman, Vadim Gerasimov.
+// Portions Copyright (c) 2009 The Go Authors.
+//
+// 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.
+
+// See ../../nacl/README.
+
+package main
+
+import (
+       "bytes"
+       "exp/draw"
+       "exp/nacl/av"
+       "exp/nacl/srpc"
+       "image"
+       "log"
+       "os"
+       "runtime"
+       "time"
+       "./pdp1"
+)
+
+func main() {
+       runtime.LockOSThread()
+       if srpc.Enabled() {
+               go srpc.ServeRuntime()
+       }
+
+       w, err := av.Init(av.SubsystemVideo, 512, 512)
+       if err != nil {
+               log.Exitf("av.Init: %s", err)
+       }
+
+       kc := make(chan int)
+       go demuxEvents(w, kc)
+
+       var m SpacewarPDP1
+       m.Init(w, kc)
+       m.PC = 4
+       f := bytes.NewBuffer([]byte(spacewarCode))
+       if err = m.Load(f); err != nil {
+               log.Exitf("loading %s: %s", "spacewar.lst", err)
+       }
+       for err == nil {
+               //fmt.Printf("step PC=%06o ", m.PC);
+               //fmt.Printf("inst=%06o AC=%06o IO=%06o OV=%o\n",
+               //      m.Mem[m.PC], m.AC, m.IO, m.OV);
+               err = m.Step()
+       }
+       log.Exitf("step: %s", err)
+}
+
+func demuxEvents(w draw.Window, kc chan int) {
+       for event := range w.EventChan() {
+               switch e := event.(type) {
+               case draw.KeyEvent:
+                       kc <- e.Key
+               }
+       }
+       os.Exit(0)
+}
+
+// A SpacewarPDP1 is a PDP-1 machine configured to run Spacewar!
+// It responds to traps by drawing on the display, and it flushes the
+// display and pauses every second time the program counter reaches
+// instruction 02051.
+type SpacewarPDP1 struct {
+       pdp1.M
+       nframe     int
+       frameTime  int64
+       ctxt       draw.Window
+       dx, dy     int
+       screen     draw.Image
+       ctl        pdp1.Word
+       kc         <-chan int
+       colorModel image.ColorModel
+       cmap       []image.Color
+       pix        [][]uint8
+}
+
+func min(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+func (m *SpacewarPDP1) Init(ctxt draw.Window, kc chan int) {
+       m.ctxt = ctxt
+       m.kc = kc
+       m.screen = ctxt.Screen()
+       m.dx = m.screen.Bounds().Dx()
+       m.dy = m.screen.Bounds().Dy()
+       m.colorModel = m.screen.ColorModel()
+       m.pix = make([][]uint8, m.dy)
+       for i := range m.pix {
+               m.pix[i] = make([]uint8, m.dx)
+       }
+       m.cmap = make([]image.Color, 256)
+       for i := range m.cmap {
+               var r, g, b uint8
+               r = uint8(min(0, 255))
+               g = uint8(min(i*2, 255))
+               b = uint8(min(0, 255))
+               m.cmap[i] = m.colorModel.Convert(image.RGBAColor{r, g, b, 0xff})
+       }
+}
+
+const (
+       frameDelay = 56 * 1e6 // 56 ms
+)
+
+var ctlBits = [...]pdp1.Word{
+       'f':  0000001,
+       'd':  0000002,
+       'a':  0000004,
+       's':  0000010,
+       '\'': 0040000,
+       ';':  0100000,
+       'k':  0200000,
+       'l':  0400000,
+}
+
+func (m *SpacewarPDP1) Step() os.Error {
+       if m.PC == 02051 {
+               m.pollInput()
+               m.nframe++
+               if m.nframe&1 == 0 {
+                       m.flush()
+                       t := time.Nanoseconds()
+                       if t >= m.frameTime+3*frameDelay {
+                               m.frameTime = t
+                       } else {
+                               m.frameTime += frameDelay
+                               for t < m.frameTime {
+                                       time.Sleep(m.frameTime - t)
+                                       t = time.Nanoseconds()
+                               }
+                       }
+               }
+       }
+       return m.M.Step(m)
+}
+
+func (m *SpacewarPDP1) Trap(y pdp1.Word) {
+       switch y & 077 {
+       case 7:
+               x := int(m.AC+0400000) & 0777777
+               y := int(m.IO+0400000) & 0777777
+               x = x * m.dx / 0777777
+               y = y * m.dy / 0777777
+               if 0 <= x && x < m.dx && 0 <= y && y < m.dy {
+                       n := uint8(min(int(m.pix[y][x])+128, 255))
+                       m.pix[y][x] = n
+               }
+       case 011:
+               m.IO = m.ctl
+       }
+}
+
+func (m *SpacewarPDP1) flush() {
+       // Update screen image; simulate phosphor decay.
+       for y := 0; y < m.dy; y++ {
+               for x := 0; x < m.dx; x++ {
+                       m.screen.Set(x, y, m.cmap[m.pix[y][x]])
+                       m.pix[y][x] >>= 1
+               }
+       }
+       m.ctxt.FlushImage()
+}
+
+func (m *SpacewarPDP1) pollInput() {
+       for {
+               select {
+               case ch := <-m.kc:
+                       if 0 <= ch && ch < len(ctlBits) {
+                               m.ctl |= ctlBits[ch]
+                       }
+                       if 0 <= -ch && -ch < len(ctlBits) {
+                               m.ctl &^= ctlBits[-ch]
+                       }
+               default:
+                       return
+               }
+       }
+}
diff --git a/libgo/go/expvar/expvar.go b/libgo/go/expvar/expvar.go
new file mode 100644 (file)
index 0000000..6068fbb
--- /dev/null
@@ -0,0 +1,249 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The expvar package provides a standardized interface to public variables,
+// such as operation counters in servers. It exposes these variables via
+// HTTP at /debug/vars in JSON format.
+//
+// Operations to set or modify these public variables are atomic.
+//
+// In addition to adding the HTTP handler, this package registers the
+// following variables:
+//
+//     cmdline   os.Args
+//     memstats  runtime.Memstats
+//
+// The package is sometimes only imported for the side effect of
+// registering its HTTP handler and the above variables.  To use it
+// this way, simply link this package into your program:
+//     import _ "expvar"
+//
+package expvar
+
+import (
+       "bytes"
+       "fmt"
+       "http"
+       "json"
+       "log"
+       "os"
+       "runtime"
+       "strconv"
+       "sync"
+)
+
+// Var is an abstract type for all exported variables.
+type Var interface {
+       String() string
+}
+
+// Int is a 64-bit integer variable, and satisfies the Var interface.
+type Int struct {
+       i  int64
+       mu sync.Mutex
+}
+
+func (v *Int) String() string { return strconv.Itoa64(v.i) }
+
+func (v *Int) Add(delta int64) {
+       v.mu.Lock()
+       defer v.mu.Unlock()
+       v.i += delta
+}
+
+func (v *Int) Set(value int64) {
+       v.mu.Lock()
+       defer v.mu.Unlock()
+       v.i = value
+}
+
+// Map is a string-to-Var map variable, and satisfies the Var interface.
+type Map struct {
+       m  map[string]Var
+       mu sync.Mutex
+}
+
+// KeyValue represents a single entry in a Map.
+type KeyValue struct {
+       Key   string
+       Value Var
+}
+
+func (v *Map) String() string {
+       v.mu.Lock()
+       defer v.mu.Unlock()
+       b := new(bytes.Buffer)
+       fmt.Fprintf(b, "{")
+       first := true
+       for key, val := range v.m {
+               if !first {
+                       fmt.Fprintf(b, ", ")
+               }
+               fmt.Fprintf(b, "\"%s\": %v", key, val.String())
+               first = false
+       }
+       fmt.Fprintf(b, "}")
+       return b.String()
+}
+
+func (v *Map) Init() *Map {
+       v.m = make(map[string]Var)
+       return v
+}
+
+func (v *Map) Get(key string) Var {
+       v.mu.Lock()
+       defer v.mu.Unlock()
+       return v.m[key]
+}
+
+func (v *Map) Set(key string, av Var) {
+       v.mu.Lock()
+       defer v.mu.Unlock()
+       v.m[key] = av
+}
+
+func (v *Map) Add(key string, delta int64) {
+       v.mu.Lock()
+       defer v.mu.Unlock()
+       av, ok := v.m[key]
+       if !ok {
+               av = new(Int)
+               v.m[key] = av
+       }
+
+       // Add to Int; ignore otherwise.
+       if iv, ok := av.(*Int); ok {
+               iv.Add(delta)
+       }
+}
+
+// TODO(rsc): Make sure map access in separate thread is safe.
+func (v *Map) iterate(c chan<- KeyValue) {
+       for k, v := range v.m {
+               c <- KeyValue{k, v}
+       }
+       close(c)
+}
+
+func (v *Map) Iter() <-chan KeyValue {
+       c := make(chan KeyValue)
+       go v.iterate(c)
+       return c
+}
+
+// String is a string variable, and satisfies the Var interface.
+type String struct {
+       s string
+}
+
+func (v *String) String() string { return strconv.Quote(v.s) }
+
+func (v *String) Set(value string) { v.s = value }
+
+// IntFunc wraps a func() int64 to create a value that satisfies the Var interface.
+// The function will be called each time the Var is evaluated.
+type IntFunc func() int64
+
+func (v IntFunc) String() string { return strconv.Itoa64(v()) }
+
+// StringFunc wraps a func() string to create value that satisfies the Var interface.
+// The function will be called each time the Var is evaluated.
+type StringFunc func() string
+
+func (f StringFunc) String() string { return f() }
+
+
+// All published variables.
+var vars map[string]Var = make(map[string]Var)
+var mutex sync.Mutex
+
+// Publish declares an named exported variable. This should be called from a
+// package's init function when it creates its Vars. If the name is already
+// registered then this will log.Panic.
+func Publish(name string, v Var) {
+       mutex.Lock()
+       defer mutex.Unlock()
+       if _, existing := vars[name]; existing {
+               log.Panicln("Reuse of exported var name:", name)
+       }
+       vars[name] = v
+}
+
+// Get retrieves a named exported variable.
+func Get(name string) Var {
+       return vars[name]
+}
+
+// RemoveAll removes all exported variables.
+// This is for tests; don't call this on a real server.
+func RemoveAll() {
+       mutex.Lock()
+       defer mutex.Unlock()
+       vars = make(map[string]Var)
+}
+
+// Convenience functions for creating new exported variables.
+
+func NewInt(name string) *Int {
+       v := new(Int)
+       Publish(name, v)
+       return v
+}
+
+func NewMap(name string) *Map {
+       v := new(Map).Init()
+       Publish(name, v)
+       return v
+}
+
+func NewString(name string) *String {
+       v := new(String)
+       Publish(name, v)
+       return v
+}
+
+// TODO(rsc): Make sure map access in separate thread is safe.
+func iterate(c chan<- KeyValue) {
+       for k, v := range vars {
+               c <- KeyValue{k, v}
+       }
+       close(c)
+}
+
+func Iter() <-chan KeyValue {
+       c := make(chan KeyValue)
+       go iterate(c)
+       return c
+}
+
+func expvarHandler(w http.ResponseWriter, r *http.Request) {
+       w.SetHeader("content-type", "application/json; charset=utf-8")
+       fmt.Fprintf(w, "{\n")
+       first := true
+       for name, value := range vars {
+               if !first {
+                       fmt.Fprintf(w, ",\n")
+               }
+               first = false
+               fmt.Fprintf(w, "%q: %s", name, value)
+       }
+       fmt.Fprintf(w, "\n}\n")
+}
+
+func memstats() string {
+       b, _ := json.MarshalIndent(&runtime.MemStats, "", "\t")
+       return string(b)
+}
+
+func cmdline() string {
+       b, _ := json.Marshal(os.Args)
+       return string(b)
+}
+
+func init() {
+       http.Handle("/debug/vars", http.HandlerFunc(expvarHandler))
+       Publish("cmdline", StringFunc(cmdline))
+       Publish("memstats", StringFunc(memstats))
+}
diff --git a/libgo/go/expvar/expvar_test.go b/libgo/go/expvar/expvar_test.go
new file mode 100644 (file)
index 0000000..3dfc55a
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expvar
+
+import (
+       "json"
+       "testing"
+)
+
+func TestInt(t *testing.T) {
+       reqs := NewInt("requests")
+       if reqs.i != 0 {
+               t.Errorf("reqs.i = %v, want 0", reqs.i)
+       }
+       if reqs != Get("requests").(*Int) {
+               t.Errorf("Get() failed.")
+       }
+
+       reqs.Add(1)
+       reqs.Add(3)
+       if reqs.i != 4 {
+               t.Errorf("reqs.i = %v, want 4", reqs.i)
+       }
+
+       if s := reqs.String(); s != "4" {
+               t.Errorf("reqs.String() = %q, want \"4\"", s)
+       }
+
+       reqs.Set(-2)
+       if reqs.i != -2 {
+               t.Errorf("reqs.i = %v, want -2", reqs.i)
+       }
+}
+
+func TestString(t *testing.T) {
+       name := NewString("my-name")
+       if name.s != "" {
+               t.Errorf("name.s = %q, want \"\"", name.s)
+       }
+
+       name.Set("Mike")
+       if name.s != "Mike" {
+               t.Errorf("name.s = %q, want \"Mike\"", name.s)
+       }
+
+       if s := name.String(); s != "\"Mike\"" {
+               t.Errorf("reqs.String() = %q, want \"\"Mike\"\"", s)
+       }
+}
+
+func TestMapCounter(t *testing.T) {
+       colours := NewMap("bike-shed-colours")
+
+       colours.Add("red", 1)
+       colours.Add("red", 2)
+       colours.Add("blue", 4)
+       if x := colours.m["red"].(*Int).i; x != 3 {
+               t.Errorf("colours.m[\"red\"] = %v, want 3", x)
+       }
+       if x := colours.m["blue"].(*Int).i; x != 4 {
+               t.Errorf("colours.m[\"blue\"] = %v, want 4", x)
+       }
+
+       // colours.String() should be '{"red":3, "blue":4}',
+       // though the order of red and blue could vary.
+       s := colours.String()
+       var j interface{}
+       err := json.Unmarshal([]byte(s), &j)
+       if err != nil {
+               t.Errorf("colours.String() isn't valid JSON: %v", err)
+       }
+       m, ok := j.(map[string]interface{})
+       if !ok {
+               t.Error("colours.String() didn't produce a map.")
+       }
+       red := m["red"]
+       x, ok := red.(float64)
+       if !ok {
+               t.Error("red.Kind() is not a number.")
+       }
+       if x != 3 {
+               t.Errorf("red = %v, want 3", x)
+       }
+}
+
+func TestIntFunc(t *testing.T) {
+       x := int(4)
+       ix := IntFunc(func() int64 { return int64(x) })
+       if s := ix.String(); s != "4" {
+               t.Errorf("ix.String() = %v, want 4", s)
+       }
+
+       x++
+       if s := ix.String(); s != "5" {
+               t.Errorf("ix.String() = %v, want 5", s)
+       }
+}
diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go
new file mode 100644 (file)
index 0000000..59c3340
--- /dev/null
@@ -0,0 +1,532 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+       The flag package implements command-line flag parsing.
+
+       Usage:
+
+       1) Define flags using flag.String(), Bool(), Int(), etc. Example:
+               import "flag"
+               var ip *int = flag.Int("flagname", 1234, "help message for flagname")
+       If you like, you can bind the flag to a variable using the Var() functions.
+               var flagvar int
+               func init() {
+                       flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
+               }
+       Or you can create custom flags that satisfy the Value interface (with
+       pointer receivers) and couple them to flag parsing by
+               flag.Var(&flagVal, "name", "help message for flagname")
+       For such flags, the default value is just the initial value of the variable.
+
+       2) After all flags are defined, call
+               flag.Parse()
+       to parse the command line into the defined flags.
+
+       3) Flags may then be used directly. If you're using the flags themselves,
+       they are all pointers; if you bind to variables, they're values.
+               fmt.Println("ip has value ", *ip);
+               fmt.Println("flagvar has value ", flagvar);
+
+       4) After parsing, flag.Arg(i) is the i'th argument after the flags.
+       Args are indexed from 0 up to flag.NArg().
+
+       Command line flag syntax:
+               -flag
+               -flag=x
+               -flag x  // non-boolean flags only
+       One or two minus signs may be used; they are equivalent.
+       The last form is not permitted for boolean flags because the
+       meaning of the command
+               cmd -x *
+       will change if there is a file called 0, false, etc.  You must
+       use the -flag=false form to turn off a boolean flag.
+
+       Flag parsing stops just before the first non-flag argument
+       ("-" is a non-flag argument) or after the terminator "--".
+
+       Integer flags accept 1234, 0664, 0x1234 and may be negative.
+       Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
+*/
+package flag
+
+import (
+       "fmt"
+       "os"
+       "strconv"
+)
+
+// -- Bool Value
+type boolValue bool
+
+func newBoolValue(val bool, p *bool) *boolValue {
+       *p = val
+       return (*boolValue)(p)
+}
+
+func (b *boolValue) Set(s string) bool {
+       v, err := strconv.Atob(s)
+       *b = boolValue(v)
+       return err == nil
+}
+
+func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
+
+// -- Int Value
+type intValue int
+
+func newIntValue(val int, p *int) *intValue {
+       *p = val
+       return (*intValue)(p)
+}
+
+func (i *intValue) Set(s string) bool {
+       v, err := strconv.Atoi(s)
+       *i = intValue(v)
+       return err == nil
+}
+
+func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- Int64 Value
+type int64Value int64
+
+func newInt64Value(val int64, p *int64) *int64Value {
+       *p = val
+       return (*int64Value)(p)
+}
+
+func (i *int64Value) Set(s string) bool {
+       v, err := strconv.Atoi64(s)
+       *i = int64Value(v)
+       return err == nil
+}
+
+func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- Uint Value
+type uintValue uint
+
+func newUintValue(val uint, p *uint) *uintValue {
+       *p = val
+       return (*uintValue)(p)
+}
+
+func (i *uintValue) Set(s string) bool {
+       v, err := strconv.Atoui(s)
+       *i = uintValue(v)
+       return err == nil
+}
+
+func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- uint64 Value
+type uint64Value uint64
+
+func newUint64Value(val uint64, p *uint64) *uint64Value {
+       *p = val
+       return (*uint64Value)(p)
+}
+
+func (i *uint64Value) Set(s string) bool {
+       v, err := strconv.Atoui64(s)
+       *i = uint64Value(v)
+       return err == nil
+}
+
+func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- string Value
+type stringValue string
+
+func newStringValue(val string, p *string) *stringValue {
+       *p = val
+       return (*stringValue)(p)
+}
+
+func (s *stringValue) Set(val string) bool {
+       *s = stringValue(val)
+       return true
+}
+
+func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
+
+// -- Float Value
+type floatValue float
+
+func newFloatValue(val float, p *float) *floatValue {
+       *p = val
+       return (*floatValue)(p)
+}
+
+func (f *floatValue) Set(s string) bool {
+       v, err := strconv.Atof(s)
+       *f = floatValue(v)
+       return err == nil
+}
+
+func (f *floatValue) String() string { return fmt.Sprintf("%v", *f) }
+
+// -- Float64 Value
+type float64Value float64
+
+func newFloat64Value(val float64, p *float64) *float64Value {
+       *p = val
+       return (*float64Value)(p)
+}
+
+func (f *float64Value) Set(s string) bool {
+       v, err := strconv.Atof64(s)
+       *f = float64Value(v)
+       return err == nil
+}
+
+func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
+
+// Value is the interface to the dynamic value stored in a flag.
+// (The default value is represented as a string.)
+type Value interface {
+       String() string
+       Set(string) bool
+}
+
+// A Flag represents the state of a flag.
+type Flag struct {
+       Name     string // name as it appears on command line
+       Usage    string // help message
+       Value    Value  // value as set
+       DefValue string // default value (as text); for usage message
+}
+
+type allFlags struct {
+       actual    map[string]*Flag
+       formal    map[string]*Flag
+       first_arg int // 0 is the program name, 1 is first arg
+}
+
+var flags *allFlags
+
+// VisitAll visits the flags, calling fn for each. It visits all flags, even those not set.
+func VisitAll(fn func(*Flag)) {
+       for _, f := range flags.formal {
+               fn(f)
+       }
+}
+
+// Visit visits the flags, calling fn for each. It visits only those flags that have been set.
+func Visit(fn func(*Flag)) {
+       for _, f := range flags.actual {
+               fn(f)
+       }
+}
+
+// Lookup returns the Flag structure of the named flag, returning nil if none exists.
+func Lookup(name string) *Flag {
+       return flags.formal[name]
+}
+
+// Set sets the value of the named flag.  It returns true if the set succeeded; false if
+// there is no such flag defined.
+func Set(name, value string) bool {
+       f, ok := flags.formal[name]
+       if !ok {
+               return false
+       }
+       ok = f.Value.Set(value)
+       if !ok {
+               return false
+       }
+       flags.actual[name] = f
+       return true
+}
+
+// PrintDefaults prints to standard error the default values of all defined flags.
+func PrintDefaults() {
+       VisitAll(func(f *Flag) {
+               format := "  -%s=%s: %s\n"
+               if _, ok := f.Value.(*stringValue); ok {
+                       // put quotes on the value
+                       format = "  -%s=%q: %s\n"
+               }
+               fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage)
+       })
+}
+
+// Usage prints to standard error a default usage message documenting all defined flags.
+// The function is a variable that may be changed to point to a custom function.
+var Usage = func() {
+       fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+       PrintDefaults()
+}
+
+var panicOnError = false
+
+func fail() {
+       Usage()
+       if panicOnError {
+               panic("flag parse error")
+       }
+       os.Exit(2)
+}
+
+func NFlag() int { return len(flags.actual) }
+
+// Arg returns the i'th command-line argument.  Arg(0) is the first remaining argument
+// after flags have been processed.
+func Arg(i int) string {
+       i += flags.first_arg
+       if i < 0 || i >= len(os.Args) {
+               return ""
+       }
+       return os.Args[i]
+}
+
+// NArg is the number of arguments remaining after flags have been processed.
+func NArg() int { return len(os.Args) - flags.first_arg }
+
+// Args returns the non-flag command-line arguments.
+func Args() []string { return os.Args[flags.first_arg:] }
+
+// BoolVar defines a bool flag with specified name, default value, and usage string.
+// The argument p points to a bool variable in which to store the value of the flag.
+func BoolVar(p *bool, name string, value bool, usage string) {
+       Var(newBoolValue(value, p), name, usage)
+}
+
+// Bool defines a bool flag with specified name, default value, and usage string.
+// The return value is the address of a bool variable that stores the value of the flag.
+func Bool(name string, value bool, usage string) *bool {
+       p := new(bool)
+       BoolVar(p, name, value, usage)
+       return p
+}
+
+// IntVar defines an int flag with specified name, default value, and usage string.
+// The argument p points to an int variable in which to store the value of the flag.
+func IntVar(p *int, name string, value int, usage string) {
+       Var(newIntValue(value, p), name, usage)
+}
+
+// Int defines an int flag with specified name, default value, and usage string.
+// The return value is the address of an int variable that stores the value of the flag.
+func Int(name string, value int, usage string) *int {
+       p := new(int)
+       IntVar(p, name, value, usage)
+       return p
+}
+
+// Int64Var defines an int64 flag with specified name, default value, and usage string.
+// The argument p points to an int64 variable in which to store the value of the flag.
+func Int64Var(p *int64, name string, value int64, usage string) {
+       Var(newInt64Value(value, p), name, usage)
+}
+
+// Int64 defines an int64 flag with specified name, default value, and usage string.
+// The return value is the address of an int64 variable that stores the value of the flag.
+func Int64(name string, value int64, usage string) *int64 {
+       p := new(int64)
+       Int64Var(p, name, value, usage)
+       return p
+}
+
+// UintVar defines a uint flag with specified name, default value, and usage string.
+// The argument p points to a uint variable in which to store the value of the flag.
+func UintVar(p *uint, name string, value uint, usage string) {
+       Var(newUintValue(value, p), name, usage)
+}
+
+// Uint defines a uint flag with specified name, default value, and usage string.
+// The return value is the address of a uint variable that stores the value of the flag.
+func Uint(name string, value uint, usage string) *uint {
+       p := new(uint)
+       UintVar(p, name, value, usage)
+       return p
+}
+
+// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
+// The argument p points to a uint64 variable in which to store the value of the flag.
+func Uint64Var(p *uint64, name string, value uint64, usage string) {
+       Var(newUint64Value(value, p), name, usage)
+}
+
+// Uint64 defines a uint64 flag with specified name, default value, and usage string.
+// The return value is the address of a uint64 variable that stores the value of the flag.
+func Uint64(name string, value uint64, usage string) *uint64 {
+       p := new(uint64)
+       Uint64Var(p, name, value, usage)
+       return p
+}
+
+// StringVar defines a string flag with specified name, default value, and usage string.
+// The argument p points to a string variable in which to store the value of the flag.
+func StringVar(p *string, name, value string, usage string) {
+       Var(newStringValue(value, p), name, usage)
+}
+
+// String defines a string flag with specified name, default value, and usage string.
+// The return value is the address of a string variable that stores the value of the flag.
+func String(name, value string, usage string) *string {
+       p := new(string)
+       StringVar(p, name, value, usage)
+       return p
+}
+
+// FloatVar defines a float flag with specified name, default value, and usage string.
+// The argument p points to a float variable in which to store the value of the flag.
+func FloatVar(p *float, name string, value float, usage string) {
+       Var(newFloatValue(value, p), name, usage)
+}
+
+// Float defines a float flag with specified name, default value, and usage string.
+// The return value is the address of a float variable that stores the value of the flag.
+func Float(name string, value float, usage string) *float {
+       p := new(float)
+       FloatVar(p, name, value, usage)
+       return p
+}
+
+// Float64Var defines a float64 flag with specified name, default value, and usage string.
+// The argument p points to a float64 variable in which to store the value of the flag.
+func Float64Var(p *float64, name string, value float64, usage string) {
+       Var(newFloat64Value(value, p), name, usage)
+}
+
+// Float64 defines a float64 flag with specified name, default value, and usage string.
+// The return value is the address of a float64 variable that stores the value of the flag.
+func Float64(name string, value float64, usage string) *float64 {
+       p := new(float64)
+       Float64Var(p, name, value, usage)
+       return p
+}
+
+// Var defines a user-typed flag with specified name, default value, and usage string.
+// The argument p points to a Value variable in which to store the value of the flag.
+func Var(value Value, name string, usage string) {
+       // Remember the default value as a string; it won't change.
+       f := &Flag{name, usage, value, value.String()}
+       _, alreadythere := flags.formal[name]
+       if alreadythere {
+               fmt.Fprintln(os.Stderr, "flag redefined:", name)
+               panic("flag redefinition") // Happens only if flags are declared with identical names
+       }
+       flags.formal[name] = f
+}
+
+
+func (f *allFlags) parseOne(index int) (ok bool, next int) {
+       s := os.Args[index]
+       f.first_arg = index // until proven otherwise
+       if len(s) == 0 {
+               return false, -1
+       }
+       if s[0] != '-' {
+               return false, -1
+       }
+       num_minuses := 1
+       if len(s) == 1 {
+               return false, index
+       }
+       if s[1] == '-' {
+               num_minuses++
+               if len(s) == 2 { // "--" terminates the flags
+                       return false, index + 1
+               }
+       }
+       name := s[num_minuses:]
+       if len(name) == 0 || name[0] == '-' || name[0] == '=' {
+               fmt.Fprintln(os.Stderr, "bad flag syntax:", s)
+               fail()
+       }
+
+       // it's a flag. does it have an argument?
+       has_value := false
+       value := ""
+       for i := 1; i < len(name); i++ { // equals cannot be first
+               if name[i] == '=' {
+                       value = name[i+1:]
+                       has_value = true
+                       name = name[0:i]
+                       break
+               }
+       }
+       m := flags.formal
+       flag, alreadythere := m[name] // BUG
+       if !alreadythere {
+               fmt.Fprintf(os.Stderr, "flag provided but not defined: -%s\n", name)
+               fail()
+       }
+       if f, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
+               if has_value {
+                       if !f.Set(value) {
+                               fmt.Fprintf(os.Stderr, "invalid boolean value %t for flag: -%s\n", value, name)
+                               fail()
+                       }
+               } else {
+                       f.Set("true")
+               }
+       } else {
+               // It must have a value, which might be the next argument.
+               if !has_value && index < len(os.Args)-1 {
+                       // value is the next arg
+                       has_value = true
+                       index++
+                       value = os.Args[index]
+               }
+               if !has_value {
+                       fmt.Fprintf(os.Stderr, "flag needs an argument: -%s\n", name)
+                       fail()
+               }
+               ok = flag.Value.Set(value)
+               if !ok {
+                       fmt.Fprintf(os.Stderr, "invalid value %s for flag: -%s\n", value, name)
+                       fail()
+               }
+       }
+       flags.actual[name] = flag
+       return true, index + 1
+}
+
+// Parse parses the command-line flags.  Must be called after all flags are defined
+// and before any are accessed by the program.
+func Parse() {
+       for i := 1; i < len(os.Args); {
+               ok, next := flags.parseOne(i)
+               if next > 0 {
+                       flags.first_arg = next
+                       i = next
+               }
+               if !ok {
+                       break
+               }
+       }
+}
+
+// ResetForTesting clears all flag state and sets the usage function as directed.
+// After calling ResetForTesting, parse errors in flag handling will panic rather
+// than exit the program.
+// For testing only!
+func ResetForTesting(usage func()) {
+       flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), 1}
+       Usage = usage
+       panicOnError = true
+}
+
+// ParseForTesting parses the flag state using the provided arguments. It
+// should be called after 1) ResetForTesting and 2) setting up the new flags.
+// The return value reports whether the parse was error-free.
+// For testing only!
+func ParseForTesting(args []string) (result bool) {
+       defer func() {
+               if recover() != nil {
+                       result = false
+               }
+       }()
+       os.Args = args
+       Parse()
+       return true
+}
+
+func init() {
+       flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), 1}
+}
diff --git a/libgo/go/flag/flag_test.go b/libgo/go/flag/flag_test.go
new file mode 100644 (file)
index 0000000..5fb7649
--- /dev/null
@@ -0,0 +1,182 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flag_test
+
+import (
+       . "flag"
+       "fmt"
+       "testing"
+)
+
+var (
+       test_bool    = Bool("test_bool", false, "bool value")
+       test_int     = Int("test_int", 0, "int value")
+       test_int64   = Int64("test_int64", 0, "int64 value")
+       test_uint    = Uint("test_uint", 0, "uint value")
+       test_uint64  = Uint64("test_uint64", 0, "uint64 value")
+       test_string  = String("test_string", "0", "string value")
+       test_float   = Float("test_float", 0, "float value")
+       test_float64 = Float("test_float64", 0, "float64 value")
+)
+
+func boolString(s string) string {
+       if s == "0" {
+               return "false"
+       }
+       return "true"
+}
+
+func TestEverything(t *testing.T) {
+       m := make(map[string]*Flag)
+       desired := "0"
+       visitor := func(f *Flag) {
+               if len(f.Name) > 5 && f.Name[0:5] == "test_" {
+                       m[f.Name] = f
+                       ok := false
+                       switch {
+                       case f.Value.String() == desired:
+                               ok = true
+                       case f.Name == "test_bool" && f.Value.String() == boolString(desired):
+                               ok = true
+                       }
+                       if !ok {
+                               t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
+                       }
+               }
+       }
+       VisitAll(visitor)
+       if len(m) != 8 {
+               t.Error("VisitAll misses some flags")
+               for k, v := range m {
+                       t.Log(k, *v)
+               }
+       }
+       m = make(map[string]*Flag)
+       Visit(visitor)
+       if len(m) != 0 {
+               t.Errorf("Visit sees unset flags")
+               for k, v := range m {
+                       t.Log(k, *v)
+               }
+       }
+       // Now set all flags
+       Set("test_bool", "true")
+       Set("test_int", "1")
+       Set("test_int64", "1")
+       Set("test_uint", "1")
+       Set("test_uint64", "1")
+       Set("test_string", "1")
+       Set("test_float", "1")
+       Set("test_float64", "1")
+       desired = "1"
+       Visit(visitor)
+       if len(m) != 8 {
+               t.Error("Visit fails after set")
+               for k, v := range m {
+                       t.Log(k, *v)
+               }
+       }
+}
+
+func TestUsage(t *testing.T) {
+       called := false
+       ResetForTesting(func() { called = true })
+       if ParseForTesting([]string{"a.out", "-x"}) {
+               t.Error("parse did not fail for unknown flag")
+       }
+       if !called {
+               t.Error("did not call Usage for unknown flag")
+       }
+}
+
+func TestParse(t *testing.T) {
+       ResetForTesting(func() { t.Error("bad parse") })
+       boolFlag := Bool("bool", false, "bool value")
+       bool2Flag := Bool("bool2", false, "bool2 value")
+       intFlag := Int("int", 0, "int value")
+       int64Flag := Int64("int64", 0, "int64 value")
+       uintFlag := Uint("uint", 0, "uint value")
+       uint64Flag := Uint64("uint64", 0, "uint64 value")
+       stringFlag := String("string", "0", "string value")
+       floatFlag := Float("float", 0, "float value")
+       float64Flag := Float("float64", 0, "float64 value")
+       extra := "one-extra-argument"
+       args := []string{
+               "a.out",
+               "-bool",
+               "-bool2=true",
+               "--int", "22",
+               "--int64", "23",
+               "-uint", "24",
+               "--uint64", "25",
+               "-string", "hello",
+               "--float", "3141.5",
+               "-float64", "2718e28",
+               extra,
+       }
+       if !ParseForTesting(args) {
+               t.Fatal("parse failed")
+       }
+       if *boolFlag != true {
+               t.Error("bool flag should be true, is ", *boolFlag)
+       }
+       if *bool2Flag != true {
+               t.Error("bool2 flag should be true, is ", *bool2Flag)
+       }
+       if *intFlag != 22 {
+               t.Error("int flag should be 22, is ", *intFlag)
+       }
+       if *int64Flag != 23 {
+               t.Error("int64 flag should be 23, is ", *int64Flag)
+       }
+       if *uintFlag != 24 {
+               t.Error("uint flag should be 24, is ", *uintFlag)
+       }
+       if *uint64Flag != 25 {
+               t.Error("uint64 flag should be 25, is ", *uint64Flag)
+       }
+       if *stringFlag != "hello" {
+               t.Error("string flag should be `hello`, is ", *stringFlag)
+       }
+       if *floatFlag != 3141.5 {
+               t.Error("float flag should be 3141.5, is ", *floatFlag)
+       }
+       if *float64Flag != 2718e28 {
+               t.Error("float64 flag should be 2718e28, is ", *float64Flag)
+       }
+       if len(Args()) != 1 {
+               t.Error("expected one argument, got", len(Args()))
+       } else if Args()[0] != extra {
+               t.Errorf("expected argument %q got %q", extra, Args()[0])
+       }
+}
+
+// Declare a user-defined flag.
+type flagVar []string
+
+func (f *flagVar) String() string {
+       return fmt.Sprint([]string(*f))
+}
+
+func (f *flagVar) Set(value string) bool {
+       *f = append(*f, value)
+       return true
+}
+
+func TestUserDefined(t *testing.T) {
+       ResetForTesting(func() { t.Fatal("bad parse") })
+       var v flagVar
+       Var(&v, "v", "usage")
+       if !ParseForTesting([]string{"a.out", "-v", "1", "-v", "2", "-v=3"}) {
+               t.Error("parse failed")
+       }
+       if len(v) != 3 {
+               t.Fatal("expected 3 args; got ", len(v))
+       }
+       expect := "[1 2 3]"
+       if v.String() != expect {
+               t.Errorf("expected value %q got %q", expect, v.String())
+       }
+}
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go
new file mode 100644 (file)
index 0000000..06dc730
--- /dev/null
@@ -0,0 +1,163 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+       Package fmt implements formatted I/O with functions analogous
+       to C's printf and scanf.  The format 'verbs' are derived from C's but
+       are simpler.
+
+       Printing:
+
+       The verbs:
+
+       General:
+               %v      the value in a default format.
+                       when printing structs, the plus flag (%+v) adds field names
+               %#v     a Go-syntax representation of the value
+               %T      a Go-syntax representation of the type of the value
+
+       Boolean:
+               %t      the word true or false
+       Integer:
+               %b      base 2
+               %c      the character represented by the corresponding Unicode code point
+               %d      base 10
+               %o      base 8
+               %x      base 16, with lower-case letters for a-f
+               %X      base 16, with upper-case letters for A-F
+       Floating-point and complex constituents:
+               %e      scientific notation, e.g. -1234.456e+78
+               %E      scientific notation, e.g. -1234.456E+78
+               %f      decimal point but no exponent, e.g. 123.456
+               %g      whichever of %e or %f produces more compact output
+               %G      whichever of %E or %f produces more compact output
+       String and slice of bytes:
+               %s      the uninterpreted bytes of the string or slice
+               %q      a double-quoted string safely escaped with Go syntax
+               %x      base 16 notation with two characters per byte
+       Pointer:
+               %p      base 16 notation, with leading 0x
+
+       There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
+       Similarly, there is no need to specify the size of the operand (int8, int64).
+
+       For numeric values, the width and precision flags control
+       formatting; width sets the width of the field, precision the
+       number of places after the decimal, if appropriate.  The
+       format %6.2f prints 123.45. The width of a field is the number
+       of Unicode code points in the string. This differs from C's printf where
+       the field width is the number of bytes.  Either or both of the
+       flags may be replaced with the character '*', causing their values
+       to be obtained from the next operand, which must be of type int.
+
+       Other flags:
+               +       always print a sign for numeric values
+               -       pad with spaces on the right rather than the left (left-justify the field)
+               #       alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
+                       0X for hex (%#X); suppress 0x for %p (%#p);
+                       print a raw (backquoted) string if possible for %q (%#q)
+               ' '     (space) leave a space for elided sign in numbers (% d);
+                       put spaces between bytes printing strings or slices in hex (% x)
+               0       pad with leading zeros rather than spaces
+
+       For each Printf-like function, there is also a Print function
+       that takes no format and is equivalent to saying %v for every
+       operand.  Another variant Println inserts blanks between
+       operands and appends a newline.
+
+       Regardless of the verb, if an operand is an interface value,
+       the internal concrete value is used, not the interface itself.
+       Thus:
+               var i interface{} = 23
+               fmt.Printf("%v\n", i)
+       will print 23.
+
+       If an operand implements interface Formatter, that interface
+       can be used for fine control of formatting.
+
+       If an operand implements method String() string that method
+       will be used to convert the object to a string, which will then
+       be formatted as required by the verb (if any). To avoid
+       recursion in cases such as
+               type X int
+               func (x X) String() string { return Sprintf("%d", x) }
+       cast the value before recurring:
+               func (x X) String() string { return Sprintf("%d", int(x)) }
+
+       Format errors:
+
+       If an invalid argument is given for a verb, such as providing
+       a string to %d, the generated string will contain a
+       description of the problem, as in these examples:
+
+               Wrong type or unknown verb: %!verb(type=value)
+                       Printf("%d", hi):          %!d(string=hi)
+               Too many arguments: %!(EXTRA type=value)
+                       Printf("hi", "guys"):      hi%!(EXTRA string=guys)
+               Too few arguments: %!verb(MISSING)
+                       Printf("hi%d"):            hi %!d(MISSING)
+               Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
+                       Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
+                       Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
+
+       All errors begin with the string "%!" followed sometimes
+       by a single character (the verb) and end with a parenthesized
+       description.
+
+       Scanning:
+
+       An analogous set of functions scans formatted text to yield
+       values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
+       Fscanf and Fscanln read from a specified os.Reader; Sscan,
+       Sscanf and Sscanln read from an argument string.  Sscanln,
+       Fscanln and Sscanln stop scanning at a newline and require that
+       the items be followed by one; Sscanf, Fscanf and Sscanf require
+       newlines in the input to match newlines in the format; the other
+       routines treat newlines as spaces.
+
+       Scanf, Fscanf, and Sscanf parse the arguments according to a
+       format string, analogous to that of Printf.  For example, %x
+       will scan an integer as a hexadecimal number, and %v will scan
+       the default representation format for the value.
+
+       The formats behave analogously to those of Printf with the
+       following exceptions:
+
+       %p is not implemented
+       %T is not implemented
+       %e %E %f %F %g %g are all equivalent and scan any floating
+               point or complex value
+       %s and %v on strings scan a space-delimited token
+
+       Width is interpreted in the input text (%5s means at most
+       five runes of input will be read to scan a string) but there
+       is no syntax for scanning with a precision (no %5.2f, just
+       %5f).
+
+       When scanning with a format, all non-empty runs of space
+       characters (except newline) are equivalent to a single
+       space in both the format and the input.  With that proviso,
+       text in the format string must match the input text; scanning
+       stops if it does not, with the return value of the function
+       indicating the number of arguments scanned.
+
+       In all the scanning functions, if an operand implements method
+       Scan (that is, it implements the Scanner interface) that
+       method will be used to scan the text for that operand.  Also,
+       if the number of arguments scanned is less than the number of
+       arguments provided, an error is returned.
+
+       All arguments to be scanned must be either pointers to basic
+       types or implementations of the Scanner interface.
+
+       Note: Fscan etc. can read one character (rune) past the
+       input they return, which means that a loop calling a scan
+       routine may skip some of the input.  This is usually a
+       problem only when there is no space between input values.
+       However, if the reader provided to Fscan implements UnreadRune,
+       that method will be used to save the character and successive
+       calls will not lose data.  To attach an UnreadRune method
+       to a reader without that capability, use bufio.NewReader.
+*/
+package fmt
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
new file mode 100644 (file)
index 0000000..2c09e07
--- /dev/null
@@ -0,0 +1,652 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt_test
+
+import (
+       . "fmt"
+       "io"
+       "math"
+       "runtime" // for the malloc count test only
+       "strings"
+       "testing"
+)
+
+type (
+       renamedBool       bool
+       renamedInt        int
+       renamedInt8       int8
+       renamedInt16      int16
+       renamedInt32      int32
+       renamedInt64      int64
+       renamedUint       uint
+       renamedUint8      uint8
+       renamedUint16     uint16
+       renamedUint32     uint32
+       renamedUint64     uint64
+       renamedUintptr    uintptr
+       renamedString     string
+       renamedBytes      []byte
+       renamedFloat      float
+       renamedFloat32    float32
+       renamedFloat64    float64
+       renamedComplex    complex
+       renamedComplex64  complex64
+       renamedComplex128 complex128
+)
+
+func TestFmtInterface(t *testing.T) {
+       var i1 interface{}
+       i1 = "abc"
+       s := Sprintf("%s", i1)
+       if s != "abc" {
+               t.Errorf(`Sprintf("%%s", empty("abc")) = %q want %q`, s, "abc")
+       }
+}
+
+type fmtTest struct {
+       fmt string
+       val interface{}
+       out string
+}
+
+const b32 uint32 = 1<<32 - 1
+const b64 uint64 = 1<<64 - 1
+
+var array = []int{1, 2, 3, 4, 5}
+var iarray = []interface{}{1, "hello", 2.5, nil}
+
+type A struct {
+       i int
+       j uint
+       s string
+       x []int
+}
+
+type I int
+
+func (i I) String() string { return Sprintf("<%d>", int(i)) }
+
+type B struct {
+       i I
+       j int
+}
+
+type C struct {
+       i int
+       B
+}
+
+type F int
+
+func (f F) Format(s State, c int) {
+       Fprintf(s, "<%c=F(%d)>", c, int(f))
+}
+
+type G int
+
+func (g G) GoString() string {
+       return Sprintf("GoString(%d)", int(g))
+}
+
+type S struct {
+       f F // a struct field that Formats
+       g G // a struct field that GoStrings
+}
+
+// A type with a String method with pointer receiver for testing %p
+type P int
+
+var pValue P
+
+func (p *P) String() string {
+       return "String(p)"
+}
+
+var b byte
+
+var fmttests = []fmtTest{
+       {"%d", 12345, "12345"},
+       {"%v", 12345, "12345"},
+       {"%t", true, "true"},
+
+       // basic string
+       {"%s", "abc", "abc"},
+       {"%x", "abc", "616263"},
+       {"%x", "xyz", "78797a"},
+       {"%X", "xyz", "78797A"},
+       {"%q", "abc", `"abc"`},
+
+       // basic bytes
+       {"%s", []byte("abc"), "abc"},
+       {"%x", []byte("abc"), "616263"},
+       {"% x", []byte("abc"), "61 62 63"},
+       {"%x", []byte("xyz"), "78797a"},
+       {"%X", []byte("xyz"), "78797A"},
+       {"%q", []byte("abc"), `"abc"`},
+
+       // escaped strings
+       {"%#q", `abc`, "`abc`"},
+       {"%#q", `"`, "`\"`"},
+       {"1 %#q", `\n`, "1 `\\n`"},
+       {"2 %#q", "\n", `2 "\n"`},
+       {"%q", `"`, `"\""`},
+       {"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+       {"%q", "abc\xffdef", `"abc\xffdef"`},
+       {"%q", "\u263a", `"\u263a"`},
+       {"%q", "\U0010ffff", `"\U0010ffff"`},
+
+       // width
+       {"%5s", "abc", "  abc"},
+       {"%2s", "\u263a", " \u263a"},
+       {"%-5s", "abc", "abc  "},
+       {"%05s", "abc", "00abc"},
+
+       // integers
+       {"%d", 12345, "12345"},
+       {"%d", -12345, "-12345"},
+       {"%10d", 12345, "     12345"},
+       {"%10d", -12345, "    -12345"},
+       {"%+10d", 12345, "    +12345"},
+       {"%010d", 12345, "0000012345"},
+       {"%010d", -12345, "-000012345"},
+       {"%-10d", 12345, "12345     "},
+       {"%010.3d", 1, "       001"},
+       {"%010.3d", -1, "      -001"},
+       {"%+d", 12345, "+12345"},
+       {"%+d", -12345, "-12345"},
+       {"%+d", 0, "+0"},
+       {"% d", 0, " 0"},
+       {"% d", 12345, " 12345"},
+
+       // floats
+       {"%+.3e", 0.0, "+0.000e+00"},
+       {"%+.3e", 1.0, "+1.000e+00"},
+       {"%+.3f", -1.0, "-1.000"},
+       {"% .3E", -1.0, "-1.000E+00"},
+       {"% .3e", 1.0, " 1.000e+00"},
+       {"%+.3g", 0.0, "+0"},
+       {"%+.3g", 1.0, "+1"},
+       {"%+.3g", -1.0, "-1"},
+       {"% .3g", -1.0, "-1"},
+       {"% .3g", 1.0, " 1"},
+
+       // complex values
+       {"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
+       {"%+.3f", 0i, "(+0.000+0.000i)"},
+       {"%+.3g", 0i, "(+0+0i)"},
+       {"%+.3e", 1 + 2i, "(+1.000e+00+2.000e+00i)"},
+       {"%+.3f", 1 + 2i, "(+1.000+2.000i)"},
+       {"%+.3g", 1 + 2i, "(+1+2i)"},
+       {"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
+       {"%.3f", 0i, "(0.000+0.000i)"},
+       {"%.3g", 0i, "(0+0i)"},
+       {"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
+       {"%.3f", 1 + 2i, "(1.000+2.000i)"},
+       {"%.3g", 1 + 2i, "(1+2i)"},
+       {"%.3e", -1 - 2i, "(-1.000e+00-2.000e+00i)"},
+       {"%.3f", -1 - 2i, "(-1.000-2.000i)"},
+       {"%.3g", -1 - 2i, "(-1-2i)"},
+       {"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
+       {"%+.3g", complex64(1 + 2i), "(+1+2i)"},
+       {"%+.3g", complex128(1 + 2i), "(+1+2i)"},
+
+       // erroneous formats
+       {"", 2, "%!(EXTRA int=2)"},
+       {"%d", "hello", "%!d(string=hello)"},
+
+       // old test/fmt_test.go
+       {"%d", 1234, "1234"},
+       {"%d", -1234, "-1234"},
+       {"%d", uint(1234), "1234"},
+       {"%d", uint32(b32), "4294967295"},
+       {"%d", uint64(b64), "18446744073709551615"},
+       {"%o", 01234, "1234"},
+       {"%#o", 01234, "01234"},
+       {"%o", uint32(b32), "37777777777"},
+       {"%o", uint64(b64), "1777777777777777777777"},
+       {"%x", 0x1234abcd, "1234abcd"},
+       {"%#x", 0x1234abcd, "0x1234abcd"},
+       {"%x", b32 - 0x1234567, "fedcba98"},
+       {"%X", 0x1234abcd, "1234ABCD"},
+       {"%X", b32 - 0x1234567, "FEDCBA98"},
+       {"%#X", 0, "0X0"},
+       {"%x", b64, "ffffffffffffffff"},
+       {"%b", 7, "111"},
+       {"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"},
+       {"%b", -6, "-110"},
+       {"%e", float64(1), "1.000000e+00"},
+       {"%e", float64(1234.5678e3), "1.234568e+06"},
+       {"%e", float64(1234.5678e-8), "1.234568e-05"},
+       {"%e", float64(-7), "-7.000000e+00"},
+       {"%e", float64(-1e-9), "-1.000000e-09"},
+       {"%f", float64(1234.5678e3), "1234567.800000"},
+       {"%f", float64(1234.5678e-8), "0.000012"},
+       {"%f", float64(-7), "-7.000000"},
+       {"%f", float64(-1e-9), "-0.000000"},
+       {"%g", float64(1234.5678e3), "1.2345678e+06"},
+       {"%g", float32(1234.5678e3), "1.2345678e+06"},
+       {"%g", float64(1234.5678e-8), "1.2345678e-05"},
+       {"%g", float64(-7), "-7"},
+       {"%g", float64(-1e-9), "-1e-09"},
+       {"%g", float32(-1e-9), "-1e-09"},
+       {"%E", float64(1), "1.000000E+00"},
+       {"%E", float64(1234.5678e3), "1.234568E+06"},
+       {"%E", float64(1234.5678e-8), "1.234568E-05"},
+       {"%E", float64(-7), "-7.000000E+00"},
+       {"%E", float64(-1e-9), "-1.000000E-09"},
+       {"%G", float64(1234.5678e3), "1.2345678E+06"},
+       {"%G", float32(1234.5678e3), "1.2345678E+06"},
+       {"%G", float64(1234.5678e-8), "1.2345678E-05"},
+       {"%G", float64(-7), "-7"},
+       {"%G", float64(-1e-9), "-1E-09"},
+       {"%G", float32(-1e-9), "-1E-09"},
+       {"%c", 'x', "x"},
+       {"%c", 0xe4, "ä"},
+       {"%c", 0x672c, "本"},
+       {"%c", '日', "日"},
+       {"%20.8d", 1234, "            00001234"},
+       {"%20.8d", -1234, "           -00001234"},
+       {"%20d", 1234, "                1234"},
+       {"%-20.8d", 1234, "00001234            "},
+       {"%-20.8d", -1234, "-00001234           "},
+       {"%-#20.8x", 0x1234abc, "0x01234abc          "},
+       {"%-#20.8X", 0x1234abc, "0X01234ABC          "},
+       {"%-#20.8o", 01234, "00001234            "},
+       {"%.20b", 7, "00000000000000000111"},
+       {"%20.5s", "qwertyuiop", "               qwert"},
+       {"%.5s", "qwertyuiop", "qwert"},
+       {"%-20.5s", "qwertyuiop", "qwert               "},
+       {"%20c", 'x', "                   x"},
+       {"%-20c", 'x', "x                   "},
+       {"%20.6e", 1.2345e3, "        1.234500e+03"},
+       {"%20.6e", 1.2345e-3, "        1.234500e-03"},
+       {"%20e", 1.2345e3, "        1.234500e+03"},
+       {"%20e", 1.2345e-3, "        1.234500e-03"},
+       {"%20.8e", 1.2345e3, "      1.23450000e+03"},
+       {"%20f", float64(1.23456789e3), "         1234.567890"},
+       {"%20f", float64(1.23456789e-3), "            0.001235"},
+       {"%20f", float64(12345678901.23456789), "  12345678901.234568"},
+       {"%-20f", float64(1.23456789e3), "1234.567890         "},
+       {"%20.8f", float64(1.23456789e3), "       1234.56789000"},
+       {"%20.8f", float64(1.23456789e-3), "          0.00123457"},
+       {"%g", float64(1.23456789e3), "1234.56789"},
+       {"%g", float64(1.23456789e-3), "0.00123456789"},
+       {"%g", float64(1.23456789e20), "1.23456789e+20"},
+       {"%20e", math.Inf(1), "                +Inf"},
+       {"%-20f", math.Inf(-1), "-Inf                "},
+       {"%20g", math.NaN(), "                 NaN"},
+
+       // arrays
+       {"%v", array, "[1 2 3 4 5]"},
+       {"%v", iarray, "[1 hello 2.5 <nil>]"},
+       {"%v", &array, "&[1 2 3 4 5]"},
+       {"%v", &iarray, "&[1 hello 2.5 <nil>]"},
+
+       // complexes with %v
+       {"%v", 1 + 2i, "(1+2i)"},
+       {"%v", complex64(1 + 2i), "(1+2i)"},
+       {"%v", complex128(1 + 2i), "(1+2i)"},
+
+       // structs
+       {"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
+       {"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`},
+
+       // +v on structs with Stringable items
+       {"%+v", B{1, 2}, `{i:<1> j:2}`},
+       {"%+v", C{1, B{2, 3}}, `{i:1 B:{i:<2> j:3}}`},
+
+       // q on Stringable items
+       {"%s", I(23), `<23>`},
+       {"%q", I(23), `"<23>"`},
+       {"%x", I(23), `3c32333e`},
+       {"%d", I(23), `%!d(string=<23>)`},
+
+       // go syntax
+       {"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
+       {"%#v", &b, "(*uint8)(PTR)"},
+       {"%#v", TestFmtInterface, "(func(*testing.T))(PTR)"},
+       {"%#v", make(chan int), "(chan int)(PTR)"},
+       {"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
+       {"%#v", 1000000000, "1000000000"},
+       {"%#v", map[string]int{"a": 1, "b": 2}, `map[string] int{"a":1, "b":2}`},
+       {"%#v", map[string]B{"a": {1, 2}, "b": {3, 4}}, `map[string] fmt_test.B{"a":fmt_test.B{i:1, j:2}, "b":fmt_test.B{i:3, j:4}}`},
+       {"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
+
+       // slices with other formats
+       {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
+       {"%x", []int{1, 2, 15}, `[1 2 f]`},
+       {"%d", []int{1, 2, 15}, `[1 2 15]`},
+       {"%d", []byte{1, 2, 15}, `[1 2 15]`},
+       {"%q", []string{"a", "b"}, `["a" "b"]`},
+
+       // renamings
+       {"%v", renamedBool(true), "true"},
+       {"%d", renamedBool(true), "%!d(fmt_test.renamedBool=true)"},
+       {"%o", renamedInt(8), "10"},
+       {"%d", renamedInt8(-9), "-9"},
+       {"%v", renamedInt16(10), "10"},
+       {"%v", renamedInt32(-11), "-11"},
+       {"%X", renamedInt64(255), "FF"},
+       {"%v", renamedUint(13), "13"},
+       {"%o", renamedUint8(14), "16"},
+       {"%X", renamedUint16(15), "F"},
+       {"%d", renamedUint32(16), "16"},
+       {"%X", renamedUint64(17), "11"},
+       {"%o", renamedUintptr(18), "22"},
+       {"%x", renamedString("thing"), "7468696e67"},
+       {"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`},
+       {"%q", renamedBytes([]byte("hello")), `"hello"`},
+       {"%v", renamedFloat(11), "11"},
+       {"%v", renamedFloat32(22), "22"},
+       {"%v", renamedFloat64(33), "33"},
+       {"%v", renamedComplex(7 + .2i), "(7+0.2i)"},
+       {"%v", renamedComplex64(3 + 4i), "(3+4i)"},
+       {"%v", renamedComplex128(4 - 3i), "(4-3i)"},
+
+       // Formatter
+       {"%x", F(1), "<x=F(1)>"},
+       {"%x", G(2), "2"},
+       {"%+v", S{F(4), G(5)}, "{f:<v=F(4)> g:5}"},
+
+       // GoStringer
+       {"%#v", G(6), "GoString(6)"},
+       {"%#v", S{F(7), G(8)}, "fmt_test.S{f:<v=F(7)>, g:GoString(8)}"},
+
+       // %T
+       {"%T", (4 - 3i), "complex"},
+       {"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
+       {"%T", intVal, "int"},
+       {"%6T", &intVal, "  *int"},
+
+       // %p
+       {"p0=%p", new(int), "p0=PTR"},
+       {"p1=%s", &pValue, "p1=String(p)"}, // String method...
+       {"p2=%p", &pValue, "p2=PTR"},       // ... not called with %p
+
+       // %p on non-pointers
+       {"%p", make(chan int), "PTR"},
+       {"%p", make(map[int]int), "PTR"},
+       {"%p", make([]int, 1), "PTR"},
+       {"%p", 27, "%!p(int=27)"}, // not a pointer at all
+
+       // erroneous things
+       {"%d", "hello", "%!d(string=hello)"},
+       {"no args", "hello", "no args%!(EXTRA string=hello)"},
+       {"%s", nil, "%!s(<nil>)"},
+       {"%T", nil, "<nil>"},
+       {"%-1", 100, "%!1(int=100)"},
+}
+
+func TestSprintf(t *testing.T) {
+       for _, tt := range fmttests {
+               s := Sprintf(tt.fmt, tt.val)
+               if i := strings.Index(s, "0x"); i >= 0 && strings.Contains(tt.out, "PTR") {
+                       j := i + 2
+                       for ; j < len(s); j++ {
+                               c := s[j]
+                               if (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F') {
+                                       break
+                               }
+                       }
+                       s = s[0:i] + "PTR" + s[j:]
+               }
+               if s != tt.out {
+                       if _, ok := tt.val.(string); ok {
+                               // Don't requote the already-quoted strings.
+                               // It's too confusing to read the errors.
+                               t.Errorf("Sprintf(%q, %q) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out)
+                       } else {
+                               t.Errorf("Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out)
+                       }
+               }
+       }
+}
+
+func BenchmarkSprintfEmpty(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sprintf("")
+       }
+}
+
+func BenchmarkSprintfString(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sprintf("%s", "hello")
+       }
+}
+
+func BenchmarkSprintfInt(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sprintf("%d", 5)
+       }
+}
+
+func BenchmarkSprintfIntInt(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sprintf("%d %d", 5, 6)
+       }
+}
+
+func TestCountMallocs(t *testing.T) {
+       mallocs := 0 - runtime.MemStats.Mallocs
+       for i := 0; i < 100; i++ {
+               Sprintf("")
+       }
+       mallocs += runtime.MemStats.Mallocs
+       Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/100)
+       mallocs = 0 - runtime.MemStats.Mallocs
+       for i := 0; i < 100; i++ {
+               Sprintf("xxx")
+       }
+       mallocs += runtime.MemStats.Mallocs
+       Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/100)
+       mallocs = 0 - runtime.MemStats.Mallocs
+       for i := 0; i < 100; i++ {
+               Sprintf("%x", i)
+       }
+       mallocs += runtime.MemStats.Mallocs
+       Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/100)
+       mallocs = 0 - runtime.MemStats.Mallocs
+       for i := 0; i < 100; i++ {
+               Sprintf("%x %x", i, i)
+       }
+       mallocs += runtime.MemStats.Mallocs
+       Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/100)
+}
+
+type flagPrinter struct{}
+
+func (*flagPrinter) Format(f State, c int) {
+       s := "%"
+       for i := 0; i < 128; i++ {
+               if f.Flag(i) {
+                       s += string(i)
+               }
+       }
+       if w, ok := f.Width(); ok {
+               s += Sprintf("%d", w)
+       }
+       if p, ok := f.Precision(); ok {
+               s += Sprintf(".%d", p)
+       }
+       s += string(c)
+       io.WriteString(f, "["+s+"]")
+}
+
+type flagTest struct {
+       in  string
+       out string
+}
+
+var flagtests = []flagTest{
+       {"%a", "[%a]"},
+       {"%-a", "[%-a]"},
+       {"%+a", "[%+a]"},
+       {"%#a", "[%#a]"},
+       {"% a", "[% a]"},
+       {"%0a", "[%0a]"},
+       {"%1.2a", "[%1.2a]"},
+       {"%-1.2a", "[%-1.2a]"},
+       {"%+1.2a", "[%+1.2a]"},
+       {"%-+1.2a", "[%+-1.2a]"},
+       {"%-+1.2abc", "[%+-1.2a]bc"},
+       {"%-1.2abc", "[%-1.2a]bc"},
+}
+
+func TestFlagParser(t *testing.T) {
+       var flagprinter flagPrinter
+       for _, tt := range flagtests {
+               s := Sprintf(tt.in, &flagprinter)
+               if s != tt.out {
+                       t.Errorf("Sprintf(%q, &flagprinter) => %q, want %q", tt.in, s, tt.out)
+               }
+       }
+}
+
+func TestStructPrinter(t *testing.T) {
+       var s struct {
+               a string
+               b string
+               c int
+       }
+       s.a = "abc"
+       s.b = "def"
+       s.c = 123
+       type Test struct {
+               fmt string
+               out string
+       }
+       var tests = []Test{
+               {"%v", "{abc def 123}"},
+               {"%+v", "{a:abc b:def c:123}"},
+       }
+       for _, tt := range tests {
+               out := Sprintf(tt.fmt, s)
+               if out != tt.out {
+                       t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out)
+               }
+       }
+}
+
+// Check map printing using substrings so we don't depend on the print order.
+func presentInMap(s string, a []string, t *testing.T) {
+       for i := 0; i < len(a); i++ {
+               loc := strings.Index(s, a[i])
+               if loc < 0 {
+                       t.Errorf("map print: expected to find %q in %q", a[i], s)
+               }
+               // make sure the match ends here
+               loc += len(a[i])
+               if loc >= len(s) || (s[loc] != ' ' && s[loc] != ']') {
+                       t.Errorf("map print: %q not properly terminated in %q", a[i], s)
+               }
+       }
+}
+
+func TestMapPrinter(t *testing.T) {
+       m0 := make(map[int]string)
+       s := Sprint(m0)
+       if s != "map[]" {
+               t.Errorf("empty map printed as %q not %q", s, "map[]")
+       }
+       m1 := map[int]string{1: "one", 2: "two", 3: "three"}
+       a := []string{"1:one", "2:two", "3:three"}
+       presentInMap(Sprintf("%v", m1), a, t)
+       presentInMap(Sprint(m1), a, t)
+}
+
+func TestEmptyMap(t *testing.T) {
+       const emptyMapStr = "map[]"
+       var m map[string]int
+       s := Sprint(m)
+       if s != emptyMapStr {
+               t.Errorf("nil map printed as %q not %q", s, emptyMapStr)
+       }
+       m = make(map[string]int)
+       s = Sprint(m)
+       if s != emptyMapStr {
+               t.Errorf("empty map printed as %q not %q", s, emptyMapStr)
+       }
+}
+
+// Check that Sprint (and hence Print, Fprint) puts spaces in the right places,
+// that is, between arg pairs in which neither is a string.
+func TestBlank(t *testing.T) {
+       got := Sprint("<", 1, ">:", 1, 2, 3, "!")
+       expect := "<1>:1 2 3!"
+       if got != expect {
+               t.Errorf("got %q expected %q", got, expect)
+       }
+}
+
+// Check that Sprintln (and hence Println, Fprintln) puts spaces in the right places,
+// that is, between all arg pairs.
+func TestBlankln(t *testing.T) {
+       got := Sprintln("<", 1, ">:", 1, 2, 3, "!")
+       expect := "< 1 >: 1 2 3 !\n"
+       if got != expect {
+               t.Errorf("got %q expected %q", got, expect)
+       }
+}
+
+
+// Check Formatter with Sprint, Sprintln, Sprintf
+func TestFormatterPrintln(t *testing.T) {
+       f := F(1)
+       expect := "<v=F(1)>\n"
+       s := Sprint(f, "\n")
+       if s != expect {
+               t.Errorf("Sprint wrong with Formatter: expected %q got %q", expect, s)
+       }
+       s = Sprintln(f)
+       if s != expect {
+               t.Errorf("Sprintln wrong with Formatter: expected %q got %q", expect, s)
+       }
+       s = Sprintf("%v\n", f)
+       if s != expect {
+               t.Errorf("Sprintf wrong with Formatter: expected %q got %q", expect, s)
+       }
+}
+
+func args(a ...interface{}) []interface{} { return a }
+
+type starTest struct {
+       fmt string
+       in  []interface{}
+       out string
+}
+
+var startests = []starTest{
+       {"%*d", args(4, 42), "  42"},
+       {"%.*d", args(4, 42), "0042"},
+       {"%*.*d", args(8, 4, 42), "    0042"},
+       {"%0*d", args(4, 42), "0042"},
+       {"%-*d", args(4, 42), "42  "},
+
+       // erroneous
+       {"%*d", args(nil, 42), "%!(BADWIDTH)42"},
+       {"%.*d", args(nil, 42), "%!(BADPREC)42"},
+       {"%*d", args(5, "foo"), "%!d(string=  foo)"},
+       {"%*% %d", args(20, 5), "% 5"},
+       {"%*", args(4), "%!(BADWIDTH)%!*(int=4)"},
+       {"%*d", args(int32(4), 42), "%!(BADWIDTH)42"},
+}
+
+// TODO: there's no conversion from []T to ...T, but we can fake it.  These
+// functions do the faking.  We index the table by the length of the param list.
+var sprintf = []func(string, []interface{}) string{
+       0: func(f string, i []interface{}) string { return Sprintf(f) },
+       1: func(f string, i []interface{}) string { return Sprintf(f, i[0]) },
+       2: func(f string, i []interface{}) string { return Sprintf(f, i[0], i[1]) },
+       3: func(f string, i []interface{}) string { return Sprintf(f, i[0], i[1], i[2]) },
+}
+
+func TestWidthAndPrecision(t *testing.T) {
+       for _, tt := range startests {
+               s := sprintf[len(tt.in)](tt.fmt, tt.in)
+               if s != tt.out {
+                       t.Errorf("got %q expected %q", s, tt.out)
+               }
+       }
+}
diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go
new file mode 100644 (file)
index 0000000..3ec1cf1
--- /dev/null
@@ -0,0 +1,420 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+       "bytes"
+       "strconv"
+       "utf8"
+)
+
+const (
+       nByte = 64
+
+       ldigits = "0123456789abcdef"
+       udigits = "0123456789ABCDEF"
+)
+
+const (
+       signed   = true
+       unsigned = false
+)
+
+var padZeroBytes = make([]byte, nByte)
+var padSpaceBytes = make([]byte, nByte)
+
+var newline = []byte{'\n'}
+
+func init() {
+       for i := 0; i < nByte; i++ {
+               padZeroBytes[i] = '0'
+               padSpaceBytes[i] = ' '
+       }
+}
+
+// A fmt is the raw formatter used by Printf etc.
+// It prints into a bytes.Buffer that must be set up externally.
+type fmt struct {
+       intbuf [nByte]byte
+       buf    *bytes.Buffer
+       // width, precision
+       wid  int
+       prec int
+       // flags
+       widPresent  bool
+       precPresent bool
+       minus       bool
+       plus        bool
+       sharp       bool
+       space       bool
+       zero        bool
+}
+
+func (f *fmt) clearflags() {
+       f.wid = 0
+       f.widPresent = false
+       f.prec = 0
+       f.precPresent = false
+       f.minus = false
+       f.plus = false
+       f.sharp = false
+       f.space = false
+       f.zero = false
+}
+
+func (f *fmt) init(buf *bytes.Buffer) {
+       f.buf = buf
+       f.clearflags()
+}
+
+// Compute left and right padding widths (only one will be non-zero).
+func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
+       left := !f.minus
+       w := f.wid
+       if w < 0 {
+               left = false
+               w = -w
+       }
+       w -= width
+       if w > 0 {
+               if left && f.zero {
+                       return padZeroBytes, w, 0
+               }
+               if left {
+                       return padSpaceBytes, w, 0
+               } else {
+                       // can't be zero padding on the right
+                       return padSpaceBytes, 0, w
+               }
+       }
+       return
+}
+
+// Generate n bytes of padding.
+func (f *fmt) writePadding(n int, padding []byte) {
+       for n > 0 {
+               m := n
+               if m > nByte {
+                       m = nByte
+               }
+               f.buf.Write(padding[0:m])
+               n -= m
+       }
+}
+
+// Append b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus)
+// clear flags aftewards.
+func (f *fmt) pad(b []byte) {
+       var padding []byte
+       var left, right int
+       if f.widPresent && f.wid != 0 {
+               padding, left, right = f.computePadding(len(b))
+       }
+       if left > 0 {
+               f.writePadding(left, padding)
+       }
+       f.buf.Write(b)
+       if right > 0 {
+               f.writePadding(right, padding)
+       }
+}
+
+// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// clear flags aftewards.
+func (f *fmt) padString(s string) {
+       var padding []byte
+       var left, right int
+       if f.widPresent && f.wid != 0 {
+               padding, left, right = f.computePadding(utf8.RuneCountInString(s))
+       }
+       if left > 0 {
+               f.writePadding(left, padding)
+       }
+       f.buf.WriteString(s)
+       if right > 0 {
+               f.writePadding(right, padding)
+       }
+}
+
+func putint(buf []byte, base, val uint64, digits string) int {
+       i := len(buf) - 1
+       for val >= base {
+               buf[i] = digits[val%base]
+               i--
+               val /= base
+       }
+       buf[i] = digits[val]
+       return i - 1
+}
+
+// fmt_boolean formats a boolean.
+func (f *fmt) fmt_boolean(v bool) {
+       if v {
+               f.padString("true")
+       } else {
+               f.padString("false")
+       }
+}
+
+// integer; interprets prec but not wid.  Once formatted, result is sent to pad()
+// and then flags are cleared.
+func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
+       var buf []byte = f.intbuf[0:]
+       negative := signedness == signed && a < 0
+       if negative {
+               a = -a
+       }
+
+       // two ways to ask for extra leading zero digits: %.3d or %03d.
+       // apparently the first cancels the second.
+       prec := 0
+       if f.precPresent {
+               prec = f.prec
+               f.zero = false
+       } else if f.zero && f.widPresent && !f.minus && f.wid > 0 {
+               prec = f.wid
+               if negative || f.plus || f.space {
+                       prec-- // leave room for sign
+               }
+       }
+
+       // format a into buf, ending at buf[i].  (printing is easier right-to-left.)
+       // a is made into unsigned ua.  we could make things
+       // marginally faster by splitting the 32-bit case out into a separate
+       // block but it's not worth the duplication, so ua has 64 bits.
+       i := len(f.intbuf)
+       ua := uint64(a)
+       for ua >= base {
+               i--
+               buf[i] = digits[ua%base]
+               ua /= base
+       }
+       i--
+       buf[i] = digits[ua]
+       for i > 0 && prec > nByte-i {
+               i--
+               buf[i] = '0'
+       }
+
+       // Various prefixes: 0x, -, etc.
+       if f.sharp {
+               switch base {
+               case 8:
+                       if buf[i] != '0' {
+                               i--
+                               buf[i] = '0'
+                       }
+               case 16:
+                       i--
+                       buf[i] = 'x' + digits[10] - 'a'
+                       i--
+                       buf[i] = '0'
+               }
+       }
+
+       if negative {
+               i--
+               buf[i] = '-'
+       } else if f.plus {
+               i--
+               buf[i] = '+'
+       } else if f.space {
+               i--
+               buf[i] = ' '
+       }
+       f.pad(buf[i:])
+}
+
+// fmt_s formats a string.
+func (f *fmt) fmt_s(s string) {
+       if f.precPresent {
+               if f.prec < len(s) {
+                       s = s[0:f.prec]
+               }
+       }
+       f.padString(s)
+}
+
+// fmt_sx formats a string as a hexadecimal encoding of its bytes.
+func (f *fmt) fmt_sx(s string) {
+       t := ""
+       for i := 0; i < len(s); i++ {
+               if i > 0 && f.space {
+                       t += " "
+               }
+               v := s[i]
+               t += string(ldigits[v>>4])
+               t += string(ldigits[v&0xF])
+       }
+       f.padString(t)
+}
+
+// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
+func (f *fmt) fmt_sX(s string) {
+       t := ""
+       for i := 0; i < len(s); i++ {
+               v := s[i]
+               t += string(udigits[v>>4])
+               t += string(udigits[v&0xF])
+       }
+       f.padString(t)
+}
+
+// fmt_q formats a string as a double-quoted, escaped Go string constant.
+func (f *fmt) fmt_q(s string) {
+       var quoted string
+       if f.sharp && strconv.CanBackquote(s) {
+               quoted = "`" + s + "`"
+       } else {
+               quoted = strconv.Quote(s)
+       }
+       f.padString(quoted)
+}
+
+// floating-point
+
+func doPrec(f *fmt, def int) int {
+       if f.precPresent {
+               return f.prec
+       }
+       return def
+}
+
+// Add a plus sign or space to the floating-point string representation if missing and required.
+func (f *fmt) plusSpace(s string) {
+       if s[0] != '-' {
+               if f.plus {
+                       s = "+" + s
+               } else if f.space {
+                       s = " " + s
+               }
+       }
+       f.padString(s)
+}
+
+// fmt_e64 formats a float64 in the form -1.23e+12.
+func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'e', doPrec(f, 6))) }
+
+// fmt_E64 formats a float64 in the form -1.23E+12.
+func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'E', doPrec(f, 6))) }
+
+// fmt_f64 formats a float64 in the form -1.23.
+func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'f', doPrec(f, 6))) }
+
+// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
+func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'g', doPrec(f, -1))) }
+
+// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
+func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'G', doPrec(f, -1))) }
+
+// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
+func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'b', 0)) }
+
+// float32
+// cannot defer to float64 versions
+// because it will get rounding wrong in corner cases.
+
+// fmt_e32 formats a float32 in the form -1.23e+12.
+func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'e', doPrec(f, 6))) }
+
+// fmt_E32 formats a float32 in the form -1.23E+12.
+func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'E', doPrec(f, 6))) }
+
+// fmt_f32 formats a float32 in the form -1.23.
+func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'f', doPrec(f, 6))) }
+
+// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
+func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'g', doPrec(f, -1))) }
+
+// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
+func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'G', doPrec(f, -1))) }
+
+// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
+func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.Ftoa32(v, 'b', 0)) }
+
+// fmt_c64 formats a complex64 according to the verb.
+func (f *fmt) fmt_c64(v complex64, verb int) {
+       f.buf.WriteByte('(')
+       r := real(v)
+       for i := 0; ; i++ {
+               switch verb {
+               case 'e':
+                       f.fmt_e32(r)
+               case 'E':
+                       f.fmt_E32(r)
+               case 'f':
+                       f.fmt_f32(r)
+               case 'g':
+                       f.fmt_g32(r)
+               case 'G':
+                       f.fmt_G32(r)
+               }
+               if i != 0 {
+                       break
+               }
+               f.plus = true
+               r = imag(v)
+       }
+       f.buf.Write(irparenBytes)
+}
+
+// fmt_c128 formats a complex128 according to the verb.
+func (f *fmt) fmt_c128(v complex128, verb int) {
+       f.buf.WriteByte('(')
+       r := real(v)
+       for i := 0; ; i++ {
+               switch verb {
+               case 'e':
+                       f.fmt_e64(r)
+               case 'E':
+                       f.fmt_E64(r)
+               case 'f':
+                       f.fmt_f64(r)
+               case 'g':
+                       f.fmt_g64(r)
+               case 'G':
+                       f.fmt_G64(r)
+               }
+               if i != 0 {
+                       break
+               }
+               f.plus = true
+               r = imag(v)
+       }
+       f.buf.Write(irparenBytes)
+}
+
+// float
+func (x *fmt) f(a float) {
+       if strconv.FloatSize == 32 {
+               x.fmt_f32(float32(a))
+       } else {
+               x.fmt_f64(float64(a))
+       }
+}
+
+func (x *fmt) e(a float) {
+       if strconv.FloatSize == 32 {
+               x.fmt_e32(float32(a))
+       } else {
+               x.fmt_e64(float64(a))
+       }
+}
+
+func (x *fmt) g(a float) {
+       if strconv.FloatSize == 32 {
+               x.fmt_g32(float32(a))
+       } else {
+               x.fmt_g64(float64(a))
+       }
+}
+
+func (x *fmt) fb(a float) {
+       if strconv.FloatSize == 32 {
+               x.fmt_fb32(float32(a))
+       } else {
+               x.fmt_fb64(float64(a))
+       }
+}
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
new file mode 100644 (file)
index 0000000..24b1eb3
--- /dev/null
@@ -0,0 +1,913 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "reflect"
+       "utf8"
+)
+
+// Some constants in the form of bytes, to avoid string overhead.
+// Needlessly fastidious, I suppose.
+var (
+       commaSpaceBytes = []byte(", ")
+       nilAngleBytes   = []byte("<nil>")
+       nilParenBytes   = []byte("(nil)")
+       nilBytes        = []byte("nil")
+       mapBytes        = []byte("map[")
+       missingBytes    = []byte("(MISSING)")
+       extraBytes      = []byte("%!(EXTRA ")
+       irparenBytes    = []byte("i)")
+       bytesBytes      = []byte("[]byte{")
+       widthBytes      = []byte("%!(BADWIDTH)")
+       precBytes       = []byte("%!(BADPREC)")
+)
+
+// State represents the printer state passed to custom formatters.
+// It provides access to the io.Writer interface plus information about
+// the flags and options for the operand's format specifier.
+type State interface {
+       // Write is the function to call to emit formatted output to be printed.
+       Write(b []byte) (ret int, err os.Error)
+       // Width returns the value of the width option and whether it has been set.
+       Width() (wid int, ok bool)
+       // Precision returns the value of the precision option and whether it has been set.
+       Precision() (prec int, ok bool)
+
+       // Flag returns whether the flag c, a character, has been set.
+       Flag(int) bool
+}
+
+// Formatter is the interface implemented by values with a custom formatter.
+// The implementation of Format may call Sprintf or Fprintf(f) etc.
+// to generate its output.
+type Formatter interface {
+       Format(f State, c int)
+}
+
+// Stringer is implemented by any value that has a String method(),
+// which defines the ``native'' format for that value.
+// The String method is used to print values passed as an operand
+// to a %s or %v format or to an unformatted printer such as Print.
+type Stringer interface {
+       String() string
+}
+
+// GoStringer is implemented by any value that has a GoString() method,
+// which defines the Go syntax for that value.
+// The GoString method is used to print values passed as an operand
+// to a %#v format.
+type GoStringer interface {
+       GoString() string
+}
+
+type pp struct {
+       n       int
+       buf     bytes.Buffer
+       runeBuf [utf8.UTFMax]byte
+       fmt     fmt
+}
+
+// A leaky bucket of reusable pp structures.
+var ppFree = make(chan *pp, 100)
+
+// Allocate a new pp struct.  Probably can grab the previous one from ppFree.
+func newPrinter() *pp {
+       p, ok := <-ppFree
+       if !ok {
+               p = new(pp)
+       }
+       p.fmt.init(&p.buf)
+       return p
+}
+
+// Save used pp structs in ppFree; avoids an allocation per invocation.
+func (p *pp) free() {
+       // Don't hold on to pp structs with large buffers.
+       if cap(p.buf.Bytes()) > 1024 {
+               return
+       }
+       p.buf.Reset()
+       _ = ppFree <- p
+}
+
+func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
+
+func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
+
+func (p *pp) Flag(b int) bool {
+       switch b {
+       case '-':
+               return p.fmt.minus
+       case '+':
+               return p.fmt.plus
+       case '#':
+               return p.fmt.sharp
+       case ' ':
+               return p.fmt.space
+       case '0':
+               return p.fmt.zero
+       }
+       return false
+}
+
+func (p *pp) add(c int) {
+       if c < utf8.RuneSelf {
+               p.buf.WriteByte(byte(c))
+       } else {
+               w := utf8.EncodeRune(c, p.runeBuf[0:])
+               p.buf.Write(p.runeBuf[0:w])
+       }
+}
+
+// Implement Write so we can call Fprintf on a pp (through State), for
+// recursive use in custom verbs.
+func (p *pp) Write(b []byte) (ret int, err os.Error) {
+       return p.buf.Write(b)
+}
+
+// These routines end in 'f' and take a format string.
+
+// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) {
+       p := newPrinter()
+       p.doPrintf(format, a)
+       n64, error := p.buf.WriteTo(w)
+       p.free()
+       return int(n64), error
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func Printf(format string, a ...interface{}) (n int, errno os.Error) {
+       n, errno = Fprintf(os.Stdout, format, a...)
+       return n, errno
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func Sprintf(format string, a ...interface{}) string {
+       p := newPrinter()
+       p.doPrintf(format, a)
+       s := p.buf.String()
+       p.free()
+       return s
+}
+
+// Errorf formats according to a format specifier and returns the string 
+// converted to an os.ErrorString, which satisfies the os.Error interface.
+func Errorf(format string, a ...interface{}) os.Error {
+       return os.ErrorString(Sprintf(format, a...))
+}
+
+// These routines do not take a format string
+
+// Fprint formats using the default formats for its operands and writes to w.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) {
+       p := newPrinter()
+       p.doPrint(a, false, false)
+       n64, error := p.buf.WriteTo(w)
+       p.free()
+       return int(n64), error
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Print(a ...interface{}) (n int, errno os.Error) {
+       n, errno = Fprint(os.Stdout, a...)
+       return n, errno
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func Sprint(a ...interface{}) string {
+       p := newPrinter()
+       p.doPrint(a, false, false)
+       s := p.buf.String()
+       p.free()
+       return s
+}
+
+// These routines end in 'ln', do not take a format string,
+// always add spaces between operands, and add a newline
+// after the last operand.
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) {
+       p := newPrinter()
+       p.doPrint(a, true, true)
+       n64, error := p.buf.WriteTo(w)
+       p.free()
+       return int(n64), error
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Println(a ...interface{}) (n int, errno os.Error) {
+       n, errno = Fprintln(os.Stdout, a...)
+       return n, errno
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func Sprintln(a ...interface{}) string {
+       p := newPrinter()
+       p.doPrint(a, true, true)
+       s := p.buf.String()
+       p.free()
+       return s
+}
+
+
+// Get the i'th arg of the struct value.
+// If the arg itself is an interface, return a value for
+// the thing inside the interface, not the interface itself.
+func getField(v *reflect.StructValue, i int) reflect.Value {
+       val := v.Field(i)
+       if i, ok := val.(*reflect.InterfaceValue); ok {
+               if inter := i.Interface(); inter != nil {
+                       return reflect.NewValue(inter)
+               }
+       }
+       return val
+}
+
+// Convert ASCII to integer.  n is 0 (and got is false) if no number present.
+func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
+       if start >= end {
+               return 0, false, end
+       }
+       for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
+               num = num*10 + int(s[newi]-'0')
+               isnum = true
+       }
+       return
+}
+
+// Reflection values like reflect.FuncValue implement this method. We use it for %p.
+type uintptrGetter interface {
+       Get() uintptr
+}
+
+func (p *pp) unknownType(v interface{}) {
+       if v == nil {
+               p.buf.Write(nilAngleBytes)
+               return
+       }
+       p.buf.WriteByte('?')
+       p.buf.WriteString(reflect.Typeof(v).String())
+       p.buf.WriteByte('?')
+}
+
+func (p *pp) badVerb(verb int, val interface{}) {
+       p.add('%')
+       p.add('!')
+       p.add(verb)
+       p.add('(')
+       if val == nil {
+               p.buf.Write(nilAngleBytes)
+       } else {
+               p.buf.WriteString(reflect.Typeof(val).String())
+               p.add('=')
+               p.printField(val, 'v', false, false, 0)
+       }
+       p.add(')')
+}
+
+func (p *pp) fmtBool(v bool, verb int, value interface{}) {
+       switch verb {
+       case 't', 'v':
+               p.fmt.fmt_boolean(v)
+       default:
+               p.badVerb(verb, value)
+       }
+}
+
+// fmtC formats a rune for the 'c' format.
+func (p *pp) fmtC(c int64) {
+       rune := int(c) // Check for overflow.
+       if int64(rune) != c {
+               rune = utf8.RuneError
+       }
+       w := utf8.EncodeRune(rune, p.runeBuf[0:utf8.UTFMax])
+       p.fmt.pad(p.runeBuf[0:w])
+}
+
+func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
+       switch verb {
+       case 'b':
+               p.fmt.integer(v, 2, signed, ldigits)
+       case 'c':
+               p.fmtC(v)
+       case 'd', 'v':
+               p.fmt.integer(v, 10, signed, ldigits)
+       case 'o':
+               p.fmt.integer(v, 8, signed, ldigits)
+       case 'x':
+               p.fmt.integer(v, 16, signed, ldigits)
+       case 'X':
+               p.fmt.integer(v, 16, signed, udigits)
+       default:
+               p.badVerb(verb, value)
+       }
+}
+
+// fmt_sharpHex64 formats a uint64 in hexadecimal and prefixes it with 0x by
+// temporarily turning on the sharp flag.
+func (p *pp) fmt0x64(v uint64) {
+       sharp := p.fmt.sharp
+       p.fmt.sharp = true // turn on 0x
+       p.fmt.integer(int64(v), 16, unsigned, ldigits)
+       p.fmt.sharp = sharp
+}
+
+func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
+       switch verb {
+       case 'b':
+               p.fmt.integer(int64(v), 2, unsigned, ldigits)
+       case 'c':
+               p.fmtC(int64(v))
+       case 'd':
+               p.fmt.integer(int64(v), 10, unsigned, ldigits)
+       case 'v':
+               if goSyntax {
+                       p.fmt0x64(v)
+               } else {
+                       p.fmt.integer(int64(v), 10, unsigned, ldigits)
+               }
+       case 'o':
+               p.fmt.integer(int64(v), 8, unsigned, ldigits)
+       case 'x':
+               p.fmt.integer(int64(v), 16, unsigned, ldigits)
+       case 'X':
+               p.fmt.integer(int64(v), 16, unsigned, udigits)
+       default:
+               p.badVerb(verb, value)
+       }
+}
+
+func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
+       switch verb {
+       case 'b':
+               p.fmt.fmt_fb32(v)
+       case 'e':
+               p.fmt.fmt_e32(v)
+       case 'E':
+               p.fmt.fmt_E32(v)
+       case 'f':
+               p.fmt.fmt_f32(v)
+       case 'g', 'v':
+               p.fmt.fmt_g32(v)
+       case 'G':
+               p.fmt.fmt_G32(v)
+       default:
+               p.badVerb(verb, value)
+       }
+}
+
+func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
+       switch verb {
+       case 'b':
+               p.fmt.fmt_fb64(v)
+       case 'e':
+               p.fmt.fmt_e64(v)
+       case 'E':
+               p.fmt.fmt_E64(v)
+       case 'f':
+               p.fmt.fmt_f64(v)
+       case 'g', 'v':
+               p.fmt.fmt_g64(v)
+       case 'G':
+               p.fmt.fmt_G64(v)
+       default:
+               p.badVerb(verb, value)
+       }
+}
+
+func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
+       switch verb {
+       case 'e', 'E', 'f', 'F', 'g', 'G':
+               p.fmt.fmt_c64(v, verb)
+       case 'v':
+               p.fmt.fmt_c64(v, 'g')
+       default:
+               p.badVerb(verb, value)
+       }
+}
+
+func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
+       switch verb {
+       case 'e', 'E', 'f', 'F', 'g', 'G':
+               p.fmt.fmt_c128(v, verb)
+       case 'v':
+               p.fmt.fmt_c128(v, 'g')
+       default:
+               p.badVerb(verb, value)
+       }
+}
+
+func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
+       switch verb {
+       case 'v':
+               if goSyntax {
+                       p.fmt.fmt_q(v)
+               } else {
+                       p.fmt.fmt_s(v)
+               }
+       case 's':
+               p.fmt.fmt_s(v)
+       case 'x':
+               p.fmt.fmt_sx(v)
+       case 'X':
+               p.fmt.fmt_sX(v)
+       case 'q':
+               p.fmt.fmt_q(v)
+       default:
+               p.badVerb(verb, value)
+       }
+}
+
+func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
+       if verb == 'v' || verb == 'd' {
+               if goSyntax {
+                       p.buf.Write(bytesBytes)
+               } else {
+                       p.buf.WriteByte('[')
+               }
+               for i, c := range v {
+                       if i > 0 {
+                               if goSyntax {
+                                       p.buf.Write(commaSpaceBytes)
+                               } else {
+                                       p.buf.WriteByte(' ')
+                               }
+                       }
+                       p.printField(c, 'v', p.fmt.plus, goSyntax, depth+1)
+               }
+               if goSyntax {
+                       p.buf.WriteByte('}')
+               } else {
+                       p.buf.WriteByte(']')
+               }
+               return
+       }
+       s := string(v)
+       switch verb {
+       case 's':
+               p.fmt.fmt_s(s)
+       case 'x':
+               p.fmt.fmt_sx(s)
+       case 'X':
+               p.fmt.fmt_sX(s)
+       case 'q':
+               p.fmt.fmt_q(s)
+       default:
+               p.badVerb(verb, value)
+       }
+}
+
+func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
+       v, ok := value.(uintptrGetter)
+       if !ok { // reflect.PtrValue is a uintptrGetter, so failure means it's not a pointer at all.
+               p.badVerb(verb, field)
+               return
+       }
+       u := v.Get()
+       if goSyntax {
+               p.add('(')
+               p.buf.WriteString(reflect.Typeof(field).String())
+               p.add(')')
+               p.add('(')
+               if u == 0 {
+                       p.buf.Write(nilBytes)
+               } else {
+                       p.fmt0x64(uint64(v.Get()))
+               }
+               p.add(')')
+       } else {
+               p.fmt0x64(uint64(u))
+       }
+}
+
+var (
+       intBits     = reflect.Typeof(0).Bits()
+       floatBits   = reflect.Typeof(0.0).Bits()
+       complexBits = reflect.Typeof(1i).Bits()
+       uintptrBits = reflect.Typeof(uintptr(0)).Bits()
+)
+
+func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+       if field == nil {
+               if verb == 'T' || verb == 'v' {
+                       p.buf.Write(nilAngleBytes)
+               } else {
+                       p.badVerb(verb, field)
+               }
+               return false
+       }
+
+       // Special processing considerations.
+       // %T (the value's type) and %p (its address) are special; we always do them first.
+       switch verb {
+       case 'T':
+               p.printField(reflect.Typeof(field).String(), 's', false, false, 0)
+               return false
+       case 'p':
+               p.fmtPointer(field, reflect.NewValue(field), verb, goSyntax)
+               return false
+       }
+       // Is it a Formatter?
+       if formatter, ok := field.(Formatter); ok {
+               formatter.Format(p, verb)
+               return false // this value is not a string
+
+       }
+       // Must not touch flags before Formatter looks at them.
+       if plus {
+               p.fmt.plus = false
+       }
+       // If we're doing Go syntax and the field knows how to supply it, take care of it now.
+       if goSyntax {
+               p.fmt.sharp = false
+               if stringer, ok := field.(GoStringer); ok {
+                       // Print the result of GoString unadorned.
+                       p.fmtString(stringer.GoString(), 's', false, field)
+                       return false // this value is not a string
+               }
+       } else {
+               // Is it a Stringer?
+               if stringer, ok := field.(Stringer); ok {
+                       p.printField(stringer.String(), verb, plus, false, depth)
+                       return false // this value is not a string
+               }
+       }
+
+       // Some types can be done without reflection.
+       switch f := field.(type) {
+       case bool:
+               p.fmtBool(f, verb, field)
+               return false
+       case float:
+               if floatBits == 32 {
+                       p.fmtFloat32(float32(f), verb, field)
+               } else {
+                       p.fmtFloat64(float64(f), verb, field)
+               }
+               return false
+       case float32:
+               p.fmtFloat32(f, verb, field)
+               return false
+       case float64:
+               p.fmtFloat64(f, verb, field)
+               return false
+       case complex:
+               if complexBits == 64 {
+                       p.fmtComplex64(complex64(f), verb, field)
+               } else {
+                       p.fmtComplex128(complex128(f), verb, field)
+               }
+               return false
+       case complex64:
+               p.fmtComplex64(complex64(f), verb, field)
+               return false
+       case complex128:
+               p.fmtComplex128(f, verb, field)
+               return false
+       case int:
+               p.fmtInt64(int64(f), verb, field)
+               return false
+       case int8:
+               p.fmtInt64(int64(f), verb, field)
+               return false
+       case int16:
+               p.fmtInt64(int64(f), verb, field)
+               return false
+       case int32:
+               p.fmtInt64(int64(f), verb, field)
+               return false
+       case int64:
+               p.fmtInt64(f, verb, field)
+               return false
+       case uint:
+               p.fmtUint64(uint64(f), verb, goSyntax, field)
+               return false
+       case uint8:
+               p.fmtUint64(uint64(f), verb, goSyntax, field)
+               return false
+       case uint16:
+               p.fmtUint64(uint64(f), verb, goSyntax, field)
+               return false
+       case uint32:
+               p.fmtUint64(uint64(f), verb, goSyntax, field)
+               return false
+       case uint64:
+               p.fmtUint64(f, verb, goSyntax, field)
+               return false
+       case uintptr:
+               p.fmtUint64(uint64(f), verb, goSyntax, field)
+               return false
+       case string:
+               p.fmtString(f, verb, goSyntax, field)
+               return verb == 's' || verb == 'v'
+       case []byte:
+               p.fmtBytes(f, verb, goSyntax, depth, field)
+               return verb == 's'
+       }
+
+       // Need to use reflection
+       value := reflect.NewValue(field)
+
+BigSwitch:
+       switch f := value.(type) {
+       case *reflect.BoolValue:
+               p.fmtBool(f.Get(), verb, field)
+       case *reflect.IntValue:
+               p.fmtInt64(f.Get(), verb, field)
+       case *reflect.UintValue:
+               p.fmtUint64(uint64(f.Get()), verb, goSyntax, field)
+       case *reflect.FloatValue:
+               if f.Type().Size() == 4 {
+                       p.fmtFloat32(float32(f.Get()), verb, field)
+               } else {
+                       p.fmtFloat64(float64(f.Get()), verb, field)
+               }
+       case *reflect.ComplexValue:
+               if f.Type().Size() == 8 {
+                       p.fmtComplex64(complex64(f.Get()), verb, field)
+               } else {
+                       p.fmtComplex128(complex128(f.Get()), verb, field)
+               }
+       case *reflect.StringValue:
+               p.fmtString(f.Get(), verb, goSyntax, field)
+       case *reflect.MapValue:
+               if goSyntax {
+                       p.buf.WriteString(f.Type().String())
+                       p.buf.WriteByte('{')
+               } else {
+                       p.buf.Write(mapBytes)
+               }
+               keys := f.Keys()
+               for i, key := range keys {
+                       if i > 0 {
+                               if goSyntax {
+                                       p.buf.Write(commaSpaceBytes)
+                               } else {
+                                       p.buf.WriteByte(' ')
+                               }
+                       }
+                       p.printField(key.Interface(), verb, plus, goSyntax, depth+1)
+                       p.buf.WriteByte(':')
+                       p.printField(f.Elem(key).Interface(), verb, plus, goSyntax, depth+1)
+               }
+               if goSyntax {
+                       p.buf.WriteByte('}')
+               } else {
+                       p.buf.WriteByte(']')
+               }
+       case *reflect.StructValue:
+               if goSyntax {
+                       p.buf.WriteString(reflect.Typeof(field).String())
+               }
+               p.add('{')
+               v := f
+               t := v.Type().(*reflect.StructType)
+               for i := 0; i < v.NumField(); i++ {
+                       if i > 0 {
+                               if goSyntax {
+                                       p.buf.Write(commaSpaceBytes)
+                               } else {
+                                       p.buf.WriteByte(' ')
+                               }
+                       }
+                       if plus || goSyntax {
+                               if f := t.Field(i); f.Name != "" {
+                                       p.buf.WriteString(f.Name)
+                                       p.buf.WriteByte(':')
+                               }
+                       }
+                       p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1)
+               }
+               p.buf.WriteByte('}')
+       case *reflect.InterfaceValue:
+               value := f.Elem()
+               if value == nil {
+                       if goSyntax {
+                               p.buf.WriteString(reflect.Typeof(field).String())
+                               p.buf.Write(nilParenBytes)
+                       } else {
+                               p.buf.Write(nilAngleBytes)
+                       }
+               } else {
+                       return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
+               }
+       case reflect.ArrayOrSliceValue:
+               // Byte slices are special.
+               if f.Type().(reflect.ArrayOrSliceType).Elem().Kind() == reflect.Uint8 {
+                       // We know it's a slice of bytes, but we also know it does not have static type
+                       // []byte, or it would have been caught above.  Therefore we cannot convert
+                       // it directly in the (slightly) obvious way: f.Interface().([]byte); it doesn't have
+                       // that type, and we can't write an expression of the right type and do a
+                       // conversion because we don't have a static way to write the right type.
+                       // So we build a slice by hand.  This is a rare case but it would be nice
+                       // if reflection could help a little more.
+                       bytes := make([]byte, f.Len())
+                       for i := range bytes {
+                               bytes[i] = byte(f.Elem(i).(*reflect.UintValue).Get())
+                       }
+                       p.fmtBytes(bytes, verb, goSyntax, depth, field)
+                       return verb == 's'
+               }
+               if goSyntax {
+                       p.buf.WriteString(reflect.Typeof(field).String())
+                       p.buf.WriteByte('{')
+               } else {
+                       p.buf.WriteByte('[')
+               }
+               for i := 0; i < f.Len(); i++ {
+                       if i > 0 {
+                               if goSyntax {
+                                       p.buf.Write(commaSpaceBytes)
+                               } else {
+                                       p.buf.WriteByte(' ')
+                               }
+                       }
+                       p.printField(f.Elem(i).Interface(), verb, plus, goSyntax, depth+1)
+               }
+               if goSyntax {
+                       p.buf.WriteByte('}')
+               } else {
+                       p.buf.WriteByte(']')
+               }
+       case *reflect.PtrValue:
+               v := f.Get()
+               // pointer to array or slice or struct?  ok at top level
+               // but not embedded (avoid loops)
+               if v != 0 && depth == 0 {
+                       switch a := f.Elem().(type) {
+                       case reflect.ArrayOrSliceValue:
+                               p.buf.WriteByte('&')
+                               p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+                               break BigSwitch
+                       case *reflect.StructValue:
+                               p.buf.WriteByte('&')
+                               p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+                               break BigSwitch
+                       }
+               }
+               if goSyntax {
+                       p.buf.WriteByte('(')
+                       p.buf.WriteString(reflect.Typeof(field).String())
+                       p.buf.WriteByte(')')
+                       p.buf.WriteByte('(')
+                       if v == 0 {
+                               p.buf.Write(nilBytes)
+                       } else {
+                               p.fmt0x64(uint64(v))
+                       }
+                       p.buf.WriteByte(')')
+                       break
+               }
+               if v == 0 {
+                       p.buf.Write(nilAngleBytes)
+                       break
+               }
+               p.fmt0x64(uint64(v))
+       case uintptrGetter:
+               p.fmtPointer(field, value, verb, goSyntax)
+       default:
+               p.unknownType(f)
+       }
+       return false
+}
+
+// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
+func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
+       newi, newfieldnum = end, fieldnum
+       if i < end && fieldnum < len(a) {
+               num, isInt = a[fieldnum].(int)
+               newi, newfieldnum = i+1, fieldnum+1
+       }
+       return
+}
+
+func (p *pp) doPrintf(format string, a []interface{}) {
+       end := len(format) - 1
+       fieldnum := 0 // we process one field per non-trivial format
+       for i := 0; i <= end; {
+               c, w := utf8.DecodeRuneInString(format[i:])
+               if c != '%' || i == end {
+                       if w == 1 {
+                               p.buf.WriteByte(byte(c))
+                       } else {
+                               p.buf.WriteString(format[i : i+w])
+                       }
+                       i += w
+                       continue
+               }
+               i++
+               // flags and widths
+               p.fmt.clearflags()
+       F:
+               for ; i < end; i++ {
+                       switch format[i] {
+                       case '#':
+                               p.fmt.sharp = true
+                       case '0':
+                               p.fmt.zero = true
+                       case '+':
+                               p.fmt.plus = true
+                       case '-':
+                               p.fmt.minus = true
+                       case ' ':
+                               p.fmt.space = true
+                       default:
+                               break F
+                       }
+               }
+               // do we have width?
+               if format[i] == '*' {
+                       p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
+                       if !p.fmt.widPresent {
+                               p.buf.Write(widthBytes)
+                       }
+               } else {
+                       p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
+               }
+               // do we have precision?
+               if i < end && format[i] == '.' {
+                       if format[i+1] == '*' {
+                               p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
+                               if !p.fmt.precPresent {
+                                       p.buf.Write(precBytes)
+                               }
+                       } else {
+                               p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+                       }
+               }
+               c, w = utf8.DecodeRuneInString(format[i:])
+               i += w
+               // percent is special - absorbs no operand
+               if c == '%' {
+                       p.buf.WriteByte('%') // We ignore width and prec.
+                       continue
+               }
+               if fieldnum >= len(a) { // out of operands
+                       p.buf.WriteByte('%')
+                       p.add(c)
+                       p.buf.Write(missingBytes)
+                       continue
+               }
+               field := a[fieldnum]
+               fieldnum++
+
+               goSyntax := c == 'v' && p.fmt.sharp
+               plus := c == 'v' && p.fmt.plus
+               p.printField(field, c, plus, goSyntax, 0)
+       }
+
+       if fieldnum < len(a) {
+               p.buf.Write(extraBytes)
+               for ; fieldnum < len(a); fieldnum++ {
+                       field := a[fieldnum]
+                       if field != nil {
+                               p.buf.WriteString(reflect.Typeof(field).String())
+                               p.buf.WriteByte('=')
+                       }
+                       p.printField(field, 'v', false, false, 0)
+                       if fieldnum+1 < len(a) {
+                               p.buf.Write(commaSpaceBytes)
+                       }
+               }
+               p.buf.WriteByte(')')
+       }
+}
+
+func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
+       prevString := false
+       for fieldnum := 0; fieldnum < len(a); fieldnum++ {
+               p.fmt.clearflags()
+               // always add spaces if we're doing println
+               field := a[fieldnum]
+               if fieldnum > 0 {
+                       isString := field != nil && reflect.Typeof(field).Kind() == reflect.String
+                       if addspace || !isString && !prevString {
+                               p.buf.WriteByte(' ')
+                       }
+               }
+               prevString = p.printField(field, 'v', false, false, 0)
+       }
+       if addnewline {
+               p.buf.WriteByte('\n')
+       }
+}
diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go
new file mode 100644 (file)
index 0000000..41a12d9
--- /dev/null
@@ -0,0 +1,965 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "reflect"
+       "strconv"
+       "strings"
+       "unicode"
+       "utf8"
+)
+
+// readRuner is the interface to something that can read runes.  If
+// the object provided to Scan does not satisfy this interface, the
+// object will be wrapped by a readRune object.
+type readRuner interface {
+       ReadRune() (rune int, size int, err os.Error)
+}
+
+// unreadRuner is the interface to something that can unread runes.
+// If the object provided to Scan does not satisfy this interface,
+// a local buffer will be used to back up the input, but its contents
+// will be lost when Scan returns.
+type unreadRuner interface {
+       UnreadRune() os.Error
+}
+
+// ScanState represents the scanner state passed to custom scanners.
+// Scanners may do rune-at-a-time scanning or ask the ScanState
+// to discover the next space-delimited token.
+type ScanState interface {
+       // GetRune reads the next rune (Unicode code point) from the input.
+       GetRune() (rune int, err os.Error)
+       // UngetRune causes the next call to GetRune to return the rune.
+       UngetRune()
+       // Width returns the value of the width option and whether it has been set.
+       // The unit is Unicode code points.
+       Width() (wid int, ok bool)
+       // Token returns the next space-delimited token from the input. If
+       // a width has been specified, the returned token will be no longer
+       // than the width.
+       Token() (token string, err os.Error)
+}
+
+// Scanner is implemented by any value that has a Scan method, which scans
+// the input for the representation of a value and stores the result in the
+// receiver, which must be a pointer to be useful.  The Scan method is called
+// for any argument to Scan or Scanln that implements it.
+type Scanner interface {
+       Scan(state ScanState, verb int) os.Error
+}
+
+// Scan scans text read from standard input, storing successive
+// space-separated values into successive arguments.  Newlines count
+// as space.  It returns the number of items successfully scanned.
+// If that is less than the number of arguments, err will report why.
+func Scan(a ...interface{}) (n int, err os.Error) {
+       return Fscan(os.Stdin, a...)
+}
+
+// Scanln is similar to Scan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Scanln(a ...interface{}) (n int, err os.Error) {
+       return Fscanln(os.Stdin, a...)
+}
+
+// Scanf scans text read from standard input, storing successive
+// space-separated values into successive arguments as determined by
+// the format.  It returns the number of items successfully scanned.
+func Scanf(format string, a ...interface{}) (n int, err os.Error) {
+       return Fscanf(os.Stdin, format, a...)
+}
+
+// Sscan scans the argument string, storing successive space-separated
+// values into successive arguments.  Newlines count as space.  It
+// returns the number of items successfully scanned.  If that is less
+// than the number of arguments, err will report why.
+func Sscan(str string, a ...interface{}) (n int, err os.Error) {
+       return Fscan(strings.NewReader(str), a...)
+}
+
+// Sscanln is similar to Sscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
+       return Fscanln(strings.NewReader(str), a...)
+}
+
+// Sscanf scans the argument string, storing successive space-separated
+// values into successive arguments as determined by the format.  It
+// returns the number of items successfully parsed.
+func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
+       return Fscanf(strings.NewReader(str), format, a...)
+}
+
+// Fscan scans text read from r, storing successive space-separated
+// values into successive arguments.  Newlines count as space.  It
+// returns the number of items successfully scanned.  If that is less
+// than the number of arguments, err will report why.
+func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
+       s := newScanState(r, true)
+       n, err = s.doScan(a)
+       s.free()
+       return
+}
+
+// Fscanln is similar to Fscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
+       s := newScanState(r, false)
+       n, err = s.doScan(a)
+       s.free()
+       return
+}
+
+// Fscanf scans text read from r, storing successive space-separated
+// values into successive arguments as determined by the format.  It
+// returns the number of items successfully parsed.
+func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
+       s := newScanState(r, false)
+       n, err = s.doScanf(format, a)
+       s.free()
+       return
+}
+
+// scanError represents an error generated by the scanning software.
+// It's used as a unique signature to identify such errors when recovering.
+type scanError struct {
+       err os.Error
+}
+
+const EOF = -1
+
+// ss is the internal implementation of ScanState.
+type ss struct {
+       rr         readRuner    // where to read input
+       buf        bytes.Buffer // token accumulator
+       nlIsSpace  bool         // whether newline counts as white space
+       peekRune   int          // one-rune lookahead
+       prevRune   int          // last rune returned by GetRune
+       atEOF      bool         // already read EOF
+       maxWid     int          // max width of field, in runes
+       widPresent bool         // width was specified
+       wid        int          // width consumed so far; used in accept()
+}
+
+func (s *ss) GetRune() (rune int, err os.Error) {
+       if s.peekRune >= 0 {
+               rune = s.peekRune
+               s.prevRune = rune
+               s.peekRune = -1
+               return
+       }
+       rune, _, err = s.rr.ReadRune()
+       if err == nil {
+               s.prevRune = rune
+       }
+       return
+}
+
+func (s *ss) Width() (wid int, ok bool) {
+       return s.maxWid, s.widPresent
+}
+
+// The public method returns an error; this private one panics.
+// If getRune reaches EOF, the return value is EOF (-1).
+func (s *ss) getRune() (rune int) {
+       if s.atEOF {
+               return EOF
+       }
+       if s.peekRune >= 0 {
+               rune = s.peekRune
+               s.prevRune = rune
+               s.peekRune = -1
+               return
+       }
+       rune, _, err := s.rr.ReadRune()
+       if err == nil {
+               s.prevRune = rune
+       } else if err != nil {
+               if err == os.EOF {
+                       s.atEOF = true
+                       return EOF
+               }
+               s.error(err)
+       }
+       return
+}
+
+// mustGetRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
+// It is called in cases such as string scanning where an EOF is a
+// syntax error.
+func (s *ss) mustGetRune() (rune int) {
+       if s.atEOF {
+               s.error(io.ErrUnexpectedEOF)
+       }
+       if s.peekRune >= 0 {
+               rune = s.peekRune
+               s.peekRune = -1
+               return
+       }
+       rune, _, err := s.rr.ReadRune()
+       if err != nil {
+               if err == os.EOF {
+                       err = io.ErrUnexpectedEOF
+               }
+               s.error(err)
+       }
+       return
+}
+
+
+func (s *ss) UngetRune() {
+       if u, ok := s.rr.(unreadRuner); ok {
+               u.UnreadRune()
+       } else {
+               s.peekRune = s.prevRune
+       }
+}
+
+func (s *ss) error(err os.Error) {
+       panic(scanError{err})
+}
+
+func (s *ss) errorString(err string) {
+       panic(scanError{os.ErrorString(err)})
+}
+
+func (s *ss) Token() (tok string, err os.Error) {
+       defer func() {
+               if e := recover(); e != nil {
+                       if se, ok := e.(scanError); ok {
+                               err = se.err
+                       } else {
+                               panic(e)
+                       }
+               }
+       }()
+       tok = s.token()
+       return
+}
+
+// readRune is a structure to enable reading UTF-8 encoded code points
+// from an io.Reader.  It is used if the Reader given to the scanner does
+// not already implement ReadRuner.
+type readRune struct {
+       reader  io.Reader
+       buf     [utf8.UTFMax]byte // used only inside ReadRune
+       pending int               // number of bytes in pendBuf; only >0 for bad UTF-8
+       pendBuf [utf8.UTFMax]byte // bytes left over
+}
+
+// readByte returns the next byte from the input, which may be
+// left over from a previous read if the UTF-8 was ill-formed.
+func (r *readRune) readByte() (b byte, err os.Error) {
+       if r.pending > 0 {
+               b = r.pendBuf[0]
+               copy(r.pendBuf[0:], r.pendBuf[1:])
+               r.pending--
+               return
+       }
+       _, err = r.reader.Read(r.pendBuf[0:1])
+       return r.pendBuf[0], err
+}
+
+// unread saves the bytes for the next read.
+func (r *readRune) unread(buf []byte) {
+       copy(r.pendBuf[r.pending:], buf)
+       r.pending += len(buf)
+}
+
+// ReadRune returns the next UTF-8 encoded code point from the
+// io.Reader inside r.
+func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
+       r.buf[0], err = r.readByte()
+       if err != nil {
+               return 0, 0, err
+       }
+       if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
+               rune = int(r.buf[0])
+               return
+       }
+       var n int
+       for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
+               r.buf[n], err = r.readByte()
+               if err != nil {
+                       if err == os.EOF {
+                               err = nil
+                               break
+                       }
+                       return
+               }
+       }
+       rune, size = utf8.DecodeRune(r.buf[0:n])
+       if size < n { // an error
+               r.unread(r.buf[size:n])
+       }
+       return
+}
+
+
+// A leaky bucket of reusable ss structures.
+var ssFree = make(chan *ss, 100)
+
+// Allocate a new ss struct.  Probably can grab the previous one from ssFree.
+func newScanState(r io.Reader, nlIsSpace bool) *ss {
+       s, ok := <-ssFree
+       if !ok {
+               s = new(ss)
+       }
+       if rr, ok := r.(readRuner); ok {
+               s.rr = rr
+       } else {
+               s.rr = &readRune{reader: r}
+       }
+       s.nlIsSpace = nlIsSpace
+       s.peekRune = -1
+       s.atEOF = false
+       s.maxWid = 0
+       s.widPresent = false
+       return s
+}
+
+// Save used ss structs in ssFree; avoid an allocation per invocation.
+func (s *ss) free() {
+       // Don't hold on to ss structs with large buffers.
+       if cap(s.buf.Bytes()) > 1024 {
+               return
+       }
+       s.buf.Reset()
+       s.rr = nil
+       _ = ssFree <- s
+}
+
+// skipSpace skips spaces and maybe newlines.
+func (s *ss) skipSpace(stopAtNewline bool) {
+       for {
+               rune := s.getRune()
+               if rune == EOF {
+                       return
+               }
+               if rune == '\n' {
+                       if stopAtNewline {
+                               break
+                       }
+                       if s.nlIsSpace {
+                               continue
+                       }
+                       s.errorString("unexpected newline")
+                       return
+               }
+               if !unicode.IsSpace(rune) {
+                       s.UngetRune()
+                       break
+               }
+       }
+}
+
+// token returns the next space-delimited string from the input.  It
+// skips white space.  For Scanln, it stops at newlines.  For Scan,
+// newlines are treated as spaces.
+func (s *ss) token() string {
+       s.skipSpace(false)
+       // read until white space or newline
+       for nrunes := 0; !s.widPresent || nrunes < s.maxWid; nrunes++ {
+               rune := s.getRune()
+               if rune == EOF {
+                       break
+               }
+               if unicode.IsSpace(rune) {
+                       s.UngetRune()
+                       break
+               }
+               s.buf.WriteRune(rune)
+       }
+       return s.buf.String()
+}
+
+// typeError indicates that the type of the operand did not match the format
+func (s *ss) typeError(field interface{}, expected string) {
+       s.errorString("expected field of type pointer to " + expected + "; found " + reflect.Typeof(field).String())
+}
+
+var complexError = os.ErrorString("syntax error scanning complex number")
+var boolError = os.ErrorString("syntax error scanning boolean")
+
+// accepts checks the next rune in the input.  If it's a byte (sic) in the string, it puts it in the
+// buffer and returns true. Otherwise it return false.
+func (s *ss) accept(ok string) bool {
+       if s.wid >= s.maxWid {
+               return false
+       }
+       rune := s.getRune()
+       if rune == EOF {
+               return false
+       }
+       for i := 0; i < len(ok); i++ {
+               if int(ok[i]) == rune {
+                       s.buf.WriteRune(rune)
+                       s.wid++
+                       return true
+               }
+       }
+       if rune != EOF {
+               s.UngetRune()
+       }
+       return false
+}
+
+// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
+func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
+       for _, v := range okVerbs {
+               if v == verb {
+                       return true
+               }
+       }
+       s.errorString("bad verb %" + string(verb) + " for " + typ)
+       return false
+}
+
+// scanBool returns the value of the boolean represented by the next token.
+func (s *ss) scanBool(verb int) bool {
+       if !s.okVerb(verb, "tv", "boolean") {
+               return false
+       }
+       // Syntax-checking a boolean is annoying.  We're not fastidious about case.
+       switch s.mustGetRune() {
+       case '0':
+               return false
+       case '1':
+               return true
+       case 't', 'T':
+               if s.accept("rR") && (!s.accept("uU") || !s.accept("eE")) {
+                       s.error(boolError)
+               }
+               return true
+       case 'f', 'F':
+               if s.accept("aL") && (!s.accept("lL") || !s.accept("sS") || !s.accept("eE")) {
+                       s.error(boolError)
+               }
+               return false
+       }
+       return false
+}
+
+// Numerical elements
+const (
+       binaryDigits      = "01"
+       octalDigits       = "01234567"
+       decimalDigits     = "0123456789"
+       hexadecimalDigits = "0123456789aAbBcCdDeEfF"
+       sign              = "+-"
+       period            = "."
+       exponent          = "eE"
+)
+
+// getBase returns the numeric base represented by the verb and its digit string.
+func (s *ss) getBase(verb int) (base int, digits string) {
+       s.okVerb(verb, "bdoxXv", "integer") // sets s.err
+       base = 10
+       digits = decimalDigits
+       switch verb {
+       case 'b':
+               base = 2
+               digits = binaryDigits
+       case 'o':
+               base = 8
+               digits = octalDigits
+       case 'x', 'X':
+               base = 16
+               digits = hexadecimalDigits
+       }
+       return
+}
+
+// scanNumber returns the numerical string with specified digits starting here.
+func (s *ss) scanNumber(digits string) string {
+       if !s.accept(digits) {
+               s.errorString("expected integer")
+       }
+       for s.accept(digits) {
+       }
+       return s.buf.String()
+}
+
+// scanRune returns the next rune value in the input.
+func (s *ss) scanRune(bitSize int) int64 {
+       rune := int64(s.mustGetRune())
+       n := uint(bitSize)
+       x := (rune << (64 - n)) >> (64 - n)
+       if x != rune {
+               s.errorString("overflow on character value " + string(rune))
+       }
+       return rune
+}
+
+// scanInt returns the value of the integer represented by the next
+// token, checking for overflow.  Any error is stored in s.err.
+func (s *ss) scanInt(verb int, bitSize int) int64 {
+       if verb == 'c' {
+               return s.scanRune(bitSize)
+       }
+       base, digits := s.getBase(verb)
+       s.skipSpace(false)
+       s.accept(sign) // If there's a sign, it will be left in the token buffer.
+       tok := s.scanNumber(digits)
+       i, err := strconv.Btoi64(tok, base)
+       if err != nil {
+               s.error(err)
+       }
+       n := uint(bitSize)
+       x := (i << (64 - n)) >> (64 - n)
+       if x != i {
+               s.errorString("integer overflow on token " + tok)
+       }
+       return i
+}
+
+// scanUint returns the value of the unsigned integer represented
+// by the next token, checking for overflow.  Any error is stored in s.err.
+func (s *ss) scanUint(verb int, bitSize int) uint64 {
+       if verb == 'c' {
+               return uint64(s.scanRune(bitSize))
+       }
+       base, digits := s.getBase(verb)
+       s.skipSpace(false)
+       tok := s.scanNumber(digits)
+       i, err := strconv.Btoui64(tok, base)
+       if err != nil {
+               s.error(err)
+       }
+       n := uint(bitSize)
+       x := (i << (64 - n)) >> (64 - n)
+       if x != i {
+               s.errorString("unsigned integer overflow on token " + tok)
+       }
+       return i
+}
+
+// floatToken returns the floating-point number starting here, no longer than swid
+// if the width is specified. It's not rigorous about syntax because it doesn't check that
+// we have at least some digits, but Atof will do that.
+func (s *ss) floatToken() string {
+       s.buf.Reset()
+       // leading sign?
+       s.accept(sign)
+       // digits?
+       for s.accept(decimalDigits) {
+       }
+       // decimal point?
+       if s.accept(period) {
+               // fraction?
+               for s.accept(decimalDigits) {
+               }
+       }
+       // exponent?
+       if s.accept(exponent) {
+               // leading sign?
+               s.accept(sign)
+               // digits?
+               for s.accept(decimalDigits) {
+               }
+       }
+       return s.buf.String()
+}
+
+// complexTokens returns the real and imaginary parts of the complex number starting here.
+// The number might be parenthesized and has the format (N+Ni) where N is a floating-point
+// number and there are no spaces within.
+func (s *ss) complexTokens() (real, imag string) {
+       // TODO: accept N and Ni independently?
+       parens := s.accept("(")
+       real = s.floatToken()
+       s.buf.Reset()
+       // Must now have a sign.
+       if !s.accept("+-") {
+               s.error(complexError)
+       }
+       // Sign is now in buffer
+       imagSign := s.buf.String()
+       imag = s.floatToken()
+       if !s.accept("i") {
+               s.error(complexError)
+       }
+       if parens && !s.accept(")") {
+               s.error(complexError)
+       }
+       return real, imagSign + imag
+}
+
+// convertFloat converts the string to a float64value.
+func (s *ss) convertFloat(str string, n int) float64 {
+       f, err := strconv.AtofN(str, n)
+       if err != nil {
+               s.error(err)
+       }
+       return f
+}
+
+// convertComplex converts the next token to a complex128 value.
+// The atof argument is a type-specific reader for the underlying type.
+// If we're reading complex64, atof will parse float32s and convert them
+// to float64's to avoid reproducing this code for each complex type.
+func (s *ss) scanComplex(verb int, n int) complex128 {
+       if !s.okVerb(verb, floatVerbs, "complex") {
+               return 0
+       }
+       s.skipSpace(false)
+       sreal, simag := s.complexTokens()
+       real := s.convertFloat(sreal, n/2)
+       imag := s.convertFloat(simag, n/2)
+       return cmplx(real, imag)
+}
+
+// convertString returns the string represented by the next input characters.
+// The format of the input is determined by the verb.
+func (s *ss) convertString(verb int) (str string) {
+       if !s.okVerb(verb, "svqx", "string") {
+               return ""
+       }
+       s.skipSpace(false)
+       switch verb {
+       case 'q':
+               str = s.quotedString()
+       case 'x':
+               str = s.hexString()
+       default:
+               str = s.token() // %s and %v just return the next word
+       }
+       // Empty strings other than with %q are not OK.
+       if len(str) == 0 && verb != 'q' && s.maxWid > 0 {
+               s.errorString("Scan: no data for string")
+       }
+       return
+}
+
+// quotedString returns the double- or back-quoted string represented by the next input characters.
+func (s *ss) quotedString() string {
+       quote := s.mustGetRune()
+       switch quote {
+       case '`':
+               // Back-quoted: Anything goes until EOF or back quote.
+               for {
+                       rune := s.mustGetRune()
+                       if rune == quote {
+                               break
+                       }
+                       s.buf.WriteRune(rune)
+               }
+               return s.buf.String()
+       case '"':
+               // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
+               s.buf.WriteRune(quote)
+               for {
+                       rune := s.mustGetRune()
+                       s.buf.WriteRune(rune)
+                       if rune == '\\' {
+                               // In a legal backslash escape, no matter how long, only the character
+                               // immediately after the escape can itself be a backslash or quote.
+                               // Thus we only need to protect the first character after the backslash.
+                               rune := s.mustGetRune()
+                               s.buf.WriteRune(rune)
+                       } else if rune == '"' {
+                               break
+                       }
+               }
+               result, err := strconv.Unquote(s.buf.String())
+               if err != nil {
+                       s.error(err)
+               }
+               return result
+       default:
+               s.errorString("expected quoted string")
+       }
+       return ""
+}
+
+// hexDigit returns the value of the hexadecimal digit
+func (s *ss) hexDigit(digit int) int {
+       switch digit {
+       case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+               return digit - '0'
+       case 'a', 'b', 'c', 'd', 'e', 'f':
+               return 10 + digit - 'a'
+       case 'A', 'B', 'C', 'D', 'E', 'F':
+               return 10 + digit - 'A'
+       }
+       s.errorString("Scan: illegal hex digit")
+       return 0
+}
+
+// hexByte returns the next hex-encoded (two-character) byte from the input.
+// There must be either two hexadecimal digits or a space character in the input.
+func (s *ss) hexByte() (b byte, ok bool) {
+       rune1 := s.getRune()
+       if rune1 == EOF {
+               return
+       }
+       if unicode.IsSpace(rune1) {
+               s.UngetRune()
+               return
+       }
+       rune2 := s.mustGetRune()
+       return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
+}
+
+// hexString returns the space-delimited hexpair-encoded string.
+func (s *ss) hexString() string {
+       for {
+               b, ok := s.hexByte()
+               if !ok {
+                       break
+               }
+               s.buf.WriteByte(b)
+       }
+       if s.buf.Len() == 0 {
+               s.errorString("Scan: no hex data for %x string")
+               return ""
+       }
+       return s.buf.String()
+}
+
+const floatVerbs = "eEfFgGv"
+
+// scanOne scans a single value, deriving the scanner from the type of the argument.
+func (s *ss) scanOne(verb int, field interface{}) {
+       s.buf.Reset()
+       var err os.Error
+       // If the parameter has its own Scan method, use that.
+       if v, ok := field.(Scanner); ok {
+               err = v.Scan(s, verb)
+               if err != nil {
+                       s.error(err)
+               }
+               return
+       }
+       if !s.widPresent {
+               s.maxWid = 1 << 30 // Huge
+       }
+       s.wid = 0
+       switch v := field.(type) {
+       case *bool:
+               *v = s.scanBool(verb)
+       case *complex:
+               *v = complex(s.scanComplex(verb, int(complexBits)))
+       case *complex64:
+               *v = complex64(s.scanComplex(verb, 64))
+       case *complex128:
+               *v = s.scanComplex(verb, 128)
+       case *int:
+               *v = int(s.scanInt(verb, intBits))
+       case *int8:
+               *v = int8(s.scanInt(verb, 8))
+       case *int16:
+               *v = int16(s.scanInt(verb, 16))
+       case *int32:
+               *v = int32(s.scanInt(verb, 32))
+       case *int64:
+               *v = s.scanInt(verb, 64)
+       case *uint:
+               *v = uint(s.scanUint(verb, intBits))
+       case *uint8:
+               *v = uint8(s.scanUint(verb, 8))
+       case *uint16:
+               *v = uint16(s.scanUint(verb, 16))
+       case *uint32:
+               *v = uint32(s.scanUint(verb, 32))
+       case *uint64:
+               *v = s.scanUint(verb, 64)
+       case *uintptr:
+               *v = uintptr(s.scanUint(verb, uintptrBits))
+       // Floats are tricky because you want to scan in the precision of the result, not
+       // scan in high precision and convert, in order to preserve the correct error condition.
+       case *float:
+               if s.okVerb(verb, floatVerbs, "float") {
+                       s.skipSpace(false)
+                       *v = float(s.convertFloat(s.floatToken(), int(floatBits)))
+               }
+       case *float32:
+               if s.okVerb(verb, floatVerbs, "float32") {
+                       s.skipSpace(false)
+                       *v = float32(s.convertFloat(s.floatToken(), 32))
+               }
+       case *float64:
+               if s.okVerb(verb, floatVerbs, "float64") {
+                       s.skipSpace(false)
+                       *v = s.convertFloat(s.floatToken(), 64)
+               }
+       case *string:
+               *v = s.convertString(verb)
+       case *[]byte:
+               // We scan to string and convert so we get a copy of the data.
+               // If we scanned to bytes, the slice would point at the buffer.
+               *v = []byte(s.convertString(verb))
+       default:
+               val := reflect.NewValue(v)
+               ptr, ok := val.(*reflect.PtrValue)
+               if !ok {
+                       s.errorString("Scan: type not a pointer: " + val.Type().String())
+                       return
+               }
+               switch v := ptr.Elem().(type) {
+               case *reflect.BoolValue:
+                       v.Set(s.scanBool(verb))
+               case *reflect.IntValue:
+                       v.Set(s.scanInt(verb, v.Type().Bits()))
+               case *reflect.UintValue:
+                       v.Set(s.scanUint(verb, v.Type().Bits()))
+               case *reflect.StringValue:
+                       v.Set(s.convertString(verb))
+               case *reflect.SliceValue:
+                       // For now, can only handle (renamed) []byte.
+                       typ := v.Type().(*reflect.SliceType)
+                       if typ.Elem().Kind() != reflect.Uint8 {
+                               goto CantHandle
+                       }
+                       str := s.convertString(verb)
+                       v.Set(reflect.MakeSlice(typ, len(str), len(str)))
+                       for i := 0; i < len(str); i++ {
+                               v.Elem(i).(*reflect.UintValue).Set(uint64(str[i]))
+                       }
+               case *reflect.FloatValue:
+                       s.skipSpace(false)
+                       v.Set(s.convertFloat(s.floatToken(), v.Type().Bits()))
+               case *reflect.ComplexValue:
+                       v.Set(s.scanComplex(verb, v.Type().Bits()))
+               default:
+               CantHandle:
+                       s.errorString("Scan: can't handle type: " + val.Type().String())
+               }
+       }
+}
+
+// errorHandler turns local panics into error returns.  EOFs are benign.
+func errorHandler(errp *os.Error) {
+       if e := recover(); e != nil {
+               if se, ok := e.(scanError); ok { // catch local error
+                       if se.err != os.EOF {
+                               *errp = se.err
+                       }
+               } else {
+                       panic(e)
+               }
+       }
+}
+
+// doScan does the real work for scanning without a format string.
+// At the moment, it handles only pointers to basic types.
+func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
+       defer errorHandler(&err)
+       for _, field := range a {
+               s.scanOne('v', field)
+               numProcessed++
+       }
+       // Check for newline if required.
+       if !s.nlIsSpace {
+               for {
+                       rune := s.getRune()
+                       if rune == '\n' || rune == EOF {
+                               break
+                       }
+                       if !unicode.IsSpace(rune) {
+                               s.errorString("Scan: expected newline")
+                               break
+                       }
+               }
+       }
+       return
+}
+
+// advance determines whether the next characters in the input match
+// those of the format.  It returns the number of bytes (sic) consumed
+// in the format. Newlines included, all runs of space characters in
+// either input or format behave as a single space. This routine also
+// handles the %% case.  If the return value is zero, either format
+// starts with a % (with no following %) or the input is empty.
+// If it is negative, the input did not match the string.
+func (s *ss) advance(format string) (i int) {
+       for i < len(format) {
+               fmtc, w := utf8.DecodeRuneInString(format[i:])
+               if fmtc == '%' {
+                       // %% acts like a real percent
+                       nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty
+                       if nextc != '%' {
+                               return
+                       }
+                       i += w // skip the first %
+               }
+               sawSpace := false
+               for unicode.IsSpace(fmtc) && i < len(format) {
+                       sawSpace = true
+                       i += w
+                       fmtc, w = utf8.DecodeRuneInString(format[i:])
+               }
+               if sawSpace {
+                       // There was space in the format, so there should be space (EOF)
+                       // in the input.
+                       inputc := s.getRune()
+                       if inputc == EOF {
+                               return
+                       }
+                       if !unicode.IsSpace(inputc) {
+                               // Space in format but not in input: error
+                               s.errorString("expected space in input to match format")
+                       }
+                       s.skipSpace(true)
+                       continue
+               }
+               inputc := s.mustGetRune()
+               if fmtc != inputc {
+                       s.UngetRune()
+                       return -1
+               }
+               i += w
+       }
+       return
+}
+
+// doScanf does the real work when scanning with a format string.
+//  At the moment, it handles only pointers to basic types.
+func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
+       defer errorHandler(&err)
+       end := len(format) - 1
+       // We process one item per non-trivial format
+       for i := 0; i <= end; {
+               w := s.advance(format[i:])
+               if w > 0 {
+                       i += w
+                       continue
+               }
+               // Either we failed to advance, we have a percent character, or we ran out of input.
+               if format[i] != '%' {
+                       // Can't advance format.  Why not?
+                       if w < 0 {
+                               s.errorString("input does not match format")
+                       }
+                       // Otherwise at EOF; "too many operands" error handled below
+                       break
+               }
+               i++ // % is one byte
+
+               // do we have 20 (width)?
+               s.maxWid, s.widPresent, i = parsenum(format, i, end)
+
+               c, w := utf8.DecodeRuneInString(format[i:])
+               i += w
+
+               if numProcessed >= len(a) { // out of operands
+                       s.errorString("too few operands for format %" + format[i-w:])
+                       break
+               }
+               field := a[numProcessed]
+
+               s.scanOne(c, field)
+               numProcessed++
+       }
+       if numProcessed < len(a) {
+               s.errorString("too many operands")
+       }
+       return
+}
diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go
new file mode 100644 (file)
index 0000000..9193932
--- /dev/null
@@ -0,0 +1,605 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt_test
+
+import (
+       "bufio"
+       . "fmt"
+       "io"
+       "os"
+       "reflect"
+       "regexp"
+       "strings"
+       "testing"
+       "utf8"
+)
+
+type ScanTest struct {
+       text string
+       in   interface{}
+       out  interface{}
+}
+
+type ScanfTest struct {
+       format string
+       text   string
+       in     interface{}
+       out    interface{}
+}
+
+type ScanfMultiTest struct {
+       format string
+       text   string
+       in     []interface{}
+       out    []interface{}
+       err    string
+}
+
+var (
+       boolVal              bool
+       intVal               int
+       int8Val              int8
+       int16Val             int16
+       int32Val             int32
+       int64Val             int64
+       uintVal              uint
+       uint8Val             uint8
+       uint16Val            uint16
+       uint32Val            uint32
+       uint64Val            uint64
+       floatVal             float
+       float32Val           float32
+       float64Val           float64
+       stringVal            string
+       stringVal1           string
+       bytesVal             []byte
+       complexVal           complex
+       complex64Val         complex64
+       complex128Val        complex128
+       renamedBoolVal       renamedBool
+       renamedIntVal        renamedInt
+       renamedInt8Val       renamedInt8
+       renamedInt16Val      renamedInt16
+       renamedInt32Val      renamedInt32
+       renamedInt64Val      renamedInt64
+       renamedUintVal       renamedUint
+       renamedUint8Val      renamedUint8
+       renamedUint16Val     renamedUint16
+       renamedUint32Val     renamedUint32
+       renamedUint64Val     renamedUint64
+       renamedUintptrVal    renamedUintptr
+       renamedStringVal     renamedString
+       renamedBytesVal      renamedBytes
+       renamedFloatVal      renamedFloat
+       renamedFloat32Val    renamedFloat32
+       renamedFloat64Val    renamedFloat64
+       renamedComplexVal    renamedComplex
+       renamedComplex64Val  renamedComplex64
+       renamedComplex128Val renamedComplex128
+)
+
+// Xs accepts any non-empty run of the verb character
+type Xs string
+
+func (x *Xs) Scan(state ScanState, verb int) os.Error {
+       var tok string
+       var c int
+       var err os.Error
+       wid, present := state.Width()
+       if !present {
+               tok, err = state.Token()
+       } else {
+               for i := 0; i < wid; i++ {
+                       c, err = state.GetRune()
+                       if err != nil {
+                               break
+                       }
+                       tok += string(c)
+               }
+       }
+       if err != nil {
+               return err
+       }
+       if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(tok) {
+               return os.ErrorString("syntax error for xs")
+       }
+       *x = Xs(tok)
+       return nil
+}
+
+var xVal Xs
+
+// myStringReader implements Read but not ReadRune, allowing us to test our readRune wrapper
+// type that creates something that can read runes given only Read().
+type myStringReader struct {
+       r *strings.Reader
+}
+
+func (s *myStringReader) Read(p []byte) (n int, err os.Error) {
+       return s.r.Read(p)
+}
+
+func newReader(s string) *myStringReader {
+       return &myStringReader{strings.NewReader(s)}
+}
+
+var scanTests = []ScanTest{
+       // Numbers
+       {"T\n", &boolVal, true},  // boolean test vals toggle to be sure they are written
+       {"F\n", &boolVal, false}, // restored to zero value
+       {"21\n", &intVal, 21},
+       {"22\n", &int8Val, int8(22)},
+       {"23\n", &int16Val, int16(23)},
+       {"24\n", &int32Val, int32(24)},
+       {"25\n", &int64Val, int64(25)},
+       {"127\n", &int8Val, int8(127)},
+       {"-21\n", &intVal, -21},
+       {"-22\n", &int8Val, int8(-22)},
+       {"-23\n", &int16Val, int16(-23)},
+       {"-24\n", &int32Val, int32(-24)},
+       {"-25\n", &int64Val, int64(-25)},
+       {"-128\n", &int8Val, int8(-128)},
+       {"+21\n", &intVal, +21},
+       {"+22\n", &int8Val, int8(+22)},
+       {"+23\n", &int16Val, int16(+23)},
+       {"+24\n", &int32Val, int32(+24)},
+       {"+25\n", &int64Val, int64(+25)},
+       {"+127\n", &int8Val, int8(+127)},
+       {"26\n", &uintVal, uint(26)},
+       {"27\n", &uint8Val, uint8(27)},
+       {"28\n", &uint16Val, uint16(28)},
+       {"29\n", &uint32Val, uint32(29)},
+       {"30\n", &uint64Val, uint64(30)},
+       {"255\n", &uint8Val, uint8(255)},
+       {"32767\n", &int16Val, int16(32767)},
+       {"2.3\n", &floatVal, 2.3},
+       {"2.3e1\n", &float32Val, float32(2.3e1)},
+       {"2.3e2\n", &float64Val, float64(2.3e2)},
+       {"2.35\n", &stringVal, "2.35"},
+       {"2345678\n", &bytesVal, []byte("2345678")},
+       {"(3.4e1-2i)\n", &complexVal, 3.4e1 - 2i},
+       {"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
+       {"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
+       {"hello\n", &stringVal, "hello"},
+
+       // Renamed types
+       {"true\n", &renamedBoolVal, renamedBool(true)},
+       {"F\n", &renamedBoolVal, renamedBool(false)},
+       {"101\n", &renamedIntVal, renamedInt(101)},
+       {"102\n", &renamedIntVal, renamedInt(102)},
+       {"103\n", &renamedUintVal, renamedUint(103)},
+       {"104\n", &renamedUintVal, renamedUint(104)},
+       {"105\n", &renamedInt8Val, renamedInt8(105)},
+       {"106\n", &renamedInt16Val, renamedInt16(106)},
+       {"107\n", &renamedInt32Val, renamedInt32(107)},
+       {"108\n", &renamedInt64Val, renamedInt64(108)},
+       {"109\n", &renamedUint8Val, renamedUint8(109)},
+       {"110\n", &renamedUint16Val, renamedUint16(110)},
+       {"111\n", &renamedUint32Val, renamedUint32(111)},
+       {"112\n", &renamedUint64Val, renamedUint64(112)},
+       {"113\n", &renamedUintptrVal, renamedUintptr(113)},
+       {"114\n", &renamedStringVal, renamedString("114")},
+       {"115\n", &renamedBytesVal, renamedBytes([]byte("115"))},
+
+       // Custom scanner.
+       {"  vvv ", &xVal, Xs("vvv")},
+
+       // Fixed bugs
+       {"2147483648\n", &int64Val, int64(2147483648)}, // was: integer overflow
+}
+
+var scanfTests = []ScanfTest{
+       {"%v", "TRUE\n", &boolVal, true},
+       {"%t", "false\n", &boolVal, false},
+       {"%v", "-71\n", &intVal, -71},
+       {"%d", "72\n", &intVal, 72},
+       {"%c", "a\n", &intVal, 'a'},
+       {"%c", "\u5072\n", &intVal, 0x5072},
+       {"%c", "\u1234\n", &intVal, '\u1234'},
+       {"%d", "73\n", &int8Val, int8(73)},
+       {"%d", "+74\n", &int16Val, int16(74)},
+       {"%d", "75\n", &int32Val, int32(75)},
+       {"%d", "76\n", &int64Val, int64(76)},
+       {"%b", "1001001\n", &intVal, 73},
+       {"%o", "075\n", &intVal, 075},
+       {"%x", "a75\n", &intVal, 0xa75},
+       {"%v", "71\n", &uintVal, uint(71)},
+       {"%d", "72\n", &uintVal, uint(72)},
+       {"%d", "73\n", &uint8Val, uint8(73)},
+       {"%d", "74\n", &uint16Val, uint16(74)},
+       {"%d", "75\n", &uint32Val, uint32(75)},
+       {"%d", "76\n", &uint64Val, uint64(76)},
+       {"%b", "1001001\n", &uintVal, uint(73)},
+       {"%o", "075\n", &uintVal, uint(075)},
+       {"%x", "a75\n", &uintVal, uint(0xa75)},
+       {"%x", "A75\n", &uintVal, uint(0xa75)},
+
+       // Strings
+       {"%s", "using-%s\n", &stringVal, "using-%s"},
+       {"%x", "7573696e672d2578\n", &stringVal, "using-%x"},
+       {"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
+       {"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},
+
+       // Byte slices
+       {"%s", "bytes-%s\n", &bytesVal, []byte("bytes-%s")},
+       {"%x", "62797465732d2578\n", &bytesVal, []byte("bytes-%x")},
+       {"%q", `"bytes\rwith\vdo\u0075bl\x65s"` + "\n", &bytesVal, []byte("bytes\rwith\vdoubles")},
+       {"%q", "`bytes with backs`\n", &bytesVal, []byte("bytes with backs")},
+
+       // Renamed types
+       {"%v\n", "true\n", &renamedBoolVal, renamedBool(true)},
+       {"%t\n", "F\n", &renamedBoolVal, renamedBool(false)},
+       {"%v", "101\n", &renamedIntVal, renamedInt(101)},
+       {"%c", "\u0101\n", &renamedIntVal, renamedInt('\u0101')},
+       {"%o", "0146\n", &renamedIntVal, renamedInt(102)},
+       {"%v", "103\n", &renamedUintVal, renamedUint(103)},
+       {"%d", "104\n", &renamedUintVal, renamedUint(104)},
+       {"%d", "105\n", &renamedInt8Val, renamedInt8(105)},
+       {"%d", "106\n", &renamedInt16Val, renamedInt16(106)},
+       {"%d", "107\n", &renamedInt32Val, renamedInt32(107)},
+       {"%d", "108\n", &renamedInt64Val, renamedInt64(108)},
+       {"%x", "6D\n", &renamedUint8Val, renamedUint8(109)},
+       {"%o", "0156\n", &renamedUint16Val, renamedUint16(110)},
+       {"%d", "111\n", &renamedUint32Val, renamedUint32(111)},
+       {"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
+       {"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
+       {"%s", "114\n", &renamedStringVal, renamedString("114")},
+       {"%q", "\"1155\"\n", &renamedBytesVal, renamedBytes([]byte("1155"))},
+       {"%g", "115.1\n", &renamedFloatVal, renamedFloat(115.1)},
+       {"%g", "116e1\n", &renamedFloat32Val, renamedFloat32(116e1)},
+       {"%g", "-11.7e+1", &renamedFloat64Val, renamedFloat64(-11.7e+1)},
+       {"%g", "11+5.1i\n", &renamedComplexVal, renamedComplex(11 + 5.1i)},
+       {"%g", "11+6e1i\n", &renamedComplex64Val, renamedComplex64(11 + 6e1i)},
+       {"%g", "-11.+7e+1i", &renamedComplex128Val, renamedComplex128(-11. + 7e+1i)},
+
+       // Interesting formats
+       {"here is\tthe value:%d", "here is   the\tvalue:118\n", &intVal, 118},
+       {"%% %%:%d", "% %:119\n", &intVal, 119},
+
+       // Corner cases
+       {"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
+
+       // Custom scanner.
+       {"%s", "  sss ", &xVal, Xs("sss")},
+       {"%2s", "sssss", &xVal, Xs("ss")},
+
+       // Fixed bugs
+       {"%d\n", "27\n", &intVal, 27},  // ok
+       {"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline"
+}
+
+var overflowTests = []ScanTest{
+       {"128", &int8Val, 0},
+       {"32768", &int16Val, 0},
+       {"-129", &int8Val, 0},
+       {"-32769", &int16Val, 0},
+       {"256", &uint8Val, 0},
+       {"65536", &uint16Val, 0},
+       {"1e100", &float32Val, 0},
+       {"1e500", &float64Val, 0},
+       {"(1e100+0i)", &complexVal, 0},
+       {"(1+1e100i)", &complex64Val, 0},
+       {"(1-1e500i)", &complex128Val, 0},
+}
+
+var i, j, k int
+var f float
+var s, t string
+var c complex
+var x, y Xs
+
+var multiTests = []ScanfMultiTest{
+       {"", "", nil, nil, ""},
+       {"%d", "23", args(&i), args(23), ""},
+       {"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""},
+       {"%2d%3d", "44555", args(&i, &j), args(44, 555), ""},
+       {"%2d.%3d", "66.777", args(&i, &j), args(66, 777), ""},
+       {"%d, %d", "23, 18", args(&i, &j), args(23, 18), ""},
+       {"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""},
+       {"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), float(2.5)), ""},
+       {"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
+       {"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""},
+
+       // Custom scanner.
+       {"%2e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
+
+       // Errors
+       {"%t", "23 18", args(&i), nil, "bad verb"},
+       {"%d %d %d", "23 18", args(&i, &j), args(23, 18), "too few operands"},
+       {"%d %d", "23 18 27", args(&i, &j, &k), args(23, 18), "too many operands"},
+       {"%c", "\u0100", args(&int8Val), nil, "overflow"},
+       {"X%d", "10X", args(&intVal), nil, "input does not match format"},
+
+       // Bad UTF-8: should see every byte.
+       {"%c%c%c", "\xc2X\xc2", args(&i, &j, &k), args(utf8.RuneError, 'X', utf8.RuneError), ""},
+}
+
+func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, os.Error)) {
+       for _, test := range scanTests {
+               var r io.Reader
+               if name == "StringReader" {
+                       r = strings.NewReader(test.text)
+               } else {
+                       r = newReader(test.text)
+               }
+               n, err := scan(r, test.in)
+               if err != nil {
+                       t.Errorf("%s got error scanning %q: %s", name, test.text, err)
+                       continue
+               }
+               if n != 1 {
+                       t.Errorf("%s count error on entry %q: got %d", name, test.text, n)
+                       continue
+               }
+               // The incoming value may be a pointer
+               v := reflect.NewValue(test.in)
+               if p, ok := v.(*reflect.PtrValue); ok {
+                       v = p.Elem()
+               }
+               val := v.Interface()
+               if !reflect.DeepEqual(val, test.out) {
+                       t.Errorf("%s scanning %q: expected %v got %v, type %T", name, test.text, test.out, val, val)
+               }
+       }
+}
+
+func TestScan(t *testing.T) {
+       testScan("StringReader", t, Fscan)
+}
+
+func TestMyReaderScan(t *testing.T) {
+       testScan("myStringReader", t, Fscan)
+}
+
+func TestScanln(t *testing.T) {
+       testScan("StringReader", t, Fscanln)
+}
+
+func TestMyReaderScanln(t *testing.T) {
+       testScan("myStringReader", t, Fscanln)
+}
+
+func TestScanf(t *testing.T) {
+       for _, test := range scanfTests {
+               n, err := Sscanf(test.text, test.format, test.in)
+               if err != nil {
+                       t.Errorf("got error scanning (%q, %q): %s", test.format, test.text, err)
+                       continue
+               }
+               if n != 1 {
+                       t.Errorf("count error on entry (%q, %q): got %d", test.format, test.text, n)
+                       continue
+               }
+               // The incoming value may be a pointer
+               v := reflect.NewValue(test.in)
+               if p, ok := v.(*reflect.PtrValue); ok {
+                       v = p.Elem()
+               }
+               val := v.Interface()
+               if !reflect.DeepEqual(val, test.out) {
+                       t.Errorf("scanning (%q, %q): expected %v got %v, type %T", test.format, test.text, test.out, val, val)
+               }
+       }
+}
+
+func TestScanOverflow(t *testing.T) {
+       // different machines and different types report errors with different strings.
+       re := regexp.MustCompile("overflow|too large|out of range|not representable")
+       for _, test := range overflowTests {
+               _, err := Sscan(test.text, test.in)
+               if err == nil {
+                       t.Errorf("expected overflow scanning %q", test.text)
+                       continue
+               }
+               if !re.MatchString(err.String()) {
+                       t.Errorf("expected overflow error scanning %q: %s", test.text, err)
+               }
+       }
+}
+
+// TODO: there's no conversion from []T to ...T, but we can fake it.  These
+// functions do the faking.  We index the table by the length of the param list.
+var fscanf = []func(io.Reader, string, []interface{}) (int, os.Error){
+       0: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f) },
+       1: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f, i[0]) },
+       2: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f, i[0], i[1]) },
+       3: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f, i[0], i[1], i[2]) },
+}
+
+func testScanfMulti(name string, t *testing.T) {
+       sliceType := reflect.Typeof(make([]interface{}, 1)).(*reflect.SliceType)
+       for _, test := range multiTests {
+               var r io.Reader
+               if name == "StringReader" {
+                       r = strings.NewReader(test.text)
+               } else {
+                       r = newReader(test.text)
+               }
+               n, err := fscanf[len(test.in)](r, test.format, test.in)
+               if err != nil {
+                       if test.err == "" {
+                               t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
+                       } else if strings.Index(err.String(), test.err) < 0 {
+                               t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
+                       }
+                       continue
+               }
+               if test.err != "" {
+                       t.Errorf("expected error %q error scanning (%q, %q)", test.err, test.format, test.text)
+               }
+               if n != len(test.out) {
+                       t.Errorf("count error on entry (%q, %q): expected %d got %d", test.format, test.text, len(test.out), n)
+                       continue
+               }
+               // Convert the slice of pointers into a slice of values
+               resultVal := reflect.MakeSlice(sliceType, n, n)
+               for i := 0; i < n; i++ {
+                       v := reflect.NewValue(test.in[i]).(*reflect.PtrValue).Elem()
+                       resultVal.Elem(i).(*reflect.InterfaceValue).Set(v)
+               }
+               result := resultVal.Interface()
+               if !reflect.DeepEqual(result, test.out) {
+                       t.Errorf("scanning (%q, %q): expected %v got %v", test.format, test.text, test.out, result)
+               }
+       }
+}
+
+func TestScanfMulti(t *testing.T) {
+       testScanfMulti("StringReader", t)
+}
+
+func TestMyReaderScanfMulti(t *testing.T) {
+       testScanfMulti("myStringReader", t)
+}
+
+func TestScanMultiple(t *testing.T) {
+       var a int
+       var s string
+       n, err := Sscan("123abc", &a, &s)
+       if n != 2 {
+               t.Errorf("Sscan count error: expected 2: got %d", n)
+       }
+       if err != nil {
+               t.Errorf("Sscan expected no error; got %s", err)
+       }
+       if a != 123 || s != "abc" {
+               t.Errorf("Sscan wrong values: got (%d %q) expected (123 \"abc\")", a, s)
+       }
+       n, err = Sscan("asdf", &s, &a)
+       if n != 1 {
+               t.Errorf("Sscan count error: expected 1: got %d", n)
+       }
+       if err == nil {
+               t.Errorf("Sscan expected error; got none", err)
+       }
+       if s != "asdf" {
+               t.Errorf("Sscan wrong values: got %q expected \"asdf\"", s)
+       }
+}
+
+// Empty strings are not valid input when scanning a string.
+func TestScanEmpty(t *testing.T) {
+       var s1, s2 string
+       n, err := Sscan("abc", &s1, &s2)
+       if n != 1 {
+               t.Errorf("Sscan count error: expected 1: got %d", n)
+       }
+       if err == nil {
+               t.Errorf("Sscan <one item> expected error; got none")
+       }
+       if s1 != "abc" {
+               t.Errorf("Sscan wrong values: got %q expected \"abc\"", s1)
+       }
+       n, err = Sscan("", &s1, &s2)
+       if n != 0 {
+               t.Errorf("Sscan count error: expected 0: got %d", n)
+       }
+       if err == nil {
+               t.Errorf("Sscan <empty> expected error; got none")
+       }
+       // Quoted empty string is OK.
+       n, err = Sscanf(`""`, "%q", &s1)
+       if n != 1 {
+               t.Errorf("Sscanf count error: expected 1: got %d", n)
+       }
+       if err != nil {
+               t.Errorf("Sscanf <empty> expected no error with quoted string; got %s", err)
+       }
+}
+
+func TestScanNotPointer(t *testing.T) {
+       r := strings.NewReader("1")
+       var a int
+       _, err := Fscan(r, a)
+       if err == nil {
+               t.Error("expected error scanning non-pointer")
+       } else if strings.Index(err.String(), "pointer") < 0 {
+               t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
+       }
+}
+
+func TestScanlnNoNewline(t *testing.T) {
+       var a int
+       _, err := Sscanln("1 x\n", &a)
+       if err == nil {
+               t.Error("expected error scanning string missing newline")
+       } else if strings.Index(err.String(), "newline") < 0 {
+               t.Errorf("expected newline error scanning string missing newline, got: %s", err)
+       }
+}
+
+func TestScanlnWithMiddleNewline(t *testing.T) {
+       r := strings.NewReader("123\n456\n")
+       var a, b int
+       _, err := Fscanln(r, &a, &b)
+       if err == nil {
+               t.Error("expected error scanning string with extra newline")
+       } else if strings.Index(err.String(), "newline") < 0 {
+               t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
+       }
+}
+
+// Special Reader that counts reads at end of file.
+type eofCounter struct {
+       reader   *strings.Reader
+       eofCount int
+}
+
+func (ec *eofCounter) Read(b []byte) (n int, err os.Error) {
+       n, err = ec.reader.Read(b)
+       if n == 0 {
+               ec.eofCount++
+       }
+       return
+}
+
+// Verify that when we scan, we see at most EOF once per call to a Scan function,
+// and then only when it's really an EOF
+func TestEOF(t *testing.T) {
+       ec := &eofCounter{strings.NewReader("123\n"), 0}
+       var a int
+       n, err := Fscanln(ec, &a)
+       if err != nil {
+               t.Error("unexpected error", err)
+       }
+       if n != 1 {
+               t.Error("expected to scan one item, got", n)
+       }
+       if ec.eofCount != 0 {
+               t.Error("expected zero EOFs", ec.eofCount)
+               ec.eofCount = 0 // reset for next test
+       }
+       n, err = Fscanln(ec, &a)
+       if err == nil {
+               t.Error("expected error scanning empty string")
+       }
+       if n != 0 {
+               t.Error("expected to scan zero items, got", n)
+       }
+       if ec.eofCount != 1 {
+               t.Error("expected one EOF, got", ec.eofCount)
+       }
+}
+
+// Verify that, at least when using bufio, successive calls to Fscan do not lose runes.
+func TestUnreadRuneWithBufio(t *testing.T) {
+       r := bufio.NewReader(strings.NewReader("123αb"))
+       var i int
+       var a string
+       n, err := Fscanf(r, "%d", &i)
+       if n != 1 || err != nil {
+               t.Errorf("reading int expected one item, no errors; got %d %q", n, err)
+       }
+       if i != 123 {
+               t.Errorf("expected 123; got %d", i)
+       }
+       n, err = Fscanf(r, "%s", &a)
+       if n != 1 || err != nil {
+               t.Errorf("reading string expected one item, no errors; got %d %q", n, err)
+       }
+       if a != "αb" {
+               t.Errorf("expected αb; got %q", a)
+       }
+}
diff --git a/libgo/go/fmt/stringer_test.go b/libgo/go/fmt/stringer_test.go
new file mode 100644 (file)
index 0000000..815147e
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt_test
+
+import (
+       . "fmt"
+       "testing"
+)
+
+type TI int
+type TI8 int8
+type TI16 int16
+type TI32 int32
+type TI64 int64
+type TU uint
+type TU8 uint8
+type TU16 uint16
+type TU32 uint32
+type TU64 uint64
+type TUI uintptr
+type TF float
+type TF32 float32
+type TF64 float64
+type TB bool
+type TS string
+
+func (v TI) String() string   { return Sprintf("I: %d", int(v)) }
+func (v TI8) String() string  { return Sprintf("I8: %d", int8(v)) }
+func (v TI16) String() string { return Sprintf("I16: %d", int16(v)) }
+func (v TI32) String() string { return Sprintf("I32: %d", int32(v)) }
+func (v TI64) String() string { return Sprintf("I64: %d", int64(v)) }
+func (v TU) String() string   { return Sprintf("U: %d", uint(v)) }
+func (v TU8) String() string  { return Sprintf("U8: %d", uint8(v)) }
+func (v TU16) String() string { return Sprintf("U16: %d", uint16(v)) }
+func (v TU32) String() string { return Sprintf("U32: %d", uint32(v)) }
+func (v TU64) String() string { return Sprintf("U64: %d", uint64(v)) }
+func (v TUI) String() string  { return Sprintf("UI: %d", uintptr(v)) }
+func (v TF) String() string   { return Sprintf("F: %f", float(v)) }
+func (v TF32) String() string { return Sprintf("F32: %f", float32(v)) }
+func (v TF64) String() string { return Sprintf("F64: %f", float64(v)) }
+func (v TB) String() string   { return Sprintf("B: %t", bool(v)) }
+func (v TS) String() string   { return Sprintf("S: %q", string(v)) }
+
+func check(t *testing.T, got, want string) {
+       if got != want {
+               t.Error(got, "!=", want)
+       }
+}
+
+func TestStringer(t *testing.T) {
+       s := Sprintf("%v %v %v %v %v", TI(0), TI8(1), TI16(2), TI32(3), TI64(4))
+       check(t, s, "I: 0 I8: 1 I16: 2 I32: 3 I64: 4")
+       s = Sprintf("%v %v %v %v %v %v", TU(5), TU8(6), TU16(7), TU32(8), TU64(9), TUI(10))
+       check(t, s, "U: 5 U8: 6 U16: 7 U32: 8 U64: 9 UI: 10")
+       s = Sprintf("%v %v %v", TF(1.0), TF32(2.0), TF64(3.0))
+       check(t, s, "F: 1.000000 F32: 2.000000 F64: 3.000000")
+       s = Sprintf("%v %v", TB(true), TS("x"))
+       check(t, s, "B: true S: \"x\"")
+}
diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go
new file mode 100644 (file)
index 0000000..cd66f38
--- /dev/null
@@ -0,0 +1,782 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The AST package declares the types used to represent
+// syntax trees for Go packages.
+//
+package ast
+
+import (
+       "go/token"
+       "unicode"
+       "utf8"
+)
+
+
+// ----------------------------------------------------------------------------
+// Interfaces
+//
+// There are 3 main classes of nodes: Expressions and type nodes,
+// statement nodes, and declaration nodes. The node names usually
+// match the corresponding Go spec production names to which they
+// correspond. The node fields correspond to the individual parts
+// of the respective productions.
+//
+// All nodes contain position information marking the beginning of
+// the corresponding source text segment; it is accessible via the
+// Pos accessor method. Nodes may contain additional position info
+// for language constructs where comments may be found between parts
+// of the construct (typically any larger, parenthesized subpart).
+// That position information is needed to properly position comments
+// when printing the construct.
+
+
+// All node types implement the Node interface.
+type Node interface {
+       // Pos returns the (beginning) position of the node.
+       Pos() token.Position
+}
+
+
+// All expression nodes implement the Expr interface.
+type Expr interface {
+       Node
+       exprNode()
+}
+
+
+// All statement nodes implement the Stmt interface.
+type Stmt interface {
+       Node
+       stmtNode()
+}
+
+
+// All declaration nodes implement the Decl interface.
+type Decl interface {
+       Node
+       declNode()
+}
+
+
+// ----------------------------------------------------------------------------
+// Comments
+
+// A Comment node represents a single //-style or /*-style comment.
+type Comment struct {
+       Slash token.Position // position of "/" starting the comment
+       Text  []byte         // comment text (excluding '\n' for //-style comments)
+}
+
+
+func (c *Comment) Pos() token.Position {
+       return c.Slash
+}
+
+
+// A CommentGroup represents a sequence of comments
+// with no other tokens and no empty lines between.
+//
+type CommentGroup struct {
+       List []*Comment
+}
+
+
+// ----------------------------------------------------------------------------
+// Expressions and types
+
+// A Field represents a Field declaration list in a struct type,
+// a method list in an interface type, or a parameter/result declaration
+// in a signature.
+//
+type Field struct {
+       Doc     *CommentGroup // associated documentation; or nil
+       Names   []*Ident      // field/method/parameter names; or nil if anonymous field
+       Type    Expr          // field/method/parameter type
+       Tag     *BasicLit     // field tag; or nil
+       Comment *CommentGroup // line comments; or nil
+}
+
+
+func (f *Field) Pos() token.Position {
+       if len(f.Names) > 0 {
+               return f.Names[0].Pos()
+       }
+       return f.Type.Pos()
+}
+
+
+// A FieldList represents a list of Fields, enclosed by parentheses or braces.
+type FieldList struct {
+       Opening token.Position // position of opening parenthesis/brace
+       List    []*Field       // field list
+       Closing token.Position // position of closing parenthesis/brace
+}
+
+
+// NumFields returns the number of (named and anonymous fields) in a FieldList.
+func (f *FieldList) NumFields() int {
+       n := 0
+       if f != nil {
+               for _, g := range f.List {
+                       m := len(g.Names)
+                       if m == 0 {
+                               m = 1 // anonymous field
+                       }
+                       n += m
+               }
+       }
+       return n
+}
+
+
+// An expression is represented by a tree consisting of one
+// or more of the following concrete expression nodes.
+//
+type (
+       // A BadExpr node is a placeholder for expressions containing
+       // syntax errors for which no correct expression nodes can be
+       // created.
+       //
+       BadExpr struct {
+               Begin token.Position // beginning position of bad expression
+       }
+
+       // An Ident node represents an identifier.
+       Ident struct {
+               NamePos token.Position // identifier position
+               Name    string         // identifier name
+               Obj     *Object        // denoted object; or nil
+       }
+
+       // An Ellipsis node stands for the "..." type in a
+       // parameter list or the "..." length in an array type.
+       //
+       Ellipsis struct {
+               Ellipsis token.Position // position of "..."
+               Elt      Expr           // ellipsis element type (parameter lists only)
+       }
+
+       // A BasicLit node represents a literal of basic type.
+       BasicLit struct {
+               ValuePos token.Position // literal position
+               Kind     token.Token    // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
+               Value    []byte         // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o`
+       }
+
+       // A FuncLit node represents a function literal.
+       FuncLit struct {
+               Type *FuncType  // function type
+               Body *BlockStmt // function body
+       }
+
+       // A CompositeLit node represents a composite literal.
+       CompositeLit struct {
+               Type   Expr           // literal type; or nil
+               Lbrace token.Position // position of "{"
+               Elts   []Expr         // list of composite elements
+               Rbrace token.Position // position of "}"
+       }
+
+       // A ParenExpr node represents a parenthesized expression.
+       ParenExpr struct {
+               Lparen token.Position // position of "("
+               X      Expr           // parenthesized expression
+               Rparen token.Position // position of ")"
+       }
+
+       // A SelectorExpr node represents an expression followed by a selector.
+       SelectorExpr struct {
+               X   Expr   // expression
+               Sel *Ident // field selector
+       }
+
+       // An IndexExpr node represents an expression followed by an index.
+       IndexExpr struct {
+               X     Expr // expression
+               Index Expr // index expression
+       }
+
+       // An SliceExpr node represents an expression followed by slice indices.
+       SliceExpr struct {
+               X     Expr // expression
+               Index Expr // beginning of slice range; or nil
+               End   Expr // end of slice range; or nil
+       }
+
+       // A TypeAssertExpr node represents an expression followed by a
+       // type assertion.
+       //
+       TypeAssertExpr struct {
+               X    Expr // expression
+               Type Expr // asserted type; nil means type switch X.(type)
+       }
+
+       // A CallExpr node represents an expression followed by an argument list.
+       CallExpr struct {
+               Fun      Expr           // function expression
+               Lparen   token.Position // position of "("
+               Args     []Expr         // function arguments
+               Ellipsis token.Position // position of "...", if any
+               Rparen   token.Position // position of ")"
+       }
+
+       // A StarExpr node represents an expression of the form "*" Expression.
+       // Semantically it could be a unary "*" expression, or a pointer type.
+       //
+       StarExpr struct {
+               Star token.Position // position of "*"
+               X    Expr           // operand
+       }
+
+       // A UnaryExpr node represents a unary expression.
+       // Unary "*" expressions are represented via StarExpr nodes.
+       //
+       UnaryExpr struct {
+               OpPos token.Position // position of Op
+               Op    token.Token    // operator
+               X     Expr           // operand
+       }
+
+       // A BinaryExpr node represents a binary expression.
+       BinaryExpr struct {
+               X     Expr           // left operand
+               OpPos token.Position // position of Op
+               Op    token.Token    // operator
+               Y     Expr           // right operand
+       }
+
+       // A KeyValueExpr node represents (key : value) pairs
+       // in composite literals.
+       //
+       KeyValueExpr struct {
+               Key   Expr
+               Colon token.Position // position of ":"
+               Value Expr
+       }
+)
+
+
+// The direction of a channel type is indicated by one
+// of the following constants.
+//
+type ChanDir int
+
+const (
+       SEND ChanDir = 1 << iota
+       RECV
+)
+
+
+// A type is represented by a tree consisting of one
+// or more of the following type-specific expression
+// nodes.
+//
+type (
+       // An ArrayType node represents an array or slice type.
+       ArrayType struct {
+               Lbrack token.Position // position of "["
+               Len    Expr           // Ellipsis node for [...]T array types, nil for slice types
+               Elt    Expr           // element type
+       }
+
+       // A StructType node represents a struct type.
+       StructType struct {
+               Struct     token.Position // position of "struct" keyword
+               Fields     *FieldList     // list of field declarations
+               Incomplete bool           // true if (source) fields are missing in the Fields list
+       }
+
+       // Pointer types are represented via StarExpr nodes.
+
+       // A FuncType node represents a function type.
+       FuncType struct {
+               Func    token.Position // position of "func" keyword
+               Params  *FieldList     // (incoming) parameters
+               Results *FieldList     // (outgoing) results
+       }
+
+       // An InterfaceType node represents an interface type.
+       InterfaceType struct {
+               Interface  token.Position // position of "interface" keyword
+               Methods    *FieldList     // list of methods
+               Incomplete bool           // true if (source) methods are missing in the Methods list
+       }
+
+       // A MapType node represents a map type.
+       MapType struct {
+               Map   token.Position // position of "map" keyword
+               Key   Expr
+               Value Expr
+       }
+
+       // A ChanType node represents a channel type.
+       ChanType struct {
+               Begin token.Position // position of "chan" keyword or "<-" (whichever comes first)
+               Dir   ChanDir        // channel direction
+               Value Expr           // value type
+       }
+)
+
+
+// Pos() implementations for expression/type nodes.
+//
+func (x *BadExpr) Pos() token.Position  { return x.Begin }
+func (x *Ident) Pos() token.Position    { return x.NamePos }
+func (x *Ellipsis) Pos() token.Position { return x.Ellipsis }
+func (x *BasicLit) Pos() token.Position { return x.ValuePos }
+func (x *FuncLit) Pos() token.Position  { return x.Type.Pos() }
+func (x *CompositeLit) Pos() token.Position {
+       if x.Type != nil {
+               return x.Type.Pos()
+       }
+       return x.Lbrace
+}
+func (x *ParenExpr) Pos() token.Position      { return x.Lparen }
+func (x *SelectorExpr) Pos() token.Position   { return x.X.Pos() }
+func (x *IndexExpr) Pos() token.Position      { return x.X.Pos() }
+func (x *SliceExpr) Pos() token.Position      { return x.X.Pos() }
+func (x *TypeAssertExpr) Pos() token.Position { return x.X.Pos() }
+func (x *CallExpr) Pos() token.Position       { return x.Fun.Pos() }
+func (x *StarExpr) Pos() token.Position       { return x.Star }
+func (x *UnaryExpr) Pos() token.Position      { return x.OpPos }
+func (x *BinaryExpr) Pos() token.Position     { return x.X.Pos() }
+func (x *KeyValueExpr) Pos() token.Position   { return x.Key.Pos() }
+func (x *ArrayType) Pos() token.Position      { return x.Lbrack }
+func (x *StructType) Pos() token.Position     { return x.Struct }
+func (x *FuncType) Pos() token.Position       { return x.Func }
+func (x *InterfaceType) Pos() token.Position  { return x.Interface }
+func (x *MapType) Pos() token.Position        { return x.Map }
+func (x *ChanType) Pos() token.Position       { return x.Begin }
+
+
+// exprNode() ensures that only expression/type nodes can be
+// assigned to an ExprNode.
+//
+func (x *BadExpr) exprNode()        {}
+func (x *Ident) exprNode()          {}
+func (x *Ellipsis) exprNode()       {}
+func (x *BasicLit) exprNode()       {}
+func (x *FuncLit) exprNode()        {}
+func (x *CompositeLit) exprNode()   {}
+func (x *ParenExpr) exprNode()      {}
+func (x *SelectorExpr) exprNode()   {}
+func (x *IndexExpr) exprNode()      {}
+func (x *SliceExpr) exprNode()      {}
+func (x *TypeAssertExpr) exprNode() {}
+func (x *CallExpr) exprNode()       {}
+func (x *StarExpr) exprNode()       {}
+func (x *UnaryExpr) exprNode()      {}
+func (x *BinaryExpr) exprNode()     {}
+func (x *KeyValueExpr) exprNode()   {}
+
+func (x *ArrayType) exprNode()     {}
+func (x *StructType) exprNode()    {}
+func (x *FuncType) exprNode()      {}
+func (x *InterfaceType) exprNode() {}
+func (x *MapType) exprNode()       {}
+func (x *ChanType) exprNode()      {}
+
+
+// ----------------------------------------------------------------------------
+// Convenience functions for Idents
+
+var noPos token.Position
+
+// NewIdent creates a new Ident without position.
+// Useful for ASTs generated by code other than the Go parser.
+//
+func NewIdent(name string) *Ident { return &Ident{noPos, name, nil} }
+
+
+// IsExported returns whether name is an exported Go symbol
+// (i.e., whether it begins with an uppercase letter).
+//
+func IsExported(name string) bool {
+       ch, _ := utf8.DecodeRuneInString(name)
+       return unicode.IsUpper(ch)
+}
+
+
+// IsExported returns whether id is an exported Go symbol
+// (i.e., whether it begins with an uppercase letter).
+//
+func (id *Ident) IsExported() bool { return IsExported(id.Name) }
+
+
+func (id *Ident) String() string {
+       if id != nil {
+               return id.Name
+       }
+       return "<nil>"
+}
+
+
+// ----------------------------------------------------------------------------
+// Statements
+
+// A statement is represented by a tree consisting of one
+// or more of the following concrete statement nodes.
+//
+type (
+       // A BadStmt node is a placeholder for statements containing
+       // syntax errors for which no correct statement nodes can be
+       // created.
+       //
+       BadStmt struct {
+               Begin token.Position // beginning position of bad statement
+       }
+
+       // A DeclStmt node represents a declaration in a statement list.
+       DeclStmt struct {
+               Decl Decl
+       }
+
+       // An EmptyStmt node represents an empty statement.
+       // The "position" of the empty statement is the position
+       // of the immediately preceeding semicolon.
+       //
+       EmptyStmt struct {
+               Semicolon token.Position // position of preceeding ";"
+       }
+
+       // A LabeledStmt node represents a labeled statement.
+       LabeledStmt struct {
+               Label *Ident
+               Stmt  Stmt
+       }
+
+       // An ExprStmt node represents a (stand-alone) expression
+       // in a statement list.
+       //
+       ExprStmt struct {
+               X Expr // expression
+       }
+
+       // An IncDecStmt node represents an increment or decrement statement.
+       IncDecStmt struct {
+               X   Expr
+               Tok token.Token // INC or DEC
+       }
+
+       // An AssignStmt node represents an assignment or
+       // a short variable declaration.
+       //
+       AssignStmt struct {
+               Lhs    []Expr
+               TokPos token.Position // position of Tok
+               Tok    token.Token    // assignment token, DEFINE
+               Rhs    []Expr
+       }
+
+       // A GoStmt node represents a go statement.
+       GoStmt struct {
+               Go   token.Position // position of "go" keyword
+               Call *CallExpr
+       }
+
+       // A DeferStmt node represents a defer statement.
+       DeferStmt struct {
+               Defer token.Position // position of "defer" keyword
+               Call  *CallExpr
+       }
+
+       // A ReturnStmt node represents a return statement.
+       ReturnStmt struct {
+               Return  token.Position // position of "return" keyword
+               Results []Expr
+       }
+
+       // A BranchStmt node represents a break, continue, goto,
+       // or fallthrough statement.
+       //
+       BranchStmt struct {
+               TokPos token.Position // position of Tok
+               Tok    token.Token    // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH)
+               Label  *Ident
+       }
+
+       // A BlockStmt node represents a braced statement list.
+       BlockStmt struct {
+               Lbrace token.Position // position of "{"
+               List   []Stmt
+               Rbrace token.Position // position of "}"
+       }
+
+       // An IfStmt node represents an if statement.
+       IfStmt struct {
+               If   token.Position // position of "if" keyword
+               Init Stmt
+               Cond Expr
+               Body *BlockStmt
+               Else Stmt
+       }
+
+       // A CaseClause represents a case of an expression switch statement.
+       CaseClause struct {
+               Case   token.Position // position of "case" or "default" keyword
+               Values []Expr         // nil means default case
+               Colon  token.Position // position of ":"
+               Body   []Stmt         // statement list; or nil
+       }
+
+       // A SwitchStmt node represents an expression switch statement.
+       SwitchStmt struct {
+               Switch token.Position // position of "switch" keyword
+               Init   Stmt
+               Tag    Expr
+               Body   *BlockStmt // CaseClauses only
+       }
+
+       // A TypeCaseClause represents a case of a type switch statement.
+       TypeCaseClause struct {
+               Case  token.Position // position of "case" or "default" keyword
+               Types []Expr         // nil means default case
+               Colon token.Position // position of ":"
+               Body  []Stmt         // statement list; or nil
+       }
+
+       // An TypeSwitchStmt node represents a type switch statement.
+       TypeSwitchStmt struct {
+               Switch token.Position // position of "switch" keyword
+               Init   Stmt
+               Assign Stmt       // x := y.(type)
+               Body   *BlockStmt // TypeCaseClauses only
+       }
+
+       // A CommClause node represents a case of a select statement.
+       CommClause struct {
+               Case     token.Position // position of "case" or "default" keyword
+               Tok      token.Token    // ASSIGN or DEFINE (valid only if Lhs != nil)
+               Lhs, Rhs Expr           // Rhs == nil means default case
+               Colon    token.Position // position of ":"
+               Body     []Stmt         // statement list; or nil
+       }
+
+       // An SelectStmt node represents a select statement.
+       SelectStmt struct {
+               Select token.Position // position of "select" keyword
+               Body   *BlockStmt     // CommClauses only
+       }
+
+       // A ForStmt represents a for statement.
+       ForStmt struct {
+               For  token.Position // position of "for" keyword
+               Init Stmt
+               Cond Expr
+               Post Stmt
+               Body *BlockStmt
+       }
+
+       // A RangeStmt represents a for statement with a range clause.
+       RangeStmt struct {
+               For        token.Position // position of "for" keyword
+               Key, Value Expr           // Value may be nil
+               TokPos     token.Position // position of Tok
+               Tok        token.Token    // ASSIGN, DEFINE
+               X          Expr           // value to range over
+               Body       *BlockStmt
+       }
+)
+
+
+// Pos() implementations for statement nodes.
+//
+func (s *BadStmt) Pos() token.Position        { return s.Begin }
+func (s *DeclStmt) Pos() token.Position       { return s.Decl.Pos() }
+func (s *EmptyStmt) Pos() token.Position      { return s.Semicolon }
+func (s *LabeledStmt) Pos() token.Position    { return s.Label.Pos() }
+func (s *ExprStmt) Pos() token.Position       { return s.X.Pos() }
+func (s *IncDecStmt) Pos() token.Position     { return s.X.Pos() }
+func (s *AssignStmt) Pos() token.Position     { return s.Lhs[0].Pos() }
+func (s *GoStmt) Pos() token.Position         { return s.Go }
+func (s *DeferStmt) Pos() token.Position      { return s.Defer }
+func (s *ReturnStmt) Pos() token.Position     { return s.Return }
+func (s *BranchStmt) Pos() token.Position     { return s.TokPos }
+func (s *BlockStmt) Pos() token.Position      { return s.Lbrace }
+func (s *IfStmt) Pos() token.Position         { return s.If }
+func (s *CaseClause) Pos() token.Position     { return s.Case }
+func (s *SwitchStmt) Pos() token.Position     { return s.Switch }
+func (s *TypeCaseClause) Pos() token.Position { return s.Case }
+func (s *TypeSwitchStmt) Pos() token.Position { return s.Switch }
+func (s *CommClause) Pos() token.Position     { return s.Case }
+func (s *SelectStmt) Pos() token.Position     { return s.Select }
+func (s *ForStmt) Pos() token.Position        { return s.For }
+func (s *RangeStmt) Pos() token.Position      { return s.For }
+
+
+// stmtNode() ensures that only statement nodes can be
+// assigned to a StmtNode.
+//
+func (s *BadStmt) stmtNode()        {}
+func (s *DeclStmt) stmtNode()       {}
+func (s *EmptyStmt) stmtNode()      {}
+func (s *LabeledStmt) stmtNode()    {}
+func (s *ExprStmt) stmtNode()       {}
+func (s *IncDecStmt) stmtNode()     {}
+func (s *AssignStmt) stmtNode()     {}
+func (s *GoStmt) stmtNode()         {}
+func (s *DeferStmt) stmtNode()      {}
+func (s *ReturnStmt) stmtNode()     {}
+func (s *BranchStmt) stmtNode()     {}
+func (s *BlockStmt) stmtNode()      {}
+func (s *IfStmt) stmtNode()         {}
+func (s *CaseClause) stmtNode()     {}
+func (s *SwitchStmt) stmtNode()     {}
+func (s *TypeCaseClause) stmtNode() {}
+func (s *TypeSwitchStmt) stmtNode() {}
+func (s *CommClause) stmtNode()     {}
+func (s *SelectStmt) stmtNode()     {}
+func (s *ForStmt) stmtNode()        {}
+func (s *RangeStmt) stmtNode()      {}
+
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// A Spec node represents a single (non-parenthesized) import,
+// constant, type, or variable declaration.
+//
+type (
+       // The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec.
+       Spec interface {
+               Node
+               specNode()
+       }
+
+       // An ImportSpec node represents a single package import.
+       ImportSpec struct {
+               Doc     *CommentGroup // associated documentation; or nil
+               Name    *Ident        // local package name (including "."); or nil
+               Path    *BasicLit     // package path
+               Comment *CommentGroup // line comments; or nil
+       }
+
+       // A ValueSpec node represents a constant or variable declaration
+       // (ConstSpec or VarSpec production).
+       //
+       ValueSpec struct {
+               Doc     *CommentGroup // associated documentation; or nil
+               Names   []*Ident      // value names
+               Type    Expr          // value type; or nil
+               Values  []Expr        // initial values; or nil
+               Comment *CommentGroup // line comments; or nil
+       }
+
+       // A TypeSpec node represents a type declaration (TypeSpec production).
+       TypeSpec struct {
+               Doc     *CommentGroup // associated documentation; or nil
+               Name    *Ident        // type name
+               Type    Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
+               Comment *CommentGroup // line comments; or nil
+       }
+)
+
+
+// Pos() implementations for spec nodes.
+//
+func (s *ImportSpec) Pos() token.Position {
+       if s.Name != nil {
+               return s.Name.Pos()
+       }
+       return s.Path.Pos()
+}
+func (s *ValueSpec) Pos() token.Position { return s.Names[0].Pos() }
+func (s *TypeSpec) Pos() token.Position  { return s.Name.Pos() }
+
+
+// specNode() ensures that only spec nodes can be
+// assigned to a Spec.
+//
+func (s *ImportSpec) specNode() {}
+func (s *ValueSpec) specNode()  {}
+func (s *TypeSpec) specNode()   {}
+
+
+// A declaration is represented by one of the following declaration nodes.
+//
+type (
+       // A BadDecl node is a placeholder for declarations containing
+       // syntax errors for which no correct declaration nodes can be
+       // created.
+       //
+       BadDecl struct {
+               Begin token.Position // beginning position of bad declaration
+       }
+
+       // A GenDecl node (generic declaration node) represents an import,
+       // constant, type or variable declaration. A valid Lparen position
+       // (Lparen.Line > 0) indicates a parenthesized declaration.
+       //
+       // Relationship between Tok value and Specs element type:
+       //
+       //      token.IMPORT  *ImportSpec
+       //      token.CONST   *ValueSpec
+       //      token.TYPE    *TypeSpec
+       //      token.VAR     *ValueSpec
+       //
+       GenDecl struct {
+               Doc    *CommentGroup  // associated documentation; or nil
+               TokPos token.Position // position of Tok
+               Tok    token.Token    // IMPORT, CONST, TYPE, VAR
+               Lparen token.Position // position of '(', if any
+               Specs  []Spec
+               Rparen token.Position // position of ')', if any
+       }
+
+       // A FuncDecl node represents a function declaration.
+       FuncDecl struct {
+               Doc  *CommentGroup // associated documentation; or nil
+               Recv *FieldList    // receiver (methods); or nil (functions)
+               Name *Ident        // function/method name
+               Type *FuncType     // position of Func keyword, parameters and results
+               Body *BlockStmt    // function body; or nil (forward declaration)
+       }
+)
+
+
+// Pos implementations for declaration nodes.
+//
+func (d *BadDecl) Pos() token.Position  { return d.Begin }
+func (d *GenDecl) Pos() token.Position  { return d.TokPos }
+func (d *FuncDecl) Pos() token.Position { return d.Type.Pos() }
+
+
+// declNode() ensures that only declaration nodes can be
+// assigned to a DeclNode.
+//
+func (d *BadDecl) declNode()  {}
+func (d *GenDecl) declNode()  {}
+func (d *FuncDecl) declNode() {}
+
+
+// ----------------------------------------------------------------------------
+// Files and packages
+
+// A File node represents a Go source file.
+//
+// The Comments list contains all comments in the source file in order of
+// appearance, including the comments that are pointed to from other nodes
+// via Doc and Comment fields.
+//
+type File struct {
+       Doc      *CommentGroup   // associated documentation; or nil
+       Package  token.Position  // position of "package" keyword
+       Name     *Ident          // package name
+       Decls    []Decl          // top-level declarations
+       Comments []*CommentGroup // list of all comments in the source file
+}
+
+
+func (f *File) Pos() token.Position { return f.Package }
+
+
+// A Package node represents a set of source files
+// collectively building a Go package.
+//
+type Package struct {
+       Name  string           // package name
+       Scope *Scope           // package scope; or nil
+       Files map[string]*File // Go source files by filename
+}
diff --git a/libgo/go/go/ast/filter.go b/libgo/go/go/ast/filter.go
new file mode 100644 (file)
index 0000000..c46a1e0
--- /dev/null
@@ -0,0 +1,450 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast
+
+import "go/token"
+
+// ----------------------------------------------------------------------------
+// Export filtering
+
+func identListExports(list []*Ident) []*Ident {
+       j := 0
+       for _, x := range list {
+               if x.IsExported() {
+                       list[j] = x
+                       j++
+               }
+       }
+       return list[0:j]
+}
+
+
+// isExportedType assumes that typ is a correct type.
+func isExportedType(typ Expr) bool {
+       switch t := typ.(type) {
+       case *Ident:
+               return t.IsExported()
+       case *ParenExpr:
+               return isExportedType(t.X)
+       case *SelectorExpr:
+               // assume t.X is a typename
+               return t.Sel.IsExported()
+       case *StarExpr:
+               return isExportedType(t.X)
+       }
+       return false
+}
+
+
+func fieldListExports(fields *FieldList, incomplete *bool) {
+       if fields == nil {
+               return
+       }
+       list := fields.List
+       j := 0
+       for _, f := range list {
+               exported := false
+               if len(f.Names) == 0 {
+                       // anonymous field
+                       // (Note that a non-exported anonymous field
+                       // may still refer to a type with exported
+                       // fields, so this is not absolutely correct.
+                       // However, this cannot be done w/o complete
+                       // type information.)
+                       exported = isExportedType(f.Type)
+               } else {
+                       n := len(f.Names)
+                       f.Names = identListExports(f.Names)
+                       if len(f.Names) < n {
+                               *incomplete = true
+                       }
+                       exported = len(f.Names) > 0
+               }
+               if exported {
+                       typeExports(f.Type)
+                       list[j] = f
+                       j++
+               }
+       }
+       if j < len(list) {
+               *incomplete = true
+       }
+       fields.List = list[0:j]
+}
+
+
+func paramListExports(fields *FieldList) {
+       if fields == nil {
+               return
+       }
+       for _, f := range fields.List {
+               typeExports(f.Type)
+       }
+}
+
+
+func typeExports(typ Expr) {
+       switch t := typ.(type) {
+       case *ArrayType:
+               typeExports(t.Elt)
+       case *StructType:
+               fieldListExports(t.Fields, &t.Incomplete)
+       case *FuncType:
+               paramListExports(t.Params)
+               paramListExports(t.Results)
+       case *InterfaceType:
+               fieldListExports(t.Methods, &t.Incomplete)
+       case *MapType:
+               typeExports(t.Key)
+               typeExports(t.Value)
+       case *ChanType:
+               typeExports(t.Value)
+       }
+}
+
+
+func specExports(spec Spec) bool {
+       switch s := spec.(type) {
+       case *ValueSpec:
+               s.Names = identListExports(s.Names)
+               if len(s.Names) > 0 {
+                       typeExports(s.Type)
+                       return true
+               }
+       case *TypeSpec:
+               if s.Name.IsExported() {
+                       typeExports(s.Type)
+                       return true
+               }
+       }
+       return false
+}
+
+
+func specListExports(list []Spec) []Spec {
+       j := 0
+       for _, s := range list {
+               if specExports(s) {
+                       list[j] = s
+                       j++
+               }
+       }
+       return list[0:j]
+}
+
+
+func declExports(decl Decl) bool {
+       switch d := decl.(type) {
+       case *GenDecl:
+               d.Specs = specListExports(d.Specs)
+               return len(d.Specs) > 0
+       case *FuncDecl:
+               d.Body = nil // strip body
+               return d.Name.IsExported()
+       }
+       return false
+}
+
+
+// FileExports trims the AST for a Go source file in place such that only
+// exported nodes remain: all top-level identifiers which are not exported
+// and their associated information (such as type, initial value, or function
+// body) are removed. Non-exported fields and methods of exported types are
+// stripped, and the function bodies of exported functions are set to nil.
+// The File.comments list is not changed.
+//
+// FileExports returns true if there is an exported declaration; it returns
+// false otherwise.
+//
+func FileExports(src *File) bool {
+       j := 0
+       for _, d := range src.Decls {
+               if declExports(d) {
+                       src.Decls[j] = d
+                       j++
+               }
+       }
+       src.Decls = src.Decls[0:j]
+       return j > 0
+}
+
+
+// PackageExports trims the AST for a Go package in place such that only
+// exported nodes remain. The pkg.Files list is not changed, so that file
+// names and top-level package comments don't get lost.
+//
+// PackageExports returns true if there is an exported declaration; it
+// returns false otherwise.
+//
+func PackageExports(pkg *Package) bool {
+       hasExports := false
+       for _, f := range pkg.Files {
+               if FileExports(f) {
+                       hasExports = true
+               }
+       }
+       return hasExports
+}
+
+
+// ----------------------------------------------------------------------------
+// General filtering
+
+type Filter func(string) bool
+
+func filterIdentList(list []*Ident, f Filter) []*Ident {
+       j := 0
+       for _, x := range list {
+               if f(x.Name) {
+                       list[j] = x
+                       j++
+               }
+       }
+       return list[0:j]
+}
+
+
+func filterSpec(spec Spec, f Filter) bool {
+       switch s := spec.(type) {
+       case *ValueSpec:
+               s.Names = filterIdentList(s.Names, f)
+               return len(s.Names) > 0
+       case *TypeSpec:
+               return f(s.Name.Name)
+       }
+       return false
+}
+
+
+func filterSpecList(list []Spec, f Filter) []Spec {
+       j := 0
+       for _, s := range list {
+               if filterSpec(s, f) {
+                       list[j] = s
+                       j++
+               }
+       }
+       return list[0:j]
+}
+
+
+func filterDecl(decl Decl, f Filter) bool {
+       switch d := decl.(type) {
+       case *GenDecl:
+               d.Specs = filterSpecList(d.Specs, f)
+               return len(d.Specs) > 0
+       case *FuncDecl:
+               return f(d.Name.Name)
+       }
+       return false
+}
+
+
+// FilterFile trims the AST for a Go file in place by removing all
+// names from top-level declarations (but not from parameter lists
+// or inside types) that don't pass through the filter f. If the
+// declaration is empty afterwards, the declaration is removed from
+// the AST.
+// The File.comments list is not changed.
+//
+// FilterFile returns true if there are any top-level declarations
+// left after filtering; it returns false otherwise.
+//
+func FilterFile(src *File, f Filter) bool {
+       j := 0
+       for _, d := range src.Decls {
+               if filterDecl(d, f) {
+                       src.Decls[j] = d
+                       j++
+               }
+       }
+       src.Decls = src.Decls[0:j]
+       return j > 0
+}
+
+
+// FilterPackage trims the AST for a Go package in place by removing all
+// names from top-level declarations (but not from parameter lists
+// or inside types) that don't pass through the filter f. If the
+// declaration is empty afterwards, the declaration is removed from
+// the AST.
+// The pkg.Files list is not changed, so that file names and top-level
+// package comments don't get lost.
+//
+// FilterPackage returns true if there are any top-level declarations
+// left after filtering; it returns false otherwise.
+//
+func FilterPackage(pkg *Package, f Filter) bool {
+       hasDecls := false
+       for _, src := range pkg.Files {
+               if FilterFile(src, f) {
+                       hasDecls = true
+               }
+       }
+       return hasDecls
+}
+
+
+// ----------------------------------------------------------------------------
+// Merging of package files
+
+// The MergeMode flags control the behavior of MergePackageFiles.
+type MergeMode uint
+
+const (
+       // If set, duplicate function declarations are excluded.
+       FilterFuncDuplicates MergeMode = 1 << iota
+       // If set, comments that are not associated with a specific
+       // AST node (as Doc or Comment) are excluded.
+       FilterUnassociatedComments
+)
+
+// separator is an empty //-style comment that is interspersed between
+// different comment groups when they are concatenated into a single group
+//
+var separator = &Comment{noPos, []byte("//")}
+
+
+// lineAfterComment computes the position of the beginning
+// of the line immediately following a comment.
+func lineAfterComment(c *Comment) token.Position {
+       pos := c.Pos()
+       line := pos.Line
+       text := c.Text
+       if text[1] == '*' {
+               /*-style comment - determine endline */
+               for _, ch := range text {
+                       if ch == '\n' {
+                               line++
+                       }
+               }
+       }
+       pos.Offset += len(text) + 1 // +1 for newline
+       pos.Line = line + 1         // line after comment
+       pos.Column = 1              // beginning of line
+       return pos
+}
+
+
+// MergePackageFiles creates a file AST by merging the ASTs of the
+// files belonging to a package. The mode flags control merging behavior.
+//
+func MergePackageFiles(pkg *Package, mode MergeMode) *File {
+       // Count the number of package docs, comments and declarations across
+       // all package files.
+       ndocs := 0
+       ncomments := 0
+       ndecls := 0
+       for _, f := range pkg.Files {
+               if f.Doc != nil {
+                       ndocs += len(f.Doc.List) + 1 // +1 for separator
+               }
+               ncomments += len(f.Comments)
+               ndecls += len(f.Decls)
+       }
+
+       // Collect package comments from all package files into a single
+       // CommentGroup - the collected package documentation. The order
+       // is unspecified. In general there should be only one file with
+       // a package comment; but it's better to collect extra comments
+       // than drop them on the floor.
+       var doc *CommentGroup
+       var pos token.Position
+       if ndocs > 0 {
+               list := make([]*Comment, ndocs-1) // -1: no separator before first group
+               i := 0
+               for _, f := range pkg.Files {
+                       if f.Doc != nil {
+                               if i > 0 {
+                                       // not the first group - add separator
+                                       list[i] = separator
+                                       i++
+                               }
+                               for _, c := range f.Doc.List {
+                                       list[i] = c
+                                       i++
+                               }
+                               end := lineAfterComment(f.Doc.List[len(f.Doc.List)-1])
+                               if end.Offset > pos.Offset {
+                                       // Keep the maximum end position as
+                                       // position for the package clause.
+                                       pos = end
+                               }
+                       }
+               }
+               doc = &CommentGroup{list}
+       }
+
+       // Collect declarations from all package files.
+       var decls []Decl
+       if ndecls > 0 {
+               decls = make([]Decl, ndecls)
+               funcs := make(map[string]int) // map of global function name -> decls index
+               i := 0                        // current index
+               n := 0                        // number of filtered entries
+               for _, f := range pkg.Files {
+                       for _, d := range f.Decls {
+                               if mode&FilterFuncDuplicates != 0 {
+                                       // A language entity may be declared multiple
+                                       // times in different package files; only at
+                                       // build time declarations must be unique.
+                                       // For now, exclude multiple declarations of
+                                       // functions - keep the one with documentation.
+                                       //
+                                       // TODO(gri): Expand this filtering to other
+                                       //            entities (const, type, vars) if
+                                       //            multiple declarations are common.
+                                       if f, isFun := d.(*FuncDecl); isFun {
+                                               name := f.Name.Name
+                                               if j, exists := funcs[name]; exists {
+                                                       // function declared already
+                                                       if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil {
+                                                               // existing declaration has no documentation;
+                                                               // ignore the existing declaration
+                                                               decls[j] = nil
+                                                       } else {
+                                                               // ignore the new declaration
+                                                               d = nil
+                                                       }
+                                                       n++ // filtered an entry
+                                               } else {
+                                                       funcs[name] = i
+                                               }
+                                       }
+                               }
+                               decls[i] = d
+                               i++
+                       }
+               }
+
+               // Eliminate nil entries from the decls list if entries were
+               // filtered. We do this using a 2nd pass in order to not disturb
+               // the original declaration order in the source (otherwise, this
+               // would also invalidate the monotonically increasing position
+               // info within a single file).
+               if n > 0 {
+                       i = 0
+                       for _, d := range decls {
+                               if d != nil {
+                                       decls[i] = d
+                                       i++
+                               }
+                       }
+                       decls = decls[0:i]
+               }
+       }
+
+       // Collect comments from all package files.
+       var comments []*CommentGroup
+       if mode&FilterUnassociatedComments == 0 {
+               comments = make([]*CommentGroup, ncomments)
+               i := 0
+               for _, f := range pkg.Files {
+                       i += copy(comments[i:], f.Comments)
+               }
+       }
+
+       return &File{doc, pos, NewIdent(pkg.Name), decls, comments}
+}
diff --git a/libgo/go/go/ast/print.go b/libgo/go/go/ast/print.go
new file mode 100644 (file)
index 0000000..d71490d
--- /dev/null
@@ -0,0 +1,217 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains printing suppport for ASTs.
+
+package ast
+
+import (
+       "fmt"
+       "go/token"
+       "io"
+       "os"
+       "reflect"
+)
+
+
+// A FieldFilter may be provided to Fprint to control the output.
+type FieldFilter func(name string, value reflect.Value) bool
+
+
+// NotNilFilter returns true for field values that are not nil;
+// it returns false otherwise.
+func NotNilFilter(_ string, value reflect.Value) bool {
+       v, ok := value.(interface {
+               IsNil() bool
+       })
+       return !ok || !v.IsNil()
+}
+
+
+// Fprint prints the (sub-)tree starting at AST node x to w.
+//
+// A non-nil FieldFilter f may be provided to control the output:
+// struct fields for which f(fieldname, fieldvalue) is true are
+// are printed; all others are filtered from the output.
+//
+func Fprint(w io.Writer, x interface{}, f FieldFilter) (n int, err os.Error) {
+       // setup printer
+       p := printer{
+               output: w,
+               filter: f,
+               ptrmap: make(map[interface{}]int),
+               last:   '\n', // force printing of line number on first line
+       }
+
+       // install error handler
+       defer func() {
+               n = p.written
+               if e := recover(); e != nil {
+                       err = e.(localError).err // re-panics if it's not a localError
+               }
+       }()
+
+       // print x
+       if x == nil {
+               p.printf("nil\n")
+               return
+       }
+       p.print(reflect.NewValue(x))
+       p.printf("\n")
+
+       return
+}
+
+
+// Print prints x to standard output, skipping nil fields.
+// Print(x) is the same as Fprint(os.Stdout, x, NotNilFilter).
+func Print(x interface{}) (int, os.Error) {
+       return Fprint(os.Stdout, x, NotNilFilter)
+}
+
+
+type printer struct {
+       output  io.Writer
+       filter  FieldFilter
+       ptrmap  map[interface{}]int // *reflect.PtrValue -> line number
+       written int                 // number of bytes written to output
+       indent  int                 // current indentation level
+       last    byte                // the last byte processed by Write
+       line    int                 // current line number
+}
+
+
+var indent = []byte(".  ")
+
+func (p *printer) Write(data []byte) (n int, err os.Error) {
+       var m int
+       for i, b := range data {
+               // invariant: data[0:n] has been written
+               if b == '\n' {
+                       m, err = p.output.Write(data[n : i+1])
+                       n += m
+                       if err != nil {
+                               return
+                       }
+                       p.line++
+               } else if p.last == '\n' {
+                       _, err = fmt.Fprintf(p.output, "%6d  ", p.line)
+                       if err != nil {
+                               return
+                       }
+                       for j := p.indent; j > 0; j-- {
+                               _, err = p.output.Write(indent)
+                               if err != nil {
+                                       return
+                               }
+                       }
+               }
+               p.last = b
+       }
+       m, err = p.output.Write(data[n:])
+       n += m
+       return
+}
+
+
+// localError wraps locally caught os.Errors so we can distinguish
+// them from genuine panics which we don't want to return as errors.
+type localError struct {
+       err os.Error
+}
+
+
+// printf is a convenience wrapper that takes care of print errors.
+func (p *printer) printf(format string, args ...interface{}) {
+       n, err := fmt.Fprintf(p, format, args...)
+       p.written += n
+       if err != nil {
+               panic(localError{err})
+       }
+}
+
+
+// Implementation note: Print is written for AST nodes but could be
+// used to print arbitrary data structures; such a version should
+// probably be in a different package.
+
+func (p *printer) print(x reflect.Value) {
+       // Note: This test is only needed because AST nodes
+       //       embed a token.Position, and thus all of them
+       //       understand the String() method (but it only
+       //       applies to the Position field).
+       // TODO: Should reconsider this AST design decision.
+       if pos, ok := x.Interface().(token.Position); ok {
+               p.printf("%s", pos)
+               return
+       }
+
+       if !NotNilFilter("", x) {
+               p.printf("nil")
+               return
+       }
+
+       switch v := x.(type) {
+       case *reflect.InterfaceValue:
+               p.print(v.Elem())
+
+       case *reflect.MapValue:
+               p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
+               p.indent++
+               for _, key := range v.Keys() {
+                       p.print(key)
+                       p.printf(": ")
+                       p.print(v.Elem(key))
+               }
+               p.indent--
+               p.printf("}")
+
+       case *reflect.PtrValue:
+               p.printf("*")
+               // type-checked ASTs may contain cycles - use ptrmap
+               // to keep track of objects that have been printed
+               // already and print the respective line number instead
+               ptr := v.Interface()
+               if line, exists := p.ptrmap[ptr]; exists {
+                       p.printf("(obj @ %d)", line)
+               } else {
+                       p.ptrmap[ptr] = p.line
+                       p.print(v.Elem())
+               }
+
+       case *reflect.SliceValue:
+               if s, ok := v.Interface().([]byte); ok {
+                       p.printf("%#q", s)
+                       return
+               }
+               p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
+               p.indent++
+               for i, n := 0, v.Len(); i < n; i++ {
+                       p.printf("%d: ", i)
+                       p.print(v.Elem(i))
+                       p.printf("\n")
+               }
+               p.indent--
+               p.printf("}")
+
+       case *reflect.StructValue:
+               p.printf("%s {\n", x.Type().String())
+               p.indent++
+               t := v.Type().(*reflect.StructType)
+               for i, n := 0, t.NumField(); i < n; i++ {
+                       name := t.Field(i).Name
+                       value := v.Field(i)
+                       if p.filter == nil || p.filter(name, value) {
+                               p.printf("%s: ", name)
+                               p.print(value)
+                               p.printf("\n")
+                       }
+               }
+               p.indent--
+               p.printf("}")
+
+       default:
+               p.printf("%v", x.Interface())
+       }
+}
diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go
new file mode 100644 (file)
index 0000000..956a208
--- /dev/null
@@ -0,0 +1,242 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements scopes, the objects they contain,
+// and object types.
+
+package ast
+
+// A Scope maintains the set of named language entities declared
+// in the scope and a link to the immediately surrounding (outer)
+// scope.
+//
+type Scope struct {
+       Outer   *Scope
+       Objects []*Object // in declaration order
+       // Implementation note: In some cases (struct fields,
+       // function parameters) we need the source order of
+       // variables. Thus for now, we store scope entries
+       // in a linear list. If scopes become very large
+       // (say, for packages), we may need to change this
+       // to avoid slow lookups.
+}
+
+
+// NewScope creates a new scope nested in the outer scope.
+func NewScope(outer *Scope) *Scope {
+       const n = 4 // initial scope capacity, must be > 0
+       return &Scope{outer, make([]*Object, 0, n)}
+}
+
+
+// Lookup returns the object with the given name if it is
+// found in scope s, otherwise it returns nil. Outer scopes
+// are ignored.
+//
+// Lookup always returns nil if name is "_", even if the scope
+// contains objects with that name.
+//
+func (s *Scope) Lookup(name string) *Object {
+       if name != "_" {
+               for _, obj := range s.Objects {
+                       if obj.Name == name {
+                               return obj
+                       }
+               }
+       }
+       return nil
+}
+
+
+// Insert attempts to insert a named object into the scope s.
+// If the scope does not contain an object with that name yet
+// or if the object is named "_", Insert inserts the object
+// and returns it. Otherwise, Insert leaves the scope unchanged
+// and returns the object found in the scope instead.
+//
+func (s *Scope) Insert(obj *Object) *Object {
+       alt := s.Lookup(obj.Name)
+       if alt == nil {
+               s.append(obj)
+               alt = obj
+       }
+       return alt
+}
+
+
+func (s *Scope) append(obj *Object) {
+       s.Objects = append(s.Objects, obj)
+}
+
+// ----------------------------------------------------------------------------
+// Objects
+
+// An Object describes a language entity such as a package,
+// constant, type, variable, or function (incl. methods).
+//
+type Object struct {
+       Kind Kind
+       Name string // declared name
+       Type *Type
+       Decl interface{} // corresponding Field, XxxSpec or FuncDecl
+       N    int         // value of iota for this declaration
+}
+
+
+// NewObj creates a new object of a given kind and name.
+func NewObj(kind Kind, name string) *Object {
+       return &Object{Kind: kind, Name: name}
+}
+
+
+// Kind describes what an object represents.
+type Kind int
+
+// The list of possible Object kinds.
+const (
+       Bad Kind = iota // for error handling
+       Pkg             // package
+       Con             // constant
+       Typ             // type
+       Var             // variable
+       Fun             // function or method
+)
+
+
+var objKindStrings = [...]string{
+       Bad: "bad",
+       Pkg: "package",
+       Con: "const",
+       Typ: "type",
+       Var: "var",
+       Fun: "func",
+}
+
+
+func (kind Kind) String() string { return objKindStrings[kind] }
+
+
+// IsExported returns whether obj is exported.
+func (obj *Object) IsExported() bool { return IsExported(obj.Name) }
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+// A Type represents a Go type.
+type Type struct {
+       Form     Form
+       Obj      *Object // corresponding type name, or nil
+       Scope    *Scope  // fields and methods, always present
+       N        uint    // basic type id, array length, number of function results, or channel direction
+       Key, Elt *Type   // map key and array, pointer, slice, map or channel element
+       Params   *Scope  // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
+       Expr     Expr    // corresponding AST expression
+}
+
+
+// NewType creates a new type of a given form.
+func NewType(form Form) *Type {
+       return &Type{Form: form, Scope: NewScope(nil)}
+}
+
+
+// Form describes the form of a type.
+type Form int
+
+// The list of possible type forms.
+const (
+       BadType    Form = iota // for error handling
+       Unresolved             // type not fully setup
+       Basic
+       Array
+       Struct
+       Pointer
+       Function
+       Method
+       Interface
+       Slice
+       Map
+       Channel
+       Tuple
+)
+
+
+var formStrings = [...]string{
+       BadType:    "badType",
+       Unresolved: "unresolved",
+       Basic:      "basic",
+       Array:      "array",
+       Struct:     "struct",
+       Pointer:    "pointer",
+       Function:   "function",
+       Method:     "method",
+       Interface:  "interface",
+       Slice:      "slice",
+       Map:        "map",
+       Channel:    "channel",
+       Tuple:      "tuple",
+}
+
+
+func (form Form) String() string { return formStrings[form] }
+
+
+// The list of basic type id's.
+const (
+       Bool = iota
+       Byte
+       Uint
+       Int
+       Float
+       Complex
+       Uintptr
+       String
+
+       Uint8
+       Uint16
+       Uint32
+       Uint64
+
+       Int8
+       Int16
+       Int32
+       Int64
+
+       Float32
+       Float64
+
+       Complex64
+       Complex128
+
+       // TODO(gri) ideal types are missing
+)
+
+
+var BasicTypes = map[uint]string{
+       Bool:    "bool",
+       Byte:    "byte",
+       Uint:    "uint",
+       Int:     "int",
+       Float:   "float",
+       Complex: "complex",
+       Uintptr: "uintptr",
+       String:  "string",
+
+       Uint8:  "uint8",
+       Uint16: "uint16",
+       Uint32: "uint32",
+       Uint64: "uint64",
+
+       Int8:  "int8",
+       Int16: "int16",
+       Int32: "int32",
+       Int64: "int64",
+
+       Float32: "float32",
+       Float64: "float64",
+
+       Complex64:  "complex64",
+       Complex128: "complex128",
+}
diff --git a/libgo/go/go/ast/walk.go b/libgo/go/go/ast/walk.go
new file mode 100644 (file)
index 0000000..296da56
--- /dev/null
@@ -0,0 +1,342 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast
+
+import "fmt"
+
+// A Visitor's Visit method is invoked for each node encountered by Walk.
+// If the result visitor w is not nil, Walk visits each of the children
+// of node with the visitor w, followed by a call of w.Visit(nil).
+type Visitor interface {
+       Visit(node interface{}) (w Visitor)
+}
+
+
+func walkIdent(v Visitor, x *Ident) {
+       if x != nil {
+               Walk(v, x)
+       }
+}
+
+
+func walkCommentGroup(v Visitor, g *CommentGroup) {
+       if g != nil {
+               Walk(v, g)
+       }
+}
+
+
+func walkBlockStmt(v Visitor, b *BlockStmt) {
+       if b != nil {
+               Walk(v, b)
+       }
+}
+
+
+// Walk traverses an AST in depth-first order: If node != nil, it
+// invokes v.Visit(node). If the visitor w returned by v.Visit(node) is
+// not nil, Walk visits each of the children of node with the visitor w,
+// followed by a call of w.Visit(nil).
+//
+// Walk may be called with any of the named ast node types. It also
+// accepts arguments of type []*Field, []*Ident, []Expr, []Stmt and []Decl;
+// the respective children are the slice elements.
+//
+func Walk(v Visitor, node interface{}) {
+       if node == nil {
+               return
+       }
+       if v = v.Visit(node); v == nil {
+               return
+       }
+
+       // walk children
+       // (the order of the cases matches the order
+       // of the corresponding declaration in ast.go)
+       switch n := node.(type) {
+       // Comments and fields
+       case *Comment:
+               // nothing to do
+
+       case *CommentGroup:
+               for _, c := range n.List {
+                       Walk(v, c)
+               }
+
+       case *Field:
+               walkCommentGroup(v, n.Doc)
+               Walk(v, n.Names)
+               Walk(v, n.Type)
+               Walk(v, n.Tag)
+               walkCommentGroup(v, n.Comment)
+
+       case *FieldList:
+               for _, f := range n.List {
+                       Walk(v, f)
+               }
+
+       // Expressions
+       case *BadExpr, *Ident, *Ellipsis, *BasicLit:
+               // nothing to do
+
+       case *FuncLit:
+               if n != nil {
+                       Walk(v, n.Type)
+               }
+               walkBlockStmt(v, n.Body)
+
+       case *CompositeLit:
+               Walk(v, n.Type)
+               Walk(v, n.Elts)
+
+       case *ParenExpr:
+               Walk(v, n.X)
+
+       case *SelectorExpr:
+               Walk(v, n.X)
+               walkIdent(v, n.Sel)
+
+       case *IndexExpr:
+               Walk(v, n.X)
+               Walk(v, n.Index)
+
+       case *SliceExpr:
+               Walk(v, n.X)
+               Walk(v, n.Index)
+               Walk(v, n.End)
+
+       case *TypeAssertExpr:
+               Walk(v, n.X)
+               Walk(v, n.Type)
+
+       case *CallExpr:
+               Walk(v, n.Fun)
+               Walk(v, n.Args)
+
+       case *StarExpr:
+               Walk(v, n.X)
+
+       case *UnaryExpr:
+               Walk(v, n.X)
+
+       case *BinaryExpr:
+               Walk(v, n.X)
+               Walk(v, n.Y)
+
+       case *KeyValueExpr:
+               Walk(v, n.Key)
+               Walk(v, n.Value)
+
+       // Types
+       case *ArrayType:
+               Walk(v, n.Len)
+               Walk(v, n.Elt)
+
+       case *StructType:
+               Walk(v, n.Fields)
+
+       case *FuncType:
+               Walk(v, n.Params)
+               if n.Results != nil {
+                       Walk(v, n.Results)
+               }
+
+       case *InterfaceType:
+               Walk(v, n.Methods)
+
+       case *MapType:
+               Walk(v, n.Key)
+               Walk(v, n.Value)
+
+       case *ChanType:
+               Walk(v, n.Value)
+
+       // Statements
+       case *BadStmt:
+               // nothing to do
+
+       case *DeclStmt:
+               Walk(v, n.Decl)
+
+       case *EmptyStmt:
+               // nothing to do
+
+       case *LabeledStmt:
+               walkIdent(v, n.Label)
+               Walk(v, n.Stmt)
+
+       case *ExprStmt:
+               Walk(v, n.X)
+
+       case *IncDecStmt:
+               Walk(v, n.X)
+
+       case *AssignStmt:
+               Walk(v, n.Lhs)
+               Walk(v, n.Rhs)
+
+       case *GoStmt:
+               if n.Call != nil {
+                       Walk(v, n.Call)
+               }
+
+       case *DeferStmt:
+               if n.Call != nil {
+                       Walk(v, n.Call)
+               }
+
+       case *ReturnStmt:
+               Walk(v, n.Results)
+
+       case *BranchStmt:
+               walkIdent(v, n.Label)
+
+       case *BlockStmt:
+               Walk(v, n.List)
+
+       case *IfStmt:
+               Walk(v, n.Init)
+               Walk(v, n.Cond)
+               walkBlockStmt(v, n.Body)
+               Walk(v, n.Else)
+
+       case *CaseClause:
+               Walk(v, n.Values)
+               Walk(v, n.Body)
+
+       case *SwitchStmt:
+               Walk(v, n.Init)
+               Walk(v, n.Tag)
+               walkBlockStmt(v, n.Body)
+
+       case *TypeCaseClause:
+               Walk(v, n.Types)
+               Walk(v, n.Body)
+
+       case *TypeSwitchStmt:
+               Walk(v, n.Init)
+               Walk(v, n.Assign)
+               walkBlockStmt(v, n.Body)
+
+       case *CommClause:
+               Walk(v, n.Lhs)
+               Walk(v, n.Rhs)
+               Walk(v, n.Body)
+
+       case *SelectStmt:
+               walkBlockStmt(v, n.Body)
+
+       case *ForStmt:
+               Walk(v, n.Init)
+               Walk(v, n.Cond)
+               Walk(v, n.Post)
+               walkBlockStmt(v, n.Body)
+
+       case *RangeStmt:
+               Walk(v, n.Key)
+               Walk(v, n.Value)
+               Walk(v, n.X)
+               walkBlockStmt(v, n.Body)
+
+       // Declarations
+       case *ImportSpec:
+               walkCommentGroup(v, n.Doc)
+               walkIdent(v, n.Name)
+               Walk(v, n.Path)
+               walkCommentGroup(v, n.Comment)
+
+       case *ValueSpec:
+               walkCommentGroup(v, n.Doc)
+               Walk(v, n.Names)
+               Walk(v, n.Type)
+               Walk(v, n.Values)
+               walkCommentGroup(v, n.Comment)
+
+       case *TypeSpec:
+               walkCommentGroup(v, n.Doc)
+               walkIdent(v, n.Name)
+               Walk(v, n.Type)
+               walkCommentGroup(v, n.Comment)
+
+       case *BadDecl:
+               // nothing to do
+
+       case *GenDecl:
+               walkCommentGroup(v, n.Doc)
+               for _, s := range n.Specs {
+                       Walk(v, s)
+               }
+
+       case *FuncDecl:
+               walkCommentGroup(v, n.Doc)
+               if n.Recv != nil {
+                       Walk(v, n.Recv)
+               }
+               walkIdent(v, n.Name)
+               if n.Type != nil {
+                       Walk(v, n.Type)
+               }
+               walkBlockStmt(v, n.Body)
+
+       // Files and packages
+       case *File:
+               walkCommentGroup(v, n.Doc)
+               walkIdent(v, n.Name)
+               Walk(v, n.Decls)
+               for _, g := range n.Comments {
+                       Walk(v, g)
+               }
+
+       case *Package:
+               for _, f := range n.Files {
+                       Walk(v, f)
+               }
+
+       case []*Ident:
+               for _, x := range n {
+                       Walk(v, x)
+               }
+
+       case []Expr:
+               for _, x := range n {
+                       Walk(v, x)
+               }
+
+       case []Stmt:
+               for _, x := range n {
+                       Walk(v, x)
+               }
+
+       case []Decl:
+               for _, x := range n {
+                       Walk(v, x)
+               }
+
+       default:
+               fmt.Printf("ast.Walk: unexpected type %T", n)
+               panic("ast.Walk")
+       }
+
+       v.Visit(nil)
+}
+
+
+type inspector func(node interface{}) bool
+
+func (f inspector) Visit(node interface{}) Visitor {
+       if node != nil && f(node) {
+               return f
+       }
+       return nil
+}
+
+
+// Inspect traverses an AST in depth-first order: If node != nil, it
+// invokes f(node). If f returns true, inspect invokes f for all the
+// non-nil children of node, recursively.
+//
+func Inspect(ast interface{}, f func(node interface{}) bool) {
+       Walk(inspector(f), ast)
+}
diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go
new file mode 100644 (file)
index 0000000..9ff0bd5
--- /dev/null
@@ -0,0 +1,357 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Godoc comment extraction and comment -> HTML formatting.
+
+package doc
+
+import (
+       "go/ast"
+       "io"
+       "regexp"
+       "strings"
+       "template" // for htmlEscape
+)
+
+
+func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' }
+
+
+func stripTrailingWhitespace(s string) string {
+       i := len(s)
+       for i > 0 && isWhitespace(s[i-1]) {
+               i--
+       }
+       return s[0:i]
+}
+
+
+// CommentText returns the text of comment,
+// with the comment markers - //, /*, and */ - removed.
+func CommentText(comment *ast.CommentGroup) string {
+       if comment == nil {
+               return ""
+       }
+       comments := make([]string, len(comment.List))
+       for i, c := range comment.List {
+               comments[i] = string(c.Text)
+       }
+
+       lines := make([]string, 0, 10) // most comments are less than 10 lines
+       for _, c := range comments {
+               // Remove comment markers.
+               // The parser has given us exactly the comment text.
+               switch c[1] {
+               case '/':
+                       //-style comment
+                       c = c[2:]
+                       // Remove leading space after //, if there is one.
+                       // TODO(gri) This appears to be necessary in isolated
+                       //           cases (bignum.RatFromString) - why?
+                       if len(c) > 0 && c[0] == ' ' {
+                               c = c[1:]
+                       }
+               case '*':
+                       /*-style comment */
+                       c = c[2 : len(c)-2]
+               }
+
+               // Split on newlines.
+               cl := strings.Split(c, "\n", -1)
+
+               // Walk lines, stripping trailing white space and adding to list.
+               for _, l := range cl {
+                       lines = append(lines, stripTrailingWhitespace(l))
+               }
+       }
+
+       // Remove leading blank lines; convert runs of
+       // interior blank lines to a single blank line.
+       n := 0
+       for _, line := range lines {
+               if line != "" || n > 0 && lines[n-1] != "" {
+                       lines[n] = line
+                       n++
+               }
+       }
+       lines = lines[0:n]
+
+       // Add final "" entry to get trailing newline from Join.
+       if n > 0 && lines[n-1] != "" {
+               lines = append(lines, "")
+       }
+
+       return strings.Join(lines, "\n")
+}
+
+
+// Split bytes into lines.
+func split(text []byte) [][]byte {
+       // count lines
+       n := 0
+       last := 0
+       for i, c := range text {
+               if c == '\n' {
+                       last = i + 1
+                       n++
+               }
+       }
+       if last < len(text) {
+               n++
+       }
+
+       // split
+       out := make([][]byte, n)
+       last = 0
+       n = 0
+       for i, c := range text {
+               if c == '\n' {
+                       out[n] = text[last : i+1]
+                       last = i + 1
+                       n++
+               }
+       }
+       if last < len(text) {
+               out[n] = text[last:]
+       }
+
+       return out
+}
+
+
+var (
+       ldquo = []byte("&ldquo;")
+       rdquo = []byte("&rdquo;")
+)
+
+// Escape comment text for HTML. If nice is set,
+// also turn `` into &ldquo; and '' into &rdquo;.
+func commentEscape(w io.Writer, s []byte, nice bool) {
+       last := 0
+       if nice {
+               for i := 0; i < len(s)-1; i++ {
+                       ch := s[i]
+                       if ch == s[i+1] && (ch == '`' || ch == '\'') {
+                               template.HTMLEscape(w, s[last:i])
+                               last = i + 2
+                               switch ch {
+                               case '`':
+                                       w.Write(ldquo)
+                               case '\'':
+                                       w.Write(rdquo)
+                               }
+                               i++ // loop will add one more
+                       }
+               }
+       }
+       template.HTMLEscape(w, s[last:])
+}
+
+
+const (
+       // Regexp for Go identifiers
+       identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this
+
+       // Regexp for URLs
+       protocol = `(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero):`
+       hostPart = `[a-zA-Z0-9_@\-]+`
+       filePart = `[a-zA-Z0-9_?%#~&/\-+=]+`
+       urlRx    = protocol + `//` + // http://
+               hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
+               filePart + `([:.,]` + filePart + `)*`
+)
+
+var matchRx = regexp.MustCompile(`(` + identRx + `)|(` + urlRx + `)`)
+
+var (
+       html_a      = []byte(`<a href="`)
+       html_aq     = []byte(`">`)
+       html_enda   = []byte("</a>")
+       html_i      = []byte("<i>")
+       html_endi   = []byte("</i>")
+       html_p      = []byte("<p>\n")
+       html_endp   = []byte("</p>\n")
+       html_pre    = []byte("<pre>")
+       html_endpre = []byte("</pre>\n")
+)
+
+
+// Emphasize and escape a line of text for HTML. URLs are converted into links;
+// if the URL also appears in the words map, the link is taken from the map (if
+// the corresponding map value is the empty string, the URL is not converted
+// into a link). Go identifiers that appear in the words map are italicized; if
+// the corresponding map value is not the empty string, it is considered a URL
+// and the word is converted into a link. If nice is set, the remaining text's
+// appearance is improved where it makes sense (e.g., `` is turned into &ldquo;
+// and '' into &rdquo;).
+func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
+       for {
+               m := matchRx.FindSubmatchIndex(line)
+               if m == nil {
+                       break
+               }
+               // m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is identRx)
+
+               // write text before match
+               commentEscape(w, line[0:m[0]], nice)
+
+               // analyze match
+               match := line[m[0]:m[1]]
+               url := ""
+               italics := false
+               if words != nil {
+                       url, italics = words[string(match)]
+               }
+               if m[2] < 0 {
+                       // didn't match against first parenthesized sub-regexp; must be match against urlRx
+                       if !italics {
+                               // no alternative URL in words list, use match instead
+                               url = string(match)
+                       }
+                       italics = false // don't italicize URLs
+               }
+
+               // write match
+               if len(url) > 0 {
+                       w.Write(html_a)
+                       template.HTMLEscape(w, []byte(url))
+                       w.Write(html_aq)
+               }
+               if italics {
+                       w.Write(html_i)
+               }
+               commentEscape(w, match, nice)
+               if italics {
+                       w.Write(html_endi)
+               }
+               if len(url) > 0 {
+                       w.Write(html_enda)
+               }
+
+               // advance
+               line = line[m[1]:]
+       }
+       commentEscape(w, line, nice)
+}
+
+
+func indentLen(s []byte) int {
+       i := 0
+       for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+               i++
+       }
+       return i
+}
+
+
+func isBlank(s []byte) bool { return len(s) == 0 || (len(s) == 1 && s[0] == '\n') }
+
+
+func commonPrefix(a, b []byte) []byte {
+       i := 0
+       for i < len(a) && i < len(b) && a[i] == b[i] {
+               i++
+       }
+       return a[0:i]
+}
+
+
+func unindent(block [][]byte) {
+       if len(block) == 0 {
+               return
+       }
+
+       // compute maximum common white prefix
+       prefix := block[0][0:indentLen(block[0])]
+       for _, line := range block {
+               if !isBlank(line) {
+                       prefix = commonPrefix(prefix, line[0:indentLen(line)])
+               }
+       }
+       n := len(prefix)
+
+       // remove
+       for i, line := range block {
+               if !isBlank(line) {
+                       block[i] = line[n:]
+               }
+       }
+}
+
+
+// Convert comment text to formatted HTML.
+// The comment was prepared by DocReader,
+// so it is known not to have leading, trailing blank lines
+// nor to have trailing spaces at the end of lines.
+// The comment markers have already been removed.
+//
+// Turn each run of multiple \n into </p><p>
+// Turn each run of indented lines into a <pre> block without indent.
+//
+// URLs in the comment text are converted into links; if the URL also appears
+// in the words map, the link is taken from the map (if the corresponding map
+// value is the empty string, the URL is not converted into a link).
+//
+// Go identifiers that appear in the words map are italicized; if the corresponding
+// map value is not the empty string, it is considered a URL and the word is converted
+// into a link.
+func ToHTML(w io.Writer, s []byte, words map[string]string) {
+       inpara := false
+
+       close := func() {
+               if inpara {
+                       w.Write(html_endp)
+                       inpara = false
+               }
+       }
+       open := func() {
+               if !inpara {
+                       w.Write(html_p)
+                       inpara = true
+               }
+       }
+
+       lines := split(s)
+       unindent(lines)
+       for i := 0; i < len(lines); {
+               line := lines[i]
+               if isBlank(line) {
+                       // close paragraph
+                       close()
+                       i++
+                       continue
+               }
+               if indentLen(line) > 0 {
+                       // close paragraph
+                       close()
+
+                       // count indented or blank lines
+                       j := i + 1
+                       for j < len(lines) && (isBlank(lines[j]) || indentLen(lines[j]) > 0) {
+                               j++
+                       }
+                       // but not trailing blank lines
+                       for j > i && isBlank(lines[j-1]) {
+                               j--
+                       }
+                       block := lines[i:j]
+                       i = j
+
+                       unindent(block)
+
+                       // put those lines in a pre block
+                       w.Write(html_pre)
+                       for _, line := range block {
+                               emphasize(w, line, nil, false) // no nice text formatting
+                       }
+                       w.Write(html_endpre)
+                       continue
+               }
+               // open paragraph
+               open()
+               emphasize(w, lines[i], words, true) // nice text formatting
+               i++
+       }
+       close()
+}
diff --git a/libgo/go/go/doc/doc.go b/libgo/go/go/doc/doc.go
new file mode 100644 (file)
index 0000000..b4322d5
--- /dev/null
@@ -0,0 +1,651 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The doc package extracts source code documentation from a Go AST.
+package doc
+
+import (
+       "go/ast"
+       "go/token"
+       "regexp"
+       "sort"
+)
+
+
+// ----------------------------------------------------------------------------
+
+type typeDoc struct {
+       // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
+       // if the type declaration hasn't been seen yet, decl is nil
+       decl *ast.GenDecl
+       // values, factory functions, and methods associated with the type
+       values    []*ast.GenDecl // consts and vars
+       factories map[string]*ast.FuncDecl
+       methods   map[string]*ast.FuncDecl
+}
+
+
+// docReader accumulates documentation for a single package.
+// It modifies the AST: Comments (declaration documentation)
+// that have been collected by the DocReader are set to nil
+// in the respective AST nodes so that they are not printed
+// twice (once when printing the documentation and once when
+// printing the corresponding AST node).
+//
+type docReader struct {
+       doc     *ast.CommentGroup // package documentation, if any
+       pkgName string
+       values  []*ast.GenDecl // consts and vars
+       types   map[string]*typeDoc
+       funcs   map[string]*ast.FuncDecl
+       bugs    []*ast.CommentGroup
+}
+
+
+func (doc *docReader) init(pkgName string) {
+       doc.pkgName = pkgName
+       doc.types = make(map[string]*typeDoc)
+       doc.funcs = make(map[string]*ast.FuncDecl)
+}
+
+
+func (doc *docReader) addDoc(comments *ast.CommentGroup) {
+       if doc.doc == nil {
+               // common case: just one package comment
+               doc.doc = comments
+               return
+       }
+
+       // More than one package comment: Usually there will be only
+       // one file with a package comment, but it's better to collect
+       // all comments than drop them on the floor.
+       // (This code isn't particularly clever - no amortized doubling is
+       // used - but this situation occurs rarely and is not time-critical.)
+       n1 := len(doc.doc.List)
+       n2 := len(comments.List)
+       list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
+       copy(list, doc.doc.List)
+       list[n1] = &ast.Comment{token.Position{}, []byte("//")} // separator line
+       copy(list[n1+1:], comments.List)
+       doc.doc = &ast.CommentGroup{list}
+}
+
+
+func (doc *docReader) addType(decl *ast.GenDecl) {
+       spec := decl.Specs[0].(*ast.TypeSpec)
+       typ := doc.lookupTypeDoc(spec.Name.Name)
+       // typ should always be != nil since declared types
+       // are always named - be conservative and check
+       if typ != nil {
+               // a type should be added at most once, so typ.decl
+               // should be nil - if it isn't, simply overwrite it
+               typ.decl = decl
+       }
+}
+
+
+func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
+       if name == "" {
+               return nil // no type docs for anonymous types
+       }
+       if tdoc, found := doc.types[name]; found {
+               return tdoc
+       }
+       // type wasn't found - add one without declaration
+       tdoc := &typeDoc{nil, nil, make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
+       doc.types[name] = tdoc
+       return tdoc
+}
+
+
+func baseTypeName(typ ast.Expr) string {
+       switch t := typ.(type) {
+       case *ast.Ident:
+               // if the type is not exported, the effect to
+               // a client is as if there were no type name
+               if t.IsExported() {
+                       return string(t.Name)
+               }
+       case *ast.StarExpr:
+               return baseTypeName(t.X)
+       }
+       return ""
+}
+
+
+func (doc *docReader) addValue(decl *ast.GenDecl) {
+       // determine if decl should be associated with a type
+       // Heuristic: For each typed entry, determine the type name, if any.
+       //            If there is exactly one type name that is sufficiently
+       //            frequent, associate the decl with the respective type.
+       domName := ""
+       domFreq := 0
+       prev := ""
+       for _, s := range decl.Specs {
+               if v, ok := s.(*ast.ValueSpec); ok {
+                       name := ""
+                       switch {
+                       case v.Type != nil:
+                               // a type is present; determine it's name
+                               name = baseTypeName(v.Type)
+                       case decl.Tok == token.CONST:
+                               // no type is present but we have a constant declaration;
+                               // use the previous type name (w/o more type information
+                               // we cannot handle the case of unnamed variables with
+                               // initializer expressions except for some trivial cases)
+                               name = prev
+                       }
+                       if name != "" {
+                               // entry has a named type
+                               if domName != "" && domName != name {
+                                       // more than one type name - do not associate
+                                       // with any type
+                                       domName = ""
+                                       break
+                               }
+                               domName = name
+                               domFreq++
+                       }
+                       prev = name
+               }
+       }
+
+       // determine values list
+       const threshold = 0.75
+       values := &doc.values
+       if domName != "" && domFreq >= int(float(len(decl.Specs))*threshold) {
+               // typed entries are sufficiently frequent
+               typ := doc.lookupTypeDoc(domName)
+               if typ != nil {
+                       values = &typ.values // associate with that type
+               }
+       }
+
+       *values = append(*values, decl)
+}
+
+
+// Helper function to set the table entry for function f. Makes sure that
+// at least one f with associated documentation is stored in table, if there
+// are multiple f's with the same name.
+func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
+       name := f.Name.Name
+       if g, exists := table[name]; exists && g.Doc != nil {
+               // a function with the same name has already been registered;
+               // since it has documentation, assume f is simply another
+               // implementation and ignore it
+               // TODO(gri) consider collecting all functions, or at least
+               //           all comments
+               return
+       }
+       // function doesn't exist or has no documentation; use f
+       table[name] = f
+}
+
+
+func (doc *docReader) addFunc(fun *ast.FuncDecl) {
+       name := fun.Name.Name
+
+       // determine if it should be associated with a type
+       if fun.Recv != nil {
+               // method
+               typ := doc.lookupTypeDoc(baseTypeName(fun.Recv.List[0].Type))
+               if typ != nil {
+                       // exported receiver type
+                       setFunc(typ.methods, fun)
+               }
+               // otherwise don't show the method
+               // TODO(gri): There may be exported methods of non-exported types
+               // that can be called because of exported values (consts, vars, or
+               // function results) of that type. Could determine if that is the
+               // case and then show those methods in an appropriate section.
+               return
+       }
+
+       // perhaps a factory function
+       // determine result type, if any
+       if fun.Type.Results.NumFields() >= 1 {
+               res := fun.Type.Results.List[0]
+               if len(res.Names) <= 1 {
+                       // exactly one (named or anonymous) result associated
+                       // with the first type in result signature (there may
+                       // be more than one result)
+                       tname := baseTypeName(res.Type)
+                       typ := doc.lookupTypeDoc(tname)
+                       if typ != nil {
+                               // named and exported result type
+
+                               // Work-around for failure of heuristic: In package os
+                               // too many functions are considered factory functions
+                               // for the Error type. Eliminate manually for now as
+                               // this appears to be the only important case in the
+                               // current library where the heuristic fails.
+                               if doc.pkgName == "os" && tname == "Error" &&
+                                       name != "NewError" && name != "NewSyscallError" {
+                                       // not a factory function for os.Error
+                                       setFunc(doc.funcs, fun) // treat as ordinary function
+                                       return
+                               }
+
+                               setFunc(typ.factories, fun)
+                               return
+                       }
+               }
+       }
+
+       // ordinary function
+       setFunc(doc.funcs, fun)
+}
+
+
+func (doc *docReader) addDecl(decl ast.Decl) {
+       switch d := decl.(type) {
+       case *ast.GenDecl:
+               if len(d.Specs) > 0 {
+                       switch d.Tok {
+                       case token.CONST, token.VAR:
+                               // constants and variables are always handled as a group
+                               doc.addValue(d)
+                       case token.TYPE:
+                               // types are handled individually
+                               var noPos token.Position
+                               for _, spec := range d.Specs {
+                                       // make a (fake) GenDecl node for this TypeSpec
+                                       // (we need to do this here - as opposed to just
+                                       // for printing - so we don't lose the GenDecl
+                                       // documentation)
+                                       //
+                                       // TODO(gri): Consider just collecting the TypeSpec
+                                       // node (and copy in the GenDecl.doc if there is no
+                                       // doc in the TypeSpec - this is currently done in
+                                       // makeTypeDocs below). Simpler data structures, but
+                                       // would lose GenDecl documentation if the TypeSpec
+                                       // has documentation as well.
+                                       doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, noPos, []ast.Spec{spec}, noPos})
+                                       // A new GenDecl node is created, no need to nil out d.Doc.
+                               }
+                       }
+               }
+       case *ast.FuncDecl:
+               doc.addFunc(d)
+       }
+}
+
+
+func copyCommentList(list []*ast.Comment) []*ast.Comment {
+       return append([]*ast.Comment(nil), list...)
+}
+
+var (
+       bug_markers = regexp.MustCompile("^/[/*][ \t]*BUG\\(.*\\):[ \t]*") // BUG(uid):
+       bug_content = regexp.MustCompile("[^ \n\r\t]+")                    // at least one non-whitespace char
+)
+
+
+// addFile adds the AST for a source file to the docReader.
+// Adding the same AST multiple times is a no-op.
+//
+func (doc *docReader) addFile(src *ast.File) {
+       // add package documentation
+       if src.Doc != nil {
+               doc.addDoc(src.Doc)
+               src.Doc = nil // doc consumed - remove from ast.File node
+       }
+
+       // add all declarations
+       for _, decl := range src.Decls {
+               doc.addDecl(decl)
+       }
+
+       // collect BUG(...) comments
+       for _, c := range src.Comments {
+               text := c.List[0].Text
+               if m := bug_markers.FindIndex(text); m != nil {
+                       // found a BUG comment; maybe empty
+                       if btxt := text[m[1]:]; bug_content.Match(btxt) {
+                               // non-empty BUG comment; collect comment without BUG prefix
+                               list := copyCommentList(c.List)
+                               list[0].Text = text[m[1]:]
+                               doc.bugs = append(doc.bugs, &ast.CommentGroup{list})
+                       }
+               }
+       }
+       src.Comments = nil // consumed unassociated comments - remove from ast.File node
+}
+
+
+func NewFileDoc(file *ast.File) *PackageDoc {
+       var r docReader
+       r.init(file.Name.Name)
+       r.addFile(file)
+       return r.newDoc("", nil)
+}
+
+
+func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
+       var r docReader
+       r.init(pkg.Name)
+       filenames := make([]string, len(pkg.Files))
+       i := 0
+       for filename, f := range pkg.Files {
+               r.addFile(f)
+               filenames[i] = filename
+               i++
+       }
+       return r.newDoc(importpath, filenames)
+}
+
+
+// ----------------------------------------------------------------------------
+// Conversion to external representation
+
+// ValueDoc is the documentation for a group of declared
+// values, either vars or consts.
+//
+type ValueDoc struct {
+       Doc   string
+       Decl  *ast.GenDecl
+       order int
+}
+
+type sortValueDoc []*ValueDoc
+
+func (p sortValueDoc) Len() int      { return len(p) }
+func (p sortValueDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+
+func declName(d *ast.GenDecl) string {
+       if len(d.Specs) != 1 {
+               return ""
+       }
+
+       switch v := d.Specs[0].(type) {
+       case *ast.ValueSpec:
+               return v.Names[0].Name
+       case *ast.TypeSpec:
+               return v.Name.Name
+       }
+
+       return ""
+}
+
+
+func (p sortValueDoc) Less(i, j int) bool {
+       // sort by name
+       // pull blocks (name = "") up to top
+       // in original order
+       if ni, nj := declName(p[i].Decl), declName(p[j].Decl); ni != nj {
+               return ni < nj
+       }
+       return p[i].order < p[j].order
+}
+
+
+func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
+       d := make([]*ValueDoc, len(list)) // big enough in any case
+       n := 0
+       for i, decl := range list {
+               if decl.Tok == tok {
+                       d[n] = &ValueDoc{CommentText(decl.Doc), decl, i}
+                       n++
+                       decl.Doc = nil // doc consumed - removed from AST
+               }
+       }
+       d = d[0:n]
+       sort.Sort(sortValueDoc(d))
+       return d
+}
+
+
+// FuncDoc is the documentation for a func declaration,
+// either a top-level function or a method function.
+//
+type FuncDoc struct {
+       Doc  string
+       Recv ast.Expr // TODO(rsc): Would like string here
+       Name string
+       Decl *ast.FuncDecl
+}
+
+type sortFuncDoc []*FuncDoc
+
+func (p sortFuncDoc) Len() int           { return len(p) }
+func (p sortFuncDoc) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+func (p sortFuncDoc) Less(i, j int) bool { return p[i].Name < p[j].Name }
+
+
+func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
+       d := make([]*FuncDoc, len(m))
+       i := 0
+       for _, f := range m {
+               doc := new(FuncDoc)
+               doc.Doc = CommentText(f.Doc)
+               f.Doc = nil // doc consumed - remove from ast.FuncDecl node
+               if f.Recv != nil {
+                       doc.Recv = f.Recv.List[0].Type
+               }
+               doc.Name = f.Name.Name
+               doc.Decl = f
+               d[i] = doc
+               i++
+       }
+       sort.Sort(sortFuncDoc(d))
+       return d
+}
+
+
+// TypeDoc is the documentation for a declared type.
+// Consts and Vars are sorted lists of constants and variables of (mostly) that type.
+// Factories is a sorted list of factory functions that return that type.
+// Methods is a sorted list of method functions on that type.
+type TypeDoc struct {
+       Doc       string
+       Type      *ast.TypeSpec
+       Consts    []*ValueDoc
+       Vars      []*ValueDoc
+       Factories []*FuncDoc
+       Methods   []*FuncDoc
+       Decl      *ast.GenDecl
+       order     int
+}
+
+type sortTypeDoc []*TypeDoc
+
+func (p sortTypeDoc) Len() int      { return len(p) }
+func (p sortTypeDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p sortTypeDoc) Less(i, j int) bool {
+       // sort by name
+       // pull blocks (name = "") up to top
+       // in original order
+       if ni, nj := p[i].Type.Name.Name, p[j].Type.Name.Name; ni != nj {
+               return ni < nj
+       }
+       return p[i].order < p[j].order
+}
+
+
+// NOTE(rsc): This would appear not to be correct for type ( )
+// blocks, but the doc extractor above has split them into
+// individual declarations.
+func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
+       d := make([]*TypeDoc, len(m))
+       i := 0
+       for _, old := range m {
+               // all typeDocs should have a declaration associated with
+               // them after processing an entire package - be conservative
+               // and check
+               if decl := old.decl; decl != nil {
+                       typespec := decl.Specs[0].(*ast.TypeSpec)
+                       t := new(TypeDoc)
+                       doc := typespec.Doc
+                       typespec.Doc = nil // doc consumed - remove from ast.TypeSpec node
+                       if doc == nil {
+                               // no doc associated with the spec, use the declaration doc, if any
+                               doc = decl.Doc
+                       }
+                       decl.Doc = nil // doc consumed - remove from ast.Decl node
+                       t.Doc = CommentText(doc)
+                       t.Type = typespec
+                       t.Consts = makeValueDocs(old.values, token.CONST)
+                       t.Vars = makeValueDocs(old.values, token.VAR)
+                       t.Factories = makeFuncDocs(old.factories)
+                       t.Methods = makeFuncDocs(old.methods)
+                       t.Decl = old.decl
+                       t.order = i
+                       d[i] = t
+                       i++
+               } else {
+                       // no corresponding type declaration found - move any associated
+                       // values, factory functions, and methods back to the top-level
+                       // so that they are not lost (this should only happen if a package
+                       // file containing the explicit type declaration is missing or if
+                       // an unqualified type name was used after a "." import)
+                       // 1) move values
+                       doc.values = append(doc.values, old.values...)
+                       // 2) move factory functions
+                       for name, f := range old.factories {
+                               doc.funcs[name] = f
+                       }
+                       // 3) move methods
+                       for name, f := range old.methods {
+                               // don't overwrite functions with the same name
+                               if _, found := doc.funcs[name]; !found {
+                                       doc.funcs[name] = f
+                               }
+                       }
+               }
+       }
+       d = d[0:i] // some types may have been ignored
+       sort.Sort(sortTypeDoc(d))
+       return d
+}
+
+
+func makeBugDocs(list []*ast.CommentGroup) []string {
+       d := make([]string, len(list))
+       for i, g := range list {
+               d[i] = CommentText(g)
+       }
+       return d
+}
+
+
+// PackageDoc is the documentation for an entire package.
+//
+type PackageDoc struct {
+       PackageName string
+       ImportPath  string
+       Filenames   []string
+       Doc         string
+       Consts      []*ValueDoc
+       Types       []*TypeDoc
+       Vars        []*ValueDoc
+       Funcs       []*FuncDoc
+       Bugs        []string
+}
+
+
+// newDoc returns the accumulated documentation for the package.
+//
+func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc {
+       p := new(PackageDoc)
+       p.PackageName = doc.pkgName
+       p.ImportPath = importpath
+       sort.SortStrings(filenames)
+       p.Filenames = filenames
+       p.Doc = CommentText(doc.doc)
+       // makeTypeDocs may extend the list of doc.values and
+       // doc.funcs and thus must be called before any other
+       // function consuming those lists
+       p.Types = doc.makeTypeDocs(doc.types)
+       p.Consts = makeValueDocs(doc.values, token.CONST)
+       p.Vars = makeValueDocs(doc.values, token.VAR)
+       p.Funcs = makeFuncDocs(doc.funcs)
+       p.Bugs = makeBugDocs(doc.bugs)
+       return p
+}
+
+
+// ----------------------------------------------------------------------------
+// Filtering by name
+
+type Filter func(string) bool
+
+
+func matchDecl(d *ast.GenDecl, f Filter) bool {
+       for _, d := range d.Specs {
+               switch v := d.(type) {
+               case *ast.ValueSpec:
+                       for _, name := range v.Names {
+                               if f(name.Name) {
+                                       return true
+                               }
+                       }
+               case *ast.TypeSpec:
+                       if f(v.Name.Name) {
+                               return true
+                       }
+               }
+       }
+       return false
+}
+
+
+func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
+       w := 0
+       for _, vd := range a {
+               if matchDecl(vd.Decl, f) {
+                       a[w] = vd
+                       w++
+               }
+       }
+       return a[0:w]
+}
+
+
+func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
+       w := 0
+       for _, fd := range a {
+               if f(fd.Name) {
+                       a[w] = fd
+                       w++
+               }
+       }
+       return a[0:w]
+}
+
+
+func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
+       w := 0
+       for _, td := range a {
+               n := 0 // number of matches
+               if matchDecl(td.Decl, f) {
+                       n = 1
+               } else {
+                       // type name doesn't match, but we may have matching consts, vars, factories or methods
+                       td.Consts = filterValueDocs(td.Consts, f)
+                       td.Vars = filterValueDocs(td.Vars, f)
+                       td.Factories = filterFuncDocs(td.Factories, f)
+                       td.Methods = filterFuncDocs(td.Methods, f)
+                       n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
+               }
+               if n > 0 {
+                       a[w] = td
+                       w++
+               }
+       }
+       return a[0:w]
+}
+
+
+// Filter eliminates documentation for names that don't pass through the filter f.
+// TODO: Recognize "Type.Method" as a name.
+//
+func (p *PackageDoc) Filter(f Filter) {
+       p.Consts = filterValueDocs(p.Consts, f)
+       p.Vars = filterValueDocs(p.Vars, f)
+       p.Types = filterTypeDocs(p.Types, f)
+       p.Funcs = filterFuncDocs(p.Funcs, f)
+       p.Doc = "" // don't show top-level package doc
+}
diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go
new file mode 100644 (file)
index 0000000..e451a4f
--- /dev/null
@@ -0,0 +1,204 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the exported entry points for invoking the parser.
+
+package parser
+
+import (
+       "bytes"
+       "go/ast"
+       "go/scanner"
+       "go/token"
+       "io"
+       "io/ioutil"
+       "os"
+       pathutil "path"
+)
+
+
+// If src != nil, readSource converts src to a []byte if possible;
+// otherwise it returns an error. If src == nil, readSource returns
+// the result of reading the file specified by filename.
+//
+func readSource(filename string, src interface{}) ([]byte, os.Error) {
+       if src != nil {
+               switch s := src.(type) {
+               case string:
+                       return []byte(s), nil
+               case []byte:
+                       return s, nil
+               case *bytes.Buffer:
+                       // is io.Reader, but src is already available in []byte form
+                       if s != nil {
+                               return s.Bytes(), nil
+                       }
+               case io.Reader:
+                       var buf bytes.Buffer
+                       _, err := io.Copy(&buf, s)
+                       if err != nil {
+                               return nil, err
+                       }
+                       return buf.Bytes(), nil
+               default:
+                       return nil, os.ErrorString("invalid source")
+               }
+       }
+
+       return ioutil.ReadFile(filename)
+}
+
+
+func (p *parser) parseEOF() os.Error {
+       p.expect(token.EOF)
+       return p.GetError(scanner.Sorted)
+}
+
+
+// ParseExpr parses a Go expression and returns the corresponding
+// AST node. The filename and src arguments have the same interpretation
+// as for ParseFile. If there is an error, the result expression
+// may be nil or contain a partial AST.
+//
+func ParseExpr(filename string, src interface{}) (ast.Expr, os.Error) {
+       data, err := readSource(filename, src)
+       if err != nil {
+               return nil, err
+       }
+
+       var p parser
+       p.init(filename, data, 0)
+       x := p.parseExpr()
+       if p.tok == token.SEMICOLON {
+               p.next() // consume automatically inserted semicolon, if any
+       }
+       return x, p.parseEOF()
+}
+
+
+// ParseStmtList parses a list of Go statements and returns the list
+// of corresponding AST nodes. The filename and src arguments have the same
+// interpretation as for ParseFile. If there is an error, the node
+// list may be nil or contain partial ASTs.
+//
+func ParseStmtList(filename string, src interface{}) ([]ast.Stmt, os.Error) {
+       data, err := readSource(filename, src)
+       if err != nil {
+               return nil, err
+       }
+
+       var p parser
+       p.init(filename, data, 0)
+       return p.parseStmtList(), p.parseEOF()
+}
+
+
+// ParseDeclList parses a list of Go declarations and returns the list
+// of corresponding AST nodes.  The filename and src arguments have the same
+// interpretation as for ParseFile. If there is an error, the node
+// list may be nil or contain partial ASTs.
+//
+func ParseDeclList(filename string, src interface{}) ([]ast.Decl, os.Error) {
+       data, err := readSource(filename, src)
+       if err != nil {
+               return nil, err
+       }
+
+       var p parser
+       p.init(filename, data, 0)
+       return p.parseDeclList(), p.parseEOF()
+}
+
+
+// ParseFile parses a Go source file and returns a File node.
+//
+// If src != nil, ParseFile parses the file source from src. src may
+// be provided in a variety of formats. At the moment the following types
+// are supported: string, []byte, and io.Reader. In this case, filename is
+// only used for source position information and error messages.
+//
+// If src == nil, ParseFile parses the file specified by filename.
+//
+// The mode parameter controls the amount of source text parsed and other
+// optional parser functionality.
+//
+// If the source couldn't be read, the returned AST is nil and the error
+// indicates the specific failure. If the source was read but syntax
+// errors were found, the result is a partial AST (with ast.BadX nodes
+// representing the fragments of erroneous source code). Multiple errors
+// are returned via a scanner.ErrorList which is sorted by file position.
+//
+func ParseFile(filename string, src interface{}, mode uint) (*ast.File, os.Error) {
+       data, err := readSource(filename, src)
+       if err != nil {
+               return nil, err
+       }
+
+       var p parser
+       p.init(filename, data, mode)
+       return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
+}
+
+
+// ParseFiles calls ParseFile for each file in the filenames list and returns
+// a map of package name -> package AST with all the packages found. The mode
+// bits are passed to ParseFile unchanged.
+//
+// Files with parse errors are ignored. In this case the map of packages may
+// be incomplete (missing packages and/or incomplete packages) and the first
+// error encountered is returned.
+//
+func ParseFiles(filenames []string, mode uint) (pkgs map[string]*ast.Package, first os.Error) {
+       pkgs = make(map[string]*ast.Package)
+       for _, filename := range filenames {
+               if src, err := ParseFile(filename, nil, mode); err == nil {
+                       name := src.Name.Name
+                       pkg, found := pkgs[name]
+                       if !found {
+                               pkg = &ast.Package{name, nil, make(map[string]*ast.File)}
+                               pkgs[name] = pkg
+                       }
+                       pkg.Files[filename] = src
+               } else if first == nil {
+                       first = err
+               }
+       }
+       return
+}
+
+
+// ParseDir calls ParseFile for the files in the directory specified by path and
+// returns a map of package name -> package AST with all the packages found. If
+// filter != nil, only the files with os.FileInfo entries passing through the filter
+// are considered. The mode bits are passed to ParseFile unchanged.
+//
+// If the directory couldn't be read, a nil map and the respective error are
+// returned. If a parse error occured, a non-nil but incomplete map and the
+// error are returned.
+//
+func ParseDir(path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
+       fd, err := os.Open(path, os.O_RDONLY, 0)
+       if err != nil {
+               return nil, err
+       }
+       defer fd.Close()
+
+       list, err := fd.Readdir(-1)
+       if err != nil {
+               return nil, err
+       }
+
+       filenames := make([]string, len(list))
+       n := 0
+       for i := 0; i < len(list); i++ {
+               d := &list[i]
+               if filter == nil || filter(d) {
+                       filenames[n] = pathutil.Join(path, d.Name)
+                       n++
+               }
+       }
+       filenames = filenames[0:n]
+
+       return ParseFiles(filenames, mode)
+}
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
new file mode 100644 (file)
index 0000000..390f693
--- /dev/null
@@ -0,0 +1,1870 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A parser for Go source files. Input may be provided in a variety of
+// forms (see the various Parse* functions); the output is an abstract
+// syntax tree (AST) representing the Go source. The parser is invoked
+// through one of the Parse* functions.
+//
+package parser
+
+import (
+       "fmt"
+       "go/ast"
+       "go/scanner"
+       "go/token"
+)
+
+
+// noPos is used when there is no corresponding source position for a token.
+var noPos token.Position
+
+
+// The mode parameter to the Parse* functions is a set of flags (or 0).
+// They control the amount of source code parsed and other optional
+// parser functionality.
+//
+const (
+       PackageClauseOnly uint = 1 << iota // parsing stops after package clause
+       ImportsOnly                        // parsing stops after import declarations
+       ParseComments                      // parse comments and add them to AST
+       Trace                              // print a trace of parsed productions
+)
+
+
+// The parser structure holds the parser's internal state.
+type parser struct {
+       scanner.ErrorVector
+       scanner scanner.Scanner
+
+       // Tracing/debugging
+       mode   uint // parsing mode
+       trace  bool // == (mode & Trace != 0)
+       indent uint // indentation used for tracing output
+
+       // Comments
+       comments    []*ast.CommentGroup
+       leadComment *ast.CommentGroup // the last lead comment
+       lineComment *ast.CommentGroup // the last line comment
+
+       // Next token
+       pos token.Position // token position
+       tok token.Token    // one token look-ahead
+       lit []byte         // token literal
+
+       // Non-syntactic parser control
+       exprLev int // < 0: in control clause, >= 0: in expression
+}
+
+
+// scannerMode returns the scanner mode bits given the parser's mode bits.
+func scannerMode(mode uint) uint {
+       var m uint = scanner.InsertSemis
+       if mode&ParseComments != 0 {
+               m |= scanner.ScanComments
+       }
+       return m
+}
+
+
+func (p *parser) init(filename string, src []byte, mode uint) {
+       p.scanner.Init(filename, src, p, scannerMode(mode))
+       p.mode = mode
+       p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
+       p.next()
+}
+
+
+// ----------------------------------------------------------------------------
+// Parsing support
+
+func (p *parser) printTrace(a ...interface{}) {
+       const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +
+               ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
+       const n = uint(len(dots))
+       fmt.Printf("%5d:%3d: ", p.pos.Line, p.pos.Column)
+       i := 2 * p.indent
+       for ; i > n; i -= n {
+               fmt.Print(dots)
+       }
+       fmt.Print(dots[0:i])
+       fmt.Println(a...)
+}
+
+
+func trace(p *parser, msg string) *parser {
+       p.printTrace(msg, "(")
+       p.indent++
+       return p
+}
+
+
+// Usage pattern: defer un(trace(p, "..."));
+func un(p *parser) {
+       p.indent--
+       p.printTrace(")")
+}
+
+
+// Advance to the next token.
+func (p *parser) next0() {
+       // Because of one-token look-ahead, print the previous token
+       // when tracing as it provides a more readable output. The
+       // very first token (p.pos.Line == 0) is not initialized (it
+       // is token.ILLEGAL), so don't print it .
+       if p.trace && p.pos.Line > 0 {
+               s := p.tok.String()
+               switch {
+               case p.tok.IsLiteral():
+                       p.printTrace(s, string(p.lit))
+               case p.tok.IsOperator(), p.tok.IsKeyword():
+                       p.printTrace("\"" + s + "\"")
+               default:
+                       p.printTrace(s)
+               }
+       }
+
+       p.pos, p.tok, p.lit = p.scanner.Scan()
+}
+
+// Consume a comment and return it and the line on which it ends.
+func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
+       // /*-style comments may end on a different line than where they start.
+       // Scan the comment for '\n' chars and adjust endline accordingly.
+       endline = p.pos.Line
+       if p.lit[1] == '*' {
+               for _, b := range p.lit {
+                       if b == '\n' {
+                               endline++
+                       }
+               }
+       }
+
+       comment = &ast.Comment{p.pos, p.lit}
+       p.next0()
+
+       return
+}
+
+
+// Consume a group of adjacent comments, add it to the parser's
+// comments list, and return it together with the line at which
+// the last comment in the group ends. An empty line or non-comment
+// token terminates a comment group.
+//
+func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int) {
+       var list []*ast.Comment
+       endline = p.pos.Line
+       for p.tok == token.COMMENT && endline+1 >= p.pos.Line {
+               var comment *ast.Comment
+               comment, endline = p.consumeComment()
+               list = append(list, comment)
+       }
+
+       // add comment group to the comments list
+       comments = &ast.CommentGroup{list}
+       p.comments = append(p.comments, comments)
+
+       return
+}
+
+
+// Advance to the next non-comment token. In the process, collect
+// any comment groups encountered, and remember the last lead and
+// and line comments.
+//
+// A lead comment is a comment group that starts and ends in a
+// line without any other tokens and that is followed by a non-comment
+// token on the line immediately after the comment group.
+//
+// A line comment is a comment group that follows a non-comment
+// token on the same line, and that has no tokens after it on the line
+// where it ends.
+//
+// Lead and line comments may be considered documentation that is
+// stored in the AST.
+//
+func (p *parser) next() {
+       p.leadComment = nil
+       p.lineComment = nil
+       line := p.pos.Line // current line
+       p.next0()
+
+       if p.tok == token.COMMENT {
+               var comment *ast.CommentGroup
+               var endline int
+
+               if p.pos.Line == line {
+                       // The comment is on same line as previous token; it
+                       // cannot be a lead comment but may be a line comment.
+                       comment, endline = p.consumeCommentGroup()
+                       if p.pos.Line != endline {
+                               // The next token is on a different line, thus
+                               // the last comment group is a line comment.
+                               p.lineComment = comment
+                       }
+               }
+
+               // consume successor comments, if any
+               endline = -1
+               for p.tok == token.COMMENT {
+                       comment, endline = p.consumeCommentGroup()
+               }
+
+               if endline+1 == p.pos.Line {
+                       // The next token is following on the line immediately after the
+                       // comment group, thus the last comment group is a lead comment.
+                       p.leadComment = comment
+               }
+       }
+}
+
+
+func (p *parser) errorExpected(pos token.Position, msg string) {
+       msg = "expected " + msg
+       if pos.Offset == p.pos.Offset {
+               // the error happened at the current position;
+               // make the error message more specific
+               if p.tok == token.SEMICOLON && p.lit[0] == '\n' {
+                       msg += ", found newline"
+               } else {
+                       msg += ", found '" + p.tok.String() + "'"
+                       if p.tok.IsLiteral() {
+                               msg += " " + string(p.lit)
+                       }
+               }
+       }
+       p.Error(pos, msg)
+}
+
+
+func (p *parser) expect(tok token.Token) token.Position {
+       pos := p.pos
+       if p.tok != tok {
+               p.errorExpected(pos, "'"+tok.String()+"'")
+       }
+       p.next() // make progress in any case
+       return pos
+}
+
+
+func (p *parser) expectSemi() {
+       if p.tok != token.RPAREN && p.tok != token.RBRACE {
+               p.expect(token.SEMICOLON)
+       }
+}
+
+
+// ----------------------------------------------------------------------------
+// Identifiers
+
+func (p *parser) parseIdent() *ast.Ident {
+       pos := p.pos
+       name := "_"
+       if p.tok == token.IDENT {
+               name = string(p.lit)
+               p.next()
+       } else {
+               p.expect(token.IDENT) // use expect() error handling
+       }
+       return &ast.Ident{pos, name, nil}
+}
+
+
+func (p *parser) parseIdentList() (list []*ast.Ident) {
+       if p.trace {
+               defer un(trace(p, "IdentList"))
+       }
+
+       list = append(list, p.parseIdent())
+       for p.tok == token.COMMA {
+               p.next()
+               list = append(list, p.parseIdent())
+       }
+
+       return
+}
+
+
+// ----------------------------------------------------------------------------
+// Common productions
+
+func (p *parser) parseExprList() (list []ast.Expr) {
+       if p.trace {
+               defer un(trace(p, "ExpressionList"))
+       }
+
+       list = append(list, p.parseExpr())
+       for p.tok == token.COMMA {
+               p.next()
+               list = append(list, p.parseExpr())
+       }
+
+       return
+}
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+func (p *parser) parseType() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "Type"))
+       }
+
+       typ := p.tryType()
+
+       if typ == nil {
+               p.errorExpected(p.pos, "type")
+               p.next() // make progress
+               return &ast.BadExpr{p.pos}
+       }
+
+       return typ
+}
+
+
+func (p *parser) parseQualifiedIdent() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "QualifiedIdent"))
+       }
+
+       var x ast.Expr = p.parseIdent()
+       if p.tok == token.PERIOD {
+               // first identifier is a package identifier
+               p.next()
+               sel := p.parseIdent()
+               x = &ast.SelectorExpr{x, sel}
+       }
+       return x
+}
+
+
+func (p *parser) parseTypeName() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "TypeName"))
+       }
+
+       return p.parseQualifiedIdent()
+}
+
+
+func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "ArrayType"))
+       }
+
+       lbrack := p.expect(token.LBRACK)
+       var len ast.Expr
+       if ellipsisOk && p.tok == token.ELLIPSIS {
+               len = &ast.Ellipsis{p.pos, nil}
+               p.next()
+       } else if p.tok != token.RBRACK {
+               len = p.parseExpr()
+       }
+       p.expect(token.RBRACK)
+       elt := p.parseType()
+
+       return &ast.ArrayType{lbrack, len, elt}
+}
+
+
+func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
+       idents := make([]*ast.Ident, len(list))
+       for i, x := range list {
+               ident, isIdent := x.(*ast.Ident)
+               if !isIdent {
+                       pos := x.(ast.Expr).Pos()
+                       p.errorExpected(pos, "identifier")
+                       ident = &ast.Ident{pos, "_", nil}
+               }
+               idents[i] = ident
+       }
+       return idents
+}
+
+
+func (p *parser) parseFieldDecl() *ast.Field {
+       if p.trace {
+               defer un(trace(p, "FieldDecl"))
+       }
+
+       doc := p.leadComment
+
+       // fields
+       list, typ := p.parseVarList(false)
+
+       // optional tag
+       var tag *ast.BasicLit
+       if p.tok == token.STRING {
+               tag = &ast.BasicLit{p.pos, p.tok, p.lit}
+               p.next()
+       }
+
+       // analyze case
+       var idents []*ast.Ident
+       if typ != nil {
+               // IdentifierList Type
+               idents = p.makeIdentList(list)
+       } else {
+               // ["*"] TypeName (AnonymousField)
+               typ = list[0] // we always have at least one element
+               if len(list) > 1 || !isTypeName(deref(typ)) {
+                       pos := typ.Pos()
+                       p.errorExpected(pos, "anonymous field")
+                       typ = &ast.BadExpr{pos}
+               }
+       }
+
+       p.expectSemi()
+
+       return &ast.Field{doc, idents, typ, tag, p.lineComment}
+}
+
+
+func (p *parser) parseStructType() *ast.StructType {
+       if p.trace {
+               defer un(trace(p, "StructType"))
+       }
+
+       pos := p.expect(token.STRUCT)
+       lbrace := p.expect(token.LBRACE)
+       var list []*ast.Field
+       for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN {
+               // a field declaration cannot start with a '(' but we accept
+               // it here for more robust parsing and better error messages
+               // (parseFieldDecl will check and complain if necessary)
+               list = append(list, p.parseFieldDecl())
+       }
+       rbrace := p.expect(token.RBRACE)
+
+       return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+}
+
+
+func (p *parser) parsePointerType() *ast.StarExpr {
+       if p.trace {
+               defer un(trace(p, "PointerType"))
+       }
+
+       star := p.expect(token.MUL)
+       base := p.parseType()
+
+       return &ast.StarExpr{star, base}
+}
+
+
+func (p *parser) tryVarType(isParam bool) ast.Expr {
+       if isParam && p.tok == token.ELLIPSIS {
+               pos := p.pos
+               p.next()
+               typ := p.tryType() // don't use parseType so we can provide better error message
+               if typ == nil {
+                       p.Error(pos, "'...' parameter is missing type")
+                       typ = &ast.BadExpr{pos}
+               }
+               if p.tok != token.RPAREN {
+                       p.Error(pos, "can use '...' with last parameter type only")
+               }
+               return &ast.Ellipsis{pos, typ}
+       }
+       return p.tryType()
+}
+
+
+func (p *parser) parseVarType(isParam bool) ast.Expr {
+       typ := p.tryVarType(isParam)
+       if typ == nil {
+               p.errorExpected(p.pos, "type")
+               p.next() // make progress
+               typ = &ast.BadExpr{p.pos}
+       }
+       return typ
+}
+
+
+func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
+       if p.trace {
+               defer un(trace(p, "VarList"))
+       }
+
+       // a list of identifiers looks like a list of type names
+       for {
+               // parseVarType accepts any type (including parenthesized ones)
+               // even though the syntax does not permit them here: we
+               // accept them all for more robust parsing and complain
+               // afterwards
+               list = append(list, p.parseVarType(isParam))
+               if p.tok != token.COMMA {
+                       break
+               }
+               p.next()
+       }
+
+       // if we had a list of identifiers, it must be followed by a type
+       typ = p.tryVarType(isParam)
+
+       return
+}
+
+
+func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
+       if p.trace {
+               defer un(trace(p, "ParameterList"))
+       }
+
+       list, typ := p.parseVarList(ellipsisOk)
+       if typ != nil {
+               // IdentifierList Type
+               idents := p.makeIdentList(list)
+               params = append(params, &ast.Field{nil, idents, typ, nil, nil})
+               if p.tok == token.COMMA {
+                       p.next()
+               }
+
+               for p.tok != token.RPAREN && p.tok != token.EOF {
+                       idents := p.parseIdentList()
+                       typ := p.parseVarType(ellipsisOk)
+                       params = append(params, &ast.Field{nil, idents, typ, nil, nil})
+                       if p.tok != token.COMMA {
+                               break
+                       }
+                       p.next()
+               }
+
+       } else {
+               // Type { "," Type } (anonymous parameters)
+               params = make([]*ast.Field, len(list))
+               for i, x := range list {
+                       params[i] = &ast.Field{Type: x}
+               }
+       }
+
+       return
+}
+
+
+func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
+       if p.trace {
+               defer un(trace(p, "Parameters"))
+       }
+
+       var params []*ast.Field
+       lparen := p.expect(token.LPAREN)
+       if p.tok != token.RPAREN {
+               params = p.parseParameterList(ellipsisOk)
+       }
+       rparen := p.expect(token.RPAREN)
+
+       return &ast.FieldList{lparen, params, rparen}
+}
+
+
+func (p *parser) parseResult() *ast.FieldList {
+       if p.trace {
+               defer un(trace(p, "Result"))
+       }
+
+       if p.tok == token.LPAREN {
+               return p.parseParameters(false)
+       }
+
+       typ := p.tryType()
+       if typ != nil {
+               list := make([]*ast.Field, 1)
+               list[0] = &ast.Field{Type: typ}
+               return &ast.FieldList{List: list}
+       }
+
+       return nil
+}
+
+
+func (p *parser) parseSignature() (params, results *ast.FieldList) {
+       if p.trace {
+               defer un(trace(p, "Signature"))
+       }
+
+       params = p.parseParameters(true)
+       results = p.parseResult()
+
+       return
+}
+
+
+func (p *parser) parseFuncType() *ast.FuncType {
+       if p.trace {
+               defer un(trace(p, "FuncType"))
+       }
+
+       pos := p.expect(token.FUNC)
+       params, results := p.parseSignature()
+
+       return &ast.FuncType{pos, params, results}
+}
+
+
+func (p *parser) parseMethodSpec() *ast.Field {
+       if p.trace {
+               defer un(trace(p, "MethodSpec"))
+       }
+
+       doc := p.leadComment
+       var idents []*ast.Ident
+       var typ ast.Expr
+       x := p.parseQualifiedIdent()
+       if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
+               // method
+               idents = []*ast.Ident{ident}
+               params, results := p.parseSignature()
+               typ = &ast.FuncType{noPos, params, results}
+       } else {
+               // embedded interface
+               typ = x
+       }
+       p.expectSemi()
+
+       return &ast.Field{doc, idents, typ, nil, p.lineComment}
+}
+
+
+func (p *parser) parseInterfaceType() *ast.InterfaceType {
+       if p.trace {
+               defer un(trace(p, "InterfaceType"))
+       }
+
+       pos := p.expect(token.INTERFACE)
+       lbrace := p.expect(token.LBRACE)
+       var list []*ast.Field
+       for p.tok == token.IDENT {
+               list = append(list, p.parseMethodSpec())
+       }
+       rbrace := p.expect(token.RBRACE)
+
+       return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+}
+
+
+func (p *parser) parseMapType() *ast.MapType {
+       if p.trace {
+               defer un(trace(p, "MapType"))
+       }
+
+       pos := p.expect(token.MAP)
+       p.expect(token.LBRACK)
+       key := p.parseType()
+       p.expect(token.RBRACK)
+       value := p.parseType()
+
+       return &ast.MapType{pos, key, value}
+}
+
+
+func (p *parser) parseChanType() *ast.ChanType {
+       if p.trace {
+               defer un(trace(p, "ChanType"))
+       }
+
+       pos := p.pos
+       dir := ast.SEND | ast.RECV
+       if p.tok == token.CHAN {
+               p.next()
+               if p.tok == token.ARROW {
+                       p.next()
+                       dir = ast.SEND
+               }
+       } else {
+               p.expect(token.ARROW)
+               p.expect(token.CHAN)
+               dir = ast.RECV
+       }
+       value := p.parseType()
+
+       return &ast.ChanType{pos, dir, value}
+}
+
+
+func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
+       switch p.tok {
+       case token.IDENT:
+               return p.parseTypeName()
+       case token.LBRACK:
+               return p.parseArrayType(ellipsisOk)
+       case token.STRUCT:
+               return p.parseStructType()
+       case token.MUL:
+               return p.parsePointerType()
+       case token.FUNC:
+               return p.parseFuncType()
+       case token.INTERFACE:
+               return p.parseInterfaceType()
+       case token.MAP:
+               return p.parseMapType()
+       case token.CHAN, token.ARROW:
+               return p.parseChanType()
+       case token.LPAREN:
+               lparen := p.pos
+               p.next()
+               typ := p.parseType()
+               rparen := p.expect(token.RPAREN)
+               return &ast.ParenExpr{lparen, typ, rparen}
+       }
+
+       // no type found
+       return nil
+}
+
+
+func (p *parser) tryType() ast.Expr { return p.tryRawType(false) }
+
+
+// ----------------------------------------------------------------------------
+// Blocks
+
+func (p *parser) parseStmtList() (list []ast.Stmt) {
+       if p.trace {
+               defer un(trace(p, "StatementList"))
+       }
+
+       for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
+               list = append(list, p.parseStmt())
+       }
+
+       return
+}
+
+
+func (p *parser) parseBody() *ast.BlockStmt {
+       if p.trace {
+               defer un(trace(p, "Body"))
+       }
+
+       lbrace := p.expect(token.LBRACE)
+       list := p.parseStmtList()
+       rbrace := p.expect(token.RBRACE)
+
+       return &ast.BlockStmt{lbrace, list, rbrace}
+}
+
+
+func (p *parser) parseBlockStmt() *ast.BlockStmt {
+       if p.trace {
+               defer un(trace(p, "BlockStmt"))
+       }
+
+       lbrace := p.expect(token.LBRACE)
+       list := p.parseStmtList()
+       rbrace := p.expect(token.RBRACE)
+
+       return &ast.BlockStmt{lbrace, list, rbrace}
+}
+
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+func (p *parser) parseFuncTypeOrLit() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "FuncTypeOrLit"))
+       }
+
+       typ := p.parseFuncType()
+       if p.tok != token.LBRACE {
+               // function type only
+               return typ
+       }
+
+       p.exprLev++
+       body := p.parseBody()
+       p.exprLev--
+
+       return &ast.FuncLit{typ, body}
+}
+
+
+// parseOperand may return an expression or a raw type (incl. array
+// types of the form [...]T. Callers must verify the result.
+//
+func (p *parser) parseOperand() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "Operand"))
+       }
+
+       switch p.tok {
+       case token.IDENT:
+               return p.parseIdent()
+
+       case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
+               x := &ast.BasicLit{p.pos, p.tok, p.lit}
+               p.next()
+               return x
+
+       case token.LPAREN:
+               lparen := p.pos
+               p.next()
+               p.exprLev++
+               x := p.parseExpr()
+               p.exprLev--
+               rparen := p.expect(token.RPAREN)
+               return &ast.ParenExpr{lparen, x, rparen}
+
+       case token.FUNC:
+               return p.parseFuncTypeOrLit()
+
+       default:
+               t := p.tryRawType(true) // could be type for composite literal or conversion
+               if t != nil {
+                       return t
+               }
+       }
+
+       p.errorExpected(p.pos, "operand")
+       p.next() // make progress
+       return &ast.BadExpr{p.pos}
+}
+
+
+func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "SelectorOrTypeAssertion"))
+       }
+
+       p.expect(token.PERIOD)
+       if p.tok == token.IDENT {
+               // selector
+               sel := p.parseIdent()
+               return &ast.SelectorExpr{x, sel}
+       }
+
+       // type assertion
+       p.expect(token.LPAREN)
+       var typ ast.Expr
+       if p.tok == token.TYPE {
+               // type switch: typ == nil
+               p.next()
+       } else {
+               typ = p.parseType()
+       }
+       p.expect(token.RPAREN)
+
+       return &ast.TypeAssertExpr{x, typ}
+}
+
+
+func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "IndexOrSlice"))
+       }
+
+       p.expect(token.LBRACK)
+       p.exprLev++
+       var index ast.Expr
+       if p.tok != token.COLON {
+               index = p.parseExpr()
+       }
+       if p.tok == token.COLON {
+               p.next()
+               var end ast.Expr
+               if p.tok != token.RBRACK {
+                       end = p.parseExpr()
+               }
+               x = &ast.SliceExpr{x, index, end}
+       } else {
+               x = &ast.IndexExpr{x, index}
+       }
+       p.exprLev--
+       p.expect(token.RBRACK)
+
+       return x
+}
+
+
+func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
+       if p.trace {
+               defer un(trace(p, "CallOrConversion"))
+       }
+
+       lparen := p.expect(token.LPAREN)
+       p.exprLev++
+       var list []ast.Expr
+       var ellipsis token.Position
+       for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
+               list = append(list, p.parseExpr())
+               if p.tok == token.ELLIPSIS {
+                       ellipsis = p.pos
+                       p.next()
+               }
+               if p.tok != token.COMMA {
+                       break
+               }
+               p.next()
+       }
+       p.exprLev--
+       rparen := p.expect(token.RPAREN)
+
+       return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
+}
+
+
+func (p *parser) parseElement(keyOk bool) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "Element"))
+       }
+
+       if p.tok == token.LBRACE {
+               return p.parseLiteralValue(nil)
+       }
+
+       x := p.parseExpr()
+       if keyOk && p.tok == token.COLON {
+               colon := p.pos
+               p.next()
+               x = &ast.KeyValueExpr{x, colon, p.parseElement(false)}
+       }
+       return x
+}
+
+
+func (p *parser) parseElementList() (list []ast.Expr) {
+       if p.trace {
+               defer un(trace(p, "ElementList"))
+       }
+
+       for p.tok != token.RBRACE && p.tok != token.EOF {
+               list = append(list, p.parseElement(true))
+               if p.tok != token.COMMA {
+                       break
+               }
+               p.next()
+       }
+
+       return
+}
+
+
+func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "LiteralValue"))
+       }
+
+       lbrace := p.expect(token.LBRACE)
+       var elts []ast.Expr
+       p.exprLev++
+       if p.tok != token.RBRACE {
+               elts = p.parseElementList()
+       }
+       p.exprLev--
+       rbrace := p.expect(token.RBRACE)
+       return &ast.CompositeLit{typ, lbrace, elts, rbrace}
+}
+
+
+// checkExpr checks that x is an expression (and not a type).
+func (p *parser) checkExpr(x ast.Expr) ast.Expr {
+       switch t := unparen(x).(type) {
+       case *ast.BadExpr:
+       case *ast.Ident:
+       case *ast.BasicLit:
+       case *ast.FuncLit:
+       case *ast.CompositeLit:
+       case *ast.ParenExpr:
+               panic("unreachable")
+       case *ast.SelectorExpr:
+       case *ast.IndexExpr:
+       case *ast.SliceExpr:
+       case *ast.TypeAssertExpr:
+               if t.Type == nil {
+                       // the form X.(type) is only allowed in type switch expressions
+                       p.errorExpected(x.Pos(), "expression")
+                       x = &ast.BadExpr{x.Pos()}
+               }
+       case *ast.CallExpr:
+       case *ast.StarExpr:
+       case *ast.UnaryExpr:
+               if t.Op == token.RANGE {
+                       // the range operator is only allowed at the top of a for statement
+                       p.errorExpected(x.Pos(), "expression")
+                       x = &ast.BadExpr{x.Pos()}
+               }
+       case *ast.BinaryExpr:
+       default:
+               // all other nodes are not proper expressions
+               p.errorExpected(x.Pos(), "expression")
+               x = &ast.BadExpr{x.Pos()}
+       }
+       return x
+}
+
+
+// isTypeName returns true iff x is a (qualified) TypeName.
+func isTypeName(x ast.Expr) bool {
+       switch t := x.(type) {
+       case *ast.BadExpr:
+       case *ast.Ident:
+       case *ast.SelectorExpr:
+               _, isIdent := t.X.(*ast.Ident)
+               return isIdent
+       default:
+               return false // all other nodes are not type names
+       }
+       return true
+}
+
+
+// isLiteralType returns true iff x is a legal composite literal type.
+func isLiteralType(x ast.Expr) bool {
+       switch t := x.(type) {
+       case *ast.BadExpr:
+       case *ast.Ident:
+       case *ast.SelectorExpr:
+               _, isIdent := t.X.(*ast.Ident)
+               return isIdent
+       case *ast.ArrayType:
+       case *ast.StructType:
+       case *ast.MapType:
+       default:
+               return false // all other nodes are not legal composite literal types
+       }
+       return true
+}
+
+
+// If x is of the form *T, deref returns T, otherwise it returns x.
+func deref(x ast.Expr) ast.Expr {
+       if p, isPtr := x.(*ast.StarExpr); isPtr {
+               x = p.X
+       }
+       return x
+}
+
+
+// If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
+func unparen(x ast.Expr) ast.Expr {
+       if p, isParen := x.(*ast.ParenExpr); isParen {
+               x = unparen(p.X)
+       }
+       return x
+}
+
+
+// checkExprOrType checks that x is an expression or a type
+// (and not a raw type such as [...]T).
+//
+func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
+       switch t := unparen(x).(type) {
+       case *ast.ParenExpr:
+               panic("unreachable")
+       case *ast.UnaryExpr:
+               if t.Op == token.RANGE {
+                       // the range operator is only allowed at the top of a for statement
+                       p.errorExpected(x.Pos(), "expression")
+                       x = &ast.BadExpr{x.Pos()}
+               }
+       case *ast.ArrayType:
+               if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
+                       p.Error(len.Pos(), "expected array length, found '...'")
+                       x = &ast.BadExpr{x.Pos()}
+               }
+       }
+
+       // all other nodes are expressions or types
+       return x
+}
+
+
+func (p *parser) parsePrimaryExpr() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "PrimaryExpr"))
+       }
+
+       x := p.parseOperand()
+L:
+       for {
+               switch p.tok {
+               case token.PERIOD:
+                       x = p.parseSelectorOrTypeAssertion(p.checkExpr(x))
+               case token.LBRACK:
+                       x = p.parseIndexOrSlice(p.checkExpr(x))
+               case token.LPAREN:
+                       x = p.parseCallOrConversion(p.checkExprOrType(x))
+               case token.LBRACE:
+                       if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
+                               x = p.parseLiteralValue(x)
+                       } else {
+                               break L
+                       }
+               default:
+                       break L
+               }
+       }
+
+       return x
+}
+
+
+func (p *parser) parseUnaryExpr() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "UnaryExpr"))
+       }
+
+       switch p.tok {
+       case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE:
+               pos, op := p.pos, p.tok
+               p.next()
+               x := p.parseUnaryExpr()
+               return &ast.UnaryExpr{pos, op, p.checkExpr(x)}
+
+       case token.ARROW:
+               // channel type or receive expression
+               pos := p.pos
+               p.next()
+               if p.tok == token.CHAN {
+                       p.next()
+                       value := p.parseType()
+                       return &ast.ChanType{pos, ast.RECV, value}
+               }
+
+               x := p.parseUnaryExpr()
+               return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)}
+
+       case token.MUL:
+               // pointer type or unary "*" expression
+               pos := p.pos
+               p.next()
+               x := p.parseUnaryExpr()
+               return &ast.StarExpr{pos, p.checkExprOrType(x)}
+       }
+
+       return p.parsePrimaryExpr()
+}
+
+
+func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "BinaryExpr"))
+       }
+
+       x := p.parseUnaryExpr()
+       for prec := p.tok.Precedence(); prec >= prec1; prec-- {
+               for p.tok.Precedence() == prec {
+                       pos, op := p.pos, p.tok
+                       p.next()
+                       y := p.parseBinaryExpr(prec + 1)
+                       x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)}
+               }
+       }
+
+       return x
+}
+
+
+// TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
+//            should reject when a type/raw type is obviously not allowed
+func (p *parser) parseExpr() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "Expression"))
+       }
+
+       return p.parseBinaryExpr(token.LowestPrec + 1)
+}
+
+
+// ----------------------------------------------------------------------------
+// Statements
+
+func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "SimpleStmt"))
+       }
+
+       x := p.parseExprList()
+
+       switch p.tok {
+       case token.COLON:
+               // labeled statement
+               p.next()
+               if labelOk && len(x) == 1 {
+                       if label, isIdent := x[0].(*ast.Ident); isIdent {
+                               return &ast.LabeledStmt{label, p.parseStmt()}
+                       }
+               }
+               p.Error(x[0].Pos(), "illegal label declaration")
+               return &ast.BadStmt{x[0].Pos()}
+
+       case
+               token.DEFINE, token.ASSIGN, token.ADD_ASSIGN,
+               token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN,
+               token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN,
+               token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN:
+               // assignment statement
+               pos, tok := p.pos, p.tok
+               p.next()
+               y := p.parseExprList()
+               return &ast.AssignStmt{x, pos, tok, y}
+       }
+
+       if len(x) > 1 {
+               p.Error(x[0].Pos(), "only one expression allowed")
+               // continue with first expression
+       }
+
+       if p.tok == token.INC || p.tok == token.DEC {
+               // increment or decrement
+               s := &ast.IncDecStmt{x[0], p.tok}
+               p.next() // consume "++" or "--"
+               return s
+       }
+
+       // expression
+       return &ast.ExprStmt{x[0]}
+}
+
+
+func (p *parser) parseCallExpr() *ast.CallExpr {
+       x := p.parseExpr()
+       if call, isCall := x.(*ast.CallExpr); isCall {
+               return call
+       }
+       p.errorExpected(x.Pos(), "function/method call")
+       return nil
+}
+
+
+func (p *parser) parseGoStmt() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "GoStmt"))
+       }
+
+       pos := p.expect(token.GO)
+       call := p.parseCallExpr()
+       p.expectSemi()
+       if call == nil {
+               return &ast.BadStmt{pos}
+       }
+
+       return &ast.GoStmt{pos, call}
+}
+
+
+func (p *parser) parseDeferStmt() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "DeferStmt"))
+       }
+
+       pos := p.expect(token.DEFER)
+       call := p.parseCallExpr()
+       p.expectSemi()
+       if call == nil {
+               return &ast.BadStmt{pos}
+       }
+
+       return &ast.DeferStmt{pos, call}
+}
+
+
+func (p *parser) parseReturnStmt() *ast.ReturnStmt {
+       if p.trace {
+               defer un(trace(p, "ReturnStmt"))
+       }
+
+       pos := p.pos
+       p.expect(token.RETURN)
+       var x []ast.Expr
+       if p.tok != token.SEMICOLON && p.tok != token.RBRACE {
+               x = p.parseExprList()
+       }
+       p.expectSemi()
+
+       return &ast.ReturnStmt{pos, x}
+}
+
+
+func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
+       if p.trace {
+               defer un(trace(p, "BranchStmt"))
+       }
+
+       s := &ast.BranchStmt{p.pos, tok, nil}
+       p.expect(tok)
+       if tok != token.FALLTHROUGH && p.tok == token.IDENT {
+               s.Label = p.parseIdent()
+       }
+       p.expectSemi()
+
+       return s
+}
+
+
+func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
+       if s == nil {
+               return nil
+       }
+       if es, isExpr := s.(*ast.ExprStmt); isExpr {
+               return p.checkExpr(es.X)
+       }
+       p.Error(s.Pos(), "expected condition, found simple statement")
+       return &ast.BadExpr{s.Pos()}
+}
+
+
+func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
+       if p.tok != token.LBRACE {
+               prevLev := p.exprLev
+               p.exprLev = -1
+
+               if p.tok != token.SEMICOLON {
+                       s1 = p.parseSimpleStmt(false)
+               }
+               if p.tok == token.SEMICOLON {
+                       p.next()
+                       if p.tok != token.LBRACE && p.tok != token.SEMICOLON {
+                               s2 = p.parseSimpleStmt(false)
+                       }
+                       if isForStmt {
+                               // for statements have a 3rd section
+                               p.expectSemi()
+                               if p.tok != token.LBRACE {
+                                       s3 = p.parseSimpleStmt(false)
+                               }
+                       }
+               } else {
+                       s1, s2 = nil, s1
+               }
+
+               p.exprLev = prevLev
+       }
+
+       return s1, s2, s3
+}
+
+
+func (p *parser) parseIfStmt() *ast.IfStmt {
+       if p.trace {
+               defer un(trace(p, "IfStmt"))
+       }
+
+       pos := p.expect(token.IF)
+       s1, s2, _ := p.parseControlClause(false)
+       body := p.parseBlockStmt()
+       var else_ ast.Stmt
+       if p.tok == token.ELSE {
+               p.next()
+               else_ = p.parseStmt()
+       } else {
+               p.expectSemi()
+       }
+
+       return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_}
+}
+
+
+func (p *parser) parseCaseClause() *ast.CaseClause {
+       if p.trace {
+               defer un(trace(p, "CaseClause"))
+       }
+
+       // SwitchCase
+       pos := p.pos
+       var x []ast.Expr
+       if p.tok == token.CASE {
+               p.next()
+               x = p.parseExprList()
+       } else {
+               p.expect(token.DEFAULT)
+       }
+
+       colon := p.expect(token.COLON)
+       body := p.parseStmtList()
+
+       return &ast.CaseClause{pos, x, colon, body}
+}
+
+
+func (p *parser) parseTypeList() (list []ast.Expr) {
+       if p.trace {
+               defer un(trace(p, "TypeList"))
+       }
+
+       list = append(list, p.parseType())
+       for p.tok == token.COMMA {
+               p.next()
+               list = append(list, p.parseType())
+       }
+
+       return
+}
+
+
+func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
+       if p.trace {
+               defer un(trace(p, "TypeCaseClause"))
+       }
+
+       // TypeSwitchCase
+       pos := p.pos
+       var types []ast.Expr
+       if p.tok == token.CASE {
+               p.next()
+               types = p.parseTypeList()
+       } else {
+               p.expect(token.DEFAULT)
+       }
+
+       colon := p.expect(token.COLON)
+       body := p.parseStmtList()
+
+       return &ast.TypeCaseClause{pos, types, colon, body}
+}
+
+
+func isExprSwitch(s ast.Stmt) bool {
+       if s == nil {
+               return true
+       }
+       if e, ok := s.(*ast.ExprStmt); ok {
+               if a, ok := e.X.(*ast.TypeAssertExpr); ok {
+                       return a.Type != nil // regular type assertion
+               }
+               return true
+       }
+       return false
+}
+
+
+func (p *parser) parseSwitchStmt() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "SwitchStmt"))
+       }
+
+       pos := p.expect(token.SWITCH)
+       s1, s2, _ := p.parseControlClause(false)
+
+       if isExprSwitch(s2) {
+               lbrace := p.expect(token.LBRACE)
+               var list []ast.Stmt
+               for p.tok == token.CASE || p.tok == token.DEFAULT {
+                       list = append(list, p.parseCaseClause())
+               }
+               rbrace := p.expect(token.RBRACE)
+               body := &ast.BlockStmt{lbrace, list, rbrace}
+               p.expectSemi()
+               return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
+       }
+
+       // type switch
+       // TODO(gri): do all the checks!
+       lbrace := p.expect(token.LBRACE)
+       var list []ast.Stmt
+       for p.tok == token.CASE || p.tok == token.DEFAULT {
+               list = append(list, p.parseTypeCaseClause())
+       }
+       rbrace := p.expect(token.RBRACE)
+       p.expectSemi()
+       body := &ast.BlockStmt{lbrace, list, rbrace}
+       return &ast.TypeSwitchStmt{pos, s1, s2, body}
+}
+
+
+func (p *parser) parseCommClause() *ast.CommClause {
+       if p.trace {
+               defer un(trace(p, "CommClause"))
+       }
+
+       // CommCase
+       pos := p.pos
+       var tok token.Token
+       var lhs, rhs ast.Expr
+       if p.tok == token.CASE {
+               p.next()
+               if p.tok == token.ARROW {
+                       // RecvExpr without assignment
+                       rhs = p.parseExpr()
+               } else {
+                       // SendExpr or RecvExpr
+                       rhs = p.parseExpr()
+                       if p.tok == token.ASSIGN || p.tok == token.DEFINE {
+                               // RecvExpr with assignment
+                               tok = p.tok
+                               p.next()
+                               lhs = rhs
+                               if p.tok == token.ARROW {
+                                       rhs = p.parseExpr()
+                               } else {
+                                       p.expect(token.ARROW) // use expect() error handling
+                               }
+                       }
+                       // else SendExpr
+               }
+       } else {
+               p.expect(token.DEFAULT)
+       }
+
+       colon := p.expect(token.COLON)
+       body := p.parseStmtList()
+
+       return &ast.CommClause{pos, tok, lhs, rhs, colon, body}
+}
+
+
+func (p *parser) parseSelectStmt() *ast.SelectStmt {
+       if p.trace {
+               defer un(trace(p, "SelectStmt"))
+       }
+
+       pos := p.expect(token.SELECT)
+       lbrace := p.expect(token.LBRACE)
+       var list []ast.Stmt
+       for p.tok == token.CASE || p.tok == token.DEFAULT {
+               list = append(list, p.parseCommClause())
+       }
+       rbrace := p.expect(token.RBRACE)
+       p.expectSemi()
+       body := &ast.BlockStmt{lbrace, list, rbrace}
+
+       return &ast.SelectStmt{pos, body}
+}
+
+
+func (p *parser) parseForStmt() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "ForStmt"))
+       }
+
+       pos := p.expect(token.FOR)
+       s1, s2, s3 := p.parseControlClause(true)
+       body := p.parseBlockStmt()
+       p.expectSemi()
+
+       if as, isAssign := s2.(*ast.AssignStmt); isAssign {
+               // possibly a for statement with a range clause; check assignment operator
+               if as.Tok != token.ASSIGN && as.Tok != token.DEFINE {
+                       p.errorExpected(as.TokPos, "'=' or ':='")
+                       return &ast.BadStmt{pos}
+               }
+               // check lhs
+               var key, value ast.Expr
+               switch len(as.Lhs) {
+               case 2:
+                       key, value = as.Lhs[0], as.Lhs[1]
+               case 1:
+                       key = as.Lhs[0]
+               default:
+                       p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
+                       return &ast.BadStmt{pos}
+               }
+               // check rhs
+               if len(as.Rhs) != 1 {
+                       p.errorExpected(as.Rhs[0].Pos(), "1 expressions")
+                       return &ast.BadStmt{pos}
+               }
+               if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
+                       // rhs is range expression; check lhs
+                       return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
+               } else {
+                       p.errorExpected(s2.Pos(), "range clause")
+                       return &ast.BadStmt{pos}
+               }
+       } else {
+               // regular for statement
+               return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
+       }
+
+       panic("unreachable")
+}
+
+
+func (p *parser) parseStmt() (s ast.Stmt) {
+       if p.trace {
+               defer un(trace(p, "Statement"))
+       }
+
+       switch p.tok {
+       case token.CONST, token.TYPE, token.VAR:
+               s = &ast.DeclStmt{p.parseDecl()}
+       case
+               // tokens that may start a top-level expression
+               token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
+               token.LBRACK, token.STRUCT, // composite type
+               token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators
+               s = p.parseSimpleStmt(true)
+               // because of the required look-ahead, labeled statements are
+               // parsed by parseSimpleStmt - don't expect a semicolon after
+               // them
+               if _, isLabeledStmt := s.(*ast.LabeledStmt); !isLabeledStmt {
+                       p.expectSemi()
+               }
+       case token.GO:
+               s = p.parseGoStmt()
+       case token.DEFER:
+               s = p.parseDeferStmt()
+       case token.RETURN:
+               s = p.parseReturnStmt()
+       case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
+               s = p.parseBranchStmt(p.tok)
+       case token.LBRACE:
+               s = p.parseBlockStmt()
+               p.expectSemi()
+       case token.IF:
+               s = p.parseIfStmt()
+       case token.SWITCH:
+               s = p.parseSwitchStmt()
+       case token.SELECT:
+               s = p.parseSelectStmt()
+       case token.FOR:
+               s = p.parseForStmt()
+       case token.SEMICOLON:
+               s = &ast.EmptyStmt{p.pos}
+               p.next()
+       case token.RBRACE:
+               // a semicolon may be omitted before a closing "}"
+               s = &ast.EmptyStmt{p.pos}
+       default:
+               // no statement found
+               p.errorExpected(p.pos, "statement")
+               p.next() // make progress
+               s = &ast.BadStmt{p.pos}
+       }
+
+       return
+}
+
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+type parseSpecFunction func(p *parser, doc *ast.CommentGroup) ast.Spec
+
+
+func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+       if p.trace {
+               defer un(trace(p, "ImportSpec"))
+       }
+
+       var ident *ast.Ident
+       if p.tok == token.PERIOD {
+               ident = &ast.Ident{p.pos, ".", nil}
+               p.next()
+       } else if p.tok == token.IDENT {
+               ident = p.parseIdent()
+       }
+
+       var path *ast.BasicLit
+       if p.tok == token.STRING {
+               path = &ast.BasicLit{p.pos, p.tok, p.lit}
+               p.next()
+       } else {
+               p.expect(token.STRING) // use expect() error handling
+       }
+       p.expectSemi()
+
+       return &ast.ImportSpec{doc, ident, path, p.lineComment}
+}
+
+
+func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+       if p.trace {
+               defer un(trace(p, "ConstSpec"))
+       }
+
+       idents := p.parseIdentList()
+       typ := p.tryType()
+       var values []ast.Expr
+       if typ != nil || p.tok == token.ASSIGN {
+               p.expect(token.ASSIGN)
+               values = p.parseExprList()
+       }
+       p.expectSemi()
+
+       return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+}
+
+
+func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+       if p.trace {
+               defer un(trace(p, "TypeSpec"))
+       }
+
+       ident := p.parseIdent()
+       typ := p.parseType()
+       p.expectSemi()
+
+       return &ast.TypeSpec{doc, ident, typ, p.lineComment}
+}
+
+
+func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+       if p.trace {
+               defer un(trace(p, "VarSpec"))
+       }
+
+       idents := p.parseIdentList()
+       typ := p.tryType()
+       var values []ast.Expr
+       if typ == nil || p.tok == token.ASSIGN {
+               p.expect(token.ASSIGN)
+               values = p.parseExprList()
+       }
+       p.expectSemi()
+
+       return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+}
+
+
+func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
+       if p.trace {
+               defer un(trace(p, "GenDecl("+keyword.String()+")"))
+       }
+
+       doc := p.leadComment
+       pos := p.expect(keyword)
+       var lparen, rparen token.Position
+       var list []ast.Spec
+       if p.tok == token.LPAREN {
+               lparen = p.pos
+               p.next()
+               for p.tok != token.RPAREN && p.tok != token.EOF {
+                       list = append(list, f(p, p.leadComment))
+               }
+               rparen = p.expect(token.RPAREN)
+               p.expectSemi()
+       } else {
+               list = append(list, f(p, nil))
+       }
+
+       return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
+}
+
+
+func (p *parser) parseReceiver() *ast.FieldList {
+       if p.trace {
+               defer un(trace(p, "Receiver"))
+       }
+
+       pos := p.pos
+       par := p.parseParameters(false)
+
+       // must have exactly one receiver
+       if par.NumFields() != 1 {
+               p.errorExpected(pos, "exactly one receiver")
+               par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{noPos}}}
+               return par
+       }
+
+       // recv type must be of the form ["*"] identifier
+       recv := par.List[0]
+       base := deref(recv.Type)
+       if _, isIdent := base.(*ast.Ident); !isIdent {
+               p.errorExpected(base.Pos(), "(unqualified) identifier")
+               par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{recv.Pos()}}}
+       }
+
+       return par
+}
+
+
+func (p *parser) parseFuncDecl() *ast.FuncDecl {
+       if p.trace {
+               defer un(trace(p, "FunctionDecl"))
+       }
+
+       doc := p.leadComment
+       pos := p.expect(token.FUNC)
+
+       var recv *ast.FieldList
+       if p.tok == token.LPAREN {
+               recv = p.parseReceiver()
+       }
+
+       ident := p.parseIdent()
+       params, results := p.parseSignature()
+
+       var body *ast.BlockStmt
+       if p.tok == token.LBRACE {
+               body = p.parseBody()
+       }
+       p.expectSemi()
+
+       return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+}
+
+
+func (p *parser) parseDecl() ast.Decl {
+       if p.trace {
+               defer un(trace(p, "Declaration"))
+       }
+
+       var f parseSpecFunction
+       switch p.tok {
+       case token.CONST:
+               f = parseConstSpec
+
+       case token.TYPE:
+               f = parseTypeSpec
+
+       case token.VAR:
+               f = parseVarSpec
+
+       case token.FUNC:
+               return p.parseFuncDecl()
+
+       default:
+               pos := p.pos
+               p.errorExpected(pos, "declaration")
+               decl := &ast.BadDecl{pos}
+               p.next() // make progress in any case
+               return decl
+       }
+
+       return p.parseGenDecl(p.tok, f)
+}
+
+
+func (p *parser) parseDeclList() (list []ast.Decl) {
+       if p.trace {
+               defer un(trace(p, "DeclList"))
+       }
+
+       for p.tok != token.EOF {
+               list = append(list, p.parseDecl())
+       }
+
+       return
+}
+
+
+// ----------------------------------------------------------------------------
+// Source files
+
+func (p *parser) parseFile() *ast.File {
+       if p.trace {
+               defer un(trace(p, "File"))
+       }
+
+       // package clause
+       doc := p.leadComment
+       pos := p.expect(token.PACKAGE)
+       ident := p.parseIdent()
+       p.expectSemi()
+
+       var decls []ast.Decl
+
+       // Don't bother parsing the rest if we had errors already.
+       // Likely not a Go source file at all.
+
+       if p.ErrorCount() == 0 && p.mode&PackageClauseOnly == 0 {
+               // import decls
+               for p.tok == token.IMPORT {
+                       decls = append(decls, p.parseGenDecl(token.IMPORT, parseImportSpec))
+               }
+
+               if p.mode&ImportsOnly == 0 {
+                       // rest of package body
+                       for p.tok != token.EOF {
+                               decls = append(decls, p.parseDecl())
+                       }
+               }
+       }
+
+       return &ast.File{doc, pos, ident, decls, p.comments}
+}
diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go
new file mode 100644 (file)
index 0000000..5882145
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parser
+
+import (
+       "os"
+       "testing"
+)
+
+
+var illegalInputs = []interface{}{
+       nil,
+       3.14,
+       []byte(nil),
+       "foo!",
+}
+
+
+func TestParseIllegalInputs(t *testing.T) {
+       for _, src := range illegalInputs {
+               _, err := ParseFile("", src, 0)
+               if err == nil {
+                       t.Errorf("ParseFile(%v) should have failed", src)
+               }
+       }
+}
+
+
+var validPrograms = []interface{}{
+       "package main\n",
+       `package main;`,
+       `package main; import "fmt"; func main() { fmt.Println("Hello, World!") };`,
+       `package main; func main() { if f(T{}) {} };`,
+       `package main; func main() { _ = (<-chan int)(x) };`,
+       `package main; func main() { _ = (<-chan <-chan int)(x) };`,
+       `package main; func f(func() func() func());`,
+       `package main; func f(...T);`,
+       `package main; func f(float, ...int);`,
+       `package main; func f(x int, a ...int) { f(0, a...); f(1, a...,) };`,
+       `package main; type T []int; var a []bool; func f() { if a[T{42}[0]] {} };`,
+       `package main; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`,
+       `package main; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`,
+       `package main; var a = T{{1, 2}, {3, 4}}`,
+}
+
+
+func TestParseValidPrograms(t *testing.T) {
+       for _, src := range validPrograms {
+               _, err := ParseFile("", src, 0)
+               if err != nil {
+                       t.Errorf("ParseFile(%q): %v", src, err)
+               }
+       }
+}
+
+
+var validFiles = []string{
+       "parser.go",
+       "parser_test.go",
+}
+
+
+func TestParse3(t *testing.T) {
+       for _, filename := range validFiles {
+               _, err := ParseFile(filename, nil, 0)
+               if err != nil {
+                       t.Errorf("ParseFile(%s): %v", filename, err)
+               }
+       }
+}
+
+
+func nameFilter(filename string) bool {
+       switch filename {
+       case "parser.go":
+       case "interface.go":
+       case "parser_test.go":
+       default:
+               return false
+       }
+       return true
+}
+
+
+func dirFilter(f *os.FileInfo) bool { return nameFilter(f.Name) }
+
+
+func TestParse4(t *testing.T) {
+       path := "."
+       pkgs, err := ParseDir(path, dirFilter, 0)
+       if err != nil {
+               t.Fatalf("ParseDir(%s): %v", path, err)
+       }
+       if len(pkgs) != 1 {
+               t.Errorf("incorrect number of packages: %d", len(pkgs))
+       }
+       pkg := pkgs["parser"]
+       if pkg == nil {
+               t.Errorf(`package "parser" not found`)
+               return
+       }
+       for filename, _ := range pkg.Files {
+               if !nameFilter(filename) {
+                       t.Errorf("unexpected package file: %s", filename)
+               }
+       }
+}
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
new file mode 100644 (file)
index 0000000..b58277c
--- /dev/null
@@ -0,0 +1,1481 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements printing of AST nodes; specifically
+// expressions, statements, declarations, and files. It uses
+// the print functionality implemented in printer.go.
+
+package printer
+
+import (
+       "bytes"
+       "go/ast"
+       "go/token"
+)
+
+
+// Other formatting issues:
+// - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
+//   when the comment spans multiple lines; if such a comment is just two lines, formatting is
+//   not idempotent
+// - formatting of expression lists
+// - should use blank instead of tab to separate one-line function bodies from
+//   the function header unless there is a group of consecutive one-liners
+
+
+// ----------------------------------------------------------------------------
+// Common AST nodes.
+
+// Print as many newlines as necessary (but at least min newlines) to get to
+// the current line. ws is printed before the first line break. If newSection
+// is set, the first line break is printed as formfeed. Returns true if any
+// line break was printed; returns false otherwise.
+//
+// TODO(gri): linebreak may add too many lines if the next statement at "line"
+//            is preceeded by comments because the computation of n assumes
+//            the current position before the comment and the target position
+//            after the comment. Thus, after interspersing such comments, the
+//            space taken up by them is not considered to reduce the number of
+//            linebreaks. At the moment there is no easy way to know about
+//            future (not yet interspersed) comments in this function.
+//
+func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
+       n := p.nlines(line-p.pos.Line, min)
+       if n > 0 {
+               p.print(ws)
+               if newSection {
+                       p.print(formfeed)
+                       n--
+               }
+               for ; n > 0; n-- {
+                       p.print(newline)
+               }
+               printedBreak = true
+       }
+       return
+}
+
+
+// setComment sets g as the next comment if g != nil and if node comments
+// are enabled - this mode is used when printing source code fragments such
+// as exports only. It assumes that there are no other pending comments to
+// intersperse.
+func (p *printer) setComment(g *ast.CommentGroup) {
+       if g == nil || !p.useNodeComments {
+               return
+       }
+       if p.comments == nil {
+               // initialize p.comments lazily
+               p.comments = make([]*ast.CommentGroup, 1)
+       } else if p.cindex < len(p.comments) {
+               // for some reason there are pending comments; this
+               // should never happen - handle gracefully and flush
+               // all comments up to g, ignore anything after that
+               p.flush(g.List[0].Pos(), token.ILLEGAL)
+       }
+       p.comments[0] = g
+       p.cindex = 0
+}
+
+
+type exprListMode uint
+
+const (
+       blankStart exprListMode = 1 << iota // print a blank before a non-empty list
+       blankEnd                            // print a blank after a non-empty list
+       commaSep                            // elements are separated by commas
+       commaTerm                           // list is optionally terminated by a comma
+       noIndent                            // no extra indentation in multi-line lists
+       periodSep                           // elements are separated by periods
+)
+
+
+// Sets multiLine to true if the identifier list spans multiple lines.
+// If ident is set, a multi-line identifier list is indented after the
+// first linebreak encountered.
+func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
+       // convert into an expression list so we can re-use exprList formatting
+       xlist := make([]ast.Expr, len(list))
+       for i, x := range list {
+               xlist[i] = x
+       }
+       mode := commaSep
+       if !indent {
+               mode |= noIndent
+       }
+       p.exprList(noPos, xlist, 1, mode, multiLine, noPos)
+}
+
+
+// Compute the key size of a key:value expression.
+// Returns 0 if the expression doesn't fit onto a single line.
+func (p *printer) keySize(pair *ast.KeyValueExpr) int {
+       if p.nodeSize(pair, infinity) <= infinity {
+               // entire expression fits on one line - return key size
+               return p.nodeSize(pair.Key, infinity)
+       }
+       return 0
+}
+
+
+// Print a list of expressions. If the list spans multiple
+// source lines, the original line breaks are respected between
+// expressions. Sets multiLine to true if the list spans multiple
+// lines.
+//
+// TODO(gri) Consider rewriting this to be independent of []ast.Expr
+//           so that we can use the algorithm for any kind of list
+//           (e.g., pass list via a channel over which to range).
+func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next token.Position) {
+       if len(list) == 0 {
+               return
+       }
+
+       if mode&blankStart != 0 {
+               p.print(blank)
+       }
+
+       line := list[0].Pos().Line
+       endLine := next.Line
+       if endLine == 0 {
+               // TODO(gri): endLine may be incorrect as it is really the beginning
+               //            of the last list entry. There may be only one, very long
+               //            entry in which case line == endLine.
+               endLine = list[len(list)-1].Pos().Line
+       }
+
+       if prev.IsValid() && prev.Line == line && line == endLine {
+               // all list entries on a single line
+               for i, x := range list {
+                       if i > 0 {
+                               if mode&commaSep != 0 {
+                                       p.print(token.COMMA)
+                               }
+                               p.print(blank)
+                       }
+                       p.expr0(x, depth, multiLine)
+               }
+               if mode&blankEnd != 0 {
+                       p.print(blank)
+               }
+               return
+       }
+
+       // list entries span multiple lines;
+       // use source code positions to guide line breaks
+
+       // don't add extra indentation if noIndent is set;
+       // i.e., pretend that the first line is already indented
+       ws := ignore
+       if mode&noIndent == 0 {
+               ws = indent
+       }
+
+       // the first linebreak is always a formfeed since this section must not
+       // depend on any previous formatting
+       prevBreak := -1 // index of last expression that was followed by a linebreak
+       linebreakMin := 1
+       if mode&periodSep != 0 {
+               // Make fragments like
+               //
+               // a.Bar(1,
+               //   2).Foo
+               //
+               // format correctly (a linebreak shouldn't be added before Foo) when
+               // doing period-separated expr lists by setting minimum linebreak to 0
+               // lines for them.
+               linebreakMin = 0
+       }
+       if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, ws, true) {
+               ws = ignore
+               *multiLine = true
+               prevBreak = 0
+       }
+
+       // initialize expression/key size: a zero value indicates expr/key doesn't fit on a single line
+       size := 0
+
+       // print all list elements
+       for i, x := range list {
+               prevLine := line
+               line = x.Pos().Line
+
+               // determine if the next linebreak, if any, needs to use formfeed:
+               // in general, use the entire node size to make the decision; for
+               // key:value expressions, use the key size
+               // TODO(gri) for a better result, should probably incorporate both
+               //           the key and the node size into the decision process
+               useFF := true
+
+               // determine size
+               prevSize := size
+               const infinity = 1e6 // larger than any source line
+               size = p.nodeSize(x, infinity)
+               pair, isPair := x.(*ast.KeyValueExpr)
+               if size <= infinity {
+                       // x fits on a single line
+                       if isPair {
+                               size = p.nodeSize(pair.Key, infinity) // size <= infinity
+                       }
+               } else {
+                       size = 0
+               }
+
+               // if the previous line and the current line had single-
+               // line-expressions and the key sizes are small or the
+               // the ratio between the key sizes does not exceed a
+               // threshold, align columns and do not use formfeed
+               if prevSize > 0 && size > 0 {
+                       const smallSize = 20
+                       if prevSize <= smallSize && size <= smallSize {
+                               useFF = false
+                       } else {
+                               const r = 4 // threshold
+                               ratio := float(size) / float(prevSize)
+                               useFF = ratio <= 1/r || r <= ratio
+                       }
+               }
+
+               if i > 0 {
+                       if mode&commaSep != 0 {
+                               p.print(token.COMMA)
+                       }
+                       if mode&periodSep != 0 {
+                               p.print(token.PERIOD)
+                       }
+                       if prevLine < line && prevLine > 0 && line > 0 {
+                               // lines are broken using newlines so comments remain aligned
+                               // unless forceFF is set or there are multiple expressions on
+                               // the same line in which case formfeed is used
+                               // broken with a formfeed
+                               if p.linebreak(line, linebreakMin, ws, useFF || prevBreak+1 < i) {
+                                       ws = ignore
+                                       *multiLine = true
+                                       prevBreak = i
+                               }
+                       } else if mode&periodSep == 0 {
+                               p.print(blank)
+                       }
+                       // period-separated list elements don't need a blank
+               }
+
+               if isPair && size > 0 && len(list) > 1 {
+                       // we have a key:value expression that fits onto one line and
+                       // is in a list with more then one entry: use a column for the
+                       // key such that consecutive entries can align if possible
+                       p.expr(pair.Key, multiLine)
+                       p.print(pair.Colon, token.COLON, vtab)
+                       p.expr(pair.Value, multiLine)
+               } else {
+                       p.expr0(x, depth, multiLine)
+               }
+       }
+
+       if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line {
+               // print a terminating comma if the next token is on a new line
+               p.print(token.COMMA)
+               if ws == ignore && mode&noIndent == 0 {
+                       // unindent if we indented
+                       p.print(unindent)
+               }
+               p.print(formfeed) // terminating comma needs a line break to look good
+               return
+       }
+
+       if mode&blankEnd != 0 {
+               p.print(blank)
+       }
+
+       if ws == ignore && mode&noIndent == 0 {
+               // unindent if we indented
+               p.print(unindent)
+       }
+}
+
+
+// Sets multiLine to true if the the parameter list spans multiple lines.
+func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
+       p.print(fields.Opening, token.LPAREN)
+       if len(fields.List) > 0 {
+               for i, par := range fields.List {
+                       if i > 0 {
+                               p.print(token.COMMA, blank)
+                       }
+                       if len(par.Names) > 0 {
+                               p.identList(par.Names, false, multiLine)
+                               p.print(blank)
+                       }
+                       p.expr(par.Type, multiLine)
+               }
+       }
+       p.print(fields.Closing, token.RPAREN)
+}
+
+
+// Sets multiLine to true if the signature spans multiple lines.
+func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
+       p.parameters(params, multiLine)
+       n := result.NumFields()
+       if n > 0 {
+               p.print(blank)
+               if n == 1 && result.List[0].Names == nil {
+                       // single anonymous result; no ()'s
+                       p.expr(result.List[0].Type, multiLine)
+                       return
+               }
+               p.parameters(result, multiLine)
+       }
+}
+
+
+func identListSize(list []*ast.Ident, maxSize int) (size int) {
+       for i, x := range list {
+               if i > 0 {
+                       size += 2 // ", "
+               }
+               size += len(x.Name)
+               if size >= maxSize {
+                       break
+               }
+       }
+       return
+}
+
+
+func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
+       if len(list) != 1 {
+               return false // allow only one field
+       }
+       f := list[0]
+       if f.Tag != nil || f.Comment != nil {
+               return false // don't allow tags or comments
+       }
+       // only name(s) and type
+       const maxSize = 30 // adjust as appropriate, this is an approximate value
+       namesSize := identListSize(f.Names, maxSize)
+       if namesSize > 0 {
+               namesSize = 1 // blank between names and types
+       }
+       typeSize := p.nodeSize(f.Type, maxSize)
+       return namesSize+typeSize <= maxSize
+}
+
+
+func (p *printer) setLineComment(text string) {
+       p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{noPos, []byte(text)}}})
+}
+
+
+func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprContext) {
+       p.nesting++
+       defer func() {
+               p.nesting--
+       }()
+
+       lbrace := fields.Opening
+       list := fields.List
+       rbrace := fields.Closing
+
+       if !isIncomplete && !p.commentBefore(rbrace) {
+               // possibly a one-line struct/interface
+               if len(list) == 0 {
+                       // no blank between keyword and {} in this case
+                       p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
+                       return
+               } else if ctxt&(compositeLit|structType) == compositeLit|structType &&
+                       p.isOneLineFieldList(list) { // for now ignore interfaces
+                       // small enough - print on one line
+                       // (don't use identList and ignore source line breaks)
+                       p.print(lbrace, token.LBRACE, blank)
+                       f := list[0]
+                       for i, x := range f.Names {
+                               if i > 0 {
+                                       p.print(token.COMMA, blank)
+                               }
+                               p.expr(x, ignoreMultiLine)
+                       }
+                       if len(f.Names) > 0 {
+                               p.print(blank)
+                       }
+                       p.expr(f.Type, ignoreMultiLine)
+                       p.print(blank, rbrace, token.RBRACE)
+                       return
+               }
+       }
+
+       // at least one entry or incomplete
+       p.print(blank, lbrace, token.LBRACE, indent, formfeed)
+       if ctxt&structType != 0 {
+
+               sep := vtab
+               if len(list) == 1 {
+                       sep = blank
+               }
+               var ml bool
+               for i, f := range list {
+                       if i > 0 {
+                               p.linebreak(f.Pos().Line, 1, ignore, ml)
+                       }
+                       ml = false
+                       extraTabs := 0
+                       p.setComment(f.Doc)
+                       if len(f.Names) > 0 {
+                               // named fields
+                               p.identList(f.Names, false, &ml)
+                               p.print(sep)
+                               p.expr(f.Type, &ml)
+                               extraTabs = 1
+                       } else {
+                               // anonymous field
+                               p.expr(f.Type, &ml)
+                               extraTabs = 2
+                       }
+                       if f.Tag != nil {
+                               if len(f.Names) > 0 && sep == vtab {
+                                       p.print(sep)
+                               }
+                               p.print(sep)
+                               p.expr(f.Tag, &ml)
+                               extraTabs = 0
+                       }
+                       if f.Comment != nil {
+                               for ; extraTabs > 0; extraTabs-- {
+                                       p.print(sep)
+                               }
+                               p.setComment(f.Comment)
+                       }
+               }
+               if isIncomplete {
+                       if len(list) > 0 {
+                               p.print(formfeed)
+                       }
+                       p.flush(rbrace, token.RBRACE) // make sure we don't loose the last line comment
+                       p.setLineComment("// contains unexported fields")
+               }
+
+       } else { // interface
+
+               var ml bool
+               for i, f := range list {
+                       if i > 0 {
+                               p.linebreak(f.Pos().Line, 1, ignore, ml)
+                       }
+                       ml = false
+                       p.setComment(f.Doc)
+                       if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
+                               // method
+                               p.expr(f.Names[0], &ml)
+                               p.signature(ftyp.Params, ftyp.Results, &ml)
+                       } else {
+                               // embedded interface
+                               p.expr(f.Type, &ml)
+                       }
+                       p.setComment(f.Comment)
+               }
+               if isIncomplete {
+                       if len(list) > 0 {
+                               p.print(formfeed)
+                       }
+                       p.flush(rbrace, token.RBRACE) // make sure we don't loose the last line comment
+                       p.setLineComment("// contains unexported methods")
+               }
+
+       }
+       p.print(unindent, formfeed, rbrace, token.RBRACE)
+}
+
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+// exprContext describes the syntactic environment in which an expression node is printed.
+type exprContext uint
+
+const (
+       compositeLit exprContext = 1 << iota
+       structType
+)
+
+
+func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) {
+       switch e.Op.Precedence() {
+       case 5:
+               has5 = true
+       case 6:
+               has6 = true
+       }
+
+       switch l := e.X.(type) {
+       case *ast.BinaryExpr:
+               if l.Op.Precedence() < e.Op.Precedence() {
+                       // parens will be inserted.
+                       // pretend this is an *ast.ParenExpr and do nothing.
+                       break
+               }
+               h5, h6, mp := walkBinary(l)
+               has5 = has5 || h5
+               has6 = has6 || h6
+               if maxProblem < mp {
+                       maxProblem = mp
+               }
+       }
+
+       switch r := e.Y.(type) {
+       case *ast.BinaryExpr:
+               if r.Op.Precedence() <= e.Op.Precedence() {
+                       // parens will be inserted.
+                       // pretend this is an *ast.ParenExpr and do nothing.
+                       break
+               }
+               h5, h6, mp := walkBinary(r)
+               has5 = has5 || h5
+               has6 = has6 || h6
+               if maxProblem < mp {
+                       maxProblem = mp
+               }
+
+       case *ast.StarExpr:
+               if e.Op.String() == "/" {
+                       maxProblem = 6
+               }
+
+       case *ast.UnaryExpr:
+               switch e.Op.String() + r.Op.String() {
+               case "/*", "&&", "&^":
+                       maxProblem = 6
+               case "++", "--":
+                       if maxProblem < 5 {
+                               maxProblem = 5
+                       }
+               }
+       }
+       return
+}
+
+
+func cutoff(e *ast.BinaryExpr, depth int) int {
+       has5, has6, maxProblem := walkBinary(e)
+       if maxProblem > 0 {
+               return maxProblem + 1
+       }
+       if has5 && has6 {
+               if depth == 1 {
+                       return 6
+               }
+               return 5
+       }
+       if depth == 1 {
+               return 7
+       }
+       return 5
+}
+
+
+func diffPrec(expr ast.Expr, prec int) int {
+       x, ok := expr.(*ast.BinaryExpr)
+       if !ok || prec != x.Op.Precedence() {
+               return 1
+       }
+       return 0
+}
+
+
+func reduceDepth(depth int) int {
+       depth--
+       if depth < 1 {
+               depth = 1
+       }
+       return depth
+}
+
+
+// Format the binary expression: decide the cutoff and then format.
+// Let's call depth == 1 Normal mode, and depth > 1 Compact mode.
+// (Algorithm suggestion by Russ Cox.)
+//
+// The precedences are:
+//     6             *  /  %  <<  >>  &  &^
+//     5             +  -  |  ^
+//     4             ==  !=  <  <=  >  >=
+//     3             <-
+//     2             &&
+//     1             ||
+//
+// The only decision is whether there will be spaces around levels 5 and 6.
+// There are never spaces at level 7 (unary), and always spaces at levels 4 and below.
+//
+// To choose the cutoff, look at the whole expression but excluding primary
+// expressions (function calls, parenthesized exprs), and apply these rules:
+//
+//     1) If there is a binary operator with a right side unary operand
+//        that would clash without a space, the cutoff must be (in order):
+//
+//             /*      7
+//             &&      7
+//             &^      7
+//             ++      6
+//             --      6
+//
+//         (Comparison operators always have spaces around them.)
+//
+//     2) If there is a mix of level 6 and level 5 operators, then the cutoff
+//        is 6 (use spaces to distinguish precedence) in Normal mode
+//        and 5 (never use spaces) in Compact mode.
+//
+//     3) If there are no level 5 operators or no level 6 operators, then the
+//        cutoff is 7 (always use spaces) in Normal mode
+//        and 5 (never use spaces) in Compact mode.
+//
+// Sets multiLine to true if the binary expression spans multiple lines.
+func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) {
+       prec := x.Op.Precedence()
+       if prec < prec1 {
+               // parenthesis needed
+               // Note: The parser inserts an ast.ParenExpr node; thus this case
+               //       can only occur if the AST is created in a different way.
+               p.print(token.LPAREN)
+               p.expr0(x, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+               p.print(token.RPAREN)
+               return
+       }
+
+       printBlank := prec < cutoff
+
+       ws := indent
+       p.expr1(x.X, prec, depth+diffPrec(x.X, prec), 0, multiLine)
+       if printBlank {
+               p.print(blank)
+       }
+       xline := p.pos.Line // before the operator (it may be on the next line!)
+       yline := x.Y.Pos().Line
+       p.print(x.OpPos, x.Op)
+       if xline != yline && xline > 0 && yline > 0 {
+               // at least one line break, but respect an extra empty line
+               // in the source
+               if p.linebreak(yline, 1, ws, true) {
+                       ws = ignore
+                       *multiLine = true
+                       printBlank = false // no blank after line break
+               }
+       }
+       if printBlank {
+               p.print(blank)
+       }
+       p.expr1(x.Y, prec+1, depth+1, 0, multiLine)
+       if ws == ignore {
+               p.print(unindent)
+       }
+}
+
+
+func isBinary(expr ast.Expr) bool {
+       _, ok := expr.(*ast.BinaryExpr)
+       return ok
+}
+
+
+// If the expression contains one or more selector expressions, splits it into
+// two expressions at the rightmost period. Writes entire expr to suffix when
+// selector isn't found. Rewrites AST nodes for calls, index expressions and
+// type assertions, all of which may be found in selector chains, to make them
+// parts of the chain.
+func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
+       switch x := expr.(type) {
+       case *ast.SelectorExpr:
+               body, suffix = x.X, x.Sel
+               return
+       case *ast.CallExpr:
+               body, suffix = splitSelector(x.Fun)
+               if body != nil {
+                       suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Ellipsis, x.Rparen}
+                       return
+               }
+       case *ast.IndexExpr:
+               body, suffix = splitSelector(x.X)
+               if body != nil {
+                       suffix = &ast.IndexExpr{suffix, x.Index}
+                       return
+               }
+       case *ast.SliceExpr:
+               body, suffix = splitSelector(x.X)
+               if body != nil {
+                       suffix = &ast.SliceExpr{suffix, x.Index, x.End}
+                       return
+               }
+       case *ast.TypeAssertExpr:
+               body, suffix = splitSelector(x.X)
+               if body != nil {
+                       suffix = &ast.TypeAssertExpr{suffix, x.Type}
+                       return
+               }
+       }
+       suffix = expr
+       return
+}
+
+
+// Convert an expression into an expression list split at the periods of
+// selector expressions.
+func selectorExprList(expr ast.Expr) (list []ast.Expr) {
+       // split expression
+       for expr != nil {
+               var suffix ast.Expr
+               expr, suffix = splitSelector(expr)
+               list = append(list, suffix)
+       }
+
+       // reverse list
+       for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
+               list[i], list[j] = list[j], list[i]
+       }
+
+       return
+}
+
+
+// Sets multiLine to true if the expression spans multiple lines.
+func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multiLine *bool) {
+       p.print(expr.Pos())
+
+       switch x := expr.(type) {
+       case *ast.BadExpr:
+               p.print("BadExpr")
+
+       case *ast.Ident:
+               p.print(x)
+
+       case *ast.BinaryExpr:
+               if depth < 1 {
+                       p.internalError("depth < 1:", depth)
+                       depth = 1
+               }
+               p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine)
+
+       case *ast.KeyValueExpr:
+               p.expr(x.Key, multiLine)
+               p.print(x.Colon, token.COLON, blank)
+               p.expr(x.Value, multiLine)
+
+       case *ast.StarExpr:
+               const prec = token.UnaryPrec
+               if prec < prec1 {
+                       // parenthesis needed
+                       p.print(token.LPAREN)
+                       p.print(token.MUL)
+                       p.expr(x.X, multiLine)
+                       p.print(token.RPAREN)
+               } else {
+                       // no parenthesis needed
+                       p.print(token.MUL)
+                       p.expr(x.X, multiLine)
+               }
+
+       case *ast.UnaryExpr:
+               const prec = token.UnaryPrec
+               if prec < prec1 {
+                       // parenthesis needed
+                       p.print(token.LPAREN)
+                       p.expr(x, multiLine)
+                       p.print(token.RPAREN)
+               } else {
+                       // no parenthesis needed
+                       p.print(x.Op)
+                       if x.Op == token.RANGE {
+                               // TODO(gri) Remove this code if it cannot be reached.
+                               p.print(blank)
+                       }
+                       p.expr1(x.X, prec, depth, 0, multiLine)
+               }
+
+       case *ast.BasicLit:
+               p.print(x)
+
+       case *ast.FuncLit:
+               p.expr(x.Type, multiLine)
+               p.funcBody(x.Body, distance(x.Type.Pos(), p.pos), true, multiLine)
+
+       case *ast.ParenExpr:
+               if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
+                       // don't print parentheses around an already parenthesized expression
+                       // TODO(gri) consider making this more general and incorporate precedence levels
+                       p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+               } else {
+                       p.print(token.LPAREN)
+                       p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+                       p.print(x.Rparen, token.RPAREN)
+               }
+
+       case *ast.SelectorExpr:
+               parts := selectorExprList(expr)
+               p.exprList(noPos, parts, depth, periodSep, multiLine, noPos)
+
+       case *ast.TypeAssertExpr:
+               p.expr1(x.X, token.HighestPrec, depth, 0, multiLine)
+               p.print(token.PERIOD, token.LPAREN)
+               if x.Type != nil {
+                       p.expr(x.Type, multiLine)
+               } else {
+                       p.print(token.TYPE)
+               }
+               p.print(token.RPAREN)
+
+       case *ast.IndexExpr:
+               // TODO(gri): should treat[] like parentheses and undo one level of depth
+               p.expr1(x.X, token.HighestPrec, 1, 0, multiLine)
+               p.print(token.LBRACK)
+               p.expr0(x.Index, depth+1, multiLine)
+               p.print(token.RBRACK)
+
+       case *ast.SliceExpr:
+               // TODO(gri): should treat[] like parentheses and undo one level of depth
+               p.expr1(x.X, token.HighestPrec, 1, 0, multiLine)
+               p.print(token.LBRACK)
+               if x.Index != nil {
+                       p.expr0(x.Index, depth+1, multiLine)
+               }
+               // blanks around ":" if both sides exist and either side is a binary expression
+               if depth <= 1 && x.Index != nil && x.End != nil && (isBinary(x.Index) || isBinary(x.End)) {
+                       p.print(blank, token.COLON, blank)
+               } else {
+                       p.print(token.COLON)
+               }
+               if x.End != nil {
+                       p.expr0(x.End, depth+1, multiLine)
+               }
+               p.print(token.RBRACK)
+
+       case *ast.CallExpr:
+               if len(x.Args) > 1 {
+                       depth++
+               }
+               p.expr1(x.Fun, token.HighestPrec, depth, 0, multiLine)
+               p.print(x.Lparen, token.LPAREN)
+               p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
+               if x.Ellipsis.IsValid() {
+                       p.print(x.Ellipsis, token.ELLIPSIS)
+               }
+               p.print(x.Rparen, token.RPAREN)
+
+       case *ast.CompositeLit:
+               // composite literal elements that are composite literals themselves may have the type omitted
+               if x.Type != nil {
+                       p.expr1(x.Type, token.HighestPrec, depth, compositeLit, multiLine)
+               }
+               p.print(x.Lbrace, token.LBRACE)
+               p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
+               p.print(x.Rbrace, token.RBRACE)
+
+       case *ast.Ellipsis:
+               p.print(token.ELLIPSIS)
+               if x.Elt != nil {
+                       p.expr(x.Elt, multiLine)
+               }
+
+       case *ast.ArrayType:
+               p.print(token.LBRACK)
+               if x.Len != nil {
+                       p.expr(x.Len, multiLine)
+               }
+               p.print(token.RBRACK)
+               p.expr(x.Elt, multiLine)
+
+       case *ast.StructType:
+               p.print(token.STRUCT)
+               p.fieldList(x.Fields, x.Incomplete, ctxt|structType)
+
+       case *ast.FuncType:
+               p.print(token.FUNC)
+               p.signature(x.Params, x.Results, multiLine)
+
+       case *ast.InterfaceType:
+               p.print(token.INTERFACE)
+               p.fieldList(x.Methods, x.Incomplete, ctxt)
+
+       case *ast.MapType:
+               p.print(token.MAP, token.LBRACK)
+               p.expr(x.Key, multiLine)
+               p.print(token.RBRACK)
+               p.expr(x.Value, multiLine)
+
+       case *ast.ChanType:
+               switch x.Dir {
+               case ast.SEND | ast.RECV:
+                       p.print(token.CHAN)
+               case ast.RECV:
+                       p.print(token.ARROW, token.CHAN)
+               case ast.SEND:
+                       p.print(token.CHAN, token.ARROW)
+               }
+               p.print(blank)
+               p.expr(x.Value, multiLine)
+
+       default:
+               panic("unreachable")
+       }
+
+       return
+}
+
+
+func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
+       p.expr1(x, token.LowestPrec, depth, 0, multiLine)
+}
+
+
+// Sets multiLine to true if the expression spans multiple lines.
+func (p *printer) expr(x ast.Expr, multiLine *bool) {
+       const depth = 1
+       p.expr1(x, token.LowestPrec, depth, 0, multiLine)
+}
+
+
+// ----------------------------------------------------------------------------
+// Statements
+
+// Print the statement list indented, but without a newline after the last statement.
+// Extra line breaks between statements in the source are respected but at most one
+// empty line is printed between statements.
+func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
+       // TODO(gri): fix _indent code
+       if _indent > 0 {
+               p.print(indent)
+       }
+       var multiLine bool
+       for i, s := range list {
+               // _indent == 0 only for lists of switch/select case clauses;
+               // in those cases each clause is a new section
+               p.linebreak(s.Pos().Line, 1, ignore, i == 0 || _indent == 0 || multiLine)
+               multiLine = false
+               p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
+       }
+       if _indent > 0 {
+               p.print(unindent)
+       }
+}
+
+
+// block prints an *ast.BlockStmt; it always spans at least two lines.
+func (p *printer) block(s *ast.BlockStmt, indent int) {
+       p.print(s.Pos(), token.LBRACE)
+       p.stmtList(s.List, indent, true)
+       p.linebreak(s.Rbrace.Line, 1, ignore, true)
+       p.print(s.Rbrace, token.RBRACE)
+}
+
+
+func isTypeName(x ast.Expr) bool {
+       switch t := x.(type) {
+       case *ast.Ident:
+               return true
+       case *ast.SelectorExpr:
+               return isTypeName(t.X)
+       }
+       return false
+}
+
+
+func stripParens(x ast.Expr) ast.Expr {
+       if px, strip := x.(*ast.ParenExpr); strip {
+               // parentheses must not be stripped if there are any
+               // unparenthesized composite literals starting with
+               // a type name
+               ast.Inspect(px.X, func(node interface{}) bool {
+                       switch x := node.(type) {
+                       case *ast.ParenExpr:
+                               // parentheses protect enclosed composite literals
+                               return false
+                       case *ast.CompositeLit:
+                               if isTypeName(x.Type) {
+                                       strip = false // do not strip parentheses
+                               }
+                               return false
+                       }
+                       // in all other cases, keep inspecting
+                       return true
+               })
+               if strip {
+                       return stripParens(px.X)
+               }
+       }
+       return x
+}
+
+
+func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
+       p.print(blank)
+       needsBlank := false
+       if init == nil && post == nil {
+               // no semicolons required
+               if expr != nil {
+                       p.expr(stripParens(expr), ignoreMultiLine)
+                       needsBlank = true
+               }
+       } else {
+               // all semicolons required
+               // (they are not separators, print them explicitly)
+               if init != nil {
+                       p.stmt(init, false, ignoreMultiLine)
+               }
+               p.print(token.SEMICOLON, blank)
+               if expr != nil {
+                       p.expr(stripParens(expr), ignoreMultiLine)
+                       needsBlank = true
+               }
+               if isForStmt {
+                       p.print(token.SEMICOLON, blank)
+                       needsBlank = false
+                       if post != nil {
+                               p.stmt(post, false, ignoreMultiLine)
+                               needsBlank = true
+                       }
+               }
+       }
+       if needsBlank {
+               p.print(blank)
+       }
+}
+
+
+// Sets multiLine to true if the statements spans multiple lines.
+func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
+       p.print(stmt.Pos())
+
+       switch s := stmt.(type) {
+       case *ast.BadStmt:
+               p.print("BadStmt")
+
+       case *ast.DeclStmt:
+               p.decl(s.Decl, multiLine)
+
+       case *ast.EmptyStmt:
+               // nothing to do
+
+       case *ast.LabeledStmt:
+               // a "correcting" unindent immediately following a line break
+               // is applied before the line break if there is no comment
+               // between (see writeWhitespace)
+               p.print(unindent)
+               p.expr(s.Label, multiLine)
+               p.print(token.COLON, indent)
+               if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
+                       if !nextIsRBrace {
+                               p.print(newline, e.Pos(), token.SEMICOLON)
+                               break
+                       }
+               } else {
+                       p.linebreak(s.Stmt.Pos().Line, 1, ignore, true)
+               }
+               p.stmt(s.Stmt, nextIsRBrace, multiLine)
+
+       case *ast.ExprStmt:
+               const depth = 1
+               p.expr0(s.X, depth, multiLine)
+
+       case *ast.IncDecStmt:
+               const depth = 1
+               p.expr0(s.X, depth+1, multiLine)
+               p.print(s.Tok)
+
+       case *ast.AssignStmt:
+               var depth = 1
+               if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
+                       depth++
+               }
+               p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos)
+               p.print(blank, s.TokPos, s.Tok)
+               p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, noPos)
+
+       case *ast.GoStmt:
+               p.print(token.GO, blank)
+               p.expr(s.Call, multiLine)
+
+       case *ast.DeferStmt:
+               p.print(token.DEFER, blank)
+               p.expr(s.Call, multiLine)
+
+       case *ast.ReturnStmt:
+               p.print(token.RETURN)
+               if s.Results != nil {
+                       p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, noPos)
+               }
+
+       case *ast.BranchStmt:
+               p.print(s.Tok)
+               if s.Label != nil {
+                       p.print(blank)
+                       p.expr(s.Label, multiLine)
+               }
+
+       case *ast.BlockStmt:
+               p.block(s, 1)
+               *multiLine = true
+
+       case *ast.IfStmt:
+               p.print(token.IF)
+               p.controlClause(false, s.Init, s.Cond, nil)
+               p.block(s.Body, 1)
+               *multiLine = true
+               if s.Else != nil {
+                       p.print(blank, token.ELSE, blank)
+                       switch s.Else.(type) {
+                       case *ast.BlockStmt, *ast.IfStmt:
+                               p.stmt(s.Else, nextIsRBrace, ignoreMultiLine)
+                       default:
+                               p.print(token.LBRACE, indent, formfeed)
+                               p.stmt(s.Else, true, ignoreMultiLine)
+                               p.print(unindent, formfeed, token.RBRACE)
+                       }
+               }
+
+       case *ast.CaseClause:
+               if s.Values != nil {
+                       p.print(token.CASE)
+                       p.exprList(s.Pos(), s.Values, 1, blankStart|commaSep, multiLine, s.Colon)
+               } else {
+                       p.print(token.DEFAULT)
+               }
+               p.print(s.Colon, token.COLON)
+               p.stmtList(s.Body, 1, nextIsRBrace)
+
+       case *ast.SwitchStmt:
+               p.print(token.SWITCH)
+               p.controlClause(false, s.Init, s.Tag, nil)
+               p.block(s.Body, 0)
+               *multiLine = true
+
+       case *ast.TypeCaseClause:
+               if s.Types != nil {
+                       p.print(token.CASE)
+                       p.exprList(s.Pos(), s.Types, 1, blankStart|commaSep, multiLine, s.Colon)
+               } else {
+                       p.print(token.DEFAULT)
+               }
+               p.print(s.Colon, token.COLON)
+               p.stmtList(s.Body, 1, nextIsRBrace)
+
+       case *ast.TypeSwitchStmt:
+               p.print(token.SWITCH)
+               if s.Init != nil {
+                       p.print(blank)
+                       p.stmt(s.Init, false, ignoreMultiLine)
+                       p.print(token.SEMICOLON)
+               }
+               p.print(blank)
+               p.stmt(s.Assign, false, ignoreMultiLine)
+               p.print(blank)
+               p.block(s.Body, 0)
+               *multiLine = true
+
+       case *ast.CommClause:
+               if s.Rhs != nil {
+                       p.print(token.CASE, blank)
+                       if s.Lhs != nil {
+                               p.expr(s.Lhs, multiLine)
+                               p.print(blank, s.Tok, blank)
+                       }
+                       p.expr(s.Rhs, multiLine)
+               } else {
+                       p.print(token.DEFAULT)
+               }
+               p.print(s.Colon, token.COLON)
+               p.stmtList(s.Body, 1, nextIsRBrace)
+
+       case *ast.SelectStmt:
+               p.print(token.SELECT, blank)
+               p.block(s.Body, 0)
+               *multiLine = true
+
+       case *ast.ForStmt:
+               p.print(token.FOR)
+               p.controlClause(true, s.Init, s.Cond, s.Post)
+               p.block(s.Body, 1)
+               *multiLine = true
+
+       case *ast.RangeStmt:
+               p.print(token.FOR, blank)
+               p.expr(s.Key, multiLine)
+               if s.Value != nil {
+                       p.print(token.COMMA, blank)
+                       p.expr(s.Value, multiLine)
+               }
+               p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
+               p.expr(stripParens(s.X), multiLine)
+               p.print(blank)
+               p.block(s.Body, 1)
+               *multiLine = true
+
+       default:
+               panic("unreachable")
+       }
+
+       return
+}
+
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// The parameter n is the number of specs in the group. If doIndent is set,
+// multi-line identifier lists in the spec are indented when the first
+// linebreak is encountered.
+// Sets multiLine to true if the spec spans multiple lines.
+//
+func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
+       switch s := spec.(type) {
+       case *ast.ImportSpec:
+               p.setComment(s.Doc)
+               if s.Name != nil {
+                       p.expr(s.Name, multiLine)
+                       p.print(vtab)
+               }
+               p.expr(s.Path, multiLine)
+               p.setComment(s.Comment)
+
+       case *ast.ValueSpec:
+               p.setComment(s.Doc)
+               p.identList(s.Names, doIndent, multiLine) // always present
+               if n == 1 {
+                       if s.Type != nil {
+                               p.print(blank)
+                               p.expr(s.Type, multiLine)
+                       }
+                       if s.Values != nil {
+                               p.print(blank, token.ASSIGN)
+                               p.exprList(noPos, s.Values, 1, blankStart|commaSep, multiLine, noPos)
+                       }
+                       p.setComment(s.Comment)
+
+               } else {
+                       extraTabs := 3
+                       if s.Type != nil {
+                               p.print(vtab)
+                               p.expr(s.Type, multiLine)
+                               extraTabs--
+                       }
+                       if s.Values != nil {
+                               p.print(vtab, token.ASSIGN)
+                               p.exprList(noPos, s.Values, 1, blankStart|commaSep, multiLine, noPos)
+                               extraTabs--
+                       }
+                       if s.Comment != nil {
+                               for ; extraTabs > 0; extraTabs-- {
+                                       p.print(vtab)
+                               }
+                               p.setComment(s.Comment)
+                       }
+               }
+
+       case *ast.TypeSpec:
+               p.setComment(s.Doc)
+               p.expr(s.Name, multiLine)
+               if n == 1 {
+                       p.print(blank)
+               } else {
+                       p.print(vtab)
+               }
+               p.expr(s.Type, multiLine)
+               p.setComment(s.Comment)
+
+       default:
+               panic("unreachable")
+       }
+}
+
+
+// Sets multiLine to true if the declaration spans multiple lines.
+func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
+       p.setComment(d.Doc)
+       p.print(d.Pos(), d.Tok, blank)
+
+       if d.Lparen.IsValid() {
+               // group of parenthesized declarations
+               p.print(d.Lparen, token.LPAREN)
+               if len(d.Specs) > 0 {
+                       p.print(indent, formfeed)
+                       var ml bool
+                       for i, s := range d.Specs {
+                               if i > 0 {
+                                       p.linebreak(s.Pos().Line, 1, ignore, ml)
+                               }
+                               ml = false
+                               p.spec(s, len(d.Specs), false, &ml)
+                       }
+                       p.print(unindent, formfeed)
+                       *multiLine = true
+               }
+               p.print(d.Rparen, token.RPAREN)
+
+       } else {
+               // single declaration
+               p.spec(d.Specs[0], 1, true, multiLine)
+       }
+}
+
+
+// nodeSize determines the size of n in chars after formatting.
+// The result is <= maxSize if the node fits on one line with at
+// most maxSize chars and the formatted output doesn't contain
+// any control chars. Otherwise, the result is > maxSize.
+//
+func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
+       size = maxSize + 1 // assume n doesn't fit
+       // nodeSize computation must be indendent of particular
+       // style so that we always get the same decision; print
+       // in RawFormat
+       cfg := Config{Mode: RawFormat}
+       var buf bytes.Buffer
+       if _, err := cfg.Fprint(&buf, n); err != nil {
+               return
+       }
+       if buf.Len() <= maxSize {
+               for _, ch := range buf.Bytes() {
+                       if ch < ' ' {
+                               return
+                       }
+               }
+               size = buf.Len() // n fits
+       }
+       return
+}
+
+
+func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
+       pos1 := b.Pos()
+       pos2 := b.Rbrace
+       if pos1.IsValid() && pos2.IsValid() && pos1.Line != pos2.Line {
+               // opening and closing brace are on different lines - don't make it a one-liner
+               return false
+       }
+       if len(b.List) > 5 || p.commentBefore(pos2) {
+               // too many statements or there is a comment inside - don't make it a one-liner
+               return false
+       }
+       // otherwise, estimate body size
+       const maxSize = 100
+       bodySize := 0
+       for i, s := range b.List {
+               if i > 0 {
+                       bodySize += 2 // space for a semicolon and blank
+               }
+               bodySize += p.nodeSize(s, maxSize)
+       }
+       return headerSize+bodySize <= maxSize
+}
+
+
+// Sets multiLine to true if the function body spans multiple lines.
+func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) {
+       if b == nil {
+               return
+       }
+
+       p.nesting++
+       defer func() {
+               p.nesting--
+       }()
+
+       if p.isOneLineFunc(b, headerSize) {
+               sep := vtab
+               if isLit {
+                       sep = blank
+               }
+               p.print(sep, b.Pos(), token.LBRACE)
+               if len(b.List) > 0 {
+                       p.print(blank)
+                       for i, s := range b.List {
+                               if i > 0 {
+                                       p.print(token.SEMICOLON, blank)
+                               }
+                               p.stmt(s, i == len(b.List)-1, ignoreMultiLine)
+                       }
+                       p.print(blank)
+               }
+               p.print(b.Rbrace, token.RBRACE)
+               return
+       }
+
+       p.print(blank)
+       p.block(b, 1)
+       *multiLine = true
+}
+
+
+// distance returns the column difference between from and to if both
+// are on the same line; if they are on different lines (or unknown)
+// the result is infinity.
+func distance(from, to token.Position) int {
+       if from.IsValid() && to.IsValid() && from.Line == to.Line {
+               return to.Column - from.Column
+       }
+       return infinity
+}
+
+
+// Sets multiLine to true if the declaration spans multiple lines.
+func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
+       p.setComment(d.Doc)
+       p.print(d.Pos(), token.FUNC, blank)
+       if d.Recv != nil {
+               p.parameters(d.Recv, multiLine) // method: print receiver
+               p.print(blank)
+       }
+       p.expr(d.Name, multiLine)
+       p.signature(d.Type.Params, d.Type.Results, multiLine)
+       p.funcBody(d.Body, distance(d.Pos(), p.pos), false, multiLine)
+}
+
+
+// Sets multiLine to true if the declaration spans multiple lines.
+func (p *printer) decl(decl ast.Decl, multiLine *bool) {
+       switch d := decl.(type) {
+       case *ast.BadDecl:
+               p.print(d.Pos(), "BadDecl")
+       case *ast.GenDecl:
+               p.genDecl(d, multiLine)
+       case *ast.FuncDecl:
+               p.funcDecl(d, multiLine)
+       default:
+               panic("unreachable")
+       }
+}
+
+
+// ----------------------------------------------------------------------------
+// Files
+
+func declToken(decl ast.Decl) (tok token.Token) {
+       tok = token.ILLEGAL
+       switch d := decl.(type) {
+       case *ast.GenDecl:
+               tok = d.Tok
+       case *ast.FuncDecl:
+               tok = token.FUNC
+       }
+       return
+}
+
+
+func (p *printer) file(src *ast.File) {
+       p.setComment(src.Doc)
+       p.print(src.Pos(), token.PACKAGE, blank)
+       p.expr(src.Name, ignoreMultiLine)
+
+       if len(src.Decls) > 0 {
+               tok := token.ILLEGAL
+               for _, d := range src.Decls {
+                       prev := tok
+                       tok = declToken(d)
+                       // if the declaration token changed (e.g., from CONST to TYPE)
+                       // print an empty line between top-level declarations
+                       min := 1
+                       if prev != tok {
+                               min = 2
+                       }
+                       p.linebreak(d.Pos().Line, min, ignore, false)
+                       p.decl(d, ignoreMultiLine)
+               }
+       }
+
+       p.print(newline)
+}
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
new file mode 100644 (file)
index 0000000..f8b5871
--- /dev/null
@@ -0,0 +1,1117 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The printer package implements printing of AST nodes.
+package printer
+
+import (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/token"
+       "io"
+       "os"
+       "path"
+       "runtime"
+       "tabwriter"
+)
+
+
+const debug = false // enable for debugging
+
+
+type whiteSpace int
+
+const (
+       ignore   = whiteSpace(0)
+       blank    = whiteSpace(' ')
+       vtab     = whiteSpace('\v')
+       newline  = whiteSpace('\n')
+       formfeed = whiteSpace('\f')
+       indent   = whiteSpace('>')
+       unindent = whiteSpace('<')
+)
+
+
+var (
+       esc       = []byte{tabwriter.Escape}
+       htab      = []byte{'\t'}
+       htabs     = []byte("\t\t\t\t\t\t\t\t")
+       newlines  = []byte("\n\n\n\n\n\n\n\n") // more than the max determined by nlines
+       formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
+
+       esc_quot = []byte("&#34;") // shorter than "&quot;"
+       esc_apos = []byte("&#39;") // shorter than "&apos;"
+       esc_amp  = []byte("&amp;")
+       esc_lt   = []byte("&lt;")
+       esc_gt   = []byte("&gt;")
+)
+
+
+// Special positions
+var noPos token.Position // use noPos when a position is needed but not known
+var infinity = 1 << 30
+
+
+// Use ignoreMultiLine if the multiLine information is not important.
+var ignoreMultiLine = new(bool)
+
+
+type printer struct {
+       // Configuration (does not change after initialization)
+       output io.Writer
+       Config
+       errors chan os.Error
+
+       // Current state
+       nesting int         // nesting level (0: top-level (package scope), >0: functions/decls.)
+       written int         // number of bytes written
+       indent  int         // current indentation
+       escape  bool        // true if in escape sequence
+       lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
+
+       // Buffered whitespace
+       buffer []whiteSpace
+
+       // The (possibly estimated) position in the generated output;
+       // in AST space (i.e., pos is set whenever a token position is
+       // known accurately, and updated dependending on what has been
+       // written).
+       pos token.Position
+
+       // The value of pos immediately after the last item has been
+       // written using writeItem.
+       last token.Position
+
+       // HTML support
+       lastTaggedLine int // last line for which a line tag was written
+
+       // The list of all source comments, in order of appearance.
+       comments        []*ast.CommentGroup // may be nil
+       cindex          int                 // current comment index
+       useNodeComments bool                // if not set, ignore lead and line comments of nodes
+}
+
+
+func (p *printer) init(output io.Writer, cfg *Config) {
+       p.output = output
+       p.Config = *cfg
+       p.errors = make(chan os.Error)
+       p.buffer = make([]whiteSpace, 0, 16) // whitespace sequences are short
+}
+
+
+func (p *printer) internalError(msg ...interface{}) {
+       if debug {
+               fmt.Print(p.pos.String() + ": ")
+               fmt.Println(msg...)
+               panic("go/printer")
+       }
+}
+
+
+// nlines returns the adjusted number of linebreaks given the desired number
+// of breaks n such that min <= result <= max where max depends on the current
+// nesting level.
+//
+func (p *printer) nlines(n, min int) int {
+       if n < min {
+               return min
+       }
+       max := 3 // max. number of newlines at the top level (p.nesting == 0)
+       if p.nesting > 0 {
+               max = 2 // max. number of newlines everywhere else
+       }
+       if n > max {
+               return max
+       }
+       return n
+}
+
+
+// write0 writes raw (uninterpreted) data to p.output and handles errors.
+// write0 does not indent after newlines, and does not HTML-escape or update p.pos.
+//
+func (p *printer) write0(data []byte) {
+       n, err := p.output.Write(data)
+       p.written += n
+       if err != nil {
+               p.errors <- err
+               runtime.Goexit()
+       }
+}
+
+
+// write interprets data and writes it to p.output. It inserts indentation
+// after a line break unless in a tabwriter escape sequence, and it HTML-
+// escapes characters if GenHTML is set. It updates p.pos as a side-effect.
+//
+func (p *printer) write(data []byte) {
+       i0 := 0
+       for i, b := range data {
+               switch b {
+               case '\n', '\f':
+                       // write segment ending in b
+                       p.write0(data[i0 : i+1])
+
+                       // update p.pos
+                       p.pos.Offset += i + 1 - i0
+                       p.pos.Line++
+                       p.pos.Column = 1
+
+                       if !p.escape {
+                               // write indentation
+                               // use "hard" htabs - indentation columns
+                               // must not be discarded by the tabwriter
+                               j := p.indent
+                               for ; j > len(htabs); j -= len(htabs) {
+                                       p.write0(htabs)
+                               }
+                               p.write0(htabs[0:j])
+
+                               // update p.pos
+                               p.pos.Offset += p.indent
+                               p.pos.Column += p.indent
+                       }
+
+                       // next segment start
+                       i0 = i + 1
+
+               case '"', '\'', '&', '<', '>':
+                       if p.Mode&GenHTML != 0 {
+                               // write segment ending in b
+                               p.write0(data[i0:i])
+
+                               // write HTML-escaped b
+                               var esc []byte
+                               switch b {
+                               case '"':
+                                       esc = esc_quot
+                               case '\'':
+                                       esc = esc_apos
+                               case '&':
+                                       esc = esc_amp
+                               case '<':
+                                       esc = esc_lt
+                               case '>':
+                                       esc = esc_gt
+                               }
+                               p.write0(esc)
+
+                               // update p.pos
+                               d := i + 1 - i0
+                               p.pos.Offset += d
+                               p.pos.Column += d
+
+                               // next segment start
+                               i0 = i + 1
+                       }
+
+               case tabwriter.Escape:
+                       p.escape = !p.escape
+
+                       // ignore escape chars introduced by printer - they are
+                       // invisible and must not affect p.pos (was issue #1089)
+                       p.pos.Offset--
+                       p.pos.Column--
+               }
+       }
+
+       // write remaining segment
+       p.write0(data[i0:])
+
+       // update p.pos
+       d := len(data) - i0
+       p.pos.Offset += d
+       p.pos.Column += d
+}
+
+
+func (p *printer) writeNewlines(n int, useFF bool) {
+       if n > 0 {
+               n = p.nlines(n, 0)
+               if useFF {
+                       p.write(formfeeds[0:n])
+               } else {
+                       p.write(newlines[0:n])
+               }
+       }
+}
+
+
+func (p *printer) writeTaggedItem(data []byte, tag HTMLTag) {
+       // write start tag, if any
+       // (no html-escaping and no p.pos update for tags - use write0)
+       if tag.Start != "" {
+               p.write0([]byte(tag.Start))
+       }
+       p.write(data)
+       // write end tag, if any
+       if tag.End != "" {
+               p.write0([]byte(tag.End))
+       }
+}
+
+
+// writeItem writes data at position pos. data is the text corresponding to
+// a single lexical token, but may also be comment text. pos is the actual
+// (or at least very accurately estimated) position of the data in the original
+// source text. If tags are present and GenHTML is set, the tags are written
+// before and after the data. writeItem updates p.last to the position
+// immediately following the data.
+//
+func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
+       fileChanged := false
+       if pos.IsValid() {
+               // continue with previous position if we don't have a valid pos
+               if p.last.IsValid() && p.last.Filename != pos.Filename {
+                       // the file has changed - reset state
+                       // (used when printing merged ASTs of different files
+                       // e.g., the result of ast.MergePackageFiles)
+                       p.indent = 0
+                       p.escape = false
+                       p.buffer = p.buffer[0:0]
+                       fileChanged = true
+               }
+               p.pos = pos
+       }
+       if debug {
+               // do not update p.pos - use write0
+               _, filename := path.Split(pos.Filename)
+               p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column)))
+       }
+       if p.Mode&GenHTML != 0 {
+               // write line tag if on a new line
+               // TODO(gri): should write line tags on each line at the start
+               //            will be more useful (e.g. to show line numbers)
+               if p.Styler != nil && (pos.Line != p.lastTaggedLine || fileChanged) {
+                       p.writeTaggedItem(p.Styler.LineTag(pos.Line))
+                       p.lastTaggedLine = pos.Line
+               }
+               p.writeTaggedItem(data, tag)
+       } else {
+               p.write(data)
+       }
+       p.last = p.pos
+}
+
+
+// writeCommentPrefix writes the whitespace before a comment.
+// If there is any pending whitespace, it consumes as much of
+// it as is likely to help position the comment nicely.
+// pos is the comment position, next the position of the item
+// after all pending comments, isFirst indicates if this is the
+// first comment in a group of comments, and isKeyword indicates
+// if the next item is a keyword.
+//
+func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeyword bool) {
+       if !p.last.IsValid() {
+               // there was no preceeding item and the comment is the
+               // first item to be printed - don't write any whitespace
+               return
+       }
+
+       if pos.IsValid() && pos.Filename != p.last.Filename {
+               // comment in a different file - separate with newlines (writeNewlines will limit the number)
+               p.writeNewlines(10, true)
+               return
+       }
+
+       if pos.IsValid() && pos.Line == p.last.Line {
+               // comment on the same line as last item:
+               // separate with at least one separator
+               hasSep := false
+               if isFirst {
+                       j := 0
+                       for i, ch := range p.buffer {
+                               switch ch {
+                               case blank:
+                                       // ignore any blanks before a comment
+                                       p.buffer[i] = ignore
+                                       continue
+                               case vtab:
+                                       // respect existing tabs - important
+                                       // for proper formatting of commented structs
+                                       hasSep = true
+                                       continue
+                               case indent:
+                                       // apply pending indentation
+                                       continue
+                               }
+                               j = i
+                               break
+                       }
+                       p.writeWhitespace(j)
+               }
+               // make sure there is at least one separator
+               if !hasSep {
+                       if pos.Line == next.Line {
+                               // next item is on the same line as the comment
+                               // (which must be a /*-style comment): separate
+                               // with a blank instead of a tab
+                               p.write([]byte{' '})
+                       } else {
+                               p.write(htab)
+                       }
+               }
+
+       } else {
+               // comment on a different line:
+               // separate with at least one line break
+               if isFirst {
+                       j := 0
+                       for i, ch := range p.buffer {
+                               switch ch {
+                               case blank, vtab:
+                                       // ignore any horizontal whitespace before line breaks
+                                       p.buffer[i] = ignore
+                                       continue
+                               case indent:
+                                       // apply pending indentation
+                                       continue
+                               case unindent:
+                                       // if the next token is a keyword, apply the outdent
+                                       // if it appears that the comment is aligned with the
+                                       // keyword; otherwise assume the outdent is part of a
+                                       // closing block and stop (this scenario appears with
+                                       // comments before a case label where the comments
+                                       // apply to the next case instead of the current one)
+                                       if isKeyword && pos.Column == next.Column {
+                                               continue
+                                       }
+                               case newline, formfeed:
+                                       // TODO(gri): may want to keep formfeed info in some cases
+                                       p.buffer[i] = ignore
+                               }
+                               j = i
+                               break
+                       }
+                       p.writeWhitespace(j)
+               }
+               // use formfeeds to break columns before a comment;
+               // this is analogous to using formfeeds to separate
+               // individual lines of /*-style comments
+               // (if !pos.IsValid(), pos.Line == 0, and this will
+               // print no newlines)
+               p.writeNewlines(pos.Line-p.last.Line, true)
+       }
+}
+
+
+func (p *printer) writeCommentLine(comment *ast.Comment, pos token.Position, line []byte) {
+       // line must pass through unchanged, bracket it with tabwriter.Escape
+       line = bytes.Join([][]byte{esc, line, esc}, nil)
+
+       // apply styler, if any
+       var tag HTMLTag
+       if p.Styler != nil {
+               line, tag = p.Styler.Comment(comment, line)
+       }
+
+       p.writeItem(pos, line, tag)
+}
+
+
+// TODO(gri): Similar (but not quite identical) functionality for
+//            comment processing can be found in go/doc/comment.go.
+//            Perhaps this can be factored eventually.
+
+// Split comment text into lines
+func split(text []byte) [][]byte {
+       // count lines (comment text never ends in a newline)
+       n := 1
+       for _, c := range text {
+               if c == '\n' {
+                       n++
+               }
+       }
+
+       // split
+       lines := make([][]byte, n)
+       n = 0
+       i := 0
+       for j, c := range text {
+               if c == '\n' {
+                       lines[n] = text[i:j] // exclude newline
+                       i = j + 1            // discard newline
+                       n++
+               }
+       }
+       lines[n] = text[i:]
+
+       return lines
+}
+
+
+func isBlank(s []byte) bool {
+       for _, b := range s {
+               if b > ' ' {
+                       return false
+               }
+       }
+       return true
+}
+
+
+func commonPrefix(a, b []byte) []byte {
+       i := 0
+       for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
+               i++
+       }
+       return a[0:i]
+}
+
+
+func stripCommonPrefix(lines [][]byte) {
+       if len(lines) < 2 {
+               return // at most one line - nothing to do
+       }
+       // len(lines) >= 2
+
+       // The heuristic in this function tries to handle a few
+       // common patterns of /*-style comments: Comments where
+       // the opening /* and closing */ are aligned and the
+       // rest of the comment text is aligned and indented with
+       // blanks or tabs, cases with a vertical "line of stars"
+       // on the left, and cases where the closing */ is on the
+       // same line as the last comment text.
+
+       // Compute maximum common white prefix of all but the first,
+       // last, and blank lines, and replace blank lines with empty
+       // lines (the first line starts with /* and has no prefix).
+       // In case of two-line comments, consider the last line for
+       // the prefix computation since otherwise the prefix would
+       // be empty.
+       //
+       // Note that the first and last line are never empty (they
+       // contain the opening /* and closing */ respectively) and
+       // thus they can be ignored by the blank line check.
+       var prefix []byte
+       if len(lines) > 2 {
+               for i, line := range lines[1 : len(lines)-1] {
+                       switch {
+                       case isBlank(line):
+                               lines[1+i] = nil // range starts at line 1
+                       case prefix == nil:
+                               prefix = commonPrefix(line, line)
+                       default:
+                               prefix = commonPrefix(prefix, line)
+                       }
+               }
+       } else { // len(lines) == 2
+               line := lines[1]
+               prefix = commonPrefix(line, line)
+       }
+
+       /*
+        * Check for vertical "line of stars" and correct prefix accordingly.
+        */
+       lineOfStars := false
+       if i := bytes.Index(prefix, []byte{'*'}); i >= 0 {
+               // Line of stars present.
+               if i > 0 && prefix[i-1] == ' ' {
+                       i-- // remove trailing blank from prefix so stars remain aligned
+               }
+               prefix = prefix[0:i]
+               lineOfStars = true
+       } else {
+               // No line of stars present.
+               // Determine the white space on the first line after the /*
+               // and before the beginning of the comment text, assume two
+               // blanks instead of the /* unless the first character after
+               // the /* is a tab. If the first comment line is empty but
+               // for the opening /*, assume up to 3 blanks or a tab. This
+               // whitespace may be found as suffix in the common prefix.
+               first := lines[0]
+               if isBlank(first[2:]) {
+                       // no comment text on the first line:
+                       // reduce prefix by up to 3 blanks or a tab
+                       // if present - this keeps comment text indented
+                       // relative to the /* and */'s if it was indented
+                       // in the first place
+                       i := len(prefix)
+                       for n := 0; n < 3 && i > 0 && prefix[i-1] == ' '; n++ {
+                               i--
+                       }
+                       if i == len(prefix) && i > 0 && prefix[i-1] == '\t' {
+                               i--
+                       }
+                       prefix = prefix[0:i]
+               } else {
+                       // comment text on the first line
+                       suffix := make([]byte, len(first))
+                       n := 2 // start after opening /*
+                       for n < len(first) && first[n] <= ' ' {
+                               suffix[n] = first[n]
+                               n++
+                       }
+                       if n > 2 && suffix[2] == '\t' {
+                               // assume the '\t' compensates for the /*
+                               suffix = suffix[2:n]
+                       } else {
+                               // otherwise assume two blanks
+                               suffix[0], suffix[1] = ' ', ' '
+                               suffix = suffix[0:n]
+                       }
+                       // Shorten the computed common prefix by the length of
+                       // suffix, if it is found as suffix of the prefix.
+                       if bytes.HasSuffix(prefix, suffix) {
+                               prefix = prefix[0 : len(prefix)-len(suffix)]
+                       }
+               }
+       }
+
+       // Handle last line: If it only contains a closing */, align it
+       // with the opening /*, otherwise align the text with the other
+       // lines.
+       last := lines[len(lines)-1]
+       closing := []byte("*/")
+       i := bytes.Index(last, closing)
+       if isBlank(last[0:i]) {
+               // last line only contains closing */
+               var sep []byte
+               if lineOfStars {
+                       // insert an aligning blank
+                       sep = []byte{' '}
+               }
+               lines[len(lines)-1] = bytes.Join([][]byte{prefix, closing}, sep)
+       } else {
+               // last line contains more comment text - assume
+               // it is aligned like the other lines
+               prefix = commonPrefix(prefix, last)
+       }
+
+       // Remove the common prefix from all but the first and empty lines.
+       for i, line := range lines[1:] {
+               if len(line) != 0 {
+                       lines[1+i] = line[len(prefix):] // range starts at line 1
+               }
+       }
+}
+
+
+func (p *printer) writeComment(comment *ast.Comment) {
+       text := comment.Text
+
+       // shortcut common case of //-style comments
+       if text[1] == '/' {
+               p.writeCommentLine(comment, comment.Pos(), text)
+               return
+       }
+
+       // for /*-style comments, print line by line and let the
+       // write function take care of the proper indentation
+       lines := split(text)
+       stripCommonPrefix(lines)
+
+       // write comment lines, separated by formfeed,
+       // without a line break after the last line
+       linebreak := formfeeds[0:1]
+       pos := comment.Pos()
+       for i, line := range lines {
+               if i > 0 {
+                       p.write(linebreak)
+                       pos = p.pos
+               }
+               if len(line) > 0 {
+                       p.writeCommentLine(comment, pos, line)
+               }
+       }
+}
+
+
+// writeCommentSuffix writes a line break after a comment if indicated
+// and processes any leftover indentation information. If a line break
+// is needed, the kind of break (newline vs formfeed) depends on the
+// pending whitespace. writeCommentSuffix returns true if a pending
+// formfeed was dropped from the whitespace buffer.
+//
+func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
+       for i, ch := range p.buffer {
+               switch ch {
+               case blank, vtab:
+                       // ignore trailing whitespace
+                       p.buffer[i] = ignore
+               case indent, unindent:
+                       // don't loose indentation information
+               case newline, formfeed:
+                       // if we need a line break, keep exactly one
+                       // but remember if we dropped any formfeeds
+                       if needsLinebreak {
+                               needsLinebreak = false
+                       } else {
+                               if ch == formfeed {
+                                       droppedFF = true
+                               }
+                               p.buffer[i] = ignore
+                       }
+               }
+       }
+       p.writeWhitespace(len(p.buffer))
+
+       // make sure we have a line break
+       if needsLinebreak {
+               p.write([]byte{'\n'})
+       }
+
+       return
+}
+
+
+// intersperseComments consumes all comments that appear before the next token
+// tok and prints it together with the buffered whitespace (i.e., the whitespace
+// that needs to be written before the next token). A heuristic is used to mix
+// the comments and whitespace. intersperseComments returns true if a pending
+// formfeed was dropped from the whitespace buffer.
+//
+func (p *printer) intersperseComments(next token.Position, tok token.Token) (droppedFF bool) {
+       var last *ast.Comment
+       for ; p.commentBefore(next); p.cindex++ {
+               for _, c := range p.comments[p.cindex].List {
+                       p.writeCommentPrefix(c.Pos(), next, last == nil, tok.IsKeyword())
+                       p.writeComment(c)
+                       last = c
+               }
+       }
+
+       if last != nil {
+               if last.Text[1] == '*' && last.Pos().Line == next.Line {
+                       // the last comment is a /*-style comment and the next item
+                       // follows on the same line: separate with an extra blank
+                       p.write([]byte{' '})
+               }
+               // ensure that there is a newline after a //-style comment
+               // or if we are before a closing '}' or at the end of a file
+               return p.writeCommentSuffix(last.Text[1] == '/' || tok == token.RBRACE || tok == token.EOF)
+       }
+
+       // no comment was written - we should never reach here since
+       // intersperseComments should not be called in that case
+       p.internalError("intersperseComments called without pending comments")
+       return false
+}
+
+
+// whiteWhitespace writes the first n whitespace entries.
+func (p *printer) writeWhitespace(n int) {
+       // write entries
+       var data [1]byte
+       for i := 0; i < n; i++ {
+               switch ch := p.buffer[i]; ch {
+               case ignore:
+                       // ignore!
+               case indent:
+                       p.indent++
+               case unindent:
+                       p.indent--
+                       if p.indent < 0 {
+                               p.internalError("negative indentation:", p.indent)
+                               p.indent = 0
+                       }
+               case newline, formfeed:
+                       // A line break immediately followed by a "correcting"
+                       // unindent is swapped with the unindent - this permits
+                       // proper label positioning. If a comment is between
+                       // the line break and the label, the unindent is not
+                       // part of the comment whitespace prefix and the comment
+                       // will be positioned correctly indented.
+                       if i+1 < n && p.buffer[i+1] == unindent {
+                               // Use a formfeed to terminate the current section.
+                               // Otherwise, a long label name on the next line leading
+                               // to a wide column may increase the indentation column
+                               // of lines before the label; effectively leading to wrong
+                               // indentation.
+                               p.buffer[i], p.buffer[i+1] = unindent, formfeed
+                               i-- // do it again
+                               continue
+                       }
+                       fallthrough
+               default:
+                       data[0] = byte(ch)
+                       p.write(data[0:])
+               }
+       }
+
+       // shift remaining entries down
+       i := 0
+       for ; n < len(p.buffer); n++ {
+               p.buffer[i] = p.buffer[n]
+               i++
+       }
+       p.buffer = p.buffer[0:i]
+}
+
+
+// ----------------------------------------------------------------------------
+// Printing interface
+
+
+func mayCombine(prev token.Token, next byte) (b bool) {
+       switch prev {
+       case token.INT:
+               b = next == '.' // 1.
+       case token.ADD:
+               b = next == '+' // ++
+       case token.SUB:
+               b = next == '-' // --
+       case token.QUO:
+               b = next == '*' // /*
+       case token.LSS:
+               b = next == '-' || next == '<' // <- or <<
+       case token.AND:
+               b = next == '&' || next == '^' // && or &^
+       }
+       return
+}
+
+
+// print prints a list of "items" (roughly corresponding to syntactic
+// tokens, but also including whitespace and formatting information).
+// It is the only print function that should be called directly from
+// any of the AST printing functions in nodes.go.
+//
+// Whitespace is accumulated until a non-whitespace token appears. Any
+// comments that need to appear before that token are printed first,
+// taking into account the amount and structure of any pending white-
+// space for best comment placement. Then, any leftover whitespace is
+// printed, followed by the actual token.
+//
+func (p *printer) print(args ...interface{}) {
+       for _, f := range args {
+               next := p.pos // estimated position of next item
+               var data []byte
+               var tag HTMLTag
+               var tok token.Token
+
+               switch x := f.(type) {
+               case whiteSpace:
+                       if x == ignore {
+                               // don't add ignore's to the buffer; they
+                               // may screw up "correcting" unindents (see
+                               // LabeledStmt)
+                               break
+                       }
+                       i := len(p.buffer)
+                       if i == cap(p.buffer) {
+                               // Whitespace sequences are very short so this should
+                               // never happen. Handle gracefully (but possibly with
+                               // bad comment placement) if it does happen.
+                               p.writeWhitespace(i)
+                               i = 0
+                       }
+                       p.buffer = p.buffer[0 : i+1]
+                       p.buffer[i] = x
+               case *ast.Ident:
+                       if p.Styler != nil {
+                               data, tag = p.Styler.Ident(x)
+                       } else {
+                               data = []byte(x.Name)
+                       }
+                       tok = token.IDENT
+               case *ast.BasicLit:
+                       if p.Styler != nil {
+                               data, tag = p.Styler.BasicLit(x)
+                       } else {
+                               data = x.Value
+                       }
+                       // escape all literals so they pass through unchanged
+                       // (note that valid Go programs cannot contain esc ('\xff')
+                       // bytes since they do not appear in legal UTF-8 sequences)
+                       // TODO(gri): do this more efficiently.
+                       data = []byte("\xff" + string(data) + "\xff")
+                       tok = x.Kind
+               case token.Token:
+                       s := x.String()
+                       if mayCombine(p.lastTok, s[0]) {
+                               // the previous and the current token must be
+                               // separated by a blank otherwise they combine
+                               // into a different incorrect token sequence
+                               // (except for token.INT followed by a '.' this
+                               // should never happen because it is taken care
+                               // of via binary expression formatting)
+                               if len(p.buffer) != 0 {
+                                       p.internalError("whitespace buffer not empty")
+                               }
+                               p.buffer = p.buffer[0:1]
+                               p.buffer[0] = ' '
+                       }
+                       if p.Styler != nil {
+                               data, tag = p.Styler.Token(x)
+                       } else {
+                               data = []byte(s)
+                       }
+                       tok = x
+               case token.Position:
+                       if x.IsValid() {
+                               next = x // accurate position of next item
+                       }
+                       tok = p.lastTok
+               default:
+                       fmt.Fprintf(os.Stderr, "print: unsupported argument type %T\n", f)
+                       panic("go/printer type")
+               }
+               p.lastTok = tok
+               p.pos = next
+
+               if data != nil {
+                       droppedFF := p.flush(next, tok)
+
+                       // intersperse extra newlines if present in the source
+                       // (don't do this in flush as it will cause extra newlines
+                       // at the end of a file) - use formfeeds if we dropped one
+                       // before
+                       p.writeNewlines(next.Line-p.pos.Line, droppedFF)
+
+                       p.writeItem(next, data, tag)
+               }
+       }
+}
+
+
+// commentBefore returns true iff the current comment occurs
+// before the next position in the source code.
+//
+func (p *printer) commentBefore(next token.Position) bool {
+       return p.cindex < len(p.comments) && p.comments[p.cindex].List[0].Pos().Offset < next.Offset
+}
+
+
+// Flush prints any pending comments and whitespace occuring
+// textually before the position of the next token tok. Flush
+// returns true if a pending formfeed character was dropped
+// from the whitespace buffer as a result of interspersing
+// comments.
+//
+func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
+       if p.commentBefore(next) {
+               // if there are comments before the next item, intersperse them
+               droppedFF = p.intersperseComments(next, tok)
+       } else {
+               // otherwise, write any leftover whitespace
+               p.writeWhitespace(len(p.buffer))
+       }
+       return
+}
+
+
+// ----------------------------------------------------------------------------
+// Trimmer
+
+// A trimmer is an io.Writer filter for stripping tabwriter.Escape
+// characters, trailing blanks and tabs, and for converting formfeed
+// and vtab characters into newlines and htabs (in case no tabwriter
+// is used). Text bracketed by tabwriter.Escape characters is passed
+// through unchanged.
+//
+type trimmer struct {
+       output io.Writer
+       space  bytes.Buffer
+       state  int
+}
+
+
+// trimmer is implemented as a state machine.
+// It can be in one of the following states:
+const (
+       inSpace = iota
+       inEscape
+       inText
+)
+
+
+// Design note: It is tempting to eliminate extra blanks occuring in
+//              whitespace in this function as it could simplify some
+//              of the blanks logic in the node printing functions.
+//              However, this would mess up any formatting done by
+//              the tabwriter.
+
+func (p *trimmer) Write(data []byte) (n int, err os.Error) {
+       m := 0 // if p.state != inSpace, data[m:n] is unwritten
+       var b byte
+       for n, b = range data {
+               if b == '\v' {
+                       b = '\t' // convert to htab
+               }
+               switch p.state {
+               case inSpace:
+                       switch b {
+                       case '\t', ' ':
+                               p.space.WriteByte(b) // WriteByte returns no errors
+                       case '\f', '\n':
+                               p.space.Reset()                        // discard trailing space
+                               _, err = p.output.Write(newlines[0:1]) // write newline
+                       case tabwriter.Escape:
+                               _, err = p.output.Write(p.space.Bytes())
+                               p.space.Reset()
+                               p.state = inEscape
+                               m = n + 1 // drop tabwriter.Escape
+                       default:
+                               _, err = p.output.Write(p.space.Bytes())
+                               p.space.Reset()
+                               p.state = inText
+                               m = n
+                       }
+               case inEscape:
+                       if b == tabwriter.Escape {
+                               _, err = p.output.Write(data[m:n])
+                               p.state = inSpace
+                       }
+               case inText:
+                       switch b {
+                       case '\t', ' ':
+                               _, err = p.output.Write(data[m:n])
+                               p.state = inSpace
+                               p.space.WriteByte(b) // WriteByte returns no errors
+                       case '\f':
+                               data[n] = '\n' // convert to newline
+                       case tabwriter.Escape:
+                               _, err = p.output.Write(data[m:n])
+                               p.state = inEscape
+                               m = n + 1 // drop tabwriter.Escape
+                       }
+               }
+               if err != nil {
+                       return
+               }
+       }
+       n = len(data)
+
+       if p.state != inSpace {
+               _, err = p.output.Write(data[m:n])
+               p.state = inSpace
+       }
+
+       return
+}
+
+
+// ----------------------------------------------------------------------------
+// Public interface
+
+// General printing is controlled with these Config.Mode flags.
+const (
+       GenHTML   uint = 1 << iota // generate HTML
+       RawFormat                  // do not use a tabwriter; if set, UseSpaces is ignored
+       TabIndent                  // use tabs for indentation independent of UseSpaces
+       UseSpaces                  // use spaces instead of tabs for alignment
+)
+
+
+// An HTMLTag specifies a start and end tag.
+type HTMLTag struct {
+       Start, End string // empty if tags are absent
+}
+
+
+// A Styler specifies formatting of line tags and elementary Go words.
+// A format consists of text and a (possibly empty) surrounding HTML tag.
+//
+type Styler interface {
+       LineTag(line int) ([]byte, HTMLTag)
+       Comment(c *ast.Comment, line []byte) ([]byte, HTMLTag)
+       BasicLit(x *ast.BasicLit) ([]byte, HTMLTag)
+       Ident(id *ast.Ident) ([]byte, HTMLTag)
+       Token(tok token.Token) ([]byte, HTMLTag)
+}
+
+
+// A Config node controls the output of Fprint.
+type Config struct {
+       Mode     uint   // default: 0
+       Tabwidth int    // default: 8
+       Styler   Styler // default: nil
+}
+
+
+// Fprint "pretty-prints" an AST node to output and returns the number
+// of bytes written and an error (if any) for a given configuration cfg.
+// The node type must be *ast.File, or assignment-compatible to ast.Expr,
+// ast.Decl, ast.Spec, or ast.Stmt.
+//
+func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
+       // redirect output through a trimmer to eliminate trailing whitespace
+       // (Input to a tabwriter must be untrimmed since trailing tabs provide
+       // formatting information. The tabwriter could provide trimming
+       // functionality but no tabwriter is used when RawFormat is set.)
+       output = &trimmer{output: output}
+
+       // setup tabwriter if needed and redirect output
+       var tw *tabwriter.Writer
+       if cfg.Mode&RawFormat == 0 {
+               minwidth := cfg.Tabwidth
+
+               padchar := byte('\t')
+               if cfg.Mode&UseSpaces != 0 {
+                       padchar = ' '
+               }
+
+               twmode := tabwriter.DiscardEmptyColumns
+               if cfg.Mode&GenHTML != 0 {
+                       twmode |= tabwriter.FilterHTML
+               }
+               if cfg.Mode&TabIndent != 0 {
+                       minwidth = 0
+                       twmode |= tabwriter.TabIndent
+               }
+
+               tw = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode)
+               output = tw
+       }
+
+       // setup printer and print node
+       var p printer
+       p.init(output, cfg)
+       go func() {
+               switch n := node.(type) {
+               case ast.Expr:
+                       p.nesting = 1
+                       p.useNodeComments = true
+                       p.expr(n, ignoreMultiLine)
+               case ast.Stmt:
+                       p.nesting = 1
+                       p.useNodeComments = true
+                       // A labeled statement will un-indent to position the
+                       // label. Set indent to 1 so we don't get indent "underflow".
+                       if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
+                               p.indent = 1
+                       }
+                       p.stmt(n, false, ignoreMultiLine)
+               case ast.Decl:
+                       p.nesting = 1
+                       p.useNodeComments = true
+                       p.decl(n, ignoreMultiLine)
+               case ast.Spec:
+                       p.nesting = 1
+                       p.useNodeComments = true
+                       p.spec(n, 1, false, ignoreMultiLine)
+               case *ast.File:
+                       p.nesting = 0
+                       p.comments = n.Comments
+                       p.useNodeComments = n.Comments == nil
+                       p.file(n)
+               default:
+                       p.errors <- fmt.Errorf("printer.Fprint: unsupported node type %T", n)
+                       runtime.Goexit()
+               }
+               p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF)
+               p.errors <- nil // no errors
+       }()
+       err := <-p.errors // wait for completion of goroutine
+
+       // flush tabwriter, if any
+       if tw != nil {
+               tw.Flush() // ignore errors
+       }
+
+       return p.written, err
+}
+
+
+// Fprint "pretty-prints" an AST node to output.
+// It calls Config.Fprint with default settings.
+//
+func Fprint(output io.Writer, node interface{}) os.Error {
+       _, err := (&Config{Tabwidth: 8}).Fprint(output, node) // don't care about number of bytes written
+       return err
+}
diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go
new file mode 100644 (file)
index 0000000..b5d7b81
--- /dev/null
@@ -0,0 +1,134 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package printer
+
+import (
+       "bytes"
+       "flag"
+       "io/ioutil"
+       "go/ast"
+       "go/parser"
+       "path"
+       "testing"
+)
+
+
+const (
+       dataDir  = "testdata"
+       tabwidth = 8
+)
+
+
+var update = flag.Bool("update", false, "update golden files")
+
+
+func lineString(text []byte, i int) string {
+       i0 := i
+       for i < len(text) && text[i] != '\n' {
+               i++
+       }
+       return string(text[i0:i])
+}
+
+
+type checkMode uint
+
+const (
+       export checkMode = 1 << iota
+       rawFormat
+)
+
+
+func check(t *testing.T, source, golden string, mode checkMode) {
+       // parse source
+       prog, err := parser.ParseFile(source, nil, parser.ParseComments)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       // filter exports if necessary
+       if mode&export != 0 {
+               ast.FileExports(prog) // ignore result
+               prog.Comments = nil   // don't print comments that are not in AST
+       }
+
+       // determine printer configuration
+       cfg := Config{Tabwidth: tabwidth}
+       if mode&rawFormat != 0 {
+               cfg.Mode |= RawFormat
+       }
+
+       // format source
+       var buf bytes.Buffer
+       if _, err := cfg.Fprint(&buf, prog); err != nil {
+               t.Error(err)
+       }
+       res := buf.Bytes()
+
+       // update golden files if necessary
+       if *update {
+               if err := ioutil.WriteFile(golden, res, 0644); err != nil {
+                       t.Error(err)
+               }
+               return
+       }
+
+       // get golden
+       gld, err := ioutil.ReadFile(golden)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       // compare lengths
+       if len(res) != len(gld) {
+               t.Errorf("len = %d, expected %d (= len(%s))", len(res), len(gld), golden)
+       }
+
+       // compare contents
+       for i, line, offs := 0, 1, 0; i < len(res) && i < len(gld); i++ {
+               ch := res[i]
+               if ch != gld[i] {
+                       t.Errorf("%s:%d:%d: %s", source, line, i-offs+1, lineString(res, offs))
+                       t.Errorf("%s:%d:%d: %s", golden, line, i-offs+1, lineString(gld, offs))
+                       t.Error()
+                       return
+               }
+               if ch == '\n' {
+                       line++
+                       offs = i + 1
+               }
+       }
+}
+
+
+type entry struct {
+       source, golden string
+       mode           checkMode
+}
+
+// Use gotest -update to create/update the respective golden files.
+var data = []entry{
+       {"empty.input", "empty.golden", 0},
+       {"comments.input", "comments.golden", 0},
+       {"comments.input", "comments.x", export},
+       {"linebreaks.input", "linebreaks.golden", 0},
+       {"expressions.input", "expressions.golden", 0},
+       {"expressions.input", "expressions.raw", rawFormat},
+       {"declarations.input", "declarations.golden", 0},
+       {"statements.input", "statements.golden", 0},
+}
+
+
+func Test(t *testing.T) {
+       for _, e := range data {
+               source := path.Join(dataDir, e.source)
+               golden := path.Join(dataDir, e.golden)
+               check(t, source, golden, e.mode)
+               // TODO(gri) check that golden is idempotent
+               //check(t, golden, golden, e.mode);
+       }
+}
diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden
new file mode 100644 (file)
index 0000000..200ea33
--- /dev/null
@@ -0,0 +1,479 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a package for testing comment placement by go/printer.
+//
+package main
+
+import "fmt"   // fmt
+
+const c0 = 0   // zero
+const (
+       c1      = iota  // c1
+       c2              // c2
+)
+
+// Alignment of comments in declarations>
+const (
+       _       T       = iota  // comment
+       _                       // comment
+       _                       // comment
+       _       = iota + 10
+       _       // comments
+
+       _       = 10            // comment
+       _       T       = 20    // comment
+)
+
+const (
+       _____   = iota  // foo
+       _               // bar
+       _       = 0     // bal
+       _               // bat
+)
+
+const (
+       _       T       = iota  // comment
+       _                       // comment
+       _                       // comment
+       _       = iota + 10
+       _       // comment
+       _       = 10
+       _       = 20            // comment
+       _       T       = 0     // comment
+)
+
+// The SZ struct; it is empty.
+type SZ struct{}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+       int
+       x, y, z int     // 3 unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+       S0
+       A, B, C float   // 3 exported fields
+       D, b, c int     // 2 unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+       S1
+       A, B, C float   // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface{}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+       f(x int) int    // unexported method
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+       I0
+       F(x float) float        // exported methods
+       g(x int) int            // unexported method
+}
+
+// The I2 interface; all methods are exported.
+type I2 interface {
+       I0
+       F(x float) float        // exported method
+       G(x float) float        // exported method
+}
+
+// The S3 struct; all comments except for the last one must appear in the export.
+type S3 struct {
+       // lead comment for F1
+       F1      int     // line comment for F1
+       // lead comment for F2
+       F2      int     // line comment for F2
+       f3      int     // f3 is not exported
+}
+
+// This comment group should be separated
+// with a newline from the next comment
+// group.
+
+// This comment should NOT be associated with the next declaration.
+
+var x int      // x
+var ()
+
+
+// This comment SHOULD be associated with the next declaration.
+func f0() {
+       const pi = 3.14 // pi
+       var s1 struct{} /* an empty struct */   /* foo */
+       // a struct constructor
+       // --------------------
+       var s2 struct{} = struct{}{}
+       x := pi
+}
+//
+// NO SPACE HERE
+//
+func f1() {
+       f0()
+       /* 1 */
+       // 2
+       /* 3 */
+       /* 4 */
+       f0()
+}
+
+
+func _() {
+       // this comment should be properly indented
+}
+
+
+func _(x int) int {
+       if x < 0 {      // the tab printed before this comment's // must not affect the remaining lines
+               return -x       // this statement should be properly indented
+       }
+       if x < 0 {      /* the tab printed before this comment's /* must not affect the remaining lines */
+               return -x       // this statement should be properly indented
+       }
+       return x
+}
+
+
+func typeswitch(x interface{}) {
+       switch v := x.(type) {
+       case bool, int, float:
+       case string:
+       default:
+       }
+
+       switch x.(type) {
+       }
+
+       switch v0, ok := x.(int); v := x.(type) {
+       }
+
+       switch v0, ok := x.(int); x.(type) {
+       case byte:      // this comment should be on the same line as the keyword
+               // this comment should be normally indented
+               _ = 0
+       case bool, int, float:
+               // this comment should be indented
+       case string:
+       default:
+               // this comment should be indented
+       }
+       // this comment should not be indented
+}
+
+func _() {
+       /* freestanding comment
+          aligned              line
+          aligned line
+       */
+}
+
+func _() {
+       /* freestanding comment
+          aligned              line
+          aligned line
+       */
+}
+
+func _() {
+       /* freestanding comment
+          aligned              line
+          aligned line */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned         line
+               aligned line
+       */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned         line
+               aligned line
+       */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned         line
+               aligned line */
+}
+
+
+func _() {
+       /*
+          freestanding comment
+          aligned              line
+          aligned line
+       */
+}
+
+func _() {
+       /*
+          freestanding comment
+          aligned              line
+          aligned line
+       */
+}
+
+func _() {
+       /*
+          freestanding comment
+          aligned              line
+          aligned line */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned         line
+               aligned line
+       */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned         line
+               aligned line
+       */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned         line
+               aligned line */
+}
+
+func _() {
+       /* freestanding comment
+          aligned line
+       */
+}
+
+func _() {
+       /* freestanding comment
+          aligned line
+       */
+}
+
+func _() {
+       /* freestanding comment
+          aligned line */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned line
+       */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned line
+       */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned line */
+}
+
+
+func _() {
+       /*
+          freestanding comment
+          aligned line
+       */
+}
+
+func _() {
+       /*
+          freestanding comment
+          aligned line
+       */
+}
+
+func _() {
+       /*
+          freestanding comment
+          aligned line */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned line
+       */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned line
+       */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned line */
+}
+
+/*
+ * line
+ * of
+ * stars
+ */
+
+/* another line
+ * of
+ * stars */
+
+/*     and another line
+ *     of
+ *     stars */
+
+/* a line of
+ * stars */
+
+/*     and another line of
+ *     stars */
+
+/* a line of stars
+ */
+
+/*     and another line of
+ */
+
+/* a line of stars
+ */
+
+/*     and another line of
+ */
+
+/*
+aligned in middle
+here
+        not here
+*/
+
+/*
+blank line in middle:
+
+with no leading spaces on blank line.
+*/
+
+/*
+   aligned in middle
+   here
+           not here
+*/
+
+/*
+       blank line in middle:
+
+       with no leading spaces on blank line.
+*/
+
+func _() {
+       /*
+        * line
+        * of
+        * stars
+        */
+
+       /*
+               aligned in middle
+               here
+                       not here
+       */
+
+       /*
+               blank line in middle:
+
+               with no leading spaces on blank line.
+       */
+}
+
+
+// Some interesting interspersed comments
+func _( /* this */ x /* is */ /* an */ int) {
+}
+
+func _( /* no params */ )      {}
+
+func _() {
+       f( /* no args */ )
+}
+
+func ( /* comment1 */ T /* comment2 */ ) _()   {}
+
+func _() { /* one-liner */
+}
+
+func _() {
+       _ = 0
+       /* closing curly brace should be on new line */
+}
+
+
+// Comments immediately adjacent to punctuation (for which the go/printer
+// may obly have estimated position information) must remain after the punctuation.
+func _() {
+       _ = T{
+               1,      // comment after comma
+               2,      /* comment after comma */
+               3,      // comment after comma
+       }
+       _ = T{
+               1,      // comment after comma
+               2,      /* comment after comma */
+               3,      // comment after comma
+       }
+       _ = T{
+               /* comment before literal */ 1,
+               2,      /* comment before comma - ok to move after comma */
+               3,      /* comment before comma - ok to move after comma */
+       }
+
+       for i = 0;      // comment after semicolon
+       i < 9;          /* comment after semicolon */
+       i++ {           // comment after opening curly brace
+       }
+
+       // TODO(gri) the last comment in this example should be aligned */
+       for i = 0;      // comment after semicolon
+       i < 9;          /* comment before semicolon - ok to move after semicolon */
+       i++ /* comment before opening curly brace */ {
+       }
+}
+
+
+// Line comments with tabs
+func _() {
+       var finput *bufio.Reader        // input file
+       var stderr *bufio.Writer
+       var ftable *bufio.Writer        // y.go file
+       var foutput *bufio.Writer       // y.output file
+
+       var oflag string        // -o [y.go]            - y.go file
+       var vflag string        // -v [y.output]        - y.output file
+       var lflag bool          // -l                   - disable line directives
+}
+
+
+/* This comment is the last entry in this file. It must be printed and should be followed by a newline */
diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input
new file mode 100644 (file)
index 0000000..4a9ea47
--- /dev/null
@@ -0,0 +1,479 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a package for testing comment placement by go/printer.
+//
+package main
+
+import "fmt"  // fmt
+
+const c0 = 0  // zero
+const (
+       c1 = iota  // c1
+       c2  // c2
+)
+
+// Alignment of comments in declarations>
+const (
+       _ T = iota  // comment
+       _  // comment
+       _  // comment
+       _ = iota+10
+       _  // comments
+
+       _ = 10  // comment
+       _ T = 20  // comment
+)
+
+const (
+       _____ = iota // foo
+       _ // bar
+       _  = 0    // bal
+       _ // bat
+)
+
+const (
+       _ T = iota // comment
+       _ // comment
+       _ // comment
+       _ = iota + 10
+       _ // comment
+       _ = 10
+       _ = 20 // comment
+       _ T = 0 // comment
+)
+
+// The SZ struct; it is empty.
+type SZ struct {}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+       int
+       x, y, z int  // 3 unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+       S0
+       A, B, C float  // 3 exported fields
+       D, b, c int  // 2 unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+       S1
+       A, B, C float  // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface {}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+       f(x int) int  // unexported method
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+       I0
+       F(x float) float  // exported methods
+       g(x int) int  // unexported method
+}
+
+// The I2 interface; all methods are exported.
+type I2 interface {
+       I0
+       F(x float) float  // exported method
+       G(x float) float  // exported method
+}
+
+// The S3 struct; all comments except for the last one must appear in the export.
+type S3 struct {
+       // lead comment for F1
+       F1 int // line comment for F1
+       // lead comment for F2
+       F2 int // line comment for F2
+       f3 int // f3 is not exported
+}
+
+// This comment group should be separated
+// with a newline from the next comment
+// group.
+
+// This comment should NOT be associated with the next declaration.
+
+var x int  // x
+var ()
+
+
+// This comment SHOULD be associated with the next declaration.
+func f0() {
+       const pi = 3.14  // pi
+       var s1 struct {}  /* an empty struct */ /* foo */
+       // a struct constructor
+       // --------------------
+       var s2 struct {} = struct {}{}
+       x := pi
+}
+//
+// NO SPACE HERE
+//
+func f1() {
+       f0()
+       /* 1 */
+       // 2
+       /* 3 */
+       /* 4 */
+       f0()
+}
+
+
+func _() {
+       // this comment should be properly indented
+}
+
+
+func _(x int) int {
+       if x < 0 {  // the tab printed before this comment's // must not affect the remaining lines
+               return -x  // this statement should be properly indented
+       }
+       if x < 0 {  /* the tab printed before this comment's /* must not affect the remaining lines */
+               return -x  // this statement should be properly indented
+       }
+       return x
+}
+
+
+func typeswitch(x interface{}) {
+       switch v := x.(type) {
+       case bool, int, float:
+       case string:
+       default:
+       }
+
+       switch x.(type) {
+       }
+
+       switch v0, ok := x.(int); v := x.(type) {
+       }
+
+       switch v0, ok := x.(int); x.(type) {
+       case byte:  // this comment should be on the same line as the keyword
+               // this comment should be normally indented
+               _ = 0
+       case bool, int, float:
+               // this comment should be indented
+       case string:
+       default:
+               // this comment should be indented
+       }
+       // this comment should not be indented
+}
+
+func _() {
+       /* freestanding comment
+          aligned              line
+          aligned line
+       */
+}
+
+func _() {
+       /* freestanding comment
+          aligned              line
+          aligned line
+          */
+}
+
+func _() {
+       /* freestanding comment
+          aligned              line
+          aligned line */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned         line
+               aligned line
+       */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned         line
+               aligned line
+               */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned         line
+               aligned line */
+}
+
+
+func _() {
+       /*
+          freestanding comment
+          aligned              line
+          aligned line
+       */
+}
+
+func _() {
+       /*
+          freestanding comment
+          aligned              line
+          aligned line
+          */
+}
+
+func _() {
+       /*
+          freestanding comment
+          aligned              line
+          aligned line */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned         line
+               aligned line
+       */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned         line
+               aligned line
+               */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned         line
+               aligned line */
+}
+
+func _() {
+       /* freestanding comment
+          aligned line
+       */
+}
+
+func _() {
+       /* freestanding comment
+          aligned line
+          */
+}
+
+func _() {
+       /* freestanding comment
+          aligned line */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned line
+       */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned line
+               */
+}
+
+func _() {
+       /*      freestanding comment
+               aligned line */
+}
+
+
+func _() {
+       /*
+          freestanding comment
+          aligned line
+       */
+}
+
+func _() {
+       /*
+          freestanding comment
+          aligned line
+          */
+}
+
+func _() {
+       /*
+          freestanding comment
+          aligned line */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned line
+       */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned line
+               */
+}
+
+func _() {
+       /*
+               freestanding comment
+               aligned line */
+}
+
+/*
+ * line
+ * of
+ * stars
+ */
+
+/* another line
+ * of
+ * stars */
+
+/*     and another line
+ *     of
+ *     stars */
+
+/* a line of
+ * stars */
+
+/*     and another line of
+ *     stars */
+
+/* a line of stars
+*/
+
+/*     and another line of
+*/
+
+/* a line of stars
+ */
+
+/*     and another line of
+ */
+
+/*
+aligned in middle
+here
+        not here
+*/
+
+/*
+blank line in middle:
+
+with no leading spaces on blank line.
+*/
+
+/*
+   aligned in middle
+   here
+           not here
+*/
+
+/*
+       blank line in middle:
+
+       with no leading spaces on blank line.
+*/
+
+func _() {
+       /*
+        * line
+        * of
+        * stars
+        */
+
+       /*
+       aligned in middle
+       here
+               not here
+       */
+
+       /*
+       blank line in middle:
+
+       with no leading spaces on blank line.
+*/
+}
+
+
+// Some interesting interspersed comments
+func _(/* this */x/* is *//* an */ int) {
+}
+
+func _(/* no params */) {}
+
+func _() {
+       f(/* no args */)
+}
+
+func (/* comment1 */ T /* comment2 */) _() {}
+
+func _() { /* one-liner */ }
+
+func _() {
+       _ = 0
+       /* closing curly brace should be on new line */ }
+
+
+// Comments immediately adjacent to punctuation (for which the go/printer
+// may obly have estimated position information) must remain after the punctuation.
+func _() {
+       _ = T{
+               1,    // comment after comma
+               2,    /* comment after comma */
+               3  ,  // comment after comma
+       }
+       _ = T{
+               1  ,// comment after comma
+               2  ,/* comment after comma */
+               3,// comment after comma
+       }
+       _ = T{
+               /* comment before literal */1,
+               2/* comment before comma - ok to move after comma */,
+               3  /* comment before comma - ok to move after comma */  ,
+       }
+
+       for
+               i=0;// comment after semicolon
+               i<9;/* comment after semicolon */
+               i++{// comment after opening curly brace
+       }
+
+       // TODO(gri) the last comment in this example should be aligned */
+       for
+               i=0;// comment after semicolon
+               i<9/* comment before semicolon - ok to move after semicolon */;
+               i++ /* comment before opening curly brace */ {
+       }
+}
+
+
+// Line comments with tabs
+func _() {
+var    finput          *bufio.Reader                   // input file
+var    stderr          *bufio.Writer
+var    ftable          *bufio.Writer                   // y.go file
+var    foutput         *bufio.Writer                   // y.output file
+
+var    oflag           string                          // -o [y.go]            - y.go file
+var    vflag           string                          // -v [y.output]        - y.output file
+var    lflag           bool                            // -l                   - disable line directives
+}
+
+
+/* This comment is the last entry in this file. It must be printed and should be followed by a newline */
diff --git a/libgo/go/go/printer/testdata/comments.x b/libgo/go/go/printer/testdata/comments.x
new file mode 100644 (file)
index 0000000..4d7a928
--- /dev/null
@@ -0,0 +1,57 @@
+// This is a package for testing comment placement by go/printer.
+//
+package main
+
+
+// The SZ struct; it is empty.
+type SZ struct{}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+       // contains unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+       S0
+       A, B, C float   // 3 exported fields
+       D       int     // 2 unexported fields
+       // contains unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+       S1
+       A, B, C float   // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface{}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+       // contains unexported methods
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+       I0
+       F(x float) float        // exported methods
+       // contains unexported methods
+}
+
+// The I2 interface; all methods are exported.
+type I2 interface {
+       I0
+       F(x float) float        // exported method
+       G(x float) float        // exported method
+}
+
+// The S3 struct; all comments except for the last one must appear in the export.
+type S3 struct {
+       // lead comment for F1
+       F1      int     // line comment for F1
+       // lead comment for F2
+       F2      int     // line comment for F2
+       // contains unexported fields
+}
diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden
new file mode 100644 (file)
index 0000000..394460c
--- /dev/null
@@ -0,0 +1,658 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package imports
+
+import "io"
+
+import (
+       _       "io"
+)
+
+import _       "io"
+
+import (
+       "io"
+       "io"
+       "io"
+)
+
+import (
+       "io"
+       aLongRename     "io"
+
+       b       "io"
+)
+
+import (
+       "unrenamed"
+       renamed "renameMe"
+       .       "io"
+       _       "io"
+       "io"
+       .       "os"
+)
+
+// no newlines between consecutive single imports, but
+// respect extra line breaks in the source (at most one empty line)
+import _       "io"
+import _       "io"
+import _       "io"
+
+import _       "os"
+import _       "os"
+import _       "os"
+
+
+import _       "fmt"
+import _       "fmt"
+import _       "fmt"
+
+import "foo"   // a comment
+import "bar"   // a comment
+
+import (
+       _       "foo"
+       // a comment
+       "bar"
+       "foo"   // a comment
+       "bar"   // a comment
+)
+
+// comments + renames
+import (
+       "unrenamed"     // a comment
+       renamed         "renameMe"
+       .               "io"            /* a comment */
+       _               "io/ioutil"     // a comment
+       "io"            // testing alignment
+       .               "os"
+       // a comment
+)
+
+// a case that caused problems in the past (comment placement)
+import (
+       .       "fmt"
+       "io"
+       "malloc"        // for the malloc count test only
+       "math"
+       "strings"
+       "testing"
+)
+
+
+// at least one empty line between declarations of different kind
+import _       "io"
+
+var _ int
+
+
+// printing of constant literals
+const (
+       _       = "foobar"
+       _       = "a۰۱۸"
+       _       = "foo६४"
+       _       = "bar9876"
+       _       = 0
+       _       = 1
+       _       = 123456789012345678890
+       _       = 01234567
+       _       = 0xcafebabe
+       _       = 0.
+       _       = .0
+       _       = 3.14159265
+       _       = 1e0
+       _       = 1e+100
+       _       = 1e-100
+       _       = 2.71828e-1000
+       _       = 0i
+       _       = 1i
+       _       = 012345678901234567889i
+       _       = 123456789012345678890i
+       _       = 0.i
+       _       = .0i
+       _       = 3.14159265i
+       _       = 1e0i
+       _       = 1e+100i
+       _       = 1e-100i
+       _       = 2.71828e-1000i
+       _       = 'a'
+       _       = '\000'
+       _       = '\xFF'
+       _       = '\uff16'
+       _       = '\U0000ff16'
+       _       = `foobar`
+       _       = `foo
+---
+---
+bar`
+)
+
+
+func _() {
+       // the following decls need a semicolon at the end
+       type _ int
+       type _ *int
+       type _ []int
+       type _ map[string]int
+       type _ chan int
+       type _ func() int
+
+       var _ int
+       var _ *int
+       var _ []int
+       var _ map[string]int
+       var _ chan int
+       var _ func() int
+
+       // the following decls don't need a semicolon at the end
+       type _ struct{}
+       type _ *struct{}
+       type _ []struct{}
+       type _ map[string]struct{}
+       type _ chan struct{}
+       type _ func() struct{}
+
+       type _ interface{}
+       type _ *interface{}
+       type _ []interface{}
+       type _ map[string]interface{}
+       type _ chan interface{}
+       type _ func() interface{}
+
+       var _ struct{}
+       var _ *struct{}
+       var _ []struct{}
+       var _ map[string]struct{}
+       var _ chan struct{}
+       var _ func() struct{}
+
+       var _ interface{}
+       var _ *interface{}
+       var _ []interface{}
+       var _ map[string]interface{}
+       var _ chan interface{}
+       var _ func() interface{}
+}
+
+
+// don't lose blank lines in grouped declarations
+const (
+       _       int     = 0
+       _       float   = 1
+
+       _       string  = "foo"
+
+       _       = iota
+       _
+
+       // a comment
+       _
+
+       _
+)
+
+
+type (
+       _       int
+       _       struct{}
+
+       _       interface{}
+
+       // a comment
+       _       map[string]int
+)
+
+
+var (
+       _       int     = 0
+       _       float   = 1
+
+       _       string  = "foo"
+
+       _       bool
+
+       // a comment
+       _       bool
+)
+
+
+// don't lose blank lines in this struct
+type _ struct {
+       String  struct {
+               Str, Len int
+       }
+       Slice   struct {
+               Array, Len, Cap int
+       }
+       Eface   struct {
+               Typ, Ptr int
+       }
+
+       UncommonType    struct {
+               Name, PkgPath int
+       }
+       CommonType      struct {
+               Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
+       }
+       Type    struct {
+               Typ, Ptr int
+       }
+       StructField     struct {
+               Name, PkgPath, Typ, Tag, Offset int
+       }
+       StructType      struct {
+               Fields int
+       }
+       PtrType struct {
+               Elem int
+       }
+       SliceType       struct {
+               Elem int
+       }
+       ArrayType       struct {
+               Elem, Len int
+       }
+
+       Stktop  struct {
+               Stackguard, Stackbase, Gobuf int
+       }
+       Gobuf   struct {
+               Sp, Pc, G int
+       }
+       G       struct {
+               Stackbase, Sched, Status, Alllink int
+       }
+}
+
+
+// no tabs for single or ungrouped decls
+func _() {
+       const xxxxxx = 0
+       type x int
+       var xxx int
+       var yyyy float = 3.14
+       var zzzzz = "bar"
+
+       const (
+               xxxxxx = 0
+       )
+       type (
+               x int
+       )
+       var (
+               xxx int
+       )
+       var (
+               yyyy float = 3.14
+       )
+       var (
+               zzzzz = "bar"
+       )
+}
+
+// tabs for multiple or grouped decls
+func _() {
+       // no entry has a type
+       const (
+               zzzzzz  = 1
+               z       = 2
+               zzz     = 3
+       )
+       // some entries have a type
+       const (
+               xxxxxx          = 1
+               x               = 2
+               xxx             = 3
+               yyyyyyyy        float   = iota
+               yyyy            = "bar"
+               yyy
+               yy      = 2
+       )
+}
+
+func _() {
+       // no entry has a type
+       var (
+               zzzzzz  = 1
+               z       = 2
+               zzz     = 3
+       )
+       // no entry has a value
+       var (
+               _       int
+               _       float
+               _       string
+
+               _       int     // comment
+               _       float   // comment
+               _       string  // comment
+       )
+       // some entries have a type
+       var (
+               xxxxxx          int
+               x               float
+               xxx             string
+               yyyyyyyy        int     = 1234
+               y               float   = 3.14
+               yyyy            = "bar"
+               yyy             string  = "foo"
+       )
+       // mixed entries - all comments should be aligned
+       var (
+               a, b, c                 int
+               x                       = 10
+               d                       int                     // comment
+               y                       = 20                    // comment
+               f, ff, fff, ffff        int     = 0, 1, 2, 3    // comment
+       )
+       // respect original line breaks
+       var _ = []T{
+               T{0x20, "Telugu"},
+       }
+       var _ = []T{
+               // respect original line breaks
+               T{0x20, "Telugu"},
+       }
+}
+
+func _() {
+       type (
+               xxxxxx  int
+               x       float
+               xxx     string
+               xxxxx   []x
+               xx      struct{}
+               xxxxxxx struct {
+                       _, _    int
+                       _       float
+               }
+               xxxx    chan<- string
+       )
+}
+
+
+// formatting of structs
+type _ struct{}
+
+type _ struct { /* this comment should be visible */
+}
+
+type _ struct {
+       // this comment should be visible and properly indented
+}
+
+type _ struct {        // this comment must not change indentation
+       f                       int
+       f, ff, fff, ffff        int
+}
+
+type _ struct {
+       string
+}
+
+type _ struct {
+       string  // comment
+}
+
+type _ struct {
+       string "tag"
+}
+
+type _ struct {
+       string "tag"    // comment
+}
+
+type _ struct {
+       f int
+}
+
+type _ struct {
+       f int   // comment
+}
+
+type _ struct {
+       f int "tag"
+}
+
+type _ struct {
+       f int "tag"     // comment
+}
+
+type _ struct {
+       bool
+       a, b, c                 int
+       int                     "tag"
+       ES                              // comment
+       float                   "tag"   // comment
+       f                       int     // comment
+       f, ff, fff, ffff        int     // comment
+       g                       float   "tag"
+       h                       float   "tag"   // comment
+}
+
+type _ struct {
+       a, b,
+       c, d    int     // this line should be indented
+       u, v, w, x      float   // this line should be indented
+       p, q,
+       r, s    float   // this line should be indented
+}
+
+
+// difficult cases
+type _ struct {
+       bool            // comment
+       text    []byte  // comment
+}
+
+
+// formatting of interfaces
+type EI interface{}
+
+type _ interface {
+       EI
+}
+
+type _ interface {
+       f()
+       fffff()
+}
+
+type _ interface {
+       EI
+       f()
+       fffffg()
+}
+
+type _ interface {     // this comment must not change indentation
+       EI                              // here's a comment
+       f()                             // no blank between identifier and ()
+       fffff()                         // no blank between identifier and ()
+       gggggggggggg(x, y, z int)       // hurray
+}
+
+
+// formatting of variable declarations
+func _() {
+       type day struct {
+               n               int
+               short, long     string
+       }
+       var (
+               Sunday          = day{0, "SUN", "Sunday"}
+               Monday          = day{1, "MON", "Monday"}
+               Tuesday         = day{2, "TUE", "Tuesday"}
+               Wednesday       = day{3, "WED", "Wednesday"}
+               Thursday        = day{4, "THU", "Thursday"}
+               Friday          = day{5, "FRI", "Friday"}
+               Saturday        = day{6, "SAT", "Saturday"}
+       )
+}
+
+
+// formatting of multi-line variable declarations
+var a1, b1, c1 int     // all on one line
+
+var a2, b2,
+       c2 int  // this line should be indented
+
+var (
+       a3, b3,
+       c3, d3  int     // this line should be indented
+       a4, b4, c4      int     // this line should be indented
+)
+
+
+func _() {
+       var privateKey2 = &Block{Type:  "RSA PRIVATE KEY",
+               Headers:        map[string]string{},
+               Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
+                       0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
+                       0xd4, 0x0, 0xae, 0x6a, 0x4d, 0x1b, 0x8a, 0x3b, 0x6a, 0x13,
+                       0x64, 0x2b, 0x23, 0xf2, 0x8b, 0x0, 0x3b, 0xfb, 0x97, 0x79,
+               },
+       }
+}
+
+
+func _() {
+       var Universe = Scope{
+               Names: map[string]*Ident{
+                       // basic types
+                       "bool":         nil,
+                       "byte":         nil,
+                       "int8":         nil,
+                       "int16":        nil,
+                       "int32":        nil,
+                       "int64":        nil,
+                       "uint8":        nil,
+                       "uint16":       nil,
+                       "uint32":       nil,
+                       "uint64":       nil,
+                       "float32":      nil,
+                       "float64":      nil,
+                       "string":       nil,
+
+                       // convenience types
+                       "int":          nil,
+                       "uint":         nil,
+                       "uintptr":      nil,
+                       "float":        nil,
+
+                       // constants
+                       "false":        nil,
+                       "true":         nil,
+                       "iota":         nil,
+                       "nil":          nil,
+
+                       // functions
+                       "cap":          nil,
+                       "len":          nil,
+                       "new":          nil,
+                       "make":         nil,
+                       "panic":        nil,
+                       "panicln":      nil,
+                       "print":        nil,
+                       "println":      nil,
+               },
+       }
+}
+
+
+// alignment of map composite entries
+var _ = map[int]int{
+       // small key sizes: always align even if size ratios are large
+       a:                      a,
+       abcdefghabcdefgh:       a,
+       ab:                     a,
+       abc:                    a,
+       abcdefgabcdefg:         a,
+       abcd:                   a,
+       abcde:                  a,
+       abcdef:                 a,
+
+       // mixed key sizes: align when key sizes change within accepted ratio
+       abcdefgh:               a,
+       abcdefghabcdefg:        a,
+       abcdefghij:             a,
+       abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a,      // outlier - do not align with previous line
+       abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij:           a,      // align with previous line
+
+       ab:     a,      // do not align with previous line
+       abcde:  a,      // align with previous line
+}
+
+
+func _() {
+       var _ = T{
+               a,      // must introduce trailing comma
+       }
+}
+
+
+// formatting of function results
+func _() func()                                {}
+func _() func(int)                     { return nil }
+func _() func(int) int                 { return nil }
+func _() func(int) func(int) func()    { return nil }
+
+
+// formatting of consecutive single-line functions
+func _()       {}
+func _()       {}
+func _()       {}
+
+func _()       {}      // an empty line before this function
+func _()       {}
+func _()       {}
+
+func _()               { f(1, 2, 3) }
+func _(x int) int      { y := x; return y + 1 }
+func _() int           { type T struct{}; var x T; return x }
+
+// these must remain multi-line since they are multi-line in the source
+func _() {
+       f(1, 2, 3)
+}
+func _(x int) int {
+       y := x
+       return y + 1
+}
+func _() int {
+       type T struct{}
+       var x T
+       return x
+}
+
+
+// making function declarations safe for new semicolon rules
+func _() { /* multi-line func because of comment */
+}
+
+func _() {
+       /* multi-line func because block is on multiple lines */
+}
+
+
+// ellipsis parameters
+func _(...int)
+func _(...*int)
+func _(...[]int)
+func _(...struct{})
+func _(bool, ...interface{})
+func _(bool, ...func())
+func _(bool, ...func(...int))
+func _(bool, ...map[string]int)
+func _(bool, ...chan int)
+
+func _(b bool, x ...int)
+func _(b bool, x ...*int)
+func _(b bool, x ...[]int)
+func _(b bool, x ...struct{})
+func _(x ...interface{})
+func _(x ...func())
+func _(x ...func(...int))
+func _(x ...map[string]int)
+func _(x ...chan int)
diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input
new file mode 100644 (file)
index 0000000..94e659d
--- /dev/null
@@ -0,0 +1,646 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package imports
+
+import "io"
+
+import (
+       _ "io"
+)
+
+import _ "io"
+
+import (
+       "io"
+       "io"
+       "io"
+)
+
+import (
+       "io"
+       aLongRename "io"
+
+       b "io"
+)
+
+import (
+       "unrenamed"
+       renamed "renameMe"
+       . "io"
+       _ "io"
+       "io"
+       . "os"
+)
+
+// no newlines between consecutive single imports, but
+// respect extra line breaks in the source (at most one empty line)
+import _ "io"
+import _ "io"
+import _ "io"
+
+import _ "os"
+import _ "os"
+import _ "os"
+
+
+import _ "fmt"
+import _ "fmt"
+import _ "fmt"
+
+import "foo"  // a comment
+import "bar"  // a comment
+
+import (
+       _ "foo"
+       // a comment
+       "bar"
+       "foo"  // a comment
+       "bar"  // a comment
+)
+
+// comments + renames
+import (
+       "unrenamed" // a comment
+       renamed "renameMe"
+       . "io" /* a comment */
+       _ "io/ioutil" // a comment
+       "io" // testing alignment
+       . "os"
+       // a comment
+)
+
+// a case that caused problems in the past (comment placement)
+import (
+       . "fmt"
+       "io"
+       "malloc"        // for the malloc count test only
+       "math"
+       "strings"
+       "testing"
+)
+
+
+// at least one empty line between declarations of different kind
+import _ "io"
+var _ int
+
+
+// printing of constant literals
+const (
+       _ = "foobar"
+       _ = "a۰۱۸"
+       _ = "foo६४"
+       _ = "bar9876"
+       _ = 0
+       _ = 1
+       _ = 123456789012345678890
+       _ = 01234567
+       _ = 0xcafebabe
+       _ = 0.
+       _ = .0
+       _ = 3.14159265
+       _ = 1e0
+       _ = 1e+100
+       _ = 1e-100
+       _ = 2.71828e-1000
+       _ = 0i
+       _ = 1i
+       _ = 012345678901234567889i
+       _ = 123456789012345678890i
+       _ = 0.i
+       _ = .0i
+       _ = 3.14159265i
+       _ = 1e0i
+       _ = 1e+100i
+       _ = 1e-100i
+       _ = 2.71828e-1000i
+       _ = 'a'
+       _ = '\000'
+       _ = '\xFF'
+       _ = '\uff16'
+       _ = '\U0000ff16'
+       _ = `foobar`
+       _ = `foo
+---
+---
+bar`
+)
+
+
+func _() {
+       // the following decls need a semicolon at the end
+       type _ int
+       type _ *int
+       type _ []int
+       type _ map[string]int
+       type _ chan int
+       type _ func() int
+
+       var _ int
+       var _ *int
+       var _ []int
+       var _ map[string]int
+       var _ chan int
+       var _ func() int
+
+       // the following decls don't need a semicolon at the end
+       type _ struct{}
+       type _ *struct{}
+       type _ []struct{}
+       type _ map[string]struct{}
+       type _ chan struct{}
+       type _ func() struct{}
+
+       type _ interface{}
+       type _ *interface{}
+       type _ []interface{}
+       type _ map[string]interface{}
+       type _ chan interface{}
+       type _ func() interface{}
+
+       var _ struct{}
+       var _ *struct{}
+       var _ []struct{}
+       var _ map[string]struct{}
+       var _ chan struct{}
+       var _ func() struct{}
+
+       var _ interface{}
+       var _ *interface{}
+       var _ []interface{}
+       var _ map[string]interface{}
+       var _ chan interface{}
+       var _ func() interface{}
+}
+
+
+// don't lose blank lines in grouped declarations
+const (
+       _ int = 0
+       _ float = 1
+
+       _ string = "foo"
+
+       _ = iota
+       _
+       
+       // a comment
+       _
+
+       _
+)
+
+
+type (
+       _ int
+       _ struct {}
+       
+       _ interface{}
+       
+       // a comment
+       _ map[string]int
+)
+
+
+var (
+       _ int = 0
+       _ float = 1
+
+       _ string = "foo"
+
+       _ bool
+       
+       // a comment
+       _ bool
+)
+
+
+// don't lose blank lines in this struct
+type _ struct {
+       String struct {
+               Str, Len int
+       }
+       Slice struct {
+               Array, Len, Cap int
+       }
+       Eface struct {
+               Typ, Ptr int
+       }
+
+       UncommonType struct {
+               Name, PkgPath int
+       }
+       CommonType struct {
+               Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
+       }
+       Type struct {
+               Typ, Ptr int
+       }
+       StructField struct {
+               Name, PkgPath, Typ, Tag, Offset int
+       }
+       StructType struct {
+               Fields int
+       }
+       PtrType struct {
+               Elem int
+       }
+       SliceType struct {
+               Elem int
+       }
+       ArrayType struct {
+               Elem, Len int
+       }
+
+       Stktop struct {
+               Stackguard, Stackbase, Gobuf int
+       }
+       Gobuf struct {
+               Sp, Pc, G int
+       }
+       G struct {
+               Stackbase, Sched, Status, Alllink int
+       }
+}
+
+
+// no tabs for single or ungrouped decls
+func _() {
+       const xxxxxx = 0
+       type x int
+       var xxx int
+       var yyyy float = 3.14
+       var zzzzz = "bar"
+
+       const (
+               xxxxxx = 0
+       )
+       type (
+               x int
+       )
+       var (
+               xxx int
+       )
+       var (
+               yyyy float = 3.14
+       )
+       var (
+               zzzzz = "bar"
+       )
+}
+
+// tabs for multiple or grouped decls
+func _() {
+       // no entry has a type
+       const (
+               zzzzzz = 1
+               z = 2
+               zzz = 3
+       )
+       // some entries have a type
+       const (
+               xxxxxx = 1
+               x = 2
+               xxx = 3
+               yyyyyyyy float = iota
+               yyyy = "bar"
+               yyy
+               yy = 2
+       )
+}
+
+func _() {
+       // no entry has a type
+       var (
+               zzzzzz = 1
+               z = 2
+               zzz = 3
+       )
+       // no entry has a value
+       var (
+               _ int
+               _ float
+               _ string
+
+               _ int  // comment
+               _ float  // comment
+               _ string  // comment
+       )
+       // some entries have a type
+       var (
+               xxxxxx int
+               x float
+               xxx string
+               yyyyyyyy int = 1234
+               y float = 3.14
+               yyyy = "bar"
+               yyy string = "foo"
+       )
+       // mixed entries - all comments should be aligned
+       var (
+               a, b, c int
+               x = 10
+               d int  // comment
+               y = 20  // comment
+               f, ff, fff, ffff int = 0, 1, 2, 3  // comment
+       )
+       // respect original line breaks
+       var _ = []T {
+               T{0x20, "Telugu"},
+       }
+       var _ = []T {
+               // respect original line breaks
+               T{0x20, "Telugu"},
+       }
+}
+
+func _() {
+       type (
+               xxxxxx int
+               x float
+               xxx string
+               xxxxx []x
+               xx struct{}
+               xxxxxxx struct {
+                       _, _ int
+                       _ float
+               }
+               xxxx chan<- string
+       )
+}
+
+
+// formatting of structs
+type _ struct{}
+
+type _ struct{ /* this comment should be visible */ }
+
+type _ struct{
+       // this comment should be visible and properly indented
+}
+
+type _ struct {  // this comment must not change indentation
+       f int
+       f, ff, fff, ffff int
+}
+
+type _ struct {
+       string
+}
+
+type _ struct {
+       string  // comment
+}
+
+type _ struct {
+       string "tag"
+}
+
+type _ struct {
+       string "tag"  // comment
+}
+
+type _ struct {
+       f int
+}
+
+type _ struct {
+       f int  // comment
+}
+
+type _ struct {
+       f int "tag"
+}
+
+type _ struct {
+       f int "tag"  // comment
+}
+
+type _ struct {
+       bool
+       a, b, c int
+       int "tag"
+       ES // comment
+       float "tag"  // comment
+       f int  // comment
+       f, ff, fff, ffff int  // comment
+       g float "tag"
+       h float "tag"  // comment
+}
+
+type _ struct { a, b,
+c, d int  // this line should be indented
+u, v, w, x float // this line should be indented
+p, q,
+r, s float // this line should be indented
+}
+
+
+// difficult cases
+type _ struct {
+       bool  // comment
+       text []byte  // comment
+}
+
+
+// formatting of interfaces
+type EI interface{}
+
+type _ interface {
+       EI
+}
+
+type _ interface {
+       f()
+       fffff()
+}
+
+type _ interface {
+       EI
+       f()
+       fffffg()
+}
+
+type _ interface {  // this comment must not change indentation
+       EI  // here's a comment
+       f()  // no blank between identifier and ()
+       fffff()  // no blank between identifier and ()
+       gggggggggggg(x, y, z int) ()  // hurray
+}
+
+
+// formatting of variable declarations
+func _() {
+       type day struct { n int; short, long string }
+       var (
+               Sunday = day{ 0, "SUN", "Sunday" }
+               Monday = day{ 1, "MON", "Monday" }
+               Tuesday = day{ 2, "TUE", "Tuesday" }
+               Wednesday = day{ 3, "WED", "Wednesday" }
+               Thursday = day{ 4, "THU", "Thursday" }
+               Friday = day{ 5, "FRI", "Friday" }
+               Saturday = day{ 6, "SAT", "Saturday" }
+       )
+}
+
+
+// formatting of multi-line variable declarations
+var a1, b1, c1 int  // all on one line
+
+var a2, b2,
+c2 int  // this line should be indented
+
+var (a3, b3,
+c3, d3 int  // this line should be indented
+a4, b4, c4 int  // this line should be indented
+)
+
+
+func _() {
+       var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
+                                       Headers: map[string]string{},
+                                       Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
+                       0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
+                       0xd4, 0x0, 0xae, 0x6a, 0x4d, 0x1b, 0x8a, 0x3b, 0x6a, 0x13,
+                       0x64, 0x2b, 0x23, 0xf2, 0x8b, 0x0, 0x3b, 0xfb, 0x97, 0x79,
+               },
+       }
+}
+
+
+func _() {
+       var Universe = Scope {
+               Names: map[string]*Ident {
+                       // basic types
+                       "bool": nil,
+                       "byte": nil,
+                       "int8": nil,
+                       "int16": nil,
+                       "int32": nil,
+                       "int64": nil,
+                       "uint8": nil,
+                       "uint16": nil,
+                       "uint32": nil,
+                       "uint64": nil,
+                       "float32": nil,
+                       "float64": nil,
+                       "string": nil,
+
+                       // convenience types
+                       "int": nil,
+                       "uint": nil,
+                       "uintptr": nil,
+                       "float": nil,
+
+                       // constants
+                       "false": nil,
+                       "true": nil,
+                       "iota": nil,
+                       "nil": nil,
+
+                       // functions
+                       "cap": nil,
+                       "len": nil,
+                       "new": nil,
+                       "make": nil,
+                       "panic": nil,
+                       "panicln": nil,
+                       "print": nil,
+                       "println": nil,
+               },
+       }
+}
+
+
+// alignment of map composite entries
+var _ = map[int]int{
+       // small key sizes: always align even if size ratios are large
+       a: a,
+       abcdefghabcdefgh: a,
+       ab: a,
+       abc: a,
+       abcdefgabcdefg: a,
+       abcd: a,
+       abcde: a,
+       abcdef: a,
+
+       // mixed key sizes: align when key sizes change within accepted ratio
+       abcdefgh: a,
+       abcdefghabcdefg: a,
+       abcdefghij: a,
+       abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // outlier - do not align with previous line
+       abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // align with previous line
+
+       ab: a, // do not align with previous line
+       abcde: a, // align with previous line
+}
+
+
+func _() {
+       var _ = T{
+               a,      // must introduce trailing comma
+       }
+}
+
+
+// formatting of function results
+func _() func() {}
+func _() func(int) { return nil }
+func _() func(int) int { return nil }
+func _() func(int) func(int) func() { return nil }
+
+
+// formatting of consecutive single-line functions
+func _() {}
+func _() {}
+func _() {}
+
+func _() {}  // an empty line before this function
+func _() {}
+func _() {}
+
+func _() { f(1, 2, 3) }
+func _(x int) int { y := x; return y+1 }
+func _() int { type T struct{}; var x T; return x }
+
+// these must remain multi-line since they are multi-line in the source
+func _() {
+       f(1, 2, 3)
+}
+func _(x int) int {
+       y := x; return y+1
+}
+func _() int {
+       type T struct{}; var x T; return x
+}
+
+
+// making function declarations safe for new semicolon rules
+func _() { /* multi-line func because of comment */ }
+
+func _() {
+/* multi-line func because block is on multiple lines */ }
+
+
+// ellipsis parameters
+func _(...int)
+func _(...*int)
+func _(...[]int)
+func _(...struct{})
+func _(bool, ...interface{})
+func _(bool, ...func())
+func _(bool, ...func(...int))
+func _(bool, ...map[string]int)
+func _(bool, ...chan int)
+
+func _(b bool, x ...int)
+func _(b bool, x ...*int)
+func _(b bool, x ...[]int)
+func _(b bool, x ...struct{})
+func _(x ...interface{})
+func _(x ...func())
+func _(x ...func(...int))
+func _(x ...map[string]int)
+func _(x ...chan int)
diff --git a/libgo/go/go/printer/testdata/empty.golden b/libgo/go/go/printer/testdata/empty.golden
new file mode 100644 (file)
index 0000000..a055f47
--- /dev/null
@@ -0,0 +1,5 @@
+// a comment at the beginning of the file
+
+package empty
+
+// a comment at the end of the file
diff --git a/libgo/go/go/printer/testdata/empty.input b/libgo/go/go/printer/testdata/empty.input
new file mode 100644 (file)
index 0000000..a055f47
--- /dev/null
@@ -0,0 +1,5 @@
+// a comment at the beginning of the file
+
+package empty
+
+// a comment at the end of the file
diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden
new file mode 100644 (file)
index 0000000..882c762
--- /dev/null
@@ -0,0 +1,554 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expressions
+
+type T struct {
+       x, y, z int
+}
+
+var (
+       a, b, c, d, e                                           int
+       under_bar                                               int
+       longIdentifier1, longIdentifier2, longIdentifier3       int
+       t0, t1, t2                                              T
+       s                                                       string
+       p                                                       *int
+)
+
+
+func _() {
+       // no spaces around simple or parenthesized expressions
+       _ = (a + 0)
+       _ = a + b
+       _ = a + b + c
+       _ = a + b - c
+       _ = a - b - c
+       _ = a + (b * c)
+       _ = a + (b / c)
+       _ = a - (b % c)
+       _ = 1 + a
+       _ = a + 1
+       _ = a + b + 1
+       _ = s[a]
+       _ = s[a:]
+       _ = s[:b]
+       _ = s[1:2]
+       _ = s[a:b]
+       _ = s[0:len(s)]
+       _ = s[0] << 1
+       _ = (s[0] << 1) & 0xf
+       _ = s[0]<<2 | s[1]>>4
+       _ = "foo" + s
+       _ = s + "foo"
+       _ = 'a' + 'b'
+       _ = len(s) / 2
+       _ = len(t0.x) / a
+
+       // spaces around expressions of different precedence or expressions containing spaces
+       _ = a + -b
+       _ = a - ^b
+       _ = a / *p
+       _ = a + b*c
+       _ = 1 + b*c
+       _ = a + 2*c
+       _ = a + c*2
+       _ = 1 + 2*3
+       _ = s[1 : 2*3]
+       _ = s[a : b-c]
+       _ = s[0:]
+       _ = s[a+b]
+       _ = s[:b-c]
+       _ = s[a+b:]
+       _ = a[a<<b+1]
+       _ = a[a<<b+1:]
+       _ = s[a+b : len(s)]
+       _ = s[len(s):-a]
+       _ = s[a : len(s)+1]
+       _ = s[a:len(s)+1] + s
+
+       // spaces around operators with equal or lower precedence than comparisons
+       _ = a == b
+       _ = a != b
+       _ = a > b
+       _ = a >= b
+       _ = a < b
+       _ = a <= b
+       _ = a < b && c > d
+       _ = a < b || c > d
+
+       // spaces around "long" operands
+       _ = a + longIdentifier1
+       _ = longIdentifier1 + a
+       _ = longIdentifier1 + longIdentifier2*longIdentifier3
+       _ = s + "a longer string"
+
+       // some selected cases
+       _ = a + t0.x
+       _ = a + t0.x + t1.x*t2.x
+       _ = a + b + c + d + e + 2*3
+       _ = a + b + c + 2*3 + d + e
+       _ = (a + b + c) * 2
+       _ = a - b + c - d + (a + b + c) + d&e
+       _ = under_bar - 1
+       _ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
+       _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+}
+
+
+func _() {
+       a + b
+       a + b + c
+       a + b*c
+       a + (b * c)
+       (a + b) * c
+       a + (b * c * d)
+       a + (b*c + d)
+
+       1 << x
+       -1 << x
+       1<<x - 1
+       -1<<x - 1
+
+       f(a + b)
+       f(a + b + c)
+       f(a + b*c)
+       f(a + (b * c))
+       f(1<<x-1, 1<<x-2)
+
+       1<<d.logWindowSize - 1
+
+       buf = make(x, 2*cap(b.buf)+n)
+
+       dst[i*3+2] = dbuf[0] << 2
+       dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4
+
+       b.buf = b.buf[0 : b.off+m+n]
+       b.buf = b.buf[0 : b.off+m*n]
+       f(b.buf[0 : b.off+m+n])
+
+       signed += ' ' * 8
+       tw.octal(header[148:155], chksum)
+
+       x > 0 && i >= 0
+
+       x1, x0 := x>>w2, x&m2
+       z0 = t1<<w2 + t0
+       z1 = (t1 + t0>>w2) >> w2
+       q1, r1 := x1/d1, x1%d1
+       r1 = r1*b2 | x0>>w2
+       x1 = (x1 << z) | (x0 >> (uint(w) - z))
+       x1 = x1<<z | x0>>(uint(w)-z)
+
+       buf[0 : len(buf)+1]
+       buf[0 : n+1]
+
+       a, b = b, a
+       a = b + c
+       a = b*c + d
+       a*b + c
+       a - b - c
+       a - (b - c)
+       a - b*c
+       a - (b * c)
+       a * b / c
+       a / *b
+       x[a|^b]
+       x[a / *b]
+       a & ^b
+       a + +b
+       a - -b
+       x[a*-b]
+       x[a + +b]
+       x ^ y ^ z
+       b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
+       len(longVariableName) * 2
+
+       token(matchType + xlength<<lengthShift + xoffset)
+}
+
+
+func f(x int, args ...int) {
+       f(0, args...)
+       f(1, args)
+       f(2, args[0])
+
+       // make sure syntactically legal code remains syntactically legal
+       f(3, 42 ...)    // a blank must remain between 42 and ...
+       f(4, 42....)
+       f(5, 42....)
+       f(6, 42.0...)
+       f(7, 42.0...)
+       f(8, .42...)
+       f(9, .42...)
+       f(10, 42e0...)
+       f(11, 42e0...)
+
+       _ = 42 .x       // a blank must remain between 42 and .x
+       _ = 42..x
+       _ = 42..x
+       _ = 42.0.x
+       _ = 42.0.x
+       _ = .42.x
+       _ = .42.x
+       _ = 42e0.x
+       _ = 42e0.x
+
+       // a blank must remain between the binary operator and the 2nd operand
+       _ = x / *y
+       _ = x < -1
+       _ = x < <-1
+       _ = x + +1
+       _ = x - -1
+       _ = x & &x
+       _ = x & ^x
+
+       _ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
+}
+
+
+func _() {
+       _ = T{}
+       _ = struct{}{}
+       _ = [10]T{}
+       _ = [...]T{}
+       _ = []T{}
+       _ = map[int]T{}
+}
+
+
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+       _ = struct{}{}
+       _ = struct{ x int }{0}
+       _ = struct{ x, y, z int }{0, 1, 2}
+       _ = struct{ int }{0}
+       _ = struct {
+               s struct {
+                       int
+               }
+       }{struct{ int }{0}}     // compositeLit context not propagated => multiLine result
+}
+
+
+func _() {
+       // do not modify literals
+       _ = "tab1       tab2    tab3    end"    // string contains 3 tabs
+       _ = "tab1 tab2 tab3 end"        // same string with 3 blanks - may be unaligned because editors see tabs in strings
+       _ = ""                          // this comment should be aligned with the one on the previous line
+       _ = ``
+       _ = `
+`
+       _ = `foo
+               bar`
+       _ = `three spaces before the end of the line starting here:   
+they must not be removed`
+}
+
+
+func _() {
+       // one-line function literals (body is on a single line)
+       _ = func() {}
+       _ = func() int { return 0 }
+       _ = func(x, y int) bool { m := (x + y) / 2; return m < 0 }
+
+       // multi-line function literals (body is not on one line)
+       _ = func() {
+       }
+       _ = func() int {
+               return 0
+       }
+       _ = func(x, y int) bool {
+               m := (x + y) / 2
+               return x < y
+       }
+
+       f(func() {
+       })
+       f(func() int {
+               return 0
+       })
+       f(func(x, y int) bool {
+               m := (x + y) / 2
+               return x < y
+       })
+}
+
+
+func _() {
+       _ = [][]int{
+               []int{1},
+               []int{1, 2},
+               []int{1, 2, 3},
+       }
+       _ = [][]int{
+               {1},
+               []int{1, 2},
+               []int{1, 2, 3},
+       }
+       _ = [][]int{
+               {1},
+               {1, 2},
+               {1, 2, 3},
+       }
+       _ = [][]int{{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
+       // do not add extra indentation to multi-line string lists
+       _ = "foo" + "bar"
+       _ = "foo" +
+               "bar" +
+               "bah"
+       _ = []string{
+               "abc" +
+                       "def",
+               "foo" +
+                       "bar",
+       }
+}
+
+
+const _ = F1 +
+       `string = "%s";` +
+       `ptr = *;` +
+       `datafmt.T2 = s ["-" p "-"];`
+
+
+const _ = `datafmt "datafmt";` +
+       `default = "%v";` +
+       `array = *;` +
+       `datafmt.T3 = s  {" " a a / ","};`
+
+
+const _ = `datafmt "datafmt";` +
+       `default = "%v";` +
+       `array = *;` +
+       `datafmt.T3 = s  {" " a a / ","};`
+
+
+func _() {
+       _ = F1 +
+               `string = "%s";` +
+               `ptr = *;` +
+               `datafmt.T2 = s ["-" p "-"];`
+
+       _ =
+               `datafmt "datafmt";` +
+                       `default = "%v";` +
+                       `array = *;` +
+                       `datafmt.T3 = s  {" " a a / ","};`
+
+       _ = `datafmt "datafmt";` +
+               `default = "%v";` +
+               `array = *;` +
+               `datafmt.T3 = s  {" " a a / ","};`
+}
+
+
+func _() {
+       // respect source lines in multi-line expressions
+       _ = a +
+               b +
+               c
+       _ = a < b ||
+               b < a
+       _ = "933262154439441526816992388562667004907159682643816214685929" +
+               "638952175999932299156089414639761565182862536979208272237582" +
+               "51185210916864000000000000000000000000"        // 100!
+       _ = "170141183460469231731687303715884105727"   // prime
+}
+
+
+// Alignment after overlong lines
+const (
+       _       = "991"
+       _       = "2432902008176640000" // 20!
+       _       = "933262154439441526816992388562667004907159682643816214685929" +
+               "638952175999932299156089414639761565182862536979208272237582" +
+               "51185210916864000000000000000000000000"        // 100!
+       _       = "170141183460469231731687303715884105727"     // prime
+)
+
+
+// Correct placement of operators and comments in multi-line expressions
+func _() {
+       _ = a + // comment
+               b +     // comment
+               c
+       _ = "a" +
+               "b" +   // comment
+               "c"
+       _ = "ba0408" + "7265717569726564"       // field 71, encoding 2, string "required"
+}
+
+
+// Correct placement of terminating comma/closing parentheses in multi-line calls.
+func _() {
+       f(1,
+               2,
+               3)
+       f(1,
+               2,
+               3,
+       )
+       f(1,
+               2,
+               3)      // comment
+       f(1,
+               2,
+               3,      // comment
+       )
+       f(1,
+               2,
+               3)      // comment
+       f(1,
+               2,
+               3,      // comment
+       )
+}
+
+
+// Align comments in multi-line lists of single-line expressions.
+var txpix = [NCOL]draw.Color{
+       draw.Yellow,            // yellow
+       draw.Cyan,              // cyan
+       draw.Green,             // lime green
+       draw.GreyBlue,          // slate
+       draw.Red,               /* red */
+       draw.GreyGreen,         /* olive green */
+       draw.Blue,              /* blue */
+       draw.Color(0xFF55AAFF), /* pink */
+       draw.Color(0xFFAAFFFF), /* lavender */
+       draw.Color(0xBB005DFF), /* maroon */
+}
+
+
+func same(t, u *Time) bool {
+       // respect source lines in multi-line expressions
+       return t.Year == u.Year &&
+               t.Month == u.Month &&
+               t.Day == u.Day &&
+               t.Hour == u.Hour &&
+               t.Minute == u.Minute &&
+               t.Second == u.Second &&
+               t.Weekday == u.Weekday &&
+               t.ZoneOffset == u.ZoneOffset &&
+               t.Zone == u.Zone
+}
+
+
+func (p *parser) charClass() {
+       // respect source lines in multi-line expressions
+       if cc.negate && len(cc.ranges) == 2 &&
+               cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+               nl := new(_NotNl)
+               p.re.add(nl)
+       }
+}
+
+
+func addState(s []state, inst instr, match []int) {
+       // handle comments correctly in multi-line expressions
+       for i := 0; i < l; i++ {
+               if s[i].inst.index() == index &&        // same instruction
+                       s[i].match[0] < pos {   // earlier match already going; leftmost wins
+                       return s
+               }
+       }
+}
+
+func (self *T) foo(x int) *T   { return self }
+
+func _()       { module.Func1().Func2() }
+
+func _() {
+       _ = new(T).
+               foo(1).
+               foo(2).
+               foo(3)
+
+       _ = new(T).
+               foo(1).
+               foo(2). // inline comments
+               foo(3)
+
+       _ = new(T).foo(1).foo(2).foo(3)
+
+       // handle multiline argument list correctly
+       _ = new(T).
+               foo(
+                       1).
+               foo(2)
+
+       _ = new(T).foo(
+               1).foo(2)
+
+       _ = Array[3+
+               4]
+
+       _ = Method(1, 2,
+               3)
+
+       _ = new(T).
+               foo().
+               bar().(*Type)
+
+       _ = new(T).
+               foo().
+               bar().(*Type).
+               baz()
+
+       _ = new(T).
+               foo().
+               bar()["idx"]
+
+       _ = new(T).
+               foo().
+               bar()["idx"].
+               baz()
+
+       _ = new(T).
+               foo().
+               bar()[1:2]
+
+       _ = new(T).
+               foo().
+               bar()[1:2].
+               baz()
+
+       _ = new(T).
+               Field.
+               Array[3+
+                       4].
+               Table["foo"].
+               Blob.(*Type).
+               Slices[1:4].
+               Method(1, 2,
+                       3).
+               Thingy
+
+       _ = a.b.c
+       _ = a.
+               b.
+               c
+       _ = a.b().c
+       _ = a.
+               b().
+               c
+       _ = a.b[0].c
+       _ = a.
+               b[0].
+               c
+       _ = a.b[0:].c
+       _ = a.
+               b[0:].
+               c
+       _ = a.b.(T).c
+       _ = a.
+               b.(T).
+               c
+}
diff --git a/libgo/go/go/printer/testdata/expressions.input b/libgo/go/go/printer/testdata/expressions.input
new file mode 100644 (file)
index 0000000..647706b
--- /dev/null
@@ -0,0 +1,548 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expressions
+
+type T struct {
+       x, y, z int
+}
+
+var (
+       a, b, c, d, e int
+       under_bar int
+       longIdentifier1, longIdentifier2, longIdentifier3 int
+       t0, t1, t2 T
+       s string
+       p *int
+)
+
+
+func _() {
+       // no spaces around simple or parenthesized expressions
+       _ = (a+0)
+       _ = a+b
+       _ = a+b+c
+       _ = a+b-c
+       _ = a-b-c
+       _ = a+(b*c)
+       _ = a+(b/c)
+       _ = a-(b%c)
+       _ = 1+a
+       _ = a+1
+       _ = a+b+1
+       _ = s[a]
+       _ = s[a:]
+       _ = s[:b]
+       _ = s[1:2]
+       _ = s[a:b]
+       _ = s[0:len(s)]
+       _ = s[0]<<1
+       _ = (s[0]<<1)&0xf
+       _ = s[0] << 2 | s[1] >> 4
+       _ = "foo"+s
+       _ = s+"foo"
+       _ = 'a'+'b'
+       _ = len(s)/2
+       _ = len(t0.x)/a
+
+       // spaces around expressions of different precedence or expressions containing spaces
+       _ = a + -b
+       _ = a - ^b
+       _ = a / *p
+       _ = a + b*c
+       _ = 1 + b*c
+       _ = a + 2*c
+       _ = a + c*2
+       _ = 1 + 2*3
+       _ = s[1 : 2*3]
+       _ = s[a : b-c]
+       _ = s[0:]
+       _ = s[a+b]
+       _ = s[: b-c]
+       _ = s[a+b :]
+       _ = a[a<<b+1]
+       _ = a[a<<b+1 :]
+       _ = s[a+b : len(s)]
+       _ = s[len(s) : -a]
+       _ = s[a : len(s)+1]
+       _ = s[a : len(s)+1]+s
+
+       // spaces around operators with equal or lower precedence than comparisons
+       _ = a == b
+       _ = a != b
+       _ = a > b
+       _ = a >= b
+       _ = a < b
+       _ = a <= b
+       _ = a < b && c > d
+       _ = a < b || c > d
+
+       // spaces around "long" operands
+       _ = a + longIdentifier1
+       _ = longIdentifier1 + a
+       _ = longIdentifier1 + longIdentifier2 * longIdentifier3
+       _ = s + "a longer string"
+
+       // some selected cases
+       _ = a + t0.x
+       _ = a + t0.x + t1.x * t2.x
+       _ = a + b + c + d + e + 2*3
+       _ = a + b + c + 2*3 + d + e
+       _ = (a+b+c)*2
+       _ = a - b + c - d + (a+b+c) + d&e
+       _ = under_bar-1
+       _ = Open(dpath + "/file", O_WRONLY | O_CREAT, 0666)
+       _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+}
+
+
+func _() {
+       a+b
+       a+b+c
+       a+b*c
+       a+(b*c)
+       (a+b)*c
+       a+(b*c*d)
+       a+(b*c+d)
+
+       1<<x
+       -1<<x
+       1<<x-1
+       -1<<x-1
+
+       f(a+b)
+       f(a+b+c)
+       f(a+b*c)
+       f(a+(b*c))
+       f(1<<x-1, 1<<x-2)
+
+       1<<d.logWindowSize-1
+
+       buf = make(x, 2*cap(b.buf) + n)
+
+       dst[i*3+2] = dbuf[0]<<2
+       dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4
+
+       b.buf = b.buf[0:b.off+m+n]
+       b.buf = b.buf[0:b.off+m*n]
+       f(b.buf[0:b.off+m+n])
+
+       signed += ' '*8
+       tw.octal(header[148:155], chksum)
+
+       x > 0 && i >= 0
+
+       x1, x0 := x>>w2, x&m2
+       z0 = t1<<w2+t0
+       z1 = (t1+t0>>w2)>>w2
+       q1, r1 := x1/d1, x1%d1
+       r1 = r1*b2 | x0>>w2
+       x1 = (x1<<z)|(x0>>(uint(w)-z))
+       x1 = x1<<z | x0>>(uint(w)-z)
+
+       buf[0:len(buf)+1]
+       buf[0:n+1]
+
+       a,b = b,a
+       a = b+c
+       a = b*c+d
+       a*b+c
+       a-b-c
+       a-(b-c)
+       a-b*c
+       a-(b*c)
+       a*b/c
+       a/ *b
+       x[a|^b]
+       x[a/ *b]
+       a& ^b
+       a+ +b
+       a- -b
+       x[a*-b]
+       x[a+ +b]
+       x^y^z
+       b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
+       len(longVariableName)*2
+
+       token(matchType + xlength<<lengthShift + xoffset)
+}
+
+
+func f(x int, args ...int) {
+       f(0, args...)
+       f(1, args)
+       f(2, args[0])
+
+       // make sure syntactically legal code remains syntactically legal
+       f(3, 42 ...) // a blank must remain between 42 and ...
+       f(4, 42. ...)
+       f(5, 42....)
+       f(6, 42.0 ...)
+       f(7, 42.0...)
+       f(8, .42 ...)
+       f(9, .42...)
+       f(10, 42e0 ...)
+       f(11, 42e0...)
+
+       _ = 42 .x // a blank must remain between 42 and .x
+       _ = 42. .x
+       _ = 42..x
+       _ = 42.0 .x
+       _ = 42.0.x
+       _ = .42 .x
+       _ = .42.x
+       _ = 42e0 .x
+       _ = 42e0.x
+
+       // a blank must remain between the binary operator and the 2nd operand
+       _ = x/ *y
+       _ = x< -1
+       _ = x< <-1
+       _ = x+ +1
+       _ = x- -1
+       _ = x& &x
+       _ = x& ^x
+
+       _ = f(x/ *y, x< -1, x< <-1, x+ +1, x- -1, x& &x, x& ^x)
+}
+
+
+func _() {
+       _ = T{}
+       _ = struct{}{}
+       _ = [10]T{}
+       _ = [...]T{}
+       _ = []T{}
+       _ = map[int]T{}
+}
+
+
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+       _ = struct{}{}
+       _ = struct{ x int }{0}
+       _ = struct{ x, y, z int }{0, 1, 2}
+       _ = struct{ int }{0}
+       _ = struct{ s struct { int } }{struct{ int}{0}}  // compositeLit context not propagated => multiLine result
+}
+
+
+func _() {
+       // do not modify literals
+       _ = "tab1       tab2    tab3    end"  // string contains 3 tabs
+       _ = "tab1 tab2 tab3 end"  // same string with 3 blanks - may be unaligned because editors see tabs in strings
+       _ = ""  // this comment should be aligned with the one on the previous line
+       _ = ``
+       _ = `
+`
+_ = `foo
+               bar`
+       _ = `three spaces before the end of the line starting here:   
+they must not be removed`
+}
+
+
+func _() {
+       // one-line function literals (body is on a single line)
+       _ = func() {}
+       _ = func() int { return 0 }
+       _ = func(x, y int) bool { m := (x+y)/2; return m < 0 }
+
+       // multi-line function literals (body is not on one line)
+       _ = func() {
+       }
+       _ = func() int {
+               return 0
+       }
+       _ = func(x, y int) bool {
+               m := (x+y)/2; return x < y }
+
+       f(func() {
+       })
+       f(func() int {
+               return 0
+       })
+       f(func(x, y int) bool {
+               m := (x+y)/2; return x < y })
+}
+
+
+func _() {
+       _ = [][]int {
+               []int{1},
+               []int{1, 2},
+               []int{1, 2, 3},
+       }
+       _ = [][]int {
+               {1},
+               []int{1, 2},
+               []int{1, 2, 3},
+       }
+       _ = [][]int {
+               {1},
+               {1, 2},
+               {1, 2, 3},
+       }
+       _ = [][]int {{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
+       // do not add extra indentation to multi-line string lists
+       _ = "foo" + "bar"
+       _ = "foo" +
+       "bar" +
+       "bah"
+       _ = []string {
+               "abc" +
+               "def",
+               "foo" +
+               "bar",
+       }
+}
+
+
+const _ = F1 +
+       `string = "%s";` +
+       `ptr = *;` +
+       `datafmt.T2 = s ["-" p "-"];`
+
+
+const _ =
+       `datafmt "datafmt";` +
+       `default = "%v";` +
+       `array = *;` +
+       `datafmt.T3 = s  {" " a a / ","};`
+
+
+const _ = `datafmt "datafmt";` +
+`default = "%v";` +
+`array = *;` +
+`datafmt.T3 = s  {" " a a / ","};`
+
+
+func _() {
+       _ = F1 +
+               `string = "%s";` +
+               `ptr = *;` +
+               `datafmt.T2 = s ["-" p "-"];`
+
+       _ =
+               `datafmt "datafmt";` +
+               `default = "%v";` +
+               `array = *;` +
+               `datafmt.T3 = s  {" " a a / ","};`
+
+       _ = `datafmt "datafmt";` +
+       `default = "%v";` +
+       `array = *;` +
+       `datafmt.T3 = s  {" " a a / ","};`
+}
+
+
+func _() {
+       // respect source lines in multi-line expressions
+       _ = a+
+       b+
+       c
+       _ = a < b ||
+               b < a
+       _ = "933262154439441526816992388562667004907159682643816214685929" +
+       "638952175999932299156089414639761565182862536979208272237582" +
+       "51185210916864000000000000000000000000"  // 100!
+       _ = "170141183460469231731687303715884105727"  // prime
+}
+
+
+// Alignment after overlong lines
+const (
+       _ = "991"
+       _ = "2432902008176640000"  // 20!
+       _ = "933262154439441526816992388562667004907159682643816214685929" +
+       "638952175999932299156089414639761565182862536979208272237582" +
+       "51185210916864000000000000000000000000"  // 100!
+       _ = "170141183460469231731687303715884105727"  // prime
+)
+
+
+// Correct placement of operators and comments in multi-line expressions
+func _() {
+       _ = a +  // comment
+               b +  // comment
+               c
+       _ = "a" +
+               "b" +   // comment
+               "c"
+       _ = "ba0408" + "7265717569726564"     // field 71, encoding 2, string "required"
+}
+
+
+// Correct placement of terminating comma/closing parentheses in multi-line calls.
+func _() {
+       f(1,
+               2,
+               3)
+       f(1,
+               2,
+               3,
+       )
+       f(1,
+               2,
+               3)  // comment
+       f(1,
+               2,
+               3,  // comment
+       )
+       f(1,
+               2,
+               3)// comment
+       f(1,
+               2,
+               3,// comment
+       )
+}
+
+
+// Align comments in multi-line lists of single-line expressions.
+var txpix = [NCOL]draw.Color{
+       draw.Yellow, // yellow
+       draw.Cyan, // cyan
+       draw.Green, // lime green
+       draw.GreyBlue, // slate
+       draw.Red, /* red */
+       draw.GreyGreen, /* olive green */
+       draw.Blue, /* blue */
+       draw.Color(0xFF55AAFF), /* pink */
+       draw.Color(0xFFAAFFFF), /* lavender */
+       draw.Color(0xBB005DFF), /* maroon */
+}
+
+
+func same(t, u *Time) bool {
+       // respect source lines in multi-line expressions
+       return t.Year == u.Year &&
+               t.Month == u.Month &&
+               t.Day == u.Day &&
+               t.Hour == u.Hour &&
+               t.Minute == u.Minute &&
+               t.Second == u.Second &&
+               t.Weekday == u.Weekday &&
+               t.ZoneOffset == u.ZoneOffset &&
+               t.Zone == u.Zone
+}
+
+
+func (p *parser) charClass() {
+       // respect source lines in multi-line expressions
+       if cc.negate && len(cc.ranges) == 2 &&
+               cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+               nl := new(_NotNl)
+               p.re.add(nl)
+       }
+}
+
+
+func addState(s []state, inst instr, match []int) {
+       // handle comments correctly in multi-line expressions
+       for i := 0; i < l; i++ {
+               if s[i].inst.index() == index && // same instruction
+                  s[i].match[0] < pos {        // earlier match already going; leftmost wins
+                       return s
+                }
+       }
+}
+
+func (self *T) foo(x int) *T { return self }
+
+func _() { module.Func1().Func2() }
+
+func _() {
+       _ = new(T).
+               foo(1).
+                       foo(2).
+               foo(3)
+
+       _ = new(T).
+       foo(1).
+       foo(2). // inline comments
+       foo(3)
+
+       _ = new(T).foo(1).foo(2).foo(3)
+
+       // handle multiline argument list correctly
+       _ = new(T).
+       foo(
+               1).
+               foo(2)
+
+       _ = new(T).foo(
+               1).foo(2)
+
+       _ = Array[3 +
+4]
+
+       _ = Method(1, 2,
+               3)
+
+       _ = new(T).
+   foo().
+   bar() . (*Type)
+
+       _ = new(T).
+foo().
+bar().(*Type).
+baz()
+
+       _ = new(T).
+       foo().
+       bar()["idx"]
+
+       _ = new(T).
+       foo().
+       bar()["idx"]    .
+       baz()
+
+       _ = new(T).
+       foo().
+       bar()[1:2]
+
+       _ = new(T).
+       foo().
+       bar()[1:2].
+       baz()
+
+       _ = new(T).
+               Field.
+               Array[3+
+                       4].
+               Table ["foo"].
+               Blob. (*Type).
+       Slices[1:4].
+       Method(1, 2,
+       3).
+               Thingy
+
+       _ = a.b.c
+       _ = a.
+       b.
+       c
+       _ = a.b().c
+       _ = a.
+       b().
+       c
+       _ = a.b[0].c
+       _ = a.
+       b[0].
+       c
+       _ = a.b[0:].c
+       _ = a.
+       b[0:].
+       c
+       _ = a.b.(T).c
+       _ = a.
+       b.
+       (T).
+       c
+}
diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw
new file mode 100644 (file)
index 0000000..62be00c
--- /dev/null
@@ -0,0 +1,554 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expressions
+
+type T struct {
+       x, y, z int
+}
+
+var (
+       a, b, c, d, e   int
+       under_bar       int
+       longIdentifier1, longIdentifier2, longIdentifier3       int
+       t0, t1, t2      T
+       s       string
+       p       *int
+)
+
+
+func _() {
+       // no spaces around simple or parenthesized expressions
+       _ = (a + 0)
+       _ = a + b
+       _ = a + b + c
+       _ = a + b - c
+       _ = a - b - c
+       _ = a + (b * c)
+       _ = a + (b / c)
+       _ = a - (b % c)
+       _ = 1 + a
+       _ = a + 1
+       _ = a + b + 1
+       _ = s[a]
+       _ = s[a:]
+       _ = s[:b]
+       _ = s[1:2]
+       _ = s[a:b]
+       _ = s[0:len(s)]
+       _ = s[0] << 1
+       _ = (s[0] << 1) & 0xf
+       _ = s[0]<<2 | s[1]>>4
+       _ = "foo" + s
+       _ = s + "foo"
+       _ = 'a' + 'b'
+       _ = len(s) / 2
+       _ = len(t0.x) / a
+
+       // spaces around expressions of different precedence or expressions containing spaces
+       _ = a + -b
+       _ = a - ^b
+       _ = a / *p
+       _ = a + b*c
+       _ = 1 + b*c
+       _ = a + 2*c
+       _ = a + c*2
+       _ = 1 + 2*3
+       _ = s[1 : 2*3]
+       _ = s[a : b-c]
+       _ = s[0:]
+       _ = s[a+b]
+       _ = s[:b-c]
+       _ = s[a+b:]
+       _ = a[a<<b+1]
+       _ = a[a<<b+1:]
+       _ = s[a+b : len(s)]
+       _ = s[len(s):-a]
+       _ = s[a : len(s)+1]
+       _ = s[a:len(s)+1] + s
+
+       // spaces around operators with equal or lower precedence than comparisons
+       _ = a == b
+       _ = a != b
+       _ = a > b
+       _ = a >= b
+       _ = a < b
+       _ = a <= b
+       _ = a < b && c > d
+       _ = a < b || c > d
+
+       // spaces around "long" operands
+       _ = a + longIdentifier1
+       _ = longIdentifier1 + a
+       _ = longIdentifier1 + longIdentifier2*longIdentifier3
+       _ = s + "a longer string"
+
+       // some selected cases
+       _ = a + t0.x
+       _ = a + t0.x + t1.x*t2.x
+       _ = a + b + c + d + e + 2*3
+       _ = a + b + c + 2*3 + d + e
+       _ = (a + b + c) * 2
+       _ = a - b + c - d + (a + b + c) + d&e
+       _ = under_bar - 1
+       _ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
+       _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+}
+
+
+func _() {
+       a + b
+       a + b + c
+       a + b*c
+       a + (b * c)
+       (a + b) * c
+       a + (b * c * d)
+       a + (b*c + d)
+
+       1 << x
+       -1 << x
+       1<<x - 1
+       -1<<x - 1
+
+       f(a + b)
+       f(a + b + c)
+       f(a + b*c)
+       f(a + (b * c))
+       f(1<<x-1, 1<<x-2)
+
+       1<<d.logWindowSize - 1
+
+       buf = make(x, 2*cap(b.buf)+n)
+
+       dst[i*3+2] = dbuf[0] << 2
+       dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4
+
+       b.buf = b.buf[0 : b.off+m+n]
+       b.buf = b.buf[0 : b.off+m*n]
+       f(b.buf[0 : b.off+m+n])
+
+       signed += ' ' * 8
+       tw.octal(header[148:155], chksum)
+
+       x > 0 && i >= 0
+
+       x1, x0 := x>>w2, x&m2
+       z0 = t1<<w2 + t0
+       z1 = (t1 + t0>>w2) >> w2
+       q1, r1 := x1/d1, x1%d1
+       r1 = r1*b2 | x0>>w2
+       x1 = (x1 << z) | (x0 >> (uint(w) - z))
+       x1 = x1<<z | x0>>(uint(w)-z)
+
+       buf[0 : len(buf)+1]
+       buf[0 : n+1]
+
+       a, b = b, a
+       a = b + c
+       a = b*c + d
+       a*b + c
+       a - b - c
+       a - (b - c)
+       a - b*c
+       a - (b * c)
+       a * b / c
+       a / *b
+       x[a|^b]
+       x[a / *b]
+       a & ^b
+       a + +b
+       a - -b
+       x[a*-b]
+       x[a + +b]
+       x ^ y ^ z
+       b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
+       len(longVariableName) * 2
+
+       token(matchType + xlength<<lengthShift + xoffset)
+}
+
+
+func f(x int, args ...int) {
+       f(0, args...)
+       f(1, args)
+       f(2, args[0])
+
+       // make sure syntactically legal code remains syntactically legal
+       f(3, 42 ...)    // a blank must remain between 42 and ...
+       f(4, 42....)
+       f(5, 42....)
+       f(6, 42.0...)
+       f(7, 42.0...)
+       f(8, .42...)
+       f(9, .42...)
+       f(10, 42e0...)
+       f(11, 42e0...)
+
+       _ = 42 .x       // a blank must remain between 42 and .x
+       _ = 42..x
+       _ = 42..x
+       _ = 42.0.x
+       _ = 42.0.x
+       _ = .42.x
+       _ = .42.x
+       _ = 42e0.x
+       _ = 42e0.x
+
+       // a blank must remain between the binary operator and the 2nd operand
+       _ = x / *y
+       _ = x < -1
+       _ = x < <-1
+       _ = x + +1
+       _ = x - -1
+       _ = x & &x
+       _ = x & ^x
+
+       _ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
+}
+
+
+func _() {
+       _ = T{}
+       _ = struct{}{}
+       _ = [10]T{}
+       _ = [...]T{}
+       _ = []T{}
+       _ = map[int]T{}
+}
+
+
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+       _ = struct{}{}
+       _ = struct{ x int }{0}
+       _ = struct{ x, y, z int }{0, 1, 2}
+       _ = struct{ int }{0}
+       _ = struct {
+               s struct {
+                       int
+               }
+       }{struct{ int }{0}}     // compositeLit context not propagated => multiLine result
+}
+
+
+func _() {
+       // do not modify literals
+       _ = "tab1       tab2    tab3    end"    // string contains 3 tabs
+       _ = "tab1 tab2 tab3 end"        // same string with 3 blanks - may be unaligned because editors see tabs in strings
+       _ = ""  // this comment should be aligned with the one on the previous line
+       _ = ``
+       _ = `
+`
+       _ = `foo
+               bar`
+       _ = `three spaces before the end of the line starting here:   
+they must not be removed`
+}
+
+
+func _() {
+       // one-line function literals (body is on a single line)
+       _ = func() {}
+       _ = func() int { return 0 }
+       _ = func(x, y int) bool { m := (x + y) / 2; return m < 0 }
+
+       // multi-line function literals (body is not on one line)
+       _ = func() {
+       }
+       _ = func() int {
+               return 0
+       }
+       _ = func(x, y int) bool {
+               m := (x + y) / 2
+               return x < y
+       }
+
+       f(func() {
+       })
+       f(func() int {
+               return 0
+       })
+       f(func(x, y int) bool {
+               m := (x + y) / 2
+               return x < y
+       })
+}
+
+
+func _() {
+       _ = [][]int{
+               []int{1},
+               []int{1, 2},
+               []int{1, 2, 3},
+       }
+       _ = [][]int{
+               {1},
+               []int{1, 2},
+               []int{1, 2, 3},
+       }
+       _ = [][]int{
+               {1},
+               {1, 2},
+               {1, 2, 3},
+       }
+       _ = [][]int{{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
+       // do not add extra indentation to multi-line string lists
+       _ = "foo" + "bar"
+       _ = "foo" +
+               "bar" +
+               "bah"
+       _ = []string{
+               "abc" +
+                       "def",
+               "foo" +
+                       "bar",
+       }
+}
+
+
+const _ = F1 +
+       `string = "%s";` +
+       `ptr = *;` +
+       `datafmt.T2 = s ["-" p "-"];`
+
+
+const _ = `datafmt "datafmt";` +
+       `default = "%v";` +
+       `array = *;` +
+       `datafmt.T3 = s  {" " a a / ","};`
+
+
+const _ = `datafmt "datafmt";` +
+       `default = "%v";` +
+       `array = *;` +
+       `datafmt.T3 = s  {" " a a / ","};`
+
+
+func _() {
+       _ = F1 +
+               `string = "%s";` +
+               `ptr = *;` +
+               `datafmt.T2 = s ["-" p "-"];`
+
+       _ =
+               `datafmt "datafmt";` +
+                       `default = "%v";` +
+                       `array = *;` +
+                       `datafmt.T3 = s  {" " a a / ","};`
+
+       _ = `datafmt "datafmt";` +
+               `default = "%v";` +
+               `array = *;` +
+               `datafmt.T3 = s  {" " a a / ","};`
+}
+
+
+func _() {
+       // respect source lines in multi-line expressions
+       _ = a +
+               b +
+               c
+       _ = a < b ||
+               b < a
+       _ = "933262154439441526816992388562667004907159682643816214685929" +
+               "638952175999932299156089414639761565182862536979208272237582" +
+               "51185210916864000000000000000000000000"        // 100!
+       _ = "170141183460469231731687303715884105727"   // prime
+}
+
+
+// Alignment after overlong lines
+const (
+       _       = "991"
+       _       = "2432902008176640000"         // 20!
+       _       = "933262154439441526816992388562667004907159682643816214685929" +
+               "638952175999932299156089414639761565182862536979208272237582" +
+               "51185210916864000000000000000000000000"        // 100!
+       _       = "170141183460469231731687303715884105727"             // prime
+)
+
+
+// Correct placement of operators and comments in multi-line expressions
+func _() {
+       _ = a + // comment
+               b +     // comment
+               c
+       _ = "a" +
+               "b" +   // comment
+               "c"
+       _ = "ba0408" + "7265717569726564"       // field 71, encoding 2, string "required"
+}
+
+
+// Correct placement of terminating comma/closing parentheses in multi-line calls.
+func _() {
+       f(1,
+               2,
+               3)
+       f(1,
+               2,
+               3,
+       )
+       f(1,
+               2,
+               3)      // comment
+       f(1,
+               2,
+               3,      // comment
+       )
+       f(1,
+               2,
+               3)      // comment
+       f(1,
+               2,
+               3,      // comment
+       )
+}
+
+
+// Align comments in multi-line lists of single-line expressions.
+var txpix = [NCOL]draw.Color{
+       draw.Yellow,    // yellow
+       draw.Cyan,      // cyan
+       draw.Green,     // lime green
+       draw.GreyBlue,  // slate
+       draw.Red,       /* red */
+       draw.GreyGreen, /* olive green */
+       draw.Blue,      /* blue */
+       draw.Color(0xFF55AAFF), /* pink */
+       draw.Color(0xFFAAFFFF), /* lavender */
+       draw.Color(0xBB005DFF), /* maroon */
+}
+
+
+func same(t, u *Time) bool {
+       // respect source lines in multi-line expressions
+       return t.Year == u.Year &&
+               t.Month == u.Month &&
+               t.Day == u.Day &&
+               t.Hour == u.Hour &&
+               t.Minute == u.Minute &&
+               t.Second == u.Second &&
+               t.Weekday == u.Weekday &&
+               t.ZoneOffset == u.ZoneOffset &&
+               t.Zone == u.Zone
+}
+
+
+func (p *parser) charClass() {
+       // respect source lines in multi-line expressions
+       if cc.negate && len(cc.ranges) == 2 &&
+               cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+               nl := new(_NotNl)
+               p.re.add(nl)
+       }
+}
+
+
+func addState(s []state, inst instr, match []int) {
+       // handle comments correctly in multi-line expressions
+       for i := 0; i < l; i++ {
+               if s[i].inst.index() == index &&        // same instruction
+                       s[i].match[0] < pos {   // earlier match already going; leftmost wins
+                       return s
+               }
+       }
+}
+
+func (self *T) foo(x int) *T   { return self }
+
+func _()       { module.Func1().Func2() }
+
+func _() {
+       _ = new(T).
+               foo(1).
+               foo(2).
+               foo(3)
+
+       _ = new(T).
+               foo(1).
+               foo(2). // inline comments
+               foo(3)
+
+       _ = new(T).foo(1).foo(2).foo(3)
+
+       // handle multiline argument list correctly
+       _ = new(T).
+               foo(
+                       1).
+               foo(2)
+
+       _ = new(T).foo(
+               1).foo(2)
+
+       _ = Array[3+
+               4]
+
+       _ = Method(1, 2,
+               3)
+
+       _ = new(T).
+               foo().
+               bar().(*Type)
+
+       _ = new(T).
+               foo().
+               bar().(*Type).
+               baz()
+
+       _ = new(T).
+               foo().
+               bar()["idx"]
+
+       _ = new(T).
+               foo().
+               bar()["idx"].
+               baz()
+
+       _ = new(T).
+               foo().
+               bar()[1:2]
+
+       _ = new(T).
+               foo().
+               bar()[1:2].
+               baz()
+
+       _ = new(T).
+               Field.
+               Array[3+
+                       4].
+               Table["foo"].
+               Blob.(*Type).
+               Slices[1:4].
+               Method(1, 2,
+                       3).
+               Thingy
+
+       _ = a.b.c
+       _ = a.
+               b.
+               c
+       _ = a.b().c
+       _ = a.
+               b().
+               c
+       _ = a.b[0].c
+       _ = a.
+               b[0].
+               c
+       _ = a.b[0:].c
+       _ = a.
+               b[0:].
+               c
+       _ = a.b.(T).c
+       _ = a.
+               b.(T).
+               c
+}
diff --git a/libgo/go/go/printer/testdata/linebreaks.golden b/libgo/go/go/printer/testdata/linebreaks.golden
new file mode 100644 (file)
index 0000000..be780da
--- /dev/null
@@ -0,0 +1,223 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package linebreaks
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "os"
+       "reflect"
+       "strings"
+       "testing"
+)
+
+type writerTestEntry struct {
+       header          *Header
+       contents        string
+}
+
+type writerTest struct {
+       file    string  // filename of expected output
+       entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+       &writerTest{
+               file:   "testdata/writer.tar",
+               entries: []*writerTestEntry{
+                       &writerTestEntry{
+                               header: &Header{
+                                       Name:           "small.txt",
+                                       Mode:           0640,
+                                       Uid:            73025,
+                                       Gid:            5000,
+                                       Size:           5,
+                                       Mtime:          1246508266,
+                                       Typeflag:       '0',
+                                       Uname:          "dsymonds",
+                                       Gname:          "eng",
+                               },
+                               contents:       "Kilts",
+                       },
+                       &writerTestEntry{
+                               header: &Header{
+                                       Name:           "small2.txt",
+                                       Mode:           0640,
+                                       Uid:            73025,
+                                       Gid:            5000,
+                                       Size:           11,
+                                       Mtime:          1245217492,
+                                       Typeflag:       '0',
+                                       Uname:          "dsymonds",
+                                       Gname:          "eng",
+                               },
+                               contents:       "Google.com\n",
+                       },
+               },
+       },
+       // The truncated test file was produced using these commands:
+       //   dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+       //   tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+       &writerTest{
+               file:   "testdata/writer-big.tar",
+               entries: []*writerTestEntry{
+                       &writerTestEntry{
+                               header: &Header{
+                                       Name:           "tmp/16gig.txt",
+                                       Mode:           0640,
+                                       Uid:            73025,
+                                       Gid:            5000,
+                                       Size:           16 << 30,
+                                       Mtime:          1254699560,
+                                       Typeflag:       '0',
+                                       Uname:          "dsymonds",
+                                       Gname:          "eng",
+                               },
+                               // no contents
+                       },
+               },
+       },
+}
+
+type untarTest struct {
+       file    string
+       headers []*Header
+}
+
+var untarTests = []*untarTest{
+       &untarTest{
+               file:   "testdata/gnu.tar",
+               headers: []*Header{
+                       &Header{
+                               Name:           "small.txt",
+                               Mode:           0640,
+                               Uid:            73025,
+                               Gid:            5000,
+                               Size:           5,
+                               Mtime:          1244428340,
+                               Typeflag:       '0',
+                               Uname:          "dsymonds",
+                               Gname:          "eng",
+                       },
+                       &Header{
+                               Name:           "small2.txt",
+                               Mode:           0640,
+                               Uid:            73025,
+                               Gid:            5000,
+                               Size:           11,
+                               Mtime:          1244436044,
+                               Typeflag:       '0',
+                               Uname:          "dsymonds",
+                               Gname:          "eng",
+                       },
+               },
+       },
+       &untarTest{
+               file:   "testdata/star.tar",
+               headers: []*Header{
+                       &Header{
+                               Name:           "small.txt",
+                               Mode:           0640,
+                               Uid:            73025,
+                               Gid:            5000,
+                               Size:           5,
+                               Mtime:          1244592783,
+                               Typeflag:       '0',
+                               Uname:          "dsymonds",
+                               Gname:          "eng",
+                               Atime:          1244592783,
+                               Ctime:          1244592783,
+                       },
+                       &Header{
+                               Name:           "small2.txt",
+                               Mode:           0640,
+                               Uid:            73025,
+                               Gid:            5000,
+                               Size:           11,
+                               Mtime:          1244592783,
+                               Typeflag:       '0',
+                               Uname:          "dsymonds",
+                               Gname:          "eng",
+                               Atime:          1244592783,
+                               Ctime:          1244592783,
+                       },
+               },
+       },
+       &untarTest{
+               file:   "testdata/v7.tar",
+               headers: []*Header{
+                       &Header{
+                               Name:           "small.txt",
+                               Mode:           0444,
+                               Uid:            73025,
+                               Gid:            5000,
+                               Size:           5,
+                               Mtime:          1244593104,
+                               Typeflag:       '\x00',
+                       },
+                       &Header{
+                               Name:           "small2.txt",
+                               Mode:           0444,
+                               Uid:            73025,
+                               Gid:            5000,
+                               Size:           11,
+                               Mtime:          1244593104,
+                               Typeflag:       '\x00',
+                       },
+               },
+       },
+}
+
+var facts = map[int]string{
+       0:      "1",
+       1:      "1",
+       2:      "2",
+       10:     "3628800",
+       20:     "2432902008176640000",
+       100: "933262154439441526816992388562667004907159682643816214685929" +
+               "638952175999932299156089414639761565182862536979208272237582" +
+               "51185210916864000000000000000000000000",
+}
+
+func usage() {
+       fmt.Fprintf(os.Stderr,
+               // TODO(gri): the 2nd string of this string list should not be indented
+               "usage: godoc package [name ...]\n"+
+                       "       godoc -http=:6060\n")
+       flag.PrintDefaults()
+       os.Exit(2)
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+       for i, test := range untarTests {
+               f, err := os.Open(test.file, os.O_RDONLY, 0444)
+               if err != nil {
+                       t.Errorf("test %d: Unexpected error: %v", i, err)
+                       continue
+               }
+               tr := NewReader(f)
+               for j, header := range test.headers {
+                       hdr, err := tr.Next()
+                       if err != nil || hdr == nil {
+                               t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+                               f.Close()
+                               continue testLoop
+                       }
+                       if !reflect.DeepEqual(hdr, header) {
+                               t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+                                       i, j, *hdr, *header)
+                       }
+               }
+               hdr, err := tr.Next()
+               if hdr != nil || err != nil {
+                       t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, err)
+               }
+               f.Close()
+       }
+}
+
+// There should be exactly one linebreak after this comment.
diff --git a/libgo/go/go/printer/testdata/linebreaks.input b/libgo/go/go/printer/testdata/linebreaks.input
new file mode 100644 (file)
index 0000000..457b491
--- /dev/null
@@ -0,0 +1,223 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package linebreaks
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "os"
+       "reflect"
+       "strings"
+       "testing"
+)
+
+type writerTestEntry struct {
+       header *Header
+       contents string
+}
+
+type writerTest struct {
+       file string  // filename of expected output
+       entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+       &writerTest{
+               file: "testdata/writer.tar",
+               entries: []*writerTestEntry{
+                       &writerTestEntry{
+                               header: &Header{
+                                       Name: "small.txt",
+                                       Mode: 0640,
+                                       Uid: 73025,
+                                       Gid: 5000,
+                                       Size: 5,
+                                       Mtime: 1246508266,
+                                       Typeflag: '0',
+                                       Uname: "dsymonds",
+                                       Gname: "eng",
+                               },
+                               contents: "Kilts",
+                       },
+                       &writerTestEntry{
+                               header: &Header{
+                                       Name: "small2.txt",
+                                       Mode: 0640,
+                                       Uid: 73025,
+                                       Gid: 5000,
+                                       Size: 11,
+                                       Mtime: 1245217492,
+                                       Typeflag: '0',
+                                       Uname: "dsymonds",
+                                       Gname: "eng",
+                               },
+                               contents: "Google.com\n",
+                       },
+               },
+       },
+       // The truncated test file was produced using these commands:
+       //   dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+       //   tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+       &writerTest{
+               file: "testdata/writer-big.tar",
+               entries: []*writerTestEntry{
+                       &writerTestEntry{
+                               header: &Header{
+                                       Name: "tmp/16gig.txt",
+                                       Mode: 0640,
+                                       Uid: 73025,
+                                       Gid: 5000,
+                                       Size: 16 << 30,
+                                       Mtime: 1254699560,
+                                       Typeflag: '0',
+                                       Uname: "dsymonds",
+                                       Gname: "eng",
+                               },
+                               // no contents
+                       },
+               },
+       },
+}
+
+type untarTest struct {
+       file string
+       headers []*Header
+}
+
+var untarTests = []*untarTest{
+       &untarTest{
+               file: "testdata/gnu.tar",
+               headers: []*Header{
+                       &Header{
+                               Name: "small.txt",
+                               Mode: 0640,
+                               Uid: 73025,
+                               Gid: 5000,
+                               Size: 5,
+                               Mtime: 1244428340,
+                               Typeflag: '0',
+                               Uname: "dsymonds",
+                               Gname: "eng",
+                       },
+                       &Header{
+                               Name: "small2.txt",
+                               Mode: 0640,
+                               Uid: 73025,
+                               Gid: 5000,
+                               Size: 11,
+                               Mtime: 1244436044,
+                               Typeflag: '0',
+                               Uname: "dsymonds",
+                               Gname: "eng",
+                       },
+               },
+       },
+       &untarTest{
+               file: "testdata/star.tar",
+               headers: []*Header{
+                       &Header{
+                               Name: "small.txt",
+                               Mode: 0640,
+                               Uid: 73025,
+                               Gid: 5000,
+                               Size: 5,
+                               Mtime: 1244592783,
+                               Typeflag: '0',
+                               Uname: "dsymonds",
+                               Gname: "eng",
+                               Atime: 1244592783,
+                               Ctime: 1244592783,
+                       },
+                       &Header{
+                               Name: "small2.txt",
+                               Mode: 0640,
+                               Uid: 73025,
+                               Gid: 5000,
+                               Size: 11,
+                               Mtime: 1244592783,
+                               Typeflag: '0',
+                               Uname: "dsymonds",
+                               Gname: "eng",
+                               Atime: 1244592783,
+                               Ctime: 1244592783,
+                       },
+               },
+       },
+       &untarTest{
+               file: "testdata/v7.tar",
+               headers: []*Header{
+                       &Header{
+                               Name: "small.txt",
+                               Mode: 0444,
+                               Uid: 73025,
+                               Gid: 5000,
+                               Size: 5,
+                               Mtime: 1244593104,
+                               Typeflag: '\x00',
+                       },
+                       &Header{
+                               Name: "small2.txt",
+                               Mode: 0444,
+                               Uid: 73025,
+                               Gid: 5000,
+                               Size: 11,
+                               Mtime: 1244593104,
+                               Typeflag: '\x00',
+                       },
+               },
+       },
+}
+
+var facts = map[int] string {
+       0: "1",
+       1: "1",
+       2: "2",
+       10: "3628800",
+       20: "2432902008176640000",
+       100: "933262154439441526816992388562667004907159682643816214685929" +
+               "638952175999932299156089414639761565182862536979208272237582" +
+               "51185210916864000000000000000000000000",
+}
+
+func usage() {
+       fmt.Fprintf(os.Stderr,
+               // TODO(gri): the 2nd string of this string list should not be indented
+               "usage: godoc package [name ...]\n" +
+               "       godoc -http=:6060\n")
+       flag.PrintDefaults()
+       os.Exit(2)
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+       for i, test := range untarTests {
+               f, err := os.Open(test.file, os.O_RDONLY, 0444)
+               if err != nil {
+                       t.Errorf("test %d: Unexpected error: %v", i, err)
+                       continue
+               }
+               tr := NewReader(f)
+               for j, header := range test.headers {
+                       hdr, err := tr.Next()
+                       if err != nil || hdr == nil {
+                               t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+                               f.Close()
+                               continue testLoop
+                       }
+                       if !reflect.DeepEqual(hdr, header) {
+                               t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+                                        i, j, *hdr, *header)
+                       }
+               }
+               hdr, err := tr.Next()
+               if hdr != nil || err != nil {
+                       t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, err)
+               }
+               f.Close()
+       }
+}
+
+// There should be exactly one linebreak after this comment.
diff --git a/libgo/go/go/printer/testdata/statements.golden b/libgo/go/go/printer/testdata/statements.golden
new file mode 100644 (file)
index 0000000..5eceb7d
--- /dev/null
@@ -0,0 +1,417 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package statements
+
+var expr bool
+
+func use(x interface{})        {}
+
+// Formatting of if-statement headers.
+func _() {
+       if {
+       }
+       if {
+       }       // no semicolon printed
+       if expr {
+       }
+       if expr {
+       }       // no semicolon printed
+       if expr {
+       }       // no parens printed
+       if expr {
+       }       // no semicolon and parens printed
+       if x := expr; {
+               use(x)
+       }
+       if x := expr; expr {
+               use(x)
+       }
+}
+
+
+// Formatting of switch-statement headers.
+func _() {
+       switch {
+       }
+       switch {
+       }       // no semicolon printed
+       switch expr {
+       }
+       switch expr {
+       }       // no semicolon printed
+       switch expr {
+       }       // no parens printed
+       switch expr {
+       }       // no semicolon and parens printed
+       switch x := expr; {
+       default:
+               use(
+                       x)
+       }
+       switch x := expr; expr {
+       default:
+               use(x)
+       }
+}
+
+
+// Formatting of switch statement bodies.
+func _() {
+       switch {
+       }
+
+       switch x := 0; x {
+       case 1:
+               use(x)
+               use(x)  // followed by an empty line
+
+       case 2: // followed by an empty line
+
+               use(x)  // followed by an empty line
+
+       case 3: // no empty lines
+               use(x)
+               use(x)
+       }
+
+       switch x {
+       case 0:
+               use(x)
+       case 1: // this comment should have no effect on the previous or next line
+               use(x)
+       }
+
+       switch x := 0; x {
+       case 1:
+               x = 0
+               // this comment should be indented
+       case 2:
+               x = 0
+       // this comment should not be indented, it is aligned with the next case
+       case 3:
+               x = 0
+               /* indented comment
+                  aligned
+                  aligned
+               */
+               // bla
+               /* and more */
+       case 4:
+               x = 0
+       /* not indented comment
+          aligned
+          aligned
+       */
+       // bla
+       /* and more */
+       case 5:
+       }
+}
+
+
+// Formatting of for-statement headers.
+func _() {
+       for {
+       }
+       for expr {
+       }
+       for expr {
+       }       // no parens printed
+       for {
+       }       // no semicolons printed
+       for x := expr; ; {
+               use(x)
+       }
+       for expr {
+       }       // no semicolons printed
+       for expr {
+       }       // no semicolons and parens printed
+       for ; ; expr = false {
+       }
+       for x := expr; expr; {
+               use(x)
+       }
+       for x := expr; ; expr = false {
+               use(x)
+       }
+       for ; expr; expr = false {
+       }
+       for x := expr; expr; expr = false {
+               use(x)
+       }
+       for x := range []int{} {
+               use(x)
+       }
+       for x := range []int{} {
+               use(x)
+       }       // no parens printed
+}
+
+
+// Don't remove mandatory parentheses around composite literals in control clauses.
+func _() {
+       // strip parentheses - no composite literals or composite literals don't start with a type name
+       if x {
+       }
+       if x {
+       }
+       if []T{} {
+       }
+       if []T{} {
+       }
+       if []T{} {
+       }
+
+       for x {
+       }
+       for x {
+       }
+       for []T{} {
+       }
+       for []T{} {
+       }
+       for []T{} {
+       }
+
+       switch x {
+       }
+       switch x {
+       }
+       switch []T{} {
+       }
+       switch []T{} {
+       }
+
+       for _ = range []T{T{42}} {
+       }
+
+       // leave parentheses - composite literals start with a type name
+       if (T{}) {
+       }
+       if (T{}) {
+       }
+       if (T{}) {
+       }
+
+       for (T{}) {
+       }
+       for (T{}) {
+       }
+       for (T{}) {
+       }
+
+       switch (T{}) {
+       }
+       switch (T{}) {
+       }
+
+       for _ = range (T1{T{42}}) {
+       }
+
+       if x == (T{42}[0]) {
+       }
+       if (x == T{42}[0]) {
+       }
+       if x == (T{42}[0]) {
+       }
+       if x == (T{42}[0]) {
+       }
+       if x == (T{42}[0]) {
+       }
+       if x == a+b*(T{42}[0]) {
+       }
+       if (x == a+b*T{42}[0]) {
+       }
+       if x == a+b*(T{42}[0]) {
+       }
+       if x == a+(b * (T{42}[0])) {
+       }
+       if x == a+b*(T{42}[0]) {
+       }
+       if (a + b*(T{42}[0])) == x {
+       }
+       if (a + b*(T{42}[0])) == x {
+       }
+
+       if struct{ x bool }{false}.x {
+       }
+       if (struct{ x bool }{false}.x) == false {
+       }
+       if struct{ x bool }{false}.x == false {
+       }
+}
+
+
+// Extra empty lines inside functions. Do respect source code line
+// breaks between statement boundaries but print at most one empty
+// line at a time.
+func _() {
+
+       const _ = 0
+
+       const _ = 1
+       type _ int
+       type _ float
+
+       var _ = 0
+       var x = 1
+
+       // Each use(x) call below should have at most one empty line before and after.
+       // Known bug: The first use call may have more than one empty line before
+       //            (see go/printer/nodes.go, func linebreak).
+
+
+       use(x)
+
+       if x < x {
+
+               use(x)
+
+       } else {
+
+               use(x)
+
+       }
+}
+
+
+// Formatting around labels.
+func _() {
+L:
+}
+
+
+func _() {
+       // this comment should be indented
+L:     // no semicolon needed
+}
+
+
+func _() {
+       switch 0 {
+       case 0:
+       L0:
+               ;       // semicolon required
+       case 1:
+       L1:
+               ;       // semicolon required
+       default:
+       L2:     // no semicolon needed
+       }
+}
+
+
+func _() {
+       f()
+L1:
+       f()
+L2:
+       ;
+L3:
+}
+
+
+func _() {
+       // this comment should be indented
+L:
+}
+
+
+func _() {
+L:
+       _ = 0
+}
+
+
+func _() {
+       // this comment should be indented
+L:
+       _ = 0
+}
+
+
+func _() {
+       for {
+       L1:
+               _ = 0
+       L2:
+               _ = 0
+       }
+}
+
+
+func _() {
+       // this comment should be indented
+       for {
+       L1:
+               _ = 0
+       L2:
+               _ = 0
+       }
+}
+
+
+func _() {
+       if {
+               _ = 0
+       }
+       _ = 0   // the indentation here should not be affected by the long label name
+AnOverlongLabel:
+       _ = 0
+
+       if {
+               _ = 0
+       }
+       _ = 0
+
+L:
+       _ = 0
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:
+
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:     // A comment on the same line as the label, followed by a single empty line.
+       // Known bug: There may be more than one empty line before MoreCode()
+       //            (see go/printer/nodes.go, func linebreak).
+
+
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:
+
+       // There should be a single empty line before this comment.
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto AVeryLongLabelThatShouldNotAffectFormatting
+       }
+AVeryLongLabelThatShouldNotAffectFormatting:
+       // There should be a single empty line after this comment.
+
+       // There should be a single empty line before this comment.
+       MoreCode()
+}
diff --git a/libgo/go/go/printer/testdata/statements.input b/libgo/go/go/printer/testdata/statements.input
new file mode 100644 (file)
index 0000000..7819820
--- /dev/null
@@ -0,0 +1,338 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package statements
+
+var expr bool
+
+func use(x interface{}) {}
+
+// Formatting of if-statement headers.
+func _() {
+       if {}
+       if;{}  // no semicolon printed
+       if expr{}
+       if;expr{}  // no semicolon printed
+       if (expr){}  // no parens printed
+       if;((expr)){}  // no semicolon and parens printed
+       if x:=expr;{
+       use(x)}
+       if x:=expr; expr {use(x)}
+}
+
+
+// Formatting of switch-statement headers.
+func _() {
+       switch {}
+       switch;{}  // no semicolon printed
+       switch expr {}
+       switch;expr{}  // no semicolon printed
+       switch (expr) {}  // no parens printed
+       switch;((expr)){}  // no semicolon and parens printed
+       switch x := expr; { default:use(
+x)
+       }
+       switch x := expr; expr {default:use(x)}
+}
+
+
+// Formatting of switch statement bodies.
+func _() {
+       switch {
+       }
+
+       switch x := 0; x {
+       case 1:
+               use(x)
+               use(x)  // followed by an empty line
+
+       case 2:  // followed by an empty line
+
+               use(x)  // followed by an empty line
+
+       case 3:  // no empty lines
+               use(x)
+               use(x)
+       }
+
+       switch x {
+       case 0:
+               use(x)
+       case 1:  // this comment should have no effect on the previous or next line
+               use(x)
+       }
+
+       switch x := 0; x {
+       case 1:
+               x = 0
+               // this comment should be indented
+       case 2:
+               x = 0
+       // this comment should not be indented, it is aligned with the next case
+       case 3:
+               x = 0
+               /* indented comment
+                  aligned
+                  aligned
+               */
+               // bla
+               /* and more */
+       case 4:
+               x = 0
+       /* not indented comment
+          aligned
+          aligned
+       */
+       // bla
+       /* and more */
+       case 5:
+       }
+}
+
+
+// Formatting of for-statement headers.
+func _() {
+       for{}
+       for expr {}
+       for (expr) {}  // no parens printed
+       for;;{}  // no semicolons printed
+       for x :=expr;; {use( x)}
+       for; expr;{}  // no semicolons printed
+       for; ((expr));{}  // no semicolons and parens printed
+       for; ; expr = false {}
+       for x :=expr; expr; {use(x)}
+       for x := expr;; expr=false {use(x)}
+       for;expr;expr =false {
+       }
+       for x := expr;expr;expr = false { use(x) }
+       for x := range []int{} { use(x) }
+       for x := range (([]int{})) { use(x) }  // no parens printed
+}
+
+
+// Don't remove mandatory parentheses around composite literals in control clauses.
+func _() {
+       // strip parentheses - no composite literals or composite literals don't start with a type name
+       if (x) {}
+       if (((x))) {}
+       if ([]T{}) {}
+       if (([]T{})) {}
+       if ; (((([]T{})))) {}
+
+       for (x) {}
+       for (((x))) {}
+       for ([]T{}) {}
+       for (([]T{})) {}
+       for ; (((([]T{})))) ; {}
+
+       switch (x) {}
+       switch (((x))) {}
+       switch ([]T{}) {}
+       switch ; (((([]T{})))) {}
+
+       for _ = range ((([]T{T{42}}))) {}
+
+       // leave parentheses - composite literals start with a type name
+       if (T{}) {}
+       if ((T{})) {}
+       if ; ((((T{})))) {}
+
+       for (T{}) {}
+       for ((T{})) {}
+       for ; ((((T{})))) ; {}
+
+       switch (T{}) {}
+       switch ; ((((T{})))) {}
+
+       for _ = range (((T1{T{42}}))) {}
+
+       if x == (T{42}[0]) {}
+       if (x == T{42}[0]) {}
+       if (x == (T{42}[0])) {}
+       if (x == (((T{42}[0])))) {}
+       if (((x == (T{42}[0])))) {}
+       if x == a + b*(T{42}[0]) {}
+       if (x == a + b*T{42}[0]) {}
+       if (x == a + b*(T{42}[0])) {}
+       if (x == a + ((b * (T{42}[0])))) {}
+       if (((x == a + b * (T{42}[0])))) {}
+       if (((a + b * (T{42}[0])) == x)) {}
+       if (((a + b * (T{42}[0])))) == x {}
+
+       if (struct{x bool}{false}.x) {}
+       if (struct{x bool}{false}.x) == false {}
+       if (struct{x bool}{false}.x == false) {}
+}
+
+
+// Extra empty lines inside functions. Do respect source code line
+// breaks between statement boundaries but print at most one empty
+// line at a time.
+func _() {
+
+       const _ = 0
+
+       const _ = 1
+       type _ int
+       type _ float
+
+       var _ = 0
+       var x = 1
+
+       // Each use(x) call below should have at most one empty line before and after.
+       // Known bug: The first use call may have more than one empty line before
+       //            (see go/printer/nodes.go, func linebreak).
+
+
+
+       use(x)
+
+       if x < x {
+
+               use(x)
+
+       } else {
+
+               use(x)
+
+       }
+}
+
+
+// Formatting around labels.
+func _() {
+       L:
+}
+
+
+func _() {
+       // this comment should be indented
+       L: ;  // no semicolon needed
+}
+
+
+func _() {
+       switch 0 {
+       case 0:
+               L0: ;  // semicolon required
+       case 1:
+               L1: ;  // semicolon required
+       default:
+               L2: ;  // no semicolon needed
+       }
+}
+
+
+func _() {
+       f()
+L1:
+       f()
+L2:
+       ;
+L3:
+}
+
+
+func _() {
+       // this comment should be indented
+       L:
+}
+
+
+func _() {
+       L: _ = 0
+}
+
+
+func _() {
+       // this comment should be indented
+       L: _ = 0
+}
+
+
+func _() {
+       for {
+       L1: _ = 0
+       L2:
+               _ = 0
+       }
+}
+
+
+func _() {
+               // this comment should be indented
+       for {
+       L1: _ = 0
+       L2:
+               _ = 0
+       }
+}
+
+
+func _() {
+       if {
+               _ = 0
+       }
+       _ = 0  // the indentation here should not be affected by the long label name
+AnOverlongLabel:
+       _ = 0
+       
+       if {
+               _ = 0
+       }
+       _ = 0
+
+L:     _ = 0
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:
+
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:     // A comment on the same line as the label, followed by a single empty line.
+       // Known bug: There may be more than one empty line before MoreCode()
+       //            (see go/printer/nodes.go, func linebreak).
+
+
+
+
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:
+
+
+
+
+       // There should be a single empty line before this comment.
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto AVeryLongLabelThatShouldNotAffectFormatting
+       }
+AVeryLongLabelThatShouldNotAffectFormatting:
+       // There should be a single empty line after this comment.
+
+       // There should be a single empty line before this comment.
+       MoreCode()
+}
diff --git a/libgo/go/go/scanner/errors.go b/libgo/go/go/scanner/errors.go
new file mode 100644 (file)
index 0000000..47e35a7
--- /dev/null
@@ -0,0 +1,186 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package scanner
+
+import (
+       "container/vector"
+       "fmt"
+       "go/token"
+       "io"
+       "os"
+       "sort"
+)
+
+
+// An implementation of an ErrorHandler may be provided to the Scanner.
+// If a syntax error is encountered and a handler was installed, Error
+// is called with a position and an error message. The position points
+// to the beginning of the offending token.
+//
+type ErrorHandler interface {
+       Error(pos token.Position, msg string)
+}
+
+
+// ErrorVector implements the ErrorHandler interface. It maintains a list
+// of errors which can be retrieved with GetErrorList and GetError. The
+// zero value for an ErrorVector is an empty ErrorVector ready to use.
+//
+// A common usage pattern is to embed an ErrorVector alongside a
+// scanner in a data structure that uses the scanner. By passing a
+// reference to an ErrorVector to the scanner's Init call, default
+// error handling is obtained.
+//
+type ErrorVector struct {
+       errors vector.Vector
+}
+
+
+// Reset resets an ErrorVector to no errors.
+func (h *ErrorVector) Reset() { h.errors.Resize(0, 0) }
+
+
+// ErrorCount returns the number of errors collected.
+func (h *ErrorVector) ErrorCount() int { return h.errors.Len() }
+
+
+// Within ErrorVector, an error is represented by an Error node. The
+// position Pos, if valid, points to the beginning of the offending
+// token, and the error condition is described by Msg.
+//
+type Error struct {
+       Pos token.Position
+       Msg string
+}
+
+
+func (e *Error) String() string {
+       if e.Pos.Filename != "" || e.Pos.IsValid() {
+               // don't print "<unknown position>"
+               // TODO(gri) reconsider the semantics of Position.IsValid
+               return e.Pos.String() + ": " + e.Msg
+       }
+       return e.Msg
+}
+
+
+// An ErrorList is a (possibly sorted) list of Errors.
+type ErrorList []*Error
+
+
+// ErrorList implements the sort Interface.
+func (p ErrorList) Len() int      { return len(p) }
+func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+
+func (p ErrorList) Less(i, j int) bool {
+       e := &p[i].Pos
+       f := &p[j].Pos
+       // Note that it is not sufficient to simply compare file offsets because
+       // the offsets do not reflect modified line information (through //line
+       // comments).
+       if e.Filename < f.Filename {
+               return true
+       }
+       if e.Filename == f.Filename {
+               if e.Line < f.Line {
+                       return true
+               }
+               if e.Line == f.Line {
+                       return e.Column < f.Column
+               }
+       }
+       return false
+}
+
+
+func (p ErrorList) String() string {
+       switch len(p) {
+       case 0:
+               return "unspecified error"
+       case 1:
+               return p[0].String()
+       }
+       return fmt.Sprintf("%s (and %d more errors)", p[0].String(), len(p)-1)
+}
+
+
+// These constants control the construction of the ErrorList
+// returned by GetErrors.
+//
+const (
+       Raw         = iota // leave error list unchanged
+       Sorted             // sort error list by file, line, and column number
+       NoMultiples        // sort error list and leave only the first error per line
+)
+
+
+// GetErrorList returns the list of errors collected by an ErrorVector.
+// The construction of the ErrorList returned is controlled by the mode
+// parameter. If there are no errors, the result is nil.
+//
+func (h *ErrorVector) GetErrorList(mode int) ErrorList {
+       if h.errors.Len() == 0 {
+               return nil
+       }
+
+       list := make(ErrorList, h.errors.Len())
+       for i := 0; i < h.errors.Len(); i++ {
+               list[i] = h.errors.At(i).(*Error)
+       }
+
+       if mode >= Sorted {
+               sort.Sort(list)
+       }
+
+       if mode >= NoMultiples {
+               var last token.Position // initial last.Line is != any legal error line
+               i := 0
+               for _, e := range list {
+                       if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line {
+                               last = e.Pos
+                               list[i] = e
+                               i++
+                       }
+               }
+               list = list[0:i]
+       }
+
+       return list
+}
+
+
+// GetError is like GetErrorList, but it returns an os.Error instead
+// so that a nil result can be assigned to an os.Error variable and
+// remains nil.
+//
+func (h *ErrorVector) GetError(mode int) os.Error {
+       if h.errors.Len() == 0 {
+               return nil
+       }
+
+       return h.GetErrorList(mode)
+}
+
+
+// ErrorVector implements the ErrorHandler interface.
+func (h *ErrorVector) Error(pos token.Position, msg string) {
+       h.errors.Push(&Error{pos, msg})
+}
+
+
+// PrintError is a utility function that prints a list of errors to w,
+// one error per line, if the err parameter is an ErrorList. Otherwise
+// it prints the err string.
+//
+func PrintError(w io.Writer, err os.Error) {
+       if list, ok := err.(ErrorList); ok {
+               for _, e := range list {
+                       fmt.Fprintf(w, "%s\n", e)
+               }
+       } else {
+               fmt.Fprintf(w, "%s\n", err)
+       }
+}
diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go
new file mode 100644 (file)
index 0000000..64ff127
--- /dev/null
@@ -0,0 +1,719 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A scanner for Go source text. Takes a []byte as source which can
+// then be tokenized through repeated calls to the Scan function.
+// For a sample use of a scanner, see the implementation of Tokenize.
+//
+package scanner
+
+import (
+       "bytes"
+       "go/token"
+       "strconv"
+       "unicode"
+       "utf8"
+)
+
+
+// A Scanner holds the scanner's internal state while processing
+// a given text.  It can be allocated as part of another data
+// structure but must be initialized via Init before use. For
+// a sample use, see the implementation of Tokenize.
+//
+type Scanner struct {
+       // immutable state
+       src  []byte       // source
+       err  ErrorHandler // error reporting; or nil
+       mode uint         // scanning mode
+
+       // scanning state
+       filename string // current filename; may change via //line filename:line comment
+       line     int    // current line
+       column   int    // current column
+
+       ch         int  // current character
+       offset     int  // character offset
+       rdOffset   int  // reading offset (position after current character)
+       insertSemi bool // insert a semicolon before next newline
+
+       // public state - ok to modify
+       ErrorCount int // number of errors encountered
+}
+
+
+// Read the next Unicode char into S.ch.
+// S.ch < 0 means end-of-file.
+//
+func (S *Scanner) next() {
+       S.column++
+       if S.rdOffset < len(S.src) {
+               S.offset = S.rdOffset
+               if S.ch == '\n' {
+                       S.line++
+                       S.column = 1
+               }
+               r, w := int(S.src[S.rdOffset]), 1
+               switch {
+               case r == 0:
+                       S.error("illegal character NUL")
+               case r >= 0x80:
+                       // not ASCII
+                       r, w = utf8.DecodeRune(S.src[S.rdOffset:])
+                       if r == utf8.RuneError && w == 1 {
+                               S.error("illegal UTF-8 encoding")
+                       }
+               }
+               S.rdOffset += w
+               S.ch = r
+       } else {
+               S.offset = len(S.src)
+               if S.ch == '\n' {
+                       S.column = 1
+               }
+               S.ch = -1 // eof
+       }
+}
+
+
+// The mode parameter to the Init function is a set of flags (or 0).
+// They control scanner behavior.
+//
+const (
+       ScanComments      = 1 << iota // return comments as COMMENT tokens
+       AllowIllegalChars             // do not report an error for illegal chars
+       InsertSemis                   // automatically insert semicolons
+)
+
+
+// Init prepares the scanner S to tokenize the text src. Calls to Scan
+// will use the error handler err if they encounter a syntax error and
+// err is not nil. Also, for each error encountered, the Scanner field
+// ErrorCount is incremented by one. The filename parameter is used as
+// filename in the token.Position returned by Scan for each token. The
+// mode parameter determines how comments and illegal characters are
+// handled.
+//
+func (S *Scanner) Init(filename string, src []byte, err ErrorHandler, mode uint) {
+       // Explicitly initialize all fields since a scanner may be reused.
+       S.src = src
+       S.err = err
+       S.mode = mode
+
+       S.filename = filename
+       S.line = 1
+       S.column = 0
+
+       S.ch = ' '
+       S.offset = 0
+       S.rdOffset = 0
+       S.insertSemi = false
+       S.ErrorCount = 0
+
+       S.next()
+}
+
+
+func charString(ch int) string {
+       var s string
+       switch ch {
+       case -1:
+               return `EOF`
+       case '\a':
+               s = `\a`
+       case '\b':
+               s = `\b`
+       case '\f':
+               s = `\f`
+       case '\n':
+               s = `\n`
+       case '\r':
+               s = `\r`
+       case '\t':
+               s = `\t`
+       case '\v':
+               s = `\v`
+       case '\\':
+               s = `\\`
+       case '\'':
+               s = `\'`
+       default:
+               s = string(ch)
+       }
+       return "'" + s + "' (U+" + strconv.Itob(ch, 16) + ")"
+}
+
+
+func (S *Scanner) error(msg string) {
+       S.errorAt(token.Position{S.filename, S.offset, S.line, S.column}, msg)
+}
+
+
+func (S *Scanner) errorAt(pos token.Position, msg string) {
+       if S.err != nil {
+               S.err.Error(pos, msg)
+       }
+       S.ErrorCount++
+}
+
+
+var prefix = []byte("//line ")
+
+func (S *Scanner) interpretLineComment(text []byte) {
+       if bytes.HasPrefix(text, prefix) {
+               // get filename and line number, if any
+               if i := bytes.Index(text, []byte{':'}); i > 0 {
+                       if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 {
+                               // valid //line filename:line comment;
+                               // update scanner position
+                               S.filename = string(text[len(prefix):i])
+                               S.line = line - 1 // -1 since the '\n' has not been consumed yet
+                       }
+               }
+       }
+}
+
+
+func (S *Scanner) scanComment() {
+       // initial '/' already consumed; S.ch == '/' || S.ch == '*'
+       offs := S.offset - 1 // position of initial '/'
+       col := S.column - 1
+       pos := token.Position{S.filename, S.offset - 1, S.line, S.column - 1}
+
+       if S.ch == '/' {
+               //-style comment
+               S.next()
+               for S.ch != '\n' && S.ch >= 0 {
+                       S.next()
+               }
+               if col == 1 {
+                       // comment starts at the beginning of the current line
+                       S.interpretLineComment(S.src[offs:S.offset])
+               }
+               return
+       }
+
+       /*-style comment */
+       S.next()
+       for S.ch >= 0 {
+               ch := S.ch
+               S.next()
+               if ch == '*' && S.ch == '/' {
+                       S.next()
+                       return
+               }
+       }
+
+       S.errorAt(pos, "comment not terminated")
+}
+
+
+func (S *Scanner) findLineEnd() bool {
+       // initial '/' already consumed
+
+       defer func(line, col, offs int) {
+               // reset scanner state to where it was upon calling findLineEnd
+               // (we don't scan //line comments and ignore errors thus
+               // S.filename and S.ErrorCount don't change)
+               S.line = line
+               S.column = col
+               S.ch = '/'
+               S.offset = offs
+               S.rdOffset = offs + 1
+               S.next() // consume initial '/' again
+       }(S.line, S.column-1, S.offset-1)
+
+       // read ahead until a newline, EOF, or non-comment token is found
+       for S.ch == '/' || S.ch == '*' {
+               if S.ch == '/' {
+                       //-style comment always contains a newline
+                       return true
+               }
+               /*-style comment: look for newline */
+               S.next()
+               for S.ch >= 0 {
+                       ch := S.ch
+                       if ch == '\n' {
+                               return true
+                       }
+                       S.next()
+                       if ch == '*' && S.ch == '/' {
+                               S.next()
+                               break
+                       }
+               }
+               S.skipWhitespace() // S.insertSemi is set
+               if S.ch < 0 || S.ch == '\n' {
+                       return true
+               }
+               if S.ch != '/' {
+                       // non-comment token
+                       return false
+               }
+               S.next() // consume '/'
+       }
+
+       return false
+}
+
+
+func isLetter(ch int) bool {
+       return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
+}
+
+
+func isDigit(ch int) bool {
+       return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
+}
+
+
+func (S *Scanner) scanIdentifier() token.Token {
+       offs := S.offset
+       for isLetter(S.ch) || isDigit(S.ch) {
+               S.next()
+       }
+       return token.Lookup(S.src[offs:S.offset])
+}
+
+
+func digitVal(ch int) int {
+       switch {
+       case '0' <= ch && ch <= '9':
+               return ch - '0'
+       case 'a' <= ch && ch <= 'f':
+               return ch - 'a' + 10
+       case 'A' <= ch && ch <= 'F':
+               return ch - 'A' + 10
+       }
+       return 16 // larger than any legal digit val
+}
+
+
+func (S *Scanner) scanMantissa(base int) {
+       for digitVal(S.ch) < base {
+               S.next()
+       }
+}
+
+
+func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
+       // digitVal(S.ch) < 10
+       tok := token.INT
+
+       if seenDecimalPoint {
+               tok = token.FLOAT
+               S.scanMantissa(10)
+               goto exponent
+       }
+
+       if S.ch == '0' {
+               // int or float
+               pos := token.Position{S.filename, S.offset, S.line, S.column}
+               S.next()
+               if S.ch == 'x' || S.ch == 'X' {
+                       // hexadecimal int
+                       S.next()
+                       S.scanMantissa(16)
+               } else {
+                       // octal int or float
+                       seenDecimalDigit := false
+                       S.scanMantissa(8)
+                       if S.ch == '8' || S.ch == '9' {
+                               // illegal octal int or float
+                               seenDecimalDigit = true
+                               S.scanMantissa(10)
+                       }
+                       if S.ch == '.' || S.ch == 'e' || S.ch == 'E' || S.ch == 'i' {
+                               goto fraction
+                       }
+                       // octal int
+                       if seenDecimalDigit {
+                               S.errorAt(pos, "illegal octal number")
+                       }
+               }
+               goto exit
+       }
+
+       // decimal int or float
+       S.scanMantissa(10)
+
+fraction:
+       if S.ch == '.' {
+               tok = token.FLOAT
+               S.next()
+               S.scanMantissa(10)
+       }
+
+exponent:
+       if S.ch == 'e' || S.ch == 'E' {
+               tok = token.FLOAT
+               S.next()
+               if S.ch == '-' || S.ch == '+' {
+                       S.next()
+               }
+               S.scanMantissa(10)
+       }
+
+       if S.ch == 'i' {
+               tok = token.IMAG
+               S.next()
+       }
+
+exit:
+       return tok
+}
+
+
+func (S *Scanner) scanEscape(quote int) {
+       pos := token.Position{S.filename, S.offset, S.line, S.column}
+
+       var i, base, max uint32
+       switch S.ch {
+       case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
+               S.next()
+               return
+       case '0', '1', '2', '3', '4', '5', '6', '7':
+               i, base, max = 3, 8, 255
+       case 'x':
+               S.next()
+               i, base, max = 2, 16, 255
+       case 'u':
+               S.next()
+               i, base, max = 4, 16, unicode.MaxRune
+       case 'U':
+               S.next()
+               i, base, max = 8, 16, unicode.MaxRune
+       default:
+               S.next() // always make progress
+               S.errorAt(pos, "unknown escape sequence")
+               return
+       }
+
+       var x uint32
+       for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
+               d := uint32(digitVal(S.ch))
+               if d >= base {
+                       S.error("illegal character in escape sequence")
+                       break
+               }
+               x = x*base + d
+               S.next()
+       }
+       // in case of an error, consume remaining chars
+       for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
+               S.next()
+       }
+       if x > max || 0xd800 <= x && x < 0xe000 {
+               S.errorAt(pos, "escape sequence is invalid Unicode code point")
+       }
+}
+
+
+func (S *Scanner) scanChar() {
+       // '\'' opening already consumed
+       pos := token.Position{S.filename, S.offset - 1, S.line, S.column - 1}
+
+       n := 0
+       for S.ch != '\'' {
+               ch := S.ch
+               n++
+               S.next()
+               if ch == '\n' || ch < 0 {
+                       S.errorAt(pos, "character literal not terminated")
+                       n = 1
+                       break
+               }
+               if ch == '\\' {
+                       S.scanEscape('\'')
+               }
+       }
+
+       S.next()
+
+       if n != 1 {
+               S.errorAt(pos, "illegal character literal")
+       }
+}
+
+
+func (S *Scanner) scanString() {
+       // '"' opening already consumed
+       pos := token.Position{S.filename, S.offset - 1, S.line, S.column - 1}
+
+       for S.ch != '"' {
+               ch := S.ch
+               S.next()
+               if ch == '\n' || ch < 0 {
+                       S.errorAt(pos, "string not terminated")
+                       break
+               }
+               if ch == '\\' {
+                       S.scanEscape('"')
+               }
+       }
+
+       S.next()
+}
+
+
+func (S *Scanner) scanRawString() {
+       // '`' opening already consumed
+       pos := token.Position{S.filename, S.offset - 1, S.line, S.column - 1}
+
+       for S.ch != '`' {
+               ch := S.ch
+               S.next()
+               if ch < 0 {
+                       S.errorAt(pos, "string not terminated")
+                       break
+               }
+       }
+
+       S.next()
+}
+
+
+func (S *Scanner) skipWhitespace() {
+       for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' && !S.insertSemi || S.ch == '\r' {
+               S.next()
+       }
+}
+
+
+// Helper functions for scanning multi-byte tokens such as >> += >>= .
+// Different routines recognize different length tok_i based on matches
+// of ch_i. If a token ends in '=', the result is tok1 or tok3
+// respectively. Otherwise, the result is tok0 if there was no other
+// matching character, or tok2 if the matching character was ch2.
+
+func (S *Scanner) switch2(tok0, tok1 token.Token) token.Token {
+       if S.ch == '=' {
+               S.next()
+               return tok1
+       }
+       return tok0
+}
+
+
+func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) token.Token {
+       if S.ch == '=' {
+               S.next()
+               return tok1
+       }
+       if S.ch == ch2 {
+               S.next()
+               return tok2
+       }
+       return tok0
+}
+
+
+func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Token) token.Token {
+       if S.ch == '=' {
+               S.next()
+               return tok1
+       }
+       if S.ch == ch2 {
+               S.next()
+               if S.ch == '=' {
+                       S.next()
+                       return tok3
+               }
+               return tok2
+       }
+       return tok0
+}
+
+
+var newline = []byte{'\n'}
+
+// Scan scans the next token and returns the token position pos,
+// the token tok, and the literal text lit corresponding to the
+// token. The source end is indicated by token.EOF.
+//
+// If the returned token is token.SEMICOLON, the corresponding
+// literal value is ";" if the semicolon was present in the source,
+// and "\n" if the semicolon was inserted because of a newline or
+// at EOF.
+//
+// For more tolerant parsing, Scan will return a valid token if
+// possible even if a syntax error was encountered. Thus, even
+// if the resulting token sequence contains no illegal tokens,
+// a client may not assume that no error occurred. Instead it
+// must check the scanner's ErrorCount or the number of calls
+// of the error handler, if there was one installed.
+//
+func (S *Scanner) Scan() (pos token.Position, tok token.Token, lit []byte) {
+scanAgain:
+       S.skipWhitespace()
+
+       // current token start
+       insertSemi := false
+       pos, tok = token.Position{S.filename, S.offset, S.line, S.column}, token.ILLEGAL
+       offs := S.offset
+
+       // determine token value
+       switch ch := S.ch; {
+       case isLetter(ch):
+               tok = S.scanIdentifier()
+               switch tok {
+               case token.IDENT, token.BREAK, token.CONTINUE, token.FALLTHROUGH, token.RETURN:
+                       insertSemi = true
+               }
+       case digitVal(ch) < 10:
+               insertSemi = true
+               tok = S.scanNumber(false)
+       default:
+               S.next() // always make progress
+               switch ch {
+               case -1:
+                       if S.insertSemi {
+                               S.insertSemi = false // EOF consumed
+                               return pos, token.SEMICOLON, newline
+                       }
+                       tok = token.EOF
+               case '\n':
+                       // we only reach here if S.insertSemi was
+                       // set in the first place and exited early
+                       // from S.skipWhitespace()
+                       S.insertSemi = false // newline consumed
+                       return pos, token.SEMICOLON, newline
+               case '"':
+                       insertSemi = true
+                       tok = token.STRING
+                       S.scanString()
+               case '\'':
+                       insertSemi = true
+                       tok = token.CHAR
+                       S.scanChar()
+               case '`':
+                       insertSemi = true
+                       tok = token.STRING
+                       S.scanRawString()
+               case ':':
+                       tok = S.switch2(token.COLON, token.DEFINE)
+               case '.':
+                       if digitVal(S.ch) < 10 {
+                               insertSemi = true
+                               tok = S.scanNumber(true)
+                       } else if S.ch == '.' {
+                               S.next()
+                               if S.ch == '.' {
+                                       S.next()
+                                       tok = token.ELLIPSIS
+                               }
+                       } else {
+                               tok = token.PERIOD
+                       }
+               case ',':
+                       tok = token.COMMA
+               case ';':
+                       tok = token.SEMICOLON
+               case '(':
+                       tok = token.LPAREN
+               case ')':
+                       insertSemi = true
+                       tok = token.RPAREN
+               case '[':
+                       tok = token.LBRACK
+               case ']':
+                       insertSemi = true
+                       tok = token.RBRACK
+               case '{':
+                       tok = token.LBRACE
+               case '}':
+                       insertSemi = true
+                       tok = token.RBRACE
+               case '+':
+                       tok = S.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC)
+                       if tok == token.INC {
+                               insertSemi = true
+                       }
+               case '-':
+                       tok = S.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC)
+                       if tok == token.DEC {
+                               insertSemi = true
+                       }
+               case '*':
+                       tok = S.switch2(token.MUL, token.MUL_ASSIGN)
+               case '/':
+                       if S.ch == '/' || S.ch == '*' {
+                               // comment
+                               line := S.line
+                               col := S.column - 1 // beginning of comment
+                               if S.insertSemi && S.findLineEnd() {
+                                       // reset position to the beginning of the comment
+                                       S.line = line
+                                       S.column = col
+                                       S.ch = '/'
+                                       S.offset = offs
+                                       S.rdOffset = offs + 1
+                                       S.insertSemi = false // newline consumed
+                                       return pos, token.SEMICOLON, newline
+                               }
+                               S.scanComment()
+                               if S.mode&ScanComments == 0 {
+                                       // skip comment
+                                       S.insertSemi = false // newline consumed
+                                       goto scanAgain
+                               }
+                               tok = token.COMMENT
+                       } else {
+                               tok = S.switch2(token.QUO, token.QUO_ASSIGN)
+                       }
+               case '%':
+                       tok = S.switch2(token.REM, token.REM_ASSIGN)
+               case '^':
+                       tok = S.switch2(token.XOR, token.XOR_ASSIGN)
+               case '<':
+                       if S.ch == '-' {
+                               S.next()
+                               tok = token.ARROW
+                       } else {
+                               tok = S.switch4(token.LSS, token.LEQ, '<', token.SHL, token.SHL_ASSIGN)
+                       }
+               case '>':
+                       tok = S.switch4(token.GTR, token.GEQ, '>', token.SHR, token.SHR_ASSIGN)
+               case '=':
+                       tok = S.switch2(token.ASSIGN, token.EQL)
+               case '!':
+                       tok = S.switch2(token.NOT, token.NEQ)
+               case '&':
+                       if S.ch == '^' {
+                               S.next()
+                               tok = S.switch2(token.AND_NOT, token.AND_NOT_ASSIGN)
+                       } else {
+                               tok = S.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND)
+                       }
+               case '|':
+                       tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
+               default:
+                       if S.mode&AllowIllegalChars == 0 {
+                               S.errorAt(pos, "illegal character "+charString(ch))
+                       }
+                       insertSemi = S.insertSemi // preserve insertSemi info
+               }
+       }
+
+       if S.mode&InsertSemis != 0 {
+               S.insertSemi = insertSemi
+       }
+       return pos, tok, S.src[offs:S.offset]
+}
+
+
+// Tokenize calls a function f with the token position, token value, and token
+// text for each token in the source src. The other parameters have the same
+// meaning as for the Init function. Tokenize keeps scanning until f returns
+// false (usually when the token value is token.EOF). The result is the number
+// of errors encountered.
+//
+func Tokenize(filename string, src []byte, err ErrorHandler, mode uint, f func(pos token.Position, tok token.Token, lit []byte) bool) int {
+       var s Scanner
+       s.Init(filename, src, err, mode)
+       for f(s.Scan()) {
+               // action happens in f
+       }
+       return s.ErrorCount
+}
diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go
new file mode 100644 (file)
index 0000000..dbec8f7
--- /dev/null
@@ -0,0 +1,647 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package scanner
+
+import (
+       "go/token"
+       "os"
+       "testing"
+)
+
+
+const /* class */ (
+       special = iota
+       literal
+       operator
+       keyword
+)
+
+
+func tokenclass(tok token.Token) int {
+       switch {
+       case tok.IsLiteral():
+               return literal
+       case tok.IsOperator():
+               return operator
+       case tok.IsKeyword():
+               return keyword
+       }
+       return special
+}
+
+
+type elt struct {
+       tok   token.Token
+       lit   string
+       class int
+}
+
+
+var tokens = [...]elt{
+       // Special tokens
+       {token.COMMENT, "/* a comment */", special},
+       {token.COMMENT, "// a comment \n", special},
+
+       // Identifiers and basic type literals
+       {token.IDENT, "foobar", literal},
+       {token.IDENT, "a۰۱۸", literal},
+       {token.IDENT, "foo६४", literal},
+       {token.IDENT, "bar9876", literal},
+       {token.INT, "0", literal},
+       {token.INT, "1", literal},
+       {token.INT, "123456789012345678890", literal},
+       {token.INT, "01234567", literal},
+       {token.INT, "0xcafebabe", literal},
+       {token.FLOAT, "0.", literal},
+       {token.FLOAT, ".0", literal},
+       {token.FLOAT, "3.14159265", literal},
+       {token.FLOAT, "1e0", literal},
+       {token.FLOAT, "1e+100", literal},
+       {token.FLOAT, "1e-100", literal},
+       {token.FLOAT, "2.71828e-1000", literal},
+       {token.IMAG, "0i", literal},
+       {token.IMAG, "1i", literal},
+       {token.IMAG, "012345678901234567889i", literal},
+       {token.IMAG, "123456789012345678890i", literal},
+       {token.IMAG, "0.i", literal},
+       {token.IMAG, ".0i", literal},
+       {token.IMAG, "3.14159265i", literal},
+       {token.IMAG, "1e0i", literal},
+       {token.IMAG, "1e+100i", literal},
+       {token.IMAG, "1e-100i", literal},
+       {token.IMAG, "2.71828e-1000i", literal},
+       {token.CHAR, "'a'", literal},
+       {token.CHAR, "'\\000'", literal},
+       {token.CHAR, "'\\xFF'", literal},
+       {token.CHAR, "'\\uff16'", literal},
+       {token.CHAR, "'\\U0000ff16'", literal},
+       {token.STRING, "`foobar`", literal},
+       {token.STRING, "`" + `foo
+                               bar` +
+               "`",
+               literal,
+       },
+
+       // Operators and delimitors
+       {token.ADD, "+", operator},
+       {token.SUB, "-", operator},
+       {token.MUL, "*", operator},
+       {token.QUO, "/", operator},
+       {token.REM, "%", operator},
+
+       {token.AND, "&", operator},
+       {token.OR, "|", operator},
+       {token.XOR, "^", operator},
+       {token.SHL, "<<", operator},
+       {token.SHR, ">>", operator},
+       {token.AND_NOT, "&^", operator},
+
+       {token.ADD_ASSIGN, "+=", operator},
+       {token.SUB_ASSIGN, "-=", operator},
+       {token.MUL_ASSIGN, "*=", operator},
+       {token.QUO_ASSIGN, "/=", operator},
+       {token.REM_ASSIGN, "%=", operator},
+
+       {token.AND_ASSIGN, "&=", operator},
+       {token.OR_ASSIGN, "|=", operator},
+       {token.XOR_ASSIGN, "^=", operator},
+       {token.SHL_ASSIGN, "<<=", operator},
+       {token.SHR_ASSIGN, ">>=", operator},
+       {token.AND_NOT_ASSIGN, "&^=", operator},
+
+       {token.LAND, "&&", operator},
+       {token.LOR, "||", operator},
+       {token.ARROW, "<-", operator},
+       {token.INC, "++", operator},
+       {token.DEC, "--", operator},
+
+       {token.EQL, "==", operator},
+       {token.LSS, "<", operator},
+       {token.GTR, ">", operator},
+       {token.ASSIGN, "=", operator},
+       {token.NOT, "!", operator},
+
+       {token.NEQ, "!=", operator},
+       {token.LEQ, "<=", operator},
+       {token.GEQ, ">=", operator},
+       {token.DEFINE, ":=", operator},
+       {token.ELLIPSIS, "...", operator},
+
+       {token.LPAREN, "(", operator},
+       {token.LBRACK, "[", operator},
+       {token.LBRACE, "{", operator},
+       {token.COMMA, ",", operator},
+       {token.PERIOD, ".", operator},
+
+       {token.RPAREN, ")", operator},
+       {token.RBRACK, "]", operator},
+       {token.RBRACE, "}", operator},
+       {token.SEMICOLON, ";", operator},
+       {token.COLON, ":", operator},
+
+       // Keywords
+       {token.BREAK, "break", keyword},
+       {token.CASE, "case", keyword},
+       {token.CHAN, "chan", keyword},
+       {token.CONST, "const", keyword},
+       {token.CONTINUE, "continue", keyword},
+
+       {token.DEFAULT, "default", keyword},
+       {token.DEFER, "defer", keyword},
+       {token.ELSE, "else", keyword},
+       {token.FALLTHROUGH, "fallthrough", keyword},
+       {token.FOR, "for", keyword},
+
+       {token.FUNC, "func", keyword},
+       {token.GO, "go", keyword},
+       {token.GOTO, "goto", keyword},
+       {token.IF, "if", keyword},
+       {token.IMPORT, "import", keyword},
+
+       {token.INTERFACE, "interface", keyword},
+       {token.MAP, "map", keyword},
+       {token.PACKAGE, "package", keyword},
+       {token.RANGE, "range", keyword},
+       {token.RETURN, "return", keyword},
+
+       {token.SELECT, "select", keyword},
+       {token.STRUCT, "struct", keyword},
+       {token.SWITCH, "switch", keyword},
+       {token.TYPE, "type", keyword},
+       {token.VAR, "var", keyword},
+}
+
+
+const whitespace = "  \t  \n\n\n" // to separate tokens
+
+type testErrorHandler struct {
+       t *testing.T
+}
+
+func (h *testErrorHandler) Error(pos token.Position, msg string) {
+       h.t.Errorf("Error() called (msg = %s)", msg)
+}
+
+
+func newlineCount(s string) int {
+       n := 0
+       for i := 0; i < len(s); i++ {
+               if s[i] == '\n' {
+                       n++
+               }
+       }
+       return n
+}
+
+
+func checkPos(t *testing.T, lit string, pos, expected token.Position) {
+       if pos.Filename != expected.Filename {
+               t.Errorf("bad filename for %q: got %s, expected %s", lit, pos.Filename, expected.Filename)
+       }
+       if pos.Offset != expected.Offset {
+               t.Errorf("bad position for %q: got %d, expected %d", lit, pos.Offset, expected.Offset)
+       }
+       if pos.Line != expected.Line {
+               t.Errorf("bad line for %q: got %d, expected %d", lit, pos.Line, expected.Line)
+       }
+       if pos.Column != expected.Column {
+               t.Errorf("bad column for %q: got %d, expected %d", lit, pos.Column, expected.Column)
+       }
+}
+
+
+// Verify that calling Scan() provides the correct results.
+func TestScan(t *testing.T) {
+       // make source
+       var src string
+       for _, e := range tokens {
+               src += e.lit + whitespace
+       }
+       src_linecount := newlineCount(src)
+       whitespace_linecount := newlineCount(whitespace)
+
+       // verify scan
+       index := 0
+       epos := token.Position{"", 0, 1, 1} // expected position
+       nerrors := Tokenize("", []byte(src), &testErrorHandler{t}, ScanComments,
+               func(pos token.Position, tok token.Token, litb []byte) bool {
+                       e := elt{token.EOF, "", special}
+                       if index < len(tokens) {
+                               e = tokens[index]
+                       }
+                       lit := string(litb)
+                       if tok == token.EOF {
+                               lit = "<EOF>"
+                               epos.Line = src_linecount
+                               epos.Column = 1
+                       }
+                       checkPos(t, lit, pos, epos)
+                       if tok != e.tok {
+                               t.Errorf("bad token for %q: got %s, expected %s", lit, tok.String(), e.tok.String())
+                       }
+                       if e.tok.IsLiteral() && lit != e.lit {
+                               t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, e.lit)
+                       }
+                       if tokenclass(tok) != e.class {
+                               t.Errorf("bad class for %q: got %d, expected %d", lit, tokenclass(tok), e.class)
+                       }
+                       epos.Offset += len(lit) + len(whitespace)
+                       epos.Line += newlineCount(lit) + whitespace_linecount
+                       if tok == token.COMMENT && litb[1] == '/' {
+                               // correct for unaccounted '/n' in //-style comment
+                               epos.Offset++
+                               epos.Line++
+                       }
+                       index++
+                       return tok != token.EOF
+               })
+       if nerrors != 0 {
+               t.Errorf("found %d errors", nerrors)
+       }
+}
+
+
+func checkSemi(t *testing.T, line string, mode uint) {
+       var S Scanner
+       S.Init("TestSemis", []byte(line), nil, mode)
+       pos, tok, lit := S.Scan()
+       for tok != token.EOF {
+               if tok == token.ILLEGAL {
+                       // the illegal token literal indicates what
+                       // kind of semicolon literal to expect
+                       semiLit := "\n"
+                       if lit[0] == '#' {
+                               semiLit = ";"
+                       }
+                       // next token must be a semicolon
+                       semiPos := pos
+                       semiPos.Offset++
+                       semiPos.Column++
+                       pos, tok, lit = S.Scan()
+                       if tok == token.SEMICOLON {
+                               if string(lit) != semiLit {
+                                       t.Errorf(`bad literal for %q: got %q, expected %q`, line, lit, semiLit)
+                               }
+                               checkPos(t, line, pos, semiPos)
+                       } else {
+                               t.Errorf("bad token for %q: got %s, expected ;", line, tok.String())
+                       }
+               } else if tok == token.SEMICOLON {
+                       t.Errorf("bad token for %q: got ;, expected no ;", line)
+               }
+               pos, tok, lit = S.Scan()
+       }
+}
+
+
+var lines = []string{
+       // # indicates a semicolon present in the source
+       // $ indicates an automatically inserted semicolon
+       "",
+       "#;",
+       "foo$\n",
+       "123$\n",
+       "1.2$\n",
+       "'x'$\n",
+       `"x"` + "$\n",
+       "`x`$\n",
+
+       "+\n",
+       "-\n",
+       "*\n",
+       "/\n",
+       "%\n",
+
+       "&\n",
+       "|\n",
+       "^\n",
+       "<<\n",
+       ">>\n",
+       "&^\n",
+
+       "+=\n",
+       "-=\n",
+       "*=\n",
+       "/=\n",
+       "%=\n",
+
+       "&=\n",
+       "|=\n",
+       "^=\n",
+       "<<=\n",
+       ">>=\n",
+       "&^=\n",
+
+       "&&\n",
+       "||\n",
+       "<-\n",
+       "++$\n",
+       "--$\n",
+
+       "==\n",
+       "<\n",
+       ">\n",
+       "=\n",
+       "!\n",
+
+       "!=\n",
+       "<=\n",
+       ">=\n",
+       ":=\n",
+       "...\n",
+
+       "(\n",
+       "[\n",
+       "{\n",
+       ",\n",
+       ".\n",
+
+       ")$\n",
+       "]$\n",
+       "}$\n",
+       "#;\n",
+       ":\n",
+
+       "break$\n",
+       "case\n",
+       "chan\n",
+       "const\n",
+       "continue$\n",
+
+       "default\n",
+       "defer\n",
+       "else\n",
+       "fallthrough$\n",
+       "for\n",
+
+       "func\n",
+       "go\n",
+       "goto\n",
+       "if\n",
+       "import\n",
+
+       "interface\n",
+       "map\n",
+       "package\n",
+       "range\n",
+       "return$\n",
+
+       "select\n",
+       "struct\n",
+       "switch\n",
+       "type\n",
+       "var\n",
+
+       "foo$//comment\n",
+       "foo$//comment",
+       "foo$/*comment*/\n",
+       "foo$/*\n*/",
+       "foo$/*comment*/    \n",
+       "foo$/*\n*/    ",
+
+       "foo    $// comment\n",
+       "foo    $// comment",
+       "foo    $/*comment*/\n",
+       "foo    $/*\n*/",
+       "foo    $/*  */ /* \n */ bar$/**/\n",
+       "foo    $/*0*/ /*1*/ /*2*/\n",
+
+       "foo    $/*comment*/    \n",
+       "foo    $/*0*/ /*1*/ /*2*/    \n",
+       "foo    $/**/ /*-------------*/       /*----\n*/bar       $/*  \n*/baa$\n",
+       "foo    $/* an EOF terminates a line */",
+       "foo    $/* an EOF terminates a line */ /*",
+       "foo    $/* an EOF terminates a line */ //",
+
+       "package main$\n\nfunc main() {\n\tif {\n\t\treturn /* */ }$\n}$\n",
+       "package main$",
+}
+
+
+func TestSemis(t *testing.T) {
+       for _, line := range lines {
+               checkSemi(t, line, AllowIllegalChars|InsertSemis)
+               checkSemi(t, line, AllowIllegalChars|InsertSemis|ScanComments)
+
+               // if the input ended in newlines, the input must tokenize the
+               // same with or without those newlines
+               for i := len(line) - 1; i >= 0 && line[i] == '\n'; i-- {
+                       checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis)
+                       checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis|ScanComments)
+               }
+       }
+}
+
+
+var segments = []struct {
+       srcline  string // a line of source text
+       filename string // filename for current token
+       line     int    // line number for current token
+}{
+       // exactly one token per line since the test consumes one token per segment
+       {"  line1", "TestLineComments", 1},
+       {"\nline2", "TestLineComments", 2},
+       {"\nline3  //line File1.go:100", "TestLineComments", 3}, // bad line comment, ignored
+       {"\nline4", "TestLineComments", 4},
+       {"\n//line File1.go:100\n  line100", "File1.go", 100},
+       {"\n//line File2.go:200\n  line200", "File2.go", 200},
+       {"\n//line :1\n  line1", "", 1},
+       {"\n//line foo:42\n  line42", "foo", 42},
+       {"\n //line foo:42\n  line44", "foo", 44},           // bad line comment, ignored
+       {"\n//line foo 42\n  line46", "foo", 46},            // bad line comment, ignored
+       {"\n//line foo:42 extra text\n  line48", "foo", 48}, // bad line comment, ignored
+       {"\n//line foo:42\n  line42", "foo", 42},
+       {"\n//line foo:42\n  line42", "foo", 42},
+       {"\n//line File1.go:100\n  line100", "File1.go", 100},
+}
+
+
+// Verify that comments of the form "//line filename:line" are interpreted correctly.
+func TestLineComments(t *testing.T) {
+       // make source
+       var src string
+       for _, e := range segments {
+               src += e.srcline
+       }
+
+       // verify scan
+       var S Scanner
+       S.Init("TestLineComments", []byte(src), nil, 0)
+       for _, s := range segments {
+               pos, _, lit := S.Scan()
+               checkPos(t, string(lit), pos, token.Position{s.filename, pos.Offset, s.line, pos.Column})
+       }
+
+       if S.ErrorCount != 0 {
+               t.Errorf("found %d errors", S.ErrorCount)
+       }
+}
+
+
+// Verify that initializing the same scanner more then once works correctly.
+func TestInit(t *testing.T) {
+       var s Scanner
+
+       // 1st init
+       s.Init("", []byte("if true { }"), nil, 0)
+       s.Scan()              // if
+       s.Scan()              // true
+       _, tok, _ := s.Scan() // {
+       if tok != token.LBRACE {
+               t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE)
+       }
+
+       // 2nd init
+       s.Init("", []byte("go true { ]"), nil, 0)
+       _, tok, _ = s.Scan() // go
+       if tok != token.GO {
+               t.Errorf("bad token: got %s, expected %s", tok.String(), token.GO)
+       }
+
+       if s.ErrorCount != 0 {
+               t.Errorf("found %d errors", s.ErrorCount)
+       }
+}
+
+
+func TestIllegalChars(t *testing.T) {
+       var s Scanner
+
+       const src = "*?*$*@*"
+       s.Init("", []byte(src), &testErrorHandler{t}, AllowIllegalChars)
+       for offs, ch := range src {
+               pos, tok, lit := s.Scan()
+               if pos.Offset != offs {
+                       t.Errorf("bad position for %s: got %d, expected %d", string(lit), pos.Offset, offs)
+               }
+               if tok == token.ILLEGAL && string(lit) != string(ch) {
+                       t.Errorf("bad token: got %s, expected %s", string(lit), string(ch))
+               }
+       }
+
+       if s.ErrorCount != 0 {
+               t.Errorf("found %d errors", s.ErrorCount)
+       }
+}
+
+
+func TestStdErrorHander(t *testing.T) {
+       const src = "@\n" + // illegal character, cause an error
+               "@ @\n" + // two errors on the same line
+               "//line File2:20\n" +
+               "@\n" + // different file, but same line
+               "//line File2:1\n" +
+               "@ @\n" + // same file, decreasing line number
+               "//line File1:1\n" +
+               "@ @ @" // original file, line 1 again
+
+       v := new(ErrorVector)
+       nerrors := Tokenize("File1", []byte(src), v, 0,
+               func(pos token.Position, tok token.Token, litb []byte) bool {
+                       return tok != token.EOF
+               })
+
+       list := v.GetErrorList(Raw)
+       if len(list) != 9 {
+               t.Errorf("found %d raw errors, expected 9", len(list))
+               PrintError(os.Stderr, list)
+       }
+
+       list = v.GetErrorList(Sorted)
+       if len(list) != 9 {
+               t.Errorf("found %d sorted errors, expected 9", len(list))
+               PrintError(os.Stderr, list)
+       }
+
+       list = v.GetErrorList(NoMultiples)
+       if len(list) != 4 {
+               t.Errorf("found %d one-per-line errors, expected 4", len(list))
+               PrintError(os.Stderr, list)
+       }
+
+       if v.ErrorCount() != nerrors {
+               t.Errorf("found %d errors, expected %d", v.ErrorCount(), nerrors)
+       }
+}
+
+
+type errorCollector struct {
+       cnt int            // number of errors encountered
+       msg string         // last error message encountered
+       pos token.Position // last error position encountered
+}
+
+
+func (h *errorCollector) Error(pos token.Position, msg string) {
+       h.cnt++
+       h.msg = msg
+       h.pos = pos
+}
+
+
+func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
+       var s Scanner
+       var h errorCollector
+       s.Init("", []byte(src), &h, ScanComments)
+       _, tok0, _ := s.Scan()
+       _, tok1, _ := s.Scan()
+       if tok0 != tok {
+               t.Errorf("%q: got %s, expected %s", src, tok0, tok)
+       }
+       if tok1 != token.EOF {
+               t.Errorf("%q: got %s, expected EOF", src, tok1)
+       }
+       cnt := 0
+       if err != "" {
+               cnt = 1
+       }
+       if h.cnt != cnt {
+               t.Errorf("%q: got cnt %d, expected %d", src, h.cnt, cnt)
+       }
+       if h.msg != err {
+               t.Errorf("%q: got msg %q, expected %q", src, h.msg, err)
+       }
+       if h.pos.Offset != pos {
+               t.Errorf("%q: got offset %d, expected %d", src, h.pos.Offset, pos)
+       }
+}
+
+
+var errors = []struct {
+       src string
+       tok token.Token
+       pos int
+       err string
+}{
+       {`#`, token.ILLEGAL, 0, "illegal character '#' (U+23)"},
+       {`' '`, token.CHAR, 0, ""},
+       {`''`, token.CHAR, 0, "illegal character literal"},
+       {`'\8'`, token.CHAR, 2, "unknown escape sequence"},
+       {`'\08'`, token.CHAR, 3, "illegal character in escape sequence"},
+       {`'\x0g'`, token.CHAR, 4, "illegal character in escape sequence"},
+       {`'\Uffffffff'`, token.CHAR, 2, "escape sequence is invalid Unicode code point"},
+       {`'`, token.CHAR, 0, "character literal not terminated"},
+       {`""`, token.STRING, 0, ""},
+       {`"`, token.STRING, 0, "string not terminated"},
+       {"``", token.STRING, 0, ""},
+       {"`", token.STRING, 0, "string not terminated"},
+       {"/**/", token.COMMENT, 0, ""},
+       {"/*", token.COMMENT, 0, "comment not terminated"},
+       {"077", token.INT, 0, ""},
+       {"078.", token.FLOAT, 0, ""},
+       {"07801234567.", token.FLOAT, 0, ""},
+       {"078e0", token.FLOAT, 0, ""},
+       {"078", token.INT, 0, "illegal octal number"},
+       {"07800000009", token.INT, 0, "illegal octal number"},
+       {"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
+       {"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
+}
+
+
+func TestScanErrors(t *testing.T) {
+       for _, e := range errors {
+               checkError(t, e.src, e.tok, e.pos, e.err)
+       }
+}
diff --git a/libgo/go/go/token/token.go b/libgo/go/go/token/token.go
new file mode 100644 (file)
index 0000000..bc6c6a8
--- /dev/null
@@ -0,0 +1,359 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package defines constants representing the lexical
+// tokens of the Go programming language and basic operations
+// on tokens (printing, predicates).
+//
+package token
+
+import (
+       "fmt"
+       "strconv"
+)
+
+
+// Token is the set of lexical tokens of the Go programming language.
+type Token int
+
+// The list of tokens.
+const (
+       // Special tokens
+       ILLEGAL Token = iota
+       EOF
+       COMMENT
+
+       literal_beg
+       // Identifiers and basic type literals
+       // (these tokens stand for classes of literals)
+       IDENT  // main
+       INT    // 12345
+       FLOAT  // 123.45
+       IMAG   // 123.45i
+       CHAR   // 'a'
+       STRING // "abc"
+       literal_end
+
+       operator_beg
+       // Operators and delimiters
+       ADD // +
+       SUB // -
+       MUL // *
+       QUO // /
+       REM // %
+
+       AND     // &
+       OR      // |
+       XOR     // ^
+       SHL     // <<
+       SHR     // >>
+       AND_NOT // &^
+
+       ADD_ASSIGN // +=
+       SUB_ASSIGN // -=
+       MUL_ASSIGN // *=
+       QUO_ASSIGN // /=
+       REM_ASSIGN // %=
+
+       AND_ASSIGN     // &=
+       OR_ASSIGN      // |=
+       XOR_ASSIGN     // ^=
+       SHL_ASSIGN     // <<=
+       SHR_ASSIGN     // >>=
+       AND_NOT_ASSIGN // &^=
+
+       LAND  // &&
+       LOR   // ||
+       ARROW // <-
+       INC   // ++
+       DEC   // --
+
+       EQL    // ==
+       LSS    // <
+       GTR    // >
+       ASSIGN // =
+       NOT    // !
+
+       NEQ      // !=
+       LEQ      // <=
+       GEQ      // >=
+       DEFINE   // :=
+       ELLIPSIS // ...
+
+       LPAREN // (
+       LBRACK // [
+       LBRACE // {
+       COMMA  // ,
+       PERIOD // .
+
+       RPAREN    // )
+       RBRACK    // ]
+       RBRACE    // }
+       SEMICOLON // ;
+       COLON     // :
+       operator_end
+
+       keyword_beg
+       // Keywords
+       BREAK
+       CASE
+       CHAN
+       CONST
+       CONTINUE
+
+       DEFAULT
+       DEFER
+       ELSE
+       FALLTHROUGH
+       FOR
+
+       FUNC
+       GO
+       GOTO
+       IF
+       IMPORT
+
+       INTERFACE
+       MAP
+       PACKAGE
+       RANGE
+       RETURN
+
+       SELECT
+       STRUCT
+       SWITCH
+       TYPE
+       VAR
+       keyword_end
+)
+
+
+// At the moment we have no array literal syntax that lets us describe
+// the index for each element - use a map for now to make sure they are
+// in sync.
+var tokens = map[Token]string{
+       ILLEGAL: "ILLEGAL",
+
+       EOF:     "EOF",
+       COMMENT: "COMMENT",
+
+       IDENT:  "IDENT",
+       INT:    "INT",
+       FLOAT:  "FLOAT",
+       IMAG:   "IMAG",
+       CHAR:   "CHAR",
+       STRING: "STRING",
+
+       ADD: "+",
+       SUB: "-",
+       MUL: "*",
+       QUO: "/",
+       REM: "%",
+
+       AND:     "&",
+       OR:      "|",
+       XOR:     "^",
+       SHL:     "<<",
+       SHR:     ">>",
+       AND_NOT: "&^",
+
+       ADD_ASSIGN: "+=",
+       SUB_ASSIGN: "-=",
+       MUL_ASSIGN: "*=",
+       QUO_ASSIGN: "/=",
+       REM_ASSIGN: "%=",
+
+       AND_ASSIGN:     "&=",
+       OR_ASSIGN:      "|=",
+       XOR_ASSIGN:     "^=",
+       SHL_ASSIGN:     "<<=",
+       SHR_ASSIGN:     ">>=",
+       AND_NOT_ASSIGN: "&^=",
+
+       LAND:  "&&",
+       LOR:   "||",
+       ARROW: "<-",
+       INC:   "++",
+       DEC:   "--",
+
+       EQL:    "==",
+       LSS:    "<",
+       GTR:    ">",
+       ASSIGN: "=",
+       NOT:    "!",
+
+       NEQ:      "!=",
+       LEQ:      "<=",
+       GEQ:      ">=",
+       DEFINE:   ":=",
+       ELLIPSIS: "...",
+
+       LPAREN: "(",
+       LBRACK: "[",
+       LBRACE: "{",
+       COMMA:  ",",
+       PERIOD: ".",
+
+       RPAREN:    ")",
+       RBRACK:    "]",
+       RBRACE:    "}",
+       SEMICOLON: ";",
+       COLON:     ":",
+
+       BREAK:    "break",
+       CASE:     "case",
+       CHAN:     "chan",
+       CONST:    "const",
+       CONTINUE: "continue",
+
+       DEFAULT:     "default",
+       DEFER:       "defer",
+       ELSE:        "else",
+       FALLTHROUGH: "fallthrough",
+       FOR:         "for",
+
+       FUNC:   "func",
+       GO:     "go",
+       GOTO:   "goto",
+       IF:     "if",
+       IMPORT: "import",
+
+       INTERFACE: "interface",
+       MAP:       "map",
+       PACKAGE:   "package",
+       RANGE:     "range",
+       RETURN:    "return",
+
+       SELECT: "select",
+       STRUCT: "struct",
+       SWITCH: "switch",
+       TYPE:   "type",
+       VAR:    "var",
+}
+
+
+// String returns the string corresponding to the token tok.
+// For operators, delimiters, and keywords the string is the actual
+// token character sequence (e.g., for the token ADD, the string is
+// "+"). For all other tokens the string corresponds to the token
+// constant name (e.g. for the token IDENT, the string is "IDENT").
+//
+func (tok Token) String() string {
+       if str, exists := tokens[tok]; exists {
+               return str
+       }
+       return "token(" + strconv.Itoa(int(tok)) + ")"
+}
+
+
+// A set of constants for precedence-based expression parsing.
+// Non-operators have lowest precedence, followed by operators
+// starting with precedence 1 up to unary operators. The highest
+// precedence corresponds serves as "catch-all" precedence for
+// selector, indexing, and other operator and delimiter tokens.
+//
+const (
+       LowestPrec  = 0 // non-operators
+       UnaryPrec   = 7
+       HighestPrec = 8
+)
+
+
+// Precedence returns the operator precedence of the binary
+// operator op. If op is not a binary operator, the result
+// is LowestPrecedence.
+//
+func (op Token) Precedence() int {
+       switch op {
+       case LOR:
+               return 1
+       case LAND:
+               return 2
+       case ARROW:
+               return 3
+       case EQL, NEQ, LSS, LEQ, GTR, GEQ:
+               return 4
+       case ADD, SUB, OR, XOR:
+               return 5
+       case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
+               return 6
+       }
+       return LowestPrec
+}
+
+
+var keywords map[string]Token
+
+func init() {
+       keywords = make(map[string]Token)
+       for i := keyword_beg + 1; i < keyword_end; i++ {
+               keywords[tokens[i]] = i
+       }
+}
+
+
+// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
+//
+func Lookup(ident []byte) Token {
+       // TODO Maps with []byte key are illegal because []byte does not
+       //      support == . Should find a more efficient solution eventually.
+       if tok, is_keyword := keywords[string(ident)]; is_keyword {
+               return tok
+       }
+       return IDENT
+}
+
+
+// Predicates
+
+// IsLiteral returns true for tokens corresponding to identifiers
+// and basic type literals; returns false otherwise.
+//
+func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end }
+
+// IsOperator returns true for tokens corresponding to operators and
+// delimiters; returns false otherwise.
+//
+func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end }
+
+// IsKeyword returns true for tokens corresponding to keywords;
+// returns false otherwise.
+//
+func (tok Token) IsKeyword() bool { return keyword_beg < tok && tok < keyword_end }
+
+
+// Token source positions are represented by a Position value.
+// A Position is valid if the line number is > 0.
+//
+type Position struct {
+       Filename string // filename, if any
+       Offset   int    // byte offset, starting at 0
+       Line     int    // line number, starting at 1
+       Column   int    // column number, starting at 1 (character count)
+}
+
+
+// Pos is an accessor method for anonymous Position fields.
+// It returns its receiver.
+//
+func (pos *Position) Pos() Position { return *pos }
+
+
+// IsValid returns true if the position is valid.
+func (pos *Position) IsValid() bool { return pos.Line > 0 }
+
+
+func (pos Position) String() string {
+       s := pos.Filename
+       if pos.IsValid() {
+               if s != "" {
+                       s += ":"
+               }
+               s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
+       }
+       if s == "" {
+               s = "-"
+       }
+       return s
+}
diff --git a/libgo/go/go/typechecker/scope.go b/libgo/go/go/typechecker/scope.go
new file mode 100644 (file)
index 0000000..c2ec759
--- /dev/null
@@ -0,0 +1,119 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements scope support functions.
+
+package typechecker
+
+import (
+       "fmt"
+       "go/ast"
+       "go/token"
+)
+
+
+func (tc *typechecker) openScope() *ast.Scope {
+       tc.topScope = ast.NewScope(tc.topScope)
+       return tc.topScope
+}
+
+
+func (tc *typechecker) closeScope() {
+       tc.topScope = tc.topScope.Outer
+}
+
+
+// objPos computes the source position of the declaration of an object name.
+// Only required for error reporting, so doesn't have to be fast.
+func objPos(obj *ast.Object) (pos token.Position) {
+       switch d := obj.Decl.(type) {
+       case *ast.Field:
+               for _, n := range d.Names {
+                       if n.Name == obj.Name {
+                               return n.Pos()
+                       }
+               }
+       case *ast.ValueSpec:
+               for _, n := range d.Names {
+                       if n.Name == obj.Name {
+                               return n.Pos()
+                       }
+               }
+       case *ast.TypeSpec:
+               return d.Name.Pos()
+       case *ast.FuncDecl:
+               return d.Name.Pos()
+       }
+       if debug {
+               fmt.Printf("decl = %T\n", obj.Decl)
+       }
+       panic("unreachable")
+}
+
+
+// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
+// It returns the newly allocated object. If an object with the same name already exists in scope, an error
+// is reported and the object is not inserted.
+// (Objects with _ name are always inserted into a scope without errors, but they cannot be found.)
+func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+       obj := ast.NewObj(kind, name.Name)
+       obj.Decl = decl
+       obj.N = n
+       name.Obj = obj
+       if alt := scope.Insert(obj); alt != obj {
+               tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, objPos(alt))
+       }
+       return obj
+}
+
+
+// decl is the same as declInScope(tc.topScope, ...)
+func (tc *typechecker) decl(kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+       return tc.declInScope(tc.topScope, kind, name, decl, n)
+}
+
+
+// find returns the object with the given name if visible in the current scope hierarchy.
+// If no such object is found, an error is reported and a bad object is returned instead.
+func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
+       for s := tc.topScope; s != nil && obj == nil; s = s.Outer {
+               obj = s.Lookup(name.Name)
+       }
+       if obj == nil {
+               tc.Errorf(name.Pos(), "%s not declared", name.Name)
+               obj = ast.NewObj(ast.Bad, name.Name)
+       }
+       name.Obj = obj
+       return
+}
+
+
+// findField returns the object with the given name if visible in the type's scope.
+// If no such object is found, an error is reported and a bad object is returned instead.
+func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Object) {
+       // TODO(gri) This is simplistic at the moment and ignores anonymous fields.
+       obj = typ.Scope.Lookup(name.Name)
+       if obj == nil {
+               tc.Errorf(name.Pos(), "%s not declared", name.Name)
+               obj = ast.NewObj(ast.Bad, name.Name)
+       }
+       return
+}
+
+
+// printScope prints the objects in a scope.
+func printScope(scope *ast.Scope) {
+       fmt.Printf("scope %p {", scope)
+       if scope != nil && len(scope.Objects) > 0 {
+               fmt.Println()
+               for _, obj := range scope.Objects {
+                       form := "void"
+                       if obj.Type != nil {
+                               form = obj.Type.Form.String()
+                       }
+                       fmt.Printf("\t%s\t%s\n", obj.Name, form)
+               }
+       }
+       fmt.Printf("}\n")
+}
diff --git a/libgo/go/go/typechecker/testdata/test0.go b/libgo/go/go/typechecker/testdata/test0.go
new file mode 100644 (file)
index 0000000..4e317f2
--- /dev/null
@@ -0,0 +1,94 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// type declarations
+
+package P0
+
+type (
+       B bool
+       I int32
+       A [10]P
+       T struct {
+               x, y P
+       }
+       P *T
+       R *R
+       F func(A) I
+       Y interface {
+               f(A) I
+       }
+       S []P
+       M map[I]F
+       C chan<- I
+)
+
+type (
+       a/* ERROR "illegal cycle" */ a
+       a/* ERROR "already declared" */ int
+
+       b/* ERROR "illegal cycle" */ c
+       c d
+       d e
+       e b /* ERROR "not a type" */
+
+       t *t
+
+       U V
+       V W
+       W *U
+
+       P1 *S2
+       P2 P1
+
+       S1 struct {
+               a, b, c int
+               u, v, a/* ERROR "already declared" */ float
+       }
+       S2/* ERROR "illegal cycle" */ struct {
+               x S2
+       }
+
+       L1 []L1
+       L2 []int
+
+       A1 [10]int
+       A2/* ERROR "illegal cycle" */ [10]A2
+       A3/* ERROR "illegal cycle" */ [10]struct {
+               x A4
+       }
+       A4 [10]A3
+
+       F1 func()
+       F2 func(x, y, z float)
+       F3 func(x, y, x /* ERROR "already declared" */ float)
+       F4 func() (x, y, x /* ERROR "already declared" */ float)
+       F5 func(x int) (x /* ERROR "already declared" */ float)
+
+       I1 interface{}
+       I2 interface {
+               m1()
+       }
+       I3 interface {
+               m1()
+               m1 /* ERROR "already declared" */ ()
+       }
+       I4 interface {
+               m1(x, y, x /* ERROR "already declared" */ float)
+               m2() (x, y, x /* ERROR "already declared" */ float)
+               m3(x int) (x /* ERROR "already declared" */ float)
+       }
+       I5 interface {
+               m1(I5)
+       }
+
+       C1 chan int
+       C2 <-chan int
+       C3 chan<- C3
+
+       M1 map[Last]string
+       M2 map[string]M2
+
+       Last int
+)
diff --git a/libgo/go/go/typechecker/testdata/test1.go b/libgo/go/go/typechecker/testdata/test1.go
new file mode 100644 (file)
index 0000000..b0808ee
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// const and var declarations
+
+package P1
+
+const (
+       c1         /* ERROR "missing initializer" */
+       c2     int = 0
+       c3, c4 = 0
+)
diff --git a/libgo/go/go/typechecker/testdata/test3.go b/libgo/go/go/typechecker/testdata/test3.go
new file mode 100644 (file)
index 0000000..ea35808
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package P3
+
+// function and method signatures
+
+func _()                                        {}
+func _()                                        {}
+func _(x, x /* ERROR "already declared" */ int) {}
+
+func f()                                 {}
+func f /* ERROR "already declared" */ () {}
+
+func (*foo /* ERROR "invalid receiver" */ ) m() {}
+func (bar /* ERROR "not a type" */ ) m()        {}
+
+func f1(x, _, _ int) (_, _ float)                              {}
+func f2(x, y, x /* ERROR "already declared" */ int)            {}
+func f3(x, y int) (a, b, x /* ERROR "already declared" */ int) {}
+
+func (x *T) m1()                                 {}
+func (x *T) m1 /* ERROR "already declared" */ () {}
+func (x T) m1 /* ERROR "already declared" */ ()  {}
+func (T) m1 /* ERROR "already declared" */ ()    {}
+
+func (x *T) m2(u, x /* ERROR "already declared" */ int)               {}
+func (x *T) m3(a, b, c int) (u, x /* ERROR "already declared" */ int) {}
+func (T) _(x, x /* ERROR "already declared" */ int)                   {}
+func (T) _() (x, x /* ERROR "already declared" */ int)                {}
+
+//func (PT) _() {}
+
+var bar int
+
+type T struct{}
+type PT (T)
diff --git a/libgo/go/go/typechecker/testdata/test4.go b/libgo/go/go/typechecker/testdata/test4.go
new file mode 100644 (file)
index 0000000..bb9aee3
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Constant declarations
+
+package P4
+
+const (
+       c0 /* ERROR "missing initializer" */
+)
diff --git a/libgo/go/go/typechecker/typechecker.go b/libgo/go/go/typechecker/typechecker.go
new file mode 100644 (file)
index 0000000..81f6bb4
--- /dev/null
@@ -0,0 +1,481 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements typechecking of a Go AST.
+// The result of the typecheck is an augmented AST
+// with object and type information for each identifier.
+//
+package typechecker
+
+import (
+       "fmt"
+       "go/ast"
+       "go/token"
+       "go/scanner"
+       "os"
+)
+
+
+// TODO(gri) don't report errors for objects/types that are marked as bad.
+
+
+const debug = true // set for debugging output
+
+
+// An importer takes an import path and returns the data describing the
+// respective package's exported interface. The data format is TBD.
+//
+type Importer func(path string) ([]byte, os.Error)
+
+
+// CheckPackage typechecks a package and augments the AST by setting
+// *ast.Object, *ast.Type, and *ast.Scope fields accordingly. If an
+// importer is provided, it is used to handle imports, otherwise they
+// are ignored (likely leading to typechecking errors).
+//
+// If errors are reported, the AST may be incompletely augmented (fields
+// may be nil) or contain incomplete object, type, or scope information.
+//
+func CheckPackage(pkg *ast.Package, importer Importer) os.Error {
+       var tc typechecker
+       tc.importer = importer
+       tc.checkPackage(pkg)
+       return tc.GetError(scanner.Sorted)
+}
+
+
+// CheckFile typechecks a single file, but otherwise behaves like
+// CheckPackage. If the complete package consists of more than just
+// one file, the file may not typecheck without errors.
+//
+func CheckFile(file *ast.File, importer Importer) os.Error {
+       // create a single-file dummy package
+       pkg := &ast.Package{file.Name.Name, nil, map[string]*ast.File{file.Name.NamePos.Filename: file}}
+       return CheckPackage(pkg, importer)
+}
+
+
+// ----------------------------------------------------------------------------
+// Typechecker state
+
+type typechecker struct {
+       scanner.ErrorVector
+       importer Importer
+       topScope *ast.Scope           // current top-most scope
+       cyclemap map[*ast.Object]bool // for cycle detection
+       iota     int                  // current value of iota
+}
+
+
+func (tc *typechecker) Errorf(pos token.Position, format string, args ...interface{}) {
+       tc.Error(pos, fmt.Sprintf(format, args...))
+}
+
+
+func assert(pred bool) {
+       if !pred {
+               panic("internal error")
+       }
+}
+
+
+/*
+Typechecking is done in several phases:
+
+phase 1: declare all global objects; also collect all function and method declarations
+       - all objects have kind, name, decl fields; the decl field permits
+         quick lookup of an object's declaration
+       - constant objects have an iota value
+       - type objects have unresolved types with empty scopes, all others have nil types
+       - report global double declarations
+
+phase 2: bind methods to their receiver base types
+       - received base types must be declared in the package, thus for
+         each method a corresponding (unresolved) type must exist
+       - report method double declarations and errors with base types
+
+phase 3: resolve all global objects
+       - sequentially iterate through all objects in the global scope
+       - resolve types for all unresolved types and assign types to
+         all attached methods
+       - assign types to all other objects, possibly by evaluating
+         constant and initializer expressions
+       - resolution may recurse; a cyclemap is used to detect cycles
+       - report global typing errors
+
+phase 4: sequentially typecheck function and method bodies
+       - all global objects are declared and have types and values;
+         all methods have types
+       - sequentially process statements in each body; any object
+         referred to must be fully defined at this point
+       - report local typing errors
+*/
+
+func (tc *typechecker) checkPackage(pkg *ast.Package) {
+       // setup package scope
+       tc.topScope = Universe
+       tc.openScope()
+       defer tc.closeScope()
+
+       // TODO(gri) there's no file scope at the moment since we ignore imports
+
+       // phase 1: declare all global objects; also collect all function and method declarations
+       var funcs []*ast.FuncDecl
+       for _, file := range pkg.Files {
+               for _, decl := range file.Decls {
+                       tc.declGlobal(decl)
+                       if f, isFunc := decl.(*ast.FuncDecl); isFunc {
+                               funcs = append(funcs, f)
+                       }
+               }
+       }
+
+       // phase 2: bind methods to their receiver base types
+       for _, m := range funcs {
+               if m.Recv != nil {
+                       tc.bindMethod(m)
+               }
+       }
+
+       // phase 3: resolve all global objects
+       // (note that objects with _ name are also in the scope)
+       tc.cyclemap = make(map[*ast.Object]bool)
+       for _, obj := range tc.topScope.Objects {
+               tc.resolve(obj)
+       }
+       assert(len(tc.cyclemap) == 0)
+
+       // 4: sequentially typecheck function and method bodies
+       for _, f := range funcs {
+               tc.checkBlock(f.Body.List, f.Name.Obj.Type)
+       }
+
+       pkg.Scope = tc.topScope
+}
+
+
+func (tc *typechecker) declGlobal(global ast.Decl) {
+       switch d := global.(type) {
+       case *ast.BadDecl:
+               // ignore
+
+       case *ast.GenDecl:
+               iota := 0
+               var prev *ast.ValueSpec
+               for _, spec := range d.Specs {
+                       switch s := spec.(type) {
+                       case *ast.ImportSpec:
+                               // TODO(gri) imports go into file scope
+                       case *ast.ValueSpec:
+                               switch d.Tok {
+                               case token.CONST:
+                                       if s.Values == nil {
+                                               // create a new spec with type and values from the previous one
+                                               if prev != nil {
+                                                       s = &ast.ValueSpec{s.Doc, s.Names, prev.Type, prev.Values, s.Comment}
+                                               } else {
+                                                       // TODO(gri) this should probably go into the const decl code
+                                                       tc.Errorf(s.Pos(), "missing initializer for const %s", s.Names[0].Name)
+                                               }
+                                       }
+                                       for _, name := range s.Names {
+                                               tc.decl(ast.Con, name, s, iota)
+                                       }
+                               case token.VAR:
+                                       for _, name := range s.Names {
+                                               tc.decl(ast.Var, name, s, 0)
+                                       }
+                               default:
+                                       panic("unreachable")
+                               }
+                               prev = s
+                               iota++
+                       case *ast.TypeSpec:
+                               obj := tc.decl(ast.Typ, s.Name, s, 0)
+                               // give all type objects an unresolved type so
+                               // that we can collect methods in the type scope
+                               typ := ast.NewType(ast.Unresolved)
+                               obj.Type = typ
+                               typ.Obj = obj
+                       default:
+                               panic("unreachable")
+                       }
+               }
+
+       case *ast.FuncDecl:
+               if d.Recv == nil {
+                       tc.decl(ast.Fun, d.Name, d, 0)
+               }
+
+       default:
+               panic("unreachable")
+       }
+}
+
+
+// If x is of the form *T, deref returns T, otherwise it returns x.
+func deref(x ast.Expr) ast.Expr {
+       if p, isPtr := x.(*ast.StarExpr); isPtr {
+               x = p.X
+       }
+       return x
+}
+
+
+func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
+       // a method is declared in the receiver base type's scope
+       var scope *ast.Scope
+       base := deref(method.Recv.List[0].Type)
+       if name, isIdent := base.(*ast.Ident); isIdent {
+               // if base is not an *ast.Ident, we had a syntax
+               // error and the parser reported an error already
+               obj := tc.topScope.Lookup(name.Name)
+               if obj == nil {
+                       tc.Errorf(name.Pos(), "invalid receiver: %s is not declared in this package", name.Name)
+               } else if obj.Kind != ast.Typ {
+                       tc.Errorf(name.Pos(), "invalid receiver: %s is not a type", name.Name)
+               } else {
+                       typ := obj.Type
+                       assert(typ.Form == ast.Unresolved)
+                       scope = typ.Scope
+               }
+       }
+       if scope == nil {
+               // no receiver type found; use a dummy scope
+               // (we still want to type-check the method
+               // body, so make sure there is a name object
+               // and type)
+               // TODO(gri) should we record the scope so
+               // that we don't lose the receiver for type-
+               // checking of the method body?
+               scope = ast.NewScope(nil)
+       }
+       tc.declInScope(scope, ast.Fun, method.Name, method, 0)
+}
+
+
+func (tc *typechecker) resolve(obj *ast.Object) {
+       // check for declaration cycles
+       if tc.cyclemap[obj] {
+               tc.Errorf(objPos(obj), "illegal cycle in declaration of %s", obj.Name)
+               obj.Kind = ast.Bad
+               return
+       }
+       tc.cyclemap[obj] = true
+       defer func() {
+               tc.cyclemap[obj] = false, false
+       }()
+
+       // resolve non-type objects
+       typ := obj.Type
+       if typ == nil {
+               switch obj.Kind {
+               case ast.Bad:
+                       // ignore
+
+               case ast.Con:
+                       tc.declConst(obj)
+
+               case ast.Var:
+                       tc.declVar(obj)
+                       //obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)
+
+               case ast.Fun:
+                       obj.Type = ast.NewType(ast.Function)
+                       t := obj.Decl.(*ast.FuncDecl).Type
+                       tc.declSignature(obj.Type, nil, t.Params, t.Results)
+
+               default:
+                       // type objects have non-nil types when resolve is called
+                       if debug {
+                               fmt.Printf("kind = %s\n", obj.Kind)
+                       }
+                       panic("unreachable")
+               }
+               return
+       }
+
+       // resolve type objects
+       if typ.Form == ast.Unresolved {
+               tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)
+
+               // provide types for all methods
+               for _, obj := range typ.Scope.Objects {
+                       if obj.Kind == ast.Fun {
+                               assert(obj.Type == nil)
+                               obj.Type = ast.NewType(ast.Method)
+                               f := obj.Decl.(*ast.FuncDecl)
+                               t := f.Type
+                               tc.declSignature(obj.Type, f.Recv, t.Params, t.Results)
+                       }
+               }
+       }
+}
+
+
+func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *ast.Type) {
+       tc.openScope()
+       defer tc.closeScope()
+
+       // inject function/method parameters into block scope, if any
+       if ftype != nil {
+               for _, par := range ftype.Params.Objects {
+                       obj := tc.topScope.Insert(par)
+                       assert(obj == par) // ftype has no double declarations
+               }
+       }
+
+       for _, stmt := range body {
+               tc.checkStmt(stmt)
+       }
+}
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+// unparen removes parentheses around x, if any.
+func unparen(x ast.Expr) ast.Expr {
+       if ux, hasParens := x.(*ast.ParenExpr); hasParens {
+               return unparen(ux.X)
+       }
+       return x
+}
+
+
+func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref bool) (n uint) {
+       if fields != nil {
+               for _, f := range fields.List {
+                       typ := tc.typeFor(nil, f.Type, ref)
+                       for _, name := range f.Names {
+                               fld := tc.declInScope(scope, ast.Var, name, f, 0)
+                               fld.Type = typ
+                               n++
+                       }
+               }
+       }
+       return n
+}
+
+
+func (tc *typechecker) declSignature(typ *ast.Type, recv, params, results *ast.FieldList) {
+       assert((typ.Form == ast.Method) == (recv != nil))
+       typ.Params = ast.NewScope(nil)
+       tc.declFields(typ.Params, recv, true)
+       tc.declFields(typ.Params, params, true)
+       typ.N = tc.declFields(typ.Params, results, true)
+}
+
+
+func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Type) {
+       x = unparen(x)
+
+       // type name
+       if t, isIdent := x.(*ast.Ident); isIdent {
+               obj := tc.find(t)
+
+               if obj.Kind != ast.Typ {
+                       tc.Errorf(t.Pos(), "%s is not a type", t.Name)
+                       if def == nil {
+                               typ = ast.NewType(ast.BadType)
+                       } else {
+                               typ = def
+                               typ.Form = ast.BadType
+                       }
+                       typ.Expr = x
+                       return
+               }
+
+               if !ref {
+                       tc.resolve(obj) // check for cycles even if type resolved
+               }
+               typ = obj.Type
+
+               if def != nil {
+                       // new type declaration: copy type structure
+                       def.Form = typ.Form
+                       def.N = typ.N
+                       def.Key, def.Elt = typ.Key, typ.Elt
+                       def.Params = typ.Params
+                       def.Expr = x
+                       typ = def
+               }
+               return
+       }
+
+       // type literal
+       typ = def
+       if typ == nil {
+               typ = ast.NewType(ast.BadType)
+       }
+       typ.Expr = x
+
+       switch t := x.(type) {
+       case *ast.SelectorExpr:
+               if debug {
+                       fmt.Println("qualified identifier unimplemented")
+               }
+               typ.Form = ast.BadType
+
+       case *ast.StarExpr:
+               typ.Form = ast.Pointer
+               typ.Elt = tc.typeFor(nil, t.X, true)
+
+       case *ast.ArrayType:
+               if t.Len != nil {
+                       typ.Form = ast.Array
+                       // TODO(gri) compute the real length
+                       // (this may call resolve recursively)
+                       (*typ).N = 42
+               } else {
+                       typ.Form = ast.Slice
+               }
+               typ.Elt = tc.typeFor(nil, t.Elt, t.Len == nil)
+
+       case *ast.StructType:
+               typ.Form = ast.Struct
+               tc.declFields(typ.Scope, t.Fields, false)
+
+       case *ast.FuncType:
+               typ.Form = ast.Function
+               tc.declSignature(typ, nil, t.Params, t.Results)
+
+       case *ast.InterfaceType:
+               typ.Form = ast.Interface
+               tc.declFields(typ.Scope, t.Methods, true)
+
+       case *ast.MapType:
+               typ.Form = ast.Map
+               typ.Key = tc.typeFor(nil, t.Key, true)
+               typ.Elt = tc.typeFor(nil, t.Value, true)
+
+       case *ast.ChanType:
+               typ.Form = ast.Channel
+               typ.N = uint(t.Dir)
+               typ.Elt = tc.typeFor(nil, t.Value, true)
+
+       default:
+               if debug {
+                       fmt.Printf("x is %T\n", x)
+               }
+               panic("unreachable")
+       }
+
+       return
+}
+
+
+// ----------------------------------------------------------------------------
+// TODO(gri) implement these place holders
+
+func (tc *typechecker) declConst(*ast.Object) {
+}
+
+
+func (tc *typechecker) declVar(*ast.Object) {
+}
+
+
+func (tc *typechecker) checkStmt(ast.Stmt) {
+}
diff --git a/libgo/go/go/typechecker/typechecker_test.go b/libgo/go/go/typechecker/typechecker_test.go
new file mode 100644 (file)
index 0000000..c9bfea0
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements a simple typechecker test harness. Packages found
+// in the testDir directory are typechecked. Error messages reported by
+// the typechecker are compared against the error messages expected for
+// the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+//     package P0
+//     func f() {
+//             _ = x /* ERROR "not declared" */ + 1
+//     }
+// 
+// If the -pkg flag is set, only packages with package names matching
+// the regular expression provided via the flag value are tested.
+
+package typechecker
+
+import (
+       "flag"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/scanner"
+       "go/token"
+       "io/ioutil"
+       "os"
+       "regexp"
+       "sort"
+       "strings"
+       "testing"
+)
+
+
+const testDir = "./testdata" // location of test packages
+
+var (
+       pkgPat = flag.String("pkg", ".*", "regular expression to select test packages by package name")
+       trace  = flag.Bool("trace", false, "print package names")
+)
+
+
+// ERROR comments must be of the form /* ERROR "rx" */ and rx is
+// a regular expression that matches the expected error message.
+var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
+
+// expectedErrors collects the regular expressions of ERROR comments
+// found in the package files of pkg and returns them in sorted order
+// (by filename and position).
+func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
+       // scan all package files
+       for filename := range pkg.Files {
+               src, err := ioutil.ReadFile(filename)
+               if err != nil {
+                       t.Fatalf("expectedErrors(%s): %v", pkg.Name, err)
+               }
+
+               var s scanner.Scanner
+               s.Init(filename, src, nil, scanner.ScanComments)
+               var prev token.Position // position of last non-comment token
+       loop:
+               for {
+                       pos, tok, lit := s.Scan()
+                       switch tok {
+                       case token.EOF:
+                               break loop
+                       case token.COMMENT:
+                               s := errRx.FindSubmatch(lit)
+                               if len(s) == 2 {
+                                       list = append(list, &scanner.Error{prev, string(s[1])})
+                               }
+                       default:
+                               prev = pos
+                       }
+               }
+       }
+       sort.Sort(list) // multiple files may not be sorted
+       return
+}
+
+
+func testFilter(f *os.FileInfo) bool {
+       return strings.HasSuffix(f.Name, ".go") && f.Name[0] != '.'
+}
+
+
+func checkError(t *testing.T, expected, found *scanner.Error) {
+       rx, err := regexp.Compile(expected.Msg)
+       if err != nil {
+               t.Errorf("%s: %v", expected.Pos, err)
+               return
+       }
+
+       match := rx.MatchString(found.Msg)
+
+       if expected.Pos.Offset != found.Pos.Offset {
+               if match {
+                       t.Errorf("%s: expected error should have been at %s", expected.Pos, found.Pos)
+               } else {
+                       t.Errorf("%s: error matching %q expected", expected.Pos, expected.Msg)
+                       return
+               }
+       }
+
+       if !match {
+               t.Errorf("%s: %q does not match %q", expected.Pos, expected.Msg, found.Msg)
+       }
+}
+
+
+func TestTypeCheck(t *testing.T) {
+       flag.Parse()
+       pkgRx, err := regexp.Compile(*pkgPat)
+       if err != nil {
+               t.Fatalf("illegal flag value %q: %s", *pkgPat, err)
+       }
+
+       pkgs, err := parser.ParseDir(testDir, testFilter, 0)
+       if err != nil {
+               scanner.PrintError(os.Stderr, err)
+               t.Fatalf("packages in %s contain syntax errors", testDir)
+       }
+
+       for _, pkg := range pkgs {
+               if !pkgRx.MatchString(pkg.Name) {
+                       continue // only test selected packages
+               }
+
+               if *trace {
+                       fmt.Println(pkg.Name)
+               }
+
+               xlist := expectedErrors(t, pkg)
+               err := CheckPackage(pkg, nil)
+               if err != nil {
+                       if elist, ok := err.(scanner.ErrorList); ok {
+                               // verify that errors match
+                               for i := 0; i < len(xlist) && i < len(elist); i++ {
+                                       checkError(t, xlist[i], elist[i])
+                               }
+                               // the correct number or errors must have been found
+                               if len(xlist) != len(elist) {
+                                       fmt.Fprintf(os.Stderr, "%s\n", pkg.Name)
+                                       scanner.PrintError(os.Stderr, elist)
+                                       fmt.Fprintln(os.Stderr)
+                                       t.Errorf("TypeCheck(%s): %d errors expected but %d reported", pkg.Name, len(xlist), len(elist))
+                               }
+                       } else {
+                               t.Errorf("TypeCheck(%s): %v", pkg.Name, err)
+                       }
+               } else if len(xlist) > 0 {
+                       t.Errorf("TypeCheck(%s): %d errors expected but 0 reported", pkg.Name, len(xlist))
+               }
+       }
+}
diff --git a/libgo/go/go/typechecker/universe.go b/libgo/go/go/typechecker/universe.go
new file mode 100644 (file)
index 0000000..db95073
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typechecker
+
+import "go/ast"
+
+// TODO(gri) should this be in package ast?
+
+// The Universe scope contains all predeclared identifiers.
+var Universe *ast.Scope
+
+
+func def(obj *ast.Object) {
+       alt := Universe.Insert(obj)
+       if alt != obj {
+               panic("object declared twice")
+       }
+}
+
+
+func init() {
+       Universe = ast.NewScope(nil)
+
+       // basic types
+       for n, name := range ast.BasicTypes {
+               typ := ast.NewType(ast.Basic)
+               typ.N = n
+               obj := ast.NewObj(ast.Typ, name)
+               obj.Type = typ
+               typ.Obj = obj
+               def(obj)
+       }
+
+       // built-in functions
+       // TODO(gri) implement this
+}
diff --git a/libgo/go/gob/codec_test.go b/libgo/go/gob/codec_test.go
new file mode 100644 (file)
index 0000000..a95cfa9
--- /dev/null
@@ -0,0 +1,1363 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+       "bytes"
+       "math"
+       "os"
+       "reflect"
+       "strings"
+       "testing"
+       "unsafe"
+)
+
+// Guarantee encoding format by comparing some encodings to hand-written values
+type EncodeT struct {
+       x uint64
+       b []byte
+}
+
+var encodeT = []EncodeT{
+       {0x00, []byte{0x00}},
+       {0x0F, []byte{0x0F}},
+       {0xFF, []byte{0xFF, 0xFF}},
+       {0xFFFF, []byte{0xFE, 0xFF, 0xFF}},
+       {0xFFFFFF, []byte{0xFD, 0xFF, 0xFF, 0xFF}},
+       {0xFFFFFFFF, []byte{0xFC, 0xFF, 0xFF, 0xFF, 0xFF}},
+       {0xFFFFFFFFFF, []byte{0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+       {0xFFFFFFFFFFFF, []byte{0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+       {0xFFFFFFFFFFFFFF, []byte{0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+       {0xFFFFFFFFFFFFFFFF, []byte{0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+       {0x1111, []byte{0xFE, 0x11, 0x11}},
+       {0x1111111111111111, []byte{0xF8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
+       {0x8888888888888888, []byte{0xF8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}},
+       {1 << 63, []byte{0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+}
+
+// testError is meant to be used as a deferred function to turn a panic(gobError) into a
+// plain test.Error call.
+func testError(t *testing.T) {
+       if e := recover(); e != nil {
+               t.Error(e.(gobError).Error) // Will re-panic if not one of our errors, such as a runtime error.
+       }
+       return
+}
+
+// Test basic encode/decode routines for unsigned integers
+func TestUintCodec(t *testing.T) {
+       defer testError(t)
+       b := new(bytes.Buffer)
+       encState := newEncoderState(nil, b)
+       for _, tt := range encodeT {
+               b.Reset()
+               encodeUint(encState, tt.x)
+               if !bytes.Equal(tt.b, b.Bytes()) {
+                       t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
+               }
+       }
+       decState := newDecodeState(nil, &b)
+       for u := uint64(0); ; u = (u + 1) * 7 {
+               b.Reset()
+               encodeUint(encState, u)
+               v := decodeUint(decState)
+               if u != v {
+                       t.Errorf("Encode/Decode: sent %#x received %#x", u, v)
+               }
+               if u&(1<<63) != 0 {
+                       break
+               }
+       }
+}
+
+func verifyInt(i int64, t *testing.T) {
+       defer testError(t)
+       var b = new(bytes.Buffer)
+       encState := newEncoderState(nil, b)
+       encodeInt(encState, i)
+       decState := newDecodeState(nil, &b)
+       decState.buf = make([]byte, 8)
+       j := decodeInt(decState)
+       if i != j {
+               t.Errorf("Encode/Decode: sent %#x received %#x", uint64(i), uint64(j))
+       }
+}
+
+// Test basic encode/decode routines for signed integers
+func TestIntCodec(t *testing.T) {
+       for u := uint64(0); ; u = (u + 1) * 7 {
+               // Do positive and negative values
+               i := int64(u)
+               verifyInt(i, t)
+               verifyInt(-i, t)
+               verifyInt(^i, t)
+               if u&(1<<63) != 0 {
+                       break
+               }
+       }
+       verifyInt(-1<<63, t) // a tricky case
+}
+
+// The result of encoding a true boolean with field number 7
+var boolResult = []byte{0x07, 0x01}
+// The result of encoding a number 17 with field number 7
+var signedResult = []byte{0x07, 2 * 17}
+var unsignedResult = []byte{0x07, 17}
+var floatResult = []byte{0x07, 0xFE, 0x31, 0x40}
+// The result of encoding a number 17+19i with field number 7
+var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
+// The result of encoding "hello" with field number 7
+var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
+
+func newencoderState(b *bytes.Buffer) *encoderState {
+       b.Reset()
+       state := newEncoderState(nil, b)
+       state.fieldnum = -1
+       return state
+}
+
+// Test instruction execution for encoding.
+// Do not run the machine yet; instead do individual instructions crafted by hand.
+func TestScalarEncInstructions(t *testing.T) {
+       var b = new(bytes.Buffer)
+
+       // bool
+       {
+               data := struct{ a bool }{true}
+               instr := &encInstr{encBool, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(boolResult, b.Bytes()) {
+                       t.Errorf("bool enc instructions: expected % x got % x", boolResult, b.Bytes())
+               }
+       }
+
+       // int
+       {
+               b.Reset()
+               data := struct{ a int }{17}
+               instr := &encInstr{encInt, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(signedResult, b.Bytes()) {
+                       t.Errorf("int enc instructions: expected % x got % x", signedResult, b.Bytes())
+               }
+       }
+
+       // uint
+       {
+               b.Reset()
+               data := struct{ a uint }{17}
+               instr := &encInstr{encUint, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(unsignedResult, b.Bytes()) {
+                       t.Errorf("uint enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+               }
+       }
+
+       // int8
+       {
+               b.Reset()
+               data := struct{ a int8 }{17}
+               instr := &encInstr{encInt8, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(signedResult, b.Bytes()) {
+                       t.Errorf("int8 enc instructions: expected % x got % x", signedResult, b.Bytes())
+               }
+       }
+
+       // uint8
+       {
+               b.Reset()
+               data := struct{ a uint8 }{17}
+               instr := &encInstr{encUint8, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(unsignedResult, b.Bytes()) {
+                       t.Errorf("uint8 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+               }
+       }
+
+       // int16
+       {
+               b.Reset()
+               data := struct{ a int16 }{17}
+               instr := &encInstr{encInt16, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(signedResult, b.Bytes()) {
+                       t.Errorf("int16 enc instructions: expected % x got % x", signedResult, b.Bytes())
+               }
+       }
+
+       // uint16
+       {
+               b.Reset()
+               data := struct{ a uint16 }{17}
+               instr := &encInstr{encUint16, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(unsignedResult, b.Bytes()) {
+                       t.Errorf("uint16 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+               }
+       }
+
+       // int32
+       {
+               b.Reset()
+               data := struct{ a int32 }{17}
+               instr := &encInstr{encInt32, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(signedResult, b.Bytes()) {
+                       t.Errorf("int32 enc instructions: expected % x got % x", signedResult, b.Bytes())
+               }
+       }
+
+       // uint32
+       {
+               b.Reset()
+               data := struct{ a uint32 }{17}
+               instr := &encInstr{encUint32, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(unsignedResult, b.Bytes()) {
+                       t.Errorf("uint32 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+               }
+       }
+
+       // int64
+       {
+               b.Reset()
+               data := struct{ a int64 }{17}
+               instr := &encInstr{encInt64, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(signedResult, b.Bytes()) {
+                       t.Errorf("int64 enc instructions: expected % x got % x", signedResult, b.Bytes())
+               }
+       }
+
+       // uint64
+       {
+               b.Reset()
+               data := struct{ a uint64 }{17}
+               instr := &encInstr{encUint64, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(unsignedResult, b.Bytes()) {
+                       t.Errorf("uint64 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+               }
+       }
+
+       // float
+       {
+               b.Reset()
+               data := struct{ a float }{17}
+               instr := &encInstr{encFloat, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(floatResult, b.Bytes()) {
+                       t.Errorf("float enc instructions: expected % x got % x", floatResult, b.Bytes())
+               }
+       }
+
+       // float32
+       {
+               b.Reset()
+               data := struct{ a float32 }{17}
+               instr := &encInstr{encFloat32, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(floatResult, b.Bytes()) {
+                       t.Errorf("float32 enc instructions: expected % x got % x", floatResult, b.Bytes())
+               }
+       }
+
+       // float64
+       {
+               b.Reset()
+               data := struct{ a float64 }{17}
+               instr := &encInstr{encFloat64, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(floatResult, b.Bytes()) {
+                       t.Errorf("float64 enc instructions: expected % x got % x", floatResult, b.Bytes())
+               }
+       }
+
+       // bytes == []uint8
+       {
+               b.Reset()
+               data := struct{ a []byte }{[]byte("hello")}
+               instr := &encInstr{encUint8Array, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(bytesResult, b.Bytes()) {
+                       t.Errorf("bytes enc instructions: expected % x got % x", bytesResult, b.Bytes())
+               }
+       }
+
+       // string
+       {
+               b.Reset()
+               data := struct{ a string }{"hello"}
+               instr := &encInstr{encString, 6, 0, 0}
+               state := newencoderState(b)
+               instr.op(instr, state, unsafe.Pointer(&data))
+               if !bytes.Equal(bytesResult, b.Bytes()) {
+                       t.Errorf("string enc instructions: expected % x got % x", bytesResult, b.Bytes())
+               }
+       }
+}
+
+func execDec(typ string, instr *decInstr, state *decodeState, t *testing.T, p unsafe.Pointer) {
+       defer testError(t)
+       v := int(decodeUint(state))
+       if v+state.fieldnum != 6 {
+               t.Fatalf("decoding field number %d, got %d", 6, v+state.fieldnum)
+       }
+       instr.op(instr, state, decIndirect(p, instr.indir))
+       state.fieldnum = 6
+}
+
+func newDecodeStateFromData(data []byte) *decodeState {
+       b := bytes.NewBuffer(data)
+       state := newDecodeState(nil, &b)
+       state.fieldnum = -1
+       return state
+}
+
+// Test instruction execution for decoding.
+// Do not run the machine yet; instead do individual instructions crafted by hand.
+func TestScalarDecInstructions(t *testing.T) {
+       ovfl := os.ErrorString("overflow")
+
+       // bool
+       {
+               var data struct {
+                       a bool
+               }
+               instr := &decInstr{decBool, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(boolResult)
+               execDec("bool", instr, state, t, unsafe.Pointer(&data))
+               if data.a != true {
+                       t.Errorf("bool a = %v not true", data.a)
+               }
+       }
+       // int
+       {
+               var data struct {
+                       a int
+               }
+               instr := &decInstr{decOpMap[reflect.Int], 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(signedResult)
+               execDec("int", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("int a = %v not 17", data.a)
+               }
+       }
+
+       // uint
+       {
+               var data struct {
+                       a uint
+               }
+               instr := &decInstr{decOpMap[reflect.Uint], 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(unsignedResult)
+               execDec("uint", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("uint a = %v not 17", data.a)
+               }
+       }
+
+       // int8
+       {
+               var data struct {
+                       a int8
+               }
+               instr := &decInstr{decInt8, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(signedResult)
+               execDec("int8", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("int8 a = %v not 17", data.a)
+               }
+       }
+
+       // uint8
+       {
+               var data struct {
+                       a uint8
+               }
+               instr := &decInstr{decUint8, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(unsignedResult)
+               execDec("uint8", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("uint8 a = %v not 17", data.a)
+               }
+       }
+
+       // int16
+       {
+               var data struct {
+                       a int16
+               }
+               instr := &decInstr{decInt16, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(signedResult)
+               execDec("int16", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("int16 a = %v not 17", data.a)
+               }
+       }
+
+       // uint16
+       {
+               var data struct {
+                       a uint16
+               }
+               instr := &decInstr{decUint16, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(unsignedResult)
+               execDec("uint16", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("uint16 a = %v not 17", data.a)
+               }
+       }
+
+       // int32
+       {
+               var data struct {
+                       a int32
+               }
+               instr := &decInstr{decInt32, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(signedResult)
+               execDec("int32", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("int32 a = %v not 17", data.a)
+               }
+       }
+
+       // uint32
+       {
+               var data struct {
+                       a uint32
+               }
+               instr := &decInstr{decUint32, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(unsignedResult)
+               execDec("uint32", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("uint32 a = %v not 17", data.a)
+               }
+       }
+
+       // uintptr
+       {
+               var data struct {
+                       a uintptr
+               }
+               instr := &decInstr{decOpMap[reflect.Uintptr], 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(unsignedResult)
+               execDec("uintptr", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("uintptr a = %v not 17", data.a)
+               }
+       }
+
+       // int64
+       {
+               var data struct {
+                       a int64
+               }
+               instr := &decInstr{decInt64, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(signedResult)
+               execDec("int64", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("int64 a = %v not 17", data.a)
+               }
+       }
+
+       // uint64
+       {
+               var data struct {
+                       a uint64
+               }
+               instr := &decInstr{decUint64, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(unsignedResult)
+               execDec("uint64", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("uint64 a = %v not 17", data.a)
+               }
+       }
+
+       // float
+       {
+               var data struct {
+                       a float
+               }
+               instr := &decInstr{decOpMap[reflect.Float], 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(floatResult)
+               execDec("float", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("float a = %v not 17", data.a)
+               }
+       }
+
+       // float32
+       {
+               var data struct {
+                       a float32
+               }
+               instr := &decInstr{decFloat32, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(floatResult)
+               execDec("float32", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("float32 a = %v not 17", data.a)
+               }
+       }
+
+       // float64
+       {
+               var data struct {
+                       a float64
+               }
+               instr := &decInstr{decFloat64, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(floatResult)
+               execDec("float64", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17 {
+                       t.Errorf("float64 a = %v not 17", data.a)
+               }
+       }
+
+       // complex
+       {
+               var data struct {
+                       a complex
+               }
+               instr := &decInstr{decOpMap[reflect.Complex], 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(complexResult)
+               execDec("complex", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17+19i {
+                       t.Errorf("complex a = %v not 17+19i", data.a)
+               }
+       }
+
+       // complex64
+       {
+               var data struct {
+                       a complex64
+               }
+               instr := &decInstr{decOpMap[reflect.Complex64], 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(complexResult)
+               execDec("complex", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17+19i {
+                       t.Errorf("complex a = %v not 17+19i", data.a)
+               }
+       }
+
+       // complex128
+       {
+               var data struct {
+                       a complex128
+               }
+               instr := &decInstr{decOpMap[reflect.Complex128], 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(complexResult)
+               execDec("complex", instr, state, t, unsafe.Pointer(&data))
+               if data.a != 17+19i {
+                       t.Errorf("complex a = %v not 17+19i", data.a)
+               }
+       }
+
+       // bytes == []uint8
+       {
+               var data struct {
+                       a []byte
+               }
+               instr := &decInstr{decUint8Array, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(bytesResult)
+               execDec("bytes", instr, state, t, unsafe.Pointer(&data))
+               if string(data.a) != "hello" {
+                       t.Errorf(`bytes a = %q not "hello"`, string(data.a))
+               }
+       }
+
+       // string
+       {
+               var data struct {
+                       a string
+               }
+               instr := &decInstr{decString, 6, 0, 0, ovfl}
+               state := newDecodeStateFromData(bytesResult)
+               execDec("bytes", instr, state, t, unsafe.Pointer(&data))
+               if data.a != "hello" {
+                       t.Errorf(`bytes a = %q not "hello"`, data.a)
+               }
+       }
+}
+
+func TestEndToEnd(t *testing.T) {
+       type T2 struct {
+               t string
+       }
+       s1 := "string1"
+       s2 := "string2"
+       type T1 struct {
+               a, b, c int
+               m       map[string]*float
+               n       *[3]float
+               strs    *[2]string
+               int64s  *[]int64
+               ri      complex64
+               s       string
+               y       []byte
+               t       *T2
+       }
+       pi := 3.14159
+       e := 2.71828
+       t1 := &T1{
+               a:      17,
+               b:      18,
+               c:      -5,
+               m:      map[string]*float{"pi": &pi, "e": &e},
+               n:      &[3]float{1.5, 2.5, 3.5},
+               strs:   &[2]string{s1, s2},
+               int64s: &[]int64{77, 89, 123412342134},
+               ri:     17 - 23i,
+               s:      "Now is the time",
+               y:      []byte("hello, sailor"),
+               t:      &T2{"this is T2"},
+       }
+       b := new(bytes.Buffer)
+       err := NewEncoder(b).Encode(t1)
+       if err != nil {
+               t.Error("encode:", err)
+       }
+       var _t1 T1
+       err = NewDecoder(b).Decode(&_t1)
+       if err != nil {
+               t.Fatal("decode:", err)
+       }
+       if !reflect.DeepEqual(t1, &_t1) {
+               t.Errorf("encode expected %v got %v", *t1, _t1)
+       }
+}
+
+func TestOverflow(t *testing.T) {
+       type inputT struct {
+               maxi int64
+               mini int64
+               maxu uint64
+               maxf float64
+               minf float64
+               maxc complex128
+               minc complex128
+       }
+       var it inputT
+       var err os.Error
+       b := new(bytes.Buffer)
+       enc := NewEncoder(b)
+       dec := NewDecoder(b)
+
+       // int8
+       b.Reset()
+       it = inputT{
+               maxi: math.MaxInt8 + 1,
+       }
+       type outi8 struct {
+               maxi int8
+               mini int8
+       }
+       var o1 outi8
+       enc.Encode(it)
+       err = dec.Decode(&o1)
+       if err == nil || err.String() != `value for "maxi" out of range` {
+               t.Error("wrong overflow error for int8:", err)
+       }
+       it = inputT{
+               mini: math.MinInt8 - 1,
+       }
+       b.Reset()
+       enc.Encode(it)
+       err = dec.Decode(&o1)
+       if err == nil || err.String() != `value for "mini" out of range` {
+               t.Error("wrong underflow error for int8:", err)
+       }
+
+       // int16
+       b.Reset()
+       it = inputT{
+               maxi: math.MaxInt16 + 1,
+       }
+       type outi16 struct {
+               maxi int16
+               mini int16
+       }
+       var o2 outi16
+       enc.Encode(it)
+       err = dec.Decode(&o2)
+       if err == nil || err.String() != `value for "maxi" out of range` {
+               t.Error("wrong overflow error for int16:", err)
+       }
+       it = inputT{
+               mini: math.MinInt16 - 1,
+       }
+       b.Reset()
+       enc.Encode(it)
+       err = dec.Decode(&o2)
+       if err == nil || err.String() != `value for "mini" out of range` {
+               t.Error("wrong underflow error for int16:", err)
+       }
+
+       // int32
+       b.Reset()
+       it = inputT{
+               maxi: math.MaxInt32 + 1,
+       }
+       type outi32 struct {
+               maxi int32
+               mini int32
+       }
+       var o3 outi32
+       enc.Encode(it)
+       err = dec.Decode(&o3)
+       if err == nil || err.String() != `value for "maxi" out of range` {
+               t.Error("wrong overflow error for int32:", err)
+       }
+       it = inputT{
+               mini: math.MinInt32 - 1,
+       }
+       b.Reset()
+       enc.Encode(it)
+       err = dec.Decode(&o3)
+       if err == nil || err.String() != `value for "mini" out of range` {
+               t.Error("wrong underflow error for int32:", err)
+       }
+
+       // uint8
+       b.Reset()
+       it = inputT{
+               maxu: math.MaxUint8 + 1,
+       }
+       type outu8 struct {
+               maxu uint8
+       }
+       var o4 outu8
+       enc.Encode(it)
+       err = dec.Decode(&o4)
+       if err == nil || err.String() != `value for "maxu" out of range` {
+               t.Error("wrong overflow error for uint8:", err)
+       }
+
+       // uint16
+       b.Reset()
+       it = inputT{
+               maxu: math.MaxUint16 + 1,
+       }
+       type outu16 struct {
+               maxu uint16
+       }
+       var o5 outu16
+       enc.Encode(it)
+       err = dec.Decode(&o5)
+       if err == nil || err.String() != `value for "maxu" out of range` {
+               t.Error("wrong overflow error for uint16:", err)
+       }
+
+       // uint32
+       b.Reset()
+       it = inputT{
+               maxu: math.MaxUint32 + 1,
+       }
+       type outu32 struct {
+               maxu uint32
+       }
+       var o6 outu32
+       enc.Encode(it)
+       err = dec.Decode(&o6)
+       if err == nil || err.String() != `value for "maxu" out of range` {
+               t.Error("wrong overflow error for uint32:", err)
+       }
+
+       // float32
+       b.Reset()
+       it = inputT{
+               maxf: math.MaxFloat32 * 2,
+       }
+       type outf32 struct {
+               maxf float32
+               minf float32
+       }
+       var o7 outf32
+       enc.Encode(it)
+       err = dec.Decode(&o7)
+       if err == nil || err.String() != `value for "maxf" out of range` {
+               t.Error("wrong overflow error for float32:", err)
+       }
+
+       // complex64
+       b.Reset()
+       it = inputT{
+               maxc: cmplx(math.MaxFloat32*2, math.MaxFloat32*2),
+       }
+       type outc64 struct {
+               maxc complex64
+               minc complex64
+       }
+       var o8 outc64
+       enc.Encode(it)
+       err = dec.Decode(&o8)
+       if err == nil || err.String() != `value for "maxc" out of range` {
+               t.Error("wrong overflow error for complex64:", err)
+       }
+}
+
+
+func TestNesting(t *testing.T) {
+       type RT struct {
+               a    string
+               next *RT
+       }
+       rt := new(RT)
+       rt.a = "level1"
+       rt.next = new(RT)
+       rt.next.a = "level2"
+       b := new(bytes.Buffer)
+       NewEncoder(b).Encode(rt)
+       var drt RT
+       dec := NewDecoder(b)
+       err := dec.Decode(&drt)
+       if err != nil {
+               t.Errorf("decoder error:", err)
+       }
+       if drt.a != rt.a {
+               t.Errorf("nesting: encode expected %v got %v", *rt, drt)
+       }
+       if drt.next == nil {
+               t.Errorf("nesting: recursion failed")
+       }
+       if drt.next.a != rt.next.a {
+               t.Errorf("nesting: encode expected %v got %v", *rt.next, *drt.next)
+       }
+}
+
+// These three structures have the same data with different indirections
+type T0 struct {
+       a int
+       b int
+       c int
+       d int
+}
+type T1 struct {
+       a int
+       b *int
+       c **int
+       d ***int
+}
+type T2 struct {
+       a ***int
+       b **int
+       c *int
+       d int
+}
+
+func TestAutoIndirection(t *testing.T) {
+       // First transfer t1 into t0
+       var t1 T1
+       t1.a = 17
+       t1.b = new(int)
+       *t1.b = 177
+       t1.c = new(*int)
+       *t1.c = new(int)
+       **t1.c = 1777
+       t1.d = new(**int)
+       *t1.d = new(*int)
+       **t1.d = new(int)
+       ***t1.d = 17777
+       b := new(bytes.Buffer)
+       enc := NewEncoder(b)
+       enc.Encode(t1)
+       dec := NewDecoder(b)
+       var t0 T0
+       dec.Decode(&t0)
+       if t0.a != 17 || t0.b != 177 || t0.c != 1777 || t0.d != 17777 {
+               t.Errorf("t1->t0: expected {17 177 1777 17777}; got %v", t0)
+       }
+
+       // Now transfer t2 into t0
+       var t2 T2
+       t2.d = 17777
+       t2.c = new(int)
+       *t2.c = 1777
+       t2.b = new(*int)
+       *t2.b = new(int)
+       **t2.b = 177
+       t2.a = new(**int)
+       *t2.a = new(*int)
+       **t2.a = new(int)
+       ***t2.a = 17
+       b.Reset()
+       enc.Encode(t2)
+       t0 = T0{}
+       dec.Decode(&t0)
+       if t0.a != 17 || t0.b != 177 || t0.c != 1777 || t0.d != 17777 {
+               t.Errorf("t2->t0 expected {17 177 1777 17777}; got %v", t0)
+       }
+
+       // Now transfer t0 into t1
+       t0 = T0{17, 177, 1777, 17777}
+       b.Reset()
+       enc.Encode(t0)
+       t1 = T1{}
+       dec.Decode(&t1)
+       if t1.a != 17 || *t1.b != 177 || **t1.c != 1777 || ***t1.d != 17777 {
+               t.Errorf("t0->t1 expected {17 177 1777 17777}; got {%d %d %d %d}", t1.a, *t1.b, **t1.c, ***t1.d)
+       }
+
+       // Now transfer t0 into t2
+       b.Reset()
+       enc.Encode(t0)
+       t2 = T2{}
+       dec.Decode(&t2)
+       if ***t2.a != 17 || **t2.b != 177 || *t2.c != 1777 || t2.d != 17777 {
+               t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.a, **t2.b, *t2.c, t2.d)
+       }
+
+       // Now do t2 again but without pre-allocated pointers.
+       b.Reset()
+       enc.Encode(t0)
+       ***t2.a = 0
+       **t2.b = 0
+       *t2.c = 0
+       t2.d = 0
+       dec.Decode(&t2)
+       if ***t2.a != 17 || **t2.b != 177 || *t2.c != 1777 || t2.d != 17777 {
+               t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.a, **t2.b, *t2.c, t2.d)
+       }
+}
+
+type RT0 struct {
+       a int
+       b string
+       c float
+}
+type RT1 struct {
+       c      float
+       b      string
+       a      int
+       notSet string
+}
+
+func TestReorderedFields(t *testing.T) {
+       var rt0 RT0
+       rt0.a = 17
+       rt0.b = "hello"
+       rt0.c = 3.14159
+       b := new(bytes.Buffer)
+       NewEncoder(b).Encode(rt0)
+       dec := NewDecoder(b)
+       var rt1 RT1
+       // Wire type is RT0, local type is RT1.
+       err := dec.Decode(&rt1)
+       if err != nil {
+               t.Error("decode error:", err)
+       }
+       if rt0.a != rt1.a || rt0.b != rt1.b || rt0.c != rt1.c {
+               t.Errorf("rt1->rt0: expected %v; got %v", rt0, rt1)
+       }
+}
+
+// Like an RT0 but with fields we'll ignore on the decode side.
+type IT0 struct {
+       a        int64
+       b        string
+       ignore_d []int
+       ignore_e [3]float
+       ignore_f bool
+       ignore_g string
+       ignore_h []byte
+       ignore_i *RT1
+       ignore_m map[string]int
+       c        float
+}
+
+func TestIgnoredFields(t *testing.T) {
+       var it0 IT0
+       it0.a = 17
+       it0.b = "hello"
+       it0.c = 3.14159
+       it0.ignore_d = []int{1, 2, 3}
+       it0.ignore_e[0] = 1.0
+       it0.ignore_e[1] = 2.0
+       it0.ignore_e[2] = 3.0
+       it0.ignore_f = true
+       it0.ignore_g = "pay no attention"
+       it0.ignore_h = []byte("to the curtain")
+       it0.ignore_i = &RT1{3.1, "hi", 7, "hello"}
+       it0.ignore_m = map[string]int{"one": 1, "two": 2}
+
+       b := new(bytes.Buffer)
+       NewEncoder(b).Encode(it0)
+       dec := NewDecoder(b)
+       var rt1 RT1
+       // Wire type is IT0, local type is RT1.
+       err := dec.Decode(&rt1)
+       if err != nil {
+               t.Error("error: ", err)
+       }
+       if int(it0.a) != rt1.a || it0.b != rt1.b || it0.c != rt1.c {
+               t.Errorf("rt1->rt0: expected %v; got %v", it0, rt1)
+       }
+}
+
+type Bad0 struct {
+       ch chan int
+       c  float
+}
+
+var nilEncoder *Encoder
+
+func TestInvalidField(t *testing.T) {
+       var bad0 Bad0
+       bad0.ch = make(chan int)
+       b := new(bytes.Buffer)
+       err := nilEncoder.encode(b, reflect.NewValue(&bad0))
+       if err == nil {
+               t.Error("expected error; got none")
+       } else if strings.Index(err.String(), "type") < 0 {
+               t.Error("expected type error; got", err)
+       }
+}
+
+type Indirect struct {
+       a ***[3]int
+       s ***[]int
+       m ****map[string]int
+}
+
+type Direct struct {
+       a [3]int
+       s []int
+       m map[string]int
+}
+
+func TestIndirectSliceMapArray(t *testing.T) {
+       // Marshal indirect, unmarshal to direct.
+       i := new(Indirect)
+       i.a = new(**[3]int)
+       *i.a = new(*[3]int)
+       **i.a = new([3]int)
+       ***i.a = [3]int{1, 2, 3}
+       i.s = new(**[]int)
+       *i.s = new(*[]int)
+       **i.s = new([]int)
+       ***i.s = []int{4, 5, 6}
+       i.m = new(***map[string]int)
+       *i.m = new(**map[string]int)
+       **i.m = new(*map[string]int)
+       ***i.m = new(map[string]int)
+       ****i.m = map[string]int{"one": 1, "two": 2, "three": 3}
+       b := new(bytes.Buffer)
+       NewEncoder(b).Encode(i)
+       dec := NewDecoder(b)
+       var d Direct
+       err := dec.Decode(&d)
+       if err != nil {
+               t.Error("error: ", err)
+       }
+       if len(d.a) != 3 || d.a[0] != 1 || d.a[1] != 2 || d.a[2] != 3 {
+               t.Errorf("indirect to direct: d.a is %v not %v", d.a, ***i.a)
+       }
+       if len(d.s) != 3 || d.s[0] != 4 || d.s[1] != 5 || d.s[2] != 6 {
+               t.Errorf("indirect to direct: d.s is %v not %v", d.s, ***i.s)
+       }
+       if len(d.m) != 3 || d.m["one"] != 1 || d.m["two"] != 2 || d.m["three"] != 3 {
+               t.Errorf("indirect to direct: d.m is %v not %v", d.m, ***i.m)
+       }
+       // Marshal direct, unmarshal to indirect.
+       d.a = [3]int{11, 22, 33}
+       d.s = []int{44, 55, 66}
+       d.m = map[string]int{"four": 4, "five": 5, "six": 6}
+       i = new(Indirect)
+       b.Reset()
+       NewEncoder(b).Encode(d)
+       dec = NewDecoder(b)
+       err = dec.Decode(&i)
+       if err != nil {
+               t.Error("error: ", err)
+       }
+       if len(***i.a) != 3 || (***i.a)[0] != 11 || (***i.a)[1] != 22 || (***i.a)[2] != 33 {
+               t.Errorf("direct to indirect: ***i.a is %v not %v", ***i.a, d.a)
+       }
+       if len(***i.s) != 3 || (***i.s)[0] != 44 || (***i.s)[1] != 55 || (***i.s)[2] != 66 {
+               t.Errorf("direct to indirect: ***i.s is %v not %v", ***i.s, ***i.s)
+       }
+       if len(****i.m) != 3 || (****i.m)["four"] != 4 || (****i.m)["five"] != 5 || (****i.m)["six"] != 6 {
+               t.Errorf("direct to indirect: ****i.m is %v not %v", ****i.m, d.m)
+       }
+}
+
+// An interface with several implementations
+type Squarer interface {
+       Square() int
+}
+
+type Int int
+
+func (i Int) Square() int {
+       return int(i * i)
+}
+
+type Float float
+
+func (f Float) Square() int {
+       return int(f * f)
+}
+
+type Vector []int
+
+func (v Vector) Square() int {
+       sum := 0
+       for _, x := range v {
+               sum += x * x
+       }
+       return sum
+}
+
+type Point struct {
+       a, b int
+}
+
+func (p Point) Square() int {
+       return p.a*p.a + p.b*p.b
+}
+
+// A struct with interfaces in it.
+type InterfaceItem struct {
+       i             int
+       sq1, sq2, sq3 Squarer
+       f             float
+       sq            []Squarer
+}
+
+// The same struct without interfaces
+type NoInterfaceItem struct {
+       i int
+       f float
+}
+
+func TestInterface(t *testing.T) {
+       iVal := Int(3)
+       fVal := Float(5)
+       // Sending a Vector will require that the receiver define a type in the middle of
+       // receiving the value for item2.
+       vVal := Vector{1, 2, 3}
+       b := new(bytes.Buffer)
+       item1 := &InterfaceItem{1, iVal, fVal, vVal, 11.5, []Squarer{iVal, fVal, nil, vVal}}
+       // Register the types.
+       Register(Int(0))
+       Register(Float(0))
+       Register(Vector{})
+       err := NewEncoder(b).Encode(item1)
+       if err != nil {
+               t.Error("expected no encode error; got", err)
+       }
+
+       item2 := InterfaceItem{}
+       err = NewDecoder(b).Decode(&item2)
+       if err != nil {
+               t.Fatal("decode:", err)
+       }
+       if item2.i != item1.i {
+               t.Error("normal int did not decode correctly")
+       }
+       if item2.sq1 == nil || item2.sq1.Square() != iVal.Square() {
+               t.Error("Int did not decode correctly")
+       }
+       if item2.sq2 == nil || item2.sq2.Square() != fVal.Square() {
+               t.Error("Float did not decode correctly")
+       }
+       if item2.sq3 == nil || item2.sq3.Square() != vVal.Square() {
+               t.Error("Vector did not decode correctly")
+       }
+       if item2.f != item1.f {
+               t.Error("normal float did not decode correctly")
+       }
+       // Now check that we received a slice of Squarers correctly, including a nil element
+       if len(item1.sq) != len(item2.sq) {
+               t.Fatalf("[]Squarer length wrong: got %d; expected %d", len(item2.sq), len(item1.sq))
+       }
+       for i, v1 := range item1.sq {
+               v2 := item2.sq[i]
+               if v1 == nil || v2 == nil {
+                       if v1 != nil || v2 != nil {
+                               t.Errorf("item %d inconsistent nils", i)
+                       }
+                       continue
+                       if v1.Square() != v2.Square() {
+                               t.Errorf("item %d inconsistent values: %v %v", v1, v2)
+                       }
+               }
+       }
+
+}
+
+// A struct with all basic types, stored in interfaces.
+type BasicInterfaceItem struct {
+       Int, Int8, Int16, Int32, Int64      interface{}
+       Uint, Uint8, Uint16, Uint32, Uint64 interface{}
+       Float, Float32, Float64             interface{}
+       Complex, Complex64, Complex128      interface{}
+       Bool                                interface{}
+       String                              interface{}
+       Bytes                               interface{}
+}
+
+func TestInterfaceBasic(t *testing.T) {
+       b := new(bytes.Buffer)
+       item1 := &BasicInterfaceItem{
+               int(1), int8(1), int16(1), int32(1), int64(1),
+               uint(1), uint8(1), uint16(1), uint32(1), uint64(1),
+               float(1), float32(1), float64(1),
+               complex(0i), complex64(0i), complex128(0i),
+               true,
+               "hello",
+               []byte("sailor"),
+       }
+       err := NewEncoder(b).Encode(item1)
+       if err != nil {
+               t.Error("expected no encode error; got", err)
+       }
+
+       item2 := &BasicInterfaceItem{}
+       err = NewDecoder(b).Decode(&item2)
+       if err != nil {
+               t.Fatal("decode:", err)
+       }
+       if !reflect.DeepEqual(item1, item2) {
+               t.Errorf("encode expected %v got %v", item1, item2)
+       }
+       // Hand check a couple for correct types.
+       if v, ok := item2.Bool.(bool); !ok || !v {
+               t.Error("boolean should be true")
+       }
+       if v, ok := item2.String.(string); !ok || v != item1.String.(string) {
+               t.Errorf("string should be %v is %v", item1.String, v)
+       }
+}
+
+type String string
+
+type PtrInterfaceItem struct {
+       str interface{} // basic
+       Str interface{} // derived
+}
+
+// We'll send pointers; should receive values.
+// Also check that we can register T but send *T.
+func TestInterfacePointer(t *testing.T) {
+       b := new(bytes.Buffer)
+       str1 := "howdy"
+       str2 := String("kiddo")
+       item1 := &PtrInterfaceItem{
+               &str1,
+               &str2,
+       }
+       // Register the type.
+       Register(str2)
+       err := NewEncoder(b).Encode(item1)
+       if err != nil {
+               t.Error("expected no encode error; got", err)
+       }
+
+       item2 := &PtrInterfaceItem{}
+       err = NewDecoder(b).Decode(&item2)
+       if err != nil {
+               t.Fatal("decode:", err)
+       }
+       // Hand test for correct types and values.
+       if v, ok := item2.str.(string); !ok || v != str1 {
+               t.Errorf("basic string failed: %q should be %q", v, str1)
+       }
+       if v, ok := item2.Str.(String); !ok || v != str2 {
+               t.Errorf("derived type String failed: %q should be %q", v, str2)
+       }
+}
+
+func TestIgnoreInterface(t *testing.T) {
+       iVal := Int(3)
+       fVal := Float(5)
+       // Sending a Point will require that the receiver define a type in the middle of
+       // receiving the value for item2.
+       pVal := Point{2, 3}
+       b := new(bytes.Buffer)
+       item1 := &InterfaceItem{1, iVal, fVal, pVal, 11.5, nil}
+       // Register the types.
+       Register(Int(0))
+       Register(Float(0))
+       Register(Point{})
+       err := NewEncoder(b).Encode(item1)
+       if err != nil {
+               t.Error("expected no encode error; got", err)
+       }
+
+       item2 := NoInterfaceItem{}
+       err = NewDecoder(b).Decode(&item2)
+       if err != nil {
+               t.Fatal("decode:", err)
+       }
+       if item2.i != item1.i {
+               t.Error("normal int did not decode correctly")
+       }
+       if item2.f != item2.f {
+               t.Error("normal float did not decode correctly")
+       }
+}
+
+// A type that won't be defined in the gob until we send it in an interface value.
+type OnTheFly struct {
+       a int
+}
+
+type DT struct {
+       //      X OnTheFly
+       a     int
+       b     string
+       c     float
+       i     interface{}
+       j     interface{}
+       i_nil interface{}
+       m     map[string]int
+       r     [3]int
+       s     []string
+}
+
+func TestDebug(t *testing.T) {
+       if debugFunc == nil {
+               return
+       }
+       Register(OnTheFly{})
+       var dt DT
+       dt.a = 17
+       dt.b = "hello"
+       dt.c = 3.14159
+       dt.i = 271828
+       dt.j = OnTheFly{3}
+       dt.i_nil = nil
+       dt.m = map[string]int{"one": 1, "two": 2}
+       dt.r = [3]int{11, 22, 33}
+       dt.s = []string{"hi", "joe"}
+       b := new(bytes.Buffer)
+       err := NewEncoder(b).Encode(dt)
+       if err != nil {
+               t.Fatal("encode:", err)
+       }
+       debugBuffer := bytes.NewBuffer(b.Bytes())
+       dt2 := &DT{}
+       err = NewDecoder(b).Decode(&dt2)
+       if err != nil {
+               t.Error("decode:", err)
+       }
+       debugFunc(debugBuffer)
+}
diff --git a/libgo/go/gob/decode.go b/libgo/go/gob/decode.go
new file mode 100644 (file)
index 0000000..5a19b78
--- /dev/null
@@ -0,0 +1,1013 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+// TODO(rsc): When garbage collector changes, revisit
+// the allocations in this file that use unsafe.Pointer.
+
+import (
+       "bytes"
+       "io"
+       "math"
+       "os"
+       "reflect"
+       "unsafe"
+)
+
+var (
+       errBadUint = os.ErrorString("gob: encoded unsigned integer out of range")
+       errBadType = os.ErrorString("gob: unknown type id or corrupted data")
+       errRange   = os.ErrorString("gob: internal error: field numbers out of bounds")
+)
+
+// The execution state of an instance of the decoder. A new state
+// is created for nested objects.
+type decodeState struct {
+       dec *Decoder
+       // The buffer is stored with an extra indirection because it may be replaced
+       // if we load a type during decode (when reading an interface value).
+       b        **bytes.Buffer
+       fieldnum int // the last field number read.
+       buf      []byte
+}
+
+func newDecodeState(dec *Decoder, b **bytes.Buffer) *decodeState {
+       d := new(decodeState)
+       d.dec = dec
+       d.b = b
+       d.buf = make([]byte, uint64Size)
+       return d
+}
+
+func overflow(name string) os.ErrorString {
+       return os.ErrorString(`value for "` + name + `" out of range`)
+}
+
+// decodeUintReader reads an encoded unsigned integer from an io.Reader.
+// Used only by the Decoder to read the message length.
+func decodeUintReader(r io.Reader, buf []byte) (x uint64, err os.Error) {
+       _, err = r.Read(buf[0:1])
+       if err != nil {
+               return
+       }
+       b := buf[0]
+       if b <= 0x7f {
+               return uint64(b), nil
+       }
+       nb := -int(int8(b))
+       if nb > uint64Size {
+               err = errBadUint
+               return
+       }
+       var n int
+       n, err = io.ReadFull(r, buf[0:nb])
+       if err != nil {
+               if err == os.EOF {
+                       err = io.ErrUnexpectedEOF
+               }
+               return
+       }
+       // Could check that the high byte is zero but it's not worth it.
+       for i := 0; i < n; i++ {
+               x <<= 8
+               x |= uint64(buf[i])
+       }
+       return
+}
+
+// decodeUint reads an encoded unsigned integer from state.r.
+// Does not check for overflow.
+func decodeUint(state *decodeState) (x uint64) {
+       b, err := state.b.ReadByte()
+       if err != nil {
+               error(err)
+       }
+       if b <= 0x7f {
+               return uint64(b)
+       }
+       nb := -int(int8(b))
+       if nb > uint64Size {
+               error(errBadUint)
+       }
+       n, err := state.b.Read(state.buf[0:nb])
+       if err != nil {
+               error(err)
+       }
+       // Don't need to check error; it's safe to loop regardless.
+       // Could check that the high byte is zero but it's not worth it.
+       for i := 0; i < n; i++ {
+               x <<= 8
+               x |= uint64(state.buf[i])
+       }
+       return x
+}
+
+// decodeInt reads an encoded signed integer from state.r.
+// Does not check for overflow.
+func decodeInt(state *decodeState) int64 {
+       x := decodeUint(state)
+       if x&1 != 0 {
+               return ^int64(x >> 1)
+       }
+       return int64(x >> 1)
+}
+
+type decOp func(i *decInstr, state *decodeState, p unsafe.Pointer)
+
+// The 'instructions' of the decoding machine
+type decInstr struct {
+       op     decOp
+       field  int            // field number of the wire type
+       indir  int            // how many pointer indirections to reach the value in the struct
+       offset uintptr        // offset in the structure of the field to encode
+       ovfl   os.ErrorString // error message for overflow/underflow (for arrays, of the elements)
+}
+
+// Since the encoder writes no zeros, if we arrive at a decoder we have
+// a value to extract and store.  The field number has already been read
+// (it's how we knew to call this decoder).
+// Each decoder is responsible for handling any indirections associated
+// with the data structure.  If any pointer so reached is nil, allocation must
+// be done.
+
+// Walk the pointer hierarchy, allocating if we find a nil.  Stop one before the end.
+func decIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
+       for ; indir > 1; indir-- {
+               if *(*unsafe.Pointer)(p) == nil {
+                       // Allocation required
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(unsafe.Pointer))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       return p
+}
+
+func ignoreUint(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       decodeUint(state)
+}
+
+func ignoreTwoUints(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       decodeUint(state)
+       decodeUint(state)
+}
+
+func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(bool))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       *(*bool)(p) = decodeInt(state) != 0
+}
+
+func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int8))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       v := decodeInt(state)
+       if v < math.MinInt8 || math.MaxInt8 < v {
+               error(i.ovfl)
+       } else {
+               *(*int8)(p) = int8(v)
+       }
+}
+
+func decUint8(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint8))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       v := decodeUint(state)
+       if math.MaxUint8 < v {
+               error(i.ovfl)
+       } else {
+               *(*uint8)(p) = uint8(v)
+       }
+}
+
+func decInt16(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int16))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       v := decodeInt(state)
+       if v < math.MinInt16 || math.MaxInt16 < v {
+               error(i.ovfl)
+       } else {
+               *(*int16)(p) = int16(v)
+       }
+}
+
+func decUint16(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint16))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       v := decodeUint(state)
+       if math.MaxUint16 < v {
+               error(i.ovfl)
+       } else {
+               *(*uint16)(p) = uint16(v)
+       }
+}
+
+func decInt32(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int32))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       v := decodeInt(state)
+       if v < math.MinInt32 || math.MaxInt32 < v {
+               error(i.ovfl)
+       } else {
+               *(*int32)(p) = int32(v)
+       }
+}
+
+func decUint32(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint32))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       v := decodeUint(state)
+       if math.MaxUint32 < v {
+               error(i.ovfl)
+       } else {
+               *(*uint32)(p) = uint32(v)
+       }
+}
+
+func decInt64(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int64))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       *(*int64)(p) = int64(decodeInt(state))
+}
+
+func decUint64(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint64))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       *(*uint64)(p) = uint64(decodeUint(state))
+}
+
+// Floating-point numbers are transmitted as uint64s holding the bits
+// of the underlying representation.  They are sent byte-reversed, with
+// the exponent end coming out first, so integer floating point numbers
+// (for example) transmit more compactly.  This routine does the
+// unswizzling.
+func floatFromBits(u uint64) float64 {
+       var v uint64
+       for i := 0; i < 8; i++ {
+               v <<= 8
+               v |= u & 0xFF
+               u >>= 8
+       }
+       return math.Float64frombits(v)
+}
+
+func storeFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       v := floatFromBits(decodeUint(state))
+       av := v
+       if av < 0 {
+               av = -av
+       }
+       // +Inf is OK in both 32- and 64-bit floats.  Underflow is always OK.
+       if math.MaxFloat32 < av && av <= math.MaxFloat64 {
+               error(i.ovfl)
+       } else {
+               *(*float32)(p) = float32(v)
+       }
+}
+
+func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float32))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       storeFloat32(i, state, p)
+}
+
+func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float64))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       *(*float64)(p) = floatFromBits(uint64(decodeUint(state)))
+}
+
+// Complex numbers are just a pair of floating-point numbers, real part first.
+func decComplex64(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex64))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       storeFloat32(i, state, p)
+       storeFloat32(i, state, unsafe.Pointer(uintptr(p)+uintptr(unsafe.Sizeof(float(0)))))
+}
+
+func decComplex128(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex128))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       real := floatFromBits(uint64(decodeUint(state)))
+       imag := floatFromBits(uint64(decodeUint(state)))
+       *(*complex128)(p) = cmplx(real, imag)
+}
+
+// uint8 arrays are encoded as an unsigned count followed by the raw bytes.
+func decUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]uint8))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       b := make([]uint8, decodeUint(state))
+       state.b.Read(b)
+       *(*[]uint8)(p) = b
+}
+
+// Strings are encoded as an unsigned count followed by the raw bytes.
+func decString(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       if i.indir > 0 {
+               if *(*unsafe.Pointer)(p) == nil {
+                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]byte))
+               }
+               p = *(*unsafe.Pointer)(p)
+       }
+       b := make([]byte, decodeUint(state))
+       state.b.Read(b)
+       *(*string)(p) = string(b)
+}
+
+func ignoreUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) {
+       b := make([]byte, decodeUint(state))
+       state.b.Read(b)
+}
+
+// Execution engine
+
+// The encoder engine is an array of instructions indexed by field number of the incoming
+// decoder.  It is executed with random access according to field number.
+type decEngine struct {
+       instr    []decInstr
+       numInstr int // the number of active instructions
+}
+
+// allocate makes sure storage is available for an object of underlying type rtyp
+// that is indir levels of indirection through p.
+func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
+       if indir == 0 {
+               return p
+       }
+       up := unsafe.Pointer(p)
+       if indir > 1 {
+               up = decIndirect(up, indir)
+       }
+       if *(*unsafe.Pointer)(up) == nil {
+               // Allocate object.
+               *(*unsafe.Pointer)(up) = unsafe.New(rtyp)
+       }
+       return *(*uintptr)(up)
+}
+
+func (dec *Decoder) decodeSingle(engine *decEngine, rtyp reflect.Type, b **bytes.Buffer, p uintptr, indir int) (err os.Error) {
+       defer catchError(&err)
+       p = allocate(rtyp, p, indir)
+       state := newDecodeState(dec, b)
+       state.fieldnum = singletonField
+       basep := p
+       delta := int(decodeUint(state))
+       if delta != 0 {
+               errorf("gob decode: corrupted data: non-zero delta for singleton")
+       }
+       instr := &engine.instr[singletonField]
+       ptr := unsafe.Pointer(basep) // offset will be zero
+       if instr.indir > 1 {
+               ptr = decIndirect(ptr, instr.indir)
+       }
+       instr.op(instr, state, ptr)
+       return nil
+}
+
+func (dec *Decoder) decodeStruct(engine *decEngine, rtyp *reflect.StructType, b **bytes.Buffer, p uintptr, indir int) (err os.Error) {
+       defer catchError(&err)
+       p = allocate(rtyp, p, indir)
+       state := newDecodeState(dec, b)
+       state.fieldnum = -1
+       basep := p
+       for state.b.Len() > 0 {
+               delta := int(decodeUint(state))
+               if delta < 0 {
+                       errorf("gob decode: corrupted data: negative delta")
+               }
+               if delta == 0 { // struct terminator is zero delta fieldnum
+                       break
+               }
+               fieldnum := state.fieldnum + delta
+               if fieldnum >= len(engine.instr) {
+                       error(errRange)
+                       break
+               }
+               instr := &engine.instr[fieldnum]
+               p := unsafe.Pointer(basep + instr.offset)
+               if instr.indir > 1 {
+                       p = decIndirect(p, instr.indir)
+               }
+               instr.op(instr, state, p)
+               state.fieldnum = fieldnum
+       }
+       return nil
+}
+
+func (dec *Decoder) ignoreStruct(engine *decEngine, b **bytes.Buffer) (err os.Error) {
+       defer catchError(&err)
+       state := newDecodeState(dec, b)
+       state.fieldnum = -1
+       for state.b.Len() > 0 {
+               delta := int(decodeUint(state))
+               if delta < 0 {
+                       errorf("gob ignore decode: corrupted data: negative delta")
+               }
+               if delta == 0 { // struct terminator is zero delta fieldnum
+                       break
+               }
+               fieldnum := state.fieldnum + delta
+               if fieldnum >= len(engine.instr) {
+                       error(errRange)
+               }
+               instr := &engine.instr[fieldnum]
+               instr.op(instr, state, unsafe.Pointer(nil))
+               state.fieldnum = fieldnum
+       }
+       return nil
+}
+
+func (dec *Decoder) decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) {
+       instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
+       for i := 0; i < length; i++ {
+               up := unsafe.Pointer(p)
+               if elemIndir > 1 {
+                       up = decIndirect(up, elemIndir)
+               }
+               elemOp(instr, state, up)
+               p += uintptr(elemWid)
+       }
+}
+
+func (dec *Decoder) decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) {
+       if indir > 0 {
+               p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
+       }
+       if n := decodeUint(state); n != uint64(length) {
+               errorf("gob: length mismatch in decodeArray")
+       }
+       dec.decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl)
+}
+
+func decodeIntoValue(state *decodeState, op decOp, indir int, v reflect.Value, ovfl os.ErrorString) reflect.Value {
+       instr := &decInstr{op, 0, indir, 0, ovfl}
+       up := unsafe.Pointer(v.Addr())
+       if indir > 1 {
+               up = decIndirect(up, indir)
+       }
+       op(instr, state, up)
+       return v
+}
+
+func (dec *Decoder) decodeMap(mtyp *reflect.MapType, state *decodeState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.ErrorString) {
+       if indir > 0 {
+               p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect
+       }
+       up := unsafe.Pointer(p)
+       if *(*unsafe.Pointer)(up) == nil { // maps are represented as a pointer in the runtime
+               // Allocate map.
+               *(*unsafe.Pointer)(up) = unsafe.Pointer(reflect.MakeMap(mtyp).Get())
+       }
+       // Maps cannot be accessed by moving addresses around the way
+       // that slices etc. can.  We must recover a full reflection value for
+       // the iteration.
+       v := reflect.NewValue(unsafe.Unreflect(mtyp, unsafe.Pointer((p)))).(*reflect.MapValue)
+       n := int(decodeUint(state))
+       for i := 0; i < n; i++ {
+               key := decodeIntoValue(state, keyOp, keyIndir, reflect.MakeZero(mtyp.Key()), ovfl)
+               elem := decodeIntoValue(state, elemOp, elemIndir, reflect.MakeZero(mtyp.Elem()), ovfl)
+               v.SetElem(key, elem)
+       }
+}
+
+func (dec *Decoder) ignoreArrayHelper(state *decodeState, elemOp decOp, length int) {
+       instr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
+       for i := 0; i < length; i++ {
+               elemOp(instr, state, nil)
+       }
+}
+
+func (dec *Decoder) ignoreArray(state *decodeState, elemOp decOp, length int) {
+       if n := decodeUint(state); n != uint64(length) {
+               errorf("gob: length mismatch in ignoreArray")
+       }
+       dec.ignoreArrayHelper(state, elemOp, length)
+}
+
+func (dec *Decoder) ignoreMap(state *decodeState, keyOp, elemOp decOp) {
+       n := int(decodeUint(state))
+       keyInstr := &decInstr{keyOp, 0, 0, 0, os.ErrorString("no error")}
+       elemInstr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
+       for i := 0; i < n; i++ {
+               keyOp(keyInstr, state, nil)
+               elemOp(elemInstr, state, nil)
+       }
+}
+
+func (dec *Decoder) decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) {
+       n := int(uintptr(decodeUint(state)))
+       if indir > 0 {
+               up := unsafe.Pointer(p)
+               if *(*unsafe.Pointer)(up) == nil {
+                       // Allocate the slice header.
+                       *(*unsafe.Pointer)(up) = unsafe.Pointer(new([]unsafe.Pointer))
+               }
+               p = *(*uintptr)(up)
+       }
+       // Allocate storage for the slice elements, that is, the underlying array.
+       // Always write a header at p.
+       hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p))
+       hdrp.Data = uintptr(unsafe.NewArray(atyp.Elem(), n))
+       hdrp.Len = n
+       hdrp.Cap = n
+       dec.decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, n, elemIndir, ovfl)
+}
+
+func (dec *Decoder) ignoreSlice(state *decodeState, elemOp decOp) {
+       dec.ignoreArrayHelper(state, elemOp, int(decodeUint(state)))
+}
+
+// setInterfaceValue sets an interface value to a concrete value through
+// reflection.  If the concrete value does not implement the interface, the
+// setting will panic.  This routine turns the panic into an error return.
+// This dance avoids manually checking that the value satisfies the
+// interface.
+// TODO(rsc): avoid panic+recover after fixing issue 327.
+func setInterfaceValue(ivalue *reflect.InterfaceValue, value reflect.Value) {
+       defer func() {
+               if e := recover(); e != nil {
+                       error(e.(os.Error))
+               }
+       }()
+       ivalue.Set(value)
+}
+
+// decodeInterface receives the name of a concrete type followed by its value.
+// If the name is empty, the value is nil and no value is sent.
+func (dec *Decoder) decodeInterface(ityp *reflect.InterfaceType, state *decodeState, p uintptr, indir int) {
+       // Create an interface reflect.Value.  We need one even for the nil case.
+       ivalue := reflect.MakeZero(ityp).(*reflect.InterfaceValue)
+       // Read the name of the concrete type.
+       b := make([]byte, decodeUint(state))
+       state.b.Read(b)
+       name := string(b)
+       if name == "" {
+               // Copy the representation of the nil interface value to the target.
+               // This is horribly unsafe and special.
+               *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.Get()
+               return
+       }
+       // The concrete type must be registered.
+       typ, ok := nameToConcreteType[name]
+       if !ok {
+               errorf("gob: name not registered for interface: %q", name)
+       }
+       // Read the concrete value.
+       value := reflect.MakeZero(typ)
+       dec.decodeValueFromBuffer(value, false, true)
+       if dec.err != nil {
+               error(dec.err)
+       }
+       // Allocate the destination interface value.
+       if indir > 0 {
+               p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect
+       }
+       // Assign the concrete value to the interface.
+       // Tread carefully; it might not satisfy the interface.
+       setInterfaceValue(ivalue, value)
+       // Copy the representation of the interface value to the target.
+       // This is horribly unsafe and special.
+       *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.Get()
+}
+
+func (dec *Decoder) ignoreInterface(state *decodeState) {
+       // Read the name of the concrete type.
+       b := make([]byte, decodeUint(state))
+       _, err := state.b.Read(b)
+       if err != nil {
+               error(err)
+       }
+       dec.decodeValueFromBuffer(nil, true, true)
+       if dec.err != nil {
+               error(err)
+       }
+}
+
+// Index by Go types.
+var decOpMap = []decOp{
+       reflect.Bool:       decBool,
+       reflect.Int8:       decInt8,
+       reflect.Int16:      decInt16,
+       reflect.Int32:      decInt32,
+       reflect.Int64:      decInt64,
+       reflect.Uint8:      decUint8,
+       reflect.Uint16:     decUint16,
+       reflect.Uint32:     decUint32,
+       reflect.Uint64:     decUint64,
+       reflect.Float32:    decFloat32,
+       reflect.Float64:    decFloat64,
+       reflect.Complex64:  decComplex64,
+       reflect.Complex128: decComplex128,
+       reflect.String:     decString,
+}
+
+// Indexed by gob types.  tComplex will be added during type.init().
+var decIgnoreOpMap = map[typeId]decOp{
+       tBool:    ignoreUint,
+       tInt:     ignoreUint,
+       tUint:    ignoreUint,
+       tFloat:   ignoreUint,
+       tBytes:   ignoreUint8Array,
+       tString:  ignoreUint8Array,
+       tComplex: ignoreTwoUints,
+}
+
+// Return the decoding op for the base type under rt and
+// the indirection count to reach it.
+func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp, int) {
+       typ, indir := indirect(rt)
+       var op decOp
+       k := typ.Kind()
+       if int(k) < len(decOpMap) {
+               op = decOpMap[k]
+       }
+       if op == nil {
+               // Special cases
+               switch t := typ.(type) {
+               case *reflect.ArrayType:
+                       name = "element of " + name
+                       elemId := dec.wireType[wireId].arrayT.Elem
+                       elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
+                       ovfl := overflow(name)
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               state.dec.decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl)
+                       }
+
+               case *reflect.MapType:
+                       name = "element of " + name
+                       keyId := dec.wireType[wireId].mapT.Key
+                       elemId := dec.wireType[wireId].mapT.Elem
+                       keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), name)
+                       elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
+                       ovfl := overflow(name)
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               up := unsafe.Pointer(p)
+                               state.dec.decodeMap(t, state, uintptr(up), keyOp, elemOp, i.indir, keyIndir, elemIndir, ovfl)
+                       }
+
+               case *reflect.SliceType:
+                       name = "element of " + name
+                       if t.Elem().Kind() == reflect.Uint8 {
+                               op = decUint8Array
+                               break
+                       }
+                       var elemId typeId
+                       if tt, ok := builtinIdToType[wireId]; ok {
+                               elemId = tt.(*sliceType).Elem
+                       } else {
+                               elemId = dec.wireType[wireId].sliceT.Elem
+                       }
+                       elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
+                       ovfl := overflow(name)
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               state.dec.decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
+                       }
+
+               case *reflect.StructType:
+                       // Generate a closure that calls out to the engine for the nested type.
+                       enginePtr, err := dec.getDecEnginePtr(wireId, typ)
+                       if err != nil {
+                               error(err)
+                       }
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               // indirect through enginePtr to delay evaluation for recursive structs
+                               err = dec.decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir)
+                               if err != nil {
+                                       error(err)
+                               }
+                       }
+               case *reflect.InterfaceType:
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               dec.decodeInterface(t, state, uintptr(p), i.indir)
+                       }
+               }
+       }
+       if op == nil {
+               errorf("gob: decode can't handle type %s", rt.String())
+       }
+       return op, indir
+}
+
+// Return the decoding op for a field that has no destination.
+func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
+       op, ok := decIgnoreOpMap[wireId]
+       if !ok {
+               if wireId == tInterface {
+                       // Special case because it's a method: the ignored item might
+                       // define types and we need to record their state in the decoder.
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               dec.ignoreInterface(state)
+                       }
+                       return op
+               }
+               // Special cases
+               wire := dec.wireType[wireId]
+               switch {
+               case wire == nil:
+                       panic("internal error: can't find ignore op for type " + wireId.string())
+               case wire.arrayT != nil:
+                       elemId := wire.arrayT.Elem
+                       elemOp := dec.decIgnoreOpFor(elemId)
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               state.dec.ignoreArray(state, elemOp, wire.arrayT.Len)
+                       }
+
+               case wire.mapT != nil:
+                       keyId := dec.wireType[wireId].mapT.Key
+                       elemId := dec.wireType[wireId].mapT.Elem
+                       keyOp := dec.decIgnoreOpFor(keyId)
+                       elemOp := dec.decIgnoreOpFor(elemId)
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               state.dec.ignoreMap(state, keyOp, elemOp)
+                       }
+
+               case wire.sliceT != nil:
+                       elemId := wire.sliceT.Elem
+                       elemOp := dec.decIgnoreOpFor(elemId)
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               state.dec.ignoreSlice(state, elemOp)
+                       }
+
+               case wire.structT != nil:
+                       // Generate a closure that calls out to the engine for the nested type.
+                       enginePtr, err := dec.getIgnoreEnginePtr(wireId)
+                       if err != nil {
+                               error(err)
+                       }
+                       op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+                               // indirect through enginePtr to delay evaluation for recursive structs
+                               state.dec.ignoreStruct(*enginePtr, state.b)
+                       }
+               }
+       }
+       if op == nil {
+               errorf("ignore can't handle type %s", wireId.string())
+       }
+       return op
+}
+
+// Are these two gob Types compatible?
+// Answers the question for basic types, arrays, and slices.
+// Structs are considered ok; fields will be checked later.
+func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
+       fr, _ = indirect(fr)
+       switch t := fr.(type) {
+       default:
+               // map, chan, etc: cannot handle.
+               return false
+       case *reflect.BoolType:
+               return fw == tBool
+       case *reflect.IntType:
+               return fw == tInt
+       case *reflect.UintType:
+               return fw == tUint
+       case *reflect.FloatType:
+               return fw == tFloat
+       case *reflect.ComplexType:
+               return fw == tComplex
+       case *reflect.StringType:
+               return fw == tString
+       case *reflect.InterfaceType:
+               return fw == tInterface
+       case *reflect.ArrayType:
+               wire, ok := dec.wireType[fw]
+               if !ok || wire.arrayT == nil {
+                       return false
+               }
+               array := wire.arrayT
+               return t.Len() == array.Len && dec.compatibleType(t.Elem(), array.Elem)
+       case *reflect.MapType:
+               wire, ok := dec.wireType[fw]
+               if !ok || wire.mapT == nil {
+                       return false
+               }
+               mapType := wire.mapT
+               return dec.compatibleType(t.Key(), mapType.Key) && dec.compatibleType(t.Elem(), mapType.Elem)
+       case *reflect.SliceType:
+               // Is it an array of bytes?
+               if t.Elem().Kind() == reflect.Uint8 {
+                       return fw == tBytes
+               }
+               // Extract and compare element types.
+               var sw *sliceType
+               if tt, ok := builtinIdToType[fw]; ok {
+                       sw = tt.(*sliceType)
+               } else {
+                       sw = dec.wireType[fw].sliceT
+               }
+               elem, _ := indirect(t.Elem())
+               return sw != nil && dec.compatibleType(elem, sw.Elem)
+       case *reflect.StructType:
+               return true
+       }
+       return true
+}
+
+func (dec *Decoder) compileSingle(remoteId typeId, rt reflect.Type) (engine *decEngine, err os.Error) {
+       engine = new(decEngine)
+       engine.instr = make([]decInstr, 1) // one item
+       name := rt.String()                // best we can do
+       if !dec.compatibleType(rt, remoteId) {
+               return nil, os.ErrorString("gob: wrong type received for local value " + name)
+       }
+       op, indir := dec.decOpFor(remoteId, rt, name)
+       ovfl := os.ErrorString(`value for "` + name + `" out of range`)
+       engine.instr[singletonField] = decInstr{op, singletonField, indir, 0, ovfl}
+       engine.numInstr = 1
+       return
+}
+
+func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEngine, err os.Error) {
+       defer catchError(&err)
+       srt, ok := rt.(*reflect.StructType)
+       if !ok {
+               return dec.compileSingle(remoteId, rt)
+       }
+       var wireStruct *structType
+       // Builtin types can come from global pool; the rest must be defined by the decoder.
+       // Also we know we're decoding a struct now, so the client must have sent one.
+       if t, ok := builtinIdToType[remoteId]; ok {
+               wireStruct, _ = t.(*structType)
+       } else {
+               wireStruct = dec.wireType[remoteId].structT
+       }
+       if wireStruct == nil {
+               errorf("gob: type mismatch in decoder: want struct type %s; got non-struct", rt.String())
+       }
+       engine = new(decEngine)
+       engine.instr = make([]decInstr, len(wireStruct.field))
+       // Loop over the fields of the wire type.
+       for fieldnum := 0; fieldnum < len(wireStruct.field); fieldnum++ {
+               wireField := wireStruct.field[fieldnum]
+               // Find the field of the local type with the same name.
+               localField, present := srt.FieldByName(wireField.name)
+               ovfl := overflow(wireField.name)
+               // TODO(r): anonymous names
+               if !present {
+                       op := dec.decIgnoreOpFor(wireField.id)
+                       engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl}
+                       continue
+               }
+               if !dec.compatibleType(localField.Type, wireField.id) {
+                       errorf("gob: wrong type (%s) for received field %s.%s", localField.Type, wireStruct.name, wireField.name)
+               }
+               op, indir := dec.decOpFor(wireField.id, localField.Type, localField.Name)
+               engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(localField.Offset), ovfl}
+               engine.numInstr++
+       }
+       return
+}
+
+func (dec *Decoder) getDecEnginePtr(remoteId typeId, rt reflect.Type) (enginePtr **decEngine, err os.Error) {
+       decoderMap, ok := dec.decoderCache[rt]
+       if !ok {
+               decoderMap = make(map[typeId]**decEngine)
+               dec.decoderCache[rt] = decoderMap
+       }
+       if enginePtr, ok = decoderMap[remoteId]; !ok {
+               // To handle recursive types, mark this engine as underway before compiling.
+               enginePtr = new(*decEngine)
+               decoderMap[remoteId] = enginePtr
+               *enginePtr, err = dec.compileDec(remoteId, rt)
+               if err != nil {
+                       decoderMap[remoteId] = nil, false
+               }
+       }
+       return
+}
+
+// When ignoring struct data, in effect we compile it into this type
+type emptyStruct struct{}
+
+var emptyStructType = reflect.Typeof(emptyStruct{})
+
+func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error) {
+       var ok bool
+       if enginePtr, ok = dec.ignorerCache[wireId]; !ok {
+               // To handle recursive types, mark this engine as underway before compiling.
+               enginePtr = new(*decEngine)
+               dec.ignorerCache[wireId] = enginePtr
+               *enginePtr, err = dec.compileDec(wireId, emptyStructType)
+               if err != nil {
+                       dec.ignorerCache[wireId] = nil, false
+               }
+       }
+       return
+}
+
+func (dec *Decoder) decode(wireId typeId, val reflect.Value) os.Error {
+       // Dereference down to the underlying struct type.
+       rt, indir := indirect(val.Type())
+       enginePtr, err := dec.getDecEnginePtr(wireId, rt)
+       if err != nil {
+               return err
+       }
+       engine := *enginePtr
+       if st, ok := rt.(*reflect.StructType); ok {
+               if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].structT.field) > 0 {
+                       name := rt.Name()
+                       return os.ErrorString("gob: type mismatch: no fields matched compiling decoder for " + name)
+               }
+               return dec.decodeStruct(engine, st, dec.state.b, uintptr(val.Addr()), indir)
+       }
+       return dec.decodeSingle(engine, rt, dec.state.b, uintptr(val.Addr()), indir)
+}
+
+func init() {
+       var fop, cop decOp
+       switch reflect.Typeof(float(0)).Bits() {
+       case 32:
+               fop = decFloat32
+               cop = decComplex64
+       case 64:
+               fop = decFloat64
+               cop = decComplex128
+       default:
+               panic("gob: unknown size of float")
+       }
+       decOpMap[reflect.Float] = fop
+       decOpMap[reflect.Complex] = cop
+
+       var iop, uop decOp
+       switch reflect.Typeof(int(0)).Bits() {
+       case 32:
+               iop = decInt32
+               uop = decUint32
+       case 64:
+               iop = decInt64
+               uop = decUint64
+       default:
+               panic("gob: unknown size of int/uint")
+       }
+       decOpMap[reflect.Int] = iop
+       decOpMap[reflect.Uint] = uop
+
+       // Finally uintptr
+       switch reflect.Typeof(uintptr(0)).Bits() {
+       case 32:
+               uop = decUint32
+       case 64:
+               uop = decUint64
+       default:
+               panic("gob: unknown size of uintptr")
+       }
+       decOpMap[reflect.Uintptr] = uop
+}
diff --git a/libgo/go/gob/decoder.go b/libgo/go/gob/decoder.go
new file mode 100644 (file)
index 0000000..af3e78a
--- /dev/null
@@ -0,0 +1,164 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "reflect"
+       "sync"
+)
+
+// A Decoder manages the receipt of type and data information read from the
+// remote side of a connection.
+type Decoder struct {
+       mutex        sync.Mutex                              // each item must be received atomically
+       r            io.Reader                               // source of the data
+       wireType     map[typeId]*wireType                    // map from remote ID to local description
+       decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
+       ignorerCache map[typeId]**decEngine                  // ditto for ignored objects
+       state        *decodeState                            // reads data from in-memory buffer
+       countState   *decodeState                            // reads counts from wire
+       buf          []byte
+       countBuf     [9]byte // counts may be uint64s (unlikely!), require 9 bytes
+       byteBuffer   *bytes.Buffer
+       err          os.Error
+}
+
+// NewDecoder returns a new decoder that reads from the io.Reader.
+func NewDecoder(r io.Reader) *Decoder {
+       dec := new(Decoder)
+       dec.r = r
+       dec.wireType = make(map[typeId]*wireType)
+       dec.state = newDecodeState(dec, &dec.byteBuffer) // buffer set in Decode()
+       dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
+       dec.ignorerCache = make(map[typeId]**decEngine)
+
+       return dec
+}
+
+// recvType loads the definition of a type and reloads the Decoder's buffer.
+func (dec *Decoder) recvType(id typeId) {
+       // Have we already seen this type?  That's an error
+       if dec.wireType[id] != nil {
+               dec.err = os.ErrorString("gob: duplicate type received")
+               return
+       }
+
+       // Type:
+       wire := new(wireType)
+       dec.err = dec.decode(tWireType, reflect.NewValue(wire))
+       if dec.err != nil {
+               return
+       }
+       // Remember we've seen this type.
+       dec.wireType[id] = wire
+
+       // Load the next parcel.
+       dec.recv()
+}
+
+// Decode reads the next value from the connection and stores
+// it in the data represented by the empty interface value.
+// The value underlying e must be the correct type for the next
+// data item received, and must be a pointer.
+func (dec *Decoder) Decode(e interface{}) os.Error {
+       value := reflect.NewValue(e)
+       // If e represents a value as opposed to a pointer, the answer won't
+       // get back to the caller.  Make sure it's a pointer.
+       if value.Type().Kind() != reflect.Ptr {
+               dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+               return dec.err
+       }
+       return dec.DecodeValue(value)
+}
+
+// recv reads the next count-delimited item from the input. It is the converse
+// of Encoder.send.
+func (dec *Decoder) recv() {
+       // Read a count.
+       var nbytes uint64
+       nbytes, dec.err = decodeUintReader(dec.r, dec.countBuf[0:])
+       if dec.err != nil {
+               return
+       }
+       // Allocate the buffer.
+       if nbytes > uint64(len(dec.buf)) {
+               dec.buf = make([]byte, nbytes+1000)
+       }
+       dec.byteBuffer = bytes.NewBuffer(dec.buf[0:nbytes])
+
+       // Read the data
+       _, dec.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
+       if dec.err != nil {
+               if dec.err == os.EOF {
+                       dec.err = io.ErrUnexpectedEOF
+               }
+               return
+       }
+}
+
+// decodeValueFromBuffer grabs the next value from the input. The Decoder's
+// buffer already contains data.  If the next item in the buffer is a type
+// descriptor, it may be necessary to reload the buffer, but recvType does that.
+func (dec *Decoder) decodeValueFromBuffer(value reflect.Value, ignoreInterfaceValue, countPresent bool) {
+       for dec.state.b.Len() > 0 {
+               // Receive a type id.
+               id := typeId(decodeInt(dec.state))
+
+               // Is it a new type?
+               if id < 0 { // 0 is the error state, handled above
+                       // If the id is negative, we have a type.
+                       dec.recvType(-id)
+                       if dec.err != nil {
+                               break
+                       }
+                       continue
+               }
+
+               // Make sure the type has been defined already or is a builtin type (for
+               // top-level singleton values).
+               if dec.wireType[id] == nil && builtinIdToType[id] == nil {
+                       dec.err = errBadType
+                       break
+               }
+               // An interface value is preceded by a byte count.
+               if countPresent {
+                       count := int(decodeUint(dec.state))
+                       if ignoreInterfaceValue {
+                               // An interface value is preceded by a byte count. Just skip that many bytes.
+                               dec.state.b.Next(int(count))
+                               break
+                       }
+                       // Otherwise fall through and decode it.
+               }
+               dec.err = dec.decode(id, value)
+               break
+       }
+}
+
+// DecodeValue reads the next value from the connection and stores
+// it in the data represented by the reflection value.
+// The value must be the correct type for the next
+// data item received.
+func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
+       // Make sure we're single-threaded through here.
+       dec.mutex.Lock()
+       defer dec.mutex.Unlock()
+
+       dec.err = nil
+       dec.recv()
+       if dec.err != nil {
+               return dec.err
+       }
+       dec.decodeValueFromBuffer(value, false, false)
+       return dec.err
+}
+
+// If debug.go is compiled into the program , debugFunc prints a human-readable
+// representation of the gob data read from r by calling that file's Debug function.
+// Otherwise it is nil.
+var debugFunc func(io.Reader)
diff --git a/libgo/go/gob/doc.go b/libgo/go/gob/doc.go
new file mode 100644 (file)
index 0000000..2e7232d
--- /dev/null
@@ -0,0 +1,299 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The gob package manages streams of gobs - binary values exchanged between an
+Encoder (transmitter) and a Decoder (receiver).  A typical use is transporting
+arguments and results of remote procedure calls (RPCs) such as those provided by
+package "rpc".
+
+A stream of gobs is self-describing.  Each data item in the stream is preceded by
+a specification of its type, expressed in terms of a small set of predefined
+types.  Pointers are not transmitted, but the things they point to are
+transmitted; that is, the values are flattened.  Recursive types work fine, but
+recursive values (data with cycles) are problematic.  This may change.
+
+To use gobs, create an Encoder and present it with a series of data items as
+values or addresses that can be dereferenced to values.  The Encoder makes sure
+all type information is sent before it is needed.  At the receive side, a
+Decoder retrieves values from the encoded stream and unpacks them into local
+variables.
+
+The source and destination values/types need not correspond exactly.  For structs,
+fields (identified by name) that are in the source but absent from the receiving
+variable will be ignored.  Fields that are in the receiving variable but missing
+from the transmitted type or value will be ignored in the destination.  If a field
+with the same name is present in both, their types must be compatible. Both the
+receiver and transmitter will do all necessary indirection and dereferencing to
+convert between gobs and actual Go values.  For instance, a gob type that is
+schematically,
+
+       struct { a, b int }
+
+can be sent from or received into any of these Go types:
+
+       struct { a, b int }     // the same
+       *struct { a, b int }    // extra indirection of the struct
+       struct { *a, **b int }  // extra indirection of the fields
+       struct { a, b int64 }   // different concrete value type; see below
+
+It may also be received into any of these:
+
+       struct { a, b int }     // the same
+       struct { b, a int }     // ordering doesn't matter; matching is by name
+       struct { a, b, c int }  // extra field (c) ignored
+       struct { b int }        // missing field (a) ignored; data will be dropped
+       struct { b, c int }     // missing field (a) ignored; extra field (c) ignored.
+
+Attempting to receive into these types will draw a decode error:
+
+       struct { a int; b uint }        // change of signedness for b
+       struct { a int; b float }       // change of type for b
+       struct { }                      // no field names in common
+       struct { c, d int }             // no field names in common
+
+Integers are transmitted two ways: arbitrary precision signed integers or
+arbitrary precision unsigned integers.  There is no int8, int16 etc.
+discrimination in the gob format; there are only signed and unsigned integers.  As
+described below, the transmitter sends the value in a variable-length encoding;
+the receiver accepts the value and stores it in the destination variable.
+Floating-point numbers are always sent using IEEE-754 64-bit precision (see
+below).
+
+Signed integers may be received into any signed integer variable: int, int16, etc.;
+unsigned integers may be received into any unsigned integer variable; and floating
+point values may be received into any floating point variable.  However,
+the destination variable must be able to represent the value or the decode
+operation will fail.
+
+Structs, arrays and slices are also supported.  Strings and arrays of bytes are
+supported with a special, efficient representation (see below).
+
+Interfaces, functions, and channels cannot be sent in a gob.  Attempting
+to encode a value that contains one will fail.
+
+The rest of this comment documents the encoding, details that are not important
+for most users.  Details are presented bottom-up.
+
+An unsigned integer is sent one of two ways.  If it is less than 128, it is sent
+as a byte with that value.  Otherwise it is sent as a minimal-length big-endian
+(high byte first) byte stream holding the value, preceded by one byte holding the
+byte count, negated.  Thus 0 is transmitted as (00), 7 is transmitted as (07) and
+256 is transmitted as (FE 01 00).
+
+A boolean is encoded within an unsigned integer: 0 for false, 1 for true.
+
+A signed integer, i, is encoded within an unsigned integer, u.  Within u, bits 1
+upward contain the value; bit 0 says whether they should be complemented upon
+receipt.  The encode algorithm looks like this:
+
+       uint u;
+       if i < 0 {
+               u = (^i << 1) | 1       // complement i, bit 0 is 1
+       } else {
+               u = (i << 1)    // do not complement i, bit 0 is 0
+       }
+       encodeUnsigned(u)
+
+The low bit is therefore analogous to a sign bit, but making it the complement bit
+instead guarantees that the largest negative integer is not a special case.  For
+example, -129=^128=(^256>>1) encodes as (FE 01 01).
+
+Floating-point numbers are always sent as a representation of a float64 value.
+That value is converted to a uint64 using math.Float64bits.  The uint64 is then
+byte-reversed and sent as a regular unsigned integer.  The byte-reversal means the
+exponent and high-precision part of the mantissa go first.  Since the low bits are
+often zero, this can save encoding bytes.  For instance, 17.0 is encoded in only
+three bytes (FE 31 40).
+
+Strings and slices of bytes are sent as an unsigned count followed by that many
+uninterpreted bytes of the value.
+
+All other slices and arrays are sent as an unsigned count followed by that many
+elements using the standard gob encoding for their type, recursively.
+
+Structs are sent as a sequence of (field number, field value) pairs.  The field
+value is sent using the standard gob encoding for its type, recursively.  If a
+field has the zero value for its type, it is omitted from the transmission.  The
+field number is defined by the type of the encoded struct: the first field of the
+encoded type is field 0, the second is field 1, etc.  When encoding a value, the
+field numbers are delta encoded for efficiency and the fields are always sent in
+order of increasing field number; the deltas are therefore unsigned.  The
+initialization for the delta encoding sets the field number to -1, so an unsigned
+integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
+= 7 or (01 07).  Finally, after all the fields have been sent a terminating mark
+denotes the end of the struct.  That mark is a delta=0 value, which has
+representation (00).
+
+Interface types are not checked for compatibility; all interface types are
+treated, for transmission, as members of a single "interface" type, analogous to
+int or []byte - in effect they're all treated as interface{}.  Interface values
+are transmitted as a string identifying the concrete type being sent (a name
+that must be pre-defined by calling Register), followed by a byte count of the
+length of the following data (so the value can be skipped if it cannot be
+stored), followed by the usual encoding of concrete (dynamic) value stored in
+the interface value.  (A nil interface value is identified by the empty string
+and transmits no value.) Upon receipt, the decoder verifies that the unpacked
+concrete item satisfies the interface of the receiving variable.
+
+The representation of types is described below.  When a type is defined on a given
+connection between an Encoder and Decoder, it is assigned a signed integer type
+id.  When Encoder.Encode(v) is called, it makes sure there is an id assigned for
+the type of v and all its elements and then it sends the pair (typeid, encoded-v)
+where typeid is the type id of the encoded type of v and encoded-v is the gob
+encoding of the value v.
+
+To define a type, the encoder chooses an unused, positive type id and sends the
+pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType
+description, constructed from these types:
+
+       type wireType struct {
+               s structType
+       }
+       type arrayType struct {
+               commonType
+               Elem typeId
+               Len  int
+       }
+       type commonType {
+               name string // the name of the struct type
+               _id  int    // the id of the type, repeated for so it's inside the type
+       }
+       type sliceType struct {
+               commonType
+               Elem typeId
+       }
+       type structType struct {
+               commonType
+               field []*fieldType // the fields of the struct.
+       }
+       type fieldType struct {
+               name string // the name of the field.
+               id   int    // the type id of the field, which must be already defined
+       }
+       type mapType struct {
+               commonType
+               Key  typeId
+               Elem typeId
+       }
+
+If there are nested type ids, the types for all inner type ids must be defined
+before the top-level type id is used to describe an encoded-v.
+
+For simplicity in setup, the connection is defined to understand these types a
+priori, as well as the basic gob types int, uint, etc.  Their ids are:
+
+       bool        1
+       int         2
+       uint        3
+       float       4
+       []byte      5
+       string      6
+       complex     7
+       interface   8
+       // gap for reserved ids.
+       wireType    16
+       arrayType   17
+       commonType  18
+       sliceType   19
+       structType  20
+       fieldType   21
+       // 22 is slice of fieldType.
+       mapType     23
+
+In summary, a gob stream looks like
+
+       ((-type id, encoding of a wireType)* (type id, encoding of a value))*
+
+where * signifies zero or more repetitions and the type id of a value must
+be predefined or be defined before the value in the stream.
+*/
+package gob
+
+/*
+For implementers and the curious, here is an encoded example.  Given
+       type Point struct {x, y int}
+and the value
+       p := Point{22, 33}
+the bytes transmitted that encode p will be:
+       1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00
+       01 02 01 01 78 01 04 00 01 01 79 01 04 00 00 00
+       07 ff 82 01 2c 01 42 00
+They are determined as follows.
+
+Since this is the first transmission of type Point, the type descriptor
+for Point itself must be sent before the value.  This is the first type
+we've sent on this Encoder, so it has type id 65 (0 through 64 are
+reserved).
+
+       1f      // This item (a type descriptor) is 31 bytes long.
+       ff 81   // The negative of the id for the type we're defining, -65.
+               // This is one byte (indicated by FF = -1) followed by
+               // ^-65<<1 | 1.  The low 1 bit signals to complement the
+               // rest upon receipt.
+
+       // Now we send a type descriptor, which is itself a struct (wireType).
+       // The type of wireType itself is known (it's built in, as is the type of
+       // all its components), so we just need to send a *value* of type wireType
+       // that represents type "Point".
+       // Here starts the encoding of that value.
+       // Set the field number implicitly to -1; this is done at the beginning
+       // of every struct, including nested structs.
+       03      // Add 3 to field number; now 2 (wireType.structType; this is a struct).
+               // structType starts with an embedded commonType, which appears
+               // as a regular structure here too.
+       01      // add 1 to field number (now 0); start of embedded commonType.
+       01      // add 1 to field number (now 0, the name of the type)
+       05      // string is (unsigned) 5 bytes long
+       50 6f 69 6e 74  // wireType.structType.commonType.name = "Point"
+       01      // add 1 to field number (now 1, the id of the type)
+       ff 82   // wireType.structType.commonType._id = 65
+       00      // end of embedded wiretype.structType.commonType struct
+       01      // add 1 to field number (now 1, the field array in wireType.structType)
+       02      // There are two fields in the type (len(structType.field))
+       01      // Start of first field structure; add 1 to get field number 0: field[0].name
+       01      // 1 byte
+       78      // structType.field[0].name = "x"
+       01      // Add 1 to get field number 1: field[0].id
+       04      // structType.field[0].typeId is 2 (signed int).
+       00      // End of structType.field[0]; start structType.field[1]; set field number to -1.
+       01      // Add 1 to get field number 0: field[1].name
+       01      // 1 byte
+       79      // structType.field[1].name = "y"
+       01      // Add 1 to get field number 1: field[0].id
+       04      // struct.Type.field[1].typeId is 2 (signed int).
+       00      // End of structType.field[1]; end of structType.field.
+       00      // end of wireType.structType structure
+       00      // end of wireType structure
+
+Now we can send the Point value.  Again the field number resets to -1:
+
+       07      // this value is 7 bytes long
+       ff 82   // the type number, 65 (1 byte (-FF) followed by 65<<1)
+       01      // add one to field number, yielding field 0
+       2c      // encoding of signed "22" (0x22 = 44 = 22<<1); Point.x = 22
+       01      // add one to field number, yielding field 1
+       42      // encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33
+       00      // end of structure
+
+The type encoding is long and fairly intricate but we send it only once.
+If p is transmitted a second time, the type is already known so the
+output will be just:
+
+       07 ff 82 01 2c 01 42 00
+
+A single non-struct value at top level is transmitted like a field with
+delta tag 0.  For instance, a signed integer with value 3 presented as
+the argument to Encode will emit:
+
+       03 04 00 06
+
+Which represents:
+
+       03      // this value is 3 bytes long
+       04      // the type number, 2, represents an integer
+       00      // tag delta 0
+       06      // value 3
+
+*/
diff --git a/libgo/go/gob/encode.go b/libgo/go/gob/encode.go
new file mode 100644 (file)
index 0000000..7393866
--- /dev/null
@@ -0,0 +1,589 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+       "bytes"
+       "io"
+       "math"
+       "os"
+       "reflect"
+       "unsafe"
+)
+
+const uint64Size = unsafe.Sizeof(uint64(0))
+
+// The global execution state of an instance of the encoder.
+// Field numbers are delta encoded and always increase. The field
+// number is initialized to -1 so 0 comes out as delta(1). A delta of
+// 0 terminates the structure.
+type encoderState struct {
+       enc      *Encoder
+       b        *bytes.Buffer
+       sendZero bool                 // encoding an array element or map key/value pair; send zero values
+       fieldnum int                  // the last field number written.
+       buf      [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
+}
+
+func newEncoderState(enc *Encoder, b *bytes.Buffer) *encoderState {
+       return &encoderState{enc: enc, b: b}
+}
+
+// Unsigned integers have a two-state encoding.  If the number is less
+// than 128 (0 through 0x7F), its value is written directly.
+// Otherwise the value is written in big-endian byte order preceded
+// by the byte length, negated.
+
+// encodeUint writes an encoded unsigned integer to state.b.
+func encodeUint(state *encoderState, x uint64) {
+       if x <= 0x7F {
+               err := state.b.WriteByte(uint8(x))
+               if err != nil {
+                       error(err)
+               }
+               return
+       }
+       var n, m int
+       m = uint64Size
+       for n = 1; x > 0; n++ {
+               state.buf[m] = uint8(x & 0xFF)
+               x >>= 8
+               m--
+       }
+       state.buf[m] = uint8(-(n - 1))
+       n, err := state.b.Write(state.buf[m : uint64Size+1])
+       if err != nil {
+               error(err)
+       }
+}
+
+// encodeInt writes an encoded signed integer to state.w.
+// The low bit of the encoding says whether to bit complement the (other bits of the)
+// uint to recover the int.
+func encodeInt(state *encoderState, i int64) {
+       var x uint64
+       if i < 0 {
+               x = uint64(^i<<1) | 1
+       } else {
+               x = uint64(i << 1)
+       }
+       encodeUint(state, uint64(x))
+}
+
+type encOp func(i *encInstr, state *encoderState, p unsafe.Pointer)
+
+// The 'instructions' of the encoding machine
+type encInstr struct {
+       op     encOp
+       field  int     // field number
+       indir  int     // how many pointer indirections to reach the value in the struct
+       offset uintptr // offset in the structure of the field to encode
+}
+
+// Emit a field number and update the state to record its value for delta encoding.
+// If the instruction pointer is nil, do nothing
+func (state *encoderState) update(instr *encInstr) {
+       if instr != nil {
+               encodeUint(state, uint64(instr.field-state.fieldnum))
+               state.fieldnum = instr.field
+       }
+}
+
+// Each encoder is responsible for handling any indirections associated
+// with the data structure.  If any pointer so reached is nil, no bytes are written.
+// If the data item is zero, no bytes are written.
+// Otherwise, the output (for a scalar) is the field number, as an encoded integer,
+// followed by the field data in its appropriate format.
+
+func encIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
+       for ; indir > 0; indir-- {
+               p = *(*unsafe.Pointer)(p)
+               if p == nil {
+                       return unsafe.Pointer(nil)
+               }
+       }
+       return p
+}
+
+func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       b := *(*bool)(p)
+       if b || state.sendZero {
+               state.update(i)
+               if b {
+                       encodeUint(state, 1)
+               } else {
+                       encodeUint(state, 0)
+               }
+       }
+}
+
+func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := int64(*(*int)(p))
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeInt(state, v)
+       }
+}
+
+func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := uint64(*(*uint)(p))
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeUint(state, v)
+       }
+}
+
+func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := int64(*(*int8)(p))
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeInt(state, v)
+       }
+}
+
+func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := uint64(*(*uint8)(p))
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeUint(state, v)
+       }
+}
+
+func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := int64(*(*int16)(p))
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeInt(state, v)
+       }
+}
+
+func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := uint64(*(*uint16)(p))
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeUint(state, v)
+       }
+}
+
+func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := int64(*(*int32)(p))
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeInt(state, v)
+       }
+}
+
+func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := uint64(*(*uint32)(p))
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeUint(state, v)
+       }
+}
+
+func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := *(*int64)(p)
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeInt(state, v)
+       }
+}
+
+func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := *(*uint64)(p)
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeUint(state, v)
+       }
+}
+
+func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       v := uint64(*(*uintptr)(p))
+       if v != 0 || state.sendZero {
+               state.update(i)
+               encodeUint(state, v)
+       }
+}
+
+// Floating-point numbers are transmitted as uint64s holding the bits
+// of the underlying representation.  They are sent byte-reversed, with
+// the exponent end coming out first, so integer floating point numbers
+// (for example) transmit more compactly.  This routine does the
+// swizzling.
+func floatBits(f float64) uint64 {
+       u := math.Float64bits(f)
+       var v uint64
+       for i := 0; i < 8; i++ {
+               v <<= 8
+               v |= u & 0xFF
+               u >>= 8
+       }
+       return v
+}
+
+func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       f := *(*float)(p)
+       if f != 0 || state.sendZero {
+               v := floatBits(float64(f))
+               state.update(i)
+               encodeUint(state, v)
+       }
+}
+
+func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       f := *(*float32)(p)
+       if f != 0 || state.sendZero {
+               v := floatBits(float64(f))
+               state.update(i)
+               encodeUint(state, v)
+       }
+}
+
+func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       f := *(*float64)(p)
+       if f != 0 || state.sendZero {
+               state.update(i)
+               v := floatBits(f)
+               encodeUint(state, v)
+       }
+}
+
+// Complex numbers are just a pair of floating-point numbers, real part first.
+func encComplex(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       c := *(*complex)(p)
+       if c != 0+0i || state.sendZero {
+               rpart := floatBits(float64(real(c)))
+               ipart := floatBits(float64(imag(c)))
+               state.update(i)
+               encodeUint(state, rpart)
+               encodeUint(state, ipart)
+       }
+}
+
+func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       c := *(*complex64)(p)
+       if c != 0+0i || state.sendZero {
+               rpart := floatBits(float64(real(c)))
+               ipart := floatBits(float64(imag(c)))
+               state.update(i)
+               encodeUint(state, rpart)
+               encodeUint(state, ipart)
+       }
+}
+
+func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       c := *(*complex128)(p)
+       if c != 0+0i || state.sendZero {
+               rpart := floatBits(real(c))
+               ipart := floatBits(imag(c))
+               state.update(i)
+               encodeUint(state, rpart)
+               encodeUint(state, ipart)
+       }
+}
+
+// Byte arrays are encoded as an unsigned count followed by the raw bytes.
+func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       b := *(*[]byte)(p)
+       if len(b) > 0 || state.sendZero {
+               state.update(i)
+               encodeUint(state, uint64(len(b)))
+               state.b.Write(b)
+       }
+}
+
+// Strings are encoded as an unsigned count followed by the raw bytes.
+func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       s := *(*string)(p)
+       if len(s) > 0 || state.sendZero {
+               state.update(i)
+               encodeUint(state, uint64(len(s)))
+               io.WriteString(state.b, s)
+       }
+}
+
+// The end of a struct is marked by a delta field number of 0.
+func encStructTerminator(i *encInstr, state *encoderState, p unsafe.Pointer) {
+       encodeUint(state, 0)
+}
+
+// Execution engine
+
+// The encoder engine is an array of instructions indexed by field number of the encoding
+// data, typically a struct.  It is executed top to bottom, walking the struct.
+type encEngine struct {
+       instr []encInstr
+}
+
+const singletonField = 0
+
+func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+       state := newEncoderState(enc, b)
+       state.fieldnum = singletonField
+       // There is no surrounding struct to frame the transmission, so we must
+       // generate data even if the item is zero.  To do this, set sendZero.
+       state.sendZero = true
+       instr := &engine.instr[singletonField]
+       p := unsafe.Pointer(basep) // offset will be zero
+       if instr.indir > 0 {
+               if p = encIndirect(p, instr.indir); p == nil {
+                       return
+               }
+       }
+       instr.op(instr, state, p)
+}
+
+func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+       state := newEncoderState(enc, b)
+       state.fieldnum = -1
+       for i := 0; i < len(engine.instr); i++ {
+               instr := &engine.instr[i]
+               p := unsafe.Pointer(basep + instr.offset)
+               if instr.indir > 0 {
+                       if p = encIndirect(p, instr.indir); p == nil {
+                               continue
+                       }
+               }
+               instr.op(instr, state, p)
+       }
+}
+
+func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) {
+       state := newEncoderState(enc, b)
+       state.fieldnum = -1
+       state.sendZero = true
+       encodeUint(state, uint64(length))
+       for i := 0; i < length; i++ {
+               elemp := p
+               up := unsafe.Pointer(elemp)
+               if elemIndir > 0 {
+                       if up = encIndirect(up, elemIndir); up == nil {
+                               errorf("gob: encodeArray: nil element")
+                       }
+                       elemp = uintptr(up)
+               }
+               op(nil, state, unsafe.Pointer(elemp))
+               p += uintptr(elemWid)
+       }
+}
+
+func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) {
+       for i := 0; i < indir && v != nil; i++ {
+               v = reflect.Indirect(v)
+       }
+       if v == nil {
+               errorf("gob: encodeReflectValue: nil element")
+       }
+       op(nil, state, unsafe.Pointer(v.Addr()))
+}
+
+func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) {
+       state := newEncoderState(enc, b)
+       state.fieldnum = -1
+       state.sendZero = true
+       keys := mv.Keys()
+       encodeUint(state, uint64(len(keys)))
+       for _, key := range keys {
+               encodeReflectValue(state, key, keyOp, keyIndir)
+               encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir)
+       }
+}
+
+// To send an interface, we send a string identifying the concrete type, followed
+// by the type identifier (which might require defining that type right now), followed
+// by the concrete value.  A nil value gets sent as the empty string for the name,
+// followed by no value.
+func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) {
+       state := newEncoderState(enc, b)
+       state.fieldnum = -1
+       state.sendZero = true
+       if iv.IsNil() {
+               encodeUint(state, 0)
+               return
+       }
+
+       typ, _ := indirect(iv.Elem().Type())
+       name, ok := concreteTypeToName[typ]
+       if !ok {
+               errorf("gob: type not registered for interface: %s", typ)
+       }
+       // Send the name.
+       encodeUint(state, uint64(len(name)))
+       _, err := io.WriteString(state.b, name)
+       if err != nil {
+               error(err)
+       }
+       // Send (and maybe first define) the type id.
+       enc.sendTypeDescriptor(typ)
+       // Encode the value into a new buffer.
+       data := new(bytes.Buffer)
+       err = enc.encode(data, iv.Elem())
+       if err != nil {
+               error(err)
+       }
+       encodeUint(state, uint64(data.Len()))
+       _, err = state.b.Write(data.Bytes())
+       if err != nil {
+               error(err)
+       }
+}
+
+var encOpMap = []encOp{
+       reflect.Bool:       encBool,
+       reflect.Int:        encInt,
+       reflect.Int8:       encInt8,
+       reflect.Int16:      encInt16,
+       reflect.Int32:      encInt32,
+       reflect.Int64:      encInt64,
+       reflect.Uint:       encUint,
+       reflect.Uint8:      encUint8,
+       reflect.Uint16:     encUint16,
+       reflect.Uint32:     encUint32,
+       reflect.Uint64:     encUint64,
+       reflect.Uintptr:    encUintptr,
+       reflect.Float:      encFloat,
+       reflect.Float32:    encFloat32,
+       reflect.Float64:    encFloat64,
+       reflect.Complex:    encComplex,
+       reflect.Complex64:  encComplex64,
+       reflect.Complex128: encComplex128,
+       reflect.String:     encString,
+}
+
+// Return the encoding op for the base type under rt and
+// the indirection count to reach it.
+func (enc *Encoder) encOpFor(rt reflect.Type) (encOp, int) {
+       typ, indir := indirect(rt)
+       var op encOp
+       k := typ.Kind()
+       if int(k) < len(encOpMap) {
+               op = encOpMap[k]
+       }
+       if op == nil {
+               // Special cases
+               switch t := typ.(type) {
+               case *reflect.SliceType:
+                       if t.Elem().Kind() == reflect.Uint8 {
+                               op = encUint8Array
+                               break
+                       }
+                       // Slices have a header; we decode it to find the underlying array.
+                       elemOp, indir := enc.encOpFor(t.Elem())
+                       op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+                               slice := (*reflect.SliceHeader)(p)
+                               if slice.Len == 0 {
+                                       return
+                               }
+                               state.update(i)
+                               state.enc.encodeArray(state.b, slice.Data, elemOp, t.Elem().Size(), indir, int(slice.Len))
+                       }
+               case *reflect.ArrayType:
+                       // True arrays have size in the type.
+                       elemOp, indir := enc.encOpFor(t.Elem())
+                       op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+                               state.update(i)
+                               state.enc.encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len())
+                       }
+               case *reflect.MapType:
+                       keyOp, keyIndir := enc.encOpFor(t.Key())
+                       elemOp, elemIndir := enc.encOpFor(t.Elem())
+                       op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+                               // Maps cannot be accessed by moving addresses around the way
+                               // that slices etc. can.  We must recover a full reflection value for
+                               // the iteration.
+                               v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p))))
+                               mv := reflect.Indirect(v).(*reflect.MapValue)
+                               if mv.Len() == 0 {
+                                       return
+                               }
+                               state.update(i)
+                               state.enc.encodeMap(state.b, mv, keyOp, elemOp, keyIndir, elemIndir)
+                       }
+               case *reflect.StructType:
+                       // Generate a closure that calls out to the engine for the nested type.
+                       enc.getEncEngine(typ)
+                       info := mustGetTypeInfo(typ)
+                       op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+                               state.update(i)
+                               // indirect through info to delay evaluation for recursive structs
+                               state.enc.encodeStruct(state.b, info.encoder, uintptr(p))
+                       }
+               case *reflect.InterfaceType:
+                       op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+                               // Interfaces transmit the name and contents of the concrete
+                               // value they contain.
+                               v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p))))
+                               iv := reflect.Indirect(v).(*reflect.InterfaceValue)
+                               if !state.sendZero && (iv == nil || iv.IsNil()) {
+                                       return
+                               }
+                               state.update(i)
+                               state.enc.encodeInterface(state.b, iv)
+                       }
+               }
+       }
+       if op == nil {
+               errorf("gob enc: can't happen: encode type %s", rt.String())
+       }
+       return op, indir
+}
+
+// The local Type was compiled from the actual value, so we know it's compatible.
+func (enc *Encoder) compileEnc(rt reflect.Type) *encEngine {
+       srt, isStruct := rt.(*reflect.StructType)
+       engine := new(encEngine)
+       if isStruct {
+               engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator
+               for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ {
+                       f := srt.Field(fieldnum)
+                       op, indir := enc.encOpFor(f.Type)
+                       engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)}
+               }
+               engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0}
+       } else {
+               engine.instr = make([]encInstr, 1)
+               op, indir := enc.encOpFor(rt)
+               engine.instr[0] = encInstr{op, singletonField, indir, 0} // offset is zero
+       }
+       return engine
+}
+
+// typeLock must be held (or we're in initialization and guaranteed single-threaded).
+// The reflection type must have all its indirections processed out.
+func (enc *Encoder) getEncEngine(rt reflect.Type) *encEngine {
+       info, err1 := getTypeInfo(rt)
+       if err1 != nil {
+               error(err1)
+       }
+       if info.encoder == nil {
+               // mark this engine as underway before compiling to handle recursive types.
+               info.encoder = new(encEngine)
+               info.encoder = enc.compileEnc(rt)
+       }
+       return info.encoder
+}
+
+// Put this in a function so we can hold the lock only while compiling, not when encoding.
+func (enc *Encoder) lockAndGetEncEngine(rt reflect.Type) *encEngine {
+       typeLock.Lock()
+       defer typeLock.Unlock()
+       return enc.getEncEngine(rt)
+}
+
+func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value) (err os.Error) {
+       defer catchError(&err)
+       // Dereference down to the underlying object.
+       rt, indir := indirect(value.Type())
+       for i := 0; i < indir; i++ {
+               value = reflect.Indirect(value)
+       }
+       engine := enc.lockAndGetEncEngine(rt)
+       if value.Type().Kind() == reflect.Struct {
+               enc.encodeStruct(b, engine, value.Addr())
+       } else {
+               enc.encodeSingle(b, engine, value.Addr())
+       }
+       return nil
+}
diff --git a/libgo/go/gob/encoder.go b/libgo/go/gob/encoder.go
new file mode 100644 (file)
index 0000000..340a602
--- /dev/null
@@ -0,0 +1,207 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "reflect"
+       "sync"
+)
+
+// An Encoder manages the transmission of type and data information to the
+// other side of a connection.
+type Encoder struct {
+       mutex      sync.Mutex              // each item must be sent atomically
+       w          io.Writer               // where to send the data
+       sent       map[reflect.Type]typeId // which types we've already sent
+       state      *encoderState           // so we can encode integers, strings directly
+       countState *encoderState           // stage for writing counts
+       buf        []byte                  // for collecting the output.
+       err        os.Error
+}
+
+// NewEncoder returns a new encoder that will transmit on the io.Writer.
+func NewEncoder(w io.Writer) *Encoder {
+       enc := new(Encoder)
+       enc.w = w
+       enc.sent = make(map[reflect.Type]typeId)
+       enc.state = newEncoderState(enc, new(bytes.Buffer))
+       enc.countState = newEncoderState(enc, new(bytes.Buffer))
+       return enc
+}
+
+func (enc *Encoder) badType(rt reflect.Type) {
+       enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
+}
+
+func (enc *Encoder) setError(err os.Error) {
+       if enc.err == nil { // remember the first.
+               enc.err = err
+       }
+       enc.state.b.Reset()
+}
+
+// Send the data item preceded by a unsigned count of its length.
+func (enc *Encoder) send() {
+       // Encode the length.
+       encodeUint(enc.countState, uint64(enc.state.b.Len()))
+       // Build the buffer.
+       countLen := enc.countState.b.Len()
+       total := countLen + enc.state.b.Len()
+       if total > len(enc.buf) {
+               enc.buf = make([]byte, total+1000) // extra for growth
+       }
+       // Place the length before the data.
+       // TODO(r): avoid the extra copy here.
+       enc.countState.b.Read(enc.buf[0:countLen])
+       // Now the data.
+       enc.state.b.Read(enc.buf[countLen:total])
+       // Write the data.
+       _, err := enc.w.Write(enc.buf[0:total])
+       if err != nil {
+               enc.setError(err)
+       }
+}
+
+func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
+       // Drill down to the base type.
+       rt, _ := indirect(origt)
+
+       switch rt := rt.(type) {
+       default:
+               // Basic types and interfaces do not need to be described.
+               return
+       case *reflect.SliceType:
+               // If it's []uint8, don't send; it's considered basic.
+               if rt.Elem().Kind() == reflect.Uint8 {
+                       return
+               }
+               // Otherwise we do send.
+               break
+       case *reflect.ArrayType:
+               // arrays must be sent so we know their lengths and element types.
+               break
+       case *reflect.MapType:
+               // maps must be sent so we know their lengths and key/value types.
+               break
+       case *reflect.StructType:
+               // structs must be sent so we know their fields.
+               break
+       case *reflect.ChanType, *reflect.FuncType:
+               // Probably a bad field in a struct.
+               enc.badType(rt)
+               return
+       }
+
+       // Have we already sent this type?  This time we ask about the base type.
+       if _, alreadySent := enc.sent[rt]; alreadySent {
+               return
+       }
+
+       // Need to send it.
+       typeLock.Lock()
+       info, err := getTypeInfo(rt)
+       typeLock.Unlock()
+       if err != nil {
+               enc.setError(err)
+               return
+       }
+       // Send the pair (-id, type)
+       // Id:
+       encodeInt(enc.state, -int64(info.id))
+       // Type:
+       enc.encode(enc.state.b, reflect.NewValue(info.wire))
+       enc.send()
+       if enc.err != nil {
+               return
+       }
+
+       // Remember we've sent this type.
+       enc.sent[rt] = info.id
+       // Remember we've sent the top-level, possibly indirect type too.
+       enc.sent[origt] = info.id
+       // Now send the inner types
+       switch st := rt.(type) {
+       case *reflect.StructType:
+               for i := 0; i < st.NumField(); i++ {
+                       enc.sendType(st.Field(i).Type)
+               }
+       case reflect.ArrayOrSliceType:
+               enc.sendType(st.Elem())
+       }
+       return true
+}
+
+// Encode transmits the data item represented by the empty interface value,
+// guaranteeing that all necessary type information has been transmitted first.
+func (enc *Encoder) Encode(e interface{}) os.Error {
+       return enc.EncodeValue(reflect.NewValue(e))
+}
+
+// sendTypeId makes sure the remote side knows about this type.
+// It will send a descriptor if this is the first time the type has been
+// sent.  Regardless, it sends the id.
+func (enc *Encoder) sendTypeDescriptor(rt reflect.Type) {
+       // Make sure the type is known to the other side.
+       // First, have we already sent this type?
+       if _, alreadySent := enc.sent[rt]; !alreadySent {
+               // No, so send it.
+               sent := enc.sendType(rt)
+               if enc.err != nil {
+                       return
+               }
+               // If the type info has still not been transmitted, it means we have
+               // a singleton basic type (int, []byte etc.) at top level.  We don't
+               // need to send the type info but we do need to update enc.sent.
+               if !sent {
+                       typeLock.Lock()
+                       info, err := getTypeInfo(rt)
+                       typeLock.Unlock()
+                       if err != nil {
+                               enc.setError(err)
+                               return
+                       }
+                       enc.sent[rt] = info.id
+               }
+       }
+
+       // Identify the type of this top-level value.
+       encodeInt(enc.state, int64(enc.sent[rt]))
+}
+
+// EncodeValue transmits the data item represented by the reflection value,
+// guaranteeing that all necessary type information has been transmitted first.
+func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
+       // Make sure we're single-threaded through here, so multiple
+       // goroutines can share an encoder.
+       enc.mutex.Lock()
+       defer enc.mutex.Unlock()
+
+       enc.err = nil
+       rt, _ := indirect(value.Type())
+
+       // Sanity check only: encoder should never come in with data present.
+       if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
+               enc.err = os.ErrorString("encoder: buffer not empty")
+               return enc.err
+       }
+
+       enc.sendTypeDescriptor(rt)
+       if enc.err != nil {
+               return enc.err
+       }
+
+       // Encode the object.
+       err := enc.encode(enc.state.b, value)
+       if err != nil {
+               enc.setError(err)
+       } else {
+               enc.send()
+       }
+
+       return enc.err
+}
diff --git a/libgo/go/gob/encoder_test.go b/libgo/go/gob/encoder_test.go
new file mode 100644 (file)
index 0000000..91d85bb
--- /dev/null
@@ -0,0 +1,356 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "reflect"
+       "strings"
+       "testing"
+)
+
+type ET2 struct {
+       x string
+}
+
+type ET1 struct {
+       a    int
+       et2  *ET2
+       next *ET1
+}
+
+// Like ET1 but with a different name for a field
+type ET3 struct {
+       a             int
+       et2           *ET2
+       differentNext *ET1
+}
+
+// Like ET1 but with a different type for a field
+type ET4 struct {
+       a    int
+       et2  float
+       next int
+}
+
+func TestEncoderDecoder(t *testing.T) {
+       b := new(bytes.Buffer)
+       enc := NewEncoder(b)
+       et1 := new(ET1)
+       et1.a = 7
+       et1.et2 = new(ET2)
+       err := enc.Encode(et1)
+       if err != nil {
+               t.Error("encoder fail:", err)
+       }
+       dec := NewDecoder(b)
+       newEt1 := new(ET1)
+       err = dec.Decode(newEt1)
+       if err != nil {
+               t.Fatal("error decoding ET1:", err)
+       }
+
+       if !reflect.DeepEqual(et1, newEt1) {
+               t.Fatalf("invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
+       }
+       if b.Len() != 0 {
+               t.Error("not at eof;", b.Len(), "bytes left")
+       }
+
+       enc.Encode(et1)
+       newEt1 = new(ET1)
+       err = dec.Decode(newEt1)
+       if err != nil {
+               t.Fatal("round 2: error decoding ET1:", err)
+       }
+       if !reflect.DeepEqual(et1, newEt1) {
+               t.Fatalf("round 2: invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
+       }
+       if b.Len() != 0 {
+               t.Error("round 2: not at eof;", b.Len(), "bytes left")
+       }
+
+       // Now test with a running encoder/decoder pair that we recognize a type mismatch.
+       err = enc.Encode(et1)
+       if err != nil {
+               t.Error("round 3: encoder fail:", err)
+       }
+       newEt2 := new(ET2)
+       err = dec.Decode(newEt2)
+       if err == nil {
+               t.Fatal("round 3: expected `bad type' error decoding ET2")
+       }
+}
+
+// Run one value through the encoder/decoder, but use the wrong type.
+// Input is always an ET1; we compare it to whatever is under 'e'.
+func badTypeCheck(e interface{}, shouldFail bool, msg string, t *testing.T) {
+       b := new(bytes.Buffer)
+       enc := NewEncoder(b)
+       et1 := new(ET1)
+       et1.a = 7
+       et1.et2 = new(ET2)
+       err := enc.Encode(et1)
+       if err != nil {
+               t.Error("encoder fail:", err)
+       }
+       dec := NewDecoder(b)
+       err = dec.Decode(e)
+       if shouldFail && err == nil {
+               t.Error("expected error for", msg)
+       }
+       if !shouldFail && err != nil {
+               t.Error("unexpected error for", msg, err)
+       }
+}
+
+// Test that we recognize a bad type the first time.
+func TestWrongTypeDecoder(t *testing.T) {
+       badTypeCheck(new(ET2), true, "no fields in common", t)
+       badTypeCheck(new(ET3), false, "different name of field", t)
+       badTypeCheck(new(ET4), true, "different type of field", t)
+}
+
+func corruptDataCheck(s string, err os.Error, t *testing.T) {
+       b := bytes.NewBufferString(s)
+       dec := NewDecoder(b)
+       err1 := dec.Decode(new(ET2))
+       if err1 != err {
+               t.Error("expected error", err, "got", err1)
+       }
+}
+
+// Check that we survive bad data.
+func TestBadData(t *testing.T) {
+       corruptDataCheck("", os.EOF, t)
+       corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t)
+       corruptDataCheck("\x03now is the time for all good men", errBadType, t)
+}
+
+// Types not supported by the Encoder.
+var unsupportedValues = []interface{}{
+       make(chan int),
+       func(a int) bool { return true },
+}
+
+func TestUnsupported(t *testing.T) {
+       var b bytes.Buffer
+       enc := NewEncoder(&b)
+       for _, v := range unsupportedValues {
+               err := enc.Encode(v)
+               if err == nil {
+                       t.Errorf("expected error for %T; got none", v)
+               }
+       }
+}
+
+func encAndDec(in, out interface{}) os.Error {
+       b := new(bytes.Buffer)
+       enc := NewEncoder(b)
+       err := enc.Encode(in)
+       if err != nil {
+               return err
+       }
+       dec := NewDecoder(b)
+       err = dec.Decode(out)
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+func TestTypeToPtrType(t *testing.T) {
+       // Encode a T, decode a *T
+       type Type0 struct {
+               a int
+       }
+       t0 := Type0{7}
+       t0p := (*Type0)(nil)
+       if err := encAndDec(t0, t0p); err != nil {
+               t.Error(err)
+       }
+}
+
+func TestPtrTypeToType(t *testing.T) {
+       // Encode a *T, decode a T
+       type Type1 struct {
+               a uint
+       }
+       t1p := &Type1{17}
+       var t1 Type1
+       if err := encAndDec(t1, t1p); err != nil {
+               t.Error(err)
+       }
+}
+
+func TestTypeToPtrPtrPtrPtrType(t *testing.T) {
+       type Type2 struct {
+               a ****float
+       }
+       t2 := Type2{}
+       t2.a = new(***float)
+       *t2.a = new(**float)
+       **t2.a = new(*float)
+       ***t2.a = new(float)
+       ****t2.a = 27.4
+       t2pppp := new(***Type2)
+       if err := encAndDec(t2, t2pppp); err != nil {
+               t.Error(err)
+       }
+       if ****(****t2pppp).a != ****t2.a {
+               t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).a, ****t2.a)
+       }
+}
+
+func TestSlice(t *testing.T) {
+       type Type3 struct {
+               a []string
+       }
+       t3p := &Type3{[]string{"hello", "world"}}
+       var t3 Type3
+       if err := encAndDec(t3, t3p); err != nil {
+               t.Error(err)
+       }
+}
+
+func TestValueError(t *testing.T) {
+       // Encode a *T, decode a T
+       type Type4 struct {
+               a int
+       }
+       t4p := &Type4{3}
+       var t4 Type4 // note: not a pointer.
+       if err := encAndDec(t4p, t4); err == nil || strings.Index(err.String(), "pointer") < 0 {
+               t.Error("expected error about pointer; got", err)
+       }
+}
+
+func TestArray(t *testing.T) {
+       type Type5 struct {
+               a [3]string
+               b [3]byte
+       }
+       type Type6 struct {
+               a [2]string // can't hold t5.a
+       }
+       t5 := Type5{[3]string{"hello", ",", "world"}, [3]byte{1, 2, 3}}
+       var t5p Type5
+       if err := encAndDec(t5, &t5p); err != nil {
+               t.Error(err)
+       }
+       var t6 Type6
+       if err := encAndDec(t5, &t6); err == nil {
+               t.Error("should fail with mismatched array sizes")
+       }
+}
+
+// Regression test for bug: must send zero values inside arrays
+func TestDefaultsInArray(t *testing.T) {
+       type Type7 struct {
+               b []bool
+               i []int
+               s []string
+               f []float
+       }
+       t7 := Type7{
+               []bool{false, false, true},
+               []int{0, 0, 1},
+               []string{"hi", "", "there"},
+               []float{0, 0, 1},
+       }
+       var t7p Type7
+       if err := encAndDec(t7, &t7p); err != nil {
+               t.Error(err)
+       }
+}
+
+var testInt int
+var testFloat32 float32
+var testString string
+var testSlice []string
+var testMap map[string]int
+var testArray [7]int
+
+type SingleTest struct {
+       in  interface{}
+       out interface{}
+       err string
+}
+
+var singleTests = []SingleTest{
+       {17, &testInt, ""},
+       {float32(17.5), &testFloat32, ""},
+       {"bike shed", &testString, ""},
+       {[]string{"bike", "shed", "paint", "color"}, &testSlice, ""},
+       {map[string]int{"seven": 7, "twelve": 12}, &testMap, ""},
+       {[7]int{4, 55, 0, 0, 0, 0, 0}, &testArray, ""}, // case that once triggered a bug
+       {[7]int{4, 55, 1, 44, 22, 66, 1234}, &testArray, ""},
+
+       // Decode errors
+       {172, &testFloat32, "wrong type"},
+}
+
+func TestSingletons(t *testing.T) {
+       b := new(bytes.Buffer)
+       enc := NewEncoder(b)
+       dec := NewDecoder(b)
+       for _, test := range singleTests {
+               b.Reset()
+               err := enc.Encode(test.in)
+               if err != nil {
+                       t.Errorf("error encoding %v: %s", test.in, err)
+                       continue
+               }
+               err = dec.Decode(test.out)
+               switch {
+               case err != nil && test.err == "":
+                       t.Errorf("error decoding %v: %s", test.in, err)
+                       continue
+               case err == nil && test.err != "":
+                       t.Errorf("expected error decoding %v: %s", test.in, test.err)
+                       continue
+               case err != nil && test.err != "":
+                       if strings.Index(err.String(), test.err) < 0 {
+                               t.Errorf("wrong error decoding %v: wanted %s, got %v", test.in, test.err, err)
+                       }
+                       continue
+               }
+               // Get rid of the pointer in the rhs
+               val := reflect.NewValue(test.out).(*reflect.PtrValue).Elem().Interface()
+               if !reflect.DeepEqual(test.in, val) {
+                       t.Errorf("decoding singleton: expected %v got %v", test.in, val)
+               }
+       }
+}
+
+func TestStructNonStruct(t *testing.T) {
+       type Struct struct {
+               a string
+       }
+       type NonStruct string
+       s := Struct{"hello"}
+       var sp Struct
+       if err := encAndDec(s, &sp); err != nil {
+               t.Error(err)
+       }
+       var ns NonStruct
+       if err := encAndDec(s, &ns); err == nil {
+               t.Error("should get error for struct/non-struct")
+       } else if strings.Index(err.String(), "type") < 0 {
+               t.Error("for struct/non-struct expected type error; got", err)
+       }
+       // Now try the other way
+       var nsp NonStruct
+       if err := encAndDec(ns, &nsp); err != nil {
+               t.Error(err)
+       }
+       if err := encAndDec(ns, &s); err == nil {
+               t.Error("should get error for non-struct/struct")
+       } else if strings.Index(err.String(), "type") < 0 {
+               t.Error("for non-struct/struct expected type error; got", err)
+       }
+}
diff --git a/libgo/go/gob/error.go b/libgo/go/gob/error.go
new file mode 100644 (file)
index 0000000..b053761
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+       "fmt"
+       "os"
+)
+
+// Errors in decoding and encoding are handled using panic and recover.
+// Panics caused by user error (that is, everything except run-time panics
+// such as "index out of bounds" errors) do not leave the file that caused
+// them, but are instead turned into plain os.Error returns.  Encoding and
+// decoding functions and methods that do not return an os.Error either use
+// panic to report an error or are guaranteed error-free.
+
+// A gobError wraps an os.Error and is used to distinguish errors (panics) generated in this package.
+type gobError struct {
+       os.Error
+}
+
+// errorf is like error but takes Printf-style arguments to construct an os.Error.
+func errorf(format string, args ...interface{}) {
+       error(fmt.Errorf(format, args...))
+}
+
+// error wraps the argument error and uses it as the argument to panic.
+func error(err os.Error) {
+       panic(gobError{Error: err})
+}
+
+// catchError is meant to be used as a deferred function to turn a panic(gobError) into a
+// plain os.Error.  It overwrites the error return of the function that deferred its call.
+func catchError(err *os.Error) {
+       if e := recover(); e != nil {
+               *err = e.(gobError).Error // Will re-panic if not one of our errors, such as a runtime error.
+       }
+       return
+}
diff --git a/libgo/go/gob/type.go b/libgo/go/gob/type.go
new file mode 100644 (file)
index 0000000..d68c877
--- /dev/null
@@ -0,0 +1,528 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+       "fmt"
+       "os"
+       "reflect"
+       "sync"
+)
+
+// Reflection types are themselves interface values holding structs
+// describing the type.  Each type has a different struct so that struct can
+// be the kind.  For example, if typ is the reflect type for an int8, typ is
+// a pointer to a reflect.Int8Type struct; if typ is the reflect type for a
+// function, typ is a pointer to a reflect.FuncType struct; we use the type
+// of that pointer as the kind.
+
+// A typeId represents a gob Type as an integer that can be passed on the wire.
+// Internally, typeIds are used as keys to a map to recover the underlying type info.
+type typeId int32
+
+var nextId typeId       // incremented for each new type we build
+var typeLock sync.Mutex // set while building a type
+const firstUserId = 64  // lowest id number granted to user
+
+type gobType interface {
+       id() typeId
+       setId(id typeId)
+       Name() string
+       string() string // not public; only for debugging
+       safeString(seen map[typeId]bool) string
+}
+
+var types = make(map[reflect.Type]gobType)
+var idToType = make(map[typeId]gobType)
+var builtinIdToType map[typeId]gobType // set in init() after builtins are established
+
+func setTypeId(typ gobType) {
+       nextId++
+       typ.setId(nextId)
+       idToType[nextId] = typ
+}
+
+func (t typeId) gobType() gobType {
+       if t == 0 {
+               return nil
+       }
+       return idToType[t]
+}
+
+// string returns the string representation of the type associated with the typeId.
+func (t typeId) string() string {
+       if t.gobType() == nil {
+               return "<nil>"
+       }
+       return t.gobType().string()
+}
+
+// Name returns the name of the type associated with the typeId.
+func (t typeId) Name() string {
+       if t.gobType() == nil {
+               return "<nil>"
+       }
+       return t.gobType().Name()
+}
+
+// Common elements of all types.
+type commonType struct {
+       name string
+       _id  typeId
+}
+
+func (t *commonType) id() typeId { return t._id }
+
+func (t *commonType) setId(id typeId) { t._id = id }
+
+func (t *commonType) string() string { return t.name }
+
+func (t *commonType) safeString(seen map[typeId]bool) string {
+       return t.name
+}
+
+func (t *commonType) Name() string { return t.name }
+
+// Create and check predefined types
+// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
+
+var (
+       // Primordial types, needed during initialization.
+       tBool      = bootstrapType("bool", false, 1)
+       tInt       = bootstrapType("int", int(0), 2)
+       tUint      = bootstrapType("uint", uint(0), 3)
+       tFloat     = bootstrapType("float", float64(0), 4)
+       tBytes     = bootstrapType("bytes", make([]byte, 0), 5)
+       tString    = bootstrapType("string", "", 6)
+       tComplex   = bootstrapType("complex", 0+0i, 7)
+       tInterface = bootstrapType("interface", interface{}(nil), 8)
+       // Reserve some Ids for compatible expansion
+       tReserved7 = bootstrapType("_reserved1", struct{ r7 int }{}, 9)
+       tReserved6 = bootstrapType("_reserved1", struct{ r6 int }{}, 10)
+       tReserved5 = bootstrapType("_reserved1", struct{ r5 int }{}, 11)
+       tReserved4 = bootstrapType("_reserved1", struct{ r4 int }{}, 12)
+       tReserved3 = bootstrapType("_reserved1", struct{ r3 int }{}, 13)
+       tReserved2 = bootstrapType("_reserved1", struct{ r2 int }{}, 14)
+       tReserved1 = bootstrapType("_reserved1", struct{ r1 int }{}, 15)
+)
+
+// Predefined because it's needed by the Decoder
+var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
+
+func init() {
+       // Some magic numbers to make sure there are no surprises.
+       checkId(16, tWireType)
+       checkId(17, mustGetTypeInfo(reflect.Typeof(arrayType{})).id)
+       checkId(18, mustGetTypeInfo(reflect.Typeof(commonType{})).id)
+       checkId(19, mustGetTypeInfo(reflect.Typeof(sliceType{})).id)
+       checkId(20, mustGetTypeInfo(reflect.Typeof(structType{})).id)
+       checkId(21, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
+       checkId(23, mustGetTypeInfo(reflect.Typeof(mapType{})).id)
+
+       builtinIdToType = make(map[typeId]gobType)
+       for k, v := range idToType {
+               builtinIdToType[k] = v
+       }
+
+       // Move the id space upwards to allow for growth in the predefined world
+       // without breaking existing files.
+       if nextId > firstUserId {
+               panic(fmt.Sprintln("nextId too large:", nextId))
+       }
+       nextId = firstUserId
+       registerBasics()
+}
+
+// Array type
+type arrayType struct {
+       commonType
+       Elem typeId
+       Len  int
+}
+
+func newArrayType(name string, elem gobType, length int) *arrayType {
+       a := &arrayType{commonType{name: name}, elem.id(), length}
+       setTypeId(a)
+       return a
+}
+
+func (a *arrayType) safeString(seen map[typeId]bool) string {
+       if seen[a._id] {
+               return a.name
+       }
+       seen[a._id] = true
+       return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))
+}
+
+func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) }
+
+// Map type
+type mapType struct {
+       commonType
+       Key  typeId
+       Elem typeId
+}
+
+func newMapType(name string, key, elem gobType) *mapType {
+       m := &mapType{commonType{name: name}, key.id(), elem.id()}
+       setTypeId(m)
+       return m
+}
+
+func (m *mapType) safeString(seen map[typeId]bool) string {
+       if seen[m._id] {
+               return m.name
+       }
+       seen[m._id] = true
+       key := m.Key.gobType().safeString(seen)
+       elem := m.Elem.gobType().safeString(seen)
+       return fmt.Sprintf("map[%s]%s", key, elem)
+}
+
+func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }
+
+// Slice type
+type sliceType struct {
+       commonType
+       Elem typeId
+}
+
+func newSliceType(name string, elem gobType) *sliceType {
+       s := &sliceType{commonType{name: name}, elem.id()}
+       setTypeId(s)
+       return s
+}
+
+func (s *sliceType) safeString(seen map[typeId]bool) string {
+       if seen[s._id] {
+               return s.name
+       }
+       seen[s._id] = true
+       return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))
+}
+
+func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+// Struct type
+type fieldType struct {
+       name string
+       id   typeId
+}
+
+type structType struct {
+       commonType
+       field []*fieldType
+}
+
+func (s *structType) safeString(seen map[typeId]bool) string {
+       if s == nil {
+               return "<nil>"
+       }
+       if _, ok := seen[s._id]; ok {
+               return s.name
+       }
+       seen[s._id] = true
+       str := s.name + " = struct { "
+       for _, f := range s.field {
+               str += fmt.Sprintf("%s %s; ", f.name, f.id.gobType().safeString(seen))
+       }
+       str += "}"
+       return str
+}
+
+func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+func newStructType(name string) *structType {
+       s := &structType{commonType{name: name}, nil}
+       setTypeId(s)
+       return s
+}
+
+// Step through the indirections on a type to discover the base type.
+// Return the base type and the number of indirections.
+func indirect(t reflect.Type) (rt reflect.Type, count int) {
+       rt = t
+       for {
+               pt, ok := rt.(*reflect.PtrType)
+               if !ok {
+                       break
+               }
+               rt = pt.Elem()
+               count++
+       }
+       return
+}
+
+func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
+       switch t := rt.(type) {
+       // All basic types are easy: they are predefined.
+       case *reflect.BoolType:
+               return tBool.gobType(), nil
+
+       case *reflect.IntType:
+               return tInt.gobType(), nil
+
+       case *reflect.UintType:
+               return tUint.gobType(), nil
+
+       case *reflect.FloatType:
+               return tFloat.gobType(), nil
+
+       case *reflect.ComplexType:
+               return tComplex.gobType(), nil
+
+       case *reflect.StringType:
+               return tString.gobType(), nil
+
+       case *reflect.InterfaceType:
+               return tInterface.gobType(), nil
+
+       case *reflect.ArrayType:
+               gt, err := getType("", t.Elem())
+               if err != nil {
+                       return nil, err
+               }
+               return newArrayType(name, gt, t.Len()), nil
+
+       case *reflect.MapType:
+               kt, err := getType("", t.Key())
+               if err != nil {
+                       return nil, err
+               }
+               vt, err := getType("", t.Elem())
+               if err != nil {
+                       return nil, err
+               }
+               return newMapType(name, kt, vt), nil
+
+       case *reflect.SliceType:
+               // []byte == []uint8 is a special case
+               if t.Elem().Kind() == reflect.Uint8 {
+                       return tBytes.gobType(), nil
+               }
+               gt, err := getType(t.Elem().Name(), t.Elem())
+               if err != nil {
+                       return nil, err
+               }
+               return newSliceType(name, gt), nil
+
+       case *reflect.StructType:
+               // Install the struct type itself before the fields so recursive
+               // structures can be constructed safely.
+               strType := newStructType(name)
+               types[rt] = strType
+               idToType[strType.id()] = strType
+               field := make([]*fieldType, t.NumField())
+               for i := 0; i < t.NumField(); i++ {
+                       f := t.Field(i)
+                       typ, _ := indirect(f.Type)
+                       tname := typ.Name()
+                       if tname == "" {
+                               t, _ := indirect(f.Type)
+                               tname = t.String()
+                       }
+                       gt, err := getType(tname, f.Type)
+                       if err != nil {
+                               return nil, err
+                       }
+                       field[i] = &fieldType{f.Name, gt.id()}
+               }
+               strType.field = field
+               return strType, nil
+
+       default:
+               return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String())
+       }
+       return nil, nil
+}
+
+// getType returns the Gob type describing the given reflect.Type.
+// typeLock must be held.
+func getType(name string, rt reflect.Type) (gobType, os.Error) {
+       rt, _ = indirect(rt)
+       typ, present := types[rt]
+       if present {
+               return typ, nil
+       }
+       typ, err := newTypeObject(name, rt)
+       if err == nil {
+               types[rt] = typ
+       }
+       return typ, err
+}
+
+func checkId(want, got typeId) {
+       if want != got {
+               fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(want), int(got))
+               panic("bootstrap type wrong id: " + got.Name() + " " + got.string() + " not " + want.string())
+       }
+}
+
+// used for building the basic types; called only from init()
+func bootstrapType(name string, e interface{}, expect typeId) typeId {
+       rt := reflect.Typeof(e)
+       _, present := types[rt]
+       if present {
+               panic("bootstrap type already present: " + name + ", " + rt.String())
+       }
+       typ := &commonType{name: name}
+       types[rt] = typ
+       setTypeId(typ)
+       checkId(expect, nextId)
+       return nextId
+}
+
+// Representation of the information we send and receive about this type.
+// Each value we send is preceded by its type definition: an encoded int.
+// However, the very first time we send the value, we first send the pair
+// (-id, wireType).
+// For bootstrapping purposes, we assume that the recipient knows how
+// to decode a wireType; it is exactly the wireType struct here, interpreted
+// using the gob rules for sending a structure, except that we assume the
+// ids for wireType and structType are known.  The relevant pieces
+// are built in encode.go's init() function.
+// To maintain binary compatibility, if you extend this type, always put
+// the new fields last.
+type wireType struct {
+       arrayT  *arrayType
+       sliceT  *sliceType
+       structT *structType
+       mapT    *mapType
+}
+
+func (w *wireType) name() string {
+       if w.structT != nil {
+               return w.structT.name
+       }
+       return "unknown"
+}
+
+type typeInfo struct {
+       id      typeId
+       encoder *encEngine
+       wire    *wireType
+}
+
+var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
+
+// The reflection type must have all its indirections processed out.
+// typeLock must be held.
+func getTypeInfo(rt reflect.Type) (*typeInfo, os.Error) {
+       if rt.Kind() == reflect.Ptr {
+               panic("pointer type in getTypeInfo: " + rt.String())
+       }
+       info, ok := typeInfoMap[rt]
+       if !ok {
+               info = new(typeInfo)
+               name := rt.Name()
+               gt, err := getType(name, rt)
+               if err != nil {
+                       return nil, err
+               }
+               info.id = gt.id()
+               t := info.id.gobType()
+               switch typ := rt.(type) {
+               case *reflect.ArrayType:
+                       info.wire = &wireType{arrayT: t.(*arrayType)}
+               case *reflect.MapType:
+                       info.wire = &wireType{mapT: t.(*mapType)}
+               case *reflect.SliceType:
+                       // []byte == []uint8 is a special case handled separately
+                       if typ.Elem().Kind() != reflect.Uint8 {
+                               info.wire = &wireType{sliceT: t.(*sliceType)}
+                       }
+               case *reflect.StructType:
+                       info.wire = &wireType{structT: t.(*structType)}
+               }
+               typeInfoMap[rt] = info
+       }
+       return info, nil
+}
+
+// Called only when a panic is acceptable and unexpected.
+func mustGetTypeInfo(rt reflect.Type) *typeInfo {
+       t, err := getTypeInfo(rt)
+       if err != nil {
+               panic("getTypeInfo: " + err.String())
+       }
+       return t
+}
+
+var (
+       nameToConcreteType = make(map[string]reflect.Type)
+       concreteTypeToName = make(map[reflect.Type]string)
+)
+
+// RegisterName is like Register but uses the provided name rather than the
+// type's default.
+func RegisterName(name string, value interface{}) {
+       if name == "" {
+               // reserved for nil
+               panic("attempt to register empty name")
+       }
+       rt, _ := indirect(reflect.Typeof(value))
+       // Check for incompatible duplicates.
+       if t, ok := nameToConcreteType[name]; ok && t != rt {
+               panic("gob: registering duplicate types for " + name)
+       }
+       if n, ok := concreteTypeToName[rt]; ok && n != name {
+               panic("gob: registering duplicate names for " + rt.String())
+       }
+       nameToConcreteType[name] = rt
+       concreteTypeToName[rt] = name
+}
+
+// Register records a type, identified by a value for that type, under its
+// internal type name.  That name will identify the concrete type of a value
+// sent or received as an interface variable.  Only types that will be
+// transferred as implementations of interface values need to be registered.
+// Expecting to be used only during initialization, it panics if the mapping
+// between types and names is not a bijection.
+func Register(value interface{}) {
+       // Default to printed representation for unnamed types
+       rt := reflect.Typeof(value)
+       name := rt.String()
+
+       // But for named types (or pointers to them), qualify with import path.
+       // Dereference one pointer looking for a named type.
+       star := ""
+       if rt.Name() == "" {
+               if pt, ok := rt.(*reflect.PtrType); ok {
+                       star = "*"
+                       rt = pt
+               }
+       }
+       if rt.Name() != "" {
+               if rt.PkgPath() == "" {
+                       name = star + rt.Name()
+               } else {
+                       name = star + rt.PkgPath() + "." + rt.Name()
+               }
+       }
+
+       RegisterName(name, value)
+}
+
+func registerBasics() {
+       Register(int(0))
+       Register(int8(0))
+       Register(int16(0))
+       Register(int32(0))
+       Register(int64(0))
+       Register(uint(0))
+       Register(uint8(0))
+       Register(uint16(0))
+       Register(uint32(0))
+       Register(uint64(0))
+       Register(float(0))
+       Register(float32(0))
+       Register(float64(0))
+       Register(complex(0i))
+       Register(complex64(0i))
+       Register(complex128(0i))
+       Register(false)
+       Register("")
+       Register([]byte(nil))
+}
diff --git a/libgo/go/gob/type_test.go b/libgo/go/gob/type_test.go
new file mode 100644 (file)
index 0000000..106e4f1
--- /dev/null
@@ -0,0 +1,153 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+       "reflect"
+       "testing"
+)
+
+type typeT struct {
+       id  typeId
+       str string
+}
+
+var basicTypes = []typeT{
+       {tBool, "bool"},
+       {tInt, "int"},
+       {tUint, "uint"},
+       {tFloat, "float"},
+       {tBytes, "bytes"},
+       {tString, "string"},
+}
+
+func getTypeUnlocked(name string, rt reflect.Type) gobType {
+       typeLock.Lock()
+       defer typeLock.Unlock()
+       t, err := getType(name, rt)
+       if err != nil {
+               panic("getTypeUnlocked: " + err.String())
+       }
+       return t
+}
+
+// Sanity checks
+func TestBasic(t *testing.T) {
+       for _, tt := range basicTypes {
+               if tt.id.string() != tt.str {
+                       t.Errorf("checkType: expected %q got %s", tt.str, tt.id.string())
+               }
+               if tt.id == 0 {
+                       t.Errorf("id for %q is zero", tt.str)
+               }
+       }
+}
+
+// Reregister some basic types to check registration is idempotent.
+func TestReregistration(t *testing.T) {
+       newtyp := getTypeUnlocked("int", reflect.Typeof(int(0)))
+       if newtyp != tInt.gobType() {
+               t.Errorf("reregistration of %s got new type", newtyp.string())
+       }
+       newtyp = getTypeUnlocked("uint", reflect.Typeof(uint(0)))
+       if newtyp != tUint.gobType() {
+               t.Errorf("reregistration of %s got new type", newtyp.string())
+       }
+       newtyp = getTypeUnlocked("string", reflect.Typeof("hello"))
+       if newtyp != tString.gobType() {
+               t.Errorf("reregistration of %s got new type", newtyp.string())
+       }
+}
+
+func TestArrayType(t *testing.T) {
+       var a3 [3]int
+       a3int := getTypeUnlocked("foo", reflect.Typeof(a3))
+       newa3int := getTypeUnlocked("bar", reflect.Typeof(a3))
+       if a3int != newa3int {
+               t.Errorf("second registration of [3]int creates new type")
+       }
+       var a4 [4]int
+       a4int := getTypeUnlocked("goo", reflect.Typeof(a4))
+       if a3int == a4int {
+               t.Errorf("registration of [3]int creates same type as [4]int")
+       }
+       var b3 [3]bool
+       a3bool := getTypeUnlocked("", reflect.Typeof(b3))
+       if a3int == a3bool {
+               t.Errorf("registration of [3]bool creates same type as [3]int")
+       }
+       str := a3bool.string()
+       expected := "[3]bool"
+       if str != expected {
+               t.Errorf("array printed as %q; expected %q", str, expected)
+       }
+}
+
+func TestSliceType(t *testing.T) {
+       var s []int
+       sint := getTypeUnlocked("slice", reflect.Typeof(s))
+       var news []int
+       newsint := getTypeUnlocked("slice1", reflect.Typeof(news))
+       if sint != newsint {
+               t.Errorf("second registration of []int creates new type")
+       }
+       var b []bool
+       sbool := getTypeUnlocked("", reflect.Typeof(b))
+       if sbool == sint {
+               t.Errorf("registration of []bool creates same type as []int")
+       }
+       str := sbool.string()
+       expected := "[]bool"
+       if str != expected {
+               t.Errorf("slice printed as %q; expected %q", str, expected)
+       }
+}
+
+func TestMapType(t *testing.T) {
+       var m map[string]int
+       mapStringInt := getTypeUnlocked("map", reflect.Typeof(m))
+       var newm map[string]int
+       newMapStringInt := getTypeUnlocked("map1", reflect.Typeof(newm))
+       if mapStringInt != newMapStringInt {
+               t.Errorf("second registration of map[string]int creates new type")
+       }
+       var b map[string]bool
+       mapStringBool := getTypeUnlocked("", reflect.Typeof(b))
+       if mapStringBool == mapStringInt {
+               t.Errorf("registration of map[string]bool creates same type as map[string]int")
+       }
+       str := mapStringBool.string()
+       expected := "map[string]bool"
+       if str != expected {
+               t.Errorf("map printed as %q; expected %q", str, expected)
+       }
+}
+
+type Bar struct {
+       x string
+}
+
+// This structure has pointers and refers to itself, making it a good test case.
+type Foo struct {
+       a int
+       b int32 // will become int
+       c string
+       d []byte
+       e *float      // will become float
+       f ****float64 // will become float
+       g *Bar
+       h *Bar // should not interpolate the definition of Bar again
+       i *Foo // will not explode
+}
+
+func TestStructType(t *testing.T) {
+       sstruct := getTypeUnlocked("Foo", reflect.Typeof(Foo{}))
+       str := sstruct.string()
+       // If we can print it correctly, we built it correctly.
+       expected := "Foo = struct { a int; b int; c string; d bytes; e float; f float; g Bar = struct { x string; }; h Bar; i Foo; }"
+       if str != expected {
+               t.Errorf("struct printed as %q; expected %q", str, expected)
+       }
+}
diff --git a/libgo/go/hash/adler32/adler32.go b/libgo/go/hash/adler32/adler32.go
new file mode 100644 (file)
index 0000000..cd0c259
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the Adler-32 checksum.
+// Defined in RFC 1950:
+//     Adler-32 is composed of two sums accumulated per byte: s1 is
+//     the sum of all bytes, s2 is the sum of all s1 values. Both sums
+//     are done modulo 65521. s1 is initialized to 1, s2 to zero.  The
+//     Adler-32 checksum is stored as s2*65536 + s1 in most-
+//     significant-byte first (network) order.
+package adler32
+
+import (
+       "hash"
+       "os"
+)
+
+const (
+       mod = 65521
+)
+
+// The size of an Adler-32 checksum in bytes.
+const Size = 4
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+       // invariant: (a < mod && b < mod) || a <= b
+       // invariant: a + b + 255 <= 0xffffffff
+       a, b uint32
+}
+
+func (d *digest) Reset() { d.a, d.b = 1, 0 }
+
+// New returns a new hash.Hash32 computing the Adler-32 checksum.
+func New() hash.Hash32 {
+       d := new(digest)
+       d.Reset()
+       return d
+}
+
+func (d *digest) Size() int { return Size }
+
+// Add p to the running checksum a, b.
+func update(a, b uint32, p []byte) (aa, bb uint32) {
+       for i := 0; i < len(p); i++ {
+               a += uint32(p[i])
+               b += a
+               // invariant: a <= b
+               if b > (0xffffffff-255)/2 {
+                       a %= mod
+                       b %= mod
+                       // invariant: a < mod && b < mod
+               } else {
+                       // invariant: a + b + 255 <= 2 * b + 255 <= 0xffffffff
+               }
+       }
+       return a, b
+}
+
+// Return the 32-bit checksum corresponding to a, b.
+func finish(a, b uint32) uint32 {
+       if b >= mod {
+               a %= mod
+               b %= mod
+       }
+       return b<<16 | a
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+       d.a, d.b = update(d.a, d.b, p)
+       return len(p), nil
+}
+
+func (d *digest) Sum32() uint32 { return finish(d.a, d.b) }
+
+func (d *digest) Sum() []byte {
+       p := make([]byte, 4)
+       s := d.Sum32()
+       p[0] = byte(s >> 24)
+       p[1] = byte(s >> 16)
+       p[2] = byte(s >> 8)
+       p[3] = byte(s)
+       return p
+}
+
+// Checksum returns the Adler-32 checksum of data.
+func Checksum(data []byte) uint32 { return finish(update(1, 0, data)) }
diff --git a/libgo/go/hash/adler32/adler32_test.go b/libgo/go/hash/adler32/adler32_test.go
new file mode 100644 (file)
index 0000000..ffa5569
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package adler32
+
+import (
+       "io"
+       "testing"
+)
+
+type _Adler32Test struct {
+       out uint32
+       in  string
+}
+
+var golden = []_Adler32Test{
+       {0x1, ""},
+       {0x620062, "a"},
+       {0x12600c4, "ab"},
+       {0x24d0127, "abc"},
+       {0x3d8018b, "abcd"},
+       {0x5c801f0, "abcde"},
+       {0x81e0256, "abcdef"},
+       {0xadb02bd, "abcdefg"},
+       {0xe000325, "abcdefgh"},
+       {0x118e038e, "abcdefghi"},
+       {0x158603f8, "abcdefghij"},
+       {0x3f090f02, "Discard medicine more than two years old."},
+       {0x46d81477, "He who has a shady past knows that nice guys finish last."},
+       {0x40ee0ee1, "I wouldn't marry him with a ten foot pole."},
+       {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {0x5b2e1480, "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {0x8c3c09ea, "Nepal premier won't resign."},
+       {0x45ac18fd, "For every action there is an equal and opposite government program."},
+       {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."},
+       {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {0x61b507df, "size:  a.out:  bad magic"},
+       {0xb8631171, "The major problem is with sendmail.  -Mark Horton"},
+       {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {0x7cc6102b, "If the enemy is within range, then so are you."},
+       {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."},
+       {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {0xb55b0b09, "C is as portable as Stonehedge!!"},
+       {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {0x2e5d1316, "How can you write a big system without C++?  -Paul Glick"},
+       {0xd0201df6, "'Invariant assertions' is the most elegant programming technique!  -Tom Szymanski"},
+}
+
+func TestGolden(t *testing.T) {
+       for i := 0; i < len(golden); i++ {
+               g := golden[i]
+               c := New()
+               io.WriteString(c, g.in)
+               s := c.Sum32()
+               if s != g.out {
+                       t.Errorf("adler32(%s) = 0x%x want 0x%x", g.in, s, g.out)
+                       t.FailNow()
+               }
+       }
+}
diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go
new file mode 100644 (file)
index 0000000..2ab0c54
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the 32-bit cyclic redundancy check, or CRC-32, checksum.
+// See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for information.
+package crc32
+
+import (
+       "hash"
+       "os"
+)
+
+// The size of a CRC-32 checksum in bytes.
+const Size = 4
+
+// Predefined polynomials.
+const (
+       // Far and away the most common CRC-32 polynomial.
+       // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ...
+       IEEE = 0xedb88320
+
+       // Castagnoli's polynomial, used in iSCSI.
+       // Has better error detection characteristics than IEEE.
+       // http://dx.doi.org/10.1109/26.231911
+       Castagnoli = 0x82f63b78
+
+       // Koopman's polynomial.
+       // Also has better error detection characteristics than IEEE.
+       // http://dx.doi.org/10.1109/DSN.2002.1028931
+       Koopman = 0xeb31d82e
+)
+
+// Table is a 256-word table representing the polynomial for efficient processing.
+type Table [256]uint32
+
+// MakeTable returns the Table constructed from the specified polynomial.
+func MakeTable(poly uint32) *Table {
+       t := new(Table)
+       for i := 0; i < 256; i++ {
+               crc := uint32(i)
+               for j := 0; j < 8; j++ {
+                       if crc&1 == 1 {
+                               crc = (crc >> 1) ^ poly
+                       } else {
+                               crc >>= 1
+                       }
+               }
+               t[i] = crc
+       }
+       return t
+}
+
+// IEEETable is the table for the IEEE polynomial.
+var IEEETable = MakeTable(IEEE)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+       crc uint32
+       tab *Table
+}
+
+// New creates a new hash.Hash32 computing the CRC-32 checksum
+// using the polynomial represented by the Table.
+func New(tab *Table) hash.Hash32 { return &digest{0, tab} }
+
+// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum
+// using the IEEE polynomial.
+func NewIEEE() hash.Hash32 { return New(IEEETable) }
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Reset() { d.crc = 0 }
+
+func update(crc uint32, tab *Table, p []byte) uint32 {
+       crc = ^crc
+       for _, v := range p {
+               crc = tab[byte(crc)^v] ^ (crc >> 8)
+       }
+       return ^crc
+}
+
+// Update returns the result of adding the bytes in p to the crc.
+func Update(crc uint32, tab *Table, p []byte) uint32 {
+       return update(crc, tab, p)
+}
+
+func (d *digest) Write(p []byte) (n int, err os.Error) {
+       d.crc = update(d.crc, d.tab, p)
+       return len(p), nil
+}
+
+func (d *digest) Sum32() uint32 { return d.crc }
+
+func (d *digest) Sum() []byte {
+       p := make([]byte, 4)
+       s := d.Sum32()
+       p[0] = byte(s >> 24)
+       p[1] = byte(s >> 16)
+       p[2] = byte(s >> 8)
+       p[3] = byte(s)
+       return p
+}
+
+// Checksum returns the CRC-32 checksum of data
+// using the polynomial represented by the Table.
+func Checksum(data []byte, tab *Table) uint32 { return update(0, tab, data) }
+
+// ChecksumIEEE returns the CRC-32 checksum of data
+// using the IEEE polynomial.
+func ChecksumIEEE(data []byte) uint32 { return update(0, IEEETable, data) }
diff --git a/libgo/go/hash/crc32/crc32_test.go b/libgo/go/hash/crc32/crc32_test.go
new file mode 100644 (file)
index 0000000..cf5743c
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package crc32
+
+import (
+       "io"
+       "testing"
+)
+
+type test struct {
+       out uint32
+       in  string
+}
+
+var golden = []test{
+       {0x0, ""},
+       {0xe8b7be43, "a"},
+       {0x9e83486d, "ab"},
+       {0x352441c2, "abc"},
+       {0xed82cd11, "abcd"},
+       {0x8587d865, "abcde"},
+       {0x4b8e39ef, "abcdef"},
+       {0x312a6aa6, "abcdefg"},
+       {0xaeef2a50, "abcdefgh"},
+       {0x8da988af, "abcdefghi"},
+       {0x3981703a, "abcdefghij"},
+       {0x6b9cdfe7, "Discard medicine more than two years old."},
+       {0xc90ef73f, "He who has a shady past knows that nice guys finish last."},
+       {0xb902341f, "I wouldn't marry him with a ten foot pole."},
+       {0x42080e8, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {0x154c6d11, "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {0x4c418325, "Nepal premier won't resign."},
+       {0x33955150, "For every action there is an equal and opposite government program."},
+       {0x26216a4b, "His money is twice tainted: 'taint yours and 'taint mine."},
+       {0x1abbe45e, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {0xc89a94f7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {0xab3abe14, "size:  a.out:  bad magic"},
+       {0xbab102b6, "The major problem is with sendmail.  -Mark Horton"},
+       {0x999149d7, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {0x6d52a33c, "If the enemy is within range, then so are you."},
+       {0x90631e8d, "It's well we cannot hear the screams/That we create in others' dreams."},
+       {0x78309130, "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {0x7d0a377f, "C is as portable as Stonehedge!!"},
+       {0x8c79fd79, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {0xa20b7167, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {0x8e0bb443, "How can you write a big system without C++?  -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+       for i := 0; i < len(golden); i++ {
+               g := golden[i]
+               c := NewIEEE()
+               io.WriteString(c, g.in)
+               s := c.Sum32()
+               if s != g.out {
+                       t.Errorf("crc32(%s) = 0x%x want 0x%x", g.in, s, g.out)
+                       t.FailNow()
+               }
+       }
+}
+
+func BenchmarkCrc32KB(b *testing.B) {
+       b.StopTimer()
+       data := make([]uint8, 1024)
+       for i := 0; i < 1024; i++ {
+               data[i] = uint8(i)
+       }
+       c := NewIEEE()
+       b.StartTimer()
+
+       for i := 0; i < b.N; i++ {
+               c.Write(data)
+       }
+}
diff --git a/libgo/go/hash/crc64/crc64.go b/libgo/go/hash/crc64/crc64.go
new file mode 100644 (file)
index 0000000..89e4319
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the 64-bit cyclic redundancy check, or CRC-64, checksum.
+// See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for information.
+package crc64
+
+import (
+       "hash"
+       "os"
+)
+
+// The size of a CRC-64 checksum in bytes.
+const Size = 8
+
+// Predefined polynomials.
+const (
+       // The ISO polynomial, defined in ISO 3309 and used in HDLC.
+       ISO = 0xD800000000000000
+
+       // The ECMA polynomial, defined in ECMA 182.
+       ECMA = 0xC96C5795D7870F42
+)
+
+// Table is a 256-word table representing the polynomial for efficient processing.
+type Table [256]uint64
+
+// MakeTable returns the Table constructed from the specified polynomial.
+func MakeTable(poly uint64) *Table {
+       t := new(Table)
+       for i := 0; i < 256; i++ {
+               crc := uint64(i)
+               for j := 0; j < 8; j++ {
+                       if crc&1 == 1 {
+                               crc = (crc >> 1) ^ poly
+                       } else {
+                               crc >>= 1
+                       }
+               }
+               t[i] = crc
+       }
+       return t
+}
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+       crc uint64
+       tab *Table
+}
+
+// New creates a new hash.Hash64 computing the CRC-64 checksum
+// using the polynomial represented by the Table.
+func New(tab *Table) hash.Hash64 { return &digest{0, tab} }
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Reset() { d.crc = 0 }
+
+func update(crc uint64, tab *Table, p []byte) uint64 {
+       crc = ^crc
+       for _, v := range p {
+               crc = tab[byte(crc)^v] ^ (crc >> 8)
+       }
+       return ^crc
+}
+
+// Update returns the result of adding the bytes in p to the crc.
+func Update(crc uint64, tab *Table, p []byte) uint64 {
+       return update(crc, tab, p)
+}
+
+func (d *digest) Write(p []byte) (n int, err os.Error) {
+       d.crc = update(d.crc, d.tab, p)
+       return len(p), nil
+}
+
+func (d *digest) Sum64() uint64 { return d.crc }
+
+func (d *digest) Sum() []byte {
+       p := make([]byte, 8)
+       s := d.Sum64()
+       p[0] = byte(s >> 54)
+       p[1] = byte(s >> 48)
+       p[2] = byte(s >> 40)
+       p[3] = byte(s >> 32)
+       p[4] = byte(s >> 24)
+       p[5] = byte(s >> 16)
+       p[6] = byte(s >> 8)
+       p[7] = byte(s)
+       return p
+}
+
+// Checksum returns the CRC-64 checksum of data
+// using the polynomial represented by the Table.
+func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) }
diff --git a/libgo/go/hash/crc64/crc64_test.go b/libgo/go/hash/crc64/crc64_test.go
new file mode 100644 (file)
index 0000000..e932524
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package crc64
+
+import (
+       "io"
+       "testing"
+)
+
+type test struct {
+       out uint64
+       in  string
+}
+
+var golden = []test{
+       {0x0, ""},
+       {0x3420000000000000, "a"},
+       {0x36c4200000000000, "ab"},
+       {0x3776c42000000000, "abc"},
+       {0x336776c420000000, "abcd"},
+       {0x32d36776c4200000, "abcde"},
+       {0x3002d36776c42000, "abcdef"},
+       {0x31b002d36776c420, "abcdefg"},
+       {0xe21b002d36776c4, "abcdefgh"},
+       {0x8b6e21b002d36776, "abcdefghi"},
+       {0x7f5b6e21b002d367, "abcdefghij"},
+       {0x8ec0e7c835bf9cdf, "Discard medicine more than two years old."},
+       {0xc7db1759e2be5ab4, "He who has a shady past knows that nice guys finish last."},
+       {0xfbf9d9603a6fa020, "I wouldn't marry him with a ten foot pole."},
+       {0xeafc4211a6daa0ef, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+       {0x3e05b21c7a4dc4da, "The days of the digital watch are numbered.  -Tom Stoppard"},
+       {0x5255866ad6ef28a6, "Nepal premier won't resign."},
+       {0x8a79895be1e9c361, "For every action there is an equal and opposite government program."},
+       {0x8878963a649d4916, "His money is twice tainted: 'taint yours and 'taint mine."},
+       {0xa7b9d53ea87eb82f, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+       {0xdb6805c0966a2f9c, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+       {0xf3553c65dacdadd2, "size:  a.out:  bad magic"},
+       {0x9d5e034087a676b9, "The major problem is with sendmail.  -Mark Horton"},
+       {0xa6db2d7f8da96417, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+       {0x325e00cd2fe819f9, "If the enemy is within range, then so are you."},
+       {0x88c6600ce58ae4c6, "It's well we cannot hear the screams/That we create in others' dreams."},
+       {0x28c4a3f3b769e078, "You remind me of a TV show, but that's all right: I watch it anyway."},
+       {0xa698a34c9d9f1dca, "C is as portable as Stonehedge!!"},
+       {0xf6c1e2a8c26c5cfc, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+       {0xd402559dfe9b70c, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+       {0xdb6efff26aa94946, "How can you write a big system without C++?  -Paul Glick"},
+}
+
+var tab = MakeTable(ISO)
+
+func TestGolden(t *testing.T) {
+       for i := 0; i < len(golden); i++ {
+               g := golden[i]
+               c := New(tab)
+               io.WriteString(c, g.in)
+               s := c.Sum64()
+               if s != g.out {
+                       t.Errorf("crc64(%s) = 0x%x want 0x%x", g.in, s, g.out)
+                       t.FailNow()
+               }
+       }
+}
+
+func BenchmarkCrc64KB(b *testing.B) {
+       b.StopTimer()
+       data := make([]uint8, 1024)
+       for i := 0; i < 1024; i++ {
+               data[i] = uint8(i)
+       }
+       c := New(tab)
+       b.StartTimer()
+
+       for i := 0; i < b.N; i++ {
+               c.Write(data)
+       }
+}
diff --git a/libgo/go/hash/hash.go b/libgo/go/hash/hash.go
new file mode 100644 (file)
index 0000000..56ac259
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hash
+
+import "io"
+
+// Hash is the common interface implemented by all hash functions.
+type Hash interface {
+       // Write adds more data to the running hash.
+       // It never returns an error.
+       io.Writer
+
+       // Sum returns the current hash, without changing the
+       // underlying hash state.
+       Sum() []byte
+
+       // Reset resets the hash to one with zero bytes written.
+       Reset()
+
+       // Size returns the number of bytes Sum will return.
+       Size() int
+}
+
+// Hash32 is the common interface implemented by all 32-bit hash functions.
+type Hash32 interface {
+       Hash
+       Sum32() uint32
+}
+
+// Hash64 is the common interface implemented by all 64-bit hash functions.
+type Hash64 interface {
+       Hash
+       Sum64() uint64
+}
diff --git a/libgo/go/html/doc.go b/libgo/go/html/doc.go
new file mode 100644 (file)
index 0000000..9f5d478
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The html package implements an HTML5-compliant tokenizer and parser.
+
+Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
+caller's responsibility to ensure that r provides UTF-8 encoded HTML.
+
+       z := html.NewTokenizer(r)
+
+Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
+which parses the next token and returns its type, or an error:
+
+       for {
+               tt := z.Next()
+               if tt == html.Error {
+                       // ...
+                       return ...
+               }
+               // Process the current token.
+       }
+
+There are two APIs for retrieving the current token. The high-level API is to
+call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
+allow optionally calling Raw after Next but before Token, Text, TagName, or
+TagAttr. In EBNF notation, the valid call sequence per token is:
+
+       Next {Raw} [ Token | Text | TagName {TagAttr} ]
+
+Token returns an independent data structure that completely describes a token.
+Entities (such as "&lt;") are unescaped, tag names and attribute keys are
+lower-cased, and attributes are collected into a []Attribute. For example:
+
+       for {
+               if z.Next() == html.Error {
+                       // Returning os.EOF indicates success.
+                       return z.Error()
+               }
+               emitToken(z.Token())
+       }
+
+The low-level API performs fewer allocations and copies, but the contents of
+the []byte values returned by Text, TagName and TagAttr may change on the next
+call to Next. For example, to extract an HTML page's anchor text:
+
+       depth := 0
+       for {
+               tt := z.Next()
+               switch tt {
+               case Error:
+                       return z.Error()
+               case Text:
+                       if depth > 0 {
+                               // emitBytes should copy the []byte it receives,
+                               // if it doesn't process it immediately.
+                               emitBytes(z.Text())
+                       }
+               case StartTag, EndTag:
+                       tn, _ := z.TagName()
+                       if len(tn) == 1 && tn[0] == 'a' {
+                               if tt == StartTag {
+                                       depth++
+                               } else {
+                                       depth--
+                               }
+                       }
+               }
+       }
+
+The relevant specifications include:
+http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html and
+http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
+*/
+package html
+
+// The tokenization algorithm implemented by this package is not a line-by-line
+// transliteration of the relatively verbose state-machine in the WHATWG
+// specification. A more direct approach is used instead, where the program
+// counter implies the state, such as whether it is tokenizing a tag or a text
+// node. Specification compliance is verified by checking expected and actual
+// outputs over a test suite rather than aiming for algorithmic fidelity.
+
+// TODO(nigeltao): Implement a parser, not just a tokenizer.
+// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
+// TODO(nigeltao): How does parsing interact with a JavaScript engine?
diff --git a/libgo/go/html/entity.go b/libgo/go/html/entity.go
new file mode 100644 (file)
index 0000000..e9f27b9
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+       "utf8"
+)
+
+// entity is a map from HTML entity names to their values. The semicolon matters:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html
+// lists both "amp" and "amp;" as two separate entries.
+//
+// TODO(nigeltao): Take the complete map from the HTML5 spec section 10.5 "Named character references".
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html
+// Note that the HTML5 list is larger than the HTML4 list at
+// http://www.w3.org/TR/html4/sgml/entities.html
+var entity = map[string]int{
+       "aacute":  '\U000000E1',
+       "aacute;": '\U000000E1',
+       "amp;":    '\U00000026',
+       "apos;":   '\U00000027',
+       "gt;":     '\U0000003E',
+       "lt;":     '\U0000003C',
+       "quot;":   '\U00000022',
+}
+
+func init() {
+       // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key).
+       // The +1 comes from the leading "&". This property implies that the length of
+       // unescaped text is <= the length of escaped text.
+       for k, v := range entity {
+               if 1+len(k) < utf8.RuneLen(v) {
+                       panic("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v))
+               }
+       }
+}
diff --git a/libgo/go/html/escape.go b/libgo/go/html/escape.go
new file mode 100644 (file)
index 0000000..f30086f
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+       "bytes"
+       "strings"
+       "utf8"
+)
+
+// unescapeEntity reads an entity like "&lt;" from b[src:] and writes the
+// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
+// Precondition: src[0] == '&' && dst <= src.
+func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
+       // TODO(nigeltao): Check that this entity substitution algorithm matches the spec:
+       // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
+       // TODO(nigeltao): Handle things like "&#20013;" or "&#x4e2d;".
+
+       // i starts at 1 because we already know that s[0] == '&'.
+       i, s := 1, b[src:]
+       for i < len(s) {
+               c := s[i]
+               i++
+               // Lower-cased characters are more common in entities, so we check for them first.
+               if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' {
+                       continue
+               }
+               if c != ';' {
+                       i--
+               }
+               x := entity[string(s[1:i])]
+               if x != 0 {
+                       return dst + utf8.EncodeRune(x, b[dst:]), src + i
+               }
+               break
+       }
+       dst1, src1 = dst+i, src+i
+       copy(b[dst:dst1], b[src:src1])
+       return dst1, src1
+}
+
+// unescape unescapes b's entities in-place, so that "a&lt;b" becomes "a<b".
+func unescape(b []byte) []byte {
+       for i, c := range b {
+               if c == '&' {
+                       dst, src := unescapeEntity(b, i, i)
+                       for src < len(b) {
+                               c := b[src]
+                               if c == '&' {
+                                       dst, src = unescapeEntity(b, dst, src)
+                               } else {
+                                       b[dst] = c
+                                       dst, src = dst+1, src+1
+                               }
+                       }
+                       return b[0:dst]
+               }
+       }
+       return b
+}
+
+const escapedChars = `&'<>"`
+
+func escape(buf *bytes.Buffer, s string) {
+       i := strings.IndexAny(s, escapedChars)
+       for i != -1 {
+               buf.WriteString(s[0:i])
+               var esc string
+               switch s[i] {
+               case '&':
+                       esc = "&amp;"
+               case '\'':
+                       esc = "&apos;"
+               case '<':
+                       esc = "&lt;"
+               case '>':
+                       esc = "&gt;"
+               case '"':
+                       esc = "&quot;"
+               default:
+                       panic("unrecognized escape character")
+               }
+               s = s[i+1:]
+               buf.WriteString(esc)
+               i = strings.IndexAny(s, escapedChars)
+       }
+       buf.WriteString(s)
+}
+
+// EscapeString escapes special characters like "<" to become "&lt;". It
+// escapes only five such characters: amp, apos, lt, gt and quot.
+// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
+// always true.
+func EscapeString(s string) string {
+       if strings.IndexAny(s, escapedChars) == -1 {
+               return s
+       }
+       buf := bytes.NewBuffer(nil)
+       escape(buf, s)
+       return buf.String()
+}
+
+// UnescapeString unescapes entities like "&lt;" to become "<". It unescapes a
+// larger range of entities than EscapeString escapes. For example, "&aacute;"
+// unescapes to "á", as does "&#225;" and "&xE1;".
+// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
+// always true.
+func UnescapeString(s string) string {
+       for _, c := range s {
+               if c == '&' {
+                       return string(unescape([]byte(s)))
+               }
+       }
+       return s
+}
diff --git a/libgo/go/html/testdata/webkit/README b/libgo/go/html/testdata/webkit/README
new file mode 100644 (file)
index 0000000..9b4c2d8
--- /dev/null
@@ -0,0 +1,28 @@
+The *.dat files in this directory are copied from The WebKit Open Source
+Project, specifically $WEBKITROOT/LayoutTests/html5lib/resources.
+WebKit is licensed under a BSD style license.
+http://webkit.org/coding/bsd-license.html says:
+
+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. 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 INC. 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.
+
diff --git a/libgo/go/html/testdata/webkit/comments01.dat b/libgo/go/html/testdata/webkit/comments01.dat
new file mode 100644 (file)
index 0000000..388d952
--- /dev/null
@@ -0,0 +1,126 @@
+#data
+FOO<!-- BAR -->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR  -->
+|     "BAZ"
+
+#data
+FOO<!-- BAR --!>BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR  -->
+|     "BAZ"
+
+#data
+FOO<!-- BAR --   >BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR --    -->
+|     "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR -- <QUX> -- MUX  -->
+|     "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX --!>BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR -- <QUX> -- MUX  -->
+|     "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -- >BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR -- <QUX> -- MUX --  -->
+|     "BAZ"
+
+#data
+FOO<!---->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  -->
+|     "BAZ"
+
+#data
+FOO<!--->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  -->
+|     "BAZ"
+
+#data
+FOO<!-->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  -->
+|     "BAZ"
+
+#data
+<?xml version="1.0">Hi
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+|   <head>
+|   <body>
+|     "Hi"
+
+#data
+<?xml version="1.0">
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?xml version
+#errors
+#document
+| <!-- ?xml version -->
+| <html>
+|   <head>
+|   <body>
diff --git a/libgo/go/html/testdata/webkit/doctype01.dat b/libgo/go/html/testdata/webkit/doctype01.dat
new file mode 100644 (file)
index 0000000..575129c
--- /dev/null
@@ -0,0 +1,335 @@
+#data
+<!DOCTYPE html>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!dOctYpE HtMl>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPEhtml>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE>Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE >Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato taco "ddd>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato sYstEM>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato sYstEM    >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE   potato       sYstEM  ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM taco  >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM 'taco"'>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "taco">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "tai'co">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEMtaco "ddd">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato grass SYSTEM taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato pUbLIcgoof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC goof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "go'of">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go'of'>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go:hh   of' >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+   "http://www.w3.org/TR/html4/strict.dtd">Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE ...>Hello
+#errors
+#document
+| <!DOCTYPE ...>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [ 
+<!-- internal declarations -->
+]>
+#errors
+#document
+| <!DOCTYPE root-element>
+| <html>
+|   <head>
+|   <body>
+|     "
+]>"
+
+#data
+<!DOCTYPE html PUBLIC
+  "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
+    "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "Mine!"
diff --git a/libgo/go/html/testdata/webkit/dom2string.js b/libgo/go/html/testdata/webkit/dom2string.js
new file mode 100644 (file)
index 0000000..45897fd
--- /dev/null
@@ -0,0 +1,135 @@
+String.prototype.toAsciiLowerCase = function () {
+  var output = "";
+  for (var i = 0, len = this.length; i < len; ++i) {
+    if (this.charCodeAt(i) >= 0x41 && this.charCodeAt(i) <= 0x5A) {
+      output += String.fromCharCode(this.charCodeAt(i) + 0x20)
+    } else {
+      output += this.charAt(i);
+    }
+  }
+  return output;
+}
+
+function indent(ancestors) {
+  var str = "";
+  if (ancestors > 0) {
+    while (ancestors--)
+      str += "  ";
+  }
+  return str;
+}
+
+function dom2string(node, ancestors) {
+  var str = "";
+  if (typeof ancestors == "undefined")
+    var ancestors = 0;
+  if (!node.firstChild)
+    return "| ";
+  var parent = node;
+  var current = node.firstChild;
+  var next = null;
+  var misnested = null;
+  for (;;) {
+    str += "\n| " + indent(ancestors);
+    switch (current.nodeType) {
+      case 10:
+        str += '<!DOCTYPE ' + current.nodeName + '>';
+        break;
+      case 8:
+        try {
+          str += '<!-- ' + current.nodeValue + ' -->';
+        } catch (e) {
+          str += '<!--  -->';
+        }
+        if (parent != current.parentNode) {
+          return str += ' (misnested... aborting)';
+        }
+        break;
+      case 7:
+        str += '<?' + current.nodeName + current.nodeValue + '>';
+        break;
+      case 4:
+        str += '<![CDATA[ ' + current.nodeValue + ' ]]>';
+        break;
+      case 3:
+        str += '"' + current.nodeValue + '"';
+        if (parent != current.parentNode) {
+          return str += ' (misnested... aborting)';
+        }
+        break;
+      case 1:
+        str += "<";
+        switch (current.namespaceURI) {
+          case "http://www.w3.org/2000/svg":
+            str += "svg ";
+            break;
+          case "http://www.w3.org/1998/Math/MathML":
+            str += "math ";
+            break;
+        }
+        if (current.localName && current.namespaceURI && current.namespaceURI != null) {
+          str += current.localName;
+        } else {
+          str += current.nodeName.toAsciiLowerCase();
+        }
+        str += '>';
+        if (parent != current.parentNode) {
+          return str += ' (misnested... aborting)';
+        } else {
+          if (current.attributes) {
+            var attrNames = [];
+            var attrPos = {};
+            for (var j = 0; j < current.attributes.length; j += 1) {
+              if (current.attributes[j].specified) {
+                var name = "";
+                switch (current.attributes[j].namespaceURI) {
+                  case "http://www.w3.org/XML/1998/namespace":
+                    name += "xml ";
+                    break;
+                  case "http://www.w3.org/2000/xmlns/":
+                    name += "xmlns ";
+                    break;
+                  case "http://www.w3.org/1999/xlink":
+                    name += "xlink ";
+                    break;
+                }
+                if (current.attributes[j].localName) {
+                  name += current.attributes[j].localName;
+                } else {
+                  name += current.attributes[j].nodeName;
+                }
+                attrNames.push(name);
+                attrPos[name] = j;
+              }
+            }
+            if (attrNames.length > 0) {
+              attrNames.sort();
+              for (var j = 0; j < attrNames.length; j += 1) {
+                str += "\n| " + indent(1 + ancestors) + attrNames[j];
+                str += '="' + current.attributes[attrPos[attrNames[j]]].nodeValue + '"';
+              }
+            }
+          }
+          if (next = current.firstChild) {
+            parent = current;
+            current = next;
+            ancestors++;
+            continue;
+          }
+        }
+        break;
+    }
+    for (;;) {
+      if (next = current.nextSibling) {
+        current = next;
+        break;
+      }
+      current = current.parentNode;
+      parent = parent.parentNode;
+      ancestors--;
+      if (current == node) {
+        return str.substring(1);
+      }
+    }
+  }
+}
diff --git a/libgo/go/html/testdata/webkit/entities01.dat b/libgo/go/html/testdata/webkit/entities01.dat
new file mode 100644 (file)
index 0000000..926642e
--- /dev/null
@@ -0,0 +1,612 @@
+#data
+FOO&gt;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO>BAR"
+
+#data
+FOO&gtBAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO>BAR"
+
+#data
+FOO&gt BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO> BAR"
+
+#data
+FOO&gt;;;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO>;;BAR"
+
+#data
+I'm &notit; I tell you
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "I'm ¬it; I tell you"
+
+#data
+I'm &notin; I tell you
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "I'm ∉ I tell you"
+
+#data
+FOO& BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO& BAR"
+
+#data
+FOO&<BAR>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&"
+|     <bar>
+
+#data
+FOO&&&&gt;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&&&>BAR"
+
+#data
+FOO&#41;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO)BAR"
+
+#data
+FOO&#x41;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOABAR"
+
+#data
+FOO&#X41;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOABAR"
+
+#data
+FOO&#BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&#BAR"
+
+#data
+FOO&#ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&#ZOO"
+
+#data
+FOO&#xBAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOºR"
+
+#data
+FOO&#xZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&#xZOO"
+
+#data
+FOO&#XZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&#XZOO"
+
+#data
+FOO&#41BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO)BAR"
+
+#data
+FOO&#x41BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO䆺R"
+
+#data
+FOO&#x41ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOAZOO"
+
+#data
+FOO&#x0000;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#x000D;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO\rZOO"
+
+#data
+FOO&#x0078;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOxZOO"
+
+#data
+FOO&#x0079;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOyZOO"
+
+#data
+FOO&#x0080;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO€ZOO"
+
+#data
+FOO&#x0081;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO\81ZOO"
+
+#data
+FOO&#x0082;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‚ZOO"
+
+#data
+FOO&#x0083;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOƒZOO"
+
+#data
+FOO&#x0084;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO„ZOO"
+
+#data
+FOO&#x0085;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO…ZOO"
+
+#data
+FOO&#x0086;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO†ZOO"
+
+#data
+FOO&#x0087;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‡ZOO"
+
+#data
+FOO&#x0088;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOˆZOO"
+
+#data
+FOO&#x0089;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‰ZOO"
+
+#data
+FOO&#x008A;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOŠZOO"
+
+#data
+FOO&#x008B;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‹ZOO"
+
+#data
+FOO&#x008C;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOŒZOO"
+
+#data
+FOO&#x008D;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO\8dZOO"
+
+#data
+FOO&#x008E;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOŽZOO"
+
+#data
+FOO&#x008F;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO\8fZOO"
+
+#data
+FOO&#x0090;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO\90ZOO"
+
+#data
+FOO&#x0091;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‘ZOO"
+
+#data
+FOO&#x0092;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO’ZOO"
+
+#data
+FOO&#x0093;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO“ZOO"
+
+#data
+FOO&#x0094;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO”ZOO"
+
+#data
+FOO&#x0095;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO•ZOO"
+
+#data
+FOO&#x0096;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO–ZOO"
+
+#data
+FOO&#x0097;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO—ZOO"
+
+#data
+FOO&#x0098;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO˜ZOO"
+
+#data
+FOO&#x0099;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO™ZOO"
+
+#data
+FOO&#x009A;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOšZOO"
+
+#data
+FOO&#x009B;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO›ZOO"
+
+#data
+FOO&#x009C;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOœZOO"
+
+#data
+FOO&#x009D;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO\9dZOO"
+
+#data
+FOO&#x009E;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOžZOO"
+
+#data
+FOO&#x009F;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOŸZOO"
+
+#data
+FOO&#x00A0;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO ZOO"
+
+#data
+FOO&#xD7FF;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO퟿ZOO"
+
+#data
+FOO&#xD800;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xD801;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xDFFE;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xDFFF;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xE000;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOZOO"
+
+#data
+FOO&#x10FFFE;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO􏿾ZOO"
+
+#data
+FOO&#x1087D4;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO􈟔ZOO"
+
+#data
+FOO&#x10FFFF;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO􏿿ZOO"
+
+#data
+FOO&#x110000;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xFFFFFF;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
diff --git a/libgo/go/html/testdata/webkit/entities02.dat b/libgo/go/html/testdata/webkit/entities02.dat
new file mode 100644 (file)
index 0000000..0b4dd66
--- /dev/null
@@ -0,0 +1,129 @@
+#data
+<div bar="ZZ&gt;YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ>YY"
+
+#data
+<div bar="ZZ&"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&"
+
+#data
+<div bar='ZZ&'></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&"
+
+#data
+<div bar=ZZ&></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&"
+
+#data
+<div bar="ZZ&gt=YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gt=YY"
+
+#data
+<div bar="ZZ&gt0YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gt0YY"
+
+#data
+<div bar="ZZ&gt9YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gt9YY"
+
+#data
+<div bar="ZZ&gtaYY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gtaYY"
+
+#data
+<div bar="ZZ&gtZYY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gtZYY"
+
+#data
+<div bar="ZZ&gt YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ> YY"
+
+#data
+<div bar="ZZ&gt"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ>"
+
+#data
+<div bar='ZZ&gt'></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ>"
+
+#data
+<div bar=ZZ&gt></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ>"
diff --git a/libgo/go/html/testdata/webkit/scriptdata01.dat b/libgo/go/html/testdata/webkit/scriptdata01.dat
new file mode 100644 (file)
index 0000000..76b67f4
--- /dev/null
@@ -0,0 +1,308 @@
+#data
+FOO<script>'Hello'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'Hello'"
+|     "BAR"
+
+#data
+FOO<script></script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script></script >BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script></script/>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script></script/ >BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script type="text/plain"></scriptx>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "</scriptx>BAR"
+
+#data
+FOO<script></script foo=">" dd>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script>'<'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<'"
+|     "BAR"
+
+#data
+FOO<script>'<!'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!'"
+|     "BAR"
+
+#data
+FOO<script>'<!-'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-'"
+|     "BAR"
+
+#data
+FOO<script>'<!--'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!--'"
+|     "BAR"
+
+#data
+FOO<script>'<!---'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!---'"
+|     "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-->'"
+|     "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-->'"
+|     "BAR"
+
+#data
+FOO<script>'<!-- potato'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-- potato'"
+|     "BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-- <sCrIpt'"
+|     "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt>'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt> -'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt> --'</script>BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt> -->'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-- <sCrIpt> -->'"
+|     "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --!>'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt> --!>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -- >'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt> -- >'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt '</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt '</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt/'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt\'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt\'"
+|     "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR</script>QUX
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt/'</script>BAR"
+|     "QUX"
diff --git a/libgo/go/html/testdata/webkit/tests1.dat b/libgo/go/html/testdata/webkit/tests1.dat
new file mode 100644 (file)
index 0000000..ad58d31
--- /dev/null
@@ -0,0 +1,1949 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "Test"
+
+#data
+<p>One<p>Two
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "One"
+|     <p>
+|       "Two"
+
+#data
+Line1<br>Line2<br>Line3<br>Line4
+#errors
+Line: 1 Col: 5 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "Line1"
+|     <br>
+|     "Line2"
+|     <br>
+|     "Line3"
+|     <br>
+|     "Line4"
+
+#data
+<html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head></head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head></head><body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head></head><body></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (body).
+Line: 1 Col: 26 Unexpected end tag (html).
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<head></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+</head>
+#errors
+Line: 1 Col: 7 Unexpected end tag (head). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+</body>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (body) after the (implied) root element.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+</html>
+#errors
+Line: 1 Col: 7 Unexpected end tag (html). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <i>
+
+#data
+<b><table><td></b><i></table>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 30 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <i>
+|       "X"
+
+#data
+<h1>Hello<h2>World
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Heading cannot be a child of another heading.
+18: End of file seen and there were open elements.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <h1>
+|       "Hello"
+|     <h2>
+|       "World"
+
+#data
+<a><p>X<a>Y</a>Z</p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 10 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <p>
+|       <a>
+|         "X"
+|       <a>
+|         "Y"
+|       "Z"
+
+#data
+<b><button></b></button></b>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <button>
+
+#data
+<p><b><div><marquee></p></b></div>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|     <div>
+|       <b>
+|         <marquee>
+|           <p>
+|           "X"
+
+#data
+<script><div></script></div><title><p></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end tag (div). Ignored.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<div>"
+|     <title>
+|       "<p>"
+|   <body>
+|     <p>
+|     <p>
+
+#data
+<!--><div>--<!-->
+#errors
+Line: 1 Col: 5 Incorrect comment.
+Line: 1 Col: 10 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Incorrect comment.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <!--  -->
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "--"
+|       <!--  -->
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <hr>
+|     <p>
+
+#data
+<select><b><option><select><option></b></select>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 49 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|     <option>
+|       "X"
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 63 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 64 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <a>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <a>
+|                 <table>
+|               <a>
+|     <a>
+|       <b>
+|         "X"
+|       "C"
+|     <a>
+|       "Y"
+
+#data
+<a X>0<b>1<a Y>2
+#errors
+Line: 1 Col: 5 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       x=""
+|       "0"
+|       <b>
+|         "1"
+|     <b>
+|       <a>
+|         y=""
+|         "2"
+
+#data
+<!-----><font><div>hello<table>excite!<b>me!<th><i>please!</tr><!--X-->
+#errors
+Line: 1 Col: 7 Unexpected '-' after '--' found in comment.
+Line: 1 Col: 14 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected start tag (b) in table context caused voodoo mode.
+Line: 1 Col: 48 Unexpected implied end tag (b) in the table phase.
+Line: 1 Col: 48 Unexpected table cell start tag (th) in the table body phase.
+Line: 1 Col: 63 Got table cell end tag (th) while required end tags are missing.
+Line: 1 Col: 71 Unexpected end of file. Expected table content.
+#document
+| <!-- - -->
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       <div>
+|         "helloexcite!"
+|         <b>
+|           "me!"
+|         <table>
+|           <tbody>
+|             <tr>
+|               <th>
+|                 <i>
+|                   "please!"
+|             <!-- X -->
+
+#data
+<!DOCTYPE html><li>hello<li>world<ul>how<li>do</ul>you</body><!--do-->
+#errors
+Line: 1 Col: 61 Unexpected end tag (li). Missing end tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <li>
+|       "hello"
+|     <li>
+|       "world"
+|       <ul>
+|         "how"
+|         <li>
+|           "do"
+|       "you"
+|   <!-- do -->
+
+#data
+<!DOCTYPE html>A<option>B<optgroup>C<select>D</option>E
+#errors
+Line: 1 Col: 54 Unexpected end tag (option) in the select phase. Ignored.
+Line: 1 Col: 55 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "A"
+|     <option>
+|       "B"
+|     <optgroup>
+|       "C"
+|       <select>
+|         "DE"
+
+#data
+<
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "<"
+
+#data
+<#
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "<#"
+
+#data
+</
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected end of file.
+Line: 1 Col: 2 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "</"
+
+#data
+</#
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character '#' found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ? -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?#
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?# -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!--  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!#
+#errors
+Line: 1 Col: 3 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?COMMENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 11 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COMMENT? -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!COMMENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 10 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COMMENT -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+</ COMMENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!--  COMMENT  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?COM--MENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 13 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COM--MENT? -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!COM--MENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COM--MENT -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+</ COM--MENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 14 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!--  COM--MENT  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><style> EOF
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       " EOF"
+|   <body>
+
+#data
+<!DOCTYPE html><script> <!-- </script> --> </script> EOF
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       " <!-- "
+|     " "
+|   <body>
+|     "-->  EOF"
+
+#data
+<b><p></b>TEST
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 10 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|     <p>
+|       <b>
+|       "TEST"
+
+#data
+<p id=a><b><p id=b></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (p). Ignored.
+Line: 1 Col: 23 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       id="a"
+|       <b>
+|     <p>
+|       id="b"
+|       "TEST"
+
+#data
+<b id=a><p><b id=b></p></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (p). Ignored.
+Line: 1 Col: 27 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 31 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       id="a"
+|       <p>
+|         <b>
+|           id="b"
+|       "TEST"
+
+#data
+<!DOCTYPE html><title>U-test</title><body><div><p>Test<u></p></div></body>
+#errors
+Line: 1 Col: 61 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "U-test"
+|   <body>
+|     <div>
+|       <p>
+|         "Test"
+|         <u>
+
+#data
+<!DOCTYPE html><font><table></font></table></font>
+#errors
+Line: 1 Col: 35 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 35 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       <table>
+
+#data
+<font><p>hello<b>cruel</font>world
+#errors
+Line: 1 Col: 6 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|     <p>
+|       <font>
+|         "hello"
+|         <b>
+|           "cruel"
+|       <b>
+|         "world"
+
+#data
+<b>Test</i>Test
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 11 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "TestTest"
+
+#data
+<b>A<cite>B<div>C
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "A"
+|       <cite>
+|         "B"
+|         <div>
+|           "C"
+
+#data
+<b>A<cite>B<div>C</cite>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end tag (cite). Ignored.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "A"
+|       <cite>
+|         "B"
+|         <div>
+|           "CD"
+
+#data
+<b>A<cite>B<div>C</b>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 21 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 22 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "A"
+|       <cite>
+|         "B"
+|     <div>
+|       <b>
+|         "C"
+|       "D"
+
+#data
+<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST
+#errors
+Line: 1 Col: 6 Unexpected start tag (cite). Expected DOCTYPE.
+Line: 1 Col: 46 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 50 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <cite>
+|       <b>
+|         <cite>
+|           <i>
+|             <cite>
+|               <i>
+|                 <cite>
+|                   <i>
+|       <i>
+|         <i>
+|           <i>
+|             <div>
+|               <b>
+|                 "X"
+|               "TEST"
+
+#data
+
+#errors
+Line: 1 Col: 0 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<DIV>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 5 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+
+#data
+<DIV> abc
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 9 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc"
+
+#data
+<DIV> abc <B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+
+#data
+<DIV> abc <B> def
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def"
+
+#data
+<DIV> abc <B> def <I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+
+#data
+<DIV> abc <B> def <I> ghi
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi"
+
+#data
+<DIV> abc <B> def <I> ghi <P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|           <p>
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|           <p>
+|             " jkl"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|         <p>
+|           <b>
+|             " jkl "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|         <p>
+|           <b>
+|             " jkl "
+|           " mno"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|       <p>
+|         <i>
+|           <b>
+|             " jkl "
+|           " mno "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|       <p>
+|         <i>
+|           <b>
+|             " jkl "
+|           " mno "
+|         " pqr"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|       <p>
+|         <i>
+|           <b>
+|             " jkl "
+|           " mno "
+|         " pqr "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> stu
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 60 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|       <p>
+|         <i>
+|           <b>
+|             " jkl "
+|           " mno "
+|         " pqr "
+|       " stu"
+
+#data
+<test attribute---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
+#errors
+Line: 1 Col: 1040 Unexpected start tag (test). Expected DOCTYPE.
+Line: 1 Col: 1040 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <test>
+|       attribute----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------=""
+
+#data
+<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 39 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 39 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 39 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 45 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="blah"
+|       "aba"
+|       <a>
+|         href="foo"
+|         "br"
+|       <a>
+|         href="foo"
+|         "x"
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|     <a>
+|       href="foo"
+|       "aoe"
+
+#data
+<a href="blah">aba<table><tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 60 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="blah"
+|       "abax"
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <a>
+|                 href="foo"
+|                 "br"
+|       "aoe"
+
+#data
+<table><a href="blah">aba<tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 29 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="blah"
+|       "aba"
+|     <a>
+|       href="blah"
+|       "x"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <a>
+|               href="foo"
+|               "br"
+|     <a>
+|       href="blah"
+|       "aoe"
+
+#data
+<a href=a>aa<marquee>aa<a href=b>bb</marquee>aa
+#errors
+Line: 1 Col: 10 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 45 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="a"
+|       "aa"
+|       <marquee>
+|         "aa"
+|         <a>
+|           href="b"
+|           "bb"
+|       "aa"
+
+#data
+<wbr><strike><code></strike><code><strike></code>
+#errors
+Line: 1 Col: 5 Unexpected start tag (wbr). Expected DOCTYPE.
+Line: 1 Col: 28 End tag (strike) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 49 Unexpected end tag (code). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <wbr>
+|     <strike>
+|       <code>
+|     <code>
+|       <code>
+|         <strike>
+
+#data
+<title><meta></title><link><title><meta></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       "<meta>"
+|     <link>
+|     <title>
+|       "<meta>"
+|   <body>
+
+#data
+<style><!--</style><meta><script>--><link></script>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|     <meta>
+|     <script>
+|       "--><link>"
+|   <body>
+
+#data
+<head><meta></head><link>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected start tag (link) that can be in head. Moved.
+#document
+| <html>
+|   <head>
+|     <meta>
+|     <link>
+|   <body>
+
+#data
+<table><tr><tr><td><td><span><th><span>X</table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 33 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 48 Got table cell end tag (th) while required end tags are missing.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|         <tr>
+|           <td>
+|           <td>
+|             <span>
+|           <th>
+|             <span>
+|               "X"
+
+#data
+<body><body><base><link><meta><title><p></title><body><p></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (body).
+Line: 1 Col: 54 Unexpected start tag (body).
+Line: 1 Col: 64 Unexpected end tag (p). Missing end tag (body).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <base>
+|     <link>
+|     <meta>
+|     <title>
+|       "<p>"
+|     <p>
+
+#data
+<textarea><p></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<p>"
+
+#data
+<p><image></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (image). Treated as img.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <img>
+
+#data
+<a><table><a></table><p><a><div><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 13 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 13 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 21 Unexpected end tag (table). Expected end tag (a).
+Line: 1 Col: 27 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 27 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 32 Unexpected end tag (p). Ignored.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 35 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <a>
+|       <table>
+|     <p>
+|       <a>
+|     <div>
+|       <a>
+
+#data
+<head></p><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end tag (p). Ignored.
+#document
+| <html>
+|   <head>
+|     <meta>
+|   <body>
+|     <p>
+
+#data
+<head></html><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected start tag (meta).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <meta>
+|     <p>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <i>
+
+#data
+<b><table><td></b><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <i>
+
+#data
+<h1><h2>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+8: Heading cannot be a child of another heading.
+8: End of file seen and there were open elements.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <h1>
+|     <h2>
+
+#data
+<a><p><a></a></p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 9 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 21 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <p>
+|       <a>
+|       <a>
+
+#data
+<b><button></b></button></b>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <button>
+
+#data
+<p><b><div><marquee></p></b></div>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|     <div>
+|       <b>
+|         <marquee>
+|           <p>
+
+#data
+<script></script></div><title></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (div). Ignored.
+#document
+| <html>
+|   <head>
+|     <script>
+|     <title>
+|   <body>
+|     <p>
+|     <p>
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <hr>
+|     <p>
+
+#data
+<select><b><option><select><option></b></select>
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 48 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|     <option>
+
+#data
+<html><head><title></title><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|   <body>
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 54 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 54 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <a>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <a>
+|                 <table>
+|               <a>
+|     <a>
+
+#data
+<ul><li></li><div><li></div><li><li><div><li><address><li><b><em></b><li></ul>
+#errors
+Line: 1 Col: 4 Unexpected start tag (ul). Expected DOCTYPE.
+Line: 1 Col: 45 Missing end tag (div, li).
+Line: 1 Col: 58 Missing end tag (address, li).
+Line: 1 Col: 69 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|       <div>
+|         <li>
+|       <li>
+|       <li>
+|         <div>
+|       <li>
+|         <address>
+|       <li>
+|         <b>
+|           <em>
+|       <li>
+
+#data
+<ul><li><ul></li><li>a</li></ul></li></ul>
+#errors
+XXX: fix me
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|         <ul>
+|           <li>
+|             "a"
+
+#data
+<frameset><frame><frameset><frame></frameset><noframes></noframes></frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+|     <frameset>
+|       <frame>
+|     <noframes>
+
+#data
+<h1><table><td><h3></table><h3></h1>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+15: “td” start tag in table body.
+27: Unclosed elements.
+31: Heading cannot be a child of another heading.
+36: End tag “h1” seen but there were unclosed elements.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <h1>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <h3>
+|     <h3>
+
+#data
+<table><colgroup><col><colgroup><col><col><col><colgroup><col><col><thead><tr><td></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+|         <col>
+|       <colgroup>
+|         <col>
+|         <col>
+|         <col>
+|       <colgroup>
+|         <col>
+|         <col>
+|       <thead>
+|         <tr>
+|           <td>
+
+#data
+<table><col><tbody><col><tr><col><td><col></table><col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 55 Unexpected start tag col. Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+|         <col>
+|       <tbody>
+|       <colgroup>
+|         <col>
+|       <tbody>
+|         <tr>
+|       <colgroup>
+|         <col>
+|       <tbody>
+|         <tr>
+|           <td>
+|       <colgroup>
+|         <col>
+
+#data
+<table><colgroup><tbody><colgroup><tr><colgroup><td><colgroup></table><colgroup>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 52 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 80 Unexpected start tag colgroup. Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+|       <tbody>
+|       <colgroup>
+|       <tbody>
+|         <tr>
+|       <colgroup>
+|       <tbody>
+|         <tr>
+|           <td>
+|       <colgroup>
+
+#data
+</strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element.
+Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element.
+Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element.
+Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element.
+Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element.
+Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element.
+Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element.
+Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element.
+Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element.
+Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element.
+Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element.
+Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element.
+Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element.
+Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element.
+Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element.
+Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element.
+Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element.
+Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element.
+Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element.
+Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element.
+Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element.
+Line: 1 Col: 130 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 140 This element (img) has no end tag.
+Line: 1 Col: 148 Unexpected end tag (title). Ignored.
+Line: 1 Col: 155 Unexpected end tag (span). Ignored.
+Line: 1 Col: 163 Unexpected end tag (style). Ignored.
+Line: 1 Col: 172 Unexpected end tag (script). Ignored.
+Line: 1 Col: 180 Unexpected end tag (table). Ignored.
+Line: 1 Col: 185 Unexpected end tag (th). Ignored.
+Line: 1 Col: 190 Unexpected end tag (td). Ignored.
+Line: 1 Col: 195 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 203 This element (frame) has no end tag.
+Line: 1 Col: 210 This element (area) has no end tag.
+Line: 1 Col: 217 Unexpected end tag (link). Ignored.
+Line: 1 Col: 225 This element (param) has no end tag.
+Line: 1 Col: 230 This element (hr) has no end tag.
+Line: 1 Col: 238 This element (input) has no end tag.
+Line: 1 Col: 244 Unexpected end tag (col). Ignored.
+Line: 1 Col: 251 Unexpected end tag (base). Ignored.
+Line: 1 Col: 258 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 269 This element (basefont) has no end tag.
+Line: 1 Col: 279 This element (bgsound) has no end tag.
+Line: 1 Col: 287 This element (embed) has no end tag.
+Line: 1 Col: 296 This element (spacer) has no end tag.
+Line: 1 Col: 300 Unexpected end tag (p). Ignored.
+Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 320 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 339 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 355 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 393 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 460 This element (wbr) has no end tag.
+Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 513 Unexpected end tag (html). Ignored.
+Line: 1 Col: 513 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 520 Unexpected end tag (head). Ignored.
+Line: 1 Col: 529 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 537 This element (image) has no end tag.
+Line: 1 Col: 547 This element (isindex) has no end tag.
+Line: 1 Col: 557 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 568 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 599 Unexpected end tag (option). Ignored.
+Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 622 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <br>
+|     <p>
+
+#data
+<table><tr></strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode.
+Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode.
+Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode.
+Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode.
+Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode.
+Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (blink). Ignored.
+Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode.
+Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode.
+Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag.
+Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode.
+Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode.
+Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode.
+Line: 1 Col: 99 Unexpected end tag (select). Ignored.
+Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode.
+Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag.
+Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode.
+Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag.
+Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode.
+Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag.
+Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode.
+Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag.
+Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode.
+Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag.
+Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode.
+Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag.
+Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored.
+Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode.
+Line: 1 Col: 141 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode.
+Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode.
+Line: 1 Col: 151 This element (img) has no end tag.
+Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode.
+Line: 1 Col: 159 Unexpected end tag (title). Ignored.
+Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 166 Unexpected end tag (span). Ignored.
+Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode.
+Line: 1 Col: 174 Unexpected end tag (style). Ignored.
+Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode.
+Line: 1 Col: 183 Unexpected end tag (script). Ignored.
+Line: 1 Col: 196 Unexpected end tag (th). Ignored.
+Line: 1 Col: 201 Unexpected end tag (td). Ignored.
+Line: 1 Col: 206 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 214 This element (frame) has no end tag.
+Line: 1 Col: 221 This element (area) has no end tag.
+Line: 1 Col: 228 Unexpected end tag (link). Ignored.
+Line: 1 Col: 236 This element (param) has no end tag.
+Line: 1 Col: 241 This element (hr) has no end tag.
+Line: 1 Col: 249 This element (input) has no end tag.
+Line: 1 Col: 255 Unexpected end tag (col). Ignored.
+Line: 1 Col: 262 Unexpected end tag (base). Ignored.
+Line: 1 Col: 269 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 280 This element (basefont) has no end tag.
+Line: 1 Col: 290 This element (bgsound) has no end tag.
+Line: 1 Col: 298 This element (embed) has no end tag.
+Line: 1 Col: 307 This element (spacer) has no end tag.
+Line: 1 Col: 311 Unexpected end tag (p). Ignored.
+Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 331 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 350 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 366 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 404 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 471 This element (wbr) has no end tag.
+Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 524 Unexpected end tag (html). Ignored.
+Line: 1 Col: 524 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 531 Unexpected end tag (head). Ignored.
+Line: 1 Col: 540 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 548 This element (image) has no end tag.
+Line: 1 Col: 558 This element (isindex) has no end tag.
+Line: 1 Col: 568 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 590 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 610 Unexpected end tag (option). Ignored.
+Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 633 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <br>
+|     <table>
+|       <tbody>
+|         <tr>
+|     <p>
+
+#data
+<frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <frameset>
diff --git a/libgo/go/html/testdata/webkit/tests10.dat b/libgo/go/html/testdata/webkit/tests10.dat
new file mode 100644 (file)
index 0000000..877c9a3
--- /dev/null
@@ -0,0 +1,430 @@
+#data
+<!DOCTYPE html><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<!DOCTYPE html><body><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<!DOCTYPE html><body><select><svg></svg></select>
+#errors
+35: Stray “svg” start tag.
+42: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!DOCTYPE html><body><select><option><svg></svg></option></select>
+#errors
+43: Stray “svg” start tag.
+50: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+
+#data
+<!DOCTYPE html><body><table><svg></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+41: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+53: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g><g>bar</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+58: Stray end tag “g”.
+65: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><svg><g>foo</g><g>bar</g></svg></tbody></table>
+#errors
+41: Start tag “svg” seen in “table”.
+53: Stray end tag “g”.
+65: Stray end tag “g”.
+72: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <table>
+|       <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><svg><g>foo</g><g>bar</g></svg></tr></tbody></table>
+#errors
+45: Start tag “svg” seen in “table”.
+57: Stray end tag “g”.
+69: Stray end tag “g”.
+76: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|               <svg g>
+|                 "foo"
+|               <svg g>
+|                 "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|               <svg g>
+|                 "foo"
+|               <svg g>
+|                 "bar"
+|             <p>
+|               "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g></svg><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <svg svg>
+|           <svg g>
+|             "foo"
+|           <svg g>
+|             "bar"
+|         <p>
+|           "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+70: HTML start tag “p” in a foreign namespace context.
+81: “table” closed but “caption” was still open.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <svg svg>
+|           <svg g>
+|             "foo"
+|           <svg g>
+|             "bar"
+|         <p>
+|           "baz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g>baz</table><p>quux
+#errors
+78: “table” closed but “caption” was still open.
+78: Unclosed elements on stack.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <svg svg>
+|           <svg g>
+|             "foo"
+|           <svg g>
+|             "bar"
+|           "baz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+44: Start tag “svg” seen in “table”.
+56: Stray end tag “g”.
+68: Stray end tag “g”.
+71: HTML start tag “p” in a foreign namespace context.
+71: Start tag “p” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <p>
+|       "baz"
+|     <table>
+|       <colgroup>
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+50: Stray “svg” start tag.
+54: Stray “g” start tag.
+62: Stray end tag “g”
+66: Stray “g” start tag.
+74: Stray end tag “g”
+77: Stray “p” start tag.
+88: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <select>
+|               "foobarbaz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+36: Start tag “select” seen in “table”.
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+54: Stray end tag “g”
+58: Stray “g” start tag.
+66: Stray end tag “g”
+69: Stray “p” start tag.
+80: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       "foobarbaz"
+|     <table>
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body></body></html><svg><g>foo</g><g>bar</g><p>baz
+#errors
+41: Stray “svg” start tag.
+68: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <p>
+|       "baz"
+
+#data
+<!DOCTYPE html><body></body><svg><g>foo</g><g>bar</g><p>baz
+#errors
+34: Stray “svg” start tag.
+61: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <p>
+|       "baz"
+
+#data
+<!DOCTYPE html><frameset><svg><g></g><g></g><p><span>
+#errors
+31: Stray “svg” start tag.
+35: Stray “g” start tag.
+40: Stray end tag “g”
+44: Stray “g” start tag.
+49: Stray end tag “g”
+52: Stray “p” start tag.
+58: Stray “span” start tag.
+58: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><svg><g></g><g></g><p><span>
+#errors
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+51: Stray end tag “g”
+55: Stray “g” start tag.
+60: Stray end tag “g”
+63: Stray “p” start tag.
+69: Stray “span” start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><svg xlink:href=foo></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     <svg svg>
+|       xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo></g></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <svg svg>
+|       <svg g>
+|         xlink href="foo"
+|         xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <svg svg>
+|       <svg g>
+|         xlink href="foo"
+|         xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo />bar</svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <svg svg>
+|       <svg g>
+|         xlink href="foo"
+|         xml lang="en"
+|       "bar"
diff --git a/libgo/go/html/testdata/webkit/tests11.dat b/libgo/go/html/testdata/webkit/tests11.dat
new file mode 100644 (file)
index 0000000..638cde4
--- /dev/null
@@ -0,0 +1,482 @@
+#data
+<!DOCTYPE html><body><svg attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       attributeName=""
+|       attributeType=""
+|       baseFrequency=""
+|       baseProfile=""
+|       calcMode=""
+|       clipPathUnits=""
+|       contentScriptType=""
+|       contentStyleType=""
+|       diffuseConstant=""
+|       edgeMode=""
+|       externalResourcesRequired=""
+|       filterRes=""
+|       filterUnits=""
+|       glyphRef=""
+|       gradientTransform=""
+|       gradientUnits=""
+|       kernelMatrix=""
+|       kernelUnitLength=""
+|       keyPoints=""
+|       keySplines=""
+|       keyTimes=""
+|       lengthAdjust=""
+|       limitingConeAngle=""
+|       markerHeight=""
+|       markerUnits=""
+|       markerWidth=""
+|       maskContentUnits=""
+|       maskUnits=""
+|       numOctaves=""
+|       pathLength=""
+|       patternContentUnits=""
+|       patternTransform=""
+|       patternUnits=""
+|       pointsAtX=""
+|       pointsAtY=""
+|       pointsAtZ=""
+|       preserveAlpha=""
+|       preserveAspectRatio=""
+|       primitiveUnits=""
+|       refX=""
+|       refY=""
+|       repeatCount=""
+|       repeatDur=""
+|       requiredExtensions=""
+|       requiredFeatures=""
+|       specularConstant=""
+|       specularExponent=""
+|       spreadMethod=""
+|       startOffset=""
+|       stdDeviation=""
+|       stitchTiles=""
+|       surfaceScale=""
+|       systemLanguage=""
+|       tableValues=""
+|       targetX=""
+|       targetY=""
+|       textLength=""
+|       viewBox=""
+|       viewTarget=""
+|       xChannelSelector=""
+|       yChannelSelector=""
+|       zoomAndPan=""
+
+#data
+<!DOCTYPE html><BODY><SVG ATTRIBUTENAME='' ATTRIBUTETYPE='' BASEFREQUENCY='' BASEPROFILE='' CALCMODE='' CLIPPATHUNITS='' CONTENTSCRIPTTYPE='' CONTENTSTYLETYPE='' DIFFUSECONSTANT='' EDGEMODE='' EXTERNALRESOURCESREQUIRED='' FILTERRES='' FILTERUNITS='' GLYPHREF='' GRADIENTTRANSFORM='' GRADIENTUNITS='' KERNELMATRIX='' KERNELUNITLENGTH='' KEYPOINTS='' KEYSPLINES='' KEYTIMES='' LENGTHADJUST='' LIMITINGCONEANGLE='' MARKERHEIGHT='' MARKERUNITS='' MARKERWIDTH='' MASKCONTENTUNITS='' MASKUNITS='' NUMOCTAVES='' PATHLENGTH='' PATTERNCONTENTUNITS='' PATTERNTRANSFORM='' PATTERNUNITS='' POINTSATX='' POINTSATY='' POINTSATZ='' PRESERVEALPHA='' PRESERVEASPECTRATIO='' PRIMITIVEUNITS='' REFX='' REFY='' REPEATCOUNT='' REPEATDUR='' REQUIREDEXTENSIONS='' REQUIREDFEATURES='' SPECULARCONSTANT='' SPECULAREXPONENT='' SPREADMETHOD='' STARTOFFSET='' STDDEVIATION='' STITCHTILES='' SURFACESCALE='' SYSTEMLANGUAGE='' TABLEVALUES='' TARGETX='' TARGETY='' TEXTLENGTH='' VIEWBOX='' VIEWTARGET='' XCHANNELSELECTOR='' YCHANNELSELECTOR='' ZOOMANDPAN=''></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       attributeName=""
+|       attributeType=""
+|       baseFrequency=""
+|       baseProfile=""
+|       calcMode=""
+|       clipPathUnits=""
+|       contentScriptType=""
+|       contentStyleType=""
+|       diffuseConstant=""
+|       edgeMode=""
+|       externalResourcesRequired=""
+|       filterRes=""
+|       filterUnits=""
+|       glyphRef=""
+|       gradientTransform=""
+|       gradientUnits=""
+|       kernelMatrix=""
+|       kernelUnitLength=""
+|       keyPoints=""
+|       keySplines=""
+|       keyTimes=""
+|       lengthAdjust=""
+|       limitingConeAngle=""
+|       markerHeight=""
+|       markerUnits=""
+|       markerWidth=""
+|       maskContentUnits=""
+|       maskUnits=""
+|       numOctaves=""
+|       pathLength=""
+|       patternContentUnits=""
+|       patternTransform=""
+|       patternUnits=""
+|       pointsAtX=""
+|       pointsAtY=""
+|       pointsAtZ=""
+|       preserveAlpha=""
+|       preserveAspectRatio=""
+|       primitiveUnits=""
+|       refX=""
+|       refY=""
+|       repeatCount=""
+|       repeatDur=""
+|       requiredExtensions=""
+|       requiredFeatures=""
+|       specularConstant=""
+|       specularExponent=""
+|       spreadMethod=""
+|       startOffset=""
+|       stdDeviation=""
+|       stitchTiles=""
+|       surfaceScale=""
+|       systemLanguage=""
+|       tableValues=""
+|       targetX=""
+|       targetY=""
+|       textLength=""
+|       viewBox=""
+|       viewTarget=""
+|       xChannelSelector=""
+|       yChannelSelector=""
+|       zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><svg attributename='' attributetype='' basefrequency='' baseprofile='' calcmode='' clippathunits='' contentscripttype='' contentstyletype='' diffuseconstant='' edgemode='' externalresourcesrequired='' filterres='' filterunits='' glyphref='' gradienttransform='' gradientunits='' kernelmatrix='' kernelunitlength='' keypoints='' keysplines='' keytimes='' lengthadjust='' limitingconeangle='' markerheight='' markerunits='' markerwidth='' maskcontentunits='' maskunits='' numoctaves='' pathlength='' patterncontentunits='' patterntransform='' patternunits='' pointsatx='' pointsaty='' pointsatz='' preservealpha='' preserveaspectratio='' primitiveunits='' refx='' refy='' repeatcount='' repeatdur='' requiredextensions='' requiredfeatures='' specularconstant='' specularexponent='' spreadmethod='' startoffset='' stddeviation='' stitchtiles='' surfacescale='' systemlanguage='' tablevalues='' targetx='' targety='' textlength='' viewbox='' viewtarget='' xchannelselector='' ychannelselector='' zoomandpan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       attributeName=""
+|       attributeType=""
+|       baseFrequency=""
+|       baseProfile=""
+|       calcMode=""
+|       clipPathUnits=""
+|       contentScriptType=""
+|       contentStyleType=""
+|       diffuseConstant=""
+|       edgeMode=""
+|       externalResourcesRequired=""
+|       filterRes=""
+|       filterUnits=""
+|       glyphRef=""
+|       gradientTransform=""
+|       gradientUnits=""
+|       kernelMatrix=""
+|       kernelUnitLength=""
+|       keyPoints=""
+|       keySplines=""
+|       keyTimes=""
+|       lengthAdjust=""
+|       limitingConeAngle=""
+|       markerHeight=""
+|       markerUnits=""
+|       markerWidth=""
+|       maskContentUnits=""
+|       maskUnits=""
+|       numOctaves=""
+|       pathLength=""
+|       patternContentUnits=""
+|       patternTransform=""
+|       patternUnits=""
+|       pointsAtX=""
+|       pointsAtY=""
+|       pointsAtZ=""
+|       preserveAlpha=""
+|       preserveAspectRatio=""
+|       primitiveUnits=""
+|       refX=""
+|       refY=""
+|       repeatCount=""
+|       repeatDur=""
+|       requiredExtensions=""
+|       requiredFeatures=""
+|       specularConstant=""
+|       specularExponent=""
+|       spreadMethod=""
+|       startOffset=""
+|       stdDeviation=""
+|       stitchTiles=""
+|       surfaceScale=""
+|       systemLanguage=""
+|       tableValues=""
+|       targetX=""
+|       targetY=""
+|       textLength=""
+|       viewBox=""
+|       viewTarget=""
+|       xChannelSelector=""
+|       yChannelSelector=""
+|       zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><math attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       attributename=""
+|       attributetype=""
+|       basefrequency=""
+|       baseprofile=""
+|       calcmode=""
+|       clippathunits=""
+|       contentscripttype=""
+|       contentstyletype=""
+|       diffuseconstant=""
+|       edgemode=""
+|       externalresourcesrequired=""
+|       filterres=""
+|       filterunits=""
+|       glyphref=""
+|       gradienttransform=""
+|       gradientunits=""
+|       kernelmatrix=""
+|       kernelunitlength=""
+|       keypoints=""
+|       keysplines=""
+|       keytimes=""
+|       lengthadjust=""
+|       limitingconeangle=""
+|       markerheight=""
+|       markerunits=""
+|       markerwidth=""
+|       maskcontentunits=""
+|       maskunits=""
+|       numoctaves=""
+|       pathlength=""
+|       patterncontentunits=""
+|       patterntransform=""
+|       patternunits=""
+|       pointsatx=""
+|       pointsaty=""
+|       pointsatz=""
+|       preservealpha=""
+|       preserveaspectratio=""
+|       primitiveunits=""
+|       refx=""
+|       refy=""
+|       repeatcount=""
+|       repeatdur=""
+|       requiredextensions=""
+|       requiredfeatures=""
+|       specularconstant=""
+|       specularexponent=""
+|       spreadmethod=""
+|       startoffset=""
+|       stddeviation=""
+|       stitchtiles=""
+|       surfacescale=""
+|       systemlanguage=""
+|       tablevalues=""
+|       targetx=""
+|       targety=""
+|       textlength=""
+|       viewbox=""
+|       viewtarget=""
+|       xchannelselector=""
+|       ychannelselector=""
+|       zoomandpan=""
+
+#data
+<!DOCTYPE html><body><svg><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg altGlyph>
+|       <svg altGlyphDef>
+|       <svg altGlyphItem>
+|       <svg animateColor>
+|       <svg animateMotion>
+|       <svg animateTransform>
+|       <svg clipPath>
+|       <svg feBlend>
+|       <svg feColorMatrix>
+|       <svg feComponentTransfer>
+|       <svg feComposite>
+|       <svg feConvolveMatrix>
+|       <svg feDiffuseLighting>
+|       <svg feDisplacementMap>
+|       <svg feDistantLight>
+|       <svg feFlood>
+|       <svg feFuncA>
+|       <svg feFuncB>
+|       <svg feFuncG>
+|       <svg feFuncR>
+|       <svg feGaussianBlur>
+|       <svg feImage>
+|       <svg feMerge>
+|       <svg feMergeNode>
+|       <svg feMorphology>
+|       <svg feOffset>
+|       <svg fePointLight>
+|       <svg feSpecularLighting>
+|       <svg feSpotLight>
+|       <svg feTile>
+|       <svg feTurbulence>
+|       <svg foreignObject>
+|       <svg glyphRef>
+|       <svg linearGradient>
+|       <svg radialGradient>
+|       <svg textPath>
+
+#data
+<!DOCTYPE html><body><svg><altglyph /><altglyphdef /><altglyphitem /><animatecolor /><animatemotion /><animatetransform /><clippath /><feblend /><fecolormatrix /><fecomponenttransfer /><fecomposite /><feconvolvematrix /><fediffuselighting /><fedisplacementmap /><fedistantlight /><feflood /><fefunca /><fefuncb /><fefuncg /><fefuncr /><fegaussianblur /><feimage /><femerge /><femergenode /><femorphology /><feoffset /><fepointlight /><fespecularlighting /><fespotlight /><fetile /><feturbulence /><foreignobject /><glyphref /><lineargradient /><radialgradient /><textpath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg altGlyph>
+|       <svg altGlyphDef>
+|       <svg altGlyphItem>
+|       <svg animateColor>
+|       <svg animateMotion>
+|       <svg animateTransform>
+|       <svg clipPath>
+|       <svg feBlend>
+|       <svg feColorMatrix>
+|       <svg feComponentTransfer>
+|       <svg feComposite>
+|       <svg feConvolveMatrix>
+|       <svg feDiffuseLighting>
+|       <svg feDisplacementMap>
+|       <svg feDistantLight>
+|       <svg feFlood>
+|       <svg feFuncA>
+|       <svg feFuncB>
+|       <svg feFuncG>
+|       <svg feFuncR>
+|       <svg feGaussianBlur>
+|       <svg feImage>
+|       <svg feMerge>
+|       <svg feMergeNode>
+|       <svg feMorphology>
+|       <svg feOffset>
+|       <svg fePointLight>
+|       <svg feSpecularLighting>
+|       <svg feSpotLight>
+|       <svg feTile>
+|       <svg feTurbulence>
+|       <svg foreignObject>
+|       <svg glyphRef>
+|       <svg linearGradient>
+|       <svg radialGradient>
+|       <svg textPath>
+
+#data
+<!DOCTYPE html><BODY><SVG><ALTGLYPH /><ALTGLYPHDEF /><ALTGLYPHITEM /><ANIMATECOLOR /><ANIMATEMOTION /><ANIMATETRANSFORM /><CLIPPATH /><FEBLEND /><FECOLORMATRIX /><FECOMPONENTTRANSFER /><FECOMPOSITE /><FECONVOLVEMATRIX /><FEDIFFUSELIGHTING /><FEDISPLACEMENTMAP /><FEDISTANTLIGHT /><FEFLOOD /><FEFUNCA /><FEFUNCB /><FEFUNCG /><FEFUNCR /><FEGAUSSIANBLUR /><FEIMAGE /><FEMERGE /><FEMERGENODE /><FEMORPHOLOGY /><FEOFFSET /><FEPOINTLIGHT /><FESPECULARLIGHTING /><FESPOTLIGHT /><FETILE /><FETURBULENCE /><FOREIGNOBJECT /><GLYPHREF /><LINEARGRADIENT /><RADIALGRADIENT /><TEXTPATH /></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg altGlyph>
+|       <svg altGlyphDef>
+|       <svg altGlyphItem>
+|       <svg animateColor>
+|       <svg animateMotion>
+|       <svg animateTransform>
+|       <svg clipPath>
+|       <svg feBlend>
+|       <svg feColorMatrix>
+|       <svg feComponentTransfer>
+|       <svg feComposite>
+|       <svg feConvolveMatrix>
+|       <svg feDiffuseLighting>
+|       <svg feDisplacementMap>
+|       <svg feDistantLight>
+|       <svg feFlood>
+|       <svg feFuncA>
+|       <svg feFuncB>
+|       <svg feFuncG>
+|       <svg feFuncR>
+|       <svg feGaussianBlur>
+|       <svg feImage>
+|       <svg feMerge>
+|       <svg feMergeNode>
+|       <svg feMorphology>
+|       <svg feOffset>
+|       <svg fePointLight>
+|       <svg feSpecularLighting>
+|       <svg feSpotLight>
+|       <svg feTile>
+|       <svg feTurbulence>
+|       <svg foreignObject>
+|       <svg glyphRef>
+|       <svg linearGradient>
+|       <svg radialGradient>
+|       <svg textPath>
+
+#data
+<!DOCTYPE html><body><math><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math altglyph>
+|       <math altglyphdef>
+|       <math altglyphitem>
+|       <math animatecolor>
+|       <math animatemotion>
+|       <math animatetransform>
+|       <math clippath>
+|       <math feblend>
+|       <math fecolormatrix>
+|       <math fecomponenttransfer>
+|       <math fecomposite>
+|       <math feconvolvematrix>
+|       <math fediffuselighting>
+|       <math fedisplacementmap>
+|       <math fedistantlight>
+|       <math feflood>
+|       <math fefunca>
+|       <math fefuncb>
+|       <math fefuncg>
+|       <math fefuncr>
+|       <math fegaussianblur>
+|       <math feimage>
+|       <math femerge>
+|       <math femergenode>
+|       <math femorphology>
+|       <math feoffset>
+|       <math fepointlight>
+|       <math fespecularlighting>
+|       <math fespotlight>
+|       <math fetile>
+|       <math feturbulence>
+|       <math foreignobject>
+|       <math glyphref>
+|       <math lineargradient>
+|       <math radialgradient>
+|       <math textpath>
+
+#data
+<!DOCTYPE html><body><svg><solidColor /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg solidcolor>
diff --git a/libgo/go/html/testdata/webkit/tests12.dat b/libgo/go/html/testdata/webkit/tests12.dat
new file mode 100644 (file)
index 0000000..63107d2
--- /dev/null
@@ -0,0 +1,62 @@
+#data
+<!DOCTYPE html><body><p>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "foo"
+|       <math math>
+|         <math mtext>
+|           <i>
+|             "baz"
+|         <math annotation-xml>
+|           <svg svg>
+|             <svg desc>
+|               <b>
+|                 "eggs"
+|             <svg g>
+|               <svg foreignObject>
+|                 <p>
+|                   "spam"
+|                 <table>
+|                   <tbody>
+|                     <tr>
+|                       <td>
+|                         <img>
+|             <svg g>
+|               "quux"
+|       "bar"
+
+#data
+<!DOCTYPE html><body>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "foo"
+|     <math math>
+|       <math mtext>
+|         <i>
+|           "baz"
+|       <math annotation-xml>
+|         <svg svg>
+|           <svg desc>
+|             <b>
+|               "eggs"
+|           <svg g>
+|             <svg foreignObject>
+|               <p>
+|                 "spam"
+|               <table>
+|                 <tbody>
+|                   <tr>
+|                     <td>
+|                       <img>
+|           <svg g>
+|             "quux"
+|     "bar"
diff --git a/libgo/go/html/testdata/webkit/tests13.dat b/libgo/go/html/testdata/webkit/tests13.dat
new file mode 100644 (file)
index 0000000..d180e8e
--- /dev/null
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<html><head>
+<title>404 Not Found</title>
+</head><body>
+<h1>Not Found</h1>
+<p>The requested URL /html5lib-tests/data/tests13.dat was not found on this server.</p>
+<p>Additionally, a 404 Not Found
+error was encountered while trying to use an ErrorDocument to handle the request.</p>
+</body></html>
diff --git a/libgo/go/html/testdata/webkit/tests14.dat b/libgo/go/html/testdata/webkit/tests14.dat
new file mode 100644 (file)
index 0000000..72f8015
--- /dev/null
@@ -0,0 +1,74 @@
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <xyz:abc>
+
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc><span></span>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <xyz:abc>
+|     <span>
+
+#data
+<!DOCTYPE html><html><html abc:def=gh><xyz:abc></xyz:abc>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+|   abc:def="gh"
+|   <head>
+|   <body>
+|     <xyz:abc>
+
+#data
+<!DOCTYPE html><html xml:lang=bar><html xml:lang=foo>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+|   xml:lang="bar"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><html 123=456>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   123="456"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><html 123=456><html 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   123="456"
+|   789="012"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><html><body 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     789="012"
\ No newline at end of file
diff --git a/libgo/go/html/testdata/webkit/tests15.dat b/libgo/go/html/testdata/webkit/tests15.dat
new file mode 100644 (file)
index 0000000..7f016ca
--- /dev/null
@@ -0,0 +1,208 @@
+#data
+<!DOCTYPE html><p><b><i><u></p> <p>X
+#errors
+Line: 1 Col: 31 Unexpected end tag (p). Ignored.
+Line: 1 Col: 36 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|         <i>
+|           <u>
+|     <b>
+|       <i>
+|         <u>
+|           " "
+|           <p>
+|             "X"
+
+#data
+<p><b><i><u></p>
+<p>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag (p). Ignored.
+Line: 2 Col: 4 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|         <i>
+|           <u>
+|     <b>
+|       <i>
+|         <u>
+|           "
+"
+|           <p>
+|             "X"
+
+#data
+<!doctype html></html> <head>
+#errors
+Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " "
+
+#data
+<!doctype html></body><meta>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <meta>
+
+#data
+<html></html><!-- foo -->
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+|   <head>
+|   <body>
+| <!--  foo  -->
+
+#data
+<!doctype html></body><title>X</title>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "X"
+
+#data
+<!doctype html><table> X<meta></table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " X"
+|     <meta>
+|     <table>
+
+#data
+<!doctype html><table> x</table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " x"
+|     <table>
+
+#data
+<!doctype html><table> x </table>
+#errors
+Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " x "
+|     <table>
+
+#data
+<!doctype html><table><tr> x</table>
+#errors
+Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " x"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table>X<style> <tr>x </style> </table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <table>
+|       <style>
+|         " <tr>x "
+|       " "
+
+#data
+<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div>
+#errors
+Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <a>
+|         "foo"
+|       <table>
+|         " "
+|         <tbody>
+|           <tr>
+|             <td>
+|               "bar"
+|             " "
+
+#data
+<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes>
+#errors
+6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Stray start tag “frame”.
+21: Stray end tag “frame”.
+29: Stray end tag “frame”.
+39: “frameset” start tag after “body” already open.
+105: End of file seen inside an [R]CDATA element.
+105: End of file seen and there were open elements.
+XXX: These errors are wrong, please fix me!
+#document
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+|     <frameset>
+|       <frame>
+|     <noframes>
+|       "</frameset><noframes>"
+
+#data
+<!DOCTYPE html><object></html>
+#errors
+1: Expected closing tag. Unexpected end of file
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <object>
\ No newline at end of file
diff --git a/libgo/go/html/testdata/webkit/tests16.dat b/libgo/go/html/testdata/webkit/tests16.dat
new file mode 100644 (file)
index 0000000..937dba9
--- /dev/null
@@ -0,0 +1,2277 @@
+#data
+<!doctype html><script>
+#errors
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<!doctype html><script>a
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "a"
+|   <body>
+
+#data
+<!doctype html><script><
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<"
+|   <body>
+
+#data
+<!doctype html><script></
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</"
+|   <body>
+
+#data
+<!doctype html><script></S
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</S"
+|   <body>
+
+#data
+<!doctype html><script></SC
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SC"
+|   <body>
+
+#data
+<!doctype html><script></SCR
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SCR"
+|   <body>
+
+#data
+<!doctype html><script></SCRI
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SCRI"
+|   <body>
+
+#data
+<!doctype html><script></SCRIP
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SCRIP"
+|   <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SCRIPT"
+|   <body>
+
+#data
+<!doctype html><script></SCRIPT 
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<!doctype html><script></s
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</s"
+|   <body>
+
+#data
+<!doctype html><script></sc
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</sc"
+|   <body>
+
+#data
+<!doctype html><script></scr
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</scr"
+|   <body>
+
+#data
+<!doctype html><script></scri
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</scri"
+|   <body>
+
+#data
+<!doctype html><script></scrip
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</scrip"
+|   <body>
+
+#data
+<!doctype html><script></script
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</script"
+|   <body>
+
+#data
+<!doctype html><script></script 
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<!doctype html><script><!
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!"
+|   <body>
+
+#data
+<!doctype html><script><!a
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!a"
+|   <body>
+
+#data
+<!doctype html><script><!-
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!-"
+|   <body>
+
+#data
+<!doctype html><script><!-a
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!-a"
+|   <body>
+
+#data
+<!doctype html><script><!--
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--"
+|   <body>
+
+#data
+<!doctype html><script><!--a
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--a"
+|   <body>
+
+#data
+<!doctype html><script><!--<
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<"
+|   <body>
+
+#data
+<!doctype html><script><!--<a
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<a"
+|   <body>
+
+#data
+<!doctype html><script><!--</
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--</"
+|   <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--</script"
+|   <body>
+
+#data
+<!doctype html><script><!--</script 
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--"
+|   <body>
+
+#data
+<!doctype html><script><!--<s
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<s"
+|   <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script"
+|   <body>
+
+#data
+<!doctype html><script><!--<script 
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script <
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script <"
+|   <body>
+
+#data
+<!doctype html><script><!--<script <a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script <a"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </s
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </s"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+Line: 1 Col: 43 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </scripta
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </scripta"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script 
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script>
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script>"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script/
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script/"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script <
+#errors
+Line: 1 Col: 45 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script <"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script <a
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script <a"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script </"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script </script"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </script 
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </script/
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script -
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -"
+|   <body>
+
+#data
+<!doctype html><script><!--<script -a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -a"
+|   <body>
+
+#data
+<!doctype html><script><!--<script -<
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -<"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --a
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --a"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --<
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --<"
+|   <body>
+
+#data
+<!doctype html><script><!--<script -->
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --><
+#errors
+Line: 1 Col: 39 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --><"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></
+#errors
+Line: 1 Col: 40 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --></"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --></script"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></script 
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></script/
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script><\/script>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script><\/script>-->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></scr'+'ipt>-->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>--><!--</script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>--><!--"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-- ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>-- >"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- -></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>- ->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- - ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>- - >"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 49 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script>--!></script>X"
+|   <body>
+
+#data
+<!doctype html><script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 59 Unexpected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<scr'+'ipt>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 57 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></scr'+'ipt></script>X"
+|   <body>
+
+#data
+<!doctype html><style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 52 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--<style>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><style><!--</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|   <body>
+|     "X"
+
+#data
+<!doctype html><style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--..."
+|   <body>
+|     "...-->"
+
+#data
+<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+|   <body>
+|     "X"
+
+#data
+<!doctype html><style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 66 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--...<style><!--...--!>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><style><!--...</style><!-- --><style>@import ...</style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--..."
+|     <!--   -->
+|     <style>
+|       "@import ..."
+|   <body>
+
+#data
+<!doctype html><style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 63 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "...<style><!--..."
+|     <!--   -->
+|   <body>
+
+#data
+<!doctype html><style>...<!--[if IE]><style>...</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "...<!--[if IE]><style>..."
+|   <body>
+|     "X"
+
+#data
+<!doctype html><title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 52 Unexpected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "<!--<title>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><title>&lt;/title></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "</title>"
+|   <body>
+
+#data
+<!doctype html><title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "foo/title><link></head><body>X"
+|   <body>
+
+#data
+<!doctype html><noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noscript).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--<noscript>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--"
+|   <body>
+|     "X"
+|     <noscript>
+|       "-->"
+
+#data
+<!doctype html><noscript><iframe></noscript>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noscript>
+|       "<iframe>"
+|   <body>
+|     "X"
+
+#data
+<!doctype html><noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noframes).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noframes>
+|       "<!--<noframes>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><noframes><body><script><!--...</script></body></noframes></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noframes>
+|       "<body><script><!--...</script></body>"
+|   <body>
+
+#data
+<!doctype html><textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 64 Unexpected end tag (textarea).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<!--<textarea>"
+|     "-->"
+
+#data
+<!doctype html><textarea>&lt;/textarea></textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "</textarea>"
+
+#data
+<!doctype html><iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 56 Unexpected end tag (iframe).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       "<!--<iframe>"
+|     "-->"
+
+#data
+<!doctype html><iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       "...<!--X->...<!--/X->..."
+
+#data
+<!doctype html><xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 44 Unexpected end tag (xmp).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <xmp>
+|       "<!--<xmp>"
+|     "-->"
+
+#data
+<!doctype html><noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 60 Unexpected end tag (noembed).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <noembed>
+|       "<!--<noembed>"
+|     "-->"
+
+#data
+<script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<script>a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "a"
+|   <body>
+
+#data
+<script><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<"
+|   <body>
+
+#data
+<script></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</"
+|   <body>
+
+#data
+<script></S
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</S"
+|   <body>
+
+#data
+<script></SC
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SC"
+|   <body>
+
+#data
+<script></SCR
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SCR"
+|   <body>
+
+#data
+<script></SCRI
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SCRI"
+|   <body>
+
+#data
+<script></SCRIP
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SCRIP"
+|   <body>
+
+#data
+<script></SCRIPT
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SCRIPT"
+|   <body>
+
+#data
+<script></SCRIPT 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<script></s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</s"
+|   <body>
+
+#data
+<script></sc
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</sc"
+|   <body>
+
+#data
+<script></scr
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</scr"
+|   <body>
+
+#data
+<script></scri
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</scri"
+|   <body>
+
+#data
+<script></scrip
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</scrip"
+|   <body>
+
+#data
+<script></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</script"
+|   <body>
+
+#data
+<script></script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<script><!
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!"
+|   <body>
+
+#data
+<script><!a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!a"
+|   <body>
+
+#data
+<script><!-
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!-"
+|   <body>
+
+#data
+<script><!-a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!-a"
+|   <body>
+
+#data
+<script><!--
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--"
+|   <body>
+
+#data
+<script><!--a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--a"
+|   <body>
+
+#data
+<script><!--<
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<"
+|   <body>
+
+#data
+<script><!--<a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<a"
+|   <body>
+
+#data
+<script><!--</
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--</"
+|   <body>
+
+#data
+<script><!--</script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--</script"
+|   <body>
+
+#data
+<script><!--</script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--"
+|   <body>
+
+#data
+<script><!--<s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<s"
+|   <body>
+
+#data
+<script><!--<script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script"
+|   <body>
+
+#data
+<script><!--<script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script "
+|   <body>
+
+#data
+<script><!--<script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script <"
+|   <body>
+
+#data
+<script><!--<script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script <a"
+|   <body>
+
+#data
+<script><!--<script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </"
+|   <body>
+
+#data
+<script><!--<script </s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </s"
+|   <body>
+
+#data
+<script><!--<script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script"
+|   <body>
+
+#data
+<script><!--<script </scripta
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </scripta"
+|   <body>
+
+#data
+<script><!--<script </script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<script><!--<script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script>"
+|   <body>
+
+#data
+<script><!--<script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script/"
+|   <body>
+
+#data
+<script><!--<script </script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script <"
+|   <body>
+
+#data
+<script><!--<script </script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script <a"
+|   <body>
+
+#data
+<script><!--<script </script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script </"
+|   <body>
+
+#data
+<script><!--<script </script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script </script"
+|   <body>
+
+#data
+<script><!--<script </script </script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<script><!--<script </script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<script><!--<script </script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<script><!--<script -
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -"
+|   <body>
+
+#data
+<script><!--<script -a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -a"
+|   <body>
+
+#data
+<script><!--<script --
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --"
+|   <body>
+
+#data
+<script><!--<script --a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --a"
+|   <body>
+
+#data
+<script><!--<script -->
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<script><!--<script --><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --><"
+|   <body>
+
+#data
+<script><!--<script --></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --></"
+|   <body>
+
+#data
+<script><!--<script --></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --></script"
+|   <body>
+
+#data
+<script><!--<script --></script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<script><!--<script --></script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<script><!--<script --></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<script><!--<script><\/script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script><\/script>-->"
+|   <body>
+
+#data
+<script><!--<script></scr'+'ipt>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></scr'+'ipt>-->"
+|   <body>
+
+#data
+<script><!--<script></script><script></script></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>--><!--</script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>--><!--"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>-- ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>-- >"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>- -></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>- ->"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>- - ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>- - >"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>-></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>->"
+|   <body>
+
+#data
+<script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script>--!></script>X"
+|   <body>
+
+#data
+<script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 44 Unexpected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<scr'+'ipt>"
+|   <body>
+|     "-->"
+
+#data
+<script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 42 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></scr'+'ipt></script>X"
+|   <body>
+
+#data
+<style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--<style>"
+|   <body>
+|     "-->"
+
+#data
+<style><!--</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|   <body>
+|     "X"
+
+#data
+<style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 36 Unexpected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--..."
+|   <body>
+|     "...-->"
+
+#data
+<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+|   <body>
+|     "X"
+
+#data
+<style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--...<style><!--...--!>"
+|   <body>
+|     "-->"
+
+#data
+<style><!--...</style><!-- --><style>@import ...</style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--..."
+|     <!--   -->
+|     <style>
+|       "@import ..."
+|   <body>
+
+#data
+<style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 48 Unexpected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "...<style><!--..."
+|     <!--   -->
+|   <body>
+
+#data
+<style>...<!--[if IE]><style>...</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       "...<!--[if IE]><style>..."
+|   <body>
+|     "X"
+
+#data
+<title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (title).
+#document
+| <html>
+|   <head>
+|     <title>
+|       "<!--<title>"
+|   <body>
+|     "-->"
+
+#data
+<title>&lt;/title></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       "</title>"
+|   <body>
+
+#data
+<title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+|   <head>
+|     <title>
+|       "foo/title><link></head><body>X"
+|   <body>
+
+#data
+<noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noscript).
+#document
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--<noscript>"
+|   <body>
+|     "-->"
+
+#data
+<noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--"
+|   <body>
+|     "X"
+|     <noscript>
+|       "-->"
+
+#data
+<noscript><iframe></noscript>X
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <noscript>
+|       "<iframe>"
+|   <body>
+|     "X"
+
+#data
+<noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noframes).
+#document
+| <html>
+|   <head>
+|     <noframes>
+|       "<!--<noframes>"
+|   <body>
+|     "-->"
+
+#data
+<noframes><body><script><!--...</script></body></noframes></html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <noframes>
+|       "<body><script><!--...</script></body>"
+|   <body>
+
+#data
+<textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (textarea).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<!--<textarea>"
+|     "-->"
+
+#data
+<textarea>&lt;/textarea></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "</textarea>"
+
+#data
+<iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+Line: 1 Col: 41 Unexpected end tag (iframe).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       "<!--<iframe>"
+|     "-->"
+
+#data
+<iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       "...<!--X->...<!--/X->..."
+
+#data
+<xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end tag (xmp).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <xmp>
+|       "<!--<xmp>"
+|     "-->"
+
+#data
+<noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE.
+Line: 1 Col: 45 Unexpected end tag (noembed).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <noembed>
+|       "<!--<noembed>"
+|     "-->"
+
+#data
+<!doctype html><table>
+
+#errors
+Line 2 Col 0 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       "
+"
+
+#data
+<!doctype html><table><td><span><font></span><span>
+#errors
+Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase.
+Line 1 Col 45 Unexpected end tag (span).
+Line 1 Col 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <span>
+|               <font>
+|             <font>
+|               <span>
+
+#data
+<!doctype html><form><table></form><form></table></form>
+#errors
+35: Stray end tag “form”.
+41: Start tag “form” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <table>
+|         <form>
diff --git a/libgo/go/html/testdata/webkit/tests2.dat b/libgo/go/html/testdata/webkit/tests2.dat
new file mode 100644 (file)
index 0000000..d33996e
--- /dev/null
@@ -0,0 +1,738 @@
+#data
+<!DOCTYPE html>Test
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "Test"
+
+#data
+<textarea>test</div>test
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 24 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "test</div>test"
+
+#data
+<table><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 11 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><td>test</tbody></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "test"
+
+#data
+<frame>test
+#errors
+Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected start tag frame. Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "test"
+
+#data
+<!DOCTYPE html><frameset>test
+#errors
+Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><frameset><!DOCTYPE html>
+#errors
+Line: 1 Col: 40 Unexpected DOCTYPE. Ignored.
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><font><p><b>test</font>
+#errors
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|     <p>
+|       <font>
+|         <b>
+|           "test"
+
+#data
+<!DOCTYPE html><dt><div><dd>
+#errors
+Line: 1 Col: 28 Missing end tag (div, dt).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <dt>
+|       <div>
+|     <dd>
+
+#data
+<script></x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</x"
+|   <body>
+
+#data
+<table><plaintext><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "<td>"
+|     <table>
+
+#data
+<plaintext></plaintext>
+#errors
+Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+
+#data
+<!DOCTYPE html><table><tr>TEST
+#errors
+Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "TEST"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4>
+#errors
+Line: 1 Col: 37 Unexpected start tag (body).
+Line: 1 Col: 53 Unexpected start tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     t1="1"
+|     t2="2"
+|     t3="3"
+|     t4="4"
+
+#data
+</b test
+#errors
+Line: 1 Col: 8 Unexpected end of file in attribute name.
+Line: 1 Col: 8 End tag contains unexpected attributes.
+Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html></b test<b &=&amp>X
+#errors
+Line: 1 Col: 32 Named entity didn't end with ';'.
+Line: 1 Col: 33 End tag contains unexpected attributes.
+Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+
+#data
+<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 54 Unexpected end of file in the tag name.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       type="text/x-foobar;baz"
+|       "X</SCRipt"
+|   <body>
+
+#data
+&
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&"
+
+#data
+&#
+#errors
+Line: 1 Col: 1 Numeric entity expected. Got end of file instead.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&#"
+
+#data
+&#X
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&#X"
+
+#data
+&#x
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&#x"
+
+#data
+&#45
+#errors
+Line: 1 Col: 4 Numeric entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "-"
+
+#data
+&x-test
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&x-test"
+
+#data
+<!doctypehtml><p><li>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <li>
+
+#data
+<!doctypehtml><p><dt>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <dt>
+
+#data
+<!doctypehtml><p><dd>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <dd>
+
+#data
+<!doctypehtml><p><form>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <form>
+
+#data
+<!DOCTYPE html><p></P>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     "X"
+
+#data
+&AMP
+#errors
+Line: 1 Col: 4 Named entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&"
+
+#data
+&AMp;
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&AMp;"
+
+#data
+<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY>
+#errors
+Line: 1 Col: 110 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly>
+
+#data
+<!DOCTYPE html>X</body>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "XX"
+
+#data
+<!DOCTYPE html><!-- X
+#errors
+Line: 1 Col: 21 Unexpected end of file in comment.
+#document
+| <!DOCTYPE html>
+| <!--  X -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><table><caption>test TEST</caption><td>test
+#errors
+Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         "test TEST"
+|       <tbody>
+|         <tr>
+|           <td>
+|             "test"
+
+#data
+<!DOCTYPE html><select><option><optgroup>
+#errors
+Line: 1 Col: 41 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|       <optgroup>
+
+#data
+<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>
+#errors
+Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 76 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <optgroup>
+|         <option>
+|       <option>
+|     <option>
+
+#data
+<!DOCTYPE html><select><optgroup><option><optgroup>
+#errors
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <optgroup>
+|         <option>
+|       <optgroup>
+
+#data
+<!DOCTYPE html><font><input><input></font>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       <input>
+|       <input>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!--  XXX - XXX  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX
+#errors
+Line: 1 Col: 29 Unexpected end of file in comment (-)
+#document
+| <!DOCTYPE html>
+| <!--  XXX - XXX -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!--  XXX - XXX - XXX  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<isindex test=x name=x>
+#errors
+Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected start tag isindex. Don't use it!
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Insert your search keywords here: "
+|         <input>
+|           name="isindex"
+|           test="x"
+|       <hr>
+
+#data
+test
+test
+#errors
+Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "test
+test"
+
+#data
+<!DOCTYPE html><body><title>test</body></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "test</body>"
+
+#data
+<!DOCTYPE html><body><title>X</title><meta name=z><link rel=foo><style>
+x { content:"</style" } </style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "X"
+|     <meta>
+|       name="z"
+|     <link>
+|       rel="foo"
+|     <style>
+|       "
+x { content:"</style" } "
+
+#data
+<!DOCTYPE html><select><optgroup></optgroup></select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <optgroup>
+
+#data
+#errors
+Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html>  <html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><script>
+</script>  <title>x</title>  </head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "
+"
+|     "  "
+|     <title>
+|       "x"
+|     "  "
+|   <body>
+
+#data
+<!DOCTYPE html><html><body><html id=x>
+#errors
+Line: 1 Col: 38 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   id="x"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html>X</body><html id="x">
+#errors
+Line: 1 Col: 36 Unexpected start tag token (html) in the after body phase.
+Line: 1 Col: 36 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   id="x"
+|   <head>
+|   <body>
+|     "X"
+
+#data
+<!DOCTYPE html><head><html id=x>
+#errors
+Line: 1 Col: 32 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   id="x"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html>X</html>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "XX"
+
+#data
+<!DOCTYPE html>X</html> 
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X "
+
+#data
+<!DOCTYPE html>X</html><p>X
+#errors
+Line: 1 Col: 26 Unexpected start tag (p).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <p>
+|       "X"
+
+#data
+<!DOCTYPE html>X<p/x/y/z>
+#errors
+Line: 1 Col: 19 Expected a > after the /.
+Line: 1 Col: 21 Solidus (/) incorrectly placed in tag.
+Line: 1 Col: 23 Solidus (/) incorrectly placed in tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <p>
+|       x=""
+|       y=""
+|       z=""
+
+#data
+<!DOCTYPE html><!--x--
+#errors
+Line: 1 Col: 22 Unexpected end of file in comment (--).
+#document
+| <!DOCTYPE html>
+| <!-- x -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><table><tr><td></p></table>
+#errors
+Line: 1 Col: 34 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <p>
+
+#data
+<!DOCTYPE <!DOCTYPE HTML>><!--<!--x-->-->
+#errors
+Line: 1 Col: 20 Expected space or '>'. Got ''
+Line: 1 Col: 25 Erroneous DOCTYPE.
+Line: 1 Col: 35 Unexpected character in comment found.
+#document
+| <!DOCTYPE <!doctype>
+| <html>
+|   <head>
+|   <body>
+|     ">"
+|     <!-- <!--x -->
+|     "-->"
diff --git a/libgo/go/html/testdata/webkit/tests3.dat b/libgo/go/html/testdata/webkit/tests3.dat
new file mode 100644 (file)
index 0000000..b0781a8
--- /dev/null
@@ -0,0 +1,293 @@
+#data
+<head></head><style></style>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+|   <head>
+|     <style>
+|   <body>
+
+#data
+<head></head><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved.
+#document
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<head></head><!-- --><style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+|   <head>
+|     <style>
+|     <script>
+|   <!--   -->
+|   <!--   -->
+|   <body>
+
+#data
+<head></head><!-- -->x<style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <!--   -->
+|   <body>
+|     "x"
+|     <style>
+|     <!--   -->
+|     <script>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "foo
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x</pre><span>
+</span></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "x"
+|     <span>
+|       "
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x
+y</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "x
+y"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x<div>
+y</pre></body></html>
+#errors
+Line: 2 Col: 7 End tag (pre) seen too early. Expected other end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "x"
+|       <div>
+|         "
+y"
+
+#data
+<!DOCTYPE html><HTML><META><HEAD></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <meta>
+|   <body>
+
+#data
+<!DOCTYPE html><HTML><HEAD><head></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<textarea>foo<span>bar</span><i>baz
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "foo<span>bar</span><i>baz"
+
+#data
+<title>foo<span>bar</em><i>baz
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+|   <head>
+|     <title>
+|       "foo<span>bar</em><i>baz"
+|   <body>
+
+#data
+<!DOCTYPE html><textarea>
+</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+
+#data
+<!DOCTYPE html><textarea>
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "foo"
+
+#data
+<!DOCTYPE html><textarea>
+
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><ul><li><div><p><li></ul></body></html>
+#errors
+Line: 1 Col: 60 Missing end tag (div, li).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|         <div>
+|           <p>
+|       <li>
+
+#data
+<!doctype html><nobr><nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <nobr>
+|     <nobr>
+|     <nobr>
+
+#data
+<!doctype html><nobr><nobr></nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <nobr>
+|     <nobr>
+|     <nobr>
+
+#data
+<!doctype html><html><body><p><table></table></body></html>
+#errors
+Not known
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <table>
+
+#data
+<p><table></table>
+#errors
+Not known
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <table>
diff --git a/libgo/go/html/testdata/webkit/tests4.dat b/libgo/go/html/testdata/webkit/tests4.dat
new file mode 100644 (file)
index 0000000..3c50632
--- /dev/null
@@ -0,0 +1,59 @@
+#data
+direct div content
+#errors
+#document-fragment
+div
+#document
+| "direct div content"
+
+#data
+direct textarea content
+#errors
+#document-fragment
+textarea
+#document
+| "direct textarea content"
+
+#data
+textarea content with <em>pseudo</em> <foo>markup
+#errors
+#document-fragment
+textarea
+#document
+| "textarea content with <em>pseudo</em> <foo>markup"
+
+#data
+this is &#x0043;DATA inside a <style> element
+#errors
+#document-fragment
+style
+#document
+| "this is &#x0043;DATA inside a <style> element"
+
+#data
+</plaintext>
+#errors
+#document-fragment
+plaintext
+#document
+| "</plaintext>"
+
+#data
+setting html's innerHTML
+#errors
+Line: 1 Col: 24 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+|   "setting html's innerHTML"
+
+#data
+<title>setting head's innerHTML</title>
+#errors
+#document-fragment
+head
+#document
+| <title>
+|   "setting head's innerHTML"
diff --git a/libgo/go/html/testdata/webkit/tests5.dat b/libgo/go/html/testdata/webkit/tests5.dat
new file mode 100644 (file)
index 0000000..d7b5128
--- /dev/null
@@ -0,0 +1,191 @@
+#data
+<style> <!-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!-- "
+|   <body>
+|     "x"
+
+#data
+<style> <!-- </style> --> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!-- "
+|     " "
+|   <body>
+|     "--> x"
+
+#data
+<style> <!--> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!--> "
+|   <body>
+|     "x"
+
+#data
+<style> <!---> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!---> "
+|   <body>
+|     "x"
+
+#data
+<iframe> <!---> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       " <!---> "
+|     "x"
+
+#data
+<iframe> <!--- </iframe>->x</iframe> --> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       " <!--- "
+|     "->x --> x"
+
+#data
+<script> <!-- </script> --> </script>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       " <!-- "
+|     " "
+|   <body>
+|     "--> x"
+
+#data
+<title> <!-- </title> --> </title>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       " <!-- "
+|     " "
+|   <body>
+|     "--> x"
+
+#data
+<textarea> <!--- </textarea>->x</textarea> --> </textarea>x
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       " <!--- "
+|     "->x --> x"
+
+#data
+<style> <!</-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!</-- "
+|   <body>
+|     "x"
+
+#data
+<p><xmp></xmp>
+#errors
+XXX: Unknown
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <xmp>
+
+#data
+<xmp> <!-- > --> </xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <xmp>
+|       " <!-- > --> "
+
+#data
+<title>&amp;</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       "&"
+|   <body>
+
+#data
+<title><!--&amp;--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       "<!--&-->"
+|   <body>
+
+#data
+<title><!--</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+|   <head>
+|     <title>
+|       "<!--"
+|   <body>
+
+#data
+<noscript><!--</noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--"
+|   <body>
+|     "-->"
diff --git a/libgo/go/html/testdata/webkit/tests6.dat b/libgo/go/html/testdata/webkit/tests6.dat
new file mode 100644 (file)
index 0000000..2fb7996
--- /dev/null
@@ -0,0 +1,653 @@
+#data
+<!doctype html></head> <head>
+#errors
+Line: 1 Col: 29 Unexpected start tag head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   " "
+|   <body>
+
+#data
+<!doctype html><form><div></form><div>
+#errors
+33: End tag "form" seen but there were unclosed elements.
+38: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <div>
+|         <div>
+
+#data
+<!doctype html><title>&amp;</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "&"
+|   <body>
+
+#data
+<!doctype html><title><!--&amp;--></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "<!--&-->"
+|   <body>
+
+#data
+<!doctype>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 10 Unexpected > character. Expected DOCTYPE name.
+Line: 1 Col: 10 Erroneous DOCTYPE.
+#document
+| <!DOCTYPE >
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!---x
+#errors
+Line: 1 Col: 6 Unexpected end of file in comment.
+Line: 1 Col: 6 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- -x -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<body>
+<div>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body).
+Line: 2 Col: 5 Expected closing tag. Unexpected end of file.
+#document-fragment
+div
+#document
+| "
+"
+| <div>
+
+#data
+<frameset></frameset>
+foo
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 3 Unexpected non-space characters in the after frameset phase. Ignored.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+
+#data
+<frameset></frameset>
+<noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+|   <noframes>
+
+#data
+<frameset></frameset>
+<div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 5 Unexpected start tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+
+#data
+<frameset></frameset>
+</html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+
+#data
+<frameset></frameset>
+</div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 6 Unexpected end tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+
+#data
+<form><form>
+#errors
+Line: 1 Col: 6 Unexpected start tag (form). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (form).
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+
+#data
+<button><button>
+#errors
+Line: 1 Col: 8 Unexpected start tag (button). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (button) implies end tag (button).
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <button>
+|     <button>
+
+#data
+<table><tr><td></th>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (th). Ignored.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><caption><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (td). Ignored.
+Line: 1 Col: 20 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><caption><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <div>
+
+#data
+</caption><div>
+#errors
+Line: 1 Col: 10 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption><div></caption>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end tag (caption). Missing end tag (div).
+Line: 1 Col: 31 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <div>
+
+#data
+<table><caption></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+
+#data
+</table><div>
+#errors
+Line: 1 Col: 8 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 8 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption></body></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (body). Ignored.
+Line: 1 Col: 29 Unexpected end tag (col). Ignored.
+Line: 1 Col: 40 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 47 Unexpected end tag (html). Ignored.
+Line: 1 Col: 55 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 60 Unexpected end tag (td). Ignored.
+Line: 1 Col: 68 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 73 Unexpected end tag (th). Ignored.
+Line: 1 Col: 81 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 86 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 86 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+
+#data
+<table><caption><div></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 27 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <div>
+
+#data
+<table><tr><td></body></caption></col></colgroup></html>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (body). Ignored.
+Line: 1 Col: 32 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 38 Unexpected end tag (col). Ignored.
+Line: 1 Col: 49 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 56 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+</table></tbody></tfoot></thead></tr><div>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 24 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 32 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 37 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document-fragment
+td
+#document
+| <div>
+
+#data
+<table><colgroup>foo
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "foo"
+|     <table>
+|       <colgroup>
+
+#data
+foo<col>
+#errors
+Line: 1 Col: 3 Unexpected end tag (colgroup). Ignored.
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<table><colgroup></col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 This element (col) has no end tag.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+
+#data
+<frameset><div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+</frameset><frame>
+#errors
+Line: 1 Col: 11 Unexpected end tag token (frameset) in the frameset phase (innerHTML).
+#document-fragment
+frameset
+#document
+| <frame>
+
+#data
+<frameset></div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+</body><div>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Ignored.
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document-fragment
+body
+#document
+| <div>
+
+#data
+<table><tr><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+</tr><td>
+#errors
+Line: 1 Col: 5 Unexpected end tag (tr). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</tbody></tfoot></thead><td>
+#errors
+Line: 1 Col: 8 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 24 Unexpected end tag (thead). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<table><tr><div><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected implied end tag (div) in the table row phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<caption><col><colgroup><tbody><tfoot><thead><tr>
+#errors
+Line: 1 Col: 9 Unexpected start tag (caption).
+Line: 1 Col: 14 Unexpected start tag (col).
+Line: 1 Col: 24 Unexpected start tag (colgroup).
+Line: 1 Col: 31 Unexpected start tag (tbody).
+Line: 1 Col: 38 Unexpected start tag (tfoot).
+Line: 1 Col: 45 Unexpected start tag (thead).
+Line: 1 Col: 49 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></thead>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (thead) in the table body phase. Ignored.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></body></caption></col></colgroup></html></td></th></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end tag (body) in the table body phase. Ignored.
+Line: 1 Col: 31 Unexpected end tag (caption) in the table body phase. Ignored.
+Line: 1 Col: 37 Unexpected end tag (col) in the table body phase. Ignored.
+Line: 1 Col: 48 Unexpected end tag (colgroup) in the table body phase. Ignored.
+Line: 1 Col: 55 Unexpected end tag (html) in the table body phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (td) in the table body phase. Ignored.
+Line: 1 Col: 65 Unexpected end tag (th) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end tag (tr) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+
+#data
+<table><tbody></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+
+#data
+<table><table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 14 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|     <table>
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end tag (body). Ignored.
+Line: 1 Col: 24 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 30 Unexpected end tag (col). Ignored.
+Line: 1 Col: 41 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 48 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 61 Unexpected end tag (td). Ignored.
+Line: 1 Col: 69 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 74 Unexpected end tag (th). Ignored.
+Line: 1 Col: 82 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 87 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 87 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+table
+#document
+| <tbody>
+|   <tr>
+
+#data
+<body></body></html>
+#errors
+Line: 1 Col: 20 Unexpected html end tag in inner html mode.
+Line: 1 Col: 20 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+
+#data
+<html><frameset></frameset></html> 
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   " "
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html></html>
+#errors
+Line: 1 Col: 50 Erroneous DOCTYPE.
+Line: 1 Col: 63 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<param><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (param). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<source><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (source). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+</html><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+</body><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+|   <head>
+|   <frameset>
diff --git a/libgo/go/html/testdata/webkit/tests7.dat b/libgo/go/html/testdata/webkit/tests7.dat
new file mode 100644 (file)
index 0000000..f5193c6
--- /dev/null
@@ -0,0 +1,390 @@
+#data
+<!doctype html><body><title>X</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "X"
+
+#data
+<!doctype html><table><title>X</title></table>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) in table context caused voodoo mode.
+Line: 1 Col: 38 Unexpected end tag (title) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "X"
+|     <table>
+
+#data
+<!doctype html><head></head><title>X</title>
+#errors
+Line: 1 Col: 35 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "X"
+|   <body>
+
+#data
+<!doctype html></head><title>X</title>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "X"
+|   <body>
+
+#data
+<!doctype html><table><meta></table>
+#errors
+Line: 1 Col: 28 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <meta>
+|     <table>
+
+#data
+<!doctype html><table>X<tr><td><table> <meta></table></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 45 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <meta>
+|             <table>
+|               " "
+
+#data
+<!doctype html><html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!doctype html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!doctype html><table><style> <tr>x </style> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <style>
+|         " <tr>x "
+|       " "
+
+#data
+<!doctype html><table><TBODY><script> <tr>x </script> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <script>
+|           " <tr>x "
+|         " "
+
+#data
+<!doctype html><p><applet><p>X</p></applet>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <applet>
+|         <p>
+|           "X"
+
+#data
+<!doctype html><listing>
+X</listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <listing>
+|       "X"
+
+#data
+<!doctype html><select><input>X
+#errors
+Line: 1 Col: 30 Unexpected input start tag in the select phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <input>
+|     "X"
+
+#data
+<!doctype html><select><select>X
+#errors
+Line: 1 Col: 31 Unexpected select start tag in the select phase treated as select end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     "X"
+
+#data
+<!doctype html><table><input type=hidDEN></table>
+#errors
+Line: 1 Col: 41 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table>X<input type=hidDEN></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <table>
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table>  <input type=hidDEN></table>
+#errors
+Line: 1 Col: 43 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       "  "
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table>  <input type='hidDEN'></table>
+#errors
+Line: 1 Col: 45 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       "  "
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table><input type=" hidden"><input type=hidDEN></table>
+#errors
+Line: 1 Col: 44 Unexpected start tag (input) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <input>
+|       type=" hidden"
+|     <table>
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table><select>X<tr>
+#errors
+Line: 1 Col: 30 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 35 Unexpected table element start tag (trs) in the select in table phase.
+Line: 1 Col: 35 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       "X"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><select>X</select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       "X"
+
+#data
+<!DOCTYPE hTmL><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<body>X</body></body>
+#errors
+Line: 1 Col: 21 Unexpected end tag token (body) in the after body phase.
+Line: 1 Col: 21 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+|   "X"
+
+#data
+<div><p>a</x> b
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (x). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <p>
+|         "a b"
+
+#data
+<table><tr><td><code></code> </table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <code>
+|             " "
+
+#data
+<table><b><tr><td>aaa</td></tr>bbb</table>ccc
+#errors
+XXX: Fix me
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|     <b>
+|       "bbb"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "aaa"
+|     <b>
+|       "ccc"
+
+#data
+A<table><tr> B</tr> B</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+|   <head>
+|   <body>
+|     "A B B"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+A<table><tr> B</tr> </em>C</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+|   <head>
+|   <body>
+|     "A BC"
+|     <table>
+|       <tbody>
+|         <tr>
+|         " "
+
+#data
+<select><keygen>
+#errors
+Not known
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <keygen>
diff --git a/libgo/go/html/testdata/webkit/tests8.dat b/libgo/go/html/testdata/webkit/tests8.dat
new file mode 100644 (file)
index 0000000..90e6c91
--- /dev/null
@@ -0,0 +1,148 @@
+#data
+<div>
+<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 3 Col: 7 Unexpected end tag (span). Ignored.
+Line: 3 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "
+"
+|       <div>
+|       "
+x"
+
+#data
+<div>x<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 2 Col: 7 Unexpected end tag (span). Ignored.
+Line: 2 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "x"
+|       <div>
+|       "
+x"
+
+#data
+<div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "x"
+|       <div>
+|       "xx"
+
+#data
+<div>x<div></div>y</span>z
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "x"
+|       <div>
+|       "yz"
+
+#data
+<table><div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 18 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 24 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span). Ignored.
+Line: 1 Col: 33 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "x"
+|       <div>
+|       "xx"
+|     <table>
+
+#data
+x<table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 9 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "xx"
+|     <table>
+
+#data
+x<table><table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 16 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "x"
+|     <table>
+|     "x"
+|     <table>
+
+#data
+<b>a<div></div><div></b>y
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "a"
+|       <div>
+|     <div>
+|       <b>
+|       "y"
+
+#data
+<a><div><p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <div>
+|       <a>
+|       <p>
+|         <a>
diff --git a/libgo/go/html/testdata/webkit/tests9.dat b/libgo/go/html/testdata/webkit/tests9.dat
new file mode 100644 (file)
index 0000000..2b715f8
--- /dev/null
@@ -0,0 +1,430 @@
+#data
+<!DOCTYPE html><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+
+#data
+<!DOCTYPE html><body><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+
+#data
+<!DOCTYPE html><body><select><math></math></select>
+#errors
+Line: 1 Col: 35 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 42 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!DOCTYPE html><body><select><option><math></math></option></select>
+#errors
+Line: 1 Col: 43 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 50 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+
+#data
+<!DOCTYPE html><body><table><math></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi><mi>bar</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><math><mi>foo</mi><mi>bar</mi></math></tbody></table>
+#errors
+Line: 1 Col: 41 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 72 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <table>
+|       <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><math><mi>foo</mi><mi>bar</mi></math></tr></tbody></table>
+#errors
+Line: 1 Col: 45 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 57 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 69 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 76 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <math math>
+|               <math mi>
+|                 "foo"
+|               <math mi>
+|                 "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <math math>
+|               <math mi>
+|                 "foo"
+|               <math mi>
+|                 "bar"
+|             <p>
+|               "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi></math><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <math math>
+|           <math mi>
+|             "foo"
+|           <math mi>
+|             "bar"
+|         <p>
+|           "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 70 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 81 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <math math>
+|           <math mi>
+|             "foo"
+|           <math mi>
+|             "bar"
+|         <p>
+|           "baz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi>baz</table><p>quux
+#errors
+Line: 1 Col: 78 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 78 Unexpected end tag (caption). Missing end tag (math).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <math math>
+|           <math mi>
+|             "foo"
+|           <math mi>
+|             "bar"
+|           "baz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 44 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 56 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 68 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 71 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 71 Unexpected start tag (p) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <p>
+|       "baz"
+|     <table>
+|       <colgroup>
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 50 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 62 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 74 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 77 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 88 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <select>
+|               "foobarbaz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 36 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 42 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 80 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       "foobarbaz"
+|     <table>
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body></body></html><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 41 Unexpected start tag (math).
+Line: 1 Col: 68 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <p>
+|       "baz"
+
+#data
+<!DOCTYPE html><body></body><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 34 Unexpected start tag token (math) in the after body phase.
+Line: 1 Col: 61 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <p>
+|       "baz"
+
+#data
+<!DOCTYPE html><frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 31 Unexpected start tag token (math) in the frameset phase. Ignored.
+Line: 1 Col: 35 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 40 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 44 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 49 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 52 Unexpected start tag token (p) in the frameset phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (span) in the frameset phase. Ignored.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 42 Unexpected start tag (math) in the after frameset phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 51 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 55 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 63 Unexpected start tag (p) in the after frameset phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag (span) in the after frameset phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><math xlink:href=foo></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     <math math>
+|       xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo></mi></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <math math>
+|       <math mi>
+|         xlink href="foo"
+|         xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <math math>
+|       <math mi>
+|         xlink href="foo"
+|         xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo />bar</math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <math math>
+|       <math mi>
+|         xlink href="foo"
+|         xml lang="en"
+|       "bar"
diff --git a/libgo/go/html/testdata/webkit/webkit01.dat b/libgo/go/html/testdata/webkit/webkit01.dat
new file mode 100644 (file)
index 0000000..544da9e
--- /dev/null
@@ -0,0 +1,211 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "Test"
+
+#data
+<div></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+
+#data
+<div>Test</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "Test"
+
+#data
+<di
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<div>Hello</div>
+<script>
+console.log("PASS");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "Hello"
+|     "
+"
+|     <script>
+|       "
+console.log("PASS");
+"
+|     "
+"
+|     <div>
+|       "Bye"
+
+#data
+<div foo="bar">Hello</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       foo="bar"
+|       "Hello"
+
+#data
+<div>Hello</div>
+<script>
+console.log("FOO<span>BAR</span>BAZ");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "Hello"
+|     "
+"
+|     <script>
+|       "
+console.log("FOO<span>BAR</span>BAZ");
+"
+|     "
+"
+|     <div>
+|       "Bye"
+
+#data
+<foo bar="baz"></foo><potato quack="duck"></potato>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       bar="baz"
+|     <potato>
+|       quack="duck"
+
+#data
+<foo bar="baz"><potato quack="duck"></potato></foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       bar="baz"
+|       <potato>
+|         quack="duck"
+
+#data
+<foo></foo bar="baz"><potato></potato quack="duck">
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|     <potato>
+
+#data
+1<script>document.write("2")</script>3
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "1"
+|     <script>
+|       "document.write("2")"
+|     "23"
+
+#data
+1<script>document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")</script>4
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "1"
+|     <script>
+|       "document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")"
+|     <script>
+|       "document.write('2')"
+|     "2"
+|     <script>
+|       "document.write('3')"
+|     "34"
+
+#data
+</ tttt>
+#errors
+#document
+| <!--  tttt -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<div FOO ><img><img></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       foo=""
+|       <img>
+|       <img>
+
+#data
+<p>Test</p<p>Test2</p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "Test"
+|       "Test2"
+
+#data
+<rdar://problem/6869687>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <rdar:>
+|       6869687=""
+|       problem=""
+
+#data
+<A>test< /A>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "test< /A>"
diff --git a/libgo/go/html/token.go b/libgo/go/html/token.go
new file mode 100644 (file)
index 0000000..0d4de25
--- /dev/null
@@ -0,0 +1,397 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "strconv"
+)
+
+// A TokenType is the type of a Token.
+type TokenType int
+
+const (
+       // Error means that an error occurred during tokenization.
+       Error TokenType = iota
+       // Text means a text node.
+       Text
+       // A StartTag looks like <a>.
+       StartTag
+       // An EndTag looks like </a>.
+       EndTag
+       // A SelfClosingTag tag looks like <br/>.
+       SelfClosingTag
+)
+
+// String returns a string representation of the TokenType.
+func (t TokenType) String() string {
+       switch t {
+       case Error:
+               return "Error"
+       case Text:
+               return "Text"
+       case StartTag:
+               return "StartTag"
+       case EndTag:
+               return "EndTag"
+       case SelfClosingTag:
+               return "SelfClosingTag"
+       }
+       return "Invalid(" + strconv.Itoa(int(t)) + ")"
+}
+
+// An Attribute is an attribute key-value pair. Key is alphabetic (and hence
+// does not contain escapable characters like '&', '<' or '>'), and Val is
+// unescaped (it looks like "a<b" rather than "a&lt;b").
+type Attribute struct {
+       Key, Val string
+}
+
+// A Token consists of a TokenType and some Data (tag name for start and end
+// tags, content for text). A tag Token may also contain a slice of Attributes.
+// Data is unescaped for both tag and text Tokens (it looks like "a<b" rather
+// than "a&lt;b").
+type Token struct {
+       Type TokenType
+       Data string
+       Attr []Attribute
+}
+
+// tagString returns a string representation of a tag Token's Data and Attr.
+func (t Token) tagString() string {
+       if len(t.Attr) == 0 {
+               return t.Data
+       }
+       buf := bytes.NewBuffer(nil)
+       buf.WriteString(t.Data)
+       for _, a := range t.Attr {
+               buf.WriteByte(' ')
+               buf.WriteString(a.Key)
+               buf.WriteString(`="`)
+               escape(buf, a.Val)
+               buf.WriteByte('"')
+       }
+       return buf.String()
+}
+
+// String returns a string representation of the Token.
+func (t Token) String() string {
+       switch t.Type {
+       case Error:
+               return ""
+       case Text:
+               return EscapeString(t.Data)
+       case StartTag:
+               return "<" + t.tagString() + ">"
+       case EndTag:
+               return "</" + t.tagString() + ">"
+       case SelfClosingTag:
+               return "<" + t.tagString() + "/>"
+       }
+       return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
+}
+
+// A Tokenizer returns a stream of HTML Tokens.
+type Tokenizer struct {
+       // r is the source of the HTML text.
+       r io.Reader
+       // tt is the TokenType of the most recently read token. If tt == Error
+       // then err is the error associated with trying to read that token.
+       tt  TokenType
+       err os.Error
+       // buf[p0:p1] holds the raw data of the most recent token.
+       // buf[p1:] is buffered input that will yield future tokens.
+       p0, p1 int
+       buf    []byte
+}
+
+// Error returns the error associated with the most recent Error token. This is
+// typically os.EOF, meaning the end of tokenization.
+func (z *Tokenizer) Error() os.Error {
+       if z.tt != Error {
+               return nil
+       }
+       return z.err
+}
+
+// Raw returns the unmodified text of the current token. Calling Next, Token,
+// Text, TagName or TagAttr may change the contents of the returned slice.
+func (z *Tokenizer) Raw() []byte {
+       return z.buf[z.p0:z.p1]
+}
+
+// readByte returns the next byte from the input stream, doing a buffered read
+// from z.r into z.buf if necessary. z.buf[z.p0:z.p1] remains a contiguous byte
+// slice that holds all the bytes read so far for the current token.
+func (z *Tokenizer) readByte() (byte, os.Error) {
+       if z.p1 >= len(z.buf) {
+               // Our buffer is exhausted and we have to read from z.r.
+               // We copy z.buf[z.p0:z.p1] to the beginning of z.buf. If the length
+               // z.p1 - z.p0 is more than half the capacity of z.buf, then we
+               // allocate a new buffer before the copy.
+               c := cap(z.buf)
+               d := z.p1 - z.p0
+               var buf1 []byte
+               if 2*d > c {
+                       buf1 = make([]byte, d, 2*c)
+               } else {
+                       buf1 = z.buf[0:d]
+               }
+               copy(buf1, z.buf[z.p0:z.p1])
+               z.p0, z.p1, z.buf = 0, d, buf1[0:d]
+               // Now that we have copied the live bytes to the start of the buffer,
+               // we read from z.r into the remainder.
+               n, err := z.r.Read(buf1[d:cap(buf1)])
+               if err != nil {
+                       return 0, err
+               }
+               z.buf = buf1[0 : d+n]
+       }
+       x := z.buf[z.p1]
+       z.p1++
+       return x, nil
+}
+
+// readTo keeps reading bytes until x is found.
+func (z *Tokenizer) readTo(x uint8) os.Error {
+       for {
+               c, err := z.readByte()
+               if err != nil {
+                       return err
+               }
+               switch c {
+               case x:
+                       return nil
+               case '\\':
+                       _, err = z.readByte()
+                       if err != nil {
+                               return err
+                       }
+               }
+       }
+       panic("unreachable")
+}
+
+// nextTag returns the next TokenType starting from the tag open state.
+func (z *Tokenizer) nextTag() (tt TokenType, err os.Error) {
+       c, err := z.readByte()
+       if err != nil {
+               return Error, err
+       }
+       switch {
+       case c == '/':
+               tt = EndTag
+       // Lower-cased characters are more common in tag names, so we check for them first.
+       case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
+               tt = StartTag
+       case c == '!':
+               return Error, os.NewError("html: TODO(nigeltao): implement comments")
+       case c == '?':
+               return Error, os.NewError("html: TODO(nigeltao): implement XML processing instructions")
+       default:
+               return Error, os.NewError("html: TODO(nigeltao): handle malformed tags")
+       }
+       for {
+               c, err := z.readByte()
+               if err != nil {
+                       return Text, err
+               }
+               switch c {
+               case '"':
+                       err = z.readTo('"')
+                       if err != nil {
+                               return Text, err
+                       }
+               case '\'':
+                       err = z.readTo('\'')
+                       if err != nil {
+                               return Text, err
+                       }
+               case '>':
+                       if z.buf[z.p1-2] == '/' && tt == StartTag {
+                               return SelfClosingTag, nil
+                       }
+                       return tt, nil
+               }
+       }
+       panic("unreachable")
+}
+
+// Next scans the next token and returns its type.
+func (z *Tokenizer) Next() TokenType {
+       if z.err != nil {
+               z.tt = Error
+               return z.tt
+       }
+       z.p0 = z.p1
+       c, err := z.readByte()
+       if err != nil {
+               z.tt, z.err = Error, err
+               return z.tt
+       }
+       if c == '<' {
+               z.tt, z.err = z.nextTag()
+               return z.tt
+       }
+       for {
+               c, err := z.readByte()
+               if err != nil {
+                       z.tt, z.err = Error, err
+                       if err == os.EOF {
+                               z.tt = Text
+                       }
+                       return z.tt
+               }
+               if c == '<' {
+                       z.p1--
+                       z.tt = Text
+                       return z.tt
+               }
+       }
+       panic("unreachable")
+}
+
+// trim returns the largest j such that z.buf[i:j] contains only white space,
+// or only white space plus the final ">" or "/>" of the raw data.
+func (z *Tokenizer) trim(i int) int {
+       k := z.p1
+       for ; i < k; i++ {
+               switch z.buf[i] {
+               case ' ', '\n', '\t', '\f':
+                       continue
+               case '>':
+                       if i == k-1 {
+                               return k
+                       }
+               case '/':
+                       if i == k-2 {
+                               return k
+                       }
+               }
+               return i
+       }
+       return k
+}
+
+// lower finds the largest alphabetic [a-zA-Z]* word at the start of z.buf[i:]
+// and returns that word lower-cased, as well as the trimmed cursor location
+// after that word.
+func (z *Tokenizer) lower(i int) ([]byte, int) {
+       i0 := i
+loop:
+       for ; i < z.p1; i++ {
+               c := z.buf[i]
+               // TODO(nigeltao): Check what '0' <= c && c <= '9' should do.
+               switch {
+               case 'A' <= c && c <= 'Z':
+                       z.buf[i] = c + 'a' - 'A'
+               case 'a' <= c && c <= 'z':
+                       // No-op.
+               default:
+                       break loop
+               }
+       }
+       return z.buf[i0:i], z.trim(i)
+}
+
+// Text returns the raw data after unescaping.
+// The contents of the returned slice may change on the next call to Next.
+func (z *Tokenizer) Text() []byte {
+       s := unescape(z.Raw())
+       z.p0 = z.p1
+       return s
+}
+
+// TagName returns the lower-cased name of a tag token (the `img` out of
+// `<IMG SRC="foo">`), and whether the tag has attributes.
+// The contents of the returned slice may change on the next call to Next.
+func (z *Tokenizer) TagName() (name []byte, remaining bool) {
+       i := z.p0 + 1
+       if i >= z.p1 {
+               z.p0 = z.p1
+               return nil, false
+       }
+       if z.buf[i] == '/' {
+               i++
+       }
+       name, z.p0 = z.lower(i)
+       remaining = z.p0 != z.p1
+       return
+}
+
+// TagAttr returns the lower-cased key and unescaped value of the next unparsed
+// attribute for the current tag token, and whether there are more attributes.
+// The contents of the returned slices may change on the next call to Next.
+func (z *Tokenizer) TagAttr() (key, val []byte, remaining bool) {
+       key, i := z.lower(z.p0)
+       // Get past the "=\"".
+       if i == z.p1 || z.buf[i] != '=' {
+               return
+       }
+       i = z.trim(i + 1)
+       if i == z.p1 || z.buf[i] != '"' {
+               return
+       }
+       i = z.trim(i + 1)
+       // Copy and unescape everything up to the closing '"'.
+       dst, src := i, i
+loop:
+       for src < z.p1 {
+               c := z.buf[src]
+               switch c {
+               case '"':
+                       src++
+                       break loop
+               case '&':
+                       dst, src = unescapeEntity(z.buf, dst, src)
+               case '\\':
+                       if src == z.p1 {
+                               z.buf[dst] = '\\'
+                               dst++
+                       } else {
+                               z.buf[dst] = z.buf[src+1]
+                               dst, src = dst+1, src+2
+                       }
+               default:
+                       z.buf[dst] = c
+                       dst, src = dst+1, src+1
+               }
+       }
+       val, z.p0 = z.buf[i:dst], z.trim(src)
+       remaining = z.p0 != z.p1
+       return
+}
+
+// Token returns the next Token. The result's Data and Attr values remain valid
+// after subsequent Next calls.
+func (z *Tokenizer) Token() Token {
+       t := Token{Type: z.tt}
+       switch z.tt {
+       case Text:
+               t.Data = string(z.Text())
+       case StartTag, EndTag, SelfClosingTag:
+               var attr []Attribute
+               name, remaining := z.TagName()
+               for remaining {
+                       var key, val []byte
+                       key, val, remaining = z.TagAttr()
+                       attr = append(attr, Attribute{string(key), string(val)})
+               }
+               t.Data = string(name)
+               t.Attr = attr
+       }
+       return t
+}
+
+// NewTokenizer returns a new HTML Tokenizer for the given Reader.
+// The input is assumed to be UTF-8 encoded.
+func NewTokenizer(r io.Reader) *Tokenizer {
+       return &Tokenizer{
+               r:   r,
+               buf: make([]byte, 0, 4096),
+       }
+}
diff --git a/libgo/go/html/token_test.go b/libgo/go/html/token_test.go
new file mode 100644 (file)
index 0000000..5759476
--- /dev/null
@@ -0,0 +1,162 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+       "bytes"
+       "os"
+       "testing"
+)
+
+type tokenTest struct {
+       // A short description of the test case.
+       desc string
+       // The HTML to parse.
+       html string
+       // The string representations of the expected tokens.
+       tokens []string
+}
+
+var tokenTests = []tokenTest{
+       // A single text node. The tokenizer should not break text nodes on whitespace,
+       // nor should it normalize whitespace within a text node.
+       {
+               "text",
+               "foo  bar",
+               []string{
+                       "foo  bar",
+               },
+       },
+       // An entity.
+       {
+               "entity",
+               "one &lt; two",
+               []string{
+                       "one &lt; two",
+               },
+       },
+       // A start, self-closing and end tag. The tokenizer does not care if the start
+       // and end tokens don't match; that is the job of the parser.
+       {
+               "tags",
+               "<a>b<c/>d</e>",
+               []string{
+                       "<a>",
+                       "b",
+                       "<c/>",
+                       "d",
+                       "</e>",
+               },
+       },
+       // An attribute with a backslash.
+       {
+               "backslash",
+               `<p id="a\"b">`,
+               []string{
+                       `<p id="a&quot;b">`,
+               },
+       },
+       // Entities, tag name and attribute key lower-casing, and whitespace
+       // normalization within a tag.
+       {
+               "tricky",
+               "<p \t\n iD=\"a&quot;B\"  foo=\"bar\"><EM>te&lt;&amp;;xt</em></p>",
+               []string{
+                       `<p id="a&quot;B" foo="bar">`,
+                       "<em>",
+                       "te&lt;&amp;;xt",
+                       "</em>",
+                       "</p>",
+               },
+       },
+       // A non-existant entity. Tokenizing and converting back to a string should
+       // escape the "&" to become "&amp;".
+       {
+               "noSuchEntity",
+               `<a b="c&noSuchEntity;d">&lt;&alsoDoesntExist;&`,
+               []string{
+                       `<a b="c&amp;noSuchEntity;d">`,
+                       "&lt;&amp;alsoDoesntExist;&amp;",
+               },
+       },
+}
+
+func TestTokenizer(t *testing.T) {
+loop:
+       for _, tt := range tokenTests {
+               z := NewTokenizer(bytes.NewBuffer([]byte(tt.html)))
+               for i, s := range tt.tokens {
+                       if z.Next() == Error {
+                               t.Errorf("%s token %d: want %q got error %v", tt.desc, i, s, z.Error())
+                               continue loop
+                       }
+                       actual := z.Token().String()
+                       if s != actual {
+                               t.Errorf("%s token %d: want %q got %q", tt.desc, i, s, actual)
+                               continue loop
+                       }
+               }
+               z.Next()
+               if z.Error() != os.EOF {
+                       t.Errorf("%s: want EOF got %q", tt.desc, z.Token().String())
+               }
+       }
+}
+
+func TestUnescapeEscape(t *testing.T) {
+       ss := []string{
+               ``,
+               `abc def`,
+               `a & b`,
+               `a&amp;b`,
+               `a &amp b`,
+               `&quot;`,
+               `"`,
+               `"<&>"`,
+               `&quot;&lt;&amp;&gt;&quot;`,
+               `3&5==1 && 0<1, "0&lt;1", a+acute=&aacute;`,
+       }
+       for _, s := range ss {
+               if s != UnescapeString(EscapeString(s)) {
+                       t.Errorf("s != UnescapeString(EscapeString(s)), s=%q", s)
+               }
+       }
+}
+
+func TestBufAPI(t *testing.T) {
+       s := "0<a>1</a>2<b>3<a>4<a>5</a>6</b>7</a>8<a/>9"
+       z := NewTokenizer(bytes.NewBuffer([]byte(s)))
+       result := bytes.NewBuffer(nil)
+       depth := 0
+loop:
+       for {
+               tt := z.Next()
+               switch tt {
+               case Error:
+                       if z.Error() != os.EOF {
+                               t.Error(z.Error())
+                       }
+                       break loop
+               case Text:
+                       if depth > 0 {
+                               result.Write(z.Text())
+                       }
+               case StartTag, EndTag:
+                       tn, _ := z.TagName()
+                       if len(tn) == 1 && tn[0] == 'a' {
+                               if tt == StartTag {
+                                       depth++
+                               } else {
+                                       depth--
+                               }
+                       }
+               }
+       }
+       u := "14567"
+       v := string(result.Bytes())
+       if u != v {
+               t.Errorf("TestBufAPI: want %q got %q", u, v)
+       }
+}
diff --git a/libgo/go/http/chunked.go b/libgo/go/http/chunked.go
new file mode 100644 (file)
index 0000000..66195f0
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "io"
+       "os"
+       "strconv"
+)
+
+// NewChunkedWriter returns a new writer that translates writes into HTTP
+// "chunked" format before writing them to w.  Closing the returned writer
+// sends the final 0-length chunk that marks the end of the stream.
+func NewChunkedWriter(w io.Writer) io.WriteCloser {
+       return &chunkedWriter{w}
+}
+
+// Writing to ChunkedWriter translates to writing in HTTP chunked Transfer
+// Encoding wire format to the undering Wire writer.
+type chunkedWriter struct {
+       Wire io.Writer
+}
+
+// Write the contents of data as one chunk to Wire.
+// NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has
+// a bug since it does not check for success of io.WriteString
+func (cw *chunkedWriter) Write(data []byte) (n int, err os.Error) {
+
+       // Don't send 0-length data. It looks like EOF for chunked encoding.
+       if len(data) == 0 {
+               return 0, nil
+       }
+
+       head := strconv.Itob(len(data), 16) + "\r\n"
+
+       if _, err = io.WriteString(cw.Wire, head); err != nil {
+               return 0, err
+       }
+       if n, err = cw.Wire.Write(data); err != nil {
+               return
+       }
+       if n != len(data) {
+               err = io.ErrShortWrite
+               return
+       }
+       _, err = io.WriteString(cw.Wire, "\r\n")
+
+       return
+}
+
+func (cw *chunkedWriter) Close() os.Error {
+       _, err := io.WriteString(cw.Wire, "0\r\n")
+       return err
+}
diff --git a/libgo/go/http/client.go b/libgo/go/http/client.go
new file mode 100644 (file)
index 0000000..87f5c34
--- /dev/null
@@ -0,0 +1,236 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Primitive HTTP client. See RFC 2616.
+
+package http
+
+import (
+       "bufio"
+       "bytes"
+       "crypto/tls"
+       "encoding/base64"
+       "fmt"
+       "io"
+       "net"
+       "os"
+       "strconv"
+       "strings"
+)
+
+// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
+// return true if the string includes a port.
+func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
+
+// Used in Send to implement io.ReadCloser by bundling together the
+// bufio.Reader through which we read the response, and the underlying
+// network connection.
+type readClose struct {
+       io.Reader
+       io.Closer
+}
+
+// Send issues an HTTP request.  Caller should close resp.Body when done reading it.
+//
+// TODO: support persistent connections (multiple requests on a single connection).
+// send() method is nonpublic because, when we refactor the code for persistent
+// connections, it may no longer make sense to have a method with this signature.
+func send(req *Request) (resp *Response, err os.Error) {
+       if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
+               return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
+       }
+
+       addr := req.URL.Host
+       if !hasPort(addr) {
+               addr += ":" + req.URL.Scheme
+       }
+       info := req.URL.RawUserinfo
+       if len(info) > 0 {
+               enc := base64.URLEncoding
+               encoded := make([]byte, enc.EncodedLen(len(info)))
+               enc.Encode(encoded, []byte(info))
+               if req.Header == nil {
+                       req.Header = make(map[string]string)
+               }
+               req.Header["Authorization"] = "Basic " + string(encoded)
+       }
+
+       var conn io.ReadWriteCloser
+       if req.URL.Scheme == "http" {
+               conn, err = net.Dial("tcp", "", addr)
+               if err != nil {
+                       return nil, err
+               }
+       } else { // https
+               conn, err = tls.Dial("tcp", "", addr)
+               if err != nil {
+                       return nil, err
+               }
+               h := req.URL.Host
+               if hasPort(h) {
+                       h = h[0:strings.LastIndex(h, ":")]
+               }
+               if err := conn.(*tls.Conn).VerifyHostname(h); err != nil {
+                       return nil, err
+               }
+       }
+
+       err = req.Write(conn)
+       if err != nil {
+               conn.Close()
+               return nil, err
+       }
+
+       reader := bufio.NewReader(conn)
+       resp, err = ReadResponse(reader, req.Method)
+       if err != nil {
+               conn.Close()
+               return nil, err
+       }
+
+       resp.Body = readClose{resp.Body, conn}
+
+       return
+}
+
+// True if the specified HTTP status code is one for which the Get utility should
+// automatically redirect.
+func shouldRedirect(statusCode int) bool {
+       switch statusCode {
+       case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect:
+               return true
+       }
+       return false
+}
+
+// Get issues a GET to the specified URL.  If the response is one of the following
+// redirect codes, it follows the redirect, up to a maximum of 10 redirects:
+//
+//    301 (Moved Permanently)
+//    302 (Found)
+//    303 (See Other)
+//    307 (Temporary Redirect)
+//
+// finalURL is the URL from which the response was fetched -- identical to the
+// input URL unless redirects were followed.
+//
+// Caller should close r.Body when done reading it.
+func Get(url string) (r *Response, finalURL string, err os.Error) {
+       // TODO: if/when we add cookie support, the redirected request shouldn't
+       // necessarily supply the same cookies as the original.
+       // TODO: set referrer header on redirects.
+       for redirect := 0; ; redirect++ {
+               if redirect >= 10 {
+                       err = os.ErrorString("stopped after 10 redirects")
+                       break
+               }
+
+               var req Request
+               if req.URL, err = ParseURL(url); err != nil {
+                       break
+               }
+               url = req.URL.String()
+               if r, err = send(&req); err != nil {
+                       break
+               }
+               if shouldRedirect(r.StatusCode) {
+                       r.Body.Close()
+                       if url = r.GetHeader("Location"); url == "" {
+                               err = os.ErrorString(fmt.Sprintf("%d response missing Location header", r.StatusCode))
+                               break
+                       }
+                       continue
+               }
+               finalURL = url
+               return
+       }
+
+       err = &URLError{"Get", url, err}
+       return
+}
+
+// Post issues a POST to the specified URL.
+//
+// Caller should close r.Body when done reading it.
+func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Error) {
+       var req Request
+       req.Method = "POST"
+       req.ProtoMajor = 1
+       req.ProtoMinor = 1
+       req.Close = true
+       req.Body = nopCloser{body}
+       req.Header = map[string]string{
+               "Content-Type": bodyType,
+       }
+       req.TransferEncoding = []string{"chunked"}
+
+       req.URL, err = ParseURL(url)
+       if err != nil {
+               return nil, err
+       }
+
+       return send(&req)
+}
+
+// PostForm issues a POST to the specified URL, 
+// with data's keys and values urlencoded as the request body.
+//
+// Caller should close r.Body when done reading it.
+func PostForm(url string, data map[string]string) (r *Response, err os.Error) {
+       var req Request
+       req.Method = "POST"
+       req.ProtoMajor = 1
+       req.ProtoMinor = 1
+       req.Close = true
+       body := urlencode(data)
+       req.Body = nopCloser{body}
+       req.Header = map[string]string{
+               "Content-Type":   "application/x-www-form-urlencoded",
+               "Content-Length": strconv.Itoa(body.Len()),
+       }
+       req.ContentLength = int64(body.Len())
+
+       req.URL, err = ParseURL(url)
+       if err != nil {
+               return nil, err
+       }
+
+       return send(&req)
+}
+
+func urlencode(data map[string]string) (b *bytes.Buffer) {
+       b = new(bytes.Buffer)
+       first := true
+       for k, v := range data {
+               if first {
+                       first = false
+               } else {
+                       b.WriteByte('&')
+               }
+               b.WriteString(URLEscape(k))
+               b.WriteByte('=')
+               b.WriteString(URLEscape(v))
+       }
+       return
+}
+
+// Head issues a HEAD to the specified URL.
+func Head(url string) (r *Response, err os.Error) {
+       var req Request
+       req.Method = "HEAD"
+       if req.URL, err = ParseURL(url); err != nil {
+               return
+       }
+       url = req.URL.String()
+       if r, err = send(&req); err != nil {
+               return
+       }
+       return
+}
+
+type nopCloser struct {
+       io.Reader
+}
+
+func (nopCloser) Close() os.Error { return nil }
diff --git a/libgo/go/http/client_test.go b/libgo/go/http/client_test.go
new file mode 100644 (file)
index 0000000..013653a
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests for client.go
+
+package http
+
+import (
+       "io/ioutil"
+       "strings"
+       "testing"
+)
+
+func TestClient(t *testing.T) {
+       // TODO: add a proper test suite.  Current test merely verifies that
+       // we can retrieve the Google robots.txt file.
+
+       r, _, err := Get("http://www.google.com/robots.txt")
+       var b []byte
+       if err == nil {
+               b, err = ioutil.ReadAll(r.Body)
+               r.Body.Close()
+       }
+       if err != nil {
+               t.Error(err)
+       } else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
+               t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
+       }
+}
+
+func TestClientHead(t *testing.T) {
+       r, err := Head("http://www.google.com/robots.txt")
+       if err != nil {
+               t.Fatal(err)
+       }
+       if _, ok := r.Header["Last-Modified"]; !ok {
+               t.Error("Last-Modified header not found.")
+       }
+}
diff --git a/libgo/go/http/dump.go b/libgo/go/http/dump.go
new file mode 100644 (file)
index 0000000..73ac979
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "bytes"
+       "io"
+       "os"
+)
+
+
+// One of the copies, say from b to r2, could be avoided by using a more
+// elaborate trick where the other copy is made during Request/Response.Write.
+// This would complicate things too much, given that these functions are for
+// debugging only.
+func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err os.Error) {
+       var buf bytes.Buffer
+       if _, err = buf.ReadFrom(b); err != nil {
+               return nil, nil, err
+       }
+       if err = b.Close(); err != nil {
+               return nil, nil, err
+       }
+       return nopCloser{&buf}, nopCloser{bytes.NewBuffer(buf.Bytes())}, nil
+}
+
+// DumpRequest returns the wire representation of req,
+// optionally including the request body, for debugging.
+// DumpRequest is semantically a no-op, but in order to
+// dump the body, it reads the body data into memory and
+// changes req.Body to refer to the in-memory copy.
+func DumpRequest(req *Request, body bool) (dump []byte, err os.Error) {
+       var b bytes.Buffer
+       save := req.Body
+       if !body || req.Body == nil {
+               req.Body = nil
+       } else {
+               save, req.Body, err = drainBody(req.Body)
+               if err != nil {
+                       return
+               }
+       }
+       err = req.Write(&b)
+       req.Body = save
+       if err != nil {
+               return
+       }
+       dump = b.Bytes()
+       return
+}
+
+// DumpResponse is like DumpRequest but dumps a response.
+func DumpResponse(resp *Response, body bool) (dump []byte, err os.Error) {
+       var b bytes.Buffer
+       save := resp.Body
+       savecl := resp.ContentLength
+       if !body || resp.Body == nil {
+               resp.Body = nil
+               resp.ContentLength = 0
+       } else {
+               save, resp.Body, err = drainBody(resp.Body)
+               if err != nil {
+                       return
+               }
+       }
+       err = resp.Write(&b)
+       resp.Body = save
+       resp.ContentLength = savecl
+       if err != nil {
+               return
+       }
+       dump = b.Bytes()
+       return
+}
diff --git a/libgo/go/http/fs.go b/libgo/go/http/fs.go
new file mode 100644 (file)
index 0000000..b3047f1
--- /dev/null
@@ -0,0 +1,176 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// HTTP file system request handler
+
+package http
+
+import (
+       "fmt"
+       "io"
+       "mime"
+       "os"
+       "path"
+       "strings"
+       "time"
+       "utf8"
+)
+
+// Heuristic: b is text if it is valid UTF-8 and doesn't
+// contain any unprintable ASCII or Unicode characters.
+func isText(b []byte) bool {
+       for len(b) > 0 && utf8.FullRune(b) {
+               rune, size := utf8.DecodeRune(b)
+               if size == 1 && rune == utf8.RuneError {
+                       // decoding error
+                       return false
+               }
+               if 0x80 <= rune && rune <= 0x9F {
+                       return false
+               }
+               if rune < ' ' {
+                       switch rune {
+                       case '\n', '\r', '\t':
+                               // okay
+                       default:
+                               // binary garbage
+                               return false
+                       }
+               }
+               b = b[size:]
+       }
+       return true
+}
+
+func dirList(w ResponseWriter, f *os.File) {
+       fmt.Fprintf(w, "<pre>\n")
+       for {
+               dirs, err := f.Readdir(100)
+               if err != nil || len(dirs) == 0 {
+                       break
+               }
+               for _, d := range dirs {
+                       name := d.Name
+                       if d.IsDirectory() {
+                               name += "/"
+                       }
+                       // TODO htmlescape
+                       fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", name, name)
+               }
+       }
+       fmt.Fprintf(w, "</pre>\n")
+}
+
+func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
+       const indexPage = "/index.html"
+
+       // redirect .../index.html to .../
+       if strings.HasSuffix(r.URL.Path, indexPage) {
+               Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
+               return
+       }
+
+       f, err := os.Open(name, os.O_RDONLY, 0)
+       if err != nil {
+               // TODO expose actual error?
+               NotFound(w, r)
+               return
+       }
+       defer f.Close()
+
+       d, err1 := f.Stat()
+       if err1 != nil {
+               // TODO expose actual error?
+               NotFound(w, r)
+               return
+       }
+
+       if redirect {
+               // redirect to canonical path: / at end of directory url
+               // r.URL.Path always begins with /
+               url := r.URL.Path
+               if d.IsDirectory() {
+                       if url[len(url)-1] != '/' {
+                               Redirect(w, r, url+"/", StatusMovedPermanently)
+                               return
+                       }
+               } else {
+                       if url[len(url)-1] == '/' {
+                               Redirect(w, r, url[0:len(url)-1], StatusMovedPermanently)
+                               return
+                       }
+               }
+       }
+
+       if t, _ := time.Parse(TimeFormat, r.Header["If-Modified-Since"]); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
+               w.WriteHeader(StatusNotModified)
+               return
+       }
+       w.SetHeader("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))
+
+       // use contents of index.html for directory, if present
+       if d.IsDirectory() {
+               index := name + indexPage
+               ff, err := os.Open(index, os.O_RDONLY, 0)
+               if err == nil {
+                       defer ff.Close()
+                       dd, err := ff.Stat()
+                       if err == nil {
+                               name = index
+                               d = dd
+                               f = ff
+                       }
+               }
+       }
+
+       if d.IsDirectory() {
+               dirList(w, f)
+               return
+       }
+
+       // serve file
+       // use extension to find content type.
+       ext := path.Ext(name)
+       if ctype := mime.TypeByExtension(ext); ctype != "" {
+               w.SetHeader("Content-Type", ctype)
+       } else {
+               // read first chunk to decide between utf-8 text and binary
+               var buf [1024]byte
+               n, _ := io.ReadFull(f, buf[0:])
+               b := buf[0:n]
+               if isText(b) {
+                       w.SetHeader("Content-Type", "text-plain; charset=utf-8")
+               } else {
+                       w.SetHeader("Content-Type", "application/octet-stream") // generic binary
+               }
+               w.Write(b)
+       }
+       io.Copy(w, f)
+}
+
+// ServeFile replies to the request with the contents of the named file or directory.
+func ServeFile(w ResponseWriter, r *Request, name string) {
+       serveFile(w, r, name, false)
+}
+
+type fileHandler struct {
+       root   string
+       prefix string
+}
+
+// FileServer returns a handler that serves HTTP requests
+// with the contents of the file system rooted at root.
+// It strips prefix from the incoming requests before
+// looking up the file name in the file system.
+func FileServer(root, prefix string) Handler { return &fileHandler{root, prefix} }
+
+func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
+       path := r.URL.Path
+       if !strings.HasPrefix(path, f.prefix) {
+               NotFound(w, r)
+               return
+       }
+       path = path[len(f.prefix):]
+       serveFile(w, r, f.root+"/"+path, true)
+}
diff --git a/libgo/go/http/lex.go b/libgo/go/http/lex.go
new file mode 100644 (file)
index 0000000..93b67e7
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+// This file deals with lexical matters of HTTP
+
+func isSeparator(c byte) bool {
+       switch c {
+       case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t':
+               return true
+       }
+       return false
+}
+
+func isSpace(c byte) bool {
+       switch c {
+       case ' ', '\t', '\r', '\n':
+               return true
+       }
+       return false
+}
+
+func isCtl(c byte) bool { return (0 <= c && c <= 31) || c == 127 }
+
+func isChar(c byte) bool { return 0 <= c && c <= 127 }
+
+func isAnyText(c byte) bool { return !isCtl(c) }
+
+func isQdText(c byte) bool { return isAnyText(c) && c != '"' }
+
+func isToken(c byte) bool { return isChar(c) && !isCtl(c) && !isSeparator(c) }
+
+// Valid escaped sequences are not specified in RFC 2616, so for now, we assume
+// that they coincide with the common sense ones used by GO. Malformed
+// characters should probably not be treated as errors by a robust (forgiving)
+// parser, so we replace them with the '?' character.
+func httpUnquotePair(b byte) byte {
+       // skip the first byte, which should always be '\'
+       switch b {
+       case 'a':
+               return '\a'
+       case 'b':
+               return '\b'
+       case 'f':
+               return '\f'
+       case 'n':
+               return '\n'
+       case 'r':
+               return '\r'
+       case 't':
+               return '\t'
+       case 'v':
+               return '\v'
+       case '\\':
+               return '\\'
+       case '\'':
+               return '\''
+       case '"':
+               return '"'
+       }
+       return '?'
+}
+
+// raw must begin with a valid quoted string. Only the first quoted string is
+// parsed and is unquoted in result. eaten is the number of bytes parsed, or -1
+// upon failure.
+func httpUnquote(raw []byte) (eaten int, result string) {
+       buf := make([]byte, len(raw))
+       if raw[0] != '"' {
+               return -1, ""
+       }
+       eaten = 1
+       j := 0 // # of bytes written in buf
+       for i := 1; i < len(raw); i++ {
+               switch b := raw[i]; b {
+               case '"':
+                       eaten++
+                       buf = buf[0:j]
+                       return i + 1, string(buf)
+               case '\\':
+                       if len(raw) < i+2 {
+                               return -1, ""
+                       }
+                       buf[j] = httpUnquotePair(raw[i+1])
+                       eaten += 2
+                       j++
+                       i++
+               default:
+                       if isQdText(b) {
+                               buf[j] = b
+                       } else {
+                               buf[j] = '?'
+                       }
+                       eaten++
+                       j++
+               }
+       }
+       return -1, ""
+}
+
+// This is a best effort parse, so errors are not returned, instead not all of
+// the input string might be parsed. result is always non-nil.
+func httpSplitFieldValue(fv string) (eaten int, result []string) {
+       result = make([]string, 0, len(fv))
+       raw := []byte(fv)
+       i := 0
+       chunk := ""
+       for i < len(raw) {
+               b := raw[i]
+               switch {
+               case b == '"':
+                       eaten, unq := httpUnquote(raw[i:len(raw)])
+                       if eaten < 0 {
+                               return i, result
+                       } else {
+                               i += eaten
+                               chunk += unq
+                       }
+               case isSeparator(b):
+                       if chunk != "" {
+                               result = result[0 : len(result)+1]
+                               result[len(result)-1] = chunk
+                               chunk = ""
+                       }
+                       i++
+               case isToken(b):
+                       chunk += string(b)
+                       i++
+               case b == '\n' || b == '\r':
+                       i++
+               default:
+                       chunk += "?"
+                       i++
+               }
+       }
+       if chunk != "" {
+               result = result[0 : len(result)+1]
+               result[len(result)-1] = chunk
+               chunk = ""
+       }
+       return i, result
+}
diff --git a/libgo/go/http/lex_test.go b/libgo/go/http/lex_test.go
new file mode 100644 (file)
index 0000000..5386f75
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "testing"
+)
+
+type lexTest struct {
+       Raw    string
+       Parsed int // # of parsed characters
+       Result []string
+}
+
+var lexTests = []lexTest{
+       {
+               Raw:    `"abc"def,:ghi`,
+               Parsed: 13,
+               Result: []string{"abcdef", "ghi"},
+       },
+       // My understanding of the RFC is that escape sequences outside of
+       // quotes are not interpreted?
+       {
+               Raw:    `"\t"\t"\t"`,
+               Parsed: 10,
+               Result: []string{"\t", "t\t"},
+       },
+       {
+               Raw:    `"\yab"\r\n`,
+               Parsed: 10,
+               Result: []string{"?ab", "r", "n"},
+       },
+       {
+               Raw:    "ab\f",
+               Parsed: 3,
+               Result: []string{"ab?"},
+       },
+       {
+               Raw:    "\"ab \" c,de f, gh, ij\n\t\r",
+               Parsed: 23,
+               Result: []string{"ab ", "c", "de", "f", "gh", "ij"},
+       },
+}
+
+func min(x, y int) int {
+       if x <= y {
+               return x
+       }
+       return y
+}
+
+func TestSplitFieldValue(t *testing.T) {
+       for k, l := range lexTests {
+               parsed, result := httpSplitFieldValue(l.Raw)
+               if parsed != l.Parsed {
+                       t.Errorf("#%d: Parsed %d, expected %d", k, parsed, l.Parsed)
+               }
+               if len(result) != len(l.Result) {
+                       t.Errorf("#%d: Result len  %d, expected %d", k, len(result), len(l.Result))
+               }
+               for i := 0; i < min(len(result), len(l.Result)); i++ {
+                       if result[i] != l.Result[i] {
+                               t.Errorf("#%d: %d-th entry mismatch. Have {%s}, expect {%s}",
+                                       k, i, result[i], l.Result[i])
+                       }
+               }
+       }
+}
diff --git a/libgo/go/http/persist.go b/libgo/go/http/persist.go
new file mode 100644 (file)
index 0000000..8bfc097
--- /dev/null
@@ -0,0 +1,303 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "bufio"
+       "container/list"
+       "io"
+       "net"
+       "os"
+       "sync"
+)
+
+var ErrPersistEOF = &ProtocolError{"persistent connection closed"}
+
+// A ServerConn reads requests and sends responses over an underlying
+// connection, until the HTTP keepalive logic commands an end. ServerConn
+// does not close the underlying connection. Instead, the user calls Close
+// and regains control over the connection. ServerConn supports pipe-lining,
+// i.e. requests can be read out of sync (but in the same order) while the
+// respective responses are sent.
+type ServerConn struct {
+       c               net.Conn
+       r               *bufio.Reader
+       clsd            bool     // indicates a graceful close
+       re, we          os.Error // read/write errors
+       lastBody        io.ReadCloser
+       nread, nwritten int
+       lk              sync.Mutex // protected read/write to re,we
+}
+
+// NewServerConn returns a new ServerConn reading and writing c.  If r is not
+// nil, it is the buffer to use when reading c.
+func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
+       if r == nil {
+               r = bufio.NewReader(c)
+       }
+       return &ServerConn{c: c, r: r}
+}
+
+// Close detaches the ServerConn and returns the underlying connection as well
+// as the read-side bufio which may have some left over data. Close may be
+// called before Read has signaled the end of the keep-alive logic. The user
+// should not call Close while Read or Write is in progress.
+func (sc *ServerConn) Close() (c net.Conn, r *bufio.Reader) {
+       sc.lk.Lock()
+       defer sc.lk.Unlock()
+       c = sc.c
+       r = sc.r
+       sc.c = nil
+       sc.r = nil
+       return
+}
+
+// Read returns the next request on the wire. An ErrPersistEOF is returned if
+// it is gracefully determined that there are no more requests (e.g. after the
+// first request on an HTTP/1.0 connection, or after a Connection:close on a
+// HTTP/1.1 connection). Read can be called concurrently with Write, but not
+// with another Read.
+func (sc *ServerConn) Read() (req *Request, err os.Error) {
+
+       sc.lk.Lock()
+       if sc.we != nil { // no point receiving if write-side broken or closed
+               defer sc.lk.Unlock()
+               return nil, sc.we
+       }
+       if sc.re != nil {
+               defer sc.lk.Unlock()
+               return nil, sc.re
+       }
+       sc.lk.Unlock()
+
+       // Make sure body is fully consumed, even if user does not call body.Close
+       if sc.lastBody != nil {
+               // body.Close is assumed to be idempotent and multiple calls to
+               // it should return the error that its first invokation
+               // returned.
+               err = sc.lastBody.Close()
+               sc.lastBody = nil
+               if err != nil {
+                       sc.lk.Lock()
+                       defer sc.lk.Unlock()
+                       sc.re = err
+                       return nil, err
+               }
+       }
+
+       req, err = ReadRequest(sc.r)
+       if err != nil {
+               sc.lk.Lock()
+               defer sc.lk.Unlock()
+               if err == io.ErrUnexpectedEOF {
+                       // A close from the opposing client is treated as a
+                       // graceful close, even if there was some unparse-able
+                       // data before the close.
+                       sc.re = ErrPersistEOF
+                       return nil, sc.re
+               } else {
+                       sc.re = err
+                       return
+               }
+       }
+       sc.lastBody = req.Body
+       sc.nread++
+       if req.Close {
+               sc.lk.Lock()
+               defer sc.lk.Unlock()
+               sc.re = ErrPersistEOF
+               return req, sc.re
+       }
+       return
+}
+
+// Pending returns the number of unanswered requests
+// that have been received on the connection.
+func (sc *ServerConn) Pending() int {
+       sc.lk.Lock()
+       defer sc.lk.Unlock()
+       return sc.nread - sc.nwritten
+}
+
+// Write writes a repsonse. To close the connection gracefully, set the
+// Response.Close field to true. Write should be considered operational until
+// it returns an error, regardless of any errors returned on the Read side.
+// Write can be called concurrently with Read, but not with another Write.
+func (sc *ServerConn) Write(resp *Response) os.Error {
+
+       sc.lk.Lock()
+       if sc.we != nil {
+               defer sc.lk.Unlock()
+               return sc.we
+       }
+       sc.lk.Unlock()
+       if sc.nread <= sc.nwritten {
+               return os.NewError("persist server pipe count")
+       }
+
+       if resp.Close {
+               // After signaling a keep-alive close, any pipelined unread
+               // requests will be lost. It is up to the user to drain them
+               // before signaling.
+               sc.lk.Lock()
+               sc.re = ErrPersistEOF
+               sc.lk.Unlock()
+       }
+
+       err := resp.Write(sc.c)
+       if err != nil {
+               sc.lk.Lock()
+               defer sc.lk.Unlock()
+               sc.we = err
+               return err
+       }
+       sc.nwritten++
+
+       return nil
+}
+
+// A ClientConn sends request and receives headers over an underlying
+// connection, while respecting the HTTP keepalive logic. ClientConn is not
+// responsible for closing the underlying connection. One must call Close to
+// regain control of that connection and deal with it as desired.
+type ClientConn struct {
+       c               net.Conn
+       r               *bufio.Reader
+       re, we          os.Error // read/write errors
+       lastBody        io.ReadCloser
+       nread, nwritten int
+       reqm            list.List  // request methods in order of execution
+       lk              sync.Mutex // protects read/write to reqm,re,we
+}
+
+// NewClientConn returns a new ClientConn reading and writing c.  If r is not
+// nil, it is the buffer to use when reading c.
+func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
+       if r == nil {
+               r = bufio.NewReader(c)
+       }
+       return &ClientConn{c: c, r: r}
+}
+
+// Close detaches the ClientConn and returns the underlying connection as well
+// as the read-side bufio which may have some left over data. Close may be
+// called before the user or Read have signaled the end of the keep-alive
+// logic. The user should not call Close while Read or Write is in progress.
+func (cc *ClientConn) Close() (c net.Conn, r *bufio.Reader) {
+       cc.lk.Lock()
+       c = cc.c
+       r = cc.r
+       cc.c = nil
+       cc.r = nil
+       cc.reqm.Init()
+       cc.lk.Unlock()
+       return
+}
+
+// Write writes a request. An ErrPersistEOF error is returned if the connection
+// has been closed in an HTTP keepalive sense. If req.Close equals true, the
+// keepalive connection is logically closed after this request and the opposing
+// server is informed. An ErrUnexpectedEOF indicates the remote closed the
+// underlying TCP connection, which is usually considered as graceful close.
+// Write can be called concurrently with Read, but not with another Write.
+func (cc *ClientConn) Write(req *Request) os.Error {
+
+       cc.lk.Lock()
+       if cc.re != nil { // no point sending if read-side closed or broken
+               defer cc.lk.Unlock()
+               return cc.re
+       }
+       if cc.we != nil {
+               defer cc.lk.Unlock()
+               return cc.we
+       }
+       cc.lk.Unlock()
+
+       if req.Close {
+               // We write the EOF to the write-side error, because there
+               // still might be some pipelined reads
+               cc.lk.Lock()
+               cc.we = ErrPersistEOF
+               cc.lk.Unlock()
+       }
+
+       err := req.Write(cc.c)
+       if err != nil {
+               cc.lk.Lock()
+               defer cc.lk.Unlock()
+               cc.we = err
+               return err
+       }
+       cc.nwritten++
+       cc.lk.Lock()
+       cc.reqm.PushBack(req.Method)
+       cc.lk.Unlock()
+
+       return nil
+}
+
+// Pending returns the number of unanswered requests
+// that have been sent on the connection.
+func (cc *ClientConn) Pending() int {
+       cc.lk.Lock()
+       defer cc.lk.Unlock()
+       return cc.nwritten - cc.nread
+}
+
+// Read reads the next response from the wire. A valid response might be
+// returned together with an ErrPersistEOF, which means that the remote
+// requested that this be the last request serviced. Read can be called
+// concurrently with Write, but not with another Read.
+func (cc *ClientConn) Read() (resp *Response, err os.Error) {
+
+       cc.lk.Lock()
+       if cc.re != nil {
+               defer cc.lk.Unlock()
+               return nil, cc.re
+       }
+       cc.lk.Unlock()
+
+       if cc.nread >= cc.nwritten {
+               return nil, os.NewError("persist client pipe count")
+       }
+
+       // Make sure body is fully consumed, even if user does not call body.Close
+       if cc.lastBody != nil {
+               // body.Close is assumed to be idempotent and multiple calls to
+               // it should return the error that its first invokation
+               // returned.
+               err = cc.lastBody.Close()
+               cc.lastBody = nil
+               if err != nil {
+                       cc.lk.Lock()
+                       defer cc.lk.Unlock()
+                       cc.re = err
+                       return nil, err
+               }
+       }
+
+       cc.lk.Lock()
+       m := cc.reqm.Front()
+       cc.reqm.Remove(m)
+       cc.lk.Unlock()
+       resp, err = ReadResponse(cc.r, m.Value.(string))
+       if err != nil {
+               cc.lk.Lock()
+               defer cc.lk.Unlock()
+               cc.re = err
+               return
+       }
+       cc.lastBody = resp.Body
+
+       cc.nread++
+
+       if resp.Close {
+               cc.lk.Lock()
+               defer cc.lk.Unlock()
+               cc.re = ErrPersistEOF // don't send any more requests
+               return resp, cc.re
+       }
+       return
+}
diff --git a/libgo/go/http/pprof/pprof.go b/libgo/go/http/pprof/pprof.go
new file mode 100644 (file)
index 0000000..f7db9aa
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pprof serves via its HTTP server runtime profiling data
+// in the format expected by the pprof visualization tool.
+// For more information about pprof, see
+// http://code.google.com/p/google-perftools/.
+//
+// The package is typically only imported for the side effect of
+// registering its HTTP handlers.
+// The handled paths all begin with /debug/pprof/.
+//
+// To use pprof, link this package into your program:
+//     import _ "http/pprof"
+//
+// Then use the pprof tool to look at the heap profile:
+//
+//     pprof http://localhost:6060/debug/pprof/heap
+//
+package pprof
+
+import (
+       "bufio"
+       "fmt"
+       "http"
+       "os"
+       "runtime"
+       "runtime/pprof"
+       "strconv"
+       "strings"
+)
+
+func init() {
+       http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
+       http.Handle("/debug/pprof/heap", http.HandlerFunc(Heap))
+       http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
+}
+
+// Cmdline responds with the running program's
+// command line, with arguments separated by NUL bytes.
+// The package initialization registers it as /debug/pprof/cmdline.
+func Cmdline(w http.ResponseWriter, r *http.Request) {
+       w.SetHeader("content-type", "text/plain; charset=utf-8")
+       fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
+}
+
+// Heap responds with the pprof-formatted heap profile.
+// The package initialization registers it as /debug/pprof/heap.
+func Heap(w http.ResponseWriter, r *http.Request) {
+       w.SetHeader("content-type", "text/plain; charset=utf-8")
+       pprof.WriteHeapProfile(w)
+}
+
+// Symbol looks up the program counters listed in the request,
+// responding with a table mapping program counters to function names.
+// The package initialization registers it as /debug/pprof/symbol.
+func Symbol(w http.ResponseWriter, r *http.Request) {
+       w.SetHeader("content-type", "text/plain; charset=utf-8")
+
+       // We don't know how many symbols we have, but we
+       // do have symbol information.  Pprof only cares whether
+       // this number is 0 (no symbols available) or > 0.
+       fmt.Fprintf(w, "num_symbols: 1\n")
+
+       var b *bufio.Reader
+       if r.Method == "POST" {
+               b = bufio.NewReader(r.Body)
+       } else {
+               b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
+       }
+
+       for {
+               word, err := b.ReadSlice('+')
+               if err == nil {
+                       word = word[0 : len(word)-1] // trim +
+               }
+               pc, _ := strconv.Btoui64(string(word), 0)
+               if pc != 0 {
+                       f := runtime.FuncForPC(uintptr(pc))
+                       if f != nil {
+                               fmt.Fprintf(w, "%#x %s\n", pc, f.Name())
+                       }
+               }
+
+               // Wait until here to check for err; the last
+               // symbol will have an err because it doesn't end in +.
+               if err != nil {
+                       break
+               }
+       }
+}
diff --git a/libgo/go/http/readrequest_test.go b/libgo/go/http/readrequest_test.go
new file mode 100644 (file)
index 0000000..067e17d
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "io"
+       "testing"
+)
+
+type reqTest struct {
+       Raw  string
+       Req  Request
+       Body string
+}
+
+var reqTests = []reqTest{
+       // Baseline test; All Request fields included for template use
+       {
+               "GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
+                       "Host: www.techcrunch.com\r\n" +
+                       "User-Agent: Fake\r\n" +
+                       "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" +
+                       "Accept-Language: en-us,en;q=0.5\r\n" +
+                       "Accept-Encoding: gzip,deflate\r\n" +
+                       "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
+                       "Keep-Alive: 300\r\n" +
+                       "Content-Length: 7\r\n" +
+                       "Proxy-Connection: keep-alive\r\n\r\n" +
+                       "abcdef\n???",
+
+               Request{
+                       Method: "GET",
+                       RawURL: "http://www.techcrunch.com/",
+                       URL: &URL{
+                               Raw:          "http://www.techcrunch.com/",
+                               Scheme:       "http",
+                               RawPath:      "/",
+                               RawAuthority: "www.techcrunch.com",
+                               RawUserinfo:  "",
+                               Host:         "www.techcrunch.com",
+                               Path:         "/",
+                               RawQuery:     "",
+                               Fragment:     "",
+                       },
+                       Proto:      "HTTP/1.1",
+                       ProtoMajor: 1,
+                       ProtoMinor: 1,
+                       Header: map[string]string{
+                               "Accept":           "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
+                               "Accept-Language":  "en-us,en;q=0.5",
+                               "Accept-Encoding":  "gzip,deflate",
+                               "Accept-Charset":   "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
+                               "Keep-Alive":       "300",
+                               "Proxy-Connection": "keep-alive",
+                               "Content-Length":   "7",
+                       },
+                       Close:         false,
+                       ContentLength: 7,
+                       Host:          "www.techcrunch.com",
+                       Referer:       "",
+                       UserAgent:     "Fake",
+                       Form:          map[string][]string{},
+               },
+
+               "abcdef\n",
+       },
+}
+
+func TestReadRequest(t *testing.T) {
+       for i := range reqTests {
+               tt := &reqTests[i]
+               var braw bytes.Buffer
+               braw.WriteString(tt.Raw)
+               req, err := ReadRequest(bufio.NewReader(&braw))
+               if err != nil {
+                       t.Errorf("#%d: %s", i, err)
+                       continue
+               }
+               rbody := req.Body
+               req.Body = nil
+               diff(t, fmt.Sprintf("#%d Request", i), req, &tt.Req)
+               var bout bytes.Buffer
+               if rbody != nil {
+                       io.Copy(&bout, rbody)
+                       rbody.Close()
+               }
+               body := bout.String()
+               if body != tt.Body {
+                       t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
+               }
+       }
+}
diff --git a/libgo/go/http/request.go b/libgo/go/http/request.go
new file mode 100644 (file)
index 0000000..b886899
--- /dev/null
@@ -0,0 +1,693 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// HTTP Request reading and parsing.
+
+// The http package implements parsing of HTTP requests, replies,
+// and URLs and provides an extensible HTTP server and a basic
+// HTTP client.
+package http
+
+import (
+       "bufio"
+       "bytes"
+       "container/vector"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "mime"
+       "mime/multipart"
+       "os"
+       "strconv"
+       "strings"
+)
+
+const (
+       maxLineLength  = 4096 // assumed <= bufio.defaultBufSize
+       maxValueLength = 4096
+       maxHeaderLines = 1024
+       chunkSize      = 4 << 10 // 4 KB chunks
+)
+
+// HTTP request parsing errors.
+type ProtocolError struct {
+       os.ErrorString
+}
+
+var (
+       ErrLineTooLong          = &ProtocolError{"header line too long"}
+       ErrHeaderTooLong        = &ProtocolError{"header too long"}
+       ErrShortBody            = &ProtocolError{"entity body too short"}
+       ErrNotSupported         = &ProtocolError{"feature not supported"}
+       ErrUnexpectedTrailer    = &ProtocolError{"trailer header without chunked transfer encoding"}
+       ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
+       ErrNotMultipart         = &ProtocolError{"request Content-Type isn't multipart/form-data"}
+       ErrMissingBoundary      = &ProtocolError{"no multipart boundary param Content-Type"}
+)
+
+type badStringError struct {
+       what string
+       str  string
+}
+
+func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e.str) }
+
+var reqExcludeHeader = map[string]bool{
+       "Host":              true,
+       "User-Agent":        true,
+       "Referer":           true,
+       "Content-Length":    true,
+       "Transfer-Encoding": true,
+       "Trailer":           true,
+}
+
+// A Request represents a parsed HTTP request header.
+type Request struct {
+       Method     string // GET, POST, PUT, etc.
+       RawURL     string // The raw URL given in the request.
+       URL        *URL   // Parsed URL.
+       Proto      string // "HTTP/1.0"
+       ProtoMajor int    // 1
+       ProtoMinor int    // 0
+
+       // A header maps request lines to their values.
+       // If the header says
+       //
+       //      accept-encoding: gzip, deflate
+       //      Accept-Language: en-us
+       //      Connection: keep-alive
+       //
+       // then
+       //
+       //      Header = map[string]string{
+       //              "Accept-Encoding": "gzip, deflate",
+       //              "Accept-Language": "en-us",
+       //              "Connection": "keep-alive",
+       //      }
+       //
+       // HTTP defines that header names are case-insensitive.
+       // The request parser implements this by canonicalizing the
+       // name, making the first character and any characters
+       // following a hyphen uppercase and the rest lowercase.
+       Header map[string]string
+
+       // The message body.
+       Body io.ReadCloser
+
+       // ContentLength records the length of the associated content.
+       // The value -1 indicates that the length is unknown.
+       // Values >= 0 indicate that the given number of bytes may be read from Body.
+       ContentLength int64
+
+       // TransferEncoding lists the transfer encodings from outermost to innermost.
+       // An empty list denotes the "identity" encoding.
+       TransferEncoding []string
+
+       // Whether to close the connection after replying to this request.
+       Close bool
+
+       // The host on which the URL is sought.
+       // Per RFC 2616, this is either the value of the Host: header
+       // or the host name given in the URL itself.
+       Host string
+
+       // The referring URL, if sent in the request.
+       //
+       // Referer is misspelled as in the request itself,
+       // a mistake from the earliest days of HTTP.
+       // This value can also be fetched from the Header map
+       // as Header["Referer"]; the benefit of making it
+       // available as a structure field is that the compiler
+       // can diagnose programs that use the alternate
+       // (correct English) spelling req.Referrer but cannot
+       // diagnose programs that use Header["Referrer"].
+       Referer string
+
+       // The User-Agent: header string, if sent in the request.
+       UserAgent string
+
+       // The parsed form. Only available after ParseForm is called.
+       Form map[string][]string
+
+       // Trailer maps trailer keys to values.  Like for Header, if the
+       // response has multiple trailer lines with the same key, they will be
+       // concatenated, delimited by commas.
+       Trailer map[string]string
+}
+
+// ProtoAtLeast returns whether the HTTP protocol used
+// in the request is at least major.minor.
+func (r *Request) ProtoAtLeast(major, minor int) bool {
+       return r.ProtoMajor > major ||
+               r.ProtoMajor == major && r.ProtoMinor >= minor
+}
+
+// MultipartReader returns a MIME multipart reader if this is a
+// multipart/form-data POST request, else returns nil and an error.
+func (r *Request) MultipartReader() (multipart.Reader, os.Error) {
+       v, ok := r.Header["Content-Type"]
+       if !ok {
+               return nil, ErrNotMultipart
+       }
+       d, params := mime.ParseMediaType(v)
+       if d != "multipart/form-data" {
+               return nil, ErrNotMultipart
+       }
+       boundary, ok := params["boundary"]
+       if !ok {
+               return nil, ErrMissingBoundary
+       }
+       return multipart.NewReader(r.Body, boundary), nil
+}
+
+// Return value if nonempty, def otherwise.
+func valueOrDefault(value, def string) string {
+       if value != "" {
+               return value
+       }
+       return def
+}
+
+const defaultUserAgent = "Go http package"
+
+// Write writes an HTTP/1.1 request -- header and body -- in wire format.
+// This method consults the following fields of req:
+//     Host
+//     RawURL, if non-empty, or else URL
+//     Method (defaults to "GET")
+//     UserAgent (defaults to defaultUserAgent)
+//     Referer
+//     Header
+//     Body
+//
+// If Body is present, Write forces "Transfer-Encoding: chunked" as a header
+// and then closes Body when finished sending it.
+func (req *Request) Write(w io.Writer) os.Error {
+       host := req.Host
+       if host == "" {
+               host = req.URL.Host
+       }
+
+       uri := req.RawURL
+       if uri == "" {
+               uri = valueOrDefault(urlEscape(req.URL.Path, encodePath), "/")
+               if req.URL.RawQuery != "" {
+                       uri += "?" + req.URL.RawQuery
+               }
+       }
+
+       fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), uri)
+
+       // Header lines
+       fmt.Fprintf(w, "Host: %s\r\n", host)
+       fmt.Fprintf(w, "User-Agent: %s\r\n", valueOrDefault(req.UserAgent, defaultUserAgent))
+       if req.Referer != "" {
+               fmt.Fprintf(w, "Referer: %s\r\n", req.Referer)
+       }
+
+       // Process Body,ContentLength,Close,Trailer
+       tw, err := newTransferWriter(req)
+       if err != nil {
+               return err
+       }
+       err = tw.WriteHeader(w)
+       if err != nil {
+               return err
+       }
+
+       // TODO: split long values?  (If so, should share code with Conn.Write)
+       // TODO: if Header includes values for Host, User-Agent, or Referer, this
+       // may conflict with the User-Agent or Referer headers we add manually.
+       // One solution would be to remove the Host, UserAgent, and Referer fields
+       // from Request, and introduce Request methods along the lines of
+       // Response.{GetHeader,AddHeader} and string constants for "Host",
+       // "User-Agent" and "Referer".
+       err = writeSortedKeyValue(w, req.Header, reqExcludeHeader)
+       if err != nil {
+               return err
+       }
+
+       io.WriteString(w, "\r\n")
+
+       // Write body and trailer
+       err = tw.WriteBody(w)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+// Read a line of bytes (up to \n) from b.
+// Give up if the line exceeds maxLineLength.
+// The returned bytes are a pointer into storage in
+// the bufio, so they are only valid until the next bufio read.
+func readLineBytes(b *bufio.Reader) (p []byte, err os.Error) {
+       if p, err = b.ReadSlice('\n'); err != nil {
+               // We always know when EOF is coming.
+               // If the caller asked for a line, there should be a line.
+               if err == os.EOF {
+                       err = io.ErrUnexpectedEOF
+               } else if err == bufio.ErrBufferFull {
+                       err = ErrLineTooLong
+               }
+               return nil, err
+       }
+       if len(p) >= maxLineLength {
+               return nil, ErrLineTooLong
+       }
+
+       // Chop off trailing white space.
+       var i int
+       for i = len(p); i > 0; i-- {
+               if c := p[i-1]; c != ' ' && c != '\r' && c != '\t' && c != '\n' {
+                       break
+               }
+       }
+       return p[0:i], nil
+}
+
+// readLineBytes, but convert the bytes into a string.
+func readLine(b *bufio.Reader) (s string, err os.Error) {
+       p, e := readLineBytes(b)
+       if e != nil {
+               return "", e
+       }
+       return string(p), nil
+}
+
+var colon = []byte{':'}
+
+// Read a key/value pair from b.
+// A key/value has the form Key: Value\r\n
+// and the Value can continue on multiple lines if each continuation line
+// starts with a space.
+func readKeyValue(b *bufio.Reader) (key, value string, err os.Error) {
+       line, e := readLineBytes(b)
+       if e != nil {
+               return "", "", e
+       }
+       if len(line) == 0 {
+               return "", "", nil
+       }
+
+       // Scan first line for colon.
+       i := bytes.Index(line, colon)
+       if i < 0 {
+               goto Malformed
+       }
+
+       key = string(line[0:i])
+       if strings.Contains(key, " ") {
+               // Key field has space - no good.
+               goto Malformed
+       }
+
+       // Skip initial space before value.
+       for i++; i < len(line); i++ {
+               if line[i] != ' ' {
+                       break
+               }
+       }
+       value = string(line[i:])
+
+       // Look for extension lines, which must begin with space.
+       for {
+               c, e := b.ReadByte()
+               if c != ' ' {
+                       if e != os.EOF {
+                               b.UnreadByte()
+                       }
+                       break
+               }
+
+               // Eat leading space.
+               for c == ' ' {
+                       if c, e = b.ReadByte(); e != nil {
+                               if e == os.EOF {
+                                       e = io.ErrUnexpectedEOF
+                               }
+                               return "", "", e
+                       }
+               }
+               b.UnreadByte()
+
+               // Read the rest of the line and add to value.
+               if line, e = readLineBytes(b); e != nil {
+                       return "", "", e
+               }
+               value += " " + string(line)
+
+               if len(value) >= maxValueLength {
+                       return "", "", &badStringError{"value too long for key", key}
+               }
+       }
+       return key, value, nil
+
+Malformed:
+       return "", "", &badStringError{"malformed header line", string(line)}
+}
+
+// Convert decimal at s[i:len(s)] to integer,
+// returning value, string position where the digits stopped,
+// and whether there was a valid number (digits, not too big).
+func atoi(s string, i int) (n, i1 int, ok bool) {
+       const Big = 1000000
+       if i >= len(s) || s[i] < '0' || s[i] > '9' {
+               return 0, 0, false
+       }
+       n = 0
+       for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+               n = n*10 + int(s[i]-'0')
+               if n > Big {
+                       return 0, 0, false
+               }
+       }
+       return n, i, true
+}
+
+// Parse HTTP version: "HTTP/1.2" -> (1, 2, true).
+func parseHTTPVersion(vers string) (int, int, bool) {
+       if len(vers) < 5 || vers[0:5] != "HTTP/" {
+               return 0, 0, false
+       }
+       major, i, ok := atoi(vers, 5)
+       if !ok || i >= len(vers) || vers[i] != '.' {
+               return 0, 0, false
+       }
+       var minor int
+       minor, i, ok = atoi(vers, i+1)
+       if !ok || i != len(vers) {
+               return 0, 0, false
+       }
+       return major, minor, true
+}
+
+// CanonicalHeaderKey returns the canonical format of the
+// HTTP header key s.  The canonicalization converts the first
+// letter and any letter following a hyphen to upper case;
+// the rest are converted to lowercase.  For example, the
+// canonical key for "accept-encoding" is "Accept-Encoding".
+func CanonicalHeaderKey(s string) string {
+       // canonicalize: first letter upper case
+       // and upper case after each dash.
+       // (Host, User-Agent, If-Modified-Since).
+       // HTTP headers are ASCII only, so no Unicode issues.
+       var a []byte
+       upper := true
+       for i := 0; i < len(s); i++ {
+               v := s[i]
+               if upper && 'a' <= v && v <= 'z' {
+                       if a == nil {
+                               a = []byte(s)
+                       }
+                       a[i] = v + 'A' - 'a'
+               }
+               if !upper && 'A' <= v && v <= 'Z' {
+                       if a == nil {
+                               a = []byte(s)
+                       }
+                       a[i] = v + 'a' - 'A'
+               }
+               upper = false
+               if v == '-' {
+                       upper = true
+               }
+       }
+       if a != nil {
+               return string(a)
+       }
+       return s
+}
+
+type chunkedReader struct {
+       r   *bufio.Reader
+       n   uint64 // unread bytes in chunk
+       err os.Error
+}
+
+func newChunkedReader(r *bufio.Reader) *chunkedReader {
+       return &chunkedReader{r: r}
+}
+
+func (cr *chunkedReader) beginChunk() {
+       // chunk-size CRLF
+       var line string
+       line, cr.err = readLine(cr.r)
+       if cr.err != nil {
+               return
+       }
+       cr.n, cr.err = strconv.Btoui64(line, 16)
+       if cr.err != nil {
+               return
+       }
+       if cr.n == 0 {
+               // trailer CRLF
+               for {
+                       line, cr.err = readLine(cr.r)
+                       if cr.err != nil {
+                               return
+                       }
+                       if line == "" {
+                               break
+                       }
+               }
+               cr.err = os.EOF
+       }
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err os.Error) {
+       if cr.err != nil {
+               return 0, cr.err
+       }
+       if cr.n == 0 {
+               cr.beginChunk()
+               if cr.err != nil {
+                       return 0, cr.err
+               }
+       }
+       if uint64(len(b)) > cr.n {
+               b = b[0:cr.n]
+       }
+       n, cr.err = cr.r.Read(b)
+       cr.n -= uint64(n)
+       if cr.n == 0 && cr.err == nil {
+               // end of chunk (CRLF)
+               b := make([]byte, 2)
+               if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil {
+                       if b[0] != '\r' || b[1] != '\n' {
+                               cr.err = os.NewError("malformed chunked encoding")
+                       }
+               }
+       }
+       return n, cr.err
+}
+
+// ReadRequest reads and parses a request from b.
+func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
+       req = new(Request)
+
+       // First line: GET /index.html HTTP/1.0
+       var s string
+       if s, err = readLine(b); err != nil {
+               return nil, err
+       }
+
+       var f []string
+       if f = strings.Split(s, " ", 3); len(f) < 3 {
+               return nil, &badStringError{"malformed HTTP request", s}
+       }
+       req.Method, req.RawURL, req.Proto = f[0], f[1], f[2]
+       var ok bool
+       if req.ProtoMajor, req.ProtoMinor, ok = parseHTTPVersion(req.Proto); !ok {
+               return nil, &badStringError{"malformed HTTP version", req.Proto}
+       }
+
+       if req.URL, err = ParseURL(req.RawURL); err != nil {
+               return nil, err
+       }
+
+       // Subsequent lines: Key: value.
+       nheader := 0
+       req.Header = make(map[string]string)
+       for {
+               var key, value string
+               if key, value, err = readKeyValue(b); err != nil {
+                       return nil, err
+               }
+               if key == "" {
+                       break
+               }
+               if nheader++; nheader >= maxHeaderLines {
+                       return nil, ErrHeaderTooLong
+               }
+
+               key = CanonicalHeaderKey(key)
+
+               // RFC 2616 says that if you send the same header key
+               // multiple times, it has to be semantically equivalent
+               // to concatenating the values separated by commas.
+               oldvalue, present := req.Header[key]
+               if present {
+                       req.Header[key] = oldvalue + "," + value
+               } else {
+                       req.Header[key] = value
+               }
+       }
+
+       // RFC2616: Must treat
+       //      GET /index.html HTTP/1.1
+       //      Host: www.google.com
+       // and
+       //      GET http://www.google.com/index.html HTTP/1.1
+       //      Host: doesntmatter
+       // the same.  In the second case, any Host line is ignored.
+       req.Host = req.URL.Host
+       if req.Host == "" {
+               req.Host = req.Header["Host"]
+       }
+       req.Header["Host"] = "", false
+
+       fixPragmaCacheControl(req.Header)
+
+       // Pull out useful fields as a convenience to clients.
+       req.Referer = req.Header["Referer"]
+       req.Header["Referer"] = "", false
+
+       req.UserAgent = req.Header["User-Agent"]
+       req.Header["User-Agent"] = "", false
+
+       // TODO: Parse specific header values:
+       //      Accept
+       //      Accept-Encoding
+       //      Accept-Language
+       //      Authorization
+       //      Cache-Control
+       //      Connection
+       //      Date
+       //      Expect
+       //      From
+       //      If-Match
+       //      If-Modified-Since
+       //      If-None-Match
+       //      If-Range
+       //      If-Unmodified-Since
+       //      Max-Forwards
+       //      Proxy-Authorization
+       //      Referer [sic]
+       //      TE (transfer-codings)
+       //      Trailer
+       //      Transfer-Encoding
+       //      Upgrade
+       //      User-Agent
+       //      Via
+       //      Warning
+
+       err = readTransfer(req, b)
+       if err != nil {
+               return nil, err
+       }
+
+       return req, nil
+}
+
+// ParseQuery parses the URL-encoded query string and returns
+// a map listing the values specified for each key.
+// ParseQuery always returns a non-nil map containing all the
+// valid query parameters found; err describes the first decoding error
+// encountered, if any.
+func ParseQuery(query string) (m map[string][]string, err os.Error) {
+       m = make(map[string][]string)
+       err = parseQuery(m, query)
+       return
+}
+
+func parseQuery(m map[string][]string, query string) (err os.Error) {
+       for _, kv := range strings.Split(query, "&", -1) {
+               if len(kv) == 0 {
+                       continue
+               }
+               kvPair := strings.Split(kv, "=", 2)
+
+               var key, value string
+               var e os.Error
+               key, e = URLUnescape(kvPair[0])
+               if e == nil && len(kvPair) > 1 {
+                       value, e = URLUnescape(kvPair[1])
+               }
+               if e != nil {
+                       err = e
+                       continue
+               }
+               vec := vector.StringVector(m[key])
+               vec.Push(value)
+               m[key] = vec
+       }
+       return err
+}
+
+// ParseForm parses the request body as a form for POST requests, or the raw query for GET requests.
+// It is idempotent.
+func (r *Request) ParseForm() (err os.Error) {
+       if r.Form != nil {
+               return
+       }
+
+       r.Form = make(map[string][]string)
+       if r.URL != nil {
+               err = parseQuery(r.Form, r.URL.RawQuery)
+       }
+       if r.Method == "POST" {
+               if r.Body == nil {
+                       return os.ErrorString("missing form body")
+               }
+               ct := r.Header["Content-Type"]
+               switch strings.Split(ct, ";", 2)[0] {
+               case "text/plain", "application/x-www-form-urlencoded", "":
+                       b, e := ioutil.ReadAll(r.Body)
+                       if e != nil {
+                               if err == nil {
+                                       err = e
+                               }
+                               break
+                       }
+                       e = parseQuery(r.Form, string(b))
+                       if err == nil {
+                               err = e
+                       }
+               // TODO(dsymonds): Handle multipart/form-data
+               default:
+                       return &badStringError{"unknown Content-Type", ct}
+               }
+       }
+       return err
+}
+
+// FormValue returns the first value for the named component of the query.
+// FormValue calls ParseForm if necessary.
+func (r *Request) FormValue(key string) string {
+       if r.Form == nil {
+               r.ParseForm()
+       }
+       if vs := r.Form[key]; len(vs) > 0 {
+               return vs[0]
+       }
+       return ""
+}
+
+func (r *Request) expectsContinue() bool {
+       expectation, ok := r.Header["Expect"]
+       return ok && strings.ToLower(expectation) == "100-continue"
+}
+
+func (r *Request) wantsHttp10KeepAlive() bool {
+       if r.ProtoMajor != 1 || r.ProtoMinor != 0 {
+               return false
+       }
+       value, exists := r.Header["Connection"]
+       if !exists {
+               return false
+       }
+       return strings.Contains(strings.ToLower(value), "keep-alive")
+}
diff --git a/libgo/go/http/request_test.go b/libgo/go/http/request_test.go
new file mode 100644 (file)
index 0000000..d25e5e5
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "bytes"
+       "reflect"
+       "regexp"
+       "strings"
+       "testing"
+)
+
+type stringMultimap map[string][]string
+
+type parseTest struct {
+       query string
+       out   stringMultimap
+}
+
+var parseTests = []parseTest{
+       {
+               query: "a=1&b=2",
+               out:   stringMultimap{"a": []string{"1"}, "b": []string{"2"}},
+       },
+       {
+               query: "a=1&a=2&a=banana",
+               out:   stringMultimap{"a": []string{"1", "2", "banana"}},
+       },
+       {
+               query: "ascii=%3Ckey%3A+0x90%3E",
+               out:   stringMultimap{"ascii": []string{"<key: 0x90>"}},
+       },
+}
+
+func TestParseForm(t *testing.T) {
+       for i, test := range parseTests {
+               form, err := ParseQuery(test.query)
+               if err != nil {
+                       t.Errorf("test %d: Unexpected error: %v", i, err)
+                       continue
+               }
+               if len(form) != len(test.out) {
+                       t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
+               }
+               for k, evs := range test.out {
+                       vs, ok := form[k]
+                       if !ok {
+                               t.Errorf("test %d: Missing key %q", i, k)
+                               continue
+                       }
+                       if len(vs) != len(evs) {
+                               t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
+                               continue
+                       }
+                       for j, ev := range evs {
+                               if v := vs[j]; v != ev {
+                                       t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
+                               }
+                       }
+               }
+       }
+}
+
+func TestQuery(t *testing.T) {
+       req := &Request{Method: "GET"}
+       req.URL, _ = ParseURL("http://www.google.com/search?q=foo&q=bar")
+       if q := req.FormValue("q"); q != "foo" {
+               t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+       }
+}
+
+func TestPostQuery(t *testing.T) {
+       req := &Request{Method: "POST"}
+       req.URL, _ = ParseURL("http://www.google.com/search?q=foo&q=bar&both=x")
+       req.Header = map[string]string{"Content-Type": "application/x-www-form-urlencoded; boo!"}
+       req.Body = nopCloser{strings.NewReader("z=post&both=y")}
+       if q := req.FormValue("q"); q != "foo" {
+               t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+       }
+       if z := req.FormValue("z"); z != "post" {
+               t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
+       }
+       if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"x", "y"}) {
+               t.Errorf(`req.FormValue("both") = %q, want ["x", "y"]`, both)
+       }
+}
+
+type stringMap map[string]string
+type parseContentTypeTest struct {
+       contentType stringMap
+       error       bool
+}
+
+var parseContentTypeTests = []parseContentTypeTest{
+       {contentType: stringMap{"Content-Type": "text/plain"}},
+       {contentType: stringMap{"Content-Type": ""}},
+       {contentType: stringMap{"Content-Type": "text/plain; boundary="}},
+       {
+               contentType: stringMap{"Content-Type": "application/unknown"},
+               error:       true,
+       },
+}
+
+func TestPostContentTypeParsing(t *testing.T) {
+       for i, test := range parseContentTypeTests {
+               req := &Request{
+                       Method: "POST",
+                       Header: test.contentType,
+                       Body:   nopCloser{bytes.NewBufferString("body")},
+               }
+               err := req.ParseForm()
+               if !test.error && err != nil {
+                       t.Errorf("test %d: Unexpected error: %v", i, err)
+               }
+               if test.error && err == nil {
+                       t.Errorf("test %d should have returned error", i)
+               }
+       }
+}
+
+func TestMultipartReader(t *testing.T) {
+       req := &Request{
+               Method: "POST",
+               Header: stringMap{"Content-Type": `multipart/form-data; boundary="foo123"`},
+               Body:   nopCloser{new(bytes.Buffer)},
+       }
+       multipart, err := req.MultipartReader()
+       if multipart == nil {
+               t.Errorf("expected multipart; error: %v", err)
+       }
+
+       req.Header = stringMap{"Content-Type": "text/plain"}
+       multipart, err = req.MultipartReader()
+       if multipart != nil {
+               t.Errorf("unexpected multipart for text/plain")
+       }
+}
+
+func TestRedirect(t *testing.T) {
+       const (
+               start = "http://google.com/"
+               endRe = "^http://www\\.google\\.[a-z.]+/$"
+       )
+       var end = regexp.MustCompile(endRe)
+       r, url, err := Get(start)
+       if err != nil {
+               t.Fatal(err)
+       }
+       r.Body.Close()
+       if r.StatusCode != 200 || !end.MatchString(url) {
+               t.Fatalf("Get(%s) got status %d at %q, want 200 matching %q", start, r.StatusCode, url, endRe)
+       }
+}
diff --git a/libgo/go/http/requestwrite_test.go b/libgo/go/http/requestwrite_test.go
new file mode 100644 (file)
index 0000000..3ceabe4
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "bytes"
+       "testing"
+)
+
+type reqWriteTest struct {
+       Req Request
+       Raw string
+}
+
+var reqWriteTests = []reqWriteTest{
+       // HTTP/1.1 => chunked coding; no body; no trailer
+       {
+               Request{
+                       Method: "GET",
+                       RawURL: "http://www.techcrunch.com/",
+                       URL: &URL{
+                               Raw:          "http://www.techcrunch.com/",
+                               Scheme:       "http",
+                               RawPath:      "http://www.techcrunch.com/",
+                               RawAuthority: "www.techcrunch.com",
+                               RawUserinfo:  "",
+                               Host:         "www.techcrunch.com",
+                               Path:         "/",
+                               RawQuery:     "",
+                               Fragment:     "",
+                       },
+                       Proto:      "HTTP/1.1",
+                       ProtoMajor: 1,
+                       ProtoMinor: 1,
+                       Header: map[string]string{
+                               "Accept":           "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
+                               "Accept-Charset":   "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
+                               "Accept-Encoding":  "gzip,deflate",
+                               "Accept-Language":  "en-us,en;q=0.5",
+                               "Keep-Alive":       "300",
+                               "Proxy-Connection": "keep-alive",
+                       },
+                       Body:      nil,
+                       Close:     false,
+                       Host:      "www.techcrunch.com",
+                       Referer:   "",
+                       UserAgent: "Fake",
+                       Form:      map[string][]string{},
+               },
+
+               "GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
+                       "Host: www.techcrunch.com\r\n" +
+                       "User-Agent: Fake\r\n" +
+                       "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
+                       "Accept-Encoding: gzip,deflate\r\n" +
+                       "Accept-Language: en-us,en;q=0.5\r\n" +
+                       "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" +
+                       "Keep-Alive: 300\r\n" +
+                       "Proxy-Connection: keep-alive\r\n\r\n",
+       },
+       // HTTP/1.1 => chunked coding; body; empty trailer
+       {
+               Request{
+                       Method: "GET",
+                       URL: &URL{
+                               Scheme: "http",
+                               Host:   "www.google.com",
+                               Path:   "/search",
+                       },
+                       ProtoMajor:       1,
+                       ProtoMinor:       1,
+                       Header:           map[string]string{},
+                       Body:             nopCloser{bytes.NewBufferString("abcdef")},
+                       TransferEncoding: []string{"chunked"},
+               },
+
+               "GET /search HTTP/1.1\r\n" +
+                       "Host: www.google.com\r\n" +
+                       "User-Agent: Go http package\r\n" +
+                       "Transfer-Encoding: chunked\r\n\r\n" +
+                       "6\r\nabcdef\r\n0\r\n\r\n",
+       },
+       // HTTP/1.1 POST => chunked coding; body; empty trailer
+       {
+               Request{
+                       Method: "POST",
+                       URL: &URL{
+                               Scheme: "http",
+                               Host:   "www.google.com",
+                               Path:   "/search",
+                       },
+                       ProtoMajor:       1,
+                       ProtoMinor:       1,
+                       Header:           map[string]string{},
+                       Close:            true,
+                       Body:             nopCloser{bytes.NewBufferString("abcdef")},
+                       TransferEncoding: []string{"chunked"},
+               },
+
+               "POST /search HTTP/1.1\r\n" +
+                       "Host: www.google.com\r\n" +
+                       "User-Agent: Go http package\r\n" +
+                       "Connection: close\r\n" +
+                       "Transfer-Encoding: chunked\r\n\r\n" +
+                       "6\r\nabcdef\r\n0\r\n\r\n",
+       },
+       // default to HTTP/1.1
+       {
+               Request{
+                       Method: "GET",
+                       RawURL: "/search",
+                       Host:   "www.google.com",
+               },
+
+               "GET /search HTTP/1.1\r\n" +
+                       "Host: www.google.com\r\n" +
+                       "User-Agent: Go http package\r\n" +
+                       "\r\n",
+       },
+}
+
+func TestRequestWrite(t *testing.T) {
+       for i := range reqWriteTests {
+               tt := &reqWriteTests[i]
+               var braw bytes.Buffer
+               err := tt.Req.Write(&braw)
+               if err != nil {
+                       t.Errorf("error writing #%d: %s", i, err)
+                       continue
+               }
+               sraw := braw.String()
+               if sraw != tt.Raw {
+                       t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, sraw)
+                       continue
+               }
+       }
+}
diff --git a/libgo/go/http/response.go b/libgo/go/http/response.go
new file mode 100644 (file)
index 0000000..6a209c9
--- /dev/null
@@ -0,0 +1,247 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// HTTP Response reading and parsing.
+
+package http
+
+import (
+       "bufio"
+       "fmt"
+       "io"
+       "os"
+       "sort"
+       "strconv"
+       "strings"
+)
+
+var respExcludeHeader = map[string]bool{
+       "Content-Length":    true,
+       "Transfer-Encoding": true,
+       "Trailer":           true,
+}
+
+// Response represents the response from an HTTP request.
+//
+type Response struct {
+       Status     string // e.g. "200 OK"
+       StatusCode int    // e.g. 200
+       Proto      string // e.g. "HTTP/1.0"
+       ProtoMajor int    // e.g. 1
+       ProtoMinor int    // e.g. 0
+
+       // RequestMethod records the method used in the HTTP request.
+       // Header fields such as Content-Length have method-specific meaning.
+       RequestMethod string // e.g. "HEAD", "CONNECT", "GET", etc.
+
+       // Header maps header keys to values.  If the response had multiple
+       // headers with the same key, they will be concatenated, with comma
+       // delimiters.  (Section 4.2 of RFC 2616 requires that multiple headers
+       // be semantically equivalent to a comma-delimited sequence.) Values
+       // duplicated by other fields in this struct (e.g., ContentLength) are
+       // omitted from Header.
+       //
+       // Keys in the map are canonicalized (see CanonicalHeaderKey).
+       Header map[string]string
+
+       // Body represents the response body.
+       Body io.ReadCloser
+
+       // ContentLength records the length of the associated content.  The
+       // value -1 indicates that the length is unknown.  Unless RequestMethod
+       // is "HEAD", values >= 0 indicate that the given number of bytes may
+       // be read from Body.
+       ContentLength int64
+
+       // Contains transfer encodings from outer-most to inner-most. Value is
+       // nil, means that "identity" encoding is used.
+       TransferEncoding []string
+
+       // Close records whether the header directed that the connection be
+       // closed after reading Body.  The value is advice for clients: neither
+       // ReadResponse nor Response.Write ever closes a connection.
+       Close bool
+
+       // Trailer maps trailer keys to values.  Like for Header, if the
+       // response has multiple trailer lines with the same key, they will be
+       // concatenated, delimited by commas.
+       Trailer map[string]string
+}
+
+// ReadResponse reads and returns an HTTP response from r.  The RequestMethod
+// parameter specifies the method used in the corresponding request (e.g.,
+// "GET", "HEAD").  Clients must call resp.Body.Close when finished reading
+// resp.Body.  After that call, clients can inspect resp.Trailer to find
+// key/value pairs included in the response trailer.
+func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os.Error) {
+
+       resp = new(Response)
+
+       resp.RequestMethod = strings.ToUpper(requestMethod)
+
+       // Parse the first line of the response.
+       line, err := readLine(r)
+       if err != nil {
+               return nil, err
+       }
+       f := strings.Split(line, " ", 3)
+       if len(f) < 3 {
+               return nil, &badStringError{"malformed HTTP response", line}
+       }
+       resp.Status = f[1] + " " + f[2]
+       resp.StatusCode, err = strconv.Atoi(f[1])
+       if err != nil {
+               return nil, &badStringError{"malformed HTTP status code", f[1]}
+       }
+
+       resp.Proto = f[0]
+       var ok bool
+       if resp.ProtoMajor, resp.ProtoMinor, ok = parseHTTPVersion(resp.Proto); !ok {
+               return nil, &badStringError{"malformed HTTP version", resp.Proto}
+       }
+
+       // Parse the response headers.
+       nheader := 0
+       resp.Header = make(map[string]string)
+       for {
+               key, value, err := readKeyValue(r)
+               if err != nil {
+                       return nil, err
+               }
+               if key == "" {
+                       break // end of response header
+               }
+               if nheader++; nheader >= maxHeaderLines {
+                       return nil, ErrHeaderTooLong
+               }
+               resp.AddHeader(key, value)
+       }
+
+       fixPragmaCacheControl(resp.Header)
+
+       err = readTransfer(resp, r)
+       if err != nil {
+               return nil, err
+       }
+
+       return resp, nil
+}
+
+// RFC2616: Should treat
+//     Pragma: no-cache
+// like
+//     Cache-Control: no-cache
+func fixPragmaCacheControl(header map[string]string) {
+       if header["Pragma"] == "no-cache" {
+               if _, presentcc := header["Cache-Control"]; !presentcc {
+                       header["Cache-Control"] = "no-cache"
+               }
+       }
+}
+
+// AddHeader adds a value under the given key.  Keys are not case sensitive.
+func (r *Response) AddHeader(key, value string) {
+       key = CanonicalHeaderKey(key)
+
+       oldValues, oldValuesPresent := r.Header[key]
+       if oldValuesPresent {
+               r.Header[key] = oldValues + "," + value
+       } else {
+               r.Header[key] = value
+       }
+}
+
+// GetHeader returns the value of the response header with the given key.
+// If there were multiple headers with this key, their values are concatenated,
+// with a comma delimiter.  If there were no response headers with the given
+// key, GetHeader returns an empty string.  Keys are not case sensitive.
+func (r *Response) GetHeader(key string) (value string) {
+       return r.Header[CanonicalHeaderKey(key)]
+}
+
+// ProtoAtLeast returns whether the HTTP protocol used
+// in the response is at least major.minor.
+func (r *Response) ProtoAtLeast(major, minor int) bool {
+       return r.ProtoMajor > major ||
+               r.ProtoMajor == major && r.ProtoMinor >= minor
+}
+
+// Writes the response (header, body and trailer) in wire format. This method
+// consults the following fields of resp:
+//
+//  StatusCode
+//  ProtoMajor
+//  ProtoMinor
+//  RequestMethod
+//  TransferEncoding
+//  Trailer
+//  Body
+//  ContentLength
+//  Header, values for non-canonical keys will have unpredictable behavior
+//
+func (resp *Response) Write(w io.Writer) os.Error {
+
+       // RequestMethod should be upper-case
+       resp.RequestMethod = strings.ToUpper(resp.RequestMethod)
+
+       // Status line
+       text := resp.Status
+       if text == "" {
+               var ok bool
+               text, ok = statusText[resp.StatusCode]
+               if !ok {
+                       text = "status code " + strconv.Itoa(resp.StatusCode)
+               }
+       }
+       io.WriteString(w, "HTTP/"+strconv.Itoa(resp.ProtoMajor)+".")
+       io.WriteString(w, strconv.Itoa(resp.ProtoMinor)+" ")
+       io.WriteString(w, strconv.Itoa(resp.StatusCode)+" "+text+"\r\n")
+
+       // Process Body,ContentLength,Close,Trailer
+       tw, err := newTransferWriter(resp)
+       if err != nil {
+               return err
+       }
+       err = tw.WriteHeader(w)
+       if err != nil {
+               return err
+       }
+
+       // Rest of header
+       err = writeSortedKeyValue(w, resp.Header, respExcludeHeader)
+       if err != nil {
+               return err
+       }
+
+       // End-of-header
+       io.WriteString(w, "\r\n")
+
+       // Write body and trailer
+       err = tw.WriteBody(w)
+       if err != nil {
+               return err
+       }
+
+       // Success
+       return nil
+}
+
+func writeSortedKeyValue(w io.Writer, kvm map[string]string, exclude map[string]bool) os.Error {
+       kva := make([]string, len(kvm))
+       i := 0
+       for k, v := range kvm {
+               if !exclude[k] {
+                       kva[i] = fmt.Sprint(k + ": " + v + "\r\n")
+                       i++
+               }
+       }
+       kva = kva[0:i]
+       sort.SortStrings(kva)
+       for _, l := range kva {
+               if _, err := io.WriteString(w, l); err != nil {
+                       return err
+               }
+       }
+       return nil
+}
diff --git a/libgo/go/http/response_test.go b/libgo/go/http/response_test.go
new file mode 100644 (file)
index 0000000..f21587f
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "io"
+       "reflect"
+       "testing"
+)
+
+type respTest struct {
+       Raw  string
+       Resp Response
+       Body string
+}
+
+var respTests = []respTest{
+       // Unchunked response without Content-Length.
+       {
+               "HTTP/1.0 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
+               Response{
+                       Status:        "200 OK",
+                       StatusCode:    200,
+                       Proto:         "HTTP/1.0",
+                       ProtoMajor:    1,
+                       ProtoMinor:    0,
+                       RequestMethod: "GET",
+                       Header: map[string]string{
+                               "Connection": "close", // TODO(rsc): Delete?
+                       },
+                       Close:         true,
+                       ContentLength: -1,
+               },
+
+               "Body here\n",
+       },
+
+       // Unchunked response with Content-Length.
+       {
+               "HTTP/1.0 200 OK\r\n" +
+                       "Content-Length: 10\r\n" +
+                       "Connection: close\r\n" +
+                       "\r\n" +
+                       "Body here\n",
+
+               Response{
+                       Status:        "200 OK",
+                       StatusCode:    200,
+                       Proto:         "HTTP/1.0",
+                       ProtoMajor:    1,
+                       ProtoMinor:    0,
+                       RequestMethod: "GET",
+                       Header: map[string]string{
+                               "Connection":     "close", // TODO(rsc): Delete?
+                               "Content-Length": "10",    // TODO(rsc): Delete?
+                       },
+                       Close:         true,
+                       ContentLength: 10,
+               },
+
+               "Body here\n",
+       },
+
+       // Chunked response without Content-Length.
+       {
+               "HTTP/1.0 200 OK\r\n" +
+                       "Transfer-Encoding: chunked\r\n" +
+                       "\r\n" +
+                       "0a\r\n" +
+                       "Body here\n" +
+                       "0\r\n" +
+                       "\r\n",
+
+               Response{
+                       Status:           "200 OK",
+                       StatusCode:       200,
+                       Proto:            "HTTP/1.0",
+                       ProtoMajor:       1,
+                       ProtoMinor:       0,
+                       RequestMethod:    "GET",
+                       Header:           map[string]string{},
+                       Close:            true,
+                       ContentLength:    -1,
+                       TransferEncoding: []string{"chunked"},
+               },
+
+               "Body here\n",
+       },
+
+       // Chunked response with Content-Length.
+       {
+               "HTTP/1.0 200 OK\r\n" +
+                       "Transfer-Encoding: chunked\r\n" +
+                       "Content-Length: 10\r\n" +
+                       "\r\n" +
+                       "0a\r\n" +
+                       "Body here\n" +
+                       "0\r\n" +
+                       "\r\n",
+
+               Response{
+                       Status:           "200 OK",
+                       StatusCode:       200,
+                       Proto:            "HTTP/1.0",
+                       ProtoMajor:       1,
+                       ProtoMinor:       0,
+                       RequestMethod:    "GET",
+                       Header:           map[string]string{},
+                       Close:            true,
+                       ContentLength:    -1, // TODO(rsc): Fix?
+                       TransferEncoding: []string{"chunked"},
+               },
+
+               "Body here\n",
+       },
+}
+
+func TestReadResponse(t *testing.T) {
+       for i := range respTests {
+               tt := &respTests[i]
+               var braw bytes.Buffer
+               braw.WriteString(tt.Raw)
+               resp, err := ReadResponse(bufio.NewReader(&braw), tt.Resp.RequestMethod)
+               if err != nil {
+                       t.Errorf("#%d: %s", i, err)
+                       continue
+               }
+               rbody := resp.Body
+               resp.Body = nil
+               diff(t, fmt.Sprintf("#%d Response", i), resp, &tt.Resp)
+               var bout bytes.Buffer
+               if rbody != nil {
+                       io.Copy(&bout, rbody)
+                       rbody.Close()
+               }
+               body := bout.String()
+               if body != tt.Body {
+                       t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
+               }
+       }
+}
+
+func diff(t *testing.T, prefix string, have, want interface{}) {
+       hv := reflect.NewValue(have).(*reflect.PtrValue).Elem().(*reflect.StructValue)
+       wv := reflect.NewValue(want).(*reflect.PtrValue).Elem().(*reflect.StructValue)
+       if hv.Type() != wv.Type() {
+               t.Errorf("%s: type mismatch %v vs %v", prefix, hv.Type(), wv.Type())
+       }
+       for i := 0; i < hv.NumField(); i++ {
+               hf := hv.Field(i).Interface()
+               wf := wv.Field(i).Interface()
+               if !reflect.DeepEqual(hf, wf) {
+                       t.Errorf("%s: %s = %v want %v", prefix, hv.Type().(*reflect.StructType).Field(i).Name, hf, wf)
+               }
+       }
+}
diff --git a/libgo/go/http/responsewrite_test.go b/libgo/go/http/responsewrite_test.go
new file mode 100644 (file)
index 0000000..9f10be5
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "bytes"
+       "testing"
+)
+
+type respWriteTest struct {
+       Resp Response
+       Raw  string
+}
+
+var respWriteTests = []respWriteTest{
+       // HTTP/1.0, identity coding; no trailer
+       {
+               Response{
+                       StatusCode:    503,
+                       ProtoMajor:    1,
+                       ProtoMinor:    0,
+                       RequestMethod: "GET",
+                       Header:        map[string]string{},
+                       Body:          nopCloser{bytes.NewBufferString("abcdef")},
+                       ContentLength: 6,
+               },
+
+               "HTTP/1.0 503 Service Unavailable\r\n" +
+                       "Content-Length: 6\r\n\r\n" +
+                       "abcdef",
+       },
+       // Unchunked response without Content-Length.
+       {
+               Response{
+                       StatusCode:    200,
+                       ProtoMajor:    1,
+                       ProtoMinor:    0,
+                       RequestMethod: "GET",
+                       Header:        map[string]string{},
+                       Body:          nopCloser{bytes.NewBufferString("abcdef")},
+                       ContentLength: -1,
+               },
+               "HTTP/1.0 200 OK\r\n" +
+                       "\r\n" +
+                       "abcdef",
+       },
+       // HTTP/1.1, chunked coding; empty trailer; close
+       {
+               Response{
+                       StatusCode:       200,
+                       ProtoMajor:       1,
+                       ProtoMinor:       1,
+                       RequestMethod:    "GET",
+                       Header:           map[string]string{},
+                       Body:             nopCloser{bytes.NewBufferString("abcdef")},
+                       ContentLength:    6,
+                       TransferEncoding: []string{"chunked"},
+                       Close:            true,
+               },
+
+               "HTTP/1.1 200 OK\r\n" +
+                       "Connection: close\r\n" +
+                       "Transfer-Encoding: chunked\r\n\r\n" +
+                       "6\r\nabcdef\r\n0\r\n\r\n",
+       },
+}
+
+func TestResponseWrite(t *testing.T) {
+       for i := range respWriteTests {
+               tt := &respWriteTests[i]
+               var braw bytes.Buffer
+               err := tt.Resp.Write(&braw)
+               if err != nil {
+                       t.Errorf("error writing #%d: %s", i, err)
+                       continue
+               }
+               sraw := braw.String()
+               if sraw != tt.Raw {
+                       t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, sraw)
+                       continue
+               }
+       }
+}
diff --git a/libgo/go/http/server.go b/libgo/go/http/server.go
new file mode 100644 (file)
index 0000000..68fd32b
--- /dev/null
@@ -0,0 +1,754 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// HTTP server.  See RFC 2616.
+
+// TODO(rsc):
+//     logging
+//     cgi support
+//     post support
+
+package http
+
+import (
+       "bufio"
+       "crypto/rand"
+       "crypto/tls"
+       "fmt"
+       "io"
+       "log"
+       "net"
+       "os"
+       "path"
+       "strconv"
+       "strings"
+       "time"
+)
+
+// Errors introduced by the HTTP server.
+var (
+       ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush")
+       ErrBodyNotAllowed  = os.NewError("http: response status code does not allow body")
+       ErrHijacked        = os.NewError("Conn has been hijacked")
+)
+
+// Objects implementing the Handler interface can be
+// registered to serve a particular path or subtree
+// in the HTTP server.
+//
+// ServeHTTP should write reply headers and data to the ResponseWriter
+// and then return.  Returning signals that the request is finished
+// and that the HTTP server can move on to the next request on
+// the connection.
+type Handler interface {
+       ServeHTTP(ResponseWriter, *Request)
+}
+
+// A ResponseWriter interface is used by an HTTP handler to
+// construct an HTTP response.
+type ResponseWriter interface {
+       // RemoteAddr returns the address of the client that sent the current request
+       RemoteAddr() string
+
+       // UsingTLS returns true if the client is connected using TLS
+       UsingTLS() bool
+
+       // SetHeader sets a header line in the eventual response.
+       // For example, SetHeader("Content-Type", "text/html; charset=utf-8")
+       // will result in the header line
+       //
+       //      Content-Type: text/html; charset=utf-8
+       //
+       // being sent.  UTF-8 encoded HTML is the default setting for
+       // Content-Type in this library, so users need not make that
+       // particular call.  Calls to SetHeader after WriteHeader (or Write)
+       // are ignored.
+       SetHeader(string, string)
+
+       // Write writes the data to the connection as part of an HTTP reply.
+       // If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
+       // before writing the data.
+       Write([]byte) (int, os.Error)
+
+       // WriteHeader sends an HTTP response header with status code.
+       // If WriteHeader is not called explicitly, the first call to Write
+       // will trigger an implicit WriteHeader(http.StatusOK).
+       // Thus explicit calls to WriteHeader are mainly used to
+       // send error codes.
+       WriteHeader(int)
+
+       // Flush sends any buffered data to the client.
+       Flush()
+
+       // Hijack lets the caller take over the connection.
+       // After a call to Hijack(), the HTTP server library
+       // will not do anything else with the connection.
+       // It becomes the caller's responsibility to manage
+       // and close the connection.
+       Hijack() (io.ReadWriteCloser, *bufio.ReadWriter, os.Error)
+}
+
+// A conn represents the server side of an HTTP connection.
+type conn struct {
+       remoteAddr string             // network address of remote side
+       handler    Handler            // request handler
+       rwc        io.ReadWriteCloser // i/o connection
+       buf        *bufio.ReadWriter  // buffered rwc
+       hijacked   bool               // connection has been hijacked by handler
+       usingTLS   bool               // a flag indicating connection over TLS
+}
+
+// A response represents the server side of an HTTP response.
+type response struct {
+       conn          *conn
+       req           *Request          // request for this response
+       chunking      bool              // using chunked transfer encoding for reply body
+       wroteHeader   bool              // reply header has been written
+       wroteContinue bool              // 100 Continue response was written
+       header        map[string]string // reply header parameters
+       written       int64             // number of bytes written in body
+       status        int               // status code passed to WriteHeader
+
+       // close connection after this reply.  set on request and
+       // updated after response from handler if there's a
+       // "Connection: keep-alive" response header and a
+       // Content-Length.
+       closeAfterReply bool
+}
+
+// Create new connection from rwc.
+func newConn(rwc net.Conn, handler Handler) (c *conn, err os.Error) {
+       c = new(conn)
+       c.remoteAddr = rwc.RemoteAddr().String()
+       c.handler = handler
+       c.rwc = rwc
+       _, c.usingTLS = rwc.(*tls.Conn)
+       br := bufio.NewReader(rwc)
+       bw := bufio.NewWriter(rwc)
+       c.buf = bufio.NewReadWriter(br, bw)
+       return c, nil
+}
+
+// wrapper around io.ReaderCloser which on first read, sends an
+// HTTP/1.1 100 Continue header
+type expectContinueReader struct {
+       resp       *response
+       readCloser io.ReadCloser
+}
+
+func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
+       if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked {
+               ecr.resp.wroteContinue = true
+               io.WriteString(ecr.resp.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
+               ecr.resp.conn.buf.Flush()
+       }
+       return ecr.readCloser.Read(p)
+}
+
+func (ecr *expectContinueReader) Close() os.Error {
+       return ecr.readCloser.Close()
+}
+
+// TimeFormat is the time format to use with
+// time.Parse and time.Time.Format when parsing
+// or generating times in HTTP headers.
+// It is like time.RFC1123 but hard codes GMT as the time zone.
+const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
+
+// Read next request from connection.
+func (c *conn) readRequest() (w *response, err os.Error) {
+       if c.hijacked {
+               return nil, ErrHijacked
+       }
+       var req *Request
+       if req, err = ReadRequest(c.buf.Reader); err != nil {
+               return nil, err
+       }
+
+       w = new(response)
+       w.conn = c
+       w.req = req
+       w.header = make(map[string]string)
+
+       // Expect 100 Continue support
+       if req.expectsContinue() && req.ProtoAtLeast(1, 1) {
+               // Wrap the Body reader with one that replies on the connection
+               req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
+       }
+
+       // Default output is HTML encoded in UTF-8.
+       w.SetHeader("Content-Type", "text/html; charset=utf-8")
+       w.SetHeader("Date", time.UTC().Format(TimeFormat))
+
+       if req.ProtoAtLeast(1, 1) {
+               // HTTP/1.1 or greater: use chunked transfer encoding
+               // to avoid closing the connection at EOF.
+               w.chunking = true
+               w.SetHeader("Transfer-Encoding", "chunked")
+       } else {
+               // HTTP version < 1.1: cannot do chunked transfer
+               // encoding, so signal EOF by closing connection.
+               // Will be overridden if the HTTP handler ends up
+               // writing a Content-Length and the client requested
+               // "Connection: keep-alive"
+               w.closeAfterReply = true
+       }
+
+       return w, nil
+}
+
+// UsingTLS implements the ResponseWriter.UsingTLS
+func (w *response) UsingTLS() bool {
+       return w.conn.usingTLS
+}
+
+// RemoteAddr implements the ResponseWriter.RemoteAddr method
+func (w *response) RemoteAddr() string { return w.conn.remoteAddr }
+
+// SetHeader implements the ResponseWriter.SetHeader method
+func (w *response) SetHeader(hdr, val string) { w.header[CanonicalHeaderKey(hdr)] = val }
+
+// WriteHeader implements the ResponseWriter.WriteHeader method
+func (w *response) WriteHeader(code int) {
+       if w.conn.hijacked {
+               log.Print("http: response.WriteHeader on hijacked connection")
+               return
+       }
+       if w.wroteHeader {
+               log.Print("http: multiple response.WriteHeader calls")
+               return
+       }
+       w.wroteHeader = true
+       w.status = code
+       if code == StatusNotModified {
+               // Must not have body.
+               w.header["Content-Type"] = "", false
+               w.header["Transfer-Encoding"] = "", false
+               w.chunking = false
+       }
+       if !w.req.ProtoAtLeast(1, 0) {
+               return
+       }
+       proto := "HTTP/1.0"
+       if w.req.ProtoAtLeast(1, 1) {
+               proto = "HTTP/1.1"
+       }
+       codestring := strconv.Itoa(code)
+       text, ok := statusText[code]
+       if !ok {
+               text = "status code " + codestring
+       }
+       io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n")
+       for k, v := range w.header {
+               io.WriteString(w.conn.buf, k+": "+v+"\r\n")
+       }
+       io.WriteString(w.conn.buf, "\r\n")
+}
+
+// Write implements the ResponseWriter.Write method
+func (w *response) Write(data []byte) (n int, err os.Error) {
+       if w.conn.hijacked {
+               log.Print("http: response.Write on hijacked connection")
+               return 0, ErrHijacked
+       }
+       if !w.wroteHeader {
+               if w.req.wantsHttp10KeepAlive() {
+                       _, hasLength := w.header["Content-Length"]
+                       if hasLength {
+                               _, connectionHeaderSet := w.header["Connection"]
+                               if !connectionHeaderSet {
+                                       w.header["Connection"] = "keep-alive"
+                               }
+                       }
+               }
+               w.WriteHeader(StatusOK)
+       }
+       if len(data) == 0 {
+               return 0, nil
+       }
+
+       if w.status == StatusNotModified {
+               // Must not have body.
+               return 0, ErrBodyNotAllowed
+       }
+
+       w.written += int64(len(data)) // ignoring errors, for errorKludge
+
+       // TODO(rsc): if chunking happened after the buffering,
+       // then there would be fewer chunk headers.
+       // On the other hand, it would make hijacking more difficult.
+       if w.chunking {
+               fmt.Fprintf(w.conn.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt
+       }
+       n, err = w.conn.buf.Write(data)
+       if err == nil && w.chunking {
+               if n != len(data) {
+                       err = io.ErrShortWrite
+               }
+               if err == nil {
+                       io.WriteString(w.conn.buf, "\r\n")
+               }
+       }
+
+       return n, err
+}
+
+// If this is an error reply (4xx or 5xx)
+// and the handler wrote some data explaining the error,
+// some browsers (i.e., Chrome, Internet Explorer)
+// will show their own error instead unless the error is
+// long enough.  The minimum lengths used in those
+// browsers are in the 256-512 range.
+// Pad to 1024 bytes.
+func errorKludge(w *response) {
+       const min = 1024
+
+       // Is this an error?
+       if kind := w.status / 100; kind != 4 && kind != 5 {
+               return
+       }
+
+       // Did the handler supply any info?  Enough?
+       if w.written == 0 || w.written >= min {
+               return
+       }
+
+       // Is it a broken browser?
+       var msg string
+       switch agent := w.req.UserAgent; {
+       case strings.Contains(agent, "MSIE"):
+               msg = "Internet Explorer"
+       case strings.Contains(agent, "Chrome/"):
+               msg = "Chrome"
+       default:
+               return
+       }
+       msg += " would ignore this error page if this text weren't here.\n"
+
+       // Is it text?  ("Content-Type" is always in the map)
+       baseType := strings.Split(w.header["Content-Type"], ";", 2)[0]
+       switch baseType {
+       case "text/html":
+               io.WriteString(w, "<!-- ")
+               for w.written < min {
+                       io.WriteString(w, msg)
+               }
+               io.WriteString(w, " -->")
+       case "text/plain":
+               io.WriteString(w, "\n")
+               for w.written < min {
+                       io.WriteString(w, msg)
+               }
+       }
+}
+
+func (w *response) finishRequest() {
+       // If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length
+       // back, we can make this a keep-alive response ...
+       if w.req.wantsHttp10KeepAlive() {
+               _, sentLength := w.header["Content-Length"]
+               if sentLength && w.header["Connection"] == "keep-alive" {
+                       w.closeAfterReply = false
+               }
+       }
+       if !w.wroteHeader {
+               w.WriteHeader(StatusOK)
+       }
+       errorKludge(w)
+       if w.chunking {
+               io.WriteString(w.conn.buf, "0\r\n")
+               // trailer key/value pairs, followed by blank line
+               io.WriteString(w.conn.buf, "\r\n")
+       }
+       w.conn.buf.Flush()
+}
+
+// Flush implements the ResponseWriter.Flush method.
+func (w *response) Flush() {
+       if !w.wroteHeader {
+               w.WriteHeader(StatusOK)
+       }
+       w.conn.buf.Flush()
+}
+
+// Close the connection.
+func (c *conn) close() {
+       if c.buf != nil {
+               c.buf.Flush()
+               c.buf = nil
+       }
+       if c.rwc != nil {
+               c.rwc.Close()
+               c.rwc = nil
+       }
+}
+
+// Serve a new connection.
+func (c *conn) serve() {
+       for {
+               w, err := c.readRequest()
+               if err != nil {
+                       break
+               }
+               // HTTP cannot have multiple simultaneous active requests.[*]
+               // Until the server replies to this request, it can't read another,
+               // so we might as well run the handler in this goroutine.
+               // [*] Not strictly true: HTTP pipelining.  We could let them all process
+               // in parallel even if their responses need to be serialized.
+               c.handler.ServeHTTP(w, w.req)
+               if c.hijacked {
+                       return
+               }
+               w.finishRequest()
+               if w.closeAfterReply {
+                       break
+               }
+       }
+       c.close()
+}
+
+// Hijack impements the ResponseWriter.Hijack method.
+func (w *response) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.Error) {
+       if w.conn.hijacked {
+               return nil, nil, ErrHijacked
+       }
+       w.conn.hijacked = true
+       rwc = w.conn.rwc
+       buf = w.conn.buf
+       w.conn.rwc = nil
+       w.conn.buf = nil
+       return
+}
+
+// The HandlerFunc type is an adapter to allow the use of
+// ordinary functions as HTTP handlers.  If f is a function
+// with the appropriate signature, HandlerFunc(f) is a
+// Handler object that calls f.
+type HandlerFunc func(ResponseWriter, *Request)
+
+// ServeHTTP calls f(w, req).
+func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
+       f(w, r)
+}
+
+// Helper handlers
+
+// Error replies to the request with the specified error message and HTTP code.
+func Error(w ResponseWriter, error string, code int) {
+       w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+       w.WriteHeader(code)
+       fmt.Fprintln(w, error)
+}
+
+// NotFound replies to the request with an HTTP 404 not found error.
+func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) }
+
+// NotFoundHandler returns a simple request handler
+// that replies to each request with a ``404 page not found'' reply.
+func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
+
+// Redirect replies to the request with a redirect to url,
+// which may be a path relative to the request path.
+func Redirect(w ResponseWriter, r *Request, url string, code int) {
+       // RFC2616 recommends that a short note "SHOULD" be included in the
+       // response because older user agents may not understand 301/307.
+       note := "<a href=\"%v\">" + statusText[code] + "</a>.\n"
+       if r.Method == "POST" {
+               note = ""
+       }
+
+       u, err := ParseURL(url)
+       if err != nil {
+               goto finish
+       }
+
+       // If url was relative, make absolute by
+       // combining with request path.
+       // The browser would probably do this for us,
+       // but doing it ourselves is more reliable.
+
+       // NOTE(rsc): RFC 2616 says that the Location
+       // line must be an absolute URI, like
+       // "http://www.google.com/redirect/",
+       // not a path like "/redirect/".
+       // Unfortunately, we don't know what to
+       // put in the host name section to get the
+       // client to connect to us again, so we can't
+       // know the right absolute URI to send back.
+       // Because of this problem, no one pays attention
+       // to the RFC; they all send back just a new path.
+       // So do we.
+       oldpath := r.URL.Path
+       if oldpath == "" { // should not happen, but avoid a crash if it does
+               oldpath = "/"
+       }
+       if u.Scheme == "" {
+               // no leading http://server
+               if url == "" || url[0] != '/' {
+                       // make relative path absolute
+                       olddir, _ := path.Split(oldpath)
+                       url = olddir + url
+               }
+
+               // clean up but preserve trailing slash
+               trailing := url[len(url)-1] == '/'
+               url = path.Clean(url)
+               if trailing && url[len(url)-1] != '/' {
+                       url += "/"
+               }
+       }
+
+finish:
+       w.SetHeader("Location", url)
+       w.WriteHeader(code)
+       fmt.Fprintf(w, note, url)
+}
+
+// Redirect to a fixed URL
+type redirectHandler struct {
+       url  string
+       code int
+}
+
+func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) {
+       Redirect(w, r, rh.url, rh.code)
+}
+
+// RedirectHandler returns a request handler that redirects
+// each request it receives to the given url using the given
+// status code.
+func RedirectHandler(url string, code int) Handler {
+       return &redirectHandler{url, code}
+}
+
+// ServeMux is an HTTP request multiplexer.
+// It matches the URL of each incoming request against a list of registered
+// patterns and calls the handler for the pattern that
+// most closely matches the URL.
+//
+// Patterns named fixed paths, like "/favicon.ico",
+// or subtrees, like "/images/" (note the trailing slash).
+// Patterns must begin with /.
+// Longer patterns take precedence over shorter ones, so that
+// if there are handlers registered for both "/images/"
+// and "/images/thumbnails/", the latter handler will be
+// called for paths beginning "/images/thumbnails/" and the
+// former will receiver requests for any other paths in the
+// "/images/" subtree.
+//
+// In the future, the pattern syntax may be relaxed to allow
+// an optional host-name at the beginning of the pattern,
+// so that a handler might register for the two patterns
+// "/codesearch" and "codesearch.google.com/"
+// without taking over requests for http://www.google.com/.
+//
+// ServeMux also takes care of sanitizing the URL request path,
+// redirecting any request containing . or .. elements to an
+// equivalent .- and ..-free URL.
+type ServeMux struct {
+       m map[string]Handler
+}
+
+// NewServeMux allocates and returns a new ServeMux.
+func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} }
+
+// DefaultServeMux is the default ServeMux used by Serve.
+var DefaultServeMux = NewServeMux()
+
+// Does path match pattern?
+func pathMatch(pattern, path string) bool {
+       if len(pattern) == 0 {
+               // should not happen
+               return false
+       }
+       n := len(pattern)
+       if pattern[n-1] != '/' {
+               return pattern == path
+       }
+       return len(path) >= n && path[0:n] == pattern
+}
+
+// Return the canonical path for p, eliminating . and .. elements.
+func cleanPath(p string) string {
+       if p == "" {
+               return "/"
+       }
+       if p[0] != '/' {
+               p = "/" + p
+       }
+       np := path.Clean(p)
+       // path.Clean removes trailing slash except for root;
+       // put the trailing slash back if necessary.
+       if p[len(p)-1] == '/' && np != "/" {
+               np += "/"
+       }
+       return np
+}
+
+// ServeHTTP dispatches the request to the handler whose
+// pattern most closely matches the request URL.
+func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
+       // Clean path to canonical form and redirect.
+       if p := cleanPath(r.URL.Path); p != r.URL.Path {
+               w.SetHeader("Location", p)
+               w.WriteHeader(StatusMovedPermanently)
+               return
+       }
+
+       // Most-specific (longest) pattern wins.
+       var h Handler
+       var n = 0
+       for k, v := range mux.m {
+               if !pathMatch(k, r.URL.Path) {
+                       continue
+               }
+               if h == nil || len(k) > n {
+                       n = len(k)
+                       h = v
+               }
+       }
+       if h == nil {
+               h = NotFoundHandler()
+       }
+       h.ServeHTTP(w, r)
+}
+
+// Handle registers the handler for the given pattern.
+func (mux *ServeMux) Handle(pattern string, handler Handler) {
+       if pattern == "" || pattern[0] != '/' {
+               panic("http: invalid pattern " + pattern)
+       }
+
+       mux.m[pattern] = handler
+
+       // Helpful behavior:
+       // If pattern is /tree/, insert permanent redirect for /tree.
+       n := len(pattern)
+       if n > 0 && pattern[n-1] == '/' {
+               mux.m[pattern[0:n-1]] = RedirectHandler(pattern, StatusMovedPermanently)
+       }
+}
+
+// HandleFunc registers the handler function for the given pattern.
+func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
+       mux.Handle(pattern, HandlerFunc(handler))
+}
+
+// Handle registers the handler for the given pattern
+// in the DefaultServeMux.
+func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
+
+// HandleFunc registers the handler function for the given pattern
+// in the DefaultServeMux.
+func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
+       DefaultServeMux.HandleFunc(pattern, handler)
+}
+
+// Serve accepts incoming HTTP connections on the listener l,
+// creating a new service thread for each.  The service threads
+// read requests and then call handler to reply to them.
+// Handler is typically nil, in which case the DefaultServeMux is used.
+func Serve(l net.Listener, handler Handler) os.Error {
+       if handler == nil {
+               handler = DefaultServeMux
+       }
+       for {
+               rw, e := l.Accept()
+               if e != nil {
+                       return e
+               }
+               c, err := newConn(rw, handler)
+               if err != nil {
+                       continue
+               }
+               go c.serve()
+       }
+       panic("not reached")
+}
+
+// ListenAndServe listens on the TCP network address addr
+// and then calls Serve with handler to handle requests
+// on incoming connections.  Handler is typically nil,
+// in which case the DefaultServeMux is used.
+//
+// A trivial example server is:
+//
+//     package main
+//
+//     import (
+//             "http"
+//             "io"
+//             "log"
+//     )
+//
+//     // hello world, the web server
+//     func HelloServer(w http.ResponseWriter, req *http.Request) {
+//             io.WriteString(w, "hello, world!\n")
+//     }
+//
+//     func main() {
+//             http.HandleFunc("/hello", HelloServer)
+//             err := http.ListenAndServe(":12345", nil)
+//             if err != nil {
+//                     log.Exit("ListenAndServe: ", err.String())
+//             }
+//     }
+func ListenAndServe(addr string, handler Handler) os.Error {
+       l, e := net.Listen("tcp", addr)
+       if e != nil {
+               return e
+       }
+       e = Serve(l, handler)
+       l.Close()
+       return e
+}
+
+// ListenAndServeTLS acts identically to ListenAndServe, except that it
+// expects HTTPS connections. Additionally, files containing a certificate and
+// matching private key for the server must be provided.
+//
+// A trivial example server is:
+//
+//     import (
+//             "http"
+//             "log"
+//     )
+//
+//     func handler(w http.ResponseWriter, req *http.Request) {
+//             w.SetHeader("Content-Type", "text/plain")
+//             w.Write([]byte("This is an example server.\n"))
+//     }
+//
+//     func main() {
+//             http.HandleFunc("/", handler)
+//             log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/")
+//             err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil)
+//             if err != nil {
+//                     log.Exit(err)
+//             }
+//     }
+//
+// One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.
+func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) os.Error {
+       config := &tls.Config{
+               Rand:       rand.Reader,
+               Time:       time.Seconds,
+               NextProtos: []string{"http/1.1"},
+       }
+
+       var err os.Error
+       config.Certificates = make([]tls.Certificate, 1)
+       config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+       if err != nil {
+               return err
+       }
+
+       conn, err := net.Listen("tcp", addr)
+       if err != nil {
+               return err
+       }
+
+       tlsListener := tls.NewListener(conn, config)
+       return Serve(tlsListener, handler)
+}
diff --git a/libgo/go/http/status.go b/libgo/go/http/status.go
new file mode 100644 (file)
index 0000000..b6e2d65
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+// HTTP status codes, defined in RFC 2616.
+const (
+       StatusContinue           = 100
+       StatusSwitchingProtocols = 101
+
+       StatusOK                   = 200
+       StatusCreated              = 201
+       StatusAccepted             = 202
+       StatusNonAuthoritativeInfo = 203
+       StatusNoContent            = 204
+       StatusResetContent         = 205
+       StatusPartialContent       = 206
+
+       StatusMultipleChoices   = 300
+       StatusMovedPermanently  = 301
+       StatusFound             = 302
+       StatusSeeOther          = 303
+       StatusNotModified       = 304
+       StatusUseProxy          = 305
+       StatusTemporaryRedirect = 307
+
+       StatusBadRequest                   = 400
+       StatusUnauthorized                 = 401
+       StatusPaymentRequired              = 402
+       StatusForbidden                    = 403
+       StatusNotFound                     = 404
+       StatusMethodNotAllowed             = 405
+       StatusNotAcceptable                = 406
+       StatusProxyAuthRequired            = 407
+       StatusRequestTimeout               = 408
+       StatusConflict                     = 409
+       StatusGone                         = 410
+       StatusLengthRequired               = 411
+       StatusPreconditionFailed           = 412
+       StatusRequestEntityTooLarge        = 413
+       StatusRequestURITooLong            = 414
+       StatusUnsupportedMediaType         = 415
+       StatusRequestedRangeNotSatisfiable = 416
+       StatusExpectationFailed            = 417
+
+       StatusInternalServerError     = 500
+       StatusNotImplemented          = 501
+       StatusBadGateway              = 502
+       StatusServiceUnavailable      = 503
+       StatusGatewayTimeout          = 504
+       StatusHTTPVersionNotSupported = 505
+)
+
+var statusText = map[int]string{
+       StatusContinue:           "Continue",
+       StatusSwitchingProtocols: "Switching Protocols",
+
+       StatusOK:                   "OK",
+       StatusCreated:              "Created",
+       StatusAccepted:             "Accepted",
+       StatusNonAuthoritativeInfo: "Non-Authoritative Information",
+       StatusNoContent:            "No Content",
+       StatusResetContent:         "Reset Content",
+       StatusPartialContent:       "Partial Content",
+
+       StatusMultipleChoices:   "Multiple Choices",
+       StatusMovedPermanently:  "Moved Permanently",
+       StatusFound:             "Found",
+       StatusSeeOther:          "See Other",
+       StatusNotModified:       "Not Modified",
+       StatusUseProxy:          "Use Proxy",
+       StatusTemporaryRedirect: "Temporary Redirect",
+
+       StatusBadRequest:                   "Bad Request",
+       StatusUnauthorized:                 "Unauthorized",
+       StatusPaymentRequired:              "Payment Required",
+       StatusForbidden:                    "Forbidden",
+       StatusNotFound:                     "Not Found",
+       StatusMethodNotAllowed:             "Method Not Allowed",
+       StatusNotAcceptable:                "Not Acceptable",
+       StatusProxyAuthRequired:            "Proxy Authentication Required",
+       StatusRequestTimeout:               "Request Timeout",
+       StatusConflict:                     "Conflict",
+       StatusGone:                         "Gone",
+       StatusLengthRequired:               "Length Required",
+       StatusPreconditionFailed:           "Precondition Failed",
+       StatusRequestEntityTooLarge:        "Request Entity Too Large",
+       StatusRequestURITooLong:            "Request URI Too Long",
+       StatusUnsupportedMediaType:         "Unsupported Media Type",
+       StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
+       StatusExpectationFailed:            "Expectation Failed",
+
+       StatusInternalServerError:     "Internal Server Error",
+       StatusNotImplemented:          "Not Implemented",
+       StatusBadGateway:              "Bad Gateway",
+       StatusServiceUnavailable:      "Service Unavailable",
+       StatusGatewayTimeout:          "Gateway Timeout",
+       StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
+}
+
+// StatusText returns a text for the HTTP status code. It returns the empty
+// string if the code is unknown.
+func StatusText(code int) string {
+       return statusText[code]
+}
diff --git a/libgo/go/http/transfer.go b/libgo/go/http/transfer.go
new file mode 100644 (file)
index 0000000..75030e8
--- /dev/null
@@ -0,0 +1,441 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "bufio"
+       "io"
+       "os"
+       "strconv"
+       "strings"
+)
+
+// transferWriter inspects the fields of a user-supplied Request or Response,
+// sanitizes them without changing the user object and provides methods for
+// writing the respective header, body and trailer in wire format.
+type transferWriter struct {
+       Body             io.ReadCloser
+       ResponseToHEAD   bool
+       ContentLength    int64
+       Close            bool
+       TransferEncoding []string
+       Trailer          map[string]string
+}
+
+func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
+       t = &transferWriter{}
+
+       // Extract relevant fields
+       atLeastHTTP11 := false
+       switch rr := r.(type) {
+       case *Request:
+               t.Body = rr.Body
+               t.ContentLength = rr.ContentLength
+               t.Close = rr.Close
+               t.TransferEncoding = rr.TransferEncoding
+               t.Trailer = rr.Trailer
+               atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
+       case *Response:
+               t.Body = rr.Body
+               t.ContentLength = rr.ContentLength
+               t.Close = rr.Close
+               t.TransferEncoding = rr.TransferEncoding
+               t.Trailer = rr.Trailer
+               atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
+               t.ResponseToHEAD = noBodyExpected(rr.RequestMethod)
+       }
+
+       // Sanitize Body,ContentLength,TransferEncoding
+       if t.ResponseToHEAD {
+               t.Body = nil
+               t.TransferEncoding = nil
+               // ContentLength is expected to hold Content-Length
+               if t.ContentLength < 0 {
+                       return nil, ErrMissingContentLength
+               }
+       } else {
+               if !atLeastHTTP11 || t.Body == nil {
+                       t.TransferEncoding = nil
+               }
+               if chunked(t.TransferEncoding) {
+                       t.ContentLength = -1
+               } else if t.Body == nil { // no chunking, no body
+                       t.ContentLength = 0
+               }
+       }
+
+       // Sanitize Trailer
+       if !chunked(t.TransferEncoding) {
+               t.Trailer = nil
+       }
+
+       return t, nil
+}
+
+func noBodyExpected(requestMethod string) bool {
+       return requestMethod == "HEAD"
+}
+
+func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
+       if t.Close {
+               _, err = io.WriteString(w, "Connection: close\r\n")
+               if err != nil {
+                       return
+               }
+       }
+
+       // Write Content-Length and/or Transfer-Encoding whose values are a
+       // function of the sanitized field triple (Body, ContentLength,
+       // TransferEncoding)
+       if chunked(t.TransferEncoding) {
+               _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
+               if err != nil {
+                       return
+               }
+       } else if t.ContentLength > 0 || t.ResponseToHEAD {
+               io.WriteString(w, "Content-Length: ")
+               _, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
+               if err != nil {
+                       return
+               }
+       }
+
+       // Write Trailer header
+       if t.Trailer != nil {
+               // TODO: At some point, there should be a generic mechanism for
+               // writing long headers, using HTTP line splitting
+               io.WriteString(w, "Trailer: ")
+               needComma := false
+               for k, _ := range t.Trailer {
+                       k = CanonicalHeaderKey(k)
+                       switch k {
+                       case "Transfer-Encoding", "Trailer", "Content-Length":
+                               return &badStringError{"invalid Trailer key", k}
+                       }
+                       if needComma {
+                               io.WriteString(w, ",")
+                       }
+                       io.WriteString(w, k)
+                       needComma = true
+               }
+               _, err = io.WriteString(w, "\r\n")
+       }
+
+       return
+}
+
+func (t *transferWriter) WriteBody(w io.Writer) (err os.Error) {
+       // Write body
+       if t.Body != nil {
+               if chunked(t.TransferEncoding) {
+                       cw := NewChunkedWriter(w)
+                       _, err = io.Copy(cw, t.Body)
+                       if err == nil {
+                               err = cw.Close()
+                       }
+               } else if t.ContentLength == -1 {
+                       _, err = io.Copy(w, t.Body)
+               } else {
+                       _, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength))
+               }
+               if err != nil {
+                       return err
+               }
+               if err = t.Body.Close(); err != nil {
+                       return err
+               }
+       }
+
+       // TODO(petar): Place trailer writer code here.
+       if chunked(t.TransferEncoding) {
+               // Last chunk, empty trailer
+               _, err = io.WriteString(w, "\r\n")
+       }
+
+       return
+}
+
+type transferReader struct {
+       // Input
+       Header        map[string]string
+       StatusCode    int
+       RequestMethod string
+       ProtoMajor    int
+       ProtoMinor    int
+       // Output
+       Body             io.ReadCloser
+       ContentLength    int64
+       TransferEncoding []string
+       Close            bool
+       Trailer          map[string]string
+}
+
+// msg is *Request or *Response.
+func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
+       t := &transferReader{}
+
+       // Unify input
+       switch rr := msg.(type) {
+       case *Response:
+               t.Header = rr.Header
+               t.StatusCode = rr.StatusCode
+               t.RequestMethod = rr.RequestMethod
+               t.ProtoMajor = rr.ProtoMajor
+               t.ProtoMinor = rr.ProtoMinor
+               t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
+       case *Request:
+               t.Header = rr.Header
+               t.ProtoMajor = rr.ProtoMajor
+               t.ProtoMinor = rr.ProtoMinor
+               // Transfer semantics for Requests are exactly like those for
+               // Responses with status code 200, responding to a GET method
+               t.StatusCode = 200
+               t.RequestMethod = "GET"
+       }
+
+       // Default to HTTP/1.1
+       if t.ProtoMajor == 0 && t.ProtoMinor == 0 {
+               t.ProtoMajor, t.ProtoMinor = 1, 1
+       }
+
+       // Transfer encoding, content length
+       t.TransferEncoding, err = fixTransferEncoding(t.Header)
+       if err != nil {
+               return err
+       }
+
+       t.ContentLength, err = fixLength(t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
+       if err != nil {
+               return err
+       }
+
+       // Trailer
+       t.Trailer, err = fixTrailer(t.Header, t.TransferEncoding)
+       if err != nil {
+               return err
+       }
+
+       // Prepare body reader.  ContentLength < 0 means chunked encoding
+       // or close connection when finished, since multipart is not supported yet
+       switch {
+       case chunked(t.TransferEncoding):
+               t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
+       case t.ContentLength >= 0:
+               // TODO: limit the Content-Length. This is an easy DoS vector.
+               t.Body = &body{Reader: io.LimitReader(r, t.ContentLength), closing: t.Close}
+       default:
+               // t.ContentLength < 0, i.e. "Content-Length" not mentioned in header
+               if t.Close {
+                       // Close semantics (i.e. HTTP/1.0)
+                       t.Body = &body{Reader: r, closing: t.Close}
+               } else {
+                       // Persistent connection (i.e. HTTP/1.1)
+                       t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close}
+               }
+               // TODO(petar): It may be a good idea, for extra robustness, to
+               // assume ContentLength=0 for GET requests (and other special
+               // cases?). This logic should be in fixLength().
+       }
+
+       // Unify output
+       switch rr := msg.(type) {
+       case *Request:
+               rr.Body = t.Body
+               rr.ContentLength = t.ContentLength
+               rr.TransferEncoding = t.TransferEncoding
+               rr.Close = t.Close
+               rr.Trailer = t.Trailer
+       case *Response:
+               rr.Body = t.Body
+               rr.ContentLength = t.ContentLength
+               rr.TransferEncoding = t.TransferEncoding
+               rr.Close = t.Close
+               rr.Trailer = t.Trailer
+       }
+
+       return nil
+}
+
+// Checks whether chunked is part of the encodings stack
+func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
+
+// Sanitize transfer encoding
+func fixTransferEncoding(header map[string]string) ([]string, os.Error) {
+       raw, present := header["Transfer-Encoding"]
+       if !present {
+               return nil, nil
+       }
+
+       header["Transfer-Encoding"] = "", false
+       encodings := strings.Split(raw, ",", -1)
+       te := make([]string, 0, len(encodings))
+       // TODO: Even though we only support "identity" and "chunked"
+       // encodings, the loop below is designed with foresight. One
+       // invariant that must be maintained is that, if present,
+       // chunked encoding must always come first.
+       for _, encoding := range encodings {
+               encoding = strings.ToLower(strings.TrimSpace(encoding))
+               // "identity" encoding is not recored
+               if encoding == "identity" {
+                       break
+               }
+               if encoding != "chunked" {
+                       return nil, &badStringError{"unsupported transfer encoding", encoding}
+               }
+               te = te[0 : len(te)+1]
+               te[len(te)-1] = encoding
+       }
+       if len(te) > 1 {
+               return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")}
+       }
+       if len(te) > 0 {
+               // Chunked encoding trumps Content-Length. See RFC 2616
+               // Section 4.4. Currently len(te) > 0 implies chunked
+               // encoding.
+               header["Content-Length"] = "", false
+               return te, nil
+       }
+
+       return nil, nil
+}
+
+// Determine the expected body length, using RFC 2616 Section 4.4. This
+// function is not a method, because ultimately it should be shared by
+// ReadResponse and ReadRequest.
+func fixLength(status int, requestMethod string, header map[string]string, te []string) (int64, os.Error) {
+
+       // Logic based on response type or status
+       if noBodyExpected(requestMethod) {
+               return 0, nil
+       }
+       if status/100 == 1 {
+               return 0, nil
+       }
+       switch status {
+       case 204, 304:
+               return 0, nil
+       }
+
+       // Logic based on Transfer-Encoding
+       if chunked(te) {
+               return -1, nil
+       }
+
+       // Logic based on Content-Length
+       if cl, present := header["Content-Length"]; present {
+               cl = strings.TrimSpace(cl)
+               if cl != "" {
+                       n, err := strconv.Atoi64(cl)
+                       if err != nil || n < 0 {
+                               return -1, &badStringError{"bad Content-Length", cl}
+                       }
+                       return n, nil
+               } else {
+                       header["Content-Length"] = "", false
+               }
+       }
+
+       // Logic based on media type. The purpose of the following code is just
+       // to detect whether the unsupported "multipart/byteranges" is being
+       // used. A proper Content-Type parser is needed in the future.
+       if strings.Contains(strings.ToLower(header["Content-Type"]), "multipart/byteranges") {
+               return -1, ErrNotSupported
+       }
+
+       // Body-EOF logic based on other methods (like closing, or chunked coding)
+       return -1, nil
+}
+
+// Determine whether to hang up after sending a request and body, or
+// receiving a response and body
+// 'header' is the request headers
+func shouldClose(major, minor int, header map[string]string) bool {
+       if major < 1 {
+               return true
+       } else if major == 1 && minor == 0 {
+               v, present := header["Connection"]
+               if !present {
+                       return true
+               }
+               v = strings.ToLower(v)
+               if !strings.Contains(v, "keep-alive") {
+                       return true
+               }
+               return false
+       } else if v, present := header["Connection"]; present {
+               // TODO: Should split on commas, toss surrounding white space,
+               // and check each field.
+               if v == "close" {
+                       header["Connection"] = "", false
+                       return true
+               }
+       }
+       return false
+}
+
+// Parse the trailer header
+func fixTrailer(header map[string]string, te []string) (map[string]string, os.Error) {
+       raw, present := header["Trailer"]
+       if !present {
+               return nil, nil
+       }
+
+       header["Trailer"] = "", false
+       trailer := make(map[string]string)
+       keys := strings.Split(raw, ",", -1)
+       for _, key := range keys {
+               key = CanonicalHeaderKey(strings.TrimSpace(key))
+               switch key {
+               case "Transfer-Encoding", "Trailer", "Content-Length":
+                       return nil, &badStringError{"bad trailer key", key}
+               }
+               trailer[key] = ""
+       }
+       if len(trailer) == 0 {
+               return nil, nil
+       }
+       if !chunked(te) {
+               // Trailer and no chunking
+               return nil, ErrUnexpectedTrailer
+       }
+       return trailer, nil
+}
+
+// body turns a Reader into a ReadCloser.
+// Close ensures that the body has been fully read
+// and then reads the trailer if necessary.
+type body struct {
+       io.Reader
+       hdr     interface{}   // non-nil (Response or Request) value means read trailer
+       r       *bufio.Reader // underlying wire-format reader for the trailer
+       closing bool          // is the connection to be closed after reading body?
+}
+
+func (b *body) Close() os.Error {
+       if b.hdr == nil && b.closing {
+               // no trailer and closing the connection next.
+               // no point in reading to EOF.
+               return nil
+       }
+
+       trashBuf := make([]byte, 1024) // local for thread safety
+       for {
+               _, err := b.Read(trashBuf)
+               if err == nil {
+                       continue
+               }
+               if err == os.EOF {
+                       break
+               }
+               return err
+       }
+       if b.hdr == nil { // not reading trailer
+               return nil
+       }
+
+       // TODO(petar): Put trailer reader code here
+
+       return nil
+}
diff --git a/libgo/go/http/url.go b/libgo/go/http/url.go
new file mode 100644 (file)
index 0000000..b878c00
--- /dev/null
@@ -0,0 +1,517 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse URLs (actually URIs, but that seems overly pedantic).
+// RFC 3986
+
+package http
+
+import (
+       "os"
+       "strconv"
+       "strings"
+)
+
+// URLError reports an error and the operation and URL that caused it.
+type URLError struct {
+       Op    string
+       URL   string
+       Error os.Error
+}
+
+func (e *URLError) String() string { return e.Op + " " + e.URL + ": " + e.Error.String() }
+
+func ishex(c byte) bool {
+       switch {
+       case '0' <= c && c <= '9':
+               return true
+       case 'a' <= c && c <= 'f':
+               return true
+       case 'A' <= c && c <= 'F':
+               return true
+       }
+       return false
+}
+
+func unhex(c byte) byte {
+       switch {
+       case '0' <= c && c <= '9':
+               return c - '0'
+       case 'a' <= c && c <= 'f':
+               return c - 'a' + 10
+       case 'A' <= c && c <= 'F':
+               return c - 'A' + 10
+       }
+       return 0
+}
+
+type encoding int
+
+const (
+       encodePath encoding = 1 + iota
+       encodeUserPassword
+       encodeQueryComponent
+       encodeFragment
+       encodeOpaque
+)
+
+
+type URLEscapeError string
+
+func (e URLEscapeError) String() string {
+       return "invalid URL escape " + strconv.Quote(string(e))
+}
+
+// Return true if the specified character should be escaped when
+// appearing in a URL string, according to RFC 2396.
+// When 'all' is true the full range of reserved characters are matched.
+func shouldEscape(c byte, mode encoding) bool {
+       // RFC 2396 §2.3 Unreserved characters (alphanum)
+       if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
+               return false
+       }
+       switch c {
+       case '-', '_', '.', '!', '~', '*', '\'', '(', ')': // §2.3 Unreserved characters (mark)
+               return false
+
+       case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
+               // Different sections of the URL allow a few of
+               // the reserved characters to appear unescaped.
+               switch mode {
+               case encodePath: // §3.3
+                       // The RFC allows : @ & = + $ , but saves / ; for assigning
+                       // meaning to individual path segments.  This package
+                       // only manipulates the path as a whole, so we allow those
+                       // last two as well.  Clients that need to distinguish between
+                       // `/foo;y=z/bar` and `/foo%3by=z/bar` will have to re-decode RawPath.
+                       // That leaves only ? to escape.
+                       return c == '?'
+
+               case encodeUserPassword: // §3.2.2
+                       // The RFC allows ; : & = + $ , in userinfo, so we must escape only @ and /.
+                       // The parsing of userinfo treats : as special so we must escape that too.
+                       return c == '@' || c == '/' || c == ':'
+
+               case encodeQueryComponent: // §3.4
+                       // The RFC reserves (so we must escape) everything.
+                       return true
+
+               case encodeFragment: // §4.1
+                       // The RFC text is silent but the grammar allows
+                       // everything, so escape nothing.
+                       return false
+
+               case encodeOpaque: // §3 opaque_part
+                       // The RFC allows opaque_part to use all characters
+                       // except that the leading / must be escaped.
+                       // (We implement that case in String.)
+                       return false
+               }
+       }
+
+       // Everything else must be escaped.
+       return true
+}
+
+// CanonicalPath applies the algorithm specified in RFC 2396 to
+// simplify the path, removing unnecessary  . and .. elements.
+func CanonicalPath(path string) string {
+       buf := []byte(path)
+       a := buf[0:0]
+       // state helps to find /.. ^.. ^. and /. patterns.
+       // state == 1 - prev char is '/' or beginning of the string.
+       // state > 1  - prev state > 0 and prev char was '.'
+       // state == 0 - otherwise
+       state := 1
+       cnt := 0
+       for _, v := range buf {
+               switch v {
+               case '/':
+                       s := state
+                       state = 1
+                       switch s {
+                       case 2:
+                               a = a[0 : len(a)-1]
+                               continue
+                       case 3:
+                               if cnt > 0 {
+                                       i := len(a) - 4
+                                       for ; i >= 0 && a[i] != '/'; i-- {
+                                       }
+                                       a = a[0 : i+1]
+                                       cnt--
+                                       continue
+                               }
+                       default:
+                               if len(a) > 0 {
+                                       cnt++
+                               }
+                       }
+               case '.':
+                       if state > 0 {
+                               state++
+                       }
+               default:
+                       state = 0
+               }
+               l := len(a)
+               a = a[0 : l+1]
+               a[l] = v
+       }
+       switch {
+       case state == 2:
+               a = a[0 : len(a)-1]
+       case state == 3 && cnt > 0:
+               i := len(a) - 4
+               for ; i >= 0 && a[i] != '/'; i-- {
+               }
+               a = a[0 : i+1]
+       }
+       return string(a)
+}
+
+// URLUnescape unescapes a string in ``URL encoded'' form,
+// converting %AB into the byte 0xAB and '+' into ' ' (space).
+// It returns an error if any % is not followed
+// by two hexadecimal digits.
+// Despite the name, this encoding applies only to individual
+// components of the query portion of the URL.
+func URLUnescape(s string) (string, os.Error) {
+       return urlUnescape(s, encodeQueryComponent)
+}
+
+// urlUnescape is like URLUnescape but mode specifies
+// which section of the URL is being unescaped.
+func urlUnescape(s string, mode encoding) (string, os.Error) {
+       // Count %, check that they're well-formed.
+       n := 0
+       hasPlus := false
+       for i := 0; i < len(s); {
+               switch s[i] {
+               case '%':
+                       n++
+                       if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
+                               s = s[i:]
+                               if len(s) > 3 {
+                                       s = s[0:3]
+                               }
+                               return "", URLEscapeError(s)
+                       }
+                       i += 3
+               case '+':
+                       hasPlus = mode == encodeQueryComponent
+                       i++
+               default:
+                       i++
+               }
+       }
+
+       if n == 0 && !hasPlus {
+               return s, nil
+       }
+
+       t := make([]byte, len(s)-2*n)
+       j := 0
+       for i := 0; i < len(s); {
+               switch s[i] {
+               case '%':
+                       t[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
+                       j++
+                       i += 3
+               case '+':
+                       if mode == encodeQueryComponent {
+                               t[j] = ' '
+                       } else {
+                               t[j] = '+'
+                       }
+                       j++
+                       i++
+               default:
+                       t[j] = s[i]
+                       j++
+                       i++
+               }
+       }
+       return string(t), nil
+}
+
+// URLEscape converts a string into ``URL encoded'' form.
+// Despite the name, this encoding applies only to individual
+// components of the query portion of the URL.
+func URLEscape(s string) string {
+       return urlEscape(s, encodeQueryComponent)
+}
+
+func urlEscape(s string, mode encoding) string {
+       spaceCount, hexCount := 0, 0
+       for i := 0; i < len(s); i++ {
+               c := s[i]
+               if shouldEscape(c, mode) {
+                       if c == ' ' && mode == encodeQueryComponent {
+                               spaceCount++
+                       } else {
+                               hexCount++
+                       }
+               }
+       }
+
+       if spaceCount == 0 && hexCount == 0 {
+               return s
+       }
+
+       t := make([]byte, len(s)+2*hexCount)
+       j := 0
+       for i := 0; i < len(s); i++ {
+               switch c := s[i]; {
+               case c == ' ' && mode == encodeQueryComponent:
+                       t[j] = '+'
+                       j++
+               case shouldEscape(c, mode):
+                       t[j] = '%'
+                       t[j+1] = "0123456789abcdef"[c>>4]
+                       t[j+2] = "0123456789abcdef"[c&15]
+                       j += 3
+               default:
+                       t[j] = s[i]
+                       j++
+               }
+       }
+       return string(t)
+}
+
+// UnescapeUserinfo parses the RawUserinfo field of a URL
+// as the form user or user:password and unescapes and returns
+// the two halves.
+//
+// This functionality should only be used with legacy web sites.
+// RFC 2396 warns that interpreting Userinfo this way
+// ``is NOT RECOMMENDED, because the passing of authentication
+// information in clear text (such as URI) has proven to be a
+// security risk in almost every case where it has been used.''
+func UnescapeUserinfo(rawUserinfo string) (user, password string, err os.Error) {
+       u, p := split(rawUserinfo, ':', true)
+       if user, err = urlUnescape(u, encodeUserPassword); err != nil {
+               return "", "", err
+       }
+       if password, err = urlUnescape(p, encodeUserPassword); err != nil {
+               return "", "", err
+       }
+       return
+}
+
+// EscapeUserinfo combines user and password in the form
+// user:password (or just user if password is empty) and then
+// escapes it for use as the URL.RawUserinfo field.
+//
+// This functionality should only be used with legacy web sites.
+// RFC 2396 warns that interpreting Userinfo this way
+// ``is NOT RECOMMENDED, because the passing of authentication
+// information in clear text (such as URI) has proven to be a
+// security risk in almost every case where it has been used.''
+func EscapeUserinfo(user, password string) string {
+       raw := urlEscape(user, encodeUserPassword)
+       if password != "" {
+               raw += ":" + urlEscape(password, encodeUserPassword)
+       }
+       return raw
+}
+
+// A URL represents a parsed URL (technically, a URI reference).
+// The general form represented is:
+//     scheme://[userinfo@]host/path[?query][#fragment]
+// The Raw, RawAuthority, RawPath, and RawQuery fields are in "wire format"
+// (special characters must be hex-escaped if not meant to have special meaning).
+// All other fields are logical values; '+' or '%' represent themselves.
+//
+// The various Raw values are supplied in wire format because
+// clients typically have to split them into pieces before further
+// decoding.
+type URL struct {
+       Raw          string // the original string
+       Scheme       string // scheme
+       RawAuthority string // [userinfo@]host
+       RawUserinfo  string // userinfo
+       Host         string // host
+       RawPath      string // /path[?query][#fragment]
+       Path         string // /path
+       OpaquePath   bool   // path is opaque (unrooted when scheme is present)
+       RawQuery     string // query
+       Fragment     string // fragment
+}
+
+// Maybe rawurl is of the form scheme:path.
+// (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
+// If so, return scheme, path; else return "", rawurl.
+func getscheme(rawurl string) (scheme, path string, err os.Error) {
+       for i := 0; i < len(rawurl); i++ {
+               c := rawurl[i]
+               switch {
+               case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
+               // do nothing
+               case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
+                       if i == 0 {
+                               return "", rawurl, nil
+                       }
+               case c == ':':
+                       if i == 0 {
+                               return "", "", os.ErrorString("missing protocol scheme")
+                       }
+                       return rawurl[0:i], rawurl[i+1:], nil
+               default:
+                       // we have encountered an invalid character,
+                       // so there is no valid scheme
+                       return "", rawurl, nil
+               }
+       }
+       return "", rawurl, nil
+}
+
+// Maybe s is of the form t c u.
+// If so, return t, c u (or t, u if cutc == true).
+// If not, return s, "".
+func split(s string, c byte, cutc bool) (string, string) {
+       for i := 0; i < len(s); i++ {
+               if s[i] == c {
+                       if cutc {
+                               return s[0:i], s[i+1:]
+                       }
+                       return s[0:i], s[i:]
+               }
+       }
+       return s, ""
+}
+
+// ParseURL parses rawurl into a URL structure.
+// The string rawurl is assumed not to have a #fragment suffix.
+// (Web browsers strip #fragment before sending the URL to a web server.)
+func ParseURL(rawurl string) (url *URL, err os.Error) {
+       if rawurl == "" {
+               err = os.ErrorString("empty url")
+               goto Error
+       }
+       url = new(URL)
+       url.Raw = rawurl
+
+       // Split off possible leading "http:", "mailto:", etc.
+       // Cannot contain escaped characters.
+       var path string
+       if url.Scheme, path, err = getscheme(rawurl); err != nil {
+               goto Error
+       }
+
+       if url.Scheme != "" && (len(path) == 0 || path[0] != '/') {
+               // RFC 2396:
+               // Absolute URI (has scheme) with non-rooted path
+               // is uninterpreted.  It doesn't even have a ?query.
+               // This is the case that handles mailto:name@example.com.
+               url.RawPath = path
+
+               if url.Path, err = urlUnescape(path, encodeOpaque); err != nil {
+                       goto Error
+               }
+               url.OpaquePath = true
+       } else {
+               // Split off query before parsing path further.
+               url.RawPath = path
+               path, query := split(path, '?', false)
+               if len(query) > 1 {
+                       url.RawQuery = query[1:]
+               }
+
+               // Maybe path is //authority/path
+               if url.Scheme != "" && len(path) > 2 && path[0:2] == "//" {
+                       url.RawAuthority, path = split(path[2:], '/', false)
+                       url.RawPath = url.RawPath[2+len(url.RawAuthority):]
+               }
+
+               // Split authority into userinfo@host.
+               // If there's no @, split's default is wrong.  Check explicitly.
+               var rawHost string
+               if strings.Index(url.RawAuthority, "@") < 0 {
+                       rawHost = url.RawAuthority
+               } else {
+                       url.RawUserinfo, rawHost = split(url.RawAuthority, '@', true)
+               }
+
+               // We leave RawAuthority only in raw form because clients
+               // of common protocols should be using Userinfo and Host
+               // instead.  Clients that wish to use RawAuthority will have to
+               // interpret it themselves: RFC 2396 does not define the meaning.
+
+               if strings.Contains(rawHost, "%") {
+                       // Host cannot contain escaped characters.
+                       err = os.ErrorString("hexadecimal escape in host")
+                       goto Error
+               }
+               url.Host = rawHost
+
+               if url.Path, err = urlUnescape(path, encodePath); err != nil {
+                       goto Error
+               }
+       }
+       return url, nil
+
+Error:
+       return nil, &URLError{"parse", rawurl, err}
+
+}
+
+// ParseURLReference is like ParseURL but allows a trailing #fragment.
+func ParseURLReference(rawurlref string) (url *URL, err os.Error) {
+       // Cut off #frag.
+       rawurl, frag := split(rawurlref, '#', false)
+       if url, err = ParseURL(rawurl); err != nil {
+               return nil, err
+       }
+       url.Raw += frag
+       url.RawPath += frag
+       if len(frag) > 1 {
+               frag = frag[1:]
+               if url.Fragment, err = urlUnescape(frag, encodeFragment); err != nil {
+                       return nil, &URLError{"parse", rawurl, err}
+               }
+       }
+       return url, nil
+}
+
+// String reassembles url into a valid URL string.
+//
+// There are redundant fields stored in the URL structure:
+// the String method consults Scheme, Path, Host, RawUserinfo,
+// RawQuery, and Fragment, but not Raw, RawPath or Authority.
+func (url *URL) String() string {
+       result := ""
+       if url.Scheme != "" {
+               result += url.Scheme + ":"
+       }
+       if url.Host != "" || url.RawUserinfo != "" {
+               result += "//"
+               if url.RawUserinfo != "" {
+                       // hide the password, if any
+                       info := url.RawUserinfo
+                       if i := strings.Index(info, ":"); i >= 0 {
+                               info = info[0:i] + ":******"
+                       }
+                       result += info + "@"
+               }
+               result += url.Host
+       }
+       if url.OpaquePath {
+               path := url.Path
+               if strings.HasPrefix(path, "/") {
+                       result += "%2f"
+                       path = path[1:]
+               }
+               result += urlEscape(path, encodeOpaque)
+       } else {
+               result += urlEscape(url.Path, encodePath)
+       }
+       if url.RawQuery != "" {
+               result += "?" + url.RawQuery
+       }
+       if url.Fragment != "" {
+               result += "#" + urlEscape(url.Fragment, encodeFragment)
+       }
+       return result
+}
diff --git a/libgo/go/http/url_test.go b/libgo/go/http/url_test.go
new file mode 100644 (file)
index 0000000..8198e5f
--- /dev/null
@@ -0,0 +1,509 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "fmt"
+       "os"
+       "reflect"
+       "testing"
+)
+
+// TODO(rsc):
+//     test URLUnescape
+//     test URLEscape
+//     test ParseURL
+
+type URLTest struct {
+       in        string
+       out       *URL
+       roundtrip string // expected result of reserializing the URL; empty means same as "in".
+}
+
+var urltests = []URLTest{
+       // no path
+       {
+               "http://www.google.com",
+               &URL{
+                       Raw:          "http://www.google.com",
+                       Scheme:       "http",
+                       RawAuthority: "www.google.com",
+                       Host:         "www.google.com",
+               },
+               "",
+       },
+       // path
+       {
+               "http://www.google.com/",
+               &URL{
+                       Raw:          "http://www.google.com/",
+                       Scheme:       "http",
+                       RawAuthority: "www.google.com",
+                       Host:         "www.google.com",
+                       RawPath:      "/",
+                       Path:         "/",
+               },
+               "",
+       },
+       // path with hex escaping
+       {
+               "http://www.google.com/file%20one%26two",
+               &URL{
+                       Raw:          "http://www.google.com/file%20one%26two",
+                       Scheme:       "http",
+                       RawAuthority: "www.google.com",
+                       Host:         "www.google.com",
+                       RawPath:      "/file%20one%26two",
+                       Path:         "/file one&two",
+               },
+               "http://www.google.com/file%20one&two",
+       },
+       // user
+       {
+               "ftp://webmaster@www.google.com/",
+               &URL{
+                       Raw:          "ftp://webmaster@www.google.com/",
+                       Scheme:       "ftp",
+                       RawAuthority: "webmaster@www.google.com",
+                       RawUserinfo:  "webmaster",
+                       Host:         "www.google.com",
+                       RawPath:      "/",
+                       Path:         "/",
+               },
+               "",
+       },
+       // escape sequence in username
+       {
+               "ftp://john%20doe@www.google.com/",
+               &URL{
+                       Raw:          "ftp://john%20doe@www.google.com/",
+                       Scheme:       "ftp",
+                       RawAuthority: "john%20doe@www.google.com",
+                       RawUserinfo:  "john%20doe",
+                       Host:         "www.google.com",
+                       RawPath:      "/",
+                       Path:         "/",
+               },
+               "ftp://john%20doe@www.google.com/",
+       },
+       // query
+       {
+               "http://www.google.com/?q=go+language",
+               &URL{
+                       Raw:          "http://www.google.com/?q=go+language",
+                       Scheme:       "http",
+                       RawAuthority: "www.google.com",
+                       Host:         "www.google.com",
+                       RawPath:      "/?q=go+language",
+                       Path:         "/",
+                       RawQuery:     "q=go+language",
+               },
+               "",
+       },
+       // query with hex escaping: NOT parsed
+       {
+               "http://www.google.com/?q=go%20language",
+               &URL{
+                       Raw:          "http://www.google.com/?q=go%20language",
+                       Scheme:       "http",
+                       RawAuthority: "www.google.com",
+                       Host:         "www.google.com",
+                       RawPath:      "/?q=go%20language",
+                       Path:         "/",
+                       RawQuery:     "q=go%20language",
+               },
+               "",
+       },
+       // %20 outside query
+       {
+               "http://www.google.com/a%20b?q=c+d",
+               &URL{
+                       Raw:          "http://www.google.com/a%20b?q=c+d",
+                       Scheme:       "http",
+                       RawAuthority: "www.google.com",
+                       Host:         "www.google.com",
+                       RawPath:      "/a%20b?q=c+d",
+                       Path:         "/a b",
+                       RawQuery:     "q=c+d",
+               },
+               "",
+       },
+       // path without leading /, so no query parsing
+       {
+               "http:www.google.com/?q=go+language",
+               &URL{
+                       Raw:        "http:www.google.com/?q=go+language",
+                       Scheme:     "http",
+                       RawPath:    "www.google.com/?q=go+language",
+                       Path:       "www.google.com/?q=go+language",
+                       OpaquePath: true,
+               },
+               "http:www.google.com/?q=go+language",
+       },
+       // path without leading /, so no query parsing
+       {
+               "http:%2f%2fwww.google.com/?q=go+language",
+               &URL{
+                       Raw:        "http:%2f%2fwww.google.com/?q=go+language",
+                       Scheme:     "http",
+                       RawPath:    "%2f%2fwww.google.com/?q=go+language",
+                       Path:       "//www.google.com/?q=go+language",
+                       OpaquePath: true,
+               },
+               "http:%2f/www.google.com/?q=go+language",
+       },
+       // non-authority
+       {
+               "mailto:/webmaster@golang.org",
+               &URL{
+                       Raw:     "mailto:/webmaster@golang.org",
+                       Scheme:  "mailto",
+                       RawPath: "/webmaster@golang.org",
+                       Path:    "/webmaster@golang.org",
+               },
+               "",
+       },
+       // non-authority
+       {
+               "mailto:webmaster@golang.org",
+               &URL{
+                       Raw:        "mailto:webmaster@golang.org",
+                       Scheme:     "mailto",
+                       RawPath:    "webmaster@golang.org",
+                       Path:       "webmaster@golang.org",
+                       OpaquePath: true,
+               },
+               "",
+       },
+       // unescaped :// in query should not create a scheme
+       {
+               "/foo?query=http://bad",
+               &URL{
+                       Raw:      "/foo?query=http://bad",
+                       RawPath:  "/foo?query=http://bad",
+                       Path:     "/foo",
+                       RawQuery: "query=http://bad",
+               },
+               "",
+       },
+       // leading // without scheme shouldn't create an authority
+       {
+               "//foo",
+               &URL{
+                       Raw:     "//foo",
+                       Scheme:  "",
+                       RawPath: "//foo",
+                       Path:    "//foo",
+               },
+               "",
+       },
+       {
+               "http://user:password@google.com",
+               &URL{
+                       Raw:          "http://user:password@google.com",
+                       Scheme:       "http",
+                       RawAuthority: "user:password@google.com",
+                       RawUserinfo:  "user:password",
+                       Host:         "google.com",
+               },
+               "http://user:******@google.com",
+       },
+       {
+               "http://user:longerpass@google.com",
+               &URL{
+                       Raw:          "http://user:longerpass@google.com",
+                       Scheme:       "http",
+                       RawAuthority: "user:longerpass@google.com",
+                       RawUserinfo:  "user:longerpass",
+                       Host:         "google.com",
+               },
+               "http://user:******@google.com",
+       },
+}
+
+var urlnofragtests = []URLTest{
+       {
+               "http://www.google.com/?q=go+language#foo",
+               &URL{
+                       Raw:          "http://www.google.com/?q=go+language#foo",
+                       Scheme:       "http",
+                       RawAuthority: "www.google.com",
+                       Host:         "www.google.com",
+                       RawPath:      "/?q=go+language#foo",
+                       Path:         "/",
+                       RawQuery:     "q=go+language#foo",
+               },
+               "",
+       },
+}
+
+var urlfragtests = []URLTest{
+       {
+               "http://www.google.com/?q=go+language#foo",
+               &URL{
+                       Raw:          "http://www.google.com/?q=go+language#foo",
+                       Scheme:       "http",
+                       RawAuthority: "www.google.com",
+                       Host:         "www.google.com",
+                       RawPath:      "/?q=go+language#foo",
+                       Path:         "/",
+                       RawQuery:     "q=go+language",
+                       Fragment:     "foo",
+               },
+               "",
+       },
+       {
+               "http://www.google.com/?q=go+language#foo%26bar",
+               &URL{
+                       Raw:          "http://www.google.com/?q=go+language#foo%26bar",
+                       Scheme:       "http",
+                       RawAuthority: "www.google.com",
+                       Host:         "www.google.com",
+                       RawPath:      "/?q=go+language#foo%26bar",
+                       Path:         "/",
+                       RawQuery:     "q=go+language",
+                       Fragment:     "foo&bar",
+               },
+               "http://www.google.com/?q=go+language#foo&bar",
+       },
+}
+
+// more useful string for debugging than fmt's struct printer
+func ufmt(u *URL) string {
+       return fmt.Sprintf("%q, %q, %q, %q, %q, %q, %q, %q, %q",
+               u.Raw, u.Scheme, u.RawPath, u.RawAuthority, u.RawUserinfo,
+               u.Host, u.Path, u.RawQuery, u.Fragment)
+}
+
+func DoTest(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) {
+       for _, tt := range tests {
+               u, err := parse(tt.in)
+               if err != nil {
+                       t.Errorf("%s(%q) returned error %s", name, tt.in, err)
+                       continue
+               }
+               if !reflect.DeepEqual(u, tt.out) {
+                       t.Errorf("%s(%q):\n\thave %v\n\twant %v\n",
+                               name, tt.in, ufmt(u), ufmt(tt.out))
+               }
+       }
+}
+
+func TestParseURL(t *testing.T) {
+       DoTest(t, ParseURL, "ParseURL", urltests)
+       DoTest(t, ParseURL, "ParseURL", urlnofragtests)
+}
+
+func TestParseURLReference(t *testing.T) {
+       DoTest(t, ParseURLReference, "ParseURLReference", urltests)
+       DoTest(t, ParseURLReference, "ParseURLReference", urlfragtests)
+}
+
+func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) {
+       for _, tt := range tests {
+               u, err := parse(tt.in)
+               if err != nil {
+                       t.Errorf("%s(%q) returned error %s", name, tt.in, err)
+                       continue
+               }
+               s := u.String()
+               expected := tt.in
+               if len(tt.roundtrip) > 0 {
+                       expected = tt.roundtrip
+               }
+               if s != expected {
+                       t.Errorf("%s(%q).String() == %q (expected %q)", name, tt.in, s, expected)
+               }
+       }
+}
+
+func TestURLString(t *testing.T) {
+       DoTestString(t, ParseURL, "ParseURL", urltests)
+       DoTestString(t, ParseURL, "ParseURL", urlnofragtests)
+       DoTestString(t, ParseURLReference, "ParseURLReference", urltests)
+       DoTestString(t, ParseURLReference, "ParseURLReference", urlfragtests)
+}
+
+type URLEscapeTest struct {
+       in  string
+       out string
+       err os.Error
+}
+
+var unescapeTests = []URLEscapeTest{
+       {
+               "",
+               "",
+               nil,
+       },
+       {
+               "abc",
+               "abc",
+               nil,
+       },
+       {
+               "1%41",
+               "1A",
+               nil,
+       },
+       {
+               "1%41%42%43",
+               "1ABC",
+               nil,
+       },
+       {
+               "%4a",
+               "J",
+               nil,
+       },
+       {
+               "%6F",
+               "o",
+               nil,
+       },
+       {
+               "%", // not enough characters after %
+               "",
+               URLEscapeError("%"),
+       },
+       {
+               "%a", // not enough characters after %
+               "",
+               URLEscapeError("%a"),
+       },
+       {
+               "%1", // not enough characters after %
+               "",
+               URLEscapeError("%1"),
+       },
+       {
+               "123%45%6", // not enough characters after %
+               "",
+               URLEscapeError("%6"),
+       },
+       {
+               "%zzzzz", // invalid hex digits
+               "",
+               URLEscapeError("%zz"),
+       },
+}
+
+func TestURLUnescape(t *testing.T) {
+       for _, tt := range unescapeTests {
+               actual, err := URLUnescape(tt.in)
+               if actual != tt.out || (err != nil) != (tt.err != nil) {
+                       t.Errorf("URLUnescape(%q) = %q, %s; want %q, %s", tt.in, actual, err, tt.out, tt.err)
+               }
+       }
+}
+
+var escapeTests = []URLEscapeTest{
+       {
+               "",
+               "",
+               nil,
+       },
+       {
+               "abc",
+               "abc",
+               nil,
+       },
+       {
+               "one two",
+               "one+two",
+               nil,
+       },
+       {
+               "10%",
+               "10%25",
+               nil,
+       },
+       {
+               " ?&=#+%!<>#\"{}|\\^[]`☺\t",
+               "+%3f%26%3d%23%2b%25!%3c%3e%23%22%7b%7d%7c%5c%5e%5b%5d%60%e2%98%ba%09",
+               nil,
+       },
+}
+
+func TestURLEscape(t *testing.T) {
+       for _, tt := range escapeTests {
+               actual := URLEscape(tt.in)
+               if tt.out != actual {
+                       t.Errorf("URLEscape(%q) = %q, want %q", tt.in, actual, tt.out)
+               }
+
+               // for bonus points, verify that escape:unescape is an identity.
+               roundtrip, err := URLUnescape(actual)
+               if roundtrip != tt.in || err != nil {
+                       t.Errorf("URLUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]")
+               }
+       }
+}
+
+type CanonicalPathTest struct {
+       in  string
+       out string
+}
+
+var canonicalTests = []CanonicalPathTest{
+       {"", ""},
+       {"/", "/"},
+       {".", ""},
+       {"./", ""},
+       {"/a/", "/a/"},
+       {"a/", "a/"},
+       {"a/./", "a/"},
+       {"./a", "a"},
+       {"/a/../b", "/b"},
+       {"a/../b", "b"},
+       {"a/../../b", "../b"},
+       {"a/.", "a/"},
+       {"../.././a", "../../a"},
+       {"/../.././a", "/../../a"},
+       {"a/b/g/../..", "a/"},
+       {"a/b/..", "a/"},
+       {"a/b/.", "a/b/"},
+       {"a/b/../../../..", "../.."},
+       {"a./", "a./"},
+       {"/../a/b/../../../", "/../../"},
+       {"../a/b/../../../", "../../"},
+}
+
+func TestCanonicalPath(t *testing.T) {
+       for _, tt := range canonicalTests {
+               actual := CanonicalPath(tt.in)
+               if tt.out != actual {
+                       t.Errorf("CanonicalPath(%q) = %q, want %q", tt.in, actual, tt.out)
+               }
+       }
+}
+
+type UserinfoTest struct {
+       User     string
+       Password string
+       Raw      string
+}
+
+var userinfoTests = []UserinfoTest{
+       {"user", "password", "user:password"},
+       {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./",
+               "foo%3abar:~!%40%23$%25%5e&*()_+%7b%7d%7c%5b%5d%5c-=%60%3a;'%22%3c%3e?,.%2f"},
+}
+
+func TestEscapeUserinfo(t *testing.T) {
+       for _, tt := range userinfoTests {
+               if raw := EscapeUserinfo(tt.User, tt.Password); raw != tt.Raw {
+                       t.Errorf("EscapeUserinfo(%q, %q) = %q, want %q", tt.User, tt.Password, raw, tt.Raw)
+               }
+       }
+}
+
+func TestUnescapeUserinfo(t *testing.T) {
+       for _, tt := range userinfoTests {
+               if user, pass, err := UnescapeUserinfo(tt.Raw); user != tt.User || pass != tt.Password || err != nil {
+                       t.Errorf("UnescapeUserinfo(%q) = %q, %q, %v, want %q, %q, nil", tt.Raw, user, pass, err, tt.User, tt.Password)
+               }
+       }
+}
diff --git a/libgo/go/image/color.go b/libgo/go/image/color.go
new file mode 100644 (file)
index 0000000..c1345c0
--- /dev/null
@@ -0,0 +1,251 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+// All Colors can convert themselves, with a possible loss of precision,
+// to 64-bit alpha-premultiplied RGBA. Each channel value ranges within
+// [0, 0xFFFF].
+type Color interface {
+       RGBA() (r, g, b, a uint32)
+}
+
+// An RGBAColor represents a traditional 32-bit alpha-premultiplied color,
+// having 8 bits for each of red, green, blue and alpha.
+type RGBAColor struct {
+       R, G, B, A uint8
+}
+
+func (c RGBAColor) RGBA() (r, g, b, a uint32) {
+       r = uint32(c.R)
+       r |= r << 8
+       g = uint32(c.G)
+       g |= g << 8
+       b = uint32(c.B)
+       b |= b << 8
+       a = uint32(c.A)
+       a |= a << 8
+       return
+}
+
+// An RGBA64Color represents a 64-bit alpha-premultiplied color,
+// having 16 bits for each of red, green, blue and alpha.
+type RGBA64Color struct {
+       R, G, B, A uint16
+}
+
+func (c RGBA64Color) RGBA() (r, g, b, a uint32) {
+       return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
+}
+
+// An NRGBAColor represents a non-alpha-premultiplied 32-bit color.
+type NRGBAColor struct {
+       R, G, B, A uint8
+}
+
+func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
+       r = uint32(c.R)
+       r |= r << 8
+       r *= uint32(c.A)
+       r /= 0xff
+       g = uint32(c.G)
+       g |= g << 8
+       g *= uint32(c.A)
+       g /= 0xff
+       b = uint32(c.B)
+       b |= b << 8
+       b *= uint32(c.A)
+       b /= 0xff
+       a = uint32(c.A)
+       a |= a << 8
+       return
+}
+
+// An NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
+// having 16 bits for each of red, green, blue and alpha.
+type NRGBA64Color struct {
+       R, G, B, A uint16
+}
+
+func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
+       r = uint32(c.R)
+       r *= uint32(c.A)
+       r /= 0xffff
+       g = uint32(c.G)
+       g *= uint32(c.A)
+       g /= 0xffff
+       b = uint32(c.B)
+       b *= uint32(c.A)
+       b /= 0xffff
+       a = uint32(c.A)
+       return
+}
+
+// An AlphaColor represents an 8-bit alpha.
+type AlphaColor struct {
+       A uint8
+}
+
+func (c AlphaColor) RGBA() (r, g, b, a uint32) {
+       a = uint32(c.A)
+       a |= a << 8
+       return a, a, a, a
+}
+
+// An Alpha16Color represents a 16-bit alpha.
+type Alpha16Color struct {
+       A uint16
+}
+
+func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
+       a = uint32(c.A)
+       return a, a, a, a
+}
+
+// A GrayColor represents an 8-bit grayscale color.
+type GrayColor struct {
+       Y uint8
+}
+
+func (c GrayColor) RGBA() (r, g, b, a uint32) {
+       y := uint32(c.Y)
+       y |= y << 8
+       return y, y, y, 0xffff
+}
+
+// A Gray16Color represents a 16-bit grayscale color.
+type Gray16Color struct {
+       Y uint16
+}
+
+func (c Gray16Color) RGBA() (r, g, b, a uint32) {
+       y := uint32(c.Y)
+       return y, y, y, 0xffff
+}
+
+// A ColorModel can convert foreign Colors, with a possible loss of precision,
+// to a Color from its own color model.
+type ColorModel interface {
+       Convert(c Color) Color
+}
+
+// The ColorModelFunc type is an adapter to allow the use of an ordinary
+// color conversion function as a ColorModel.  If f is such a function,
+// ColorModelFunc(f) is a ColorModel object that invokes f to implement
+// the conversion.
+type ColorModelFunc func(Color) Color
+
+func (f ColorModelFunc) Convert(c Color) Color {
+       return f(c)
+}
+
+func toRGBAColor(c Color) Color {
+       if _, ok := c.(RGBAColor); ok {
+               return c
+       }
+       r, g, b, a := c.RGBA()
+       return RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
+}
+
+func toRGBA64Color(c Color) Color {
+       if _, ok := c.(RGBA64Color); ok {
+               return c
+       }
+       r, g, b, a := c.RGBA()
+       return RGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
+func toNRGBAColor(c Color) Color {
+       if _, ok := c.(NRGBAColor); ok {
+               return c
+       }
+       r, g, b, a := c.RGBA()
+       if a == 0xffff {
+               return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
+       }
+       if a == 0 {
+               return NRGBAColor{0, 0, 0, 0}
+       }
+       // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
+       r = (r * 0xffff) / a
+       g = (g * 0xffff) / a
+       b = (b * 0xffff) / a
+       return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
+}
+
+func toNRGBA64Color(c Color) Color {
+       if _, ok := c.(NRGBA64Color); ok {
+               return c
+       }
+       r, g, b, a := c.RGBA()
+       if a == 0xffff {
+               return NRGBA64Color{uint16(r), uint16(g), uint16(b), 0xffff}
+       }
+       if a == 0 {
+               return NRGBA64Color{0, 0, 0, 0}
+       }
+       // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
+       r = (r * 0xffff) / a
+       g = (g * 0xffff) / a
+       b = (b * 0xffff) / a
+       return NRGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
+func toAlphaColor(c Color) Color {
+       if _, ok := c.(AlphaColor); ok {
+               return c
+       }
+       _, _, _, a := c.RGBA()
+       return AlphaColor{uint8(a >> 8)}
+}
+
+func toAlpha16Color(c Color) Color {
+       if _, ok := c.(Alpha16Color); ok {
+               return c
+       }
+       _, _, _, a := c.RGBA()
+       return Alpha16Color{uint16(a)}
+}
+
+func toGrayColor(c Color) Color {
+       if _, ok := c.(GrayColor); ok {
+               return c
+       }
+       r, g, b, _ := c.RGBA()
+       y := (299*r + 587*g + 114*b + 500) / 1000
+       return GrayColor{uint8(y >> 8)}
+}
+
+func toGray16Color(c Color) Color {
+       if _, ok := c.(Gray16Color); ok {
+               return c
+       }
+       r, g, b, _ := c.RGBA()
+       y := (299*r + 587*g + 114*b + 500) / 1000
+       return Gray16Color{uint16(y)}
+}
+
+// The ColorModel associated with RGBAColor.
+var RGBAColorModel ColorModel = ColorModelFunc(toRGBAColor)
+
+// The ColorModel associated with RGBA64Color.
+var RGBA64ColorModel ColorModel = ColorModelFunc(toRGBA64Color)
+
+// The ColorModel associated with NRGBAColor.
+var NRGBAColorModel ColorModel = ColorModelFunc(toNRGBAColor)
+
+// The ColorModel associated with NRGBA64Color.
+var NRGBA64ColorModel ColorModel = ColorModelFunc(toNRGBA64Color)
+
+// The ColorModel associated with AlphaColor.
+var AlphaColorModel ColorModel = ColorModelFunc(toAlphaColor)
+
+// The ColorModel associated with Alpha16Color.
+var Alpha16ColorModel ColorModel = ColorModelFunc(toAlpha16Color)
+
+// The ColorModel associated with GrayColor.
+var GrayColorModel ColorModel = ColorModelFunc(toGrayColor)
+
+// The ColorModel associated with Gray16Color.
+var Gray16ColorModel ColorModel = ColorModelFunc(toGray16Color)
diff --git a/libgo/go/image/format.go b/libgo/go/image/format.go
new file mode 100644 (file)
index 0000000..1d541b0
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+       "bufio"
+       "io"
+       "os"
+)
+
+// An UnknownFormatErr indicates that decoding encountered an unknown format.
+var UnknownFormatErr = os.NewError("image: unknown format")
+
+// A format holds an image format's name, magic header and how to decode it.
+type format struct {
+       name, magic  string
+       decode       func(io.Reader) (Image, os.Error)
+       decodeConfig func(io.Reader) (Config, os.Error)
+}
+
+// Formats is the list of registered formats.
+var formats []format
+
+// RegisterFormat registers an image format for use by Decode.
+// Name is the name of the format, like "jpeg" or "png".
+// Magic is the magic prefix that identifies the format's encoding.
+// Decode is the function that decodes the encoded image.
+// DecodeConfig is the function that decodes just its configuration.
+func RegisterFormat(name, magic string, decode func(io.Reader) (Image, os.Error), decodeConfig func(io.Reader) (Config, os.Error)) {
+       formats = append(formats, format{name, magic, decode, decodeConfig})
+}
+
+// A reader is an io.Reader that can also peek ahead.
+type reader interface {
+       io.Reader
+       Peek(int) ([]byte, os.Error)
+}
+
+// AsReader converts an io.Reader to a reader.
+func asReader(r io.Reader) reader {
+       if rr, ok := r.(reader); ok {
+               return rr
+       }
+       return bufio.NewReader(r)
+}
+
+// sniff determines the format of r's data.
+func sniff(r reader) format {
+       for _, f := range formats {
+               s, err := r.Peek(len(f.magic))
+               if err == nil && string(s) == f.magic {
+                       return f
+               }
+       }
+       return format{}
+}
+
+// Decode decodes an image that has been encoded in a registered format.
+// The string returned is the format name used during format registration.
+// Format registration is typically done by the init method of the codec-
+// specific package.
+func Decode(r io.Reader) (Image, string, os.Error) {
+       rr := asReader(r)
+       f := sniff(rr)
+       if f.decode == nil {
+               return nil, "", UnknownFormatErr
+       }
+       m, err := f.decode(rr)
+       return m, f.name, err
+}
+
+// DecodeConfig decodes the color model and dimensions of an image that has
+// been encoded in a registered format. The string returned is the format name
+// used during format registration. Format registration is typically done by
+// the init method of the codec-specific package.
+func DecodeConfig(r io.Reader) (Config, string, os.Error) {
+       rr := asReader(r)
+       f := sniff(rr)
+       if f.decodeConfig == nil {
+               return Config{}, "", UnknownFormatErr
+       }
+       c, err := f.decodeConfig(rr)
+       return c, f.name, err
+}
diff --git a/libgo/go/image/geom.go b/libgo/go/image/geom.go
new file mode 100644 (file)
index 0000000..ccfe9cd
--- /dev/null
@@ -0,0 +1,223 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+       "strconv"
+)
+
+// A Point is an X, Y coordinate pair. The axes increase right and down.
+type Point struct {
+       X, Y int
+}
+
+// String returns a string representation of p like "(3,4)".
+func (p Point) String() string {
+       return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
+}
+
+// Add returns the vector p+q.
+func (p Point) Add(q Point) Point {
+       return Point{p.X + q.X, p.Y + q.Y}
+}
+
+// Sub returns the vector p-q.
+func (p Point) Sub(q Point) Point {
+       return Point{p.X - q.X, p.Y - q.Y}
+}
+
+// Mul returns the vector p*k.
+func (p Point) Mul(k int) Point {
+       return Point{p.X * k, p.Y * k}
+}
+
+// Div returns the vector p/k.
+func (p Point) Div(k int) Point {
+       return Point{p.X / k, p.Y / k}
+}
+
+// Mod returns the point q in r such that p.X-q.X is a multiple of r's width
+// and p.Y-q.Y is a multiple of r's height.
+func (p Point) Mod(r Rectangle) Point {
+       w, h := r.Dx(), r.Dy()
+       p = p.Sub(r.Min)
+       p.X = p.X % w
+       if p.X < 0 {
+               p.X += w
+       }
+       p.Y = p.Y % h
+       if p.Y < 0 {
+               p.Y += h
+       }
+       return p.Add(r.Min)
+}
+
+// Eq returns whether p and q are equal.
+func (p Point) Eq(q Point) bool {
+       return p.X == q.X && p.Y == q.Y
+}
+
+// ZP is the zero Point.
+var ZP Point
+
+// Pt is shorthand for Point{X, Y}.
+func Pt(X, Y int) Point {
+       return Point{X, Y}
+}
+
+// A Rectangle contains the points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
+// It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
+// well-formed. A rectangle's methods always return well-formed outputs for
+// well-formed inputs.
+type Rectangle struct {
+       Min, Max Point
+}
+
+// String returns a string representation of r like "(3,4)-(6,5)".
+func (r Rectangle) String() string {
+       return r.Min.String() + "-" + r.Max.String()
+}
+
+// Dx returns r's width.
+func (r Rectangle) Dx() int {
+       return r.Max.X - r.Min.X
+}
+
+// Dy returns r's height.
+func (r Rectangle) Dy() int {
+       return r.Max.Y - r.Min.Y
+}
+
+// Size returns r's width and height.
+func (r Rectangle) Size() Point {
+       return Point{
+               r.Max.X - r.Min.X,
+               r.Max.Y - r.Min.Y,
+       }
+}
+
+// Add returns the rectangle r translated by p.
+func (r Rectangle) Add(p Point) Rectangle {
+       return Rectangle{
+               Point{r.Min.X + p.X, r.Min.Y + p.Y},
+               Point{r.Max.X + p.X, r.Max.Y + p.Y},
+       }
+}
+
+// Add returns the rectangle r translated by -p.
+func (r Rectangle) Sub(p Point) Rectangle {
+       return Rectangle{
+               Point{r.Min.X - p.X, r.Min.Y - p.Y},
+               Point{r.Max.X - p.X, r.Max.Y - p.Y},
+       }
+}
+
+// Inset returns the rectangle r inset by n, which may be negative. If either
+// of r's dimensions is less than 2*n then an empty rectangle near the center
+// of r will be returned.
+func (r Rectangle) Inset(n int) Rectangle {
+       if r.Dx() < 2*n {
+               r.Min.X = (r.Min.X + r.Max.X) / 2
+               r.Max.X = r.Min.X
+       } else {
+               r.Min.X += n
+               r.Max.X -= n
+       }
+       if r.Dy() < 2*n {
+               r.Min.Y = (r.Min.Y + r.Max.Y) / 2
+               r.Max.Y = r.Min.Y
+       } else {
+               r.Min.Y += n
+               r.Max.Y -= n
+       }
+       return r
+}
+
+// Intersect returns the largest rectangle contained by both r and s. If the
+// two rectangles do not overlap then the zero rectangle will be returned.
+func (r Rectangle) Intersect(s Rectangle) Rectangle {
+       if r.Min.X < s.Min.X {
+               r.Min.X = s.Min.X
+       }
+       if r.Min.Y < s.Min.Y {
+               r.Min.Y = s.Min.Y
+       }
+       if r.Max.X > s.Max.X {
+               r.Max.X = s.Max.X
+       }
+       if r.Max.Y > s.Max.Y {
+               r.Max.Y = s.Max.Y
+       }
+       if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
+               return ZR
+       }
+       return r
+}
+
+// Union returns the smallest rectangle that contains both r and s.
+func (r Rectangle) Union(s Rectangle) Rectangle {
+       if r.Min.X > s.Min.X {
+               r.Min.X = s.Min.X
+       }
+       if r.Min.Y > s.Min.Y {
+               r.Min.Y = s.Min.Y
+       }
+       if r.Max.X < s.Max.X {
+               r.Max.X = s.Max.X
+       }
+       if r.Max.Y < s.Max.Y {
+               r.Max.Y = s.Max.Y
+       }
+       return r
+}
+
+// Empty returns whether the rectangle contains no points.
+func (r Rectangle) Empty() bool {
+       return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
+}
+
+// Eq returns whether r and s are equal.
+func (r Rectangle) Eq(s Rectangle) bool {
+       return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
+               r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
+}
+
+// Overlaps returns whether r and s have a non-empty intersection.
+func (r Rectangle) Overlaps(s Rectangle) bool {
+       return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
+               r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
+}
+
+// Contains returns whether r contains p.
+func (r Rectangle) Contains(p Point) bool {
+       return p.X >= r.Min.X && p.X < r.Max.X &&
+               p.Y >= r.Min.Y && p.Y < r.Max.Y
+}
+
+// Canon returns the canonical version of r. The returned rectangle has minimum
+// and maximum coordinates swapped if necessary so that it is well-formed.
+func (r Rectangle) Canon() Rectangle {
+       if r.Max.X < r.Min.X {
+               r.Min.X, r.Max.X = r.Max.X, r.Min.X
+       }
+       if r.Max.Y < r.Min.Y {
+               r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
+       }
+       return r
+}
+
+// ZR is the zero Rectangle.
+var ZR Rectangle
+
+// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
+func Rect(x0, y0, x1, y1 int) Rectangle {
+       if x0 > x1 {
+               x0, x1 = x1, x0
+       }
+       if y0 > y1 {
+               y0, y1 = y1, y0
+       }
+       return Rectangle{Point{x0, y0}, Point{x1, y1}}
+}
diff --git a/libgo/go/image/image.go b/libgo/go/image/image.go
new file mode 100644 (file)
index 0000000..c0e96e1
--- /dev/null
@@ -0,0 +1,506 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The image package implements a basic 2-D image library.
+package image
+
+// A Config consists of an image's color model and dimensions.
+type Config struct {
+       ColorModel    ColorModel
+       Width, Height int
+}
+
+// An Image is a finite rectangular grid of Colors drawn from a ColorModel.
+type Image interface {
+       // ColorModel returns the Image's ColorModel.
+       ColorModel() ColorModel
+       // Bounds returns the domain for which At can return non-zero color.
+       // The bounds do not necessarily contain the point (0, 0).
+       Bounds() Rectangle
+       // At returns the color of the pixel at (x, y).
+       // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
+       // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
+       At(x, y int) Color
+}
+
+// An RGBA is an in-memory image of RGBAColor values.
+type RGBA struct {
+       // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+       Pix    []RGBAColor
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *RGBA) ColorModel() ColorModel { return RGBAColorModel }
+
+func (p *RGBA) Bounds() Rectangle { return p.Rect }
+
+func (p *RGBA) At(x, y int) Color {
+       if !p.Rect.Contains(Point{x, y}) {
+               return RGBAColor{}
+       }
+       return p.Pix[y*p.Stride+x]
+}
+
+func (p *RGBA) Set(x, y int, c Color) {
+       if !p.Rect.Contains(Point{x, y}) {
+               return
+       }
+       p.Pix[y*p.Stride+x] = toRGBAColor(c).(RGBAColor)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *RGBA) Opaque() bool {
+       if p.Rect.Empty() {
+               return true
+       }
+       base := p.Rect.Min.Y * p.Stride
+       i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+       for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+               for _, c := range p.Pix[i0:i1] {
+                       if c.A != 0xff {
+                               return false
+                       }
+               }
+               i0 += p.Stride
+               i1 += p.Stride
+       }
+       return true
+}
+
+// NewRGBA returns a new RGBA with the given width and height.
+func NewRGBA(w, h int) *RGBA {
+       buf := make([]RGBAColor, w*h)
+       return &RGBA{buf, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An RGBA64 is an in-memory image of RGBA64Color values.
+type RGBA64 struct {
+       // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+       Pix    []RGBA64Color
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *RGBA64) ColorModel() ColorModel { return RGBA64ColorModel }
+
+func (p *RGBA64) Bounds() Rectangle { return p.Rect }
+
+func (p *RGBA64) At(x, y int) Color {
+       if !p.Rect.Contains(Point{x, y}) {
+               return RGBA64Color{}
+       }
+       return p.Pix[y*p.Stride+x]
+}
+
+func (p *RGBA64) Set(x, y int, c Color) {
+       if !p.Rect.Contains(Point{x, y}) {
+               return
+       }
+       p.Pix[y*p.Stride+x] = toRGBA64Color(c).(RGBA64Color)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *RGBA64) Opaque() bool {
+       if p.Rect.Empty() {
+               return true
+       }
+       base := p.Rect.Min.Y * p.Stride
+       i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+       for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+               for _, c := range p.Pix[i0:i1] {
+                       if c.A != 0xffff {
+                               return false
+                       }
+               }
+               i0 += p.Stride
+               i1 += p.Stride
+       }
+       return true
+}
+
+// NewRGBA64 returns a new RGBA64 with the given width and height.
+func NewRGBA64(w, h int) *RGBA64 {
+       pix := make([]RGBA64Color, w*h)
+       return &RGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An NRGBA is an in-memory image of NRGBAColor values.
+type NRGBA struct {
+       // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+       Pix    []NRGBAColor
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *NRGBA) ColorModel() ColorModel { return NRGBAColorModel }
+
+func (p *NRGBA) Bounds() Rectangle { return p.Rect }
+
+func (p *NRGBA) At(x, y int) Color {
+       if !p.Rect.Contains(Point{x, y}) {
+               return NRGBAColor{}
+       }
+       return p.Pix[y*p.Stride+x]
+}
+
+func (p *NRGBA) Set(x, y int, c Color) {
+       if !p.Rect.Contains(Point{x, y}) {
+               return
+       }
+       p.Pix[y*p.Stride+x] = toNRGBAColor(c).(NRGBAColor)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *NRGBA) Opaque() bool {
+       if p.Rect.Empty() {
+               return true
+       }
+       base := p.Rect.Min.Y * p.Stride
+       i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+       for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+               for _, c := range p.Pix[i0:i1] {
+                       if c.A != 0xff {
+                               return false
+                       }
+               }
+               i0 += p.Stride
+               i1 += p.Stride
+       }
+       return true
+}
+
+// NewNRGBA returns a new NRGBA with the given width and height.
+func NewNRGBA(w, h int) *NRGBA {
+       pix := make([]NRGBAColor, w*h)
+       return &NRGBA{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An NRGBA64 is an in-memory image of NRGBA64Color values.
+type NRGBA64 struct {
+       // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+       Pix    []NRGBA64Color
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *NRGBA64) ColorModel() ColorModel { return NRGBA64ColorModel }
+
+func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
+
+func (p *NRGBA64) At(x, y int) Color {
+       if !p.Rect.Contains(Point{x, y}) {
+               return NRGBA64Color{}
+       }
+       return p.Pix[y*p.Stride+x]
+}
+
+func (p *NRGBA64) Set(x, y int, c Color) {
+       if !p.Rect.Contains(Point{x, y}) {
+               return
+       }
+       p.Pix[y*p.Stride+x] = toNRGBA64Color(c).(NRGBA64Color)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *NRGBA64) Opaque() bool {
+       if p.Rect.Empty() {
+               return true
+       }
+       base := p.Rect.Min.Y * p.Stride
+       i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+       for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+               for _, c := range p.Pix[i0:i1] {
+                       if c.A != 0xffff {
+                               return false
+                       }
+               }
+               i0 += p.Stride
+               i1 += p.Stride
+       }
+       return true
+}
+
+// NewNRGBA64 returns a new NRGBA64 with the given width and height.
+func NewNRGBA64(w, h int) *NRGBA64 {
+       pix := make([]NRGBA64Color, w*h)
+       return &NRGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An Alpha is an in-memory image of AlphaColor values.
+type Alpha struct {
+       // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+       Pix    []AlphaColor
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *Alpha) ColorModel() ColorModel { return AlphaColorModel }
+
+func (p *Alpha) Bounds() Rectangle { return p.Rect }
+
+func (p *Alpha) At(x, y int) Color {
+       if !p.Rect.Contains(Point{x, y}) {
+               return AlphaColor{}
+       }
+       return p.Pix[y*p.Stride+x]
+}
+
+func (p *Alpha) Set(x, y int, c Color) {
+       if !p.Rect.Contains(Point{x, y}) {
+               return
+       }
+       p.Pix[y*p.Stride+x] = toAlphaColor(c).(AlphaColor)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Alpha) Opaque() bool {
+       if p.Rect.Empty() {
+               return true
+       }
+       base := p.Rect.Min.Y * p.Stride
+       i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+       for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+               for _, c := range p.Pix[i0:i1] {
+                       if c.A != 0xff {
+                               return false
+                       }
+               }
+               i0 += p.Stride
+               i1 += p.Stride
+       }
+       return true
+}
+
+// NewAlpha returns a new Alpha with the given width and height.
+func NewAlpha(w, h int) *Alpha {
+       pix := make([]AlphaColor, w*h)
+       return &Alpha{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An Alpha16 is an in-memory image of Alpha16Color values.
+type Alpha16 struct {
+       // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+       Pix    []Alpha16Color
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *Alpha16) ColorModel() ColorModel { return Alpha16ColorModel }
+
+func (p *Alpha16) Bounds() Rectangle { return p.Rect }
+
+func (p *Alpha16) At(x, y int) Color {
+       if !p.Rect.Contains(Point{x, y}) {
+               return Alpha16Color{}
+       }
+       return p.Pix[y*p.Stride+x]
+}
+
+func (p *Alpha16) Set(x, y int, c Color) {
+       if !p.Rect.Contains(Point{x, y}) {
+               return
+       }
+       p.Pix[y*p.Stride+x] = toAlpha16Color(c).(Alpha16Color)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Alpha16) Opaque() bool {
+       if p.Rect.Empty() {
+               return true
+       }
+       base := p.Rect.Min.Y * p.Stride
+       i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+       for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+               for _, c := range p.Pix[i0:i1] {
+                       if c.A != 0xffff {
+                               return false
+                       }
+               }
+               i0 += p.Stride
+               i1 += p.Stride
+       }
+       return true
+}
+
+// NewAlpha16 returns a new Alpha16 with the given width and height.
+func NewAlpha16(w, h int) *Alpha16 {
+       pix := make([]Alpha16Color, w*h)
+       return &Alpha16{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// A Gray is an in-memory image of GrayColor values.
+type Gray struct {
+       // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+       Pix    []GrayColor
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *Gray) ColorModel() ColorModel { return GrayColorModel }
+
+func (p *Gray) Bounds() Rectangle { return p.Rect }
+
+func (p *Gray) At(x, y int) Color {
+       if !p.Rect.Contains(Point{x, y}) {
+               return GrayColor{}
+       }
+       return p.Pix[y*p.Stride+x]
+}
+
+func (p *Gray) Set(x, y int, c Color) {
+       if !p.Rect.Contains(Point{x, y}) {
+               return
+       }
+       p.Pix[y*p.Stride+x] = toGrayColor(c).(GrayColor)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Gray) Opaque() bool {
+       return true
+}
+
+// NewGray returns a new Gray with the given width and height.
+func NewGray(w, h int) *Gray {
+       pix := make([]GrayColor, w*h)
+       return &Gray{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// A Gray16 is an in-memory image of Gray16Color values.
+type Gray16 struct {
+       // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+       Pix    []Gray16Color
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *Gray16) ColorModel() ColorModel { return Gray16ColorModel }
+
+func (p *Gray16) Bounds() Rectangle { return p.Rect }
+
+func (p *Gray16) At(x, y int) Color {
+       if !p.Rect.Contains(Point{x, y}) {
+               return Gray16Color{}
+       }
+       return p.Pix[y*p.Stride+x]
+}
+
+func (p *Gray16) Set(x, y int, c Color) {
+       if !p.Rect.Contains(Point{x, y}) {
+               return
+       }
+       p.Pix[y*p.Stride+x] = toGray16Color(c).(Gray16Color)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Gray16) Opaque() bool {
+       return true
+}
+
+// NewGray16 returns a new Gray16 with the given width and height.
+func NewGray16(w, h int) *Gray16 {
+       pix := make([]Gray16Color, w*h)
+       return &Gray16{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// A PalettedColorModel represents a fixed palette of colors.
+type PalettedColorModel []Color
+
+func diff(a, b uint32) uint32 {
+       if a > b {
+               return a - b
+       }
+       return b - a
+}
+
+// Convert returns the palette color closest to c in Euclidean R,G,B space.
+func (p PalettedColorModel) Convert(c Color) Color {
+       if len(p) == 0 {
+               return nil
+       }
+       cr, cg, cb, _ := c.RGBA()
+       // Shift by 1 bit to avoid potential uint32 overflow in sum-squared-difference.
+       cr >>= 1
+       cg >>= 1
+       cb >>= 1
+       result := Color(nil)
+       bestSSD := uint32(1<<32 - 1)
+       for _, v := range p {
+               vr, vg, vb, _ := v.RGBA()
+               vr >>= 1
+               vg >>= 1
+               vb >>= 1
+               dr, dg, db := diff(cr, vr), diff(cg, vg), diff(cb, vb)
+               ssd := (dr * dr) + (dg * dg) + (db * db)
+               if ssd < bestSSD {
+                       bestSSD = ssd
+                       result = v
+               }
+       }
+       return result
+}
+
+// A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel.
+type Paletted struct {
+       // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+       Pix    []uint8
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+       // Palette is the image's palette.
+       Palette PalettedColorModel
+}
+
+func (p *Paletted) ColorModel() ColorModel { return p.Palette }
+
+func (p *Paletted) Bounds() Rectangle { return p.Rect }
+
+func (p *Paletted) At(x, y int) Color {
+       if len(p.Palette) == 0 {
+               return nil
+       }
+       if !p.Rect.Contains(Point{x, y}) {
+               return p.Palette[0]
+       }
+       return p.Palette[p.Pix[y*p.Stride+x]]
+}
+
+func (p *Paletted) ColorIndexAt(x, y int) uint8 {
+       if !p.Rect.Contains(Point{x, y}) {
+               return 0
+       }
+       return p.Pix[y*p.Stride+x]
+}
+
+func (p *Paletted) SetColorIndex(x, y int, index uint8) {
+       if !p.Rect.Contains(Point{x, y}) {
+               return
+       }
+       p.Pix[y*p.Stride+x] = index
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Paletted) Opaque() bool {
+       for _, c := range p.Palette {
+               _, _, _, a := c.RGBA()
+               if a != 0xffff {
+                       return false
+               }
+       }
+       return true
+}
+
+// NewPaletted returns a new Paletted with the given width, height and palette.
+func NewPaletted(w, h int, m PalettedColorModel) *Paletted {
+       pix := make([]uint8, w*h)
+       return &Paletted{pix, w, Rectangle{ZP, Point{w, h}}, m}
+}
diff --git a/libgo/go/image/jpeg/huffman.go b/libgo/go/image/jpeg/huffman.go
new file mode 100644 (file)
index 0000000..0d03a73
--- /dev/null
@@ -0,0 +1,190 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jpeg
+
+import (
+       "io"
+       "os"
+)
+
+// Each code is at most 16 bits long.
+const maxCodeLength = 16
+
+// Each decoded value is a uint8, so there are at most 256 such values.
+const maxNumValues = 256
+
+// Bit stream for the Huffman decoder.
+// The n least significant bits of a form the unread bits, to be read in MSB to LSB order.
+type bits struct {
+       a int // accumulator.
+       n int // the number of unread bits in a.
+       m int // mask. m==1<<(n-1) when n>0, with m==0 when n==0.
+}
+
+// Huffman table decoder, specified in section C.
+type huffman struct {
+       l        [maxCodeLength]int
+       length   int                 // sum of l[i].
+       val      [maxNumValues]uint8 // the decoded values, as sorted by their encoding.
+       size     [maxNumValues]int   // size[i] is the number of bits to encode val[i].
+       code     [maxNumValues]int   // code[i] is the encoding of val[i].
+       minCode  [maxCodeLength]int  // min codes of length i, or -1 if no codes of that length.
+       maxCode  [maxCodeLength]int  // max codes of length i, or -1 if no codes of that length.
+       valIndex [maxCodeLength]int  // index into val of minCode[i].
+}
+
+// Reads bytes from the io.Reader to ensure that bits.n is at least n.
+func (d *decoder) ensureNBits(n int) os.Error {
+       for d.b.n < n {
+               c, err := d.r.ReadByte()
+               if err != nil {
+                       return err
+               }
+               d.b.a = d.b.a<<8 | int(c)
+               d.b.n += 8
+               if d.b.m == 0 {
+                       d.b.m = 1 << 7
+               } else {
+                       d.b.m <<= 8
+               }
+               // Byte stuffing, specified in section F.1.2.3.
+               if c == 0xff {
+                       c, err = d.r.ReadByte()
+                       if err != nil {
+                               return err
+                       }
+                       if c != 0x00 {
+                               return FormatError("missing 0xff00 sequence")
+                       }
+               }
+       }
+       return nil
+}
+
+// The composition of RECEIVE and EXTEND, specified in section F.2.2.1.
+func (d *decoder) receiveExtend(t uint8) (int, os.Error) {
+       err := d.ensureNBits(int(t))
+       if err != nil {
+               return 0, err
+       }
+       d.b.n -= int(t)
+       d.b.m >>= t
+       s := 1 << t
+       x := (d.b.a >> uint8(d.b.n)) & (s - 1)
+       if x < s>>1 {
+               x += ((-1) << t) + 1
+       }
+       return x, nil
+}
+
+// Processes a Define Huffman Table marker, and initializes a huffman struct from its contents.
+// Specified in section B.2.4.2.
+func (d *decoder) processDHT(n int) os.Error {
+       for n > 0 {
+               if n < 17 {
+                       return FormatError("DHT has wrong length")
+               }
+               _, err := io.ReadFull(d.r, d.tmp[0:17])
+               if err != nil {
+                       return err
+               }
+               tc := d.tmp[0] >> 4
+               if tc > maxTc {
+                       return FormatError("bad Tc value")
+               }
+               th := d.tmp[0] & 0x0f
+               const isBaseline = true // Progressive mode is not yet supported.
+               if th > maxTh || isBaseline && th > 1 {
+                       return FormatError("bad Th value")
+               }
+               h := &d.huff[tc][th]
+
+               // Read l and val (and derive length).
+               h.length = 0
+               for i := 0; i < maxCodeLength; i++ {
+                       h.l[i] = int(d.tmp[i+1])
+                       h.length += h.l[i]
+               }
+               if h.length == 0 {
+                       return FormatError("Huffman table has zero length")
+               }
+               if h.length > maxNumValues {
+                       return FormatError("Huffman table has excessive length")
+               }
+               n -= h.length + 17
+               if n < 0 {
+                       return FormatError("DHT has wrong length")
+               }
+               _, err = io.ReadFull(d.r, h.val[0:h.length])
+               if err != nil {
+                       return err
+               }
+
+               // Derive size.
+               k := 0
+               for i := 0; i < maxCodeLength; i++ {
+                       for j := 0; j < h.l[i]; j++ {
+                               h.size[k] = i + 1
+                               k++
+                       }
+               }
+
+               // Derive code.
+               code := 0
+               size := h.size[0]
+               for i := 0; i < h.length; i++ {
+                       if size != h.size[i] {
+                               code <<= uint8(h.size[i] - size)
+                               size = h.size[i]
+                       }
+                       h.code[i] = code
+                       code++
+               }
+
+               // Derive minCode, maxCode, and valIndex.
+               k = 0
+               index := 0
+               for i := 0; i < maxCodeLength; i++ {
+                       if h.l[i] == 0 {
+                               h.minCode[i] = -1
+                               h.maxCode[i] = -1
+                               h.valIndex[i] = -1
+                       } else {
+                               h.minCode[i] = k
+                               h.maxCode[i] = k + h.l[i] - 1
+                               h.valIndex[i] = index
+                               k += h.l[i]
+                               index += h.l[i]
+                       }
+                       k <<= 1
+               }
+       }
+       return nil
+}
+
+// Returns the next Huffman-coded value from the bit stream, decoded according to h.
+// TODO(nigeltao): This decoding algorithm is simple, but slow. A lookahead table, instead of always
+// peeling off only 1 bit at at time, ought to be faster.
+func (d *decoder) decodeHuffman(h *huffman) (uint8, os.Error) {
+       if h.length == 0 {
+               return 0, FormatError("uninitialized Huffman table")
+       }
+       for i, code := 0, 0; i < maxCodeLength; i++ {
+               err := d.ensureNBits(1)
+               if err != nil {
+                       return 0, err
+               }
+               if d.b.a&d.b.m != 0 {
+                       code |= 1
+               }
+               d.b.n--
+               d.b.m >>= 1
+               if code <= h.maxCode[i] {
+                       return h.val[h.valIndex[i]+code-h.minCode[i]], nil
+               }
+               code <<= 1
+       }
+       return 0, FormatError("bad Huffman code")
+}
diff --git a/libgo/go/image/jpeg/idct.go b/libgo/go/image/jpeg/idct.go
new file mode 100644 (file)
index 0000000..5189931
--- /dev/null
@@ -0,0 +1,190 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a Go translation of idct.c from
+//
+// http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_IEC_13818-4_2004_Conformance_Testing/Video/verifier/mpeg2decode_960109.tar.gz
+//
+// which carries the following notice:
+
+/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */
+
+/*
+ * Disclaimer of Warranty
+ *
+ * These software programs are available to the user without any license fee or
+ * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
+ * any and all warranties, whether express, implied, or statuary, including any
+ * implied warranties or merchantability or of fitness for a particular
+ * purpose.  In no event shall the copyright-holder be liable for any
+ * incidental, punitive, or consequential damages of any kind whatsoever
+ * arising from the use of these programs.
+ *
+ * This disclaimer of warranty extends to the user of these programs and user's
+ * customers, employees, agents, transferees, successors, and assigns.
+ *
+ * The MPEG Software Simulation Group does not represent or warrant that the
+ * programs furnished hereunder are free of infringement of any third-party
+ * patents.
+ *
+ * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
+ * are subject to royalty fees to patent holders.  Many of these patents are
+ * general enough such that they are unavoidable regardless of implementation
+ * design.
+ *
+ */
+
+package jpeg
+
+const (
+       w1 = 2841 // 2048*sqrt(2)*cos(1*pi/16)
+       w2 = 2676 // 2048*sqrt(2)*cos(2*pi/16)
+       w3 = 2408 // 2048*sqrt(2)*cos(3*pi/16)
+       w5 = 1609 // 2048*sqrt(2)*cos(5*pi/16)
+       w6 = 1108 // 2048*sqrt(2)*cos(6*pi/16)
+       w7 = 565  // 2048*sqrt(2)*cos(7*pi/16)
+
+       w1pw7 = w1 + w7
+       w1mw7 = w1 - w7
+       w2pw6 = w2 + w6
+       w2mw6 = w2 - w6
+       w3pw5 = w3 + w5
+       w3mw5 = w3 - w5
+
+       r2 = 181 // 256/sqrt(2)
+)
+
+// 2-D Inverse Discrete Cosine Transformation, followed by a +128 level shift.
+//
+// The input coefficients should already have been multiplied by the appropriate quantization table.
+// We use fixed-point computation, with the number of bits for the fractional component varying over the
+// intermediate stages. The final values are expected to range within [0, 255], after a +128 level shift.
+//
+// For more on the actual algorithm, see Z. Wang, "Fast algorithms for the discrete W transform and
+// for the discrete Fourier transform", IEEE Trans. on ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984.
+func idct(b *[blockSize]int) {
+       // Horizontal 1-D IDCT.
+       for y := 0; y < 8; y++ {
+               // If all the AC components are zero, then the IDCT is trivial.
+               if b[y*8+1] == 0 && b[y*8+2] == 0 && b[y*8+3] == 0 &&
+                       b[y*8+4] == 0 && b[y*8+5] == 0 && b[y*8+6] == 0 && b[y*8+7] == 0 {
+                       dc := b[y*8+0] << 3
+                       b[y*8+0] = dc
+                       b[y*8+1] = dc
+                       b[y*8+2] = dc
+                       b[y*8+3] = dc
+                       b[y*8+4] = dc
+                       b[y*8+5] = dc
+                       b[y*8+6] = dc
+                       b[y*8+7] = dc
+                       continue
+               }
+
+               // Prescale.
+               x0 := (b[y*8+0] << 11) + 128
+               x1 := b[y*8+4] << 11
+               x2 := b[y*8+6]
+               x3 := b[y*8+2]
+               x4 := b[y*8+1]
+               x5 := b[y*8+7]
+               x6 := b[y*8+5]
+               x7 := b[y*8+3]
+
+               // Stage 1.
+               x8 := w7 * (x4 + x5)
+               x4 = x8 + w1mw7*x4
+               x5 = x8 - w1pw7*x5
+               x8 = w3 * (x6 + x7)
+               x6 = x8 - w3mw5*x6
+               x7 = x8 - w3pw5*x7
+
+               // Stage 2.
+               x8 = x0 + x1
+               x0 -= x1
+               x1 = w6 * (x3 + x2)
+               x2 = x1 - w2pw6*x2
+               x3 = x1 + w2mw6*x3
+               x1 = x4 + x6
+               x4 -= x6
+               x6 = x5 + x7
+               x5 -= x7
+
+               // Stage 3.
+               x7 = x8 + x3
+               x8 -= x3
+               x3 = x0 + x2
+               x0 -= x2
+               x2 = (r2*(x4+x5) + 128) >> 8
+               x4 = (r2*(x4-x5) + 128) >> 8
+
+               // Stage 4.
+               b[8*y+0] = (x7 + x1) >> 8
+               b[8*y+1] = (x3 + x2) >> 8
+               b[8*y+2] = (x0 + x4) >> 8
+               b[8*y+3] = (x8 + x6) >> 8
+               b[8*y+4] = (x8 - x6) >> 8
+               b[8*y+5] = (x0 - x4) >> 8
+               b[8*y+6] = (x3 - x2) >> 8
+               b[8*y+7] = (x7 - x1) >> 8
+       }
+
+       // Vertical 1-D IDCT.
+       for x := 0; x < 8; x++ {
+               // Similar to the horizontal 1-D IDCT case, if all the AC components are zero, then the IDCT is trivial.
+               // However, after performing the horizontal 1-D IDCT, there are typically non-zero AC components, so
+               // we do not bother to check for the all-zero case.
+
+               // Prescale.
+               y0 := (b[8*0+x] << 8) + 8192
+               y1 := b[8*4+x] << 8
+               y2 := b[8*6+x]
+               y3 := b[8*2+x]
+               y4 := b[8*1+x]
+               y5 := b[8*7+x]
+               y6 := b[8*5+x]
+               y7 := b[8*3+x]
+
+               // Stage 1.
+               y8 := w7*(y4+y5) + 4
+               y4 = (y8 + w1mw7*y4) >> 3
+               y5 = (y8 - w1pw7*y5) >> 3
+               y8 = w3*(y6+y7) + 4
+               y6 = (y8 - w3mw5*y6) >> 3
+               y7 = (y8 - w3pw5*y7) >> 3
+
+               // Stage 2.
+               y8 = y0 + y1
+               y0 -= y1
+               y1 = w6*(y3+y2) + 4
+               y2 = (y1 - w2pw6*y2) >> 3
+               y3 = (y1 + w2mw6*y3) >> 3
+               y1 = y4 + y6
+               y4 -= y6
+               y6 = y5 + y7
+               y5 -= y7
+
+               // Stage 3.
+               y7 = y8 + y3
+               y8 -= y3
+               y3 = y0 + y2
+               y0 -= y2
+               y2 = (r2*(y4+y5) + 128) >> 8
+               y4 = (r2*(y4-y5) + 128) >> 8
+
+               // Stage 4.
+               b[8*0+x] = (y7 + y1) >> 14
+               b[8*1+x] = (y3 + y2) >> 14
+               b[8*2+x] = (y0 + y4) >> 14
+               b[8*3+x] = (y8 + y6) >> 14
+               b[8*4+x] = (y8 - y6) >> 14
+               b[8*5+x] = (y0 - y4) >> 14
+               b[8*6+x] = (y3 - y2) >> 14
+               b[8*7+x] = (y7 - y1) >> 14
+       }
+
+       // Level shift.
+       for i := range *b {
+               b[i] += 128
+       }
+}
diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go
new file mode 100644 (file)
index 0000000..fb9cb11
--- /dev/null
@@ -0,0 +1,455 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The jpeg package implements a decoder for JPEG images, as defined in ITU-T T.81.
+package jpeg
+
+// See http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+
+import (
+       "bufio"
+       "image"
+       "io"
+       "os"
+)
+
+// A FormatError reports that the input is not a valid JPEG.
+type FormatError string
+
+func (e FormatError) String() string { return "invalid JPEG format: " + string(e) }
+
+// An UnsupportedError reports that the input uses a valid but unimplemented JPEG feature.
+type UnsupportedError string
+
+func (e UnsupportedError) String() string { return "unsupported JPEG feature: " + string(e) }
+
+// Component specification, specified in section B.2.2.
+type component struct {
+       c  uint8 // Component identifier.
+       h  uint8 // Horizontal sampling factor.
+       v  uint8 // Vertical sampling factor.
+       tq uint8 // Quantization table destination selector.
+}
+
+const (
+       blockSize = 64 // A DCT block is 8x8.
+
+       dcTableClass = 0
+       acTableClass = 1
+       maxTc        = 1
+       maxTh        = 3
+       maxTq        = 3
+
+       // We only support 4:4:4, 4:2:2 and 4:2:0 downsampling, and assume that the components are Y, Cb, Cr.
+       nComponent = 3
+       maxH       = 2
+       maxV       = 2
+)
+
+const (
+       soiMarker   = 0xd8 // Start Of Image.
+       eoiMarker   = 0xd9 // End Of Image.
+       sof0Marker  = 0xc0 // Start Of Frame (Baseline).
+       sof2Marker  = 0xc2 // Start Of Frame (Progressive).
+       dhtMarker   = 0xc4 // Define Huffman Table.
+       dqtMarker   = 0xdb // Define Quantization Table.
+       sosMarker   = 0xda // Start Of Scan.
+       driMarker   = 0xdd // Define Restart Interval.
+       rst0Marker  = 0xd0 // ReSTart (0).
+       rst7Marker  = 0xd7 // ReSTart (7).
+       app0Marker  = 0xe0 // APPlication specific (0).
+       app15Marker = 0xef // APPlication specific (15).
+       comMarker   = 0xfe // COMment.
+)
+
+// Maps from the zig-zag ordering to the natural ordering.
+var unzig = [blockSize]int{
+       0, 1, 8, 16, 9, 2, 3, 10,
+       17, 24, 32, 25, 18, 11, 4, 5,
+       12, 19, 26, 33, 40, 48, 41, 34,
+       27, 20, 13, 6, 7, 14, 21, 28,
+       35, 42, 49, 56, 57, 50, 43, 36,
+       29, 22, 15, 23, 30, 37, 44, 51,
+       58, 59, 52, 45, 38, 31, 39, 46,
+       53, 60, 61, 54, 47, 55, 62, 63,
+}
+
+// If the passed in io.Reader does not also have ReadByte, then Decode will introduce its own buffering.
+type Reader interface {
+       io.Reader
+       ReadByte() (c byte, err os.Error)
+}
+
+type decoder struct {
+       r             Reader
+       width, height int
+       image         *image.RGBA
+       ri            int // Restart Interval.
+       comps         [nComponent]component
+       huff          [maxTc + 1][maxTh + 1]huffman
+       quant         [maxTq + 1][blockSize]int
+       b             bits
+       blocks        [nComponent][maxH * maxV][blockSize]int
+       tmp           [1024]byte
+}
+
+// Reads and ignores the next n bytes.
+func (d *decoder) ignore(n int) os.Error {
+       for n > 0 {
+               m := len(d.tmp)
+               if m > n {
+                       m = n
+               }
+               _, err := io.ReadFull(d.r, d.tmp[0:m])
+               if err != nil {
+                       return err
+               }
+               n -= m
+       }
+       return nil
+}
+
+// Specified in section B.2.2.
+func (d *decoder) processSOF(n int) os.Error {
+       if n != 6+3*nComponent {
+               return UnsupportedError("SOF has wrong length")
+       }
+       _, err := io.ReadFull(d.r, d.tmp[0:6+3*nComponent])
+       if err != nil {
+               return err
+       }
+       // We only support 8-bit precision.
+       if d.tmp[0] != 8 {
+               return UnsupportedError("precision")
+       }
+       d.height = int(d.tmp[1])<<8 + int(d.tmp[2])
+       d.width = int(d.tmp[3])<<8 + int(d.tmp[4])
+       if d.tmp[5] != nComponent {
+               return UnsupportedError("SOF has wrong number of image components")
+       }
+       for i := 0; i < nComponent; i++ {
+               hv := d.tmp[7+3*i]
+               d.comps[i].c = d.tmp[6+3*i]
+               d.comps[i].h = hv >> 4
+               d.comps[i].v = hv & 0x0f
+               d.comps[i].tq = d.tmp[8+3*i]
+               // We only support YCbCr images, and 4:4:4, 4:2:2 or 4:2:0 chroma downsampling ratios. This implies that
+               // the (h, v) values for the Y component are either (1, 1), (2, 1) or (2, 2), and the
+               // (h, v) values for the Cr and Cb components must be (1, 1).
+               if i == 0 {
+                       if hv != 0x11 && hv != 0x21 && hv != 0x22 {
+                               return UnsupportedError("luma downsample ratio")
+                       }
+               } else {
+                       if hv != 0x11 {
+                               return UnsupportedError("chroma downsample ratio")
+                       }
+               }
+       }
+       return nil
+}
+
+// Specified in section B.2.4.1.
+func (d *decoder) processDQT(n int) os.Error {
+       const qtLength = 1 + blockSize
+       for ; n >= qtLength; n -= qtLength {
+               _, err := io.ReadFull(d.r, d.tmp[0:qtLength])
+               if err != nil {
+                       return err
+               }
+               pq := d.tmp[0] >> 4
+               if pq != 0 {
+                       return UnsupportedError("bad Pq value")
+               }
+               tq := d.tmp[0] & 0x0f
+               if tq > maxTq {
+                       return FormatError("bad Tq value")
+               }
+               for i := range d.quant[tq] {
+                       d.quant[tq][i] = int(d.tmp[i+1])
+               }
+       }
+       if n != 0 {
+               return FormatError("DQT has wrong length")
+       }
+       return nil
+}
+
+// Set the Pixel (px, py)'s RGB value, based on its YCbCr value.
+func (d *decoder) calcPixel(px, py, lumaBlock, lumaIndex, chromaIndex int) {
+       y, cb, cr := d.blocks[0][lumaBlock][lumaIndex], d.blocks[1][0][chromaIndex], d.blocks[2][0][chromaIndex]
+       // The JFIF specification (http://www.w3.org/Graphics/JPEG/jfif3.pdf, page 3) gives the formula
+       // for translating YCbCr to RGB as:
+       //   R = Y + 1.402 (Cr-128)
+       //   G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
+       //   B = Y + 1.772 (Cb-128)
+       yPlusHalf := 100000*y + 50000
+       cb -= 128
+       cr -= 128
+       r := (yPlusHalf + 140200*cr) / 100000
+       g := (yPlusHalf - 34414*cb - 71414*cr) / 100000
+       b := (yPlusHalf + 177200*cb) / 100000
+       if r < 0 {
+               r = 0
+       } else if r > 255 {
+               r = 255
+       }
+       if g < 0 {
+               g = 0
+       } else if g > 255 {
+               g = 255
+       }
+       if b < 0 {
+               b = 0
+       } else if b > 255 {
+               b = 255
+       }
+       d.image.Pix[py*d.image.Stride+px] = image.RGBAColor{uint8(r), uint8(g), uint8(b), 0xff}
+}
+
+// Convert the MCU from YCbCr to RGB.
+func (d *decoder) convertMCU(mx, my, h0, v0 int) {
+       lumaBlock := 0
+       for v := 0; v < v0; v++ {
+               for h := 0; h < h0; h++ {
+                       chromaBase := 8*4*v + 4*h
+                       py := 8 * (v0*my + v)
+                       for y := 0; y < 8 && py < d.height; y++ {
+                               px := 8 * (h0*mx + h)
+                               lumaIndex := 8 * y
+                               chromaIndex := chromaBase + 8*(y/v0)
+                               for x := 0; x < 8 && px < d.width; x++ {
+                                       d.calcPixel(px, py, lumaBlock, lumaIndex, chromaIndex)
+                                       if h0 == 1 {
+                                               chromaIndex += 1
+                                       } else {
+                                               chromaIndex += x % 2
+                                       }
+                                       lumaIndex++
+                                       px++
+                               }
+                               py++
+                       }
+                       lumaBlock++
+               }
+       }
+}
+
+// Specified in section B.2.3.
+func (d *decoder) processSOS(n int) os.Error {
+       if d.image == nil {
+               d.image = image.NewRGBA(d.width, d.height)
+       }
+       if n != 4+2*nComponent {
+               return UnsupportedError("SOS has wrong length")
+       }
+       _, err := io.ReadFull(d.r, d.tmp[0:4+2*nComponent])
+       if err != nil {
+               return err
+       }
+       if d.tmp[0] != nComponent {
+               return UnsupportedError("SOS has wrong number of image components")
+       }
+       var scanComps [nComponent]struct {
+               td uint8 // DC table selector.
+               ta uint8 // AC table selector.
+       }
+       h0, v0 := int(d.comps[0].h), int(d.comps[0].v) // The h and v values from the Y components.
+       for i := 0; i < nComponent; i++ {
+               cs := d.tmp[1+2*i] // Component selector.
+               if cs != d.comps[i].c {
+                       return UnsupportedError("scan components out of order")
+               }
+               scanComps[i].td = d.tmp[2+2*i] >> 4
+               scanComps[i].ta = d.tmp[2+2*i] & 0x0f
+       }
+       // mxx and myy are the number of MCUs (Minimum Coded Units) in the image.
+       mxx := (d.width + 8*int(h0) - 1) / (8 * int(h0))
+       myy := (d.height + 8*int(v0) - 1) / (8 * int(v0))
+
+       mcu, expectedRST := 0, uint8(rst0Marker)
+       var allZeroes [blockSize]int
+       var dc [nComponent]int
+       for my := 0; my < myy; my++ {
+               for mx := 0; mx < mxx; mx++ {
+                       for i := 0; i < nComponent; i++ {
+                               qt := &d.quant[d.comps[i].tq]
+                               for j := 0; j < int(d.comps[i].h*d.comps[i].v); j++ {
+                                       d.blocks[i][j] = allZeroes
+
+                                       // Decode the DC coefficient, as specified in section F.2.2.1.
+                                       value, err := d.decodeHuffman(&d.huff[dcTableClass][scanComps[i].td])
+                                       if err != nil {
+                                               return err
+                                       }
+                                       if value > 16 {
+                                               return UnsupportedError("excessive DC component")
+                                       }
+                                       dcDelta, err := d.receiveExtend(value)
+                                       if err != nil {
+                                               return err
+                                       }
+                                       dc[i] += dcDelta
+                                       d.blocks[i][j][0] = dc[i] * qt[0]
+
+                                       // Decode the AC coefficients, as specified in section F.2.2.2.
+                                       for k := 1; k < blockSize; k++ {
+                                               value, err := d.decodeHuffman(&d.huff[acTableClass][scanComps[i].ta])
+                                               if err != nil {
+                                                       return err
+                                               }
+                                               v0 := value >> 4
+                                               v1 := value & 0x0f
+                                               if v1 != 0 {
+                                                       k += int(v0)
+                                                       if k > blockSize {
+                                                               return FormatError("bad DCT index")
+                                                       }
+                                                       ac, err := d.receiveExtend(v1)
+                                                       if err != nil {
+                                                               return err
+                                                       }
+                                                       d.blocks[i][j][unzig[k]] = ac * qt[k]
+                                               } else {
+                                                       if v0 != 0x0f {
+                                                               break
+                                                       }
+                                                       k += 0x0f
+                                               }
+                                       }
+
+                                       idct(&d.blocks[i][j])
+                               } // for j
+                       } // for i
+                       d.convertMCU(mx, my, int(d.comps[0].h), int(d.comps[0].v))
+                       mcu++
+                       if d.ri > 0 && mcu%d.ri == 0 && mcu < mxx*myy {
+                               // A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
+                               // but this one assumes well-formed input, and hence the restart marker follows immediately.
+                               _, err := io.ReadFull(d.r, d.tmp[0:2])
+                               if err != nil {
+                                       return err
+                               }
+                               if d.tmp[0] != 0xff || d.tmp[1] != expectedRST {
+                                       return FormatError("bad RST marker")
+                               }
+                               expectedRST++
+                               if expectedRST == rst7Marker+1 {
+                                       expectedRST = rst0Marker
+                               }
+                               // Reset the Huffman decoder.
+                               d.b = bits{}
+                               // Reset the DC components, as per section F.2.1.3.1.
+                               for i := 0; i < nComponent; i++ {
+                                       dc[i] = 0
+                               }
+                       }
+               } // for mx
+       } // for my
+
+       return nil
+}
+
+// Specified in section B.2.4.4.
+func (d *decoder) processDRI(n int) os.Error {
+       if n != 2 {
+               return FormatError("DRI has wrong length")
+       }
+       _, err := io.ReadFull(d.r, d.tmp[0:2])
+       if err != nil {
+               return err
+       }
+       d.ri = int(d.tmp[0])<<8 + int(d.tmp[1])
+       return nil
+}
+
+// decode reads a JPEG image from r and returns it as an image.Image.
+func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, os.Error) {
+       if rr, ok := r.(Reader); ok {
+               d.r = rr
+       } else {
+               d.r = bufio.NewReader(r)
+       }
+
+       // Check for the Start Of Image marker.
+       _, err := io.ReadFull(d.r, d.tmp[0:2])
+       if err != nil {
+               return nil, err
+       }
+       if d.tmp[0] != 0xff || d.tmp[1] != soiMarker {
+               return nil, FormatError("missing SOI marker")
+       }
+
+       // Process the remaining segments until the End Of Image marker.
+       for {
+               _, err := io.ReadFull(d.r, d.tmp[0:2])
+               if err != nil {
+                       return nil, err
+               }
+               if d.tmp[0] != 0xff {
+                       return nil, FormatError("missing 0xff marker start")
+               }
+               marker := d.tmp[1]
+               if marker == eoiMarker { // End Of Image.
+                       break
+               }
+
+               // Read the 16-bit length of the segment. The value includes the 2 bytes for the
+               // length itself, so we subtract 2 to get the number of remaining bytes.
+               _, err = io.ReadFull(d.r, d.tmp[0:2])
+               if err != nil {
+                       return nil, err
+               }
+               n := int(d.tmp[0])<<8 + int(d.tmp[1]) - 2
+               if n < 0 {
+                       return nil, FormatError("short segment length")
+               }
+
+               switch {
+               case marker == sof0Marker: // Start Of Frame (Baseline).
+                       err = d.processSOF(n)
+                       if configOnly {
+                               return nil, err
+                       }
+               case marker == sof2Marker: // Start Of Frame (Progressive).
+                       err = UnsupportedError("progressive mode")
+               case marker == dhtMarker: // Define Huffman Table.
+                       err = d.processDHT(n)
+               case marker == dqtMarker: // Define Quantization Table.
+                       err = d.processDQT(n)
+               case marker == sosMarker: // Start Of Scan.
+                       err = d.processSOS(n)
+               case marker == driMarker: // Define Restart Interval.
+                       err = d.processDRI(n)
+               case marker >= app0Marker && marker <= app15Marker || marker == comMarker: // APPlication specific, or COMment.
+                       err = d.ignore(n)
+               default:
+                       err = UnsupportedError("unknown marker")
+               }
+               if err != nil {
+                       return nil, err
+               }
+       }
+       return d.image, nil
+}
+
+// Decode reads a JPEG image from r and returns it as an image.Image.
+func Decode(r io.Reader) (image.Image, os.Error) {
+       var d decoder
+       return d.decode(r, false)
+}
+
+// DecodeConfig returns the color model and dimensions of a JPEG image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+       var d decoder
+       if _, err := d.decode(r, true); err != nil {
+               return image.Config{}, err
+       }
+       return image.Config{image.RGBAColorModel, d.width, d.height}, nil
+}
+
+func init() {
+       image.RegisterFormat("jpeg", "\xff\xd8", Decode, DecodeConfig)
+}
diff --git a/libgo/go/image/names.go b/libgo/go/image/names.go
new file mode 100644 (file)
index 0000000..c309684
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+var (
+       // Black is an opaque black ColorImage.
+       Black = NewColorImage(Gray16Color{0})
+       // White is an opaque white ColorImage.
+       White = NewColorImage(Gray16Color{0xffff})
+       // Transparent is a fully transparent ColorImage.
+       Transparent = NewColorImage(Alpha16Color{0})
+       // Opaque is a fully opaque ColorImage.
+       Opaque = NewColorImage(Alpha16Color{0xffff})
+)
+
+// A ColorImage is an infinite-sized Image of uniform Color.
+// It implements both the Color and Image interfaces.
+type ColorImage struct {
+       C Color
+}
+
+func (c *ColorImage) RGBA() (r, g, b, a uint32) {
+       return c.C.RGBA()
+}
+
+func (c *ColorImage) ColorModel() ColorModel {
+       return ColorModelFunc(func(Color) Color { return c.C })
+}
+
+func (c *ColorImage) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
+
+func (c *ColorImage) At(x, y int) Color { return c.C }
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (c *ColorImage) Opaque() bool {
+       _, _, _, a := c.C.RGBA()
+       return a == 0xffff
+}
+
+func NewColorImage(c Color) *ColorImage {
+       return &ColorImage{c}
+}
+
+// A Tiled is an infinite-sized Image that repeats another Image in both
+// directions. Tiled{i, p}.At(x, y) will equal i.At(x+p.X, y+p.Y) for all
+// points {x+p.X, y+p.Y} within i's Bounds.
+type Tiled struct {
+       I      Image
+       Offset Point
+}
+
+func (t *Tiled) ColorModel() ColorModel {
+       return t.I.ColorModel()
+}
+
+func (t *Tiled) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
+
+func (t *Tiled) At(x, y int) Color {
+       p := Point{x, y}.Add(t.Offset).Mod(t.I.Bounds())
+       return t.I.At(p.X, p.Y)
+}
+
+func NewTiled(i Image, offset Point) *Tiled {
+       return &Tiled{i, offset}
+}
diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go
new file mode 100644 (file)
index 0000000..e2d679b
--- /dev/null
@@ -0,0 +1,588 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The png package implements a PNG image decoder and encoder.
+//
+// The PNG specification is at http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html
+package png
+
+import (
+       "compress/zlib"
+       "fmt"
+       "hash"
+       "hash/crc32"
+       "image"
+       "io"
+       "os"
+)
+
+// Color type, as per the PNG spec.
+const (
+       ctGrayscale      = 0
+       ctTrueColor      = 2
+       ctPaletted       = 3
+       ctGrayscaleAlpha = 4
+       ctTrueColorAlpha = 6
+)
+
+// A cb is a combination of color type and bit depth.
+const (
+       cbInvalid = iota
+       cbG8
+       cbTC8
+       cbP8
+       cbTCA8
+       cbG16
+       cbTC16
+       cbTCA16
+)
+
+// Filter type, as per the PNG spec.
+const (
+       ftNone    = 0
+       ftSub     = 1
+       ftUp      = 2
+       ftAverage = 3
+       ftPaeth   = 4
+       nFilter   = 5
+)
+
+// Decoding stage.
+// The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND
+// chunks must appear in that order. There may be multiple IDAT chunks, and
+// IDAT chunks must be sequential (i.e. they may not have any other chunks
+// between them).
+const (
+       dsStart = iota
+       dsSeenIHDR
+       dsSeenPLTE
+       dsSeenIDAT
+       dsSeenIEND
+)
+
+const pngHeader = "\x89PNG\r\n\x1a\n"
+
+type imgOrErr struct {
+       img image.Image
+       err os.Error
+}
+
+type decoder struct {
+       width, height int
+       palette       image.PalettedColorModel
+       cb            int
+       stage         int
+       idatWriter    io.WriteCloser
+       idatDone      chan imgOrErr
+       tmp           [3 * 256]byte
+}
+
+// A FormatError reports that the input is not a valid PNG.
+type FormatError string
+
+func (e FormatError) String() string { return "png: invalid format: " + string(e) }
+
+var chunkOrderError = FormatError("chunk out of order")
+
+// An IDATDecodingError wraps an inner error (such as a ZLIB decoding error) encountered while processing an IDAT chunk.
+type IDATDecodingError struct {
+       Err os.Error
+}
+
+func (e IDATDecodingError) String() string { return "png: IDAT decoding error: " + e.Err.String() }
+
+// An UnsupportedError reports that the input uses a valid but unimplemented PNG feature.
+type UnsupportedError string
+
+func (e UnsupportedError) String() string { return "png: unsupported feature: " + string(e) }
+
+// Big-endian.
+func parseUint32(b []uint8) uint32 {
+       return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
+}
+
+func abs(x int) int {
+       if x < 0 {
+               return -x
+       }
+       return x
+}
+
+func min(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+       if length != 13 {
+               return FormatError("bad IHDR length")
+       }
+       _, err := io.ReadFull(r, d.tmp[0:13])
+       if err != nil {
+               return err
+       }
+       crc.Write(d.tmp[0:13])
+       if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
+               return UnsupportedError("compression, filter or interlace method")
+       }
+       w := int32(parseUint32(d.tmp[0:4]))
+       h := int32(parseUint32(d.tmp[4:8]))
+       if w < 0 || h < 0 {
+               return FormatError("negative dimension")
+       }
+       nPixels := int64(w) * int64(h)
+       if nPixels != int64(int(nPixels)) {
+               return UnsupportedError("dimension overflow")
+       }
+       d.cb = cbInvalid
+       switch d.tmp[8] {
+       case 8:
+               switch d.tmp[9] {
+               case ctGrayscale:
+                       d.cb = cbG8
+               case ctTrueColor:
+                       d.cb = cbTC8
+               case ctPaletted:
+                       d.cb = cbP8
+               case ctTrueColorAlpha:
+                       d.cb = cbTCA8
+               }
+       case 16:
+               switch d.tmp[9] {
+               case ctGrayscale:
+                       d.cb = cbG16
+               case ctTrueColor:
+                       d.cb = cbTC16
+               case ctTrueColorAlpha:
+                       d.cb = cbTCA16
+               }
+       }
+       if d.cb == cbInvalid {
+               return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d", d.tmp[8], d.tmp[9]))
+       }
+       d.width, d.height = int(w), int(h)
+       return nil
+}
+
+func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+       np := int(length / 3) // The number of palette entries.
+       if length%3 != 0 || np <= 0 || np > 256 {
+               return FormatError("bad PLTE length")
+       }
+       n, err := io.ReadFull(r, d.tmp[0:3*np])
+       if err != nil {
+               return err
+       }
+       crc.Write(d.tmp[0:n])
+       switch d.cb {
+       case cbP8:
+               d.palette = image.PalettedColorModel(make([]image.Color, np))
+               for i := 0; i < np; i++ {
+                       d.palette[i] = image.RGBAColor{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
+               }
+       case cbTC8, cbTCA8, cbTC16, cbTCA16:
+               // As per the PNG spec, a PLTE chunk is optional (and for practical purposes,
+               // ignorable) for the ctTrueColor and ctTrueColorAlpha color types (section 4.1.2).
+       default:
+               return FormatError("PLTE, color type mismatch")
+       }
+       return nil
+}
+
+func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+       if length > 256 {
+               return FormatError("bad tRNS length")
+       }
+       n, err := io.ReadFull(r, d.tmp[0:length])
+       if err != nil {
+               return err
+       }
+       crc.Write(d.tmp[0:n])
+       switch d.cb {
+       case cbG8, cbG16:
+               return UnsupportedError("grayscale transparency")
+       case cbTC8, cbTC16:
+               return UnsupportedError("truecolor transparency")
+       case cbP8:
+               if n > len(d.palette) {
+                       return FormatError("bad tRNS length")
+               }
+               for i := 0; i < n; i++ {
+                       rgba := d.palette[i].(image.RGBAColor)
+                       d.palette[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d.tmp[i]}
+               }
+       case cbTCA8, cbTCA16:
+               return FormatError("tRNS, color type mismatch")
+       }
+       return nil
+}
+
+// The Paeth filter function, as per the PNG specification.
+func paeth(a, b, c uint8) uint8 {
+       p := int(a) + int(b) - int(c)
+       pa := abs(p - int(a))
+       pb := abs(p - int(b))
+       pc := abs(p - int(c))
+       if pa <= pb && pa <= pc {
+               return a
+       } else if pb <= pc {
+               return b
+       }
+       return c
+}
+
+func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
+       r, err := zlib.NewReader(idat)
+       if err != nil {
+               return nil, err
+       }
+       defer r.Close()
+       bpp := 0 // Bytes per pixel.
+       maxPalette := uint8(0)
+       var (
+               gray     *image.Gray
+               rgba     *image.RGBA
+               paletted *image.Paletted
+               nrgba    *image.NRGBA
+               gray16   *image.Gray16
+               rgba64   *image.RGBA64
+               nrgba64  *image.NRGBA64
+               img      image.Image
+       )
+       switch d.cb {
+       case cbG8:
+               bpp = 1
+               gray = image.NewGray(d.width, d.height)
+               img = gray
+       case cbTC8:
+               bpp = 3
+               rgba = image.NewRGBA(d.width, d.height)
+               img = rgba
+       case cbP8:
+               bpp = 1
+               paletted = image.NewPaletted(d.width, d.height, d.palette)
+               img = paletted
+               maxPalette = uint8(len(d.palette) - 1)
+       case cbTCA8:
+               bpp = 4
+               nrgba = image.NewNRGBA(d.width, d.height)
+               img = nrgba
+       case cbG16:
+               bpp = 2
+               gray16 = image.NewGray16(d.width, d.height)
+               img = gray16
+       case cbTC16:
+               bpp = 6
+               rgba64 = image.NewRGBA64(d.width, d.height)
+               img = rgba64
+       case cbTCA16:
+               bpp = 8
+               nrgba64 = image.NewNRGBA64(d.width, d.height)
+               img = nrgba64
+       }
+       // cr and pr are the bytes for the current and previous row.
+       // The +1 is for the per-row filter type, which is at cr[0].
+       cr := make([]uint8, 1+bpp*d.width)
+       pr := make([]uint8, 1+bpp*d.width)
+
+       for y := 0; y < d.height; y++ {
+               // Read the decompressed bytes.
+               _, err := io.ReadFull(r, cr)
+               if err != nil {
+                       return nil, err
+               }
+
+               // Apply the filter.
+               cdat := cr[1:]
+               pdat := pr[1:]
+               switch cr[0] {
+               case ftNone:
+                       // No-op.
+               case ftSub:
+                       for i := bpp; i < len(cdat); i++ {
+                               cdat[i] += cdat[i-bpp]
+                       }
+               case ftUp:
+                       for i := 0; i < len(cdat); i++ {
+                               cdat[i] += pdat[i]
+                       }
+               case ftAverage:
+                       for i := 0; i < bpp; i++ {
+                               cdat[i] += pdat[i] / 2
+                       }
+                       for i := bpp; i < len(cdat); i++ {
+                               cdat[i] += uint8((int(cdat[i-bpp]) + int(pdat[i])) / 2)
+                       }
+               case ftPaeth:
+                       for i := 0; i < bpp; i++ {
+                               cdat[i] += paeth(0, pdat[i], 0)
+                       }
+                       for i := bpp; i < len(cdat); i++ {
+                               cdat[i] += paeth(cdat[i-bpp], pdat[i], pdat[i-bpp])
+                       }
+               default:
+                       return nil, FormatError("bad filter type")
+               }
+
+               // Convert from bytes to colors.
+               switch d.cb {
+               case cbG8:
+                       for x := 0; x < d.width; x++ {
+                               gray.Set(x, y, image.GrayColor{cdat[x]})
+                       }
+               case cbTC8:
+                       for x := 0; x < d.width; x++ {
+                               rgba.Set(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
+                       }
+               case cbP8:
+                       for x := 0; x < d.width; x++ {
+                               if cdat[x] > maxPalette {
+                                       return nil, FormatError("palette index out of range")
+                               }
+                               paletted.SetColorIndex(x, y, cdat[x])
+                       }
+               case cbTCA8:
+                       for x := 0; x < d.width; x++ {
+                               nrgba.Set(x, y, image.NRGBAColor{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
+                       }
+               case cbG16:
+                       for x := 0; x < d.width; x++ {
+                               ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
+                               gray16.Set(x, y, image.Gray16Color{ycol})
+                       }
+               case cbTC16:
+                       for x := 0; x < d.width; x++ {
+                               rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+                               gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+                               bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+                               rgba64.Set(x, y, image.RGBA64Color{rcol, gcol, bcol, 0xffff})
+                       }
+               case cbTCA16:
+                       for x := 0; x < d.width; x++ {
+                               rcol := uint16(cdat[8*x+0])<<8 | uint16(cdat[8*x+1])
+                               gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3])
+                               bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5])
+                               acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7])
+                               nrgba64.Set(x, y, image.NRGBA64Color{rcol, gcol, bcol, acol})
+                       }
+               }
+
+               // The current row for y is the previous row for y+1.
+               pr, cr = cr, pr
+       }
+       return img, nil
+}
+
+func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+       // There may be more than one IDAT chunk, but their contents must be
+       // treated as if it was one continuous stream (to the zlib decoder).
+       // We bring up an io.Pipe and write the IDAT chunks into the pipe as
+       // we see them, and decode the stream in a separate go-routine, which
+       // signals its completion (successful or not) via a channel.
+       if d.idatWriter == nil {
+               pr, pw := io.Pipe()
+               d.idatWriter = pw
+               d.idatDone = make(chan imgOrErr)
+               go func() {
+                       img, err := d.idatReader(pr)
+                       if err == os.EOF {
+                               err = FormatError("too little IDAT")
+                       }
+                       pr.CloseWithError(FormatError("too much IDAT"))
+                       d.idatDone <- imgOrErr{img, err}
+               }()
+       }
+       var buf [4096]byte
+       for length > 0 {
+               n, err1 := r.Read(buf[0:min(len(buf), int(length))])
+               // We delay checking err1. It is possible to get n bytes and an error,
+               // but if the n bytes themselves contain a FormatError, for example, we
+               // want to report that error, and not the one that made the Read stop.
+               n, err2 := d.idatWriter.Write(buf[0:n])
+               if err2 != nil {
+                       return err2
+               }
+               if err1 != nil {
+                       return err1
+               }
+               crc.Write(buf[0:n])
+               length -= uint32(n)
+       }
+       return nil
+}
+
+func (d *decoder) parseIEND(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+       if length != 0 {
+               return FormatError("bad IEND length")
+       }
+       return nil
+}
+
+func (d *decoder) parseChunk(r io.Reader) os.Error {
+       // Read the length.
+       n, err := io.ReadFull(r, d.tmp[0:4])
+       if err == os.EOF {
+               return io.ErrUnexpectedEOF
+       }
+       if err != nil {
+               return err
+       }
+       length := parseUint32(d.tmp[0:4])
+
+       // Read the chunk type.
+       n, err = io.ReadFull(r, d.tmp[0:4])
+       if err == os.EOF {
+               return io.ErrUnexpectedEOF
+       }
+       if err != nil {
+               return err
+       }
+       crc := crc32.NewIEEE()
+       crc.Write(d.tmp[0:4])
+
+       // Read the chunk data.
+       switch string(d.tmp[0:4]) {
+       case "IHDR":
+               if d.stage != dsStart {
+                       return chunkOrderError
+               }
+               d.stage = dsSeenIHDR
+               err = d.parseIHDR(r, crc, length)
+       case "PLTE":
+               if d.stage != dsSeenIHDR {
+                       return chunkOrderError
+               }
+               d.stage = dsSeenPLTE
+               err = d.parsePLTE(r, crc, length)
+       case "tRNS":
+               if d.stage != dsSeenPLTE {
+                       return chunkOrderError
+               }
+               err = d.parsetRNS(r, crc, length)
+       case "IDAT":
+               if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
+                       return chunkOrderError
+               }
+               d.stage = dsSeenIDAT
+               err = d.parseIDAT(r, crc, length)
+       case "IEND":
+               if d.stage != dsSeenIDAT {
+                       return chunkOrderError
+               }
+               d.stage = dsSeenIEND
+               err = d.parseIEND(r, crc, length)
+       default:
+               // Ignore this chunk (of a known length).
+               var ignored [4096]byte
+               for length > 0 {
+                       n, err = io.ReadFull(r, ignored[0:min(len(ignored), int(length))])
+                       if err != nil {
+                               return err
+                       }
+                       crc.Write(ignored[0:n])
+                       length -= uint32(n)
+               }
+       }
+       if err != nil {
+               return err
+       }
+
+       // Read the checksum.
+       n, err = io.ReadFull(r, d.tmp[0:4])
+       if err == os.EOF {
+               return io.ErrUnexpectedEOF
+       }
+       if err != nil {
+               return err
+       }
+       if parseUint32(d.tmp[0:4]) != crc.Sum32() {
+               return FormatError("invalid checksum")
+       }
+       return nil
+}
+
+func (d *decoder) checkHeader(r io.Reader) os.Error {
+       _, err := io.ReadFull(r, d.tmp[0:8])
+       if err != nil {
+               return err
+       }
+       if string(d.tmp[0:8]) != pngHeader {
+               return FormatError("not a PNG file")
+       }
+       return nil
+}
+
+// Decode reads a PNG image from r and returns it as an image.Image.
+// The type of Image returned depends on the PNG contents.
+func Decode(r io.Reader) (image.Image, os.Error) {
+       var d decoder
+       err := d.checkHeader(r)
+       if err != nil {
+               return nil, err
+       }
+       for d.stage != dsSeenIEND {
+               err = d.parseChunk(r)
+               if err != nil {
+                       break
+               }
+       }
+       var img image.Image
+       if d.idatWriter != nil {
+               d.idatWriter.Close()
+               ie := <-d.idatDone
+               if err == nil {
+                       img, err = ie.img, ie.err
+               }
+       }
+       if err != nil {
+               return nil, err
+       }
+       return img, nil
+}
+
+// DecodeConfig returns the color model and dimensions of a PNG image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+       var d decoder
+       err := d.checkHeader(r)
+       if err != nil {
+               return image.Config{}, err
+       }
+       for {
+               err = d.parseChunk(r)
+               if err != nil {
+                       return image.Config{}, err
+               }
+               if d.stage == dsSeenIHDR && d.cb != cbP8 {
+                       break
+               }
+               if d.stage == dsSeenPLTE && d.cb == cbP8 {
+                       break
+               }
+       }
+       var cm image.ColorModel
+       switch d.cb {
+       case cbG8:
+               cm = image.GrayColorModel
+       case cbTC8:
+               cm = image.RGBAColorModel
+       case cbP8:
+               cm = d.palette
+       case cbTCA8:
+               cm = image.NRGBAColorModel
+       case cbG16:
+               cm = image.Gray16ColorModel
+       case cbTC16:
+               cm = image.RGBA64ColorModel
+       case cbTCA16:
+               cm = image.NRGBA64ColorModel
+       }
+       return image.Config{cm, d.width, d.height}, nil
+}
+
+func init() {
+       image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)
+}
diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go
new file mode 100644 (file)
index 0000000..fefceee
--- /dev/null
@@ -0,0 +1,190 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package png
+
+import (
+       "bufio"
+       "fmt"
+       "image"
+       "io"
+       "os"
+       "testing"
+)
+
+// The go PNG library currently supports only a subset of the full PNG specification.
+// In particular, bit depths other than 8 or 16 are not supported, nor are grayscale-
+// alpha images.
+var filenames = []string{
+       //"basn0g01",   // bit depth is not 8 or 16
+       //"basn0g02",   // bit depth is not 8 or 16
+       //"basn0g04",   // bit depth is not 8 or 16
+       "basn0g08",
+       "basn0g16",
+       "basn2c08",
+       "basn2c16",
+       //"basn3p01",   // bit depth is not 8 or 16
+       //"basn3p02",   // bit depth is not 8 or 16
+       //"basn3p04",   // bit depth is not 8 or 16
+       "basn3p08",
+       //"basn4a08",   // grayscale-alpha color model
+       //"basn4a16",   // grayscale-alpha color model
+       "basn6a08",
+       "basn6a16",
+}
+
+func readPng(filename string) (image.Image, os.Error) {
+       f, err := os.Open(filename, os.O_RDONLY, 0444)
+       if err != nil {
+               return nil, err
+       }
+       defer f.Close()
+       return Decode(f)
+}
+
+// An approximation of the sng command-line tool.
+func sng(w io.WriteCloser, filename string, png image.Image) {
+       defer w.Close()
+       bounds := png.Bounds()
+       cm := png.ColorModel()
+       var bitdepth int
+       switch cm {
+       case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel, image.GrayColorModel:
+               bitdepth = 8
+       default:
+               bitdepth = 16
+       }
+       cpm, _ := cm.(image.PalettedColorModel)
+       var paletted *image.Paletted
+       if cpm != nil {
+               bitdepth = 8
+               paletted = png.(*image.Paletted)
+       }
+
+       // Write the filename and IHDR.
+       io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
+       fmt.Fprintf(w, "    width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
+       switch {
+       case cm == image.RGBAColorModel, cm == image.RGBA64ColorModel:
+               io.WriteString(w, "    using color;\n")
+       case cm == image.NRGBAColorModel, cm == image.NRGBA64ColorModel:
+               io.WriteString(w, "    using color alpha;\n")
+       case cm == image.GrayColorModel, cm == image.Gray16ColorModel:
+               io.WriteString(w, "    using grayscale;\n")
+       case cpm != nil:
+               io.WriteString(w, "    using color palette;\n")
+       default:
+               io.WriteString(w, "unknown PNG decoder color model\n")
+       }
+       io.WriteString(w, "}\n")
+
+       // We fake a gAMA output. The test files have a gAMA chunk but the go PNG parser ignores it
+       // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder").
+       io.WriteString(w, "gAMA {1.0000}\n")
+
+       // Write the PLTE (if applicable).
+       if cpm != nil {
+               io.WriteString(w, "PLTE {\n")
+               for i := 0; i < len(cpm); i++ {
+                       r, g, b, _ := cpm[i].RGBA()
+                       r >>= 8
+                       g >>= 8
+                       b >>= 8
+                       fmt.Fprintf(w, "    (%3d,%3d,%3d)     # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b)
+               }
+               io.WriteString(w, "}\n")
+       }
+
+       // Write the IMAGE.
+       io.WriteString(w, "IMAGE {\n    pixels hex\n")
+       for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+               switch {
+               case cm == image.GrayColorModel:
+                       for x := bounds.Min.X; x < bounds.Max.X; x++ {
+                               gray := png.At(x, y).(image.GrayColor)
+                               fmt.Fprintf(w, "%02x", gray.Y)
+                       }
+               case cm == image.Gray16ColorModel:
+                       for x := bounds.Min.X; x < bounds.Max.X; x++ {
+                               gray16 := png.At(x, y).(image.Gray16Color)
+                               fmt.Fprintf(w, "%04x ", gray16.Y)
+                       }
+               case cm == image.RGBAColorModel:
+                       for x := bounds.Min.X; x < bounds.Max.X; x++ {
+                               rgba := png.At(x, y).(image.RGBAColor)
+                               fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B)
+                       }
+               case cm == image.RGBA64ColorModel:
+                       for x := bounds.Min.X; x < bounds.Max.X; x++ {
+                               rgba64 := png.At(x, y).(image.RGBA64Color)
+                               fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B)
+                       }
+               case cm == image.NRGBAColorModel:
+                       for x := bounds.Min.X; x < bounds.Max.X; x++ {
+                               nrgba := png.At(x, y).(image.NRGBAColor)
+                               fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
+                       }
+               case cm == image.NRGBA64ColorModel:
+                       for x := bounds.Min.X; x < bounds.Max.X; x++ {
+                               nrgba64 := png.At(x, y).(image.NRGBA64Color)
+                               fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+                       }
+               case cpm != nil:
+                       for x := bounds.Min.X; x < bounds.Max.X; x++ {
+                               fmt.Fprintf(w, "%02x", paletted.ColorIndexAt(x, y))
+                       }
+               }
+               io.WriteString(w, "\n")
+       }
+       io.WriteString(w, "}\n")
+}
+
+func TestReader(t *testing.T) {
+       for _, fn := range filenames {
+               // Read the .png file.
+               image, err := readPng("testdata/pngsuite/" + fn + ".png")
+               if err != nil {
+                       t.Error(fn, err)
+                       continue
+               }
+               piper, pipew := io.Pipe()
+               pb := bufio.NewReader(piper)
+               go sng(pipew, fn, image)
+               defer piper.Close()
+
+               // Read the .sng file.
+               sf, err := os.Open("testdata/pngsuite/"+fn+".sng", os.O_RDONLY, 0444)
+               if err != nil {
+                       t.Error(fn, err)
+                       continue
+               }
+               defer sf.Close()
+               sb := bufio.NewReader(sf)
+               if err != nil {
+                       t.Error(fn, err)
+                       continue
+               }
+
+               // Compare the two, in SNG format, line by line.
+               for {
+                       ps, perr := pb.ReadString('\n')
+                       ss, serr := sb.ReadString('\n')
+                       if perr == os.EOF && serr == os.EOF {
+                               break
+                       }
+                       if perr != nil {
+                               t.Error(fn, perr)
+                               break
+                       }
+                       if serr != nil {
+                               t.Error(fn, serr)
+                               break
+                       }
+                       if ps != ss {
+                               t.Errorf("%s: Mismatch\n%sversus\n%s\n", fn, ps, ss)
+                               break
+                       }
+               }
+       }
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/README b/libgo/go/image/png/testdata/pngsuite/README
new file mode 100644 (file)
index 0000000..27e7c65
--- /dev/null
@@ -0,0 +1,9 @@
+The *.png and README.original files in this directory are copied from
+libpng.org, specifically contrib/pngsuite/* in libpng-1.2.40.tar.gz.
+README.original gives the following license for those files:
+
+       Permission to use, copy, and distribute these images for any purpose
+       and without fee is hereby granted.
+
+The *.sng files in this directory were generated from the *.png files
+by the sng command-line tool.
diff --git a/libgo/go/image/png/testdata/pngsuite/README.original b/libgo/go/image/png/testdata/pngsuite/README.original
new file mode 100644 (file)
index 0000000..714d12c
--- /dev/null
@@ -0,0 +1,85 @@
+
+pngsuite
+--------
+(c) Willem van Schaik, 1999
+
+Permission to use, copy, and distribute these images for any purpose and
+without fee is hereby granted.
+
+These 15 images are part of the much larger PngSuite test-set of 
+images, available for developers of PNG supporting software. The 
+complete set, available at http:/www.schaik.com/pngsuite/, contains 
+a variety of images to test interlacing, gamma settings, ancillary
+chunks, etc.
+
+The images in this directory represent the basic PNG color-types:
+grayscale (1-16 bit deep), full color (8 or 16 bit), paletted
+(1-8 bit) and grayscale or color images with alpha channel. You
+can use them to test the proper functioning of PNG software.
+
+    filename      depth type
+    ------------ ------ --------------
+    basn0g01.png  1-bit grayscale
+    basn0g02.png  2-bit grayscale
+    basn0g04.png  4-bit grayscale
+    basn0g08.png  8-bit grayscale
+    basn0g16.png 16-bit grayscale
+    basn2c08.png  8-bit truecolor
+    basn2c16.png 16-bit truecolor
+    basn3p01.png  1-bit paletted
+    basn3p02.png  2-bit paletted
+    basn3p04.png  4-bit paletted
+    basn3p08.png  8-bit paletted
+    basn4a08.png  8-bit gray with alpha
+    basn4a16.png 16-bit gray with alpha
+    basn6a08.png  8-bit RGBA
+    basn6a16.png 16-bit RGBA
+
+Here is the correct result of typing "pngtest -m *.png" in
+this directory:
+
+Testing basn0g01.png: PASS (524 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g02.png: PASS (448 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g04.png: PASS (520 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g08.png: PASS (3 zero samples)
+ Filter 1 was used 9 times
+ Filter 4 was used 23 times
+Testing basn0g16.png: PASS (1 zero samples)
+ Filter 1 was used 1 times
+ Filter 2 was used 31 times
+Testing basn2c08.png: PASS (6 zero samples)
+ Filter 1 was used 5 times
+ Filter 4 was used 27 times
+Testing basn2c16.png: PASS (592 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn3p01.png: PASS (512 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p02.png: PASS (448 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p04.png: PASS (544 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p08.png: PASS (4 zero samples)
+ Filter 0 was used 32 times
+Testing basn4a08.png: PASS (32 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn4a16.png: PASS (64 zero samples)
+ Filter 0 was used 1 times
+ Filter 1 was used 2 times
+ Filter 2 was used 1 times
+ Filter 4 was used 28 times
+Testing basn6a08.png: PASS (160 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn6a16.png: PASS (1072 zero samples)
+ Filter 1 was used 4 times
+ Filter 4 was used 28 times
+libpng passes test
+
+Willem van Schaik
+<willem@schaik.com>
+October 1999
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g01.png b/libgo/go/image/png/testdata/pngsuite/basn0g01.png
new file mode 100644 (file)
index 0000000..e31e1c7
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn0g01.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g01.sng b/libgo/go/image/png/testdata/pngsuite/basn0g01.sng
new file mode 100644 (file)
index 0000000..e712d8e
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn0g01.png
+IHDR {
+    width: 32; height: 32; bitdepth: 1;
+    using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+fffffffe
+fffffffc
+fffffff8
+fffffff0
+f3f3ffe0
+f3f3ffc0
+f3f3ff80
+f333ff00
+f333fe00
+f333fc00
+f807f800
+f807f000
+fccfe000
+fccfc000
+ffff8000
+ffff0000
+fffe0000
+fffc0000
+fff80fe0
+fff00fe0
+ffe00c30
+ffc00c30
+ff800fe0
+ff000fe0
+fe000c30
+fc000c30
+f8000fe0
+f0000fe0
+e0000000
+c0000000
+80000000
+00000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g02.png b/libgo/go/image/png/testdata/pngsuite/basn0g02.png
new file mode 100644 (file)
index 0000000..68809dd
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn0g02.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g02.sng b/libgo/go/image/png/testdata/pngsuite/basn0g02.sng
new file mode 100644 (file)
index 0000000..e7f2d7e
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn0g02.png
+IHDR {
+    width: 32; height: 32; bitdepth: 2;
+    using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+0055aaff0055aaff
+0055aaff0055aaff
+0055aaff0055aaff
+0055aaff0055aaff
+55aaff0055aaff00
+55aaff0055aaff00
+55aaff0055aaff00
+55aaff0055aaff00
+aaff0055aaff0055
+aaff0055aaff0055
+aaff0055aaff0055
+aaff0055aaff0055
+ff0055aaff0055aa
+ff0055aaff0055aa
+ff0055aaff0055aa
+ff0055aaff0055aa
+0055aaff0055aaff
+0055aaff0055aaff
+0055aaff0055aaff
+0055aaff0055aaff
+55aaff0055aaff00
+55aaff0055aaff00
+55aaff0055aaff00
+55aaff0055aaff00
+aaff0055aaff0055
+aaff0055aaff0055
+aaff0055aaff0055
+aaff0055aaff0055
+ff0055aaff0055aa
+ff0055aaff0055aa
+ff0055aaff0055aa
+ff0055aaff0055aa
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g04.png b/libgo/go/image/png/testdata/pngsuite/basn0g04.png
new file mode 100644 (file)
index 0000000..6fa089c
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn0g04.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g04.sng b/libgo/go/image/png/testdata/pngsuite/basn0g04.sng
new file mode 100644 (file)
index 0000000..396c508
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn0g04.png
+IHDR {
+    width: 32; height: 32; bitdepth: 4;
+    using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+00001111222233334444555566667777
+00001111222233334444555566667777
+00001111222233334444555566667777
+00001111222233334444555566667777
+11112222333344445555666677778888
+11112222333344445555666677778888
+11112222333344445555666677778888
+11112222333344445555666677778888
+22223333444455556666777788889999
+22223333444455556666777788889999
+22223333444455556666777788889999
+22223333444455556666777788889999
+3333444455556666777788889999aaaa
+3333444455556666777788889999aaaa
+3333444455556666777788889999aaaa
+3333444455556666777788889999aaaa
+444455556666777788889999aaaabbbb
+444455556666777788889999aaaabbbb
+444455556666777788889999aaaabbbb
+444455556666777788889999aaaabbbb
+55556666777788889999aaaabbbbcccc
+55556666777788889999aaaabbbbcccc
+55556666777788889999aaaabbbbcccc
+55556666777788889999aaaabbbbcccc
+6666777788889999aaaabbbbccccdddd
+6666777788889999aaaabbbbccccdddd
+6666777788889999aaaabbbbccccdddd
+6666777788889999aaaabbbbccccdddd
+777788889999aaaabbbbccccddddeeee
+777788889999aaaabbbbccccddddeeee
+777788889999aaaabbbbccccddddeeee
+777788889999aaaabbbbccccddddeeee
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g08.png b/libgo/go/image/png/testdata/pngsuite/basn0g08.png
new file mode 100644 (file)
index 0000000..bf522ee
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn0g08.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g08.sng b/libgo/go/image/png/testdata/pngsuite/basn0g08.sng
new file mode 100644 (file)
index 0000000..7389eb7
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn0g08.png
+IHDR {
+    width: 32; height: 32; bitdepth: 8;
+    using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
+404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f
+808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
+a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
+c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+fefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0df
+dedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bf
+bebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f
+9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f
+7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f
+5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f
+3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f
+1e1d1c1b1a191817161514131211100f0e0d0c0b0a0908070605040302010001
+02030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021
+22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041
+42434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061
+62636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081
+82838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1
+a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1
+c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1
+e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfefffefd
+fcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedd
+dcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebd
+bcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d
+9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d
+7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d
+5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d
+3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d
+1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100010203
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g16.png b/libgo/go/image/png/testdata/pngsuite/basn0g16.png
new file mode 100644 (file)
index 0000000..318ebca
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn0g16.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g16.sng b/libgo/go/image/png/testdata/pngsuite/basn0g16.sng
new file mode 100644 (file)
index 0000000..922391a
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn0g16.png
+IHDR {
+    width: 32; height: 32; bitdepth: 16;
+    using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+0000 0900 1200 1b00 2400 2d00 3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 
+0200 0b00 1400 1d00 2600 2f00 3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 
+0400 0d00 1600 1f00 2800 3100 3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 
+0600 0f00 1800 2100 2a00 3300 3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 
+0800 1100 1a00 2300 2c00 3500 3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 
+0a00 1300 1c00 2500 2e00 3700 4000 4900 5200 5b00 6400 6d00 7600 7f00 8800 9100 9a00 a300 ac00 b500 be00 c700 d000 d900 e200 eb00 f400 fd00 edff d2ff b7ff 9cff 
+0c00 1500 1e00 2700 3000 3900 4200 4b00 5400 5d00 6600 6f00 7800 8100 8a00 9300 9c00 a500 ae00 b700 c000 c900 d200 db00 e400 ed00 f600 ff00 e7ff ccff b1ff 96ff 
+0e00 1700 2000 2900 3200 3b00 4400 4d00 5600 5f00 6800 7100 7a00 8300 8c00 9500 9e00 a700 b000 b900 c200 cb00 d400 dd00 e600 ef00 f800 fcff e1ff c6ff abff 90ff 
+1000 1900 2200 2b00 3400 3d00 4600 4f00 5800 6100 6a00 7300 7c00 8500 8e00 9700 a000 a900 b200 bb00 c400 cd00 d600 df00 e800 f100 fa00 f6ff dbff c0ff a5ff 8aff 
+1200 1b00 2400 2d00 3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 9fff 84ff 
+1400 1d00 2600 2f00 3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 99ff 7eff 
+1600 1f00 2800 3100 3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 93ff 78ff 
+1800 2100 2a00 3300 3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 8dff 72ff 
+1a00 2300 2c00 3500 3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 87ff 6cff 
+1c00 2500 2e00 3700 4000 4900 5200 5b00 6400 6d00 7600 7f00 8800 9100 9a00 a300 ac00 b500 be00 c700 d000 d900 e200 eb00 f400 fd00 edff d2ff b7ff 9cff 81ff 66ff 
+1e00 2700 3000 3900 4200 4b00 5400 5d00 6600 6f00 7800 8100 8a00 9300 9c00 a500 ae00 b700 c000 c900 d200 db00 e400 ed00 f600 ff00 e7ff ccff b1ff 96ff 7bff 60ff 
+2000 2900 3200 3b00 4400 4d00 5600 5f00 6800 7100 7a00 8300 8c00 9500 9e00 a700 b000 b900 c200 cb00 d400 dd00 e600 ef00 f800 fcff e1ff c6ff abff 90ff 75ff 5aff 
+2200 2b00 3400 3d00 4600 4f00 5800 6100 6a00 7300 7c00 8500 8e00 9700 a000 a900 b200 bb00 c400 cd00 d600 df00 e800 f100 fa00 f6ff dbff c0ff a5ff 8aff 6fff 54ff 
+2400 2d00 3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 9fff 84ff 69ff 4eff 
+2600 2f00 3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 99ff 7eff 63ff 48ff 
+2800 3100 3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 93ff 78ff 5dff 42ff 
+2a00 3300 3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 8dff 72ff 57ff 3cff 
+2c00 3500 3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 87ff 6cff 51ff 36ff 
+2e00 3700 4000 4900 5200 5b00 6400 6d00 7600 7f00 8800 9100 9a00 a300 ac00 b500 be00 c700 d000 d900 e200 eb00 f400 fd00 edff d2ff b7ff 9cff 81ff 66ff 4bff 30ff 
+3000 3900 4200 4b00 5400 5d00 6600 6f00 7800 8100 8a00 9300 9c00 a500 ae00 b700 c000 c900 d200 db00 e400 ed00 f600 ff00 e7ff ccff b1ff 96ff 7bff 60ff 45ff 2aff 
+3200 3b00 4400 4d00 5600 5f00 6800 7100 7a00 8300 8c00 9500 9e00 a700 b000 b900 c200 cb00 d400 dd00 e600 ef00 f800 fcff e1ff c6ff abff 90ff 75ff 5aff 3fff 24ff 
+3400 3d00 4600 4f00 5800 6100 6a00 7300 7c00 8500 8e00 9700 a000 a900 b200 bb00 c400 cd00 d600 df00 e800 f100 fa00 f6ff dbff c0ff a5ff 8aff 6fff 54ff 39ff 1eff 
+3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 9fff 84ff 69ff 4eff 33ff 18ff 
+3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 99ff 7eff 63ff 48ff 2dff 12ff 
+3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 93ff 78ff 5dff 42ff 27ff 0cff 
+3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 8dff 72ff 57ff 3cff 21ff 06ff 
+3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 87ff 6cff 51ff 36ff 1bff 00ff 
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn2c08.png b/libgo/go/image/png/testdata/pngsuite/basn2c08.png
new file mode 100644 (file)
index 0000000..21d2f91
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn2c08.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn2c08.sng b/libgo/go/image/png/testdata/pngsuite/basn2c08.sng
new file mode 100644 (file)
index 0000000..09a6131
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn2c08.png
+IHDR {
+    width: 32; height: 32; bitdepth: 8;
+    using color;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+ffffff fffffe fffffd fffffc fffffb fffffa fffff9 fffff8 fffff7 fffff6 fffff5 fffff4 fffff3 fffff2 fffff1 fffff0 ffffef ffffee ffffed ffffec ffffeb ffffea ffffe9 ffffe8 ffffe7 ffffe6 ffffe5 ffffe4 ffffe3 ffffe2 ffffe1 ffffe0 
+ffffdf ffffde ffffdd ffffdc ffffdb ffffda ffffd9 ffffd8 ffffd7 ffffd6 ffffd5 ffffd4 ffffd3 ffffd2 ffffd1 ffffd0 ffffcf ffffce ffffcd ffffcc ffffcb ffffca ffffc9 ffffc8 ffffc7 ffffc6 ffffc5 ffffc4 ffffc3 ffffc2 ffffc1 ffffc0 
+ffffbf ffffbe ffffbd ffffbc ffffbb ffffba ffffb9 ffffb8 ffffb7 ffffb6 ffffb5 ffffb4 ffffb3 ffffb2 ffffb1 ffffb0 ffffaf ffffae ffffad ffffac ffffab ffffaa ffffa9 ffffa8 ffffa7 ffffa6 ffffa5 ffffa4 ffffa3 ffffa2 ffffa1 ffffa0 
+ffff9f ffff9e ffff9d ffff9c ffff9b ffff9a ffff99 ffff98 ffff97 ffff96 ffff95 ffff94 ffff93 ffff92 ffff91 ffff90 ffff8f ffff8e ffff8d ffff8c ffff8b ffff8a ffff89 ffff88 ffff87 ffff86 ffff85 ffff84 ffff83 ffff82 ffff81 ffff80 
+ffff7f ffff7e ffff7d ffff7c ffff7b ffff7a ffff79 ffff78 ffff77 ffff76 ffff75 ffff74 ffff73 ffff72 ffff71 ffff70 ffff6f ffff6e ffff6d ffff6c ffff6b ffff6a ffff69 ffff68 ffff67 ffff66 ffff65 ffff64 ffff63 ffff62 ffff61 ffff60 
+ffff5f ffff5e ffff5d ffff5c ffff5b ffff5a ffff59 ffff58 ffff57 ffff56 ffff55 ffff54 ffff53 ffff52 ffff51 ffff50 ffff4f ffff4e ffff4d ffff4c ffff4b ffff4a ffff49 ffff48 ffff47 ffff46 ffff45 ffff44 ffff43 ffff42 ffff41 ffff40 
+ffff3f ffff3e ffff3d ffff3c ffff3b ffff3a ffff39 ffff38 ffff37 ffff36 ffff35 ffff34 ffff33 ffff32 ffff31 ffff30 ffff2f ffff2e ffff2d ffff2c ffff2b ffff2a ffff29 ffff28 ffff27 ffff26 ffff25 ffff24 ffff23 ffff22 ffff21 ffff20 
+ffff1f ffff1e ffff1d ffff1c ffff1b ffff1a ffff19 ffff18 ffff17 ffff16 ffff15 ffff14 ffff13 ffff12 ffff11 ffff10 ffff0f ffff0e ffff0d ffff0c ffff0b ffff0a ffff09 ffff08 ffff07 ffff06 ffff05 ffff04 ffff03 ffff02 ffff01 ffff00 
+ffffff fffeff fffdff fffcff fffbff fffaff fff9ff fff8ff fff7ff fff6ff fff5ff fff4ff fff3ff fff2ff fff1ff fff0ff ffefff ffeeff ffedff ffecff ffebff ffeaff ffe9ff ffe8ff ffe7ff ffe6ff ffe5ff ffe4ff ffe3ff ffe2ff ffe1ff ffe0ff 
+ffdfff ffdeff ffddff ffdcff ffdbff ffdaff ffd9ff ffd8ff ffd7ff ffd6ff ffd5ff ffd4ff ffd3ff ffd2ff ffd1ff ffd0ff ffcfff ffceff ffcdff ffccff ffcbff ffcaff ffc9ff ffc8ff ffc7ff ffc6ff ffc5ff ffc4ff ffc3ff ffc2ff ffc1ff ffc0ff 
+ffbfff ffbeff ffbdff ffbcff ffbbff ffbaff ffb9ff ffb8ff ffb7ff ffb6ff ffb5ff ffb4ff ffb3ff ffb2ff ffb1ff ffb0ff ffafff ffaeff ffadff ffacff ffabff ffaaff ffa9ff ffa8ff ffa7ff ffa6ff ffa5ff ffa4ff ffa3ff ffa2ff ffa1ff ffa0ff 
+ff9fff ff9eff ff9dff ff9cff ff9bff ff9aff ff99ff ff98ff ff97ff ff96ff ff95ff ff94ff ff93ff ff92ff ff91ff ff90ff ff8fff ff8eff ff8dff ff8cff ff8bff ff8aff ff89ff ff88ff ff87ff ff86ff ff85ff ff84ff ff83ff ff82ff ff81ff ff80ff 
+ff7fff ff7eff ff7dff ff7cff ff7bff ff7aff ff79ff ff78ff ff77ff ff76ff ff75ff ff74ff ff73ff ff72ff ff71ff ff70ff ff6fff ff6eff ff6dff ff6cff ff6bff ff6aff ff69ff ff68ff ff67ff ff66ff ff65ff ff64ff ff63ff ff62ff ff61ff ff60ff 
+ff5fff ff5eff ff5dff ff5cff ff5bff ff5aff ff59ff ff58ff ff57ff ff56ff ff55ff ff54ff ff53ff ff52ff ff51ff ff50ff ff4fff ff4eff ff4dff ff4cff ff4bff ff4aff ff49ff ff48ff ff47ff ff46ff ff45ff ff44ff ff43ff ff42ff ff41ff ff40ff 
+ff3fff ff3eff ff3dff ff3cff ff3bff ff3aff ff39ff ff38ff ff37ff ff36ff ff35ff ff34ff ff33ff ff32ff ff31ff ff30ff ff2fff ff2eff ff2dff ff2cff ff2bff ff2aff ff29ff ff28ff ff27ff ff26ff ff25ff ff24ff ff23ff ff22ff ff21ff ff20ff 
+ff1fff ff1eff ff1dff ff1cff ff1bff ff1aff ff19ff ff18ff ff17ff ff16ff ff15ff ff14ff ff13ff ff12ff ff11ff ff10ff ff0fff ff0eff ff0dff ff0cff ff0bff ff0aff ff09ff ff08ff ff07ff ff06ff ff05ff ff04ff ff03ff ff02ff ff01ff ff00ff 
+ffffff feffff fdffff fcffff fbffff faffff f9ffff f8ffff f7ffff f6ffff f5ffff f4ffff f3ffff f2ffff f1ffff f0ffff efffff eeffff edffff ecffff ebffff eaffff e9ffff e8ffff e7ffff e6ffff e5ffff e4ffff e3ffff e2ffff e1ffff e0ffff 
+dfffff deffff ddffff dcffff dbffff daffff d9ffff d8ffff d7ffff d6ffff d5ffff d4ffff d3ffff d2ffff d1ffff d0ffff cfffff ceffff cdffff ccffff cbffff caffff c9ffff c8ffff c7ffff c6ffff c5ffff c4ffff c3ffff c2ffff c1ffff c0ffff 
+bfffff beffff bdffff bcffff bbffff baffff b9ffff b8ffff b7ffff b6ffff b5ffff b4ffff b3ffff b2ffff b1ffff b0ffff afffff aeffff adffff acffff abffff aaffff a9ffff a8ffff a7ffff a6ffff a5ffff a4ffff a3ffff a2ffff a1ffff a0ffff 
+9fffff 9effff 9dffff 9cffff 9bffff 9affff 99ffff 98ffff 97ffff 96ffff 95ffff 94ffff 93ffff 92ffff 91ffff 90ffff 8fffff 8effff 8dffff 8cffff 8bffff 8affff 89ffff 88ffff 87ffff 86ffff 85ffff 84ffff 83ffff 82ffff 81ffff 80ffff 
+7fffff 7effff 7dffff 7cffff 7bffff 7affff 79ffff 78ffff 77ffff 76ffff 75ffff 74ffff 73ffff 72ffff 71ffff 70ffff 6fffff 6effff 6dffff 6cffff 6bffff 6affff 69ffff 68ffff 67ffff 66ffff 65ffff 64ffff 63ffff 62ffff 61ffff 60ffff 
+5fffff 5effff 5dffff 5cffff 5bffff 5affff 59ffff 58ffff 57ffff 56ffff 55ffff 54ffff 53ffff 52ffff 51ffff 50ffff 4fffff 4effff 4dffff 4cffff 4bffff 4affff 49ffff 48ffff 47ffff 46ffff 45ffff 44ffff 43ffff 42ffff 41ffff 40ffff 
+3fffff 3effff 3dffff 3cffff 3bffff 3affff 39ffff 38ffff 37ffff 36ffff 35ffff 34ffff 33ffff 32ffff 31ffff 30ffff 2fffff 2effff 2dffff 2cffff 2bffff 2affff 29ffff 28ffff 27ffff 26ffff 25ffff 24ffff 23ffff 22ffff 21ffff 20ffff 
+1fffff 1effff 1dffff 1cffff 1bffff 1affff 19ffff 18ffff 17ffff 16ffff 15ffff 14ffff 13ffff 12ffff 11ffff 10ffff 0fffff 0effff 0dffff 0cffff 0bffff 0affff 09ffff 08ffff 07ffff 06ffff 05ffff 04ffff 03ffff 02ffff 01ffff 00ffff 
+ffffff fefefe fdfdfd fcfcfc fbfbfb fafafa f9f9f9 f8f8f8 f7f7f7 f6f6f6 f5f5f5 f4f4f4 f3f3f3 f2f2f2 f1f1f1 f0f0f0 efefef eeeeee ededed ececec ebebeb eaeaea e9e9e9 e8e8e8 e7e7e7 e6e6e6 e5e5e5 e4e4e4 e3e3e3 e2e2e2 e1e1e1 e0e0e0 
+dfdfdf dedede dddddd dcdcdc dbdbdb dadada d9d9d9 d8d8d8 d7d7d7 d6d6d6 d5d5d5 d4d4d4 d3d3d3 d2d2d2 d1d1d1 d0d0d0 cfcfcf cecece cdcdcd cccccc cbcbcb cacaca c9c9c9 c8c8c8 c7c7c7 c6c6c6 c5c5c5 c4c4c4 c3c3c3 c2c2c2 c1c1c1 c0c0c0 
+bfbfbf bebebe bdbdbd bcbcbc bbbbbb bababa b9b9b9 b8b8b8 b7b7b7 b6b6b6 b5b5b5 b4b4b4 b3b3b3 b2b2b2 b1b1b1 b0b0b0 afafaf aeaeae adadad acacac ababab aaaaaa a9a9a9 a8a8a8 a7a7a7 a6a6a6 a5a5a5 a4a4a4 a3a3a3 a2a2a2 a1a1a1 a0a0a0 
+9f9f9f 9e9e9e 9d9d9d 9c9c9c 9b9b9b 9a9a9a 999999 989898 979797 969696 959595 949494 939393 929292 919191 909090 8f8f8f 8e8e8e 8d8d8d 8c8c8c 8b8b8b 8a8a8a 898989 888888 878787 868686 858585 848484 838383 828282 818181 808080 
+7f7f7f 7e7e7e 7d7d7d 7c7c7c 7b7b7b 7a7a7a 797979 787878 777777 767676 757575 747474 737373 727272 717171 707070 6f6f6f 6e6e6e 6d6d6d 6c6c6c 6b6b6b 6a6a6a 696969 686868 676767 666666 656565 646464 636363 626262 616161 606060 
+5f5f5f 5e5e5e 5d5d5d 5c5c5c 5b5b5b 5a5a5a 595959 585858 575757 565656 555555 545454 535353 525252 515151 505050 4f4f4f 4e4e4e 4d4d4d 4c4c4c 4b4b4b 4a4a4a 494949 484848 474747 464646 454545 444444 434343 424242 414141 404040 
+3f3f3f 3e3e3e 3d3d3d 3c3c3c 3b3b3b 3a3a3a 393939 383838 373737 363636 353535 343434 333333 323232 313131 303030 2f2f2f 2e2e2e 2d2d2d 2c2c2c 2b2b2b 2a2a2a 292929 282828 272727 262626 252525 242424 232323 222222 212121 202020 
+1f1f1f 1e1e1e 1d1d1d 1c1c1c 1b1b1b 1a1a1a 191919 181818 171717 161616 151515 141414 131313 121212 111111 101010 0f0f0f 0e0e0e 0d0d0d 0c0c0c 0b0b0b 0a0a0a 090909 080808 070707 060606 050505 040404 030303 020202 010101 000000 
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn2c16.png b/libgo/go/image/png/testdata/pngsuite/basn2c16.png
new file mode 100644 (file)
index 0000000..1bd4a4d
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn2c16.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn2c16.sng b/libgo/go/image/png/testdata/pngsuite/basn2c16.sng
new file mode 100644 (file)
index 0000000..bac7c9d
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn2c16.png
+IHDR {
+    width: 32; height: 32; bitdepth: 16;
+    using color;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+ffffffff0000 f7bdffff0000 ef7bffff0000 e739ffff0000 def7ffff0000 d6b5ffff0000 ce73ffff0000 c631ffff0000 bdefffff0000 b5adffff0000 ad6bffff0000 a529ffff0000 9ce7ffff0000 94a5ffff0000 8c63ffff0000 8421ffff0000 7bdeffff0000 739cffff0000 6b5affff0000 6318ffff0000 5ad6ffff0000 5294ffff0000 4a52ffff0000 4210ffff0000 39ceffff0000 318cffff0000 294affff0000 2108ffff0000 18c6ffff0000 1084ffff0000 0842ffff0000 0000ffff0000 
+fffff7bd0000 f7bdf7bd0000 ef7bf7bd0000 e739f7bd0000 def7f7bd0000 d6b5f7bd0000 ce73f7bd0000 c631f7bd0000 bdeff7bd0000 b5adf7bd0000 ad6bf7bd0000 a529f7bd0000 9ce7f7bd0000 94a5f7bd0000 8c63f7bd0000 8421f7bd0000 7bdef7bd0000 739cf7bd0000 6b5af7bd0000 6318f7bd0000 5ad6f7bd0000 5294f7bd0000 4a52f7bd0000 4210f7bd0000 39cef7bd0000 318cf7bd0000 294af7bd0000 2108f7bd0000 18c6f7bd0000 1084f7bd0000 0842f7bd0000 0000f7bd0842 
+ffffef7b0000 f7bdef7b0000 ef7bef7b0000 e739ef7b0000 def7ef7b0000 d6b5ef7b0000 ce73ef7b0000 c631ef7b0000 bdefef7b0000 b5adef7b0000 ad6bef7b0000 a529ef7b0000 9ce7ef7b0000 94a5ef7b0000 8c63ef7b0000 8421ef7b0000 7bdeef7b0000 739cef7b0000 6b5aef7b0000 6318ef7b0000 5ad6ef7b0000 5294ef7b0000 4a52ef7b0000 4210ef7b0000 39ceef7b0000 318cef7b0000 294aef7b0000 2108ef7b0000 18c6ef7b0000 1084ef7b0000 0842ef7b0842 0000ef7b1084 
+ffffe7390000 f7bde7390000 ef7be7390000 e739e7390000 def7e7390000 d6b5e7390000 ce73e7390000 c631e7390000 bdefe7390000 b5ade7390000 ad6be7390000 a529e7390000 9ce7e7390000 94a5e7390000 8c63e7390000 8421e7390000 7bdee7390000 739ce7390000 6b5ae7390000 6318e7390000 5ad6e7390000 5294e7390000 4a52e7390000 4210e7390000 39cee7390000 318ce7390000 294ae7390000 2108e7390000 18c6e7390000 1084e7390842 0842e7391084 0000e73918c6 
+ffffdef70000 f7bddef70000 ef7bdef70000 e739def70000 def7def70000 d6b5def70000 ce73def70000 c631def70000 bdefdef70000 b5addef70000 ad6bdef70000 a529def70000 9ce7def70000 94a5def70000 8c63def70000 8421def70000 7bdedef70000 739cdef70000 6b5adef70000 6318def70000 5ad6def70000 5294def70000 4a52def70000 4210def70000 39cedef70000 318cdef70000 294adef70000 2108def70000 18c6def70842 1084def71084 0842def718c6 0000def72108 
+ffffd6b50000 f7bdd6b50000 ef7bd6b50000 e739d6b50000 def7d6b50000 d6b5d6b50000 ce73d6b50000 c631d6b50000 bdefd6b50000 b5add6b50000 ad6bd6b50000 a529d6b50000 9ce7d6b50000 94a5d6b50000 8c63d6b50000 8421d6b50000 7bded6b50000 739cd6b50000 6b5ad6b50000 6318d6b50000 5ad6d6b50000 5294d6b50000 4a52d6b50000 4210d6b50000 39ced6b50000 318cd6b50000 294ad6b50000 2108d6b50842 18c6d6b51084 1084d6b518c6 0842d6b52108 0000d6b5294a 
+ffffce730000 f7bdce730000 ef7bce730000 e739ce730000 def7ce730000 d6b5ce730000 ce73ce730000 c631ce730000 bdefce730000 b5adce730000 ad6bce730000 a529ce730000 9ce7ce730000 94a5ce730000 8c63ce730000 8421ce730000 7bdece730000 739cce730000 6b5ace730000 6318ce730000 5ad6ce730000 5294ce730000 4a52ce730000 4210ce730000 39cece730000 318cce730000 294ace730842 2108ce731084 18c6ce7318c6 1084ce732108 0842ce73294a 0000ce73318c 
+ffffc6310000 f7bdc6310000 ef7bc6310000 e739c6310000 def7c6310000 d6b5c6310000 ce73c6310000 c631c6310000 bdefc6310000 b5adc6310000 ad6bc6310000 a529c6310000 9ce7c6310000 94a5c6310000 8c63c6310000 8421c6310000 7bdec6310000 739cc6310000 6b5ac6310000 6318c6310000 5ad6c6310000 5294c6310000 4a52c6310000 4210c6310000 39cec6310000 318cc6310842 294ac6311084 2108c63118c6 18c6c6312108 1084c631294a 0842c631318c 0000c63139ce 
+ffffbdef0000 f7bdbdef0000 ef7bbdef0000 e739bdef0000 def7bdef0000 d6b5bdef0000 ce73bdef0000 c631bdef0000 bdefbdef0000 b5adbdef0000 ad6bbdef0000 a529bdef0000 9ce7bdef0000 94a5bdef0000 8c63bdef0000 8421bdef0000 7bdebdef0000 739cbdef0000 6b5abdef0000 6318bdef0000 5ad6bdef0000 5294bdef0000 4a52bdef0000 4210bdef0000 39cebdef0842 318cbdef1084 294abdef18c6 2108bdef2108 18c6bdef294a 1084bdef318c 0842bdef39ce 0000bdef4210 
+ffffb5ad0000 f7bdb5ad0000 ef7bb5ad0000 e739b5ad0000 def7b5ad0000 d6b5b5ad0000 ce73b5ad0000 c631b5ad0000 bdefb5ad0000 b5adb5ad0000 ad6bb5ad0000 a529b5ad0000 9ce7b5ad0000 94a5b5ad0000 8c63b5ad0000 8421b5ad0000 7bdeb5ad0000 739cb5ad0000 6b5ab5ad0000 6318b5ad0000 5ad6b5ad0000 5294b5ad0000 4a52b5ad0000 4210b5ad0842 39ceb5ad1084 318cb5ad18c6 294ab5ad2108 2108b5ad294a 18c6b5ad318c 1084b5ad39ce 0842b5ad4210 0000b5ad4a52 
+ffffad6b0000 f7bdad6b0000 ef7bad6b0000 e739ad6b0000 def7ad6b0000 d6b5ad6b0000 ce73ad6b0000 c631ad6b0000 bdefad6b0000 b5adad6b0000 ad6bad6b0000 a529ad6b0000 9ce7ad6b0000 94a5ad6b0000 8c63ad6b0000 8421ad6b0000 7bdead6b0000 739cad6b0000 6b5aad6b0000 6318ad6b0000 5ad6ad6b0000 5294ad6b0000 4a52ad6b0842 4210ad6b1084 39cead6b18c6 318cad6b2108 294aad6b294a 2108ad6b318c 18c6ad6b39ce 1084ad6b4210 0842ad6b4a52 0000ad6b5294 
+ffffa5290000 f7bda5290000 ef7ba5290000 e739a5290000 def7a5290000 d6b5a5290000 ce73a5290000 c631a5290000 bdefa5290000 b5ada5290000 ad6ba5290000 a529a5290000 9ce7a5290000 94a5a5290000 8c63a5290000 8421a5290000 7bdea5290000 739ca5290000 6b5aa5290000 6318a5290000 5ad6a5290000 5294a5290842 4a52a5291084 4210a52918c6 39cea5292108 318ca529294a 294aa529318c 2108a52939ce 18c6a5294210 1084a5294a52 0842a5295294 0000a5295ad6 
+ffff9ce70000 f7bd9ce70000 ef7b9ce70000 e7399ce70000 def79ce70000 d6b59ce70000 ce739ce70000 c6319ce70000 bdef9ce70000 b5ad9ce70000 ad6b9ce70000 a5299ce70000 9ce79ce70000 94a59ce70000 8c639ce70000 84219ce70000 7bde9ce70000 739c9ce70000 6b5a9ce70000 63189ce70000 5ad69ce70842 52949ce71084 4a529ce718c6 42109ce72108 39ce9ce7294a 318c9ce7318c 294a9ce739ce 21089ce74210 18c69ce74a52 10849ce75294 08429ce75ad6 00009ce76318 
+ffff94a50000 f7bd94a50000 ef7b94a50000 e73994a50000 def794a50000 d6b594a50000 ce7394a50000 c63194a50000 bdef94a50000 b5ad94a50000 ad6b94a50000 a52994a50000 9ce794a50000 94a594a50000 8c6394a50000 842194a50000 7bde94a50000 739c94a50000 6b5a94a50000 631894a50842 5ad694a51084 529494a518c6 4a5294a52108 421094a5294a 39ce94a5318c 318c94a539ce 294a94a54210 210894a54a52 18c694a55294 108494a55ad6 084294a56318 000094a56b5a 
+ffff8c630000 f7bd8c630000 ef7b8c630000 e7398c630000 def78c630000 d6b58c630000 ce738c630000 c6318c630000 bdef8c630000 b5ad8c630000 ad6b8c630000 a5298c630000 9ce78c630000 94a58c630000 8c638c630000 84218c630000 7bde8c630000 739c8c630000 6b5a8c630842 63188c631084 5ad68c6318c6 52948c632108 4a528c63294a 42108c63318c 39ce8c6339ce 318c8c634210 294a8c634a52 21088c635294 18c68c635ad6 10848c636318 08428c636b5a 00008c63739c 
+ffff84210000 f7bd84210000 ef7b84210000 e73984210000 def784210000 d6b584210000 ce7384210000 c63184210000 bdef84210000 b5ad84210000 ad6b84210000 a52984210000 9ce784210000 94a584210000 8c6384210000 842184210000 7bde84210000 739c84210842 6b5a84211084 6318842118c6 5ad684212108 52948421294a 4a528421318c 4210842139ce 39ce84214210 318c84214a52 294a84215294 210884215ad6 18c684216318 108484216b5a 08428421739c 000084217bde 
+ffff7bde0000 f7bd7bde0000 ef7b7bde0000 e7397bde0000 def77bde0000 d6b57bde0000 ce737bde0000 c6317bde0000 bdef7bde0000 b5ad7bde0000 ad6b7bde0000 a5297bde0000 9ce77bde0000 94a57bde0000 8c637bde0000 84217bde0000 7bde7bde0842 739c7bde1084 6b5a7bde18c6 63187bde2108 5ad67bde294a 52947bde318c 4a527bde39ce 42107bde4210 39ce7bde4a52 318c7bde5294 294a7bde5ad6 21087bde6318 18c67bde6b5a 10847bde739c 08427bde7bde 00007bde8421 
+ffff739c0000 f7bd739c0000 ef7b739c0000 e739739c0000 def7739c0000 d6b5739c0000 ce73739c0000 c631739c0000 bdef739c0000 b5ad739c0000 ad6b739c0000 a529739c0000 9ce7739c0000 94a5739c0000 8c63739c0000 8421739c0842 7bde739c1084 739c739c18c6 6b5a739c2108 6318739c294a 5ad6739c318c 5294739c39ce 4a52739c4210 4210739c4a52 39ce739c5294 318c739c5ad6 294a739c6318 2108739c6b5a 18c6739c739c 1084739c7bde 0842739c8421 0000739c8c63 
+ffff6b5a0000 f7bd6b5a0000 ef7b6b5a0000 e7396b5a0000 def76b5a0000 d6b56b5a0000 ce736b5a0000 c6316b5a0000 bdef6b5a0000 b5ad6b5a0000 ad6b6b5a0000 a5296b5a0000 9ce76b5a0000 94a56b5a0000 8c636b5a0842 84216b5a1084 7bde6b5a18c6 739c6b5a2108 6b5a6b5a294a 63186b5a318c 5ad66b5a39ce 52946b5a4210 4a526b5a4a52 42106b5a5294 39ce6b5a5ad6 318c6b5a6318 294a6b5a6b5a 21086b5a739c 18c66b5a7bde 10846b5a8421 08426b5a8c63 00006b5a94a5 
+ffff63180000 f7bd63180000 ef7b63180000 e73963180000 def763180000 d6b563180000 ce7363180000 c63163180000 bdef63180000 b5ad63180000 ad6b63180000 a52963180000 9ce763180000 94a563180842 8c6363181084 8421631818c6 7bde63182108 739c6318294a 6b5a6318318c 6318631839ce 5ad663184210 529463184a52 4a5263185294 421063185ad6 39ce63186318 318c63186b5a 294a6318739c 210863187bde 18c663188421 108463188c63 0842631894a5 000063189ce7 
+ffff5ad60000 f7bd5ad60000 ef7b5ad60000 e7395ad60000 def75ad60000 d6b55ad60000 ce735ad60000 c6315ad60000 bdef5ad60000 b5ad5ad60000 ad6b5ad60000 a5295ad60000 9ce75ad60842 94a55ad61084 8c635ad618c6 84215ad62108 7bde5ad6294a 739c5ad6318c 6b5a5ad639ce 63185ad64210 5ad65ad64a52 52945ad65294 4a525ad65ad6 42105ad66318 39ce5ad66b5a 318c5ad6739c 294a5ad67bde 21085ad68421 18c65ad68c63 10845ad694a5 08425ad69ce7 00005ad6a529 
+ffff52940000 f7bd52940000 ef7b52940000 e73952940000 def752940000 d6b552940000 ce7352940000 c63152940000 bdef52940000 b5ad52940000 ad6b52940000 a52952940842 9ce752941084 94a5529418c6 8c6352942108 84215294294a 7bde5294318c 739c529439ce 6b5a52944210 631852944a52 5ad652945294 529452945ad6 4a5252946318 421052946b5a 39ce5294739c 318c52947bde 294a52948421 210852948c63 18c6529494a5 108452949ce7 08425294a529 00005294ad6b 
+ffff4a520000 f7bd4a520000 ef7b4a520000 e7394a520000 def74a520000 d6b54a520000 ce734a520000 c6314a520000 bdef4a520000 b5ad4a520000 ad6b4a520842 a5294a521084 9ce74a5218c6 94a54a522108 8c634a52294a 84214a52318c 7bde4a5239ce 739c4a524210 6b5a4a524a52 63184a525294 5ad64a525ad6 52944a526318 4a524a526b5a 42104a52739c 39ce4a527bde 318c4a528421 294a4a528c63 21084a5294a5 18c64a529ce7 10844a52a529 08424a52ad6b 00004a52b5ad 
+ffff42100000 f7bd42100000 ef7b42100000 e73942100000 def742100000 d6b542100000 ce7342100000 c63142100000 bdef42100000 b5ad42100842 ad6b42101084 a529421018c6 9ce742102108 94a54210294a 8c634210318c 8421421039ce 7bde42104210 739c42104a52 6b5a42105294 631842105ad6 5ad642106318 529442106b5a 4a524210739c 421042107bde 39ce42108421 318c42108c63 294a421094a5 210842109ce7 18c64210a529 10844210ad6b 08424210b5ad 00004210bdef 
+ffff39ce0000 f7bd39ce0000 ef7b39ce0000 e73939ce0000 def739ce0000 d6b539ce0000 ce7339ce0000 c63139ce0000 bdef39ce0842 b5ad39ce1084 ad6b39ce18c6 a52939ce2108 9ce739ce294a 94a539ce318c 8c6339ce39ce 842139ce4210 7bde39ce4a52 739c39ce5294 6b5a39ce5ad6 631839ce6318 5ad639ce6b5a 529439ce739c 4a5239ce7bde 421039ce8421 39ce39ce8c63 318c39ce94a5 294a39ce9ce7 210839cea529 18c639cead6b 108439ceb5ad 084239cebdef 000039cec631 
+ffff318c0000 f7bd318c0000 ef7b318c0000 e739318c0000 def7318c0000 d6b5318c0000 ce73318c0000 c631318c0842 bdef318c1084 b5ad318c18c6 ad6b318c2108 a529318c294a 9ce7318c318c 94a5318c39ce 8c63318c4210 8421318c4a52 7bde318c5294 739c318c5ad6 6b5a318c6318 6318318c6b5a 5ad6318c739c 5294318c7bde 4a52318c8421 4210318c8c63 39ce318c94a5 318c318c9ce7 294a318ca529 2108318cad6b 18c6318cb5ad 1084318cbdef 0842318cc631 0000318cce73 
+ffff294a0000 f7bd294a0000 ef7b294a0000 e739294a0000 def7294a0000 d6b5294a0000 ce73294a0842 c631294a1084 bdef294a18c6 b5ad294a2108 ad6b294a294a a529294a318c 9ce7294a39ce 94a5294a4210 8c63294a4a52 8421294a5294 7bde294a5ad6 739c294a6318 6b5a294a6b5a 6318294a739c 5ad6294a7bde 5294294a8421 4a52294a8c63 4210294a94a5 39ce294a9ce7 318c294aa529 294a294aad6b 2108294ab5ad 18c6294abdef 1084294ac631 0842294ace73 0000294ad6b5 
+ffff21080000 f7bd21080000 ef7b21080000 e73921080000 def721080000 d6b521080842 ce7321081084 c631210818c6 bdef21082108 b5ad2108294a ad6b2108318c a529210839ce 9ce721084210 94a521084a52 8c6321085294 842121085ad6 7bde21086318 739c21086b5a 6b5a2108739c 631821087bde 5ad621088421 529421088c63 4a52210894a5 421021089ce7 39ce2108a529 318c2108ad6b 294a2108b5ad 21082108bdef 18c62108c631 10842108ce73 08422108d6b5 00002108def7 
+ffff18c60000 f7bd18c60000 ef7b18c60000 e73918c60000 def718c60842 d6b518c61084 ce7318c618c6 c63118c62108 bdef18c6294a b5ad18c6318c ad6b18c639ce a52918c64210 9ce718c64a52 94a518c65294 8c6318c65ad6 842118c66318 7bde18c66b5a 739c18c6739c 6b5a18c67bde 631818c68421 5ad618c68c63 529418c694a5 4a5218c69ce7 421018c6a529 39ce18c6ad6b 318c18c6b5ad 294a18c6bdef 210818c6c631 18c618c6ce73 108418c6d6b5 084218c6def7 000018c6e739 
+ffff10840000 f7bd10840000 ef7b10840000 e73910840842 def710841084 d6b5108418c6 ce7310842108 c6311084294a bdef1084318c b5ad108439ce ad6b10844210 a52910844a52 9ce710845294 94a510845ad6 8c6310846318 842110846b5a 7bde1084739c 739c10847bde 6b5a10848421 631810848c63 5ad6108494a5 529410849ce7 4a521084a529 42101084ad6b 39ce1084b5ad 318c1084bdef 294a1084c631 21081084ce73 18c61084d6b5 10841084def7 08421084e739 00001084ef7b 
+ffff08420000 f7bd08420000 ef7b08420842 e73908421084 def7084218c6 d6b508422108 ce730842294a c6310842318c bdef084239ce b5ad08424210 ad6b08424a52 a52908425294 9ce708425ad6 94a508426318 8c6308426b5a 84210842739c 7bde08427bde 739c08428421 6b5a08428c63 6318084294a5 5ad608429ce7 52940842a529 4a520842ad6b 42100842b5ad 39ce0842bdef 318c0842c631 294a0842ce73 21080842d6b5 18c60842def7 10840842e739 08420842ef7b 00000842f7bd 
+ffff00000000 f7bd00000842 ef7b00001084 e739000018c6 def700002108 d6b50000294a ce730000318c c631000039ce bdef00004210 b5ad00004a52 ad6b00005294 a52900005ad6 9ce700006318 94a500006b5a 8c630000739c 842100007bde 7bde00008421 739c00008c63 6b5a000094a5 631800009ce7 5ad60000a529 52940000ad6b 4a520000b5ad 42100000bdef 39ce0000c631 318c0000ce73 294a0000d6b5 21080000def7 18c60000e739 10840000ef7b 08420000f7bd 00000000ffff 
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p01.png b/libgo/go/image/png/testdata/pngsuite/basn3p01.png
new file mode 100644 (file)
index 0000000..a21db59
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn3p01.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p01.sng b/libgo/go/image/png/testdata/pngsuite/basn3p01.sng
new file mode 100644 (file)
index 0000000..a8b3ce8
--- /dev/null
@@ -0,0 +1,45 @@
+#SNG: from basn3p01.png
+IHDR {
+    width: 32; height: 32; bitdepth: 1;
+    using color palette;
+}
+gAMA {1.0000}
+PLTE {
+    (238,255, 34)     # rgb = (0xee,0xff,0x22)
+    ( 34,102,255)     # rgb = (0x22,0x66,0xff)
+}
+IMAGE {
+    pixels hex
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p02.png b/libgo/go/image/png/testdata/pngsuite/basn3p02.png
new file mode 100644 (file)
index 0000000..1d0ab61
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn3p02.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p02.sng b/libgo/go/image/png/testdata/pngsuite/basn3p02.sng
new file mode 100644 (file)
index 0000000..f2321aa
--- /dev/null
@@ -0,0 +1,50 @@
+#SNG: from basn3p02.png
+IHDR {
+    width: 32; height: 32; bitdepth: 2;
+    using color palette;
+}
+gAMA {1.0000}
+sBIT {
+    red: 1; green: 1; blue: 1;
+}
+PLTE {
+    (  0,255,  0)     # rgb = (0x00,0xff,0x00) green1
+    (255,  0,  0)     # rgb = (0xff,0x00,0x00) red1
+    (255,255,  0)     # rgb = (0xff,0xff,0x00) yellow1
+    (  0,  0,255)     # rgb = (0x00,0x00,0xff) blue1
+}
+IMAGE {
+    pixels hex
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p04.png b/libgo/go/image/png/testdata/pngsuite/basn3p04.png
new file mode 100644 (file)
index 0000000..6dc6eac
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn3p04.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p04.sng b/libgo/go/image/png/testdata/pngsuite/basn3p04.sng
new file mode 100644 (file)
index 0000000..e52885d
--- /dev/null
@@ -0,0 +1,61 @@
+#SNG: from basn3p04.png
+IHDR {
+    width: 32; height: 32; bitdepth: 4;
+    using color palette;
+}
+gAMA {1.0000}
+sBIT {
+    red: 4; green: 4; blue: 4;
+}
+PLTE {
+    ( 34,  0,255)     # rgb = (0x22,0x00,0xff)
+    (  0,255,255)     # rgb = (0x00,0xff,0xff) cyan1
+    (136,  0,255)     # rgb = (0x88,0x00,0xff)
+    ( 34,255,  0)     # rgb = (0x22,0xff,0x00)
+    (  0,153,255)     # rgb = (0x00,0x99,0xff)
+    (255,102,  0)     # rgb = (0xff,0x66,0x00)
+    (221,  0,255)     # rgb = (0xdd,0x00,0xff)
+    (119,255,  0)     # rgb = (0x77,0xff,0x00)
+    (255,  0,  0)     # rgb = (0xff,0x00,0x00) red1
+    (  0,255,153)     # rgb = (0x00,0xff,0x99)
+    (221,255,  0)     # rgb = (0xdd,0xff,0x00)
+    (255,  0,187)     # rgb = (0xff,0x00,0xbb)
+    (255,187,  0)     # rgb = (0xff,0xbb,0x00)
+    (  0, 68,255)     # rgb = (0x00,0x44,0xff)
+    (  0,255, 68)     # rgb = (0x00,0xff,0x44)
+}
+IMAGE {
+    pixels hex
+88885555ccccaaaa77773333eeee9999
+88885555ccccaaaa77773333eeee9999
+88885555ccccaaaa77773333eeee9999
+88885555ccccaaaa77773333eeee9999
+5555ccccaaaa77773333eeee99991111
+5555ccccaaaa77773333eeee99991111
+5555ccccaaaa77773333eeee99991111
+5555ccccaaaa77773333eeee99991111
+ccccaaaa77773333eeee999911114444
+ccccaaaa77773333eeee999911114444
+ccccaaaa77773333eeee999911114444
+ccccaaaa77773333eeee999911114444
+aaaa77773333eeee999911114444dddd
+aaaa77773333eeee999911114444dddd
+aaaa77773333eeee999911114444dddd
+aaaa77773333eeee999911114444dddd
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+3333eeee999911114444dddd00002222
+3333eeee999911114444dddd00002222
+3333eeee999911114444dddd00002222
+3333eeee999911114444dddd00002222
+eeee999911114444dddd000022226666
+eeee999911114444dddd000022226666
+eeee999911114444dddd000022226666
+eeee999911114444dddd000022226666
+999911114444dddd000022226666bbbb
+999911114444dddd000022226666bbbb
+999911114444dddd000022226666bbbb
+999911114444dddd000022226666bbbb
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p08.png b/libgo/go/image/png/testdata/pngsuite/basn3p08.png
new file mode 100644 (file)
index 0000000..0e07f48
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn3p08.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p08.sng b/libgo/go/image/png/testdata/pngsuite/basn3p08.sng
new file mode 100644 (file)
index 0000000..0423bb2
--- /dev/null
@@ -0,0 +1,299 @@
+#SNG: from basn3p08.png
+IHDR {
+    width: 32; height: 32; bitdepth: 8;
+    using color palette;
+}
+gAMA {1.0000}
+PLTE {
+    ( 34, 68,  0)     # rgb = (0x22,0x44,0x00)
+    (245,255,237)     # rgb = (0xf5,0xff,0xed)
+    (119,255,119)     # rgb = (0x77,0xff,0x77)
+    (203,255,255)     # rgb = (0xcb,0xff,0xff)
+    ( 17, 10,  0)     # rgb = (0x11,0x0a,0x00)
+    ( 58,119,  0)     # rgb = (0x3a,0x77,0x00)
+    ( 34, 34,255)     # rgb = (0x22,0x22,0xff)
+    (255, 17,255)     # rgb = (0xff,0x11,0xff)
+    ( 17,  0,  0)     # rgb = (0x11,0x00,0x00)
+    ( 34, 34,  0)     # rgb = (0x22,0x22,0x00)
+    (255,172, 85)     # rgb = (0xff,0xac,0x55)
+    (102,255,102)     # rgb = (0x66,0xff,0x66)
+    (255,102,102)     # rgb = (0xff,0x66,0x66)
+    (255,  1,255)     # rgb = (0xff,0x01,0xff)
+    ( 34, 18,  0)     # rgb = (0x22,0x12,0x00)
+    (220,255,255)     # rgb = (0xdc,0xff,0xff)
+    (204,255,153)     # rgb = (0xcc,0xff,0x99)
+    ( 68, 68,255)     # rgb = (0x44,0x44,0xff)
+    (  0, 85, 85)     # rgb = (0x00,0x55,0x55)
+    ( 34,  0,  0)     # rgb = (0x22,0x00,0x00)
+    (203,203,255)     # rgb = (0xcb,0xcb,0xff)
+    ( 68, 68,  0)     # rgb = (0x44,0x44,0x00)
+    ( 85,255, 85)     # rgb = (0x55,0xff,0x55)
+    (203,203,  0)     # rgb = (0xcb,0xcb,0x00)
+    ( 51, 26,  0)     # rgb = (0x33,0x1a,0x00)
+    (255,236,220)     # rgb = (0xff,0xec,0xdc)
+    (237,255,255)     # rgb = (0xed,0xff,0xff)
+    (228,255,203)     # rgb = (0xe4,0xff,0xcb)
+    (255,220,220)     # rgb = (0xff,0xdc,0xdc)
+    ( 68,255, 68)     # rgb = (0x44,0xff,0x44)
+    (102,102,255)     # rgb = (0x66,0x66,0xff)
+    ( 51,  0,  0)     # rgb = (0x33,0x00,0x00)
+    ( 68, 34,  0)     # rgb = (0x44,0x22,0x00)
+    (237,237,255)     # rgb = (0xed,0xed,0xff)
+    (102,102,  0)     # rgb = (0x66,0x66,0x00)
+    (255,164, 68)     # rgb = (0xff,0xa4,0x44)
+    (255,255,170)     # rgb = (0xff,0xff,0xaa)
+    (237,237,  0)     # rgb = (0xed,0xed,0x00)
+    (  0,203,203)     # rgb = (0x00,0xcb,0xcb)
+    (254,255,255)     # rgb = (0xfe,0xff,0xff)
+    (253,255,254)     # rgb = (0xfd,0xff,0xfe)
+    (255,255,  1)     # rgb = (0xff,0xff,0x01)
+    ( 51,255, 51)     # rgb = (0x33,0xff,0x33)
+    ( 85, 42,  0)     # rgb = (0x55,0x2a,0x00)
+    (  1,  1,255)     # rgb = (0x01,0x01,0xff)
+    (136,136,255)     # rgb = (0x88,0x88,0xff)
+    (  0,170,170)     # rgb = (0x00,0xaa,0xaa)
+    (  1,  1,  0)     # rgb = (0x01,0x01,0x00)
+    ( 68,  0,  0)     # rgb = (0x44,0x00,0x00)
+    (136,136,  0)     # rgb = (0x88,0x88,0x00)
+    (255,228,203)     # rgb = (0xff,0xe4,0xcb)
+    (186, 91,  0)     # rgb = (0xba,0x5b,0x00)
+    ( 34,255, 34)     # rgb = (0x22,0xff,0x22)
+    (102, 50,  0)     # rgb = (0x66,0x32,0x00)
+    (255,255,153)     # rgb = (0xff,0xff,0x99)
+    (170,170,255)     # rgb = (0xaa,0xaa,0xff)
+    ( 85,  0,  0)     # rgb = (0x55,0x00,0x00)
+    (170,170,  0)     # rgb = (0xaa,0xaa,0x00)
+    (203, 99,  0)     # rgb = (0xcb,0x63,0x00)
+    ( 17,255, 17)     # rgb = (0x11,0xff,0x11)
+    (212,255,170)     # rgb = (0xd4,0xff,0xaa)
+    (119, 58,  0)     # rgb = (0x77,0x3a,0x00)
+    (255, 68, 68)     # rgb = (0xff,0x44,0x44)
+    (220,107,  0)     # rgb = (0xdc,0x6b,0x00)
+    (102,  0,  0)     # rgb = (0x66,0x00,0x00)
+    (  1,255,  1)     # rgb = (0x01,0xff,0x01)
+    (136, 66,  0)     # rgb = (0x88,0x42,0x00)
+    (236,255,220)     # rgb = (0xec,0xff,0xdc)
+    (107,220,  0)     # rgb = (0x6b,0xdc,0x00)
+    (255,220,186)     # rgb = (0xff,0xdc,0xba)
+    (  0, 51, 51)     # rgb = (0x00,0x33,0x33)
+    (  0,237,  0)     # rgb = (0x00,0xed,0x00)
+    (237,115,  0)     # rgb = (0xed,0x73,0x00)
+    (255,255,136)     # rgb = (0xff,0xff,0x88)
+    (153, 74,  0)     # rgb = (0x99,0x4a,0x00)
+    ( 17,255,255)     # rgb = (0x11,0xff,0xff)
+    (119,  0,  0)     # rgb = (0x77,0x00,0x00)
+    (255,131,  1)     # rgb = (0xff,0x83,0x01)
+    (255,186,186)     # rgb = (0xff,0xba,0xba)
+    (254,123,  0)     # rgb = (0xfe,0x7b,0x00)
+    (255,254,255)     # rgb = (0xff,0xfe,0xff)
+    (  0,203,  0)     # rgb = (0x00,0xcb,0x00)
+    (255,153,153)     # rgb = (0xff,0x99,0x99)
+    ( 34,255,255)     # rgb = (0x22,0xff,0xff)
+    (136,  0,  0)     # rgb = (0x88,0x00,0x00)
+    (255,255,119)     # rgb = (0xff,0xff,0x77)
+    (  0,136,136)     # rgb = (0x00,0x88,0x88)
+    (255,220,255)     # rgb = (0xff,0xdc,0xff)
+    ( 26, 51,  0)     # rgb = (0x1a,0x33,0x00)
+    (  0,  0,170)     # rgb = (0x00,0x00,0xaa)
+    ( 51,255,255)     # rgb = (0x33,0xff,0xff)
+    (  0,153,  0)     # rgb = (0x00,0x99,0x00)
+    (153,  0,  0)     # rgb = (0x99,0x00,0x00)
+    (  0,  0,  1)     # rgb = (0x00,0x00,0x01)
+    ( 50,102,  0)     # rgb = (0x32,0x66,0x00)
+    (255,186,255)     # rgb = (0xff,0xba,0xff)
+    ( 68,255,255)     # rgb = (0x44,0xff,0xff)
+    (255,170,255)     # rgb = (0xff,0xaa,0xff)
+    (  0,119,  0)     # rgb = (0x00,0x77,0x00)
+    (  0,254,254)     # rgb = (0x00,0xfe,0xfe)
+    (170,  0,  0)     # rgb = (0xaa,0x00,0x00)
+    ( 74,153,  0)     # rgb = (0x4a,0x99,0x00)
+    (255,255,102)     # rgb = (0xff,0xff,0x66)
+    (255, 34, 34)     # rgb = (0xff,0x22,0x22)
+    (  0,  0,153)     # rgb = (0x00,0x00,0x99)
+    (139,255, 17)     # rgb = (0x8b,0xff,0x11)
+    ( 85,255,255)     # rgb = (0x55,0xff,0xff)
+    (255,  1,  1)     # rgb = (0xff,0x01,0x01)
+    (255,136,255)     # rgb = (0xff,0x88,0xff)
+    (  0, 85,  0)     # rgb = (0x00,0x55,0x00)
+    (  0, 17, 17)     # rgb = (0x00,0x11,0x11)
+    (255,255,254)     # rgb = (0xff,0xff,0xfe)
+    (255,253,254)     # rgb = (0xff,0xfd,0xfe)
+    (164,255, 68)     # rgb = (0xa4,0xff,0x44)
+    (102,255,255)     # rgb = (0x66,0xff,0xff)
+    (255,102,255)     # rgb = (0xff,0x66,0xff)
+    (  0, 51,  0)     # rgb = (0x00,0x33,0x00)
+    (255,255, 85)     # rgb = (0xff,0xff,0x55)
+    (255,119,119)     # rgb = (0xff,0x77,0x77)
+    (  0,  0,136)     # rgb = (0x00,0x00,0x88)
+    (255, 68,255)     # rgb = (0xff,0x44,0xff)
+    (  0, 17,  0)     # rgb = (0x00,0x11,0x00)
+    (119,255,255)     # rgb = (0x77,0xff,0xff)
+    (  0,102,102)     # rgb = (0x00,0x66,0x66)
+    (255,255,237)     # rgb = (0xff,0xff,0xed)
+    (  0,  1,  0)     # rgb = (0x00,0x01,0x00)
+    (255,245,237)     # rgb = (0xff,0xf5,0xed)
+    ( 17, 17,255)     # rgb = (0x11,0x11,0xff)
+    (255,255, 68)     # rgb = (0xff,0xff,0x44)
+    (255, 34,255)     # rgb = (0xff,0x22,0xff)
+    (255,237,237)     # rgb = (0xff,0xed,0xed)
+    ( 17, 17,  0)     # rgb = (0x11,0x11,0x00)
+    (136,255,255)     # rgb = (0x88,0xff,0xff)
+    (  0,  0,119)     # rgb = (0x00,0x00,0x77)
+    (147,255, 34)     # rgb = (0x93,0xff,0x22)
+    (  0,220,220)     # rgb = (0x00,0xdc,0xdc)
+    ( 51, 51,255)     # rgb = (0x33,0x33,0xff)
+    (254,  0,254)     # rgb = (0xfe,0x00,0xfe)
+    (186,186,255)     # rgb = (0xba,0xba,0xff)
+    (153,255,255)     # rgb = (0x99,0xff,0xff)
+    ( 51, 51,  0)     # rgb = (0x33,0x33,0x00)
+    ( 99,203,  0)     # rgb = (0x63,0xcb,0x00)
+    (186,186,  0)     # rgb = (0xba,0xba,0x00)
+    (172,255, 85)     # rgb = (0xac,0xff,0x55)
+    (255,255,220)     # rgb = (0xff,0xff,0xdc)
+    (255,255, 51)     # rgb = (0xff,0xff,0x33)
+    (123,254,  0)     # rgb = (0x7b,0xfe,0x00)
+    (237,  0,237)     # rgb = (0xed,0x00,0xed)
+    ( 85, 85,255)     # rgb = (0x55,0x55,0xff)
+    (170,255,255)     # rgb = (0xaa,0xff,0xff)
+    (220,220,255)     # rgb = (0xdc,0xdc,0xff)
+    ( 85, 85,  0)     # rgb = (0x55,0x55,0x00)
+    (  0,  0,102)     # rgb = (0x00,0x00,0x66)
+    (220,220,  0)     # rgb = (0xdc,0xdc,0x00)
+    (220,  0,220)     # rgb = (0xdc,0x00,0xdc)
+    (131,255,  1)     # rgb = (0x83,0xff,0x01)
+    (119,119,255)     # rgb = (0x77,0x77,0xff)
+    (254,254,255)     # rgb = (0xfe,0xfe,0xff)
+    (255,255,203)     # rgb = (0xff,0xff,0xcb)
+    (255, 85, 85)     # rgb = (0xff,0x55,0x55)
+    (119,119,  0)     # rgb = (0x77,0x77,0x00)
+    (254,254,  0)     # rgb = (0xfe,0xfe,0x00)
+    (203,  0,203)     # rgb = (0xcb,0x00,0xcb)
+    (  0,  0,254)     # rgb = (0x00,0x00,0xfe)
+    (  1,  2,  0)     # rgb = (0x01,0x02,0x00)
+    (  1,  0,  0)     # rgb = (0x01,0x00,0x00)
+    ( 18, 34,  0)     # rgb = (0x12,0x22,0x00)
+    (255,255, 34)     # rgb = (0xff,0xff,0x22)
+    (  0, 68, 68)     # rgb = (0x00,0x44,0x44)
+    (155,255, 51)     # rgb = (0x9b,0xff,0x33)
+    (255,212,170)     # rgb = (0xff,0xd4,0xaa)
+    (  0,  0, 85)     # rgb = (0x00,0x00,0x55)
+    (153,153,255)     # rgb = (0x99,0x99,0xff)
+    (153,153,  0)     # rgb = (0x99,0x99,0x00)
+    (186,  0,186)     # rgb = (0xba,0x00,0xba)
+    ( 42, 85,  0)     # rgb = (0x2a,0x55,0x00)
+    (255,203,203)     # rgb = (0xff,0xcb,0xcb)
+    (180,255,102)     # rgb = (0xb4,0xff,0x66)
+    (255,155, 51)     # rgb = (0xff,0x9b,0x33)
+    (255,255,186)     # rgb = (0xff,0xff,0xba)
+    (170,  0,170)     # rgb = (0xaa,0x00,0xaa)
+    ( 66,136,  0)     # rgb = (0x42,0x88,0x00)
+    ( 83,170,  0)     # rgb = (0x53,0xaa,0x00)
+    (255,170,170)     # rgb = (0xff,0xaa,0xaa)
+    (  0,  0,237)     # rgb = (0x00,0x00,0xed)
+    (  0,186,186)     # rgb = (0x00,0xba,0xba)
+    (255,255, 17)     # rgb = (0xff,0xff,0x11)
+    (  0,254,  0)     # rgb = (0x00,0xfe,0x00)
+    (  0,  0, 68)     # rgb = (0x00,0x00,0x44)
+    (  0,153,153)     # rgb = (0x00,0x99,0x99)
+    (153,  0,153)     # rgb = (0x99,0x00,0x99)
+    (255,204,153)     # rgb = (0xff,0xcc,0x99)
+    (186,  0,  0)     # rgb = (0xba,0x00,0x00)
+    (136,  0,136)     # rgb = (0x88,0x00,0x88)
+    (  0,220,  0)     # rgb = (0x00,0xdc,0x00)
+    (255,147, 34)     # rgb = (0xff,0x93,0x22)
+    (  0,  0,220)     # rgb = (0x00,0x00,0xdc)
+    (254,255,254)     # rgb = (0xfe,0xff,0xfe)
+    (170, 83,  0)     # rgb = (0xaa,0x53,0x00)
+    (119,  0,119)     # rgb = (0x77,0x00,0x77)
+    (  2,  1,  0)     # rgb = (0x02,0x01,0x00)
+    (203,  0,  0)     # rgb = (0xcb,0x00,0x00)
+    (  0,  0, 51)     # rgb = (0x00,0x00,0x33)
+    (255,237,255)     # rgb = (0xff,0xed,0xff)
+    (  0,186,  0)     # rgb = (0x00,0xba,0x00)
+    (255, 51, 51)     # rgb = (0xff,0x33,0x33)
+    (237,255,237)     # rgb = (0xed,0xff,0xed)
+    (255,196,136)     # rgb = (0xff,0xc4,0x88)
+    (188,255,119)     # rgb = (0xbc,0xff,0x77)
+    (  0,170,  0)     # rgb = (0x00,0xaa,0x00)
+    (102,  0,102)     # rgb = (0x66,0x00,0x66)
+    (  0, 34, 34)     # rgb = (0x00,0x22,0x22)
+    (220,  0,  0)     # rgb = (0xdc,0x00,0x00)
+    (255,203,255)     # rgb = (0xff,0xcb,0xff)
+    (220,255,220)     # rgb = (0xdc,0xff,0xdc)
+    (255,139, 17)     # rgb = (0xff,0x8b,0x11)
+    (  0,  0,203)     # rgb = (0x00,0x00,0xcb)
+    (  0,  1,  1)     # rgb = (0x00,0x01,0x01)
+    ( 85,  0, 85)     # rgb = (0x55,0x00,0x55)
+    (  0,136,  0)     # rgb = (0x00,0x88,0x00)
+    (  0,  0, 34)     # rgb = (0x00,0x00,0x22)
+    (  1,255,255)     # rgb = (0x01,0xff,0xff)
+    (203,255,203)     # rgb = (0xcb,0xff,0xcb)
+    (237,  0,  0)     # rgb = (0xed,0x00,0x00)
+    (255,136,136)     # rgb = (0xff,0x88,0x88)
+    ( 68,  0, 68)     # rgb = (0x44,0x00,0x44)
+    ( 91,186,  0)     # rgb = (0x5b,0xba,0x00)
+    (255,188,119)     # rgb = (0xff,0xbc,0x77)
+    (255,153,255)     # rgb = (0xff,0x99,0xff)
+    (  0,102,  0)     # rgb = (0x00,0x66,0x00)
+    (186,255,186)     # rgb = (0xba,0xff,0xba)
+    (  0,119,119)     # rgb = (0x00,0x77,0x77)
+    (115,237,  0)     # rgb = (0x73,0xed,0x00)
+    (254,  0,  0)     # rgb = (0xfe,0x00,0x00)
+    ( 51,  0, 51)     # rgb = (0x33,0x00,0x33)
+    (  0,  0,186)     # rgb = (0x00,0x00,0xba)
+    (255,119,255)     # rgb = (0xff,0x77,0xff)
+    (  0, 68,  0)     # rgb = (0x00,0x44,0x00)
+    (170,255,170)     # rgb = (0xaa,0xff,0xaa)
+    (255,254,254)     # rgb = (0xff,0xfe,0xfe)
+    (  0,  0, 17)     # rgb = (0x00,0x00,0x11)
+    ( 34,  0, 34)     # rgb = (0x22,0x00,0x22)
+    (196,255,136)     # rgb = (0xc4,0xff,0x88)
+    (  0,237,237)     # rgb = (0x00,0xed,0xed)
+    (153,255,153)     # rgb = (0x99,0xff,0x99)
+    (255, 85,255)     # rgb = (0xff,0x55,0xff)
+    (  0, 34,  0)     # rgb = (0x00,0x22,0x00)
+    (255,180,102)     # rgb = (0xff,0xb4,0x66)
+    ( 17,  0, 17)     # rgb = (0x11,0x00,0x11)
+    ( 10, 17,  0)     # rgb = (0x0a,0x11,0x00)
+    (255, 17, 17)     # rgb = (0xff,0x11,0x11)
+    (220,255,186)     # rgb = (0xdc,0xff,0xba)
+    (186,255,255)     # rgb = (0xba,0xff,0xff)
+    (136,255,136)     # rgb = (0x88,0xff,0x88)
+    (  1,  0,  1)     # rgb = (0x01,0x00,0x01)
+    (255, 51,255)     # rgb = (0xff,0x33,0xff)
+}
+IMAGE {
+    pixels hex
+a5a5a5a5a4a4a4a42f2f2f2fc8c8c8c87d7d7d7dd9d9d9d95d5d5d5dfefefefe
+080808080404040483838383f9f9f9f9797979796e6e6e6ef0f0f0f0f8f8f8f8
+131313130e0e0e0e09090909a6a6a6a6f6f6f6f6d3d3d3d3dcdcdcdcf1f1f1f1
+1f1f1f1f181818188c8c8c8c585858587474747446464646cacacacaeaeaeaea
+30303030202020201515151500000000ededededa8a8a8a8bcbcbcbce1e1e1e1
+383838382b2b2b2b97979797afafafaf6d6d6d6d12121212ababababdadadada
+4040404035353535222222225e5e5e5ee5e5e5e57b7b7b7b98989898d2d2d2d2
+4c4c4c4c3d3d3d3da0a0a0a00505050562626262e7e7e7e785858585c7c7c7c7
+545454544242424231313131b5b5b5b5dbdbdbdb5656565677777777c1c1c1c1
+5c5c5c5c4a4a4a4aadadadad656565655b5b5b5bbdbdbdbd68686868bebebebe
+64646464c6c6c6c639393939b6b6b6b6d1d1d1d12e2e2e2e59595959b4b4b4b4
+c0c0c0c0333333338e8e8e8ee2e2e2e2ccccccccb9b9b9b9ebebebebaeaeaeae
+c9c9c9c93a3a3a3a171717178d8d8d8d5151515126262626d8d8d8d8a2a2a2a2
+d4d4d4d43f3f3f3f9999999944444444c2c2c2c287878787c4c4c4c49a9a9a9a
+dfdfdfdf4848484825252525e8e8e8e847474747f3f3f3f3b8b8b8b893939393
+e9e9e9e94f4f4f4fa1a1a1a192929292bbbbbbbb63636363a3a3a3a389898989
+6b6b6b6b4d4d4d4d292929299b9b9b9b41414141dddddddd2c2c2c2c0d0d0d0d
+fafafafad7d7d7d7babababa696969693b3b3b3b4b4b4b4b7f7f7f7f07070707
+67676767c3c3c3c3a7a7a7a78686868634343434535353530606060681818181
+cdcdcdcdb2b2b2b291919191a9a9a9a92a2a2a2a5a5a5a5a88888888ffffffff
+3e3e3e3e2323232380808080717171711d1d1d1d606060601111111178787878
+9f9f9f9f0a0a0a0a757575758f8f8f8f161616166a6a6a6a94949494f5f5f5f5
+0c0c0c0cf7f7f7f766666666b1b1b1b10b0b0b0b727272721e1e1e1e73737373
+76767676e3e3e3e355555555d0d0d0d0020202027a7a7a7a9c9c9c9cecececec
+e0e0e0e0cfcfcfcf49494949f2f2f2f2fdfdfdfd848484842d2d2d2d6c6c6c6c
+52525252bfbfbfbf3636363610101010f4f4f4f48b8b8b8bacacacace4e4e4e4
+b7b7b7b7aaaaaaaa242424243c3c3c3ceeeeeeee959595953737373761616161
+4e4e4e4e45454545b3b3b3b3fbfbfbfbe6e6e6e6fcfcfcfc8a8a8a8a5f5f5f5f
+b0b0b0b0323232329e9e9e9e1b1b1b1bdededede0303030314141414d5d5d5d5
+1c1c1c1c191919199090909043434343d6d6d6d60f0f0f0f9696969657575757
+828282827e7e7e7e7c7c7c7c01010101cececece1a1a1a1a21212121cbcbcbcb
+efefefef707070706f6f6f6f28282828c5c5c5c5272727279d9d9d9d50505050
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn4a08.png b/libgo/go/image/png/testdata/pngsuite/basn4a08.png
new file mode 100644 (file)
index 0000000..3bb0dd0
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn4a08.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn4a08.sng b/libgo/go/image/png/testdata/pngsuite/basn4a08.sng
new file mode 100644 (file)
index 0000000..b760382
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn4a08.png
+IHDR {
+    width: 32; height: 32; bitdepth: 8;
+    using grayscale alpha;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+ff00 ff08 ff10 ff18 ff20 ff29 ff31 ff39 ff41 ff4a ff52 ff5a ff62 ff6a ff73 ff7b ff83 ff8b ff94 ff9c ffa4 ffac ffb4 ffbd ffc5 ffcd ffd5 ffde ffe6 ffee fff6 ffff 
+f600 f608 f610 f618 f620 f629 f631 f639 f641 f64a f652 f65a f662 f66a f673 f67b f683 f68b f694 f69c f6a4 f6ac f6b4 f6bd f6c5 f6cd f6d5 f6de f6e6 f6ee f6f6 f6ff 
+ee00 ee08 ee10 ee18 ee20 ee29 ee31 ee39 ee41 ee4a ee52 ee5a ee62 ee6a ee73 ee7b ee83 ee8b ee94 ee9c eea4 eeac eeb4 eebd eec5 eecd eed5 eede eee6 eeee eef6 eeff 
+e600 e608 e610 e618 e620 e629 e631 e639 e641 e64a e652 e65a e662 e66a e673 e67b e683 e68b e694 e69c e6a4 e6ac e6b4 e6bd e6c5 e6cd e6d5 e6de e6e6 e6ee e6f6 e6ff 
+de00 de08 de10 de18 de20 de29 de31 de39 de41 de4a de52 de5a de62 de6a de73 de7b de83 de8b de94 de9c dea4 deac deb4 debd dec5 decd ded5 dede dee6 deee def6 deff 
+d500 d508 d510 d518 d520 d529 d531 d539 d541 d54a d552 d55a d562 d56a d573 d57b d583 d58b d594 d59c d5a4 d5ac d5b4 d5bd d5c5 d5cd d5d5 d5de d5e6 d5ee d5f6 d5ff 
+cd00 cd08 cd10 cd18 cd20 cd29 cd31 cd39 cd41 cd4a cd52 cd5a cd62 cd6a cd73 cd7b cd83 cd8b cd94 cd9c cda4 cdac cdb4 cdbd cdc5 cdcd cdd5 cdde cde6 cdee cdf6 cdff 
+c500 c508 c510 c518 c520 c529 c531 c539 c541 c54a c552 c55a c562 c56a c573 c57b c583 c58b c594 c59c c5a4 c5ac c5b4 c5bd c5c5 c5cd c5d5 c5de c5e6 c5ee c5f6 c5ff 
+bd00 bd08 bd10 bd18 bd20 bd29 bd31 bd39 bd41 bd4a bd52 bd5a bd62 bd6a bd73 bd7b bd83 bd8b bd94 bd9c bda4 bdac bdb4 bdbd bdc5 bdcd bdd5 bdde bde6 bdee bdf6 bdff 
+b400 b408 b410 b418 b420 b429 b431 b439 b441 b44a b452 b45a b462 b46a b473 b47b b483 b48b b494 b49c b4a4 b4ac b4b4 b4bd b4c5 b4cd b4d5 b4de b4e6 b4ee b4f6 b4ff 
+ac00 ac08 ac10 ac18 ac20 ac29 ac31 ac39 ac41 ac4a ac52 ac5a ac62 ac6a ac73 ac7b ac83 ac8b ac94 ac9c aca4 acac acb4 acbd acc5 accd acd5 acde ace6 acee acf6 acff 
+a400 a408 a410 a418 a420 a429 a431 a439 a441 a44a a452 a45a a462 a46a a473 a47b a483 a48b a494 a49c a4a4 a4ac a4b4 a4bd a4c5 a4cd a4d5 a4de a4e6 a4ee a4f6 a4ff 
+9c00 9c08 9c10 9c18 9c20 9c29 9c31 9c39 9c41 9c4a 9c52 9c5a 9c62 9c6a 9c73 9c7b 9c83 9c8b 9c94 9c9c 9ca4 9cac 9cb4 9cbd 9cc5 9ccd 9cd5 9cde 9ce6 9cee 9cf6 9cff 
+9400 9408 9410 9418 9420 9429 9431 9439 9441 944a 9452 945a 9462 946a 9473 947b 9483 948b 9494 949c 94a4 94ac 94b4 94bd 94c5 94cd 94d5 94de 94e6 94ee 94f6 94ff 
+8b00 8b08 8b10 8b18 8b20 8b29 8b31 8b39 8b41 8b4a 8b52 8b5a 8b62 8b6a 8b73 8b7b 8b83 8b8b 8b94 8b9c 8ba4 8bac 8bb4 8bbd 8bc5 8bcd 8bd5 8bde 8be6 8bee 8bf6 8bff 
+8300 8308 8310 8318 8320 8329 8331 8339 8341 834a 8352 835a 8362 836a 8373 837b 8383 838b 8394 839c 83a4 83ac 83b4 83bd 83c5 83cd 83d5 83de 83e6 83ee 83f6 83ff 
+7b00 7b08 7b10 7b18 7b20 7b29 7b31 7b39 7b41 7b4a 7b52 7b5a 7b62 7b6a 7b73 7b7b 7b83 7b8b 7b94 7b9c 7ba4 7bac 7bb4 7bbd 7bc5 7bcd 7bd5 7bde 7be6 7bee 7bf6 7bff 
+7300 7308 7310 7318 7320 7329 7331 7339 7341 734a 7352 735a 7362 736a 7373 737b 7383 738b 7394 739c 73a4 73ac 73b4 73bd 73c5 73cd 73d5 73de 73e6 73ee 73f6 73ff 
+6a00 6a08 6a10 6a18 6a20 6a29 6a31 6a39 6a41 6a4a 6a52 6a5a 6a62 6a6a 6a73 6a7b 6a83 6a8b 6a94 6a9c 6aa4 6aac 6ab4 6abd 6ac5 6acd 6ad5 6ade 6ae6 6aee 6af6 6aff 
+6200 6208 6210 6218 6220 6229 6231 6239 6241 624a 6252 625a 6262 626a 6273 627b 6283 628b 6294 629c 62a4 62ac 62b4 62bd 62c5 62cd 62d5 62de 62e6 62ee 62f6 62ff 
+5a00 5a08 5a10 5a18 5a20 5a29 5a31 5a39 5a41 5a4a 5a52 5a5a 5a62 5a6a 5a73 5a7b 5a83 5a8b 5a94 5a9c 5aa4 5aac 5ab4 5abd 5ac5 5acd 5ad5 5ade 5ae6 5aee 5af6 5aff 
+5200 5208 5210 5218 5220 5229 5231 5239 5241 524a 5252 525a 5262 526a 5273 527b 5283 528b 5294 529c 52a4 52ac 52b4 52bd 52c5 52cd 52d5 52de 52e6 52ee 52f6 52ff 
+4a00 4a08 4a10 4a18 4a20 4a29 4a31 4a39 4a41 4a4a 4a52 4a5a 4a62 4a6a 4a73 4a7b 4a83 4a8b 4a94 4a9c 4aa4 4aac 4ab4 4abd 4ac5 4acd 4ad5 4ade 4ae6 4aee 4af6 4aff 
+4100 4108 4110 4118 4120 4129 4131 4139 4141 414a 4152 415a 4162 416a 4173 417b 4183 418b 4194 419c 41a4 41ac 41b4 41bd 41c5 41cd 41d5 41de 41e6 41ee 41f6 41ff 
+3900 3908 3910 3918 3920 3929 3931 3939 3941 394a 3952 395a 3962 396a 3973 397b 3983 398b 3994 399c 39a4 39ac 39b4 39bd 39c5 39cd 39d5 39de 39e6 39ee 39f6 39ff 
+3100 3108 3110 3118 3120 3129 3131 3139 3141 314a 3152 315a 3162 316a 3173 317b 3183 318b 3194 319c 31a4 31ac 31b4 31bd 31c5 31cd 31d5 31de 31e6 31ee 31f6 31ff 
+2900 2908 2910 2918 2920 2929 2931 2939 2941 294a 2952 295a 2962 296a 2973 297b 2983 298b 2994 299c 29a4 29ac 29b4 29bd 29c5 29cd 29d5 29de 29e6 29ee 29f6 29ff 
+2000 2008 2010 2018 2020 2029 2031 2039 2041 204a 2052 205a 2062 206a 2073 207b 2083 208b 2094 209c 20a4 20ac 20b4 20bd 20c5 20cd 20d5 20de 20e6 20ee 20f6 20ff 
+1800 1808 1810 1818 1820 1829 1831 1839 1841 184a 1852 185a 1862 186a 1873 187b 1883 188b 1894 189c 18a4 18ac 18b4 18bd 18c5 18cd 18d5 18de 18e6 18ee 18f6 18ff 
+1000 1008 1010 1018 1020 1029 1031 1039 1041 104a 1052 105a 1062 106a 1073 107b 1083 108b 1094 109c 10a4 10ac 10b4 10bd 10c5 10cd 10d5 10de 10e6 10ee 10f6 10ff 
+0800 0808 0810 0818 0820 0829 0831 0839 0841 084a 0852 085a 0862 086a 0873 087b 0883 088b 0894 089c 08a4 08ac 08b4 08bd 08c5 08cd 08d5 08de 08e6 08ee 08f6 08ff 
+0000 0008 0010 0018 0020 0029 0031 0039 0041 004a 0052 005a 0062 006a 0073 007b 0083 008b 0094 009c 00a4 00ac 00b4 00bd 00c5 00cd 00d5 00de 00e6 00ee 00f6 00ff 
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn4a16.png b/libgo/go/image/png/testdata/pngsuite/basn4a16.png
new file mode 100644 (file)
index 0000000..6dbee9f
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn4a16.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn4a16.sng b/libgo/go/image/png/testdata/pngsuite/basn4a16.sng
new file mode 100644 (file)
index 0000000..d3b9b47
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn4a16.png
+IHDR {
+    width: 32; height: 32; bitdepth: 16;
+    using grayscale alpha;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+00000000 10840000 21080000 318c0000 42100000 52940000 63180000 739c0000 84200000 94a40000 a5280000 b5ac0000 c6300000 d6b40000 e7380000 f7bc0000 f7bc0000 e7380000 d6b40000 c6300000 b5ac0000 a5280000 94a40000 84200000 739c0000 63180000 52940000 42100000 318c0000 21080000 10840000 00000000 
+10840000 00001085 11a71085 234f1085 34f61085 469e1085 58461085 69ed1085 7b951085 8d3d1085 9ee41085 b08c1085 c2341085 d3db1085 e5831085 f72b1085 f72b1085 e5831085 d3db1085 c2341085 b08c1085 9ee41085 8d3d1085 7b951085 69ed1085 58461085 469e1085 34f61085 234f1085 11a71085 00001085 10840000 
+21080000 11a71085 00002109 12f62109 25ec2109 38e32109 4bd92109 5ed02109 71c62109 84bd2109 97b32109 aaa92109 bda02109 d0962109 e38d2109 f6832109 f6832109 e38d2109 d0962109 bda02109 aaa92109 97b32109 84bd2109 71c62109 5ed02109 4bd92109 38e32109 25ec2109 12f62109 00002109 11a71085 21080000 
+318c0000 234f1085 12f62109 0000318d 147a318d 28f5318d 3d70318d 51eb318d 6665318d 7ae0318d 8f5b318d a3d6318d b851318d cccb318d e146318d f5c1318d f5c1318d e146318d cccb318d b851318d a3d6318d 8f5b318d 7ae0318d 6665318d 51eb318d 3d70318d 28f5318d 147a318d 0000318d 12f62109 234f1085 318c0000 
+42100000 34f61085 25ec2109 147a318d 00004211 16424211 2c854211 42c84211 590a4211 6f4d4211 85904211 9bd24211 b2154211 c8584211 de9a4211 f4dd4211 f4dd4211 de9a4211 c8584211 b2154211 9bd24211 85904211 6f4d4211 590a4211 42c84211 2c854211 16424211 00004211 147a318d 25ec2109 34f61085 42100000 
+52940000 469e1085 38e32109 28f5318d 16424211 00005295 18615295 30c25295 49245295 61855295 79e75295 92485295 aaa95295 c30b5295 db6c5295 f3ce5295 f3ce5295 db6c5295 c30b5295 aaa95295 92485295 79e75295 61855295 49245295 30c25295 18615295 00005295 16424211 28f5318d 38e32109 469e1085 52940000 
+63180000 58461085 4bd92109 3d70318d 2c854211 18615295 00006319 1af26319 35e46319 50d76319 6bc96319 86bc6319 a1ae6319 bca06319 d7936319 f2856319 f2856319 d7936319 bca06319 a1ae6319 86bc6319 6bc96319 50d76319 35e46319 1af26319 00006319 18615295 2c854211 3d70318d 4bd92109 58461085 63180000 
+739c0000 69ed1085 5ed02109 51eb318d 42c84211 30c25295 1af26319 0000739d 1e1d739d 3c3b739d 5a59739d 7877739d 9695739d b4b3739d d2d1739d f0ef739d f0ef739d d2d1739d b4b3739d 9695739d 7877739d 5a59739d 3c3b739d 1e1d739d 0000739d 1af26319 30c25295 42c84211 51eb318d 5ed02109 69ed1085 739c0000 
+84200000 7b951085 71c62109 6665318d 590a4211 49245295 35e46319 1e1d739d 00008421 22218421 44438421 66658421 88878421 aaa98421 cccb8421 eeed8421 eeed8421 cccb8421 aaa98421 88878421 66658421 44438421 22218421 00008421 1e1d739d 35e46319 49245295 590a4211 6665318d 71c62109 7b951085 84200000 
+94a40000 8d3d1085 84bd2109 7ae0318d 6f4d4211 61855295 50d76319 3c3b739d 22218421 000094a5 276294a5 4ec494a5 762694a5 9d8994a5 c4eb94a5 ec4d94a5 ec4d94a5 c4eb94a5 9d8994a5 762694a5 4ec494a5 276294a5 000094a5 22218421 3c3b739d 50d76319 61855295 6f4d4211 7ae0318d 84bd2109 8d3d1085 94a40000 
+a5280000 9ee41085 97b32109 8f5b318d 85904211 79e75295 6bc96319 5a59739d 44438421 276294a5 0000a529 2e8ba529 5d16a529 8ba2a529 ba2da529 e8b9a529 e8b9a529 ba2da529 8ba2a529 5d16a529 2e8ba529 0000a529 276294a5 44438421 5a59739d 6bc96319 79e75295 85904211 8f5b318d 97b32109 9ee41085 a5280000 
+b5ac0000 b08c1085 aaa92109 a3d6318d 9bd24211 92485295 86bc6319 7877739d 66658421 4ec494a5 2e8ba529 0000b5ad 38e3b5ad 71c6b5ad aaa9b5ad e38db5ad e38db5ad aaa9b5ad 71c6b5ad 38e3b5ad 0000b5ad 2e8ba529 4ec494a5 66658421 7877739d 86bc6319 92485295 9bd24211 a3d6318d aaa92109 b08c1085 b5ac0000 
+c6300000 c2341085 bda02109 b851318d b2154211 aaa95295 a1ae6319 9695739d 88878421 762694a5 5d16a529 38e3b5ad 0000c631 4924c631 9248c631 db6cc631 db6cc631 9248c631 4924c631 0000c631 38e3b5ad 5d16a529 762694a5 88878421 9695739d a1ae6319 aaa95295 b2154211 b851318d bda02109 c2341085 c6300000 
+d6b40000 d3db1085 d0962109 cccb318d c8584211 c30b5295 bca06319 b4b3739d aaa98421 9d8994a5 8ba2a529 71c6b5ad 4924c631 0000d6b5 6665d6b5 cccbd6b5 cccbd6b5 6665d6b5 0000d6b5 4924c631 71c6b5ad 8ba2a529 9d8994a5 aaa98421 b4b3739d bca06319 c30b5295 c8584211 cccb318d d0962109 d3db1085 d6b40000 
+e7380000 e5831085 e38d2109 e146318d de9a4211 db6c5295 d7936319 d2d1739d cccb8421 c4eb94a5 ba2da529 aaa9b5ad 9248c631 6665d6b5 0000e739 aaa9e739 aaa9e739 0000e739 6665d6b5 9248c631 aaa9b5ad ba2da529 c4eb94a5 cccb8421 d2d1739d d7936319 db6c5295 de9a4211 e146318d e38d2109 e5831085 e7380000 
+f7bc0000 f72b1085 f6832109 f5c1318d f4dd4211 f3ce5295 f2856319 f0ef739d eeed8421 ec4d94a5 e8b9a529 e38db5ad db6cc631 cccbd6b5 aaa9e739 0000f7bd 0000f7bd aaa9e739 cccbd6b5 db6cc631 e38db5ad e8b9a529 ec4d94a5 eeed8421 f0ef739d f2856319 f3ce5295 f4dd4211 f5c1318d f6832109 f72b1085 f7bc0000 
+f7bc0000 f72b1085 f6832109 f5c1318d f4dd4211 f3ce5295 f2856319 f0ef739d eeed8421 ec4d94a5 e8b9a529 e38db5ad db6cc631 cccbd6b5 aaa9e739 0000f7bd 0000f7bd aaa9e739 cccbd6b5 db6cc631 e38db5ad e8b9a529 ec4d94a5 eeed8421 f0ef739d f2856319 f3ce5295 f4dd4211 f5c1318d f6832109 f72b1085 f7bc0000 
+e7380000 e5831085 e38d2109 e146318d de9a4211 db6c5295 d7936319 d2d1739d cccb8421 c4eb94a5 ba2da529 aaa9b5ad 9248c631 6665d6b5 0000e739 aaa9e739 aaa9e739 0000e739 6665d6b5 9248c631 aaa9b5ad ba2da529 c4eb94a5 cccb8421 d2d1739d d7936319 db6c5295 de9a4211 e146318d e38d2109 e5831085 e7380000 
+d6b40000 d3db1085 d0962109 cccb318d c8584211 c30b5295 bca06319 b4b3739d aaa98421 9d8994a5 8ba2a529 71c6b5ad 4924c631 0000d6b5 6665d6b5 cccbd6b5 cccbd6b5 6665d6b5 0000d6b5 4924c631 71c6b5ad 8ba2a529 9d8994a5 aaa98421 b4b3739d bca06319 c30b5295 c8584211 cccb318d d0962109 d3db1085 d6b40000 
+c6300000 c2341085 bda02109 b851318d b2154211 aaa95295 a1ae6319 9695739d 88878421 762694a5 5d16a529 38e3b5ad 0000c631 4924c631 9248c631 db6cc631 db6cc631 9248c631 4924c631 0000c631 38e3b5ad 5d16a529 762694a5 88878421 9695739d a1ae6319 aaa95295 b2154211 b851318d bda02109 c2341085 c6300000 
+b5ac0000 b08c1085 aaa92109 a3d6318d 9bd24211 92485295 86bc6319 7877739d 66658421 4ec494a5 2e8ba529 0000b5ad 38e3b5ad 71c6b5ad aaa9b5ad e38db5ad e38db5ad aaa9b5ad 71c6b5ad 38e3b5ad 0000b5ad 2e8ba529 4ec494a5 66658421 7877739d 86bc6319 92485295 9bd24211 a3d6318d aaa92109 b08c1085 b5ac0000 
+a5280000 9ee41085 97b32109 8f5b318d 85904211 79e75295 6bc96319 5a59739d 44438421 276294a5 0000a529 2e8ba529 5d16a529 8ba2a529 ba2da529 e8b9a529 e8b9a529 ba2da529 8ba2a529 5d16a529 2e8ba529 0000a529 276294a5 44438421 5a59739d 6bc96319 79e75295 85904211 8f5b318d 97b32109 9ee41085 a5280000 
+94a40000 8d3d1085 84bd2109 7ae0318d 6f4d4211 61855295 50d76319 3c3b739d 22218421 000094a5 276294a5 4ec494a5 762694a5 9d8994a5 c4eb94a5 ec4d94a5 ec4d94a5 c4eb94a5 9d8994a5 762694a5 4ec494a5 276294a5 000094a5 22218421 3c3b739d 50d76319 61855295 6f4d4211 7ae0318d 84bd2109 8d3d1085 94a40000 
+84200000 7b951085 71c62109 6665318d 590a4211 49245295 35e46319 1e1d739d 00008421 22218421 44438421 66658421 88878421 aaa98421 cccb8421 eeed8421 eeed8421 cccb8421 aaa98421 88878421 66658421 44438421 22218421 00008421 1e1d739d 35e46319 49245295 590a4211 6665318d 71c62109 7b951085 84200000 
+739c0000 69ed1085 5ed02109 51eb318d 42c84211 30c25295 1af26319 0000739d 1e1d739d 3c3b739d 5a59739d 7877739d 9695739d b4b3739d d2d1739d f0ef739d f0ef739d d2d1739d b4b3739d 9695739d 7877739d 5a59739d 3c3b739d 1e1d739d 0000739d 1af26319 30c25295 42c84211 51eb318d 5ed02109 69ed1085 739c0000 
+63180000 58461085 4bd92109 3d70318d 2c854211 18615295 00006319 1af26319 35e46319 50d76319 6bc96319 86bc6319 a1ae6319 bca06319 d7936319 f2856319 f2856319 d7936319 bca06319 a1ae6319 86bc6319 6bc96319 50d76319 35e46319 1af26319 00006319 18615295 2c854211 3d70318d 4bd92109 58461085 63180000 
+52940000 469e1085 38e32109 28f5318d 16424211 00005295 18615295 30c25295 49245295 61855295 79e75295 92485295 aaa95295 c30b5295 db6c5295 f3ce5295 f3ce5295 db6c5295 c30b5295 aaa95295 92485295 79e75295 61855295 49245295 30c25295 18615295 00005295 16424211 28f5318d 38e32109 469e1085 52940000 
+42100000 34f61085 25ec2109 147a318d 00004211 16424211 2c854211 42c84211 590a4211 6f4d4211 85904211 9bd24211 b2154211 c8584211 de9a4211 f4dd4211 f4dd4211 de9a4211 c8584211 b2154211 9bd24211 85904211 6f4d4211 590a4211 42c84211 2c854211 16424211 00004211 147a318d 25ec2109 34f61085 42100000 
+318c0000 234f1085 12f62109 0000318d 147a318d 28f5318d 3d70318d 51eb318d 6665318d 7ae0318d 8f5b318d a3d6318d b851318d cccb318d e146318d f5c1318d f5c1318d e146318d cccb318d b851318d a3d6318d 8f5b318d 7ae0318d 6665318d 51eb318d 3d70318d 28f5318d 147a318d 0000318d 12f62109 234f1085 318c0000 
+21080000 11a71085 00002109 12f62109 25ec2109 38e32109 4bd92109 5ed02109 71c62109 84bd2109 97b32109 aaa92109 bda02109 d0962109 e38d2109 f6832109 f6832109 e38d2109 d0962109 bda02109 aaa92109 97b32109 84bd2109 71c62109 5ed02109 4bd92109 38e32109 25ec2109 12f62109 00002109 11a71085 21080000 
+10840000 00001085 11a71085 234f1085 34f61085 469e1085 58461085 69ed1085 7b951085 8d3d1085 9ee41085 b08c1085 c2341085 d3db1085 e5831085 f72b1085 f72b1085 e5831085 d3db1085 c2341085 b08c1085 9ee41085 8d3d1085 7b951085 69ed1085 58461085 469e1085 34f61085 234f1085 11a71085 00001085 10840000 
+00000000 10840000 21080000 318c0000 42100000 52940000 63180000 739c0000 84200000 94a40000 a5280000 b5ac0000 c6300000 d6b40000 e7380000 f7bc0000 f7bc0000 e7380000 d6b40000 c6300000 b5ac0000 a5280000 94a40000 84200000 739c0000 63180000 52940000 42100000 318c0000 21080000 10840000 00000000 
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn6a08.png b/libgo/go/image/png/testdata/pngsuite/basn6a08.png
new file mode 100644 (file)
index 0000000..6106230
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn6a08.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn6a08.sng b/libgo/go/image/png/testdata/pngsuite/basn6a08.sng
new file mode 100644 (file)
index 0000000..c1e0bf4
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn6a08.png
+IHDR {
+    width: 32; height: 32; bitdepth: 8;
+    using color alpha;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+ff000800 ff000808 ff000810 ff000818 ff000820 ff000829 ff000831 ff000839 ff000841 ff00084a ff000852 ff00085a ff000862 ff00086a ff000873 ff00087b ff000883 ff00088b ff000894 ff00089c ff0008a4 ff0008ac ff0008b4 ff0008bd ff0008c5 ff0008cd ff0008d5 ff0008de ff0008e6 ff0008ee ff0008f6 ff0008ff 
+ff1f0800 ff1f0808 ff1f0810 ff1f0818 ff1f0820 ff1f0829 ff1f0831 ff1f0839 ff1f0841 ff1f084a ff1f0852 ff1f085a ff1f0862 ff1f086a ff1f0873 ff1f087b ff1f0883 ff1f088b ff1f0894 ff1f089c ff1f08a4 ff1f08ac ff1f08b4 ff1f08bd ff1f08c5 ff1f08cd ff1f08d5 ff1f08de ff1f08e6 ff1f08ee ff1f08f6 ff1f08ff 
+ff3f0800 ff3f0808 ff3f0810 ff3f0818 ff3f0820 ff3f0829 ff3f0831 ff3f0839 ff3f0841 ff3f084a ff3f0852 ff3f085a ff3f0862 ff3f086a ff3f0873 ff3f087b ff3f0883 ff3f088b ff3f0894 ff3f089c ff3f08a4 ff3f08ac ff3f08b4 ff3f08bd ff3f08c5 ff3f08cd ff3f08d5 ff3f08de ff3f08e6 ff3f08ee ff3f08f6 ff3f08ff 
+ff5f0800 ff5f0808 ff5f0810 ff5f0818 ff5f0820 ff5f0829 ff5f0831 ff5f0839 ff5f0841 ff5f084a ff5f0852 ff5f085a ff5f0862 ff5f086a ff5f0873 ff5f087b ff5f0883 ff5f088b ff5f0894 ff5f089c ff5f08a4 ff5f08ac ff5f08b4 ff5f08bd ff5f08c5 ff5f08cd ff5f08d5 ff5f08de ff5f08e6 ff5f08ee ff5f08f6 ff5f08ff 
+ff7f0700 ff7f0708 ff7f0710 ff7f0718 ff7f0720 ff7f0729 ff7f0731 ff7f0739 ff7f0741 ff7f074a ff7f0752 ff7f075a ff7f0762 ff7f076a ff7f0773 ff7f077b ff7f0783 ff7f078b ff7f0794 ff7f079c ff7f07a4 ff7f07ac ff7f07b4 ff7f07bd ff7f07c5 ff7f07cd ff7f07d5 ff7f07de ff7f07e6 ff7f07ee ff7f07f6 ff7f07ff 
+ff9f0700 ff9f0708 ff9f0710 ff9f0718 ff9f0720 ff9f0729 ff9f0731 ff9f0739 ff9f0741 ff9f074a ff9f0752 ff9f075a ff9f0762 ff9f076a ff9f0773 ff9f077b ff9f0783 ff9f078b ff9f0794 ff9f079c ff9f07a4 ff9f07ac ff9f07b4 ff9f07bd ff9f07c5 ff9f07cd ff9f07d5 ff9f07de ff9f07e6 ff9f07ee ff9f07f6 ff9f07ff 
+ffbf0700 ffbf0708 ffbf0710 ffbf0718 ffbf0720 ffbf0729 ffbf0731 ffbf0739 ffbf0741 ffbf074a ffbf0752 ffbf075a ffbf0762 ffbf076a ffbf0773 ffbf077b ffbf0783 ffbf078b ffbf0794 ffbf079c ffbf07a4 ffbf07ac ffbf07b4 ffbf07bd ffbf07c5 ffbf07cd ffbf07d5 ffbf07de ffbf07e6 ffbf07ee ffbf07f6 ffbf07ff 
+ffdf0700 ffdf0708 ffdf0710 ffdf0718 ffdf0720 ffdf0729 ffdf0731 ffdf0739 ffdf0741 ffdf074a ffdf0752 ffdf075a ffdf0762 ffdf076a ffdf0773 ffdf077b ffdf0783 ffdf078b ffdf0794 ffdf079c ffdf07a4 ffdf07ac ffdf07b4 ffdf07bd ffdf07c5 ffdf07cd ffdf07d5 ffdf07de ffdf07e6 ffdf07ee ffdf07f6 ffdf07ff 
+ffff0600 ffff0608 ffff0610 ffff0618 ffff0620 ffff0629 ffff0631 ffff0639 ffff0641 ffff064a ffff0652 ffff065a ffff0662 ffff066a ffff0673 ffff067b ffff0683 ffff068b ffff0694 ffff069c ffff06a4 ffff06ac ffff06b4 ffff06bd ffff06c5 ffff06cd ffff06d5 ffff06de ffff06e6 ffff06ee ffff06f6 ffff06ff 
+e0ff0600 e0ff0608 e0ff0610 e0ff0618 e0ff0620 e0ff0629 e0ff0631 e0ff0639 e0ff0641 e0ff064a e0ff0652 e0ff065a e0ff0662 e0ff066a e0ff0673 e0ff067b e0ff0683 e0ff068b e0ff0694 e0ff069c e0ff06a4 e0ff06ac e0ff06b4 e0ff06bd e0ff06c5 e0ff06cd e0ff06d5 e0ff06de e0ff06e6 e0ff06ee e0ff06f6 e0ff06ff 
+c0ff0600 c0ff0608 c0ff0610 c0ff0618 c0ff0620 c0ff0629 c0ff0631 c0ff0639 c0ff0641 c0ff064a c0ff0652 c0ff065a c0ff0662 c0ff066a c0ff0673 c0ff067b c0ff0683 c0ff068b c0ff0694 c0ff069c c0ff06a4 c0ff06ac c0ff06b4 c0ff06bd c0ff06c5 c0ff06cd c0ff06d5 c0ff06de c0ff06e6 c0ff06ee c0ff06f6 c0ff06ff 
+a0ff0500 a0ff0508 a0ff0510 a0ff0518 a0ff0520 a0ff0529 a0ff0531 a0ff0539 a0ff0541 a0ff054a a0ff0552 a0ff055a a0ff0562 a0ff056a a0ff0573 a0ff057b a0ff0583 a0ff058b a0ff0594 a0ff059c a0ff05a4 a0ff05ac a0ff05b4 a0ff05bd a0ff05c5 a0ff05cd a0ff05d5 a0ff05de a0ff05e6 a0ff05ee a0ff05f6 a0ff05ff 
+80ff0500 80ff0508 80ff0510 80ff0518 80ff0520 80ff0529 80ff0531 80ff0539 80ff0541 80ff054a 80ff0552 80ff055a 80ff0562 80ff056a 80ff0573 80ff057b 80ff0583 80ff058b 80ff0594 80ff059c 80ff05a4 80ff05ac 80ff05b4 80ff05bd 80ff05c5 80ff05cd 80ff05d5 80ff05de 80ff05e6 80ff05ee 80ff05f6 80ff05ff 
+60ff0500 60ff0508 60ff0510 60ff0518 60ff0520 60ff0529 60ff0531 60ff0539 60ff0541 60ff054a 60ff0552 60ff055a 60ff0562 60ff056a 60ff0573 60ff057b 60ff0583 60ff058b 60ff0594 60ff059c 60ff05a4 60ff05ac 60ff05b4 60ff05bd 60ff05c5 60ff05cd 60ff05d5 60ff05de 60ff05e6 60ff05ee 60ff05f6 60ff05ff 
+40ff0500 40ff0508 40ff0510 40ff0518 40ff0520 40ff0529 40ff0531 40ff0539 40ff0541 40ff054a 40ff0552 40ff055a 40ff0562 40ff056a 40ff0573 40ff057b 40ff0583 40ff058b 40ff0594 40ff059c 40ff05a4 40ff05ac 40ff05b4 40ff05bd 40ff05c5 40ff05cd 40ff05d5 40ff05de 40ff05e6 40ff05ee 40ff05f6 40ff05ff 
+20ff0400 20ff0408 20ff0410 20ff0418 20ff0420 20ff0429 20ff0431 20ff0439 20ff0441 20ff044a 20ff0452 20ff045a 20ff0462 20ff046a 20ff0473 20ff047b 20ff0483 20ff048b 20ff0494 20ff049c 20ff04a4 20ff04ac 20ff04b4 20ff04bd 20ff04c5 20ff04cd 20ff04d5 20ff04de 20ff04e6 20ff04ee 20ff04f6 20ff04ff 
+04ff0000 04ff0008 04ff0010 04ff0018 04ff0020 04ff0029 04ff0031 04ff0039 04ff0041 04ff004a 04ff0052 04ff005a 04ff0062 04ff006a 04ff0073 04ff007b 04ff0083 04ff008b 04ff0094 04ff009c 04ff00a4 04ff00ac 04ff00b4 04ff00bd 04ff00c5 04ff00cd 04ff00d5 04ff00de 04ff00e6 04ff00ee 04ff00f6 04ff00ff 
+04ff1f00 04ff1f08 04ff1f10 04ff1f18 04ff1f20 04ff1f29 04ff1f31 04ff1f39 04ff1f41 04ff1f4a 04ff1f52 04ff1f5a 04ff1f62 04ff1f6a 04ff1f73 04ff1f7b 04ff1f83 04ff1f8b 04ff1f94 04ff1f9c 04ff1fa4 04ff1fac 04ff1fb4 04ff1fbd 04ff1fc5 04ff1fcd 04ff1fd5 04ff1fde 04ff1fe6 04ff1fee 04ff1ff6 04ff1fff 
+03ff3f00 03ff3f08 03ff3f10 03ff3f18 03ff3f20 03ff3f29 03ff3f31 03ff3f39 03ff3f41 03ff3f4a 03ff3f52 03ff3f5a 03ff3f62 03ff3f6a 03ff3f73 03ff3f7b 03ff3f83 03ff3f8b 03ff3f94 03ff3f9c 03ff3fa4 03ff3fac 03ff3fb4 03ff3fbd 03ff3fc5 03ff3fcd 03ff3fd5 03ff3fde 03ff3fe6 03ff3fee 03ff3ff6 03ff3fff 
+03ff5f00 03ff5f08 03ff5f10 03ff5f18 03ff5f20 03ff5f29 03ff5f31 03ff5f39 03ff5f41 03ff5f4a 03ff5f52 03ff5f5a 03ff5f62 03ff5f6a 03ff5f73 03ff5f7b 03ff5f83 03ff5f8b 03ff5f94 03ff5f9c 03ff5fa4 03ff5fac 03ff5fb4 03ff5fbd 03ff5fc5 03ff5fcd 03ff5fd5 03ff5fde 03ff5fe6 03ff5fee 03ff5ff6 03ff5fff 
+03ff7f00 03ff7f08 03ff7f10 03ff7f18 03ff7f20 03ff7f29 03ff7f31 03ff7f39 03ff7f41 03ff7f4a 03ff7f52 03ff7f5a 03ff7f62 03ff7f6a 03ff7f73 03ff7f7b 03ff7f83 03ff7f8b 03ff7f94 03ff7f9c 03ff7fa4 03ff7fac 03ff7fb4 03ff7fbd 03ff7fc5 03ff7fcd 03ff7fd5 03ff7fde 03ff7fe6 03ff7fee 03ff7ff6 03ff7fff 
+03ff9f00 03ff9f08 03ff9f10 03ff9f18 03ff9f20 03ff9f29 03ff9f31 03ff9f39 03ff9f41 03ff9f4a 03ff9f52 03ff9f5a 03ff9f62 03ff9f6a 03ff9f73 03ff9f7b 03ff9f83 03ff9f8b 03ff9f94 03ff9f9c 03ff9fa4 03ff9fac 03ff9fb4 03ff9fbd 03ff9fc5 03ff9fcd 03ff9fd5 03ff9fde 03ff9fe6 03ff9fee 03ff9ff6 03ff9fff 
+02ffbf00 02ffbf08 02ffbf10 02ffbf18 02ffbf20 02ffbf29 02ffbf31 02ffbf39 02ffbf41 02ffbf4a 02ffbf52 02ffbf5a 02ffbf62 02ffbf6a 02ffbf73 02ffbf7b 02ffbf83 02ffbf8b 02ffbf94 02ffbf9c 02ffbfa4 02ffbfac 02ffbfb4 02ffbfbd 02ffbfc5 02ffbfcd 02ffbfd5 02ffbfde 02ffbfe6 02ffbfee 02ffbff6 02ffbfff 
+02ffdf00 02ffdf08 02ffdf10 02ffdf18 02ffdf20 02ffdf29 02ffdf31 02ffdf39 02ffdf41 02ffdf4a 02ffdf52 02ffdf5a 02ffdf62 02ffdf6a 02ffdf73 02ffdf7b 02ffdf83 02ffdf8b 02ffdf94 02ffdf9c 02ffdfa4 02ffdfac 02ffdfb4 02ffdfbd 02ffdfc5 02ffdfcd 02ffdfd5 02ffdfde 02ffdfe6 02ffdfee 02ffdff6 02ffdfff 
+02ffff00 02ffff08 02ffff10 02ffff18 02ffff20 02ffff29 02ffff31 02ffff39 02ffff41 02ffff4a 02ffff52 02ffff5a 02ffff62 02ffff6a 02ffff73 02ffff7b 02ffff83 02ffff8b 02ffff94 02ffff9c 02ffffa4 02ffffac 02ffffb4 02ffffbd 02ffffc5 02ffffcd 02ffffd5 02ffffde 02ffffe6 02ffffee 02fffff6 02ffffff 
+01e0ff00 01e0ff08 01e0ff10 01e0ff18 01e0ff20 01e0ff29 01e0ff31 01e0ff39 01e0ff41 01e0ff4a 01e0ff52 01e0ff5a 01e0ff62 01e0ff6a 01e0ff73 01e0ff7b 01e0ff83 01e0ff8b 01e0ff94 01e0ff9c 01e0ffa4 01e0ffac 01e0ffb4 01e0ffbd 01e0ffc5 01e0ffcd 01e0ffd5 01e0ffde 01e0ffe6 01e0ffee 01e0fff6 01e0ffff 
+01c0ff00 01c0ff08 01c0ff10 01c0ff18 01c0ff20 01c0ff29 01c0ff31 01c0ff39 01c0ff41 01c0ff4a 01c0ff52 01c0ff5a 01c0ff62 01c0ff6a 01c0ff73 01c0ff7b 01c0ff83 01c0ff8b 01c0ff94 01c0ff9c 01c0ffa4 01c0ffac 01c0ffb4 01c0ffbd 01c0ffc5 01c0ffcd 01c0ffd5 01c0ffde 01c0ffe6 01c0ffee 01c0fff6 01c0ffff 
+01a0ff00 01a0ff08 01a0ff10 01a0ff18 01a0ff20 01a0ff29 01a0ff31 01a0ff39 01a0ff41 01a0ff4a 01a0ff52 01a0ff5a 01a0ff62 01a0ff6a 01a0ff73 01a0ff7b 01a0ff83 01a0ff8b 01a0ff94 01a0ff9c 01a0ffa4 01a0ffac 01a0ffb4 01a0ffbd 01a0ffc5 01a0ffcd 01a0ffd5 01a0ffde 01a0ffe6 01a0ffee 01a0fff6 01a0ffff 
+0180ff00 0180ff08 0180ff10 0180ff18 0180ff20 0180ff29 0180ff31 0180ff39 0180ff41 0180ff4a 0180ff52 0180ff5a 0180ff62 0180ff6a 0180ff73 0180ff7b 0180ff83 0180ff8b 0180ff94 0180ff9c 0180ffa4 0180ffac 0180ffb4 0180ffbd 0180ffc5 0180ffcd 0180ffd5 0180ffde 0180ffe6 0180ffee 0180fff6 0180ffff 
+0060ff00 0060ff08 0060ff10 0060ff18 0060ff20 0060ff29 0060ff31 0060ff39 0060ff41 0060ff4a 0060ff52 0060ff5a 0060ff62 0060ff6a 0060ff73 0060ff7b 0060ff83 0060ff8b 0060ff94 0060ff9c 0060ffa4 0060ffac 0060ffb4 0060ffbd 0060ffc5 0060ffcd 0060ffd5 0060ffde 0060ffe6 0060ffee 0060fff6 0060ffff 
+0040ff00 0040ff08 0040ff10 0040ff18 0040ff20 0040ff29 0040ff31 0040ff39 0040ff41 0040ff4a 0040ff52 0040ff5a 0040ff62 0040ff6a 0040ff73 0040ff7b 0040ff83 0040ff8b 0040ff94 0040ff9c 0040ffa4 0040ffac 0040ffb4 0040ffbd 0040ffc5 0040ffcd 0040ffd5 0040ffde 0040ffe6 0040ffee 0040fff6 0040ffff 
+0020ff00 0020ff08 0020ff10 0020ff18 0020ff20 0020ff29 0020ff31 0020ff39 0020ff41 0020ff4a 0020ff52 0020ff5a 0020ff62 0020ff6a 0020ff73 0020ff7b 0020ff83 0020ff8b 0020ff94 0020ff9c 0020ffa4 0020ffac 0020ffb4 0020ffbd 0020ffc5 0020ffcd 0020ffd5 0020ffde 0020ffe6 0020ffee 0020fff6 0020ffff 
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn6a16.png b/libgo/go/image/png/testdata/pngsuite/basn6a16.png
new file mode 100644 (file)
index 0000000..a9bf3cb
Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn6a16.png differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn6a16.sng b/libgo/go/image/png/testdata/pngsuite/basn6a16.sng
new file mode 100644 (file)
index 0000000..13c70a4
--- /dev/null
@@ -0,0 +1,41 @@
+#SNG: from basn6a16.png
+IHDR {
+    width: 32; height: 32; bitdepth: 16;
+    using color alpha;
+}
+gAMA {1.0000}
+IMAGE {
+    pixels hex
+ffffffff00000000 f7bcffff00000000 ef7affff00000000 e738ffff00000000 def6ffff00000000 d6b4ffff00000000 ce72ffff00000000 c630ffff00000000 bdeeffff00000000 b5acffff00000000 ad6affff00000000 a528ffff00000000 9ce6ffff00000000 94a4ffff00000000 8c62ffff00000000 8420ffff00000000 7bdeffff00000000 739cffff00000000 6b5affff00000000 6318ffff00000000 5ad6ffff00000000 5294ffff00000000 4a52ffff00000000 4210ffff00000000 39ceffff00000000 318cffff00000000 294affff00000000 2108ffff00000000 18c6ffff00000000 1084ffff00000000 0842ffff00000000 0000ffff00000000 
+fffff7bc00000000 ffffffff00001085 f72bffff00001085 ee57ffff00001085 e583ffff00001085 dcafffff00001085 d3dbffff00001085 cb08ffff00001085 c234ffff00001085 b960ffff00001085 b08cffff00001085 a7b8ffff00001085 9ee4ffff00001085 9611ffff00001085 8d3dffff00001085 8469ffff00001085 7b95ffff00001085 72c1ffff00001085 69edffff00001085 611affff00001085 5846ffff00001085 4f72ffff00001085 469effff00001085 3dcaffff00001085 34f6ffff00001085 2c23ffff00001085 234fffff00001085 1a7bffff00001085 11a7ffff00001085 08d3ffff00001085 0000ffff00001085 0000f7bc08420000 
+ffffef7a00000000 fffff72b00001085 ffffffff00002109 f683ffff00002109 ed08ffff00002109 e38dffff00002109 da12ffff00002109 d096ffff00002109 c71bffff00002109 bda0ffff00002109 b425ffff00002109 aaa9ffff00002109 a12effff00002109 97b3ffff00002109 8e38ffff00002109 84bdffff00002109 7b41ffff00002109 71c6ffff00002109 684bffff00002109 5ed0ffff00002109 5554ffff00002109 4bd9ffff00002109 425effff00002109 38e3ffff00002109 2f68ffff00002109 25ecffff00002109 1c71ffff00002109 12f6ffff00002109 097bffff00002109 0000ffff00002109 0000f72b08d31085 0000ef7a10840000 
+ffffe73800000000 ffffee5700001085 fffff68300002109 ffffffff0000318d f5c1ffff0000318d eb84ffff0000318d e146ffff0000318d d709ffff0000318d ccccffff0000318d c28effff0000318d b851ffff0000318d ae13ffff0000318d a3d6ffff0000318d 9998ffff0000318d 8f5bffff0000318d 851effff0000318d 7ae0ffff0000318d 70a3ffff0000318d 6665ffff0000318d 5c28ffff0000318d 51ebffff0000318d 47adffff0000318d 3d70ffff0000318d 3332ffff0000318d 28f5ffff0000318d 1eb8ffff0000318d 147affff0000318d 0a3dffff0000318d 0000ffff0000318d 0000f683097b2109 0000ee5711a71085 0000e73818c60000 
+ffffdef600000000 ffffe58300001085 ffffed0800002109 fffff5c10000318d ffffffff00004211 f4ddffff00004211 e9bcffff00004211 de9affff00004211 d379ffff00004211 c858ffff00004211 bd36ffff00004211 b215ffff00004211 a6f4ffff00004211 9bd2ffff00004211 90b1ffff00004211 8590ffff00004211 7a6effff00004211 6f4dffff00004211 642cffff00004211 590affff00004211 4de9ffff00004211 42c8ffff00004211 37a6ffff00004211 2c85ffff00004211 2164ffff00004211 1642ffff00004211 0b21ffff00004211 0000ffff00004211 0000f5c10a3d318d 0000ed0812f62109 0000e5831a7b1085 0000def621080000 
+ffffd6b400000000 ffffdcaf00001085 ffffe38d00002109 ffffeb840000318d fffff4dd00004211 ffffffff00005295 f3ceffff00005295 e79dffff00005295 db6cffff00005295 cf3cffff00005295 c30bffff00005295 b6daffff00005295 aaa9ffff00005295 9e79ffff00005295 9248ffff00005295 8617ffff00005295 79e7ffff00005295 6db6ffff00005295 6185ffff00005295 5554ffff00005295 4924ffff00005295 3cf3ffff00005295 30c2ffff00005295 2492ffff00005295 1861ffff00005295 0c30ffff00005295 0000ffff00005295 0000f4dd0b214211 0000eb84147a318d 0000e38d1c712109 0000dcaf234f1085 0000d6b4294a0000 
+ffffce7200000000 ffffd3db00001085 ffffda1200002109 ffffe1460000318d ffffe9bc00004211 fffff3ce00005295 ffffffff00006319 f285ffff00006319 e50cffff00006319 d793ffff00006319 ca1affff00006319 bca0ffff00006319 af27ffff00006319 a1aeffff00006319 9435ffff00006319 86bcffff00006319 7942ffff00006319 6bc9ffff00006319 5e50ffff00006319 50d7ffff00006319 435effff00006319 35e4ffff00006319 286bffff00006319 1af2ffff00006319 0d79ffff00006319 0000ffff00006319 0000f3ce0c305295 0000e9bc16424211 0000e1461eb8318d 0000da1225ec2109 0000d3db2c231085 0000ce72318c0000 
+ffffc63000000000 ffffcb0800001085 ffffd09600002109 ffffd7090000318d ffffde9a00004211 ffffe79d00005295 fffff28500006319 ffffffff0000739d f0f0ffff0000739d e1e1ffff0000739d d2d2ffff0000739d c3c3ffff0000739d b4b3ffff0000739d a5a4ffff0000739d 9695ffff0000739d 8786ffff0000739d 7877ffff0000739d 6968ffff0000739d 5a59ffff0000739d 4b4affff0000739d 3c3bffff0000739d 2d2cffff0000739d 1e1dffff0000739d 0f0effff0000739d 0000ffff0000739d 0000f2850d796319 0000e79d18615295 0000de9a21644211 0000d70928f5318d 0000d0962f682109 0000cb0834f61085 0000c63039ce0000 
+ffffbdee00000000 ffffc23400001085 ffffc71b00002109 ffffcccc0000318d ffffd37900004211 ffffdb6c00005295 ffffe50c00006319 fffff0f00000739d ffffffff00008421 eeeeffff00008421 ddddffff00008421 ccccffff00008421 bbbaffff00008421 aaa9ffff00008421 9998ffff00008421 8887ffff00008421 7776ffff00008421 6665ffff00008421 5554ffff00008421 4443ffff00008421 3332ffff00008421 2221ffff00008421 1110ffff00008421 0000ffff00008421 0000f0f00f0e739d 0000e50c1af26319 0000db6c24925295 0000d3792c854211 0000cccc3332318d 0000c71b38e32109 0000c2343dca1085 0000bdee42100000 
+ffffb5ac00000000 ffffb96000001085 ffffbda000002109 ffffc28e0000318d ffffc85800004211 ffffcf3c00005295 ffffd79300006319 ffffe1e10000739d ffffeeee00008421 ffffffff000094a5 ec4dffff000094a5 d89cffff000094a5 c4ebffff000094a5 b13affff000094a5 9d89ffff000094a5 89d8ffff000094a5 7626ffff000094a5 6275ffff000094a5 4ec4ffff000094a5 3b13ffff000094a5 2762ffff000094a5 13b1ffff000094a5 0000ffff000094a5 0000eeee11108421 0000e1e11e1d739d 0000d793286b6319 0000cf3c30c25295 0000c85837a64211 0000c28e3d70318d 0000bda0425e2109 0000b960469e1085 0000b5ac4a520000 
+ffffad6a00000000 ffffb08c00001085 ffffb42500002109 ffffb8510000318d ffffbd3600004211 ffffc30b00005295 ffffca1a00006319 ffffd2d20000739d ffffdddd00008421 ffffec4d000094a5 ffffffff0000a529 e8b9ffff0000a529 d173ffff0000a529 ba2dffff0000a529 a2e8ffff0000a529 8ba2ffff0000a529 745cffff0000a529 5d16ffff0000a529 45d1ffff0000a529 2e8bffff0000a529 1745ffff0000a529 0000ffff0000a529 0000ec4d13b194a5 0000dddd22218421 0000d2d22d2c739d 0000ca1a35e46319 0000c30b3cf35295 0000bd3642c84211 0000b85147ad318d 0000b4254bd92109 0000b08c4f721085 0000ad6a52940000 
+ffffa52800000000 ffffa7b800001085 ffffaaa900002109 ffffae130000318d ffffb21500004211 ffffb6da00005295 ffffbca000006319 ffffc3c30000739d ffffcccc00008421 ffffd89c000094a5 ffffe8b90000a529 ffffffff0000b5ad e38dffff0000b5ad c71bffff0000b5ad aaa9ffff0000b5ad 8e38ffff0000b5ad 71c6ffff0000b5ad 5554ffff0000b5ad 38e3ffff0000b5ad 1c71ffff0000b5ad 0000ffff0000b5ad 0000e8b91745a529 0000d89c276294a5 0000cccc33328421 0000c3c33c3b739d 0000bca0435e6319 0000b6da49245295 0000b2154de94211 0000ae1351eb318d 0000aaa955542109 0000a7b858461085 0000a5285ad60000 
+ffff9ce600000000 ffff9ee400001085 ffffa12e00002109 ffffa3d60000318d ffffa6f400004211 ffffaaa900005295 ffffaf2700006319 ffffb4b30000739d ffffbbba00008421 ffffc4eb000094a5 ffffd1730000a529 ffffe38d0000b5ad ffffffff0000c631 db6cffff0000c631 b6daffff0000c631 9248ffff0000c631 6db6ffff0000c631 4924ffff0000c631 2492ffff0000c631 0000ffff0000c631 0000e38d1c71b5ad 0000d1732e8ba529 0000c4eb3b1394a5 0000bbba44438421 0000b4b34b4a739d 0000af2750d76319 0000aaa955545295 0000a6f4590a4211 0000a3d65c28318d 0000a12e5ed02109 00009ee4611a1085 00009ce663180000 
+ffff94a400000000 ffff961100001085 ffff97b300002109 ffff99980000318d ffff9bd200004211 ffff9e7900005295 ffffa1ae00006319 ffffa5a40000739d ffffaaa900008421 ffffb13a000094a5 ffffba2d0000a529 ffffc71b0000b5ad ffffdb6c0000c631 ffffffff0000d6b5 ccccffff0000d6b5 9998ffff0000d6b5 6665ffff0000d6b5 3332ffff0000d6b5 0000ffff0000d6b5 0000db6c2492c631 0000c71b38e3b5ad 0000ba2d45d1a529 0000b13a4ec494a5 0000aaa955548421 0000a5a45a59739d 0000a1ae5e506319 00009e7961855295 00009bd2642c4211 000099986665318d 000097b3684b2109 0000961169ed1085 000094a46b5a0000 
+ffff8c6200000000 ffff8d3d00001085 ffff8e3800002109 ffff8f5b0000318d ffff90b100004211 ffff924800005295 ffff943500006319 ffff96950000739d ffff999800008421 ffff9d89000094a5 ffffa2e80000a529 ffffaaa90000b5ad ffffb6da0000c631 ffffcccc0000d6b5 ffffffff0000e739 aaa9ffff0000e739 5554ffff0000e739 0000ffff0000e739 0000cccc3332d6b5 0000b6da4924c631 0000aaa95554b5ad 0000a2e85d16a529 00009d89627594a5 0000999866658421 000096956968739d 000094356bc96319 000092486db65295 000090b16f4d4211 00008f5b70a3318d 00008e3871c62109 00008d3d72c11085 00008c62739c0000 
+ffff842000000000 ffff846900001085 ffff84bd00002109 ffff851e0000318d ffff859000004211 ffff861700005295 ffff86bc00006319 ffff87860000739d ffff888700008421 ffff89d8000094a5 ffff8ba20000a529 ffff8e380000b5ad ffff92480000c631 ffff99980000d6b5 ffffaaa90000e739 ffffffff0000f7bd 0000ffff0000f7bd 0000aaa95554e739 000099986665d6b5 000092486db6c631 00008e3871c6b5ad 00008ba2745ca529 000089d8762694a5 0000888777768421 000087867877739d 000086bc79426319 0000861779e75295 000085907a6e4211 0000851e7ae0318d 000084bd7b412109 000084697b951085 000084207bde0000 
+ffff7bde00000000 ffff7b9500001085 ffff7b4100002109 ffff7ae00000318d ffff7a6e00004211 ffff79e700005295 ffff794200006319 ffff78770000739d ffff777600008421 ffff7626000094a5 ffff745c0000a529 ffff71c60000b5ad ffff6db60000c631 ffff66650000d6b5 ffff55540000e739 ffff00000000f7bd 00000000fffff7bd 00005554aaa9e739 000066659998d6b5 00006db69248c631 000071c68e38b5ad 0000745c8ba2a529 0000762689d894a5 0000777688878421 000078778786739d 0000794286bc6319 000079e786175295 00007a6e85904211 00007ae0851e318d 00007b4184bd2109 00007b9584691085 00007bde84200000 
+ffff739c00000000 ffff72c100001085 ffff71c600002109 ffff70a30000318d ffff6f4d00004211 ffff6db600005295 ffff6bc900006319 ffff69680000739d ffff666500008421 ffff6275000094a5 ffff5d160000a529 ffff55540000b5ad ffff49240000c631 ffff33320000d6b5 ffff00000000e739 aaa900005554e739 55540000aaa9e739 00000000ffffe739 00003332ccccd6b5 00004924b6dac631 00005554aaa9b5ad 00005d16a2e8a529 000062759d8994a5 0000666599988421 000069689695739d 00006bc994356319 00006db692485295 00006f4d90b14211 000070a38f5b318d 000071c68e382109 000072c18d3d1085 0000739c8c620000 
+ffff6b5a00000000 ffff69ed00001085 ffff684b00002109 ffff66650000318d ffff642c00004211 ffff618500005295 ffff5e5000006319 ffff5a590000739d ffff555400008421 ffff4ec4000094a5 ffff45d10000a529 ffff38e30000b5ad ffff24920000c631 ffff00000000d6b5 cccc00003332d6b5 999800006665d6b5 666500009998d6b5 33320000ccccd6b5 00000000ffffd6b5 00002492db6cc631 000038e3c71bb5ad 000045d1ba2da529 00004ec4b13a94a5 00005554aaa98421 00005a59a5a4739d 00005e50a1ae6319 000061859e795295 0000642c9bd24211 000066659998318d 0000684b97b32109 000069ed96111085 00006b5a94a40000 
+ffff631800000000 ffff611a00001085 ffff5ed000002109 ffff5c280000318d ffff590a00004211 ffff555400005295 ffff50d700006319 ffff4b4a0000739d ffff444300008421 ffff3b13000094a5 ffff2e8b0000a529 ffff1c710000b5ad ffff00000000c631 db6c00002492c631 b6da00004924c631 924800006db6c631 6db600009248c631 49240000b6dac631 24920000db6cc631 00000000ffffc631 00001c71e38db5ad 00002e8bd173a529 00003b13c4eb94a5 00004443bbba8421 00004b4ab4b3739d 000050d7af276319 00005554aaa95295 0000590aa6f44211 00005c28a3d6318d 00005ed0a12e2109 0000611a9ee41085 000063189ce60000 
+ffff5ad600000000 ffff584600001085 ffff555400002109 ffff51eb0000318d ffff4de900004211 ffff492400005295 ffff435e00006319 ffff3c3b0000739d ffff333200008421 ffff2762000094a5 ffff17450000a529 ffff00000000b5ad e38d00001c71b5ad c71b000038e3b5ad aaa900005554b5ad 8e38000071c6b5ad 71c600008e38b5ad 55540000aaa9b5ad 38e30000c71bb5ad 1c710000e38db5ad 00000000ffffb5ad 00001745e8b9a529 00002762d89c94a5 00003332cccc8421 00003c3bc3c3739d 0000435ebca06319 00004924b6da5295 00004de9b2154211 000051ebae13318d 00005554aaa92109 00005846a7b81085 00005ad6a5280000 
+ffff529400000000 ffff4f7200001085 ffff4bd900002109 ffff47ad0000318d ffff42c800004211 ffff3cf300005295 ffff35e400006319 ffff2d2c0000739d ffff222100008421 ffff13b1000094a5 ffff00000000a529 e8b900001745a529 d17300002e8ba529 ba2d000045d1a529 a2e800005d16a529 8ba20000745ca529 745c00008ba2a529 5d160000a2e8a529 45d10000ba2da529 2e8b0000d173a529 17450000e8b9a529 00000000ffffa529 000013b1ec4d94a5 00002221dddd8421 00002d2cd2d2739d 000035e4ca1a6319 00003cf3c30b5295 000042c8bd364211 000047adb851318d 00004bd9b4252109 00004f72b08c1085 00005294ad6a0000 
+ffff4a5200000000 ffff469e00001085 ffff425e00002109 ffff3d700000318d ffff37a600004211 ffff30c200005295 ffff286b00006319 ffff1e1d0000739d ffff111000008421 ffff0000000094a5 ec4d000013b194a5 d89c0000276294a5 c4eb00003b1394a5 b13a00004ec494a5 9d890000627594a5 89d80000762694a5 7626000089d894a5 627500009d8994a5 4ec40000b13a94a5 3b130000c4eb94a5 27620000d89c94a5 13b10000ec4d94a5 00000000ffff94a5 00001110eeee8421 00001e1de1e1739d 0000286bd7936319 000030c2cf3c5295 000037a6c8584211 00003d70c28e318d 0000425ebda02109 0000469eb9601085 00004a52b5ac0000 
+ffff421000000000 ffff3dca00001085 ffff38e300002109 ffff33320000318d ffff2c8500004211 ffff249200005295 ffff1af200006319 ffff0f0e0000739d ffff000000008421 eeee000011108421 dddd000022218421 cccc000033328421 bbba000044438421 aaa9000055548421 9998000066658421 8887000077768421 7776000088878421 6665000099988421 55540000aaa98421 44430000bbba8421 33320000cccc8421 22210000dddd8421 11100000eeee8421 00000000ffff8421 00000f0ef0f0739d 00001af2e50c6319 00002492db6c5295 00002c85d3794211 00003332cccc318d 000038e3c71b2109 00003dcac2341085 00004210bdee0000 
+ffff39ce00000000 ffff34f600001085 ffff2f6800002109 ffff28f50000318d ffff216400004211 ffff186100005295 ffff0d7900006319 ffff00000000739d f0f000000f0e739d e1e100001e1d739d d2d200002d2c739d c3c300003c3b739d b4b300004b4a739d a5a400005a59739d 969500006968739d 878600007877739d 787700008786739d 696800009695739d 5a590000a5a4739d 4b4a0000b4b3739d 3c3b0000c3c3739d 2d2c0000d2d2739d 1e1d0000e1e1739d 0f0e0000f0f0739d 00000000ffff739d 00000d79f2856319 00001861e79d5295 00002164de9a4211 000028f5d709318d 00002f68d0962109 000034f6cb081085 000039cec6300000 
+ffff318c00000000 ffff2c2300001085 ffff25ec00002109 ffff1eb80000318d ffff164200004211 ffff0c3000005295 ffff000000006319 f28500000d796319 e50c00001af26319 d7930000286b6319 ca1a000035e46319 bca00000435e6319 af27000050d76319 a1ae00005e506319 943500006bc96319 86bc000079426319 7942000086bc6319 6bc9000094356319 5e500000a1ae6319 50d70000af276319 435e0000bca06319 35e40000ca1a6319 286b0000d7936319 1af20000e50c6319 0d790000f2856319 00000000ffff6319 00000c30f3ce5295 00001642e9bc4211 00001eb8e146318d 000025ecda122109 00002c23d3db1085 0000318cce720000 
+ffff294a00000000 ffff234f00001085 ffff1c7100002109 ffff147a0000318d ffff0b2100004211 ffff000000005295 f3ce00000c305295 e79d000018615295 db6c000024925295 cf3c000030c25295 c30b00003cf35295 b6da000049245295 aaa9000055545295 9e79000061855295 924800006db65295 8617000079e75295 79e7000086175295 6db6000092485295 618500009e795295 55540000aaa95295 49240000b6da5295 3cf30000c30b5295 30c20000cf3c5295 24920000db6c5295 18610000e79d5295 0c300000f3ce5295 00000000ffff5295 00000b21f4dd4211 0000147aeb84318d 00001c71e38d2109 0000234fdcaf1085 0000294ad6b40000 
+ffff210800000000 ffff1a7b00001085 ffff12f600002109 ffff0a3d0000318d ffff000000004211 f4dd00000b214211 e9bc000016424211 de9a000021644211 d37900002c854211 c858000037a64211 bd36000042c84211 b21500004de94211 a6f40000590a4211 9bd20000642c4211 90b100006f4d4211 859000007a6e4211 7a6e000085904211 6f4d000090b14211 642c00009bd24211 590a0000a6f44211 4de90000b2154211 42c80000bd364211 37a60000c8584211 2c850000d3794211 21640000de9a4211 16420000e9bc4211 0b210000f4dd4211 00000000ffff4211 00000a3df5c1318d 000012f6ed082109 00001a7be5831085 00002108def60000 
+ffff18c600000000 ffff11a700001085 ffff097b00002109 ffff00000000318d f5c100000a3d318d eb840000147a318d e14600001eb8318d d709000028f5318d cccc00003332318d c28e00003d70318d b851000047ad318d ae13000051eb318d a3d600005c28318d 999800006665318d 8f5b000070a3318d 851e00007ae0318d 7ae00000851e318d 70a300008f5b318d 666500009998318d 5c280000a3d6318d 51eb0000ae13318d 47ad0000b851318d 3d700000c28e318d 33320000cccc318d 28f50000d709318d 1eb80000e146318d 147a0000eb84318d 0a3d0000f5c1318d 00000000ffff318d 0000097bf6832109 000011a7ee571085 000018c6e7380000 
+ffff108400000000 ffff08d300001085 ffff000000002109 f6830000097b2109 ed08000012f62109 e38d00001c712109 da12000025ec2109 d09600002f682109 c71b000038e32109 bda00000425e2109 b42500004bd92109 aaa9000055542109 a12e00005ed02109 97b30000684b2109 8e38000071c62109 84bd00007b412109 7b41000084bd2109 71c600008e382109 684b000097b32109 5ed00000a12e2109 55540000aaa92109 4bd90000b4252109 425e0000bda02109 38e30000c71b2109 2f680000d0962109 25ec0000da122109 1c710000e38d2109 12f60000ed082109 097b0000f6832109 00000000ffff2109 000008d3f72b1085 00001084ef7a0000 
+ffff084200000000 ffff000000001085 f72b000008d31085 ee57000011a71085 e58300001a7b1085 dcaf0000234f1085 d3db00002c231085 cb08000034f61085 c23400003dca1085 b9600000469e1085 b08c00004f721085 a7b8000058461085 9ee40000611a1085 9611000069ed1085 8d3d000072c11085 846900007b951085 7b95000084691085 72c100008d3d1085 69ed000096111085 611a00009ee41085 58460000a7b81085 4f720000b08c1085 469e0000b9601085 3dca0000c2341085 34f60000cb081085 2c230000d3db1085 234f0000dcaf1085 1a7b0000e5831085 11a70000ee571085 08d30000f72b1085 00000000ffff1085 00000842f7bc0000 
+ffff000000000000 f7bc000008420000 ef7a000010840000 e738000018c60000 def6000021080000 d6b40000294a0000 ce720000318c0000 c630000039ce0000 bdee000042100000 b5ac00004a520000 ad6a000052940000 a52800005ad60000 9ce6000063180000 94a400006b5a0000 8c620000739c0000 842000007bde0000 7bde000084200000 739c00008c620000 6b5a000094a40000 631800009ce60000 5ad60000a5280000 52940000ad6a0000 4a520000b5ac0000 42100000bdee0000 39ce0000c6300000 318c0000ce720000 294a0000d6b40000 21080000def60000 18c60000e7380000 10840000ef7a0000 08420000f7bc0000 00000000ffff0000 
+}
diff --git a/libgo/go/image/png/writer.go b/libgo/go/image/png/writer.go
new file mode 100644 (file)
index 0000000..081d06b
--- /dev/null
@@ -0,0 +1,437 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package png
+
+import (
+       "bufio"
+       "compress/zlib"
+       "hash/crc32"
+       "image"
+       "io"
+       "os"
+       "strconv"
+)
+
+type encoder struct {
+       w      io.Writer
+       m      image.Image
+       cb     int
+       err    os.Error
+       header [8]byte
+       footer [4]byte
+       tmp    [3 * 256]byte
+}
+
+// Big-endian.
+func writeUint32(b []uint8, u uint32) {
+       b[0] = uint8(u >> 24)
+       b[1] = uint8(u >> 16)
+       b[2] = uint8(u >> 8)
+       b[3] = uint8(u >> 0)
+}
+
+type opaquer interface {
+       Opaque() bool
+}
+
+// Returns whether or not the image is fully opaque.
+func opaque(m image.Image) bool {
+       if o, ok := m.(opaquer); ok {
+               return o.Opaque()
+       }
+       b := m.Bounds()
+       for y := b.Min.Y; y < b.Max.Y; y++ {
+               for x := b.Min.X; x < b.Max.X; x++ {
+                       _, _, _, a := m.At(x, y).RGBA()
+                       if a != 0xffff {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
+// The absolute value of a byte interpreted as a signed int8.
+func abs8(d uint8) int {
+       if d < 128 {
+               return int(d)
+       }
+       return 256 - int(d)
+}
+
+func (e *encoder) writeChunk(b []byte, name string) {
+       if e.err != nil {
+               return
+       }
+       n := uint32(len(b))
+       if int(n) != len(b) {
+               e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b)))
+               return
+       }
+       writeUint32(e.header[0:4], n)
+       e.header[4] = name[0]
+       e.header[5] = name[1]
+       e.header[6] = name[2]
+       e.header[7] = name[3]
+       crc := crc32.NewIEEE()
+       crc.Write(e.header[4:8])
+       crc.Write(b)
+       writeUint32(e.footer[0:4], crc.Sum32())
+
+       _, e.err = e.w.Write(e.header[0:8])
+       if e.err != nil {
+               return
+       }
+       _, e.err = e.w.Write(b)
+       if e.err != nil {
+               return
+       }
+       _, e.err = e.w.Write(e.footer[0:4])
+}
+
+func (e *encoder) writeIHDR() {
+       b := e.m.Bounds()
+       writeUint32(e.tmp[0:4], uint32(b.Dx()))
+       writeUint32(e.tmp[4:8], uint32(b.Dy()))
+       // Set bit depth and color type.
+       switch e.cb {
+       case cbG8:
+               e.tmp[8] = 8
+               e.tmp[9] = ctGrayscale
+       case cbTC8:
+               e.tmp[8] = 8
+               e.tmp[9] = ctTrueColor
+       case cbP8:
+               e.tmp[8] = 8
+               e.tmp[9] = ctPaletted
+       case cbTCA8:
+               e.tmp[8] = 8
+               e.tmp[9] = ctTrueColorAlpha
+       case cbG16:
+               e.tmp[8] = 16
+               e.tmp[9] = ctGrayscale
+       case cbTC16:
+               e.tmp[8] = 16
+               e.tmp[9] = ctTrueColor
+       case cbTCA16:
+               e.tmp[8] = 16
+               e.tmp[9] = ctTrueColorAlpha
+       }
+       e.tmp[10] = 0 // default compression method
+       e.tmp[11] = 0 // default filter method
+       e.tmp[12] = 0 // non-interlaced
+       e.writeChunk(e.tmp[0:13], "IHDR")
+}
+
+func (e *encoder) writePLTE(p image.PalettedColorModel) {
+       if len(p) < 1 || len(p) > 256 {
+               e.err = FormatError("bad palette length: " + strconv.Itoa(len(p)))
+               return
+       }
+       for i := 0; i < len(p); i++ {
+               r, g, b, a := p[i].RGBA()
+               if a != 0xffff {
+                       e.err = UnsupportedError("non-opaque palette color")
+                       return
+               }
+               e.tmp[3*i+0] = uint8(r >> 8)
+               e.tmp[3*i+1] = uint8(g >> 8)
+               e.tmp[3*i+2] = uint8(b >> 8)
+       }
+       e.writeChunk(e.tmp[0:3*len(p)], "PLTE")
+}
+
+// An encoder is an io.Writer that satisfies writes by writing PNG IDAT chunks,
+// including an 8-byte header and 4-byte CRC checksum per Write call. Such calls
+// should be relatively infrequent, since writeIDATs uses a bufio.Writer.
+//
+// This method should only be called from writeIDATs (via writeImage).
+// No other code should treat an encoder as an io.Writer.
+//
+// Note that, because the zlib Reader may involve an io.Pipe, e.Write calls may
+// occur on a separate go-routine than the e.writeIDATs call, and care should be
+// taken that e's state (such as its tmp buffer) is not modified concurrently.
+func (e *encoder) Write(b []byte) (int, os.Error) {
+       e.writeChunk(b, "IDAT")
+       if e.err != nil {
+               return 0, e.err
+       }
+       return len(b), nil
+}
+
+// Chooses the filter to use for encoding the current row, and applies it.
+// The return value is the index of the filter and also of the row in cr that has had it applied.
+func filter(cr [][]byte, pr []byte, bpp int) int {
+       // We try all five filter types, and pick the one that minimizes the sum of absolute differences.
+       // This is the same heuristic that libpng uses, although the filters are attempted in order of
+       // estimated most likely to be minimal (ftUp, ftPaeth, ftNone, ftSub, ftAverage), rather than
+       // in their enumeration order (ftNone, ftSub, ftUp, ftAverage, ftPaeth).
+       cdat0 := cr[0][1:]
+       cdat1 := cr[1][1:]
+       cdat2 := cr[2][1:]
+       cdat3 := cr[3][1:]
+       cdat4 := cr[4][1:]
+       pdat := pr[1:]
+       n := len(cdat0)
+
+       // The up filter.
+       sum := 0
+       for i := 0; i < n; i++ {
+               cdat2[i] = cdat0[i] - pdat[i]
+               sum += abs8(cdat2[i])
+       }
+       best := sum
+       filter := ftUp
+
+       // The Paeth filter.
+       sum = 0
+       for i := 0; i < bpp; i++ {
+               cdat4[i] = cdat0[i] - paeth(0, pdat[i], 0)
+               sum += abs8(cdat4[i])
+       }
+       for i := bpp; i < n; i++ {
+               cdat4[i] = cdat0[i] - paeth(cdat0[i-bpp], pdat[i], pdat[i-bpp])
+               sum += abs8(cdat4[i])
+               if sum >= best {
+                       break
+               }
+       }
+       if sum < best {
+               best = sum
+               filter = ftPaeth
+       }
+
+       // The none filter.
+       sum = 0
+       for i := 0; i < n; i++ {
+               sum += abs8(cdat0[i])
+               if sum >= best {
+                       break
+               }
+       }
+       if sum < best {
+               best = sum
+               filter = ftNone
+       }
+
+       // The sub filter.
+       sum = 0
+       for i := 0; i < bpp; i++ {
+               cdat1[i] = cdat0[i]
+               sum += abs8(cdat1[i])
+       }
+       for i := bpp; i < n; i++ {
+               cdat1[i] = cdat0[i] - cdat0[i-bpp]
+               sum += abs8(cdat1[i])
+               if sum >= best {
+                       break
+               }
+       }
+       if sum < best {
+               best = sum
+               filter = ftSub
+       }
+
+       // The average filter.
+       sum = 0
+       for i := 0; i < bpp; i++ {
+               cdat3[i] = cdat0[i] - pdat[i]/2
+               sum += abs8(cdat3[i])
+       }
+       for i := bpp; i < n; i++ {
+               cdat3[i] = cdat0[i] - uint8((int(cdat0[i-bpp])+int(pdat[i]))/2)
+               sum += abs8(cdat3[i])
+               if sum >= best {
+                       break
+               }
+       }
+       if sum < best {
+               best = sum
+               filter = ftAverage
+       }
+
+       return filter
+}
+
+func writeImage(w io.Writer, m image.Image, cb int) os.Error {
+       zw, err := zlib.NewWriter(w)
+       if err != nil {
+               return err
+       }
+       defer zw.Close()
+
+       bpp := 0 // Bytes per pixel.
+       var paletted *image.Paletted
+       switch cb {
+       case cbG8:
+               bpp = 1
+       case cbTC8:
+               bpp = 3
+       case cbP8:
+               bpp = 1
+               paletted = m.(*image.Paletted)
+       case cbTCA8:
+               bpp = 4
+       case cbTC16:
+               bpp = 6
+       case cbTCA16:
+               bpp = 8
+       case cbG16:
+               bpp = 2
+       }
+       // cr[*] and pr are the bytes for the current and previous row.
+       // cr[0] is unfiltered (or equivalently, filtered with the ftNone filter).
+       // cr[ft], for non-zero filter types ft, are buffers for transforming cr[0] under the
+       // other PNG filter types. These buffers are allocated once and re-used for each row.
+       // The +1 is for the per-row filter type, which is at cr[*][0].
+       b := m.Bounds()
+       var cr [nFilter][]uint8
+       for i := 0; i < len(cr); i++ {
+               cr[i] = make([]uint8, 1+bpp*b.Dx())
+               cr[i][0] = uint8(i)
+       }
+       pr := make([]uint8, 1+bpp*b.Dx())
+
+       for y := b.Min.Y; y < b.Max.Y; y++ {
+               // Convert from colors to bytes.
+               switch cb {
+               case cbG8:
+                       for x := b.Min.X; x < b.Max.X; x++ {
+                               c := image.GrayColorModel.Convert(m.At(x, y)).(image.GrayColor)
+                               cr[0][x+1] = c.Y
+                       }
+               case cbTC8:
+                       for x := b.Min.X; x < b.Max.X; x++ {
+                               // We have previously verified that the alpha value is fully opaque.
+                               r, g, b, _ := m.At(x, y).RGBA()
+                               cr[0][3*x+1] = uint8(r >> 8)
+                               cr[0][3*x+2] = uint8(g >> 8)
+                               cr[0][3*x+3] = uint8(b >> 8)
+                       }
+               case cbP8:
+                       rowOffset := y * paletted.Stride
+                       copy(cr[0][b.Min.X+1:], paletted.Pix[rowOffset+b.Min.X:rowOffset+b.Max.X])
+               case cbTCA8:
+                       // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
+                       for x := b.Min.X; x < b.Max.X; x++ {
+                               c := image.NRGBAColorModel.Convert(m.At(x, y)).(image.NRGBAColor)
+                               cr[0][4*x+1] = c.R
+                               cr[0][4*x+2] = c.G
+                               cr[0][4*x+3] = c.B
+                               cr[0][4*x+4] = c.A
+                       }
+               case cbG16:
+                       for x := b.Min.X; x < b.Max.X; x++ {
+                               c := image.Gray16ColorModel.Convert(m.At(x, y)).(image.Gray16Color)
+                               cr[0][2*x+1] = uint8(c.Y >> 8)
+                               cr[0][2*x+2] = uint8(c.Y)
+                       }
+               case cbTC16:
+                       for x := b.Min.X; x < b.Max.X; x++ {
+                               // We have previously verified that the alpha value is fully opaque.
+                               r, g, b, _ := m.At(x, y).RGBA()
+                               cr[0][6*x+1] = uint8(r >> 8)
+                               cr[0][6*x+2] = uint8(r)
+                               cr[0][6*x+3] = uint8(g >> 8)
+                               cr[0][6*x+4] = uint8(g)
+                               cr[0][6*x+5] = uint8(b >> 8)
+                               cr[0][6*x+6] = uint8(b)
+                       }
+               case cbTCA16:
+                       // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
+                       for x := b.Min.X; x < b.Max.X; x++ {
+                               c := image.NRGBA64ColorModel.Convert(m.At(x, y)).(image.NRGBA64Color)
+                               cr[0][8*x+1] = uint8(c.R >> 8)
+                               cr[0][8*x+2] = uint8(c.R)
+                               cr[0][8*x+3] = uint8(c.G >> 8)
+                               cr[0][8*x+4] = uint8(c.G)
+                               cr[0][8*x+5] = uint8(c.B >> 8)
+                               cr[0][8*x+6] = uint8(c.B)
+                               cr[0][8*x+7] = uint8(c.A >> 8)
+                               cr[0][8*x+8] = uint8(c.A)
+                       }
+               }
+
+               // Apply the filter.
+               f := filter(cr[0:nFilter], pr, bpp)
+
+               // Write the compressed bytes.
+               _, err = zw.Write(cr[f])
+               if err != nil {
+                       return err
+               }
+
+               // The current row for y is the previous row for y+1.
+               pr, cr[0] = cr[0], pr
+       }
+       return nil
+}
+
+// Write the actual image data to one or more IDAT chunks.
+func (e *encoder) writeIDATs() {
+       if e.err != nil {
+               return
+       }
+       var bw *bufio.Writer
+       bw, e.err = bufio.NewWriterSize(e, 1<<15)
+       if e.err != nil {
+               return
+       }
+       e.err = writeImage(bw, e.m, e.cb)
+       if e.err != nil {
+               return
+       }
+       e.err = bw.Flush()
+}
+
+func (e *encoder) writeIEND() { e.writeChunk(e.tmp[0:0], "IEND") }
+
+// Encode writes the Image m to w in PNG format. Any Image may be encoded, but
+// images that are not image.NRGBA might be encoded lossily.
+func Encode(w io.Writer, m image.Image) os.Error {
+       // Obviously, negative widths and heights are invalid. Furthermore, the PNG
+       // spec section 11.2.2 says that zero is invalid. Excessively large images are
+       // also rejected.
+       mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy())
+       if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
+               return FormatError("invalid image size: " + strconv.Itoa64(mw) + "x" + strconv.Itoa64(mw))
+       }
+
+       var e encoder
+       e.w = w
+       e.m = m
+       pal, _ := m.(*image.Paletted)
+       if pal != nil {
+               e.cb = cbP8
+       } else {
+               switch m.ColorModel() {
+               case image.GrayColorModel:
+                       e.cb = cbG8
+               case image.Gray16ColorModel:
+                       e.cb = cbG16
+               case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel:
+                       if opaque(m) {
+                               e.cb = cbTC8
+                       } else {
+                               e.cb = cbTCA8
+                       }
+               default:
+                       if opaque(m) {
+                               e.cb = cbTC16
+                       } else {
+                               e.cb = cbTCA16
+                       }
+               }
+       }
+
+       _, e.err = io.WriteString(w, pngHeader)
+       e.writeIHDR()
+       if pal != nil {
+               e.writePLTE(pal.Palette)
+       }
+       e.writeIDATs()
+       e.writeIEND()
+       return e.err
+}
diff --git a/libgo/go/image/png/writer_test.go b/libgo/go/image/png/writer_test.go
new file mode 100644 (file)
index 0000000..f218a55
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package png
+
+import (
+       "bytes"
+       "fmt"
+       "image"
+       "io"
+       "os"
+       "testing"
+)
+
+func diff(m0, m1 image.Image) os.Error {
+       b0, b1 := m0.Bounds(), m1.Bounds()
+       if !b0.Eq(b1) {
+               return fmt.Errorf("dimensions differ: %v vs %v", b0, b1)
+       }
+       for y := b0.Min.Y; y < b0.Max.Y; y++ {
+               for x := b0.Min.X; x < b0.Max.X; x++ {
+                       r0, g0, b0, a0 := m0.At(x, y).RGBA()
+                       r1, g1, b1, a1 := m1.At(x, y).RGBA()
+                       if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
+                               return fmt.Errorf("colors differ at (%d, %d): %v vs %v", x, y, m0.At(x, y), m1.At(x, y))
+                       }
+               }
+       }
+       return nil
+}
+
+func TestWriter(t *testing.T) {
+       // The filenames variable is declared in reader_test.go.
+       for _, fn := range filenames {
+               qfn := "testdata/pngsuite/" + fn + ".png"
+               // Read the image.
+               m0, err := readPng(qfn)
+               if err != nil {
+                       t.Error(fn, err)
+                       continue
+               }
+               // Read the image again, and push it through a pipe that encodes at the write end, and decodes at the read end.
+               pr, pw := io.Pipe()
+               defer pr.Close()
+               go func() {
+                       defer pw.Close()
+                       m1, err := readPng(qfn)
+                       if err != nil {
+                               t.Error(fn, err)
+                               return
+                       }
+                       err = Encode(pw, m1)
+                       if err != nil {
+                               t.Error(fn, err)
+                               return
+                       }
+               }()
+               m2, err := Decode(pr)
+               if err != nil {
+                       t.Error(fn, err)
+                       continue
+               }
+               // Compare the two.
+               err = diff(m0, m2)
+               if err != nil {
+                       t.Error(fn, err)
+                       continue
+               }
+       }
+}
+
+func BenchmarkEncodePaletted(b *testing.B) {
+       b.StopTimer()
+       img := image.NewPaletted(640, 480,
+               []image.Color{
+                       image.RGBAColor{0, 0, 0, 255},
+                       image.RGBAColor{255, 255, 255, 255},
+               })
+       b.StartTimer()
+       buffer := new(bytes.Buffer)
+       for i := 0; i < b.N; i++ {
+               buffer.Reset()
+               Encode(buffer, img)
+       }
+}
diff --git a/libgo/go/index/suffixarray/suffixarray.go b/libgo/go/index/suffixarray/suffixarray.go
new file mode 100644 (file)
index 0000000..0a17472
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The suffixarray package implements substring search in logarithmic time
+// using an in-memory suffix array.
+//
+// Example use:
+//
+//     // create index for some data
+//     index := suffixarray.New(data)
+//
+//     // lookup byte slice s
+//     offsets1 := index.Lookup(s, -1) // the list of all indices where s occurs in data
+//     offsets2 := index.Lookup(s, 3)  // the list of at most 3 indices where s occurs in data
+//
+package suffixarray
+
+import (
+       "bytes"
+       "container/vector"
+       "sort"
+)
+
+// BUG(gri): For larger data (10MB) which contains very long (say 100000)
+// contiguous sequences of identical bytes, index creation time will be extremely slow.
+
+// TODO(gri): Use a more sophisticated algorithm to create the suffix array.
+
+
+// Index implements a suffix array for fast substring search.
+type Index struct {
+       data []byte
+       sa   []int // suffix array for data
+}
+
+
+// New creates a new Index for data.
+// Index creation time is approximately O(N*log(N)) for N = len(data).
+//
+func New(data []byte) *Index {
+       sa := make([]int, len(data))
+       for i, _ := range sa {
+               sa[i] = i
+       }
+       x := &Index{data, sa}
+       sort.Sort((*index)(x))
+       return x
+}
+
+
+func (x *Index) at(i int) []byte {
+       return x.data[x.sa[i]:]
+}
+
+
+// Binary search according to "A Method of Programming", E.W. Dijkstra.
+func (x *Index) search(s []byte) int {
+       i, j := 0, len(x.sa)
+       // i < j for non-empty x
+       for i+1 < j {
+               // 0 <= i < j <= len(x.sa) && (x.at(i) <= s < x.at(j) || (s is not in x))
+               h := i + (j-i)/2 // i < h < j
+               if bytes.Compare(x.at(h), s) <= 0 {
+                       i = h
+               } else { // s < x.at(h)
+                       j = h
+               }
+       }
+       // i+1 == j for non-empty x
+       return i
+}
+
+
+// Lookup returns an unsorted list of at most n indices where the byte string s
+// occurs in the indexed data. If n < 0, all occurrences are returned.
+// The result is nil if s is empty, s is not found, or n == 0.
+// Lookup time is O((log(N) + len(result))*len(s)) where N is the
+// size of the indexed data.
+//
+func (x *Index) Lookup(s []byte, n int) []int {
+       var res vector.IntVector
+
+       if len(s) > 0 && n != 0 {
+               // find matching suffix index i
+               i := x.search(s)
+               // x.at(i) <= s < x.at(i+1)
+
+               // ignore the first suffix if it is < s
+               if i < len(x.sa) && bytes.Compare(x.at(i), s) < 0 {
+                       i++
+               }
+
+               // collect the following suffixes with matching prefixes
+               for (n < 0 || len(res) < n) && i < len(x.sa) && bytes.HasPrefix(x.at(i), s) {
+                       res.Push(x.sa[i])
+                       i++
+               }
+       }
+
+       return res
+}
+
+
+// index is used to hide the sort.Interface
+type index Index
+
+func (x *index) Len() int           { return len(x.sa) }
+func (x *index) Less(i, j int) bool { return bytes.Compare(x.at(i), x.at(j)) < 0 }
+func (x *index) Swap(i, j int)      { x.sa[i], x.sa[j] = x.sa[j], x.sa[i] }
+func (a *index) at(i int) []byte    { return a.data[a.sa[i]:] }
diff --git a/libgo/go/index/suffixarray/suffixarray_test.go b/libgo/go/index/suffixarray/suffixarray_test.go
new file mode 100644 (file)
index 0000000..8280750
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package suffixarray
+
+import (
+       "container/vector"
+       "sort"
+       "strings"
+       "testing"
+)
+
+
+type testCase struct {
+       name    string   // name of test case
+       source  string   // source to index
+       lookups []string // strings to lookup
+}
+
+
+var testCases = []testCase{
+       {
+               "empty string",
+               "",
+               []string{
+                       "",
+                       "foo",
+               },
+       },
+
+       {
+               "all a's",
+               "aaaaaaaaaa", // 10 a's
+               []string{
+                       "",
+                       "a",
+                       "aa",
+                       "aaa",
+                       "aaaa",
+                       "aaaaa",
+                       "aaaaaa",
+                       "aaaaaaa",
+                       "aaaaaaaa",
+                       "aaaaaaaaa",
+                       "aaaaaaaaaa",
+                       "aaaaaaaaaaa", // 11 a's
+               },
+       },
+
+       {
+               "abc",
+               "abc",
+               []string{
+                       "a",
+                       "b",
+                       "c",
+                       "ab",
+                       "bc",
+                       "abc",
+               },
+       },
+
+       {
+               "barbara*3",
+               "barbarabarbarabarbara",
+               []string{
+                       "a",
+                       "bar",
+                       "rab",
+                       "arab",
+                       "barbar",
+               },
+       },
+
+       {
+               "typing drill",
+               "Now is the time for all good men to come to the aid of their country.",
+               []string{
+                       "Now",
+                       "the time",
+                       "to come the aid",
+                       "is the time for all good men to come to the aid of their",
+               },
+       },
+}
+
+
+// find all occurences of s in source; report at most n occurences
+func find(src, s string, n int) []int {
+       var res vector.IntVector
+       if s != "" && n != 0 {
+               // find at most n occurences of s in src
+               for i := -1; n < 0 || len(res) < n; {
+                       j := strings.Index(src[i+1:], s)
+                       if j < 0 {
+                               break
+                       }
+                       i += j + 1
+                       res.Push(i)
+               }
+       }
+       return res
+}
+
+
+func testLookups(t *testing.T, src string, x *Index, tc *testCase, n int) {
+       for _, s := range tc.lookups {
+               res := x.Lookup([]byte(s), n)
+               exp := find(tc.source, s, n)
+
+               // check that the lengths match
+               if len(res) != len(exp) {
+                       t.Errorf("test %q, lookup %q (n = %d): expected %d results; got %d", tc.name, s, n, len(exp), len(res))
+               }
+
+               // if n >= 0 the number of results is limited --- unless n >= all results,
+               // we may obtain different positions from the Index and from find (because
+               // Index may not find the results in the same order as find) => in general
+               // we cannot simply check that the res and exp lists are equal
+
+               // check that there are no duplicates
+               sort.SortInts(res)
+               for i, r := range res {
+                       if i > 0 && res[i-1] == r {
+                               t.Errorf("test %q, lookup %q, result %d (n = %d): found duplicate index %d", tc.name, s, i, n, r)
+                       }
+               }
+
+               // check that each result is in fact a correct match
+               for i, r := range res {
+                       if r < 0 || len(src) <= r {
+                               t.Errorf("test %q, lookup %q, result %d (n = %d): index %d out of range [0, %d[", tc.name, s, i, n, r, len(src))
+                       } else if !strings.HasPrefix(src[r:], s) {
+                               t.Errorf("test %q, lookup %q, result %d (n = %d): index %d not a match", tc.name, s, i, n, r)
+                       }
+               }
+
+               if n < 0 {
+                       // all results computed - sorted res and exp must be equal
+                       for i, r := range res {
+                               e := exp[i]
+                               if r != e {
+                                       t.Errorf("test %q, lookup %q, result %d: expected index %d; got %d", tc.name, s, i, e, r)
+                                       continue
+                               }
+                       }
+               }
+       }
+}
+
+
+func TestIndex(t *testing.T) {
+       for _, tc := range testCases {
+               x := New([]byte(tc.source))
+               testLookups(t, tc.source, x, &tc, 0)
+               testLookups(t, tc.source, x, &tc, 1)
+               testLookups(t, tc.source, x, &tc, 10)
+               testLookups(t, tc.source, x, &tc, -1)
+       }
+}
diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go
new file mode 100644 (file)
index 0000000..2b2f4d5
--- /dev/null
@@ -0,0 +1,364 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package provides basic interfaces to I/O primitives.
+// Its primary job is to wrap existing implementations of such primitives,
+// such as those in package os, into shared public interfaces that
+// abstract the functionality, plus some other related primitives.
+package io
+
+import "os"
+
+// Error represents an unexpected I/O behavior.
+type Error struct {
+       os.ErrorString
+}
+
+// ErrShortWrite means that a write accepted fewer bytes than requested
+// but failed to return an explicit error.
+var ErrShortWrite os.Error = &Error{"short write"}
+
+// ErrShortBuffer means that a read required a longer buffer than was provided.
+var ErrShortBuffer os.Error = &Error{"short buffer"}
+
+// ErrUnexpectedEOF means that os.EOF was encountered in the
+// middle of reading a fixed-size block or data structure.
+var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}
+
+// Reader is the interface that wraps the basic Read method.
+//
+// Read reads up to len(p) bytes into p.  It returns the number of bytes
+// read (0 <= n <= len(p)) and any error encountered.
+// Even if Read returns n < len(p),
+// it may use all of p as scratch space during the call.
+// If some data is available but not len(p) bytes, Read conventionally
+// returns what is available rather than block waiting for more.
+//
+// At the end of the input stream, Read returns 0, os.EOF.
+// Read may return a non-zero number of bytes with a non-nil err.
+// In particular, a Read that exhausts the input may return n > 0, os.EOF.
+type Reader interface {
+       Read(p []byte) (n int, err os.Error)
+}
+
+// Writer is the interface that wraps the basic Write method.
+//
+// Write writes len(p) bytes from p to the underlying data stream.
+// It returns the number of bytes written from p (0 <= n <= len(p))
+// and any error encountered that caused the write to stop early.
+// Write must return a non-nil error if it returns n < len(p).
+type Writer interface {
+       Write(p []byte) (n int, err os.Error)
+}
+
+// Closer is the interface that wraps the basic Close method.
+type Closer interface {
+       Close() os.Error
+}
+
+// Seeker is the interface that wraps the basic Seek method.
+//
+// Seek sets the offset for the next Read or Write to offset,
+// interpreted according to whence: 0 means relative to the origin of
+// the file, 1 means relative to the current offset, and 2 means
+// relative to the end.  Seek returns the new offset and an Error, if
+// any.
+type Seeker interface {
+       Seek(offset int64, whence int) (ret int64, err os.Error)
+}
+
+// ReadWriter is the interface that groups the basic Read and Write methods.
+type ReadWriter interface {
+       Reader
+       Writer
+}
+
+// ReadCloser is the interface that groups the basic Read and Close methods.
+type ReadCloser interface {
+       Reader
+       Closer
+}
+
+// WriteCloser is the interface that groups the basic Write and Close methods.
+type WriteCloser interface {
+       Writer
+       Closer
+}
+
+// ReadWriteCloser is the interface that groups the basic Read, Write and Close methods.
+type ReadWriteCloser interface {
+       Reader
+       Writer
+       Closer
+}
+
+// ReadSeeker is the interface that groups the basic Read and Seek methods.
+type ReadSeeker interface {
+       Reader
+       Seeker
+}
+
+// WriteSeeker is the interface that groups the basic Write and Seek methods.
+type WriteSeeker interface {
+       Writer
+       Seeker
+}
+
+// ReadWriteSeeker is the interface that groups the basic Read, Write and Seek methods.
+type ReadWriteSeeker interface {
+       Reader
+       Writer
+       Seeker
+}
+
+// ReaderFrom is the interface that wraps the ReadFrom method.
+type ReaderFrom interface {
+       ReadFrom(r Reader) (n int64, err os.Error)
+}
+
+// WriterTo is the interface that wraps the WriteTo method.
+type WriterTo interface {
+       WriteTo(w Writer) (n int64, err os.Error)
+}
+
+// ReaderAt is the interface that wraps the basic ReadAt method.
+//
+// ReadAt reads len(p) bytes into p starting at offset off in the
+// underlying data stream.  It returns the number of bytes
+// read (0 <= n <= len(p)) and any error encountered.
+//
+// Even if ReadAt returns n < len(p),
+// it may use all of p as scratch space during the call.
+// If some data is available but not len(p) bytes, ReadAt blocks
+// until either all the data is available or an error occurs.
+//
+// At the end of the input stream, ReadAt returns 0, os.EOF.
+// ReadAt may return a non-zero number of bytes with a non-nil err.
+// In particular, a ReadAt that exhausts the input may return n > 0, os.EOF.
+type ReaderAt interface {
+       ReadAt(p []byte, off int64) (n int, err os.Error)
+}
+
+// WriterAt is the interface that wraps the basic WriteAt method.
+//
+// WriteAt writes len(p) bytes from p to the underlying data stream
+// at offset off.  It returns the number of bytes written from p (0 <= n <= len(p))
+// and any error encountered that caused the write to stop early.
+// WriteAt must return a non-nil error if it returns n < len(p).
+type WriterAt interface {
+       WriteAt(p []byte, off int64) (n int, err os.Error)
+}
+
+// ReadByter is the interface that wraps the ReadByte method.
+//
+// ReadByte reads and returns the next byte from the input.
+// If no byte is available, err will be set.
+type ReadByter interface {
+       ReadByte() (c byte, err os.Error)
+}
+
+// WriteString writes the contents of the string s to w, which accepts an array of bytes.
+func WriteString(w Writer, s string) (n int, err os.Error) {
+       return w.Write([]byte(s))
+}
+
+// ReadAtLeast reads from r into buf until it has read at least min bytes.
+// It returns the number of bytes copied and an error if fewer bytes were read.
+// The error is os.EOF only if no bytes were read.
+// If an EOF happens after reading fewer than min bytes,
+// ReadAtLeast returns ErrUnexpectedEOF.
+// If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer.
+func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
+       if len(buf) < min {
+               return 0, ErrShortBuffer
+       }
+       for n < min {
+               nn, e := r.Read(buf[n:])
+               if nn > 0 {
+                       n += nn
+               }
+               if e != nil {
+                       if e == os.EOF && n > 0 {
+                               e = ErrUnexpectedEOF
+                       }
+                       return n, e
+               }
+       }
+       return
+}
+
+// ReadFull reads exactly len(buf) bytes from r into buf.
+// It returns the number of bytes copied and an error if fewer bytes were read.
+// The error is os.EOF only if no bytes were read.
+// If an EOF happens after reading some but not all the bytes,
+// ReadFull returns ErrUnexpectedEOF.
+func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
+       return ReadAtLeast(r, buf, len(buf))
+}
+
+// Copyn copies n bytes (or until an error) from src to dst.
+// It returns the number of bytes copied and the error, if any.
+//
+// If dst implements the ReaderFrom interface,
+// the copy is implemented by calling dst.ReadFrom(src).
+func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
+       // If the writer has a ReadFrom method, use it to to do the copy.
+       // Avoids a buffer allocation and a copy.
+       if rt, ok := dst.(ReaderFrom); ok {
+               return rt.ReadFrom(LimitReader(src, n))
+       }
+       buf := make([]byte, 32*1024)
+       for written < n {
+               l := len(buf)
+               if d := n - written; d < int64(l) {
+                       l = int(d)
+               }
+               nr, er := src.Read(buf[0:l])
+               if nr > 0 {
+                       nw, ew := dst.Write(buf[0:nr])
+                       if nw > 0 {
+                               written += int64(nw)
+                       }
+                       if ew != nil {
+                               err = ew
+                               break
+                       }
+                       if nr != nw {
+                               err = ErrShortWrite
+                               break
+                       }
+               }
+               if er != nil {
+                       err = er
+                       break
+               }
+       }
+       return written, err
+}
+
+// Copy copies from src to dst until either EOF is reached
+// on src or an error occurs.  It returns the number of bytes
+// copied and the error, if any.
+//
+// If dst implements the ReaderFrom interface,
+// the copy is implemented by calling dst.ReadFrom(src).
+// Otherwise, if src implements the WriterTo interface,
+// the copy is implemented by calling src.WriteTo(dst).
+func Copy(dst Writer, src Reader) (written int64, err os.Error) {
+       // If the writer has a ReadFrom method, use it to to do the copy.
+       // Avoids an allocation and a copy.
+       if rt, ok := dst.(ReaderFrom); ok {
+               return rt.ReadFrom(src)
+       }
+       // Similarly, if the reader has a WriteTo method, use it to to do the copy.
+       if wt, ok := src.(WriterTo); ok {
+               return wt.WriteTo(dst)
+       }
+       buf := make([]byte, 32*1024)
+       for {
+               nr, er := src.Read(buf)
+               if nr > 0 {
+                       nw, ew := dst.Write(buf[0:nr])
+                       if nw > 0 {
+                               written += int64(nw)
+                       }
+                       if ew != nil {
+                               err = ew
+                               break
+                       }
+                       if nr != nw {
+                               err = ErrShortWrite
+                               break
+                       }
+               }
+               if er == os.EOF {
+                       break
+               }
+               if er != nil {
+                       err = er
+                       break
+               }
+       }
+       return written, err
+}
+
+// LimitReader returns a Reader that reads from r
+// but stops with os.EOF after n bytes.
+func LimitReader(r Reader, n int64) Reader { return &limitedReader{r, n} }
+
+type limitedReader struct {
+       r Reader
+       n int64
+}
+
+func (l *limitedReader) Read(p []byte) (n int, err os.Error) {
+       if l.n <= 0 {
+               return 0, os.EOF
+       }
+       if int64(len(p)) > l.n {
+               p = p[0:l.n]
+       }
+       n, err = l.r.Read(p)
+       l.n -= int64(n)
+       return
+}
+
+// NewSectionReader returns a SectionReader that reads from r
+// starting at offset off and stops with os.EOF after n bytes.
+func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
+       return &SectionReader{r, off, off, off + n}
+}
+
+// SectionReader implements Read, Seek, and ReadAt on a section
+// of an underlying ReaderAt.
+type SectionReader struct {
+       r     ReaderAt
+       base  int64
+       off   int64
+       limit int64
+}
+
+func (s *SectionReader) Read(p []byte) (n int, err os.Error) {
+       if s.off >= s.limit {
+               return 0, os.EOF
+       }
+       if max := s.limit - s.off; int64(len(p)) > max {
+               p = p[0:max]
+       }
+       n, err = s.r.ReadAt(p, s.off)
+       s.off += int64(n)
+       return
+}
+
+func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error) {
+       switch whence {
+       default:
+               return 0, os.EINVAL
+       case 0:
+               offset += s.base
+       case 1:
+               offset += s.off
+       case 2:
+               offset += s.limit
+       }
+       if offset < s.base || offset > s.limit {
+               return 0, os.EINVAL
+       }
+       s.off = offset
+       return offset - s.base, nil
+}
+
+func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err os.Error) {
+       if off < 0 || off >= s.limit-s.base {
+               return 0, os.EOF
+       }
+       off += s.base
+       if max := s.limit - off; int64(len(p)) > max {
+               p = p[0:max]
+       }
+       return s.r.ReadAt(p, off)
+}
+
+// Size returns the size of the section in bytes.
+func (s *SectionReader) Size() int64 { return s.limit - s.base }
diff --git a/libgo/go/io/io_test.go b/libgo/go/io/io_test.go
new file mode 100644 (file)
index 0000000..20f240a
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io_test
+
+import (
+       "bytes"
+       . "io"
+       "os"
+       "testing"
+)
+
+// An version of bytes.Buffer without ReadFrom and WriteTo
+type Buffer struct {
+       bytes.Buffer
+       ReaderFrom // conflicts with and hides bytes.Buffer's ReaderFrom.
+       WriterTo   // conflicts with and hides bytes.Buffer's WriterTo.
+}
+
+// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and Copyn.
+
+func TestCopy(t *testing.T) {
+       rb := new(Buffer)
+       wb := new(Buffer)
+       rb.WriteString("hello, world.")
+       Copy(wb, rb)
+       if wb.String() != "hello, world." {
+               t.Errorf("Copy did not work properly")
+       }
+}
+
+func TestCopyReadFrom(t *testing.T) {
+       rb := new(Buffer)
+       wb := new(bytes.Buffer) // implements ReadFrom.
+       rb.WriteString("hello, world.")
+       Copy(wb, rb)
+       if wb.String() != "hello, world." {
+               t.Errorf("Copy did not work properly")
+       }
+}
+
+func TestCopyWriteTo(t *testing.T) {
+       rb := new(bytes.Buffer) // implements WriteTo.
+       wb := new(Buffer)
+       rb.WriteString("hello, world.")
+       Copy(wb, rb)
+       if wb.String() != "hello, world." {
+               t.Errorf("Copy did not work properly")
+       }
+}
+
+func TestCopyn(t *testing.T) {
+       rb := new(Buffer)
+       wb := new(Buffer)
+       rb.WriteString("hello, world.")
+       Copyn(wb, rb, 5)
+       if wb.String() != "hello" {
+               t.Errorf("Copyn did not work properly")
+       }
+}
+
+func TestCopynReadFrom(t *testing.T) {
+       rb := new(Buffer)
+       wb := new(bytes.Buffer) // implements ReadFrom.
+       rb.WriteString("hello")
+       Copyn(wb, rb, 5)
+       if wb.String() != "hello" {
+               t.Errorf("Copyn did not work properly")
+       }
+}
+
+func TestCopynWriteTo(t *testing.T) {
+       rb := new(bytes.Buffer) // implements WriteTo.
+       wb := new(Buffer)
+       rb.WriteString("hello, world.")
+       Copyn(wb, rb, 5)
+       if wb.String() != "hello" {
+               t.Errorf("Copyn did not work properly")
+       }
+}
+
+func TestReadAtLeast(t *testing.T) {
+       var rb bytes.Buffer
+       rb.Write([]byte("0123"))
+       buf := make([]byte, 2)
+       n, err := ReadAtLeast(&rb, buf, 2)
+       if err != nil {
+               t.Error(err)
+       }
+       n, err = ReadAtLeast(&rb, buf, 4)
+       if err != ErrShortBuffer {
+               t.Errorf("expected ErrShortBuffer got %v", err)
+       }
+       if n != 0 {
+               t.Errorf("expected to have read 0 bytes, got %v", n)
+       }
+       n, err = ReadAtLeast(&rb, buf, 1)
+       if err != nil {
+               t.Error(err)
+       }
+       if n != 2 {
+               t.Errorf("expected to have read 2 bytes, got %v", n)
+       }
+       n, err = ReadAtLeast(&rb, buf, 2)
+       if err != os.EOF {
+               t.Errorf("expected EOF, got %v", err)
+       }
+       if n != 0 {
+               t.Errorf("expected to have read 0 bytes, got %v", n)
+       }
+       rb.Write([]byte("4"))
+       n, err = ReadAtLeast(&rb, buf, 2)
+       if err != ErrUnexpectedEOF {
+               t.Errorf("expected ErrUnexpectedEOF, got %v", err)
+       }
+       if n != 1 {
+               t.Errorf("expected to have read 1 bytes, got %v", n)
+       }
+}
diff --git a/libgo/go/io/ioutil/ioutil.go b/libgo/go/io/ioutil/ioutil.go
new file mode 100644 (file)
index 0000000..fb3fdcd
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Utility functions.
+
+package ioutil
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "sort"
+)
+
+// ReadAll reads from r until an error or EOF and returns the data it read.
+func ReadAll(r io.Reader) ([]byte, os.Error) {
+       var buf bytes.Buffer
+       _, err := io.Copy(&buf, r)
+       return buf.Bytes(), err
+}
+
+// ReadFile reads the file named by filename and returns the contents.
+func ReadFile(filename string) ([]byte, os.Error) {
+       f, err := os.Open(filename, os.O_RDONLY, 0)
+       if err != nil {
+               return nil, err
+       }
+       defer f.Close()
+       // It's a good but not certain bet that FileInfo will tell us exactly how much to
+       // read, so let's try it but be prepared for the answer to be wrong.
+       fi, err := f.Stat()
+       var n int64
+       if err == nil && fi.Size < 2e9 { // Don't preallocate a huge buffer, just in case.
+               n = fi.Size
+       }
+       // Add a little extra in case Size is zero, and to avoid another allocation after
+       // Read has filled the buffer.
+       n += bytes.MinRead
+       // Pre-allocate the correct size of buffer, then set its size to zero.  The
+       // Buffer will read into the allocated space cheaply.  If the size was wrong,
+       // we'll either waste some space off the end or reallocate as needed, but
+       // in the overwhelmingly common case we'll get it just right.
+       buf := bytes.NewBuffer(make([]byte, 0, n))
+       _, err = buf.ReadFrom(f)
+       return buf.Bytes(), err
+}
+
+// WriteFile writes data to a file named by filename.
+// If the file does not exist, WriteFile creates it with permissions perm;
+// otherwise WriteFile truncates it before writing.
+func WriteFile(filename string, data []byte, perm uint32) os.Error {
+       f, err := os.Open(filename, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, perm)
+       if err != nil {
+               return err
+       }
+       n, err := f.Write(data)
+       f.Close()
+       if err == nil && n < len(data) {
+               err = io.ErrShortWrite
+       }
+       return err
+}
+
+// A dirList implements sort.Interface.
+type fileInfoList []*os.FileInfo
+
+func (f fileInfoList) Len() int           { return len(f) }
+func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
+func (f fileInfoList) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
+
+// ReadDir reads the directory named by dirname and returns
+// a list of sorted directory entries.
+func ReadDir(dirname string) ([]*os.FileInfo, os.Error) {
+       f, err := os.Open(dirname, os.O_RDONLY, 0)
+       if err != nil {
+               return nil, err
+       }
+       list, err := f.Readdir(-1)
+       f.Close()
+       if err != nil {
+               return nil, err
+       }
+       fi := make(fileInfoList, len(list))
+       for i := range list {
+               fi[i] = &list[i]
+       }
+       sort.Sort(fi)
+       return fi, nil
+}
diff --git a/libgo/go/io/ioutil/ioutil_test.go b/libgo/go/io/ioutil/ioutil_test.go
new file mode 100644 (file)
index 0000000..150ee6d
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ioutil_test
+
+import (
+       . "io/ioutil"
+       "os"
+       "testing"
+)
+
+func checkSize(t *testing.T, path string, size int64) {
+       dir, err := os.Stat(path)
+       if err != nil {
+               t.Fatalf("Stat %q (looking for size %d): %s", path, size, err)
+       }
+       if dir.Size != size {
+               t.Errorf("Stat %q: size %d want %d", path, dir.Size, size)
+       }
+}
+
+func TestReadFile(t *testing.T) {
+       filename := "rumpelstilzchen"
+       contents, err := ReadFile(filename)
+       if err == nil {
+               t.Fatalf("ReadFile %s: error expected, none found", filename)
+       }
+
+       filename = "ioutil_test.go"
+       contents, err = ReadFile(filename)
+       if err != nil {
+               t.Fatalf("ReadFile %s: %v", filename, err)
+       }
+
+       checkSize(t, filename, int64(len(contents)))
+}
+
+func TestWriteFile(t *testing.T) {
+       filename := "_test/rumpelstilzchen"
+       data := "Programming today is a race between software engineers striving to " +
+               "build bigger and better idiot-proof programs, and the Universe trying " +
+               "to produce bigger and better idiots. So far, the Universe is winning."
+
+       if err := WriteFile(filename, []byte(data), 0644); err != nil {
+               t.Fatalf("WriteFile %s: %v", filename, err)
+       }
+
+       contents, err := ReadFile(filename)
+       if err != nil {
+               t.Fatalf("ReadFile %s: %v", filename, err)
+       }
+
+       if string(contents) != data {
+               t.Fatalf("contents = %q\nexpected = %q", string(contents), data)
+       }
+
+       // cleanup
+       os.Remove(filename) // ignore error
+}
+
+
+func TestReadDir(t *testing.T) {
+       dirname := "rumpelstilzchen"
+       _, err := ReadDir(dirname)
+       if err == nil {
+               t.Fatalf("ReadDir %s: error expected, none found", dirname)
+       }
+
+       dirname = "."
+       list, err := ReadDir(dirname)
+       if err != nil {
+               t.Fatalf("ReadDir %s: %v", dirname, err)
+       }
+
+       foundTest := false
+       foundTestDir := false
+       for _, dir := range list {
+               switch {
+               case dir.IsRegular() && dir.Name == "ioutil_test.go":
+                       foundTest = true
+               case dir.IsDirectory() && dir.Name == "_test":
+                       foundTestDir = true
+               }
+       }
+       if !foundTest {
+               t.Fatalf("ReadDir %s: test file not found", dirname)
+       }
+       if !foundTestDir {
+               t.Fatalf("ReadDir %s: _test directory not found", dirname)
+       }
+}
diff --git a/libgo/go/io/ioutil/tempfile.go b/libgo/go/io/ioutil/tempfile.go
new file mode 100644 (file)
index 0000000..114eca2
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ioutil
+
+import (
+       "os"
+       "strconv"
+)
+
+// Random number state, accessed without lock; racy but harmless.
+// We generate random temporary file names so that there's a good
+// chance the file doesn't exist yet - keeps the number of tries in
+// TempFile to a minimum.
+var rand uint32
+
+func reseed() uint32 {
+       sec, nsec, _ := os.Time()
+       return uint32(sec*1e9 + nsec + int64(os.Getpid()))
+}
+
+func nextSuffix() string {
+       r := rand
+       if r == 0 {
+               r = reseed()
+       }
+       r = r*1664525 + 1013904223 // constants from Numerical Recipes
+       rand = r
+       return strconv.Itoa(int(1e9 + r%1e9))[1:]
+}
+
+// TempFile creates a new temporary file in the directory dir
+// with a name beginning with prefix, opens the file for reading
+// and writing, and returns the resulting *os.File.
+// If dir is the empty string, TempFile uses the default directory
+// for temporary files (see os.TempDir).
+// Multiple programs calling TempFile simultaneously
+// will not choose the same file.  The caller can use f.Name()
+// to find the name of the file.  It is the caller's responsibility to
+// remove the file when no longer needed.
+func TempFile(dir, prefix string) (f *os.File, err os.Error) {
+       if dir == "" {
+               dir = os.TempDir()
+       }
+
+       nconflict := 0
+       for i := 0; i < 10000; i++ {
+               name := dir + "/" + prefix + nextSuffix()
+               f, err = os.Open(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
+               if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST {
+                       if nconflict++; nconflict > 10 {
+                               rand = reseed()
+                       }
+                       continue
+               }
+               break
+       }
+       return
+}
diff --git a/libgo/go/io/ioutil/tempfile_test.go b/libgo/go/io/ioutil/tempfile_test.go
new file mode 100644 (file)
index 0000000..d949a86
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ioutil_test
+
+import (
+       . "io/ioutil"
+       "os"
+       "regexp"
+       "testing"
+)
+
+func TestTempFile(t *testing.T) {
+       f, err := TempFile("/_not_exists_", "foo")
+       if f != nil || err == nil {
+               t.Errorf("TempFile(`/_not_exists_`, `foo`) = %v, %v", f, err)
+       }
+
+       dir := os.TempDir()
+       f, err = TempFile(dir, "ioutil_test")
+       if f == nil || err != nil {
+               t.Errorf("TempFile(dir, `ioutil_test`) = %v, %v", f, err)
+       }
+       if f != nil {
+               re := regexp.MustCompile("^" + regexp.QuoteMeta(dir) + "/ioutil_test[0-9]+$")
+               if !re.MatchString(f.Name()) {
+                       t.Errorf("TempFile(`"+dir+"`, `ioutil_test`) created bad name %s", f.Name())
+               }
+               os.Remove(f.Name())
+       }
+       f.Close()
+}
diff --git a/libgo/go/io/multi.go b/libgo/go/io/multi.go
new file mode 100644 (file)
index 0000000..88e4f1b
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io
+
+import "os"
+
+type multiReader struct {
+       readers []Reader
+}
+
+func (mr *multiReader) Read(p []byte) (n int, err os.Error) {
+       for len(mr.readers) > 0 {
+               n, err = mr.readers[0].Read(p)
+               if n > 0 || err != os.EOF {
+                       if err == os.EOF {
+                               // This shouldn't happen.
+                               // Well-behaved Readers should never
+                               // return non-zero bytes read with an
+                               // EOF.  But if so, we clean it.
+                               err = nil
+                       }
+                       return
+               }
+               mr.readers = mr.readers[1:]
+       }
+       return 0, os.EOF
+}
+
+// MultiReader returns a Reader that's the logical concatenation of
+// the provided input readers.  They're read sequentially.  Once all
+// inputs are drained, Read will return os.EOF.
+func MultiReader(readers ...Reader) Reader {
+       return &multiReader{readers}
+}
+
+type multiWriter struct {
+       writers []Writer
+}
+
+func (t *multiWriter) Write(p []byte) (n int, err os.Error) {
+       for _, w := range t.writers {
+               n, err = w.Write(p)
+               if err != nil {
+                       return
+               }
+               if n != len(p) {
+                       err = ErrShortWrite
+                       return
+               }
+       }
+       return len(p), nil
+}
+
+// MultiWriter creates a writer that duplicates its writes to all the
+// provided writers, similar to the Unix tee(1) command.
+func MultiWriter(writers ...Writer) Writer {
+       return &multiWriter{writers}
+}
diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go
new file mode 100644 (file)
index 0000000..3ecb7c7
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io_test
+
+import (
+       . "io"
+       "bytes"
+       "crypto/sha1"
+       "fmt"
+       "os"
+       "strings"
+       "testing"
+)
+
+func TestMultiReader(t *testing.T) {
+       var mr Reader
+       var buf []byte
+       nread := 0
+       withFooBar := func(tests func()) {
+               r1 := strings.NewReader("foo ")
+               r2 := strings.NewReader("bar")
+               mr = MultiReader(r1, r2)
+               buf = make([]byte, 20)
+               tests()
+       }
+       expectRead := func(size int, expected string, eerr os.Error) {
+               nread++
+               n, gerr := mr.Read(buf[0:size])
+               if n != len(expected) {
+                       t.Errorf("#%d, expected %d bytes; got %d",
+                               nread, len(expected), n)
+               }
+               got := string(buf[0:n])
+               if got != expected {
+                       t.Errorf("#%d, expected %q; got %q",
+                               nread, expected, got)
+               }
+               if gerr != eerr {
+                       t.Errorf("#%d, expected error %v; got %v",
+                               nread, eerr, gerr)
+               }
+               buf = buf[n:]
+       }
+       withFooBar(func() {
+               expectRead(2, "fo", nil)
+               expectRead(5, "o ", nil)
+               expectRead(5, "bar", nil)
+               expectRead(5, "", os.EOF)
+       })
+       withFooBar(func() {
+               expectRead(4, "foo ", nil)
+               expectRead(1, "b", nil)
+               expectRead(3, "ar", nil)
+               expectRead(1, "", os.EOF)
+       })
+       withFooBar(func() {
+               expectRead(5, "foo ", nil)
+       })
+}
+
+func TestMultiWriter(t *testing.T) {
+       sha1 := sha1.New()
+       sink := new(bytes.Buffer)
+       mw := MultiWriter(sha1, sink)
+
+       sourceString := "My input text."
+       source := strings.NewReader(sourceString)
+       written, err := Copy(mw, source)
+
+       if written != int64(len(sourceString)) {
+               t.Errorf("short write of %d, not %d", written, len(sourceString))
+       }
+
+       if err != nil {
+               t.Errorf("unexpected error: %v", err)
+       }
+
+       sha1hex := fmt.Sprintf("%x", sha1.Sum())
+       if sha1hex != "01cb303fa8c30a64123067c5aa6284ba7ec2d31b" {
+               t.Error("incorrect sha1 value")
+       }
+
+       if sink.String() != sourceString {
+               t.Errorf("expected %q; got %q", sourceString, sink.String())
+       }
+}
diff --git a/libgo/go/io/pipe.go b/libgo/go/io/pipe.go
new file mode 100644 (file)
index 0000000..df76418
--- /dev/null
@@ -0,0 +1,305 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Pipe adapter to connect code expecting an io.Reader
+// with code expecting an io.Writer.
+
+package io
+
+import (
+       "os"
+       "runtime"
+       "sync"
+)
+
+type pipeResult struct {
+       n   int
+       err os.Error
+}
+
+// Shared pipe structure.
+type pipe struct {
+       // Reader sends on cr1, receives on cr2.
+       // Writer does the same on cw1, cw2.
+       r1, w1 chan []byte
+       r2, w2 chan pipeResult
+
+       rclose chan os.Error // read close; error to return to writers
+       wclose chan os.Error // write close; error to return to readers
+
+       done chan int // read or write half is done
+}
+
+func (p *pipe) run() {
+       var (
+               rb    []byte      // pending Read
+               wb    []byte      // pending Write
+               wn    int         // amount written so far from wb
+               rerr  os.Error    // if read end is closed, error to send to writers
+               werr  os.Error    // if write end is closed, error to send to readers
+               r1    chan []byte // p.cr1 or nil depending on whether Read is ok
+               w1    chan []byte // p.cw1 or nil depending on whether Write is ok
+               ndone int
+       )
+
+       // Read and Write are enabled at the start.
+       r1 = p.r1
+       w1 = p.w1
+
+       for {
+               select {
+               case <-p.done:
+                       if ndone++; ndone == 2 {
+                               // both reader and writer are gone
+                               // close out any existing i/o
+                               if r1 == nil {
+                                       p.r2 <- pipeResult{0, os.EINVAL}
+                               }
+                               if w1 == nil {
+                                       p.w2 <- pipeResult{0, os.EINVAL}
+                               }
+                               return
+                       }
+                       continue
+               case rerr = <-p.rclose:
+                       if w1 == nil {
+                               // finish pending Write
+                               p.w2 <- pipeResult{wn, rerr}
+                               wn = 0
+                               w1 = p.w1 // allow another Write
+                       }
+                       if r1 == nil {
+                               // Close of read side during Read.
+                               // finish pending Read with os.EINVAL.
+                               p.r2 <- pipeResult{0, os.EINVAL}
+                               r1 = p.r1 // allow another Read
+                       }
+                       continue
+               case werr = <-p.wclose:
+                       if r1 == nil {
+                               // finish pending Read
+                               p.r2 <- pipeResult{0, werr}
+                               r1 = p.r1 // allow another Read
+                       }
+                       if w1 == nil {
+                               // Close of write side during Write.
+                               // finish pending Write with os.EINVAL.
+                               p.w2 <- pipeResult{wn, os.EINVAL}
+                               wn = 0
+                               w1 = p.w1 // allow another Write
+                       }
+                       continue
+               case rb = <-r1:
+                       if werr != nil {
+                               // write end is closed
+                               p.r2 <- pipeResult{0, werr}
+                               continue
+                       }
+                       if rerr != nil {
+                               // read end is closed
+                               p.r2 <- pipeResult{0, os.EINVAL}
+                               continue
+                       }
+                       r1 = nil // disable Read until this one is done
+               case wb = <-w1:
+                       if rerr != nil {
+                               // read end is closed
+                               p.w2 <- pipeResult{0, rerr}
+                               continue
+                       }
+                       if werr != nil {
+                               // write end is closed
+                               p.w2 <- pipeResult{0, os.EINVAL}
+                               continue
+                       }
+                       w1 = nil // disable Write until this one is done
+               }
+
+               if r1 == nil && w1 == nil {
+                       // Have rb and wb.  Execute.
+                       n := copy(rb, wb)
+                       wn += n
+                       wb = wb[n:]
+
+                       // Finish Read.
+                       p.r2 <- pipeResult{n, nil}
+                       r1 = p.r1 // allow another Read
+
+                       // Maybe finish Write.
+                       if len(wb) == 0 {
+                               p.w2 <- pipeResult{wn, nil}
+                               wn = 0
+                               w1 = p.w1 // allow another Write
+                       }
+               }
+       }
+}
+
+// Read/write halves of the pipe.
+// They are separate structures for two reasons:
+//  1.  If one end becomes garbage without being Closed,
+//      its finalizer can Close so that the other end
+//      does not hang indefinitely.
+//  2.  Clients cannot use interface conversions on the
+//      read end to find the Write method, and vice versa.
+
+type pipeHalf struct {
+       c1     chan []byte
+       c2     chan pipeResult
+       cclose chan os.Error
+       done   chan int
+
+       lock   sync.Mutex
+       closed bool
+
+       io       sync.Mutex
+       ioclosed bool
+}
+
+func (p *pipeHalf) rw(data []byte) (n int, err os.Error) {
+       // Run i/o operation.
+       // Check ioclosed flag under lock to make sure we're still allowed to do i/o.
+       p.io.Lock()
+       if p.ioclosed {
+               p.io.Unlock()
+               return 0, os.EINVAL
+       }
+       p.io.Unlock()
+       p.c1 <- data
+       res := <-p.c2
+       return res.n, res.err
+}
+
+func (p *pipeHalf) close(err os.Error) os.Error {
+       // Close pipe half.
+       // Only first call to close does anything.
+       p.lock.Lock()
+       if p.closed {
+               p.lock.Unlock()
+               return os.EINVAL
+       }
+       p.closed = true
+       p.lock.Unlock()
+
+       // First, send the close notification.
+       p.cclose <- err
+
+       // Runner is now responding to rw operations
+       // with os.EINVAL.  Cut off future rw operations
+       // by setting ioclosed flag.
+       p.io.Lock()
+       p.ioclosed = true
+       p.io.Unlock()
+
+       // With ioclosed set, there will be no more rw operations
+       // working on the channels.
+       // Tell the runner we won't be bothering it anymore.
+       p.done <- 1
+
+       // Successfully torn down; can disable finalizer.
+       runtime.SetFinalizer(p, nil)
+
+       return nil
+}
+
+func (p *pipeHalf) finalizer() {
+       p.close(os.EINVAL)
+}
+
+
+// A PipeReader is the read half of a pipe.
+type PipeReader struct {
+       pipeHalf
+}
+
+// Read implements the standard Read interface:
+// it reads data from the pipe, blocking until a writer
+// arrives or the write end is closed.
+// If the write end is closed with an error, that error is
+// returned as err; otherwise err is nil.
+func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
+       return r.rw(data)
+}
+
+// Close closes the reader; subsequent writes to the
+// write half of the pipe will return the error os.EPIPE.
+func (r *PipeReader) Close() os.Error {
+       return r.CloseWithError(nil)
+}
+
+// CloseWithError closes the reader; subsequent writes
+// to the write half of the pipe will return the error err.
+func (r *PipeReader) CloseWithError(err os.Error) os.Error {
+       if err == nil {
+               err = os.EPIPE
+       }
+       return r.close(err)
+}
+
+// A PipeWriter is the write half of a pipe.
+type PipeWriter struct {
+       pipeHalf
+}
+
+// Write implements the standard Write interface:
+// it writes data to the pipe, blocking until readers
+// have consumed all the data or the read end is closed.
+// If the read end is closed with an error, that err is
+// returned as err; otherwise err is os.EPIPE.
+func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
+       return w.rw(data)
+}
+
+// Close closes the writer; subsequent reads from the
+// read half of the pipe will return no bytes and os.EOF.
+func (w *PipeWriter) Close() os.Error {
+       return w.CloseWithError(nil)
+}
+
+// CloseWithError closes the writer; subsequent reads from the
+// read half of the pipe will return no bytes and the error err.
+func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
+       if err == nil {
+               err = os.EOF
+       }
+       return w.close(err)
+}
+
+// Pipe creates a synchronous in-memory pipe.
+// It can be used to connect code expecting an io.Reader
+// with code expecting an io.Writer.
+// Reads on one end are matched with writes on the other,
+// copying data directly between the two; there is no internal buffering.
+func Pipe() (*PipeReader, *PipeWriter) {
+       p := &pipe{
+               r1:     make(chan []byte),
+               r2:     make(chan pipeResult),
+               w1:     make(chan []byte),
+               w2:     make(chan pipeResult),
+               rclose: make(chan os.Error),
+               wclose: make(chan os.Error),
+               done:   make(chan int),
+       }
+       go p.run()
+
+       // NOTE: Cannot use composite literal here:
+       //      pipeHalf{c1: p.cr1, c2: p.cr2, cclose: p.crclose, cdone: p.cdone}
+       // because this implicitly copies the pipeHalf, which copies the inner mutex.
+
+       r := new(PipeReader)
+       r.c1 = p.r1
+       r.c2 = p.r2
+       r.cclose = p.rclose
+       r.done = p.done
+       runtime.SetFinalizer(r, (*PipeReader).finalizer)
+
+       w := new(PipeWriter)
+       w.c1 = p.w1
+       w.c2 = p.w2
+       w.cclose = p.wclose
+       w.done = p.done
+       runtime.SetFinalizer(w, (*PipeWriter).finalizer)
+
+       return r, w
+}
diff --git a/libgo/go/io/pipe_test.go b/libgo/go/io/pipe_test.go
new file mode 100644 (file)
index 0000000..bd4b94f
--- /dev/null
@@ -0,0 +1,271 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io_test
+
+import (
+       "fmt"
+       . "io"
+       "os"
+       "testing"
+       "time"
+)
+
+func checkWrite(t *testing.T, w Writer, data []byte, c chan int) {
+       n, err := w.Write(data)
+       if err != nil {
+               t.Errorf("write: %v", err)
+       }
+       if n != len(data) {
+               t.Errorf("short write: %d != %d", n, len(data))
+       }
+       c <- 0
+}
+
+// Test a single read/write pair.
+func TestPipe1(t *testing.T) {
+       c := make(chan int)
+       r, w := Pipe()
+       var buf = make([]byte, 64)
+       go checkWrite(t, w, []byte("hello, world"), c)
+       n, err := r.Read(buf)
+       if err != nil {
+               t.Errorf("read: %v", err)
+       } else if n != 12 || string(buf[0:12]) != "hello, world" {
+               t.Errorf("bad read: got %q", buf[0:n])
+       }
+       <-c
+       r.Close()
+       w.Close()
+}
+
+func reader(t *testing.T, r Reader, c chan int) {
+       var buf = make([]byte, 64)
+       for {
+               n, err := r.Read(buf)
+               if err == os.EOF {
+                       c <- 0
+                       break
+               }
+               if err != nil {
+                       t.Errorf("read: %v", err)
+               }
+               c <- n
+       }
+}
+
+// Test a sequence of read/write pairs.
+func TestPipe2(t *testing.T) {
+       c := make(chan int)
+       r, w := Pipe()
+       go reader(t, r, c)
+       var buf = make([]byte, 64)
+       for i := 0; i < 5; i++ {
+               p := buf[0 : 5+i*10]
+               n, err := w.Write(p)
+               if n != len(p) {
+                       t.Errorf("wrote %d, got %d", len(p), n)
+               }
+               if err != nil {
+                       t.Errorf("write: %v", err)
+               }
+               nn := <-c
+               if nn != n {
+                       t.Errorf("wrote %d, read got %d", n, nn)
+               }
+       }
+       w.Close()
+       nn := <-c
+       if nn != 0 {
+               t.Errorf("final read got %d", nn)
+       }
+}
+
+type pipeReturn struct {
+       n   int
+       err os.Error
+}
+
+// Test a large write that requires multiple reads to satisfy.
+func writer(w WriteCloser, buf []byte, c chan pipeReturn) {
+       n, err := w.Write(buf)
+       w.Close()
+       c <- pipeReturn{n, err}
+}
+
+func TestPipe3(t *testing.T) {
+       c := make(chan pipeReturn)
+       r, w := Pipe()
+       var wdat = make([]byte, 128)
+       for i := 0; i < len(wdat); i++ {
+               wdat[i] = byte(i)
+       }
+       go writer(w, wdat, c)
+       var rdat = make([]byte, 1024)
+       tot := 0
+       for n := 1; n <= 256; n *= 2 {
+               nn, err := r.Read(rdat[tot : tot+n])
+               if err != nil && err != os.EOF {
+                       t.Fatalf("read: %v", err)
+               }
+
+               // only final two reads should be short - 1 byte, then 0
+               expect := n
+               if n == 128 {
+                       expect = 1
+               } else if n == 256 {
+                       expect = 0
+                       if err != os.EOF {
+                               t.Fatalf("read at end: %v", err)
+                       }
+               }
+               if nn != expect {
+                       t.Fatalf("read %d, expected %d, got %d", n, expect, nn)
+               }
+               tot += nn
+       }
+       pr := <-c
+       if pr.n != 128 || pr.err != nil {
+               t.Fatalf("write 128: %d, %v", pr.n, pr.err)
+       }
+       if tot != 128 {
+               t.Fatalf("total read %d != 128", tot)
+       }
+       for i := 0; i < 128; i++ {
+               if rdat[i] != byte(i) {
+                       t.Fatalf("rdat[%d] = %d", i, rdat[i])
+               }
+       }
+}
+
+// Test read after/before writer close.
+
+type closer interface {
+       CloseWithError(os.Error) os.Error
+       Close() os.Error
+}
+
+type pipeTest struct {
+       async          bool
+       err            os.Error
+       closeWithError bool
+}
+
+func (p pipeTest) String() string {
+       return fmt.Sprintf("async=%v err=%v closeWithError=%v", p.async, p.err, p.closeWithError)
+}
+
+var pipeTests = []pipeTest{
+       {true, nil, false},
+       {true, nil, true},
+       {true, ErrShortWrite, true},
+       {false, nil, false},
+       {false, nil, true},
+       {false, ErrShortWrite, true},
+}
+
+func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
+       time.Sleep(1e6) // 1 ms
+       var err os.Error
+       if tt.closeWithError {
+               err = cl.CloseWithError(tt.err)
+       } else {
+               err = cl.Close()
+       }
+       if err != nil {
+               t.Errorf("delayClose: %v", err)
+       }
+       ch <- 0
+}
+
+func TestPipeReadClose(t *testing.T) {
+       for _, tt := range pipeTests {
+               c := make(chan int, 1)
+               r, w := Pipe()
+               if tt.async {
+                       go delayClose(t, w, c, tt)
+               } else {
+                       delayClose(t, w, c, tt)
+               }
+               var buf = make([]byte, 64)
+               n, err := r.Read(buf)
+               <-c
+               want := tt.err
+               if want == nil {
+                       want = os.EOF
+               }
+               if err != want {
+                       t.Errorf("read from closed pipe: %v want %v", err, want)
+               }
+               if n != 0 {
+                       t.Errorf("read on closed pipe returned %d", n)
+               }
+               if err = r.Close(); err != nil {
+                       t.Errorf("r.Close: %v", err)
+               }
+       }
+}
+
+// Test close on Read side during Read.
+func TestPipeReadClose2(t *testing.T) {
+       c := make(chan int, 1)
+       r, _ := Pipe()
+       go delayClose(t, r, c, pipeTest{})
+       n, err := r.Read(make([]byte, 64))
+       <-c
+       if n != 0 || err != os.EINVAL {
+               t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, os.EINVAL)
+       }
+}
+
+// Test write after/before reader close.
+
+func TestPipeWriteClose(t *testing.T) {
+       for _, tt := range pipeTests {
+               c := make(chan int, 1)
+               r, w := Pipe()
+               if tt.async {
+                       go delayClose(t, r, c, tt)
+               } else {
+                       delayClose(t, r, c, tt)
+               }
+               n, err := WriteString(w, "hello, world")
+               <-c
+               expect := tt.err
+               if expect == nil {
+                       expect = os.EPIPE
+               }
+               if err != expect {
+                       t.Errorf("write on closed pipe: %v want %v", err, expect)
+               }
+               if n != 0 {
+                       t.Errorf("write on closed pipe returned %d", n)
+               }
+               if err = w.Close(); err != nil {
+                       t.Errorf("w.Close: %v", err)
+               }
+       }
+}
+
+func TestWriteEmpty(t *testing.T) {
+       r, w := Pipe()
+       go func() {
+               w.Write([]byte{})
+               w.Close()
+       }()
+       var b [2]byte
+       ReadFull(r, b[0:2])
+       r.Close()
+}
+
+func TestWriteNil(t *testing.T) {
+       r, w := Pipe()
+       go func() {
+               w.Write(nil)
+               w.Close()
+       }()
+       var b [2]byte
+       ReadFull(r, b[0:2])
+       r.Close()
+}
diff --git a/libgo/go/json/decode.go b/libgo/go/json/decode.go
new file mode 100644 (file)
index 0000000..b6c575c
--- /dev/null
@@ -0,0 +1,861 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Represents JSON data structure using native Go types: booleans, floats,
+// strings, arrays, and maps.
+
+package json
+
+import (
+       "container/vector"
+       "os"
+       "reflect"
+       "runtime"
+       "strconv"
+       "strings"
+       "unicode"
+       "utf16"
+       "utf8"
+)
+
+// Unmarshal parses the JSON-encoded data and stores the result
+// in the value pointed to by v.
+//
+// Unmarshal traverses the value v recursively.
+// If an encountered value implements the Unmarshaler interface,
+// Unmarshal calls its UnmarshalJSON method with a well-formed
+// JSON encoding.
+//
+// Otherwise, Unmarshal uses the inverse of the encodings that
+// Marshal uses, allocating maps, slices, and pointers as necessary,
+// with the following additional rules:
+//
+// To unmarshal a JSON value into a nil interface value, the
+// type stored in the interface value is one of:
+//
+//     bool, for JSON booleans
+//     float64, for JSON numbers
+//     string, for JSON strings
+//     []interface{}, for JSON arrays
+//     map[string]interface{}, for JSON objects
+//     nil for JSON null
+//
+// If a JSON value is not appropriate for a given target type,
+// or if a JSON number overflows the target type, Unmarshal
+// skips that field and completes the unmarshalling as best it can.
+// If no more serious errors are encountered, Unmarshal returns
+// an UnmarshalTypeError describing the earliest such error.
+//
+func Unmarshal(data []byte, v interface{}) os.Error {
+       d := new(decodeState).init(data)
+
+       // Quick check for well-formedness.
+       // Avoids filling out half a data structure
+       // before discovering a JSON syntax error.
+       err := checkValid(data, &d.scan)
+       if err != nil {
+               return err
+       }
+
+       return d.unmarshal(v)
+}
+
+// Unmarshaler is the interface implemented by objects
+// that can unmarshal a JSON description of themselves.
+// The input can be assumed to be a valid JSON object
+// encoding.  UnmarshalJSON must copy the JSON data
+// if it wishes to retain the data after returning.
+type Unmarshaler interface {
+       UnmarshalJSON([]byte) os.Error
+}
+
+
+// An UnmarshalTypeError describes a JSON value that was
+// not appropriate for a value of a specific Go type.
+type UnmarshalTypeError struct {
+       Value string       // description of JSON value - "bool", "array", "number -5"
+       Type  reflect.Type // type of Go value it could not be assigned to
+}
+
+func (e *UnmarshalTypeError) String() string {
+       return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
+}
+
+// An UnmarshalFieldError describes a JSON object key that
+// led to an unexported (and therefore unwritable) struct field.
+type UnmarshalFieldError struct {
+       Key   string
+       Type  *reflect.StructType
+       Field reflect.StructField
+}
+
+func (e *UnmarshalFieldError) String() string {
+       return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
+}
+
+// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
+// (The argument to Unmarshal must be a non-nil pointer.)
+type InvalidUnmarshalError struct {
+       Type reflect.Type
+}
+
+func (e *InvalidUnmarshalError) String() string {
+       if e.Type == nil {
+               return "json: Unmarshal(nil)"
+       }
+
+       if _, ok := e.Type.(*reflect.PtrType); !ok {
+               return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
+       }
+       return "json: Unmarshal(nil " + e.Type.String() + ")"
+}
+
+func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
+       defer func() {
+               if r := recover(); r != nil {
+                       if _, ok := r.(runtime.Error); ok {
+                               panic(r)
+                       }
+                       err = r.(os.Error)
+               }
+       }()
+
+       rv := reflect.NewValue(v)
+       pv, ok := rv.(*reflect.PtrValue)
+       if !ok || pv.IsNil() {
+               return &InvalidUnmarshalError{reflect.Typeof(v)}
+       }
+
+       d.scan.reset()
+       // We decode rv not pv.Elem because the Unmarshaler interface
+       // test must be applied at the top level of the value.
+       d.value(rv)
+       return d.savedError
+}
+
+// decodeState represents the state while decoding a JSON value.
+type decodeState struct {
+       data       []byte
+       off        int // read offset in data
+       scan       scanner
+       nextscan   scanner // for calls to nextValue
+       savedError os.Error
+}
+
+// errPhase is used for errors that should not happen unless
+// there is a bug in the JSON decoder or something is editing
+// the data slice while the decoder executes.
+var errPhase = os.NewError("JSON decoder out of sync - data changing underfoot?")
+
+func (d *decodeState) init(data []byte) *decodeState {
+       d.data = data
+       d.off = 0
+       d.savedError = nil
+       return d
+}
+
+// error aborts the decoding by panicking with err.
+func (d *decodeState) error(err os.Error) {
+       panic(err)
+}
+
+// saveError saves the first err it is called with,
+// for reporting at the end of the unmarshal.
+func (d *decodeState) saveError(err os.Error) {
+       if d.savedError == nil {
+               d.savedError = err
+       }
+}
+
+// next cuts off and returns the next full JSON value in d.data[d.off:].
+// The next value is known to be an object or array, not a literal.
+func (d *decodeState) next() []byte {
+       c := d.data[d.off]
+       item, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+       if err != nil {
+               d.error(err)
+       }
+       d.off = len(d.data) - len(rest)
+
+       // Our scanner has seen the opening brace/bracket
+       // and thinks we're still in the middle of the object.
+       // invent a closing brace/bracket to get it out.
+       if c == '{' {
+               d.scan.step(&d.scan, '}')
+       } else {
+               d.scan.step(&d.scan, ']')
+       }
+
+       return item
+}
+
+// scanWhile processes bytes in d.data[d.off:] until it
+// receives a scan code not equal to op.
+// It updates d.off and returns the new scan code.
+func (d *decodeState) scanWhile(op int) int {
+       var newOp int
+       for {
+               if d.off >= len(d.data) {
+                       newOp = d.scan.eof()
+                       d.off = len(d.data) + 1 // mark processed EOF with len+1
+               } else {
+                       c := int(d.data[d.off])
+                       d.off++
+                       newOp = d.scan.step(&d.scan, c)
+               }
+               if newOp != op {
+                       break
+               }
+       }
+       return newOp
+}
+
+// value decodes a JSON value from d.data[d.off:] into the value.
+// it updates d.off to point past the decoded value.
+func (d *decodeState) value(v reflect.Value) {
+       if v == nil {
+               _, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+               if err != nil {
+                       d.error(err)
+               }
+               d.off = len(d.data) - len(rest)
+
+               // d.scan thinks we're still at the beginning of the item.
+               // Feed in an empty string - the shortest, simplest value -
+               // so that it knows we got to the end of the value.
+               if d.scan.step == stateRedo {
+                       panic("redo")
+               }
+               d.scan.step(&d.scan, '"')
+               d.scan.step(&d.scan, '"')
+               return
+       }
+
+       switch op := d.scanWhile(scanSkipSpace); op {
+       default:
+               d.error(errPhase)
+
+       case scanBeginArray:
+               d.array(v)
+
+       case scanBeginObject:
+               d.object(v)
+
+       case scanBeginLiteral:
+               d.literal(v)
+       }
+}
+
+// indirect walks down v allocating pointers as needed,
+// until it gets to a non-pointer.
+// if it encounters an Unmarshaler, indirect stops and returns that.
+// if wantptr is true, indirect stops at the last pointer.
+func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
+       for {
+               var isUnmarshaler bool
+               if v.Type().NumMethod() > 0 {
+                       // Remember that this is an unmarshaler,
+                       // but wait to return it until after allocating
+                       // the pointer (if necessary).
+                       _, isUnmarshaler = v.Interface().(Unmarshaler)
+               }
+
+               if iv, ok := v.(*reflect.InterfaceValue); ok && !iv.IsNil() {
+                       v = iv.Elem()
+                       continue
+               }
+               pv, ok := v.(*reflect.PtrValue)
+               if !ok {
+                       break
+               }
+               _, isptrptr := pv.Elem().(*reflect.PtrValue)
+               if !isptrptr && wantptr && !isUnmarshaler {
+                       return nil, pv
+               }
+               if pv.IsNil() {
+                       pv.PointTo(reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()))
+               }
+               if isUnmarshaler {
+                       // Using v.Interface().(Unmarshaler)
+                       // here means that we have to use a pointer
+                       // as the struct field.  We cannot use a value inside
+                       // a pointer to a struct, because in that case
+                       // v.Interface() is the value (x.f) not the pointer (&x.f).
+                       // This is an unfortunate consequence of reflect.
+                       // An alternative would be to look up the
+                       // UnmarshalJSON method and return a FuncValue.
+                       return v.Interface().(Unmarshaler), nil
+               }
+               v = pv.Elem()
+       }
+       return nil, v
+}
+
+// array consumes an array from d.data[d.off-1:], decoding into the value v.
+// the first byte of the array ('[') has been read already.
+func (d *decodeState) array(v reflect.Value) {
+       // Check for unmarshaler.
+       unmarshaler, pv := d.indirect(v, false)
+       if unmarshaler != nil {
+               d.off--
+               err := unmarshaler.UnmarshalJSON(d.next())
+               if err != nil {
+                       d.error(err)
+               }
+               return
+       }
+       v = pv
+
+       // Decoding into nil interface?  Switch to non-reflect code.
+       iv, ok := v.(*reflect.InterfaceValue)
+       if ok {
+               iv.Set(reflect.NewValue(d.arrayInterface()))
+               return
+       }
+
+       // Check type of target.
+       av, ok := v.(reflect.ArrayOrSliceValue)
+       if !ok {
+               d.saveError(&UnmarshalTypeError{"array", v.Type()})
+               d.off--
+               d.next()
+               return
+       }
+
+       sv, _ := v.(*reflect.SliceValue)
+
+       i := 0
+       for {
+               // Look ahead for ] - can only happen on first iteration.
+               op := d.scanWhile(scanSkipSpace)
+               if op == scanEndArray {
+                       break
+               }
+
+               // Back up so d.value can have the byte we just read.
+               d.off--
+               d.scan.undo(op)
+
+               // Get element of array, growing if necessary.
+               if i >= av.Cap() && sv != nil {
+                       newcap := sv.Cap() + sv.Cap()/2
+                       if newcap < 4 {
+                               newcap = 4
+                       }
+                       newv := reflect.MakeSlice(sv.Type().(*reflect.SliceType), sv.Len(), newcap)
+                       reflect.ArrayCopy(newv, sv)
+                       sv.Set(newv)
+               }
+               if i >= av.Len() && sv != nil {
+                       // Must be slice; gave up on array during i >= av.Cap().
+                       sv.SetLen(i + 1)
+               }
+
+               // Decode into element.
+               if i < av.Len() {
+                       d.value(av.Elem(i))
+               } else {
+                       // Ran out of fixed array: skip.
+                       d.value(nil)
+               }
+               i++
+
+               // Next token must be , or ].
+               op = d.scanWhile(scanSkipSpace)
+               if op == scanEndArray {
+                       break
+               }
+               if op != scanArrayValue {
+                       d.error(errPhase)
+               }
+       }
+       if i < av.Len() {
+               if sv == nil {
+                       // Array.  Zero the rest.
+                       z := reflect.MakeZero(av.Type().(*reflect.ArrayType).Elem())
+                       for ; i < av.Len(); i++ {
+                               av.Elem(i).SetValue(z)
+                       }
+               } else {
+                       sv.SetLen(i)
+               }
+       }
+}
+
+// matchName returns true if key should be written to a field named name.
+func matchName(key, name string) bool {
+       return strings.ToLower(key) == strings.ToLower(name)
+}
+
+// object consumes an object from d.data[d.off-1:], decoding into the value v.
+// the first byte of the object ('{') has been read already.
+func (d *decodeState) object(v reflect.Value) {
+       // Check for unmarshaler.
+       unmarshaler, pv := d.indirect(v, false)
+       if unmarshaler != nil {
+               d.off--
+               err := unmarshaler.UnmarshalJSON(d.next())
+               if err != nil {
+                       d.error(err)
+               }
+               return
+       }
+       v = pv
+
+       // Decoding into nil interface?  Switch to non-reflect code.
+       iv, ok := v.(*reflect.InterfaceValue)
+       if ok {
+               iv.Set(reflect.NewValue(d.objectInterface()))
+               return
+       }
+
+       // Check type of target: struct or map[string]T
+       var (
+               mv *reflect.MapValue
+               sv *reflect.StructValue
+       )
+       switch v := v.(type) {
+       case *reflect.MapValue:
+               // map must have string type
+               t := v.Type().(*reflect.MapType)
+               if t.Key() != reflect.Typeof("") {
+                       d.saveError(&UnmarshalTypeError{"object", v.Type()})
+                       break
+               }
+               mv = v
+               if mv.IsNil() {
+                       mv.SetValue(reflect.MakeMap(t))
+               }
+       case *reflect.StructValue:
+               sv = v
+       default:
+               d.saveError(&UnmarshalTypeError{"object", v.Type()})
+       }
+
+       if mv == nil && sv == nil {
+               d.off--
+               d.next() // skip over { } in input
+               return
+       }
+
+       for {
+               // Read opening " of string key or closing }.
+               op := d.scanWhile(scanSkipSpace)
+               if op == scanEndObject {
+                       // closing } - can only happen on first iteration.
+                       break
+               }
+               if op != scanBeginLiteral {
+                       d.error(errPhase)
+               }
+
+               // Read string key.
+               start := d.off - 1
+               op = d.scanWhile(scanContinue)
+               item := d.data[start : d.off-1]
+               key, ok := unquote(item)
+               if !ok {
+                       d.error(errPhase)
+               }
+
+               // Figure out field corresponding to key.
+               var subv reflect.Value
+               if mv != nil {
+                       subv = reflect.MakeZero(mv.Type().(*reflect.MapType).Elem())
+               } else {
+                       var f reflect.StructField
+                       var ok bool
+                       // First try for field with that tag.
+                       st := sv.Type().(*reflect.StructType)
+                       for i := 0; i < sv.NumField(); i++ {
+                               f = st.Field(i)
+                               if f.Tag == key {
+                                       ok = true
+                                       break
+                               }
+                       }
+                       if !ok {
+                               // Second, exact match.
+                               f, ok = st.FieldByName(key)
+                       }
+                       if !ok {
+                               // Third, case-insensitive match.
+                               f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+                       }
+
+                       // Extract value; name must be exported.
+                       if ok {
+                               if f.PkgPath != "" {
+                                       d.saveError(&UnmarshalFieldError{key, st, f})
+                               } else {
+                                       subv = sv.FieldByIndex(f.Index)
+                               }
+                       }
+               }
+
+               // Read : before value.
+               if op == scanSkipSpace {
+                       op = d.scanWhile(scanSkipSpace)
+               }
+               if op != scanObjectKey {
+                       d.error(errPhase)
+               }
+
+               // Read value.
+               d.value(subv)
+
+               // Write value back to map;
+               // if using struct, subv points into struct already.
+               if mv != nil {
+                       mv.SetElem(reflect.NewValue(key), subv)
+               }
+
+               // Next token must be , or }.
+               op = d.scanWhile(scanSkipSpace)
+               if op == scanEndObject {
+                       break
+               }
+               if op != scanObjectValue {
+                       d.error(errPhase)
+               }
+       }
+}
+
+// literal consumes a literal from d.data[d.off-1:], decoding into the value v.
+// The first byte of the literal has been read already
+// (that's how the caller knows it's a literal).
+func (d *decodeState) literal(v reflect.Value) {
+       // All bytes inside literal return scanContinue op code.
+       start := d.off - 1
+       op := d.scanWhile(scanContinue)
+
+       // Scan read one byte too far; back up.
+       d.off--
+       d.scan.undo(op)
+       item := d.data[start:d.off]
+
+       // Check for unmarshaler.
+       wantptr := item[0] == 'n' // null
+       unmarshaler, pv := d.indirect(v, wantptr)
+       if unmarshaler != nil {
+               err := unmarshaler.UnmarshalJSON(item)
+               if err != nil {
+                       d.error(err)
+               }
+               return
+       }
+       v = pv
+
+       switch c := item[0]; c {
+       case 'n': // null
+               switch v.(type) {
+               default:
+                       d.saveError(&UnmarshalTypeError{"null", v.Type()})
+               case *reflect.InterfaceValue, *reflect.PtrValue, *reflect.MapValue:
+                       v.SetValue(nil)
+               }
+
+       case 't', 'f': // true, false
+               value := c == 't'
+               switch v := v.(type) {
+               default:
+                       d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+               case *reflect.BoolValue:
+                       v.Set(value)
+               case *reflect.InterfaceValue:
+                       v.Set(reflect.NewValue(value))
+               }
+
+       case '"': // string
+               s, ok := unquote(item)
+               if !ok {
+                       d.error(errPhase)
+               }
+               switch v := v.(type) {
+               default:
+                       d.saveError(&UnmarshalTypeError{"string", v.Type()})
+               case *reflect.StringValue:
+                       v.Set(s)
+               case *reflect.InterfaceValue:
+                       v.Set(reflect.NewValue(s))
+               }
+
+       default: // number
+               if c != '-' && (c < '0' || c > '9') {
+                       d.error(errPhase)
+               }
+               s := string(item)
+               switch v := v.(type) {
+               default:
+                       d.error(&UnmarshalTypeError{"number", v.Type()})
+               case *reflect.InterfaceValue:
+                       n, err := strconv.Atof64(s)
+                       if err != nil {
+                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+                               break
+                       }
+                       v.Set(reflect.NewValue(n))
+
+               case *reflect.IntValue:
+                       n, err := strconv.Atoi64(s)
+                       if err != nil || v.Overflow(n) {
+                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+                               break
+                       }
+                       v.Set(n)
+
+               case *reflect.UintValue:
+                       n, err := strconv.Atoui64(s)
+                       if err != nil || v.Overflow(n) {
+                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+                               break
+                       }
+                       v.Set(n)
+
+               case *reflect.FloatValue:
+                       n, err := strconv.AtofN(s, v.Type().Bits())
+                       if err != nil || v.Overflow(n) {
+                               d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+                               break
+                       }
+                       v.Set(n)
+               }
+       }
+}
+
+// The xxxInterface routines build up a value to be stored
+// in an empty interface.  They are not strictly necessary,
+// but they avoid the weight of reflection in this common case.
+
+// valueInterface is like value but returns interface{}
+func (d *decodeState) valueInterface() interface{} {
+       switch d.scanWhile(scanSkipSpace) {
+       default:
+               d.error(errPhase)
+       case scanBeginArray:
+               return d.arrayInterface()
+       case scanBeginObject:
+               return d.objectInterface()
+       case scanBeginLiteral:
+               return d.literalInterface()
+       }
+       panic("unreachable")
+}
+
+// arrayInterface is like array but returns []interface{}.
+func (d *decodeState) arrayInterface() []interface{} {
+       var v vector.Vector
+       for {
+               // Look ahead for ] - can only happen on first iteration.
+               op := d.scanWhile(scanSkipSpace)
+               if op == scanEndArray {
+                       break
+               }
+
+               // Back up so d.value can have the byte we just read.
+               d.off--
+               d.scan.undo(op)
+
+               v.Push(d.valueInterface())
+
+               // Next token must be , or ].
+               op = d.scanWhile(scanSkipSpace)
+               if op == scanEndArray {
+                       break
+               }
+               if op != scanArrayValue {
+                       d.error(errPhase)
+               }
+       }
+       return v
+}
+
+// objectInterface is like object but returns map[string]interface{}.
+func (d *decodeState) objectInterface() map[string]interface{} {
+       m := make(map[string]interface{})
+       for {
+               // Read opening " of string key or closing }.
+               op := d.scanWhile(scanSkipSpace)
+               if op == scanEndObject {
+                       // closing } - can only happen on first iteration.
+                       break
+               }
+               if op != scanBeginLiteral {
+                       d.error(errPhase)
+               }
+
+               // Read string key.
+               start := d.off - 1
+               op = d.scanWhile(scanContinue)
+               item := d.data[start : d.off-1]
+               key, ok := unquote(item)
+               if !ok {
+                       d.error(errPhase)
+               }
+
+               // Read : before value.
+               if op == scanSkipSpace {
+                       op = d.scanWhile(scanSkipSpace)
+               }
+               if op != scanObjectKey {
+                       d.error(errPhase)
+               }
+
+               // Read value.
+               m[key] = d.valueInterface()
+
+               // Next token must be , or }.
+               op = d.scanWhile(scanSkipSpace)
+               if op == scanEndObject {
+                       break
+               }
+               if op != scanObjectValue {
+                       d.error(errPhase)
+               }
+       }
+       return m
+}
+
+
+// literalInterface is like literal but returns an interface value.
+func (d *decodeState) literalInterface() interface{} {
+       // All bytes inside literal return scanContinue op code.
+       start := d.off - 1
+       op := d.scanWhile(scanContinue)
+
+       // Scan read one byte too far; back up.
+       d.off--
+       d.scan.undo(op)
+       item := d.data[start:d.off]
+
+       switch c := item[0]; c {
+       case 'n': // null
+               return nil
+
+       case 't', 'f': // true, false
+               return c == 't'
+
+       case '"': // string
+               s, ok := unquote(item)
+               if !ok {
+                       d.error(errPhase)
+               }
+               return s
+
+       default: // number
+               if c != '-' && (c < '0' || c > '9') {
+                       d.error(errPhase)
+               }
+               n, err := strconv.Atof64(string(item))
+               if err != nil {
+                       d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.Typeof(float64(0))})
+               }
+               return n
+       }
+       panic("unreachable")
+}
+
+// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
+// or it returns -1.
+func getu4(s []byte) int {
+       if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
+               return -1
+       }
+       rune, err := strconv.Btoui64(string(s[2:6]), 16)
+       if err != nil {
+               return -1
+       }
+       return int(rune)
+}
+
+// unquote converts a quoted JSON string literal s into an actual string t.
+// The rules are different than for Go, so cannot use strconv.Unquote.
+func unquote(s []byte) (t string, ok bool) {
+       if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
+               return
+       }
+       b := make([]byte, len(s)+2*utf8.UTFMax)
+       w := 0
+       for r := 1; r < len(s)-1; {
+               // Out of room?  Can only happen if s is full of
+               // malformed UTF-8 and we're replacing each
+               // byte with RuneError.
+               if w >= len(b)-2*utf8.UTFMax {
+                       nb := make([]byte, (len(b)+utf8.UTFMax)*2)
+                       copy(nb, b[0:w])
+                       b = nb
+               }
+               switch c := s[r]; {
+               case c == '\\':
+                       r++
+                       if r >= len(s)-1 {
+                               return
+                       }
+                       switch s[r] {
+                       default:
+                               return
+                       case '"', '\\', '/', '\'':
+                               b[w] = s[r]
+                               r++
+                               w++
+                       case 'b':
+                               b[w] = '\b'
+                               r++
+                               w++
+                       case 'f':
+                               b[w] = '\f'
+                               r++
+                               w++
+                       case 'n':
+                               b[w] = '\n'
+                               r++
+                               w++
+                       case 'r':
+                               b[w] = '\r'
+                               r++
+                               w++
+                       case 't':
+                               b[w] = '\t'
+                               r++
+                               w++
+                       case 'u':
+                               r--
+                               rune := getu4(s[r:])
+                               if rune < 0 {
+                                       return
+                               }
+                               r += 6
+                               if utf16.IsSurrogate(rune) {
+                                       rune1 := getu4(s[r:])
+                                       if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
+                                               // A valid pair; consume.
+                                               r += 6
+                                               w += utf8.EncodeRune(dec, b[w:])
+                                               break
+                                       }
+                                       // Invalid surrogate; fall back to replacement rune.
+                                       rune = unicode.ReplacementChar
+                               }
+                               w += utf8.EncodeRune(rune, b[w:])
+                       }
+
+               // Quote, control characters are invalid.
+               case c == '"', c < ' ':
+                       return
+
+               // ASCII
+               case c < utf8.RuneSelf:
+                       b[w] = c
+                       r++
+                       w++
+
+               // Coerce to well-formed UTF-8.
+               default:
+                       rune, size := utf8.DecodeRune(s[r:])
+                       r += size
+                       w += utf8.EncodeRune(rune, b[w:])
+               }
+       }
+       return string(b[0:w]), true
+}
diff --git a/libgo/go/json/decode_test.go b/libgo/go/json/decode_test.go
new file mode 100644 (file)
index 0000000..b805d3d
--- /dev/null
@@ -0,0 +1,509 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+       "bytes"
+       "os"
+       "reflect"
+       "strings"
+       "testing"
+)
+
+type T struct {
+       X string
+       Y int
+}
+
+type tx struct {
+       x int
+}
+
+var txType = reflect.Typeof((*tx)(nil)).(*reflect.PtrType).Elem().(*reflect.StructType)
+
+// A type that can unmarshal itself.
+
+type unmarshaler struct {
+       T bool
+}
+
+func (u *unmarshaler) UnmarshalJSON(b []byte) os.Error {
+       *u = unmarshaler{true} // All we need to see that UnmarshalJson is called.
+       return nil
+}
+
+var (
+       um0, um1 unmarshaler // target2 of unmarshaling
+       ump      = &um1
+       umtrue   = unmarshaler{true}
+)
+
+
+type unmarshalTest struct {
+       in  string
+       ptr interface{}
+       out interface{}
+       err os.Error
+}
+
+var unmarshalTests = []unmarshalTest{
+       // basic types
+       {`true`, new(bool), true, nil},
+       {`1`, new(int), 1, nil},
+       {`1.2`, new(float), 1.2, nil},
+       {`-5`, new(int16), int16(-5), nil},
+       {`"a\u1234"`, new(string), "a\u1234", nil},
+       {`"http:\/\/"`, new(string), "http://", nil},
+       {`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil},
+       {`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil},
+       {"null", new(interface{}), nil, nil},
+       {`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.Typeof("")}},
+       {`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
+
+       // syntax errors
+       {`{"X": "foo", "Y"}`, nil, nil, SyntaxError("invalid character '}' after object key")},
+
+       // composite tests
+       {allValueIndent, new(All), allValue, nil},
+       {allValueCompact, new(All), allValue, nil},
+       {allValueIndent, new(*All), &allValue, nil},
+       {allValueCompact, new(*All), &allValue, nil},
+       {pallValueIndent, new(All), pallValue, nil},
+       {pallValueCompact, new(All), pallValue, nil},
+       {pallValueIndent, new(*All), &pallValue, nil},
+       {pallValueCompact, new(*All), &pallValue, nil},
+
+       // unmarshal interface test
+       {`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called
+       {`{"T":false}`, &ump, &umtrue, nil},
+}
+
+func TestMarshal(t *testing.T) {
+       b, err := Marshal(allValue)
+       if err != nil {
+               t.Fatalf("Marshal allValue: %v", err)
+       }
+       if string(b) != allValueCompact {
+               t.Errorf("Marshal allValueCompact")
+               diff(t, b, []byte(allValueCompact))
+               return
+       }
+
+       b, err = Marshal(pallValue)
+       if err != nil {
+               t.Fatalf("Marshal pallValue: %v", err)
+       }
+       if string(b) != pallValueCompact {
+               t.Errorf("Marshal pallValueCompact")
+               diff(t, b, []byte(pallValueCompact))
+               return
+       }
+}
+
+func TestUnmarshal(t *testing.T) {
+       var scan scanner
+       for i, tt := range unmarshalTests {
+               in := []byte(tt.in)
+               if err := checkValid(in, &scan); err != nil {
+                       if !reflect.DeepEqual(err, tt.err) {
+                               t.Errorf("#%d: checkValid: %v", i, err)
+                               continue
+                       }
+               }
+               if tt.ptr == nil {
+                       continue
+               }
+               // v = new(right-type)
+               v := reflect.NewValue(tt.ptr).(*reflect.PtrValue)
+               v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem()))
+               if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqual(err, tt.err) {
+                       t.Errorf("#%d: %v want %v", i, err, tt.err)
+                       continue
+               }
+               if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
+                       t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
+                       data, _ := Marshal(v.Elem().Interface())
+                       println(string(data))
+                       data, _ = Marshal(tt.out)
+                       println(string(data))
+                       return
+                       continue
+               }
+       }
+}
+
+func TestUnmarshalMarshal(t *testing.T) {
+       var v interface{}
+       if err := Unmarshal(jsonBig, &v); err != nil {
+               t.Fatalf("Unmarshal: %v", err)
+       }
+       b, err := Marshal(v)
+       if err != nil {
+               t.Fatalf("Marshal: %v", err)
+       }
+       if bytes.Compare(jsonBig, b) != 0 {
+               t.Errorf("Marshal jsonBig")
+               diff(t, b, jsonBig)
+               return
+       }
+}
+
+type Xint struct {
+       X int
+}
+
+func TestUnmarshalInterface(t *testing.T) {
+       var xint Xint
+       var i interface{} = &xint
+       if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
+               t.Fatalf("Unmarshal: %v", err)
+       }
+       if xint.X != 1 {
+               t.Fatalf("Did not write to xint")
+       }
+}
+
+func TestUnmarshalPtrPtr(t *testing.T) {
+       var xint Xint
+       pxint := &xint
+       if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
+               t.Fatalf("Unmarshal: %v", err)
+       }
+       if xint.X != 1 {
+               t.Fatalf("Did not write to xint")
+       }
+}
+
+func TestHTMLEscape(t *testing.T) {
+       b, err := MarshalForHTML("foobarbaz<>&quux")
+       if err != nil {
+               t.Fatalf("MarshalForHTML error: %v", err)
+       }
+       if !bytes.Equal(b, []byte(`"foobarbaz\u003c\u003e\u0026quux"`)) {
+               t.Fatalf("Unexpected encoding of \"<>&\": %s", b)
+       }
+}
+
+func noSpace(c int) int {
+       if isSpace(c) {
+               return -1
+       }
+       return c
+}
+
+type All struct {
+       Bool    bool
+       Int     int
+       Int8    int8
+       Int16   int16
+       Int32   int32
+       Int64   int64
+       Uint    uint
+       Uint8   uint8
+       Uint16  uint16
+       Uint32  uint32
+       Uint64  uint64
+       Uintptr uintptr
+       Float   float
+       Float32 float32
+       Float64 float64
+
+       Foo string "bar"
+
+       PBool    *bool
+       PInt     *int
+       PInt8    *int8
+       PInt16   *int16
+       PInt32   *int32
+       PInt64   *int64
+       PUint    *uint
+       PUint8   *uint8
+       PUint16  *uint16
+       PUint32  *uint32
+       PUint64  *uint64
+       PUintptr *uintptr
+       PFloat   *float
+       PFloat32 *float32
+       PFloat64 *float64
+
+       String  string
+       PString *string
+
+       Map   map[string]Small
+       MapP  map[string]*Small
+       PMap  *map[string]Small
+       PMapP *map[string]*Small
+
+       EmptyMap map[string]Small
+       NilMap   map[string]Small
+
+       Slice   []Small
+       SliceP  []*Small
+       PSlice  *[]Small
+       PSliceP *[]*Small
+
+       EmptySlice []Small
+       NilSlice   []Small
+
+       StringSlice []string
+       ByteSlice   []byte
+
+       Small   Small
+       PSmall  *Small
+       PPSmall **Small
+
+       Interface  interface{}
+       PInterface *interface{}
+}
+
+type Small struct {
+       Tag string
+}
+
+var allValue = All{
+       Bool:    true,
+       Int:     2,
+       Int8:    3,
+       Int16:   4,
+       Int32:   5,
+       Int64:   6,
+       Uint:    7,
+       Uint8:   8,
+       Uint16:  9,
+       Uint32:  10,
+       Uint64:  11,
+       Uintptr: 12,
+       Float:   13.1,
+       Float32: 14.1,
+       Float64: 15.1,
+       Foo:     "foo",
+       String:  "16",
+       Map: map[string]Small{
+               "17": {Tag: "tag17"},
+               "18": {Tag: "tag18"},
+       },
+       MapP: map[string]*Small{
+               "19": &Small{Tag: "tag19"},
+               "20": nil,
+       },
+       EmptyMap:    map[string]Small{},
+       Slice:       []Small{{Tag: "tag20"}, {Tag: "tag21"}},
+       SliceP:      []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
+       EmptySlice:  []Small{},
+       StringSlice: []string{"str24", "str25", "str26"},
+       ByteSlice:   []byte{27, 28, 29},
+       Small:       Small{Tag: "tag30"},
+       PSmall:      &Small{Tag: "tag31"},
+       Interface:   float64(5.2),
+}
+
+var pallValue = All{
+       PBool:      &allValue.Bool,
+       PInt:       &allValue.Int,
+       PInt8:      &allValue.Int8,
+       PInt16:     &allValue.Int16,
+       PInt32:     &allValue.Int32,
+       PInt64:     &allValue.Int64,
+       PUint:      &allValue.Uint,
+       PUint8:     &allValue.Uint8,
+       PUint16:    &allValue.Uint16,
+       PUint32:    &allValue.Uint32,
+       PUint64:    &allValue.Uint64,
+       PUintptr:   &allValue.Uintptr,
+       PFloat:     &allValue.Float,
+       PFloat32:   &allValue.Float32,
+       PFloat64:   &allValue.Float64,
+       PString:    &allValue.String,
+       PMap:       &allValue.Map,
+       PMapP:      &allValue.MapP,
+       PSlice:     &allValue.Slice,
+       PSliceP:    &allValue.SliceP,
+       PPSmall:    &allValue.PSmall,
+       PInterface: &allValue.Interface,
+}
+
+var allValueIndent = `{
+       "Bool": true,
+       "Int": 2,
+       "Int8": 3,
+       "Int16": 4,
+       "Int32": 5,
+       "Int64": 6,
+       "Uint": 7,
+       "Uint8": 8,
+       "Uint16": 9,
+       "Uint32": 10,
+       "Uint64": 11,
+       "Uintptr": 12,
+       "Float": 13.1,
+       "Float32": 14.1,
+       "Float64": 15.1,
+       "bar": "foo",
+       "PBool": null,
+       "PInt": null,
+       "PInt8": null,
+       "PInt16": null,
+       "PInt32": null,
+       "PInt64": null,
+       "PUint": null,
+       "PUint8": null,
+       "PUint16": null,
+       "PUint32": null,
+       "PUint64": null,
+       "PUintptr": null,
+       "PFloat": null,
+       "PFloat32": null,
+       "PFloat64": null,
+       "String": "16",
+       "PString": null,
+       "Map": {
+               "17": {
+                       "Tag": "tag17"
+               },
+               "18": {
+                       "Tag": "tag18"
+               }
+       },
+       "MapP": {
+               "19": {
+                       "Tag": "tag19"
+               },
+               "20": null
+       },
+       "PMap": null,
+       "PMapP": null,
+       "EmptyMap": {},
+       "NilMap": null,
+       "Slice": [
+               {
+                       "Tag": "tag20"
+               },
+               {
+                       "Tag": "tag21"
+               }
+       ],
+       "SliceP": [
+               {
+                       "Tag": "tag22"
+               },
+               null,
+               {
+                       "Tag": "tag23"
+               }
+       ],
+       "PSlice": null,
+       "PSliceP": null,
+       "EmptySlice": [],
+       "NilSlice": [],
+       "StringSlice": [
+               "str24",
+               "str25",
+               "str26"
+       ],
+       "ByteSlice": [
+               27,
+               28,
+               29
+       ],
+       "Small": {
+               "Tag": "tag30"
+       },
+       "PSmall": {
+               "Tag": "tag31"
+       },
+       "PPSmall": null,
+       "Interface": 5.2,
+       "PInterface": null
+}`
+
+var allValueCompact = strings.Map(noSpace, allValueIndent)
+
+var pallValueIndent = `{
+       "Bool": false,
+       "Int": 0,
+       "Int8": 0,
+       "Int16": 0,
+       "Int32": 0,
+       "Int64": 0,
+       "Uint": 0,
+       "Uint8": 0,
+       "Uint16": 0,
+       "Uint32": 0,
+       "Uint64": 0,
+       "Uintptr": 0,
+       "Float": 0,
+       "Float32": 0,
+       "Float64": 0,
+       "bar": "",
+       "PBool": true,
+       "PInt": 2,
+       "PInt8": 3,
+       "PInt16": 4,
+       "PInt32": 5,
+       "PInt64": 6,
+       "PUint": 7,
+       "PUint8": 8,
+       "PUint16": 9,
+       "PUint32": 10,
+       "PUint64": 11,
+       "PUintptr": 12,
+       "PFloat": 13.1,
+       "PFloat32": 14.1,
+       "PFloat64": 15.1,
+       "String": "",
+       "PString": "16",
+       "Map": null,
+       "MapP": null,
+       "PMap": {
+               "17": {
+                       "Tag": "tag17"
+               },
+               "18": {
+                       "Tag": "tag18"
+               }
+       },
+       "PMapP": {
+               "19": {
+                       "Tag": "tag19"
+               },
+               "20": null
+       },
+       "EmptyMap": null,
+       "NilMap": null,
+       "Slice": [],
+       "SliceP": [],
+       "PSlice": [
+               {
+                       "Tag": "tag20"
+               },
+               {
+                       "Tag": "tag21"
+               }
+       ],
+       "PSliceP": [
+               {
+                       "Tag": "tag22"
+               },
+               null,
+               {
+                       "Tag": "tag23"
+               }
+       ],
+       "EmptySlice": [],
+       "NilSlice": [],
+       "StringSlice": [],
+       "ByteSlice": [],
+       "Small": {
+               "Tag": ""
+       },
+       "PSmall": null,
+       "PPSmall": {
+               "Tag": "tag31"
+       },
+       "Interface": null,
+       "PInterface": 5.2
+}`
+
+var pallValueCompact = strings.Map(noSpace, pallValueIndent)
diff --git a/libgo/go/json/encode.go b/libgo/go/json/encode.go
new file mode 100644 (file)
index 0000000..8b2f99f
--- /dev/null
@@ -0,0 +1,298 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The json package implements encoding and decoding of JSON objects as
+// defined in RFC 4627.
+package json
+
+import (
+       "os"
+       "bytes"
+       "reflect"
+       "runtime"
+       "sort"
+       "strconv"
+)
+
+// Marshal returns the JSON encoding of v.
+//
+// Marshal traverses the value v recursively.
+// If an encountered value implements the Marshaler interface,
+// Marshal calls its MarshalJSON method to produce JSON.
+//
+// Otherwise, Marshal uses the following type-dependent default encodings:
+//
+// Boolean values encode as JSON booleans.
+//
+// Floating point and integer values encode as JSON numbers.
+//
+// String values encode as JSON strings, with each invalid UTF-8 sequence
+// replaced by the encoding of the Unicode replacement character U+FFFD.
+//
+// Array and slice values encode as JSON arrays.
+//
+// Struct values encode as JSON objects.  Each struct field becomes
+// a member of the object.  By default the object's key name is the
+// struct field name converted to lower case.  If the struct field
+// has a tag, that tag will be used as the name instead.
+//
+// Map values encode as JSON objects.
+// The map's key type must be string; the object keys are used directly
+// as map keys.
+//
+// Pointer values encode as the value pointed to.
+// A nil pointer encodes as the null JSON object.
+//
+// Interface values encode as the value contained in the interface.
+// A nil interface value encodes as the null JSON object.
+//
+// Channel, complex, and function values cannot be encoded in JSON.
+// Attempting to encode such a value causes Marshal to return
+// an InvalidTypeError.
+//
+// JSON cannot represent cyclic data structures and Marshal does not
+// handle them.  Passing cyclic structures to Marshal will result in
+// an infinite recursion.
+//
+func Marshal(v interface{}) ([]byte, os.Error) {
+       e := &encodeState{}
+       err := e.marshal(v)
+       if err != nil {
+               return nil, err
+       }
+       return e.Bytes(), nil
+}
+
+// MarshalIndent is like Marshal but applies Indent to format the output.
+func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
+       b, err := Marshal(v)
+       if err != nil {
+               return nil, err
+       }
+       var buf bytes.Buffer
+       err = Indent(&buf, b, prefix, indent)
+       if err != nil {
+               return nil, err
+       }
+       return buf.Bytes(), nil
+}
+
+// MarshalForHTML is like Marshal but applies HTMLEscape to the output.
+func MarshalForHTML(v interface{}) ([]byte, os.Error) {
+       b, err := Marshal(v)
+       if err != nil {
+               return nil, err
+       }
+       var buf bytes.Buffer
+       HTMLEscape(&buf, b)
+       return buf.Bytes(), nil
+}
+
+// HTMLEscape appends to dst the JSON-encoded src with <, >, and &
+// characters inside string literals changed to \u003c, \u003e, \u0026
+// so that the JSON will be safe to embed inside HTML <script> tags.
+// For historical reasons, web browsers don't honor standard HTML
+// escaping within <script> tags, so an alternative JSON encoding must
+// be used.
+func HTMLEscape(dst *bytes.Buffer, src []byte) {
+       // < > & can only appear in string literals,
+       // so just scan the string one byte at a time.
+       start := 0
+       for i, c := range src {
+               if c == '<' || c == '>' || c == '&' {
+                       if start < i {
+                               dst.Write(src[start:i])
+                       }
+                       dst.WriteString(`\u00`)
+                       dst.WriteByte(hex[c>>4])
+                       dst.WriteByte(hex[c&0xF])
+                       start = i + 1
+               }
+       }
+       if start < len(src) {
+               dst.Write(src[start:])
+       }
+}
+
+// Marshaler is the interface implemented by objects that
+// can marshal themselves into valid JSON.
+type Marshaler interface {
+       MarshalJSON() ([]byte, os.Error)
+}
+
+type UnsupportedTypeError struct {
+       Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) String() string {
+       return "json: unsupported type: " + e.Type.String()
+}
+
+type MarshalerError struct {
+       Type  reflect.Type
+       Error os.Error
+}
+
+func (e *MarshalerError) String() string {
+       return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
+}
+
+type interfaceOrPtrValue interface {
+       IsNil() bool
+       Elem() reflect.Value
+}
+
+var hex = "0123456789abcdef"
+
+// An encodeState encodes JSON into a bytes.Buffer.
+type encodeState struct {
+       bytes.Buffer // accumulated output
+}
+
+func (e *encodeState) marshal(v interface{}) (err os.Error) {
+       defer func() {
+               if r := recover(); r != nil {
+                       if _, ok := r.(runtime.Error); ok {
+                               panic(r)
+                       }
+                       err = r.(os.Error)
+               }
+       }()
+       e.reflectValue(reflect.NewValue(v))
+       return nil
+}
+
+func (e *encodeState) error(err os.Error) {
+       panic(err)
+}
+
+func (e *encodeState) reflectValue(v reflect.Value) {
+       if v == nil {
+               e.WriteString("null")
+               return
+       }
+
+       if j, ok := v.Interface().(Marshaler); ok {
+               b, err := j.MarshalJSON()
+               if err == nil {
+                       // copy JSON into buffer, checking validity.
+                       err = Compact(&e.Buffer, b)
+               }
+               if err != nil {
+                       e.error(&MarshalerError{v.Type(), err})
+               }
+               return
+       }
+
+       switch v := v.(type) {
+       case *reflect.BoolValue:
+               x := v.Get()
+               if x {
+                       e.WriteString("true")
+               } else {
+                       e.WriteString("false")
+               }
+
+       case *reflect.IntValue:
+               e.WriteString(strconv.Itoa64(v.Get()))
+
+       case *reflect.UintValue:
+               e.WriteString(strconv.Uitoa64(v.Get()))
+
+       case *reflect.FloatValue:
+               e.WriteString(strconv.FtoaN(v.Get(), 'g', -1, v.Type().Bits()))
+
+       case *reflect.StringValue:
+               e.string(v.Get())
+
+       case *reflect.StructValue:
+               e.WriteByte('{')
+               t := v.Type().(*reflect.StructType)
+               n := v.NumField()
+               for i := 0; i < n; i++ {
+                       if i > 0 {
+                               e.WriteByte(',')
+                       }
+                       f := t.Field(i)
+                       if f.Tag != "" {
+                               e.string(f.Tag)
+                       } else {
+                               e.string(f.Name)
+                       }
+                       e.WriteByte(':')
+                       e.reflectValue(v.Field(i))
+               }
+               e.WriteByte('}')
+
+       case *reflect.MapValue:
+               if _, ok := v.Type().(*reflect.MapType).Key().(*reflect.StringType); !ok {
+                       e.error(&UnsupportedTypeError{v.Type()})
+               }
+               if v.IsNil() {
+                       e.WriteString("null")
+                       break
+               }
+               e.WriteByte('{')
+               var sv stringValues = v.Keys()
+               sort.Sort(sv)
+               for i, k := range sv {
+                       if i > 0 {
+                               e.WriteByte(',')
+                       }
+                       e.string(k.(*reflect.StringValue).Get())
+                       e.WriteByte(':')
+                       e.reflectValue(v.Elem(k))
+               }
+               e.WriteByte('}')
+
+       case reflect.ArrayOrSliceValue:
+               e.WriteByte('[')
+               n := v.Len()
+               for i := 0; i < n; i++ {
+                       if i > 0 {
+                               e.WriteByte(',')
+                       }
+                       e.reflectValue(v.Elem(i))
+               }
+               e.WriteByte(']')
+
+       case interfaceOrPtrValue:
+               if v.IsNil() {
+                       e.WriteString("null")
+                       return
+               }
+               e.reflectValue(v.Elem())
+
+       default:
+               e.error(&UnsupportedTypeError{v.Type()})
+       }
+       return
+}
+
+// stringValues is a slice of reflect.Value holding *reflect.StringValue.
+// It implements the methods to sort by string.
+type stringValues []reflect.Value
+
+func (sv stringValues) Len() int           { return len(sv) }
+func (sv stringValues) Swap(i, j int)      { sv[i], sv[j] = sv[j], sv[i] }
+func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
+func (sv stringValues) get(i int) string   { return sv[i].(*reflect.StringValue).Get() }
+
+func (e *encodeState) string(s string) {
+       e.WriteByte('"')
+       for _, c := range s {
+               switch {
+               case c < 0x20:
+                       e.WriteString(`\u00`)
+                       e.WriteByte(hex[c>>4])
+                       e.WriteByte(hex[c&0xF])
+               case c == '\\' || c == '"':
+                       e.WriteByte('\\')
+                       fallthrough
+               default:
+                       e.WriteRune(c)
+               }
+       }
+       e.WriteByte('"')
+}
diff --git a/libgo/go/json/indent.go b/libgo/go/json/indent.go
new file mode 100644 (file)
index 0000000..000da42
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+       "bytes"
+       "os"
+)
+
+// Compact appends to dst the JSON-encoded src with
+// insignificant space characters elided.
+func Compact(dst *bytes.Buffer, src []byte) os.Error {
+       origLen := dst.Len()
+       var scan scanner
+       scan.reset()
+       start := 0
+       for i, c := range src {
+               v := scan.step(&scan, int(c))
+               if v >= scanSkipSpace {
+                       if v == scanError {
+                               break
+                       }
+                       if start < i {
+                               dst.Write(src[start:i])
+                       }
+                       start = i + 1
+               }
+       }
+       if scan.eof() == scanError {
+               dst.Truncate(origLen)
+               return scan.err
+       }
+       if start < len(src) {
+               dst.Write(src[start:])
+       }
+       return nil
+}
+
+func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
+       dst.WriteByte('\n')
+       dst.WriteString(prefix)
+       for i := 0; i < depth; i++ {
+               dst.WriteString(indent)
+       }
+}
+
+// Indent appends to dst an indented form of the JSON-encoded src.
+// Each element in a JSON object or array begins on a new,
+// indented line beginning with prefix followed by one or more
+// copies of indent according to the indentation nesting.
+// The data appended to dst has no trailing newline, to make it easier
+// to embed inside other formatted JSON data.
+func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) os.Error {
+       origLen := dst.Len()
+       var scan scanner
+       scan.reset()
+       needIndent := false
+       depth := 0
+       for _, c := range src {
+               v := scan.step(&scan, int(c))
+               if v == scanSkipSpace {
+                       continue
+               }
+               if v == scanError {
+                       break
+               }
+               if needIndent && v != scanEndObject && v != scanEndArray {
+                       needIndent = false
+                       depth++
+                       newline(dst, prefix, indent, depth)
+               }
+
+               // Emit semantically uninteresting bytes
+               // (in particular, punctuation in strings) unmodified.
+               if v == scanContinue {
+                       dst.WriteByte(c)
+                       continue
+               }
+
+               // Add spacing around real punctuation.
+               switch c {
+               case '{', '[':
+                       // delay indent so that empty object and array are formatted as {} and [].
+                       needIndent = true
+                       dst.WriteByte(c)
+
+               case ',':
+                       dst.WriteByte(c)
+                       newline(dst, prefix, indent, depth)
+
+               case ':':
+                       dst.WriteByte(c)
+                       dst.WriteByte(' ')
+
+               case '}', ']':
+                       if needIndent {
+                               // suppress indent in empty object/array
+                               needIndent = false
+                       } else {
+                               depth--
+                               newline(dst, prefix, indent, depth)
+                       }
+                       dst.WriteByte(c)
+
+               default:
+                       dst.WriteByte(c)
+               }
+       }
+       if scan.eof() == scanError {
+               dst.Truncate(origLen)
+               return scan.err
+       }
+       return nil
+}
diff --git a/libgo/go/json/scanner.go b/libgo/go/json/scanner.go
new file mode 100644 (file)
index 0000000..112c8f9
--- /dev/null
@@ -0,0 +1,618 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+// JSON value parser state machine.
+// Just about at the limit of what is reasonable to write by hand.
+// Some parts are a bit tedious, but overall it nicely factors out the
+// otherwise common code from the multiple scanning functions
+// in this package (Compact, Indent, checkValid, nextValue, etc).
+//
+// This file starts with two simple examples using the scanner
+// before diving into the scanner itself.
+
+import (
+       "os"
+       "strconv"
+)
+
+// checkValid verifies that data is valid JSON-encoded data.
+// scan is passed in for use by checkValid to avoid an allocation.
+func checkValid(data []byte, scan *scanner) os.Error {
+       scan.reset()
+       for _, c := range data {
+               if scan.step(scan, int(c)) == scanError {
+                       return scan.err
+               }
+       }
+       if scan.eof() == scanError {
+               return scan.err
+       }
+       return nil
+}
+
+// nextValue splits data after the next whole JSON value,
+// returning that value and the bytes that follow it as separate slices.
+// scan is passed in for use by nextValue to avoid an allocation.
+func nextValue(data []byte, scan *scanner) (value, rest []byte, err os.Error) {
+       scan.reset()
+       for i, c := range data {
+               v := scan.step(scan, int(c))
+               if v >= scanEnd {
+                       switch v {
+                       case scanError:
+                               return nil, nil, scan.err
+                       case scanEnd:
+                               return data[0:i], data[i:], nil
+                       }
+               }
+       }
+       if scan.eof() == scanError {
+               return nil, nil, scan.err
+       }
+       return data, nil, nil
+}
+
+// A SyntaxError is a description of a JSON syntax error.
+type SyntaxError string
+
+func (e SyntaxError) String() string { return string(e) }
+
+
+// A scanner is a JSON scanning state machine.
+// Callers call scan.reset() and then pass bytes in one at a time
+// by calling scan.step(&scan, c) for each byte.
+// The return value, referred to as an opcode, tells the
+// caller about significant parsing events like beginning
+// and ending literals, objects, and arrays, so that the
+// caller can follow along if it wishes.
+// The return value scanEnd indicates that a single top-level
+// JSON value has been completed, *before* the byte that
+// just got passed in.  (The indication must be delayed in order
+// to recognize the end of numbers: is 123 a whole value or
+// the beginning of 12345e+6?).
+type scanner struct {
+       // The step is a func to be called to execute the next transition.
+       // Also tried using an integer constant and a single func
+       // with a switch, but using the func directly was 10% faster
+       // on a 64-bit Mac Mini, and it's nicer to read.
+       step func(*scanner, int) int
+
+       // Stack of what we're in the middle of - array values, object keys, object values.
+       parseState []int
+
+       // Error that happened, if any.
+       err os.Error
+
+       // 1-byte redo (see undo method)
+       redoCode  int
+       redoState func(*scanner, int) int
+}
+
+// These values are returned by the state transition functions
+// assigned to scanner.state and the method scanner.eof.
+// They give details about the current state of the scan that
+// callers might be interested to know about.
+// It is okay to ignore the return value of any particular
+// call to scanner.state: if one call returns scanError,
+// every subsequent call will return scanError too.
+const (
+       // Continue.
+       scanContinue     = iota // uninteresting byte
+       scanBeginLiteral        // end implied by next result != scanContinue
+       scanBeginObject         // begin object
+       scanObjectKey           // just finished object key (string)
+       scanObjectValue         // just finished non-last object value
+       scanEndObject           // end object (implies scanObjectValue if possible)
+       scanBeginArray          // begin array
+       scanArrayValue          // just finished array value
+       scanEndArray            // end array (implies scanArrayValue if possible)
+       scanSkipSpace           // space byte; can skip; known to be last "continue" result
+
+       // Stop.
+       scanEnd   // top-level value ended *before* this byte; known to be first "stop" result
+       scanError // hit an error, scanner.err.
+)
+
+// These values are stored in the parseState stack.
+// They give the current state of a composite value
+// being scanned.  If the parser is inside a nested value
+// the parseState describes the nested state, outermost at entry 0.
+const (
+       parseObjectKey   = iota // parsing object key (before colon)
+       parseObjectValue        // parsing object value (after colon)
+       parseArrayValue         // parsing array value
+)
+
+// reset prepares the scanner for use.
+// It must be called before calling s.step.
+func (s *scanner) reset() {
+       s.step = stateBeginValue
+       s.parseState = s.parseState[0:0]
+       s.err = nil
+}
+
+// eof tells the scanner that the end of input has been reached.
+// It returns a scan status just as s.step does.
+func (s *scanner) eof() int {
+       if s.err != nil {
+               return scanError
+       }
+       if s.step == stateEndTop {
+               return scanEnd
+       }
+       s.step(s, ' ')
+       if s.step == stateEndTop {
+               return scanEnd
+       }
+       if s.err == nil {
+               s.err = SyntaxError("unexpected end of JSON input")
+       }
+       return scanError
+}
+
+// pushParseState pushes a new parse state p onto the parse stack.
+func (s *scanner) pushParseState(p int) {
+       s.parseState = append(s.parseState, p)
+}
+
+// popParseState pops a parse state (already obtained) off the stack
+// and updates s.step accordingly.
+func (s *scanner) popParseState() {
+       n := len(s.parseState) - 1
+       s.parseState = s.parseState[0:n]
+       if n == 0 {
+               s.step = stateEndTop
+       } else {
+               s.step = stateEndValue
+       }
+}
+
+func isSpace(c int) bool {
+       return c == ' ' || c == '\t' || c == '\r' || c == '\n'
+}
+
+// NOTE(rsc): The various instances of
+//
+//     if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+//
+// below should all be if c <= ' ' && isSpace(c), but inlining
+// the checks makes a significant difference (>10%) in tight loops
+// such as nextValue.  These should be rewritten with the clearer
+// function call once 6g knows to inline the call.
+
+// stateBeginValueOrEmpty is the state after reading `[`.
+func stateBeginValueOrEmpty(s *scanner, c int) int {
+       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+               return scanSkipSpace
+       }
+       if c == ']' {
+               return stateEndValue(s, c)
+       }
+       return stateBeginValue(s, c)
+}
+
+// stateBeginValue is the state at the beginning of the input.
+func stateBeginValue(s *scanner, c int) int {
+       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+               return scanSkipSpace
+       }
+       switch c {
+       case '{':
+               s.step = stateBeginStringOrEmpty
+               s.pushParseState(parseObjectKey)
+               return scanBeginObject
+       case '[':
+               s.step = stateBeginValueOrEmpty
+               s.pushParseState(parseArrayValue)
+               return scanBeginArray
+       case '"':
+               s.step = stateInString
+               return scanBeginLiteral
+       case '-':
+               s.step = stateNeg
+               return scanBeginLiteral
+       case '0': // beginning of 0.123
+               s.step = state0
+               return scanBeginLiteral
+       case 't': // beginning of true
+               s.step = stateT
+               return scanBeginLiteral
+       case 'f': // beginning of false
+               s.step = stateF
+               return scanBeginLiteral
+       case 'n': // beginning of null
+               s.step = stateN
+               return scanBeginLiteral
+       }
+       if '1' <= c && c <= '9' { // beginning of 1234.5
+               s.step = state1
+               return scanBeginLiteral
+       }
+       return s.error(c, "looking for beginning of value")
+}
+
+// stateBeginStringOrEmpty is the state after reading `{`.
+func stateBeginStringOrEmpty(s *scanner, c int) int {
+       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+               return scanSkipSpace
+       }
+       if c == '}' {
+               n := len(s.parseState)
+               s.parseState[n-1] = parseObjectValue
+               return stateEndValue(s, c)
+       }
+       return stateBeginString(s, c)
+}
+
+// stateBeginString is the state after reading `{"key": value,`.
+func stateBeginString(s *scanner, c int) int {
+       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+               return scanSkipSpace
+       }
+       if c == '"' {
+               s.step = stateInString
+               return scanBeginLiteral
+       }
+       return s.error(c, "looking for beginning of object key string")
+}
+
+// stateEndValue is the state after completing a value,
+// such as after reading `{}` or `true` or `["x"`.
+func stateEndValue(s *scanner, c int) int {
+       n := len(s.parseState)
+       if n == 0 {
+               // Completed top-level before the current byte.
+               s.step = stateEndTop
+               return stateEndTop(s, c)
+       }
+       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+               s.step = stateEndValue
+               return scanSkipSpace
+       }
+       ps := s.parseState[n-1]
+       switch ps {
+       case parseObjectKey:
+               if c == ':' {
+                       s.parseState[n-1] = parseObjectValue
+                       s.step = stateBeginValue
+                       return scanObjectKey
+               }
+               return s.error(c, "after object key")
+       case parseObjectValue:
+               if c == ',' {
+                       s.parseState[n-1] = parseObjectKey
+                       s.step = stateBeginString
+                       return scanObjectValue
+               }
+               if c == '}' {
+                       s.popParseState()
+                       return scanEndObject
+               }
+               return s.error(c, "after object key:value pair")
+       case parseArrayValue:
+               if c == ',' {
+                       s.step = stateBeginValue
+                       return scanArrayValue
+               }
+               if c == ']' {
+                       s.popParseState()
+                       return scanEndArray
+               }
+               return s.error(c, "after array element")
+       }
+       return s.error(c, "")
+}
+
+// stateEndTop is the state after finishing the top-level value,
+// such as after reading `{}` or `[1,2,3]`.
+// Only space characters should be seen now.
+func stateEndTop(s *scanner, c int) int {
+       if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
+               // Complain about non-space byte on next call.
+               s.error(c, "after top-level value")
+       }
+       return scanEnd
+}
+
+// stateInString is the state after reading `"`.
+func stateInString(s *scanner, c int) int {
+       if c == '"' {
+               s.step = stateEndValue
+               return scanContinue
+       }
+       if c == '\\' {
+               s.step = stateInStringEsc
+               return scanContinue
+       }
+       if c < 0x20 {
+               return s.error(c, "in string literal")
+       }
+       return scanContinue
+}
+
+// stateInStringEsc is the state after reading `"\` during a quoted string.
+func stateInStringEsc(s *scanner, c int) int {
+       switch c {
+       case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
+               s.step = stateInString
+               return scanContinue
+       }
+       if c == 'u' {
+               s.step = stateInStringEscU
+               return scanContinue
+       }
+       return s.error(c, "in string escape code")
+}
+
+// stateInStringEscU is the state after reading `"\u` during a quoted string.
+func stateInStringEscU(s *scanner, c int) int {
+       if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+               s.step = stateInStringEscU1
+               return scanContinue
+       }
+       // numbers
+       return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU1 is the state after reading `"\u1` during a quoted string.
+func stateInStringEscU1(s *scanner, c int) int {
+       if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+               s.step = stateInStringEscU12
+               return scanContinue
+       }
+       // numbers
+       return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU12 is the state after reading `"\u12` during a quoted string.
+func stateInStringEscU12(s *scanner, c int) int {
+       if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+               s.step = stateInStringEscU123
+               return scanContinue
+       }
+       // numbers
+       return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU123 is the state after reading `"\u123` during a quoted string.
+func stateInStringEscU123(s *scanner, c int) int {
+       if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+               s.step = stateInString
+               return scanContinue
+       }
+       // numbers
+       return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU123 is the state after reading `-` during a number.
+func stateNeg(s *scanner, c int) int {
+       if c == '0' {
+               s.step = state0
+               return scanContinue
+       }
+       if '1' <= c && c <= '9' {
+               s.step = state1
+               return scanContinue
+       }
+       return s.error(c, "in numeric literal")
+}
+
+// state1 is the state after reading a non-zero integer during a number,
+// such as after reading `1` or `100` but not `0`.
+func state1(s *scanner, c int) int {
+       if '0' <= c && c <= '9' {
+               s.step = state1
+               return scanContinue
+       }
+       return state0(s, c)
+}
+
+// state0 is the state after reading `0` during a number.
+func state0(s *scanner, c int) int {
+       if c == '.' {
+               s.step = stateDot
+               return scanContinue
+       }
+       if c == 'e' {
+               s.step = stateE
+               return scanContinue
+       }
+       return stateEndValue(s, c)
+}
+
+// stateDot is the state after reading the integer and decimal point in a number,
+// such as after reading `1.`.
+func stateDot(s *scanner, c int) int {
+       if '0' <= c && c <= '9' {
+               s.step = stateDot0
+               return scanContinue
+       }
+       return s.error(c, "after decimal point in numeric literal")
+}
+
+// stateDot0 is the state after reading the integer, decimal point, and subsequent
+// digits of a number, such as after reading `3.14`.
+func stateDot0(s *scanner, c int) int {
+       if '0' <= c && c <= '9' {
+               s.step = stateDot0
+               return scanContinue
+       }
+       if c == 'e' {
+               s.step = stateE
+               return scanContinue
+       }
+       return stateEndValue(s, c)
+}
+
+// stateE is the state after reading the mantissa and e in a number,
+// such as after reading `314e` or `0.314e`.
+func stateE(s *scanner, c int) int {
+       if c == '+' {
+               s.step = stateESign
+               return scanContinue
+       }
+       if c == '-' {
+               s.step = stateESign
+               return scanContinue
+       }
+       return stateESign(s, c)
+}
+
+// stateESign is the state after reading the mantissa, e, and sign in a number,
+// such as after reading `314e-` or `0.314e+`.
+func stateESign(s *scanner, c int) int {
+       if '0' <= c && c <= '9' {
+               s.step = stateE0
+               return scanContinue
+       }
+       return s.error(c, "in exponent of numeric literal")
+}
+
+// stateE0 is the state after reading the mantissa, e, optional sign,
+// and at least one digit of the exponent in a number,
+// such as after reading `314e-2` or `0.314e+1` or `3.14e0`.
+func stateE0(s *scanner, c int) int {
+       if '0' <= c && c <= '9' {
+               s.step = stateE0
+               return scanContinue
+       }
+       return stateEndValue(s, c)
+}
+
+// stateT is the state after reading `t`.
+func stateT(s *scanner, c int) int {
+       if c == 'r' {
+               s.step = stateTr
+               return scanContinue
+       }
+       return s.error(c, "in literal true (expecting 'r')")
+}
+
+// stateTr is the state after reading `tr`.
+func stateTr(s *scanner, c int) int {
+       if c == 'u' {
+               s.step = stateTru
+               return scanContinue
+       }
+       return s.error(c, "in literal true (expecting 'u')")
+}
+
+// stateTru is the state after reading `tru`.
+func stateTru(s *scanner, c int) int {
+       if c == 'e' {
+               s.step = stateEndValue
+               return scanContinue
+       }
+       return s.error(c, "in literal true (expecting 'e')")
+}
+
+// stateF is the state after reading `f`.
+func stateF(s *scanner, c int) int {
+       if c == 'a' {
+               s.step = stateFa
+               return scanContinue
+       }
+       return s.error(c, "in literal false (expecting 'a')")
+}
+
+// stateFa is the state after reading `fa`.
+func stateFa(s *scanner, c int) int {
+       if c == 'l' {
+               s.step = stateFal
+               return scanContinue
+       }
+       return s.error(c, "in literal false (expecting 'l')")
+}
+
+// stateFal is the state after reading `fal`.
+func stateFal(s *scanner, c int) int {
+       if c == 's' {
+               s.step = stateFals
+               return scanContinue
+       }
+       return s.error(c, "in literal false (expecting 's')")
+}
+
+// stateFals is the state after reading `fals`.
+func stateFals(s *scanner, c int) int {
+       if c == 'e' {
+               s.step = stateEndValue
+               return scanContinue
+       }
+       return s.error(c, "in literal false (expecting 'e')")
+}
+
+// stateN is the state after reading `n`.
+func stateN(s *scanner, c int) int {
+       if c == 'u' {
+               s.step = stateNu
+               return scanContinue
+       }
+       return s.error(c, "in literal null (expecting 'u')")
+}
+
+// stateNu is the state after reading `nu`.
+func stateNu(s *scanner, c int) int {
+       if c == 'l' {
+               s.step = stateNul
+               return scanContinue
+       }
+       return s.error(c, "in literal null (expecting 'l')")
+}
+
+// stateNul is the state after reading `nul`.
+func stateNul(s *scanner, c int) int {
+       if c == 'l' {
+               s.step = stateEndValue
+               return scanContinue
+       }
+       return s.error(c, "in literal null (expecting 'l')")
+}
+
+// stateError is the state after reaching a syntax error,
+// such as after reading `[1}` or `5.1.2`.
+func stateError(s *scanner, c int) int {
+       return scanError
+}
+
+// error records an error and switches to the error state.
+func (s *scanner) error(c int, context string) int {
+       s.step = stateError
+       s.err = SyntaxError("invalid character " + quoteChar(c) + " " + context)
+       return scanError
+}
+
+// quoteChar formats c as a quoted character literal
+func quoteChar(c int) string {
+       // special cases - different from quoted strings
+       if c == '\'' {
+               return `'\''`
+       }
+       if c == '"' {
+               return `'"'`
+       }
+
+       // use quoted string with different quotation marks
+       s := strconv.Quote(string(c))
+       return "'" + s[1:len(s)-1] + "'"
+}
+
+// undo causes the scanner to return scanCode from the next state transition.
+// This gives callers a simple 1-byte undo mechanism.
+func (s *scanner) undo(scanCode int) {
+       if s.step == stateRedo {
+               panic("invalid use of scanner")
+       }
+       s.redoCode = scanCode
+       s.redoState = s.step
+       s.step = stateRedo
+}
+
+// stateRedo helps implement the scanner's 1-byte undo.
+func stateRedo(s *scanner, c int) int {
+       s.step = s.redoState
+       return s.redoCode
+}
diff --git a/libgo/go/json/scanner_test.go b/libgo/go/json/scanner_test.go
new file mode 100644 (file)
index 0000000..82d520b
--- /dev/null
@@ -0,0 +1,260 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+       "bytes"
+       "math"
+       "rand"
+       "testing"
+)
+
+// Tests of simple examples.
+
+type example struct {
+       compact string
+       indent  string
+}
+
+var examples = []example{
+       {`1`, `1`},
+       {`{}`, `{}`},
+       {`[]`, `[]`},
+       {`{"":2}`, "{\n\t\"\": 2\n}"},
+       {`[3]`, "[\n\t3\n]"},
+       {`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
+       {`{"x":1}`, "{\n\t\"x\": 1\n}"},
+       {ex1, ex1i},
+}
+
+var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]`
+
+var ex1i = `[
+       true,
+       false,
+       null,
+       "x",
+       1,
+       1.5,
+       0,
+       -5e+2
+]`
+
+func TestCompact(t *testing.T) {
+       var buf bytes.Buffer
+       for _, tt := range examples {
+               buf.Reset()
+               if err := Compact(&buf, []byte(tt.compact)); err != nil {
+                       t.Errorf("Compact(%#q): %v", tt.compact, err)
+               } else if s := buf.String(); s != tt.compact {
+                       t.Errorf("Compact(%#q) = %#q, want original", tt.compact, s)
+               }
+
+               buf.Reset()
+               if err := Compact(&buf, []byte(tt.indent)); err != nil {
+                       t.Errorf("Compact(%#q): %v", tt.indent, err)
+                       continue
+               } else if s := buf.String(); s != tt.compact {
+                       t.Errorf("Compact(%#q) = %#q, want %#q", tt.indent, s, tt.compact)
+               }
+       }
+}
+
+func TestIndent(t *testing.T) {
+       var buf bytes.Buffer
+       for _, tt := range examples {
+               buf.Reset()
+               if err := Indent(&buf, []byte(tt.indent), "", "\t"); err != nil {
+                       t.Errorf("Indent(%#q): %v", tt.indent, err)
+               } else if s := buf.String(); s != tt.indent {
+                       t.Errorf("Indent(%#q) = %#q, want original", tt.indent, s)
+               }
+
+               buf.Reset()
+               if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
+                       t.Errorf("Indent(%#q): %v", tt.compact, err)
+                       continue
+               } else if s := buf.String(); s != tt.indent {
+                       t.Errorf("Indent(%#q) = %#q, want %#q", tt.compact, s, tt.indent)
+               }
+       }
+}
+
+// Tests of a large random structure.
+
+func TestCompactBig(t *testing.T) {
+       var buf bytes.Buffer
+       if err := Compact(&buf, jsonBig); err != nil {
+               t.Fatalf("Compact: %v", err)
+       }
+       b := buf.Bytes()
+       if bytes.Compare(b, jsonBig) != 0 {
+               t.Error("Compact(jsonBig) != jsonBig")
+               diff(t, b, jsonBig)
+               return
+       }
+}
+
+func TestIndentBig(t *testing.T) {
+       var buf bytes.Buffer
+       if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
+               t.Fatalf("Indent1: %v", err)
+       }
+       b := buf.Bytes()
+       if len(b) == len(jsonBig) {
+               // jsonBig is compact (no unnecessary spaces);
+               // indenting should make it bigger
+               t.Fatalf("Indent(jsonBig) did not get bigger")
+       }
+
+       // should be idempotent
+       var buf1 bytes.Buffer
+       if err := Indent(&buf1, b, "", "\t"); err != nil {
+               t.Fatalf("Indent2: %v", err)
+       }
+       b1 := buf1.Bytes()
+       if bytes.Compare(b1, b) != 0 {
+               t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)")
+               diff(t, b1, b)
+               return
+       }
+
+       // should get back to original
+       buf1.Reset()
+       if err := Compact(&buf1, b); err != nil {
+               t.Fatalf("Compact: %v", err)
+       }
+       b1 = buf1.Bytes()
+       if bytes.Compare(b1, jsonBig) != 0 {
+               t.Error("Compact(Indent(jsonBig)) != jsonBig")
+               diff(t, b1, jsonBig)
+               return
+       }
+}
+
+func TestNextValueBig(t *testing.T) {
+       var scan scanner
+       item, rest, err := nextValue(jsonBig, &scan)
+       if err != nil {
+               t.Fatalf("nextValue: ", err)
+       }
+       if len(item) != len(jsonBig) || &item[0] != &jsonBig[0] {
+               t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
+       }
+       if len(rest) != 0 {
+               t.Errorf("invalid rest: %d", len(rest))
+       }
+
+       item, rest, err = nextValue(bytes.Add(jsonBig, []byte("HELLO WORLD")), &scan)
+       if err != nil {
+               t.Fatalf("nextValue extra: ", err)
+       }
+       if len(item) != len(jsonBig) {
+               t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
+       }
+       if string(rest) != "HELLO WORLD" {
+               t.Errorf("invalid rest: %d", len(rest))
+       }
+}
+
+func BenchmarkSkipValue(b *testing.B) {
+       var scan scanner
+       for i := 0; i < b.N; i++ {
+               nextValue(jsonBig, &scan)
+       }
+       b.SetBytes(int64(len(jsonBig)))
+}
+
+func diff(t *testing.T, a, b []byte) {
+       for i := 0; ; i++ {
+               if i >= len(a) || i >= len(b) || a[i] != b[i] {
+                       j := i - 10
+                       if j < 0 {
+                               j = 0
+                       }
+                       t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:]))
+                       return
+               }
+       }
+}
+
+func trim(b []byte) []byte {
+       if len(b) > 20 {
+               return b[0:20]
+       }
+       return b
+}
+
+// Generate a random JSON object.
+
+var jsonBig []byte
+
+func init() {
+       b, err := Marshal(genValue(10000))
+       if err != nil {
+               panic(err)
+       }
+       jsonBig = b
+}
+
+func genValue(n int) interface{} {
+       if n > 1 {
+               switch rand.Intn(2) {
+               case 0:
+                       return genArray(n)
+               case 1:
+                       return genMap(n)
+               }
+       }
+       switch rand.Intn(3) {
+       case 0:
+               return rand.Intn(2) == 0
+       case 1:
+               return rand.NormFloat64()
+       case 2:
+               return genString(30)
+       }
+       panic("unreachable")
+}
+
+func genString(stddev float64) string {
+       n := int(math.Fabs(rand.NormFloat64()*stddev + stddev/2))
+       c := make([]int, n)
+       for i := range c {
+               f := math.Fabs(rand.NormFloat64()*64 + 32)
+               if f > 0x10ffff {
+                       f = 0x10ffff
+               }
+               c[i] = int(f)
+       }
+       return string(c)
+}
+
+func genArray(n int) []interface{} {
+       f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+       if f > n {
+               f = n
+       }
+       x := make([]interface{}, int(f))
+       for i := range x {
+               x[i] = genValue(((i+1)*n)/f - (i*n)/f)
+       }
+       return x
+}
+
+func genMap(n int) map[string]interface{} {
+       f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+       if f > n {
+               f = n
+       }
+       if n > 0 && f == 0 {
+               f = 1
+       }
+       x := make(map[string]interface{})
+       for i := 0; i < f; i++ {
+               x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f)
+       }
+       return x
+}
diff --git a/libgo/go/json/stream.go b/libgo/go/json/stream.go
new file mode 100644 (file)
index 0000000..d4fb346
--- /dev/null
@@ -0,0 +1,185 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+       "bytes"
+       "io"
+       "os"
+)
+
+// A Decoder reads and decodes JSON objects from an input stream.
+type Decoder struct {
+       r    io.Reader
+       buf  []byte
+       d    decodeState
+       scan scanner
+       err  os.Error
+}
+
+// NewDecoder returns a new decoder that reads from r.
+func NewDecoder(r io.Reader) *Decoder {
+       return &Decoder{r: r}
+}
+
+// Decode reads the next JSON-encoded value from the
+// connection and stores it in the value pointed to by v.
+//
+// See the documentation for Unmarshal for details about
+// the conversion of JSON into a Go value.
+func (dec *Decoder) Decode(v interface{}) os.Error {
+       if dec.err != nil {
+               return dec.err
+       }
+
+       n, err := dec.readValue()
+       if err != nil {
+               return err
+       }
+
+       // Don't save err from unmarshal into dec.err:
+       // the connection is still usable since we read a complete JSON
+       // object from it before the error happened.
+       dec.d.init(dec.buf[0:n])
+       err = dec.d.unmarshal(v)
+
+       // Slide rest of data down.
+       rest := copy(dec.buf, dec.buf[n:])
+       dec.buf = dec.buf[0:rest]
+
+       return err
+}
+
+// readValue reads a JSON value into dec.buf.
+// It returns the length of the encoding.
+func (dec *Decoder) readValue() (int, os.Error) {
+       dec.scan.reset()
+
+       scanp := 0
+       var err os.Error
+Input:
+       for {
+               // Look in the buffer for a new value.
+               for i, c := range dec.buf[scanp:] {
+                       v := dec.scan.step(&dec.scan, int(c))
+                       if v == scanEnd {
+                               scanp += i
+                               break Input
+                       }
+                       // scanEnd is delayed one byte.
+                       // We might block trying to get that byte from src,
+                       // so instead invent a space byte.
+                       if v == scanEndObject && dec.scan.step(&dec.scan, ' ') == scanEnd {
+                               scanp += i + 1
+                               break Input
+                       }
+                       if v == scanError {
+                               dec.err = dec.scan.err
+                               return 0, dec.scan.err
+                       }
+               }
+               scanp = len(dec.buf)
+
+               // Did the last read have an error?
+               // Delayed until now to allow buffer scan.
+               if err != nil {
+                       if err == os.EOF {
+                               if dec.scan.step(&dec.scan, ' ') == scanEnd {
+                                       break Input
+                               }
+                               if nonSpace(dec.buf) {
+                                       err = io.ErrUnexpectedEOF
+                               }
+                       }
+                       dec.err = err
+                       return 0, err
+               }
+
+               // Make room to read more into the buffer.
+               const minRead = 512
+               if cap(dec.buf)-len(dec.buf) < minRead {
+                       newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
+                       copy(newBuf, dec.buf)
+                       dec.buf = newBuf
+               }
+
+               // Read.  Delay error for next iteration (after scan).
+               var n int
+               n, err = dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
+               dec.buf = dec.buf[0 : len(dec.buf)+n]
+       }
+       return scanp, nil
+}
+
+func nonSpace(b []byte) bool {
+       for _, c := range b {
+               if !isSpace(int(c)) {
+                       return true
+               }
+       }
+       return false
+}
+
+// An Encoder writes JSON objects to an output stream.
+type Encoder struct {
+       w   io.Writer
+       e   encodeState
+       err os.Error
+}
+
+// NewEncoder returns a new encoder that writes to w.
+func NewEncoder(w io.Writer) *Encoder {
+       return &Encoder{w: w}
+}
+
+// Encode writes the JSON encoding of v to the connection.
+//
+// See the documentation for Marshal for details about the
+// conversion of Go values to JSON.
+func (enc *Encoder) Encode(v interface{}) os.Error {
+       if enc.err != nil {
+               return enc.err
+       }
+       enc.e.Reset()
+       err := enc.e.marshal(v)
+       if err != nil {
+               return err
+       }
+
+       // Terminate each value with a newline.
+       // This makes the output look a little nicer
+       // when debugging, and some kind of space
+       // is required if the encoded value was a number,
+       // so that the reader knows there aren't more
+       // digits coming.
+       enc.e.WriteByte('\n')
+
+       if _, err = enc.w.Write(enc.e.Bytes()); err != nil {
+               enc.err = err
+       }
+       return err
+}
+
+// RawMessage is a raw encoded JSON object.
+// It implements Marshaler and Unmarshaler and can
+// be used to delay JSON decoding or precompute a JSON encoding.
+type RawMessage []byte
+
+// MarshalJSON returns *m as the JSON encoding of m.
+func (m *RawMessage) MarshalJSON() ([]byte, os.Error) {
+       return *m, nil
+}
+
+// UnmarshalJSON sets *m to a copy of data.
+func (m *RawMessage) UnmarshalJSON(data []byte) os.Error {
+       if m == nil {
+               return os.NewError("json.RawMessage: UnmarshalJSON on nil pointer")
+       }
+       *m = bytes.Add((*m)[0:0], data)
+       return nil
+}
+
+var _ Marshaler = (*RawMessage)(nil)
+var _ Unmarshaler = (*RawMessage)(nil)
diff --git a/libgo/go/json/stream_test.go b/libgo/go/json/stream_test.go
new file mode 100644 (file)
index 0000000..ab90b75
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+       "bytes"
+       "reflect"
+       "testing"
+)
+
+// Test values for the stream test.
+// One of each JSON kind.
+var streamTest = []interface{}{
+       float64(0.1),
+       "hello",
+       nil,
+       true,
+       false,
+       []interface{}{"a", "b", "c"},
+       map[string]interface{}{"K": "Kelvin", "ß": "long s"},
+       float64(3.14), // another value to make sure something can follow map
+}
+
+var streamEncoded = `0.1
+"hello"
+null
+true
+false
+["a","b","c"]
+{"ß":"long s","K":"Kelvin"}
+3.14
+`
+
+func TestEncoder(t *testing.T) {
+       for i := 0; i <= len(streamTest); i++ {
+               var buf bytes.Buffer
+               enc := NewEncoder(&buf)
+               for j, v := range streamTest[0:i] {
+                       if err := enc.Encode(v); err != nil {
+                               t.Fatalf("encode #%d: %v", j, err)
+                       }
+               }
+               if have, want := buf.String(), nlines(streamEncoded, i); have != want {
+                       t.Errorf("encoding %d items: mismatch", i)
+                       diff(t, []byte(have), []byte(want))
+                       break
+               }
+       }
+}
+
+func TestDecoder(t *testing.T) {
+       for i := 0; i <= len(streamTest); i++ {
+               // Use stream without newlines as input,
+               // just to stress the decoder even more.
+               // Our test input does not include back-to-back numbers.
+               // Otherwise stripping the newlines would
+               // merge two adjacent JSON values.
+               var buf bytes.Buffer
+               for _, c := range nlines(streamEncoded, i) {
+                       if c != '\n' {
+                               buf.WriteRune(c)
+                       }
+               }
+               out := make([]interface{}, i)
+               dec := NewDecoder(&buf)
+               for j := range out {
+                       if err := dec.Decode(&out[j]); err != nil {
+                               t.Fatalf("decode #%d/%d: %v", j, i, err)
+                       }
+               }
+               if !reflect.DeepEqual(out, streamTest[0:i]) {
+                       t.Errorf("decoding %d items: mismatch")
+                       for j := range out {
+                               if !reflect.DeepEqual(out[j], streamTest[j]) {
+                                       t.Errorf("#%d: have %v want %v", out[j], streamTest[j])
+                               }
+                       }
+                       break
+               }
+       }
+}
+
+func nlines(s string, n int) string {
+       if n <= 0 {
+               return ""
+       }
+       for i, c := range s {
+               if c == '\n' {
+                       if n--; n == 0 {
+                               return s[0 : i+1]
+                       }
+               }
+       }
+       return s
+}
+
+func TestRawMessage(t *testing.T) {
+       // TODO(rsc): Should not need the * in *RawMessage
+       var data struct {
+               X  float64
+               Id *RawMessage
+               Y  float32
+       }
+       const raw = `["\u0056",null]`
+       const msg = `{"X":0.1,"Id":["\u0056",null],"Y":0.2}`
+       err := Unmarshal([]byte(msg), &data)
+       if err != nil {
+               t.Fatalf("Unmarshal: %v", err)
+       }
+       if string([]byte(*data.Id)) != raw {
+               t.Fatalf("Raw mismatch: have %#q want %#q", []byte(*data.Id), raw)
+       }
+       b, err := Marshal(&data)
+       if err != nil {
+               t.Fatalf("Marshal: %v", err)
+       }
+       if string(b) != msg {
+               t.Fatalf("Marshal: have %#q want %#q", b, msg)
+       }
+}
diff --git a/libgo/go/log/log.go b/libgo/go/log/log.go
new file mode 100644 (file)
index 0000000..ac24b4d
--- /dev/null
@@ -0,0 +1,232 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Simple logging package. It defines a type, Logger, with methods
+// for formatting output. It also has a predefined 'standard' Logger
+// accessible through helper functions Print[f|ln], Exit[f|ln], and
+// Panic[f|ln], which are easier to use than creating a Logger manually.
+// That logger writes to standard error and prints the date and time
+// of each logged message.
+// The Exit functions call os.Exit(1) after writing the log message.
+// The Panic functions call panic after writing the log message.
+package log
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "runtime"
+       "os"
+       "time"
+)
+
+// These flags define which text to prefix to each log entry generated by the Logger.
+const (
+       // Bits or'ed together to control what's printed. There is no control over the
+       // order they appear (the order listed here) or the format they present (as
+       // described in the comments).  A colon appears after these items:
+       //      2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
+       Ldate         = 1 << iota // the date: 2009/0123
+       Ltime                     // the time: 01:23:23
+       Lmicroseconds             // microsecond resolution: 01:23:23.123123.  assumes Ltime.
+       Llongfile                 // full file name and line number: /a/b/c/d.go:23
+       Lshortfile                // final file name element and line number: d.go:23. overrides Llongfile
+)
+
+// Logger represents an active logging object.
+type Logger struct {
+       out    io.Writer // destination for output
+       prefix string    // prefix to write at beginning of each line
+       flag   int       // properties
+}
+
+// New creates a new Logger.   The out variable sets the
+// destination to which log data will be written.
+// The prefix appears at the beginning of each generated log line.
+// The flag argument defines the logging properties.
+func New(out io.Writer, prefix string, flag int) *Logger {
+       return &Logger{out, prefix, flag}
+}
+
+var std = New(os.Stderr, "", Ldate|Ltime)
+
+// Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
+// Knows the buffer has capacity.
+func itoa(buf *bytes.Buffer, i int, wid int) {
+       var u uint = uint(i)
+       if u == 0 && wid <= 1 {
+               buf.WriteByte('0')
+               return
+       }
+
+       // Assemble decimal in reverse order.
+       var b [32]byte
+       bp := len(b)
+       for ; u > 0 || wid > 0; u /= 10 {
+               bp--
+               wid--
+               b[bp] = byte(u%10) + '0'
+       }
+
+       // avoid slicing b to avoid an allocation.
+       for bp < len(b) {
+               buf.WriteByte(b[bp])
+               bp++
+       }
+}
+
+func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
+       buf.WriteString(l.prefix)
+       if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
+               t := time.SecondsToLocalTime(ns / 1e9)
+               if l.flag&Ldate != 0 {
+                       itoa(buf, int(t.Year), 4)
+                       buf.WriteByte('/')
+                       itoa(buf, int(t.Month), 2)
+                       buf.WriteByte('/')
+                       itoa(buf, int(t.Day), 2)
+                       buf.WriteByte(' ')
+               }
+               if l.flag&(Ltime|Lmicroseconds) != 0 {
+                       itoa(buf, int(t.Hour), 2)
+                       buf.WriteByte(':')
+                       itoa(buf, int(t.Minute), 2)
+                       buf.WriteByte(':')
+                       itoa(buf, int(t.Second), 2)
+                       if l.flag&Lmicroseconds != 0 {
+                               buf.WriteByte('.')
+                               itoa(buf, int(ns%1e9)/1e3, 6)
+                       }
+                       buf.WriteByte(' ')
+               }
+       }
+       if l.flag&(Lshortfile|Llongfile) != 0 {
+               _, file, line, ok := runtime.Caller(calldepth)
+               if ok {
+                       if l.flag&Lshortfile != 0 {
+                               short := file
+                               for i := len(file) - 1; i > 0; i-- {
+                                       if file[i] == '/' {
+                                               short = file[i+1:]
+                                               break
+                                       }
+                               }
+                               file = short
+                       }
+               } else {
+                       file = "???"
+                       line = 0
+               }
+               buf.WriteString(file)
+               buf.WriteByte(':')
+               itoa(buf, line, -1)
+               buf.WriteString(": ")
+       }
+}
+
+// Output writes the output for a logging event.  The string s contains
+// the text to print after the prefix specified by the flags of the
+// Logger.  A newline is appended if the last character of s is not
+// already a newline.  Calldepth is used to recover the PC and is
+// provided for generality, although at the moment on all pre-defined
+// paths it will be 2.
+func (l *Logger) Output(calldepth int, s string) os.Error {
+       now := time.Nanoseconds() // get this early.
+       buf := new(bytes.Buffer)
+       l.formatHeader(buf, now, calldepth+1)
+       buf.WriteString(s)
+       if len(s) > 0 && s[len(s)-1] != '\n' {
+               buf.WriteByte('\n')
+       }
+       _, err := l.out.Write(buf.Bytes())
+       return err
+}
+
+// Printf calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Printf.
+func (l *Logger) Printf(format string, v ...interface{}) {
+       l.Output(2, fmt.Sprintf(format, v...))
+}
+
+// Print calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Print.
+func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }
+
+// Println calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Println.
+func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }
+
+// SetOutput sets the output destination for the standard logger.
+func SetOutput(w io.Writer) {
+       std.out = w
+}
+
+// SetFlags sets the output flags for the standard logger.
+func SetFlags(flag int) {
+       std.flag = flag
+}
+
+// SetPrefix sets the output prefix for the standard logger.
+func SetPrefix(prefix string) {
+       std.prefix = prefix
+}
+
+// These functions write to the standard logger.
+
+// Print calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Print.
+func Print(v ...interface{}) {
+       std.Output(2, fmt.Sprint(v...))
+}
+
+// Printf calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Printf.
+func Printf(format string, v ...interface{}) {
+       std.Output(2, fmt.Sprintf(format, v...))
+}
+
+// Println calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Println.
+func Println(v ...interface{}) {
+       std.Output(2, fmt.Sprintln(v...))
+}
+
+// Exit is equivalent to Print() followed by a call to os.Exit(1).
+func Exit(v ...interface{}) {
+       std.Output(2, fmt.Sprint(v...))
+       os.Exit(1)
+}
+
+// Exitf is equivalent to Printf() followed by a call to os.Exit(1).
+func Exitf(format string, v ...interface{}) {
+       std.Output(2, fmt.Sprintf(format, v...))
+       os.Exit(1)
+}
+
+// Exitln is equivalent to Println() followed by a call to os.Exit(1).
+func Exitln(v ...interface{}) {
+       std.Output(2, fmt.Sprintln(v...))
+       os.Exit(1)
+}
+
+// Panic is equivalent to Print() followed by a call to panic().
+func Panic(v ...interface{}) {
+       s := fmt.Sprint(v...)
+       std.Output(2, s)
+       panic(s)
+}
+
+// Panicf is equivalent to Printf() followed by a call to panic().
+func Panicf(format string, v ...interface{}) {
+       s := fmt.Sprintf(format, v...)
+       std.Output(2, s)
+       panic(s)
+}
+
+// Panicln is equivalent to Println() followed by a call to panic().
+func Panicln(v ...interface{}) {
+       s := fmt.Sprintln(v...)
+       std.Output(2, s)
+       panic(s)
+}
diff --git a/libgo/go/log/log_test.go b/libgo/go/log/log_test.go
new file mode 100644 (file)
index 0000000..bd4d1a9
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package log
+
+// These tests are too simple.
+
+import (
+       "bytes"
+       "os"
+       "regexp"
+       "testing"
+)
+
+const (
+       Rdate         = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
+       Rtime         = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
+       Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
+       Rline         = `[0-9]+:` // must update if the calls to l.Printf / l.Print below move
+       Rlongfile     = `.*/[A-Za-z0-9_\-]+\.go:|\?\?\?:` + Rline
+       Rshortfile    = `[A-Za-z0-9_\-]+\.go:|\?\?\?:` + Rline
+)
+
+type tester struct {
+       flag    int
+       prefix  string
+       pattern string // regexp that log output must match; we add ^ and expected_text$ always
+}
+
+var tests = []tester{
+       // individual pieces:
+       {0, "", ""},
+       {0, "XXX", "XXX"},
+       {Ldate, "", Rdate + " "},
+       {Ltime, "", Rtime + " "},
+       {Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
+       {Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
+       {Llongfile, "", Rlongfile + " "},
+       {Lshortfile, "", Rshortfile + " "},
+       {Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
+       // everything at once:
+       {Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "},
+       {Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "},
+}
+
+// Test using Println("hello", 23, "world") or using Printf("hello %d world", 23)
+func testPrint(t *testing.T, flag int, prefix string, pattern string, useFormat bool) {
+       buf := new(bytes.Buffer)
+       SetOutput(buf)
+       SetFlags(flag)
+       SetPrefix(prefix)
+       if useFormat {
+               Printf("hello %d world", 23)
+       } else {
+               Println("hello", 23, "world")
+       }
+       line := buf.String()
+       line = line[0 : len(line)-1]
+       pattern = "^" + pattern + "hello 23 world$"
+       matched, err4 := regexp.MatchString(pattern, line)
+       if err4 != nil {
+               t.Fatal("pattern did not compile:", err4)
+       }
+       if !matched {
+               t.Errorf("log output should match %q is %q", pattern, line)
+       }
+       SetOutput(os.Stderr)
+}
+
+func TestAll(t *testing.T) {
+       for _, testcase := range tests {
+               testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, false)
+               testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, true)
+       }
+}
+
+func TestOutput(t *testing.T) {
+       const testString = "test"
+       var b bytes.Buffer
+       l := New(&b, "", 0)
+       l.Println(testString)
+       if expect := testString + "\n"; b.String() != expect {
+               t.Errorf("log output should match %q is %q", expect, b.String())
+       }
+}
diff --git a/libgo/go/math/acosh.go b/libgo/go/math/acosh.go
new file mode 100644 (file)
index 0000000..d8067c0
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_acosh.c
+// and came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// __ieee754_acosh(x)
+// Method :
+//     Based on
+//             acosh(x) = log [ x + sqrt(x*x-1) ]
+//     we have
+//             acosh(x) := log(x)+ln2, if x is large; else
+//             acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+//             acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+//
+// Special cases:
+//     acosh(x) is NaN with signal if x<1.
+//     acosh(NaN) is NaN without signal.
+//
+
+// Acosh(x) calculates the inverse hyperbolic cosine of x.
+//
+// Special cases are:
+//     Acosh(x) = NaN if x < 1
+//     Acosh(NaN) = NaN
+func Acosh(x float64) float64 {
+       const (
+               Ln2   = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
+               Large = 1 << 28                    // 2**28
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN
+       // when compiler does it for us
+       // first case is special case
+       switch {
+       case x < 1 || x != x: // x < 1 || IsNaN(x):
+               return NaN()
+       case x == 1:
+               return 0
+       case x >= Large:
+               return Log(x) + Ln2 // x > 2**28
+       case x > 2:
+               return Log(2*x - 1/(x+Sqrt(x*x-1))) // 2**28 > x > 2
+       }
+       t := x - 1
+       return Log1p(t + Sqrt(2*t+t*t)) // 2 >= x > 1
+}
diff --git a/libgo/go/math/all_test.go b/libgo/go/math/all_test.go
new file mode 100644 (file)
index 0000000..7a61280
--- /dev/null
@@ -0,0 +1,2592 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math_test
+
+import (
+       "fmt"
+       . "math"
+       "runtime"
+       "testing"
+)
+
+var vf = []float64{
+       4.9790119248836735e+00,
+       7.7388724745781045e+00,
+       -2.7688005719200159e-01,
+       -5.0106036182710749e+00,
+       9.6362937071984173e+00,
+       2.9263772392439646e+00,
+       5.2290834314593066e+00,
+       2.7279399104360102e+00,
+       1.8253080916808550e+00,
+       -8.6859247685756013e+00,
+}
+// The expected results below were computed by the high precision calculators
+// at http://keisan.casio.com/.  More exact input values (array vf[], above)
+// were obtained by printing them with "%.26f".  The answers were calculated
+// to 26 digits (by using the "Digit number" drop-down control of each
+// calculator).
+var acos = []float64{
+       1.0496193546107222142571536e+00,
+       6.8584012813664425171660692e-01,
+       1.5984878714577160325521819e+00,
+       2.0956199361475859327461799e+00,
+       2.7053008467824138592616927e-01,
+       1.2738121680361776018155625e+00,
+       1.0205369421140629186287407e+00,
+       1.2945003481781246062157835e+00,
+       1.3872364345374451433846657e+00,
+       2.6231510803970463967294145e+00,
+}
+var acosh = []float64{
+       2.4743347004159012494457618e+00,
+       2.8576385344292769649802701e+00,
+       7.2796961502981066190593175e-01,
+       2.4796794418831451156471977e+00,
+       3.0552020742306061857212962e+00,
+       2.044238592688586588942468e+00,
+       2.5158701513104513595766636e+00,
+       1.99050839282411638174299e+00,
+       1.6988625798424034227205445e+00,
+       2.9611454842470387925531875e+00,
+}
+var asin = []float64{
+       5.2117697218417440497416805e-01,
+       8.8495619865825236751471477e-01,
+       -02.769154466281941332086016e-02,
+       -5.2482360935268931351485822e-01,
+       1.3002662421166552333051524e+00,
+       2.9698415875871901741575922e-01,
+       5.5025938468083370060258102e-01,
+       2.7629597861677201301553823e-01,
+       1.83559892257451475846656e-01,
+       -1.0523547536021497774980928e+00,
+}
+var asinh = []float64{
+       2.3083139124923523427628243e+00,
+       2.743551594301593620039021e+00,
+       -2.7345908534880091229413487e-01,
+       -2.3145157644718338650499085e+00,
+       2.9613652154015058521951083e+00,
+       1.7949041616585821933067568e+00,
+       2.3564032905983506405561554e+00,
+       1.7287118790768438878045346e+00,
+       1.3626658083714826013073193e+00,
+       -2.8581483626513914445234004e+00,
+}
+var atan = []float64{
+       1.372590262129621651920085e+00,
+       1.442290609645298083020664e+00,
+       -2.7011324359471758245192595e-01,
+       -1.3738077684543379452781531e+00,
+       1.4673921193587666049154681e+00,
+       1.2415173565870168649117764e+00,
+       1.3818396865615168979966498e+00,
+       1.2194305844639670701091426e+00,
+       1.0696031952318783760193244e+00,
+       -1.4561721938838084990898679e+00,
+}
+var atanh = []float64{
+       5.4651163712251938116878204e-01,
+       1.0299474112843111224914709e+00,
+       -2.7695084420740135145234906e-02,
+       -5.5072096119207195480202529e-01,
+       1.9943940993171843235906642e+00,
+       3.01448604578089708203017e-01,
+       5.8033427206942188834370595e-01,
+       2.7987997499441511013958297e-01,
+       1.8459947964298794318714228e-01,
+       -1.3273186910532645867272502e+00,
+}
+var atan2 = []float64{
+       1.1088291730037004444527075e+00,
+       9.1218183188715804018797795e-01,
+       1.5984772603216203736068915e+00,
+       2.0352918654092086637227327e+00,
+       8.0391819139044720267356014e-01,
+       1.2861075249894661588866752e+00,
+       1.0889904479131695712182587e+00,
+       1.3044821793397925293797357e+00,
+       1.3902530903455392306872261e+00,
+       2.2859857424479142655411058e+00,
+}
+var cbrt = []float64{
+       1.7075799841925094446722675e+00,
+       1.9779982212970353936691498e+00,
+       -6.5177429017779910853339447e-01,
+       -1.7111838886544019873338113e+00,
+       2.1279920909827937423960472e+00,
+       1.4303536770460741452312367e+00,
+       1.7357021059106154902341052e+00,
+       1.3972633462554328350552916e+00,
+       1.2221149580905388454977636e+00,
+       -2.0556003730500069110343596e+00,
+}
+var ceil = []float64{
+       5.0000000000000000e+00,
+       8.0000000000000000e+00,
+       0.0000000000000000e+00,
+       -5.0000000000000000e+00,
+       1.0000000000000000e+01,
+       3.0000000000000000e+00,
+       6.0000000000000000e+00,
+       3.0000000000000000e+00,
+       2.0000000000000000e+00,
+       -8.0000000000000000e+00,
+}
+var copysign = []float64{
+       -4.9790119248836735e+00,
+       -7.7388724745781045e+00,
+       -2.7688005719200159e-01,
+       -5.0106036182710749e+00,
+       -9.6362937071984173e+00,
+       -2.9263772392439646e+00,
+       -5.2290834314593066e+00,
+       -2.7279399104360102e+00,
+       -1.8253080916808550e+00,
+       -8.6859247685756013e+00,
+}
+var cos = []float64{
+       2.634752140995199110787593e-01,
+       1.148551260848219865642039e-01,
+       9.6191297325640768154550453e-01,
+       2.938141150061714816890637e-01,
+       -9.777138189897924126294461e-01,
+       -9.7693041344303219127199518e-01,
+       4.940088096948647263961162e-01,
+       -9.1565869021018925545016502e-01,
+       -2.517729313893103197176091e-01,
+       -7.39241351595676573201918e-01,
+}
+var cosh = []float64{
+       7.2668796942212842775517446e+01,
+       1.1479413465659254502011135e+03,
+       1.0385767908766418550935495e+00,
+       7.5000957789658051428857788e+01,
+       7.655246669605357888468613e+03,
+       9.3567491758321272072888257e+00,
+       9.331351599270605471131735e+01,
+       7.6833430994624643209296404e+00,
+       3.1829371625150718153881164e+00,
+       2.9595059261916188501640911e+03,
+}
+var erf = []float64{
+       5.1865354817738701906913566e-01,
+       7.2623875834137295116929844e-01,
+       -3.123458688281309990629839e-02,
+       -5.2143121110253302920437013e-01,
+       8.2704742671312902508629582e-01,
+       3.2101767558376376743993945e-01,
+       5.403990312223245516066252e-01,
+       3.0034702916738588551174831e-01,
+       2.0369924417882241241559589e-01,
+       -7.8069386968009226729944677e-01,
+}
+var erfc = []float64{
+       4.8134645182261298093086434e-01,
+       2.7376124165862704883070156e-01,
+       1.0312345868828130999062984e+00,
+       1.5214312111025330292043701e+00,
+       1.7295257328687097491370418e-01,
+       6.7898232441623623256006055e-01,
+       4.596009687776754483933748e-01,
+       6.9965297083261411448825169e-01,
+       7.9630075582117758758440411e-01,
+       1.7806938696800922672994468e+00,
+}
+var exp = []float64{
+       1.4533071302642137507696589e+02,
+       2.2958822575694449002537581e+03,
+       7.5814542574851666582042306e-01,
+       6.6668778421791005061482264e-03,
+       1.5310493273896033740861206e+04,
+       1.8659907517999328638667732e+01,
+       1.8662167355098714543942057e+02,
+       1.5301332413189378961665788e+01,
+       6.2047063430646876349125085e+00,
+       1.6894712385826521111610438e-04,
+}
+var expm1 = []float64{
+       5.105047796122957327384770212e-02,
+       8.046199708567344080562675439e-02,
+       -2.764970978891639815187418703e-03,
+       -4.8871434888875355394330300273e-02,
+       1.0115864277221467777117227494e-01,
+       2.969616407795910726014621657e-02,
+       5.368214487944892300914037972e-02,
+       2.765488851131274068067445335e-02,
+       1.842068661871398836913874273e-02,
+       -8.3193870863553801814961137573e-02,
+}
+var exp2 = []float64{
+       3.1537839463286288034313104e+01,
+       2.1361549283756232296144849e+02,
+       8.2537402562185562902577219e-01,
+       3.1021158628740294833424229e-02,
+       7.9581744110252191462569661e+02,
+       7.6019905892596359262696423e+00,
+       3.7506882048388096973183084e+01,
+       6.6250893439173561733216375e+00,
+       3.5438267900243941544605339e+00,
+       2.4281533133513300984289196e-03,
+}
+var fabs = []float64{
+       4.9790119248836735e+00,
+       7.7388724745781045e+00,
+       2.7688005719200159e-01,
+       5.0106036182710749e+00,
+       9.6362937071984173e+00,
+       2.9263772392439646e+00,
+       5.2290834314593066e+00,
+       2.7279399104360102e+00,
+       1.8253080916808550e+00,
+       8.6859247685756013e+00,
+}
+var fdim = []float64{
+       4.9790119248836735e+00,
+       7.7388724745781045e+00,
+       0.0000000000000000e+00,
+       0.0000000000000000e+00,
+       9.6362937071984173e+00,
+       2.9263772392439646e+00,
+       5.2290834314593066e+00,
+       2.7279399104360102e+00,
+       1.8253080916808550e+00,
+       0.0000000000000000e+00,
+}
+var floor = []float64{
+       4.0000000000000000e+00,
+       7.0000000000000000e+00,
+       -1.0000000000000000e+00,
+       -6.0000000000000000e+00,
+       9.0000000000000000e+00,
+       2.0000000000000000e+00,
+       5.0000000000000000e+00,
+       2.0000000000000000e+00,
+       1.0000000000000000e+00,
+       -9.0000000000000000e+00,
+}
+var fmod = []float64{
+       4.197615023265299782906368e-02,
+       2.261127525421895434476482e+00,
+       3.231794108794261433104108e-02,
+       4.989396381728925078391512e+00,
+       3.637062928015826201999516e-01,
+       1.220868282268106064236690e+00,
+       4.770916568540693347699744e+00,
+       1.816180268691969246219742e+00,
+       8.734595415957246977711748e-01,
+       1.314075231424398637614104e+00,
+}
+
+type fi struct {
+       f float64
+       i int
+}
+
+var frexp = []fi{
+       {6.2237649061045918750e-01, 3},
+       {9.6735905932226306250e-01, 3},
+       {-5.5376011438400318000e-01, -1},
+       {-6.2632545228388436250e-01, 3},
+       {6.02268356699901081250e-01, 4},
+       {7.3159430981099115000e-01, 2},
+       {6.5363542893241332500e-01, 3},
+       {6.8198497760900255000e-01, 2},
+       {9.1265404584042750000e-01, 1},
+       {-5.4287029803597508250e-01, 4},
+}
+var gamma = []float64{
+       2.3254348370739963835386613898e+01,
+       2.991153837155317076427529816e+03,
+       -4.561154336726758060575129109e+00,
+       7.719403468842639065959210984e-01,
+       1.6111876618855418534325755566e+05,
+       1.8706575145216421164173224946e+00,
+       3.4082787447257502836734201635e+01,
+       1.579733951448952054898583387e+00,
+       9.3834586598354592860187267089e-01,
+       -2.093995902923148389186189429e-05,
+}
+var j0 = []float64{
+       -1.8444682230601672018219338e-01,
+       2.27353668906331975435892e-01,
+       9.809259936157051116270273e-01,
+       -1.741170131426226587841181e-01,
+       -2.1389448451144143352039069e-01,
+       -2.340905848928038763337414e-01,
+       -1.0029099691890912094586326e-01,
+       -1.5466726714884328135358907e-01,
+       3.252650187653420388714693e-01,
+       -8.72218484409407250005360235e-03,
+}
+var j1 = []float64{
+       -3.251526395295203422162967e-01,
+       1.893581711430515718062564e-01,
+       -1.3711761352467242914491514e-01,
+       3.287486536269617297529617e-01,
+       1.3133899188830978473849215e-01,
+       3.660243417832986825301766e-01,
+       -3.4436769271848174665420672e-01,
+       4.329481396640773768835036e-01,
+       5.8181350531954794639333955e-01,
+       -2.7030574577733036112996607e-01,
+}
+var j2 = []float64{
+       5.3837518920137802565192769e-02,
+       -1.7841678003393207281244667e-01,
+       9.521746934916464142495821e-03,
+       4.28958355470987397983072e-02,
+       2.4115371837854494725492872e-01,
+       4.842458532394520316844449e-01,
+       -3.142145220618633390125946e-02,
+       4.720849184745124761189957e-01,
+       3.122312022520957042957497e-01,
+       7.096213118930231185707277e-02,
+}
+var jM3 = []float64{
+       -3.684042080996403091021151e-01,
+       2.8157665936340887268092661e-01,
+       4.401005480841948348343589e-04,
+       3.629926999056814081597135e-01,
+       3.123672198825455192489266e-02,
+       -2.958805510589623607540455e-01,
+       -3.2033177696533233403289416e-01,
+       -2.592737332129663376736604e-01,
+       -1.0241334641061485092351251e-01,
+       -2.3762660886100206491674503e-01,
+}
+var lgamma = []fi{
+       {3.146492141244545774319734e+00, 1},
+       {8.003414490659126375852113e+00, 1},
+       {1.517575735509779707488106e+00, -1},
+       {-2.588480028182145853558748e-01, 1},
+       {1.1989897050205555002007985e+01, 1},
+       {6.262899811091257519386906e-01, 1},
+       {3.5287924899091566764846037e+00, 1},
+       {4.5725644770161182299423372e-01, 1},
+       {-6.363667087767961257654854e-02, 1},
+       {-1.077385130910300066425564e+01, -1},
+}
+var log = []float64{
+       1.605231462693062999102599e+00,
+       2.0462560018708770653153909e+00,
+       -1.2841708730962657801275038e+00,
+       1.6115563905281545116286206e+00,
+       2.2655365644872016636317461e+00,
+       1.0737652208918379856272735e+00,
+       1.6542360106073546632707956e+00,
+       1.0035467127723465801264487e+00,
+       6.0174879014578057187016475e-01,
+       2.161703872847352815363655e+00,
+}
+var logb = []float64{
+       2.0000000000000000e+00,
+       2.0000000000000000e+00,
+       -2.0000000000000000e+00,
+       2.0000000000000000e+00,
+       3.0000000000000000e+00,
+       1.0000000000000000e+00,
+       2.0000000000000000e+00,
+       1.0000000000000000e+00,
+       0.0000000000000000e+00,
+       3.0000000000000000e+00,
+}
+var log10 = []float64{
+       6.9714316642508290997617083e-01,
+       8.886776901739320576279124e-01,
+       -5.5770832400658929815908236e-01,
+       6.998900476822994346229723e-01,
+       9.8391002850684232013281033e-01,
+       4.6633031029295153334285302e-01,
+       7.1842557117242328821552533e-01,
+       4.3583479968917773161304553e-01,
+       2.6133617905227038228626834e-01,
+       9.3881606348649405716214241e-01,
+}
+var log1p = []float64{
+       4.8590257759797794104158205e-02,
+       7.4540265965225865330849141e-02,
+       -2.7726407903942672823234024e-03,
+       -5.1404917651627649094953380e-02,
+       9.1998280672258624681335010e-02,
+       2.8843762576593352865894824e-02,
+       5.0969534581863707268992645e-02,
+       2.6913947602193238458458594e-02,
+       1.8088493239630770262045333e-02,
+       -9.0865245631588989681559268e-02,
+}
+var log2 = []float64{
+       2.3158594707062190618898251e+00,
+       2.9521233862883917703341018e+00,
+       -1.8526669502700329984917062e+00,
+       2.3249844127278861543568029e+00,
+       3.268478366538305087466309e+00,
+       1.5491157592596970278166492e+00,
+       2.3865580889631732407886495e+00,
+       1.447811865817085365540347e+00,
+       8.6813999540425116282815557e-01,
+       3.118679457227342224364709e+00,
+}
+var modf = [][2]float64{
+       {4.0000000000000000e+00, 9.7901192488367350108546816e-01},
+       {7.0000000000000000e+00, 7.3887247457810456552351752e-01},
+       {0.0000000000000000e+00, -2.7688005719200159404635997e-01},
+       {-5.0000000000000000e+00, -1.060361827107492160848778e-02},
+       {9.0000000000000000e+00, 6.3629370719841737980004837e-01},
+       {2.0000000000000000e+00, 9.2637723924396464525443662e-01},
+       {5.0000000000000000e+00, 2.2908343145930665230025625e-01},
+       {2.0000000000000000e+00, 7.2793991043601025126008608e-01},
+       {1.0000000000000000e+00, 8.2530809168085506044576505e-01},
+       {-8.0000000000000000e+00, -6.8592476857560136238589621e-01},
+}
+var nextafter = []float64{
+       4.97901192488367438926388786e+00,
+       7.73887247457810545370193722e+00,
+       -2.7688005719200153853520874e-01,
+       -5.01060361827107403343006808e+00,
+       9.63629370719841915615688777e+00,
+       2.92637723924396508934364647e+00,
+       5.22908343145930754047867595e+00,
+       2.72793991043601069534929593e+00,
+       1.82530809168085528249036997e+00,
+       -8.68592476857559958602905681e+00,
+}
+var pow = []float64{
+       9.5282232631648411840742957e+04,
+       5.4811599352999901232411871e+07,
+       5.2859121715894396531132279e-01,
+       9.7587991957286474464259698e-06,
+       4.328064329346044846740467e+09,
+       8.4406761805034547437659092e+02,
+       1.6946633276191194947742146e+05,
+       5.3449040147551939075312879e+02,
+       6.688182138451414936380374e+01,
+       2.0609869004248742886827439e-09,
+}
+var remainder = []float64{
+       4.197615023265299782906368e-02,
+       2.261127525421895434476482e+00,
+       3.231794108794261433104108e-02,
+       -2.120723654214984321697556e-02,
+       3.637062928015826201999516e-01,
+       1.220868282268106064236690e+00,
+       -4.581668629186133046005125e-01,
+       -9.117596417440410050403443e-01,
+       8.734595415957246977711748e-01,
+       1.314075231424398637614104e+00,
+}
+var signbit = []bool{
+       false,
+       false,
+       true,
+       true,
+       false,
+       false,
+       false,
+       false,
+       false,
+       true,
+}
+var sin = []float64{
+       -9.6466616586009283766724726e-01,
+       9.9338225271646545763467022e-01,
+       -2.7335587039794393342449301e-01,
+       9.5586257685042792878173752e-01,
+       -2.099421066779969164496634e-01,
+       2.135578780799860532750616e-01,
+       -8.694568971167362743327708e-01,
+       4.019566681155577786649878e-01,
+       9.6778633541687993721617774e-01,
+       -6.734405869050344734943028e-01,
+}
+var sinh = []float64{
+       7.2661916084208532301448439e+01,
+       1.1479409110035194500526446e+03,
+       -2.8043136512812518927312641e-01,
+       -7.499429091181587232835164e+01,
+       7.6552466042906758523925934e+03,
+       9.3031583421672014313789064e+00,
+       9.330815755828109072810322e+01,
+       7.6179893137269146407361477e+00,
+       3.021769180549615819524392e+00,
+       -2.95950575724449499189888e+03,
+}
+var sqrt = []float64{
+       2.2313699659365484748756904e+00,
+       2.7818829009464263511285458e+00,
+       5.2619393496314796848143251e-01,
+       2.2384377628763938724244104e+00,
+       3.1042380236055381099288487e+00,
+       1.7106657298385224403917771e+00,
+       2.286718922705479046148059e+00,
+       1.6516476350711159636222979e+00,
+       1.3510396336454586262419247e+00,
+       2.9471892997524949215723329e+00,
+}
+var tan = []float64{
+       -3.661316565040227801781974e+00,
+       8.64900232648597589369854e+00,
+       -2.8417941955033612725238097e-01,
+       3.253290185974728640827156e+00,
+       2.147275640380293804770778e-01,
+       -2.18600910711067004921551e-01,
+       -1.760002817872367935518928e+00,
+       -4.389808914752818126249079e-01,
+       -3.843885560201130679995041e+00,
+       9.10988793377685105753416e-01,
+}
+var tanh = []float64{
+       9.9990531206936338549262119e-01,
+       9.9999962057085294197613294e-01,
+       -2.7001505097318677233756845e-01,
+       -9.9991110943061718603541401e-01,
+       9.9999999146798465745022007e-01,
+       9.9427249436125236705001048e-01,
+       9.9994257600983138572705076e-01,
+       9.9149409509772875982054701e-01,
+       9.4936501296239685514466577e-01,
+       -9.9999994291374030946055701e-01,
+}
+var trunc = []float64{
+       4.0000000000000000e+00,
+       7.0000000000000000e+00,
+       -0.0000000000000000e+00,
+       -5.0000000000000000e+00,
+       9.0000000000000000e+00,
+       2.0000000000000000e+00,
+       5.0000000000000000e+00,
+       2.0000000000000000e+00,
+       1.0000000000000000e+00,
+       -8.0000000000000000e+00,
+}
+var y0 = []float64{
+       -3.053399153780788357534855e-01,
+       1.7437227649515231515503649e-01,
+       -8.6221781263678836910392572e-01,
+       -3.100664880987498407872839e-01,
+       1.422200649300982280645377e-01,
+       4.000004067997901144239363e-01,
+       -3.3340749753099352392332536e-01,
+       4.5399790746668954555205502e-01,
+       4.8290004112497761007536522e-01,
+       2.7036697826604756229601611e-01,
+}
+var y1 = []float64{
+       0.15494213737457922210218611,
+       -0.2165955142081145245075746,
+       -2.4644949631241895201032829,
+       0.1442740489541836405154505,
+       0.2215379960518984777080163,
+       0.3038800915160754150565448,
+       0.0691107642452362383808547,
+       0.2380116417809914424860165,
+       -0.20849492979459761009678934,
+       0.0242503179793232308250804,
+}
+var y2 = []float64{
+       0.3675780219390303613394936,
+       -0.23034826393250119879267257,
+       -16.939677983817727205631397,
+       0.367653980523052152867791,
+       -0.0962401471767804440353136,
+       -0.1923169356184851105200523,
+       0.35984072054267882391843766,
+       -0.2794987252299739821654982,
+       -0.7113490692587462579757954,
+       -0.2647831587821263302087457,
+}
+var yM3 = []float64{
+       -0.14035984421094849100895341,
+       -0.097535139617792072703973,
+       242.25775994555580176377379,
+       -0.1492267014802818619511046,
+       0.26148702629155918694500469,
+       0.56675383593895176530394248,
+       -0.206150264009006981070575,
+       0.64784284687568332737963658,
+       1.3503631555901938037008443,
+       0.1461869756579956803341844,
+}
+
+// arguments and expected results for special cases
+var vfacosSC = []float64{
+       -Pi,
+       1,
+       Pi,
+       NaN(),
+}
+var acosSC = []float64{
+       NaN(),
+       0,
+       NaN(),
+       NaN(),
+}
+
+var vfacoshSC = []float64{
+       Inf(-1),
+       0.5,
+       1,
+       Inf(1),
+       NaN(),
+}
+var acoshSC = []float64{
+       NaN(),
+       NaN(),
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vfasinSC = []float64{
+       -Pi,
+       Copysign(0, -1),
+       0,
+       Pi,
+       NaN(),
+}
+var asinSC = []float64{
+       NaN(),
+       Copysign(0, -1),
+       0,
+       NaN(),
+       NaN(),
+}
+
+var vfasinhSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var asinhSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vfatanSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var atanSC = []float64{
+       -Pi / 2,
+       Copysign(0, -1),
+       0,
+       Pi / 2,
+       NaN(),
+}
+
+var vfatanhSC = []float64{
+       Inf(-1),
+       -Pi,
+       -1,
+       Copysign(0, -1),
+       0,
+       1,
+       Pi,
+       Inf(1),
+       NaN(),
+}
+var atanhSC = []float64{
+       NaN(),
+       NaN(),
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+       NaN(),
+       NaN(),
+}
+var vfatan2SC = [][2]float64{
+       {Inf(-1), Inf(-1)},
+       {Inf(-1), -Pi},
+       {Inf(-1), 0},
+       {Inf(-1), +Pi},
+       {Inf(-1), Inf(1)},
+       {Inf(-1), NaN()},
+       {-Pi, Inf(-1)},
+       {-Pi, 0},
+       {-Pi, Inf(1)},
+       {-Pi, NaN()},
+       {Copysign(0, -1), Inf(-1)},
+       {Copysign(0, -1), -Pi},
+       {Copysign(0, -1), Copysign(0, -1)},
+       {Copysign(0, -1), 0},
+       {Copysign(0, -1), +Pi},
+       {Copysign(0, -1), Inf(1)},
+       {Copysign(0, -1), NaN()},
+       {0, Inf(-1)},
+       {0, -Pi},
+       {0, Copysign(0, -1)},
+       {0, 0},
+       {0, +Pi},
+       {0, Inf(1)},
+       {0, NaN()},
+       {+Pi, Inf(-1)},
+       {+Pi, 0},
+       {+Pi, Inf(1)},
+       {+Pi, NaN()},
+       {Inf(1), Inf(-1)},
+       {Inf(1), -Pi},
+       {Inf(1), 0},
+       {Inf(1), +Pi},
+       {Inf(1), Inf(1)},
+       {Inf(1), NaN()},
+       {NaN(), NaN()},
+}
+var atan2SC = []float64{
+       -3 * Pi / 4,     // atan2(-Inf, -Inf)
+       -Pi / 2,         // atan2(-Inf, -Pi)
+       -Pi / 2,         // atan2(-Inf, +0)
+       -Pi / 2,         // atan2(-Inf, +Pi)
+       -Pi / 4,         // atan2(-Inf, +Inf)
+       NaN(),           // atan2(-Inf, NaN)
+       -Pi,             // atan2(-Pi, -Inf)
+       -Pi / 2,         // atan2(-Pi, +0)
+       Copysign(0, -1), // atan2(-Pi, Inf)
+       NaN(),           // atan2(-Pi, NaN)
+       -Pi,             // atan2(-0, -Inf)
+       -Pi,             // atan2(-0, -Pi)
+       -Pi,             // atan2(-0, -0)
+       Copysign(0, -1), // atan2(-0, +0)
+       Copysign(0, -1), // atan2(-0, +Pi)
+       Copysign(0, -1), // atan2(-0, +Inf)
+       NaN(),           // atan2(-0, NaN)
+       Pi,              // atan2(+0, -Inf)
+       Pi,              // atan2(+0, -Pi)
+       Pi,              // atan2(+0, -0)
+       0,               // atan2(+0, +0)
+       0,               // atan2(+0, +Pi)
+       0,               // atan2(+0, +Inf)
+       NaN(),           // atan2(+0, NaN)
+       Pi,              // atan2(+Pi, -Inf)
+       Pi / 2,          // atan2(+Pi, +0)
+       0,               // atan2(+Pi, +Inf)
+       NaN(),           // atan2(+Pi, NaN)
+       3 * Pi / 4,      // atan2(+Inf, -Inf)
+       Pi / 2,          // atan2(+Inf, -Pi)
+       Pi / 2,          // atan2(+Inf, +0)
+       Pi / 2,          // atan2(+Inf, +Pi)
+       Pi / 4,          // atan2(+Inf, +Inf)
+       NaN(),           // atan2(+Inf, NaN)
+       NaN(),           // atan2(NaN, NaN)
+}
+
+var vfcbrtSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var cbrtSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vfceilSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var ceilSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vfcopysignSC = []float64{
+       Inf(-1),
+       Inf(1),
+       NaN(),
+}
+var copysignSC = []float64{
+       Inf(-1),
+       Inf(-1),
+       NaN(),
+}
+
+var vfcosSC = []float64{
+       Inf(-1),
+       Inf(1),
+       NaN(),
+}
+var cosSC = []float64{
+       NaN(),
+       NaN(),
+       NaN(),
+}
+
+var vfcoshSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var coshSC = []float64{
+       Inf(1),
+       1,
+       1,
+       Inf(1),
+       NaN(),
+}
+
+var vferfSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var erfSC = []float64{
+       -1,
+       Copysign(0, -1),
+       0,
+       1,
+       NaN(),
+}
+
+var vferfcSC = []float64{
+       Inf(-1),
+       Inf(1),
+       NaN(),
+}
+var erfcSC = []float64{
+       2,
+       0,
+       NaN(),
+}
+
+var vfexpSC = []float64{
+       Inf(-1),
+       -2000,
+       2000,
+       Inf(1),
+       NaN(),
+}
+var expSC = []float64{
+       0,
+       0,
+       Inf(1),
+       Inf(1),
+       NaN(),
+}
+
+var vfexpm1SC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var expm1SC = []float64{
+       -1,
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vffabsSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var fabsSC = []float64{
+       Inf(1),
+       0,
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vffmodSC = [][2]float64{
+       {Inf(-1), Inf(-1)},
+       {Inf(-1), -Pi},
+       {Inf(-1), 0},
+       {Inf(-1), Pi},
+       {Inf(-1), Inf(1)},
+       {Inf(-1), NaN()},
+       {-Pi, Inf(-1)},
+       {-Pi, 0},
+       {-Pi, Inf(1)},
+       {-Pi, NaN()},
+       {Copysign(0, -1), Inf(-1)},
+       {Copysign(0, -1), 0},
+       {Copysign(0, -1), Inf(1)},
+       {Copysign(0, -1), NaN()},
+       {0, Inf(-1)},
+       {0, 0},
+       {0, Inf(1)},
+       {0, NaN()},
+       {Pi, Inf(-1)},
+       {Pi, 0},
+       {Pi, Inf(1)},
+       {Pi, NaN()},
+       {Inf(1), Inf(-1)},
+       {Inf(1), -Pi},
+       {Inf(1), 0},
+       {Inf(1), Pi},
+       {Inf(1), Inf(1)},
+       {Inf(1), NaN()},
+       {NaN(), Inf(-1)},
+       {NaN(), -Pi},
+       {NaN(), 0},
+       {NaN(), Pi},
+       {NaN(), Inf(1)},
+       {NaN(), NaN()},
+}
+var fmodSC = []float64{
+       NaN(),           // fmod(-Inf, -Inf)
+       NaN(),           // fmod(-Inf, -Pi)
+       NaN(),           // fmod(-Inf, 0)
+       NaN(),           // fmod(-Inf, Pi)
+       NaN(),           // fmod(-Inf, +Inf)
+       NaN(),           // fmod(-Inf, NaN)
+       -Pi,             // fmod(-Pi, -Inf)
+       NaN(),           // fmod(-Pi, 0)
+       -Pi,             // fmod(-Pi, +Inf)
+       NaN(),           // fmod(-Pi, NaN)
+       Copysign(0, -1), // fmod(-0, -Inf)
+       NaN(),           // fmod(-0, 0)
+       Copysign(0, -1), // fmod(-0, Inf)
+       NaN(),           // fmod(-0, NaN)
+       0,               // fmod(0, -Inf)
+       NaN(),           // fmod(0, 0)
+       0,               // fmod(0, +Inf)
+       NaN(),           // fmod(0, NaN)
+       Pi,              // fmod(Pi, -Inf)
+       NaN(),           // fmod(Pi, 0)
+       Pi,              // fmod(Pi, +Inf)
+       NaN(),           // fmod(Pi, NaN)
+       NaN(),           // fmod(+Inf, -Inf)
+       NaN(),           // fmod(+Inf, -Pi)
+       NaN(),           // fmod(+Inf, 0)
+       NaN(),           // fmod(+Inf, Pi)
+       NaN(),           // fmod(+Inf, +Inf)
+       NaN(),           // fmod(+Inf, NaN)
+       NaN(),           // fmod(NaN, -Inf)
+       NaN(),           // fmod(NaN, -Pi)
+       NaN(),           // fmod(NaN, 0)
+       NaN(),           // fmod(NaN, Pi)
+       NaN(),           // fmod(NaN, +Inf)
+       NaN(),           // fmod(NaN, NaN)
+}
+
+var vffrexpSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var frexpSC = []fi{
+       {Inf(-1), 0},
+       {Copysign(0, -1), 0},
+       {0, 0},
+       {Inf(1), 0},
+       {NaN(), 0},
+}
+
+var vfgammaSC = []float64{
+       Inf(-1),
+       -3,
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var gammaSC = []float64{
+       Inf(-1),
+       Inf(1),
+       Inf(1),
+       Inf(1),
+       Inf(1),
+       NaN(),
+}
+
+var vfhypotSC = [][2]float64{
+       {Inf(-1), Inf(-1)},
+       {Inf(-1), 0},
+       {Inf(-1), Inf(1)},
+       {Inf(-1), NaN()},
+       {Copysign(0, -1), Copysign(0, -1)},
+       {Copysign(0, -1), 0},
+       {0, Copysign(0, -1)},
+       {0, 0}, // +0, +0
+       {0, Inf(-1)},
+       {0, Inf(1)},
+       {0, NaN()},
+       {Inf(1), Inf(-1)},
+       {Inf(1), 0},
+       {Inf(1), Inf(1)},
+       {Inf(1), NaN()},
+       {NaN(), Inf(-1)},
+       {NaN(), 0},
+       {NaN(), Inf(1)},
+       {NaN(), NaN()},
+}
+var hypotSC = []float64{
+       Inf(1),
+       Inf(1),
+       Inf(1),
+       Inf(1),
+       0,
+       0,
+       0,
+       0,
+       Inf(1),
+       Inf(1),
+       NaN(),
+       Inf(1),
+       Inf(1),
+       Inf(1),
+       Inf(1),
+       Inf(1),
+       NaN(),
+       Inf(1),
+       NaN(),
+}
+
+var vfilogbSC = []float64{
+       Inf(-1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var ilogbSC = []int{
+       MaxInt32,
+       MinInt32,
+       MaxInt32,
+       MaxInt32,
+}
+
+var vfj0SC = []float64{
+       Inf(-1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var j0SC = []float64{
+       0,
+       1,
+       0,
+       NaN(),
+}
+var j1SC = []float64{
+       0,
+       0,
+       0,
+       NaN(),
+}
+var j2SC = []float64{
+       0,
+       0,
+       0,
+       NaN(),
+}
+var jM3SC = []float64{
+       0,
+       0,
+       0,
+       NaN(),
+}
+
+var vflgammaSC = []float64{
+       Inf(-1),
+       -3,
+       0,
+       1,
+       2,
+       Inf(1),
+       NaN(),
+}
+var lgammaSC = []fi{
+       {Inf(-1), 1},
+       {Inf(1), 1},
+       {Inf(1), 1},
+       {0, 1},
+       {0, 1},
+       {Inf(1), 1},
+       {NaN(), 1},
+}
+
+var vflogSC = []float64{
+       Inf(-1),
+       -Pi,
+       Copysign(0, -1),
+       0,
+       1,
+       Inf(1),
+       NaN(),
+}
+var logSC = []float64{
+       NaN(),
+       NaN(),
+       Inf(-1),
+       Inf(-1),
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vflogbSC = []float64{
+       Inf(-1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var logbSC = []float64{
+       Inf(1),
+       Inf(-1),
+       Inf(1),
+       NaN(),
+}
+
+var vflog1pSC = []float64{
+       Inf(-1),
+       -Pi,
+       -1,
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var log1pSC = []float64{
+       NaN(),
+       NaN(),
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vfmodfSC = []float64{
+       Inf(-1),
+       Inf(1),
+       NaN(),
+}
+var modfSC = [][2]float64{
+       {Inf(-1), NaN()}, // [2]float64{Copysign(0, -1), Inf(-1)},
+       {Inf(1), NaN()},  // [2]float64{0, Inf(1)},
+       {NaN(), NaN()},
+}
+
+var vfnextafterSC = [][2]float64{
+       {0, NaN()},
+       {NaN(), 0},
+       {NaN(), NaN()},
+}
+var nextafterSC = []float64{
+       NaN(),
+       NaN(),
+       NaN(),
+}
+
+var vfpowSC = [][2]float64{
+       {Inf(-1), -Pi},
+       {Inf(-1), -3},
+       {Inf(-1), Copysign(0, -1)},
+       {Inf(-1), 0},
+       {Inf(-1), 1},
+       {Inf(-1), 3},
+       {Inf(-1), Pi},
+       {Inf(-1), NaN()},
+
+       {-Pi, Inf(-1)},
+       {-Pi, -Pi},
+       {-Pi, Copysign(0, -1)},
+       {-Pi, 0},
+       {-Pi, 1},
+       {-Pi, Pi},
+       {-Pi, Inf(1)},
+       {-Pi, NaN()},
+
+       {-1, Inf(-1)},
+       {-1, Inf(1)},
+       {-1, NaN()},
+       {-1 / 2, Inf(-1)},
+       {-1 / 2, Inf(1)},
+       {Copysign(0, -1), Inf(-1)},
+       {Copysign(0, -1), -Pi},
+       {Copysign(0, -1), -3},
+       {Copysign(0, -1), 3},
+       {Copysign(0, -1), Pi},
+       {Copysign(0, -1), Inf(1)},
+
+       {0, Inf(-1)},
+       {0, -Pi},
+       {0, -3},
+       {0, Copysign(0, -1)},
+       {0, 0},
+       {0, 3},
+       {0, Pi},
+       {0, Inf(1)},
+       {0, NaN()},
+
+       {1 / 2, Inf(-1)},
+       {1 / 2, Inf(1)},
+       {1, Inf(-1)},
+       {1, Inf(1)},
+       {1, NaN()},
+
+       {Pi, Inf(-1)},
+       {Pi, Copysign(0, -1)},
+       {Pi, 0},
+       {Pi, 1},
+       {Pi, Inf(1)},
+       {Pi, NaN()},
+       {Inf(1), -Pi},
+       {Inf(1), Copysign(0, -1)},
+       {Inf(1), 0},
+       {Inf(1), 1},
+       {Inf(1), Pi},
+       {Inf(1), NaN()},
+       {NaN(), -Pi},
+       {NaN(), Copysign(0, -1)},
+       {NaN(), 0},
+       {NaN(), 1},
+       {NaN(), Pi},
+       {NaN(), NaN()},
+}
+var powSC = []float64{
+       0,               // pow(-Inf, -Pi)
+       Copysign(0, -1), // pow(-Inf, -3)
+       1,               // pow(-Inf, -0)
+       1,               // pow(-Inf, +0)
+       Inf(-1),         // pow(-Inf, 1)
+       Inf(-1),         // pow(-Inf, 3)
+       Inf(1),          // pow(-Inf, Pi)
+       NaN(),           // pow(-Inf, NaN)
+       0,               // pow(-Pi, -Inf)
+       NaN(),           // pow(-Pi, -Pi)
+       1,               // pow(-Pi, -0)
+       1,               // pow(-Pi, +0)
+       -Pi,             // pow(-Pi, 1)
+       NaN(),           // pow(-Pi, Pi)
+       Inf(1),          // pow(-Pi, +Inf)
+       NaN(),           // pow(-Pi, NaN)
+       1,               // pow(-1, -Inf) IEEE 754-2008
+       1,               // pow(-1, +Inf) IEEE 754-2008
+       NaN(),           // pow(-1, NaN)
+       Inf(1),          // pow(-1/2, -Inf)
+       0,               // pow(-1/2, +Inf)
+       Inf(1),          // pow(-0, -Inf)
+       Inf(1),          // pow(-0, -Pi)
+       Inf(-1),         // pow(-0, -3) IEEE 754-2008
+       Copysign(0, -1), // pow(-0, 3) IEEE 754-2008
+       0,               // pow(-0, +Pi)
+       0,               // pow(-0, +Inf)
+       Inf(1),          // pow(+0, -Inf)
+       Inf(1),          // pow(+0, -Pi)
+       Inf(1),          // pow(+0, -3)
+       1,               // pow(+0, -0)
+       1,               // pow(+0, +0)
+       0,               // pow(+0, 3)
+       0,               // pow(+0, +Pi)
+       0,               // pow(+0, +Inf)
+       NaN(),           // pow(+0, NaN)
+       Inf(1),          // pow(1/2, -Inf)
+       0,               // pow(1/2, +Inf)
+       1,               // pow(1, -Inf) IEEE 754-2008
+       1,               // pow(1, +Inf) IEEE 754-2008
+       1,               // pow(1, NaN) IEEE 754-2008
+       0,               // pow(+Pi, -Inf)
+       1,               // pow(+Pi, -0)
+       1,               // pow(+Pi, +0)
+       Pi,              // pow(+Pi, 1)
+       Inf(1),          // pow(+Pi, +Inf)
+       NaN(),           // pow(+Pi, NaN)
+       0,               // pow(+Inf, -Pi)
+       1,               // pow(+Inf, -0)
+       1,               // pow(+Inf, +0)
+       Inf(1),          // pow(+Inf, 1)
+       Inf(1),          // pow(+Inf, Pi)
+       NaN(),           // pow(+Inf, NaN)
+       NaN(),           // pow(NaN, -Pi)
+       1,               // pow(NaN, -0)
+       1,               // pow(NaN, +0)
+       NaN(),           // pow(NaN, 1)
+       NaN(),           // pow(NaN, +Pi)
+       NaN(),           // pow(NaN, NaN)
+}
+
+var vfsignbitSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var signbitSC = []bool{
+       true,
+       true,
+       false,
+       false,
+       false,
+}
+
+var vfsinSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var sinSC = []float64{
+       NaN(),
+       Copysign(0, -1),
+       0,
+       NaN(),
+       NaN(),
+}
+
+var vfsinhSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var sinhSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vfsqrtSC = []float64{
+       Inf(-1),
+       -Pi,
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var sqrtSC = []float64{
+       NaN(),
+       NaN(),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+
+var vftanhSC = []float64{
+       Inf(-1),
+       Copysign(0, -1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var tanhSC = []float64{
+       -1,
+       Copysign(0, -1),
+       0,
+       1,
+       NaN(),
+}
+
+var vfy0SC = []float64{
+       Inf(-1),
+       0,
+       Inf(1),
+       NaN(),
+}
+var y0SC = []float64{
+       NaN(),
+       Inf(-1),
+       0,
+       NaN(),
+}
+var y1SC = []float64{
+       NaN(),
+       Inf(-1),
+       0,
+       NaN(),
+}
+var y2SC = []float64{
+       NaN(),
+       Inf(-1),
+       0,
+       NaN(),
+}
+var yM3SC = []float64{
+       NaN(),
+       Inf(1),
+       0,
+       NaN(),
+}
+
+func tolerance(a, b, e float64) bool {
+       d := a - b
+       if d < 0 {
+               d = -d
+       }
+
+       if a != 0 {
+               e = e * a
+               if e < 0 {
+                       e = -e
+               }
+       }
+       return d < e
+}
+func kindaclose(a, b float64) bool { return tolerance(a, b, 1e-8) }
+func close(a, b float64) bool      { return tolerance(a, b, 1e-14) }
+func veryclose(a, b float64) bool  { return tolerance(a, b, 4e-16) }
+func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
+func alike(a, b float64) bool {
+       switch {
+       case IsNaN(a) && IsNaN(b):
+               return true
+       case a == b:
+               return Signbit(a) == Signbit(b)
+       }
+       return false
+}
+
+func TestAcos(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := vf[i] / 10
+               if f := Acos(a); !close(acos[i], f) {
+                       t.Errorf("Acos(%g) = %g, want %g", a, f, acos[i])
+               }
+       }
+       for i := 0; i < len(vfacosSC); i++ {
+               if f := Acos(vfacosSC[i]); !alike(acosSC[i], f) {
+                       t.Errorf("Acos(%g) = %g, want %g", vfacosSC[i], f, acosSC[i])
+               }
+       }
+}
+
+func TestAcosh(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := 1 + Fabs(vf[i])
+               if f := Acosh(a); !veryclose(acosh[i], f) {
+                       t.Errorf("Acosh(%g) = %g, want %g", a, f, acosh[i])
+               }
+       }
+       for i := 0; i < len(vfacoshSC); i++ {
+               if f := Acosh(vfacoshSC[i]); !alike(acoshSC[i], f) {
+                       t.Errorf("Acosh(%g) = %g, want %g", vfacoshSC[i], f, acoshSC[i])
+               }
+       }
+}
+
+func TestAsin(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := vf[i] / 10
+               if f := Asin(a); !veryclose(asin[i], f) {
+                       t.Errorf("Asin(%g) = %g, want %g", a, f, asin[i])
+               }
+       }
+       for i := 0; i < len(vfasinSC); i++ {
+               if f := Asin(vfasinSC[i]); !alike(asinSC[i], f) {
+                       t.Errorf("Asin(%g) = %g, want %g", vfasinSC[i], f, asinSC[i])
+               }
+       }
+}
+
+func TestAsinh(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Asinh(vf[i]); !veryclose(asinh[i], f) {
+                       t.Errorf("Asinh(%g) = %g, want %g", vf[i], f, asinh[i])
+               }
+       }
+       for i := 0; i < len(vfasinhSC); i++ {
+               if f := Asinh(vfasinhSC[i]); !alike(asinhSC[i], f) {
+                       t.Errorf("Asinh(%g) = %g, want %g", vfasinhSC[i], f, asinhSC[i])
+               }
+       }
+}
+
+func TestAtan(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Atan(vf[i]); !veryclose(atan[i], f) {
+                       t.Errorf("Atan(%g) = %g, want %g", vf[i], f, atan[i])
+               }
+       }
+       for i := 0; i < len(vfatanSC); i++ {
+               if f := Atan(vfatanSC[i]); !alike(atanSC[i], f) {
+                       t.Errorf("Atan(%g) = %g, want %g", vfatanSC[i], f, atanSC[i])
+               }
+       }
+}
+
+func TestAtanh(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := vf[i] / 10
+               if f := Atanh(a); !veryclose(atanh[i], f) {
+                       t.Errorf("Atanh(%g) = %g, want %g", a, f, atanh[i])
+               }
+       }
+       for i := 0; i < len(vfatanhSC); i++ {
+               if f := Atanh(vfatanhSC[i]); !alike(atanhSC[i], f) {
+                       t.Errorf("Atanh(%g) = %g, want %g", vfatanhSC[i], f, atanhSC[i])
+               }
+       }
+}
+
+func TestAtan2(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Atan2(10, vf[i]); !veryclose(atan2[i], f) {
+                       t.Errorf("Atan2(10, %g) = %g, want %g", vf[i], f, atan2[i])
+               }
+       }
+       for i := 0; i < len(vfatan2SC); i++ {
+               if f := Atan2(vfatan2SC[i][0], vfatan2SC[i][1]); !alike(atan2SC[i], f) {
+                       t.Errorf("Atan2(%g, %g) = %g, want %g", vfatan2SC[i][0], vfatan2SC[i][1], f, atan2SC[i])
+               }
+       }
+}
+
+func TestCbrt(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Cbrt(vf[i]); !veryclose(cbrt[i], f) {
+                       t.Errorf("Cbrt(%g) = %g, want %g", vf[i], f, cbrt[i])
+               }
+       }
+       for i := 0; i < len(vfcbrtSC); i++ {
+               if f := Cbrt(vfcbrtSC[i]); !alike(cbrtSC[i], f) {
+                       t.Errorf("Cbrt(%g) = %g, want %g", vfcbrtSC[i], f, cbrtSC[i])
+               }
+       }
+}
+
+func TestCeil(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Ceil(vf[i]); ceil[i] != f {
+                       t.Errorf("Ceil(%g) = %g, want %g", vf[i], f, ceil[i])
+               }
+       }
+       for i := 0; i < len(vfceilSC); i++ {
+               if f := Ceil(vfceilSC[i]); !alike(ceilSC[i], f) {
+                       t.Errorf("Ceil(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
+               }
+       }
+}
+
+func TestCopysign(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Copysign(vf[i], -1); copysign[i] != f {
+                       t.Errorf("Copysign(%g, -1) = %g, want %g", vf[i], f, copysign[i])
+               }
+       }
+       for i := 0; i < len(vf); i++ {
+               if f := Copysign(vf[i], 1); -copysign[i] != f {
+                       t.Errorf("Copysign(%g, 1) = %g, want %g", vf[i], f, -copysign[i])
+               }
+       }
+       for i := 0; i < len(vfcopysignSC); i++ {
+               if f := Copysign(vfcopysignSC[i], -1); !alike(copysignSC[i], f) {
+                       t.Errorf("Copysign(%g, -1) = %g, want %g", vfcopysignSC[i], f, copysignSC[i])
+               }
+       }
+}
+
+func TestCos(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Cos(vf[i]); !close(cos[i], f) {
+                       t.Errorf("Cos(%g) = %g, want %g", vf[i], f, cos[i])
+               }
+       }
+       for i := 0; i < len(vfcosSC); i++ {
+               if f := Cos(vfcosSC[i]); !alike(cosSC[i], f) {
+                       t.Errorf("Cos(%g) = %g, want %g", vfcosSC[i], f, cosSC[i])
+               }
+       }
+}
+
+func TestCosh(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Cosh(vf[i]); !close(cosh[i], f) {
+                       t.Errorf("Cosh(%g) = %g, want %g", vf[i], f, cosh[i])
+               }
+       }
+       for i := 0; i < len(vfcoshSC); i++ {
+               if f := Cosh(vfcoshSC[i]); !alike(coshSC[i], f) {
+                       t.Errorf("Cosh(%g) = %g, want %g", vfcoshSC[i], f, coshSC[i])
+               }
+       }
+}
+
+func TestErf(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := vf[i] / 10
+               if f := Erf(a); !veryclose(erf[i], f) {
+                       t.Errorf("Erf(%g) = %g, want %g", a, f, erf[i])
+               }
+       }
+       for i := 0; i < len(vferfSC); i++ {
+               if f := Erf(vferfSC[i]); !alike(erfSC[i], f) {
+                       t.Errorf("Erf(%g) = %g, want %g", vferfSC[i], f, erfSC[i])
+               }
+       }
+}
+
+func TestErfc(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := vf[i] / 10
+               if f := Erfc(a); !veryclose(erfc[i], f) {
+                       t.Errorf("Erfc(%g) = %g, want %g", a, f, erfc[i])
+               }
+       }
+       for i := 0; i < len(vferfcSC); i++ {
+               if f := Erfc(vferfcSC[i]); !alike(erfcSC[i], f) {
+                       t.Errorf("Erfc(%g) = %g, want %g", vferfcSC[i], f, erfcSC[i])
+               }
+       }
+}
+
+func TestExp(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Exp(vf[i]); !close(exp[i], f) {
+                       t.Errorf("Exp(%g) = %g, want %g", vf[i], f, exp[i])
+               }
+       }
+       for i := 0; i < len(vfexpSC); i++ {
+               if f := Exp(vfexpSC[i]); !alike(expSC[i], f) {
+                       t.Errorf("Exp(%g) = %g, want %g", vfexpSC[i], f, expSC[i])
+               }
+       }
+}
+
+func TestExpm1(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := vf[i] / 100
+               if f := Expm1(a); !veryclose(expm1[i], f) {
+                       t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1[i])
+               }
+       }
+       for i := 0; i < len(vfexpm1SC); i++ {
+               if f := Expm1(vfexpm1SC[i]); !alike(expm1SC[i], f) {
+                       t.Errorf("Expm1(%g) = %g, want %g", vfexpm1SC[i], f, expm1SC[i])
+               }
+       }
+}
+
+func TestExp2(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Exp2(vf[i]); !close(exp2[i], f) {
+                       t.Errorf("Exp2(%g) = %g, want %g", vf[i], f, exp2[i])
+               }
+       }
+       for i := 0; i < len(vfexpSC); i++ {
+               if f := Exp2(vfexpSC[i]); !alike(expSC[i], f) {
+                       t.Errorf("Exp2(%g) = %g, want %g", vfexpSC[i], f, expSC[i])
+               }
+       }
+}
+
+func TestFabs(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Fabs(vf[i]); fabs[i] != f {
+                       t.Errorf("Fabs(%g) = %g, want %g", vf[i], f, fabs[i])
+               }
+       }
+       for i := 0; i < len(vffabsSC); i++ {
+               if f := Fabs(vffabsSC[i]); !alike(fabsSC[i], f) {
+                       t.Errorf("Fabs(%g) = %g, want %g", vffabsSC[i], f, fabsSC[i])
+               }
+       }
+}
+
+func TestFdim(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Fdim(vf[i], 0); fdim[i] != f {
+                       t.Errorf("Fdim(%g, %g) = %g, want %g", vf[i], 0.0, f, fdim[i])
+               }
+       }
+}
+
+func TestFloor(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Floor(vf[i]); floor[i] != f {
+                       t.Errorf("Floor(%g) = %g, want %g", vf[i], f, floor[i])
+               }
+       }
+       for i := 0; i < len(vfceilSC); i++ {
+               if f := Floor(vfceilSC[i]); !alike(ceilSC[i], f) {
+                       t.Errorf("Floor(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
+               }
+       }
+}
+
+func TestFmax(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Fmax(vf[i], ceil[i]); ceil[i] != f {
+                       t.Errorf("Fmax(%g, %g) = %g, want %g", vf[i], ceil[i], f, ceil[i])
+               }
+       }
+}
+
+func TestFmin(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Fmin(vf[i], floor[i]); floor[i] != f {
+                       t.Errorf("Fmin(%g, %g) = %g, want %g", vf[i], floor[i], f, floor[i])
+               }
+       }
+}
+
+func TestFmod(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Fmod(10, vf[i]); fmod[i] != f {
+                       t.Errorf("Fmod(10, %g) = %g, want %g", vf[i], f, fmod[i])
+               }
+       }
+       for i := 0; i < len(vffmodSC); i++ {
+               if f := Fmod(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
+                       t.Errorf("Fmod(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
+               }
+       }
+}
+
+func TestFrexp(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f, j := Frexp(vf[i]); !veryclose(frexp[i].f, f) || frexp[i].i != j {
+                       t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vf[i], f, j, frexp[i].f, frexp[i].i)
+               }
+       }
+       for i := 0; i < len(vffrexpSC); i++ {
+               if f, j := Frexp(vffrexpSC[i]); !alike(frexpSC[i].f, f) || frexpSC[i].i != j {
+                       t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpSC[i], f, j, frexpSC[i].f, frexpSC[i].i)
+               }
+       }
+}
+
+func TestGamma(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Gamma(vf[i]); !close(gamma[i], f) {
+                       t.Errorf("Gamma(%g) = %g, want %g", vf[i], f, gamma[i])
+               }
+       }
+       for i := 0; i < len(vfgammaSC); i++ {
+               if f := Gamma(vfgammaSC[i]); !alike(gammaSC[i], f) {
+                       t.Errorf("Gamma(%g) = %g, want %g", vfgammaSC[i], f, gammaSC[i])
+               }
+       }
+}
+
+func TestHypot(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := Fabs(1e200 * tanh[i] * Sqrt(2))
+               if f := Hypot(1e200*tanh[i], 1e200*tanh[i]); !veryclose(a, f) {
+                       t.Errorf("Hypot(%g, %g) = %g, want %g", 1e200*tanh[i], 1e200*tanh[i], f, a)
+               }
+       }
+       for i := 0; i < len(vfhypotSC); i++ {
+               if f := Hypot(vfhypotSC[i][0], vfhypotSC[i][1]); !alike(hypotSC[i], f) {
+                       t.Errorf("Hypot(%g, %g) = %g, want %g", vfhypotSC[i][0], vfhypotSC[i][1], f, hypotSC[i])
+               }
+       }
+}
+
+func TestIlogb(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := frexp[i].i - 1 // adjust because fr in the interval [½, 1)
+               if e := Ilogb(vf[i]); a != e {
+                       t.Errorf("Ilogb(%g) = %d, want %d", vf[i], e, a)
+               }
+       }
+       for i := 0; i < len(vflogbSC); i++ {
+               if e := Ilogb(vflogbSC[i]); ilogbSC[i] != e {
+                       t.Errorf("Ilogb(%g) = %d, want %d", vflogbSC[i], e, ilogbSC[i])
+               }
+       }
+}
+
+func TestJ0(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := J0(vf[i]); !soclose(j0[i], f, 4e-14) {
+                       t.Errorf("J0(%g) = %g, want %g", vf[i], f, j0[i])
+               }
+       }
+       for i := 0; i < len(vfj0SC); i++ {
+               if f := J0(vfj0SC[i]); !alike(j0SC[i], f) {
+                       t.Errorf("J0(%g) = %g, want %g", vfj0SC[i], f, j0SC[i])
+               }
+       }
+}
+
+func TestJ1(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := J1(vf[i]); !close(j1[i], f) {
+                       t.Errorf("J1(%g) = %g, want %g", vf[i], f, j1[i])
+               }
+       }
+       for i := 0; i < len(vfj0SC); i++ {
+               if f := J1(vfj0SC[i]); !alike(j1SC[i], f) {
+                       t.Errorf("J1(%g) = %g, want %g", vfj0SC[i], f, j1SC[i])
+               }
+       }
+}
+
+func TestJn(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Jn(2, vf[i]); !close(j2[i], f) {
+                       t.Errorf("Jn(2, %g) = %g, want %g", vf[i], f, j2[i])
+               }
+               if f := Jn(-3, vf[i]); !close(jM3[i], f) {
+                       t.Errorf("Jn(-3, %g) = %g, want %g", vf[i], f, jM3[i])
+               }
+       }
+       for i := 0; i < len(vfj0SC); i++ {
+               if f := Jn(2, vfj0SC[i]); !alike(j2SC[i], f) {
+                       t.Errorf("Jn(2, %g) = %g, want %g", vfj0SC[i], f, j2SC[i])
+               }
+               if f := Jn(-3, vfj0SC[i]); !alike(jM3SC[i], f) {
+                       t.Errorf("Jn(-3, %g) = %g, want %g", vfj0SC[i], f, jM3SC[i])
+               }
+       }
+}
+
+func TestLdexp(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Ldexp(frexp[i].f, frexp[i].i); !veryclose(vf[i], f) {
+                       t.Errorf("Ldexp(%g, %d) = %g, want %g", frexp[i].f, frexp[i].i, f, vf[i])
+               }
+       }
+       for i := 0; i < len(vffrexpSC); i++ {
+               if f := Ldexp(frexpSC[i].f, frexpSC[i].i); !alike(vffrexpSC[i], f) {
+                       t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpSC[i].f, frexpSC[i].i, f, vffrexpSC[i])
+               }
+       }
+}
+
+func TestLgamma(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f, s := Lgamma(vf[i]); !close(lgamma[i].f, f) || lgamma[i].i != s {
+                       t.Errorf("Lgamma(%g) = %g, %d, want %g, %d", vf[i], f, s, lgamma[i].f, lgamma[i].i)
+               }
+       }
+       for i := 0; i < len(vflgammaSC); i++ {
+               if f, s := Lgamma(vflgammaSC[i]); !alike(lgammaSC[i].f, f) || lgammaSC[i].i != s {
+                       t.Errorf("Lgamma(%g) = %g, %d, want %g, %d", vflgammaSC[i], f, s, lgammaSC[i].f, lgammaSC[i].i)
+               }
+       }
+}
+
+func TestLog(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := Fabs(vf[i])
+               if f := Log(a); log[i] != f {
+                       t.Errorf("Log(%g) = %g, want %g", a, f, log[i])
+               }
+       }
+       if f := Log(10); f != Ln10 {
+               t.Errorf("Log(%g) = %g, want %g", 10.0, f, Ln10)
+       }
+       for i := 0; i < len(vflogSC); i++ {
+               if f := Log(vflogSC[i]); !alike(logSC[i], f) {
+                       t.Errorf("Log(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+               }
+       }
+}
+
+func TestLogb(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Logb(vf[i]); logb[i] != f {
+                       t.Errorf("Logb(%g) = %g, want %g", vf[i], f, logb[i])
+               }
+       }
+       for i := 0; i < len(vflogbSC); i++ {
+               if f := Logb(vflogbSC[i]); !alike(logbSC[i], f) {
+                       t.Errorf("Logb(%g) = %g, want %g", vflogbSC[i], f, logbSC[i])
+               }
+       }
+}
+
+func TestLog10(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := Fabs(vf[i])
+               if f := Log10(a); !veryclose(log10[i], f) {
+                       t.Errorf("Log10(%g) = %g, want %g", a, f, log10[i])
+               }
+       }
+       if f := Log10(E); f != Log10E {
+               t.Errorf("Log10(%g) = %g, want %g", E, f, Log10E)
+       }
+       for i := 0; i < len(vflogSC); i++ {
+               if f := Log10(vflogSC[i]); !alike(logSC[i], f) {
+                       t.Errorf("Log10(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+               }
+       }
+}
+
+func TestLog1p(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := vf[i] / 100
+               if f := Log1p(a); !veryclose(log1p[i], f) {
+                       t.Errorf("Log1p(%g) = %g, want %g", a, f, log1p[i])
+               }
+       }
+       a := float64(9)
+       if f := Log1p(a); f != Ln10 {
+               t.Errorf("Log1p(%g) = %g, want %g", a, f, Ln10)
+       }
+       for i := 0; i < len(vflogSC); i++ {
+               if f := Log1p(vflog1pSC[i]); !alike(log1pSC[i], f) {
+                       t.Errorf("Log1p(%g) = %g, want %g", vflog1pSC[i], f, log1pSC[i])
+               }
+       }
+}
+
+func TestLog2(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := Fabs(vf[i])
+               if f := Log2(a); !veryclose(log2[i], f) {
+                       t.Errorf("Log2(%g) = %g, want %g", a, f, log2[i])
+               }
+       }
+       if f := Log2(E); f != Log2E {
+               t.Errorf("Log2(%g) = %g, want %g", E, f, Log2E)
+       }
+       for i := 0; i < len(vflogSC); i++ {
+               if f := Log2(vflogSC[i]); !alike(logSC[i], f) {
+                       t.Errorf("Log2(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+               }
+       }
+}
+
+func TestModf(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f, g := Modf(vf[i]); !veryclose(modf[i][0], f) || !veryclose(modf[i][1], g) {
+                       t.Errorf("Modf(%g) = %g, %g, want %g, %g", vf[i], f, g, modf[i][0], modf[i][1])
+               }
+       }
+       for i := 0; i < len(vfmodfSC); i++ {
+               if f, g := Modf(vfmodfSC[i]); !alike(modfSC[i][0], f) || !alike(modfSC[i][1], g) {
+                       t.Errorf("Modf(%g) = %g, %g, want %g, %g", vfmodfSC[i], f, g, modfSC[i][0], modfSC[i][1])
+               }
+       }
+}
+
+func TestNextafter(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Nextafter(vf[i], 10); nextafter[i] != f {
+                       t.Errorf("Nextafter(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter[i])
+               }
+       }
+       for i := 0; i < len(vfmodfSC); i++ {
+               if f := Nextafter(vfnextafterSC[i][0], vfnextafterSC[i][1]); !alike(nextafterSC[i], f) {
+                       t.Errorf("Nextafter(%g, %g) = %g want %g", vfnextafterSC[i][0], vfnextafterSC[i][1], f, nextafterSC[i])
+               }
+       }
+}
+
+func TestPow(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Pow(10, vf[i]); !close(pow[i], f) {
+                       t.Errorf("Pow(10, %g) = %g, want %g", vf[i], f, pow[i])
+               }
+       }
+       for i := 0; i < len(vfpowSC); i++ {
+               if f := Pow(vfpowSC[i][0], vfpowSC[i][1]); !alike(powSC[i], f) {
+                       t.Errorf("Pow(%g, %g) = %g, want %g", vfpowSC[i][0], vfpowSC[i][1], f, powSC[i])
+               }
+       }
+}
+
+func TestRemainder(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Remainder(10, vf[i]); remainder[i] != f {
+                       t.Errorf("Remainder(10, %g) = %g, want %g", vf[i], f, remainder[i])
+               }
+       }
+       for i := 0; i < len(vffmodSC); i++ {
+               if f := Remainder(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
+                       t.Errorf("Remainder(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
+               }
+       }
+}
+
+func TestSignbit(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Signbit(vf[i]); signbit[i] != f {
+                       t.Errorf("Signbit(%g) = %t, want %t", vf[i], f, signbit[i])
+               }
+       }
+       for i := 0; i < len(vfsignbitSC); i++ {
+               if f := Signbit(vfsignbitSC[i]); signbitSC[i] != f {
+                       t.Errorf("Signbit(%g) = %t, want %t", vfsignbitSC[i], f, signbitSC[i])
+               }
+       }
+}
+func TestSin(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Sin(vf[i]); !close(sin[i], f) {
+                       t.Errorf("Sin(%g) = %g, want %g", vf[i], f, sin[i])
+               }
+       }
+       for i := 0; i < len(vfsinSC); i++ {
+               if f := Sin(vfsinSC[i]); !alike(sinSC[i], f) {
+                       t.Errorf("Sin(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
+               }
+       }
+}
+
+func TestSincos(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if s, c := Sincos(vf[i]); !close(sin[i], s) || !close(cos[i], c) {
+                       t.Errorf("Sincos(%g) = %g, %g want %g, %g", vf[i], s, c, sin[i], cos[i])
+               }
+       }
+}
+
+func TestSinh(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Sinh(vf[i]); !close(sinh[i], f) {
+                       t.Errorf("Sinh(%g) = %g, want %g", vf[i], f, sinh[i])
+               }
+       }
+       for i := 0; i < len(vfsinhSC); i++ {
+               if f := Sinh(vfsinhSC[i]); !alike(sinhSC[i], f) {
+                       t.Errorf("Sinh(%g) = %g, want %g", vfsinhSC[i], f, sinhSC[i])
+               }
+       }
+}
+
+func TestSqrt(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := Fabs(vf[i])
+               if f := SqrtGo(a); sqrt[i] != f {
+                       t.Errorf("SqrtGo(%g) = %g, want %g", a, f, sqrt[i])
+               }
+               a = Fabs(vf[i])
+               if f := Sqrt(a); sqrt[i] != f {
+                       t.Errorf("Sqrt(%g) = %g, want %g", a, f, sqrt[i])
+               }
+       }
+       for i := 0; i < len(vfsqrtSC); i++ {
+               if f := SqrtGo(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
+                       t.Errorf("SqrtGo(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
+               }
+               if f := Sqrt(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
+                       t.Errorf("Sqrt(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
+               }
+       }
+}
+
+func TestTan(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Tan(vf[i]); !close(tan[i], f) {
+                       t.Errorf("Tan(%g) = %g, want %g", vf[i], f, tan[i])
+               }
+       }
+       // same special cases as Sin
+       for i := 0; i < len(vfsinSC); i++ {
+               if f := Tan(vfsinSC[i]); !alike(sinSC[i], f) {
+                       t.Errorf("Tan(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
+               }
+       }
+
+       // Make sure portable Tan(Pi/2) doesn't panic (it used to).
+       // The portable implementation returns NaN.
+       // Assembly implementations might not,
+       // because Pi/2 is not exactly representable.
+       if runtime.GOARCH != "386" {
+               if f := Tan(Pi / 2); !alike(f, NaN()) {
+                       t.Errorf("Tan(%g) = %g, want %g", Pi/2, f, NaN())
+               }
+       }
+}
+
+func TestTanh(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Tanh(vf[i]); !veryclose(tanh[i], f) {
+                       t.Errorf("Tanh(%g) = %g, want %g", vf[i], f, tanh[i])
+               }
+       }
+       for i := 0; i < len(vftanhSC); i++ {
+               if f := Tanh(vftanhSC[i]); !alike(tanhSC[i], f) {
+                       t.Errorf("Tanh(%g) = %g, want %g", vftanhSC[i], f, tanhSC[i])
+               }
+       }
+}
+
+func TestTrunc(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               if f := Trunc(vf[i]); trunc[i] != f {
+                       t.Errorf("Trunc(%g) = %g, want %g", vf[i], f, trunc[i])
+               }
+       }
+       for i := 0; i < len(vfceilSC); i++ {
+               if f := Trunc(vfceilSC[i]); !alike(ceilSC[i], f) {
+                       t.Errorf("Trunc(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
+               }
+       }
+}
+
+func TestY0(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := Fabs(vf[i])
+               if f := Y0(a); !close(y0[i], f) {
+                       t.Errorf("Y0(%g) = %g, want %g", a, f, y0[i])
+               }
+       }
+       for i := 0; i < len(vfy0SC); i++ {
+               if f := Y0(vfy0SC[i]); !alike(y0SC[i], f) {
+                       t.Errorf("Y0(%g) = %g, want %g", vfy0SC[i], f, y0SC[i])
+               }
+       }
+}
+
+func TestY1(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := Fabs(vf[i])
+               if f := Y1(a); !soclose(y1[i], f, 2e-14) {
+                       t.Errorf("Y1(%g) = %g, want %g", a, f, y1[i])
+               }
+       }
+       for i := 0; i < len(vfy0SC); i++ {
+               if f := Y1(vfy0SC[i]); !alike(y1SC[i], f) {
+                       t.Errorf("Y1(%g) = %g, want %g", vfy0SC[i], f, y1SC[i])
+               }
+       }
+}
+
+func TestYn(t *testing.T) {
+       for i := 0; i < len(vf); i++ {
+               a := Fabs(vf[i])
+               if f := Yn(2, a); !close(y2[i], f) {
+                       t.Errorf("Yn(2, %g) = %g, want %g", a, f, y2[i])
+               }
+               if f := Yn(-3, a); !close(yM3[i], f) {
+                       t.Errorf("Yn(-3, %g) = %g, want %g", a, f, yM3[i])
+               }
+       }
+       for i := 0; i < len(vfy0SC); i++ {
+               if f := Yn(2, vfy0SC[i]); !alike(y2SC[i], f) {
+                       t.Errorf("Yn(2, %g) = %g, want %g", vfy0SC[i], f, y2SC[i])
+               }
+               if f := Yn(-3, vfy0SC[i]); !alike(yM3SC[i], f) {
+                       t.Errorf("Yn(-3, %g) = %g, want %g", vfy0SC[i], f, yM3SC[i])
+               }
+       }
+}
+
+// Check that math functions of high angle values
+// return similar results to low angle values
+func TestLargeCos(t *testing.T) {
+       large := float64(100000 * Pi)
+       for i := 0; i < len(vf); i++ {
+               f1 := Cos(vf[i])
+               f2 := Cos(vf[i] + large)
+               if !kindaclose(f1, f2) {
+                       t.Errorf("Cos(%g) = %g, want %g", vf[i]+large, f2, f1)
+               }
+       }
+}
+
+func TestLargeSin(t *testing.T) {
+       large := float64(100000 * Pi)
+       for i := 0; i < len(vf); i++ {
+               f1 := Sin(vf[i])
+               f2 := Sin(vf[i] + large)
+               if !kindaclose(f1, f2) {
+                       t.Errorf("Sin(%g) = %g, want %g", vf[i]+large, f2, f1)
+               }
+       }
+}
+
+func TestLargeSincos(t *testing.T) {
+       large := float64(100000 * Pi)
+       for i := 0; i < len(vf); i++ {
+               f1, g1 := Sincos(vf[i])
+               f2, g2 := Sincos(vf[i] + large)
+               if !kindaclose(f1, f2) || !kindaclose(g1, g2) {
+                       t.Errorf("Sincos(%g) = %g, %g, want %g, %g", vf[i]+large, f2, g2, f1, g1)
+               }
+       }
+}
+
+func TestLargeTan(t *testing.T) {
+       large := float64(100000 * Pi)
+       for i := 0; i < len(vf); i++ {
+               f1 := Tan(vf[i])
+               f2 := Tan(vf[i] + large)
+               if !kindaclose(f1, f2) {
+                       t.Errorf("Tan(%g) = %g, want %g", vf[i]+large, f2, f1)
+               }
+       }
+}
+
+// Check that math constants are accepted by compiler
+// and have right value (assumes strconv.Atof works).
+// http://code.google.com/p/go/issues/detail?id=201
+
+type floatTest struct {
+       val  interface{}
+       name string
+       str  string
+}
+
+var floatTests = []floatTest{
+       {float64(MaxFloat64), "MaxFloat64", "1.7976931348623157e+308"},
+       {float64(MinFloat64), "MinFloat64", "5e-324"},
+       {float32(MaxFloat32), "MaxFloat32", "3.4028235e+38"},
+       {float32(MinFloat32), "MinFloat32", "1e-45"},
+}
+
+func TestFloatMinMax(t *testing.T) {
+       for _, tt := range floatTests {
+               s := fmt.Sprint(tt.val)
+               if s != tt.str {
+                       t.Errorf("Sprint(%v) = %s, want %s", tt.name, s, tt.str)
+               }
+       }
+}
+
+// Benchmarks
+
+func BenchmarkAcos(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Acos(.5)
+       }
+}
+
+func BenchmarkAcosh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Acosh(1.5)
+       }
+}
+
+func BenchmarkAsin(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Asin(.5)
+       }
+}
+
+func BenchmarkAsinh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Asinh(.5)
+       }
+}
+
+func BenchmarkAtan(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atan(.5)
+       }
+}
+
+func BenchmarkAtanh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atanh(.5)
+       }
+}
+
+func BenchmarkAtan2(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atan2(.5, 1)
+       }
+}
+
+func BenchmarkCbrt(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Cbrt(10)
+       }
+}
+
+func BenchmarkCeil(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Ceil(.5)
+       }
+}
+
+func BenchmarkCopysign(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Copysign(.5, -1)
+       }
+}
+
+func BenchmarkCos(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Cos(.5)
+       }
+}
+
+func BenchmarkCosh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Cosh(2.5)
+       }
+}
+
+func BenchmarkErf(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Erf(.5)
+       }
+}
+
+func BenchmarkErfc(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Erfc(.5)
+       }
+}
+
+func BenchmarkExp(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Exp(.5)
+       }
+}
+
+func BenchmarkExpm1(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Expm1(.5)
+       }
+}
+
+func BenchmarkExp2(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Exp2(.5)
+       }
+}
+
+func BenchmarkFabs(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Fabs(.5)
+       }
+}
+
+func BenchmarkFdim(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Fdim(10, 3)
+       }
+}
+
+func BenchmarkFloor(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Floor(.5)
+       }
+}
+
+func BenchmarkFmax(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Fmax(10, 3)
+       }
+}
+
+func BenchmarkFmin(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Fmin(10, 3)
+       }
+}
+
+func BenchmarkFmod(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Fmod(10, 3)
+       }
+}
+
+func BenchmarkFrexp(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Frexp(8)
+       }
+}
+
+func BenchmarkGamma(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Gamma(2.5)
+       }
+}
+
+func BenchmarkHypot(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Hypot(3, 4)
+       }
+}
+
+func BenchmarkHypotGo(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               HypotGo(3, 4)
+       }
+}
+
+func BenchmarkIlogb(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Ilogb(.5)
+       }
+}
+
+func BenchmarkJ0(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               J0(2.5)
+       }
+}
+
+func BenchmarkJ1(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               J1(2.5)
+       }
+}
+
+func BenchmarkJn(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Jn(2, 2.5)
+       }
+}
+
+func BenchmarkLdexp(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Ldexp(.5, 2)
+       }
+}
+
+func BenchmarkLgamma(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Lgamma(2.5)
+       }
+}
+
+func BenchmarkLog(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Log(.5)
+       }
+}
+
+func BenchmarkLogb(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Logb(.5)
+       }
+}
+
+func BenchmarkLog1p(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Log1p(.5)
+       }
+}
+
+func BenchmarkLog10(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Log10(.5)
+       }
+}
+
+func BenchmarkLog2(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Log2(.5)
+       }
+}
+
+func BenchmarkModf(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Modf(1.5)
+       }
+}
+
+func BenchmarkNextafter(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Nextafter(.5, 1)
+       }
+}
+
+func BenchmarkPowInt(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Pow(2, 2)
+       }
+}
+
+func BenchmarkPowFrac(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Pow(2.5, 1.5)
+       }
+}
+
+func BenchmarkRemainder(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Remainder(10, 3)
+       }
+}
+
+func BenchmarkSignbit(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Signbit(2.5)
+       }
+}
+
+func BenchmarkSin(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sin(.5)
+       }
+}
+
+func BenchmarkSincos(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sincos(.5)
+       }
+}
+
+func BenchmarkSinh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sinh(2.5)
+       }
+}
+
+func BenchmarkSqrt(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Sqrt(10)
+       }
+}
+
+func BenchmarkSqrtGo(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               SqrtGo(10)
+       }
+}
+
+func BenchmarkTan(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Tan(.5)
+       }
+}
+
+func BenchmarkTanh(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Tanh(2.5)
+       }
+}
+func BenchmarkTrunc(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Trunc(.5)
+       }
+}
+
+func BenchmarkY0(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Y0(2.5)
+       }
+}
+
+func BenchmarkY1(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Y1(2.5)
+       }
+}
+
+func BenchmarkYn(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Yn(2, 2.5)
+       }
+}
diff --git a/libgo/go/math/asin.go b/libgo/go/math/asin.go
new file mode 100644 (file)
index 0000000..3bace8f
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+/*
+       Floating-point arcsine and arccosine.
+
+       They are implemented by computing the arctangent
+       after appropriate range reduction.
+*/
+
+// Asin returns the arcsine of x.
+//
+// Special cases are:
+//     Asin(±0) = ±0
+//     Asin(x) = NaN if x < -1 or x > 1
+func Asin(x float64) float64 {
+       if x == 0 {
+               return x // special case
+       }
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+       if x > 1 {
+               return NaN() // special case
+       }
+
+       temp := Sqrt(1 - x*x)
+       if x > 0.7 {
+               temp = Pi/2 - satan(temp/x)
+       } else {
+               temp = satan(x / temp)
+       }
+
+       if sign {
+               temp = -temp
+       }
+       return temp
+}
+
+// Acos returns the arccosine of x.
+//
+// Special case is:
+//     Acos(x) = NaN if x < -1 or x > 1
+func Acos(x float64) float64 { return Pi/2 - Asin(x) }
diff --git a/libgo/go/math/asinh.go b/libgo/go/math/asinh.go
new file mode 100644 (file)
index 0000000..90dcd27
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/s_asinh.c
+// and came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// asinh(x)
+// Method :
+//     Based on
+//             asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+//     we have
+//     asinh(x) := x  if  1+x*x=1,
+//              := sign(x)*(log(x)+ln2)) for large |x|, else
+//              := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+//              := sign(x)*log1p(|x| + x**2/(1 + sqrt(1+x**2)))
+//
+
+// Asinh(x) calculates the inverse hyperbolic sine of x.
+//
+// Special cases are:
+//     Asinh(+Inf) = +Inf
+//     Asinh(-Inf) = -Inf
+//     Asinh(NaN) = NaN
+func Asinh(x float64) float64 {
+       const (
+               Ln2      = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
+               NearZero = 1.0 / (1 << 28)            // 2**-28
+               Large    = 1 << 28                    // 2**28
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       if x != x || x > MaxFloat64 || x < -MaxFloat64 { // IsNaN(x) || IsInf(x, 0)
+               return x
+       }
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+       var temp float64
+       switch {
+       case x > Large:
+               temp = Log(x) + Ln2 // |x| > 2**28
+       case x > 2:
+               temp = Log(2*x + 1/(Sqrt(x*x+1)+x)) // 2**28 > |x| > 2.0
+       case x < NearZero:
+               temp = x // |x| < 2**-28
+       default:
+               temp = Log1p(x + x*x/(1+Sqrt(1+x*x))) // 2.0 > |x| > 2**-28
+       }
+       if sign {
+               temp = -temp
+       }
+       return temp
+}
diff --git a/libgo/go/math/atan.go b/libgo/go/math/atan.go
new file mode 100644 (file)
index 0000000..9d4ec2f
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       Floating-point arctangent.
+
+       Atan returns the value of the arctangent of its
+       argument in the range [-pi/2,pi/2].
+       There are no error returns.
+       Coefficients are #5077 from Hart & Cheney. (19.56D)
+*/
+
+// xatan evaluates a series valid in the
+// range [-0.414...,+0.414...]. (tan(pi/8))
+func xatan(arg float64) float64 {
+       const (
+               P4 = .161536412982230228262e2
+               P3 = .26842548195503973794141e3
+               P2 = .11530293515404850115428136e4
+               P1 = .178040631643319697105464587e4
+               P0 = .89678597403663861959987488e3
+               Q4 = .5895697050844462222791e2
+               Q3 = .536265374031215315104235e3
+               Q2 = .16667838148816337184521798e4
+               Q1 = .207933497444540981287275926e4
+               Q0 = .89678597403663861962481162e3
+       )
+       sq := arg * arg
+       value := ((((P4*sq+P3)*sq+P2)*sq+P1)*sq + P0)
+       value = value / (((((sq+Q4)*sq+Q3)*sq+Q2)*sq+Q1)*sq + Q0)
+       return value * arg
+}
+
+// satan reduces its argument (known to be positive)
+// to the range [0,0.414...] and calls xatan.
+func satan(arg float64) float64 {
+       if arg < Sqrt2-1 {
+               return xatan(arg)
+       }
+       if arg > Sqrt2+1 {
+               return Pi/2 - xatan(1/arg)
+       }
+       return Pi/4 + xatan((arg-1)/(arg+1))
+}
+
+// Atan returns the arctangent of x.
+//
+// Special cases are:
+//     Atan(±0) = ±0
+//     Atan(±Inf) = ±Pi/2
+func Atan(x float64) float64 {
+       if x == 0 {
+               return x
+       }
+       if x > 0 {
+               return satan(x)
+       }
+       return -satan(-x)
+}
diff --git a/libgo/go/math/atan2.go b/libgo/go/math/atan2.go
new file mode 100644 (file)
index 0000000..49d4bdd
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Atan2 returns the arc tangent of y/x, using
+// the signs of the two to determine the quadrant
+// of the return value.
+//
+// Special cases are (in order):
+//     Atan2(y, NaN) = NaN
+//     Atan2(NaN, x) = NaN
+//     Atan2(+0, x>=0) = +0
+//     Atan2(-0, x>=0) = -0
+//     Atan2(+0, x<=-0) = +Pi
+//     Atan2(-0, x<=-0) = -Pi
+//     Atan2(y>0, 0) = +Pi/2
+//     Atan2(y<0, 0) = -Pi/2
+//     Atan2(+Inf, +Inf) = +Pi/4
+//     Atan2(-Inf, +Inf) = -Pi/4
+//     Atan2(+Inf, -Inf) = 3Pi/4
+//     Atan2(-Inf, -Inf) = -3Pi/4
+//     Atan2(y, +Inf) = 0
+//     Atan2(y>0, -Inf) = +Pi
+//     Atan2(y<0, -Inf) = -Pi
+//     Atan2(+Inf, x) = +Pi/2
+//     Atan2(-Inf, x) = -Pi/2
+func Atan2(y, x float64) float64 {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case y != y || x != x: // IsNaN(y) || IsNaN(x):
+               return NaN()
+       case y == 0:
+               if x >= 0 && !Signbit(x) {
+                       return Copysign(0, y)
+               }
+               return Copysign(Pi, y)
+       case x == 0:
+               return Copysign(Pi/2, y)
+       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+               if x > MaxFloat64 { // IsInf(x, 1) {
+                       switch {
+                       case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+                               return Copysign(Pi/4, y)
+                       default:
+                               return Copysign(0, y)
+                       }
+               }
+               switch {
+               case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+                       return Copysign(3*Pi/4, y)
+               default:
+                       return Copysign(Pi, y)
+               }
+       case y < -MaxFloat64 || y > MaxFloat64: //IsInf(y, 0):
+               return Copysign(Pi/2, y)
+       }
+
+       // Call atan and determine the quadrant.
+       q := Atan(y / x)
+       if x < 0 {
+               if q <= 0 {
+                       return q + Pi
+               }
+               return q - Pi
+       }
+       return q
+}
diff --git a/libgo/go/math/atanh.go b/libgo/go/math/atanh.go
new file mode 100644 (file)
index 0000000..6aecb7b
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_atanh.c
+// and came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// __ieee754_atanh(x)
+// Method :
+//     1. Reduce x to positive by atanh(-x) = -atanh(x)
+//     2. For x>=0.5
+//                 1              2x                          x
+//     atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+//                 2             1 - x                      1 - x
+//
+//     For x<0.5
+//     atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+//
+// Special cases:
+//     atanh(x) is NaN if |x| > 1 with signal;
+//     atanh(NaN) is that NaN with no signal;
+//     atanh(+-1) is +-INF with signal.
+//
+
+// Atanh(x) calculates the inverse hyperbolic tangent of x.
+//
+// Special cases are:
+//     Atanh(x) = NaN if x < -1 or x > 1
+//     Atanh(1) = +Inf
+//     Atanh(-1) = -Inf
+//     Atanh(NaN) = NaN
+func Atanh(x float64) float64 {
+       const NearZero = 1.0 / (1 << 28) // 2**-28
+       // TODO(rsc): Remove manual inlining of IsNaN
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x < -1 || x > 1 || x != x: // x < -1 || x > 1 || IsNaN(x):
+               return NaN()
+       case x == 1:
+               return Inf(1)
+       case x == -1:
+               return Inf(-1)
+       }
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+       var temp float64
+       switch {
+       case x < NearZero:
+               temp = x
+       case x < 0.5:
+               temp = x + x
+               temp = 0.5 * Log1p(temp+temp*x/(1-x))
+       default:
+               temp = 0.5 * Log1p((x+x)/(1-x))
+       }
+       if sign {
+               temp = -temp
+       }
+       return temp
+}
diff --git a/libgo/go/math/bits.go b/libgo/go/math/bits.go
new file mode 100644 (file)
index 0000000..d36cd18
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+const (
+       uvnan    = 0x7FF0000000000001
+       uvinf    = 0x7FF0000000000000
+       uvneginf = 0xFFF0000000000000
+       mask     = 0x7FF
+       shift    = 64 - 11 - 1
+       bias     = 1022
+)
+
+// Inf returns positive infinity if sign >= 0, negative infinity if sign < 0.
+func Inf(sign int) float64 {
+       var v uint64
+       if sign >= 0 {
+               v = uvinf
+       } else {
+               v = uvneginf
+       }
+       return Float64frombits(v)
+}
+
+// NaN returns an IEEE 754 ``not-a-number'' value.
+func NaN() float64 { return Float64frombits(uvnan) }
+
+// IsNaN returns whether f is an IEEE 754 ``not-a-number'' value.
+func IsNaN(f float64) (is bool) {
+       // IEEE 754 says that only NaNs satisfy f != f.
+       // To avoid the floating-point hardware, could use:
+       //      x := Float64bits(f);
+       //      return uint32(x>>shift)&mask == mask && x != uvinf && x != uvneginf
+       return f != f
+}
+
+// IsInf returns whether f is an infinity, according to sign.
+// If sign > 0, IsInf returns whether f is positive infinity.
+// If sign < 0, IsInf returns whether f is negative infinity.
+// If sign == 0, IsInf returns whether f is either infinity.
+func IsInf(f float64, sign int) bool {
+       // Test for infinity by comparing against maximum float.
+       // To avoid the floating-point hardware, could use:
+       //      x := Float64bits(f);
+       //      return sign >= 0 && x == uvinf || sign <= 0 && x == uvneginf;
+       return sign >= 0 && f > MaxFloat64 || sign <= 0 && f < -MaxFloat64
+}
diff --git a/libgo/go/math/cbrt.go b/libgo/go/math/cbrt.go
new file mode 100644 (file)
index 0000000..d2b7e91
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       The algorithm is based in part on "Optimal Partitioning of
+       Newton's Method for Calculating Roots", by Gunter Meinardus
+       and G. D. Taylor, Mathematics of Computation © 1980 American
+       Mathematical Society.
+       (http://www.jstor.org/stable/2006387?seq=9, accessed 11-Feb-2010)
+*/
+
+// Cbrt returns the cube root of its argument.
+//
+// Special cases are:
+//     Cbrt(±0) = ±0
+//     Cbrt(±Inf) = ±Inf
+//     Cbrt(NaN) = NaN
+func Cbrt(x float64) float64 {
+       const (
+               A1 = 1.662848358e-01
+               A2 = 1.096040958e+00
+               A3 = 4.105032829e-01
+               A4 = 5.649335816e-01
+               B1 = 2.639607233e-01
+               B2 = 8.699282849e-01
+               B3 = 1.629083358e-01
+               B4 = 2.824667908e-01
+               C1 = 4.190115298e-01
+               C2 = 6.904625373e-01
+               C3 = 6.46502159e-02
+               C4 = 1.412333954e-01
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x == 0 || x != x || x < -MaxFloat64 || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 0):
+               return x
+       }
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+       // Reduce argument
+       f, e := Frexp(x)
+       m := e % 3
+       if m > 0 {
+               m -= 3
+               e -= m // e is multiple of 3
+       }
+       f = Ldexp(f, m) // 0.125 <= f < 1.0
+
+       // Estimate cube root
+       switch m {
+       case 0: // 0.5 <= f < 1.0
+               f = A1*f + A2 - A3/(A4+f)
+       case -1: // 0.25 <= f < 0.5
+               f = B1*f + B2 - B3/(B4+f)
+       default: // 0.125 <= f < 0.25
+               f = C1*f + C2 - C3/(C4+f)
+       }
+       y := Ldexp(f, e/3) // e/3 = exponent of cube root
+
+       // Iterate
+       s := y * y * y
+       t := s + x
+       y *= (t + x) / (s + t)
+       // Reiterate
+       s = (y*y*y - x) / x
+       y -= y * (((14.0/81.0)*s-(2.0/9.0))*s + (1.0 / 3.0)) * s
+       if sign {
+               y = -y
+       }
+       return y
+}
diff --git a/libgo/go/math/const.go b/libgo/go/math/const.go
new file mode 100644 (file)
index 0000000..6a78d00
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The math package provides basic constants and mathematical functions.
+package math
+
+// Mathematical constants.
+// Reference: http://www.research.att.com/~njas/sequences/Axxxxxx
+const (
+       E   = 2.71828182845904523536028747135266249775724709369995957496696763 // A001113
+       Pi  = 3.14159265358979323846264338327950288419716939937510582097494459 // A000796
+       Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // A001622
+
+       Sqrt2   = 1.41421356237309504880168872420969807856967187537694807317667974 // A002193
+       SqrtE   = 1.64872127070012814684865078781416357165377610071014801157507931 // A019774
+       SqrtPi  = 1.77245385090551602729816748334114518279754945612238712821380779 // A002161
+       SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // A139339
+
+       Ln2    = 0.693147180559945309417232121458176568075500134360255254120680009 // A002162
+       Log2E  = 1 / Ln2
+       Ln10   = 2.30258509299404568401799145468436420760110148862877297603332790 // A002392
+       Log10E = 1 / Ln10
+)
+
+// Floating-point limit values.
+// Max is the largest finite value representable by the type.
+// Min is the smallest nonzero value representable by the type.
+const (
+       MaxFloat32 = 3.40282346638528859811704183484516925440e+38  /* 2**127 * (2**24 - 1) / 2**23 */
+       MinFloat32 = 1.401298464324817070923729583289916131280e-45 /* 1 / 2**(127 - 1 + 23) */
+
+       MaxFloat64 = 1.797693134862315708145274237317043567981e+308 /* 2**1023 * (2**53 - 1) / 2**52 */
+       MinFloat64 = 4.940656458412465441765687928682213723651e-324 /* 1 / 2**(1023 - 1 + 52) */
+)
+
+// Integer limit values.
+const (
+       MaxInt8   = 1<<7 - 1
+       MinInt8   = -1 << 7
+       MaxInt16  = 1<<15 - 1
+       MinInt16  = -1 << 15
+       MaxInt32  = 1<<31 - 1
+       MinInt32  = -1 << 31
+       MaxInt64  = 1<<63 - 1
+       MinInt64  = -1 << 63
+       MaxUint8  = 1<<8 - 1
+       MaxUint16 = 1<<16 - 1
+       MaxUint32 = 1<<32 - 1
+       MaxUint64 = 1<<64 - 1
+)
+
+// BUG(rsc): The manual should define the special cases for all of these functions.
diff --git a/libgo/go/math/copysign.go b/libgo/go/math/copysign.go
new file mode 100644 (file)
index 0000000..ee65456
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Copysign(x, y) returns a value with the magnitude
+// of x and the sign of y.
+func Copysign(x, y float64) float64 {
+       const sign = 1 << 63
+       return Float64frombits(Float64bits(x)&^sign | Float64bits(y)&sign)
+}
diff --git a/libgo/go/math/erf.go b/libgo/go/math/erf.go
new file mode 100644 (file)
index 0000000..b608999
--- /dev/null
@@ -0,0 +1,340 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+/*
+       Floating-point error function and complementary error function.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/s_erf.c and
+// came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// double erf(double x)
+// double erfc(double x)
+//                           x
+//                    2      |\
+//     erf(x)  =  ---------  | exp(-t*t)dt
+//                 sqrt(pi) \|
+//                           0
+//
+//     erfc(x) =  1-erf(x)
+//  Note that
+//              erf(-x) = -erf(x)
+//              erfc(-x) = 2 - erfc(x)
+//
+// Method:
+//      1. For |x| in [0, 0.84375]
+//          erf(x)  = x + x*R(x**2)
+//          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25]
+//                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375]
+//         where R = P/Q where P is an odd poly of degree 8 and
+//         Q is an odd poly of degree 10.
+//                                               -57.90
+//                      | R - (erf(x)-x)/x | <= 2
+//
+//
+//         Remark. The formula is derived by noting
+//          erf(x) = (2/sqrt(pi))*(x - x**3/3 + x**5/10 - x**7/42 + ....)
+//         and that
+//          2/sqrt(pi) = 1.128379167095512573896158903121545171688
+//         is close to one. The interval is chosen because the fix
+//         point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+//         near 0.6174), and by some experiment, 0.84375 is chosen to
+//         guarantee the error is less than one ulp for erf.
+//
+//      2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+//         c = 0.84506291151 rounded to single (24 bits)
+//              erf(x)  = sign(x) * (c  + P1(s)/Q1(s))
+//              erfc(x) = (1-c)  - P1(s)/Q1(s) if x > 0
+//                        1+(c+P1(s)/Q1(s))    if x < 0
+//              |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+//         Remark: here we use the taylor series expansion at x=1.
+//              erf(1+s) = erf(1) + s*Poly(s)
+//                       = 0.845.. + P1(s)/Q1(s)
+//         That is, we use rational approximation to approximate
+//                      erf(1+s) - (c = (single)0.84506291151)
+//         Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+//         where
+//              P1(s) = degree 6 poly in s
+//              Q1(s) = degree 6 poly in s
+//
+//      3. For x in [1.25,1/0.35(~2.857143)],
+//              erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+//              erf(x)  = 1 - erfc(x)
+//         where
+//              R1(z) = degree 7 poly in z, (z=1/x**2)
+//              S1(z) = degree 8 poly in z
+//
+//      4. For x in [1/0.35,28]
+//              erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+//                      = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+//                      = 2.0 - tiny            (if x <= -6)
+//              erf(x)  = sign(x)*(1.0 - erfc(x)) if x < 6, else
+//              erf(x)  = sign(x)*(1.0 - tiny)
+//         where
+//              R2(z) = degree 6 poly in z, (z=1/x**2)
+//              S2(z) = degree 7 poly in z
+//
+//      Note1:
+//         To compute exp(-x*x-0.5625+R/S), let s be a single
+//         precision number and s := x; then
+//              -x*x = -s*s + (s-x)*(s+x)
+//              exp(-x*x-0.5626+R/S) =
+//                      exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+//      Note2:
+//         Here 4 and 5 make use of the asymptotic series
+//                        exp(-x*x)
+//              erfc(x) ~ ---------- * ( 1 + Poly(1/x**2) )
+//                        x*sqrt(pi)
+//         We use rational approximation to approximate
+//              g(s)=f(1/x**2) = log(erfc(x)*x) - x*x + 0.5625
+//         Here is the error bound for R1/S1 and R2/S2
+//              |R1/S1 - f(x)|  < 2**(-62.57)
+//              |R2/S2 - f(x)|  < 2**(-61.52)
+//
+//      5. For inf > x >= 28
+//              erf(x)  = sign(x) *(1 - tiny)  (raise inexact)
+//              erfc(x) = tiny*tiny (raise underflow) if x > 0
+//                      = 2 - tiny if x<0
+//
+//      7. Special case:
+//              erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1,
+//              erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+//              erfc/erf(NaN) is NaN
+
+const (
+       erx = 8.45062911510467529297e-01 // 0x3FEB0AC160000000
+       // Coefficients for approximation to  erf in [0, 0.84375]
+       efx  = 1.28379167095512586316e-01  // 0x3FC06EBA8214DB69
+       efx8 = 1.02703333676410069053e+00  // 0x3FF06EBA8214DB69
+       pp0  = 1.28379167095512558561e-01  // 0x3FC06EBA8214DB68
+       pp1  = -3.25042107247001499370e-01 // 0xBFD4CD7D691CB913
+       pp2  = -2.84817495755985104766e-02 // 0xBF9D2A51DBD7194F
+       pp3  = -5.77027029648944159157e-03 // 0xBF77A291236668E4
+       pp4  = -2.37630166566501626084e-05 // 0xBEF8EAD6120016AC
+       qq1  = 3.97917223959155352819e-01  // 0x3FD97779CDDADC09
+       qq2  = 6.50222499887672944485e-02  // 0x3FB0A54C5536CEBA
+       qq3  = 5.08130628187576562776e-03  // 0x3F74D022C4D36B0F
+       qq4  = 1.32494738004321644526e-04  // 0x3F215DC9221C1A10
+       qq5  = -3.96022827877536812320e-06 // 0xBED09C4342A26120
+       // Coefficients for approximation to  erf  in [0.84375, 1.25]
+       pa0 = -2.36211856075265944077e-03 // 0xBF6359B8BEF77538
+       pa1 = 4.14856118683748331666e-01  // 0x3FDA8D00AD92B34D
+       pa2 = -3.72207876035701323847e-01 // 0xBFD7D240FBB8C3F1
+       pa3 = 3.18346619901161753674e-01  // 0x3FD45FCA805120E4
+       pa4 = -1.10894694282396677476e-01 // 0xBFBC63983D3E28EC
+       pa5 = 3.54783043256182359371e-02  // 0x3FA22A36599795EB
+       pa6 = -2.16637559486879084300e-03 // 0xBF61BF380A96073F
+       qa1 = 1.06420880400844228286e-01  // 0x3FBB3E6618EEE323
+       qa2 = 5.40397917702171048937e-01  // 0x3FE14AF092EB6F33
+       qa3 = 7.18286544141962662868e-02  // 0x3FB2635CD99FE9A7
+       qa4 = 1.26171219808761642112e-01  // 0x3FC02660E763351F
+       qa5 = 1.36370839120290507362e-02  // 0x3F8BEDC26B51DD1C
+       qa6 = 1.19844998467991074170e-02  // 0x3F888B545735151D
+       // Coefficients for approximation to  erfc in [1.25, 1/0.35]
+       ra0 = -9.86494403484714822705e-03 // 0xBF843412600D6435
+       ra1 = -6.93858572707181764372e-01 // 0xBFE63416E4BA7360
+       ra2 = -1.05586262253232909814e+01 // 0xC0251E0441B0E726
+       ra3 = -6.23753324503260060396e+01 // 0xC04F300AE4CBA38D
+       ra4 = -1.62396669462573470355e+02 // 0xC0644CB184282266
+       ra5 = -1.84605092906711035994e+02 // 0xC067135CEBCCABB2
+       ra6 = -8.12874355063065934246e+01 // 0xC054526557E4D2F2
+       ra7 = -9.81432934416914548592e+00 // 0xC023A0EFC69AC25C
+       sa1 = 1.96512716674392571292e+01  // 0x4033A6B9BD707687
+       sa2 = 1.37657754143519042600e+02  // 0x4061350C526AE721
+       sa3 = 4.34565877475229228821e+02  // 0x407B290DD58A1A71
+       sa4 = 6.45387271733267880336e+02  // 0x40842B1921EC2868
+       sa5 = 4.29008140027567833386e+02  // 0x407AD02157700314
+       sa6 = 1.08635005541779435134e+02  // 0x405B28A3EE48AE2C
+       sa7 = 6.57024977031928170135e+00  // 0x401A47EF8E484A93
+       sa8 = -6.04244152148580987438e-02 // 0xBFAEEFF2EE749A62
+       // Coefficients for approximation to  erfc in [1/.35, 28]
+       rb0 = -9.86494292470009928597e-03 // 0xBF84341239E86F4A
+       rb1 = -7.99283237680523006574e-01 // 0xBFE993BA70C285DE
+       rb2 = -1.77579549177547519889e+01 // 0xC031C209555F995A
+       rb3 = -1.60636384855821916062e+02 // 0xC064145D43C5ED98
+       rb4 = -6.37566443368389627722e+02 // 0xC083EC881375F228
+       rb5 = -1.02509513161107724954e+03 // 0xC09004616A2E5992
+       rb6 = -4.83519191608651397019e+02 // 0xC07E384E9BDC383F
+       sb1 = 3.03380607434824582924e+01  // 0x403E568B261D5190
+       sb2 = 3.25792512996573918826e+02  // 0x40745CAE221B9F0A
+       sb3 = 1.53672958608443695994e+03  // 0x409802EB189D5118
+       sb4 = 3.19985821950859553908e+03  // 0x40A8FFB7688C246A
+       sb5 = 2.55305040643316442583e+03  // 0x40A3F219CEDF3BE6
+       sb6 = 4.74528541206955367215e+02  // 0x407DA874E79FE763
+       sb7 = -2.24409524465858183362e+01 // 0xC03670E242712D62
+)
+
+// Erf(x) returns the error function of x.
+//
+// Special cases are:
+//     Erf(+Inf) = 1
+//     Erf(-Inf) = -1
+//     Erf(NaN) = NaN
+func Erf(x float64) float64 {
+       const (
+               VeryTiny = 2.848094538889218e-306 // 0x0080000000000000
+               Small    = 1.0 / (1 << 28)        // 2**-28
+       )
+       // special cases
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       switch {
+       case x != x: // IsNaN(x):
+               return NaN()
+       case x > MaxFloat64: // IsInf(x, 1):
+               return 1
+       case x < -MaxFloat64: // IsInf(x, -1):
+               return -1
+       }
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+       if x < 0.84375 { // |x| < 0.84375
+               var temp float64
+               if x < Small { // |x| < 2**-28
+                       if x < VeryTiny {
+                               temp = 0.125 * (8.0*x + efx8*x) // avoid underflow
+                       } else {
+                               temp = x + efx*x
+                       }
+               } else {
+                       z := x * x
+                       r := pp0 + z*(pp1+z*(pp2+z*(pp3+z*pp4)))
+                       s := 1 + z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))))
+                       y := r / s
+                       temp = x + x*y
+               }
+               if sign {
+                       return -temp
+               }
+               return temp
+       }
+       if x < 1.25 { // 0.84375 <= |x| < 1.25
+               s := x - 1
+               P := pa0 + s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))))
+               Q := 1 + s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))))
+               if sign {
+                       return -erx - P/Q
+               }
+               return erx + P/Q
+       }
+       if x >= 6 { // inf > |x| >= 6
+               if sign {
+                       return -1
+               }
+               return 1
+       }
+       s := 1 / (x * x)
+       var R, S float64
+       if x < 1/0.35 { // |x| < 1 / 0.35  ~ 2.857143
+               R = ra0 + s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(ra5+s*(ra6+s*ra7))))))
+               S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8)))))))
+       } else { // |x| >= 1 / 0.35  ~ 2.857143
+               R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
+               S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
+       }
+       z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+       r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
+       if sign {
+               return r/x - 1
+       }
+       return 1 - r/x
+}
+
+// Erfc(x) returns the complementary error function of x.
+//
+// Special cases are:
+//     Erfc(+Inf) = 0
+//     Erfc(-Inf) = 2
+//     Erfc(NaN) = NaN
+func Erfc(x float64) float64 {
+       const Tiny = 1.0 / (1 << 56) // 2**-56
+       // special cases
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       switch {
+       case x != x: // IsNaN(x):
+               return NaN()
+       case x > MaxFloat64: // IsInf(x, 1):
+               return 0
+       case x < -MaxFloat64: // IsInf(x, -1):
+               return 2
+       }
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+       if x < 0.84375 { // |x| < 0.84375
+               var temp float64
+               if x < Tiny { // |x| < 2**-56
+                       temp = x
+               } else {
+                       z := x * x
+                       r := pp0 + z*(pp1+z*(pp2+z*(pp3+z*pp4)))
+                       s := 1 + z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))))
+                       y := r / s
+                       if x < 0.25 { // |x| < 1/4
+                               temp = x + x*y
+                       } else {
+                               temp = 0.5 + (x*y + (x - 0.5))
+                       }
+               }
+               if sign {
+                       return 1 + temp
+               }
+               return 1 - temp
+       }
+       if x < 1.25 { // 0.84375 <= |x| < 1.25
+               s := x - 1
+               P := pa0 + s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))))
+               Q := 1 + s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))))
+               if sign {
+                       return 1 + erx + P/Q
+               }
+               return 1 - erx - P/Q
+
+       }
+       if x < 28 { // |x| < 28
+               s := 1 / (x * x)
+               var R, S float64
+               if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143
+                       R = ra0 + s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(ra5+s*(ra6+s*ra7))))))
+                       S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8)))))))
+               } else { // |x| >= 1 / 0.35 ~ 2.857143
+                       if sign && x > 6 {
+                               return 2 // x < -6
+                       }
+                       R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
+                       S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
+               }
+               z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+               r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
+               if sign {
+                       return 2 - r/x
+               }
+               return r / x
+       }
+       if sign {
+               return 2
+       }
+       return 0
+}
diff --git a/libgo/go/math/exp.go b/libgo/go/math/exp.go
new file mode 100644 (file)
index 0000000..90409c3
--- /dev/null
@@ -0,0 +1,141 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c
+// and came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+//
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// exp(x)
+// Returns the exponential of x.
+//
+// Method
+//   1. Argument reduction:
+//      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+//      Given x, find r and integer k such that
+//
+//               x = k*ln2 + r,  |r| <= 0.5*ln2.
+//
+//      Here r will be represented as r = hi-lo for better
+//      accuracy.
+//
+//   2. Approximation of exp(r) by a special rational function on
+//      the interval [0,0.34658]:
+//      Write
+//          R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+//      We use a special Remes algorithm on [0,0.34658] to generate
+//      a polynomial of degree 5 to approximate R. The maximum error
+//      of this polynomial approximation is bounded by 2**-59. In
+//      other words,
+//          R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+//      (where z=r*r, and the values of P1 to P5 are listed below)
+//      and
+//          |                  5          |     -59
+//          | 2.0+P1*z+...+P5*z   -  R(z) | <= 2
+//          |                             |
+//      The computation of exp(r) thus becomes
+//                             2*r
+//              exp(r) = 1 + -------
+//                            R - r
+//                                 r*R1(r)
+//                     = 1 + r + ----------- (for better accuracy)
+//                                2 - R1(r)
+//      where
+//                               2       4             10
+//              R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+//
+//   3. Scale back to obtain exp(x):
+//      From step 1, we have
+//         exp(x) = 2**k * exp(r)
+//
+// Special cases:
+//      exp(INF) is INF, exp(NaN) is NaN;
+//      exp(-INF) is 0, and
+//      for finite argument, only exp(0)=1 is exact.
+//
+// Accuracy:
+//      according to an error analysis, the error is always less than
+//      1 ulp (unit in the last place).
+//
+// Misc. info.
+//      For IEEE double
+//          if x >  7.09782712893383973096e+02 then exp(x) overflow
+//          if x < -7.45133219101941108420e+02 then exp(x) underflow
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+
+// Exp returns e**x, the base-e exponential of x.
+//
+// Special cases are:
+//     Exp(+Inf) = +Inf
+//     Exp(NaN) = NaN
+// Very large values overflow to 0 or +Inf.
+// Very small values underflow to 1.
+func Exp(x float64) float64 {
+       const (
+               Ln2Hi = 6.93147180369123816490e-01
+               Ln2Lo = 1.90821492927058770002e-10
+               Log2e = 1.44269504088896338700e+00
+               P1    = 1.66666666666666019037e-01  /* 0x3FC55555; 0x5555553E */
+               P2    = -2.77777777770155933842e-03 /* 0xBF66C16C; 0x16BEBD93 */
+               P3    = 6.61375632143793436117e-05  /* 0x3F11566A; 0xAF25DE2C */
+               P4    = -1.65339022054652515390e-06 /* 0xBEBBBD41; 0xC5D26BF1 */
+               P5    = 4.13813679705723846039e-08  /* 0x3E663769; 0x72BEA4D0 */
+
+               Overflow  = 7.09782712893383973096e+02
+               Underflow = -7.45133219101941108420e+02
+               NearZero  = 1.0 / (1 << 28) // 2**-28
+       )
+
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+               return x
+       case x < -MaxFloat64: // IsInf(x, -1):
+               return 0
+       case x > Overflow:
+               return Inf(1)
+       case x < Underflow:
+               return 0
+       case -NearZero < x && x < NearZero:
+               return 1
+       }
+
+       // reduce; computed as r = hi - lo for extra precision.
+       var k int
+       switch {
+       case x < 0:
+               k = int(Log2e*x - 0.5)
+       case x > 0:
+               k = int(Log2e*x + 0.5)
+       }
+       hi := x - float64(k)*Ln2Hi
+       lo := float64(k) * Ln2Lo
+       r := hi - lo
+
+       // compute
+       t := r * r
+       c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))))
+       y := 1 - ((lo - (r*c)/(2-c)) - hi)
+       // TODO(rsc): make sure Ldexp can handle boundary k
+       return Ldexp(y, k)
+}
diff --git a/libgo/go/math/exp2.go b/libgo/go/math/exp2.go
new file mode 100644 (file)
index 0000000..1e67f29
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Exp2 returns 2**x, the base-2 exponential of x.
+//
+// Special cases are the same as Exp.
+func Exp2(x float64) float64 { return Exp(x * Ln2) }
diff --git a/libgo/go/math/expm1.go b/libgo/go/math/expm1.go
new file mode 100644 (file)
index 0000000..35100ca
--- /dev/null
@@ -0,0 +1,238 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/s_expm1.c
+// and came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// expm1(x)
+// Returns exp(x)-1, the exponential of x minus 1.
+//
+// Method
+//   1. Argument reduction:
+//      Given x, find r and integer k such that
+//
+//               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658
+//
+//      Here a correction term c will be computed to compensate
+//      the error in r when rounded to a floating-point number.
+//
+//   2. Approximating expm1(r) by a special rational function on
+//      the interval [0,0.34658]:
+//      Since
+//          r*(exp(r)+1)/(exp(r)-1) = 2+ r**2/6 - r**4/360 + ...
+//      we define R1(r*r) by
+//          r*(exp(r)+1)/(exp(r)-1) = 2+ r**2/6 * R1(r*r)
+//      That is,
+//          R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+//                   = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+//                   = 1 - r**2/60 + r**4/2520 - r**6/100800 + ...
+//      We use a special Reme algorithm on [0,0.347] to generate
+//      a polynomial of degree 5 in r*r to approximate R1. The
+//      maximum error of this polynomial approximation is bounded
+//      by 2**-61. In other words,
+//          R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+//      where   Q1  =  -1.6666666666666567384E-2,
+//              Q2  =   3.9682539681370365873E-4,
+//              Q3  =  -9.9206344733435987357E-6,
+//              Q4  =   2.5051361420808517002E-7,
+//              Q5  =  -6.2843505682382617102E-9;
+//      (where z=r*r, and the values of Q1 to Q5 are listed below)
+//      with error bounded by
+//          |                  5           |     -61
+//          | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2
+//          |                              |
+//
+//      expm1(r) = exp(r)-1 is then computed by the following
+//      specific way which minimize the accumulation rounding error:
+//                             2     3
+//                            r     r    [ 3 - (R1 + R1*r/2)  ]
+//            expm1(r) = r + --- + --- * [--------------------]
+//                            2     2    [ 6 - r*(3 - R1*r/2) ]
+//
+//      To compensate the error in the argument reduction, we use
+//              expm1(r+c) = expm1(r) + c + expm1(r)*c
+//                         ~ expm1(r) + c + r*c
+//      Thus c+r*c will be added in as the correction terms for
+//      expm1(r+c). Now rearrange the term to avoid optimization
+//      screw up:
+//                      (      2                                    2 )
+//                      ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  )
+//       expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+//                      ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  )
+//                      (                                             )
+//
+//                 = r - E
+//   3. Scale back to obtain expm1(x):
+//      From step 1, we have
+//         expm1(x) = either 2**k*[expm1(r)+1] - 1
+//                  = or     2**k*[expm1(r) + (1-2**-k)]
+//   4. Implementation notes:
+//      (A). To save one multiplication, we scale the coefficient Qi
+//           to Qi*2**i, and replace z by (x**2)/2.
+//      (B). To achieve maximum accuracy, we compute expm1(x) by
+//        (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+//        (ii)  if k=0, return r-E
+//        (iii) if k=-1, return 0.5*(r-E)-0.5
+//        (iv)  if k=1 if r < -0.25, return 2*((r+0.5)- E)
+//                     else          return  1.0+2.0*(r-E);
+//        (v)   if (k<-2||k>56) return 2**k(1-(E-r)) - 1 (or exp(x)-1)
+//        (vi)  if k <= 20, return 2**k((1-2**-k)-(E-r)), else
+//        (vii) return 2**k(1-((E+2**-k)-r))
+//
+// Special cases:
+//      expm1(INF) is INF, expm1(NaN) is NaN;
+//      expm1(-INF) is -1, and
+//      for finite argument, only expm1(0)=0 is exact.
+//
+// Accuracy:
+//      according to an error analysis, the error is always less than
+//      1 ulp (unit in the last place).
+//
+// Misc. info.
+//      For IEEE double
+//          if x >  7.09782712893383973096e+02 then expm1(x) overflow
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+//
+
+// Expm1 returns e**x - 1, the base-e exponential of x minus 1.
+// It is more accurate than Exp(x) - 1 when x is near zero.
+//
+// Special cases are:
+//     Expm1(+Inf) = +Inf
+//     Expm1(-Inf) = -1
+//     Expm1(NaN) = NaN
+// Very large values overflow to -1 or +Inf.
+func Expm1(x float64) float64 {
+       const (
+               Othreshold = 7.09782712893383973096e+02 // 0x40862E42FEFA39EF
+               Ln2X56     = 3.88162421113569373274e+01 // 0x4043687a9f1af2b1
+               Ln2HalfX3  = 1.03972077083991796413e+00 // 0x3ff0a2b23f3bab73
+               Ln2Half    = 3.46573590279972654709e-01 // 0x3fd62e42fefa39ef
+               Ln2Hi      = 6.93147180369123816490e-01 // 0x3fe62e42fee00000
+               Ln2Lo      = 1.90821492927058770002e-10 // 0x3dea39ef35793c76
+               InvLn2     = 1.44269504088896338700e+00 // 0x3ff71547652b82fe
+               Tiny       = 1.0 / (1 << 54)            // 2**-54 = 0x3c90000000000000
+               // scaled coefficients related to expm1
+               Q1 = -3.33333333333331316428e-02 // 0xBFA11111111110F4
+               Q2 = 1.58730158725481460165e-03  // 0x3F5A01A019FE5585
+               Q3 = -7.93650757867487942473e-05 // 0xBF14CE199EAADBB7
+               Q4 = 4.00821782732936239552e-06  // 0x3ED0CFCA86E65239
+               Q5 = -2.01099218183624371326e-07 // 0xBE8AFDB76E09C32D
+       )
+
+       // special cases
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       switch {
+       case x > MaxFloat64 || x != x: // IsInf(x, 1) || IsNaN(x):
+               return x
+       case x < -MaxFloat64: // IsInf(x, -1):
+               return -1
+       }
+
+       absx := x
+       sign := false
+       if x < 0 {
+               absx = -absx
+               sign = true
+       }
+
+       // filter out huge argument
+       if absx >= Ln2X56 { // if |x| >= 56 * ln2
+               if absx >= Othreshold { // if |x| >= 709.78...
+                       return Inf(1) // overflow
+               }
+               if sign {
+                       return -1 // x < -56*ln2, return -1.0
+               }
+       }
+
+       // argument reduction
+       var c float64
+       var k int
+       if absx > Ln2Half { // if  |x| > 0.5 * ln2
+               var hi, lo float64
+               if absx < Ln2HalfX3 { // and |x| < 1.5 * ln2
+                       if !sign {
+                               hi = x - Ln2Hi
+                               lo = Ln2Lo
+                               k = 1
+                       } else {
+                               hi = x + Ln2Hi
+                               lo = -Ln2Lo
+                               k = -1
+                       }
+               } else {
+                       if !sign {
+                               k = int(InvLn2*x + 0.5)
+                       } else {
+                               k = int(InvLn2*x - 0.5)
+                       }
+                       t := float64(k)
+                       hi = x - t*Ln2Hi // t * Ln2Hi is exact here
+                       lo = t * Ln2Lo
+               }
+               x = hi - lo
+               c = (hi - x) - lo
+       } else if absx < Tiny { // when |x| < 2**-54, return x
+               return x
+       } else {
+               k = 0
+       }
+
+       // x is now in primary range
+       hfx := 0.5 * x
+       hxs := x * hfx
+       r1 := 1 + hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))))
+       t := 3 - r1*hfx
+       e := hxs * ((r1 - t) / (6.0 - x*t))
+       if k != 0 {
+               e = (x*(e-c) - c)
+               e -= hxs
+               switch {
+               case k == -1:
+                       return 0.5*(x-e) - 0.5
+               case k == 1:
+                       if x < -0.25 {
+                               return -2 * (e - (x + 0.5))
+                       }
+                       return 1 + 2*(x-e)
+               case k <= -2 || k > 56: // suffice to return exp(x)-1
+                       y := 1 - (e - x)
+                       y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
+                       return y - 1
+               }
+               if k < 20 {
+                       t := Float64frombits(0x3ff0000000000000 - (0x20000000000000 >> uint(k))) // t=1-2**-k
+                       y := t - (e - x)
+                       y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
+                       return y
+               }
+               t := Float64frombits(uint64((0x3ff - k) << 52)) // 2**-k
+               y := x - (e + t)
+               y += 1
+               y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
+               return y
+       }
+       return x - (x*e - hxs) // c is 0
+}
diff --git a/libgo/go/math/fabs.go b/libgo/go/math/fabs.go
new file mode 100644 (file)
index 0000000..3431231
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Fabs returns the absolute value of x.
+//
+// Special cases are:
+//     Fabs(+Inf) = +Inf
+//     Fabs(-Inf) = +Inf
+//     Fabs(NaN) = NaN
+func Fabs(x float64) float64 {
+       switch {
+       case x < 0:
+               return -x
+       case x == 0:
+               return 0 // return correctly fabs(-0)
+       }
+       return x
+}
diff --git a/libgo/go/math/fdim.go b/libgo/go/math/fdim.go
new file mode 100644 (file)
index 0000000..1899313
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Fdim returns the maximum of x-y or 0.
+func Fdim(x, y float64) float64 {
+       if x > y {
+               return x - y
+       }
+       return 0
+}
+
+// Fmax returns the larger of x or y.
+func Fmax(x, y float64) float64 {
+       if x > y {
+               return x
+       }
+       return y
+}
+
+// Fmin returns the smaller of x or y.
+func Fmin(x, y float64) float64 {
+       if x < y {
+               return x
+       }
+       return y
+}
diff --git a/libgo/go/math/floor.go b/libgo/go/math/floor.go
new file mode 100644 (file)
index 0000000..b22b94a
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2009-2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// Floor returns the greatest integer value less than or equal to x.
+//
+// Special cases are:
+//     Floor(+Inf) = +Inf
+//     Floor(-Inf) = -Inf
+//     Floor(NaN) = NaN
+func Floor(x float64) float64 {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+               return x
+       }
+       if x < 0 {
+               d, fract := Modf(-x)
+               if fract != 0.0 {
+                       d = d + 1
+               }
+               return -d
+       }
+       d, _ := Modf(x)
+       return d
+}
+
+// Ceil returns the least integer value greater than or equal to x.
+//
+// Special cases are:
+//     Ceil(+Inf) = +Inf
+//     Ceil(-Inf) = -Inf
+//     Ceil(NaN) = NaN
+func Ceil(x float64) float64 { return -Floor(-x) }
+
+// Trunc returns the integer value of x.
+//
+// Special cases are:
+//     Trunc(+Inf) = +Inf
+//     Trunc(-Inf) = -Inf
+//     Trunc(NaN) = NaN
+func Trunc(x float64) float64 {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+               return x
+       }
+       d, _ := Modf(x)
+       return d
+}
diff --git a/libgo/go/math/fmod.go b/libgo/go/math/fmod.go
new file mode 100644 (file)
index 0000000..fc57f74
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2009-2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+/*
+       Floating-point mod function.
+*/
+
+// Fmod returns the floating-point remainder of x/y.
+// The magnitude of the result is less than y and its
+// sign agrees with that of x.
+//
+// Special cases are:
+//     if x is not finite, Fmod returns NaN
+//     if y is 0 or NaN, Fmod returns NaN
+func Fmod(x, y float64) float64 {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us.
+       if y == 0 || x > MaxFloat64 || x < -MaxFloat64 || x != x || y != y { // y == 0 || IsInf(x, 0) || IsNaN(x) || IsNan(y)
+               return NaN()
+       }
+       if y < 0 {
+               y = -y
+       }
+
+       yfr, yexp := Frexp(y)
+       sign := false
+       r := x
+       if x < 0 {
+               r = -x
+               sign = true
+       }
+
+       for r >= y {
+               rfr, rexp := Frexp(r)
+               if rfr < yfr {
+                       rexp = rexp - 1
+               }
+               r = r - Ldexp(y, rexp-yexp)
+       }
+       if sign {
+               r = -r
+       }
+       return r
+}
diff --git a/libgo/go/math/frexp.go b/libgo/go/math/frexp.go
new file mode 100644 (file)
index 0000000..b63b508
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Frexp breaks f into a normalized fraction
+// and an integral power of two.
+// It returns frac and exp satisfying f == frac × 2**exp,
+// with the absolute value of frac in the interval [½, 1).
+func Frexp(f float64) (frac float64, exp int) {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case f == 0:
+               return f, 0 // correctly return -0
+       case f < -MaxFloat64 || f > MaxFloat64 || f != f: // IsInf(f, 0) || IsNaN(f):
+               return f, 0
+       }
+       x := Float64bits(f)
+       exp = int((x>>shift)&mask) - bias
+       x &^= mask << shift
+       x |= bias << shift
+       frac = Float64frombits(x)
+       return
+}
diff --git a/libgo/go/math/gamma.go b/libgo/go/math/gamma.go
new file mode 100644 (file)
index 0000000..4c5b17d
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/cprob/gamma.c.
+// The go code is a simplified version of the original C.
+//
+//      tgamma.c
+//
+//      Gamma function
+//
+// SYNOPSIS:
+//
+// double x, y, tgamma();
+// extern int signgam;
+//
+// y = tgamma( x );
+//
+// DESCRIPTION:
+//
+// Returns gamma function of the argument.  The result is
+// correctly signed, and the sign (+1 or -1) is also
+// returned in a global (extern) variable named signgam.
+// This variable is also filled in by the logarithmic gamma
+// function lgamma().
+//
+// Arguments |x| <= 34 are reduced by recurrence and the function
+// approximated by a rational function of degree 6/7 in the
+// interval (2,3).  Large arguments are handled by Stirling's
+// formula. Large negative arguments are made positive using
+// a reflection formula.
+//
+// ACCURACY:
+//
+//                      Relative error:
+// arithmetic   domain     # trials      peak         rms
+//    DEC      -34, 34      10000       1.3e-16     2.5e-17
+//    IEEE    -170,-33      20000       2.3e-15     3.3e-16
+//    IEEE     -33,  33     20000       9.4e-16     2.2e-16
+//    IEEE      33, 171.6   20000       2.3e-15     3.2e-16
+//
+// Error for arguments outside the test range will be larger
+// owing to error amplification by the exponential function.
+//
+// Cephes Math Library Release 2.8:  June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+//    Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+//   The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+//   Stephen L. Moshier
+//   moshier@na-net.ornl.gov
+
+var _P = []float64{
+       1.60119522476751861407e-04,
+       1.19135147006586384913e-03,
+       1.04213797561761569935e-02,
+       4.76367800457137231464e-02,
+       2.07448227648435975150e-01,
+       4.94214826801497100753e-01,
+       9.99999999999999996796e-01,
+}
+var _Q = []float64{
+       -2.31581873324120129819e-05,
+       5.39605580493303397842e-04,
+       -4.45641913851797240494e-03,
+       1.18139785222060435552e-02,
+       3.58236398605498653373e-02,
+       -2.34591795718243348568e-01,
+       7.14304917030273074085e-02,
+       1.00000000000000000320e+00,
+}
+var _S = []float64{
+       7.87311395793093628397e-04,
+       -2.29549961613378126380e-04,
+       -2.68132617805781232825e-03,
+       3.47222221605458667310e-03,
+       8.33333333333482257126e-02,
+}
+
+// Gamma function computed by Stirling's formula.
+// The polynomial is valid for 33 <= x <= 172.
+func stirling(x float64) float64 {
+       const (
+               SqrtTwoPi   = 2.506628274631000502417
+               MaxStirling = 143.01608
+       )
+       w := 1 / x
+       w = 1 + w*((((_S[0]*w+_S[1])*w+_S[2])*w+_S[3])*w+_S[4])
+       y := Exp(x)
+       if x > MaxStirling { // avoid Pow() overflow
+               v := Pow(x, 0.5*x-0.25)
+               y = v * (v / y)
+       } else {
+               y = Pow(x, x-0.5) / y
+       }
+       y = SqrtTwoPi * y * w
+       return y
+}
+
+// Gamma(x) returns the Gamma function of x.
+//
+// Special cases are:
+//     Gamma(Inf) = Inf
+//     Gamma(-Inf) = -Inf
+//     Gamma(NaN) = NaN
+// Large values overflow to +Inf.
+// Negative integer values equal ±Inf.
+func Gamma(x float64) float64 {
+       const Euler = 0.57721566490153286060651209008240243104215933593992 // A001620
+       // special cases
+       switch {
+       case x < -MaxFloat64 || x != x: // IsInf(x, -1) || IsNaN(x):
+               return x
+       case x < -170.5674972726612 || x > 171.61447887182298:
+               return Inf(1)
+       }
+       q := Fabs(x)
+       p := Floor(q)
+       if q > 33 {
+               if x >= 0 {
+                       return stirling(x)
+               }
+               signgam := 1
+               if ip := int(p); ip&1 == 0 {
+                       signgam = -1
+               }
+               z := q - p
+               if z > 0.5 {
+                       p = p + 1
+                       z = q - p
+               }
+               z = q * Sin(Pi*z)
+               if z == 0 {
+                       return Inf(signgam)
+               }
+               z = Pi / (Fabs(z) * stirling(q))
+               return float64(signgam) * z
+       }
+
+       // Reduce argument
+       z := float64(1)
+       for x >= 3 {
+               x = x - 1
+               z = z * x
+       }
+       for x < 0 {
+               if x > -1e-09 {
+                       goto small
+               }
+               z = z / x
+               x = x + 1
+       }
+       for x < 2 {
+               if x < 1e-09 {
+                       goto small
+               }
+               z = z / x
+               x = x + 1
+       }
+
+       if x == 2 {
+               return z
+       }
+
+       x = x - 2
+       p = (((((x*_P[0]+_P[1])*x+_P[2])*x+_P[3])*x+_P[4])*x+_P[5])*x + _P[6]
+       q = ((((((x*_Q[0]+_Q[1])*x+_Q[2])*x+_Q[3])*x+_Q[4])*x+_Q[5])*x+_Q[6])*x + _Q[7]
+       return z * p / q
+
+small:
+       if x == 0 {
+               return Inf(1)
+       }
+       return z / ((1 + Euler*x) * x)
+}
diff --git a/libgo/go/math/hypot.go b/libgo/go/math/hypot.go
new file mode 100644 (file)
index 0000000..ecd115d
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       Hypot -- sqrt(p*p + q*q), but overflows only if the result does.
+*/
+
+// Hypot computes Sqrt(p*p + q*q), taking care to avoid
+// unnecessary overflow and underflow.
+//
+// Special cases are:
+//     Hypot(p, q) = +Inf if p or q is infinite
+//     Hypot(p, q) = NaN if p or q is NaN
+func Hypot(p, q float64) float64 {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case p < -MaxFloat64 || p > MaxFloat64 || q < -MaxFloat64 || q > MaxFloat64: // IsInf(p, 0) || IsInf(q, 0):
+               return Inf(1)
+       case p != p || q != q: // IsNaN(p) || IsNaN(q):
+               return NaN()
+       }
+       if p < 0 {
+               p = -p
+       }
+       if q < 0 {
+               q = -q
+       }
+       if p < q {
+               p, q = q, p
+       }
+       if p == 0 {
+               return 0
+       }
+       q = q / p
+       return p * Sqrt(1+q*q)
+}
diff --git a/libgo/go/math/hypot_port.go b/libgo/go/math/hypot_port.go
new file mode 100644 (file)
index 0000000..27f335b
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright 2009-2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       Hypot -- sqrt(p*p + q*q), but overflows only if the result does.
+       See:
+               Cleve Moler and Donald Morrison,
+               Replacing Square Roots by Pythagorean Sums
+               IBM Journal of Research and Development,
+               Vol. 27, Number 6, pp. 577-581, Nov. 1983
+*/
+
+// Hypot computes Sqrt(p*p + q*q), taking care to avoid
+// unnecessary overflow and underflow.
+//
+// Special cases are:
+//     Hypot(p, q) = +Inf if p or q is infinite
+//     Hypot(p, q) = NaN if p or q is NaN
+func hypotGo(p, q float64) float64 {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case p < -MaxFloat64 || p > MaxFloat64 || q < -MaxFloat64 || q > MaxFloat64: // IsInf(p, 0) || IsInf(q, 0):
+               return Inf(1)
+       case p != p || q != q: // IsNaN(p) || IsNaN(q):
+               return NaN()
+       }
+       if p < 0 {
+               p = -p
+       }
+       if q < 0 {
+               q = -q
+       }
+
+       if p < q {
+               p, q = q, p
+       }
+
+       if p == 0 {
+               return 0
+       }
+
+       pfac := p
+       q = q / p
+       r := q
+       p = 1
+       for {
+               r = r * r
+               s := r + 4
+               if s == 4 {
+                       return p * pfac
+               }
+               r = r / s
+               p = p + 2*r*p
+               q = q * r
+               r = q / p
+       }
+       panic("unreachable")
+}
diff --git a/libgo/go/math/hypot_test.go b/libgo/go/math/hypot_test.go
new file mode 100644 (file)
index 0000000..85ce1d4
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Make hypotGo available for testing.
+
+func HypotGo(x, y float64) float64 { return hypotGo(x, y) }
diff --git a/libgo/go/math/j0.go b/libgo/go/math/j0.go
new file mode 100644 (file)
index 0000000..5aaf4ab
--- /dev/null
@@ -0,0 +1,433 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       Bessel function of the first and second kinds of order zero.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_j0.c and
+// came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_j0(x), __ieee754_y0(x)
+// Bessel function of the first and second kinds of order zero.
+// Method -- j0(x):
+//      1. For tiny x, we use j0(x) = 1 - x**2/4 + x**4/64 - ...
+//      2. Reduce x to |x| since j0(x)=j0(-x),  and
+//         for x in (0,2)
+//              j0(x) = 1-z/4+ z**2*R0/S0,  where z = x*x;
+//         (precision:  |j0-1+z/4-z**2R0/S0 |<2**-63.67 )
+//         for x in (2,inf)
+//              j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+//         where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+//         as follow:
+//              cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+//                      = 1/sqrt(2) * (cos(x) + sin(x))
+//              sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+//                      = 1/sqrt(2) * (sin(x) - cos(x))
+//         (To avoid cancellation, use
+//              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+//         to compute the worse one.)
+//
+//      3 Special cases
+//              j0(nan)= nan
+//              j0(0) = 1
+//              j0(inf) = 0
+//
+// Method -- y0(x):
+//      1. For x<2.
+//         Since
+//              y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x**2/4 - ...)
+//         therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+//         We use the following function to approximate y0,
+//              y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x**2
+//         where
+//              U(z) = u00 + u01*z + ... + u06*z**6
+//              V(z) = 1  + v01*z + ... + v04*z**4
+//         with absolute approximation error bounded by 2**-72.
+//         Note: For tiny x, U/V = u0 and j0(x)~1, hence
+//              y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+//      2. For x>=2.
+//              y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+//         where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+//         by the method mentioned above.
+//      3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+//
+
+// J0 returns the order-zero Bessel function of the first kind.
+//
+// Special cases are:
+//     J0(±Inf) = 0
+//     J0(0) = 1
+//     J0(NaN) = NaN
+func J0(x float64) float64 {
+       const (
+               Huge   = 1e300
+               TwoM27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000
+               TwoM13 = 1.0 / (1 << 13) // 2**-13 0x3f20000000000000
+               Two129 = 1 << 129        // 2**129 0x4800000000000000
+               // R0/S0 on [0, 2]
+               R02 = 1.56249999999999947958e-02  // 0x3F8FFFFFFFFFFFFD
+               R03 = -1.89979294238854721751e-04 // 0xBF28E6A5B61AC6E9
+               R04 = 1.82954049532700665670e-06  // 0x3EBEB1D10C503919
+               R05 = -4.61832688532103189199e-09 // 0xBE33D5E773D63FCE
+               S01 = 1.56191029464890010492e-02  // 0x3F8FFCE882C8C2A4
+               S02 = 1.16926784663337450260e-04  // 0x3F1EA6D2DD57DBF4
+               S03 = 5.13546550207318111446e-07  // 0x3EA13B54CE84D5A9
+               S04 = 1.16614003333790000205e-09  // 0x3E1408BCF4745D8F
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x != x: // IsNaN(x)
+               return x
+       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+               return 0
+       case x == 0:
+               return 1
+       }
+
+       if x < 0 {
+               x = -x
+       }
+       if x >= 2 {
+               s, c := Sincos(x)
+               ss := s - c
+               cc := s + c
+
+               // make sure x+x does not overflow
+               if x < MaxFloat64/2 {
+                       z := -Cos(x + x)
+                       if s*c < 0 {
+                               cc = z / ss
+                       } else {
+                               ss = z / cc
+                       }
+               }
+
+               // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+               // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+
+               var z float64
+               if x > Two129 { // |x| > ~6.8056e+38
+                       z = (1 / SqrtPi) * cc / Sqrt(x)
+               } else {
+                       u := pzero(x)
+                       v := qzero(x)
+                       z = (1 / SqrtPi) * (u*cc - v*ss) / Sqrt(x)
+               }
+               return z // |x| >= 2.0
+       }
+       if x < TwoM13 { // |x| < ~1.2207e-4
+               if x < TwoM27 {
+                       return 1 // |x| < ~7.4506e-9
+               }
+               return 1 - 0.25*x*x // ~7.4506e-9 < |x| < ~1.2207e-4
+       }
+       z := x * x
+       r := z * (R02 + z*(R03+z*(R04+z*R05)))
+       s := 1 + z*(S01+z*(S02+z*(S03+z*S04)))
+       if x < 1 {
+               return 1 + z*(-0.25+(r/s)) // |x| < 1.00
+       }
+       u := 0.5 * x
+       return (1+u)*(1-u) + z*(r/s) // 1.0 < |x| < 2.0
+}
+
+// Y0 returns the order-zero Bessel function of the second kind.
+//
+// Special cases are:
+//     Y0(+Inf) = 0
+//     Y0(0) = -Inf
+//     Y0(x < 0) = NaN
+//     Y0(NaN) = NaN
+func Y0(x float64) float64 {
+       const (
+               TwoM27 = 1.0 / (1 << 27)             // 2**-27 0x3e40000000000000
+               Two129 = 1 << 129                    // 2**129 0x4800000000000000
+               U00    = -7.38042951086872317523e-02 // 0xBFB2E4D699CBD01F
+               U01    = 1.76666452509181115538e-01  // 0x3FC69D019DE9E3FC
+               U02    = -1.38185671945596898896e-02 // 0xBF8C4CE8B16CFA97
+               U03    = 3.47453432093683650238e-04  // 0x3F36C54D20B29B6B
+               U04    = -3.81407053724364161125e-06 // 0xBECFFEA773D25CAD
+               U05    = 1.95590137035022920206e-08  // 0x3E5500573B4EABD4
+               U06    = -3.98205194132103398453e-11 // 0xBDC5E43D693FB3C8
+               V01    = 1.27304834834123699328e-02  // 0x3F8A127091C9C71A
+               V02    = 7.60068627350353253702e-05  // 0x3F13ECBBF578C6C1
+               V03    = 2.59150851840457805467e-07  // 0x3E91642D7FF202FD
+               V04    = 4.41110311332675467403e-10  // 0x3DFE50183BD6D9EF
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x < 0 || x != x: // x < 0 || IsNaN(x):
+               return NaN()
+       case x > MaxFloat64: // IsInf(x, 1):
+               return 0
+       case x == 0:
+               return Inf(-1)
+       }
+
+       if x >= 2 { // |x| >= 2.0
+
+               // y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+               //     where x0 = x-pi/4
+               // Better formula:
+               //     cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+               //             =  1/sqrt(2) * (sin(x) + cos(x))
+               //     sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+               //             =  1/sqrt(2) * (sin(x) - cos(x))
+               // To avoid cancellation, use
+               //     sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+               // to compute the worse one.
+
+               s, c := Sincos(x)
+               ss := s - c
+               cc := s + c
+
+               // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+               // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+
+               // make sure x+x does not overflow
+               if x < MaxFloat64/2 {
+                       z := -Cos(x + x)
+                       if s*c < 0 {
+                               cc = z / ss
+                       } else {
+                               ss = z / cc
+                       }
+               }
+               var z float64
+               if x > Two129 { // |x| > ~6.8056e+38
+                       z = (1 / SqrtPi) * ss / Sqrt(x)
+               } else {
+                       u := pzero(x)
+                       v := qzero(x)
+                       z = (1 / SqrtPi) * (u*ss + v*cc) / Sqrt(x)
+               }
+               return z // |x| >= 2.0
+       }
+       if x <= TwoM27 {
+               return U00 + (2/Pi)*Log(x) // |x| < ~7.4506e-9
+       }
+       z := x * x
+       u := U00 + z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06)))))
+       v := 1 + z*(V01+z*(V02+z*(V03+z*V04)))
+       return u/v + (2/Pi)*J0(x)*Log(x) // ~7.4506e-9 < |x| < 2.0
+}
+
+// The asymptotic expansions of pzero is
+//      1 - 9/128 s**2 + 11025/98304 s**4 - ..., where s = 1/x.
+// For x >= 2, We approximate pzero by
+//     pzero(x) = 1 + (R/S)
+// where  R = pR0 + pR1*s**2 + pR2*s**4 + ... + pR5*s**10
+//       S = 1 + pS0*s**2 + ... + pS4*s**10
+// and
+//      | pzero(x)-1-R/S | <= 2  ** ( -60.26)
+
+// for x in [inf, 8]=1/[0,0.125]
+var p0R8 = [6]float64{
+       0.00000000000000000000e+00,  // 0x0000000000000000
+       -7.03124999999900357484e-02, // 0xBFB1FFFFFFFFFD32
+       -8.08167041275349795626e+00, // 0xC02029D0B44FA779
+       -2.57063105679704847262e+02, // 0xC07011027B19E863
+       -2.48521641009428822144e+03, // 0xC0A36A6ECD4DCAFC
+       -5.25304380490729545272e+03, // 0xC0B4850B36CC643D
+}
+var p0S8 = [5]float64{
+       1.16534364619668181717e+02, // 0x405D223307A96751
+       3.83374475364121826715e+03, // 0x40ADF37D50596938
+       4.05978572648472545552e+04, // 0x40E3D2BB6EB6B05F
+       1.16752972564375915681e+05, // 0x40FC810F8F9FA9BD
+       4.76277284146730962675e+04, // 0x40E741774F2C49DC
+}
+
+// for x in [8,4.5454]=1/[0.125,0.22001]
+var p0R5 = [6]float64{
+       -1.14125464691894502584e-11, // 0xBDA918B147E495CC
+       -7.03124940873599280078e-02, // 0xBFB1FFFFE69AFBC6
+       -4.15961064470587782438e+00, // 0xC010A370F90C6BBF
+       -6.76747652265167261021e+01, // 0xC050EB2F5A7D1783
+       -3.31231299649172967747e+02, // 0xC074B3B36742CC63
+       -3.46433388365604912451e+02, // 0xC075A6EF28A38BD7
+}
+var p0S5 = [5]float64{
+       6.07539382692300335975e+01, // 0x404E60810C98C5DE
+       1.05125230595704579173e+03, // 0x40906D025C7E2864
+       5.97897094333855784498e+03, // 0x40B75AF88FBE1D60
+       9.62544514357774460223e+03, // 0x40C2CCB8FA76FA38
+       2.40605815922939109441e+03, // 0x40A2CC1DC70BE864
+}
+
+// for x in [4.547,2.8571]=1/[0.2199,0.35001]
+var p0R3 = [6]float64{
+       -2.54704601771951915620e-09, // 0xBE25E1036FE1AA86
+       -7.03119616381481654654e-02, // 0xBFB1FFF6F7C0E24B
+       -2.40903221549529611423e+00, // 0xC00345B2AEA48074
+       -2.19659774734883086467e+01, // 0xC035F74A4CB94E14
+       -5.80791704701737572236e+01, // 0xC04D0A22420A1A45
+       -3.14479470594888503854e+01, // 0xC03F72ACA892D80F
+}
+var p0S3 = [5]float64{
+       3.58560338055209726349e+01, // 0x4041ED9284077DD3
+       3.61513983050303863820e+02, // 0x40769839464A7C0E
+       1.19360783792111533330e+03, // 0x4092A66E6D1061D6
+       1.12799679856907414432e+03, // 0x40919FFCB8C39B7E
+       1.73580930813335754692e+02, // 0x4065B296FC379081
+}
+
+// for x in [2.8570,2]=1/[0.3499,0.5]
+var p0R2 = [6]float64{
+       -8.87534333032526411254e-08, // 0xBE77D316E927026D
+       -7.03030995483624743247e-02, // 0xBFB1FF62495E1E42
+       -1.45073846780952986357e+00, // 0xBFF736398A24A843
+       -7.63569613823527770791e+00, // 0xC01E8AF3EDAFA7F3
+       -1.11931668860356747786e+01, // 0xC02662E6C5246303
+       -3.23364579351335335033e+00, // 0xC009DE81AF8FE70F
+}
+var p0S2 = [5]float64{
+       2.22202997532088808441e+01, // 0x40363865908B5959
+       1.36206794218215208048e+02, // 0x4061069E0EE8878F
+       2.70470278658083486789e+02, // 0x4070E78642EA079B
+       1.53875394208320329881e+02, // 0x40633C033AB6FAFF
+       1.46576176948256193810e+01, // 0x402D50B344391809
+}
+
+func pzero(x float64) float64 {
+       var p [6]float64
+       var q [5]float64
+       if x >= 8 {
+               p = p0R8
+               q = p0S8
+       } else if x >= 4.5454 {
+               p = p0R5
+               q = p0S5
+       } else if x >= 2.8571 {
+               p = p0R3
+               q = p0S3
+       } else if x >= 2 {
+               p = p0R2
+               q = p0S2
+       }
+       z := 1 / (x * x)
+       r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+       s := 1 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))))
+       return 1 + r/s
+}
+
+// For x >= 8, the asymptotic expansions of qzero is
+//      -1/8 s + 75/1024 s**3 - ..., where s = 1/x.
+// We approximate pzero by
+//      qzero(x) = s*(-1.25 + (R/S))
+// where R = qR0 + qR1*s**2 + qR2*s**4 + ... + qR5*s**10
+//       S = 1 + qS0*s**2 + ... + qS5*s**12
+// and
+//      | qzero(x)/s +1.25-R/S | <= 2**(-61.22)
+
+// for x in [inf, 8]=1/[0,0.125]
+var q0R8 = [6]float64{
+       0.00000000000000000000e+00, // 0x0000000000000000
+       7.32421874999935051953e-02, // 0x3FB2BFFFFFFFFE2C
+       1.17682064682252693899e+01, // 0x402789525BB334D6
+       5.57673380256401856059e+02, // 0x40816D6315301825
+       8.85919720756468632317e+03, // 0x40C14D993E18F46D
+       3.70146267776887834771e+04, // 0x40E212D40E901566
+}
+var q0S8 = [6]float64{
+       1.63776026895689824414e+02,  // 0x406478D5365B39BC
+       8.09834494656449805916e+03,  // 0x40BFA2584E6B0563
+       1.42538291419120476348e+05,  // 0x4101665254D38C3F
+       8.03309257119514397345e+05,  // 0x412883DA83A52B43
+       8.40501579819060512818e+05,  // 0x4129A66B28DE0B3D
+       -3.43899293537866615225e+05, // 0xC114FD6D2C9530C5
+}
+
+// for x in [8,4.5454]=1/[0.125,0.22001]
+var q0R5 = [6]float64{
+       1.84085963594515531381e-11, // 0x3DB43D8F29CC8CD9
+       7.32421766612684765896e-02, // 0x3FB2BFFFD172B04C
+       5.83563508962056953777e+00, // 0x401757B0B9953DD3
+       1.35111577286449829671e+02, // 0x4060E3920A8788E9
+       1.02724376596164097464e+03, // 0x40900CF99DC8C481
+       1.98997785864605384631e+03, // 0x409F17E953C6E3A6
+}
+var q0S5 = [6]float64{
+       8.27766102236537761883e+01,  // 0x4054B1B3FB5E1543
+       2.07781416421392987104e+03,  // 0x40A03BA0DA21C0CE
+       1.88472887785718085070e+04,  // 0x40D267D27B591E6D
+       5.67511122894947329769e+04,  // 0x40EBB5E397E02372
+       3.59767538425114471465e+04,  // 0x40E191181F7A54A0
+       -5.35434275601944773371e+03, // 0xC0B4EA57BEDBC609
+}
+
+// for x in [4.547,2.8571]=1/[0.2199,0.35001]
+var q0R3 = [6]float64{
+       4.37741014089738620906e-09, // 0x3E32CD036ADECB82
+       7.32411180042911447163e-02, // 0x3FB2BFEE0E8D0842
+       3.34423137516170720929e+00, // 0x400AC0FC61149CF5
+       4.26218440745412650017e+01, // 0x40454F98962DAEDD
+       1.70808091340565596283e+02, // 0x406559DBE25EFD1F
+       1.66733948696651168575e+02, // 0x4064D77C81FA21E0
+}
+var q0S3 = [6]float64{
+       4.87588729724587182091e+01,  // 0x40486122BFE343A6
+       7.09689221056606015736e+02,  // 0x40862D8386544EB3
+       3.70414822620111362994e+03,  // 0x40ACF04BE44DFC63
+       6.46042516752568917582e+03,  // 0x40B93C6CD7C76A28
+       2.51633368920368957333e+03,  // 0x40A3A8AAD94FB1C0
+       -1.49247451836156386662e+02, // 0xC062A7EB201CF40F
+}
+
+// for x in [2.8570,2]=1/[0.3499,0.5]
+var q0R2 = [6]float64{
+       1.50444444886983272379e-07, // 0x3E84313B54F76BDB
+       7.32234265963079278272e-02, // 0x3FB2BEC53E883E34
+       1.99819174093815998816e+00, // 0x3FFFF897E727779C
+       1.44956029347885735348e+01, // 0x402CFDBFAAF96FE5
+       3.16662317504781540833e+01, // 0x403FAA8E29FBDC4A
+       1.62527075710929267416e+01, // 0x403040B171814BB4
+}
+var q0S2 = [6]float64{
+       3.03655848355219184498e+01,  // 0x403E5D96F7C07AED
+       2.69348118608049844624e+02,  // 0x4070D591E4D14B40
+       8.44783757595320139444e+02,  // 0x408A664522B3BF22
+       8.82935845112488550512e+02,  // 0x408B977C9C5CC214
+       2.12666388511798828631e+02,  // 0x406A95530E001365
+       -5.31095493882666946917e+00, // 0xC0153E6AF8B32931
+}
+
+func qzero(x float64) float64 {
+       var p, q [6]float64
+       if x >= 8 {
+               p = q0R8
+               q = q0S8
+       } else if x >= 4.5454 {
+               p = q0R5
+               q = q0S5
+       } else if x >= 2.8571 {
+               p = q0R3
+               q = q0S3
+       } else if x >= 2 {
+               p = q0R2
+               q = q0S2
+       }
+       z := 1 / (x * x)
+       r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+       s := 1 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))))
+       return (-0.125 + r/s) / x
+}
diff --git a/libgo/go/math/j1.go b/libgo/go/math/j1.go
new file mode 100644 (file)
index 0000000..278162e
--- /dev/null
@@ -0,0 +1,426 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       Bessel function of the first and second kinds of order one.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_j1.c and
+// came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_j1(x), __ieee754_y1(x)
+// Bessel function of the first and second kinds of order one.
+// Method -- j1(x):
+//      1. For tiny x, we use j1(x) = x/2 - x**3/16 + x**5/384 - ...
+//      2. Reduce x to |x| since j1(x)=-j1(-x),  and
+//         for x in (0,2)
+//              j1(x) = x/2 + x*z*R0/S0,  where z = x*x;
+//         (precision:  |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+//         for x in (2,inf)
+//              j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+//              y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+//         where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+//         as follow:
+//              cos(x1) =  cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+//                      =  1/sqrt(2) * (sin(x) - cos(x))
+//              sin(x1) =  sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+//                      = -1/sqrt(2) * (sin(x) + cos(x))
+//         (To avoid cancellation, use
+//              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+//         to compute the worse one.)
+//
+//      3 Special cases
+//              j1(nan)= nan
+//              j1(0) = 0
+//              j1(inf) = 0
+//
+// Method -- y1(x):
+//      1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN
+//      2. For x<2.
+//         Since
+//              y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x**3-...)
+//         therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+//         We use the following function to approximate y1,
+//              y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x**2
+//         where for x in [0,2] (abs err less than 2**-65.89)
+//              U(z) = U0[0] + U0[1]*z + ... + U0[4]*z**4
+//              V(z) = 1  + v0[0]*z + ... + v0[4]*z**5
+//         Note: For tiny x, 1/x dominate y1 and hence
+//              y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+//      3. For x>=2.
+//               y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+//         where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+//         by method mentioned above.
+
+// J1 returns the order-one Bessel function of the first kind.
+//
+// Special cases are:
+//     J1(±Inf) = 0
+//     J1(NaN) = NaN
+func J1(x float64) float64 {
+       const (
+               TwoM27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000
+               Two129 = 1 << 129        // 2**129 0x4800000000000000
+               // R0/S0 on [0, 2]
+               R00 = -6.25000000000000000000e-02 // 0xBFB0000000000000
+               R01 = 1.40705666955189706048e-03  // 0x3F570D9F98472C61
+               R02 = -1.59955631084035597520e-05 // 0xBEF0C5C6BA169668
+               R03 = 4.96727999609584448412e-08  // 0x3E6AAAFA46CA0BD9
+               S01 = 1.91537599538363460805e-02  // 0x3F939D0B12637E53
+               S02 = 1.85946785588630915560e-04  // 0x3F285F56B9CDF664
+               S03 = 1.17718464042623683263e-06  // 0x3EB3BFF8333F8498
+               S04 = 5.04636257076217042715e-09  // 0x3E35AC88C97DFF2C
+               S05 = 1.23542274426137913908e-11  // 0x3DAB2ACFCFB97ED8
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x != x: // IsNaN(x)
+               return x
+       case x < -MaxFloat64 || x > MaxFloat64 || x == 0: // IsInf(x, 0) || x == 0:
+               return 0
+       }
+
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+       if x >= 2 {
+               s, c := Sincos(x)
+               ss := -s - c
+               cc := s - c
+
+               // make sure x+x does not overflow
+               if x < MaxFloat64/2 {
+                       z := Cos(x + x)
+                       if s*c > 0 {
+                               cc = z / ss
+                       } else {
+                               ss = z / cc
+                       }
+               }
+
+               // j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+               // y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+
+               var z float64
+               if x > Two129 {
+                       z = (1 / SqrtPi) * cc / Sqrt(x)
+               } else {
+                       u := pone(x)
+                       v := qone(x)
+                       z = (1 / SqrtPi) * (u*cc - v*ss) / Sqrt(x)
+               }
+               if sign {
+                       return -z
+               }
+               return z
+       }
+       if x < TwoM27 { // |x|<2**-27
+               return 0.5 * x // inexact if x!=0 necessary
+       }
+       z := x * x
+       r := z * (R00 + z*(R01+z*(R02+z*R03)))
+       s := 1.0 + z*(S01+z*(S02+z*(S03+z*(S04+z*S05))))
+       r *= x
+       z = 0.5*x + r/s
+       if sign {
+               return -z
+       }
+       return z
+}
+
+// Y1 returns the order-one Bessel function of the second kind.
+//
+// Special cases are:
+//     Y1(+Inf) = 0
+//     Y1(0) = -Inf
+//     Y1(x < 0) = NaN
+//     Y1(NaN) = NaN
+func Y1(x float64) float64 {
+       const (
+               TwoM54 = 1.0 / (1 << 54)             // 2**-54 0x3c90000000000000
+               Two129 = 1 << 129                    // 2**129 0x4800000000000000
+               U00    = -1.96057090646238940668e-01 // 0xBFC91866143CBC8A
+               U01    = 5.04438716639811282616e-02  // 0x3FA9D3C776292CD1
+               U02    = -1.91256895875763547298e-03 // 0xBF5F55E54844F50F
+               U03    = 2.35252600561610495928e-05  // 0x3EF8AB038FA6B88E
+               U04    = -9.19099158039878874504e-08 // 0xBE78AC00569105B8
+               V00    = 1.99167318236649903973e-02  // 0x3F94650D3F4DA9F0
+               V01    = 2.02552581025135171496e-04  // 0x3F2A8C896C257764
+               V02    = 1.35608801097516229404e-06  // 0x3EB6C05A894E8CA6
+               V03    = 6.22741452364621501295e-09  // 0x3E3ABF1D5BA69A86
+               V04    = 1.66559246207992079114e-11  // 0x3DB25039DACA772A
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x < 0 || x != x: // x < 0 || IsNaN(x):
+               return NaN()
+       case x > MaxFloat64: // IsInf(x, 1):
+               return 0
+       case x == 0:
+               return Inf(-1)
+       }
+
+       if x >= 2 {
+               s, c := Sincos(x)
+               ss := -s - c
+               cc := s - c
+
+               // make sure x+x does not overflow
+               if x < MaxFloat64/2 {
+                       z := Cos(x + x)
+                       if s*c > 0 {
+                               cc = z / ss
+                       } else {
+                               ss = z / cc
+                       }
+               }
+               // y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+               // where x0 = x-3pi/4
+               //     Better formula:
+               //         cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+               //                 =  1/sqrt(2) * (sin(x) - cos(x))
+               //         sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+               //                 = -1/sqrt(2) * (cos(x) + sin(x))
+               // To avoid cancellation, use
+               //     sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+               // to compute the worse one.
+
+               var z float64
+               if x > Two129 {
+                       z = (1 / SqrtPi) * ss / Sqrt(x)
+               } else {
+                       u := pone(x)
+                       v := qone(x)
+                       z = (1 / SqrtPi) * (u*ss + v*cc) / Sqrt(x)
+               }
+               return z
+       }
+       if x <= TwoM54 { // x < 2**-54
+               return -(2 / Pi) / x
+       }
+       z := x * x
+       u := U00 + z*(U01+z*(U02+z*(U03+z*U04)))
+       v := 1 + z*(V00+z*(V01+z*(V02+z*(V03+z*V04))))
+       return x*(u/v) + (2/Pi)*(J1(x)*Log(x)-1/x)
+}
+
+// For x >= 8, the asymptotic expansions of pone is
+//      1 + 15/128 s**2 - 4725/2**15 s**4 - ..., where s = 1/x.
+// We approximate pone by
+//      pone(x) = 1 + (R/S)
+// where R = pr0 + pr1*s**2 + pr2*s**4 + ... + pr5*s**10
+//       S = 1 + ps0*s**2 + ... + ps4*s**10
+// and
+//      | pone(x)-1-R/S | <= 2**(-60.06)
+
+// for x in [inf, 8]=1/[0,0.125]
+var p1R8 = [6]float64{
+       0.00000000000000000000e+00, // 0x0000000000000000
+       1.17187499999988647970e-01, // 0x3FBDFFFFFFFFFCCE
+       1.32394806593073575129e+01, // 0x402A7A9D357F7FCE
+       4.12051854307378562225e+02, // 0x4079C0D4652EA590
+       3.87474538913960532227e+03, // 0x40AE457DA3A532CC
+       7.91447954031891731574e+03, // 0x40BEEA7AC32782DD
+}
+var p1S8 = [5]float64{
+       1.14207370375678408436e+02, // 0x405C8D458E656CAC
+       3.65093083420853463394e+03, // 0x40AC85DC964D274F
+       3.69562060269033463555e+04, // 0x40E20B8697C5BB7F
+       9.76027935934950801311e+04, // 0x40F7D42CB28F17BB
+       3.08042720627888811578e+04, // 0x40DE1511697A0B2D
+}
+
+// for x in [8,4.5454] = 1/[0.125,0.22001]
+var p1R5 = [6]float64{
+       1.31990519556243522749e-11, // 0x3DAD0667DAE1CA7D
+       1.17187493190614097638e-01, // 0x3FBDFFFFE2C10043
+       6.80275127868432871736e+00, // 0x401B36046E6315E3
+       1.08308182990189109773e+02, // 0x405B13B9452602ED
+       5.17636139533199752805e+02, // 0x40802D16D052D649
+       5.28715201363337541807e+02, // 0x408085B8BB7E0CB7
+}
+var p1S5 = [5]float64{
+       5.92805987221131331921e+01, // 0x404DA3EAA8AF633D
+       9.91401418733614377743e+02, // 0x408EFB361B066701
+       5.35326695291487976647e+03, // 0x40B4E9445706B6FB
+       7.84469031749551231769e+03, // 0x40BEA4B0B8A5BB15
+       1.50404688810361062679e+03, // 0x40978030036F5E51
+}
+
+// for x in[4.5453,2.8571] = 1/[0.2199,0.35001]
+var p1R3 = [6]float64{
+       3.02503916137373618024e-09, // 0x3E29FC21A7AD9EDD
+       1.17186865567253592491e-01, // 0x3FBDFFF55B21D17B
+       3.93297750033315640650e+00, // 0x400F76BCE85EAD8A
+       3.51194035591636932736e+01, // 0x40418F489DA6D129
+       9.10550110750781271918e+01, // 0x4056C3854D2C1837
+       4.85590685197364919645e+01, // 0x4048478F8EA83EE5
+}
+var p1S3 = [5]float64{
+       3.47913095001251519989e+01, // 0x40416549A134069C
+       3.36762458747825746741e+02, // 0x40750C3307F1A75F
+       1.04687139975775130551e+03, // 0x40905B7C5037D523
+       8.90811346398256432622e+02, // 0x408BD67DA32E31E9
+       1.03787932439639277504e+02, // 0x4059F26D7C2EED53
+}
+
+// for x in [2.8570,2] = 1/[0.3499,0.5]
+var p1R2 = [6]float64{
+       1.07710830106873743082e-07, // 0x3E7CE9D4F65544F4
+       1.17176219462683348094e-01, // 0x3FBDFF42BE760D83
+       2.36851496667608785174e+00, // 0x4002F2B7F98FAEC0
+       1.22426109148261232917e+01, // 0x40287C377F71A964
+       1.76939711271687727390e+01, // 0x4031B1A8177F8EE2
+       5.07352312588818499250e+00, // 0x40144B49A574C1FE
+}
+var p1S2 = [5]float64{
+       2.14364859363821409488e+01, // 0x40356FBD8AD5ECDC
+       1.25290227168402751090e+02, // 0x405F529314F92CD5
+       2.32276469057162813669e+02, // 0x406D08D8D5A2DBD9
+       1.17679373287147100768e+02, // 0x405D6B7ADA1884A9
+       8.36463893371618283368e+00, // 0x4020BAB1F44E5192
+}
+
+func pone(x float64) float64 {
+       var p [6]float64
+       var q [5]float64
+       if x >= 8 {
+               p = p1R8
+               q = p1S8
+       } else if x >= 4.5454 {
+               p = p1R5
+               q = p1S5
+       } else if x >= 2.8571 {
+               p = p1R3
+               q = p1S3
+       } else if x >= 2 {
+               p = p1R2
+               q = p1S2
+       }
+       z := 1 / (x * x)
+       r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+       s := 1.0 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))))
+       return 1 + r/s
+}
+
+// For x >= 8, the asymptotic expansions of qone is
+//      3/8 s - 105/1024 s**3 - ..., where s = 1/x.
+// We approximate qone by
+//      qone(x) = s*(0.375 + (R/S))
+// where R = qr1*s**2 + qr2*s**4 + ... + qr5*s**10
+//       S = 1 + qs1*s**2 + ... + qs6*s**12
+// and
+//      | qone(x)/s -0.375-R/S | <= 2**(-61.13)
+
+// for x in [inf, 8] = 1/[0,0.125]
+var q1R8 = [6]float64{
+       0.00000000000000000000e+00,  // 0x0000000000000000
+       -1.02539062499992714161e-01, // 0xBFBA3FFFFFFFFDF3
+       -1.62717534544589987888e+01, // 0xC0304591A26779F7
+       -7.59601722513950107896e+02, // 0xC087BCD053E4B576
+       -1.18498066702429587167e+04, // 0xC0C724E740F87415
+       -4.84385124285750353010e+04, // 0xC0E7A6D065D09C6A
+}
+var q1S8 = [6]float64{
+       1.61395369700722909556e+02,  // 0x40642CA6DE5BCDE5
+       7.82538599923348465381e+03,  // 0x40BE9162D0D88419
+       1.33875336287249578163e+05,  // 0x4100579AB0B75E98
+       7.19657723683240939863e+05,  // 0x4125F65372869C19
+       6.66601232617776375264e+05,  // 0x412457D27719AD5C
+       -2.94490264303834643215e+05, // 0xC111F9690EA5AA18
+}
+
+// for x in [8,4.5454] = 1/[0.125,0.22001]
+var q1R5 = [6]float64{
+       -2.08979931141764104297e-11, // 0xBDB6FA431AA1A098
+       -1.02539050241375426231e-01, // 0xBFBA3FFFCB597FEF
+       -8.05644828123936029840e+00, // 0xC0201CE6CA03AD4B
+       -1.83669607474888380239e+02, // 0xC066F56D6CA7B9B0
+       -1.37319376065508163265e+03, // 0xC09574C66931734F
+       -2.61244440453215656817e+03, // 0xC0A468E388FDA79D
+}
+var q1S5 = [6]float64{
+       8.12765501384335777857e+01,  // 0x405451B2FF5A11B2
+       1.99179873460485964642e+03,  // 0x409F1F31E77BF839
+       1.74684851924908907677e+04,  // 0x40D10F1F0D64CE29
+       4.98514270910352279316e+04,  // 0x40E8576DAABAD197
+       2.79480751638918118260e+04,  // 0x40DB4B04CF7C364B
+       -4.71918354795128470869e+03, // 0xC0B26F2EFCFFA004
+}
+
+// for x in [4.5454,2.8571] = 1/[0.2199,0.35001] ???
+var q1R3 = [6]float64{
+       -5.07831226461766561369e-09, // 0xBE35CFA9D38FC84F
+       -1.02537829820837089745e-01, // 0xBFBA3FEB51AEED54
+       -4.61011581139473403113e+00, // 0xC01270C23302D9FF
+       -5.78472216562783643212e+01, // 0xC04CEC71C25D16DA
+       -2.28244540737631695038e+02, // 0xC06C87D34718D55F
+       -2.19210128478909325622e+02, // 0xC06B66B95F5C1BF6
+}
+var q1S3 = [6]float64{
+       4.76651550323729509273e+01,  // 0x4047D523CCD367E4
+       6.73865112676699709482e+02,  // 0x40850EEBC031EE3E
+       3.38015286679526343505e+03,  // 0x40AA684E448E7C9A
+       5.54772909720722782367e+03,  // 0x40B5ABBAA61D54A6
+       1.90311919338810798763e+03,  // 0x409DBC7A0DD4DF4B
+       -1.35201191444307340817e+02, // 0xC060E670290A311F
+}
+
+// for x in [2.8570,2] = 1/[0.3499,0.5]
+var q1R2 = [6]float64{
+       -1.78381727510958865572e-07, // 0xBE87F12644C626D2
+       -1.02517042607985553460e-01, // 0xBFBA3E8E9148B010
+       -2.75220568278187460720e+00, // 0xC006048469BB4EDA
+       -1.96636162643703720221e+01, // 0xC033A9E2C168907F
+       -4.23253133372830490089e+01, // 0xC04529A3DE104AAA
+       -2.13719211703704061733e+01, // 0xC0355F3639CF6E52
+}
+var q1S2 = [6]float64{
+       2.95333629060523854548e+01,  // 0x403D888A78AE64FF
+       2.52981549982190529136e+02,  // 0x406F9F68DB821CBA
+       7.57502834868645436472e+02,  // 0x4087AC05CE49A0F7
+       7.39393205320467245656e+02,  // 0x40871B2548D4C029
+       1.55949003336666123687e+02,  // 0x40637E5E3C3ED8D4
+       -4.95949898822628210127e+00, // 0xC013D686E71BE86B
+}
+
+func qone(x float64) float64 {
+       var p, q [6]float64
+       if x >= 8 {
+               p = q1R8
+               q = q1S8
+       } else if x >= 4.5454 {
+               p = q1R5
+               q = q1S5
+       } else if x >= 2.8571 {
+               p = q1R3
+               q = q1S3
+       } else if x >= 2 {
+               p = q1R2
+               q = q1S2
+       }
+       z := 1 / (x * x)
+       r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+       s := 1 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))))
+       return (0.375 + r/s) / x
+}
diff --git a/libgo/go/math/jn.go b/libgo/go/math/jn.go
new file mode 100644 (file)
index 0000000..7d31743
--- /dev/null
@@ -0,0 +1,310 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       Bessel function of the first and second kinds of order n.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_jn.c and
+// came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_jn(n, x), __ieee754_yn(n, x)
+// floating point Bessel's function of the 1st and 2nd kind
+// of order n
+//
+// Special cases:
+//      y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+//      y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+// Note 2. About jn(n,x), yn(n,x)
+//      For n=0, j0(x) is called,
+//      for n=1, j1(x) is called,
+//      for n<x, forward recursion is used starting
+//      from values of j0(x) and j1(x).
+//      for n>x, a continued fraction approximation to
+//      j(n,x)/j(n-1,x) is evaluated and then backward
+//      recursion is used starting from a supposed value
+//      for j(n,x). The resulting value of j(0,x) is
+//      compared with the actual value to correct the
+//      supposed value of j(n,x).
+//
+//      yn(n,x) is similar in all respects, except
+//      that forward recursion is used for all
+//      values of n>1.
+
+// Jn returns the order-n Bessel function of the first kind.
+//
+// Special cases are:
+//     Jn(n, ±Inf) = 0
+//     Jn(n, NaN) = NaN
+func Jn(n int, x float64) float64 {
+       const (
+               TwoM29 = 1.0 / (1 << 29) // 2**-29 0x3e10000000000000
+               Two302 = 1 << 302        // 2**302 0x52D0000000000000
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x != x: // IsNaN(x)
+               return x
+       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+               return 0
+       }
+       // J(-n, x) = (-1)**n * J(n, x), J(n, -x) = (-1)**n * J(n, x)
+       // Thus, J(-n, x) = J(n, -x)
+
+       if n == 0 {
+               return J0(x)
+       }
+       if x == 0 {
+               return 0
+       }
+       if n < 0 {
+               n, x = -n, -x
+       }
+       if n == 1 {
+               return J1(x)
+       }
+       sign := false
+       if x < 0 {
+               x = -x
+               if n&1 == 1 {
+                       sign = true // odd n and negative x
+               }
+       }
+       var b float64
+       if float64(n) <= x {
+               // Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x)
+               if x >= Two302 { // x > 2**302
+
+                       // (x >> n**2)
+                       //          Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+                       //          Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+                       //          Let s=sin(x), c=cos(x),
+                       //              xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+                       //
+                       //                 n    sin(xn)*sqt2    cos(xn)*sqt2
+                       //              ----------------------------------
+                       //                 0     s-c             c+s
+                       //                 1    -s-c            -c+s
+                       //                 2    -s+c            -c-s
+                       //                 3     s+c             c-s
+
+                       var temp float64
+                       switch n & 3 {
+                       case 0:
+                               temp = Cos(x) + Sin(x)
+                       case 1:
+                               temp = -Cos(x) + Sin(x)
+                       case 2:
+                               temp = -Cos(x) - Sin(x)
+                       case 3:
+                               temp = Cos(x) - Sin(x)
+                       }
+                       b = (1 / SqrtPi) * temp / Sqrt(x)
+               } else {
+                       b = J1(x)
+                       for i, a := 1, J0(x); i < n; i++ {
+                               a, b = b, b*(float64(i+i)/x)-a // avoid underflow
+                       }
+               }
+       } else {
+               if x < TwoM29 { // x < 2**-29
+                       // x is tiny, return the first Taylor expansion of J(n,x)
+                       // J(n,x) = 1/n!*(x/2)**n  - ...
+
+                       if n > 33 { // underflow
+                               b = 0
+                       } else {
+                               temp := x * 0.5
+                               b = temp
+                               a := float64(1)
+                               for i := 2; i <= n; i++ {
+                                       a *= float64(i) // a = n!
+                                       b *= temp       // b = (x/2)**n
+                               }
+                               b /= a
+                       }
+               } else {
+                       // use backward recurrence
+                       //                      x      x**2      x**2
+                       //  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
+                       //                      2n  - 2(n+1) - 2(n+2)
+                       //
+                       //                      1      1        1
+                       //  (for large x)   =  ----  ------   ------   .....
+                       //                      2n   2(n+1)   2(n+2)
+                       //                      -- - ------ - ------ -
+                       //                       x     x         x
+                       //
+                       // Let w = 2n/x and h=2/x, then the above quotient
+                       // is equal to the continued fraction:
+                       //                  1
+                       //      = -----------------------
+                       //                     1
+                       //         w - -----------------
+                       //                        1
+                       //              w+h - ---------
+                       //                     w+2h - ...
+                       //
+                       // To determine how many terms needed, let
+                       // Q(0) = w, Q(1) = w(w+h) - 1,
+                       // Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+                       // When Q(k) > 1e4      good for single
+                       // When Q(k) > 1e9      good for double
+                       // When Q(k) > 1e17     good for quadruple
+
+                       // determine k
+                       w := float64(n+n) / x
+                       h := 2 / x
+                       q0 := w
+                       z := w + h
+                       q1 := w*z - 1
+                       k := 1
+                       for q1 < 1e9 {
+                               k += 1
+                               z += h
+                               q0, q1 = q1, z*q1-q0
+                       }
+                       m := n + n
+                       t := float64(0)
+                       for i := 2 * (n + k); i >= m; i -= 2 {
+                               t = 1 / (float64(i)/x - t)
+                       }
+                       a := t
+                       b = 1
+                       //  estimate log((2/x)**n*n!) = n*log(2/x)+n*ln(n)
+                       //  Hence, if n*(log(2n/x)) > ...
+                       //  single 8.8722839355e+01
+                       //  double 7.09782712893383973096e+02
+                       //  long double 1.1356523406294143949491931077970765006170e+04
+                       //  then recurrent value may overflow and the result is
+                       //  likely underflow to zero
+
+                       tmp := float64(n)
+                       v := 2 / x
+                       tmp = tmp * Log(Fabs(v*tmp))
+                       if tmp < 7.09782712893383973096e+02 {
+                               for i := n - 1; i > 0; i-- {
+                                       di := float64(i + i)
+                                       a, b = b, b*di/x-a
+                                       di -= 2
+                               }
+                       } else {
+                               for i := n - 1; i > 0; i-- {
+                                       di := float64(i + i)
+                                       a, b = b, b*di/x-a
+                                       di -= 2
+                                       // scale b to avoid spurious overflow
+                                       if b > 1e100 {
+                                               a /= b
+                                               t /= b
+                                               b = 1
+                                       }
+                               }
+                       }
+                       b = t * J0(x) / b
+               }
+       }
+       if sign {
+               return -b
+       }
+       return b
+}
+
+// Yn returns the order-n Bessel function of the second kind.
+//
+// Special cases are:
+//     Yn(n, +Inf) = 0
+//     Yn(n > 0, 0) = -Inf
+//     Yn(n < 0, 0) = +Inf if n is odd, -Inf if n is even
+//     Y1(n, x < 0) = NaN
+//     Y1(n, NaN) = NaN
+func Yn(n int, x float64) float64 {
+       const Two302 = 1 << 302 // 2**302 0x52D0000000000000
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x < 0 || x != x: // x < 0 || IsNaN(x):
+               return NaN()
+       case x > MaxFloat64: // IsInf(x, 1)
+               return 0
+       }
+
+       if n == 0 {
+               return Y0(x)
+       }
+       if x == 0 {
+               if n < 0 && n&1 == 1 {
+                       return Inf(1)
+               }
+               return Inf(-1)
+       }
+       sign := false
+       if n < 0 {
+               n = -n
+               if n&1 == 1 {
+                       sign = true // sign true if n < 0 && |n| odd
+               }
+       }
+       if n == 1 {
+               if sign {
+                       return -Y1(x)
+               }
+               return Y1(x)
+       }
+       var b float64
+       if x >= Two302 { // x > 2**302
+               // (x >> n**2)
+               //          Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+               //          Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+               //          Let s=sin(x), c=cos(x),
+               //              xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+               //
+               //                 n    sin(xn)*sqt2    cos(xn)*sqt2
+               //              ----------------------------------
+               //                 0     s-c             c+s
+               //                 1    -s-c            -c+s
+               //                 2    -s+c            -c-s
+               //                 3     s+c             c-s
+
+               var temp float64
+               switch n & 3 {
+               case 0:
+                       temp = Sin(x) - Cos(x)
+               case 1:
+                       temp = -Sin(x) - Cos(x)
+               case 2:
+                       temp = -Sin(x) + Cos(x)
+               case 3:
+                       temp = Sin(x) + Cos(x)
+               }
+               b = (1 / SqrtPi) * temp / Sqrt(x)
+       } else {
+               a := Y0(x)
+               b = Y1(x)
+               // quit if b is -inf
+               for i := 1; i < n && b >= -MaxFloat64; i++ { // for i := 1; i < n && !IsInf(b, -1); i++ {
+                       a, b = b, (float64(i+i)/x)*b-a
+               }
+       }
+       if sign {
+               return -b
+       }
+       return b
+}
diff --git a/libgo/go/math/ldexp.go b/libgo/go/math/ldexp.go
new file mode 100644 (file)
index 0000000..d04bf15
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Ldexp is the inverse of Frexp.
+// It returns frac × 2**exp.
+func Ldexp(frac float64, exp int) float64 {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case frac == 0:
+               return frac // correctly return -0
+       case frac != frac: // IsNaN(frac):
+               return NaN()
+       }
+       x := Float64bits(frac)
+       exp += int(x>>shift) & mask
+       if exp <= 0 {
+               return 0 // underflow
+       }
+       if exp >= mask { // overflow
+               if frac < 0 {
+                       return Inf(-1)
+               }
+               return Inf(1)
+       }
+       x &^= mask << shift
+       x |= uint64(exp) << shift
+       return Float64frombits(x)
+}
diff --git a/libgo/go/math/lgamma.go b/libgo/go/math/lgamma.go
new file mode 100644 (file)
index 0000000..dc31be9
--- /dev/null
@@ -0,0 +1,350 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       Floating-point logarithm of the Gamma function.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_lgamma_r.c and
+// came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_lgamma_r(x, signgamp)
+// Reentrant version of the logarithm of the Gamma function
+// with user provided pointer for the sign of Gamma(x).
+//
+// Method:
+//   1. Argument Reduction for 0 < x <= 8
+//      Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+//      reduce x to a number in [1.5,2.5] by
+//              lgamma(1+s) = log(s) + lgamma(s)
+//      for example,
+//              lgamma(7.3) = log(6.3) + lgamma(6.3)
+//                          = log(6.3*5.3) + lgamma(5.3)
+//                          = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+//   2. Polynomial approximation of lgamma around its
+//      minimum (ymin=1.461632144968362245) to maintain monotonicity.
+//      On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+//              Let z = x-ymin;
+//              lgamma(x) = -1.214862905358496078218 + z**2*poly(z)
+//              poly(z) is a 14 degree polynomial.
+//   2. Rational approximation in the primary interval [2,3]
+//      We use the following approximation:
+//              s = x-2.0;
+//              lgamma(x) = 0.5*s + s*P(s)/Q(s)
+//      with accuracy
+//              |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+//      Our algorithms are based on the following observation
+//
+//                             zeta(2)-1    2    zeta(3)-1    3
+// lgamma(2+s) = s*(1-Euler) + --------- * s  -  --------- * s  + ...
+//                                 2                 3
+//
+//      where Euler = 0.5772156649... is the Euler constant, which
+//      is very close to 0.5.
+//
+//   3. For x>=8, we have
+//      lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+//      (better formula:
+//         lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+//      Let z = 1/x, then we approximation
+//              f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+//      by
+//                                  3       5             11
+//              w = w0 + w1*z + w2*z  + w3*z  + ... + w6*z
+//      where
+//              |w - f(z)| < 2**-58.74
+//
+//   4. For negative x, since (G is gamma function)
+//              -x*G(-x)*G(x) = pi/sin(pi*x),
+//      we have
+//              G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+//      since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+//      Hence, for x<0, signgam = sign(sin(pi*x)) and
+//              lgamma(x) = log(|Gamma(x)|)
+//                        = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+//      Note: one should avoid computing pi*(-x) directly in the
+//            computation of sin(pi*(-x)).
+//
+//   5. Special Cases
+//              lgamma(2+s) ~ s*(1-Euler) for tiny s
+//              lgamma(1)=lgamma(2)=0
+//              lgamma(x) ~ -log(x) for tiny x
+//              lgamma(0) = lgamma(inf) = inf
+//              lgamma(-integer) = +-inf
+//
+//
+
+// Lgamma returns the natural logarithm and sign (-1 or +1) of Gamma(x).
+//
+// Special cases are:
+//     Lgamma(+Inf) = +Inf
+//     Lgamma(0) = +Inf
+//     Lgamma(-integer) = +Inf
+//     Lgamma(-Inf) = -Inf
+//     Lgamma(NaN) = NaN
+func Lgamma(x float64) (lgamma float64, sign int) {
+       const (
+               Ymin  = 1.461632144968362245
+               Two52 = 1 << 52                     // 0x4330000000000000 ~4.5036e+15
+               Two53 = 1 << 53                     // 0x4340000000000000 ~9.0072e+15
+               Two58 = 1 << 58                     // 0x4390000000000000 ~2.8823e+17
+               Tiny  = 1.0 / (1 << 70)             // 0x3b90000000000000 ~8.47033e-22
+               A0    = 7.72156649015328655494e-02  // 0x3FB3C467E37DB0C8
+               A1    = 3.22467033424113591611e-01  // 0x3FD4A34CC4A60FAD
+               A2    = 6.73523010531292681824e-02  // 0x3FB13E001A5562A7
+               A3    = 2.05808084325167332806e-02  // 0x3F951322AC92547B
+               A4    = 7.38555086081402883957e-03  // 0x3F7E404FB68FEFE8
+               A5    = 2.89051383673415629091e-03  // 0x3F67ADD8CCB7926B
+               A6    = 1.19270763183362067845e-03  // 0x3F538A94116F3F5D
+               A7    = 5.10069792153511336608e-04  // 0x3F40B6C689B99C00
+               A8    = 2.20862790713908385557e-04  // 0x3F2CF2ECED10E54D
+               A9    = 1.08011567247583939954e-04  // 0x3F1C5088987DFB07
+               A10   = 2.52144565451257326939e-05  // 0x3EFA7074428CFA52
+               A11   = 4.48640949618915160150e-05  // 0x3F07858E90A45837
+               Tc    = 1.46163214496836224576e+00  // 0x3FF762D86356BE3F
+               Tf    = -1.21486290535849611461e-01 // 0xBFBF19B9BCC38A42
+               // Tt = -(tail of Tf)
+               Tt  = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F
+               T0  = 4.83836122723810047042e-01  // 0x3FDEF72BC8EE38A2
+               T1  = -1.47587722994593911752e-01 // 0xBFC2E4278DC6C509
+               T2  = 6.46249402391333854778e-02  // 0x3FB08B4294D5419B
+               T3  = -3.27885410759859649565e-02 // 0xBFA0C9A8DF35B713
+               T4  = 1.79706750811820387126e-02  // 0x3F9266E7970AF9EC
+               T5  = -1.03142241298341437450e-02 // 0xBF851F9FBA91EC6A
+               T6  = 6.10053870246291332635e-03  // 0x3F78FCE0E370E344
+               T7  = -3.68452016781138256760e-03 // 0xBF6E2EFFB3E914D7
+               T8  = 2.25964780900612472250e-03  // 0x3F6282D32E15C915
+               T9  = -1.40346469989232843813e-03 // 0xBF56FE8EBF2D1AF1
+               T10 = 8.81081882437654011382e-04  // 0x3F4CDF0CEF61A8E9
+               T11 = -5.38595305356740546715e-04 // 0xBF41A6109C73E0EC
+               T12 = 3.15632070903625950361e-04  // 0x3F34AF6D6C0EBBF7
+               T13 = -3.12754168375120860518e-04 // 0xBF347F24ECC38C38
+               T14 = 3.35529192635519073543e-04  // 0x3F35FD3EE8C2D3F4
+               U0  = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
+               U1  = 6.32827064025093366517e-01  // 0x3FE4401E8B005DFF
+               U2  = 1.45492250137234768737e+00  // 0x3FF7475CD119BD6F
+               U3  = 9.77717527963372745603e-01  // 0x3FEF497644EA8450
+               U4  = 2.28963728064692451092e-01  // 0x3FCD4EAEF6010924
+               U5  = 1.33810918536787660377e-02  // 0x3F8B678BBF2BAB09
+               V1  = 2.45597793713041134822e+00  // 0x4003A5D7C2BD619C
+               V2  = 2.12848976379893395361e+00  // 0x40010725A42B18F5
+               V3  = 7.69285150456672783825e-01  // 0x3FE89DFBE45050AF
+               V4  = 1.04222645593369134254e-01  // 0x3FBAAE55D6537C88
+               V5  = 3.21709242282423911810e-03  // 0x3F6A5ABB57D0CF61
+               S0  = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
+               S1  = 2.14982415960608852501e-01  // 0x3FCB848B36E20878
+               S2  = 3.25778796408930981787e-01  // 0x3FD4D98F4F139F59
+               S3  = 1.46350472652464452805e-01  // 0x3FC2BB9CBEE5F2F7
+               S4  = 2.66422703033638609560e-02  // 0x3F9B481C7E939961
+               S5  = 1.84028451407337715652e-03  // 0x3F5E26B67368F239
+               S6  = 3.19475326584100867617e-05  // 0x3F00BFECDD17E945
+               R1  = 1.39200533467621045958e+00  // 0x3FF645A762C4AB74
+               R2  = 7.21935547567138069525e-01  // 0x3FE71A1893D3DCDC
+               R3  = 1.71933865632803078993e-01  // 0x3FC601EDCCFBDF27
+               R4  = 1.86459191715652901344e-02  // 0x3F9317EA742ED475
+               R5  = 7.77942496381893596434e-04  // 0x3F497DDACA41A95B
+               R6  = 7.32668430744625636189e-06  // 0x3EDEBAF7A5B38140
+               W0  = 4.18938533204672725052e-01  // 0x3FDACFE390C97D69
+               W1  = 8.33333333333329678849e-02  // 0x3FB555555555553B
+               W2  = -2.77777777728775536470e-03 // 0xBF66C16C16B02E5C
+               W3  = 7.93650558643019558500e-04  // 0x3F4A019F98CF38B6
+               W4  = -5.95187557450339963135e-04 // 0xBF4380CB8C0FE741
+               W5  = 8.36339918996282139126e-04  // 0x3F4B67BA4CDAD5D1
+               W6  = -1.63092934096575273989e-03 // 0xBF5AB89D0B9E43E4
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       sign = 1
+       switch {
+       case x != x: // IsNaN(x):
+               lgamma = x
+               return
+       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+               lgamma = x
+               return
+       case x == 0:
+               lgamma = Inf(1)
+               return
+       }
+
+       neg := false
+       if x < 0 {
+               x = -x
+               neg = true
+       }
+
+       if x < Tiny { // if |x| < 2**-70, return -log(|x|)
+               if neg {
+                       sign = -1
+               }
+               lgamma = -Log(x)
+               return
+       }
+       var nadj float64
+       if neg {
+               if x >= Two52 { // |x| >= 2**52, must be -integer
+                       lgamma = Inf(1)
+                       return
+               }
+               t := sinPi(x)
+               if t == 0 {
+                       lgamma = Inf(1) // -integer
+                       return
+               }
+               nadj = Log(Pi / Fabs(t*x))
+               if t < 0 {
+                       sign = -1
+               }
+       }
+
+       switch {
+       case x == 1 || x == 2: // purge off 1 and 2
+               lgamma = 0
+               return
+       case x < 2: // use lgamma(x) = lgamma(x+1) - log(x)
+               var y float64
+               var i int
+               if x <= 0.9 {
+                       lgamma = -Log(x)
+                       switch {
+                       case x >= (Ymin - 1 + 0.27): // 0.7316 <= x <=  0.9
+                               y = 1 - x
+                               i = 0
+                       case x >= (Ymin - 1 - 0.27): // 0.2316 <= x < 0.7316
+                               y = x - (Tc - 1)
+                               i = 1
+                       default: // 0 < x < 0.2316
+                               y = x
+                               i = 2
+                       }
+               } else {
+                       lgamma = 0
+                       switch {
+                       case x >= (Ymin + 0.27): // 1.7316 <= x < 2
+                               y = 2 - x
+                               i = 0
+                       case x >= (Ymin - 0.27): // 1.2316 <= x < 1.7316
+                               y = x - Tc
+                               i = 1
+                       default: // 0.9 < x < 1.2316
+                               y = x - 1
+                               i = 2
+                       }
+               }
+               switch i {
+               case 0:
+                       z := y * y
+                       p1 := A0 + z*(A2+z*(A4+z*(A6+z*(A8+z*A10))))
+                       p2 := z * (A1 + z*(A3+z*(A5+z*(A7+z*(A9+z*A11)))))
+                       p := y*p1 + p2
+                       lgamma += (p - 0.5*y)
+               case 1:
+                       z := y * y
+                       w := z * y
+                       p1 := T0 + w*(T3+w*(T6+w*(T9+w*T12))) // parallel comp
+                       p2 := T1 + w*(T4+w*(T7+w*(T10+w*T13)))
+                       p3 := T2 + w*(T5+w*(T8+w*(T11+w*T14)))
+                       p := z*p1 - (Tt - w*(p2+y*p3))
+                       lgamma += (Tf + p)
+               case 2:
+                       p1 := y * (U0 + y*(U1+y*(U2+y*(U3+y*(U4+y*U5)))))
+                       p2 := 1 + y*(V1+y*(V2+y*(V3+y*(V4+y*V5))))
+                       lgamma += (-0.5*y + p1/p2)
+               }
+       case x < 8: // 2 <= x < 8
+               i := int(x)
+               y := x - float64(i)
+               p := y * (S0 + y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6))))))
+               q := 1 + y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6)))))
+               lgamma = 0.5*y + p/q
+               z := float64(1) // Lgamma(1+s) = Log(s) + Lgamma(s)
+               switch i {
+               case 7:
+                       z *= (y + 6)
+                       fallthrough
+               case 6:
+                       z *= (y + 5)
+                       fallthrough
+               case 5:
+                       z *= (y + 4)
+                       fallthrough
+               case 4:
+                       z *= (y + 3)
+                       fallthrough
+               case 3:
+                       z *= (y + 2)
+                       lgamma += Log(z)
+               }
+       case x < Two58: // 8 <= x < 2**58
+               t := Log(x)
+               z := 1 / x
+               y := z * z
+               w := W0 + z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6)))))
+               lgamma = (x-0.5)*(t-1) + w
+       default: // 2**58 <= x <= Inf
+               lgamma = x * (Log(x) - 1)
+       }
+       if neg {
+               lgamma = nadj - lgamma
+       }
+       return
+}
+
+// sinPi(x) is a helper function for negative x
+func sinPi(x float64) float64 {
+       const (
+               Two52 = 1 << 52 // 0x4330000000000000 ~4.5036e+15
+               Two53 = 1 << 53 // 0x4340000000000000 ~9.0072e+15
+       )
+       if x < 0.25 {
+               return -Sin(Pi * x)
+       }
+
+       // argument reduction
+       z := Floor(x)
+       var n int
+       if z != x { // inexact
+               x = Fmod(x, 2)
+               n = int(x * 4)
+       } else {
+               if x >= Two53 { // x must be even
+                       x = 0
+                       n = 0
+               } else {
+                       if x < Two52 {
+                               z = x + Two52 // exact
+                       }
+                       n = int(1 & Float64bits(z))
+                       x = float64(n)
+                       n <<= 2
+               }
+       }
+       switch n {
+       case 0:
+               x = Sin(Pi * x)
+       case 1, 2:
+               x = Cos(Pi * (0.5 - x))
+       case 3, 4:
+               x = Sin(Pi * (1 - x))
+       case 5, 6:
+               x = -Cos(Pi * (x - 1.5))
+       default:
+               x = Sin(Pi * (x - 2))
+       }
+       return -x
+}
diff --git a/libgo/go/math/log.go b/libgo/go/math/log.go
new file mode 100644 (file)
index 0000000..39d9451
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       Floating-point logarithm.
+*/
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_log.c
+// and came with this notice.  The go code is a simpler
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_log(x)
+// Return the logrithm of x
+//
+// Method :
+//   1. Argument Reduction: find k and f such that
+//                     x = 2**k * (1+f),
+//        where  sqrt(2)/2 < 1+f < sqrt(2) .
+//
+//   2. Approximation of log(1+f).
+//     Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+//              = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+//              = 2s + s*R
+//      We use a special Reme algorithm on [0,0.1716] to generate
+//     a polynomial of degree 14 to approximate R.  The maximum error
+//     of this polynomial approximation is bounded by 2**-58.45. In
+//     other words,
+//                     2      4      6      8      10      12      14
+//         R(z) ~ L1*s +L2*s +L3*s +L4*s +L5*s  +L6*s  +L7*s
+//     (the values of L1 to L7 are listed in the program) and
+//         |      2          14          |     -58.45
+//         | L1*s +...+L7*s    -  R(z) | <= 2
+//         |                             |
+//     Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+//     In order to guarantee error in log below 1ulp, we compute log by
+//             log(1+f) = f - s*(f - R)                (if f is not too large)
+//             log(1+f) = f - (hfsq - s*(hfsq+R)).     (better accuracy)
+//
+//     3. Finally,  log(x) = k*Ln2 + log(1+f).
+//                         = k*Ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*Ln2_lo)))
+//        Here Ln2 is split into two floating point number:
+//                     Ln2_hi + Ln2_lo,
+//        where n*Ln2_hi is always exact for |n| < 2000.
+//
+// Special cases:
+//     log(x) is NaN with signal if x < 0 (including -INF) ;
+//     log(+INF) is +INF; log(0) is -INF with signal;
+//     log(NaN) is that NaN with no signal.
+//
+// Accuracy:
+//     according to an error analysis, the error is always less than
+//     1 ulp (unit in the last place).
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+
+// Log returns the natural logarithm of x.
+//
+// Special cases are:
+//     Log(+Inf) = +Inf
+//     Log(0) = -Inf
+//     Log(x < 0) = NaN
+//     Log(NaN) = NaN
+func Log(x float64) float64 {
+       const (
+               Ln2Hi = 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */
+               Ln2Lo = 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */
+               L1    = 6.666666666666735130e-01   /* 3FE55555 55555593 */
+               L2    = 3.999999999940941908e-01   /* 3FD99999 9997FA04 */
+               L3    = 2.857142874366239149e-01   /* 3FD24924 94229359 */
+               L4    = 2.222219843214978396e-01   /* 3FCC71C5 1D8E78AF */
+               L5    = 1.818357216161805012e-01   /* 3FC74664 96CB03DE */
+               L6    = 1.531383769920937332e-01   /* 3FC39A09 D078C69F */
+               L7    = 1.479819860511658591e-01   /* 3FC2F112 DF3E5244 */
+       )
+
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+               return x
+       case x < 0:
+               return NaN()
+       case x == 0:
+               return Inf(-1)
+       }
+
+       // reduce
+       f1, ki := Frexp(x)
+       if f1 < Sqrt2/2 {
+               f1 *= 2
+               ki--
+       }
+       f := f1 - 1
+       k := float64(ki)
+
+       // compute
+       s := f / (2 + f)
+       s2 := s * s
+       s4 := s2 * s2
+       t1 := s2 * (L1 + s4*(L3+s4*(L5+s4*L7)))
+       t2 := s4 * (L2 + s4*(L4+s4*L6))
+       R := t1 + t2
+       hfsq := 0.5 * f * f
+       return k*Ln2Hi - ((hfsq - (s*(hfsq+R) + k*Ln2Lo)) - f)
+}
diff --git a/libgo/go/math/log10.go b/libgo/go/math/log10.go
new file mode 100644 (file)
index 0000000..6d18baa
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Log10 returns the decimal logarithm of x.
+// The special cases are the same as for Log.
+func Log10(x float64) float64 { return Log(x) * (1 / Ln10) }
+
+// Log2 returns the binary logarithm of x.
+// The special cases are the same as for Log.
+func Log2(x float64) float64 { return Log(x) * (1 / Ln2) }
diff --git a/libgo/go/math/log10_decl.go b/libgo/go/math/log10_decl.go
new file mode 100644 (file)
index 0000000..5aec94e
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Log10(x float64) float64
+func Log2(x float64) float64
diff --git a/libgo/go/math/log1p.go b/libgo/go/math/log1p.go
new file mode 100644 (file)
index 0000000..e1fc275
--- /dev/null
@@ -0,0 +1,200 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/s_log1p.c
+// and came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// double log1p(double x)
+//
+// Method :
+//   1. Argument Reduction: find k and f such that
+//                      1+x = 2**k * (1+f),
+//         where  sqrt(2)/2 < 1+f < sqrt(2) .
+//
+//      Note. If k=0, then f=x is exact. However, if k!=0, then f
+//      may not be representable exactly. In that case, a correction
+//      term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+//      log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+//      and add back the correction term c/u.
+//      (Note: when x > 2**53, one can simply return log(x))
+//
+//   2. Approximation of log1p(f).
+//      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+//               = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+//               = 2s + s*R
+//      We use a special Reme algorithm on [0,0.1716] to generate
+//      a polynomial of degree 14 to approximate R The maximum error
+//      of this polynomial approximation is bounded by 2**-58.45. In
+//      other words,
+//                      2      4      6      8      10      12      14
+//          R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
+//      (the values of Lp1 to Lp7 are listed in the program)
+//      a-0.2929nd
+//          |      2          14          |     -58.45
+//          | Lp1*s +...+Lp7*s    -  R(z) | <= 2
+//          |                             |
+//      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+//      In order to guarantee error in log below 1ulp, we compute log
+//      by
+//              log1p(f) = f - (hfsq - s*(hfsq+R)).
+//
+//   3. Finally, log1p(x) = k*ln2 + log1p(f).
+//                        = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+//      Here ln2 is split into two floating point number:
+//                   ln2_hi + ln2_lo,
+//      where n*ln2_hi is always exact for |n| < 2000.
+//
+// Special cases:
+//      log1p(x) is NaN with signal if x < -1 (including -INF) ;
+//      log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+//      log1p(NaN) is that NaN with no signal.
+//
+// Accuracy:
+//      according to an error analysis, the error is always less than
+//      1 ulp (unit in the last place).
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+//
+// Note: Assuming log() return accurate answer, the following
+//       algorithm can be used to compute log1p(x) to within a few ULP:
+//
+//              u = 1+x;
+//              if(u==1.0) return x ; else
+//                         return log(u)*(x/(u-1.0));
+//
+//       See HP-15C Advanced Functions Handbook, p.193.
+
+// Log1p returns the natural logarithm of 1 plus its argument x.
+// It is more accurate than Log(1 + x) when x is near zero.
+//
+// Special cases are:
+//     Log1p(+Inf) = +Inf
+//     Log1p(-1) = -Inf
+//     Log1p(x < -1) = NaN
+//     Log1p(NaN) = NaN
+func Log1p(x float64) float64 {
+       const (
+               Sqrt2M1     = 4.142135623730950488017e-01  // Sqrt(2)-1 = 0x3fda827999fcef34
+               Sqrt2HalfM1 = -2.928932188134524755992e-01 // Sqrt(2)/2-1 = 0xbfd2bec333018866
+               Small       = 1.0 / (1 << 29)              // 2**-29 = 0x3e20000000000000
+               Tiny        = 1.0 / (1 << 54)              // 2**-54
+               Two53       = 1 << 53                      // 2**53
+               Ln2Hi       = 6.93147180369123816490e-01   // 3fe62e42fee00000
+               Ln2Lo       = 1.90821492927058770002e-10   // 3dea39ef35793c76
+               Lp1         = 6.666666666666735130e-01     // 3FE5555555555593
+               Lp2         = 3.999999999940941908e-01     // 3FD999999997FA04
+               Lp3         = 2.857142874366239149e-01     // 3FD2492494229359
+               Lp4         = 2.222219843214978396e-01     // 3FCC71C51D8E78AF
+               Lp5         = 1.818357216161805012e-01     // 3FC7466496CB03DE
+               Lp6         = 1.531383769920937332e-01     // 3FC39A09D078C69F
+               Lp7         = 1.479819860511658591e-01     // 3FC2F112DF3E5244
+       )
+
+       // special cases
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       switch {
+       case x < -1 || x != x: // x < -1 || IsNaN(x): // includes -Inf
+               return NaN()
+       case x == -1:
+               return Inf(-1)
+       case x > MaxFloat64: // IsInf(x, 1):
+               return Inf(1)
+       }
+
+       absx := x
+       if absx < 0 {
+               absx = -absx
+       }
+
+       var f float64
+       var iu uint64
+       k := 1
+       if absx < Sqrt2M1 { //  |x| < Sqrt(2)-1
+               if absx < Small { // |x| < 2**-29
+                       if absx < Tiny { // |x| < 2**-54
+                               return x
+                       }
+                       return x - x*x*0.5
+               }
+               if x > Sqrt2HalfM1 { // Sqrt(2)/2-1 < x
+                       // (Sqrt(2)/2-1) < x < (Sqrt(2)-1)
+                       k = 0
+                       f = x
+                       iu = 1
+               }
+       }
+       var c float64
+       if k != 0 {
+               var u float64
+               if absx < Two53 { // 1<<53
+                       u = 1.0 + x
+                       iu = Float64bits(u)
+                       k = int((iu >> 52) - 1023)
+                       if k > 0 {
+                               c = 1.0 - (u - x)
+                       } else {
+                               c = x - (u - 1.0) // correction term
+                               c /= u
+                       }
+               } else {
+                       u = x
+                       iu = Float64bits(u)
+                       k = int((iu >> 52) - 1023)
+                       c = 0
+               }
+               iu &= 0x000fffffffffffff
+               if iu < 0x0006a09e667f3bcd { // mantissa of Sqrt(2)
+                       u = Float64frombits(iu | 0x3ff0000000000000) // normalize u
+               } else {
+                       k += 1
+                       u = Float64frombits(iu | 0x3fe0000000000000) // normalize u/2
+                       iu = (0x0010000000000000 - iu) >> 2
+               }
+               f = u - 1.0 // Sqrt(2)/2 < u < Sqrt(2)
+       }
+       hfsq := 0.5 * f * f
+       var s, R, z float64
+       if iu == 0 { // |f| < 2**-20
+               if f == 0 {
+                       if k == 0 {
+                               return 0
+                       } else {
+                               c += float64(k) * Ln2Lo
+                               return float64(k)*Ln2Hi + c
+                       }
+               }
+               R = hfsq * (1.0 - 0.66666666666666666*f) // avoid division
+               if k == 0 {
+                       return f - R
+               }
+               return float64(k)*Ln2Hi - ((R - (float64(k)*Ln2Lo + c)) - f)
+       }
+       s = f / (2.0 + f)
+       z = s * s
+       R = z * (Lp1 + z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))))
+       if k == 0 {
+               return f - (hfsq - s*(hfsq+R))
+       }
+       return float64(k)*Ln2Hi - ((hfsq - (s*(hfsq+R) + (float64(k)*Ln2Lo + c))) - f)
+}
diff --git a/libgo/go/math/logb.go b/libgo/go/math/logb.go
new file mode 100644 (file)
index 0000000..22ec063
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Logb(x) returns the binary exponent of non-zero x.
+//
+// Special cases are:
+//     Logb(±Inf) = +Inf
+//     Logb(0) = -Inf
+//     Logb(NaN) = NaN
+func Logb(x float64) float64 {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x == 0:
+               return Inf(-1)
+       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+               return Inf(1)
+       case x != x: // IsNaN(x):
+               return x
+       }
+       return float64(int((Float64bits(x)>>shift)&mask) - (bias + 1))
+}
+
+// Ilogb(x) returns the binary exponent of non-zero x as an integer.
+//
+// Special cases are:
+//     Ilogb(±Inf) = MaxInt32
+//     Ilogb(0) = MinInt32
+//     Ilogb(NaN) = MaxInt32
+func Ilogb(x float64) int {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x == 0:
+               return MinInt32
+       case x != x: // IsNaN(x):
+               return MaxInt32
+       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+               return MaxInt32
+       }
+       return int((Float64bits(x)>>shift)&mask) - (bias + 1)
+}
diff --git a/libgo/go/math/modf.go b/libgo/go/math/modf.go
new file mode 100644 (file)
index 0000000..ae0c7c8
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Modf returns integer and fractional floating-point numbers
+// that sum to f.  Both values have the same sign as f.
+//
+// Special cases are:
+//     Modf(+Inf) = +Inf, NaN
+//     Modf(-Inf) = -Inf, NaN
+//     Modf(NaN) = NaN, NaN
+func Modf(f float64) (int float64, frac float64) {
+       if f < 1 {
+               if f < 0 {
+                       int, frac = Modf(-f)
+                       return -int, -frac
+               }
+               return 0, f
+       }
+
+       x := Float64bits(f)
+       e := uint(x>>shift)&mask - bias
+
+       // Keep the top 11+e bits, the integer part; clear the rest.
+       if e < 64-11 {
+               x &^= 1<<(64-11-e) - 1
+       }
+       int = Float64frombits(x)
+       frac = f - int
+       return
+}
diff --git a/libgo/go/math/nextafter.go b/libgo/go/math/nextafter.go
new file mode 100644 (file)
index 0000000..8611434
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Nextafter returns the next representable value after x towards y.
+// If x == y, then x is returned.
+//
+// Special cases are:
+//     Nextafter(NaN, y) = NaN
+//     Nextafter(x, NaN) = NaN
+func Nextafter(x, y float64) (r float64) {
+       // TODO(rsc): Remove manual inlining of IsNaN
+       // when compiler does it for us
+       switch {
+       case x != x || y != y: // IsNaN(x) || IsNaN(y): // special case
+               r = NaN()
+       case x == y:
+               r = x
+       case x == 0:
+               r = Copysign(Float64frombits(1), y)
+       case (y > x) == (x > 0):
+               r = Float64frombits(Float64bits(x) + 1)
+       default:
+               r = Float64frombits(Float64bits(x) - 1)
+       }
+       return r
+}
diff --git a/libgo/go/math/pow.go b/libgo/go/math/pow.go
new file mode 100644 (file)
index 0000000..f0ad84a
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func isOddInt(x float64) bool {
+       xi, xf := Modf(x)
+       return xf == 0 && int64(xi)&1 == 1
+}
+
+// Special cases taken from FreeBSD's /usr/src/lib/msun/src/e_pow.c
+// updated by IEEE Std. 754-2008 "Section 9.2.1 Special values".
+
+// Pow returns x**y, the base-x exponential of y.
+//
+// Special cases are (in order):
+//     Pow(x, ±0) = 1 for any x
+//     Pow(1, y) = 1 for any y
+//     Pow(x, 1) = x for any x
+//     Pow(NaN, y) = NaN
+//     Pow(x, NaN) = NaN
+//     Pow(±0, y) = ±Inf for y an odd integer < 0
+//     Pow(±0, -Inf) = +Inf
+//     Pow(±0, +Inf) = +0
+//     Pow(±0, y) = +Inf for finite y < 0 and not an odd integer
+//     Pow(±0, y) = ±0 for y an odd integer > 0
+//     Pow(±0, y) = +0 for finite y > 0 and not an odd integer
+//     Pow(-1, ±Inf) = 1
+//     Pow(x, +Inf) = +Inf for |x| > 1
+//     Pow(x, -Inf) = +0 for |x| > 1
+//     Pow(x, +Inf) = +0 for |x| < 1
+//     Pow(x, -Inf) = +Inf for |x| < 1
+//     Pow(+Inf, y) = +Inf for y > 0
+//     Pow(+Inf, y) = +0 for y < 0
+//     Pow(-Inf, y) = Pow(-0, -y)
+//     Pow(x, y) = NaN for finite x < 0 and finite non-integer y
+func Pow(x, y float64) float64 {
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       switch {
+       case y == 0 || x == 1:
+               return 1
+       case y == 1:
+               return x
+       case y == 0.5:
+               return Sqrt(x)
+       case y == -0.5:
+               return 1 / Sqrt(x)
+       case x != x || y != y: // IsNaN(x) || IsNaN(y):
+               return NaN()
+       case x == 0:
+               switch {
+               case y < 0:
+                       if isOddInt(y) {
+                               return Copysign(Inf(1), x)
+                       }
+                       return Inf(1)
+               case y > 0:
+                       if isOddInt(y) {
+                               return x
+                       }
+                       return 0
+               }
+       case y > MaxFloat64 || y < -MaxFloat64: // IsInf(y, 0):
+               switch {
+               case x == -1:
+                       return 1
+               case (Fabs(x) < 1) == IsInf(y, 1):
+                       return 0
+               default:
+                       return Inf(1)
+               }
+       case x > MaxFloat64 || x < -MaxFloat64: // IsInf(x, 0):
+               if IsInf(x, -1) {
+                       return Pow(1/x, -y) // Pow(-0, -y)
+               }
+               switch {
+               case y < 0:
+                       return 0
+               case y > 0:
+                       return Inf(1)
+               }
+       }
+
+       absy := y
+       flip := false
+       if absy < 0 {
+               absy = -absy
+               flip = true
+       }
+       yi, yf := Modf(absy)
+       if yf != 0 && x < 0 {
+               return NaN()
+       }
+       if yi >= 1<<63 {
+               return Exp(y * Log(x))
+       }
+
+       // ans = a1 * 2**ae (= 1 for now).
+       a1 := float64(1)
+       ae := 0
+
+       // ans *= x**yf
+       if yf != 0 {
+               if yf > 0.5 {
+                       yf--
+                       yi++
+               }
+               a1 = Exp(yf * Log(x))
+       }
+
+       // ans *= x**yi
+       // by multiplying in successive squarings
+       // of x according to bits of yi.
+       // accumulate powers of two into exp.
+       x1, xe := Frexp(x)
+       for i := int64(yi); i != 0; i >>= 1 {
+               if i&1 == 1 {
+                       a1 *= x1
+                       ae += xe
+               }
+               x1 *= x1
+               xe <<= 1
+               if x1 < .5 {
+                       x1 += x1
+                       xe--
+               }
+       }
+
+       // ans = a1*2**ae
+       // if flip { ans = 1 / ans }
+       // but in the opposite order
+       if flip {
+               a1 = 1 / a1
+               ae = -ae
+       }
+       return Ldexp(a1, ae)
+}
diff --git a/libgo/go/math/pow10.go b/libgo/go/math/pow10.go
new file mode 100644 (file)
index 0000000..bda2e82
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// This table might overflow 127-bit exponent representations.
+// In that case, truncate it after 1.0e38.
+var pow10tab [70]float64
+
+// Pow10 returns 10**e, the base-10 exponential of e.
+func Pow10(e int) float64 {
+       if e < 0 {
+               return 1 / Pow10(-e)
+       }
+       if e < len(pow10tab) {
+               return pow10tab[e]
+       }
+       m := e / 2
+       return Pow10(m) * Pow10(e-m)
+}
+
+func init() {
+       pow10tab[0] = 1.0e0
+       pow10tab[1] = 1.0e1
+       for i := 2; i < len(pow10tab); i++ {
+               m := i / 2
+               pow10tab[i] = pow10tab[m] * pow10tab[i-m]
+       }
+}
diff --git a/libgo/go/math/remainder.go b/libgo/go/math/remainder.go
new file mode 100644 (file)
index 0000000..be8724c
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code and the the comment below are from
+// FreeBSD's /usr/src/lib/msun/src/e_remainder.c and came
+// with this notice.  The go code is a simplified version of
+// the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_remainder(x,y)
+// Return :
+//      returns  x REM y  =  x - [x/y]*y  as if in infinite
+//      precision arithmetic, where [x/y] is the (infinite bit)
+//      integer nearest x/y (in half way cases, choose the even one).
+// Method :
+//      Based on fmod() returning  x - [x/y]chopped * y  exactly.
+
+// Remainder returns the IEEE 754 floating-point remainder of x/y.
+//
+// Special cases are:
+//     Remainder(x, NaN) = NaN
+//     Remainder(NaN, y) = NaN
+//     Remainder(Inf, y) = NaN
+//     Remainder(x, 0) = NaN
+//     Remainder(x, Inf) = x
+func Remainder(x, y float64) float64 {
+       const (
+               Tiny    = 4.45014771701440276618e-308 // 0x0020000000000000
+               HalfMax = MaxFloat64 / 2
+       )
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       // special cases
+       switch {
+       case x != x || y != y || x < -MaxFloat64 || x > MaxFloat64 || y == 0: // IsNaN(x) || IsNaN(y) || IsInf(x, 0) || y == 0:
+               return NaN()
+       case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y):
+               return x
+       }
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+       if y < 0 {
+               y = -y
+       }
+       if x == y {
+               return 0
+       }
+       if y <= HalfMax {
+               x = Fmod(x, y+y) // now x < 2y
+       }
+       if y < Tiny {
+               if x+x > y {
+                       x -= y
+                       if x+x >= y {
+                               x -= y
+                       }
+               }
+       } else {
+               yHalf := 0.5 * y
+               if x > yHalf {
+                       x -= y
+                       if x >= yHalf {
+                               x -= y
+                       }
+               }
+       }
+       if sign {
+               x = -x
+       }
+       return x
+}
diff --git a/libgo/go/math/signbit.go b/libgo/go/math/signbit.go
new file mode 100644 (file)
index 0000000..670cc1a
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Signbit returns true if x is negative or negative zero.
+func Signbit(x float64) bool {
+       return Float64bits(x)&(1<<63) != 0
+}
diff --git a/libgo/go/math/sin.go b/libgo/go/math/sin.go
new file mode 100644 (file)
index 0000000..35220cb
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+/*
+       Floating-point sine and cosine.
+
+       Coefficients are #5077 from Hart & Cheney. (18.80D)
+*/
+
+func sinus(x float64, quad int) float64 {
+       const (
+               P0 = .1357884097877375669092680e8
+               P1 = -.4942908100902844161158627e7
+               P2 = .4401030535375266501944918e6
+               P3 = -.1384727249982452873054457e5
+               P4 = .1459688406665768722226959e3
+               Q0 = .8644558652922534429915149e7
+               Q1 = .4081792252343299749395779e6
+               Q2 = .9463096101538208180571257e4
+               Q3 = .1326534908786136358911494e3
+       )
+       if x < 0 {
+               x = -x
+               quad = quad + 2
+       }
+       x = x * (2 / Pi) /* underflow? */
+       var y float64
+       if x > 32764 {
+               var e float64
+               e, y = Modf(x)
+               e = e + float64(quad)
+               f, _ := Modf(0.25 * e)
+               quad = int(e - 4*f)
+       } else {
+               k := int32(x)
+               y = x - float64(k)
+               quad = (quad + int(k)) & 3
+       }
+
+       if quad&1 != 0 {
+               y = 1 - y
+       }
+       if quad > 1 {
+               y = -y
+       }
+
+       yy := y * y
+       temp1 := ((((P4*yy+P3)*yy+P2)*yy+P1)*yy + P0) * y
+       temp2 := ((((yy+Q3)*yy+Q2)*yy+Q1)*yy + Q0)
+       return temp1 / temp2
+}
+
+// Cos returns the cosine of x.
+func Cos(x float64) float64 {
+       if x < 0 {
+               x = -x
+       }
+       return sinus(x, 1)
+}
+
+// Sin returns the sine of x.
+func Sin(x float64) float64 { return sinus(x, 0) }
diff --git a/libgo/go/math/sincos.go b/libgo/go/math/sincos.go
new file mode 100644 (file)
index 0000000..4c1576b
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Sincos(x) returns Sin(x), Cos(x).
+//
+// Special conditions are:
+//     Sincos(+Inf) = NaN, NaN
+//     Sincos(-Inf) = NaN, NaN
+//     Sincos(NaN) = NaN, NaN
+func Sincos(x float64) (sin, cos float64) { return Sin(x), Cos(x) }
diff --git a/libgo/go/math/sinh.go b/libgo/go/math/sinh.go
new file mode 100644 (file)
index 0000000..23a8719
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+/*
+       Floating-point hyperbolic sine and cosine.
+
+       The exponential func is called for arguments
+       greater in magnitude than 0.5.
+
+       A series is used for arguments smaller in magnitude than 0.5.
+
+       Cosh(x) is computed from the exponential func for
+       all arguments.
+*/
+
+// Sinh returns the hyperbolic sine of x.
+func Sinh(x float64) float64 {
+       // The coefficients are #2029 from Hart & Cheney. (20.36D)
+       const (
+               P0 = -0.6307673640497716991184787251e+6
+               P1 = -0.8991272022039509355398013511e+5
+               P2 = -0.2894211355989563807284660366e+4
+               P3 = -0.2630563213397497062819489e+2
+               Q0 = -0.6307673640497716991212077277e+6
+               Q1 = 0.1521517378790019070696485176e+5
+               Q2 = -0.173678953558233699533450911e+3
+       )
+
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+
+       var temp float64
+       switch true {
+       case x > 21:
+               temp = Exp(x) / 2
+
+       case x > 0.5:
+               temp = (Exp(x) - Exp(-x)) / 2
+
+       default:
+               sq := x * x
+               temp = (((P3*sq+P2)*sq+P1)*sq + P0) * x
+               temp = temp / (((sq+Q2)*sq+Q1)*sq + Q0)
+       }
+
+       if sign {
+               temp = -temp
+       }
+       return temp
+}
+
+// Cosh returns the hyperbolic cosine of x.
+func Cosh(x float64) float64 {
+       if x < 0 {
+               x = -x
+       }
+       if x > 21 {
+               return Exp(x) / 2
+       }
+       return (Exp(x) + Exp(-x)) / 2
+}
diff --git a/libgo/go/math/sqrt.go b/libgo/go/math/sqrt.go
new file mode 100644 (file)
index 0000000..bf6ef64
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func libc_sqrt(float64) float64 __asm__("sqrt")
+
+// Sqrt returns the square root of x.
+//
+// Special cases are:
+//     Sqrt(+Inf) = +Inf
+//     Sqrt(±0) = ±0
+//     Sqrt(x < 0) = NaN
+//     Sqrt(NaN) = NaN
+func Sqrt(x float64) float64 {
+       // special cases
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       switch {
+       case x == 0 || x != x || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 1):
+               return x
+       case x < 0:
+               return NaN()
+       }
+
+       return libc_sqrt(x)
+}
diff --git a/libgo/go/math/sqrt_decl.go b/libgo/go/math/sqrt_decl.go
new file mode 100644 (file)
index 0000000..e507746
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Sqrt(x float64) float64
diff --git a/libgo/go/math/sqrt_port.go b/libgo/go/math/sqrt_port.go
new file mode 100644 (file)
index 0000000..8d821b5
--- /dev/null
@@ -0,0 +1,143 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+       Floating-point square root.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
+// came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_sqrt(x)
+// Return correctly rounded sqrt.
+//           -----------------------------------------
+//           | Use the hardware sqrt if you have one |
+//           -----------------------------------------
+// Method:
+//   Bit by bit method using integer arithmetic. (Slow, but portable)
+//   1. Normalization
+//      Scale x to y in [1,4) with even powers of 2:
+//      find an integer k such that  1 <= (y=x*2**(2k)) < 4, then
+//              sqrt(x) = 2**k * sqrt(y)
+//   2. Bit by bit computation
+//      Let q  = sqrt(y) truncated to i bit after binary point (q = 1),
+//           i                                                   0
+//                                     i+1         2
+//          s  = 2*q , and      y  =  2   * ( y - q  ).          (1)
+//           i      i            i                 i
+//
+//      To compute q    from q , one checks whether
+//                  i+1       i
+//
+//                            -(i+1) 2
+//                      (q + 2      )  <= y.                     (2)
+//                        i
+//                                                            -(i+1)
+//      If (2) is false, then q   = q ; otherwise q   = q  + 2      .
+//                             i+1   i             i+1   i
+//
+//      With some algebric manipulation, it is not difficult to see
+//      that (2) is equivalent to
+//                             -(i+1)
+//                      s  +  2       <= y                       (3)
+//                       i                i
+//
+//      The advantage of (3) is that s  and y  can be computed by
+//                                    i      i
+//      the following recurrence formula:
+//          if (3) is false
+//
+//          s     =  s  ,       y    = y   ;                     (4)
+//           i+1      i          i+1    i
+//
+//      otherwise,
+//                         -i                      -(i+1)
+//          s     =  s  + 2  ,  y    = y  -  s  - 2              (5)
+//           i+1      i          i+1    i     i
+//
+//      One may easily use induction to prove (4) and (5).
+//      Note. Since the left hand side of (3) contain only i+2 bits,
+//            it does not necessary to do a full (53-bit) comparison
+//            in (3).
+//   3. Final rounding
+//      After generating the 53 bits result, we compute one more bit.
+//      Together with the remainder, we can decide whether the
+//      result is exact, bigger than 1/2ulp, or less than 1/2ulp
+//      (it will never equal to 1/2ulp).
+//      The rounding mode can be detected by checking whether
+//      huge + tiny is equal to huge, and whether huge - tiny is
+//      equal to huge for some floating point number "huge" and "tiny".
+//
+//
+// Notes:  Rounding mode detection omitted.  The constants "mask", "shift",
+// and "bias" are found in src/pkg/math/bits.go
+
+// Sqrt returns the square root of x.
+//
+// Special cases are:
+//     Sqrt(+Inf) = +Inf
+//     Sqrt(±0) = ±0
+//     Sqrt(x < 0) = NaN
+//     Sqrt(NaN) = NaN
+func sqrtGo(x float64) float64 {
+       // special cases
+       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+       // when compiler does it for us
+       switch {
+       case x == 0 || x != x || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 1):
+               return x
+       case x < 0:
+               return NaN()
+       }
+       ix := Float64bits(x)
+       // normalize x
+       exp := int((ix >> shift) & mask)
+       if exp == 0 { // subnormal x
+               for ix&1<<shift == 0 {
+                       ix <<= 1
+                       exp--
+               }
+               exp++
+       }
+       exp -= bias + 1 // unbias exponent
+       ix &^= mask << shift
+       ix |= 1 << shift
+       if exp&1 == 1 { // odd exp, double x to make it even
+               ix <<= 1
+       }
+       exp >>= 1 // exp = exp/2, exponent of square root
+       // generate sqrt(x) bit by bit
+       ix <<= 1
+       var q, s uint64               // q = sqrt(x)
+       r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
+       for r != 0 {
+               t := s + r
+               if t <= ix {
+                       s = t + r
+                       ix -= t
+                       q += r
+               }
+               ix <<= 1
+               r >>= 1
+       }
+       // final rounding
+       if ix != 0 { // remainder, result not exact
+               q += q & 1 // round according to extra bit
+       }
+       ix = q>>1 + uint64(exp+bias)<<shift // significand + biased exponent
+       return Float64frombits(ix)
+}
diff --git a/libgo/go/math/sqrt_test.go b/libgo/go/math/sqrt_test.go
new file mode 100644 (file)
index 0000000..84cbc16
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Make sqrtGo available for testing.
+
+func SqrtGo(x float64) float64 { return sqrtGo(x) }
diff --git a/libgo/go/math/tan.go b/libgo/go/math/tan.go
new file mode 100644 (file)
index 0000000..a36ebbf
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+/*
+       Floating point tangent.
+*/
+
+// Tan returns the tangent of x.
+func Tan(x float64) float64 {
+       // Coefficients are #4285 from Hart & Cheney. (19.74D)
+       const (
+               P0 = -.1306820264754825668269611177e+5
+               P1 = .1055970901714953193602353981e+4
+               P2 = -.1550685653483266376941705728e+2
+               P3 = .3422554387241003435328470489e-1
+               P4 = .3386638642677172096076369e-4
+               Q0 = -.1663895238947119001851464661e+5
+               Q1 = .4765751362916483698926655581e+4
+               Q2 = -.1555033164031709966900124574e+3
+       )
+
+       flag := false
+       sign := false
+       if x < 0 {
+               x = -x
+               sign = true
+       }
+       x = x * (4 / Pi) /* overflow? */
+       var e float64
+       e, x = Modf(x)
+       i := int32(e)
+
+       switch i & 3 {
+       case 1:
+               x = 1 - x
+               flag = true
+
+       case 2:
+               sign = !sign
+               flag = true
+
+       case 3:
+               x = 1 - x
+               sign = !sign
+       }
+
+       xsq := x * x
+       temp := ((((P4*xsq+P3)*xsq+P2)*xsq+P1)*xsq + P0) * x
+       temp = temp / (((xsq+Q2)*xsq+Q1)*xsq + Q0)
+
+       if flag {
+               if temp == 0 {
+                       return NaN()
+               }
+               temp = 1 / temp
+       }
+       if sign {
+               temp = -temp
+       }
+       return temp
+}
diff --git a/libgo/go/math/tanh.go b/libgo/go/math/tanh.go
new file mode 100644 (file)
index 0000000..8bcf2dd
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+/*
+       Floating-point hyperbolic tangent.
+
+       Sinh and Cosh are called except for large arguments, which
+       would cause overflow improperly.
+*/
+
+// Tanh computes the hyperbolic tangent of x.
+func Tanh(x float64) float64 {
+       if x < 0 {
+               x = -x
+               if x > 21 {
+                       return -1
+               }
+               return -Sinh(x) / Cosh(x)
+       }
+       if x > 21 {
+               return 1
+       }
+       return Sinh(x) / Cosh(x)
+}
diff --git a/libgo/go/math/unsafe.go b/libgo/go/math/unsafe.go
new file mode 100644 (file)
index 0000000..5ae6742
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+import "unsafe"
+
+// Float32bits returns the IEEE 754 binary representation of f.
+func Float32bits(f float32) uint32 { return *(*uint32)(unsafe.Pointer(&f)) }
+
+// Float32frombits returns the floating point number corresponding
+// to the IEEE 754 binary representation b.
+func Float32frombits(b uint32) float32 { return *(*float32)(unsafe.Pointer(&b)) }
+
+// Float64bits returns the IEEE 754 binary representation of f.
+func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
+
+// Float64frombits returns the floating point number corresponding
+// the IEEE 754 binary representation b.
+func Float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
diff --git a/libgo/go/mime/grammar.go b/libgo/go/mime/grammar.go
new file mode 100644 (file)
index 0000000..e60cbb8
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+       "strings"
+)
+
+// isTSpecial returns true if rune is in 'tspecials' as defined by RFC
+// 1531 and RFC 2045.
+func isTSpecial(rune int) bool {
+       return strings.IndexRune(`()<>@,;:\"/[]?=`, rune) != -1
+}
+
+// IsTokenChar returns true if rune is in 'token' as defined by RFC
+// 1531 and RFC 2045.
+func IsTokenChar(rune int) bool {
+       // token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
+       //             or tspecials>
+       return rune > 0x20 && rune < 0x7f && !isTSpecial(rune)
+}
+
+// IsQText returns true if rune is in 'qtext' as defined by RFC 822.
+func IsQText(rune int) bool {
+       // CHAR        =  <any ASCII character>        ; (  0-177,  0.-127.)
+       // qtext       =  <any CHAR excepting <">,     ; => may be folded
+       //                "\" & CR, and including
+       //                linear-white-space>
+       switch rune {
+       case '"', '\\', '\r':
+               return false
+       }
+       return rune < 0x80
+}
diff --git a/libgo/go/mime/mediatype.go b/libgo/go/mime/mediatype.go
new file mode 100644 (file)
index 0000000..eb629aa
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+       "bytes"
+       "strings"
+       "unicode"
+)
+
+// ParseMediaType parses a media type value and any optional
+// parameters, per RFC 1531.  Media types are the values in
+// Content-Type and Content-Disposition headers (RFC 2183).  On
+// success, ParseMediaType returns the media type converted to
+// lowercase and trimmed of white space and a non-nil params.  On
+// error, it returns an empty string and a nil params.
+func ParseMediaType(v string) (mediatype string, params map[string]string) {
+       i := strings.Index(v, ";")
+       if i == -1 {
+               i = len(v)
+       }
+       mediatype = strings.TrimSpace(strings.ToLower(v[0:i]))
+       params = make(map[string]string)
+
+       v = v[i:]
+       for len(v) > 0 {
+               v = strings.TrimLeftFunc(v, unicode.IsSpace)
+               if len(v) == 0 {
+                       return
+               }
+               key, value, rest := consumeMediaParam(v)
+               if key == "" {
+                       // Parse error.
+                       return "", nil
+               }
+               params[key] = value
+               v = rest
+       }
+       return
+}
+
+func isNotTokenChar(rune int) bool {
+       return !IsTokenChar(rune)
+}
+
+// consumeToken consumes a token from the beginning of provided
+// string, per RFC 2045 section 5.1 (referenced from 2183), and return
+// the token consumed and the rest of the string.  Returns ("", v) on
+// failure to consume at least one character.
+func consumeToken(v string) (token, rest string) {
+       notPos := strings.IndexFunc(v, isNotTokenChar)
+       if notPos == -1 {
+               return v, ""
+       }
+       if notPos == 0 {
+               return "", v
+       }
+       return v[0:notPos], v[notPos:]
+}
+
+// consumeValue consumes a "value" per RFC 2045, where a value is
+// either a 'token' or a 'quoted-string'.  On success, consumeValue
+// returns the value consumed (and de-quoted/escaped, if a
+// quoted-string) and the rest of the string.  On failure, returns
+// ("", v).
+func consumeValue(v string) (value, rest string) {
+       if !strings.HasPrefix(v, `"`) {
+               return consumeToken(v)
+       }
+
+       // parse a quoted-string
+       rest = v[1:] // consume the leading quote
+       buffer := new(bytes.Buffer)
+       var idx, rune int
+       var nextIsLiteral bool
+       for idx, rune = range rest {
+               switch {
+               case nextIsLiteral:
+                       if rune >= 0x80 {
+                               return "", v
+                       }
+                       buffer.WriteRune(rune)
+                       nextIsLiteral = false
+               case rune == '"':
+                       return buffer.String(), rest[idx+1:]
+               case IsQText(rune):
+                       buffer.WriteRune(rune)
+               case rune == '\\':
+                       nextIsLiteral = true
+               default:
+                       return "", v
+               }
+       }
+       return "", v
+}
+
+func consumeMediaParam(v string) (param, value, rest string) {
+       rest = strings.TrimLeftFunc(v, unicode.IsSpace)
+       if !strings.HasPrefix(rest, ";") {
+               return "", "", v
+       }
+
+       rest = rest[1:] // consume semicolon
+       rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
+       param, rest = consumeToken(rest)
+       if param == "" {
+               return "", "", v
+       }
+       if !strings.HasPrefix(rest, "=") {
+               return "", "", v
+       }
+       rest = rest[1:] // consume equals sign
+       value, rest = consumeValue(rest)
+       if value == "" {
+               return "", "", v
+       }
+       return param, value, rest
+}
diff --git a/libgo/go/mime/mediatype_test.go b/libgo/go/mime/mediatype_test.go
new file mode 100644 (file)
index 0000000..4891e89
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+       "testing"
+)
+
+func TestConsumeToken(t *testing.T) {
+       tests := [...][3]string{
+               {"foo bar", "foo", " bar"},
+               {"bar", "bar", ""},
+               {"", "", ""},
+               {" foo", "", " foo"},
+       }
+       for _, test := range tests {
+               token, rest := consumeToken(test[0])
+               expectedToken := test[1]
+               expectedRest := test[2]
+               if token != expectedToken {
+                       t.Errorf("expected to consume token '%s', not '%s' from '%s'",
+                               expectedToken, token, test[0])
+               } else if rest != expectedRest {
+                       t.Errorf("expected to have left '%s', not '%s' after reading token '%s' from '%s'",
+                               expectedRest, rest, token, test[0])
+               }
+       }
+}
+
+func TestConsumeValue(t *testing.T) {
+       tests := [...][3]string{
+               {"foo bar", "foo", " bar"},
+               {"bar", "bar", ""},
+               {" bar ", "", " bar "},
+               {`"My value"end`, "My value", "end"},
+               {`"My value" end`, "My value", " end"},
+               {`"\\" rest`, "\\", " rest"},
+               {`"My \" value"end`, "My \" value", "end"},
+               {`"\" rest`, "", `"\" rest`},
+       }
+       for _, test := range tests {
+               value, rest := consumeValue(test[0])
+               expectedValue := test[1]
+               expectedRest := test[2]
+               if value != expectedValue {
+                       t.Errorf("expected to consume value [%s], not [%s] from [%s]",
+                               expectedValue, value, test[0])
+               } else if rest != expectedRest {
+                       t.Errorf("expected to have left [%s], not [%s] after reading value [%s] from [%s]",
+                               expectedRest, rest, value, test[0])
+               }
+       }
+}
+
+func TestConsumeMediaParam(t *testing.T) {
+       tests := [...][4]string{
+               {" ; foo=bar", "foo", "bar", ""},
+               {"; foo=bar", "foo", "bar", ""},
+               {";foo=bar", "foo", "bar", ""},
+               {`;foo="bar"`, "foo", "bar", ""},
+               {`;foo="bar"; `, "foo", "bar", "; "},
+               {`;foo="bar"; foo=baz`, "foo", "bar", "; foo=baz"},
+               {` ; boundary=----CUT;`, "boundary", "----CUT", ";"},
+               {` ; key=value;  blah="value";name="foo" `, "key", "value", `;  blah="value";name="foo" `},
+               {`;  blah="value";name="foo" `, "blah", "value", `;name="foo" `},
+               {`;name="foo" `, "name", "foo", ` `},
+       }
+       for _, test := range tests {
+               param, value, rest := consumeMediaParam(test[0])
+               expectedParam := test[1]
+               expectedValue := test[2]
+               expectedRest := test[3]
+               if param != expectedParam {
+                       t.Errorf("expected to consume param [%s], not [%s] from [%s]",
+                               expectedParam, param, test[0])
+               } else if value != expectedValue {
+                       t.Errorf("expected to consume value [%s], not [%s] from [%s]",
+                               expectedValue, value, test[0])
+               } else if rest != expectedRest {
+                       t.Errorf("expected to have left [%s], not [%s] after reading [%s/%s] from [%s]",
+                               expectedRest, rest, param, value, test[0])
+               }
+       }
+}
+
+func TestParseMediaType(t *testing.T) {
+       tests := [...]string{
+               `form-data; name="foo"`,
+               ` form-data ; name=foo`,
+               `FORM-DATA;name="foo"`,
+               ` FORM-DATA ; name="foo"`,
+               ` FORM-DATA ; name="foo"`,
+               `form-data; key=value;  blah="value";name="foo" `,
+       }
+       for _, test := range tests {
+               mt, params := ParseMediaType(test)
+               if mt != "form-data" {
+                       t.Errorf("expected type form-data for %s, got [%s]", test, mt)
+                       continue
+               }
+               if params["name"] != "foo" {
+                       t.Errorf("expected name=foo for %s", test)
+               }
+       }
+}
+
+func TestParseMediaTypeBogus(t *testing.T) {
+       mt, params := ParseMediaType("bogus ;=========")
+       if mt != "" {
+               t.Error("expected empty type")
+       }
+       if params != nil {
+               t.Error("expected nil params")
+       }
+}
diff --git a/libgo/go/mime/mime_test.go b/libgo/go/mime/mime_test.go
new file mode 100644 (file)
index 0000000..17e6104
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests for type.go
+
+package mime
+
+import "testing"
+
+var typeTests = map[string]string{
+       ".t1":  "application/test",
+       ".t2":  "text/test; charset=utf-8",
+       ".png": "image/png",
+}
+
+func TestType(t *testing.T) {
+       typeFiles = []string{"test.types"}
+
+       for ext, want := range typeTests {
+               val := TypeByExtension(ext)
+               if val != want {
+                       t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
+               }
+
+       }
+}
diff --git a/libgo/go/mime/multipart/multipart.go b/libgo/go/mime/multipart/multipart.go
new file mode 100644 (file)
index 0000000..1d855c7
--- /dev/null
@@ -0,0 +1,280 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+
+/*
+Package multipart implements MIME multipart parsing, as defined in RFC
+2046.
+
+The implementation is sufficient for HTTP (RFC 2388) and the multipart
+bodies generated by popular browsers.
+*/
+package multipart
+
+import (
+       "bufio"
+       "bytes"
+       "io"
+       "mime"
+       "os"
+       "regexp"
+       "strings"
+)
+
+var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)")
+
+// Reader is an iterator over parts in a MIME multipart body.
+// Reader's underlying parser consumes its input as needed.  Seeking
+// isn't supported.
+type Reader interface {
+       // NextPart returns the next part in the multipart, or (nil,
+       // nil) on EOF.  An error is returned if the underlying reader
+       // reports errors, or on truncated or otherwise malformed
+       // input.
+       NextPart() (*Part, os.Error)
+}
+
+// A Part represents a single part in a multipart body.
+type Part struct {
+       // The headers of the body, if any, with the keys canonicalized
+       // in the same fashion that the Go http.Request headers are.
+       // i.e. "foo-bar" changes case to "Foo-Bar"
+       Header map[string]string
+
+       buffer *bytes.Buffer
+       mr     *multiReader
+}
+
+// FormName returns the name parameter if p has a Content-Disposition
+// of type "form-data".  Otherwise it returns the empty string.
+func (p *Part) FormName() string {
+       // See http://tools.ietf.org/html/rfc2183 section 2 for EBNF
+       // of Content-Disposition value format.
+       v, ok := p.Header["Content-Disposition"]
+       if !ok {
+               return ""
+       }
+       d, params := mime.ParseMediaType(v)
+       if d != "form-data" {
+               return ""
+       }
+       return params["name"]
+}
+
+// NewReader creates a new multipart Reader reading from r using the
+// given MIME boundary.
+func NewReader(reader io.Reader, boundary string) Reader {
+       return &multiReader{
+               boundary:     boundary,
+               dashBoundary: "--" + boundary,
+               endLine:      "--" + boundary + "--",
+               bufReader:    bufio.NewReader(reader),
+       }
+}
+
+// Implementation ....
+
+type devNullWriter bool
+
+func (*devNullWriter) Write(p []byte) (n int, err os.Error) {
+       return len(p), nil
+}
+
+var devNull = devNullWriter(false)
+
+func newPart(mr *multiReader) (bp *Part, err os.Error) {
+       bp = new(Part)
+       bp.Header = make(map[string]string)
+       bp.mr = mr
+       bp.buffer = new(bytes.Buffer)
+       if err = bp.populateHeaders(); err != nil {
+               bp = nil
+       }
+       return
+}
+
+func (bp *Part) populateHeaders() os.Error {
+       for {
+               line, err := bp.mr.bufReader.ReadString('\n')
+               if err != nil {
+                       return err
+               }
+               if line == "\n" || line == "\r\n" {
+                       return nil
+               }
+               if matches := headerRegexp.FindStringSubmatch(line); len(matches) == 3 {
+                       key := matches[1]
+                       value := matches[2]
+                       // TODO: canonicalize headers ala http.Request.Header?
+                       bp.Header[key] = value
+                       continue
+               }
+               return os.NewError("Unexpected header line found parsing multipart body")
+       }
+       panic("unreachable")
+}
+
+// Read reads the body of a part, after its headers and before the
+// next part (if any) begins.
+func (bp *Part) Read(p []byte) (n int, err os.Error) {
+       for {
+               if bp.buffer.Len() >= len(p) {
+                       // Internal buffer of unconsumed data is large enough for
+                       // the read request.  No need to parse more at the moment.
+                       break
+               }
+               if !bp.mr.ensureBufferedLine() {
+                       return 0, io.ErrUnexpectedEOF
+               }
+               if bp.mr.bufferedLineIsBoundary() {
+                       // Don't consume this line
+                       break
+               }
+
+               // Write all of this line, except the final CRLF
+               s := *bp.mr.bufferedLine
+               if strings.HasSuffix(s, "\r\n") {
+                       bp.mr.consumeLine()
+                       if !bp.mr.ensureBufferedLine() {
+                               return 0, io.ErrUnexpectedEOF
+                       }
+                       if bp.mr.bufferedLineIsBoundary() {
+                               // The final \r\n isn't ours.  It logically belongs
+                               // to the boundary line which follows.
+                               bp.buffer.WriteString(s[0 : len(s)-2])
+                       } else {
+                               bp.buffer.WriteString(s)
+                       }
+                       break
+               }
+               if strings.HasSuffix(s, "\n") {
+                       bp.buffer.WriteString(s)
+                       bp.mr.consumeLine()
+                       continue
+               }
+               return 0, os.NewError("multipart parse error during Read; unexpected line: " + s)
+       }
+       return bp.buffer.Read(p)
+}
+
+func (bp *Part) Close() os.Error {
+       io.Copy(&devNull, bp)
+       return nil
+}
+
+type multiReader struct {
+       boundary     string
+       dashBoundary string // --boundary
+       endLine      string // --boundary--
+
+       bufferedLine *string
+
+       bufReader   *bufio.Reader
+       currentPart *Part
+       partsRead   int
+}
+
+func (mr *multiReader) eof() bool {
+       return mr.bufferedLine == nil &&
+               !mr.readLine()
+}
+
+func (mr *multiReader) readLine() bool {
+       line, err := mr.bufReader.ReadString('\n')
+       if err != nil {
+               // TODO: care about err being EOF or not?
+               return false
+       }
+       mr.bufferedLine = &line
+       return true
+}
+
+func (mr *multiReader) bufferedLineIsBoundary() bool {
+       return strings.HasPrefix(*mr.bufferedLine, mr.dashBoundary)
+}
+
+func (mr *multiReader) ensureBufferedLine() bool {
+       if mr.bufferedLine == nil {
+               return mr.readLine()
+       }
+       return true
+}
+
+func (mr *multiReader) consumeLine() {
+       mr.bufferedLine = nil
+}
+
+func (mr *multiReader) NextPart() (*Part, os.Error) {
+       if mr.currentPart != nil {
+               mr.currentPart.Close()
+       }
+
+       for {
+               if mr.eof() {
+                       return nil, io.ErrUnexpectedEOF
+               }
+
+               if isBoundaryDelimiterLine(*mr.bufferedLine, mr.dashBoundary) {
+                       mr.consumeLine()
+                       mr.partsRead++
+                       bp, err := newPart(mr)
+                       if err != nil {
+                               return nil, err
+                       }
+                       mr.currentPart = bp
+                       return bp, nil
+               }
+
+               if hasPrefixThenNewline(*mr.bufferedLine, mr.endLine) {
+                       mr.consumeLine()
+                       // Expected EOF (no error)
+                       return nil, nil
+               }
+
+               if mr.partsRead == 0 {
+                       // skip line
+                       mr.consumeLine()
+                       continue
+               }
+
+               return nil, os.NewError("Unexpected line in Next().")
+       }
+       panic("unreachable")
+}
+
+func isBoundaryDelimiterLine(line, dashPrefix string) bool {
+       // http://tools.ietf.org/html/rfc2046#section-5.1
+       //   The boundary delimiter line is then defined as a line
+       //   consisting entirely of two hyphen characters ("-",
+       //   decimal value 45) followed by the boundary parameter
+       //   value from the Content-Type header field, optional linear
+       //   whitespace, and a terminating CRLF.
+       if !strings.HasPrefix(line, dashPrefix) {
+               return false
+       }
+       if strings.HasSuffix(line, "\r\n") {
+               return onlyHorizontalWhitespace(line[len(dashPrefix) : len(line)-2])
+       }
+       // Violate the spec and also support newlines without the
+       // carriage return...
+       if strings.HasSuffix(line, "\n") {
+               return onlyHorizontalWhitespace(line[len(dashPrefix) : len(line)-1])
+       }
+       return false
+}
+
+func onlyHorizontalWhitespace(s string) bool {
+       for i := 0; i < len(s); i++ {
+               if s[i] != ' ' && s[i] != '\t' {
+                       return false
+               }
+       }
+       return true
+}
+
+func hasPrefixThenNewline(s, prefix string) bool {
+       return strings.HasPrefix(s, prefix) &&
+               (len(s) == len(prefix)+1 && strings.HasSuffix(s, "\n") ||
+                       len(s) == len(prefix)+2 && strings.HasSuffix(s, "\r\n"))
+}
diff --git a/libgo/go/mime/multipart/multipart_test.go b/libgo/go/mime/multipart/multipart_test.go
new file mode 100644 (file)
index 0000000..7e1ed13
--- /dev/null
@@ -0,0 +1,204 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package multipart
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "json"
+       "regexp"
+       "strings"
+       "testing"
+)
+
+func TestHorizontalWhitespace(t *testing.T) {
+       if !onlyHorizontalWhitespace(" \t") {
+               t.Error("expected pass")
+       }
+       if onlyHorizontalWhitespace("foo bar") {
+               t.Error("expected failure")
+       }
+}
+
+func TestBoundaryLine(t *testing.T) {
+       boundary := "myBoundary"
+       prefix := "--" + boundary
+       if !isBoundaryDelimiterLine("--myBoundary\r\n", prefix) {
+               t.Error("expected")
+       }
+       if !isBoundaryDelimiterLine("--myBoundary \r\n", prefix) {
+               t.Error("expected")
+       }
+       if !isBoundaryDelimiterLine("--myBoundary \n", prefix) {
+               t.Error("expected")
+       }
+       if isBoundaryDelimiterLine("--myBoundary bogus \n", prefix) {
+               t.Error("expected fail")
+       }
+       if isBoundaryDelimiterLine("--myBoundary bogus--", prefix) {
+               t.Error("expected fail")
+       }
+}
+
+func escapeString(v string) string {
+       bytes, _ := json.Marshal(v)
+       return string(bytes)
+}
+
+func expectEq(t *testing.T, expected, actual, what string) {
+       if expected == actual {
+               return
+       }
+       t.Errorf("Unexpected value for %s; got %s (len %d) but expected: %s (len %d)",
+               what, escapeString(actual), len(actual), escapeString(expected), len(expected))
+}
+
+func TestFormName(t *testing.T) {
+       p := new(Part)
+       p.Header = make(map[string]string)
+       tests := [...][2]string{
+               {`form-data; name="foo"`, "foo"},
+               {` form-data ; name=foo`, "foo"},
+               {`FORM-DATA;name="foo"`, "foo"},
+               {` FORM-DATA ; name="foo"`, "foo"},
+               {` FORM-DATA ; name="foo"`, "foo"},
+               {` FORM-DATA ; name=foo`, "foo"},
+               {` FORM-DATA ; filename="foo.txt"; name=foo; baz=quux`, "foo"},
+       }
+       for _, test := range tests {
+               p.Header["Content-Disposition"] = test[0]
+               expected := test[1]
+               actual := p.FormName()
+               if actual != expected {
+                       t.Errorf("expected \"%s\"; got: \"%s\"", expected, actual)
+               }
+       }
+}
+
+func TestMultipart(t *testing.T) {
+       testBody := `
+This is a multi-part message.  This line is ignored.
+--MyBoundary
+Header1: value1
+HEADER2: value2
+foo-bar: baz
+
+My value
+The end.
+--MyBoundary
+Header1: value1b
+HEADER2: value2b
+foo-bar: bazb
+
+Line 1
+Line 2
+Line 3 ends in a newline, but just one.
+
+--MyBoundary
+
+never read data
+--MyBoundary--
+`
+       testBody = regexp.MustCompile("\n").ReplaceAllString(testBody, "\r\n")
+       bodyReader := strings.NewReader(testBody)
+
+       reader := NewReader(bodyReader, "MyBoundary")
+       buf := new(bytes.Buffer)
+
+       // Part1
+       part, err := reader.NextPart()
+       if part == nil || err != nil {
+               t.Error("Expected part1")
+               return
+       }
+       if part.Header["Header1"] != "value1" {
+               t.Error("Expected Header1: value")
+       }
+       if part.Header["foo-bar"] != "baz" {
+               t.Error("Expected foo-bar: baz")
+       }
+       buf.Reset()
+       io.Copy(buf, part)
+       expectEq(t, "My value\r\nThe end.",
+               buf.String(), "Value of first part")
+
+       // Part2
+       part, err = reader.NextPart()
+       if part == nil || err != nil {
+               t.Error("Expected part2")
+               return
+       }
+       if part.Header["foo-bar"] != "bazb" {
+               t.Error("Expected foo-bar: bazb")
+       }
+       buf.Reset()
+       io.Copy(buf, part)
+       expectEq(t, "Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n",
+               buf.String(), "Value of second part")
+
+       // Part3
+       part, err = reader.NextPart()
+       if part == nil || err != nil {
+               t.Error("Expected part3 without errors")
+               return
+       }
+
+       // Non-existent part4
+       part, err = reader.NextPart()
+       if part != nil {
+               t.Error("Didn't expect a third part.")
+       }
+       if err != nil {
+               t.Errorf("Unexpected error getting third part: %v", err)
+       }
+}
+
+func TestVariousTextLineEndings(t *testing.T) {
+       tests := [...]string{
+               "Foo\nBar",
+               "Foo\nBar\n",
+               "Foo\r\nBar",
+               "Foo\r\nBar\r\n",
+               "Foo\rBar",
+               "Foo\rBar\r",
+               "\x00\x01\x02\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10",
+       }
+
+       for testNum, expectedBody := range tests {
+               body := "--BOUNDARY\r\n" +
+                       "Content-Disposition: form-data; name=\"value\"\r\n" +
+                       "\r\n" +
+                       expectedBody +
+                       "\r\n--BOUNDARY--\r\n"
+               bodyReader := strings.NewReader(body)
+
+               reader := NewReader(bodyReader, "BOUNDARY")
+               buf := new(bytes.Buffer)
+               part, err := reader.NextPart()
+               if part == nil {
+                       t.Errorf("Expected a body part on text %d", testNum)
+                       continue
+               }
+               if err != nil {
+                       t.Errorf("Unexpected error on text %d: %v", testNum, err)
+                       continue
+               }
+               written, err := io.Copy(buf, part)
+               expectEq(t, expectedBody, buf.String(), fmt.Sprintf("test %d", testNum))
+               if err != nil {
+                       t.Errorf("Error copying multipart; bytes=%v, error=%v", written, err)
+               }
+
+               part, err = reader.NextPart()
+               if part != nil {
+                       t.Errorf("Unexpected part in test %d", testNum)
+               }
+               if err != nil {
+                       t.Errorf("Unexpected error in test %d: %v", testNum, err)
+               }
+
+       }
+}
diff --git a/libgo/go/mime/test.types b/libgo/go/mime/test.types
new file mode 100644 (file)
index 0000000..9b040ed
--- /dev/null
@@ -0,0 +1,8 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+
+ # mime package test
+application/test       t1      # Simple test
+text/test              t2      # Text test
diff --git a/libgo/go/mime/type.go b/libgo/go/mime/type.go
new file mode 100644 (file)
index 0000000..a10b780
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The mime package implements parts of the MIME spec.
+package mime
+
+import (
+       "bufio"
+       "os"
+       "strings"
+       "sync"
+)
+
+var typeFiles = []string{
+       "/etc/mime.types",
+       "/etc/apache2/mime.types",
+       "/etc/apache/mime.types",
+}
+
+var mimeTypes = map[string]string{
+       ".css":  "text/css",
+       ".gif":  "image/gif",
+       ".htm":  "text/html; charset=utf-8",
+       ".html": "text/html; charset=utf-8",
+       ".jpg":  "image/jpeg",
+       ".js":   "application/x-javascript",
+       ".pdf":  "application/pdf",
+       ".png":  "image/png",
+       ".xml":  "text/xml; charset=utf-8",
+}
+
+var mimeLock sync.RWMutex
+
+func loadMimeFile(filename string) {
+       f, err := os.Open(filename, os.O_RDONLY, 0666)
+       if err != nil {
+               return
+       }
+
+       reader := bufio.NewReader(f)
+       for {
+               line, err := reader.ReadString('\n')
+               if err != nil {
+                       f.Close()
+                       return
+               }
+               fields := strings.Fields(line)
+               if len(fields) <= 1 || fields[0][0] == '#' {
+                       continue
+               }
+               typename := fields[0]
+               if strings.HasPrefix(typename, "text/") {
+                       typename += "; charset=utf-8"
+               }
+               for _, ext := range fields[1:] {
+                       if ext[0] == '#' {
+                               break
+                       }
+                       mimeTypes["."+ext] = typename
+               }
+       }
+}
+
+func initMime() {
+       for _, filename := range typeFiles {
+               loadMimeFile(filename)
+       }
+}
+
+var once sync.Once
+
+// TypeByExtension returns the MIME type associated with the file extension ext.
+// The extension ext should begin with a leading dot, as in ".html".
+// When ext has no associated type, TypeByExtension returns "".
+//
+// The built-in table is small but is is augmented by the local
+// system's mime.types file(s) if available under one or more of these
+// names:
+//
+//   /etc/mime.types
+//   /etc/apache2/mime.types
+//   /etc/apache/mime.types
+func TypeByExtension(ext string) string {
+       once.Do(initMime)
+       mimeLock.RLock()
+       typename := mimeTypes[ext]
+       mimeLock.RUnlock()
+       return typename
+}
+
+// AddExtensionType sets the MIME type associated with
+// the extension ext to typ.  The extension should begin with
+// a leading dot, as in ".html".
+func AddExtensionType(ext, typ string) os.Error {
+       once.Do(initMime)
+       if len(ext) < 1 || ext[0] != '.' {
+               return os.EINVAL
+       }
+       mimeLock.Lock()
+       mimeTypes[ext] = typ
+       mimeLock.Unlock()
+       return nil
+}
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
new file mode 100644 (file)
index 0000000..9a4c8f6
--- /dev/null
@@ -0,0 +1,179 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import "os"
+
+// Dial connects to the remote address raddr on the network net.
+// If the string laddr is not empty, it is used as the local address
+// for the connection.
+//
+// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
+// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
+// (IPv4-only), "ip6" (IPv6-only), "unix" and "unixgram".
+//
+// For IP networks, addresses have the form host:port.  If host is
+// a literal IPv6 address, it must be enclosed in square brackets.
+//
+// Examples:
+//     Dial("tcp", "", "12.34.56.78:80")
+//     Dial("tcp", "", "google.com:80")
+//     Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80")
+//     Dial("tcp", "127.0.0.1:123", "127.0.0.1:88")
+//
+func Dial(net, laddr, raddr string) (c Conn, err os.Error) {
+       switch prefixBefore(net, ':') {
+       case "tcp", "tcp4", "tcp6":
+               var la, ra *TCPAddr
+               if laddr != "" {
+                       if la, err = ResolveTCPAddr(laddr); err != nil {
+                               goto Error
+                       }
+               }
+               if raddr != "" {
+                       if ra, err = ResolveTCPAddr(raddr); err != nil {
+                               goto Error
+                       }
+               }
+               c, err := DialTCP(net, la, ra)
+               if err != nil {
+                       return nil, err
+               }
+               return c, nil
+       case "udp", "udp4", "udp6":
+               var la, ra *UDPAddr
+               if laddr != "" {
+                       if la, err = ResolveUDPAddr(laddr); err != nil {
+                               goto Error
+                       }
+               }
+               if raddr != "" {
+                       if ra, err = ResolveUDPAddr(raddr); err != nil {
+                               goto Error
+                       }
+               }
+               c, err := DialUDP(net, la, ra)
+               if err != nil {
+                       return nil, err
+               }
+               return c, nil
+       case "unix", "unixgram":
+               var la, ra *UnixAddr
+               if raddr != "" {
+                       if ra, err = ResolveUnixAddr(net, raddr); err != nil {
+                               goto Error
+                       }
+               }
+               if laddr != "" {
+                       if la, err = ResolveUnixAddr(net, laddr); err != nil {
+                               goto Error
+                       }
+               }
+               c, err = DialUnix(net, la, ra)
+               if err != nil {
+                       return nil, err
+               }
+               return c, nil
+       case "ip", "ip4", "ip6":
+               var la, ra *IPAddr
+               if laddr != "" {
+                       if la, err = ResolveIPAddr(laddr); err != nil {
+                               goto Error
+                       }
+               }
+               if raddr != "" {
+                       if ra, err = ResolveIPAddr(raddr); err != nil {
+                               goto Error
+                       }
+               }
+               c, err := DialIP(net, la, ra)
+               if err != nil {
+                       return nil, err
+               }
+               return c, nil
+
+       }
+       err = UnknownNetworkError(net)
+Error:
+       return nil, &OpError{"dial", net + " " + raddr, nil, err}
+}
+
+// Listen announces on the local network address laddr.
+// The network string net must be a stream-oriented
+// network: "tcp", "tcp4", "tcp6", or "unix".
+func Listen(net, laddr string) (l Listener, err os.Error) {
+       switch net {
+       case "tcp", "tcp4", "tcp6":
+               var la *TCPAddr
+               if laddr != "" {
+                       if la, err = ResolveTCPAddr(laddr); err != nil {
+                               return nil, err
+                       }
+               }
+               l, err := ListenTCP(net, la)
+               if err != nil {
+                       return nil, err
+               }
+               return l, nil
+       case "unix":
+               var la *UnixAddr
+               if laddr != "" {
+                       if la, err = ResolveUnixAddr(net, laddr); err != nil {
+                               return nil, err
+                       }
+               }
+               l, err := ListenUnix(net, la)
+               if err != nil {
+                       return nil, err
+               }
+               return l, nil
+       }
+       return nil, UnknownNetworkError(net)
+}
+
+// ListenPacket announces on the local network address laddr.
+// The network string net must be a packet-oriented network:
+// "udp", "udp4", "udp6", or "unixgram".
+func ListenPacket(net, laddr string) (c PacketConn, err os.Error) {
+       switch prefixBefore(net, ':') {
+       case "udp", "udp4", "udp6":
+               var la *UDPAddr
+               if laddr != "" {
+                       if la, err = ResolveUDPAddr(laddr); err != nil {
+                               return nil, err
+                       }
+               }
+               c, err := ListenUDP(net, la)
+               if err != nil {
+                       return nil, err
+               }
+               return c, nil
+       case "unixgram":
+               var la *UnixAddr
+               if laddr != "" {
+                       if la, err = ResolveUnixAddr(net, laddr); err != nil {
+                               return nil, err
+                       }
+               }
+               c, err := DialUnix(net, la, nil)
+               if err != nil {
+                       return nil, err
+               }
+               return c, nil
+       case "ip", "ip4", "ip6":
+               var la *IPAddr
+               if laddr != "" {
+                       if la, err = ResolveIPAddr(laddr); err != nil {
+                               return nil, err
+                       }
+               }
+               c, err := ListenIP(net, la)
+               if err != nil {
+                       return nil, err
+               }
+               return c, nil
+       }
+       return nil, UnknownNetworkError(net)
+}
diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go
new file mode 100644 (file)
index 0000000..0364181
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "flag"
+       "io"
+       "syscall"
+       "testing"
+)
+
+// If an IPv6 tunnel is running (see go/stubl), we can try dialing a real IPv6 address.
+var ipv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
+
+// fd is already connected to the destination, port 80.
+// Run an HTTP request to fetch the appropriate page.
+func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
+       req := []byte("GET /intl/en/privacy.html HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
+       n, err := fd.Write(req)
+
+       buf := make([]byte, 1000)
+       n, err = io.ReadFull(fd, buf)
+
+       if n < 1000 {
+               t.Errorf("fetchGoogle: short HTTP read from %s %s - %v", network, addr, err)
+               return
+       }
+}
+
+func doDial(t *testing.T, network, addr string) {
+       fd, err := Dial(network, "", addr)
+       if err != nil {
+               t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err)
+               return
+       }
+       fetchGoogle(t, fd, network, addr)
+       fd.Close()
+}
+
+var googleaddrs = []string{
+       "74.125.19.99:80",
+       "www.google.com:80",
+       "74.125.19.99:http",
+       "www.google.com:http",
+       "074.125.019.099:0080",
+       "[::ffff:74.125.19.99]:80",
+       "[::ffff:4a7d:1363]:80",
+       "[0:0:0:0:0000:ffff:74.125.19.99]:80",
+       "[0:0:0:0:000000:ffff:74.125.19.99]:80",
+       "[0:0:0:0:0:ffff::74.125.19.99]:80",
+       "[2001:4860:0:2001::68]:80", // ipv6.google.com; removed if ipv6 flag not set
+}
+
+func TestDialGoogle(t *testing.T) {
+       // If no ipv6 tunnel, don't try the last address.
+       if !*ipv6 {
+               googleaddrs[len(googleaddrs)-1] = ""
+       }
+
+       for i := 0; i < len(googleaddrs); i++ {
+               addr := googleaddrs[i]
+               if addr == "" {
+                       continue
+               }
+               t.Logf("-- %s --", addr)
+               doDial(t, "tcp", addr)
+               if addr[0] != '[' {
+                       doDial(t, "tcp4", addr)
+
+                       if !preferIPv4 {
+                               // make sure preferIPv4 flag works.
+                               preferIPv4 = true
+                               syscall.SocketDisableIPv6 = true
+                               doDial(t, "tcp4", addr)
+                               syscall.SocketDisableIPv6 = false
+                               preferIPv4 = false
+                       }
+               }
+
+               // Only run tcp6 if the kernel will take it.
+               if kernelSupportsIPv6() {
+                       doDial(t, "tcp6", addr)
+               }
+       }
+}
diff --git a/libgo/go/net/dict/dict.go b/libgo/go/net/dict/dict.go
new file mode 100644 (file)
index 0000000..42f6553
--- /dev/null
@@ -0,0 +1,212 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dict implements the Dictionary Server Protocol
+// as defined in RFC 2229.
+package dict
+
+import (
+       "container/vector"
+       "net/textproto"
+       "os"
+       "strconv"
+       "strings"
+)
+
+// A Client represents a client connection to a dictionary server.
+type Client struct {
+       text *textproto.Conn
+}
+
+// Dial returns a new client connected to a dictionary server at
+// addr on the given network.
+func Dial(network, addr string) (*Client, os.Error) {
+       text, err := textproto.Dial(network, addr)
+       if err != nil {
+               return nil, err
+       }
+       _, _, err = text.ReadCodeLine(220)
+       if err != nil {
+               text.Close()
+               return nil, err
+       }
+       return &Client{text: text}, nil
+}
+
+// Close closes the connection to the dictionary server.
+func (c *Client) Close() os.Error {
+       return c.text.Close()
+}
+
+// A Dict represents a dictionary available on the server.
+type Dict struct {
+       Name string // short name of dictionary
+       Desc string // long description
+}
+
+// Dicts returns a list of the dictionaries available on the server.
+func (c *Client) Dicts() ([]Dict, os.Error) {
+       id, err := c.text.Cmd("SHOW DB")
+       if err != nil {
+               return nil, err
+       }
+
+       c.text.StartResponse(id)
+       defer c.text.EndResponse(id)
+
+       _, _, err = c.text.ReadCodeLine(110)
+       if err != nil {
+               return nil, err
+       }
+       lines, err := c.text.ReadDotLines()
+       if err != nil {
+               return nil, err
+       }
+       _, _, err = c.text.ReadCodeLine(250)
+
+       dicts := make([]Dict, len(lines))
+       for i := range dicts {
+               d := &dicts[i]
+               a, _ := fields(lines[i])
+               if len(a) < 2 {
+                       return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
+               }
+               d.Name = a[0]
+               d.Desc = a[1]
+       }
+       return dicts, err
+}
+
+// A Defn represents a definition.
+type Defn struct {
+       Dict Dict   // Dict where definition was found
+       Word string // Word being defined
+       Text []byte // Definition text, typically multiple lines
+}
+
+// Define requests the definition of the given word.
+// The argument dict names the dictionary to use,
+// the Name field of a Dict returned by Dicts.
+//
+// The special dictionary name "*" means to look in all the
+// server's dictionaries.
+// The special dictionary name "!" means to look in all the
+// server's dictionaries in turn, stopping after finding the word
+// in one of them.
+func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
+       id, err := c.text.Cmd("DEFINE %s %q", dict, word)
+       if err != nil {
+               return nil, err
+       }
+
+       c.text.StartResponse(id)
+       defer c.text.EndResponse(id)
+
+       _, line, err := c.text.ReadCodeLine(150)
+       if err != nil {
+               return nil, err
+       }
+       a, _ := fields(line)
+       if len(a) < 1 {
+               return nil, textproto.ProtocolError("malformed response: " + line)
+       }
+       n, err := strconv.Atoi(a[0])
+       if err != nil {
+               return nil, textproto.ProtocolError("invalid definition count: " + a[0])
+       }
+       def := make([]*Defn, n)
+       for i := 0; i < n; i++ {
+               _, line, err = c.text.ReadCodeLine(151)
+               if err != nil {
+                       return nil, err
+               }
+               a, _ := fields(line)
+               if len(a) < 3 {
+                       // skip it, to keep protocol in sync
+                       i--
+                       n--
+                       def = def[0:n]
+                       continue
+               }
+               d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
+               d.Text, err = c.text.ReadDotBytes()
+               if err != nil {
+                       return nil, err
+               }
+               def[i] = d
+       }
+       _, _, err = c.text.ReadCodeLine(250)
+       return def, err
+}
+
+// Fields returns the fields in s.
+// Fields are space separated unquoted words
+// or quoted with single or double quote.
+func fields(s string) ([]string, os.Error) {
+       var v vector.StringVector
+       i := 0
+       for {
+               for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+                       i++
+               }
+               if i >= len(s) {
+                       break
+               }
+               if s[i] == '"' || s[i] == '\'' {
+                       q := s[i]
+                       // quoted string
+                       var j int
+                       for j = i + 1; ; j++ {
+                               if j >= len(s) {
+                                       return nil, textproto.ProtocolError("malformed quoted string")
+                               }
+                               if s[j] == '\\' {
+                                       j++
+                                       continue
+                               }
+                               if s[j] == q {
+                                       j++
+                                       break
+                               }
+                       }
+                       v.Push(unquote(s[i+1 : j-1]))
+                       i = j
+               } else {
+                       // atom
+                       var j int
+                       for j = i; j < len(s); j++ {
+                               if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
+                                       break
+                               }
+                       }
+                       v.Push(s[i:j])
+                       i = j
+               }
+               if i < len(s) {
+                       c := s[i]
+                       if c != ' ' && c != '\t' {
+                               return nil, textproto.ProtocolError("quotes not on word boundaries")
+                       }
+               }
+       }
+       return v, nil
+}
+
+func unquote(s string) string {
+       if strings.Index(s, "\\") < 0 {
+               return s
+       }
+       b := []byte(s)
+       w := 0
+       for r := 0; r < len(b); r++ {
+               c := b[r]
+               if c == '\\' {
+                       r++
+                       c = b[r]
+               }
+               b[w] = c
+               w++
+       }
+       return string(b[0:w])
+}
diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go
new file mode 100644 (file)
index 0000000..f1cd47b
--- /dev/null
@@ -0,0 +1,365 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DNS client: see RFC 1035.
+// Has to be linked into package net for Dial.
+
+// TODO(rsc):
+//     Check periodically whether /etc/resolv.conf has changed.
+//     Could potentially handle many outstanding lookups faster.
+//     Could have a small cache.
+//     Random UDP source port (net.Dial should do that for us).
+//     Random request IDs.
+
+package net
+
+import (
+       "os"
+       "rand"
+       "sync"
+       "time"
+)
+
+// DNSError represents a DNS lookup error.
+type DNSError struct {
+       Error     string // description of the error
+       Name      string // name looked for
+       Server    string // server used
+       IsTimeout bool
+}
+
+func (e *DNSError) String() string {
+       if e == nil {
+               return "<nil>"
+       }
+       s := "lookup " + e.Name
+       if e.Server != "" {
+               s += " on " + e.Server
+       }
+       s += ": " + e.Error
+       return s
+}
+
+func (e *DNSError) Timeout() bool   { return e.IsTimeout }
+func (e *DNSError) Temporary() bool { return e.IsTimeout }
+
+const noSuchHost = "no such host"
+
+// Send a request on the connection and hope for a reply.
+// Up to cfg.attempts attempts.
+func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Error) {
+       if len(name) >= 256 {
+               return nil, &DNSError{Error: "name too long", Name: name}
+       }
+       out := new(dnsMsg)
+       out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
+       out.question = []dnsQuestion{
+               {name, qtype, dnsClassINET},
+       }
+       out.recursion_desired = true
+       msg, ok := out.Pack()
+       if !ok {
+               return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
+       }
+
+       for attempt := 0; attempt < cfg.attempts; attempt++ {
+               n, err := c.Write(msg)
+               if err != nil {
+                       return nil, err
+               }
+
+               c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
+
+               buf := make([]byte, 2000) // More than enough.
+               n, err = c.Read(buf)
+               if err != nil {
+                       if e, ok := err.(Error); ok && e.Timeout() {
+                               continue
+                       }
+                       return nil, err
+               }
+               buf = buf[0:n]
+               in := new(dnsMsg)
+               if !in.Unpack(buf) || in.id != out.id {
+                       continue
+               }
+               return in, nil
+       }
+       var server string
+       if a := c.RemoteAddr(); a != nil {
+               server = a.String()
+       }
+       return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
+}
+
+
+// Find answer for name in dns message.
+// On return, if err == nil, addrs != nil.
+func answer(name, server string, dns *dnsMsg, qtype uint16) (addrs []dnsRR, err os.Error) {
+       addrs = make([]dnsRR, 0, len(dns.answer))
+
+       if dns.rcode == dnsRcodeNameError && dns.recursion_available {
+               return nil, &DNSError{Error: noSuchHost, Name: name}
+       }
+       if dns.rcode != dnsRcodeSuccess {
+               // None of the error codes make sense
+               // for the query we sent.  If we didn't get
+               // a name error and we didn't get success,
+               // the server is behaving incorrectly.
+               return nil, &DNSError{Error: "server misbehaving", Name: name, Server: server}
+       }
+
+       // Look for the name.
+       // Presotto says it's okay to assume that servers listed in
+       // /etc/resolv.conf are recursive resolvers.
+       // We asked for recursion, so it should have included
+       // all the answers we need in this one packet.
+Cname:
+       for cnameloop := 0; cnameloop < 10; cnameloop++ {
+               addrs = addrs[0:0]
+               for i := 0; i < len(dns.answer); i++ {
+                       rr := dns.answer[i]
+                       h := rr.Header()
+                       if h.Class == dnsClassINET && h.Name == name {
+                               switch h.Rrtype {
+                               case qtype:
+                                       n := len(addrs)
+                                       addrs = addrs[0 : n+1]
+                                       addrs[n] = rr
+                               case dnsTypeCNAME:
+                                       // redirect to cname
+                                       name = rr.(*dnsRR_CNAME).Cname
+                                       continue Cname
+                               }
+                       }
+               }
+               if len(addrs) == 0 {
+                       return nil, &DNSError{Error: noSuchHost, Name: name, Server: server}
+               }
+               return addrs, nil
+       }
+
+       return nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
+}
+
+// Do a lookup for a single name, which must be rooted
+// (otherwise answer will not find the answers).
+func tryOneName(cfg *dnsConfig, name string, qtype uint16) (addrs []dnsRR, err os.Error) {
+       if len(cfg.servers) == 0 {
+               return nil, &DNSError{Error: "no DNS servers", Name: name}
+       }
+       for i := 0; i < len(cfg.servers); i++ {
+               // Calling Dial here is scary -- we have to be sure
+               // not to dial a name that will require a DNS lookup,
+               // or Dial will call back here to translate it.
+               // The DNS config parser has already checked that
+               // all the cfg.servers[i] are IP addresses, which
+               // Dial will use without a DNS lookup.
+               server := cfg.servers[i] + ":53"
+               c, cerr := Dial("udp", "", server)
+               if cerr != nil {
+                       err = cerr
+                       continue
+               }
+               msg, merr := exchange(cfg, c, name, qtype)
+               c.Close()
+               if merr != nil {
+                       err = merr
+                       continue
+               }
+               addrs, err = answer(name, server, msg, qtype)
+               if err == nil || err.(*DNSError).Error == noSuchHost {
+                       break
+               }
+       }
+       return
+}
+
+func convertRR_A(records []dnsRR) []string {
+       addrs := make([]string, len(records))
+       for i := 0; i < len(records); i++ {
+               rr := records[i]
+               a := rr.(*dnsRR_A).A
+               addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a)).String()
+       }
+       return addrs
+}
+
+var cfg *dnsConfig
+var dnserr os.Error
+
+func loadConfig() { cfg, dnserr = dnsReadConfig() }
+
+func isDomainName(s string) bool {
+       // See RFC 1035, RFC 3696.
+       if len(s) == 0 {
+               return false
+       }
+       if len(s) > 255 {
+               return false
+       }
+       if s[len(s)-1] != '.' { // simplify checking loop: make name end in dot
+               s += "."
+       }
+
+       last := byte('.')
+       ok := false // ok once we've seen a letter
+       partlen := 0
+       for i := 0; i < len(s); i++ {
+               c := s[i]
+               switch {
+               default:
+                       return false
+               case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_':
+                       ok = true
+                       partlen++
+               case '0' <= c && c <= '9':
+                       // fine
+                       partlen++
+               case c == '-':
+                       // byte before dash cannot be dot
+                       if last == '.' {
+                               return false
+                       }
+                       partlen++
+               case c == '.':
+                       // byte before dot cannot be dot, dash
+                       if last == '.' || last == '-' {
+                               return false
+                       }
+                       if partlen > 63 || partlen == 0 {
+                               return false
+                       }
+                       partlen = 0
+               }
+               last = c
+       }
+
+       return ok
+}
+
+var onceLoadConfig sync.Once
+
+func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+       if !isDomainName(name) {
+               return name, nil, &DNSError{Error: "invalid domain name", Name: name}
+       }
+       onceLoadConfig.Do(loadConfig)
+       if dnserr != nil || cfg == nil {
+               err = dnserr
+               return
+       }
+       // If name is rooted (trailing dot) or has enough dots,
+       // try it by itself first.
+       rooted := len(name) > 0 && name[len(name)-1] == '.'
+       if rooted || count(name, '.') >= cfg.ndots {
+               rname := name
+               if !rooted {
+                       rname += "."
+               }
+               // Can try as ordinary name.
+               addrs, err = tryOneName(cfg, rname, qtype)
+               if err == nil {
+                       cname = rname
+                       return
+               }
+       }
+       if rooted {
+               return
+       }
+
+       // Otherwise, try suffixes.
+       for i := 0; i < len(cfg.search); i++ {
+               rname := name + "." + cfg.search[i]
+               if rname[len(rname)-1] != '.' {
+                       rname += "."
+               }
+               addrs, err = tryOneName(cfg, rname, qtype)
+               if err == nil {
+                       cname = rname
+                       return
+               }
+       }
+
+       // Last ditch effort: try unsuffixed.
+       rname := name
+       if !rooted {
+               rname += "."
+       }
+       addrs, err = tryOneName(cfg, rname, qtype)
+       if err == nil {
+               cname = rname
+               return
+       }
+       return
+}
+
+// LookupHost looks for name using the local hosts file and DNS resolver.
+// It returns the canonical name for the host and an array of that
+// host's addresses.
+func LookupHost(name string) (cname string, addrs []string, err os.Error) {
+       onceLoadConfig.Do(loadConfig)
+       if dnserr != nil || cfg == nil {
+               err = dnserr
+               return
+       }
+       // Use entries from /etc/hosts if they match.
+       addrs = lookupStaticHost(name)
+       if len(addrs) > 0 {
+               cname = name
+               return
+       }
+       var records []dnsRR
+       cname, records, err = lookup(name, dnsTypeA)
+       if err != nil {
+               return
+       }
+       addrs = convertRR_A(records)
+       return
+}
+
+type SRV struct {
+       Target   string
+       Port     uint16
+       Priority uint16
+       Weight   uint16
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name, as specified in RFC 2782. In most cases
+// the proto argument can be the same as the corresponding
+// Addr.Network().
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+       target := "_" + service + "._" + proto + "." + name
+       var records []dnsRR
+       cname, records, err = lookup(target, dnsTypeSRV)
+       if err != nil {
+               return
+       }
+       addrs = make([]*SRV, len(records))
+       for i := 0; i < len(records); i++ {
+               r := records[i].(*dnsRR_SRV)
+               addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+       }
+       return
+}
+
+type MX struct {
+       Host string
+       Pref uint16
+}
+
+func LookupMX(name string) (entries []*MX, err os.Error) {
+       var records []dnsRR
+       _, records, err = lookup(name, dnsTypeMX)
+       if err != nil {
+               return
+       }
+       entries = make([]*MX, len(records))
+       for i := 0; i < len(records); i++ {
+               r := records[i].(*dnsRR_MX)
+               entries[i] = &MX{r.Mx, r.Pref}
+       }
+       return
+}
diff --git a/libgo/go/net/dnsconfig.go b/libgo/go/net/dnsconfig.go
new file mode 100644 (file)
index 0000000..26f0e04
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Read system DNS config from /etc/resolv.conf
+
+package net
+
+import "os"
+
+type dnsConfig struct {
+       servers  []string // servers to use
+       search   []string // suffixes to append to local name
+       ndots    int      // number of dots in name to trigger absolute lookup
+       timeout  int      // seconds before giving up on packet
+       attempts int      // lost packets before giving up on server
+       rotate   bool     // round robin among servers
+}
+
+var dnsconfigError os.Error
+
+type DNSConfigError struct {
+       Error os.Error
+}
+
+func (e *DNSConfigError) String() string {
+       return "error reading DNS config: " + e.Error.String()
+}
+
+func (e *DNSConfigError) Timeout() bool   { return false }
+func (e *DNSConfigError) Temporary() bool { return false }
+
+
+// See resolv.conf(5) on a Linux machine.
+// TODO(rsc): Supposed to call uname() and chop the beginning
+// of the host name to get the default search domain.
+// We assume it's in resolv.conf anyway.
+func dnsReadConfig() (*dnsConfig, os.Error) {
+       file, err := open("/etc/resolv.conf")
+       if err != nil {
+               return nil, &DNSConfigError{err}
+       }
+       conf := new(dnsConfig)
+       conf.servers = make([]string, 3)[0:0] // small, but the standard limit
+       conf.search = make([]string, 0)
+       conf.ndots = 1
+       conf.timeout = 5
+       conf.attempts = 2
+       conf.rotate = false
+       for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+               f := getFields(line)
+               if len(f) < 1 {
+                       continue
+               }
+               switch f[0] {
+               case "nameserver": // add one name server
+                       a := conf.servers
+                       n := len(a)
+                       if len(f) > 1 && n < cap(a) {
+                               // One more check: make sure server name is
+                               // just an IP address.  Otherwise we need DNS
+                               // to look it up.
+                               name := f[1]
+                               switch len(ParseIP(name)) {
+                               case 16:
+                                       name = "[" + name + "]"
+                                       fallthrough
+                               case 4:
+                                       a = a[0 : n+1]
+                                       a[n] = name
+                                       conf.servers = a
+                               }
+                       }
+
+               case "domain": // set search path to just this domain
+                       if len(f) > 1 {
+                               conf.search = make([]string, 1)
+                               conf.search[0] = f[1]
+                       } else {
+                               conf.search = make([]string, 0)
+                       }
+
+               case "search": // set search path to given servers
+                       conf.search = make([]string, len(f)-1)
+                       for i := 0; i < len(conf.search); i++ {
+                               conf.search[i] = f[i+1]
+                       }
+
+               case "options": // magic options
+                       for i := 1; i < len(f); i++ {
+                               s := f[i]
+                               switch {
+                               case len(s) >= 6 && s[0:6] == "ndots:":
+                                       n, _, _ := dtoi(s, 6)
+                                       if n < 1 {
+                                               n = 1
+                                       }
+                                       conf.ndots = n
+                               case len(s) >= 8 && s[0:8] == "timeout:":
+                                       n, _, _ := dtoi(s, 8)
+                                       if n < 1 {
+                                               n = 1
+                                       }
+                                       conf.timeout = n
+                               case len(s) >= 8 && s[0:9] == "attempts:":
+                                       n, _, _ := dtoi(s, 9)
+                                       if n < 1 {
+                                               n = 1
+                                       }
+                                       conf.attempts = n
+                               case s == "rotate":
+                                       conf.rotate = true
+                               }
+                       }
+               }
+       }
+       file.close()
+
+       return conf, nil
+}
diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go
new file mode 100644 (file)
index 0000000..dc195ca
--- /dev/null
@@ -0,0 +1,743 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DNS packet assembly.  See RFC 1035.
+//
+// This is intended to support name resolution during net.Dial.
+// It doesn't have to be blazing fast.
+//
+// Rather than write the usual handful of routines to pack and
+// unpack every message that can appear on the wire, we use
+// reflection to write a generic pack/unpack for structs and then
+// use it.  Thus, if in the future we need to define new message
+// structs, no new pack/unpack/printing code needs to be written.
+//
+// The first half of this file defines the DNS message formats.
+// The second half implements the conversion to and from wire format.
+// A few of the structure elements have string tags to aid the
+// generic pack/unpack routines.
+//
+// TODO(rsc):  There are enough names defined in this file that they're all
+// prefixed with dns.  Perhaps put this in its own package later.
+
+package net
+
+import (
+       "fmt"
+       "os"
+       "reflect"
+)
+
+// Packet formats
+
+// Wire constants.
+const (
+       // valid dnsRR_Header.Rrtype and dnsQuestion.qtype
+       dnsTypeA     = 1
+       dnsTypeNS    = 2
+       dnsTypeMD    = 3
+       dnsTypeMF    = 4
+       dnsTypeCNAME = 5
+       dnsTypeSOA   = 6
+       dnsTypeMB    = 7
+       dnsTypeMG    = 8
+       dnsTypeMR    = 9
+       dnsTypeNULL  = 10
+       dnsTypeWKS   = 11
+       dnsTypePTR   = 12
+       dnsTypeHINFO = 13
+       dnsTypeMINFO = 14
+       dnsTypeMX    = 15
+       dnsTypeTXT   = 16
+       dnsTypeSRV   = 33
+
+       // valid dnsQuestion.qtype only
+       dnsTypeAXFR  = 252
+       dnsTypeMAILB = 253
+       dnsTypeMAILA = 254
+       dnsTypeALL   = 255
+
+       // valid dnsQuestion.qclass
+       dnsClassINET   = 1
+       dnsClassCSNET  = 2
+       dnsClassCHAOS  = 3
+       dnsClassHESIOD = 4
+       dnsClassANY    = 255
+
+       // dnsMsg.rcode
+       dnsRcodeSuccess        = 0
+       dnsRcodeFormatError    = 1
+       dnsRcodeServerFailure  = 2
+       dnsRcodeNameError      = 3
+       dnsRcodeNotImplemented = 4
+       dnsRcodeRefused        = 5
+)
+
+// The wire format for the DNS packet header.
+type dnsHeader struct {
+       Id                                 uint16
+       Bits                               uint16
+       Qdcount, Ancount, Nscount, Arcount uint16
+}
+
+const (
+       // dnsHeader.Bits
+       _QR = 1 << 15 // query/response (response=1)
+       _AA = 1 << 10 // authoritative
+       _TC = 1 << 9  // truncated
+       _RD = 1 << 8  // recursion desired
+       _RA = 1 << 7  // recursion available
+)
+
+// DNS queries.
+type dnsQuestion struct {
+       Name   string "domain-name" // "domain-name" specifies encoding; see packers below
+       Qtype  uint16
+       Qclass uint16
+}
+
+// DNS responses (resource records).
+// There are many types of messages,
+// but they all share the same header.
+type dnsRR_Header struct {
+       Name     string "domain-name"
+       Rrtype   uint16
+       Class    uint16
+       Ttl      uint32
+       Rdlength uint16 // length of data after header
+}
+
+func (h *dnsRR_Header) Header() *dnsRR_Header {
+       return h
+}
+
+type dnsRR interface {
+       Header() *dnsRR_Header
+}
+
+
+// Specific DNS RR formats for each query type.
+
+type dnsRR_CNAME struct {
+       Hdr   dnsRR_Header
+       Cname string "domain-name"
+}
+
+func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_HINFO struct {
+       Hdr dnsRR_Header
+       Cpu string
+       Os  string
+}
+
+func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_MB struct {
+       Hdr dnsRR_Header
+       Mb  string "domain-name"
+}
+
+func (rr *dnsRR_MB) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_MG struct {
+       Hdr dnsRR_Header
+       Mg  string "domain-name"
+}
+
+func (rr *dnsRR_MG) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_MINFO struct {
+       Hdr   dnsRR_Header
+       Rmail string "domain-name"
+       Email string "domain-name"
+}
+
+func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_MR struct {
+       Hdr dnsRR_Header
+       Mr  string "domain-name"
+}
+
+func (rr *dnsRR_MR) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_MX struct {
+       Hdr  dnsRR_Header
+       Pref uint16
+       Mx   string "domain-name"
+}
+
+func (rr *dnsRR_MX) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_NS struct {
+       Hdr dnsRR_Header
+       Ns  string "domain-name"
+}
+
+func (rr *dnsRR_NS) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_PTR struct {
+       Hdr dnsRR_Header
+       Ptr string "domain-name"
+}
+
+func (rr *dnsRR_PTR) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_SOA struct {
+       Hdr     dnsRR_Header
+       Ns      string "domain-name"
+       Mbox    string "domain-name"
+       Serial  uint32
+       Refresh uint32
+       Retry   uint32
+       Expire  uint32
+       Minttl  uint32
+}
+
+func (rr *dnsRR_SOA) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_TXT struct {
+       Hdr dnsRR_Header
+       Txt string // not domain name
+}
+
+func (rr *dnsRR_TXT) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_SRV struct {
+       Hdr      dnsRR_Header
+       Priority uint16
+       Weight   uint16
+       Port     uint16
+       Target   string "domain-name"
+}
+
+func (rr *dnsRR_SRV) Header() *dnsRR_Header {
+       return &rr.Hdr
+}
+
+type dnsRR_A struct {
+       Hdr dnsRR_Header
+       A   uint32 "ipv4"
+}
+
+func (rr *dnsRR_A) Header() *dnsRR_Header { return &rr.Hdr }
+
+
+// Packing and unpacking.
+//
+// All the packers and unpackers take a (msg []byte, off int)
+// and return (off1 int, ok bool).  If they return ok==false, they
+// also return off1==len(msg), so that the next unpacker will
+// also fail.  This lets us avoid checks of ok until the end of a
+// packing sequence.
+
+// Map of constructors for each RR wire type.
+var rr_mk = map[int]func() dnsRR{
+       dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
+       dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
+       dnsTypeMB:    func() dnsRR { return new(dnsRR_MB) },
+       dnsTypeMG:    func() dnsRR { return new(dnsRR_MG) },
+       dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
+       dnsTypeMR:    func() dnsRR { return new(dnsRR_MR) },
+       dnsTypeMX:    func() dnsRR { return new(dnsRR_MX) },
+       dnsTypeNS:    func() dnsRR { return new(dnsRR_NS) },
+       dnsTypePTR:   func() dnsRR { return new(dnsRR_PTR) },
+       dnsTypeSOA:   func() dnsRR { return new(dnsRR_SOA) },
+       dnsTypeTXT:   func() dnsRR { return new(dnsRR_TXT) },
+       dnsTypeSRV:   func() dnsRR { return new(dnsRR_SRV) },
+       dnsTypeA:     func() dnsRR { return new(dnsRR_A) },
+}
+
+// Pack a domain name s into msg[off:].
+// Domain names are a sequence of counted strings
+// split at the dots.  They end with a zero-length string.
+func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
+       // Add trailing dot to canonicalize name.
+       if n := len(s); n == 0 || s[n-1] != '.' {
+               s += "."
+       }
+
+       // Each dot ends a segment of the name.
+       // We trade each dot byte for a length byte.
+       // There is also a trailing zero.
+       // Check that we have all the space we need.
+       tot := len(s) + 1
+       if off+tot > len(msg) {
+               return len(msg), false
+       }
+
+       // Emit sequence of counted strings, chopping at dots.
+       begin := 0
+       for i := 0; i < len(s); i++ {
+               if s[i] == '.' {
+                       if i-begin >= 1<<6 { // top two bits of length must be clear
+                               return len(msg), false
+                       }
+                       msg[off] = byte(i - begin)
+                       off++
+                       for j := begin; j < i; j++ {
+                               msg[off] = s[j]
+                               off++
+                       }
+                       begin = i + 1
+               }
+       }
+       msg[off] = 0
+       off++
+       return off, true
+}
+
+// Unpack a domain name.
+// In addition to the simple sequences of counted strings above,
+// domain names are allowed to refer to strings elsewhere in the
+// packet, to avoid repeating common suffixes when returning
+// many entries in a single domain.  The pointers are marked
+// by a length byte with the top two bits set.  Ignoring those
+// two bits, that byte and the next give a 14 bit offset from msg[0]
+// where we should pick up the trail.
+// Note that if we jump elsewhere in the packet,
+// we return off1 == the offset after the first pointer we found,
+// which is where the next record will start.
+// In theory, the pointers are only allowed to jump backward.
+// We let them jump anywhere and stop jumping after a while.
+func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
+       s = ""
+       ptr := 0 // number of pointers followed
+Loop:
+       for {
+               if off >= len(msg) {
+                       return "", len(msg), false
+               }
+               c := int(msg[off])
+               off++
+               switch c & 0xC0 {
+               case 0x00:
+                       if c == 0x00 {
+                               // end of name
+                               break Loop
+                       }
+                       // literal string
+                       if off+c > len(msg) {
+                               return "", len(msg), false
+                       }
+                       s += string(msg[off:off+c]) + "."
+                       off += c
+               case 0xC0:
+                       // pointer to somewhere else in msg.
+                       // remember location after first ptr,
+                       // since that's how many bytes we consumed.
+                       // also, don't follow too many pointers --
+                       // maybe there's a loop.
+                       if off >= len(msg) {
+                               return "", len(msg), false
+                       }
+                       c1 := msg[off]
+                       off++
+                       if ptr == 0 {
+                               off1 = off
+                       }
+                       if ptr++; ptr > 10 {
+                               return "", len(msg), false
+                       }
+                       off = (c^0xC0)<<8 | int(c1)
+               default:
+                       // 0x80 and 0x40 are reserved
+                       return "", len(msg), false
+               }
+       }
+       if ptr == 0 {
+               off1 = off
+       }
+       return s, off1, true
+}
+
+// TODO(rsc): Move into generic library?
+// Pack a reflect.StructValue into msg.  Struct members can only be uint16, uint32, string,
+// and other (often anonymous) structs.
+func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
+       for i := 0; i < val.NumField(); i++ {
+               f := val.Type().(*reflect.StructType).Field(i)
+               switch fv := val.Field(i).(type) {
+               default:
+               BadType:
+                       fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+                       return len(msg), false
+               case *reflect.StructValue:
+                       off, ok = packStructValue(fv, msg, off)
+               case *reflect.UintValue:
+                       i := fv.Get()
+                       switch fv.Type().Kind() {
+                       default:
+                               goto BadType
+                       case reflect.Uint16:
+                               if off+2 > len(msg) {
+                                       return len(msg), false
+                               }
+                               msg[off] = byte(i >> 8)
+                               msg[off+1] = byte(i)
+                               off += 2
+                       case reflect.Uint32:
+                               if off+4 > len(msg) {
+                                       return len(msg), false
+                               }
+                               msg[off] = byte(i >> 24)
+                               msg[off+1] = byte(i >> 16)
+                               msg[off+2] = byte(i >> 8)
+                               msg[off+3] = byte(i)
+                               off += 4
+                       }
+               case *reflect.StringValue:
+                       // There are multiple string encodings.
+                       // The tag distinguishes ordinary strings from domain names.
+                       s := fv.Get()
+                       switch f.Tag {
+                       default:
+                               fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+                               return len(msg), false
+                       case "domain-name":
+                               off, ok = packDomainName(s, msg, off)
+                               if !ok {
+                                       return len(msg), false
+                               }
+                       case "":
+                               // Counted string: 1 byte length.
+                               if len(s) > 255 || off+1+len(s) > len(msg) {
+                                       return len(msg), false
+                               }
+                               msg[off] = byte(len(s))
+                               off++
+                               off += copy(msg[off:], s)
+                       }
+               }
+       }
+       return off, true
+}
+
+func structValue(any interface{}) *reflect.StructValue {
+       return reflect.NewValue(any).(*reflect.PtrValue).Elem().(*reflect.StructValue)
+}
+
+func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+       off, ok = packStructValue(structValue(any), msg, off)
+       return off, ok
+}
+
+// TODO(rsc): Move into generic library?
+// Unpack a reflect.StructValue from msg.
+// Same restrictions as packStructValue.
+func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
+       for i := 0; i < val.NumField(); i++ {
+               f := val.Type().(*reflect.StructType).Field(i)
+               switch fv := val.Field(i).(type) {
+               default:
+               BadType:
+                       fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+                       return len(msg), false
+               case *reflect.StructValue:
+                       off, ok = unpackStructValue(fv, msg, off)
+               case *reflect.UintValue:
+                       switch fv.Type().Kind() {
+                       default:
+                               goto BadType
+                       case reflect.Uint16:
+                               if off+2 > len(msg) {
+                                       return len(msg), false
+                               }
+                               i := uint16(msg[off])<<8 | uint16(msg[off+1])
+                               fv.Set(uint64(i))
+                               off += 2
+                       case reflect.Uint32:
+                               if off+4 > len(msg) {
+                                       return len(msg), false
+                               }
+                               i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
+                               fv.Set(uint64(i))
+                               off += 4
+                       }
+               case *reflect.StringValue:
+                       var s string
+                       switch f.Tag {
+                       default:
+                               fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+                               return len(msg), false
+                       case "domain-name":
+                               s, off, ok = unpackDomainName(msg, off)
+                               if !ok {
+                                       return len(msg), false
+                               }
+                       case "":
+                               if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
+                                       return len(msg), false
+                               }
+                               n := int(msg[off])
+                               off++
+                               b := make([]byte, n)
+                               for i := 0; i < n; i++ {
+                                       b[i] = msg[off+i]
+                               }
+                               off += n
+                               s = string(b)
+                       }
+                       fv.Set(s)
+               }
+       }
+       return off, true
+}
+
+func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+       off, ok = unpackStructValue(structValue(any), msg, off)
+       return off, ok
+}
+
+// Generic struct printer.
+// Doesn't care about the string tag "domain-name",
+// but does look for an "ipv4" tag on uint32 variables,
+// printing them as IP addresses.
+func printStructValue(val *reflect.StructValue) string {
+       s := "{"
+       for i := 0; i < val.NumField(); i++ {
+               if i > 0 {
+                       s += ", "
+               }
+               f := val.Type().(*reflect.StructType).Field(i)
+               if !f.Anonymous {
+                       s += f.Name + "="
+               }
+               fval := val.Field(i)
+               if fv, ok := fval.(*reflect.StructValue); ok {
+                       s += printStructValue(fv)
+               } else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" {
+                       i := fv.Get()
+                       s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
+               } else {
+                       s += fmt.Sprint(fval.Interface())
+               }
+       }
+       s += "}"
+       return s
+}
+
+func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
+
+// Resource record packer.
+func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
+       var off1 int
+       // pack twice, once to find end of header
+       // and again to find end of packet.
+       // a bit inefficient but this doesn't need to be fast.
+       // off1 is end of header
+       // off2 is end of rr
+       off1, ok = packStruct(rr.Header(), msg, off)
+       off2, ok = packStruct(rr, msg, off)
+       if !ok {
+               return len(msg), false
+       }
+       // pack a third time; redo header with correct data length
+       rr.Header().Rdlength = uint16(off2 - off1)
+       packStruct(rr.Header(), msg, off)
+       return off2, true
+}
+
+// Resource record unpacker.
+func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
+       // unpack just the header, to find the rr type and length
+       var h dnsRR_Header
+       off0 := off
+       if off, ok = unpackStruct(&h, msg, off); !ok {
+               return nil, len(msg), false
+       }
+       end := off + int(h.Rdlength)
+
+       // make an rr of that type and re-unpack.
+       // again inefficient but doesn't need to be fast.
+       mk, known := rr_mk[int(h.Rrtype)]
+       if !known {
+               return &h, end, true
+       }
+       rr = mk()
+       off, ok = unpackStruct(rr, msg, off0)
+       if off != end {
+               return &h, end, true
+       }
+       return rr, off, ok
+}
+
+// Usable representation of a DNS packet.
+
+// A manually-unpacked version of (id, bits).
+// This is in its own struct for easy printing.
+type dnsMsgHdr struct {
+       id                  uint16
+       response            bool
+       opcode              int
+       authoritative       bool
+       truncated           bool
+       recursion_desired   bool
+       recursion_available bool
+       rcode               int
+}
+
+type dnsMsg struct {
+       dnsMsgHdr
+       question []dnsQuestion
+       answer   []dnsRR
+       ns       []dnsRR
+       extra    []dnsRR
+}
+
+
+func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
+       var dh dnsHeader
+
+       // Convert convenient dnsMsg into wire-like dnsHeader.
+       dh.Id = dns.id
+       dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
+       if dns.recursion_available {
+               dh.Bits |= _RA
+       }
+       if dns.recursion_desired {
+               dh.Bits |= _RD
+       }
+       if dns.truncated {
+               dh.Bits |= _TC
+       }
+       if dns.authoritative {
+               dh.Bits |= _AA
+       }
+       if dns.response {
+               dh.Bits |= _QR
+       }
+
+       // Prepare variable sized arrays.
+       question := dns.question
+       answer := dns.answer
+       ns := dns.ns
+       extra := dns.extra
+
+       dh.Qdcount = uint16(len(question))
+       dh.Ancount = uint16(len(answer))
+       dh.Nscount = uint16(len(ns))
+       dh.Arcount = uint16(len(extra))
+
+       // Could work harder to calculate message size,
+       // but this is far more than we need and not
+       // big enough to hurt the allocator.
+       msg = make([]byte, 2000)
+
+       // Pack it in: header and then the pieces.
+       off := 0
+       off, ok = packStruct(&dh, msg, off)
+       for i := 0; i < len(question); i++ {
+               off, ok = packStruct(&question[i], msg, off)
+       }
+       for i := 0; i < len(answer); i++ {
+               off, ok = packRR(answer[i], msg, off)
+       }
+       for i := 0; i < len(ns); i++ {
+               off, ok = packRR(ns[i], msg, off)
+       }
+       for i := 0; i < len(extra); i++ {
+               off, ok = packRR(extra[i], msg, off)
+       }
+       if !ok {
+               return nil, false
+       }
+       return msg[0:off], true
+}
+
+func (dns *dnsMsg) Unpack(msg []byte) bool {
+       // Header.
+       var dh dnsHeader
+       off := 0
+       var ok bool
+       if off, ok = unpackStruct(&dh, msg, off); !ok {
+               return false
+       }
+       dns.id = dh.Id
+       dns.response = (dh.Bits & _QR) != 0
+       dns.opcode = int(dh.Bits>>11) & 0xF
+       dns.authoritative = (dh.Bits & _AA) != 0
+       dns.truncated = (dh.Bits & _TC) != 0
+       dns.recursion_desired = (dh.Bits & _RD) != 0
+       dns.recursion_available = (dh.Bits & _RA) != 0
+       dns.rcode = int(dh.Bits & 0xF)
+
+       // Arrays.
+       dns.question = make([]dnsQuestion, dh.Qdcount)
+       dns.answer = make([]dnsRR, dh.Ancount)
+       dns.ns = make([]dnsRR, dh.Nscount)
+       dns.extra = make([]dnsRR, dh.Arcount)
+
+       for i := 0; i < len(dns.question); i++ {
+               off, ok = unpackStruct(&dns.question[i], msg, off)
+       }
+       for i := 0; i < len(dns.answer); i++ {
+               dns.answer[i], off, ok = unpackRR(msg, off)
+       }
+       for i := 0; i < len(dns.ns); i++ {
+               dns.ns[i], off, ok = unpackRR(msg, off)
+       }
+       for i := 0; i < len(dns.extra); i++ {
+               dns.extra[i], off, ok = unpackRR(msg, off)
+       }
+       if !ok {
+               return false
+       }
+       //      if off != len(msg) {
+       //              println("extra bytes in dns packet", off, "<", len(msg));
+       //      }
+       return true
+}
+
+func (dns *dnsMsg) String() string {
+       s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
+       if len(dns.question) > 0 {
+               s += "-- Questions\n"
+               for i := 0; i < len(dns.question); i++ {
+                       s += printStruct(&dns.question[i]) + "\n"
+               }
+       }
+       if len(dns.answer) > 0 {
+               s += "-- Answers\n"
+               for i := 0; i < len(dns.answer); i++ {
+                       s += printStruct(dns.answer[i]) + "\n"
+               }
+       }
+       if len(dns.ns) > 0 {
+               s += "-- Name servers\n"
+               for i := 0; i < len(dns.ns); i++ {
+                       s += printStruct(dns.ns[i]) + "\n"
+               }
+       }
+       if len(dns.extra) > 0 {
+               s += "-- Extra\n"
+               for i := 0; i < len(dns.extra); i++ {
+                       s += printStruct(dns.extra[i]) + "\n"
+               }
+       }
+       return s
+}
diff --git a/libgo/go/net/dnsname_test.go b/libgo/go/net/dnsname_test.go
new file mode 100644 (file)
index 0000000..fd65dcb
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "testing"
+       "runtime"
+)
+
+type testCase struct {
+       name   string
+       result bool
+}
+
+var tests = []testCase{
+       // RFC2181, section 11.
+       testCase{"_xmpp-server._tcp.google.com", true},
+       testCase{"_xmpp-server._tcp.google.com", true},
+       testCase{"foo.com", true},
+       testCase{"1foo.com", true},
+       testCase{"26.0.0.73.com", true},
+       testCase{"fo-o.com", true},
+       testCase{"fo1o.com", true},
+       testCase{"foo1.com", true},
+       testCase{"a.b..com", false},
+}
+
+func getTestCases(ch chan<- *testCase) {
+       defer close(ch)
+       var char59 = ""
+       var char63 = ""
+       var char64 = ""
+       for i := 0; i < 59; i++ {
+               char59 += "a"
+       }
+       char63 = char59 + "aaaa"
+       char64 = char63 + "a"
+
+       for _, tc := range tests {
+               ch <- &tc
+       }
+
+       ch <- &testCase{char63 + ".com", true}
+       ch <- &testCase{char64 + ".com", false}
+       // 255 char name is fine:
+       ch <- &testCase{char59 + "." + char63 + "." + char63 + "." +
+               char63 + ".com",
+               true}
+       // 256 char name is bad:
+       ch <- &testCase{char59 + "a." + char63 + "." + char63 + "." +
+               char63 + ".com",
+               false}
+}
+
+func TestDNSNames(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               return
+       }
+       ch := make(chan *testCase)
+       go getTestCases(ch)
+       for tc := range ch {
+               if isDomainName(tc.name) != tc.result {
+                       t.Errorf("isDomainName(%v) failed: Should be %v",
+                               tc.name, tc.result)
+               }
+       }
+}
diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go
new file mode 100644 (file)
index 0000000..d300e4b
--- /dev/null
@@ -0,0 +1,533 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO(rsc): All the prints in this file should go to standard error.
+
+package net
+
+import (
+       "io"
+       "os"
+       "sync"
+       "syscall"
+       "time"
+)
+
+// Network file descriptor.
+type netFD struct {
+       // locking/lifetime of sysfd
+       sysmu   sync.Mutex
+       sysref  int
+       closing bool
+
+       // immutable until Close
+       sysfd   int
+       family  int
+       proto   int
+       sysfile *os.File
+       cr      chan bool
+       cw      chan bool
+       net     string
+       laddr   Addr
+       raddr   Addr
+
+       // owned by client
+       rdeadline_delta int64
+       rdeadline       int64
+       rio             sync.Mutex
+       wdeadline_delta int64
+       wdeadline       int64
+       wio             sync.Mutex
+
+       // owned by fd wait server
+       ncr, ncw int
+}
+
+type InvalidConnError struct{}
+
+func (e *InvalidConnError) String() string  { return "invalid net.Conn" }
+func (e *InvalidConnError) Temporary() bool { return false }
+func (e *InvalidConnError) Timeout() bool   { return false }
+
+// A pollServer helps FDs determine when to retry a non-blocking
+// read or write after they get EAGAIN.  When an FD needs to wait,
+// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
+// request to the poll server.  Then receive on fd.cr/fd.cw.
+// When the pollServer finds that i/o on FD should be possible
+// again, it will send fd on fd.cr/fd.cw to wake any waiting processes.
+// This protocol is implemented as s.WaitRead() and s.WaitWrite().
+//
+// There is one subtlety: when sending on s.cr/s.cw, the
+// poll server is probably in a system call, waiting for an fd
+// to become ready.  It's not looking at the request channels.
+// To resolve this, the poll server waits not just on the FDs it has
+// been given but also its own pipe.  After sending on the
+// buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a
+// byte to the pipe, causing the pollServer's poll system call to
+// return.  In response to the pipe being readable, the pollServer
+// re-polls its request channels.
+//
+// Note that the ordering is "send request" and then "wake up server".
+// If the operations were reversed, there would be a race: the poll
+// server might wake up and look at the request channel, see that it
+// was empty, and go back to sleep, all before the requester managed
+// to send the request.  Because the send must complete before the wakeup,
+// the request channel must be buffered.  A buffer of size 1 is sufficient
+// for any request load.  If many processes are trying to submit requests,
+// one will succeed, the pollServer will read the request, and then the
+// channel will be empty for the next process's request.  A larger buffer
+// might help batch requests.
+//
+// To avoid races in closing, all fd operations are locked and
+// refcounted. when netFD.Close() is called, it calls syscall.Shutdown
+// and sets a closing flag. Only when the last reference is removed
+// will the fd be closed.
+
+type pollServer struct {
+       cr, cw   chan *netFD // buffered >= 1
+       pr, pw   *os.File
+       pending  map[int]*netFD
+       poll     *pollster // low-level OS hooks
+       deadline int64     // next deadline (nsec since 1970)
+}
+
+func (s *pollServer) AddFD(fd *netFD, mode int) {
+       intfd := fd.sysfd
+       if intfd < 0 {
+               // fd closed underfoot
+               if mode == 'r' {
+                       fd.cr <- true
+               } else {
+                       fd.cw <- true
+               }
+               return
+       }
+       if err := s.poll.AddFD(intfd, mode, false); err != nil {
+               panic("pollServer AddFD " + err.String())
+               return
+       }
+
+       var t int64
+       key := intfd << 1
+       if mode == 'r' {
+               fd.ncr++
+               t = fd.rdeadline
+       } else {
+               fd.ncw++
+               key++
+               t = fd.wdeadline
+       }
+       s.pending[key] = fd
+       if t > 0 && (s.deadline == 0 || t < s.deadline) {
+               s.deadline = t
+       }
+}
+
+func (s *pollServer) LookupFD(fd int, mode int) *netFD {
+       key := fd << 1
+       if mode == 'w' {
+               key++
+       }
+       netfd, ok := s.pending[key]
+       if !ok {
+               return nil
+       }
+       s.pending[key] = nil, false
+       return netfd
+}
+
+func (s *pollServer) WakeFD(fd *netFD, mode int) {
+       if mode == 'r' {
+               for fd.ncr > 0 {
+                       fd.ncr--
+                       fd.cr <- true
+               }
+       } else {
+               for fd.ncw > 0 {
+                       fd.ncw--
+                       fd.cw <- true
+               }
+       }
+}
+
+func (s *pollServer) Now() int64 {
+       return time.Nanoseconds()
+}
+
+func (s *pollServer) CheckDeadlines() {
+       now := s.Now()
+       // TODO(rsc): This will need to be handled more efficiently,
+       // probably with a heap indexed by wakeup time.
+
+       var next_deadline int64
+       for key, fd := range s.pending {
+               var t int64
+               var mode int
+               if key&1 == 0 {
+                       mode = 'r'
+               } else {
+                       mode = 'w'
+               }
+               if mode == 'r' {
+                       t = fd.rdeadline
+               } else {
+                       t = fd.wdeadline
+               }
+               if t > 0 {
+                       if t <= now {
+                               s.pending[key] = nil, false
+                               if mode == 'r' {
+                                       s.poll.DelFD(fd.sysfd, mode)
+                                       fd.rdeadline = -1
+                               } else {
+                                       s.poll.DelFD(fd.sysfd, mode)
+                                       fd.wdeadline = -1
+                               }
+                               s.WakeFD(fd, mode)
+                       } else if next_deadline == 0 || t < next_deadline {
+                               next_deadline = t
+                       }
+               }
+       }
+       s.deadline = next_deadline
+}
+
+func (s *pollServer) Run() {
+       var scratch [100]byte
+       for {
+               var t = s.deadline
+               if t > 0 {
+                       t = t - s.Now()
+                       if t <= 0 {
+                               s.CheckDeadlines()
+                               continue
+                       }
+               }
+               fd, mode, err := s.poll.WaitFD(t)
+               if err != nil {
+                       print("pollServer WaitFD: ", err.String(), "\n")
+                       return
+               }
+               if fd < 0 {
+                       // Timeout happened.
+                       s.CheckDeadlines()
+                       continue
+               }
+               if fd == s.pr.Fd() {
+                       // Drain our wakeup pipe.
+                       for nn, _ := s.pr.Read(scratch[0:]); nn > 0; {
+                               nn, _ = s.pr.Read(scratch[0:])
+                       }
+                       // Read from channels
+                       for fd, ok := <-s.cr; ok; fd, ok = <-s.cr {
+                               s.AddFD(fd, 'r')
+                       }
+                       for fd, ok := <-s.cw; ok; fd, ok = <-s.cw {
+                               s.AddFD(fd, 'w')
+                       }
+               } else {
+                       netfd := s.LookupFD(fd, mode)
+                       if netfd == nil {
+                               print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
+                               continue
+                       }
+                       s.WakeFD(netfd, mode)
+               }
+       }
+}
+
+var wakeupbuf [1]byte
+
+func (s *pollServer) Wakeup() { s.pw.Write(wakeupbuf[0:]) }
+
+func (s *pollServer) WaitRead(fd *netFD) {
+       s.cr <- fd
+       s.Wakeup()
+       <-fd.cr
+}
+
+func (s *pollServer) WaitWrite(fd *netFD) {
+       s.cw <- fd
+       s.Wakeup()
+       <-fd.cw
+}
+
+// Network FD methods.
+// All the network FDs use a single pollServer.
+
+var pollserver *pollServer
+var onceStartServer sync.Once
+
+func startServer() {
+       p, err := newPollServer()
+       if err != nil {
+               print("Start pollServer: ", err.String(), "\n")
+       }
+       pollserver = p
+}
+
+func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
+       onceStartServer.Do(startServer)
+       if e := syscall.SetNonblock(fd, true); e != 0 {
+               return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)}
+       }
+       f = &netFD{
+               sysfd:  fd,
+               family: family,
+               proto:  proto,
+               net:    net,
+               laddr:  laddr,
+               raddr:  raddr,
+       }
+       var ls, rs string
+       if laddr != nil {
+               ls = laddr.String()
+       }
+       if raddr != nil {
+               rs = raddr.String()
+       }
+       f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs)
+       f.cr = make(chan bool, 1)
+       f.cw = make(chan bool, 1)
+       return f, nil
+}
+
+// Add a reference to this fd.
+func (fd *netFD) incref() {
+       fd.sysmu.Lock()
+       fd.sysref++
+       fd.sysmu.Unlock()
+}
+
+// Remove a reference to this FD and close if we've been asked to do so (and
+// there are no references left.
+func (fd *netFD) decref() {
+       fd.sysmu.Lock()
+       fd.sysref--
+       if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
+               // In case the user has set linger, switch to blocking mode so
+               // the close blocks.  As long as this doesn't happen often, we
+               // can handle the extra OS processes.  Otherwise we'll need to
+               // use the pollserver for Close too.  Sigh.
+               syscall.SetNonblock(fd.sysfd, false)
+               fd.sysfile.Close()
+               fd.sysfile = nil
+               fd.sysfd = -1
+       }
+       fd.sysmu.Unlock()
+}
+
+func (fd *netFD) Close() os.Error {
+       if fd == nil || fd.sysfile == nil {
+               return os.EINVAL
+       }
+
+       fd.incref()
+       syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
+       fd.closing = true
+       fd.decref()
+       return nil
+}
+
+func (fd *netFD) Read(p []byte) (n int, err os.Error) {
+       if fd == nil {
+               return 0, os.EINVAL
+       }
+       fd.rio.Lock()
+       defer fd.rio.Unlock()
+       fd.incref()
+       defer fd.decref()
+       if fd.sysfile == nil {
+               return 0, os.EINVAL
+       }
+       if fd.rdeadline_delta > 0 {
+               fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+       } else {
+               fd.rdeadline = 0
+       }
+       var oserr os.Error
+       for {
+               var errno int
+               n, errno = syscall.Read(fd.sysfile.Fd(), p)
+               if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
+                       pollserver.WaitRead(fd)
+                       continue
+               }
+               if errno != 0 {
+                       n = 0
+                       oserr = os.Errno(errno)
+               } else if n == 0 && errno == 0 && fd.proto != syscall.SOCK_DGRAM {
+                       err = os.EOF
+               }
+               break
+       }
+       if oserr != nil {
+               err = &OpError{"read", fd.net, fd.raddr, oserr}
+       }
+       return
+}
+
+func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
+       if fd == nil || fd.sysfile == nil {
+               return 0, nil, os.EINVAL
+       }
+       fd.rio.Lock()
+       defer fd.rio.Unlock()
+       fd.incref()
+       defer fd.decref()
+       if fd.rdeadline_delta > 0 {
+               fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+       } else {
+               fd.rdeadline = 0
+       }
+       var oserr os.Error
+       for {
+               var errno int
+               n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0)
+               if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
+                       pollserver.WaitRead(fd)
+                       continue
+               }
+               if errno != 0 {
+                       n = 0
+                       oserr = os.Errno(errno)
+               }
+               break
+       }
+       if oserr != nil {
+               err = &OpError{"read", fd.net, fd.laddr, oserr}
+       }
+       return
+}
+
+func (fd *netFD) Write(p []byte) (n int, err os.Error) {
+       if fd == nil {
+               return 0, os.EINVAL
+       }
+       fd.wio.Lock()
+       defer fd.wio.Unlock()
+       fd.incref()
+       defer fd.decref()
+       if fd.sysfile == nil {
+               return 0, os.EINVAL
+       }
+       if fd.wdeadline_delta > 0 {
+               fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+       } else {
+               fd.wdeadline = 0
+       }
+       nn := 0
+       var oserr os.Error
+
+       for {
+               n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:])
+               if n > 0 {
+                       nn += n
+               }
+               if nn == len(p) {
+                       break
+               }
+               if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
+                       pollserver.WaitWrite(fd)
+                       continue
+               }
+               if errno != 0 {
+                       n = 0
+                       oserr = os.Errno(errno)
+                       break
+               }
+               if n == 0 {
+                       oserr = io.ErrUnexpectedEOF
+                       break
+               }
+       }
+       if oserr != nil {
+               err = &OpError{"write", fd.net, fd.raddr, oserr}
+       }
+       return nn, err
+}
+
+func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
+       if fd == nil || fd.sysfile == nil {
+               return 0, os.EINVAL
+       }
+       fd.wio.Lock()
+       defer fd.wio.Unlock()
+       fd.incref()
+       defer fd.decref()
+       if fd.wdeadline_delta > 0 {
+               fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+       } else {
+               fd.wdeadline = 0
+       }
+       var oserr os.Error
+       for {
+               errno := syscall.Sendto(fd.sysfd, p, 0, sa)
+               if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
+                       pollserver.WaitWrite(fd)
+                       continue
+               }
+               if errno != 0 {
+                       oserr = os.Errno(errno)
+               }
+               break
+       }
+       if oserr == nil {
+               n = len(p)
+       } else {
+               err = &OpError{"write", fd.net, fd.raddr, oserr}
+       }
+       return
+}
+
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
+       if fd == nil || fd.sysfile == nil {
+               return nil, os.EINVAL
+       }
+
+       fd.incref()
+       defer fd.decref()
+
+       // See ../syscall/exec.go for description of ForkLock.
+       // It is okay to hold the lock across syscall.Accept
+       // because we have put fd.sysfd into non-blocking mode.
+       syscall.ForkLock.RLock()
+       var s, e int
+       var sa syscall.Sockaddr
+       for {
+               s, sa, e = syscall.Accept(fd.sysfd)
+               if e != syscall.EAGAIN {
+                       break
+               }
+               syscall.ForkLock.RUnlock()
+               pollserver.WaitRead(fd)
+               syscall.ForkLock.RLock()
+       }
+       if e != 0 {
+               syscall.ForkLock.RUnlock()
+               return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)}
+       }
+       syscall.CloseOnExec(s)
+       syscall.ForkLock.RUnlock()
+
+       if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil {
+               syscall.Close(s)
+               return nil, err
+       }
+       return nfd, nil
+}
+
+func (fd *netFD) dup() (f *os.File, err os.Error) {
+       ns, e := syscall.Dup(fd.sysfd)
+       if e != 0 {
+               return nil, &OpError{"dup", fd.net, fd.laddr, os.Errno(e)}
+       }
+
+       // We want blocking mode for the new fd, hence the double negative.
+       if e = syscall.SetNonblock(ns, false); e != 0 {
+               return nil, &OpError{"setnonblock", fd.net, fd.laddr, os.Errno(e)}
+       }
+
+       return os.NewFile(ns, fd.sysfile.Name()), nil
+}
diff --git a/libgo/go/net/fd_linux.go b/libgo/go/net/fd_linux.go
new file mode 100644 (file)
index 0000000..ef86cb1
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via epoll(7).
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+const (
+       readFlags  = syscall.EPOLLIN | syscall.EPOLLRDHUP
+       writeFlags = syscall.EPOLLOUT
+)
+
+type pollster struct {
+       epfd int
+
+       // Events we're already waiting for
+       events map[int]uint32
+}
+
+func newpollster() (p *pollster, err os.Error) {
+       p = new(pollster)
+       var e int
+
+       // The arg to epoll_create is a hint to the kernel
+       // about the number of FDs we will care about.
+       // We don't know.
+       if p.epfd, e = syscall.EpollCreate(16); e != 0 {
+               return nil, os.NewSyscallError("epoll_create", e)
+       }
+       p.events = make(map[int]uint32)
+       return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
+       var ev syscall.EpollEvent
+       var already bool
+       ev.Fd = int32(fd)
+       ev.Events, already = p.events[fd]
+       if !repeat {
+               ev.Events |= syscall.EPOLLONESHOT
+       }
+       if mode == 'r' {
+               ev.Events |= readFlags
+       } else {
+               ev.Events |= writeFlags
+       }
+
+       var op int
+       if already {
+               op = syscall.EPOLL_CTL_MOD
+       } else {
+               op = syscall.EPOLL_CTL_ADD
+       }
+       if e := syscall.EpollCtl(p.epfd, op, fd, &ev); e != 0 {
+               return os.NewSyscallError("epoll_ctl", e)
+       }
+       p.events[fd] = ev.Events
+       return nil
+}
+
+func (p *pollster) StopWaiting(fd int, bits uint) {
+       events, already := p.events[fd]
+       if !already {
+               print("Epoll unexpected fd=", fd, "\n")
+               return
+       }
+
+       // If syscall.EPOLLONESHOT is not set, the wait
+       // is a repeating wait, so don't change it.
+       if events&syscall.EPOLLONESHOT == 0 {
+               return
+       }
+
+       // Disable the given bits.
+       // If we're still waiting for other events, modify the fd
+       // event in the kernel.  Otherwise, delete it.
+       events &= ^uint32(bits)
+       if int32(events)&^syscall.EPOLLONESHOT != 0 {
+               var ev syscall.EpollEvent
+               ev.Fd = int32(fd)
+               ev.Events = events
+               if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &ev); e != 0 {
+                       print("Epoll modify fd=", fd, ": ", os.Errno(e).String(), "\n")
+               }
+               p.events[fd] = events
+       } else {
+               if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != 0 {
+                       print("Epoll delete fd=", fd, ": ", os.Errno(e).String(), "\n")
+               }
+               p.events[fd] = 0, false
+       }
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+       if mode == 'r' {
+               p.StopWaiting(fd, readFlags)
+       } else {
+               p.StopWaiting(fd, writeFlags)
+       }
+}
+
+func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
+       // Get an event.
+       var evarray [1]syscall.EpollEvent
+       ev := &evarray[0]
+       var msec int = -1
+       if nsec > 0 {
+               msec = int((nsec + 1e6 - 1) / 1e6)
+       }
+       n, e := syscall.EpollWait(p.epfd, evarray[0:], msec)
+       for e == syscall.EAGAIN || e == syscall.EINTR {
+               n, e = syscall.EpollWait(p.epfd, evarray[0:], msec)
+       }
+       if e != 0 {
+               return -1, 0, os.NewSyscallError("epoll_wait", e)
+       }
+       if n == 0 {
+               return -1, 0, nil
+       }
+       fd = int(ev.Fd)
+
+       if ev.Events&writeFlags != 0 {
+               p.StopWaiting(fd, writeFlags)
+               return fd, 'w', nil
+       }
+       if ev.Events&readFlags != 0 {
+               p.StopWaiting(fd, readFlags)
+               return fd, 'r', nil
+       }
+
+       // Other events are error conditions - wake whoever is waiting.
+       events, _ := p.events[fd]
+       if events&writeFlags != 0 {
+               p.StopWaiting(fd, writeFlags)
+               return fd, 'w', nil
+       }
+       p.StopWaiting(fd, readFlags)
+       return fd, 'r', nil
+}
+
+func (p *pollster) Close() os.Error {
+       return os.NewSyscallError("close", syscall.Close(p.epfd))
+}
diff --git a/libgo/go/net/fd_rtems.go b/libgo/go/net/fd_rtems.go
new file mode 100644 (file)
index 0000000..61759ca
--- /dev/null
@@ -0,0 +1,137 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via select(2).
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+type pollster struct {
+       readFds, writeFds, repeatFds *syscall.FdSet_t
+       maxFd int
+       readyReadFds, readyWriteFds *syscall.FdSet_t
+       nReady int
+       lastFd int
+}
+
+func newpollster() (p *pollster, err os.Error) {
+       p = new(pollster)
+       p.readFds = new(syscall.FdSet_t)
+       p.writeFds = new(syscall.FdSet_t)
+       p.repeatFds = new(syscall.FdSet_t)
+       p.readyReadFds = new(syscall.FdSet_t)
+       p.readyWriteFds = new(syscall.FdSet_t)
+       p.maxFd = -1
+       p.nReady = 0
+       p.lastFd = 0
+       return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
+       if mode == 'r' {
+               syscall.FDSet(fd, p.readFds)
+       } else {
+               syscall.FDSet(fd, p.writeFds)
+       }
+
+       if repeat {
+               syscall.FDSet(fd, p.repeatFds)
+       }
+
+       if fd > p.maxFd {
+               p.maxFd = fd
+       }
+
+       return nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+       if mode == 'r' {
+               if !syscall.FDIsSet(fd, p.readFds) {
+                       print("Select unexpected fd=", fd, " for read\n")
+                       return
+               }
+               syscall.FDClr(fd, p.readFds)
+       } else {
+               if !syscall.FDIsSet(fd, p.writeFds) {
+                       print("Select unexpected fd=", fd, " for write\n")
+                       return
+               }
+               syscall.FDClr(fd, p.writeFds)
+       }
+
+       // Doesn't matter if not already present.
+       syscall.FDClr(fd, p.repeatFds)
+
+       // We don't worry about maxFd here.
+}
+
+func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
+       if p.nReady == 0 {
+               var timeout *syscall.Timeval
+               var tv syscall.Timeval
+               timeout = nil
+               if nsec > 0 {
+                       tv = syscall.NsecToTimeval(nsec)
+                       timeout = &tv
+               }
+
+               var n, e int
+               var tmpReadFds, tmpWriteFds syscall.FdSet_t
+               for {
+                       // Temporary syscall.FdSet_ts into which the values are copied
+                       // because select mutates the values.
+                       tmpReadFds = *p.readFds
+                       tmpWriteFds = *p.writeFds
+
+                       n, e = syscall.Select(p.maxFd + 1, &tmpReadFds, &tmpWriteFds, nil, timeout)
+                       if e != syscall.EINTR {
+                               break
+                       }
+               }
+               if e != 0 {
+                       return -1, 0, os.NewSyscallError("select", e)
+               }
+               if n == 0 {
+                       return -1, 0, nil
+               }
+
+               p.nReady = n
+               *p.readyReadFds = tmpReadFds
+               *p.readyWriteFds = tmpWriteFds
+               p.lastFd = 0
+       }
+
+       flag := false
+       for i := p.lastFd; i < p.maxFd + 1; i++ {
+               if syscall.FDIsSet(i, p.readyReadFds) {
+                       flag = true
+                       mode = 'r'
+                       syscall.FDClr(i, p.readyReadFds)
+               } else if syscall.FDIsSet(i, p.readyWriteFds) {
+                       flag = true
+                       mode = 'w'
+                       syscall.FDClr(i, p.readyWriteFds)
+               }
+               if flag {
+                       if !syscall.FDIsSet(i, p.repeatFds) {
+                               p.DelFD(i, mode)
+                       }
+                       p.nReady--
+                       p.lastFd = i
+                       return i, mode, nil
+               }
+       }
+
+       // Will not reach here.  Just to shut up the compiler.
+       return -1, 0, nil
+}
+
+func (p *pollster) Close() os.Error {
+       return nil
+}
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
new file mode 100644 (file)
index 0000000..1da2ca4
--- /dev/null
@@ -0,0 +1,380 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "os"
+       "sync"
+       "syscall"
+       "unsafe"
+)
+
+// BUG(brainman): The Windows implementation does not implement SetTimeout.
+
+// IO completion result parameters.
+type ioResult struct {
+       key   uint32
+       qty   uint32
+       errno int
+}
+
+// Network file descriptor.
+type netFD struct {
+       // locking/lifetime of sysfd
+       sysmu   sync.Mutex
+       sysref  int
+       closing bool
+
+       // immutable until Close
+       sysfd   int
+       family  int
+       proto   int
+       sysfile *os.File
+       cr      chan *ioResult
+       cw      chan *ioResult
+       net     string
+       laddr   Addr
+       raddr   Addr
+
+       // owned by client
+       rdeadline_delta int64
+       rdeadline       int64
+       rio             sync.Mutex
+       wdeadline_delta int64
+       wdeadline       int64
+       wio             sync.Mutex
+}
+
+type InvalidConnError struct{}
+
+func (e *InvalidConnError) String() string  { return "invalid net.Conn" }
+func (e *InvalidConnError) Temporary() bool { return false }
+func (e *InvalidConnError) Timeout() bool   { return false }
+
+// pollServer will run around waiting for io completion request
+// to arrive. Every request received will contain channel to signal
+// io owner about the completion.
+
+type pollServer struct {
+       iocp int32
+}
+
+func newPollServer() (s *pollServer, err os.Error) {
+       s = new(pollServer)
+       var e int
+       if s.iocp, e = syscall.CreateIoCompletionPort(-1, 0, 0, 1); e != 0 {
+               return nil, os.NewSyscallError("CreateIoCompletionPort", e)
+       }
+       go s.Run()
+       return s, nil
+}
+
+type ioPacket struct {
+       // Used by IOCP interface,
+       // it must be first field of the struct,
+       // as our code rely on it.
+       o syscall.Overlapped
+
+       // Link to the io owner.
+       c chan *ioResult
+}
+
+func (s *pollServer) getCompletedIO() (ov *syscall.Overlapped, result *ioResult, err os.Error) {
+       var r ioResult
+       var o *syscall.Overlapped
+       _, e := syscall.GetQueuedCompletionStatus(s.iocp, &r.qty, &r.key, &o, syscall.INFINITE)
+       switch {
+       case e == 0:
+               // Dequeued successfully completed io packet.
+               return o, &r, nil
+       case e == syscall.WAIT_TIMEOUT && o == nil:
+               // Wait has timed out (should not happen now, but might be used in the future).
+               return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
+       case o == nil:
+               // Failed to dequeue anything -> report the error.
+               return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
+       default:
+               // Dequeued failed io packet.
+               r.errno = e
+               return o, &r, nil
+       }
+       return
+}
+
+func (s *pollServer) Run() {
+       for {
+               o, r, err := s.getCompletedIO()
+               if err != nil {
+                       panic("Run pollServer: " + err.String() + "\n")
+               }
+               p := (*ioPacket)(unsafe.Pointer(o))
+               p.c <- r
+       }
+}
+
+// Network FD methods.
+// All the network FDs use a single pollServer.
+
+var pollserver *pollServer
+var onceStartServer sync.Once
+
+func startServer() {
+       p, err := newPollServer()
+       if err != nil {
+               panic("Start pollServer: " + err.String() + "\n")
+       }
+       pollserver = p
+}
+
+var initErr os.Error
+
+func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
+       if initErr != nil {
+               return nil, initErr
+       }
+       onceStartServer.Do(startServer)
+       // Associate our socket with pollserver.iocp.
+       if _, e := syscall.CreateIoCompletionPort(int32(fd), pollserver.iocp, 0, 0); e != 0 {
+               return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)}
+       }
+       f = &netFD{
+               sysfd:  fd,
+               family: family,
+               proto:  proto,
+               cr:     make(chan *ioResult),
+               cw:     make(chan *ioResult),
+               net:    net,
+               laddr:  laddr,
+               raddr:  raddr,
+       }
+       var ls, rs string
+       if laddr != nil {
+               ls = laddr.String()
+       }
+       if raddr != nil {
+               rs = raddr.String()
+       }
+       f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs)
+       return f, nil
+}
+
+// Add a reference to this fd.
+func (fd *netFD) incref() {
+       fd.sysmu.Lock()
+       fd.sysref++
+       fd.sysmu.Unlock()
+}
+
+// Remove a reference to this FD and close if we've been asked to do so (and
+// there are no references left.
+func (fd *netFD) decref() {
+       fd.sysmu.Lock()
+       fd.sysref--
+       if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
+               // In case the user has set linger, switch to blocking mode so
+               // the close blocks.  As long as this doesn't happen often, we
+               // can handle the extra OS processes.  Otherwise we'll need to
+               // use the pollserver for Close too.  Sigh.
+               syscall.SetNonblock(fd.sysfd, false)
+               fd.sysfile.Close()
+               fd.sysfile = nil
+               fd.sysfd = -1
+       }
+       fd.sysmu.Unlock()
+}
+
+func (fd *netFD) Close() os.Error {
+       if fd == nil || fd.sysfile == nil {
+               return os.EINVAL
+       }
+
+       fd.incref()
+       syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
+       fd.closing = true
+       fd.decref()
+       return nil
+}
+
+func newWSABuf(p []byte) *syscall.WSABuf {
+       var p0 *byte
+       if len(p) > 0 {
+               p0 = (*byte)(unsafe.Pointer(&p[0]))
+       }
+       return &syscall.WSABuf{uint32(len(p)), p0}
+}
+
+func (fd *netFD) Read(p []byte) (n int, err os.Error) {
+       if fd == nil {
+               return 0, os.EINVAL
+       }
+       fd.rio.Lock()
+       defer fd.rio.Unlock()
+       fd.incref()
+       defer fd.decref()
+       if fd.sysfile == nil {
+               return 0, os.EINVAL
+       }
+       // Submit receive request.
+       var pckt ioPacket
+       pckt.c = fd.cr
+       var done uint32
+       flags := uint32(0)
+       e := syscall.WSARecv(uint32(fd.sysfd), newWSABuf(p), 1, &done, &flags, &pckt.o, nil)
+       switch e {
+       case 0:
+               // IO completed immediately, but we need to get our completion message anyway.
+       case syscall.ERROR_IO_PENDING:
+               // IO started, and we have to wait for it's completion.
+       default:
+               return 0, &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(e)}
+       }
+       // Wait for our request to complete.
+       r := <-pckt.c
+       if r.errno != 0 {
+               err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)}
+       }
+       n = int(r.qty)
+       if err == nil && n == 0 {
+               err = os.EOF
+       }
+       return
+}
+
+func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
+       var r syscall.Sockaddr
+       return 0, r, nil
+}
+
+func (fd *netFD) Write(p []byte) (n int, err os.Error) {
+       if fd == nil {
+               return 0, os.EINVAL
+       }
+       fd.wio.Lock()
+       defer fd.wio.Unlock()
+       fd.incref()
+       defer fd.decref()
+       if fd.sysfile == nil {
+               return 0, os.EINVAL
+       }
+       // Submit send request.
+       var pckt ioPacket
+       pckt.c = fd.cw
+       var done uint32
+       e := syscall.WSASend(uint32(fd.sysfd), newWSABuf(p), 1, &done, uint32(0), &pckt.o, nil)
+       switch e {
+       case 0:
+               // IO completed immediately, but we need to get our completion message anyway.
+       case syscall.ERROR_IO_PENDING:
+               // IO started, and we have to wait for it's completion.
+       default:
+               return 0, &OpError{"WSASend", fd.net, fd.laddr, os.Errno(e)}
+       }
+       // Wait for our request to complete.
+       r := <-pckt.c
+       if r.errno != 0 {
+               err = &OpError{"WSASend", fd.net, fd.laddr, os.Errno(r.errno)}
+       }
+       n = int(r.qty)
+       return
+}
+
+func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
+       return 0, nil
+}
+
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
+       if fd == nil || fd.sysfile == nil {
+               return nil, os.EINVAL
+       }
+       fd.incref()
+       defer fd.decref()
+
+       // Get new socket.
+       // See ../syscall/exec.go for description of ForkLock.
+       syscall.ForkLock.RLock()
+       s, e := syscall.Socket(fd.family, fd.proto, 0)
+       if e != 0 {
+               syscall.ForkLock.RUnlock()
+               return nil, os.Errno(e)
+       }
+       syscall.CloseOnExec(s)
+       syscall.ForkLock.RUnlock()
+
+       // Associate our new socket with IOCP.
+       onceStartServer.Do(startServer)
+       if _, e = syscall.CreateIoCompletionPort(int32(s), pollserver.iocp, 0, 0); e != 0 {
+               return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
+       }
+
+       // Submit accept request.
+       // Will use new unique channel here, because, unlike Read or Write,
+       // Accept is expected to be executed by many goroutines simultaniously.
+       var pckt ioPacket
+       pckt.c = make(chan *ioResult)
+       attrs, e := syscall.AcceptIOCP(fd.sysfd, s, &pckt.o)
+       switch e {
+       case 0:
+               // IO completed immediately, but we need to get our completion message anyway.
+       case syscall.ERROR_IO_PENDING:
+               // IO started, and we have to wait for it's completion.
+       default:
+               syscall.Close(s)
+               return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(e)}
+       }
+
+       // Wait for peer connection.
+       r := <-pckt.c
+       if r.errno != 0 {
+               syscall.Close(s)
+               return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(r.errno)}
+       }
+
+       // Inherit properties of the listening socket.
+       e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd)
+       if e != 0 {
+               syscall.Close(s)
+               return nil, &OpError{"Setsockopt", fd.net, fd.laddr, os.Errno(r.errno)}
+       }
+
+       // Get local and peer addr out of AcceptEx buffer.
+       lsa, rsa := syscall.GetAcceptIOCPSockaddrs(attrs)
+
+       // Create our netFD and return it for further use.
+       laddr := toAddr(lsa)
+       raddr := toAddr(rsa)
+
+       f := &netFD{
+               sysfd:  s,
+               family: fd.family,
+               proto:  fd.proto,
+               cr:     make(chan *ioResult),
+               cw:     make(chan *ioResult),
+               net:    fd.net,
+               laddr:  laddr,
+               raddr:  raddr,
+       }
+       var ls, rs string
+       if laddr != nil {
+               ls = laddr.String()
+       }
+       if raddr != nil {
+               rs = raddr.String()
+       }
+       f.sysfile = os.NewFile(s, fd.net+":"+ls+"->"+rs)
+       return f, nil
+}
+
+func init() {
+       var d syscall.WSAData
+       e := syscall.WSAStartup(uint32(0x101), &d)
+       if e != 0 {
+               initErr = os.NewSyscallError("WSAStartup", e)
+       }
+}
+
+func (fd *netFD) dup() (f *os.File, err os.Error) {
+       // TODO: Implement this
+       return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
+}
diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go
new file mode 100644 (file)
index 0000000..556d57f
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Read static host/IP entries from /etc/hosts.
+
+package net
+
+import (
+       "os"
+       "sync"
+)
+
+const cacheMaxAge = int64(300) // 5 minutes.
+
+// hostsPath points to the file with static IP/address entries.
+var hostsPath = "/etc/hosts"
+
+// Simple cache.
+var hosts struct {
+       sync.Mutex
+       data map[string][]string
+       time int64
+       path string
+}
+
+func readHosts() {
+       now, _, _ := os.Time()
+       hp := hostsPath
+       if len(hosts.data) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
+               hs := make(map[string][]string)
+               var file *file
+               if file, _ = open(hp); file == nil {
+                       return
+               }
+               for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+                       if i := byteIndex(line, '#'); i >= 0 {
+                               // Discard comments.
+                               line = line[0:i]
+                       }
+                       f := getFields(line)
+                       if len(f) < 2 || ParseIP(f[0]) == nil {
+                               continue
+                       }
+                       for i := 1; i < len(f); i++ {
+                               h := f[i]
+                               hs[h] = append(hs[h], f[0])
+                       }
+               }
+               // Update the data cache.
+               hosts.time, _, _ = os.Time()
+               hosts.path = hp
+               hosts.data = hs
+               file.close()
+       }
+}
+
+// lookupStaticHosts looks up the addresses for the given host from /etc/hosts.
+func lookupStaticHost(host string) []string {
+       hosts.Lock()
+       defer hosts.Unlock()
+       readHosts()
+       if len(hosts.data) != 0 {
+               if ips, ok := hosts.data[host]; ok {
+                       return ips
+               }
+       }
+       return nil
+}
diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go
new file mode 100644 (file)
index 0000000..84cd92e
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "testing"
+)
+
+type hostTest struct {
+       host string
+       ips  []IP
+}
+
+
+var hosttests = []hostTest{
+       {"odin", []IP{
+               IPv4(127, 0, 0, 2),
+               IPv4(127, 0, 0, 3),
+               ParseIP("::2"),
+       }},
+       {"thor", []IP{
+               IPv4(127, 1, 1, 1),
+       }},
+       {"loki", []IP{}},
+       {"ullr", []IP{
+               IPv4(127, 1, 1, 2),
+       }},
+       {"ullrhost", []IP{
+               IPv4(127, 1, 1, 2),
+       }},
+}
+
+func TestLookupStaticHost(t *testing.T) {
+       p := hostsPath
+       hostsPath = "hosts_testdata"
+       for i := 0; i < len(hosttests); i++ {
+               tt := hosttests[i]
+               ips := lookupStaticHost(tt.host)
+               if len(ips) != len(tt.ips) {
+                       t.Errorf("# of hosts = %v; want %v",
+                               len(ips), len(tt.ips))
+                       return
+               }
+               for k, v := range ips {
+                       if tt.ips[k].String() != v {
+                               t.Errorf("lookupStaticHost(%q) = %v; want %v",
+                                       tt.host, v, tt.ips[k])
+                       }
+               }
+       }
+       hostsPath = p
+}
diff --git a/libgo/go/net/hosts_testdata b/libgo/go/net/hosts_testdata
new file mode 100644 (file)
index 0000000..b601763
--- /dev/null
@@ -0,0 +1,12 @@
+255.255.255.255        broadcasthost
+127.0.0.2      odin
+127.0.0.3      odin  # inline comment 
+::2             odin
+127.1.1.1      thor
+# aliases
+127.1.1.2      ullr ullrhost
+# Bogus entries that must be ignored.
+123.123.123    loki
+321.321.321.321
+# TODO(yvesj): Should we be able to parse this? From a Darwin system.
+fe80::1%lo0    localhost
diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go
new file mode 100644 (file)
index 0000000..e82224a
--- /dev/null
@@ -0,0 +1,446 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IP address manipulations
+//
+// IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes.
+// An IPv4 address can be converted to an IPv6 address by
+// adding a canonical prefix (10 zeros, 2 0xFFs).
+// This library accepts either size of byte array but always
+// returns 16-byte addresses.
+
+package net
+
+// IP address lengths (bytes).
+const (
+       IPv4len = 4
+       IPv6len = 16
+)
+
+// An IP is a single IP address, an array of bytes.
+// Functions in this package accept either 4-byte (IP v4)
+// or 16-byte (IP v6) arrays as input.  Unless otherwise
+// specified, functions in this package always return
+// IP addresses in 16-byte form using the canonical
+// embedding.
+//
+// Note that in this documentation, referring to an
+// IP address as an IPv4 address or an IPv6 address
+// is a semantic property of the address, not just the
+// length of the byte array: a 16-byte array can still
+// be an IPv4 address.
+type IP []byte
+
+// An IP mask is an IP address.
+type IPMask []byte
+
+// IPv4 returns the IP address (in 16-byte form) of the
+// IPv4 address a.b.c.d.
+func IPv4(a, b, c, d byte) IP {
+       p := make(IP, IPv6len)
+       for i := 0; i < 10; i++ {
+               p[i] = 0
+       }
+       p[10] = 0xff
+       p[11] = 0xff
+       p[12] = a
+       p[13] = b
+       p[14] = c
+       p[15] = d
+       return p
+}
+
+// IPv4Mask returns the IP mask (in 16-byte form) of the
+// IPv4 mask a.b.c.d.
+func IPv4Mask(a, b, c, d byte) IPMask {
+       p := make(IPMask, IPv6len)
+       for i := 0; i < 12; i++ {
+               p[i] = 0xff
+       }
+       p[12] = a
+       p[13] = b
+       p[14] = c
+       p[15] = d
+       return p
+}
+
+// Well-known IPv4 addresses
+var (
+       IPv4bcast     = IPv4(255, 255, 255, 255) // broadcast
+       IPv4allsys    = IPv4(224, 0, 0, 1)       // all systems
+       IPv4allrouter = IPv4(224, 0, 0, 2)       // all routers
+       IPv4zero      = IPv4(0, 0, 0, 0)         // all zeros
+)
+
+// Well-known IPv6 addresses
+var (
+       IPzero = make(IP, IPv6len) // all zeros
+)
+
+// Is p all zeros?
+func isZeros(p IP) bool {
+       for i := 0; i < len(p); i++ {
+               if p[i] != 0 {
+                       return false
+               }
+       }
+       return true
+}
+
+// To4 converts the IPv4 address ip to a 4-byte representation.
+// If ip is not an IPv4 address, To4 returns nil.
+func (ip IP) To4() IP {
+       if len(ip) == IPv4len {
+               return ip
+       }
+       if len(ip) == IPv6len &&
+               isZeros(ip[0:10]) &&
+               ip[10] == 0xff &&
+               ip[11] == 0xff {
+               return ip[12:16]
+       }
+       return nil
+}
+
+// To16 converts the IP address ip to a 16-byte representation.
+// If ip is not an IP address (it is the wrong length), To16 returns nil.
+func (ip IP) To16() IP {
+       if len(ip) == IPv4len {
+               return IPv4(ip[0], ip[1], ip[2], ip[3])
+       }
+       if len(ip) == IPv6len {
+               return ip
+       }
+       return nil
+}
+
+// Default route masks for IPv4.
+var (
+       classAMask = IPv4Mask(0xff, 0, 0, 0)
+       classBMask = IPv4Mask(0xff, 0xff, 0, 0)
+       classCMask = IPv4Mask(0xff, 0xff, 0xff, 0)
+)
+
+// DefaultMask returns the default IP mask for the IP address ip.
+// Only IPv4 addresses have default masks; DefaultMask returns
+// nil if ip is not a valid IPv4 address.
+func (ip IP) DefaultMask() IPMask {
+       if ip = ip.To4(); ip == nil {
+               return nil
+       }
+       switch true {
+       case ip[0] < 0x80:
+               return classAMask
+       case ip[0] < 0xC0:
+               return classBMask
+       default:
+               return classCMask
+       }
+       return nil // not reached
+}
+
+// Mask returns the result of masking the IP address ip with mask.
+func (ip IP) Mask(mask IPMask) IP {
+       n := len(ip)
+       if n != len(mask) {
+               return nil
+       }
+       out := make(IP, n)
+       for i := 0; i < n; i++ {
+               out[i] = ip[i] & mask[i]
+       }
+       return out
+}
+
+// Convert i to decimal string.
+func itod(i uint) string {
+       if i == 0 {
+               return "0"
+       }
+
+       // Assemble decimal in reverse order.
+       var b [32]byte
+       bp := len(b)
+       for ; i > 0; i /= 10 {
+               bp--
+               b[bp] = byte(i%10) + '0'
+       }
+
+       return string(b[bp:])
+}
+
+// Convert i to hexadecimal string.
+func itox(i uint) string {
+       if i == 0 {
+               return "0"
+       }
+
+       // Assemble hexadecimal in reverse order.
+       var b [32]byte
+       bp := len(b)
+       for ; i > 0; i /= 16 {
+               bp--
+               b[bp] = "0123456789abcdef"[byte(i%16)]
+       }
+
+       return string(b[bp:])
+}
+
+// String returns the string form of the IP address ip.
+// If the address is an IPv4 address, the string representation
+// is dotted decimal ("74.125.19.99").  Otherwise the representation
+// is IPv6 ("2001:4860:0:2001::68").
+func (ip IP) String() string {
+       p := ip
+
+       if len(ip) == 0 {
+               return ""
+       }
+
+       // If IPv4, use dotted notation.
+       if p4 := p.To4(); len(p4) == 4 {
+               return itod(uint(p4[0])) + "." +
+                       itod(uint(p4[1])) + "." +
+                       itod(uint(p4[2])) + "." +
+                       itod(uint(p4[3]))
+       }
+       if len(p) != IPv6len {
+               return "?"
+       }
+
+       // Find longest run of zeros.
+       e0 := -1
+       e1 := -1
+       for i := 0; i < 16; i += 2 {
+               j := i
+               for j < 16 && p[j] == 0 && p[j+1] == 0 {
+                       j += 2
+               }
+               if j > i && j-i > e1-e0 {
+                       e0 = i
+                       e1 = j
+               }
+       }
+       // The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field.
+       if e1-e0 <= 2 {
+               e0 = -1
+               e1 = -1
+       }
+
+       // Print with possible :: in place of run of zeros
+       var s string
+       for i := 0; i < 16; i += 2 {
+               if i == e0 {
+                       s += "::"
+                       i = e1
+                       if i >= 16 {
+                               break
+                       }
+               } else if i > 0 {
+                       s += ":"
+               }
+               s += itox((uint(p[i]) << 8) | uint(p[i+1]))
+       }
+       return s
+}
+
+// If mask is a sequence of 1 bits followed by 0 bits,
+// return the number of 1 bits.
+func simpleMaskLength(mask IPMask) int {
+       var n int
+       for i, v := range mask {
+               if v == 0xff {
+                       n += 8
+                       continue
+               }
+               // found non-ff byte
+               // count 1 bits
+               for v&0x80 != 0 {
+                       n++
+                       v <<= 1
+               }
+               // rest must be 0 bits
+               if v != 0 {
+                       return -1
+               }
+               for i++; i < len(mask); i++ {
+                       if mask[i] != 0 {
+                               return -1
+                       }
+               }
+               break
+       }
+       return n
+}
+
+// String returns the string representation of mask.
+// If the mask is in the canonical form--ones followed by zeros--the
+// string representation is just the decimal number of ones.
+// If the mask is in a non-canonical form, it is formatted
+// as an IP address.
+func (mask IPMask) String() string {
+       switch len(mask) {
+       case 4:
+               n := simpleMaskLength(mask)
+               if n >= 0 {
+                       return itod(uint(n + (IPv6len-IPv4len)*8))
+               }
+       case 16:
+               n := simpleMaskLength(mask)
+               if n >= 12*8 {
+                       return itod(uint(n - 12*8))
+               }
+       }
+       return IP(mask).String()
+}
+
+// Parse IPv4 address (d.d.d.d).
+func parseIPv4(s string) IP {
+       var p [IPv4len]byte
+       i := 0
+       for j := 0; j < IPv4len; j++ {
+               if i >= len(s) {
+                       // Missing octets.
+                       return nil
+               }
+               if j > 0 {
+                       if s[i] != '.' {
+                               return nil
+                       }
+                       i++
+               }
+               var (
+                       n  int
+                       ok bool
+               )
+               n, i, ok = dtoi(s, i)
+               if !ok || n > 0xFF {
+                       return nil
+               }
+               p[j] = byte(n)
+       }
+       if i != len(s) {
+               return nil
+       }
+       return IPv4(p[0], p[1], p[2], p[3])
+}
+
+// Parse IPv6 address.  Many forms.
+// The basic form is a sequence of eight colon-separated
+// 16-bit hex numbers separated by colons,
+// as in 0123:4567:89ab:cdef:0123:4567:89ab:cdef.
+// Two exceptions:
+//     * A run of zeros can be replaced with "::".
+//     * The last 32 bits can be in IPv4 form.
+// Thus, ::ffff:1.2.3.4 is the IPv4 address 1.2.3.4.
+func parseIPv6(s string) IP {
+       p := make(IP, 16)
+       ellipsis := -1 // position of ellipsis in p
+       i := 0         // index in string s
+
+       // Might have leading ellipsis
+       if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
+               ellipsis = 0
+               i = 2
+               // Might be only ellipsis
+               if i == len(s) {
+                       return p
+               }
+       }
+
+       // Loop, parsing hex numbers followed by colon.
+       j := 0
+L:
+       for j < IPv6len {
+               // Hex number.
+               n, i1, ok := xtoi(s, i)
+               if !ok || n > 0xFFFF {
+                       return nil
+               }
+
+               // If followed by dot, might be in trailing IPv4.
+               if i1 < len(s) && s[i1] == '.' {
+                       if ellipsis < 0 && j != IPv6len-IPv4len {
+                               // Not the right place.
+                               return nil
+                       }
+                       if j+IPv4len > IPv6len {
+                               // Not enough room.
+                               return nil
+                       }
+                       p4 := parseIPv4(s[i:])
+                       if p4 == nil {
+                               return nil
+                       }
+                       p[j] = p4[12]
+                       p[j+1] = p4[13]
+                       p[j+2] = p4[14]
+                       p[j+3] = p4[15]
+                       i = len(s)
+                       j += 4
+                       break
+               }
+
+               // Save this 16-bit chunk.
+               p[j] = byte(n >> 8)
+               p[j+1] = byte(n)
+               j += 2
+
+               // Stop at end of string.
+               i = i1
+               if i == len(s) {
+                       break
+               }
+
+               // Otherwise must be followed by colon and more.
+               if s[i] != ':' && i+1 == len(s) {
+                       return nil
+               }
+               i++
+
+               // Look for ellipsis.
+               if s[i] == ':' {
+                       if ellipsis >= 0 { // already have one
+                               return nil
+                       }
+                       ellipsis = j
+                       if i++; i == len(s) { // can be at end
+                               break
+                       }
+               }
+       }
+
+       // Must have used entire string.
+       if i != len(s) {
+               return nil
+       }
+
+       // If didn't parse enough, expand ellipsis.
+       if j < IPv6len {
+               if ellipsis < 0 {
+                       return nil
+               }
+               n := IPv6len - j
+               for k := j - 1; k >= ellipsis; k-- {
+                       p[k+n] = p[k]
+               }
+               for k := ellipsis + n - 1; k >= ellipsis; k-- {
+                       p[k] = 0
+               }
+       }
+       return p
+}
+
+// ParseIP parses s as an IP address, returning the result.
+// The string s can be in dotted decimal ("74.125.19.99")
+// or IPv6 ("2001:4860:0:2001::68") form.
+// If s is not a valid textual representation of an IP address,
+// ParseIP returns nil.
+func ParseIP(s string) IP {
+       p := parseIPv4(s)
+       if p != nil {
+               return p
+       }
+       return parseIPv6(s)
+}
diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go
new file mode 100644 (file)
index 0000000..e29c302
--- /dev/null
@@ -0,0 +1,94 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "testing"
+)
+
+func isEqual(a, b IP) bool {
+       if a == nil && b == nil {
+               return true
+       }
+       if a == nil || b == nil || len(a) != len(b) {
+               return false
+       }
+       for i := 0; i < len(a); i++ {
+               if a[i] != b[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+type parseIPTest struct {
+       in  string
+       out IP
+}
+
+var parseiptests = []parseIPTest{
+       {"127.0.1.2", IPv4(127, 0, 1, 2)},
+       {"127.0.0.1", IPv4(127, 0, 0, 1)},
+       {"127.0.0.256", nil},
+       {"abc", nil},
+       {"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
+       {"2001:4860:0:2001::68",
+               IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01,
+                       0, 0, 0, 0, 0, 0, 0x00, 0x68,
+               },
+       },
+       {"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
+}
+
+func TestParseIP(t *testing.T) {
+       for i := 0; i < len(parseiptests); i++ {
+               tt := parseiptests[i]
+               if out := ParseIP(tt.in); !isEqual(out, tt.out) {
+                       t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out)
+               }
+       }
+}
+
+type ipStringTest struct {
+       in  IP
+       out string
+}
+
+var ipstringtests = []ipStringTest{
+       // cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
+       {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+               0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
+               "2001:db8::123:12:1"},
+       {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0x1},
+               "2001:db8::1"},
+       {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1,
+               0, 0, 0, 0x1, 0, 0, 0, 0x1},
+               "2001:db8:0:1:0:1:0:1"},
+       {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0,
+               0, 0x1, 0, 0, 0, 0x1, 0, 0},
+               "2001:db8:1:0:1:0:1:0"},
+       {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0,
+               0, 0x1, 0, 0, 0, 0, 0, 0x1},
+               "2001::1:0:0:1"},
+       {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+               0, 0x1, 0, 0, 0, 0, 0, 0},
+               "2001:db8:0:0:1::"},
+       {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+               0, 0x1, 0, 0, 0, 0, 0, 0x1},
+               "2001:db8::1:0:0:1"},
+       {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0,
+               0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD},
+               "2001:db8::a:b:c:d"},
+}
+
+func TestIPString(t *testing.T) {
+       for i := 0; i < len(ipstringtests); i++ {
+               tt := ipstringtests[i]
+               if out := tt.in.String(); out != tt.out {
+                       t.Errorf("IP.String(%v) = %#q, want %#q", tt.in, out, tt.out)
+               }
+       }
+}
diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go
new file mode 100644 (file)
index 0000000..562298b
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+// TODO(cw): ListenPacket test, Read() test, ipv6 test &
+// Dial()/Listen() level tests
+
+package net
+
+import (
+       "bytes"
+       "flag"
+       "os"
+       "testing"
+)
+
+const ICMP_ECHO_REQUEST = 8
+const ICMP_ECHO_REPLY = 0
+
+// returns a suitable 'ping request' packet, with id & seq and a
+// payload length of pktlen
+func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
+       p := make([]byte, pktlen)
+       copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))
+
+       p[0] = ICMP_ECHO_REQUEST // type
+       p[1] = 0                 // code
+       p[2] = 0                 // cksum
+       p[3] = 0                 // cksum
+       p[4] = uint8(id >> 8)    // id
+       p[5] = uint8(id & 0xff)  // id
+       p[6] = uint8(seq >> 8)   // sequence
+       p[7] = uint8(seq & 0xff) // sequence
+
+       // calculate icmp checksum
+       cklen := len(p)
+       s := uint32(0)
+       for i := 0; i < (cklen - 1); i += 2 {
+               s += uint32(p[i+1])<<8 | uint32(p[i])
+       }
+       if cklen&1 == 1 {
+               s += uint32(p[cklen-1])
+       }
+       s = (s >> 16) + (s & 0xffff)
+       s = s + (s >> 16)
+
+       // place checksum back in header; using ^= avoids the
+       // assumption the checksum bytes are zero
+       p[2] ^= uint8(^s & 0xff)
+       p[3] ^= uint8(^s >> 8)
+
+       return p
+}
+
+func parsePingReply(p []byte) (id, seq int) {
+       id = int(p[4])<<8 | int(p[5])
+       seq = int(p[6])<<8 | int(p[7])
+       return
+}
+
+var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
+var dsthost = flag.String("dsthost", "localhost", "Destination for the ICMP ECHO request")
+
+// test (raw) IP socket using ICMP
+func TestICMP(t *testing.T) {
+       if os.Getuid() != 0 {
+               t.Logf("test disabled; must be root")
+               return
+       }
+
+       var laddr *IPAddr
+       if *srchost != "" {
+               laddr, err := ResolveIPAddr(*srchost)
+               if err != nil {
+                       t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *srchost, laddr, err)
+               }
+       }
+
+       raddr, err := ResolveIPAddr(*dsthost)
+       if err != nil {
+               t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *dsthost, raddr, err)
+       }
+
+       c, err := ListenIP("ip4:icmp", laddr)
+       if err != nil {
+               t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
+       }
+
+       sendid := os.Getpid() & 0xffff
+       const sendseq = 61455
+       const pingpktlen = 128
+       sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))
+
+       n, err := c.WriteToIP(sendpkt, raddr)
+       if err != nil || n != pingpktlen {
+               t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
+       }
+
+       c.SetTimeout(100e6)
+       resp := make([]byte, 1024)
+       for {
+               n, from, err := c.ReadFrom(resp)
+               if err != nil {
+                       t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
+               }
+               if resp[0] != ICMP_ECHO_REPLY {
+                       continue
+               }
+               rcvid, rcvseq := parsePingReply(resp)
+               if rcvid != sendid || rcvseq != sendseq {
+                       t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
+               }
+               return
+       }
+       t.Fatalf("saw no ping return")
+}
diff --git a/libgo/go/net/iprawsock.go b/libgo/go/net/iprawsock.go
new file mode 100644 (file)
index 0000000..241be15
--- /dev/null
@@ -0,0 +1,358 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// (Raw) IP sockets
+
+package net
+
+import (
+       "os"
+       "sync"
+       "syscall"
+)
+
+var onceReadProtocols sync.Once
+
+func sockaddrToIP(sa syscall.Sockaddr) Addr {
+       switch sa := sa.(type) {
+       case *syscall.SockaddrInet4:
+               return &IPAddr{sa.Addr[0:]}
+       case *syscall.SockaddrInet6:
+               return &IPAddr{sa.Addr[0:]}
+       }
+       return nil
+}
+
+// IPAddr represents the address of a IP end point.
+type IPAddr struct {
+       IP IP
+}
+
+// Network returns the address's network name, "ip".
+func (a *IPAddr) Network() string { return "ip" }
+
+func (a *IPAddr) String() string {
+       if a == nil {
+               return "<nil>"
+       }
+       return a.IP.String()
+}
+
+func (a *IPAddr) family() int {
+       if a == nil || len(a.IP) <= 4 {
+               return syscall.AF_INET
+       }
+       if ip := a.IP.To4(); ip != nil {
+               return syscall.AF_INET
+       }
+       return syscall.AF_INET6
+}
+
+func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+       return ipToSockaddr(family, a.IP, 0)
+}
+
+func (a *IPAddr) toAddr() sockaddr {
+       if a == nil { // nil *IPAddr
+               return nil // nil interface
+       }
+       return a
+}
+
+// ResolveIPAddr parses addr as a IP address and resolves domain
+// names to numeric addresses.  A literal IPv6 host address must be
+// enclosed in square brackets, as in "[::]".
+func ResolveIPAddr(addr string) (*IPAddr, os.Error) {
+       ip, err := hostToIP(addr)
+       if err != nil {
+               return nil, err
+       }
+       return &IPAddr{ip}, nil
+}
+
+// IPConn is the implementation of the Conn and PacketConn
+// interfaces for IP network connections.
+type IPConn struct {
+       fd *netFD
+}
+
+func newIPConn(fd *netFD) *IPConn { return &IPConn{fd} }
+
+func (c *IPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *IPConn) Read(b []byte) (n int, err os.Error) {
+       n, _, err = c.ReadFrom(b)
+       return
+}
+
+// Write implements the net.Conn Write method.
+func (c *IPConn) Write(b []byte) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       return c.fd.Write(b)
+}
+
+// Close closes the IP connection.
+func (c *IPConn) Close() os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       err := c.fd.Close()
+       c.fd = nil
+       return err
+}
+
+// LocalAddr returns the local network address.
+func (c *IPConn) LocalAddr() Addr {
+       if !c.ok() {
+               return nil
+       }
+       return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *IPAddr.
+func (c *IPConn) RemoteAddr() Addr {
+       if !c.ok() {
+               return nil
+       }
+       return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *IPConn) SetTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *IPConn) SetReadBuffer(bytes int) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *IPConn) SetWriteBuffer(bytes int) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setWriteBuffer(c.fd, bytes)
+}
+
+// IP-specific methods.
+
+// ReadFromIP reads a IP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromIP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetTimeout and
+// SetReadTimeout.
+func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err os.Error) {
+       if !c.ok() {
+               return 0, nil, os.EINVAL
+       }
+       // TODO(cw,rsc): consider using readv if we know the family
+       // type to avoid the header trim/copy
+       n, sa, err := c.fd.ReadFrom(b)
+       switch sa := sa.(type) {
+       case *syscall.SockaddrInet4:
+               addr = &IPAddr{sa.Addr[0:]}
+               if len(b) >= 4 { // discard ipv4 header
+                       hsize := (int(b[0]) & 0xf) * 4
+                       copy(b, b[hsize:])
+                       n -= hsize
+               }
+       case *syscall.SockaddrInet6:
+               addr = &IPAddr{sa.Addr[0:]}
+       }
+       return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+       if !c.ok() {
+               return 0, nil, os.EINVAL
+       }
+       n, uaddr, err := c.ReadFromIP(b)
+       return n, uaddr.toAddr(), err
+}
+
+// WriteToIP writes a IP packet to addr via c, copying the payload from b.
+//
+// WriteToIP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       sa, err1 := addr.sockaddr(c.fd.family)
+       if err1 != nil {
+               return 0, &OpError{Op: "write", Net: "ip", Addr: addr, Error: err1}
+       }
+       return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       a, ok := addr.(*IPAddr)
+       if !ok {
+               return 0, &OpError{"writeto", "ip", addr, os.EINVAL}
+       }
+       return c.WriteToIP(b, a)
+}
+
+// Convert "host" into IP address.
+func hostToIP(host string) (ip IP, err os.Error) {
+       var addr IP
+       // Try as an IP address.
+       addr = ParseIP(host)
+       if addr == nil {
+               // Not an IP address.  Try as a DNS name.
+               _, addrs, err1 := LookupHost(host)
+               if err1 != nil {
+                       err = err1
+                       goto Error
+               }
+               addr = ParseIP(addrs[0])
+               if addr == nil {
+                       // should not happen
+                       err = &AddrError{"LookupHost returned invalid address", addrs[0]}
+                       goto Error
+               }
+       }
+
+       return addr, nil
+
+Error:
+       return nil, err
+}
+
+
+var protocols map[string]int
+
+func readProtocols() {
+       protocols = make(map[string]int)
+       if file, err := open("/etc/protocols"); err == nil {
+               for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+                       // tcp    6   TCP    # transmission control protocol
+                       if i := byteIndex(line, '#'); i >= 0 {
+                               line = line[0:i]
+                       }
+                       f := getFields(line)
+                       if len(f) < 2 {
+                               continue
+                       }
+                       if proto, _, ok := dtoi(f[1], 0); ok {
+                               protocols[f[0]] = proto
+                               for _, alias := range f[2:] {
+                                       protocols[alias] = proto
+                               }
+                       }
+               }
+               file.close()
+       }
+}
+
+func netProtoSplit(netProto string) (net string, proto int, err os.Error) {
+       onceReadProtocols.Do(readProtocols)
+       i := last(netProto, ':')
+       if i < 0 { // no colon
+               return "", 0, os.ErrorString("no IP protocol specified")
+       }
+       net = netProto[0:i]
+       protostr := netProto[i+1:]
+       proto, i, ok := dtoi(protostr, 0)
+       if !ok || i != len(protostr) {
+               // lookup by name
+               proto, ok = protocols[protostr]
+               if ok {
+                       return
+               }
+       }
+       return
+}
+
+// DialIP connects to the remote address raddr on the network net,
+// which must be "ip", "ip4", or "ip6".
+func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
+       net, proto, err := netProtoSplit(netProto)
+       if err != nil {
+               return
+       }
+       switch prefixBefore(net, ':') {
+       case "ip", "ip4", "ip6":
+       default:
+               return nil, UnknownNetworkError(net)
+       }
+       if raddr == nil {
+               return nil, &OpError{"dial", "ip", nil, errMissingAddress}
+       }
+       fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+       if e != nil {
+               return nil, e
+       }
+       return newIPConn(fd), nil
+}
+
+// ListenIP listens for incoming IP packets addressed to the
+// local address laddr.  The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send IP
+// packets with per-packet addressing.
+func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err os.Error) {
+       net, proto, err := netProtoSplit(netProto)
+       if err != nil {
+               return
+       }
+       switch prefixBefore(net, ':') {
+       case "ip", "ip4", "ip6":
+       default:
+               return nil, UnknownNetworkError(net)
+       }
+       fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+       if e != nil {
+               return nil, e
+       }
+       return newIPConn(fd), nil
+}
+
+// BindToDevice binds an IPConn to a network interface.
+func (c *IPConn) BindToDevice(device string) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       c.fd.incref()
+       defer c.fd.decref()
+       return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
+}
diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go
new file mode 100644 (file)
index 0000000..dd796bc
--- /dev/null
@@ -0,0 +1,236 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IP sockets
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+// Should we try to use the IPv4 socket interface if we're
+// only dealing with IPv4 sockets?  As long as the host system
+// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
+// interface.  That simplifies our code and is most general.
+// Unfortunately, we need to run on kernels built without IPv6 support too.
+// So probe the kernel to figure it out.
+func kernelSupportsIPv6() bool {
+       // FreeBSD does not support this sort of interface.
+       if syscall.OS == "freebsd" {
+               return false
+       }
+       fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+       if fd >= 0 {
+               syscall.Close(fd)
+       }
+       return e == 0
+}
+
+var preferIPv4 = !kernelSupportsIPv6()
+
+// TODO(rsc): if syscall.OS == "linux", we're supposd to read
+// /proc/sys/net/core/somaxconn,
+// to take advantage of kernels that have raised the limit.
+func listenBacklog() int { return syscall.SOMAXCONN }
+
+// Internet sockets (TCP, UDP)
+
+// A sockaddr represents a TCP or UDP network address that can
+// be converted into a syscall.Sockaddr.
+type sockaddr interface {
+       Addr
+       sockaddr(family int) (syscall.Sockaddr, os.Error)
+       family() int
+}
+
+func internetSocket(net string, laddr, raddr sockaddr, socktype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
+       // Figure out IP version.
+       // If network has a suffix like "tcp4", obey it.
+       var oserr os.Error
+       family := syscall.AF_INET6
+       switch net[len(net)-1] {
+       case '4':
+               family = syscall.AF_INET
+       case '6':
+               // nothing to do
+       default:
+               // Otherwise, guess.
+               // If the addresses are IPv4 and we prefer IPv4, use 4; else 6.
+               if preferIPv4 &&
+                       (laddr == nil || laddr.family() == syscall.AF_INET) &&
+                       (raddr == nil || raddr.family() == syscall.AF_INET) {
+                       family = syscall.AF_INET
+               }
+       }
+
+       var la, ra syscall.Sockaddr
+       if laddr != nil {
+               if la, oserr = laddr.sockaddr(family); oserr != nil {
+                       goto Error
+               }
+       }
+       if raddr != nil {
+               if ra, oserr = raddr.sockaddr(family); oserr != nil {
+                       goto Error
+               }
+       }
+       fd, oserr = socket(net, family, socktype, proto, la, ra, toAddr)
+       if oserr != nil {
+               goto Error
+       }
+       return fd, nil
+
+Error:
+       addr := raddr
+       if mode == "listen" {
+               addr = laddr
+       }
+       return nil, &OpError{mode, net, addr, oserr}
+}
+
+func getip(fd int, remote bool) (ip []byte, port int, ok bool) {
+       // No attempt at error reporting because
+       // there are no possible errors, and the
+       // caller won't report them anyway.
+       var sa syscall.Sockaddr
+       if remote {
+               sa, _ = syscall.Getpeername(fd)
+       } else {
+               sa, _ = syscall.Getsockname(fd)
+       }
+       switch sa := sa.(type) {
+       case *syscall.SockaddrInet4:
+               return sa.Addr[0:], sa.Port, true
+       case *syscall.SockaddrInet6:
+               return sa.Addr[0:], sa.Port, true
+       }
+       return
+}
+
+type InvalidAddrError string
+
+func (e InvalidAddrError) String() string  { return string(e) }
+func (e InvalidAddrError) Timeout() bool   { return false }
+func (e InvalidAddrError) Temporary() bool { return false }
+
+
+func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
+       switch family {
+       case syscall.AF_INET:
+               if len(ip) == 0 {
+                       ip = IPv4zero
+               }
+               if ip = ip.To4(); ip == nil {
+                       return nil, InvalidAddrError("non-IPv4 address")
+               }
+               s := new(syscall.SockaddrInet4)
+               for i := 0; i < IPv4len; i++ {
+                       s.Addr[i] = ip[i]
+               }
+               s.Port = port
+               return s, nil
+       case syscall.AF_INET6:
+               if len(ip) == 0 {
+                       ip = IPzero
+               }
+               // IPv4 callers use 0.0.0.0 to mean "announce on any available address".
+               // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
+               // which it refuses to do.  Rewrite to the IPv6 all zeros.
+               if p4 := ip.To4(); p4 != nil && p4[0] == 0 && p4[1] == 0 && p4[2] == 0 && p4[3] == 0 {
+                       ip = IPzero
+               }
+               if ip = ip.To16(); ip == nil {
+                       return nil, InvalidAddrError("non-IPv6 address")
+               }
+               s := new(syscall.SockaddrInet6)
+               for i := 0; i < IPv6len; i++ {
+                       s.Addr[i] = ip[i]
+               }
+               s.Port = port
+               return s, nil
+       }
+       return nil, InvalidAddrError("unexpected socket family")
+}
+
+// Split "host:port" into "host" and "port".
+// Host cannot contain colons unless it is bracketed.
+func splitHostPort(hostport string) (host, port string, err os.Error) {
+       // The port starts after the last colon.
+       i := last(hostport, ':')
+       if i < 0 {
+               err = &AddrError{"missing port in address", hostport}
+               return
+       }
+
+       host, port = hostport[0:i], hostport[i+1:]
+
+       // Can put brackets around host ...
+       if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+               host = host[1 : len(host)-1]
+       } else {
+               // ... but if there are no brackets, no colons.
+               if byteIndex(host, ':') >= 0 {
+                       err = &AddrError{"too many colons in address", hostport}
+                       return
+               }
+       }
+       return
+}
+
+// Join "host" and "port" into "host:port".
+// If host contains colons, will join into "[host]:port".
+func joinHostPort(host, port string) string {
+       // If host has colons, have to bracket it.
+       if byteIndex(host, ':') >= 0 {
+               return "[" + host + "]:" + port
+       }
+       return host + ":" + port
+}
+
+// Convert "host:port" into IP address and port.
+func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
+       host, port, err := splitHostPort(hostport)
+       if err != nil {
+               goto Error
+       }
+
+       var addr IP
+       if host != "" {
+               // Try as an IP address.
+               addr = ParseIP(host)
+               if addr == nil {
+                       // Not an IP address.  Try as a DNS name.
+                       _, addrs, err1 := LookupHost(host)
+                       if err1 != nil {
+                               err = err1
+                               goto Error
+                       }
+                       addr = ParseIP(addrs[0])
+                       if addr == nil {
+                               // should not happen
+                               err = &AddrError{"LookupHost returned invalid address", addrs[0]}
+                               goto Error
+                       }
+               }
+       }
+
+       p, i, ok := dtoi(port, 0)
+       if !ok || i != len(port) {
+               p, err = LookupPort(net, port)
+               if err != nil {
+                       goto Error
+               }
+       }
+       if p < 0 || p > 0xFFFF {
+               err = &AddrError{"invalid port", port}
+               goto Error
+       }
+
+       return addr, p, nil
+
+Error:
+       return nil, 0, err
+}
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
new file mode 100644 (file)
index 0000000..c0c1c3b
--- /dev/null
@@ -0,0 +1,192 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The net package provides a portable interface to Unix
+// networks sockets, including TCP/IP, UDP, domain name
+// resolution, and Unix domain sockets.
+package net
+
+// TODO(rsc):
+//     support for raw ethernet sockets
+
+import "os"
+
+// Addr represents a network end point address.
+type Addr interface {
+       Network() string // name of the network
+       String() string  // string form of address
+}
+
+// Conn is a generic stream-oriented network connection.
+type Conn interface {
+       // Read reads data from the connection.
+       // Read can be made to time out and return a net.Error with Timeout() == true
+       // after a fixed time limit; see SetTimeout and SetReadTimeout.
+       Read(b []byte) (n int, err os.Error)
+
+       // Write writes data to the connection.
+       // Write can be made to time out and return a net.Error with Timeout() == true
+       // after a fixed time limit; see SetTimeout and SetWriteTimeout.
+       Write(b []byte) (n int, err os.Error)
+
+       // Close closes the connection.
+       // The error returned is an os.Error to satisfy io.Closer;
+       Close() os.Error
+
+       // LocalAddr returns the local network address.
+       LocalAddr() Addr
+
+       // RemoteAddr returns the remote network address.
+       RemoteAddr() Addr
+
+       // SetTimeout sets the read and write deadlines associated
+       // with the connection.
+       SetTimeout(nsec int64) os.Error
+
+       // SetReadTimeout sets the time (in nanoseconds) that
+       // Read will wait for data before returning an error with Timeout() == true.
+       // Setting nsec == 0 (the default) disables the deadline.
+       SetReadTimeout(nsec int64) os.Error
+
+       // SetWriteTimeout sets the time (in nanoseconds) that
+       // Write will wait to send its data before returning an error with Timeout() == true.
+       // Setting nsec == 0 (the default) disables the deadline.
+       // Even if write times out, it may return n > 0, indicating that
+       // some of the data was successfully written.
+       SetWriteTimeout(nsec int64) os.Error
+}
+
+// An Error represents a network error.
+type Error interface {
+       os.Error
+       Timeout() bool   // Is the error a timeout?
+       Temporary() bool // Is the error temporary?
+}
+
+// PacketConn is a generic packet-oriented network connection.
+type PacketConn interface {
+       // ReadFrom reads a packet from the connection,
+       // copying the payload into b.  It returns the number of
+       // bytes copied into b and the return address that
+       // was on the packet.
+       // ReadFrom can be made to time out and return
+       // an error with Timeout() == true after a fixed time limit;
+       // see SetTimeout and SetReadTimeout.
+       ReadFrom(b []byte) (n int, addr Addr, err os.Error)
+
+       // WriteTo writes a packet with payload b to addr.
+       // WriteTo can be made to time out and return
+       // an error with Timeout() == true after a fixed time limit;
+       // see SetTimeout and SetWriteTimeout.
+       // On packet-oriented connections, write timeouts are rare.
+       WriteTo(b []byte, addr Addr) (n int, err os.Error)
+
+       // Close closes the connection.
+       // The error returned is an os.Error to satisfy io.Closer;
+       Close() os.Error
+
+       // LocalAddr returns the local network address.
+       LocalAddr() Addr
+
+       // SetTimeout sets the read and write deadlines associated
+       // with the connection.
+       SetTimeout(nsec int64) os.Error
+
+       // SetReadTimeout sets the time (in nanoseconds) that
+       // Read will wait for data before returning an error with Timeout() == true.
+       // Setting nsec == 0 (the default) disables the deadline.
+       SetReadTimeout(nsec int64) os.Error
+
+       // SetWriteTimeout sets the time (in nanoseconds) that
+       // Write will wait to send its data before returning an error with Timeout() == true.
+       // Setting nsec == 0 (the default) disables the deadline.
+       // Even if write times out, it may return n > 0, indicating that
+       // some of the data was successfully written.
+       SetWriteTimeout(nsec int64) os.Error
+}
+
+// A Listener is a generic network listener for stream-oriented protocols.
+type Listener interface {
+       // Accept waits for and returns the next connection to the listener.
+       Accept() (c Conn, err os.Error)
+
+       // Close closes the listener.
+       // The error returned is an os.Error to satisfy io.Closer;
+       Close() os.Error
+
+       // Addr returns the listener's network address.
+       Addr() Addr
+}
+
+var errMissingAddress = os.ErrorString("missing address")
+
+type OpError struct {
+       Op    string
+       Net   string
+       Addr  Addr
+       Error os.Error
+}
+
+func (e *OpError) String() string {
+       if e == nil {
+               return "<nil>"
+       }
+       s := e.Op
+       if e.Net != "" {
+               s += " " + e.Net
+       }
+       if e.Addr != nil {
+               s += " " + e.Addr.String()
+       }
+       s += ": " + e.Error.String()
+       return s
+}
+
+type temporary interface {
+       Temporary() bool
+}
+
+func (e *OpError) Temporary() bool {
+       t, ok := e.Error.(temporary)
+       return ok && t.Temporary()
+}
+
+type timeout interface {
+       Timeout() bool
+}
+
+func (e *OpError) Timeout() bool {
+       t, ok := e.Error.(timeout)
+       return ok && t.Timeout()
+}
+
+type AddrError struct {
+       Error string
+       Addr  string
+}
+
+func (e *AddrError) String() string {
+       if e == nil {
+               return "<nil>"
+       }
+       s := e.Error
+       if e.Addr != "" {
+               s += " " + e.Addr
+       }
+       return s
+}
+
+func (e *AddrError) Temporary() bool {
+       return false
+}
+
+func (e *AddrError) Timeout() bool {
+       return false
+}
+
+type UnknownNetworkError string
+
+func (e UnknownNetworkError) String() string  { return "unknown network " + string(e) }
+func (e UnknownNetworkError) Temporary() bool { return false }
+func (e UnknownNetworkError) Timeout() bool   { return false }
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
new file mode 100644 (file)
index 0000000..febfc0a
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "flag"
+       "regexp"
+       "testing"
+)
+
+var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
+
+type DialErrorTest struct {
+       Net     string
+       Laddr   string
+       Raddr   string
+       Pattern string
+}
+
+var dialErrorTests = []DialErrorTest{
+       {
+               "datakit", "", "mh/astro/r70",
+               "dial datakit mh/astro/r70: unknown network datakit",
+       },
+       {
+               "tcp", "", "127.0.0.1:☺",
+               "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
+       },
+       {
+               "tcp", "", "no-such-name.google.com.:80",
+               "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
+       },
+       {
+               "tcp", "", "no-such-name.no-such-top-level-domain.:80",
+               "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
+       },
+       {
+               "tcp", "", "no-such-name:80",
+               `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
+       },
+       {
+               "tcp", "", "mh/astro/r70:http",
+               "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
+       },
+       {
+               "unix", "", "/etc/file-not-found",
+               "dial unix /etc/file-not-found: [nN]o such file or directory",
+       },
+       {
+               "unix", "", "/etc/",
+               "dial unix /etc/: ([pP]ermission denied|[sS]ocket operation on non-socket|[cC]onnection refused)",
+       },
+}
+
+func TestDialError(t *testing.T) {
+       if !*runErrorTest {
+               t.Logf("test disabled; use --run_error_test to enable")
+               return
+       }
+       for i, tt := range dialErrorTests {
+               c, e := Dial(tt.Net, tt.Laddr, tt.Raddr)
+               if c != nil {
+                       c.Close()
+               }
+               if e == nil {
+                       t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
+                       continue
+               }
+               s := e.String()
+               match, _ := regexp.MatchString(tt.Pattern, s)
+               if !match {
+                       t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
+               }
+       }
+}
diff --git a/libgo/go/net/newpollserver.go b/libgo/go/net/newpollserver.go
new file mode 100644 (file)
index 0000000..820e70b
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+func newPollServer() (s *pollServer, err os.Error) {
+       s = new(pollServer)
+       s.cr = make(chan *netFD, 1)
+       s.cw = make(chan *netFD, 1)
+       if s.pr, s.pw, err = os.Pipe(); err != nil {
+               return nil, err
+       }
+       var e int
+       if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
+       Errno:
+               err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+       Error:
+               s.pr.Close()
+               s.pw.Close()
+               return nil, err
+       }
+       if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
+               goto Errno
+       }
+       if s.poll, err = newpollster(); err != nil {
+               goto Error
+       }
+       if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
+               s.poll.Close()
+               goto Error
+       }
+       s.pending = make(map[int]*netFD)
+       go s.Run()
+       return s, nil
+}
diff --git a/libgo/go/net/newpollserver_rtems.go b/libgo/go/net/newpollserver_rtems.go
new file mode 100644 (file)
index 0000000..05cb71a
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+func selfConnectedTCPSocket() (pr, pw *os.File, err os.Error) {
+       // See ../syscall/exec.go for description of ForkLock.
+       syscall.ForkLock.RLock()
+       sockfd, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0)
+       if e != 0 {
+               syscall.ForkLock.RUnlock()
+               return nil, nil, os.Errno(e)
+       }
+       syscall.CloseOnExec(sockfd)
+       syscall.ForkLock.RUnlock()
+
+       // Allow reuse of recently-used addresses.
+       syscall.SetsockoptInt(sockfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+
+       var laTCP *TCPAddr
+       var la syscall.Sockaddr
+       if laTCP, err = ResolveTCPAddr("127.0.0.1:0"); err != nil {
+       Error:
+               return nil, nil, err
+       }
+       if la, err = laTCP.sockaddr(syscall.AF_INET); err != nil {
+               goto Error
+       }
+       e = syscall.Bind(sockfd, la)
+       if e != 0 {
+       Errno:
+               syscall.Close(sockfd)
+               return nil, nil, os.Errno(e)
+       }
+
+       laddr, _ := syscall.Getsockname(sockfd)
+       e = syscall.Connect(sockfd, laddr)
+       if e != 0 {
+               goto Errno
+       }
+
+       fd := os.NewFile(sockfd, "wakeupSocket")
+       return fd, fd, nil
+}
+
+func newPollServer() (s *pollServer, err os.Error) {
+       s = new(pollServer)
+       s.cr = make(chan *netFD, 1)
+       s.cw = make(chan *netFD, 1)
+       // s.pr and s.pw are indistinguishable.
+       if s.pr, s.pw, err = selfConnectedTCPSocket(); err != nil {
+               return nil, err
+       }
+       var e int
+       if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
+       Errno:
+               err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+       Error:
+               s.pr.Close()
+               return nil, err
+       }
+       if s.poll, err = newpollster(); err != nil {
+               goto Error
+       }
+       if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
+               s.poll.Close()
+               goto Error
+       }
+       s.pending = make(map[int]*netFD)
+       go s.Run()
+       return s, nil
+}
diff --git a/libgo/go/net/parse.go b/libgo/go/net/parse.go
new file mode 100644 (file)
index 0000000..605f311
--- /dev/null
@@ -0,0 +1,214 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Simple file i/o and string manipulation, to avoid
+// depending on strconv and bufio and strings.
+
+package net
+
+import (
+       "io"
+       "os"
+)
+
+type file struct {
+       file  *os.File
+       data  []byte
+       atEOF bool
+}
+
+func (f *file) close() { f.file.Close() }
+
+func (f *file) getLineFromData() (s string, ok bool) {
+       data := f.data
+       i := 0
+       for i = 0; i < len(data); i++ {
+               if data[i] == '\n' {
+                       s = string(data[0:i])
+                       ok = true
+                       // move data
+                       i++
+                       n := len(data) - i
+                       copy(data[0:], data[i:])
+                       f.data = data[0:n]
+                       return
+               }
+       }
+       if f.atEOF && len(f.data) > 0 {
+               // EOF, return all we have
+               s = string(data)
+               f.data = f.data[0:0]
+               ok = true
+       }
+       return
+}
+
+func (f *file) readLine() (s string, ok bool) {
+       if s, ok = f.getLineFromData(); ok {
+               return
+       }
+       if len(f.data) < cap(f.data) {
+               ln := len(f.data)
+               n, err := io.ReadFull(f.file, f.data[ln:cap(f.data)])
+               if n >= 0 {
+                       f.data = f.data[0 : ln+n]
+               }
+               if err == os.EOF {
+                       f.atEOF = true
+               }
+       }
+       s, ok = f.getLineFromData()
+       return
+}
+
+func open(name string) (*file, os.Error) {
+       fd, err := os.Open(name, os.O_RDONLY, 0)
+       if err != nil {
+               return nil, err
+       }
+       return &file{fd, make([]byte, 1024)[0:0], false}, nil
+}
+
+func byteIndex(s string, c byte) int {
+       for i := 0; i < len(s); i++ {
+               if s[i] == c {
+                       return i
+               }
+       }
+       return -1
+}
+
+// Count occurrences in s of any bytes in t.
+func countAnyByte(s string, t string) int {
+       n := 0
+       for i := 0; i < len(s); i++ {
+               if byteIndex(t, s[i]) >= 0 {
+                       n++
+               }
+       }
+       return n
+}
+
+// Split s at any bytes in t.
+func splitAtBytes(s string, t string) []string {
+       a := make([]string, 1+countAnyByte(s, t))
+       n := 0
+       last := 0
+       for i := 0; i < len(s); i++ {
+               if byteIndex(t, s[i]) >= 0 {
+                       if last < i {
+                               a[n] = string(s[last:i])
+                               n++
+                       }
+                       last = i + 1
+               }
+       }
+       if last < len(s) {
+               a[n] = string(s[last:])
+               n++
+       }
+       return a[0:n]
+}
+
+func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") }
+
+// Bigger than we need, not too big to worry about overflow
+const big = 0xFFFFFF
+
+// Decimal to integer starting at &s[i0].
+// Returns number, new offset, success.
+func dtoi(s string, i0 int) (n int, i int, ok bool) {
+       n = 0
+       for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+               n = n*10 + int(s[i]-'0')
+               if n >= big {
+                       return 0, i, false
+               }
+       }
+       if i == i0 {
+               return 0, i, false
+       }
+       return n, i, true
+}
+
+// Hexadecimal to integer starting at &s[i0].
+// Returns number, new offset, success.
+func xtoi(s string, i0 int) (n int, i int, ok bool) {
+       n = 0
+       for i = i0; i < len(s); i++ {
+               if '0' <= s[i] && s[i] <= '9' {
+                       n *= 16
+                       n += int(s[i] - '0')
+               } else if 'a' <= s[i] && s[i] <= 'f' {
+                       n *= 16
+                       n += int(s[i]-'a') + 10
+               } else if 'A' <= s[i] && s[i] <= 'F' {
+                       n *= 16
+                       n += int(s[i]-'A') + 10
+               } else {
+                       break
+               }
+               if n >= big {
+                       return 0, i, false
+               }
+       }
+       if i == i0 {
+               return 0, i, false
+       }
+       return n, i, true
+}
+
+// Integer to decimal.
+func itoa(i int) string {
+       var buf [30]byte
+       n := len(buf)
+       neg := false
+       if i < 0 {
+               i = -i
+               neg = true
+       }
+       ui := uint(i)
+       for ui > 0 || n == len(buf) {
+               n--
+               buf[n] = byte('0' + ui%10)
+               ui /= 10
+       }
+       if neg {
+               n--
+               buf[n] = '-'
+       }
+       return string(buf[n:])
+}
+
+// Number of occurrences of b in s.
+func count(s string, b byte) int {
+       n := 0
+       for i := 0; i < len(s); i++ {
+               if s[i] == b {
+                       n++
+               }
+       }
+       return n
+}
+
+// Returns the prefix of s up to but not including the character c
+func prefixBefore(s string, c byte) string {
+       for i, v := range s {
+               if v == int(c) {
+                       return s[0:i]
+               }
+       }
+       return s
+}
+
+// Index of rightmost occurrence of b in s.
+func last(s string, b byte) int {
+       i := len(s)
+       for i--; i >= 0; i-- {
+               if s[i] == b {
+                       break
+               }
+       }
+       return i
+}
diff --git a/libgo/go/net/parse_test.go b/libgo/go/net/parse_test.go
new file mode 100644 (file)
index 0000000..2b7784e
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "bufio"
+       "os"
+       "testing"
+       "runtime"
+)
+
+func TestReadLine(t *testing.T) {
+       // /etc/services file does not exist on windows.
+       if runtime.GOOS == "windows" {
+               return
+       }
+       filename := "/etc/services" // a nice big file
+
+       fd, err := os.Open(filename, os.O_RDONLY, 0)
+       if err != nil {
+               t.Fatalf("open %s: %v", filename, err)
+       }
+       br := bufio.NewReader(fd)
+
+       file, err := open(filename)
+       if file == nil {
+               t.Fatalf("net.open(%s) = nil", filename)
+       }
+
+       lineno := 1
+       byteno := 0
+       for {
+               bline, berr := br.ReadString('\n')
+               if n := len(bline); n > 0 {
+                       bline = bline[0 : n-1]
+               }
+               line, ok := file.readLine()
+               if (berr != nil) != !ok || bline != line {
+                       t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v",
+                               filename, lineno, byteno, bline, berr, line, ok)
+               }
+               if !ok {
+                       break
+               }
+               lineno++
+               byteno += len(line) + 1
+       }
+}
diff --git a/libgo/go/net/pipe.go b/libgo/go/net/pipe.go
new file mode 100644 (file)
index 0000000..c0bbd35
--- /dev/null
@@ -0,0 +1,62 @@
+package net
+
+import (
+       "io"
+       "os"
+)
+
+// Pipe creates a synchronous, in-memory, full duplex
+// network connection; both ends implement the Conn interface.
+// Reads on one end are matched with writes on the other,
+// copying data directly between the two; there is no internal
+// buffering.
+func Pipe() (Conn, Conn) {
+       r1, w1 := io.Pipe()
+       r2, w2 := io.Pipe()
+
+       return &pipe{r1, w2}, &pipe{r2, w1}
+}
+
+type pipe struct {
+       *io.PipeReader
+       *io.PipeWriter
+}
+
+type pipeAddr int
+
+func (pipeAddr) Network() string {
+       return "pipe"
+}
+
+func (pipeAddr) String() string {
+       return "pipe"
+}
+
+func (p *pipe) Close() os.Error {
+       err := p.PipeReader.Close()
+       err1 := p.PipeWriter.Close()
+       if err == nil {
+               err = err1
+       }
+       return err
+}
+
+func (p *pipe) LocalAddr() Addr {
+       return pipeAddr(0)
+}
+
+func (p *pipe) RemoteAddr() Addr {
+       return pipeAddr(0)
+}
+
+func (p *pipe) SetTimeout(nsec int64) os.Error {
+       return os.NewError("net.Pipe does not support timeouts")
+}
+
+func (p *pipe) SetReadTimeout(nsec int64) os.Error {
+       return os.NewError("net.Pipe does not support timeouts")
+}
+
+func (p *pipe) SetWriteTimeout(nsec int64) os.Error {
+       return os.NewError("net.Pipe does not support timeouts")
+}
diff --git a/libgo/go/net/pipe_test.go b/libgo/go/net/pipe_test.go
new file mode 100644 (file)
index 0000000..7e4c6db
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "testing"
+)
+
+func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
+       n, err := w.Write(data)
+       if err != nil {
+               t.Errorf("write: %v", err)
+       }
+       if n != len(data) {
+               t.Errorf("short write: %d != %d", n, len(data))
+       }
+       c <- 0
+}
+
+func checkRead(t *testing.T, r io.Reader, data []byte, wantErr os.Error) {
+       buf := make([]byte, len(data)+10)
+       n, err := r.Read(buf)
+       if err != wantErr {
+               t.Errorf("read: %v", err)
+               return
+       }
+       if n != len(data) || !bytes.Equal(buf[0:n], data) {
+               t.Errorf("bad read: got %q", buf[0:n])
+               return
+       }
+}
+
+// Test a simple read/write/close sequence.
+// Assumes that the underlying io.Pipe implementation
+// is solid and we're just testing the net wrapping.
+
+func TestPipe(t *testing.T) {
+       c := make(chan int)
+       cli, srv := Pipe()
+       go checkWrite(t, cli, []byte("hello, world"), c)
+       checkRead(t, srv, []byte("hello, world"), nil)
+       <-c
+       go checkWrite(t, srv, []byte("line 2"), c)
+       checkRead(t, cli, []byte("line 2"), nil)
+       <-c
+       go checkWrite(t, cli, []byte("a third line"), c)
+       checkRead(t, srv, []byte("a third line"), nil)
+       <-c
+       go srv.Close()
+       checkRead(t, cli, nil, os.EOF)
+       cli.Close()
+}
diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go
new file mode 100644 (file)
index 0000000..cd18d2b
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Read system port mappings from /etc/services
+
+package net
+
+import (
+       "os"
+       "sync"
+)
+
+var services map[string]map[string]int
+var servicesError os.Error
+var onceReadServices sync.Once
+
+func readServices() {
+       services = make(map[string]map[string]int)
+       var file *file
+       file, servicesError = open("/etc/services")
+       for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+               // "http 80/tcp www www-http # World Wide Web HTTP"
+               if i := byteIndex(line, '#'); i >= 0 {
+                       line = line[0:i]
+               }
+               f := getFields(line)
+               if len(f) < 2 {
+                       continue
+               }
+               portnet := f[1] // "tcp/80"
+               port, j, ok := dtoi(portnet, 0)
+               if !ok || port <= 0 || j >= len(portnet) || portnet[j] != '/' {
+                       continue
+               }
+               netw := portnet[j+1:] // "tcp"
+               m, ok1 := services[netw]
+               if !ok1 {
+                       m = make(map[string]int)
+                       services[netw] = m
+               }
+               for i := 0; i < len(f); i++ {
+                       if i != 1 { // f[1] was port/net
+                               m[f[i]] = port
+                       }
+               }
+       }
+       file.close()
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+       onceReadServices.Do(readServices)
+
+       switch network {
+       case "tcp4", "tcp6":
+               network = "tcp"
+       case "udp4", "udp6":
+               network = "udp"
+       }
+
+       if m, ok := services[network]; ok {
+               if port, ok = m[service]; ok {
+                       return
+               }
+       }
+       return 0, &AddrError{"unknown port", network + "/" + service}
+}
diff --git a/libgo/go/net/port_test.go b/libgo/go/net/port_test.go
new file mode 100644 (file)
index 0000000..1b7eaf2
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "testing"
+)
+
+type portTest struct {
+       netw string
+       name string
+       port int
+       ok   bool
+}
+
+var porttests = []portTest{
+       {"tcp", "echo", 7, true},
+       {"tcp", "discard", 9, true},
+       {"tcp", "systat", 11, true},
+       {"tcp", "daytime", 13, true},
+       {"tcp", "chargen", 19, true},
+       {"tcp", "ftp-data", 20, true},
+       {"tcp", "ftp", 21, true},
+       {"tcp", "telnet", 23, true},
+       {"tcp", "smtp", 25, true},
+       {"tcp", "time", 37, true},
+       {"tcp", "domain", 53, true},
+       {"tcp", "gopher", 70, true},
+       {"tcp", "finger", 79, true},
+       {"tcp", "http", 80, true},
+
+       {"udp", "echo", 7, true},
+       {"udp", "tftp", 69, true},
+       {"udp", "bootpc", 68, true},
+       {"udp", "bootps", 67, true},
+       {"udp", "domain", 53, true},
+       {"udp", "ntp", 123, true},
+       {"udp", "snmp", 161, true},
+       {"udp", "syslog", 514, true},
+
+       {"--badnet--", "zzz", 0, false},
+       {"tcp", "--badport--", 0, false},
+}
+
+func TestLookupPort(t *testing.T) {
+       for i := 0; i < len(porttests); i++ {
+               tt := porttests[i]
+               if port, err := LookupPort(tt.netw, tt.name); port != tt.port || (err == nil) != tt.ok {
+                       t.Errorf("LookupPort(%q, %q) = %v, %s; want %v",
+                               tt.netw, tt.name, port, err, tt.port)
+               }
+       }
+}
diff --git a/libgo/go/net/resolv_windows.go b/libgo/go/net/resolv_windows.go
new file mode 100644 (file)
index 0000000..d5292b8
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "syscall"
+       "unsafe"
+       "os"
+       "sync"
+)
+
+var hostentLock sync.Mutex
+var serventLock sync.Mutex
+
+func LookupHost(name string) (cname string, addrs []string, err os.Error) {
+       hostentLock.Lock()
+       defer hostentLock.Unlock()
+       h, e := syscall.GetHostByName(name)
+       if e != 0 {
+               return "", nil, os.NewSyscallError("GetHostByName", e)
+       }
+       cname = name
+       switch h.AddrType {
+       case syscall.AF_INET:
+               i := 0
+               addrs = make([]string, 100) // plenty of room to grow
+               for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ {
+                       addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3]).String()
+               }
+               addrs = addrs[0:i]
+       default: // TODO(vcc): Implement non IPv4 address lookups.
+               return "", nil, os.NewSyscallError("LookupHost", syscall.EWINDOWS)
+       }
+       return cname, addrs, nil
+}
+
+type SRV struct {
+       Target   string
+       Port     uint16
+       Priority uint16
+       Weight   uint16
+}
+
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+       var r *syscall.DNSRecord
+       target := "_" + service + "._" + proto + "." + name
+       e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
+       if int(e) != 0 {
+               return "", nil, os.NewSyscallError("LookupSRV", int(e))
+       }
+       defer syscall.DnsRecordListFree(r, 1)
+       addrs = make([]*SRV, 100)
+       i := 0
+       for p := r; p != nil && p.Type == syscall.DNS_TYPE_SRV; p = p.Next {
+               v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
+               addrs[i] = &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight}
+               i++
+       }
+       addrs = addrs[0:i]
+       return name, addrs, nil
+}
+
+func LookupPort(network, service string) (port int, err os.Error) {
+       switch network {
+       case "tcp4", "tcp6":
+               network = "tcp"
+       case "udp4", "udp6":
+               network = "udp"
+       }
+       serventLock.Lock()
+       defer serventLock.Unlock()
+       s, e := syscall.GetServByName(service, network)
+       if e != 0 {
+               return 0, os.NewSyscallError("GetServByName", e)
+       }
+       return int(syscall.Ntohs(s.Port)), nil
+}
+
+func isDomainName(s string) bool {
+       panic("unimplemented")
+}
diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go
new file mode 100644 (file)
index 0000000..46bedaa
--- /dev/null
@@ -0,0 +1,200 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "flag"
+       "io"
+       "os"
+       "strings"
+       "syscall"
+       "testing"
+       "runtime"
+)
+
+// Do not test empty datagrams by default.
+// It causes unexplained timeouts on some systems,
+// including Snow Leopard.  I think that the kernel
+// doesn't quite expect them.
+var testUDP = flag.Bool("udp", false, "whether to test UDP datagrams")
+
+func runEcho(fd io.ReadWriter, done chan<- int) {
+       var buf [1024]byte
+
+       for {
+               n, err := fd.Read(buf[0:])
+               if err != nil || n == 0 {
+                       break
+               }
+               fd.Write(buf[0:n])
+       }
+       done <- 1
+}
+
+func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
+       l, err := Listen(network, addr)
+       if err != nil {
+               t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
+       }
+       listening <- l.Addr().String()
+
+       for {
+               fd, err := l.Accept()
+               if err != nil {
+                       break
+               }
+               echodone := make(chan int)
+               go runEcho(fd, echodone)
+               <-echodone // make sure Echo stops
+               l.Close()
+       }
+       done <- 1
+}
+
+func connect(t *testing.T, network, addr string, isEmpty bool) {
+       var laddr string
+       if network == "unixgram" {
+               laddr = addr + ".local"
+       }
+       fd, err := Dial(network, laddr, addr)
+       if err != nil {
+               t.Fatalf("net.Dial(%q, %q, %q) = _, %v", network, laddr, addr, err)
+       }
+       fd.SetReadTimeout(1e9) // 1s
+
+       var b []byte
+       if !isEmpty {
+               b = []byte("hello, world\n")
+       }
+       var b1 [100]byte
+
+       n, err1 := fd.Write(b)
+       if n != len(b) {
+               t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
+       }
+
+       n, err1 = fd.Read(b1[0:])
+       if n != len(b) || err1 != nil {
+               t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
+       }
+       fd.Close()
+}
+
+func doTest(t *testing.T, network, listenaddr, dialaddr string) {
+       t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr)
+       listening := make(chan string)
+       done := make(chan int)
+       if network == "tcp" {
+               listenaddr += ":0" // any available port
+       }
+       go runServe(t, network, listenaddr, listening, done)
+       addr := <-listening // wait for server to start
+       if network == "tcp" {
+               dialaddr += addr[strings.LastIndex(addr, ":"):]
+       }
+       connect(t, network, dialaddr, false)
+       <-done // make sure server stopped
+}
+
+func TestTCPServer(t *testing.T) {
+       doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
+       doTest(t, "tcp", "", "127.0.0.1")
+       if kernelSupportsIPv6() {
+               doTest(t, "tcp", "[::]", "[::ffff:127.0.0.1]")
+               doTest(t, "tcp", "[::]", "127.0.0.1")
+               doTest(t, "tcp", "0.0.0.0", "[::ffff:127.0.0.1]")
+       }
+}
+
+func TestUnixServer(t *testing.T) {
+       // "unix" sockets are not supported on windows.
+       if runtime.GOOS == "windows" {
+               return
+       }
+       os.Remove("/tmp/gotest.net")
+       doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
+       os.Remove("/tmp/gotest.net")
+       if syscall.OS == "linux" {
+               // Test abstract unix domain socket, a Linux-ism
+               doTest(t, "unix", "@gotest/net", "@gotest/net")
+       }
+}
+
+func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
+       c, err := ListenPacket(network, addr)
+       if err != nil {
+               t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
+       }
+       listening <- c.LocalAddr().String()
+       c.SetReadTimeout(10e6) // 10ms
+       var buf [1000]byte
+       for {
+               n, addr, err := c.ReadFrom(buf[0:])
+               if e, ok := err.(Error); ok && e.Timeout() {
+                       if done <- 1 {
+                               break
+                       }
+                       continue
+               }
+               if err != nil {
+                       break
+               }
+               if _, err = c.WriteTo(buf[0:n], addr); err != nil {
+                       t.Fatalf("WriteTo %v: %v", addr, err)
+               }
+       }
+       c.Close()
+       done <- 1
+}
+
+func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) {
+       t.Logf("TestPacket %s %s %s\n", network, listenaddr, dialaddr)
+       listening := make(chan string)
+       done := make(chan int)
+       if network == "udp" {
+               listenaddr += ":0" // any available port
+       }
+       go runPacket(t, network, listenaddr, listening, done)
+       addr := <-listening // wait for server to start
+       if network == "udp" {
+               dialaddr += addr[strings.LastIndex(addr, ":"):]
+       }
+       connect(t, network, dialaddr, isEmpty)
+       <-done // tell server to stop
+       <-done // wait for stop
+}
+
+func TestUDPServer(t *testing.T) {
+       if !*testUDP {
+               return
+       }
+       for _, isEmpty := range []bool{false, true} {
+               doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
+               doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
+               if kernelSupportsIPv6() {
+                       doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]", isEmpty)
+                       doTestPacket(t, "udp", "[::]", "127.0.0.1", isEmpty)
+                       doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]", isEmpty)
+               }
+       }
+}
+
+func TestUnixDatagramServer(t *testing.T) {
+       // "unix" sockets are not supported on windows.
+       if runtime.GOOS == "windows" {
+               return
+       }
+       for _, isEmpty := range []bool{false} {
+               os.Remove("/tmp/gotest1.net")
+               os.Remove("/tmp/gotest1.net.local")
+               doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty)
+               os.Remove("/tmp/gotest1.net")
+               os.Remove("/tmp/gotest1.net.local")
+               if syscall.OS == "linux" {
+                       // Test abstract unix domain socket, a Linux-ism
+                       doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty)
+               }
+       }
+}
diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go
new file mode 100644 (file)
index 0000000..3e105ad
--- /dev/null
@@ -0,0 +1,178 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Sockets
+
+package net
+
+import (
+       "os"
+       "reflect"
+       "syscall"
+)
+
+// Boolean to int.
+func boolint(b bool) int {
+       if b {
+               return 1
+       }
+       return 0
+}
+
+// Generic socket creation.
+func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
+       // See ../syscall/exec.go for description of ForkLock.
+       syscall.ForkLock.RLock()
+       s, e := syscall.Socket(f, p, t)
+       if e != 0 {
+               syscall.ForkLock.RUnlock()
+               return nil, os.Errno(e)
+       }
+       syscall.CloseOnExec(s)
+       syscall.ForkLock.RUnlock()
+
+       // Allow reuse of recently-used addresses.
+       syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+
+       // Allow broadcast.
+       syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+
+       if f == syscall.AF_INET6 {
+               // using ip, tcp, udp, etc.
+               // allow both protocols even if the OS default is otherwise.
+               syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+       }
+
+       if la != nil {
+               e = syscall.Bind(s, la)
+               if e != 0 {
+                       syscall.Close(s)
+                       return nil, os.Errno(e)
+               }
+       }
+
+       if ra != nil {
+               e = syscall.Connect(s, ra)
+               if e != 0 {
+                       syscall.Close(s)
+                       return nil, os.Errno(e)
+               }
+       }
+
+       sa, _ := syscall.Getsockname(s)
+       laddr := toAddr(sa)
+       sa, _ = syscall.Getpeername(s)
+       raddr := toAddr(sa)
+
+       fd, err = newFD(s, f, p, net, laddr, raddr)
+       if err != nil {
+               syscall.Close(s)
+               return nil, err
+       }
+
+       return fd, nil
+}
+
+func setsockoptInt(fd, level, opt int, value int) os.Error {
+       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, opt, value))
+}
+
+func setsockoptNsec(fd, level, opt int, nsec int64) os.Error {
+       var tv = syscall.NsecToTimeval(nsec)
+       return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd, level, opt, &tv))
+}
+
+func setReadBuffer(fd *netFD, bytes int) os.Error {
+       fd.incref()
+       defer fd.decref()
+       return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
+}
+
+func setWriteBuffer(fd *netFD, bytes int) os.Error {
+       fd.incref()
+       defer fd.decref()
+       return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
+}
+
+func setReadTimeout(fd *netFD, nsec int64) os.Error {
+       fd.rdeadline_delta = nsec
+       return nil
+}
+
+func setWriteTimeout(fd *netFD, nsec int64) os.Error {
+       fd.wdeadline_delta = nsec
+       return nil
+}
+
+func setTimeout(fd *netFD, nsec int64) os.Error {
+       if e := setReadTimeout(fd, nsec); e != nil {
+               return e
+       }
+       return setWriteTimeout(fd, nsec)
+}
+
+func setReuseAddr(fd *netFD, reuse bool) os.Error {
+       fd.incref()
+       defer fd.decref()
+       return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
+}
+
+func bindToDevice(fd *netFD, dev string) os.Error {
+       // TODO(rsc): call setsockopt with null-terminated string pointer
+       return os.EINVAL
+}
+
+func setDontRoute(fd *netFD, dontroute bool) os.Error {
+       fd.incref()
+       defer fd.decref()
+       return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))
+}
+
+func setKeepAlive(fd *netFD, keepalive bool) os.Error {
+       fd.incref()
+       defer fd.decref()
+       return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
+}
+
+func setNoDelay(fd *netFD, noDelay bool) os.Error {
+       fd.incref()
+       defer fd.decref()
+       return setsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
+}
+
+func setLinger(fd *netFD, sec int) os.Error {
+       var l syscall.Linger
+       if sec >= 0 {
+               l.Onoff = 1
+               l.Linger = int32(sec)
+       } else {
+               l.Onoff = 0
+               l.Linger = 0
+       }
+       fd.incref()
+       defer fd.decref()
+       e := syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l)
+       return os.NewSyscallError("setsockopt", e)
+}
+
+type UnknownSocketError struct {
+       sa syscall.Sockaddr
+}
+
+func (e *UnknownSocketError) String() string {
+       return "unknown socket address type " + reflect.Typeof(e.sa).String()
+}
+
+func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) {
+       switch a := sa.(type) {
+       case *syscall.SockaddrInet4:
+               return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
+       case *syscall.SockaddrInet6:
+               return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
+       case *syscall.SockaddrUnix:
+               return a.Name, nil
+       }
+
+       return "", &UnknownSocketError{sa}
+}
diff --git a/libgo/go/net/srv_test.go b/libgo/go/net/srv_test.go
new file mode 100644 (file)
index 0000000..4dd6089
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO It would be nice to use a mock DNS server, to eliminate
+// external dependencies.
+
+package net
+
+import (
+       "testing"
+)
+
+func TestGoogleSRV(t *testing.T) {
+       _, addrs, err := LookupSRV("xmpp-server", "tcp", "google.com")
+       if err != nil {
+               t.Errorf("failed: %s", err)
+       }
+       if len(addrs) == 0 {
+               t.Errorf("no results")
+       }
+}
diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go
new file mode 100644 (file)
index 0000000..b0cb8f9
--- /dev/null
@@ -0,0 +1,293 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TCP sockets
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+func sockaddrToTCP(sa syscall.Sockaddr) Addr {
+       switch sa := sa.(type) {
+       case *syscall.SockaddrInet4:
+               return &TCPAddr{sa.Addr[0:], sa.Port}
+       case *syscall.SockaddrInet6:
+               return &TCPAddr{sa.Addr[0:], sa.Port}
+       }
+       return nil
+}
+
+// TCPAddr represents the address of a TCP end point.
+type TCPAddr struct {
+       IP   IP
+       Port int
+}
+
+// Network returns the address's network name, "tcp".
+func (a *TCPAddr) Network() string { return "tcp" }
+
+func (a *TCPAddr) String() string {
+       if a == nil {
+               return "<nil>"
+       }
+       return joinHostPort(a.IP.String(), itoa(a.Port))
+}
+
+func (a *TCPAddr) family() int {
+       if a == nil || len(a.IP) <= 4 {
+               return syscall.AF_INET
+       }
+       if ip := a.IP.To4(); ip != nil {
+               return syscall.AF_INET
+       }
+       return syscall.AF_INET6
+}
+
+func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+       return ipToSockaddr(family, a.IP, a.Port)
+}
+
+func (a *TCPAddr) toAddr() sockaddr {
+       if a == nil { // nil *TCPAddr
+               return nil // nil interface
+       }
+       return a
+}
+
+// ResolveTCPAddr parses addr as a TCP address of the form
+// host:port and resolves domain names or port names to
+// numeric addresses.  A literal IPv6 host address must be
+// enclosed in square brackets, as in "[::]:80".
+func ResolveTCPAddr(addr string) (*TCPAddr, os.Error) {
+       ip, port, err := hostPortToIP("tcp", addr)
+       if err != nil {
+               return nil, err
+       }
+       return &TCPAddr{ip, port}, nil
+}
+
+// TCPConn is an implementation of the Conn interface
+// for TCP network connections.
+type TCPConn struct {
+       fd *netFD
+}
+
+func newTCPConn(fd *netFD) *TCPConn {
+       c := &TCPConn{fd}
+       c.SetNoDelay(true)
+       return c
+}
+
+func (c *TCPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *TCPConn) Read(b []byte) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *TCPConn) Write(b []byte) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       return c.fd.Write(b)
+}
+
+// Close closes the TCP connection.
+func (c *TCPConn) Close() os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       err := c.fd.Close()
+       c.fd = nil
+       return err
+}
+
+// LocalAddr returns the local network address, a *TCPAddr.
+func (c *TCPConn) LocalAddr() Addr {
+       if !c.ok() {
+               return nil
+       }
+       return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *TCPAddr.
+func (c *TCPConn) RemoteAddr() Addr {
+       if !c.ok() {
+               return nil
+       }
+       return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *TCPConn) SetTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *TCPConn) SetReadTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *TCPConn) SetWriteTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *TCPConn) SetReadBuffer(bytes int) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *TCPConn) SetWriteBuffer(bytes int) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setWriteBuffer(c.fd, bytes)
+}
+
+// SetLinger sets the behavior of Close() on a connection
+// which still has data waiting to be sent or to be acknowledged.
+//
+// If sec < 0 (the default), Close returns immediately and
+// the operating system finishes sending the data in the background.
+//
+// If sec == 0, Close returns immediately and the operating system
+// discards any unsent or unacknowledged data.
+//
+// If sec > 0, Close blocks for at most sec seconds waiting for
+// data to be sent and acknowledged.
+func (c *TCPConn) SetLinger(sec int) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setLinger(c.fd, sec)
+}
+
+// SetKeepAlive sets whether the operating system should send
+// keepalive messages on the connection.
+func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setKeepAlive(c.fd, keepalive)
+}
+
+// SetNoDelay controls whether the operating system should delay
+// packet transmission in hopes of sending fewer packets
+// (Nagle's algorithm).  The default is true (no delay), meaning
+// that data is sent as soon as possible after a Write.
+func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setNoDelay(c.fd, noDelay)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+// DialTCP is like Dial but can only connect to TCP networks
+// and returns a TCPConn structure.
+func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
+       if raddr == nil {
+               return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
+       }
+       fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+       if e != nil {
+               return nil, e
+       }
+       return newTCPConn(fd), nil
+}
+
+// TCPListener is a TCP network listener.
+// Clients should typically use variables of type Listener
+// instead of assuming TCP.
+type TCPListener struct {
+       fd *netFD
+}
+
+// ListenTCP announces on the TCP address laddr and returns a TCP listener.
+// Net must be "tcp", "tcp4", or "tcp6".
+// If laddr has a port of 0, it means to listen on some available port.
+// The caller can use l.Addr() to retrieve the chosen address.
+func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
+       fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
+       if err != nil {
+               return nil, err
+       }
+       errno := syscall.Listen(fd.sysfd, listenBacklog())
+       if errno != 0 {
+               syscall.Close(fd.sysfd)
+               return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)}
+       }
+       l = new(TCPListener)
+       l.fd = fd
+       return l, nil
+}
+
+// AcceptTCP accepts the next incoming call and returns the new connection
+// and the remote address.
+func (l *TCPListener) AcceptTCP() (c *TCPConn, err os.Error) {
+       if l == nil || l.fd == nil || l.fd.sysfd < 0 {
+               return nil, os.EINVAL
+       }
+       fd, err := l.fd.accept(sockaddrToTCP)
+       if err != nil {
+               return nil, err
+       }
+       return newTCPConn(fd), nil
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *TCPListener) Accept() (c Conn, err os.Error) {
+       c1, err := l.AcceptTCP()
+       if err != nil {
+               return nil, err
+       }
+       return c1, nil
+}
+
+// Close stops listening on the TCP address.
+// Already Accepted connections are not closed.
+func (l *TCPListener) Close() os.Error {
+       if l == nil || l.fd == nil {
+               return os.EINVAL
+       }
+       return l.fd.Close()
+}
+
+// Addr returns the listener's network address, a *TCPAddr.
+func (l *TCPListener) Addr() Addr { return l.fd.laddr }
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *TCPListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
diff --git a/libgo/go/net/textproto/pipeline.go b/libgo/go/net/textproto/pipeline.go
new file mode 100644 (file)
index 0000000..8c25884
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+       "sync"
+)
+
+// A Pipeline manages a pipelined in-order request/response sequence.
+//
+// To use a Pipeline p to manage multiple clients on a connection,
+// each client should run:
+//
+//     id := p.Next()  // take a number
+//
+//     p.StartRequest(id)      // wait for turn to send request
+//     «send request»
+//     p.EndRequest(id)        // notify Pipeline that request is sent
+//
+//     p.StartResponse(id)     // wait for turn to read response
+//     «read response»
+//     p.EndResponse(id)       // notify Pipeline that response is read
+//
+// A pipelined server can use the same calls to ensure that
+// responses computed in parallel are written in the correct order.
+type Pipeline struct {
+       mu       sync.Mutex
+       id       uint
+       request  sequencer
+       response sequencer
+}
+
+// Next returns the next id for a request/response pair.
+func (p *Pipeline) Next() uint {
+       p.mu.Lock()
+       id := p.id
+       p.id++
+       p.mu.Unlock()
+       return id
+}
+
+// StartRequest blocks until it is time to send (or, if this is a server, receive)
+// the request with the given id.
+func (p *Pipeline) StartRequest(id uint) {
+       p.request.Start(id)
+}
+
+// EndRequest notifies p that the request with the given id has been sent
+// (or, if this is a server, received).
+func (p *Pipeline) EndRequest(id uint) {
+       p.request.End(id)
+}
+
+// StartResponse blocks until it is time to receive (or, if this is a server, send)
+// the request with the given id.
+func (p *Pipeline) StartResponse(id uint) {
+       p.response.Start(id)
+}
+
+// EndResponse notifies p that the response with the given id has been received
+// (or, if this is a server, sent).
+func (p *Pipeline) EndResponse(id uint) {
+       p.response.End(id)
+}
+
+// A sequencer schedules a sequence of numbered events that must
+// happen in order, one after the other.  The event numbering must start
+// at 0 and increment without skipping.  The event number wraps around
+// safely as long as there are not 2^32 simultaneous events pending.
+type sequencer struct {
+       mu   sync.Mutex
+       id   uint
+       wait map[uint]chan uint
+}
+
+// Start waits until it is time for the event numbered id to begin.
+// That is, except for the first event, it waits until End(id-1) has
+// been called.
+func (s *sequencer) Start(id uint) {
+       s.mu.Lock()
+       if s.id == id {
+               s.mu.Unlock()
+               return
+       }
+       c := make(chan uint)
+       if s.wait == nil {
+               s.wait = make(map[uint]chan uint)
+       }
+       s.wait[id] = c
+       s.mu.Unlock()
+       <-c
+}
+
+// End notifies the sequencer that the event numbered id has completed,
+// allowing it to schedule the event numbered id+1.  It is a run-time error
+// to call End with an id that is not the number of the active event.
+func (s *sequencer) End(id uint) {
+       s.mu.Lock()
+       if s.id != id {
+               panic("out of sync")
+       }
+       id++
+       s.id = id
+       if s.wait == nil {
+               s.wait = make(map[uint]chan uint)
+       }
+       c, ok := s.wait[id]
+       if ok {
+               s.wait[id] = nil, false
+       }
+       s.mu.Unlock()
+       if ok {
+               c <- 1
+       }
+}
diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go
new file mode 100644 (file)
index 0000000..aad2553
--- /dev/null
@@ -0,0 +1,494 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+       "bufio"
+       "bytes"
+       "container/vector"
+       "io"
+       "io/ioutil"
+       "os"
+       "strconv"
+)
+
+// BUG(rsc): To let callers manage exposure to denial of service
+// attacks, Reader should allow them to set and reset a limit on
+// the number of bytes read from the connection.
+
+// A Reader implements convenience methods for reading requests
+// or responses from a text protocol network connection.
+type Reader struct {
+       R   *bufio.Reader
+       dot *dotReader
+}
+
+// NewReader returns a new Reader reading from r.
+func NewReader(r *bufio.Reader) *Reader {
+       return &Reader{R: r}
+}
+
+// ReadLine reads a single line from r,
+// eliding the final \n or \r\n from the returned string.
+func (r *Reader) ReadLine() (string, os.Error) {
+       line, err := r.ReadLineBytes()
+       return string(line), err
+}
+
+// ReadLineBytes is like ReadLine but returns a []byte instead of a string.
+func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
+       r.closeDot()
+       line, err := r.R.ReadBytes('\n')
+       n := len(line)
+       if n > 0 && line[n-1] == '\n' {
+               n--
+               if n > 0 && line[n-1] == '\r' {
+                       n--
+               }
+       }
+       return line[0:n], err
+}
+
+var space = []byte{' '}
+
+// ReadContinuedLine reads a possibly continued line from r,
+// eliding the final trailing ASCII white space.
+// Lines after the first are considered continuations if they
+// begin with a space or tab character.  In the returned data,
+// continuation lines are separated from the previous line
+// only by a single space: the newline and leading white space
+// are removed.
+//
+// For example, consider this input:
+//
+//     Line 1
+//       continued...
+//     Line 2
+//
+// The first call to ReadContinuedLine will return "Line 1 continued..."
+// and the second will return "Line 2".
+//
+// A line consisting of only white space is never continued.
+//
+func (r *Reader) ReadContinuedLine() (string, os.Error) {
+       line, err := r.ReadContinuedLineBytes()
+       return string(line), err
+}
+
+// trim returns s with leading and trailing spaces and tabs removed.
+// It does not assume Unicode or UTF-8.
+func trim(s []byte) []byte {
+       i := 0
+       for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+               i++
+       }
+       n := len(s)
+       for n > i && (s[n-1] == ' ' || s[n-1] == '\t') {
+               n--
+       }
+       return s[i:n]
+}
+
+// ReadContinuedLineBytes is like ReadContinuedLine but
+// returns a []byte instead of a string.
+func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
+       // Read the first line.
+       line, err := r.ReadLineBytes()
+       if err != nil {
+               return line, err
+       }
+       if len(line) == 0 { // blank line - no continuation
+               return line, nil
+       }
+       line = trim(line)
+
+       // Look for a continuation line.
+       c, err := r.R.ReadByte()
+       if err != nil {
+               // Delay err until we read the byte next time.
+               return line, nil
+       }
+       if c != ' ' && c != '\t' {
+               // Not a continuation.
+               r.R.UnreadByte()
+               return line, nil
+       }
+
+       // Read continuation lines.
+       for {
+               // Consume leading spaces; one already gone.
+               for {
+                       c, err = r.R.ReadByte()
+                       if err != nil {
+                               break
+                       }
+                       if c != ' ' && c != '\t' {
+                               r.R.UnreadByte()
+                               break
+                       }
+               }
+               var cont []byte
+               cont, err = r.ReadLineBytes()
+               cont = trim(cont)
+               line = bytes.Add(line, space)
+               line = bytes.Add(line, cont)
+               if err != nil {
+                       break
+               }
+
+               // Check for leading space on next line.
+               if c, err = r.R.ReadByte(); err != nil {
+                       break
+               }
+               if c != ' ' && c != '\t' {
+                       r.R.UnreadByte()
+                       break
+               }
+       }
+
+       // Delay error until next call.
+       if len(line) > 0 {
+               err = nil
+       }
+       return line, err
+}
+
+func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err os.Error) {
+       line, err := r.ReadLine()
+       if err != nil {
+               return
+       }
+       if len(line) < 4 || line[3] != ' ' && line[3] != '-' {
+               err = ProtocolError("short response: " + line)
+               return
+       }
+       continued = line[3] == '-'
+       code, err = strconv.Atoi(line[0:3])
+       if err != nil || code < 100 {
+               err = ProtocolError("invalid response code: " + line)
+               return
+       }
+       message = line[4:]
+       if 1 <= expectCode && expectCode < 10 && code/100 != expectCode ||
+               10 <= expectCode && expectCode < 100 && code/10 != expectCode ||
+               100 <= expectCode && expectCode < 1000 && code != expectCode {
+               err = &Error{code, message}
+       }
+       return
+}
+
+// ReadCodeLine reads a response code line of the form
+//     code message
+// where code is a 3-digit status code and the message
+// extends to the rest of the line.  An example of such a line is:
+//     220 plan9.bell-labs.com ESMTP
+//
+// If the prefix of the status does not match the digits in expectCode,
+// ReadCodeLine returns with err set to &Error{code, message}.
+// For example, if expectCode is 31, an error will be returned if
+// the status is not in the range [310,319].
+//
+// If the response is multi-line, ReadCodeLine returns an error.
+//
+// An expectCode <= 0 disables the check of the status code.
+//
+func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err os.Error) {
+       code, continued, message, err := r.readCodeLine(expectCode)
+       if err == nil && continued {
+               err = ProtocolError("unexpected multi-line response: " + message)
+       }
+       return
+}
+
+// ReadResponse reads a multi-line response of the form
+//     code-message line 1
+//     code-message line 2
+//     ...
+//     code message line n
+// where code is a 3-digit status code. Each line should have the same code.
+// The response is terminated by a line that uses a space between the code and
+// the message line rather than a dash. Each line in message is separated by
+// a newline (\n).
+//
+// If the prefix of the status does not match the digits in expectCode,
+// ReadResponse returns with err set to &Error{code, message}.
+// For example, if expectCode is 31, an error will be returned if
+// the status is not in the range [310,319].
+//
+// An expectCode <= 0 disables the check of the status code.
+//
+func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os.Error) {
+       code, continued, message, err := r.readCodeLine(expectCode)
+       for err == nil && continued {
+               var code2 int
+               var moreMessage string
+               code2, continued, moreMessage, err = r.readCodeLine(expectCode)
+               if code != code2 {
+                       err = ProtocolError("status code mismatch: " + strconv.Itoa(code) + ", " + strconv.Itoa(code2))
+               }
+               message += "\n" + moreMessage
+       }
+       return
+}
+
+// DotReader returns a new Reader that satisfies Reads using the
+// decoded text of a dot-encoded block read from r.
+// The returned Reader is only valid until the next call
+// to a method on r.
+//
+// Dot encoding is a common framing used for data blocks
+// in text protcols like SMTP.  The data consists of a sequence
+// of lines, each of which ends in "\r\n".  The sequence itself
+// ends at a line containing just a dot: ".\r\n".  Lines beginning
+// with a dot are escaped with an additional dot to avoid
+// looking like the end of the sequence.
+//
+// The decoded form returned by the Reader's Read method
+// rewrites the "\r\n" line endings into the simpler "\n",
+// removes leading dot escapes if present, and stops with error os.EOF
+// after consuming (and discarding) the end-of-sequence line.
+func (r *Reader) DotReader() io.Reader {
+       r.closeDot()
+       r.dot = &dotReader{r: r}
+       return r.dot
+}
+
+type dotReader struct {
+       r     *Reader
+       state int
+}
+
+// Read satisfies reads by decoding dot-encoded data read from d.r.
+func (d *dotReader) Read(b []byte) (n int, err os.Error) {
+       // Run data through a simple state machine to
+       // elide leading dots, rewrite trailing \r\n into \n,
+       // and detect ending .\r\n line.
+       const (
+               stateBeginLine = iota // beginning of line; initial state; must be zero
+               stateDot              // read . at beginning of line
+               stateDotCR            // read .\r at beginning of line
+               stateCR               // read \r (possibly at end of line)
+               stateData             // reading data in middle of line
+               stateEOF              // reached .\r\n end marker line
+       )
+       br := d.r.R
+       for n < len(b) && d.state != stateEOF {
+               var c byte
+               c, err = br.ReadByte()
+               if err != nil {
+                       if err == os.EOF {
+                               err = io.ErrUnexpectedEOF
+                       }
+                       break
+               }
+               switch d.state {
+               case stateBeginLine:
+                       if c == '.' {
+                               d.state = stateDot
+                               continue
+                       }
+                       if c == '\r' {
+                               d.state = stateCR
+                               continue
+                       }
+                       d.state = stateData
+
+               case stateDot:
+                       if c == '\r' {
+                               d.state = stateDotCR
+                               continue
+                       }
+                       if c == '\n' {
+                               d.state = stateEOF
+                               continue
+                       }
+                       d.state = stateData
+
+               case stateDotCR:
+                       if c == '\n' {
+                               d.state = stateEOF
+                               continue
+                       }
+                       // Not part of .\r\n.
+                       // Consume leading dot and emit saved \r.
+                       br.UnreadByte()
+                       c = '\r'
+                       d.state = stateData
+
+               case stateCR:
+                       if c == '\n' {
+                               d.state = stateBeginLine
+                               break
+                       }
+                       // Not part of \r\n.  Emit saved \r
+                       br.UnreadByte()
+                       c = '\r'
+                       d.state = stateData
+
+               case stateData:
+                       if c == '\r' {
+                               d.state = stateCR
+                               continue
+                       }
+                       if c == '\n' {
+                               d.state = stateBeginLine
+                       }
+               }
+               b[n] = c
+               n++
+       }
+       if err == nil && d.state == stateEOF {
+               err = os.EOF
+       }
+       if err != nil && d.r.dot == d {
+               d.r.dot = nil
+       }
+       return
+}
+
+// closeDot drains the current DotReader if any,
+// making sure that it reads until the ending dot line.
+func (r *Reader) closeDot() {
+       if r.dot == nil {
+               return
+       }
+       buf := make([]byte, 128)
+       for r.dot != nil {
+               // When Read reaches EOF or an error,
+               // it will set r.dot == nil.
+               r.dot.Read(buf)
+       }
+}
+
+// ReadDotBytes reads a dot-encoding and returns the decoded data.
+//
+// See the documentation for the DotReader method for details about dot-encoding.
+func (r *Reader) ReadDotBytes() ([]byte, os.Error) {
+       return ioutil.ReadAll(r.DotReader())
+}
+
+// ReadDotLines reads a dot-encoding and returns a slice
+// containing the decoded lines, with the final \r\n or \n elided from each.
+//
+// See the documentation for the DotReader method for details about dot-encoding.
+func (r *Reader) ReadDotLines() ([]string, os.Error) {
+       // We could use ReadDotBytes and then Split it,
+       // but reading a line at a time avoids needing a
+       // large contiguous block of memory and is simpler.
+       var v vector.StringVector
+       var err os.Error
+       for {
+               var line string
+               line, err = r.ReadLine()
+               if err != nil {
+                       if err == os.EOF {
+                               err = io.ErrUnexpectedEOF
+                       }
+                       break
+               }
+
+               // Dot by itself marks end; otherwise cut one dot.
+               if len(line) > 0 && line[0] == '.' {
+                       if len(line) == 1 {
+                               break
+                       }
+                       line = line[1:]
+               }
+               v.Push(line)
+       }
+       return v, err
+}
+
+// ReadMIMEHeader reads a MIME-style header from r.
+// The header is a sequence of possibly continued Key: Value lines
+// ending in a blank line.
+// The returned map m maps CanonicalHeaderKey(key) to a
+// sequence of values in the same order encountered in the input.
+//
+// For example, consider this input:
+//
+//     My-Key: Value 1
+//     Long-Key: Even
+//            Longer Value
+//     My-Key: Value 2
+//
+// Given that input, ReadMIMEHeader returns the map:
+//
+//     map[string][]string{
+//             "My-Key": []string{"Value 1", "Value 2"},
+//             "Long-Key": []string{"Even Longer Value"},
+//     }
+//
+func (r *Reader) ReadMIMEHeader() (map[string][]string, os.Error) {
+       m := make(map[string][]string)
+       for {
+               kv, err := r.ReadContinuedLineBytes()
+               if len(kv) == 0 {
+                       return m, err
+               }
+
+               // Key ends at first colon; must not have spaces.
+               i := bytes.IndexByte(kv, ':')
+               if i < 0 || bytes.IndexByte(kv[0:i], ' ') >= 0 {
+                       return m, ProtocolError("malformed MIME header line: " + string(kv))
+               }
+               key := CanonicalHeaderKey(string(kv[0:i]))
+
+               // Skip initial spaces in value.
+               i++ // skip colon
+               for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
+                       i++
+               }
+               value := string(kv[i:])
+
+               v := vector.StringVector(m[key])
+               v.Push(value)
+               m[key] = v
+
+               if err != nil {
+                       return m, err
+               }
+       }
+       panic("unreachable")
+}
+
+// CanonicalHeaderKey returns the canonical format of the
+// MIME header key s.  The canonicalization converts the first
+// letter and any letter following a hyphen to upper case;
+// the rest are converted to lowercase.  For example, the
+// canonical key for "accept-encoding" is "Accept-Encoding".
+func CanonicalHeaderKey(s string) string {
+       // Quick check for canonical encoding.
+       needUpper := true
+       for i := 0; i < len(s); i++ {
+               c := s[i]
+               if needUpper && 'a' <= c && c <= 'z' {
+                       goto MustRewrite
+               }
+               if !needUpper && 'A' <= c && c <= 'Z' {
+                       goto MustRewrite
+               }
+               needUpper = c == '-'
+       }
+       return s
+
+MustRewrite:
+       // Canonicalize: first letter upper case
+       // and upper case after each dash.
+       // (Host, User-Agent, If-Modified-Since).
+       // MIME headers are ASCII only, so no Unicode issues.
+       a := []byte(s)
+       upper := true
+       for i, v := range a {
+               if upper && 'a' <= v && v <= 'z' {
+                       a[i] = v + 'A' - 'a'
+               }
+               if !upper && 'A' <= v && v <= 'Z' {
+                       a[i] = v + 'a' - 'A'
+               }
+               upper = v == '-'
+       }
+       return string(a)
+}
diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go
new file mode 100644 (file)
index 0000000..2cecbc7
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+       "bufio"
+       "io"
+       "os"
+       "reflect"
+       "strings"
+       "testing"
+)
+
+type canonicalHeaderKeyTest struct {
+       in, out string
+}
+
+var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{
+       {"a-b-c", "A-B-C"},
+       {"a-1-c", "A-1-C"},
+       {"User-Agent", "User-Agent"},
+       {"uSER-aGENT", "User-Agent"},
+       {"user-agent", "User-Agent"},
+       {"USER-AGENT", "User-Agent"},
+}
+
+func TestCanonicalHeaderKey(t *testing.T) {
+       for _, tt := range canonicalHeaderKeyTests {
+               if s := CanonicalHeaderKey(tt.in); s != tt.out {
+                       t.Errorf("CanonicalHeaderKey(%q) = %q, want %q", tt.in, s, tt.out)
+               }
+       }
+}
+
+func reader(s string) *Reader {
+       return NewReader(bufio.NewReader(strings.NewReader(s)))
+}
+
+func TestReadLine(t *testing.T) {
+       r := reader("line1\nline2\n")
+       s, err := r.ReadLine()
+       if s != "line1" || err != nil {
+               t.Fatalf("Line 1: %s, %v", s, err)
+       }
+       s, err = r.ReadLine()
+       if s != "line2" || err != nil {
+               t.Fatalf("Line 2: %s, %v", s, err)
+       }
+       s, err = r.ReadLine()
+       if s != "" || err != os.EOF {
+               t.Fatalf("EOF: %s, %v", s, err)
+       }
+}
+
+func TestReadContinuedLine(t *testing.T) {
+       r := reader("line1\nline\n 2\nline3\n")
+       s, err := r.ReadContinuedLine()
+       if s != "line1" || err != nil {
+               t.Fatalf("Line 1: %s, %v", s, err)
+       }
+       s, err = r.ReadContinuedLine()
+       if s != "line 2" || err != nil {
+               t.Fatalf("Line 2: %s, %v", s, err)
+       }
+       s, err = r.ReadContinuedLine()
+       if s != "line3" || err != nil {
+               t.Fatalf("Line 3: %s, %v", s, err)
+       }
+       s, err = r.ReadContinuedLine()
+       if s != "" || err != os.EOF {
+               t.Fatalf("EOF: %s, %v", s, err)
+       }
+}
+
+func TestReadCodeLine(t *testing.T) {
+       r := reader("123 hi\n234 bye\n345 no way\n")
+       code, msg, err := r.ReadCodeLine(0)
+       if code != 123 || msg != "hi" || err != nil {
+               t.Fatalf("Line 1: %d, %s, %v", code, msg, err)
+       }
+       code, msg, err = r.ReadCodeLine(23)
+       if code != 234 || msg != "bye" || err != nil {
+               t.Fatalf("Line 2: %d, %s, %v", code, msg, err)
+       }
+       code, msg, err = r.ReadCodeLine(346)
+       if code != 345 || msg != "no way" || err == nil {
+               t.Fatalf("Line 3: %d, %s, %v", code, msg, err)
+       }
+       if e, ok := err.(*Error); !ok || e.Code != code || e.Msg != msg {
+               t.Fatalf("Line 3: wrong error %v\n", err)
+       }
+       code, msg, err = r.ReadCodeLine(1)
+       if code != 0 || msg != "" || err != os.EOF {
+               t.Fatalf("EOF: %d, %s, %v", code, msg, err)
+       }
+}
+
+func TestReadDotLines(t *testing.T) {
+       r := reader("dotlines\r\n.foo\r\n..bar\n...baz\nquux\r\n\r\n.\r\nanother\n")
+       s, err := r.ReadDotLines()
+       want := []string{"dotlines", "foo", ".bar", "..baz", "quux", ""}
+       if !reflect.DeepEqual(s, want) || err != nil {
+               t.Fatalf("ReadDotLines: %v, %v", s, err)
+       }
+
+       s, err = r.ReadDotLines()
+       want = []string{"another"}
+       if !reflect.DeepEqual(s, want) || err != io.ErrUnexpectedEOF {
+               t.Fatalf("ReadDotLines2: %v, %v", s, err)
+       }
+}
+
+func TestReadDotBytes(t *testing.T) {
+       r := reader("dotlines\r\n.foo\r\n..bar\n...baz\nquux\r\n\r\n.\r\nanot.her\r\n")
+       b, err := r.ReadDotBytes()
+       want := []byte("dotlines\nfoo\n.bar\n..baz\nquux\n\n")
+       if !reflect.DeepEqual(b, want) || err != nil {
+               t.Fatalf("ReadDotBytes: %q, %v", b, err)
+       }
+
+       b, err = r.ReadDotBytes()
+       want = []byte("anot.her\n")
+       if !reflect.DeepEqual(b, want) || err != io.ErrUnexpectedEOF {
+               t.Fatalf("ReadDotBytes2: %q, %v", b, err)
+       }
+}
+
+func TestReadMIMEHeader(t *testing.T) {
+       r := reader("my-key: Value 1  \r\nLong-key: Even \n Longer Value\r\nmy-Key: Value 2\r\n\n")
+       m, err := r.ReadMIMEHeader()
+       want := map[string][]string{
+               "My-Key":   {"Value 1", "Value 2"},
+               "Long-Key": {"Even Longer Value"},
+       }
+       if !reflect.DeepEqual(m, want) || err != nil {
+               t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want)
+       }
+}
diff --git a/libgo/go/net/textproto/textproto.go b/libgo/go/net/textproto/textproto.go
new file mode 100644 (file)
index 0000000..f62009c
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The textproto package implements generic support for
+// text-based request/response protocols in the style of
+// HTTP, NNTP, and SMTP.
+//
+// The package provides:
+//
+// Error, which represents a numeric error response from
+// a server.
+//
+// Pipeline, to manage pipelined requests and responses
+// in a client.
+//
+// Reader, to read numeric response code lines,
+// key: value headers, lines wrapped with leading spaces
+// on continuation lines, and whole text blocks ending
+// with a dot on a line by itself.
+//
+// Writer, to write dot-encoded text blocks.
+//
+package textproto
+
+import (
+       "bufio"
+       "fmt"
+       "io"
+       "net"
+       "os"
+)
+
+// An Error represents a numeric error response from a server.
+type Error struct {
+       Code int
+       Msg  string
+}
+
+func (e *Error) String() string {
+       return fmt.Sprintf("%03d %s", e.Code, e.Msg)
+}
+
+// A ProtocolError describes a protocol violation such
+// as an invalid response or a hung-up connection.
+type ProtocolError string
+
+func (p ProtocolError) String() string {
+       return string(p)
+}
+
+// A Conn represents a textual network protocol connection.
+// It consists of a Reader and Writer to manage I/O
+// and a Pipeline to sequence concurrent requests on the connection.
+// These embedded types carry methods with them;
+// see the documentation of those types for details.
+type Conn struct {
+       Reader
+       Writer
+       Pipeline
+       conn io.ReadWriteCloser
+}
+
+// NewConn returns a new Conn using conn for I/O.
+func NewConn(conn io.ReadWriteCloser) *Conn {
+       return &Conn{
+               Reader: Reader{R: bufio.NewReader(conn)},
+               Writer: Writer{W: bufio.NewWriter(conn)},
+               conn:   conn,
+       }
+}
+
+// Close closes the connection.
+func (c *Conn) Close() os.Error {
+       return c.conn.Close()
+}
+
+// Dial connects to the given address on the given network using net.Dial
+// and then returns a new Conn for the connection.
+func Dial(network, addr string) (*Conn, os.Error) {
+       c, err := net.Dial(network, "", addr)
+       if err != nil {
+               return nil, err
+       }
+       return NewConn(c), nil
+}
+
+// Cmd is a convenience method that sends a command after
+// waiting its turn in the pipeline.  The command text is the
+// result of formatting format with args and appending \r\n.
+// Cmd returns the id of the command, for use with StartResponse and EndResponse.
+//
+// For example, a client might run a HELP command that returns a dot-body
+// by using:
+//
+//     id, err := c.Cmd("HELP")
+//     if err != nil {
+//             return nil, err
+//     }
+//
+//     c.StartResponse(id)
+//     defer c.EndResponse(id)
+//
+//     if _, _, err = c.ReadCodeLine(110); err != nil {
+//             return nil, err
+//     }
+//     text, err := c.ReadDotAll()
+//     if err != nil {
+//             return nil, err
+//     }
+//     return c.ReadCodeLine(250)
+//
+func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err os.Error) {
+       id = c.Next()
+       c.StartRequest(id)
+       err = c.PrintfLine(format, args...)
+       c.EndRequest(id)
+       if err != nil {
+               return 0, err
+       }
+       return id, nil
+}
diff --git a/libgo/go/net/textproto/writer.go b/libgo/go/net/textproto/writer.go
new file mode 100644 (file)
index 0000000..4e705f6
--- /dev/null
@@ -0,0 +1,119 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+       "bufio"
+       "fmt"
+       "io"
+       "os"
+)
+
+// A Writer implements convenience methods for writing
+// requests or responses to a text protocol network connection.
+type Writer struct {
+       W   *bufio.Writer
+       dot *dotWriter
+}
+
+// NewWriter returns a new Writer writing to w.
+func NewWriter(w *bufio.Writer) *Writer {
+       return &Writer{W: w}
+}
+
+var crnl = []byte{'\r', '\n'}
+var dotcrnl = []byte{'.', '\r', '\n'}
+
+// PrintfLine writes the formatted output followed by \r\n.
+func (w *Writer) PrintfLine(format string, args ...interface{}) os.Error {
+       w.closeDot()
+       fmt.Fprintf(w.W, format, args...)
+       w.W.Write(crnl)
+       return w.W.Flush()
+}
+
+// DotWriter returns a writer that can be used to write a dot-encoding to w.
+// It takes care of inserting leading dots when necessary,
+// translating line-ending \n into \r\n, and adding the final .\r\n line
+// when the DotWriter is closed.  The caller should close the
+// DotWriter before the next call to a method on w.
+//
+// See the documentation for Reader's DotReader method for details about dot-encoding.
+func (w *Writer) DotWriter() io.WriteCloser {
+       w.closeDot()
+       w.dot = &dotWriter{w: w}
+       return w.dot
+}
+
+func (w *Writer) closeDot() {
+       if w.dot != nil {
+               w.dot.Close() // sets w.dot = nil
+       }
+}
+
+type dotWriter struct {
+       w     *Writer
+       state int
+}
+
+const (
+       wstateBeginLine = iota // beginning of line; initial state; must be zero
+       wstateCR               // wrote \r (possibly at end of line)
+       wstateData             // writing data in middle of line
+)
+
+func (d *dotWriter) Write(b []byte) (n int, err os.Error) {
+       bw := d.w.W
+       for n < len(b) {
+               c := b[n]
+               switch d.state {
+               case wstateBeginLine:
+                       d.state = wstateData
+                       if c == '.' {
+                               // escape leading dot
+                               bw.WriteByte('.')
+                       }
+                       fallthrough
+
+               case wstateData:
+                       if c == '\r' {
+                               d.state = wstateCR
+                       }
+                       if c == '\n' {
+                               bw.WriteByte('\r')
+                               d.state = wstateBeginLine
+                       }
+
+               case wstateCR:
+                       d.state = wstateData
+                       if c == '\n' {
+                               d.state = wstateBeginLine
+                       }
+               }
+               if err = bw.WriteByte(c); err != nil {
+                       break
+               }
+               n++
+       }
+       return
+}
+
+func (d *dotWriter) Close() os.Error {
+       if d.w.dot == d {
+               d.w.dot = nil
+       }
+       bw := d.w.W
+       switch d.state {
+       default:
+               bw.WriteByte('\r')
+               fallthrough
+       case wstateCR:
+               bw.WriteByte('\n')
+               fallthrough
+       case wstateBeginLine:
+               bw.Write(dotcrnl)
+       }
+       return bw.Flush()
+}
diff --git a/libgo/go/net/textproto/writer_test.go b/libgo/go/net/textproto/writer_test.go
new file mode 100644 (file)
index 0000000..e03ab5e
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+       "bufio"
+       "bytes"
+       "testing"
+)
+
+func TestPrintfLine(t *testing.T) {
+       var buf bytes.Buffer
+       w := NewWriter(bufio.NewWriter(&buf))
+       err := w.PrintfLine("foo %d", 123)
+       if s := buf.String(); s != "foo 123\r\n" || err != nil {
+               t.Fatalf("s=%q; err=%s", s, err)
+       }
+}
+
+func TestDotWriter(t *testing.T) {
+       var buf bytes.Buffer
+       w := NewWriter(bufio.NewWriter(&buf))
+       d := w.DotWriter()
+       n, err := d.Write([]byte("abc\n.def\n..ghi\n.jkl\n."))
+       if n != 21 || err != nil {
+               t.Fatalf("Write: %d, %s", n, err)
+       }
+       d.Close()
+       want := "abc\r\n..def\r\n...ghi\r\n..jkl\r\n..\r\n.\r\n"
+       if s := buf.String(); s != want {
+               t.Fatalf("wrote %q", s)
+       }
+}
diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go
new file mode 100644 (file)
index 0000000..0927816
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+       "os"
+       "testing"
+       "time"
+       "runtime"
+)
+
+func testTimeout(t *testing.T, network, addr string, readFrom bool) {
+       // Timeouts are not implemented on windows.
+       if runtime.GOOS == "windows" {
+               return
+       }
+       fd, err := Dial(network, "", addr)
+       if err != nil {
+               t.Errorf("dial %s %s failed: %v", network, addr, err)
+               return
+       }
+       defer fd.Close()
+       t0 := time.Nanoseconds()
+       fd.SetReadTimeout(1e8) // 100ms
+       var b [100]byte
+       var n int
+       var err1 os.Error
+       if readFrom {
+               n, _, err1 = fd.(PacketConn).ReadFrom(b[0:])
+       } else {
+               n, err1 = fd.Read(b[0:])
+       }
+       t1 := time.Nanoseconds()
+       what := "Read"
+       if readFrom {
+               what = "ReadFrom"
+       }
+       if n != 0 || err1 == nil || !err1.(Error).Timeout() {
+               t.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
+       }
+       if t1-t0 < 0.5e8 || t1-t0 > 1.5e8 {
+               t.Errorf("fd.%s on %s %s took %f seconds, expected 0.1", what, network, addr, float64(t1-t0)/1e9)
+       }
+}
+
+func TestTimeoutUDP(t *testing.T) {
+       testTimeout(t, "udp", "127.0.0.1:53", false)
+       testTimeout(t, "udp", "127.0.0.1:53", true)
+}
+
+func TestTimeoutTCP(t *testing.T) {
+       // 74.125.19.99 is www.google.com.
+       // could use dns, but dns depends on
+       // timeouts and this is the timeout test.
+       testTimeout(t, "tcp", "74.125.19.99:80", false)
+}
diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go
new file mode 100644 (file)
index 0000000..0270954
--- /dev/null
@@ -0,0 +1,281 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// UDP sockets
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+func sockaddrToUDP(sa syscall.Sockaddr) Addr {
+       switch sa := sa.(type) {
+       case *syscall.SockaddrInet4:
+               return &UDPAddr{sa.Addr[0:], sa.Port}
+       case *syscall.SockaddrInet6:
+               return &UDPAddr{sa.Addr[0:], sa.Port}
+       }
+       return nil
+}
+
+// UDPAddr represents the address of a UDP end point.
+type UDPAddr struct {
+       IP   IP
+       Port int
+}
+
+// Network returns the address's network name, "udp".
+func (a *UDPAddr) Network() string { return "udp" }
+
+func (a *UDPAddr) String() string {
+       if a == nil {
+               return "<nil>"
+       }
+       return joinHostPort(a.IP.String(), itoa(a.Port))
+}
+
+func (a *UDPAddr) family() int {
+       if a == nil || len(a.IP) <= 4 {
+               return syscall.AF_INET
+       }
+       if ip := a.IP.To4(); ip != nil {
+               return syscall.AF_INET
+       }
+       return syscall.AF_INET6
+}
+
+func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+       return ipToSockaddr(family, a.IP, a.Port)
+}
+
+func (a *UDPAddr) toAddr() sockaddr {
+       if a == nil { // nil *UDPAddr
+               return nil // nil interface
+       }
+       return a
+}
+
+// ResolveUDPAddr parses addr as a UDP address of the form
+// host:port and resolves domain names or port names to
+// numeric addresses.  A literal IPv6 host address must be
+// enclosed in square brackets, as in "[::]:80".
+func ResolveUDPAddr(addr string) (*UDPAddr, os.Error) {
+       ip, port, err := hostPortToIP("udp", addr)
+       if err != nil {
+               return nil, err
+       }
+       return &UDPAddr{ip, port}, nil
+}
+
+// UDPConn is the implementation of the Conn and PacketConn
+// interfaces for UDP network connections.
+type UDPConn struct {
+       fd *netFD
+}
+
+func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{fd} }
+
+func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UDPConn) Read(b []byte) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *UDPConn) Write(b []byte) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       return c.fd.Write(b)
+}
+
+// Close closes the UDP connection.
+func (c *UDPConn) Close() os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       err := c.fd.Close()
+       c.fd = nil
+       return err
+}
+
+// LocalAddr returns the local network address.
+func (c *UDPConn) LocalAddr() Addr {
+       if !c.ok() {
+               return nil
+       }
+       return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *UDPAddr.
+func (c *UDPConn) RemoteAddr() Addr {
+       if !c.ok() {
+               return nil
+       }
+       return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UDPConn) SetTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UDPConn) SetReadTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UDPConn) SetWriteTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *UDPConn) SetReadBuffer(bytes int) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *UDPConn) SetWriteBuffer(bytes int) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setWriteBuffer(c.fd, bytes)
+}
+
+// UDP-specific methods.
+
+// ReadFromUDP reads a UDP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUDP can be made to time out and return an error with Timeout() == true
+// after a fixed time limit; see SetTimeout and SetReadTimeout.
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
+       if !c.ok() {
+               return 0, nil, os.EINVAL
+       }
+       n, sa, err := c.fd.ReadFrom(b)
+       switch sa := sa.(type) {
+       case *syscall.SockaddrInet4:
+               addr = &UDPAddr{sa.Addr[0:], sa.Port}
+       case *syscall.SockaddrInet6:
+               addr = &UDPAddr{sa.Addr[0:], sa.Port}
+       }
+       return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+       if !c.ok() {
+               return 0, nil, os.EINVAL
+       }
+       n, uaddr, err := c.ReadFromUDP(b)
+       return n, uaddr.toAddr(), err
+}
+
+// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
+//
+// WriteToUDP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       sa, err1 := addr.sockaddr(c.fd.family)
+       if err1 != nil {
+               return 0, &OpError{Op: "write", Net: "udp", Addr: addr, Error: err1}
+       }
+       return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       a, ok := addr.(*UDPAddr)
+       if !ok {
+               return 0, &OpError{"writeto", "udp", addr, os.EINVAL}
+       }
+       return c.WriteToUDP(b, a)
+}
+
+// DialUDP connects to the remote address raddr on the network net,
+// which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) {
+       switch net {
+       case "udp", "udp4", "udp6":
+       default:
+               return nil, UnknownNetworkError(net)
+       }
+       if raddr == nil {
+               return nil, &OpError{"dial", "udp", nil, errMissingAddress}
+       }
+       fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+       if e != nil {
+               return nil, e
+       }
+       return newUDPConn(fd), nil
+}
+
+// ListenUDP listens for incoming UDP packets addressed to the
+// local address laddr.  The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing.
+func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error) {
+       switch net {
+       case "udp", "udp4", "udp6":
+       default:
+               return nil, UnknownNetworkError(net)
+       }
+       if laddr == nil {
+               return nil, &OpError{"listen", "udp", nil, errMissingAddress}
+       }
+       fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+       if e != nil {
+               return nil, e
+       }
+       return newUDPConn(fd), nil
+}
+
+// BindToDevice binds a UDPConn to a network interface.
+func (c *UDPConn) BindToDevice(device string) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       c.fd.incref()
+       defer c.fd.decref()
+       return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UDPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
diff --git a/libgo/go/net/unixsock.go b/libgo/go/net/unixsock.go
new file mode 100644 (file)
index 0000000..82c0b6d
--- /dev/null
@@ -0,0 +1,400 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unix domain sockets
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err os.Error) {
+       var proto int
+       switch net {
+       default:
+               return nil, UnknownNetworkError(net)
+       case "unix":
+               proto = syscall.SOCK_STREAM
+       case "unixgram":
+               proto = syscall.SOCK_DGRAM
+       }
+
+       var la, ra syscall.Sockaddr
+       switch mode {
+       default:
+               panic("unixSocket mode " + mode)
+
+       case "dial":
+               if laddr != nil {
+                       la = &syscall.SockaddrUnix{Name: laddr.Name}
+               }
+               if raddr != nil {
+                       ra = &syscall.SockaddrUnix{Name: raddr.Name}
+               } else if proto != syscall.SOCK_DGRAM || laddr == nil {
+                       return nil, &OpError{Op: mode, Net: net, Error: errMissingAddress}
+               }
+
+       case "listen":
+               if laddr == nil {
+                       return nil, &OpError{mode, net, nil, errMissingAddress}
+               }
+               la = &syscall.SockaddrUnix{Name: laddr.Name}
+               if raddr != nil {
+                       return nil, &OpError{Op: mode, Net: net, Addr: raddr, Error: &AddrError{Error: "unexpected remote address", Addr: raddr.String()}}
+               }
+       }
+
+       f := sockaddrToUnix
+       if proto != syscall.SOCK_STREAM {
+               f = sockaddrToUnixgram
+       }
+       fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
+       if oserr != nil {
+               goto Error
+       }
+       return fd, nil
+
+Error:
+       addr := raddr
+       if mode == "listen" {
+               addr = laddr
+       }
+       return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr}
+}
+
+// UnixAddr represents the address of a Unix domain socket end point.
+type UnixAddr struct {
+       Name     string
+       Datagram bool
+}
+
+func sockaddrToUnix(sa syscall.Sockaddr) Addr {
+       if s, ok := sa.(*syscall.SockaddrUnix); ok {
+               return &UnixAddr{s.Name, false}
+       }
+       return nil
+}
+
+func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
+       if s, ok := sa.(*syscall.SockaddrUnix); ok {
+               return &UnixAddr{s.Name, true}
+       }
+       return nil
+}
+
+// Network returns the address's network name, "unix" or "unixgram".
+func (a *UnixAddr) Network() string {
+       if a == nil || !a.Datagram {
+               return "unix"
+       }
+       return "unixgram"
+}
+
+func (a *UnixAddr) String() string {
+       if a == nil {
+               return "<nil>"
+       }
+       return a.Name
+}
+
+func (a *UnixAddr) toAddr() Addr {
+       if a == nil { // nil *UnixAddr
+               return nil // nil interface
+       }
+       return a
+}
+
+// ResolveUnixAddr parses addr as a Unix domain socket address.
+// The string net gives the network name, "unix" or "unixgram".
+func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) {
+       var datagram bool
+       switch net {
+       case "unix":
+       case "unixgram":
+               datagram = true
+       default:
+               return nil, UnknownNetworkError(net)
+       }
+       return &UnixAddr{addr, datagram}, nil
+}
+
+// UnixConn is an implementation of the Conn interface
+// for connections to Unix domain sockets.
+type UnixConn struct {
+       fd *netFD
+}
+
+func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{fd} }
+
+func (c *UnixConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       return c.fd.Write(b)
+}
+
+// Close closes the Unix domain connection.
+func (c *UnixConn) Close() os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       err := c.fd.Close()
+       c.fd = nil
+       return err
+}
+
+// LocalAddr returns the local network address, a *UnixAddr.
+// Unlike in other protocols, LocalAddr is usually nil for dialed connections.
+func (c *UnixConn) LocalAddr() Addr {
+       if !c.ok() {
+               return nil
+       }
+       return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *UnixAddr.
+// Unlike in other protocols, RemoteAddr is usually nil for connections
+// accepted by a listener.
+func (c *UnixConn) RemoteAddr() Addr {
+       if !c.ok() {
+               return nil
+       }
+       return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UnixConn) SetTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *UnixConn) SetReadBuffer(bytes int) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *UnixConn) SetWriteBuffer(bytes int) os.Error {
+       if !c.ok() {
+               return os.EINVAL
+       }
+       return setWriteBuffer(c.fd, bytes)
+}
+
+// ReadFromUnix reads a packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUnix can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetReadTimeout.
+func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) {
+       if !c.ok() {
+               return 0, nil, os.EINVAL
+       }
+       n, sa, err := c.fd.ReadFrom(b)
+       switch sa := sa.(type) {
+       case *syscall.SockaddrUnix:
+               addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM}
+       }
+       return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+       if !c.ok() {
+               return 0, nil, os.EINVAL
+       }
+       n, uaddr, err := c.ReadFromUnix(b)
+       return n, uaddr.toAddr(), err
+}
+
+// WriteToUnix writes a packet to addr via c, copying the payload from b.
+//
+// WriteToUnix can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) {
+               return 0, os.EAFNOSUPPORT
+       }
+       sa := &syscall.SockaddrUnix{Name: addr.Name}
+       return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+       if !c.ok() {
+               return 0, os.EINVAL
+       }
+       a, ok := addr.(*UnixAddr)
+       if !ok {
+               return 0, &OpError{"writeto", "unix", addr, os.EINVAL}
+       }
+       return c.WriteToUnix(b, a)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UnixConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+// DialUnix connects to the remote address raddr on the network net,
+// which must be "unix" or "unixgram".  If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err os.Error) {
+       fd, e := unixSocket(net, laddr, raddr, "dial")
+       if e != nil {
+               return nil, e
+       }
+       return newUnixConn(fd), nil
+}
+
+// UnixListener is a Unix domain socket listener.
+// Clients should typically use variables of type Listener
+// instead of assuming Unix domain sockets.
+type UnixListener struct {
+       fd   *netFD
+       path string
+}
+
+// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
+// Net must be "unix" (stream sockets).
+func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
+       if net != "unix" && net != "unixgram" {
+               return nil, UnknownNetworkError(net)
+       }
+       if laddr != nil {
+               laddr = &UnixAddr{laddr.Name, net == "unixgram"} // make our own copy
+       }
+       fd, err := unixSocket(net, laddr, nil, "listen")
+       if err != nil {
+               return nil, err
+       }
+       e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
+       if e1 != 0 {
+               syscall.Close(fd.sysfd)
+               return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)}
+       }
+       return &UnixListener{fd, laddr.Name}, nil
+}
+
+// AcceptUnix accepts the next incoming call and returns the new connection
+// and the remote address.
+func (l *UnixListener) AcceptUnix() (c *UnixConn, err os.Error) {
+       if l == nil || l.fd == nil {
+               return nil, os.EINVAL
+       }
+       fd, e := l.fd.accept(sockaddrToUnix)
+       if e != nil {
+               return nil, e
+       }
+       c = newUnixConn(fd)
+       return c, nil
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *UnixListener) Accept() (c Conn, err os.Error) {
+       c1, err := l.AcceptUnix()
+       if err != nil {
+               return nil, err
+       }
+       return c1, nil
+}
+
+// Close stops listening on the Unix address.
+// Already accepted connections are not closed.
+func (l *UnixListener) Close() os.Error {
+       if l == nil || l.fd == nil {
+               return os.EINVAL
+       }
+
+       // The operating system doesn't clean up
+       // the file that announcing created, so
+       // we have to clean it up ourselves.
+       // There's a race here--we can't know for
+       // sure whether someone else has come along
+       // and replaced our socket name already--
+       // but this sequence (remove then close)
+       // is at least compatible with the auto-remove
+       // sequence in ListenUnix.  It's only non-Go
+       // programs that can mess us up.
+       if l.path[0] != '@' {
+               syscall.Unlink(l.path)
+       }
+       err := l.fd.Close()
+       l.fd = nil
+       return err
+}
+
+// Addr returns the listener's network address.
+func (l *UnixListener) Addr() Addr { return l.fd.laddr }
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *UnixListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
+
+// ListenUnixgram listens for incoming Unix datagram packets addressed to the
+// local address laddr.  The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing.  The network net must be "unixgram".
+func ListenUnixgram(net string, laddr *UnixAddr) (c *UDPConn, err os.Error) {
+       switch net {
+       case "unixgram":
+       default:
+               return nil, UnknownNetworkError(net)
+       }
+       if laddr == nil {
+               return nil, &OpError{"listen", "unixgram", nil, errMissingAddress}
+       }
+       fd, e := unixSocket(net, laddr, nil, "listen")
+       if e != nil {
+               return nil, e
+       }
+       return newUDPConn(fd), nil
+}
diff --git a/libgo/go/netchan/common.go b/libgo/go/netchan/common.go
new file mode 100644 (file)
index 0000000..87981ca
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package netchan
+
+import (
+       "gob"
+       "net"
+       "os"
+       "reflect"
+       "sync"
+       "time"
+)
+
+// The direction of a connection from the client's perspective.
+type Dir int
+
+const (
+       Recv Dir = iota
+       Send
+)
+
+func (dir Dir) String() string {
+       switch dir {
+       case Recv:
+               return "Recv"
+       case Send:
+               return "Send"
+       }
+       return "???"
+}
+
+// Payload types
+const (
+       payRequest = iota // request structure follows
+       payError          // error structure follows
+       payData           // user payload follows
+       payAck            // acknowledgement; no payload
+       payClosed         // channel is now closed
+)
+
+// A header is sent as a prefix to every transmission.  It will be followed by
+// a request structure, an error structure, or an arbitrary user payload structure.
+type header struct {
+       name        string
+       payloadType int
+       seqNum      int64
+}
+
+// Sent with a header once per channel from importer to exporter to report
+// that it wants to bind to a channel with the specified direction for count
+// messages.  If count is -1, it means unlimited.
+type request struct {
+       count int64
+       dir   Dir
+}
+
+// Sent with a header to report an error.
+type error struct {
+       error string
+}
+
+// Used to unify management of acknowledgements for import and export.
+type unackedCounter interface {
+       unackedCount() int64
+       ack() int64
+       seq() int64
+}
+
+// A channel and its direction.
+type chanDir struct {
+       ch  *reflect.ChanValue
+       dir Dir
+}
+
+// clientSet contains the objects and methods needed for tracking
+// clients of an exporter and draining outstanding messages.
+type clientSet struct {
+       mu      sync.Mutex // protects access to channel and client maps
+       chans   map[string]*chanDir
+       clients map[unackedCounter]bool
+}
+
+// Mutex-protected encoder and decoder pair.
+type encDec struct {
+       decLock sync.Mutex
+       dec     *gob.Decoder
+       encLock sync.Mutex
+       enc     *gob.Encoder
+}
+
+func newEncDec(conn net.Conn) *encDec {
+       return &encDec{
+               dec: gob.NewDecoder(conn),
+               enc: gob.NewEncoder(conn),
+       }
+}
+
+// Decode an item from the connection.
+func (ed *encDec) decode(value reflect.Value) os.Error {
+       ed.decLock.Lock()
+       err := ed.dec.DecodeValue(value)
+       if err != nil {
+               // TODO: tear down connection?
+       }
+       ed.decLock.Unlock()
+       return err
+}
+
+// Encode a header and payload onto the connection.
+func (ed *encDec) encode(hdr *header, payloadType int, payload interface{}) os.Error {
+       ed.encLock.Lock()
+       hdr.payloadType = payloadType
+       err := ed.enc.Encode(hdr)
+       if err == nil {
+               if payload != nil {
+                       err = ed.enc.Encode(payload)
+               }
+       }
+       if err != nil {
+               // TODO: tear down connection if there is an error?
+       }
+       ed.encLock.Unlock()
+       return err
+}
+
+// See the comment for Exporter.Drain.
+func (cs *clientSet) drain(timeout int64) os.Error {
+       startTime := time.Nanoseconds()
+       for {
+               pending := false
+               cs.mu.Lock()
+               // Any messages waiting for a client?
+               for _, chDir := range cs.chans {
+                       if chDir.ch.Len() > 0 {
+                               pending = true
+                       }
+               }
+               // Any unacknowledged messages?
+               for client := range cs.clients {
+                       n := client.unackedCount()
+                       if n > 0 { // Check for > rather than != just to be safe.
+                               pending = true
+                               break
+                       }
+               }
+               cs.mu.Unlock()
+               if !pending {
+                       break
+               }
+               if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+                       return os.ErrorString("timeout")
+               }
+               time.Sleep(100 * 1e6) // 100 milliseconds
+       }
+       return nil
+}
+
+// See the comment for Exporter.Sync.
+func (cs *clientSet) sync(timeout int64) os.Error {
+       startTime := time.Nanoseconds()
+       // seq remembers the clients and their seqNum at point of entry.
+       seq := make(map[unackedCounter]int64)
+       for client := range cs.clients {
+               seq[client] = client.seq()
+       }
+       for {
+               pending := false
+               cs.mu.Lock()
+               // Any unacknowledged messages?  Look only at clients that existed
+               // when we started and are still in this client set.
+               for client := range seq {
+                       if _, ok := cs.clients[client]; ok {
+                               if client.ack() < seq[client] {
+                                       pending = true
+                                       break
+                               }
+                       }
+               }
+               cs.mu.Unlock()
+               if !pending {
+                       break
+               }
+               if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+                       return os.ErrorString("timeout")
+               }
+               time.Sleep(100 * 1e6) // 100 milliseconds
+       }
+       return nil
+}
diff --git a/libgo/go/netchan/export.go b/libgo/go/netchan/export.go
new file mode 100644 (file)
index 0000000..8c87ee8
--- /dev/null
@@ -0,0 +1,367 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+       The netchan package implements type-safe networked channels:
+       it allows the two ends of a channel to appear on different
+       computers connected by a network.  It does this by transporting
+       data sent to a channel on one machine so it can be recovered
+       by a receive of a channel of the same type on the other.
+
+       An exporter publishes a set of channels by name.  An importer
+       connects to the exporting machine and imports the channels
+       by name. After importing the channels, the two machines can
+       use the channels in the usual way.
+
+       Networked channels are not synchronized; they always behave
+       as if they are buffered channels of at least one element.
+*/
+package netchan
+
+// BUG: can't use range clause to receive when using ImportNValues to limit the count.
+
+import (
+       "log"
+       "net"
+       "os"
+       "reflect"
+       "sync"
+)
+
+// Export
+
+// expLog is a logging convenience function.  The first argument must be a string.
+func expLog(args ...interface{}) {
+       args[0] = "netchan export: " + args[0].(string)
+       log.Print(args...)
+}
+
+// An Exporter allows a set of channels to be published on a single
+// network port.  A single machine may have multiple Exporters
+// but they must use different ports.
+type Exporter struct {
+       *clientSet
+       listener net.Listener
+}
+
+type expClient struct {
+       *encDec
+       exp     *Exporter
+       mu      sync.Mutex // protects remaining fields
+       errored bool       // client has been sent an error
+       seqNum  int64      // sequences messages sent to client; has value of highest sent
+       ackNum  int64      // highest sequence number acknowledged
+       seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
+}
+
+func newClient(exp *Exporter, conn net.Conn) *expClient {
+       client := new(expClient)
+       client.exp = exp
+       client.encDec = newEncDec(conn)
+       client.seqNum = 0
+       client.ackNum = 0
+       return client
+
+}
+
+func (client *expClient) sendError(hdr *header, err string) {
+       error := &error{err}
+       expLog("sending error to client:", error.error)
+       client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
+       client.mu.Lock()
+       client.errored = true
+       client.mu.Unlock()
+}
+
+func (client *expClient) getChan(hdr *header, dir Dir) *chanDir {
+       exp := client.exp
+       exp.mu.Lock()
+       ech, ok := exp.chans[hdr.name]
+       exp.mu.Unlock()
+       if !ok {
+               client.sendError(hdr, "no such channel: "+hdr.name)
+               return nil
+       }
+       if ech.dir != dir {
+               client.sendError(hdr, "wrong direction for channel: "+hdr.name)
+               return nil
+       }
+       return ech
+}
+
+// The function run manages sends and receives for a single client.  For each
+// (client Recv) request, this will launch a serveRecv goroutine to deliver
+// the data for that channel, while (client Send) requests are handled as
+// data arrives from the client.
+func (client *expClient) run() {
+       hdr := new(header)
+       hdrValue := reflect.NewValue(hdr)
+       req := new(request)
+       reqValue := reflect.NewValue(req)
+       error := new(error)
+       for {
+               *hdr = header{}
+               if err := client.decode(hdrValue); err != nil {
+                       expLog("error decoding client header:", err)
+                       break
+               }
+               switch hdr.payloadType {
+               case payRequest:
+                       *req = request{}
+                       if err := client.decode(reqValue); err != nil {
+                               expLog("error decoding client request:", err)
+                               break
+                       }
+                       switch req.dir {
+                       case Recv:
+                               go client.serveRecv(*hdr, req.count)
+                       case Send:
+                               // Request to send is clear as a matter of protocol
+                               // but not actually used by the implementation.
+                               // The actual sends will have payload type payData.
+                               // TODO: manage the count?
+                       default:
+                               error.error = "request: can't handle channel direction"
+                               expLog(error.error, req.dir)
+                               client.encode(hdr, payError, error)
+                       }
+               case payData:
+                       client.serveSend(*hdr)
+               case payClosed:
+                       client.serveClosed(*hdr)
+               case payAck:
+                       client.mu.Lock()
+                       if client.ackNum != hdr.seqNum-1 {
+                               // Since the sequence number is incremented and the message is sent
+                               // in a single instance of locking client.mu, the messages are guaranteed
+                               // to be sent in order.  Therefore receipt of acknowledgement N means
+                               // all messages <=N have been seen by the recipient.  We check anyway.
+                               expLog("sequence out of order:", client.ackNum, hdr.seqNum)
+                       }
+                       if client.ackNum < hdr.seqNum { // If there has been an error, don't back up the count. 
+                               client.ackNum = hdr.seqNum
+                       }
+                       client.mu.Unlock()
+               default:
+                       log.Exit("netchan export: unknown payload type", hdr.payloadType)
+               }
+       }
+       client.exp.delClient(client)
+}
+
+// Send all the data on a single channel to a client asking for a Recv.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveRecv(hdr header, count int64) {
+       ech := client.getChan(&hdr, Send)
+       if ech == nil {
+               return
+       }
+       for {
+               val := ech.ch.Recv()
+               if ech.ch.Closed() {
+                       if err := client.encode(&hdr, payClosed, nil); err != nil {
+                               expLog("error encoding server closed message:", err)
+                       }
+                       break
+               }
+               // We hold the lock during transmission to guarantee messages are
+               // sent in sequence number order.  Also, we increment first so the
+               // value of client.seqNum is the value of the highest used sequence
+               // number, not one beyond.
+               client.mu.Lock()
+               client.seqNum++
+               hdr.seqNum = client.seqNum
+               client.seqLock.Lock() // guarantee ordering of messages
+               client.mu.Unlock()
+               err := client.encode(&hdr, payData, val.Interface())
+               client.seqLock.Unlock()
+               if err != nil {
+                       expLog("error encoding client response:", err)
+                       client.sendError(&hdr, err.String())
+                       break
+               }
+               // Negative count means run forever.
+               if count >= 0 {
+                       if count--; count <= 0 {
+                               break
+                       }
+               }
+       }
+}
+
+// Receive and deliver locally one item from a client asking for a Send
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveSend(hdr header) {
+       ech := client.getChan(&hdr, Recv)
+       if ech == nil {
+               return
+       }
+       // Create a new value for each received item.
+       val := reflect.MakeZero(ech.ch.Type().(*reflect.ChanType).Elem())
+       if err := client.decode(val); err != nil {
+               expLog("value decode:", err)
+               return
+       }
+       ech.ch.Send(val)
+}
+
+// Report that client has closed the channel that is sending to us.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveClosed(hdr header) {
+       ech := client.getChan(&hdr, Recv)
+       if ech == nil {
+               return
+       }
+       ech.ch.Close()
+}
+
+func (client *expClient) unackedCount() int64 {
+       client.mu.Lock()
+       n := client.seqNum - client.ackNum
+       client.mu.Unlock()
+       return n
+}
+
+func (client *expClient) seq() int64 {
+       client.mu.Lock()
+       n := client.seqNum
+       client.mu.Unlock()
+       return n
+}
+
+func (client *expClient) ack() int64 {
+       client.mu.Lock()
+       n := client.seqNum
+       client.mu.Unlock()
+       return n
+}
+
+// Wait for incoming connections, start a new runner for each
+func (exp *Exporter) listen() {
+       for {
+               conn, err := exp.listener.Accept()
+               if err != nil {
+                       expLog("listen:", err)
+                       break
+               }
+               client := exp.addClient(conn)
+               go client.run()
+       }
+}
+
+// NewExporter creates a new Exporter to export channels
+// on the network and local address defined as in net.Listen.
+func NewExporter(network, localaddr string) (*Exporter, os.Error) {
+       listener, err := net.Listen(network, localaddr)
+       if err != nil {
+               return nil, err
+       }
+       e := &Exporter{
+               listener: listener,
+               clientSet: &clientSet{
+                       chans:   make(map[string]*chanDir),
+                       clients: make(map[unackedCounter]bool),
+               },
+       }
+       go e.listen()
+       return e, nil
+}
+
+// addClient creates a new expClient and records its existence
+func (exp *Exporter) addClient(conn net.Conn) *expClient {
+       client := newClient(exp, conn)
+       exp.clients[client] = true
+       exp.mu.Unlock()
+       return client
+}
+
+// delClient forgets the client existed
+func (exp *Exporter) delClient(client *expClient) {
+       exp.mu.Lock()
+       exp.clients[client] = false, false
+       exp.mu.Unlock()
+}
+
+// Drain waits until all messages sent from this exporter/importer, including
+// those not yet sent to any client and possibly including those sent while
+// Drain was executing, have been received by the importer.  In short, it
+// waits until all the exporter's messages have been received by a client.
+// If the timeout (measured in nanoseconds) is positive and Drain takes
+// longer than that to complete, an error is returned.
+func (exp *Exporter) Drain(timeout int64) os.Error {
+       // This wrapper function is here so the method's comment will appear in godoc.
+       return exp.clientSet.drain(timeout)
+}
+
+// Sync waits until all clients of the exporter have received the messages
+// that were sent at the time Sync was invoked.  Unlike Drain, it does not
+// wait for messages sent while it is running or messages that have not been
+// dispatched to any client.  If the timeout (measured in nanoseconds) is
+// positive and Sync takes longer than that to complete, an error is
+// returned.
+func (exp *Exporter) Sync(timeout int64) os.Error {
+       // This wrapper function is here so the method's comment will appear in godoc.
+       return exp.clientSet.sync(timeout)
+}
+
+// Addr returns the Exporter's local network address.
+func (exp *Exporter) Addr() net.Addr { return exp.listener.Addr() }
+
+func checkChan(chT interface{}, dir Dir) (*reflect.ChanValue, os.Error) {
+       chanType, ok := reflect.Typeof(chT).(*reflect.ChanType)
+       if !ok {
+               return nil, os.ErrorString("not a channel")
+       }
+       if dir != Send && dir != Recv {
+               return nil, os.ErrorString("unknown channel direction")
+       }
+       switch chanType.Dir() {
+       case reflect.BothDir:
+       case reflect.SendDir:
+               if dir != Recv {
+                       return nil, os.ErrorString("to import/export with Send, must provide <-chan")
+               }
+       case reflect.RecvDir:
+               if dir != Send {
+                       return nil, os.ErrorString("to import/export with Recv, must provide chan<-")
+               }
+       }
+       return reflect.NewValue(chT).(*reflect.ChanValue), nil
+}
+
+// Export exports a channel of a given type and specified direction.  The
+// channel to be exported is provided in the call and may be of arbitrary
+// channel type.
+// Despite the literal signature, the effective signature is
+//     Export(name string, chT chan T, dir Dir)
+func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
+       ch, err := checkChan(chT, dir)
+       if err != nil {
+               return err
+       }
+       exp.mu.Lock()
+       defer exp.mu.Unlock()
+       _, present := exp.chans[name]
+       if present {
+               return os.ErrorString("channel name already being exported:" + name)
+       }
+       exp.chans[name] = &chanDir{ch, dir}
+       return nil
+}
+
+// Hangup disassociates the named channel from the Exporter and closes
+// the channel.  Messages in flight for the channel may be dropped.
+func (exp *Exporter) Hangup(name string) os.Error {
+       exp.mu.Lock()
+       chDir, ok := exp.chans[name]
+       if ok {
+               exp.chans[name] = nil, false
+       }
+       exp.mu.Unlock()
+       if !ok {
+               return os.ErrorString("netchan export: hangup: no such channel: " + name)
+       }
+       chDir.ch.Close()
+       return nil
+}
diff --git a/libgo/go/netchan/import.go b/libgo/go/netchan/import.go
new file mode 100644 (file)
index 0000000..eef8e93
--- /dev/null
@@ -0,0 +1,221 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package netchan
+
+import (
+       "log"
+       "net"
+       "os"
+       "reflect"
+       "sync"
+)
+
+// Import
+
+// impLog is a logging convenience function.  The first argument must be a string.
+func impLog(args ...interface{}) {
+       args[0] = "netchan import: " + args[0].(string)
+       log.Print(args...)
+}
+
+// An Importer allows a set of channels to be imported from a single
+// remote machine/network port.  A machine may have multiple
+// importers, even from the same machine/network port.
+type Importer struct {
+       *encDec
+       conn     net.Conn
+       chanLock sync.Mutex // protects access to channel map
+       chans    map[string]*chanDir
+       errors   chan os.Error
+}
+
+// NewImporter creates a new Importer object to import channels
+// from an Exporter at the network and remote address as defined in net.Dial.
+// The Exporter must be available and serving when the Importer is
+// created.
+func NewImporter(network, remoteaddr string) (*Importer, os.Error) {
+       conn, err := net.Dial(network, "", remoteaddr)
+       if err != nil {
+               return nil, err
+       }
+       imp := new(Importer)
+       imp.encDec = newEncDec(conn)
+       imp.conn = conn
+       imp.chans = make(map[string]*chanDir)
+       imp.errors = make(chan os.Error, 10)
+       go imp.run()
+       return imp, nil
+}
+
+// shutdown closes all channels for which we are receiving data from the remote side.
+func (imp *Importer) shutdown() {
+       imp.chanLock.Lock()
+       for _, ich := range imp.chans {
+               if ich.dir == Recv {
+                       ich.ch.Close()
+               }
+       }
+       imp.chanLock.Unlock()
+}
+
+// Handle the data from a single imported data stream, which will
+// have the form
+//     (response, data)*
+// The response identifies by name which channel is transmitting data.
+func (imp *Importer) run() {
+       // Loop on responses; requests are sent by ImportNValues()
+       hdr := new(header)
+       hdrValue := reflect.NewValue(hdr)
+       ackHdr := new(header)
+       err := new(error)
+       errValue := reflect.NewValue(err)
+       for {
+               *hdr = header{}
+               if e := imp.decode(hdrValue); e != nil {
+                       impLog("header:", e)
+                       imp.shutdown()
+                       return
+               }
+               switch hdr.payloadType {
+               case payData:
+                       // done lower in loop
+               case payError:
+                       if e := imp.decode(errValue); e != nil {
+                               impLog("error:", e)
+                               return
+                       }
+                       if err.error != "" {
+                               impLog("response error:", err.error)
+                               if sent := imp.errors <- os.ErrorString(err.error); !sent {
+                                       imp.shutdown()
+                                       return
+                               }
+                               continue // errors are not acknowledged.
+                       }
+               case payClosed:
+                       ich := imp.getChan(hdr.name)
+                       if ich != nil {
+                               ich.ch.Close()
+                       }
+                       continue // closes are not acknowledged.
+               default:
+                       impLog("unexpected payload type:", hdr.payloadType)
+                       return
+               }
+               ich := imp.getChan(hdr.name)
+               if ich == nil {
+                       continue
+               }
+               if ich.dir != Recv {
+                       impLog("cannot happen: receive from non-Recv channel")
+                       return
+               }
+               // Acknowledge receipt
+               ackHdr.name = hdr.name
+               ackHdr.seqNum = hdr.seqNum
+               imp.encode(ackHdr, payAck, nil)
+               // Create a new value for each received item.
+               value := reflect.MakeZero(ich.ch.Type().(*reflect.ChanType).Elem())
+               if e := imp.decode(value); e != nil {
+                       impLog("importer value decode:", e)
+                       return
+               }
+               ich.ch.Send(value)
+       }
+}
+
+func (imp *Importer) getChan(name string) *chanDir {
+       imp.chanLock.Lock()
+       ich := imp.chans[name]
+       imp.chanLock.Unlock()
+       if ich == nil {
+               impLog("unknown name in netchan request:", name)
+               return nil
+       }
+       return ich
+}
+
+// Errors returns a channel from which transmission and protocol errors
+// can be read. Clients of the importer are not required to read the error
+// channel for correct execution. However, if too many errors occur
+// without being read from the error channel, the importer will shut down.
+func (imp *Importer) Errors() chan os.Error {
+       return imp.errors
+}
+
+// Import imports a channel of the given type and specified direction.
+// It is equivalent to ImportNValues with a count of -1, meaning unbounded.
+func (imp *Importer) Import(name string, chT interface{}, dir Dir) os.Error {
+       return imp.ImportNValues(name, chT, dir, -1)
+}
+
+// ImportNValues imports a channel of the given type and specified direction
+// and then receives or transmits up to n values on that channel.  A value of
+// n==-1 implies an unbounded number of values.  The channel to be bound to
+// the remote site's channel is provided in the call and may be of arbitrary
+// channel type.
+// Despite the literal signature, the effective signature is
+//     ImportNValues(name string, chT chan T, dir Dir, n int) os.Error
+// Example usage:
+//     imp, err := NewImporter("tcp", "netchanserver.mydomain.com:1234")
+//     if err != nil { log.Exit(err) }
+//     ch := make(chan myType)
+//     err = imp.ImportNValues("name", ch, Recv, 1)
+//     if err != nil { log.Exit(err) }
+//     fmt.Printf("%+v\n", <-ch)
+func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, n int) os.Error {
+       ch, err := checkChan(chT, dir)
+       if err != nil {
+               return err
+       }
+       imp.chanLock.Lock()
+       defer imp.chanLock.Unlock()
+       _, present := imp.chans[name]
+       if present {
+               return os.ErrorString("channel name already being imported:" + name)
+       }
+       imp.chans[name] = &chanDir{ch, dir}
+       // Tell the other side about this channel.
+       hdr := &header{name: name}
+       req := &request{count: int64(n), dir: dir}
+       if err = imp.encode(hdr, payRequest, req); err != nil {
+               impLog("request encode:", err)
+               return err
+       }
+       if dir == Send {
+               go func() {
+                       for i := 0; n == -1 || i < n; i++ {
+                               val := ch.Recv()
+                               if ch.Closed() {
+                                       if err = imp.encode(hdr, payClosed, nil); err != nil {
+                                               impLog("error encoding client closed message:", err)
+                                       }
+                                       return
+                               }
+                               if err = imp.encode(hdr, payData, val.Interface()); err != nil {
+                                       impLog("error encoding client send:", err)
+                                       return
+                               }
+                       }
+               }()
+       }
+       return nil
+}
+
+// Hangup disassociates the named channel from the Importer and closes
+// the channel.  Messages in flight for the channel may be dropped.
+func (imp *Importer) Hangup(name string) os.Error {
+       imp.chanLock.Lock()
+       chDir, ok := imp.chans[name]
+       if ok {
+               imp.chans[name] = nil, false
+       }
+       imp.chanLock.Unlock()
+       if !ok {
+               return os.ErrorString("netchan import: hangup: no such channel: " + name)
+       }
+       chDir.ch.Close()
+       return nil
+}
diff --git a/libgo/go/netchan/netchan_test.go b/libgo/go/netchan/netchan_test.go
new file mode 100644 (file)
index 0000000..707111a
--- /dev/null
@@ -0,0 +1,383 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package netchan
+
+import (
+       "strings"
+       "testing"
+       "time"
+)
+
+const count = 10     // number of items in most tests
+const closeCount = 5 // number of items when sender closes early
+
+const base = 23
+
+func exportSend(exp *Exporter, n int, t *testing.T) {
+       ch := make(chan int)
+       err := exp.Export("exportedSend", ch, Send)
+       if err != nil {
+               t.Fatal("exportSend:", err)
+       }
+       go func() {
+               for i := 0; i < n; i++ {
+                       ch <- base+i
+               }
+               close(ch)
+       }()
+}
+
+func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) {
+       ch := make(chan int)
+       err := exp.Export("exportedRecv", ch, Recv)
+       expDone <- true
+       if err != nil {
+               t.Fatal("exportReceive:", err)
+       }
+       for i := 0; i < count; i++ {
+               v := <-ch
+               if closed(ch) {
+                       if i != closeCount {
+                               t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i)
+                       }
+                       break
+               }
+               if v != base+i {
+                       t.Errorf("export Receive: bad value: expected %d+%d=%d; got %d", base, i, base+i, v)
+               }
+       }
+}
+
+func importSend(imp *Importer, n int, t *testing.T) {
+       ch := make(chan int)
+       err := imp.ImportNValues("exportedRecv", ch, Send, count)
+       if err != nil {
+               t.Fatal("importSend:", err)
+       }
+       go func() {
+               for i := 0; i < n; i++ {
+                       ch <- base+i
+               }
+               close(ch)
+       }()
+}
+
+func importReceive(imp *Importer, t *testing.T, done chan bool) {
+       ch := make(chan int)
+       err := imp.ImportNValues("exportedSend", ch, Recv, count)
+       if err != nil {
+               t.Fatal("importReceive:", err)
+       }
+       for i := 0; i < count; i++ {
+               v := <-ch
+               if closed(ch) {
+                       if i != closeCount {
+                               t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i)
+                       }
+                       break
+               }
+               if v != 23+i {
+                       t.Errorf("importReceive: bad value: expected %%d+%d=%d; got %+d", base, i, base+i, v)
+               }
+       }
+       if done != nil {
+               done <- true
+       }
+}
+
+func TestExportSendImportReceive(t *testing.T) {
+       exp, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       imp, err := NewImporter("tcp", exp.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+       exportSend(exp, count, t)
+       importReceive(imp, t, nil)
+}
+
+func TestExportReceiveImportSend(t *testing.T) {
+       exp, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       imp, err := NewImporter("tcp", exp.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+       expDone := make(chan bool)
+       done := make(chan bool)
+       go func() {
+               exportReceive(exp, t, expDone)
+               done <- true
+       }()
+       <-expDone
+       importSend(imp, count, t)
+       <-done
+}
+
+func TestClosingExportSendImportReceive(t *testing.T) {
+       exp, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       imp, err := NewImporter("tcp", exp.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+       exportSend(exp, closeCount, t)
+       importReceive(imp, t, nil)
+}
+
+func TestClosingImportSendExportReceive(t *testing.T) {
+       exp, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       imp, err := NewImporter("tcp", exp.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+       expDone := make(chan bool)
+       done := make(chan bool)
+       go func() {
+               exportReceive(exp, t, expDone)
+               done <- true
+       }()
+       <-expDone
+       importSend(imp, closeCount, t)
+       <-done
+}
+
+func TestErrorForIllegalChannel(t *testing.T) {
+       exp, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       imp, err := NewImporter("tcp", exp.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+       // Now export a channel.
+       ch := make(chan int, 1)
+       err = exp.Export("aChannel", ch, Send)
+       if err != nil {
+               t.Fatal("export:", err)
+       }
+       ch <- 1234
+       close(ch)
+       // Now try to import a different channel.
+       ch = make(chan int)
+       err = imp.Import("notAChannel", ch, Recv)
+       if err != nil {
+               t.Fatal("import:", err)
+       }
+       // Expect an error now.  Start a timeout.
+       timeout := make(chan bool, 1) // buffered so closure will not hang around.
+       go func() {
+               time.Sleep(10e9) // very long, to give even really slow machines a chance.
+               timeout <- true
+       }()
+       select {
+       case err = <-imp.Errors():
+               if strings.Index(err.String(), "no such channel") < 0 {
+                       t.Error("wrong error for nonexistent channel:", err)
+               }
+       case <-timeout:
+               t.Error("import of nonexistent channel did not receive an error")
+       }
+}
+
+// Not a great test but it does at least invoke Drain.
+func TestExportDrain(t *testing.T) {
+       exp, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       imp, err := NewImporter("tcp", exp.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+       done := make(chan bool)
+       go func() {
+               exportSend(exp, closeCount, t)
+               done <- true
+       }()
+       <-done
+       go importReceive(imp, t, done)
+       exp.Drain(0)
+       <-done
+}
+
+// Not a great test but it does at least invoke Sync.
+func TestExportSync(t *testing.T) {
+       exp, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       imp, err := NewImporter("tcp", exp.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+       done := make(chan bool)
+       exportSend(exp, closeCount, t)
+       go importReceive(imp, t, done)
+       exp.Sync(0)
+       <-done
+}
+
+// Test hanging up the send side of an export.
+// TODO: test hanging up the receive side of an export.
+func TestExportHangup(t *testing.T) {
+       exp, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       imp, err := NewImporter("tcp", exp.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+       ech := make(chan int)
+       err = exp.Export("exportedSend", ech, Send)
+       if err != nil {
+               t.Fatal("export:", err)
+       }
+       // Prepare to receive two values. We'll actually deliver only one.
+       ich := make(chan int)
+       err = imp.ImportNValues("exportedSend", ich, Recv, 2)
+       if err != nil {
+               t.Fatal("import exportedSend:", err)
+       }
+       // Send one value, receive it.
+       const Value = 1234
+       ech <- Value
+       v := <-ich
+       if v != Value {
+               t.Fatal("expected", Value, "got", v)
+       }
+       // Now hang up the channel.  Importer should see it close.
+       exp.Hangup("exportedSend")
+       v = <-ich
+       if !closed(ich) {
+               t.Fatal("expected channel to be closed; got value", v)
+       }
+}
+
+// Test hanging up the send side of an import.
+// TODO: test hanging up the receive side of an import.
+func TestImportHangup(t *testing.T) {
+       exp, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       imp, err := NewImporter("tcp", exp.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+       ech := make(chan int)
+       err = exp.Export("exportedRecv", ech, Recv)
+       if err != nil {
+               t.Fatal("export:", err)
+       }
+       // Prepare to Send two values. We'll actually deliver only one.
+       ich := make(chan int)
+       err = imp.ImportNValues("exportedRecv", ich, Send, 2)
+       if err != nil {
+               t.Fatal("import exportedRecv:", err)
+       }
+       // Send one value, receive it.
+       const Value = 1234
+       ich <- Value
+       v := <-ech
+       if v != Value {
+               t.Fatal("expected", Value, "got", v)
+       }
+       // Now hang up the channel.  Exporter should see it close.
+       imp.Hangup("exportedRecv")
+       v = <-ech
+       if !closed(ech) {
+               t.Fatal("expected channel to be closed; got value", v)
+       }
+}
+
+// This test cross-connects a pair of exporter/importer pairs.
+type value struct {
+       i      int
+       source string
+}
+
+func TestCrossConnect(t *testing.T) {
+       e1, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       i1, err := NewImporter("tcp", e1.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+
+       e2, err := NewExporter("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal("new exporter:", err)
+       }
+       i2, err := NewImporter("tcp", e2.Addr().String())
+       if err != nil {
+               t.Fatal("new importer:", err)
+       }
+
+       go crossExport(e1, e2, t)
+       crossImport(i1, i2, t)
+}
+
+// Export side of cross-traffic.
+func crossExport(e1, e2 *Exporter, t *testing.T) {
+       s := make(chan value)
+       err := e1.Export("exportedSend", s, Send)
+       if err != nil {
+               t.Fatal("exportSend:", err)
+       }
+
+       r := make(chan value)
+       err = e2.Export("exportedReceive", r, Recv)
+       if err != nil {
+               t.Fatal("exportReceive:", err)
+       }
+
+       crossLoop("export", s, r, t)
+}
+
+// Import side of cross-traffic.
+func crossImport(i1, i2 *Importer, t *testing.T) {
+       s := make(chan value)
+       err := i2.Import("exportedReceive", s, Send)
+       if err != nil {
+               t.Fatal("import of exportedReceive:", err)
+       }
+
+       r := make(chan value)
+       err = i1.Import("exportedSend", r, Recv)
+       if err != nil {
+               t.Fatal("import of exported Send:", err)
+       }
+
+       crossLoop("import", s, r, t)
+}
+
+// Cross-traffic: send and receive 'count' numbers.
+func crossLoop(name string, s, r chan value, t *testing.T) {
+       for si, ri := 0, 0; si < count && ri < count; {
+               select {
+               case s <- value{si, name}:
+                       si++
+               case v := <-r:
+                       if v.i != ri {
+                               t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v)
+                       }
+                       ri++
+               }
+       }
+}
diff --git a/libgo/go/os/dir.go b/libgo/go/os/dir.go
new file mode 100644 (file)
index 0000000..a5909ff
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+       "syscall"
+       "unsafe"
+)
+
+func libc_dup(fd int) int __asm__ ("dup")
+func libc_opendir(*byte) *syscall.DIR __asm__ ("opendir")
+func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) int __asm__ ("readdir_r")
+func libc_closedir(*syscall.DIR) int __asm__ ("closedir")
+
+// FIXME: pathconf returns long, not int.
+func libc_pathconf(*byte, int) int __asm__ ("pathconf")
+
+func clen(n []byte) int {
+       for i := 0; i < len(n); i++ {
+               if n[i] == 0 {
+                       return i
+               }
+       }
+       return len(n)
+}
+
+var elen int;
+
+// Negative count means read until EOF.
+func (file *File) Readdirnames(count int) (names []string, err Error) {
+       if elen == 0 {
+               var dummy syscall.Dirent;
+               elen = (unsafe.Offsetof(dummy.Name) +
+                       libc_pathconf(syscall.StringBytePtr(file.name), syscall.PC_NAME_MAX) +
+                       1);
+       }
+
+       if file.dirinfo == nil {
+               file.dirinfo = new(dirInfo)
+               file.dirinfo.buf = make([]byte, elen)
+               file.dirinfo.dir = libc_opendir(syscall.StringBytePtr(file.name))
+       }
+
+       entry_dirent := unsafe.Pointer(&file.dirinfo.buf[0]).(*syscall.Dirent)
+
+       size := count
+       if size < 0 {
+               size = 100
+       }
+       names = make([]string, 0, size) // Empty with room to grow.
+
+       dir := file.dirinfo.dir
+       if dir == nil {
+               return names, NewSyscallError("opendir", syscall.GetErrno())
+       }       
+
+       for count != 0 {
+               var result *syscall.Dirent
+               i := libc_readdir_r(dir, entry_dirent, &result)
+               if result == nil {
+                       break
+               }
+               var name = string(result.Name[0:clen(result.Name[0:])])
+               if name == "." || name == ".." {        // Useless names
+                       continue
+               }
+               count--
+               names = append(names, name)
+       }
+       return names, nil
+}
diff --git a/libgo/go/os/env.go b/libgo/go/os/env.go
new file mode 100644 (file)
index 0000000..3a6d79d
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// General environment variables.
+
+package os
+
+// Expand replaces ${var} or $var in the string based on the mapping function.
+// Invocations of undefined variables are replaced with the empty string.
+func Expand(s string, mapping func(string) string) string {
+       buf := make([]byte, 0, 2*len(s))
+       // ${} is all ASCII, so bytes are fine for this operation.
+       i := 0
+       for j := 0; j < len(s); j++ {
+               if s[j] == '$' && j+1 < len(s) {
+                       buf = append(buf, []byte(s[i:j])...)
+                       name, w := getShellName(s[j+1:])
+                       buf = append(buf, []byte(mapping(name))...)
+                       j += w
+                       i = j + 1
+               }
+       }
+       return string(buf) + s[i:]
+}
+
+// ShellExpand replaces ${var} or $var in the string according to the values
+// of the operating system's environment variables.  References to undefined
+// variables are replaced by the empty string.
+func ShellExpand(s string) string {
+       return Expand(s, Getenv)
+}
+
+// isSpellSpecialVar reports whether the character identifies a special
+// shell variable such as $*.
+func isShellSpecialVar(c uint8) bool {
+       switch c {
+       case '*', '#', '$', '@', '!', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+               return true
+       }
+       return false
+}
+
+// isAlphaNum reports whether the byte is an ASCII letter, number, or underscore
+func isAlphaNum(c uint8) bool {
+       return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
+}
+
+// getName returns the name that begins the string and the number of bytes
+// consumed to extract it.  If the name is enclosed in {}, it's part of a ${}
+// expansion and two more bytes are needed than the length of the name.
+func getShellName(s string) (string, int) {
+       switch {
+       case s[0] == '{':
+               if len(s) > 2 && isShellSpecialVar(s[1]) && s[2] == '}' {
+                       return s[1:2], 3
+               }
+               // Scan to closing brace
+               for i := 1; i < len(s); i++ {
+                       if s[i] == '}' {
+                               return s[1:i], i + 1
+                       }
+               }
+               return "", 1 // Bad syntax; just eat the brace.
+       case isShellSpecialVar(s[0]):
+               return s[0:1], 1
+       }
+       // Scan alphanumerics.
+       var i int
+       for i = 0; i < len(s) && isAlphaNum(s[i]); i++ {
+       }
+       return s[:i], i
+}
diff --git a/libgo/go/os/env_test.go b/libgo/go/os/env_test.go
new file mode 100644 (file)
index 0000000..04ff390
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+       . "os"
+       "testing"
+)
+
+// testGetenv gives us a controlled set of variables for testing Expand.
+func testGetenv(s string) string {
+       switch s {
+       case "*":
+               return "all the args"
+       case "#":
+               return "NARGS"
+       case "$":
+               return "PID"
+       case "1":
+               return "ARGUMENT1"
+       case "HOME":
+               return "/usr/gopher"
+       case "H":
+               return "(Value of H)"
+       case "home_1":
+               return "/usr/foo"
+       case "_":
+               return "underscore"
+       }
+       return ""
+}
+
+var expandTests = []struct {
+       in, out string
+}{
+       {"", ""},
+       {"$*", "all the args"},
+       {"$$", "PID"},
+       {"${*}", "all the args"},
+       {"$1", "ARGUMENT1"},
+       {"${1}", "ARGUMENT1"},
+       {"now is the time", "now is the time"},
+       {"$HOME", "/usr/gopher"},
+       {"$home_1", "/usr/foo"},
+       {"${HOME}", "/usr/gopher"},
+       {"${H}OME", "(Value of H)OME"},
+       {"A$$$#$1$H$home_1*B", "APIDNARGSARGUMENT1(Value of H)/usr/foo*B"},
+}
+
+func TestExpand(t *testing.T) {
+       for _, test := range expandTests {
+               result := Expand(test.in, testGetenv)
+               if result != test.out {
+                       t.Errorf("Expand(%q)=%q; expected %q", test.in, result, test.out)
+               }
+       }
+}
diff --git a/libgo/go/os/env_unix.go b/libgo/go/os/env_unix.go
new file mode 100644 (file)
index 0000000..e7e1c3b
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unix environment variables.
+
+package os
+
+import (
+       "sync"
+)
+
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+var env map[string]string
+var once sync.Once
+
+
+func copyenv() {
+       env = make(map[string]string)
+       for _, s := range Envs {
+               for j := 0; j < len(s); j++ {
+                       if s[j] == '=' {
+                               env[s[0:j]] = s[j+1:]
+                               break
+                       }
+               }
+       }
+}
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+       once.Do(copyenv)
+
+       if len(key) == 0 {
+               return "", EINVAL
+       }
+       v, ok := env[key]
+       if !ok {
+               return "", ENOENV
+       }
+       return v, nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+       v, _ := Getenverror(key)
+       return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+       once.Do(copyenv)
+
+       if len(key) == 0 {
+               return EINVAL
+       }
+       env[key] = value
+       return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+       once.Do(copyenv) // prevent copyenv in Getenv/Setenv
+       env = make(map[string]string)
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+       once.Do(copyenv)
+       a := make([]string, len(env))
+       i := 0
+       for k, v := range env {
+               // check i < len(a) for safety,
+               // in case env is changing underfoot.
+               if i < len(a) {
+                       a[i] = k + "=" + v
+                       i++
+               }
+       }
+       return a[0:i]
+}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+       dir := Getenv("TMPDIR")
+       if dir == "" {
+               dir = "/tmp"
+       }
+       return dir
+}
diff --git a/libgo/go/os/env_windows.go b/libgo/go/os/env_windows.go
new file mode 100644 (file)
index 0000000..6908a9c
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Windows environment variables.
+
+package os
+
+import (
+       "syscall"
+       "utf16"
+       "unsafe"
+)
+
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+       b := make([]uint16, 100)
+       n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+       if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
+               return "", ENOENV
+       }
+       if n > uint32(len(b)) {
+               b = make([]uint16, n)
+               n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+               if n > uint32(len(b)) {
+                       n = 0
+               }
+       }
+       if n == 0 {
+               return "", NewSyscallError("GetEnvironmentVariable", e)
+       }
+       return string(utf16.Decode(b[0:n])), nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+       v, _ := Getenverror(key)
+       return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+       var v *uint16
+       if len(value) > 0 {
+               v = syscall.StringToUTF16Ptr(value)
+       }
+       ok, e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
+       if !ok {
+               return NewSyscallError("SetEnvironmentVariable", e)
+       }
+       return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+       for _, s := range Environ() {
+               // Environment variables can begin with =
+               // so start looking for the separator = at j=1.
+               // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+               for j := 1; j < len(s); j++ {
+                       if s[j] == '=' {
+                               Setenv(s[0:j], "")
+                               break
+                       }
+               }
+       }
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+       s, e := syscall.GetEnvironmentStrings()
+       if e != 0 {
+               return nil
+       }
+       defer syscall.FreeEnvironmentStrings(s)
+       r := make([]string, 0, 50) // Empty with room to grow.
+       for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
+               if p[i] == 0 {
+                       // empty string marks the end
+                       if i <= from {
+                               break
+                       }
+                       r = append(r, string(utf16.Decode(p[from:i])))
+                       from = i + 1
+               }
+       }
+       return r
+}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+       const pathSep = '\\'
+       dirw := make([]uint16, syscall.MAX_PATH)
+       n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+       if n > uint32(len(dirw)) {
+               dirw = make([]uint16, n)
+               n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+               if n > uint32(len(dirw)) {
+                       n = 0
+               }
+       }
+       if n > 0 && dirw[n-1] == pathSep {
+               n--
+       }
+       return string(utf16.Decode(dirw[0:n]))
+}
diff --git a/libgo/go/os/error.go b/libgo/go/os/error.go
new file mode 100644 (file)
index 0000000..8cdf532
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import syscall "syscall"
+
+// An Error can represent any printable error condition.
+type Error interface {
+       String() string
+}
+
+// A helper type that can be embedded or wrapped to simplify satisfying
+// Error.
+type ErrorString string
+
+func (e ErrorString) String() string  { return string(e) }
+func (e ErrorString) Temporary() bool { return false }
+func (e ErrorString) Timeout() bool   { return false }
+
+// Note: If the name of the function NewError changes,
+// pkg/go/doc/doc.go should be adjusted since it hardwires
+// this name in a heuristic.
+
+// NewError converts s to an ErrorString, which satisfies the Error interface.
+func NewError(s string) Error { return ErrorString(s) }
+
+// Errno is the Unix error number.  Names such as EINVAL are simple
+// wrappers to convert the error number into an Error.
+type Errno int64
+
+func (e Errno) String() string { return syscall.Errstr(int(e)) }
+
+func (e Errno) Temporary() bool {
+       return e == Errno(syscall.EINTR) || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+       return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK)
+}
+
+// Commonly known Unix errors.
+var (
+       EPERM        Error = Errno(syscall.EPERM)
+       ENOENT       Error = Errno(syscall.ENOENT)
+       ESRCH        Error = Errno(syscall.ESRCH)
+       EINTR        Error = Errno(syscall.EINTR)
+       EIO          Error = Errno(syscall.EIO)
+       ENXIO        Error = Errno(syscall.ENXIO)
+       E2BIG        Error = Errno(syscall.E2BIG)
+       ENOEXEC      Error = Errno(syscall.ENOEXEC)
+       EBADF        Error = Errno(syscall.EBADF)
+       ECHILD       Error = Errno(syscall.ECHILD)
+       EDEADLK      Error = Errno(syscall.EDEADLK)
+       ENOMEM       Error = Errno(syscall.ENOMEM)
+       EACCES       Error = Errno(syscall.EACCES)
+       EFAULT       Error = Errno(syscall.EFAULT)
+       EBUSY        Error = Errno(syscall.EBUSY)
+       EEXIST       Error = Errno(syscall.EEXIST)
+       EXDEV        Error = Errno(syscall.EXDEV)
+       ENODEV       Error = Errno(syscall.ENODEV)
+       ENOTDIR      Error = Errno(syscall.ENOTDIR)
+       EISDIR       Error = Errno(syscall.EISDIR)
+       EINVAL       Error = Errno(syscall.EINVAL)
+       ENFILE       Error = Errno(syscall.ENFILE)
+       EMFILE       Error = Errno(syscall.EMFILE)
+       ENOTTY       Error = Errno(syscall.ENOTTY)
+       EFBIG        Error = Errno(syscall.EFBIG)
+       ENOSPC       Error = Errno(syscall.ENOSPC)
+       ESPIPE       Error = Errno(syscall.ESPIPE)
+       EROFS        Error = Errno(syscall.EROFS)
+       EMLINK       Error = Errno(syscall.EMLINK)
+       EPIPE        Error = Errno(syscall.EPIPE)
+       EAGAIN       Error = Errno(syscall.EAGAIN)
+       EDOM         Error = Errno(syscall.EDOM)
+       ERANGE       Error = Errno(syscall.ERANGE)
+       EADDRINUSE   Error = Errno(syscall.EADDRINUSE)
+       ECONNREFUSED Error = Errno(syscall.ECONNREFUSED)
+       ENAMETOOLONG Error = Errno(syscall.ENAMETOOLONG)
+       EAFNOSUPPORT Error = Errno(syscall.EAFNOSUPPORT)
+)
+
+// PathError records an error and the operation and file path that caused it.
+type PathError struct {
+       Op    string
+       Path  string
+       Error Error
+}
+
+func (e *PathError) String() string { return e.Op + " " + e.Path + ": " + e.Error.String() }
+
+// SyscallError records an error from a specific system call.
+type SyscallError struct {
+       Syscall string
+       Errno   Errno
+}
+
+func (e *SyscallError) String() string { return e.Syscall + ": " + e.Errno.String() }
+
+// Note: If the name of the function NewSyscallError changes,
+// pkg/go/doc/doc.go should be adjusted since it hardwires
+// this name in a heuristic.
+
+// NewSyscallError returns, as an Error, a new SyscallError
+// with the given system call name and error number.
+// As a convenience, if errno is 0, NewSyscallError returns nil.
+func NewSyscallError(syscall string, errno int) Error {
+       if errno == 0 {
+               return nil
+       }
+       return &SyscallError{syscall, Errno(errno)}
+}
diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go
new file mode 100644 (file)
index 0000000..501ebc2
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+       "syscall"
+)
+
+// ForkExec forks the current process and invokes Exec with the program, arguments,
+// and environment specified by name, argv, and envv.  It returns the process
+// id of the forked process and an Error, if any.  The fd array specifies the
+// file descriptors to be set up in the new process: fd[0] will be Unix file
+// descriptor 0 (standard input), fd[1] descriptor 1, and so on.  A nil entry
+// will cause the child to have no open file descriptor with that index.
+// If dir is not empty, the child chdirs into the directory before execing the program.
+func ForkExec(name string, argv []string, envv []string, dir string, fd []*File) (pid int, err Error) {
+       if envv == nil {
+               envv = Environ()
+       }
+       // Create array of integer (system) fds.
+       intfd := make([]int, len(fd))
+       for i, f := range fd {
+               if f == nil {
+                       intfd[i] = -1
+               } else {
+                       intfd[i] = f.Fd()
+               }
+       }
+
+       p, e := syscall.ForkExec(name, argv, envv, dir, intfd)
+       if e != 0 {
+               return 0, &PathError{"fork/exec", name, Errno(e)}
+       }
+       return p, nil
+}
+
+// Exec replaces the current process with an execution of the
+// named binary, with arguments argv and environment envv.
+// If successful, Exec never returns.  If it fails, it returns an Error.
+// ForkExec is almost always a better way to execute a program.
+func Exec(name string, argv []string, envv []string) Error {
+       if envv == nil {
+               envv = Environ()
+       }
+       e := syscall.Exec(name, argv, envv)
+       if e != 0 {
+               return &PathError{"exec", name, Errno(e)}
+       }
+       return nil
+}
+
+// TODO(rsc): Should os implement its own syscall.WaitStatus
+// wrapper with the methods, or is exposing the underlying one enough?
+//
+// TODO(rsc): Certainly need to have Rusage struct,
+// since syscall one might have different field types across
+// different OS.
+
+// Waitmsg stores the information about an exited process as reported by Wait.
+type Waitmsg struct {
+       Pid                int             // The process's id.
+       syscall.WaitStatus                 // System-dependent status info.
+       Rusage             *syscall.Rusage // System-dependent resource usage info.
+}
+
+// Options for Wait.
+const (
+       WNOHANG   = syscall.WNOHANG  // Don't wait if no process has exited.
+       WSTOPPED  = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported.
+       WUNTRACED = WSTOPPED
+       WRUSAGE   = 1 << 20 // Record resource usage.
+)
+
+// WRUSAGE must not be too high a bit, to avoid clashing with Linux's
+// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of
+// the options
+
+// Wait waits for process pid to exit or stop, and then returns a
+// Waitmsg describing its status and an Error, if any. The options
+// (WNOHANG etc.) affect the behavior of the Wait call.
+func Wait(pid int, options int) (w *Waitmsg, err Error) {
+       var status syscall.WaitStatus
+       var rusage *syscall.Rusage
+       if options&WRUSAGE != 0 {
+               rusage = new(syscall.Rusage)
+               options ^= WRUSAGE
+       }
+       pid1, e := syscall.Wait4(pid, &status, options, rusage)
+       if e != 0 {
+               return nil, NewSyscallError("wait", e)
+       }
+       w = new(Waitmsg)
+       w.Pid = pid1
+       w.WaitStatus = status
+       w.Rusage = rusage
+       return w, nil
+}
+
+// Convert i to decimal string.
+func itod(i int) string {
+       if i == 0 {
+               return "0"
+       }
+
+       u := uint64(i)
+       if i < 0 {
+               u = -u
+       }
+
+       // Assemble decimal in reverse order.
+       var b [32]byte
+       bp := len(b)
+       for ; u > 0; u /= 10 {
+               bp--
+               b[bp] = byte(u%10) + '0'
+       }
+
+       if i < 0 {
+               bp--
+               b[bp] = '-'
+       }
+
+       return string(b[bp:])
+}
+
+func (w Waitmsg) String() string {
+       // TODO(austin) Use signal names when possible?
+       res := ""
+       switch {
+       case w.Exited():
+               res = "exit status " + itod(w.ExitStatus())
+       case w.Signaled():
+               res = "signal " + itod(w.Signal())
+       case w.Stopped():
+               res = "stop signal " + itod(w.StopSignal())
+               if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
+                       res += " (trap " + itod(w.TrapCause()) + ")"
+               }
+       case w.Continued():
+               res = "continued"
+       }
+       if w.CoreDump() {
+               res += " (core dumped)"
+       }
+       return res
+}
+
+// Getpid returns the process id of the caller.
+func Getpid() int { return syscall.Getpid() }
+
+// Getppid returns the process id of the caller's parent.
+func Getppid() int { return syscall.Getppid() }
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
new file mode 100644 (file)
index 0000000..909e28e
--- /dev/null
@@ -0,0 +1,425 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The os package provides a platform-independent interface to operating
+// system functionality.  The design is Unix-like.
+package os
+
+import (
+       "runtime"
+       "syscall"
+)
+
+// File represents an open file descriptor.
+type File struct {
+       fd      int
+       name    string
+       dirinfo *dirInfo // nil unless directory being read
+       nepipe  int      // number of consecutive EPIPE in Write
+}
+
+// Fd returns the integer Unix file descriptor referencing the open file.
+func (file *File) Fd() int { return file.fd }
+
+// Name returns the name of the file as presented to Open.
+func (file *File) Name() string { return file.name }
+
+// NewFile returns a new File with the given file descriptor and name.
+func NewFile(fd int, name string) *File {
+       if fd < 0 {
+               return nil
+       }
+       f := &File{fd, name, nil, 0}
+       runtime.SetFinalizer(f, (*File).Close)
+       return f
+}
+
+// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
+// standard output, and standard error file descriptors.
+var (
+       Stdin  = NewFile(syscall.Stdin, "/dev/stdin")
+       Stdout = NewFile(syscall.Stdout, "/dev/stdout")
+       Stderr = NewFile(syscall.Stderr, "/dev/stderr")
+)
+
+// Flags to Open wrapping those of the underlying system. Not all flags
+// may be implemented on a given system.
+const (
+       O_RDONLY   int = syscall.O_RDONLY   // open the file read-only.
+       O_WRONLY   int = syscall.O_WRONLY   // open the file write-only.
+       O_RDWR     int = syscall.O_RDWR     // open the file read-write.
+       O_APPEND   int = syscall.O_APPEND   // append data to the file when writing.
+       O_ASYNC    int = syscall.O_ASYNC    // generate a signal when I/O is available.
+       O_CREAT    int = syscall.O_CREAT    // create a new file if none exists.
+       O_EXCL     int = syscall.O_EXCL     // used with O_CREAT, file must not exist
+       O_NOCTTY   int = syscall.O_NOCTTY   // do not make file the controlling tty.
+       O_NONBLOCK int = syscall.O_NONBLOCK // open in non-blocking mode.
+       O_NDELAY   int = O_NONBLOCK         // synonym for O_NONBLOCK
+       O_SYNC     int = syscall.O_SYNC     // open for synchronous I/O.
+       O_TRUNC    int = syscall.O_TRUNC    // if possible, truncate file when opened.
+       O_CREATE   int = O_CREAT            // create a new file if none exists.
+)
+
+type eofError int
+
+func (eofError) String() string { return "EOF" }
+
+// EOF is the Error returned by Read when no more input is available.
+// Functions should return EOF only to signal a graceful end of input.
+// If the EOF occurs unexpectedly in a structured data stream,
+// the appropriate error is either io.ErrUnexpectedEOF or some other error
+// giving more detail.
+var EOF Error = eofError(0)
+
+// Read reads up to len(b) bytes from the File.
+// It returns the number of bytes read and an Error, if any.
+// EOF is signaled by a zero count with err set to EOF.
+func (file *File) Read(b []byte) (n int, err Error) {
+       if file == nil {
+               return 0, EINVAL
+       }
+       n, e := syscall.Read(file.fd, b)
+       if n < 0 {
+               n = 0
+       }
+       if n == 0 && e == 0 {
+               return 0, EOF
+       }
+       if e != 0 {
+               err = &PathError{"read", file.name, Errno(e)}
+       }
+       return n, err
+}
+
+// ReadAt reads len(b) bytes from the File starting at byte offset off.
+// It returns the number of bytes read and the Error, if any.
+// EOF is signaled by a zero count with err set to EOF.
+// ReadAt always returns a non-nil Error when n != len(b).
+func (file *File) ReadAt(b []byte, off int64) (n int, err Error) {
+       if file == nil {
+               return 0, EINVAL
+       }
+       for len(b) > 0 {
+               m, e := syscall.Pread(file.fd, b, off)
+               if m == 0 && e == 0 {
+                       return n, EOF
+               }
+               if e != 0 {
+                       err = &PathError{"read", file.name, Errno(e)}
+                       break
+               }
+               n += m
+               b = b[m:]
+               off += int64(m)
+       }
+       return
+}
+
+// Write writes len(b) bytes to the File.
+// It returns the number of bytes written and an Error, if any.
+// Write returns a non-nil Error when n != len(b).
+func (file *File) Write(b []byte) (n int, err Error) {
+       if file == nil {
+               return 0, EINVAL
+       }
+       n, e := syscall.Write(file.fd, b)
+       if n < 0 {
+               n = 0
+       }
+       if e == syscall.EPIPE {
+               file.nepipe++
+               if file.nepipe >= 10 {
+                       Exit(syscall.EPIPE)
+               }
+       } else {
+               file.nepipe = 0
+       }
+       if e != 0 {
+               err = &PathError{"write", file.name, Errno(e)}
+       }
+       return n, err
+}
+
+// WriteAt writes len(b) bytes to the File starting at byte offset off.
+// It returns the number of bytes written and an Error, if any.
+// WriteAt returns a non-nil Error when n != len(b).
+func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
+       if file == nil {
+               return 0, EINVAL
+       }
+       for len(b) > 0 {
+               m, e := syscall.Pwrite(file.fd, b, off)
+               if e != 0 {
+                       err = &PathError{"write", file.name, Errno(e)}
+                       break
+               }
+               n += m
+               b = b[m:]
+               off += int64(m)
+       }
+       return
+}
+
+// Seek sets the offset for the next Read or Write on file to offset, interpreted
+// according to whence: 0 means relative to the origin of the file, 1 means
+// relative to the current offset, and 2 means relative to the end.
+// It returns the new offset and an Error, if any.
+func (file *File) Seek(offset int64, whence int) (ret int64, err Error) {
+       r, e := syscall.Seek(file.fd, offset, whence)
+       if e == 0 && file.dirinfo != nil && r != 0 {
+               e = syscall.EISDIR
+       }
+       if e != 0 {
+               return 0, &PathError{"seek", file.name, Errno(e)}
+       }
+       return r, nil
+}
+
+// WriteString is like Write, but writes the contents of string s rather than
+// an array of bytes.
+func (file *File) WriteString(s string) (ret int, err Error) {
+       if file == nil {
+               return 0, EINVAL
+       }
+       b := syscall.StringByteSlice(s)
+       b = b[0 : len(b)-1]
+       return file.Write(b)
+}
+
+// Pipe returns a connected pair of Files; reads from r return bytes written to w.
+// It returns the files and an Error, if any.
+func Pipe() (r *File, w *File, err Error) {
+       var p [2]int
+
+       // See ../syscall/exec.go for description of lock.
+       syscall.ForkLock.RLock()
+       e := syscall.Pipe(p[0:])
+       if e != 0 {
+               syscall.ForkLock.RUnlock()
+               return nil, nil, NewSyscallError("pipe", e)
+       }
+       syscall.CloseOnExec(p[0])
+       syscall.CloseOnExec(p[1])
+       syscall.ForkLock.RUnlock()
+
+       return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+}
+
+// Mkdir creates a new directory with the specified name and permission bits.
+// It returns an error, if any.
+func Mkdir(name string, perm uint32) Error {
+       e := syscall.Mkdir(name, perm)
+       if e != 0 {
+               return &PathError{"mkdir", name, Errno(e)}
+       }
+       return nil
+}
+
+// Stat returns a FileInfo structure describing the named file and an error, if any.
+// If name names a valid symbolic link, the returned FileInfo describes
+// the file pointed at by the link and has fi.FollowedSymlink set to true.
+// If name names an invalid symbolic link, the returned FileInfo describes
+// the link itself and has fi.FollowedSymlink set to false.
+func Stat(name string) (fi *FileInfo, err Error) {
+       var lstat, stat syscall.Stat_t
+       e := syscall.Lstat(name, &lstat)
+       if e != 0 {
+               return nil, &PathError{"stat", name, Errno(e)}
+       }
+       statp := &lstat
+       if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
+               e := syscall.Stat(name, &stat)
+               if e == 0 {
+                       statp = &stat
+               }
+       }
+       return fileInfoFromStat(name, new(FileInfo), &lstat, statp), nil
+}
+
+// Lstat returns the FileInfo structure describing the named file and an
+// error, if any.  If the file is a symbolic link, the returned FileInfo
+// describes the symbolic link.  Lstat makes no attempt to follow the link.
+func Lstat(name string) (fi *FileInfo, err Error) {
+       var stat syscall.Stat_t
+       e := syscall.Lstat(name, &stat)
+       if e != 0 {
+               return nil, &PathError{"lstat", name, Errno(e)}
+       }
+       return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
+}
+
+// Chdir changes the current working directory to the named directory.
+func Chdir(dir string) Error {
+       if e := syscall.Chdir(dir); e != 0 {
+               return &PathError{"chdir", dir, Errno(e)}
+       }
+       return nil
+}
+
+// Chdir changes the current working directory to the file,
+// which must be a directory.
+func (f *File) Chdir() Error {
+       if e := syscall.Fchdir(f.fd); e != 0 {
+               return &PathError{"chdir", f.name, Errno(e)}
+       }
+       return nil
+}
+
+// Remove removes the named file or directory.
+func Remove(name string) Error {
+       // System call interface forces us to know
+       // whether name is a file or directory.
+       // Try both: it is cheaper on average than
+       // doing a Stat plus the right one.
+       e := syscall.Unlink(name)
+       if e == 0 {
+               return nil
+       }
+       e1 := syscall.Rmdir(name)
+       if e1 == 0 {
+               return nil
+       }
+
+       // Both failed: figure out which error to return.
+       // OS X and Linux differ on whether unlink(dir)
+       // returns EISDIR, so can't use that.  However,
+       // both agree that rmdir(file) returns ENOTDIR,
+       // so we can use that to decide which error is real.
+       // Rmdir might also return ENOTDIR if given a bad
+       // file path, like /etc/passwd/foo, but in that case,
+       // both errors will be ENOTDIR, so it's okay to
+       // use the error from unlink.
+       // For windows syscall.ENOTDIR is set
+       // to syscall.ERROR_DIRECTORY, hopefully it should
+       // do the trick.
+       if e1 != syscall.ENOTDIR {
+               e = e1
+       }
+       return &PathError{"remove", name, Errno(e)}
+}
+
+// LinkError records an error during a link or symlink or rename
+// system call and the paths that caused it.
+type LinkError struct {
+       Op    string
+       Old   string
+       New   string
+       Error Error
+}
+
+func (e *LinkError) String() string {
+       return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String()
+}
+
+// Link creates a hard link.
+func Link(oldname, newname string) Error {
+       e := syscall.Link(oldname, newname)
+       if e != 0 {
+               return &LinkError{"link", oldname, newname, Errno(e)}
+       }
+       return nil
+}
+
+// Symlink creates a symbolic link.
+func Symlink(oldname, newname string) Error {
+       e := syscall.Symlink(oldname, newname)
+       if e != 0 {
+               return &LinkError{"symlink", oldname, newname, Errno(e)}
+       }
+       return nil
+}
+
+// Readlink reads the contents of a symbolic link: the destination of
+// the link.  It returns the contents and an Error, if any.
+func Readlink(name string) (string, Error) {
+       for len := 128; ; len *= 2 {
+               b := make([]byte, len)
+               n, e := syscall.Readlink(name, b)
+               if e != 0 {
+                       return "", &PathError{"readlink", name, Errno(e)}
+               }
+               if n < len {
+                       return string(b[0:n]), nil
+               }
+       }
+       // Silence 6g.
+       return "", nil
+}
+
+// Rename renames a file.
+func Rename(oldname, newname string) Error {
+       e := syscall.Rename(oldname, newname)
+       if e != 0 {
+               return &LinkError{"rename", oldname, newname, Errno(e)}
+       }
+       return nil
+}
+
+// Chmod changes the mode of the named file to mode.
+// If the file is a symbolic link, it changes the mode of the link's target.
+func Chmod(name string, mode uint32) Error {
+       if e := syscall.Chmod(name, mode); e != 0 {
+               return &PathError{"chmod", name, Errno(e)}
+       }
+       return nil
+}
+
+// Chmod changes the mode of the file to mode.
+func (f *File) Chmod(mode uint32) Error {
+       if e := syscall.Fchmod(f.fd, mode); e != 0 {
+               return &PathError{"chmod", f.name, Errno(e)}
+       }
+       return nil
+}
+
+// Chown changes the numeric uid and gid of the named file.
+// If the file is a symbolic link, it changes the uid and gid of the link's target.
+func Chown(name string, uid, gid int) Error {
+       if e := syscall.Chown(name, uid, gid); e != 0 {
+               return &PathError{"chown", name, Errno(e)}
+       }
+       return nil
+}
+
+// Lchown changes the numeric uid and gid of the named file.
+// If the file is a symbolic link, it changes the uid and gid of the link itself.
+func Lchown(name string, uid, gid int) Error {
+       if e := syscall.Lchown(name, uid, gid); e != 0 {
+               return &PathError{"lchown", name, Errno(e)}
+       }
+       return nil
+}
+
+// Chown changes the numeric uid and gid of the named file.
+func (f *File) Chown(uid, gid int) Error {
+       if e := syscall.Fchown(f.fd, uid, gid); e != 0 {
+               return &PathError{"chown", f.name, Errno(e)}
+       }
+       return nil
+}
+
+// Truncate changes the size of the file.
+// It does not change the I/O offset.
+func (f *File) Truncate(size int64) Error {
+       if e := syscall.Ftruncate(f.fd, size); e != 0 {
+               return &PathError{"truncate", f.name, Errno(e)}
+       }
+       return nil
+}
+
+// Chtimes changes the access and modification times of the named
+// file, similar to the Unix utime() or utimes() functions.
+//
+// The argument times are in nanoseconds, although the underlying
+// filesystem may truncate or round the values to a more
+// coarse time unit.
+func Chtimes(name string, atime_ns int64, mtime_ns int64) Error {
+       var utimes [2]syscall.Timeval
+       utimes[0] = syscall.NsecToTimeval(atime_ns)
+       utimes[1] = syscall.NsecToTimeval(mtime_ns)
+       if e := syscall.Utimes(name, utimes[0:]); e != 0 {
+               return &PathError{"chtimes", name, Errno(e)}
+       }
+       return nil
+}
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
new file mode 100644 (file)
index 0000000..aa322c9
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+       "runtime"
+       "syscall"
+)
+
+// Auxiliary information if the File describes a directory
+type dirInfo struct {
+       buf  []byte // buffer for directory I/O
+       dir *syscall.DIR // from opendir
+}
+
+// DevNull is the name of the operating system's ``null device.''
+// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
+const DevNull = "/dev/null"
+
+// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.)
+// if applicable.  If successful, methods on the returned File can be used for I/O.
+// It returns the File and an Error, if any.
+func Open(name string, flag int, perm uint32) (file *File, err Error) {
+       r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
+       if e != 0 {
+               return nil, &PathError{"open", name, Errno(e)}
+       }
+
+       // There's a race here with fork/exec, which we are
+       // content to live with.  See ../syscall/exec.go
+       if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
+               syscall.CloseOnExec(r)
+       }
+
+       return NewFile(r, name), nil
+}
+
+// Close closes the File, rendering it unusable for I/O.
+// It returns an Error, if any.
+func (file *File) Close() Error {
+       if file == nil || file.fd < 0 {
+               return EINVAL
+       }
+       var err Error
+       if e := syscall.Close(file.fd); e != 0 {
+               err = &PathError{"close", file.name, Errno(e)}
+       }
+       file.fd = -1 // so it can't be closed again
+
+       // no need for a finalizer anymore
+       runtime.SetFinalizer(file, nil)
+       return err
+}
+
+// Stat returns the FileInfo structure describing file.
+// It returns the FileInfo and an error, if any.
+func (file *File) Stat() (fi *FileInfo, err Error) {
+       var stat syscall.Stat_t
+       e := syscall.Fstat(file.fd, &stat)
+       if e != 0 {
+               return nil, &PathError{"stat", file.name, Errno(e)}
+       }
+       return fileInfoFromStat(file.name, new(FileInfo), &stat, &stat), nil
+}
+
+// Readdir reads the contents of the directory associated with file and
+// returns an array of up to count FileInfo structures, as would be returned
+// by Lstat, in directory order.  Subsequent calls on the same file will yield
+// further FileInfos.
+// A negative count means to read until EOF.
+// Readdir returns the array and an Error, if any.
+func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
+       dirname := file.name
+       if dirname == "" {
+               dirname = "."
+       }
+       dirname += "/"
+       names, err1 := file.Readdirnames(count)
+       if err1 != nil {
+               return nil, err1
+       }
+       fi = make([]FileInfo, len(names))
+       for i, filename := range names {
+               fip, err := Lstat(dirname + filename)
+               if fip == nil || err != nil {
+                       fi[i].Name = filename // rest is already zeroed out
+               } else {
+                       fi[i] = *fip
+               }
+       }
+       return
+}
+
+// Truncate changes the size of the named file.
+// If the file is a symbolic link, it changes the size of the link's target.
+func Truncate(name string, size int64) Error {
+       if e := syscall.Truncate(name, size); e != 0 {
+               return &PathError{"truncate", name, Errno(e)}
+       }
+       return nil
+}
diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go
new file mode 100644 (file)
index 0000000..49aaea8
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+       "syscall"
+)
+
+// Getwd returns a rooted path name corresponding to the
+// current directory.  If the current directory can be
+// reached via multiple paths (due to symbolic links),
+// Getwd may return any one of them.
+func Getwd() (string, Error) {
+       // If the operating system provides a Getwd call, use it.
+       if syscall.ImplementsGetwd {
+               s, e := syscall.Getwd()
+               return s, NewSyscallError("getwd", e)
+       }
+
+       // Otherwise, we're trying to find our way back to ".".
+       dot, err := Stat(".")
+       if err != nil {
+               return "", err
+       }
+
+       // Clumsy but widespread kludge:
+       // if $PWD is set and matches ".", use it.
+       pwd := Getenv("PWD")
+       if len(pwd) > 0 && pwd[0] == '/' {
+               d, err := Stat(pwd)
+               if err == nil && d.Dev == dot.Dev && d.Ino == dot.Ino {
+                       return pwd, nil
+               }
+       }
+
+       // Root is a special case because it has no parent
+       // and ends in a slash.
+       root, err := Stat("/")
+       if err != nil {
+               // Can't stat root - no hope.
+               return "", err
+       }
+       if root.Dev == dot.Dev && root.Ino == dot.Ino {
+               return "/", nil
+       }
+
+       // General algorithm: find name in parent
+       // and then find name of parent.  Each iteration
+       // adds /name to the beginning of pwd.
+       pwd = ""
+       for parent := ".."; ; parent = "../" + parent {
+               if len(parent) >= 1024 { // Sanity check
+                       return "", ENAMETOOLONG
+               }
+               fd, err := Open(parent, O_RDONLY, 0)
+               if err != nil {
+                       return "", err
+               }
+
+               for {
+                       names, err := fd.Readdirnames(100)
+                       if err != nil {
+                               fd.Close()
+                               return "", err
+                       }
+                       for _, name := range names {
+                               d, _ := Lstat(parent + "/" + name)
+                               if d.Dev == dot.Dev && d.Ino == dot.Ino {
+                                       pwd = "/" + name + pwd
+                                       goto Found
+                               }
+                       }
+               }
+               fd.Close()
+               return "", ENOENT
+
+       Found:
+               pd, err := fd.Stat()
+               if err != nil {
+                       return "", err
+               }
+               fd.Close()
+               if pd.Dev == root.Dev && pd.Ino == root.Ino {
+                       break
+               }
+               // Set up for next round.
+               dot = pd
+       }
+       return pwd, nil
+}
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
new file mode 100644 (file)
index 0000000..c3e5631
--- /dev/null
@@ -0,0 +1,883 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "io/ioutil"
+       . "os"
+       "strings"
+       "syscall"
+       "testing"
+)
+
+var dot = []string{
+       "env_unix.go",
+       "error.go",
+       "file.go",
+       "os_test.go",
+       "time.go",
+       "types.go",
+}
+
+type sysDir struct {
+       name  string
+       files []string
+}
+
+var sysdir = func() (sd *sysDir) {
+       switch syscall.OS {
+       case "windows":
+               sd = &sysDir{
+                       Getenv("SystemRoot") + "\\system32\\drivers\\etc",
+                       []string{
+                               "hosts",
+                               "networks",
+                               "protocol",
+                               "services",
+                       },
+               }
+       default:
+               sd = &sysDir{
+                       "/etc",
+                       []string{
+                               "group",
+                               "hosts",
+                               "passwd",
+                       },
+               }
+       }
+       return
+}()
+
+func size(name string, t *testing.T) int64 {
+       file, err := Open(name, O_RDONLY, 0)
+       defer file.Close()
+       if err != nil {
+               t.Fatal("open failed:", err)
+       }
+       var buf [100]byte
+       len := 0
+       for {
+               n, e := file.Read(buf[0:])
+               len += n
+               if e == EOF {
+                       break
+               }
+               if e != nil {
+                       t.Fatal("read failed:", err)
+               }
+       }
+       return int64(len)
+}
+
+func equal(name1, name2 string) (r bool) {
+       switch syscall.OS {
+       case "windows":
+               r = strings.ToLower(name1) == strings.ToLower(name2)
+       default:
+               r = name1 == name2
+       }
+       return
+}
+
+func newFile(testName string, t *testing.T) (f *File) {
+       // Use a local file system, not NFS.
+       // On Unix, override $TMPDIR in case the user
+       // has it set to an NFS-mounted directory.
+       dir := ""
+       if syscall.OS != "windows" {
+               dir = "/tmp"
+       }
+       f, err := ioutil.TempFile(dir, "_Go_"+testName)
+       if err != nil {
+               t.Fatalf("open %s: %s", testName, err)
+       }
+       return
+}
+
+var sfdir = sysdir.name
+var sfname = sysdir.files[0]
+
+func TestStat(t *testing.T) {
+       path := sfdir + "/" + sfname
+       dir, err := Stat(path)
+       if err != nil {
+               t.Fatal("stat failed:", err)
+       }
+       if !equal(sfname, dir.Name) {
+               t.Error("name should be ", sfname, "; is", dir.Name)
+       }
+       filesize := size(path, t)
+       if dir.Size != filesize {
+               t.Error("size should be", filesize, "; is", dir.Size)
+       }
+}
+
+func TestFstat(t *testing.T) {
+       path := sfdir + "/" + sfname
+       file, err1 := Open(path, O_RDONLY, 0)
+       defer file.Close()
+       if err1 != nil {
+               t.Fatal("open failed:", err1)
+       }
+       dir, err2 := file.Stat()
+       if err2 != nil {
+               t.Fatal("fstat failed:", err2)
+       }
+       if !equal(sfname, dir.Name) {
+               t.Error("name should be ", sfname, "; is", dir.Name)
+       }
+       filesize := size(path, t)
+       if dir.Size != filesize {
+               t.Error("size should be", filesize, "; is", dir.Size)
+       }
+}
+
+func TestLstat(t *testing.T) {
+       path := sfdir + "/" + sfname
+       dir, err := Lstat(path)
+       if err != nil {
+               t.Fatal("lstat failed:", err)
+       }
+       if !equal(sfname, dir.Name) {
+               t.Error("name should be ", sfname, "; is", dir.Name)
+       }
+       filesize := size(path, t)
+       if dir.Size != filesize {
+               t.Error("size should be", filesize, "; is", dir.Size)
+       }
+}
+
+func testReaddirnames(dir string, contents []string, t *testing.T) {
+       file, err := Open(dir, O_RDONLY, 0)
+       defer file.Close()
+       if err != nil {
+               t.Fatalf("open %q failed: %v", dir, err)
+       }
+       s, err2 := file.Readdirnames(-1)
+       if err2 != nil {
+               t.Fatalf("readdirnames %q failed: %v", err2)
+       }
+       for _, m := range contents {
+               found := false
+               for _, n := range s {
+                       if n == "." || n == ".." {
+                               t.Errorf("got %s in directory", n)
+                       }
+                       if equal(m, n) {
+                               if found {
+                                       t.Error("present twice:", m)
+                               }
+                               found = true
+                       }
+               }
+               if !found {
+                       t.Error("could not find", m)
+               }
+       }
+}
+
+func testReaddir(dir string, contents []string, t *testing.T) {
+       file, err := Open(dir, O_RDONLY, 0)
+       defer file.Close()
+       if err != nil {
+               t.Fatalf("open %q failed: %v", dir, err)
+       }
+       s, err2 := file.Readdir(-1)
+       if err2 != nil {
+               t.Fatalf("readdir %q failed: %v", dir, err2)
+       }
+       for _, m := range contents {
+               found := false
+               for _, n := range s {
+                       if equal(m, n.Name) {
+                               if found {
+                                       t.Error("present twice:", m)
+                               }
+                               found = true
+                       }
+               }
+               if !found {
+                       t.Error("could not find", m)
+               }
+       }
+}
+
+func TestReaddirnames(t *testing.T) {
+       testReaddirnames(".", dot, t)
+       testReaddirnames(sysdir.name, sysdir.files, t)
+}
+
+func TestReaddir(t *testing.T) {
+       testReaddir(".", dot, t)
+       testReaddir(sysdir.name, sysdir.files, t)
+}
+
+// Read the directory one entry at a time.
+func smallReaddirnames(file *File, length int, t *testing.T) []string {
+       names := make([]string, length)
+       count := 0
+       for {
+               d, err := file.Readdirnames(1)
+               if err != nil {
+                       t.Fatalf("readdir %q failed: %v", file.Name(), err)
+               }
+               if len(d) == 0 {
+                       break
+               }
+               names[count] = d[0]
+               count++
+       }
+       return names[0:count]
+}
+
+// Check that reading a directory one entry at a time gives the same result
+// as reading it all at once.
+func TestReaddirnamesOneAtATime(t *testing.T) {
+       // big directory that doesn't change often.
+       dir := "/usr/bin"
+       if syscall.OS == "windows" {
+               dir = Getenv("SystemRoot") + "\\system32"
+       }
+       file, err := Open(dir, O_RDONLY, 0)
+       defer file.Close()
+       if err != nil {
+               t.Fatalf("open %q failed: %v", dir, err)
+       }
+       all, err1 := file.Readdirnames(-1)
+       if err1 != nil {
+               t.Fatalf("readdirnames %q failed: %v", dir, err1)
+       }
+       file1, err2 := Open(dir, O_RDONLY, 0)
+       if err2 != nil {
+               t.Fatalf("open %q failed: %v", dir, err2)
+       }
+       small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
+       for i, n := range all {
+               if small[i] != n {
+                       t.Errorf("small read %q %q mismatch: %v", small[i], n)
+               }
+       }
+}
+
+func TestHardLink(t *testing.T) {
+       // Hardlinks are not supported under windows.
+       if syscall.OS == "windows" {
+               return
+       }
+       from, to := "hardlinktestfrom", "hardlinktestto"
+       Remove(from) // Just in case.
+       file, err := Open(to, O_CREAT|O_WRONLY, 0666)
+       if err != nil {
+               t.Fatalf("open %q failed: %v", to, err)
+       }
+       defer Remove(to)
+       if err = file.Close(); err != nil {
+               t.Errorf("close %q failed: %v", to, err)
+       }
+       err = Link(to, from)
+       if err != nil {
+               t.Fatalf("link %q, %q failed: %v", to, from, err)
+       }
+       defer Remove(from)
+       tostat, err := Stat(to)
+       if err != nil {
+               t.Fatalf("stat %q failed: %v", to, err)
+       }
+       fromstat, err := Stat(from)
+       if err != nil {
+               t.Fatalf("stat %q failed: %v", from, err)
+       }
+       if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+               t.Errorf("link %q, %q did not create hard link", to, from)
+       }
+}
+
+func TestSymLink(t *testing.T) {
+       // Symlinks are not supported under windows.
+       if syscall.OS == "windows" {
+               return
+       }
+       from, to := "symlinktestfrom", "symlinktestto"
+       Remove(from) // Just in case.
+       file, err := Open(to, O_CREAT|O_WRONLY, 0666)
+       if err != nil {
+               t.Fatalf("open %q failed: %v", to, err)
+       }
+       defer Remove(to)
+       if err = file.Close(); err != nil {
+               t.Errorf("close %q failed: %v", to, err)
+       }
+       err = Symlink(to, from)
+       if err != nil {
+               t.Fatalf("symlink %q, %q failed: %v", to, from, err)
+       }
+       defer Remove(from)
+       tostat, err := Stat(to)
+       if err != nil {
+               t.Fatalf("stat %q failed: %v", to, err)
+       }
+       if tostat.FollowedSymlink {
+               t.Fatalf("stat %q claims to have followed a symlink", to)
+       }
+       fromstat, err := Stat(from)
+       if err != nil {
+               t.Fatalf("stat %q failed: %v", from, err)
+       }
+       if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+               t.Errorf("symlink %q, %q did not create symlink", to, from)
+       }
+       fromstat, err = Lstat(from)
+       if err != nil {
+               t.Fatalf("lstat %q failed: %v", from, err)
+       }
+       if !fromstat.IsSymlink() {
+               t.Fatalf("symlink %q, %q did not create symlink", to, from)
+       }
+       fromstat, err = Stat(from)
+       if err != nil {
+               t.Fatalf("stat %q failed: %v", from, err)
+       }
+       if !fromstat.FollowedSymlink {
+               t.Fatalf("stat %q did not follow symlink")
+       }
+       s, err := Readlink(from)
+       if err != nil {
+               t.Fatalf("readlink %q failed: %v", from, err)
+       }
+       if s != to {
+               t.Fatalf("after symlink %q != %q", s, to)
+       }
+       file, err = Open(from, O_RDONLY, 0)
+       if err != nil {
+               t.Fatalf("open %q failed: %v", from, err)
+       }
+       file.Close()
+}
+
+func TestLongSymlink(t *testing.T) {
+       // Symlinks are not supported under windows.
+       if syscall.OS == "windows" {
+               return
+       }
+       s := "0123456789abcdef"
+       // Long, but not too long: a common limit is 255.
+       s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
+       from := "longsymlinktestfrom"
+       Remove(from) // Just in case.
+       err := Symlink(s, from)
+       if err != nil {
+               t.Fatalf("symlink %q, %q failed: %v", s, from, err)
+       }
+       defer Remove(from)
+       r, err := Readlink(from)
+       if err != nil {
+               t.Fatalf("readlink %q failed: %v", from, err)
+       }
+       if r != s {
+               t.Fatalf("after symlink %q != %q", r, s)
+       }
+}
+
+func TestRename(t *testing.T) {
+       from, to := "renamefrom", "renameto"
+       Remove(to) // Just in case.
+       file, err := Open(from, O_CREAT|O_WRONLY, 0666)
+       if err != nil {
+               t.Fatalf("open %q failed: %v", to, err)
+       }
+       if err = file.Close(); err != nil {
+               t.Errorf("close %q failed: %v", to, err)
+       }
+       err = Rename(from, to)
+       if err != nil {
+               t.Fatalf("rename %q, %q failed: %v", to, from, err)
+       }
+       defer Remove(to)
+       _, err = Stat(to)
+       if err != nil {
+               t.Errorf("stat %q failed: %v", to, err)
+       }
+}
+
+func TestForkExec(t *testing.T) {
+       var cmd, adir, expect string
+       var args []string
+       r, w, err := Pipe()
+       if err != nil {
+               t.Fatalf("Pipe: %v", err)
+       }
+       if syscall.OS == "windows" {
+               cmd = Getenv("COMSPEC")
+               args = []string{Getenv("COMSPEC"), "/c cd"}
+               adir = Getenv("SystemRoot")
+               expect = Getenv("SystemRoot") + "\r\n"
+       } else {
+               cmd = "/bin/pwd"
+               args = []string{"pwd"}
+               adir = "/"
+               expect = "/\n"
+       }
+       pid, err := ForkExec(cmd, args, nil, adir, []*File{nil, w, Stderr})
+       if err != nil {
+               t.Fatalf("ForkExec: %v", err)
+       }
+       w.Close()
+
+       var b bytes.Buffer
+       io.Copy(&b, r)
+       output := b.String()
+       if output != expect {
+               args[0] = cmd
+               t.Errorf("exec %q returned %q wanted %q", strings.Join(args, " "), output, expect)
+       }
+       Wait(pid, 0)
+}
+
+func checkMode(t *testing.T, path string, mode uint32) {
+       dir, err := Stat(path)
+       if err != nil {
+               t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
+       }
+       if dir.Mode&0777 != mode {
+               t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode, mode)
+       }
+}
+
+func TestChmod(t *testing.T) {
+       // Chmod is not supported under windows.
+       if syscall.OS == "windows" {
+               return
+       }
+       f := newFile("TestChmod", t)
+       defer Remove(f.Name())
+       defer f.Close()
+
+       if err := Chmod(f.Name(), 0456); err != nil {
+               t.Fatalf("chmod %s 0456: %s", f.Name(), err)
+       }
+       checkMode(t, f.Name(), 0456)
+
+       if err := f.Chmod(0123); err != nil {
+               t.Fatalf("chmod %s 0123: %s", f.Name(), err)
+       }
+       checkMode(t, f.Name(), 0123)
+}
+
+func checkUidGid(t *testing.T, path string, uid, gid int) {
+       dir, err := Stat(path)
+       if err != nil {
+               t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
+       }
+       if dir.Uid != uid {
+               t.Errorf("Stat %q: uid %d want %d", path, dir.Uid, uid)
+       }
+       if dir.Gid != gid {
+               t.Errorf("Stat %q: gid %d want %d", path, dir.Gid, gid)
+       }
+}
+
+func TestChown(t *testing.T) {
+       // Chown is not supported under windows.
+       if syscall.OS == "windows" {
+               return
+       }
+       // Use TempDir() to make sure we're on a local file system,
+       // so that the group ids returned by Getgroups will be allowed
+       // on the file.  On NFS, the Getgroups groups are
+       // basically useless.
+       f := newFile("TestChown", t)
+       defer Remove(f.Name())
+       defer f.Close()
+       dir, err := f.Stat()
+       if err != nil {
+               t.Fatalf("stat %s: %s", f.Name(), err)
+       }
+
+       // Can't change uid unless root, but can try
+       // changing the group id.  First try our current group.
+       gid := Getgid()
+       t.Log("gid:", gid)
+       if err = Chown(f.Name(), -1, gid); err != nil {
+               t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
+       }
+       checkUidGid(t, f.Name(), dir.Uid, gid)
+
+       // Then try all the auxiliary groups.
+       groups, err := Getgroups()
+       if err != nil {
+               t.Fatalf("getgroups: %s", err)
+       }
+       t.Log("groups: ", groups)
+       for _, g := range groups {
+               if err = Chown(f.Name(), -1, g); err != nil {
+                       t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
+               }
+               checkUidGid(t, f.Name(), dir.Uid, g)
+
+               // change back to gid to test fd.Chown
+               if err = f.Chown(-1, gid); err != nil {
+                       t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
+               }
+               checkUidGid(t, f.Name(), dir.Uid, gid)
+       }
+}
+
+func checkSize(t *testing.T, f *File, size int64) {
+       dir, err := f.Stat()
+       if err != nil {
+               t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
+       }
+       if dir.Size != size {
+               t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size, size)
+       }
+}
+
+func TestTruncate(t *testing.T) {
+       f := newFile("TestTruncate", t)
+       defer Remove(f.Name())
+       defer f.Close()
+
+       checkSize(t, f, 0)
+       f.Write([]byte("hello, world\n"))
+       checkSize(t, f, 13)
+       f.Truncate(10)
+       checkSize(t, f, 10)
+       f.Truncate(1024)
+       checkSize(t, f, 1024)
+       f.Truncate(0)
+       checkSize(t, f, 0)
+       f.Write([]byte("surprise!"))
+       checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+}
+
+// Use TempDir() to make sure we're on a local file system,
+// so that timings are not distorted by latency and caching.
+// On NFS, timings can be off due to caching of meta-data on
+// NFS servers (Issue 848).
+func TestChtimes(t *testing.T) {
+       f := newFile("TestChtimes", t)
+       defer Remove(f.Name())
+       defer f.Close()
+
+       f.Write([]byte("hello, world\n"))
+       f.Close()
+
+       preStat, err := Stat(f.Name())
+       if err != nil {
+               t.Fatalf("Stat %s: %s", f.Name(), err)
+       }
+
+       // Move access and modification time back a second
+       const OneSecond = 1e9 // in nanoseconds
+       err = Chtimes(f.Name(), preStat.Atime_ns-OneSecond, preStat.Mtime_ns-OneSecond)
+       if err != nil {
+               t.Fatalf("Chtimes %s: %s", f.Name(), err)
+       }
+
+       postStat, err := Stat(f.Name())
+       if err != nil {
+               t.Fatalf("second Stat %s: %s", f.Name(), err)
+       }
+
+       if postStat.Atime_ns >= preStat.Atime_ns {
+               t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
+                       preStat.Atime_ns,
+                       postStat.Atime_ns)
+       }
+
+       if postStat.Mtime_ns >= preStat.Mtime_ns {
+               t.Errorf("Mtime_ns didn't go backwards; was=%d, after=%d",
+                       preStat.Mtime_ns,
+                       postStat.Mtime_ns)
+       }
+}
+
+func TestChdirAndGetwd(t *testing.T) {
+       // TODO(brainman): file.Chdir() is not implemented on windows.
+       if syscall.OS == "windows" {
+               return
+       }
+       fd, err := Open(".", O_RDONLY, 0)
+       if err != nil {
+               t.Fatalf("Open .: %s", err)
+       }
+       // These are chosen carefully not to be symlinks on a Mac
+       // (unlike, say, /var, /etc, and /tmp).
+       dirs := []string{"/bin", "/", "/usr/bin"}
+       for mode := 0; mode < 2; mode++ {
+               for _, d := range dirs {
+                       if mode == 0 {
+                               err = Chdir(d)
+                       } else {
+                               fd1, err := Open(d, O_RDONLY, 0)
+                               if err != nil {
+                                       t.Errorf("Open %s: %s", d, err)
+                                       continue
+                               }
+                               err = fd1.Chdir()
+                               fd1.Close()
+                       }
+                       pwd, err1 := Getwd()
+                       err2 := fd.Chdir()
+                       if err2 != nil {
+                               // We changed the current directory and cannot go back.
+                               // Don't let the tests continue; they'll scribble
+                               // all over some other directory.
+                               fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
+                               Exit(1)
+                       }
+                       if err != nil {
+                               fd.Close()
+                               t.Fatalf("Chdir %s: %s", d, err)
+                       }
+                       if err1 != nil {
+                               fd.Close()
+                               t.Fatalf("Getwd in %s: %s", d, err1)
+                       }
+                       if pwd != d {
+                               fd.Close()
+                               t.Fatalf("Getwd returned %q want %q", pwd, d)
+                       }
+               }
+       }
+       fd.Close()
+}
+
+func TestTime(t *testing.T) {
+       // Just want to check that Time() is getting something.
+       // A common failure mode on Darwin is to get 0, 0,
+       // because it returns the time in registers instead of
+       // filling in the structure passed to the system call.
+       // Too bad the compiler doesn't know that
+       // 365.24*86400 is an integer.
+       sec, nsec, err := Time()
+       if sec < (2009-1970)*36524*864 {
+               t.Errorf("Time() = %d, %d, %s; not plausible", sec, nsec, err)
+       }
+}
+
+func TestSeek(t *testing.T) {
+       f := newFile("TestSeek", t)
+       defer Remove(f.Name())
+       defer f.Close()
+
+       const data = "hello, world\n"
+       io.WriteString(f, data)
+
+       type test struct {
+               in     int64
+               whence int
+               out    int64
+       }
+       var tests = []test{
+               {0, 1, int64(len(data))},
+               {0, 0, 0},
+               {5, 0, 5},
+               {0, 2, int64(len(data))},
+               {0, 0, 0},
+               {-1, 2, int64(len(data)) - 1},
+               {1 << 33, 0, 1 << 33},
+               {1 << 33, 2, 1<<33 + int64(len(data))},
+       }
+       for i, tt := range tests {
+               off, err := f.Seek(tt.in, tt.whence)
+               if off != tt.out || err != nil {
+                       if e, ok := err.(*PathError); ok && e.Error == EINVAL && tt.out > 1<<32 {
+                               // Reiserfs rejects the big seeks.
+                               // http://code.google.com/p/go/issues/detail?id=91
+                               break
+                       }
+                       t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
+               }
+       }
+}
+
+type openErrorTest struct {
+       path  string
+       mode  int
+       error Error
+}
+
+var openErrorTests = []openErrorTest{
+       {
+               sfdir + "/no-such-file",
+               O_RDONLY,
+               ENOENT,
+       },
+       {
+               sfdir,
+               O_WRONLY,
+               EISDIR,
+       },
+       {
+               sfdir + "/" + sfname + "/no-such-file",
+               O_WRONLY,
+               ENOTDIR,
+       },
+}
+
+func TestOpenError(t *testing.T) {
+       for _, tt := range openErrorTests {
+               f, err := Open(tt.path, tt.mode, 0)
+               if err == nil {
+                       t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
+                       f.Close()
+                       continue
+               }
+               perr, ok := err.(*PathError)
+               if !ok {
+                       t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
+               }
+               if perr.Error != tt.error {
+                       t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
+               }
+       }
+}
+
+func run(t *testing.T, cmd []string) string {
+       // Run /bin/hostname and collect output.
+       r, w, err := Pipe()
+       if err != nil {
+               t.Fatal(err)
+       }
+       pid, err := ForkExec("/bin/hostname", []string{"hostname"}, nil, "/", []*File{nil, w, Stderr})
+       if err != nil {
+               t.Fatal(err)
+       }
+       w.Close()
+
+       var b bytes.Buffer
+       io.Copy(&b, r)
+       Wait(pid, 0)
+       output := b.String()
+       if n := len(output); n > 0 && output[n-1] == '\n' {
+               output = output[0 : n-1]
+       }
+       if output == "" {
+               t.Fatalf("%v produced no output", cmd)
+       }
+
+       return output
+}
+
+
+func TestHostname(t *testing.T) {
+       // There is no other way to fetch hostname on windows, but via winapi.
+       if syscall.OS == "windows" {
+               return
+       }
+       // Check internal Hostname() against the output of /bin/hostname.
+       // Allow that the internal Hostname returns a Fully Qualified Domain Name
+       // and the /bin/hostname only returns the first component
+       hostname, err := Hostname()
+       if err != nil {
+               t.Fatalf("%v", err)
+       }
+       want := run(t, []string{"/bin/hostname"})
+       if hostname != want {
+               i := strings.Index(hostname, ".")
+               if i < 0 || hostname[0:i] != want {
+                       t.Errorf("Hostname() = %q, want %q", hostname, want)
+               }
+       }
+}
+
+func TestReadAt(t *testing.T) {
+       f := newFile("TestReadAt", t)
+       defer Remove(f.Name())
+       defer f.Close()
+
+       const data = "hello, world\n"
+       io.WriteString(f, data)
+
+       b := make([]byte, 5)
+       n, err := f.ReadAt(b, 7)
+       if err != nil || n != len(b) {
+               t.Fatalf("ReadAt 7: %d, %r", n, err)
+       }
+       if string(b) != "world" {
+               t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
+       }
+}
+
+func TestWriteAt(t *testing.T) {
+       f := newFile("TestWriteAt", t)
+       defer Remove(f.Name())
+       defer f.Close()
+
+       const data = "hello, world\n"
+       io.WriteString(f, data)
+
+       n, err := f.WriteAt([]byte("WORLD"), 7)
+       if err != nil || n != 5 {
+               t.Fatalf("WriteAt 7: %d, %v", n, err)
+       }
+
+       b, err := ioutil.ReadFile(f.Name())
+       if err != nil {
+               t.Fatalf("ReadFile %s: %v", f.Name(), err)
+       }
+       if string(b) != "hello, WORLD\n" {
+               t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
+       }
+}
+
+func writeFile(t *testing.T, fname string, flag int, text string) string {
+       f, err := Open(fname, flag, 0666)
+       if err != nil {
+               t.Fatalf("Open: %v", err)
+       }
+       n, err := io.WriteString(f, text)
+       if err != nil {
+               t.Fatalf("WriteString: %d, %v", n, err)
+       }
+       f.Close()
+       data, err := ioutil.ReadFile(fname)
+       if err != nil {
+               t.Fatalf("ReadFile: %v", err)
+       }
+       return string(data)
+}
+
+func TestAppend(t *testing.T) {
+       const f = "append.txt"
+       defer Remove(f)
+       s := writeFile(t, f, O_CREAT|O_TRUNC|O_RDWR, "new")
+       if s != "new" {
+               t.Fatalf("writeFile: have %q want %q", s, "new")
+       }
+       s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
+       if s != "new|append" {
+               t.Fatalf("writeFile: have %q want %q", s, "new|append")
+       }
+}
+
+func TestStatDirWithTrailingSlash(t *testing.T) {
+       // Create new dir, in _obj so it will get
+       // cleaned up by make if not by us.
+       path := "_obj/_TestStatDirWithSlash_"
+       err := MkdirAll(path, 0777)
+       if err != nil {
+               t.Fatalf("MkdirAll %q: %s", path, err)
+       }
+
+       // Stat of path should succeed.
+       _, err = Stat(path)
+       if err != nil {
+               t.Fatal("stat failed:", err)
+       }
+
+       // Stat of path+"/" should succeed too.
+       _, err = Stat(path + "/")
+       if err != nil {
+               t.Fatal("stat failed:", err)
+       }
+
+       RemoveAll("_obj/_TestMkdirAll_")
+}
diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go
new file mode 100644 (file)
index 0000000..74c83ab
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+
+// MkdirAll creates a directory named path,
+// along with any necessary parents, and returns nil,
+// or else returns an error.
+// The permission bits perm are used for all
+// directories that MkdirAll creates.
+// If path is already a directory, MkdirAll does nothing
+// and returns nil.
+func MkdirAll(path string, perm uint32) Error {
+       // If path exists, stop with success or error.
+       dir, err := Lstat(path)
+       if err == nil {
+               if dir.IsDirectory() {
+                       return nil
+               }
+               return &PathError{"mkdir", path, ENOTDIR}
+       }
+
+       // Doesn't already exist; make sure parent does.
+       i := len(path)
+       for i > 0 && path[i-1] == '/' { // Skip trailing slashes.
+               i--
+       }
+
+       j := i
+       for j > 0 && path[j-1] != '/' { // Scan backward over element.
+               j--
+       }
+
+       if j > 0 {
+               // Create parent
+               err = MkdirAll(path[0:j-1], perm)
+               if err != nil {
+                       return err
+               }
+       }
+
+       // Now parent exists, try to create.
+       err = Mkdir(path, perm)
+       if err != nil {
+               // Handle arguments like "foo/." by
+               // double-checking that directory doesn't exist.
+               dir, err1 := Lstat(path)
+               if err1 == nil && dir.IsDirectory() {
+                       return nil
+               }
+               return err
+       }
+       return nil
+}
+
+// RemoveAll removes path and any children it contains.
+// It removes everything it can but returns the first error
+// it encounters.  If the path does not exist, RemoveAll
+// returns nil (no error).
+func RemoveAll(path string) Error {
+       // Simple case: if Remove works, we're done.
+       err := Remove(path)
+       if err == nil {
+               return nil
+       }
+
+       // Otherwise, is this a directory we need to recurse into?
+       dir, serr := Lstat(path)
+       if serr != nil {
+               if serr, ok := serr.(*PathError); ok && serr.Error == ENOENT {
+                       return nil
+               }
+               return serr
+       }
+       if !dir.IsDirectory() {
+               // Not a directory; return the error from Remove.
+               return err
+       }
+
+       // Directory.
+       fd, err := Open(path, O_RDONLY, 0)
+       if err != nil {
+               return err
+       }
+
+       // Remove contents & return first error.
+       err = nil
+       for {
+               names, err1 := fd.Readdirnames(100)
+               for _, name := range names {
+                       err1 := RemoveAll(path + "/" + name)
+                       if err == nil {
+                               err = err1
+                       }
+               }
+               // If Readdirnames returned an error, use it.
+               if err == nil {
+                       err = err1
+               }
+               if len(names) == 0 {
+                       break
+               }
+       }
+
+       // Close directory, because windows won't remove opened directory.
+       fd.Close()
+
+       // Remove directory.
+       err1 := Remove(path)
+       if err == nil {
+               err = err1
+       }
+       return err
+}
diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go
new file mode 100644 (file)
index 0000000..9bc92ae
--- /dev/null
@@ -0,0 +1,162 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+       . "os"
+       "testing"
+       "syscall"
+)
+
+func TestMkdirAll(t *testing.T) {
+       // Create new dir, in _obj so it will get
+       // cleaned up by make if not by us.
+       path := "_obj/_TestMkdirAll_/dir/./dir2"
+       err := MkdirAll(path, 0777)
+       if err != nil {
+               t.Fatalf("MkdirAll %q: %s", path, err)
+       }
+
+       // Already exists, should succeed.
+       err = MkdirAll(path, 0777)
+       if err != nil {
+               t.Fatalf("MkdirAll %q (second time): %s", path, err)
+       }
+
+       // Make file.
+       fpath := path + "/file"
+       _, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
+       if err != nil {
+               t.Fatalf("create %q: %s", fpath, err)
+       }
+
+       // Can't make directory named after file.
+       err = MkdirAll(fpath, 0777)
+       if err == nil {
+               t.Fatalf("MkdirAll %q: no error")
+       }
+       perr, ok := err.(*PathError)
+       if !ok {
+               t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err)
+       }
+       if perr.Path != fpath {
+               t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, perr.Path, fpath)
+       }
+
+       // Can't make subdirectory of file.
+       ffpath := fpath + "/subdir"
+       err = MkdirAll(ffpath, 0777)
+       if err == nil {
+               t.Fatalf("MkdirAll %q: no error")
+       }
+       perr, ok = err.(*PathError)
+       if !ok {
+               t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err)
+       }
+       if perr.Path != fpath {
+               t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, perr.Path, fpath)
+       }
+
+       RemoveAll("_obj/_TestMkdirAll_")
+}
+
+func TestRemoveAll(t *testing.T) {
+       // Work directory.
+       path := "_obj/_TestRemoveAll_"
+       fpath := path + "/file"
+       dpath := path + "/dir"
+
+       // Make directory with 1 file and remove.
+       if err := MkdirAll(path, 0777); err != nil {
+               t.Fatalf("MkdirAll %q: %s", path, err)
+       }
+       fd, err := Open(fpath, O_WRONLY|O_CREAT, 0666)
+       if err != nil {
+               t.Fatalf("create %q: %s", fpath, err)
+       }
+       fd.Close()
+       if err = RemoveAll(path); err != nil {
+               t.Fatalf("RemoveAll %q (first): %s", path, err)
+       }
+       if _, err := Lstat(path); err == nil {
+               t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path)
+       }
+
+       // Make directory with file and subdirectory and remove.
+       if err = MkdirAll(dpath, 0777); err != nil {
+               t.Fatalf("MkdirAll %q: %s", dpath, err)
+       }
+       fd, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
+       if err != nil {
+               t.Fatalf("create %q: %s", fpath, err)
+       }
+       fd.Close()
+       fd, err = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
+       if err != nil {
+               t.Fatalf("create %q: %s", fpath, err)
+       }
+       fd.Close()
+       if err = RemoveAll(path); err != nil {
+               t.Fatalf("RemoveAll %q (second): %s", path, err)
+       }
+       if _, err := Lstat(path); err == nil {
+               t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
+       }
+
+       // Determine if we should run the following test.
+       testit := true
+       if syscall.OS == "windows" {
+               // Chmod is not supported under windows.
+               testit = false
+       } else {
+               // Test fails as root.
+               testit = Getuid() != 0
+       }
+       if testit {
+               // Make directory with file and subdirectory and trigger error.
+               if err = MkdirAll(dpath, 0777); err != nil {
+                       t.Fatalf("MkdirAll %q: %s", dpath, err)
+               }
+
+               for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
+                       fd, err = Open(s, O_WRONLY|O_CREAT, 0666)
+                       if err != nil {
+                               t.Fatalf("create %q: %s", s, err)
+                       }
+                       fd.Close()
+               }
+               if err = Chmod(dpath, 0); err != nil {
+                       t.Fatalf("Chmod %q 0: %s", dpath, err)
+               }
+               if err = RemoveAll(path); err == nil {
+                       _, err := Lstat(path)
+                       if err == nil {
+                               t.Errorf("Can lstat %q after supposed RemoveAll", path)
+                       }
+                       t.Fatalf("RemoveAll %q succeeded with chmod 0 subdirectory", path, err)
+               }
+               perr, ok := err.(*PathError)
+               if !ok {
+                       t.Fatalf("RemoveAll %q returned %T not *PathError", path, err)
+               }
+               if perr.Path != dpath {
+                       t.Fatalf("RemoveAll %q failed at %q not %q", path, perr.Path, dpath)
+               }
+               if err = Chmod(dpath, 0777); err != nil {
+                       t.Fatalf("Chmod %q 0777: %s", dpath, err)
+               }
+               for _, s := range []string{fpath, path + "/zzz"} {
+                       if _, err := Lstat(s); err == nil {
+                               t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
+                       }
+               }
+       }
+       if err = RemoveAll(path); err != nil {
+               t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
+       }
+       if _, err := Lstat(path); err == nil {
+               t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
+       }
+}
diff --git a/libgo/go/os/proc.go b/libgo/go/os/proc.go
new file mode 100644 (file)
index 0000000..dfddab6
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Process etc.
+
+package os
+
+import "syscall"
+
+var Args []string // provided by runtime
+var Envs []string // provided by runtime
+
+
+// Getuid returns the numeric user id of the caller.
+func Getuid() int { return syscall.Getuid() }
+
+// Geteuid returns the numeric effective user id of the caller.
+func Geteuid() int { return syscall.Geteuid() }
+
+// Getgid returns the numeric group id of the caller.
+func Getgid() int { return syscall.Getgid() }
+
+// Getegid returns the numeric effective group id of the caller.
+func Getegid() int { return syscall.Getegid() }
+
+// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
+func Getgroups() ([]int, Error) {
+       gids, errno := syscall.Getgroups()
+       return gids, NewSyscallError("getgroups", errno)
+}
+
+// Exit causes the current program to exit with the given status code.
+// Conventionally, code zero indicates success, non-zero an error.
+func Exit(code int) { syscall.Exit(code) }
diff --git a/libgo/go/os/signal/mkunix.sh b/libgo/go/os/signal/mkunix.sh
new file mode 100644 (file)
index 0000000..ec5c9d6
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+echo '// ./mkunix.sh' "$1"
+echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
+echo
+
+cat <<EOH
+package signal
+
+import (
+  "syscall"
+)
+
+var _ = syscall.Syscall  // in case there are zero signals
+
+const (
+EOH
+
+sed -n 's/^const[      ]*\(SIG[A-Z0-9][A-Z0-9]*\)[     ].*/  \1 = UnixSignal(syscall.\1)/p' "$1"
+
+echo ")"
diff --git a/libgo/go/os/signal/signal.go b/libgo/go/os/signal/signal.go
new file mode 100644 (file)
index 0000000..666c03e
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package signal implements operating system-independent signal handling.
+package signal
+
+import (
+       "runtime"
+       "strconv"
+)
+
+// A Signal can represent any operating system signal.
+type Signal interface {
+       String() string
+}
+
+type UnixSignal int32
+
+func (sig UnixSignal) String() string {
+       s := runtime.Signame(int32(sig))
+       if len(s) > 0 {
+               return s
+       }
+       return "Signal " + strconv.Itoa(int(sig))
+}
+
+// Incoming is the global signal channel.
+// All signals received by the program will be delivered to this channel.
+var Incoming <-chan Signal
+
+func process(ch chan<- Signal) {
+       for {
+               var mask uint32 = runtime.Sigrecv()
+               for sig := uint(0); sig < 32; sig++ {
+                       if mask&(1<<sig) != 0 {
+                               ch <- UnixSignal(sig)
+                       }
+               }
+       }
+}
+
+func init() {
+       runtime.Siginit()
+       ch := make(chan Signal) // Done here so Incoming can have type <-chan Signal
+       Incoming = ch
+       go process(ch)
+}
diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go
new file mode 100644 (file)
index 0000000..f2679f1
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package signal
+
+import (
+       "syscall"
+       "testing"
+)
+
+func TestSignal(t *testing.T) {
+       // Send this process a SIGHUP.
+       syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0)
+
+       if sig := (<-Incoming).(UnixSignal); sig != SIGHUP {
+               t.Errorf("signal was %v, want %v", sig, SIGHUP)
+       }
+}
diff --git a/libgo/go/os/stat.go b/libgo/go/os/stat.go
new file mode 100644 (file)
index 0000000..d6c7a54
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// AMD64, Linux
+
+package os
+
+import syscall "syscall"
+
+func isSymlink(stat *syscall.Stat_t) bool {
+       return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK
+}
+
+func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
+       fi.Dev = uint64(stat.Dev)
+       fi.Ino = uint64(stat.Ino)
+       fi.Nlink = uint64(stat.Nlink)
+       fi.Mode = uint32(stat.Mode)
+       fi.Uid = int(stat.Uid)
+       fi.Gid = int(stat.Gid)
+       fi.Rdev = uint64(stat.Rdev)
+       fi.Size = int64(stat.Size)
+       fi.Blksize = int64(stat.Blksize)
+       fi.Blocks = int64(stat.Blocks)
+       fi.Atime_ns = int64(stat.Atime.Sec)*1e9 + int64(stat.Atime.Nsec)
+       fi.Mtime_ns = int64(stat.Mtime.Sec)*1e9 + int64(stat.Mtime.Nsec)
+       fi.Ctime_ns = int64(stat.Ctime.Sec)*1e9 + int64(stat.Atime.Nsec)
+       for i := len(name)-1; i >= 0; i-- {
+               if name[i] == '/' {
+                       name = name[i+1:]
+                       break
+               }
+       }
+       fi.Name = name
+       if isSymlink(lstat) && !isSymlink(stat) {
+               fi.FollowedSymlink = true
+       }
+       return fi
+}
diff --git a/libgo/go/os/sys_bsd.go b/libgo/go/os/sys_bsd.go
new file mode 100644 (file)
index 0000000..188993b
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// os code shared between *BSD systems including OS X (Darwin)
+// and FreeBSD.
+
+package os
+
+import "syscall"
+
+func Hostname() (name string, err Error) {
+       var errno int
+       name, errno = syscall.Sysctl("kern.hostname")
+       if errno != 0 {
+               return "", NewSyscallError("sysctl kern.hostname", errno)
+       }
+       return name, nil
+}
diff --git a/libgo/go/os/sys_linux.go b/libgo/go/os/sys_linux.go
new file mode 100644 (file)
index 0000000..b82d295
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Linux-specific
+
+package os
+
+
+// Hostname returns the host name reported by the kernel.
+func Hostname() (name string, err Error) {
+       f, err := Open("/proc/sys/kernel/hostname", O_RDONLY, 0)
+       if err != nil {
+               return "", err
+       }
+       defer f.Close()
+
+       var buf [512]byte // Enough for a DNS name.
+       n, err := f.Read(buf[0:])
+       if err != nil {
+               return "", err
+       }
+
+       if n > 0 && buf[n-1] == '\n' {
+               n--
+       }
+       return string(buf[0:n]), nil
+}
diff --git a/libgo/go/os/time.go b/libgo/go/os/time.go
new file mode 100644 (file)
index 0000000..380345f
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+
+// Time returns the current time, in whole seconds and
+// fractional nanoseconds, plus an Error if any. The current
+// time is thus 1e9*sec+nsec, in nanoseconds.  The zero of
+// time is the Unix epoch.
+func Time() (sec int64, nsec int64, err Error) {
+       var tv syscall.Timeval
+       if errno := syscall.Gettimeofday(&tv); errno != 0 {
+               return 0, 0, NewSyscallError("gettimeofday", errno)
+       }
+       return int64(tv.Sec), int64(tv.Usec) * 1000, err
+}
diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go
new file mode 100644 (file)
index 0000000..79f6e9d
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+// An operating-system independent representation of Unix data structures.
+// OS-specific routines in this directory convert the OS-local versions to these.
+
+// Getpagesize returns the underlying system's memory page size.
+func Getpagesize() int { return syscall.Getpagesize() }
+
+// A FileInfo describes a file and is returned by Stat, Fstat, and Lstat
+type FileInfo struct {
+       Dev             uint64 // device number of file system holding file.
+       Ino             uint64 // inode number.
+       Nlink           uint64 // number of hard links.
+       Mode            uint32 // permission and mode bits.
+       Uid             int    // user id of owner.
+       Gid             int    // group id of owner.
+       Rdev            uint64 // device type for special file.
+       Size            int64  // length in bytes.
+       Blksize         int64  // size of blocks, in bytes.
+       Blocks          int64  // number of blocks allocated for file.
+       Atime_ns        int64  // access time; nanoseconds since epoch.
+       Mtime_ns        int64  // modified time; nanoseconds since epoch.
+       Ctime_ns        int64  // status change time; nanoseconds since epoch.
+       Name            string // name of file as presented to Open.
+       FollowedSymlink bool   // followed a symlink to get this information
+}
+
+// IsFifo reports whether the FileInfo describes a FIFO file.
+func (f *FileInfo) IsFifo() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFIFO }
+
+// IsChar reports whether the FileInfo describes a character special file.
+func (f *FileInfo) IsChar() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFCHR }
+
+// IsDirectory reports whether the FileInfo describes a directory.
+func (f *FileInfo) IsDirectory() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFDIR }
+
+// IsBlock reports whether the FileInfo describes a block special file.
+func (f *FileInfo) IsBlock() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFBLK }
+
+// IsRegular reports whether the FileInfo describes a regular file.
+func (f *FileInfo) IsRegular() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFREG }
+
+// IsSymlink reports whether the FileInfo describes a symbolic link.
+func (f *FileInfo) IsSymlink() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFLNK }
+
+// IsSocket reports whether the FileInfo describes a socket.
+func (f *FileInfo) IsSocket() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFSOCK }
+
+// Permission returns the file permission bits.
+func (f *FileInfo) Permission() uint32 { return f.Mode & 0777 }
diff --git a/libgo/go/patch/apply.go b/libgo/go/patch/apply.go
new file mode 100644 (file)
index 0000000..0dd9080
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package patch
+
+import "os"
+
+// An Op is a single operation to execute to apply a patch.
+type Op struct {
+       Verb Verb   // action
+       Src  string // source file
+       Dst  string // destination file
+       Mode int    // mode for destination (if non-zero)
+       Data []byte // data for destination (if non-nil)
+}
+
+// Apply applies the patch set to the files named in the patch set,
+// constructing an in-memory copy of the new file state.
+// It is the client's job to write the changes to the file system
+// if desired.
+//
+// The function readFile should return the contents of the named file.
+// Typically this function will be io.ReadFile.
+//
+func (set *Set) Apply(readFile func(string) ([]byte, os.Error)) ([]Op, os.Error) {
+       op := make([]Op, len(set.File))
+
+       for i, f := range set.File {
+               o := &op[i]
+               o.Verb = f.Verb
+               o.Src = f.Src
+               o.Dst = f.Dst
+               o.Mode = f.NewMode
+               if f.Diff != NoDiff || o.Verb != Edit {
+                       // Clients assume o.Data == nil means no data diff.
+                       // Start with a non-nil data.
+                       var old []byte = make([]byte, 0) // not nil
+                       var err os.Error
+                       if f.Src != "" {
+                               old, err = readFile(f.Src)
+                               if err != nil {
+                                       return nil, &os.PathError{string(f.Verb), f.Src, err}
+                               }
+                       }
+                       o.Data, err = f.Diff.Apply(old)
+                       if err != nil {
+                               return nil, &os.PathError{string(f.Verb), f.Src, err}
+                       }
+               }
+       }
+
+       return op, nil
+}
diff --git a/libgo/go/patch/git.go b/libgo/go/patch/git.go
new file mode 100644 (file)
index 0000000..6516097
--- /dev/null
@@ -0,0 +1,121 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package patch
+
+import (
+       "bytes"
+       "compress/zlib"
+       "crypto/sha1"
+       "encoding/git85"
+       "fmt"
+       "io"
+       "os"
+)
+
+func gitSHA1(data []byte) []byte {
+       if len(data) == 0 {
+               // special case: 0 length is all zeros sum
+               return make([]byte, 20)
+       }
+       h := sha1.New()
+       fmt.Fprintf(h, "blob %d\x00", len(data))
+       h.Write(data)
+       return h.Sum()
+}
+
+// BUG(rsc): The Git binary delta format is not implemented, only Git binary literals.
+
+// GitBinaryLiteral represents a Git binary literal diff.
+type GitBinaryLiteral struct {
+       OldSHA1 []byte // if non-empty, the SHA1 hash of the original
+       New     []byte // the new contents
+}
+
+// Apply implements the Diff interface's Apply method.
+func (d *GitBinaryLiteral) Apply(old []byte) ([]byte, os.Error) {
+       if sum := gitSHA1(old); !bytes.HasPrefix(sum, d.OldSHA1) {
+               return nil, ErrPatchFailure
+       }
+       return d.New, nil
+}
+
+func unhex(c byte) uint8 {
+       switch {
+       case '0' <= c && c <= '9':
+               return c - '0'
+       case 'a' <= c && c <= 'f':
+               return c - 'a' + 10
+       case 'A' <= c && c <= 'F':
+               return c - 'A' + 10
+       }
+       return 255
+}
+
+func getHex(s []byte) (data []byte, rest []byte) {
+       n := 0
+       for n < len(s) && unhex(s[n]) != 255 {
+               n++
+       }
+       n &^= 1 // Only take an even number of hex digits.
+       data = make([]byte, n/2)
+       for i := range data {
+               data[i] = unhex(s[2*i])<<4 | unhex(s[2*i+1])
+       }
+       rest = s[n:]
+       return
+}
+
+// ParseGitBinary parses raw as a Git binary patch.
+func ParseGitBinary(raw []byte) (Diff, os.Error) {
+       var oldSHA1, newSHA1 []byte
+       var sawBinary bool
+
+       for {
+               var first []byte
+               first, raw, _ = getLine(raw, 1)
+               first = bytes.TrimSpace(first)
+               if s, ok := skip(first, "index "); ok {
+                       oldSHA1, s = getHex(s)
+                       if s, ok = skip(s, ".."); !ok {
+                               continue
+                       }
+                       newSHA1, s = getHex(s)
+                       continue
+               }
+               if _, ok := skip(first, "GIT binary patch"); ok {
+                       sawBinary = true
+                       continue
+               }
+               if n, _, ok := atoi(first, "literal ", 10); ok && sawBinary {
+                       data := make([]byte, n)
+                       d := git85.NewDecoder(bytes.NewBuffer(raw))
+                       z, err := zlib.NewReader(d)
+                       if err != nil {
+                               return nil, err
+                       }
+                       defer z.Close()
+                       if _, err = io.ReadFull(z, data); err != nil {
+                               if err == os.EOF {
+                                       err = io.ErrUnexpectedEOF
+                               }
+                               return nil, err
+                       }
+                       var buf [1]byte
+                       m, err := z.Read(buf[0:])
+                       if m != 0 || err != os.EOF {
+                               return nil, os.NewError("Git binary literal longer than expected")
+                       }
+
+                       if sum := gitSHA1(data); !bytes.HasPrefix(sum, newSHA1) {
+                               return nil, os.NewError("Git binary literal SHA1 mismatch")
+                       }
+                       return &GitBinaryLiteral{oldSHA1, data}, nil
+               }
+               if !sawBinary {
+                       return nil, os.NewError("unexpected Git patch header: " + string(first))
+               }
+       }
+       panic("unreachable")
+}
diff --git a/libgo/go/patch/patch.go b/libgo/go/patch/patch.go
new file mode 100644 (file)
index 0000000..d4977dc
--- /dev/null
@@ -0,0 +1,322 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package patch implements parsing and execution of the textual and
+// binary patch descriptions used by version control tools such as
+// CVS, Git, Mercurial, and Subversion.
+package patch
+
+import (
+       "bytes"
+       "os"
+       "path"
+       "strings"
+)
+
+// A Set represents a set of patches to be applied as a single atomic unit.
+// Patch sets are often preceded by a descriptive header.
+type Set struct {
+       Header string // free-form text
+       File   []*File
+}
+
+// A File represents a collection of changes to be made to a single file.
+type File struct {
+       Verb             Verb
+       Src              string // source for Verb == Copy, Verb == Rename
+       Dst              string
+       OldMode, NewMode int // 0 indicates not used
+       Diff                 // changes to data; == NoDiff if operation does not edit file
+}
+
+// A Verb is an action performed on a file.
+type Verb string
+
+const (
+       Add    Verb = "add"
+       Copy   Verb = "copy"
+       Delete Verb = "delete"
+       Edit   Verb = "edit"
+       Rename Verb = "rename"
+)
+
+// A Diff is any object that describes changes to transform
+// an old byte stream to a new one.
+type Diff interface {
+       // Apply applies the changes listed in the diff
+       // to the string s, returning the new version of the string.
+       // Note that the string s need not be a text string.
+       Apply(old []byte) (new []byte, err os.Error)
+}
+
+// NoDiff is a no-op Diff implementation: it passes the
+// old data through unchanged.
+var NoDiff Diff = noDiffType(0)
+
+type noDiffType int
+
+func (noDiffType) Apply(old []byte) ([]byte, os.Error) {
+       return old, nil
+}
+
+// A SyntaxError represents a syntax error encountered while parsing a patch.
+type SyntaxError string
+
+func (e SyntaxError) String() string { return string(e) }
+
+var newline = []byte{'\n'}
+
+// Parse patches the patch text to create a patch Set.
+// The patch text typically comprises a textual header and a sequence
+// of file patches, as would be generated by CVS, Subversion,
+// Mercurial, or Git.
+func Parse(text []byte) (*Set, os.Error) {
+       // Split text into files.
+       // CVS and Subversion begin new files with
+       //      Index: file name.
+       //      ==================
+       //      diff -u blah blah
+       //
+       // Mercurial and Git use
+       //      diff [--git] a/file/path b/file/path.
+       //
+       // First look for Index: lines.  If none, fall back on diff lines.
+       text, files := sections(text, "Index: ")
+       if len(files) == 0 {
+               text, files = sections(text, "diff ")
+       }
+
+       set := &Set{string(text), make([]*File, len(files))}
+
+       // Parse file header and then
+       // parse files into patch chunks.
+       // Each chunk begins with @@.
+       for i, raw := range files {
+               p := new(File)
+               set.File[i] = p
+
+               // First line of hdr is the Index: that
+               // begins the section.  After that is the file name.
+               s, raw, _ := getLine(raw, 1)
+               if hasPrefix(s, "Index: ") {
+                       p.Dst = string(bytes.TrimSpace(s[7:]))
+                       goto HaveName
+               } else if hasPrefix(s, "diff ") {
+                       str := string(bytes.TrimSpace(s))
+                       i := strings.LastIndex(str, " b/")
+                       if i >= 0 {
+                               p.Dst = str[i+3:]
+                               goto HaveName
+                       }
+               }
+               return nil, SyntaxError("unexpected patch header line: " + string(s))
+       HaveName:
+               p.Dst = path.Clean(p.Dst)
+               if strings.HasPrefix(p.Dst, "../") || strings.HasPrefix(p.Dst, "/") {
+                       return nil, SyntaxError("invalid path: " + p.Dst)
+               }
+
+               // Parse header lines giving file information:
+               //      new file mode %o        - file created
+               //      deleted file mode %o    - file deleted
+               //      old file mode %o        - file mode changed
+               //      new file mode %o        - file mode changed
+               //      rename from %s  - file renamed from other file
+               //      rename to %s
+               //      copy from %s            - file copied from other file
+               //      copy to %s
+               p.Verb = Edit
+               for len(raw) > 0 {
+                       oldraw := raw
+                       var l []byte
+                       l, raw, _ = getLine(raw, 1)
+                       l = bytes.TrimSpace(l)
+                       if m, s, ok := atoi(l, "new file mode ", 8); ok && len(s) == 0 {
+                               p.NewMode = m
+                               p.Verb = Add
+                               continue
+                       }
+                       if m, s, ok := atoi(l, "deleted file mode ", 8); ok && len(s) == 0 {
+                               p.OldMode = m
+                               p.Verb = Delete
+                               p.Src = p.Dst
+                               p.Dst = ""
+                               continue
+                       }
+                       if m, s, ok := atoi(l, "old file mode ", 8); ok && len(s) == 0 {
+                               // usually implies p.Verb = "rename" or "copy"
+                               // but we'll get that from the rename or copy line.
+                               p.OldMode = m
+                               continue
+                       }
+                       if m, s, ok := atoi(l, "old mode ", 8); ok && len(s) == 0 {
+                               p.OldMode = m
+                               continue
+                       }
+                       if m, s, ok := atoi(l, "new mode ", 8); ok && len(s) == 0 {
+                               p.NewMode = m
+                               continue
+                       }
+                       if s, ok := skip(l, "rename from "); ok && len(s) > 0 {
+                               p.Src = string(s)
+                               p.Verb = Rename
+                               continue
+                       }
+                       if s, ok := skip(l, "rename to "); ok && len(s) > 0 {
+                               p.Verb = Rename
+                               continue
+                       }
+                       if s, ok := skip(l, "copy from "); ok && len(s) > 0 {
+                               p.Src = string(s)
+                               p.Verb = Copy
+                               continue
+                       }
+                       if s, ok := skip(l, "copy to "); ok && len(s) > 0 {
+                               p.Verb = Copy
+                               continue
+                       }
+                       if s, ok := skip(l, "Binary file "); ok && len(s) > 0 {
+                               // Hg prints
+                               //      Binary file foo has changed
+                               // when deleting a binary file.
+                               continue
+                       }
+                       if s, ok := skip(l, "RCS file: "); ok && len(s) > 0 {
+                               // CVS prints
+                               //      RCS file: /cvs/plan9/bin/yesterday,v
+                               //      retrieving revision 1.1
+                               // for each file.
+                               continue
+                       }
+                       if s, ok := skip(l, "retrieving revision "); ok && len(s) > 0 {
+                               // CVS prints
+                               //      RCS file: /cvs/plan9/bin/yesterday,v
+                               //      retrieving revision 1.1
+                               // for each file.
+                               continue
+                       }
+                       if hasPrefix(l, "===") || hasPrefix(l, "---") || hasPrefix(l, "+++") || hasPrefix(l, "diff ") {
+                               continue
+                       }
+                       if hasPrefix(l, "@@ -") {
+                               diff, err := ParseTextDiff(oldraw)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               p.Diff = diff
+                               break
+                       }
+                       if hasPrefix(l, "GIT binary patch") || (hasPrefix(l, "index ") && !hasPrefix(raw, "--- ")) {
+                               diff, err := ParseGitBinary(oldraw)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               p.Diff = diff
+                               break
+                       }
+                       if hasPrefix(l, "index ") {
+                               continue
+                       }
+                       return nil, SyntaxError("unexpected patch header line: " + string(l))
+               }
+               if p.Diff == nil {
+                       p.Diff = NoDiff
+               }
+               if p.Verb == Edit {
+                       p.Src = p.Dst
+               }
+       }
+
+       return set, nil
+}
+
+// getLine returns the first n lines of data and the remainder.
+// If data has no newline, getLine returns data, nil, false
+func getLine(data []byte, n int) (first []byte, rest []byte, ok bool) {
+       rest = data
+       ok = true
+       for ; n > 0; n-- {
+               nl := bytes.Index(rest, newline)
+               if nl < 0 {
+                       rest = nil
+                       ok = false
+                       break
+               }
+               rest = rest[nl+1:]
+       }
+       first = data[0 : len(data)-len(rest)]
+       return
+}
+
+// sections returns a collection of file sections,
+// each of which begins with a line satisfying prefix.
+// text before the first instance of such a line is
+// returned separately.
+func sections(text []byte, prefix string) ([]byte, [][]byte) {
+       n := 0
+       for b := text; ; {
+               if hasPrefix(b, prefix) {
+                       n++
+               }
+               nl := bytes.Index(b, newline)
+               if nl < 0 {
+                       break
+               }
+               b = b[nl+1:]
+       }
+
+       sect := make([][]byte, n+1)
+       n = 0
+       for b := text; ; {
+               if hasPrefix(b, prefix) {
+                       sect[n] = text[0 : len(text)-len(b)]
+                       n++
+                       text = b
+               }
+               nl := bytes.Index(b, newline)
+               if nl < 0 {
+                       sect[n] = text
+                       break
+               }
+               b = b[nl+1:]
+       }
+       return sect[0], sect[1:]
+}
+
+// if s begins with the prefix t, skip returns
+// s with that prefix removed and ok == true.
+func skip(s []byte, t string) (ss []byte, ok bool) {
+       if len(s) < len(t) || string(s[0:len(t)]) != t {
+               return nil, false
+       }
+       return s[len(t):], true
+}
+
+// if s begins with the prefix t and then is a sequence
+// of digits in the given base, atoi returns the number
+// represented by the digits and s with the
+// prefix and the digits removed.
+func atoi(s []byte, t string, base int) (n int, ss []byte, ok bool) {
+       if s, ok = skip(s, t); !ok {
+               return
+       }
+       var i int
+       for i = 0; i < len(s) && '0' <= s[i] && s[i] <= byte('0'+base-1); i++ {
+               n = n*base + int(s[i]-'0')
+       }
+       if i == 0 {
+               return
+       }
+       return n, s[i:], true
+}
+
+// hasPrefix returns true if s begins with t.
+func hasPrefix(s []byte, t string) bool {
+       _, ok := skip(s, t)
+       return ok
+}
+
+// splitLines returns the result of splitting s into lines.
+// The \n on each line is preserved.
+func splitLines(s []byte) [][]byte { return bytes.SplitAfter(s, newline, -1) }
diff --git a/libgo/go/patch/patch_test.go b/libgo/go/patch/patch_test.go
new file mode 100644 (file)
index 0000000..0a4aef7
--- /dev/null
@@ -0,0 +1,390 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package patch
+
+// TODO(rsc): test Apply
+
+import "testing"
+
+type Test struct {
+       in   string
+       out  string
+       diff string
+}
+
+func TestFileApply(t *testing.T) {
+       for i, test := range tests {
+               set, err := Parse([]byte(test.diff))
+               if err != nil {
+                       t.Errorf("#%d: Parse: %s", i, err)
+                       continue
+               }
+               if len(set.File) != 1 {
+                       t.Errorf("#%d: Parse returned %d patches, want 1", i, len(set.File))
+                       continue
+               }
+               new, err := set.File[0].Apply([]byte(test.in))
+               if err != nil {
+                       t.Errorf("#%d: Apply: %s", i, err)
+                       continue
+               }
+               if s := string(new); s != test.out {
+                       t.Errorf("#%d:\n--- have\n%s--- want\n%s", i, s, test.out)
+               }
+       }
+}
+
+var tests = []Test{
+       {
+               "hello, world\n",
+               "goodbye, world\n",
+               "Index: a\n" +
+                       "--- a/a\n" +
+                       "+++ b/b\n" +
+                       "@@ -1 +1 @@\n" +
+                       "-hello, world\n" +
+                       "+goodbye, world\n",
+       },
+       {
+               "hello, world\n",
+               "goodbye, world\n",
+               "Index: a\n" +
+                       "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f\n" +
+                       "--- a/a\n" +
+                       "+++ b/b\n" +
+                       "@@ -1 +1 @@\n" +
+                       "-hello, world\n" +
+                       "+goodbye, world\n",
+       },
+       {
+               "hello, world\n",
+               "goodbye, world\n",
+               "diff a/a b/b\n" +
+                       "--- a/a\n" +
+                       "+++ b/b\n" +
+                       "@@ -1,1 +1,1 @@\n" +
+                       "-hello, world\n" +
+                       "+goodbye, world\n",
+       },
+       {
+               "hello, world",
+               "goodbye, world\n",
+               "diff --git a/a b/b\n" +
+                       "--- a/a\n" +
+                       "+++ b/b\n" +
+                       "@@ -1 +1 @@\n" +
+                       "-hello, world\n" +
+                       "\\ No newline at end of file\n" +
+                       "+goodbye, world\n",
+       },
+       {
+               "hello, world\n",
+               "goodbye, world",
+               "Index: a\n" +
+                       "--- a/a\n" +
+                       "+++ b/b\n" +
+                       "@@ -1 +1 @@\n" +
+                       "-hello, world\n" +
+                       "+goodbye, world\n" +
+                       "\\ No newline at end of file\n",
+       },
+       {
+               "hello, world",
+               "goodbye, world",
+               "Index: a\n" +
+                       "--- a/a\n" +
+                       "+++ b/b\n" +
+                       "@@ -1 +1 @@\n" +
+                       "-hello, world\n" +
+                       "\\ No newline at end of file\n" +
+                       "+goodbye, world\n" +
+                       "\\ No newline at end of file\n",
+       },
+       {
+               "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\n",
+               "a\nB\nC\nD\ne\nf\ng\nj\nk\nl\nm\nN\n",
+               "Index: a\n" +
+                       "--- a/a\n" +
+                       "+++ b/b\n" +
+                       "@@ -1,14 +1,12 @@\n" +
+                       " a\n" +
+                       "-b\n" +
+                       "-c\n" +
+                       "-d\n" +
+                       "+B\n" +
+                       "+C\n" +
+                       "+D\n" +
+                       " e\n" +
+                       " f\n" +
+                       " g\n" +
+                       "-h\n" +
+                       "-i\n" +
+                       " j\n" +
+                       " k\n" +
+                       " l\n" +
+                       " m\n" +
+                       "-n\n" +
+                       "+N\n",
+       },
+       {
+               "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+               "a\nb\nc\ng\nh\ni\nj\nk\nl\nm\nN\nO\np\nq\nr\ns\nt\nu\nv\nw\nd\ne\nf\nx\n",
+               "Index: a\n" +
+                       "--- a/a\n" +
+                       "+++ b/b\n" +
+                       "@@ -1,9 +1,6 @@\n" +
+                       " a\n" +
+                       " b\n" +
+                       " c\n" +
+                       "-d\n" +
+                       "-e\n" +
+                       "-f\n" +
+                       " g\n" +
+                       " h\n" +
+                       " i\n" +
+                       "@@ -11,8 +8,8 @@ j\n" +
+                       " k\n" +
+                       " l\n" +
+                       " m\n" +
+                       "-n\n" +
+                       "-o\n" +
+                       "+N\n" +
+                       "+O\n" +
+                       " p\n" +
+                       " q\n" +
+                       " r\n" +
+                       "\n" +
+                       "@@ -21,6 +18,7 @@ t\n" +
+                       " u\n" +
+                       " v\n" +
+                       " w\n" +
+                       "+d\n" +
+                       "+e\n" +
+                       "+f\n" +
+                       " x\n" +
+                       "-y\n" +
+                       "-z\n",
+       },
+       {
+               "a\nb\nc\ng\nh\ni\nj\nk\nl\nm\nN\nO\np\nq\nr\ns\nt\nu\nv\nw\nd\ne\nf\nx\n",
+               "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+               "Index: a\n" +
+                       "--- a/b\n" +
+                       "+++ b/a\n" +
+                       "@@ -1,6 +1,9 @@\n" +
+                       " a\n" +
+                       " b\n" +
+                       " c\n" +
+                       "+d\n" +
+                       "+e\n" +
+                       "+f\n" +
+                       " g\n" +
+                       " h\n" +
+                       " i\n" +
+                       "@@ -8,8 +11,8 @@ j\n" +
+                       " k\n" +
+                       " l\n" +
+                       " m\n" +
+                       "-N\n" +
+                       "-O\n" +
+                       "+n\n" +
+                       "+o\n" +
+                       " p\n" +
+                       " q\n" +
+                       " r\n" +
+                       "@@ -18,7 +21,6 @@ t\n" +
+                       " u\n" +
+                       " v\n" +
+                       " w\n" +
+                       "-d\n" +
+                       "-e\n" +
+                       "-f\n" +
+                       " x\n" +
+                       "+y\n" +
+                       "+z\n",
+       },
+       {
+               "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+               "",
+               "Index: a\n" +
+                       "deleted file mode 100644\n" +
+                       "--- a/a\n" +
+                       "+++ /dev/null\n" +
+                       "@@ -1,26 +0,0 @@\n" +
+                       "-a\n" +
+                       "-b\n" +
+                       "-c\n" +
+                       "-d\n" +
+                       "-e\n" +
+                       "-f\n" +
+                       "-g\n" +
+                       "-h\n" +
+                       "-i\n" +
+                       "-j\n" +
+                       "-k\n" +
+                       "-l\n" +
+                       "-m\n" +
+                       "-n\n" +
+                       "-o\n" +
+                       "-p\n" +
+                       "-q\n" +
+                       "-r\n" +
+                       "-s\n" +
+                       "-t\n" +
+                       "-u\n" +
+                       "-v\n" +
+                       "-w\n" +
+                       "-x\n" +
+                       "-y\n" +
+                       "-z\n",
+       },
+       {
+               "",
+               "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+               "Index: a\n" +
+                       "new file mode 100644\n" +
+                       "--- /dev/null\n" +
+                       "+++ b/a\n" +
+                       "@@ -0,0 +1,26 @@\n" +
+                       "+a\n" +
+                       "+b\n" +
+                       "+c\n" +
+                       "+d\n" +
+                       "+e\n" +
+                       "+f\n" +
+                       "+g\n" +
+                       "+h\n" +
+                       "+i\n" +
+                       "+j\n" +
+                       "+k\n" +
+                       "+l\n" +
+                       "+m\n" +
+                       "+n\n" +
+                       "+o\n" +
+                       "+p\n" +
+                       "+q\n" +
+                       "+r\n" +
+                       "+s\n" +
+                       "+t\n" +
+                       "+u\n" +
+                       "+v\n" +
+                       "+w\n" +
+                       "+x\n" +
+                       "+y\n" +
+                       "+z\n",
+       },
+       {
+               "\xc2\xd8\xf9\x63\x8c\xf7\xc6\x9b\xb0\x3c\x39\xfa\x08\x8e\x42\x8f" +
+                       "\x1c\x7c\xaf\x54\x22\x87\xc3\xc5\x68\x9b\xe1\xbd\xbc\xc3\xe0\xda" +
+                       "\xcc\xe3\x96\xda\xc2\xaf\xbb\x75\x79\x64\x86\x60\x8a\x43\x9e\x07" +
+                       "\x9c\xaa\x92\x88\xd4\x30\xb9\x8b\x95\x04\x60\x71\xc7\xbb\x2d\x93" +
+                       "\x66\x73\x01\x24\xf3\x63\xbf\xe6\x1d\x38\x15\x56\x98\xc4\x1f\x85" +
+                       "\xc3\x60\x39\x3a\x0d\x57\x53\x0c\x29\x3f\xbb\x44\x7e\x56\x56\x9d" +
+                       "\x87\xcf\xf6\x88\xe8\x98\x05\x85\xf8\xfe\x44\x21\xfa\x33\xc9\xa4" +
+                       "\x22\xbe\x89\x05\x8b\x82\x76\xc9\x7c\xaf\x48\x28\xc4\x86\x15\x89" +
+                       "\xb9\x98\xfa\x41\xfc\x3d\x8d\x80\x29\x33\x17\x45\xa5\x7f\x67\x79" +
+                       "\x7f\x92\x3b\x2e\x4c\xc1\xd2\x1b\x9e\xcf\xed\x53\x56\xb2\x49\x58" +
+                       "\xd8\xe9\x9f\x98\xa3\xfe\x78\xe1\xe8\x74\x71\x04\x1a\x87\xd9\x68" +
+                       "\x18\x68\xd0\xae\x7b\xa4\x25\xe3\x06\x03\x7e\x8b\xd3\x50\x1f\xb1" +
+                       "\x67\x08\xe3\x93\xf4\x4f\xa1\xfb\x31\xcf\x99\x5a\x43\x9f\x4b\xc4" +
+                       "\xaa\x68\x1a\xf9\x8e\x97\x02\x80\x17\xf1\x25\x21\xdf\x94\xbf\x41" +
+                       "\x08\x59\x3d\xea\x36\x23\x03\xb5\x62\x4d\xb6\x8f\x9e\xdf\x1f\x03" +
+                       "\x7d\x70\xe0\x6f\x46\x08\x96\x79\x72\xb7\xae\x41\x2b\xbd\x2a\x95",
+
+               "\x8e\x5f\xf8\x79\x36\x8d\xbe\x68\xc4\x2c\x78\x8a\x46\x28\x40\x3e" +
+                       "\xcf\x3b\xb9\x14\xaf\xfa\x04\x9e\x4b\xa2\x52\x51\x51\xf0\xad\xd3" +
+                       "\x03\x1c\x03\x79\x5f\x53\xc7\x1a\xd5\x28\xe2\xd9\x19\x37\xa4\xfa" +
+                       "\xdd\xff\xac\xb5\xa9\x42\x4e\x17\xeb\xb4\x0d\x20\x67\x08\x43\x21" +
+                       "\x7d\x12\x27\xfa\x96\x7a\x85\xf8\x04\x5f\xf4\xfe\xda\x9f\x66\xf2" +
+                       "\xba\x04\x39\x00\xab\x3f\x23\x20\x84\x53\xb4\x88\xb6\xee\xa2\x9e" +
+                       "\xc1\xca\xd4\x09\x2a\x27\x89\x2f\xcb\xba\xa6\x41\xb6\xe9\xc5\x08" +
+                       "\xff\xf5\x95\x35\xab\xbb\x5c\x62\x96\xe7\x7c\x8f\xf2\x40\x12\xc9" +
+                       "\x2d\xfe\xff\x75\x4f\x70\x47\xc9\xcd\x15\x0a\x1c\x23\xe7\x0f\x15" +
+                       "\x95\x75\x30\x8f\x6e\x9f\x7e\xa5\x9d\xd1\x65\x1c\x4d\x4e\xf4\x32" +
+                       "\x49\x9b\xa1\x30\x44\x62\x6f\xe2\xe6\x69\x09\xf8\x7c\x7c\xbe\x07" +
+                       "\xa9\xb6\x14\x7a\x6b\x85\xe4\xbf\x48\xbe\x5b\x3b\x70\xb3\x79\x3b" +
+                       "\xc4\x35\x9d\x86\xf1\xfe\x2b\x6f\x80\x74\x50\xf3\x96\x59\x53\x1a" +
+                       "\x75\x46\x9d\x57\x72\xb3\xb1\x26\xf5\x81\xcd\x96\x08\xbc\x2b\x10" +
+                       "\xdc\x80\xbd\xd0\xdf\x03\x6d\x8d\xec\x30\x2b\x4c\xdb\x4d\x3b\xef" +
+                       "\x7d\x3a\x39\xc8\x5a\xc4\xcc\x24\x37\xde\xe2\x95\x2b\x04\x97\xb0",
+
+               // From git diff --binary
+               "Index: a\n" +
+                       "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f 100644\n" +
+                       "GIT binary patch\n" +
+                       "literal 256\n" +
+                       "zcmV+b0ssDvU-)@8jlO8aEO?4WC_p~XJGm6E`UIX!qEb;&@U7DW90Pe@Q^y+BDB{@}\n" +
+                       "zH>CRA|E#sCLQWU!v<)C<2ty%#5-0kWdWHA|U-bUkpJwv91UUe!KO-Q7Q?!V-?xLQ-\n" +
+                       "z%G3!eCy6i1x~4(4>BR{D^_4ZNyIf+H=X{UyKoZF<{{MAPa7W3_6$%_9=MNQ?buf=^\n" +
+                       "zpMIsC(PbP>PV_QKo1rj7VsGN+X$kmze7*;%wiJ46h2+0TzFRwRvw1tjHJyg>{wr^Q\n" +
+                       "zbWrn_SyLKyMx9r3v#}=ifz6f(yekmgfW6S)18t4$Fe^;kO*`*>IyuN%#LOf&-r|)j\n" +
+                       "G1edVN^?m&S\n" +
+                       "\n" +
+                       "literal 256\n" +
+                       "zcmV+b0ssEO*!g3O_r{yBJURLZjzW(de6Lg@hr`8ao8i5@!{FM?<CfaOue)`5WQJgh\n" +
+                       "zL!Jkms*;G*Fu9AB1YmK;yDgJua{(mtW54DdI2Bfy#2<yjU^zMsS5pirKf6SJR#u&d\n" +
+                       "z&-RGum<5IS{zM`AGs&bPzKI2kf_BM#uSh7wh82mqnEFBdJ&k}VGZ#gre`k4rk~=O;\n" +
+                       "z!O|O^&+SuIvPoFj>7SUR{&?Z&ba4b4huLTtXwa^Eq$T491AdFsP#>{p2;-CVPoeuU\n" +
+                       "z&zV|7pG(B5Xd3yBmjZwn@g*VOl)pg;Sv~4DBLlT!O}3Ao-yZ{gaNuu72$p$rx2{1e\n" +
+                       "Gy(*Pb;D3Ms\n" +
+                       "\n",
+       },
+       {
+               "\xc2\xd8\xf9\x63\x8c\xf7\xc6\x9b\xb0\x3c\x39\xfa\x08\x8e\x42\x8f" +
+                       "\x1c\x7c\xaf\x54\x22\x87\xc3\xc5\x68\x9b\xe1\xbd\xbc\xc3\xe0\xda" +
+                       "\xcc\xe3\x96\xda\xc2\xaf\xbb\x75\x79\x64\x86\x60\x8a\x43\x9e\x07" +
+                       "\x9c\xaa\x92\x88\xd4\x30\xb9\x8b\x95\x04\x60\x71\xc7\xbb\x2d\x93" +
+                       "\x66\x73\x01\x24\xf3\x63\xbf\xe6\x1d\x38\x15\x56\x98\xc4\x1f\x85" +
+                       "\xc3\x60\x39\x3a\x0d\x57\x53\x0c\x29\x3f\xbb\x44\x7e\x56\x56\x9d" +
+                       "\x87\xcf\xf6\x88\xe8\x98\x05\x85\xf8\xfe\x44\x21\xfa\x33\xc9\xa4" +
+                       "\x22\xbe\x89\x05\x8b\x82\x76\xc9\x7c\xaf\x48\x28\xc4\x86\x15\x89" +
+                       "\xb9\x98\xfa\x41\xfc\x3d\x8d\x80\x29\x33\x17\x45\xa5\x7f\x67\x79" +
+                       "\x7f\x92\x3b\x2e\x4c\xc1\xd2\x1b\x9e\xcf\xed\x53\x56\xb2\x49\x58" +
+                       "\xd8\xe9\x9f\x98\xa3\xfe\x78\xe1\xe8\x74\x71\x04\x1a\x87\xd9\x68" +
+                       "\x18\x68\xd0\xae\x7b\xa4\x25\xe3\x06\x03\x7e\x8b\xd3\x50\x1f\xb1" +
+                       "\x67\x08\xe3\x93\xf4\x4f\xa1\xfb\x31\xcf\x99\x5a\x43\x9f\x4b\xc4" +
+                       "\xaa\x68\x1a\xf9\x8e\x97\x02\x80\x17\xf1\x25\x21\xdf\x94\xbf\x41" +
+                       "\x08\x59\x3d\xea\x36\x23\x03\xb5\x62\x4d\xb6\x8f\x9e\xdf\x1f\x03" +
+                       "\x7d\x70\xe0\x6f\x46\x08\x96\x79\x72\xb7\xae\x41\x2b\xbd\x2a\x95",
+
+               "\x8e\x5f\xf8\x79\x36\x8d\xbe\x68\xc4\x2c\x78\x8a\x46\x28\x40\x3e" +
+                       "\xcf\x3b\xb9\x14\xaf\xfa\x04\x9e\x4b\xa2\x52\x51\x51\xf0\xad\xd3" +
+                       "\x03\x1c\x03\x79\x5f\x53\xc7\x1a\xd5\x28\xe2\xd9\x19\x37\xa4\xfa" +
+                       "\xdd\xff\xac\xb5\xa9\x42\x4e\x17\xeb\xb4\x0d\x20\x67\x08\x43\x21" +
+                       "\x7d\x12\x27\xfa\x96\x7a\x85\xf8\x04\x5f\xf4\xfe\xda\x9f\x66\xf2" +
+                       "\xba\x04\x39\x00\xab\x3f\x23\x20\x84\x53\xb4\x88\xb6\xee\xa2\x9e" +
+                       "\xc1\xca\xd4\x09\x2a\x27\x89\x2f\xcb\xba\xa6\x41\xb6\xe9\xc5\x08" +
+                       "\xff\xf5\x95\x35\xab\xbb\x5c\x62\x96\xe7\x7c\x8f\xf2\x40\x12\xc9" +
+                       "\x2d\xfe\xff\x75\x4f\x70\x47\xc9\xcd\x15\x0a\x1c\x23\xe7\x0f\x15" +
+                       "\x95\x75\x30\x8f\x6e\x9f\x7e\xa5\x9d\xd1\x65\x1c\x4d\x4e\xf4\x32" +
+                       "\x49\x9b\xa1\x30\x44\x62\x6f\xe2\xe6\x69\x09\xf8\x7c\x7c\xbe\x07" +
+                       "\xa9\xb6\x14\x7a\x6b\x85\xe4\xbf\x48\xbe\x5b\x3b\x70\xb3\x79\x3b" +
+                       "\xc4\x35\x9d\x86\xf1\xfe\x2b\x6f\x80\x74\x50\xf3\x96\x59\x53\x1a" +
+                       "\x75\x46\x9d\x57\x72\xb3\xb1\x26\xf5\x81\xcd\x96\x08\xbc\x2b\x10" +
+                       "\xdc\x80\xbd\xd0\xdf\x03\x6d\x8d\xec\x30\x2b\x4c\xdb\x4d\x3b\xef" +
+                       "\x7d\x3a\x39\xc8\x5a\xc4\xcc\x24\x37\xde\xe2\x95\x2b\x04\x97\xb0",
+
+               // From hg diff --git
+               "Index: a\n" +
+                       "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f\n" +
+                       "GIT binary patch\n" +
+                       "literal 256\n" +
+                       "zc$@(M0ssDvU-)@8jlO8aEO?4WC_p~XJGm6E`UIX!qEb;&@U7DW90Pe@Q^y+BDB{@}\n" +
+                       "zH>CRA|E#sCLQWU!v<)C<2ty%#5-0kWdWHA|U-bUkpJwv91UUe!KO-Q7Q?!V-?xLQ-\n" +
+                       "z%G3!eCy6i1x~4(4>BR{D^_4ZNyIf+H=X{UyKoZF<{{MAPa7W3_6$%_9=MNQ?buf=^\n" +
+                       "zpMIsC(PbP>PV_QKo1rj7VsGN+X$kmze7*;%wiJ46h2+0TzFRwRvw1tjHJyg>{wr^Q\n" +
+                       "zbWrn_SyLKyMx9r3v#}=ifz6f(yekmgfW6S)18t4$Fe^;kO*`*>IyuN%#LOf&-r|)j\n" +
+                       "G1edVN^?m&S\n" +
+                       "\n",
+       },
+       {
+               "",
+               "",
+               "Index: hello\n" +
+                       "===================================================================\n" +
+                       "old mode 100644\n" +
+                       "new mode 100755\n",
+       },
+}
diff --git a/libgo/go/patch/textdiff.go b/libgo/go/patch/textdiff.go
new file mode 100644 (file)
index 0000000..c7e693f
--- /dev/null
@@ -0,0 +1,171 @@
+package patch
+
+import (
+       "bytes"
+       "os"
+)
+
+type TextDiff []TextChunk
+
+// A TextChunk specifies an edit to a section of a file:
+// the text beginning at Line, which should be exactly Old,
+// is to be replaced with New.
+type TextChunk struct {
+       Line int
+       Old  []byte
+       New  []byte
+}
+
+func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
+       // Copy raw so it is safe to keep references to slices.
+       _, chunks := sections(raw, "@@ -")
+       delta := 0
+       diff := make(TextDiff, len(chunks))
+       for i, raw := range chunks {
+               c := &diff[i]
+
+               // Parse start line: @@ -oldLine,oldCount +newLine,newCount @@ junk
+               chunk := splitLines(raw)
+               chunkHeader := chunk[0]
+               var ok bool
+               var oldLine, oldCount, newLine, newCount int
+               s := chunkHeader
+               if oldLine, s, ok = atoi(s, "@@ -", 10); !ok {
+               ErrChunkHdr:
+                       return nil, SyntaxError("unexpected chunk header line: " + string(chunkHeader))
+               }
+               if len(s) == 0 || s[0] != ',' {
+                       oldCount = 1
+               } else if oldCount, s, ok = atoi(s, ",", 10); !ok {
+                       goto ErrChunkHdr
+               }
+               if newLine, s, ok = atoi(s, " +", 10); !ok {
+                       goto ErrChunkHdr
+               }
+               if len(s) == 0 || s[0] != ',' {
+                       newCount = 1
+               } else if newCount, s, ok = atoi(s, ",", 10); !ok {
+                       goto ErrChunkHdr
+               }
+               if !hasPrefix(s, " @@") {
+                       goto ErrChunkHdr
+               }
+
+               // Special case: for created or deleted files, the empty half
+               // is given as starting at line 0.  Translate to line 1.
+               if oldCount == 0 && oldLine == 0 {
+                       oldLine = 1
+               }
+               if newCount == 0 && newLine == 0 {
+                       newLine = 1
+               }
+
+               // Count lines in text
+               var dropOldNL, dropNewNL bool
+               var nold, nnew int
+               var lastch byte
+               chunk = chunk[1:]
+               for _, l := range chunk {
+                       if nold == oldCount && nnew == newCount && (len(l) == 0 || l[0] != '\\') {
+                               if len(bytes.TrimSpace(l)) != 0 {
+                                       return nil, SyntaxError("too many chunk lines")
+                               }
+                               continue
+                       }
+                       if len(l) == 0 {
+                               return nil, SyntaxError("empty chunk line")
+                       }
+                       switch l[0] {
+                       case '+':
+                               nnew++
+                       case '-':
+                               nold++
+                       case ' ':
+                               nnew++
+                               nold++
+                       case '\\':
+                               if _, ok := skip(l, "\\ No newline at end of file"); ok {
+                                       switch lastch {
+                                       case '-':
+                                               dropOldNL = true
+                                       case '+':
+                                               dropNewNL = true
+                                       case ' ':
+                                               dropOldNL = true
+                                               dropNewNL = true
+                                       default:
+                                               return nil, SyntaxError("message `\\ No newline at end of file' out of context")
+                                       }
+                                       break
+                               }
+                               fallthrough
+                       default:
+                               return nil, SyntaxError("unexpected chunk line: " + string(l))
+                       }
+                       lastch = l[0]
+               }
+
+               // Does it match the header?
+               if nold != oldCount || nnew != newCount {
+                       return nil, SyntaxError("chunk header does not match line count: " + string(chunkHeader))
+               }
+               if oldLine+delta != newLine {
+                       return nil, SyntaxError("chunk delta is out of sync with previous chunks")
+               }
+               delta += nnew - nold
+               c.Line = oldLine
+
+               var old, new bytes.Buffer
+               nold = 0
+               nnew = 0
+               for _, l := range chunk {
+                       if nold == oldCount && nnew == newCount {
+                               break
+                       }
+                       ch, l := l[0], l[1:]
+                       if ch == '\\' {
+                               continue
+                       }
+                       if ch != '+' {
+                               old.Write(l)
+                               nold++
+                       }
+                       if ch != '-' {
+                               new.Write(l)
+                               nnew++
+                       }
+               }
+               c.Old = old.Bytes()
+               c.New = new.Bytes()
+               if dropOldNL {
+                       c.Old = c.Old[0 : len(c.Old)-1]
+               }
+               if dropNewNL {
+                       c.New = c.New[0 : len(c.New)-1]
+               }
+       }
+       return diff, nil
+}
+
+var ErrPatchFailure = os.NewError("patch did not apply cleanly")
+
+// Apply applies the changes listed in the diff
+// to the data, returning the new version.
+func (d TextDiff) Apply(data []byte) ([]byte, os.Error) {
+       var buf bytes.Buffer
+       line := 1
+       for _, c := range d {
+               var ok bool
+               var prefix []byte
+               prefix, data, ok = getLine(data, c.Line-line)
+               if !ok || !bytes.HasPrefix(data, c.Old) {
+                       return nil, ErrPatchFailure
+               }
+               buf.Write(prefix)
+               data = data[len(c.Old):]
+               buf.Write(c.New)
+               line = c.Line + bytes.Count(c.Old, newline)
+       }
+       buf.Write(data)
+       return buf.Bytes(), nil
+}
diff --git a/libgo/go/path/match.go b/libgo/go/path/match.go
new file mode 100644 (file)
index 0000000..d5cd19f
--- /dev/null
@@ -0,0 +1,274 @@
+package path
+
+import (
+       "os"
+       "sort"
+       "strings"
+       "utf8"
+)
+
+var ErrBadPattern = os.NewError("syntax error in pattern")
+
+// Match returns true if name matches the shell file name pattern.
+// The syntax used by pattern is:
+//
+//     pattern:
+//             { term }
+//     term:
+//             '*'         matches any sequence of non-/ characters
+//             '?'         matches any single non-/ character
+//             '[' [ '^' ] { character-range } ']'
+//                         character class (must be non-empty)
+//             c           matches character c (c != '*', '?', '\\', '[')
+//             '\\' c      matches character c
+//
+//     character-range:
+//             c           matches character c (c != '\\', '-', ']')
+//             '\\' c      matches character c
+//             lo '-' hi   matches character c for lo <= c <= hi
+//
+// Match requires pattern to match all of name, not just a substring.
+// The only possible error return is when pattern is malformed.
+//
+func Match(pattern, name string) (matched bool, err os.Error) {
+Pattern:
+       for len(pattern) > 0 {
+               var star bool
+               var chunk string
+               star, chunk, pattern = scanChunk(pattern)
+               if star && chunk == "" {
+                       // Trailing * matches rest of string unless it has a /.
+                       return strings.Index(name, "/") < 0, nil
+               }
+               // Look for match at current position.
+               t, ok, err := matchChunk(chunk, name)
+               // if we're the last chunk, make sure we've exhausted the name
+               // otherwise we'll give a false result even if we could still match
+               // using the star
+               if ok && (len(t) == 0 || len(pattern) > 0) {
+                       name = t
+                       continue
+               }
+               if err != nil {
+                       return false, err
+               }
+               if star {
+                       // Look for match skipping i+1 bytes.
+                       // Cannot skip /.
+                       for i := 0; i < len(name) && name[i] != '/'; i++ {
+                               t, ok, err := matchChunk(chunk, name[i+1:])
+                               if ok {
+                                       // if we're the last chunk, make sure we exhausted the name
+                                       if len(pattern) == 0 && len(t) > 0 {
+                                               continue
+                                       }
+                                       name = t
+                                       continue Pattern
+                               }
+                               if err != nil {
+                                       return false, err
+                               }
+                       }
+               }
+               return false, nil
+       }
+       return len(name) == 0, nil
+}
+
+// scanChunk gets the next section of pattern, which is a non-star string
+// possibly preceded by a star.
+func scanChunk(pattern string) (star bool, chunk, rest string) {
+       for len(pattern) > 0 && pattern[0] == '*' {
+               pattern = pattern[1:]
+               star = true
+       }
+       inrange := false
+       var i int
+Scan:
+       for i = 0; i < len(pattern); i++ {
+               switch pattern[i] {
+               case '\\':
+                       // error check handled in matchChunk: bad pattern.
+                       if i+1 < len(pattern) {
+                               i++
+                       }
+                       continue
+               case '[':
+                       inrange = true
+               case ']':
+                       inrange = false
+               case '*':
+                       if !inrange {
+                               break Scan
+                       }
+               }
+       }
+       return star, pattern[0:i], pattern[i:]
+}
+
+// matchChunk checks whether chunk matches the beginning of s.
+// If so, it returns the remainder of s (after the match).
+// Chunk is all single-character operators: literals, char classes, and ?.
+func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
+       for len(chunk) > 0 {
+               if len(s) == 0 {
+                       return
+               }
+               switch chunk[0] {
+               case '[':
+                       // character class
+                       r, n := utf8.DecodeRuneInString(s)
+                       s = s[n:]
+                       chunk = chunk[1:]
+                       // possibly negated
+                       notNegated := true
+                       if len(chunk) > 0 && chunk[0] == '^' {
+                               notNegated = false
+                               chunk = chunk[1:]
+                       }
+                       // parse all ranges
+                       match := false
+                       nrange := 0
+                       for {
+                               if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
+                                       chunk = chunk[1:]
+                                       break
+                               }
+                               var lo, hi int
+                               if lo, chunk, err = getEsc(chunk); err != nil {
+                                       return
+                               }
+                               hi = lo
+                               if chunk[0] == '-' {
+                                       if hi, chunk, err = getEsc(chunk[1:]); err != nil {
+                                               return
+                                       }
+                               }
+                               if lo <= r && r <= hi {
+                                       match = true
+                               }
+                               nrange++
+                       }
+                       if match != notNegated {
+                               return
+                       }
+
+               case '?':
+                       if s[0] == '/' {
+                               return
+                       }
+                       _, n := utf8.DecodeRuneInString(s)
+                       s = s[n:]
+                       chunk = chunk[1:]
+
+               case '\\':
+                       chunk = chunk[1:]
+                       if len(chunk) == 0 {
+                               err = ErrBadPattern
+                               return
+                       }
+                       fallthrough
+
+               default:
+                       if chunk[0] != s[0] {
+                               return
+                       }
+                       s = s[1:]
+                       chunk = chunk[1:]
+               }
+       }
+       return s, true, nil
+}
+
+// getEsc gets a possibly-escaped character from chunk, for a character class.
+func getEsc(chunk string) (r int, nchunk string, err os.Error) {
+       if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
+               err = ErrBadPattern
+               return
+       }
+       if chunk[0] == '\\' {
+               chunk = chunk[1:]
+               if len(chunk) == 0 {
+                       err = ErrBadPattern
+                       return
+               }
+       }
+       r, n := utf8.DecodeRuneInString(chunk)
+       if r == utf8.RuneError && n == 1 {
+               err = ErrBadPattern
+       }
+       nchunk = chunk[n:]
+       if len(nchunk) == 0 {
+               err = ErrBadPattern
+       }
+       return
+}
+
+// Glob returns the names of all files matching pattern or nil
+// if there is no matching file. The syntax of patterns is the same
+// as in Match. The pattern may describe hierarchical names such as
+// /usr/*/bin/ed.
+//
+func Glob(pattern string) (matches []string) {
+       if !hasMeta(pattern) {
+               if _, err := os.Stat(pattern); err == nil {
+                       return []string{pattern}
+               }
+               return nil
+       }
+
+       dir, file := Split(pattern)
+       switch dir {
+       case "":
+               dir = "."
+       case "/":
+               // nothing
+       default:
+               dir = dir[0 : len(dir)-1] // chop off trailing '/'
+       }
+
+       if hasMeta(dir) {
+               for _, d := range Glob(dir) {
+                       matches = glob(d, file, matches)
+               }
+       } else {
+               return glob(dir, file, nil)
+       }
+       return matches
+}
+
+// glob searches for files matching pattern in the directory dir
+// and appends them to matches.
+func glob(dir, pattern string, matches []string) []string {
+       if fi, err := os.Stat(dir); err != nil || !fi.IsDirectory() {
+               return nil
+       }
+       d, err := os.Open(dir, os.O_RDONLY, 0666)
+       if err != nil {
+               return nil
+       }
+       defer d.Close()
+
+       names, err := d.Readdirnames(-1)
+       if err != nil {
+               return nil
+       }
+       sort.SortStrings(names)
+
+       for _, n := range names {
+               matched, err := Match(pattern, n)
+               if err != nil {
+                       return matches
+               }
+               if matched {
+                       matches = append(matches, Join(dir, n))
+               }
+       }
+       return matches
+}
+
+// hasMeta returns true if path contains any of the magic characters
+// recognized by Match.
+func hasMeta(path string) bool {
+       return strings.IndexAny(path, "*?[") != -1
+}
diff --git a/libgo/go/path/match_test.go b/libgo/go/path/match_test.go
new file mode 100644 (file)
index 0000000..141cff7
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path
+
+import (
+       "os"
+       "testing"
+)
+
+type MatchTest struct {
+       pattern, s string
+       match      bool
+       err        os.Error
+}
+
+var matchTests = []MatchTest{
+       {"abc", "abc", true, nil},
+       {"*", "abc", true, nil},
+       {"*c", "abc", true, nil},
+       {"a*", "a", true, nil},
+       {"a*", "abc", true, nil},
+       {"a*", "ab/c", false, nil},
+       {"a*/b", "abc/b", true, nil},
+       {"a*/b", "a/c/b", false, nil},
+       {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
+       {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
+       {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
+       {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
+       {"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
+       {"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
+       {"ab[c]", "abc", true, nil},
+       {"ab[b-d]", "abc", true, nil},
+       {"ab[e-g]", "abc", false, nil},
+       {"ab[^c]", "abc", false, nil},
+       {"ab[^b-d]", "abc", false, nil},
+       {"ab[^e-g]", "abc", true, nil},
+       {"a\\*b", "a*b", true, nil},
+       {"a\\*b", "ab", false, nil},
+       {"a?b", "a☺b", true, nil},
+       {"a[^a]b", "a☺b", true, nil},
+       {"a???b", "a☺b", false, nil},
+       {"a[^a][^a][^a]b", "a☺b", false, nil},
+       {"[a-ζ]*", "α", true, nil},
+       {"*[a-ζ]", "A", false, nil},
+       {"a?b", "a/b", false, nil},
+       {"a*b", "a/b", false, nil},
+       {"[\\]a]", "]", true, nil},
+       {"[\\-]", "-", true, nil},
+       {"[x\\-]", "x", true, nil},
+       {"[x\\-]", "-", true, nil},
+       {"[x\\-]", "z", false, nil},
+       {"[\\-x]", "x", true, nil},
+       {"[\\-x]", "-", true, nil},
+       {"[\\-x]", "a", false, nil},
+       {"[]a]", "]", false, ErrBadPattern},
+       {"[-]", "-", false, ErrBadPattern},
+       {"[x-]", "x", false, ErrBadPattern},
+       {"[x-]", "-", false, ErrBadPattern},
+       {"[x-]", "z", false, ErrBadPattern},
+       {"[-x]", "x", false, ErrBadPattern},
+       {"[-x]", "-", false, ErrBadPattern},
+       {"[-x]", "a", false, ErrBadPattern},
+       {"\\", "a", false, ErrBadPattern},
+       {"[a-b-c]", "a", false, ErrBadPattern},
+       {"*x", "xxx", true, nil},
+}
+
+func TestMatch(t *testing.T) {
+       for _, tt := range matchTests {
+               ok, err := Match(tt.pattern, tt.s)
+               if ok != tt.match || err != tt.err {
+                       t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match)
+               }
+       }
+}
+
+// contains returns true if vector contains the string s.
+func contains(vector []string, s string) bool {
+       for _, elem := range vector {
+               if elem == s {
+                       return true
+               }
+       }
+       return false
+}
+
+var globTests = []struct {
+       pattern, result string
+}{
+       {"match.go", "match.go"},
+       {"mat?h.go", "match.go"},
+       {"*", "match.go"},
+       // Fails in the gccgo test environment.
+       // {"../*/match.go", "../path/match.go"},
+}
+
+func TestGlob(t *testing.T) {
+       for _, tt := range globTests {
+               matches := Glob(tt.pattern)
+               if !contains(matches, tt.result) {
+                       t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
+               }
+       }
+}
diff --git a/libgo/go/path/path.go b/libgo/go/path/path.go
new file mode 100644 (file)
index 0000000..79b3000
--- /dev/null
@@ -0,0 +1,216 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The path package implements utility routines for manipulating
+// slash-separated filename paths.
+package path
+
+import (
+       "io/ioutil"
+       "os"
+       "strings"
+)
+
+// Clean returns the shortest path name equivalent to path
+// by purely lexical processing.  It applies the following rules
+// iteratively until no further processing can be done:
+//
+//     1. Replace multiple slashes with a single slash.
+//     2. Eliminate each . path name element (the current directory).
+//     3. Eliminate each inner .. path name element (the parent directory)
+//        along with the non-.. element that precedes it.
+//     4. Eliminate .. elements that begin a rooted path:
+//        that is, replace "/.." by "/" at the beginning of a path.
+//
+// If the result of this process is an empty string, Clean
+// returns the string ".".
+//
+// See also Rob Pike, ``Lexical File Names in Plan 9 or
+// Getting Dot-Dot right,''
+// http://plan9.bell-labs.com/sys/doc/lexnames.html
+func Clean(path string) string {
+       if path == "" {
+               return "."
+       }
+
+       rooted := path[0] == '/'
+       n := len(path)
+
+       // Invariants:
+       //      reading from path; r is index of next byte to process.
+       //      writing to buf; w is index of next byte to write.
+       //      dotdot is index in buf where .. must stop, either because
+       //              it is the leading slash or it is a leading ../../.. prefix.
+       buf := []byte(path)
+       r, w, dotdot := 0, 0, 0
+       if rooted {
+               r, w, dotdot = 1, 1, 1
+       }
+
+       for r < n {
+               switch {
+               case path[r] == '/':
+                       // empty path element
+                       r++
+               case path[r] == '.' && (r+1 == n || path[r+1] == '/'):
+                       // . element
+                       r++
+               case path[r] == '.' && path[r+1] == '.' && (r+2 == n || path[r+2] == '/'):
+                       // .. element: remove to last /
+                       r += 2
+                       switch {
+                       case w > dotdot:
+                               // can backtrack
+                               w--
+                               for w > dotdot && buf[w] != '/' {
+                                       w--
+                               }
+                       case !rooted:
+                               // cannot backtrack, but not rooted, so append .. element.
+                               if w > 0 {
+                                       buf[w] = '/'
+                                       w++
+                               }
+                               buf[w] = '.'
+                               w++
+                               buf[w] = '.'
+                               w++
+                               dotdot = w
+                       }
+               default:
+                       // real path element.
+                       // add slash if needed
+                       if rooted && w != 1 || !rooted && w != 0 {
+                               buf[w] = '/'
+                               w++
+                       }
+                       // copy element
+                       for ; r < n && path[r] != '/'; r++ {
+                               buf[w] = path[r]
+                               w++
+                       }
+               }
+       }
+
+       // Turn empty string into "."
+       if w == 0 {
+               buf[w] = '.'
+               w++
+       }
+
+       return string(buf[0:w])
+}
+
+// Split splits path immediately following the final slash,
+// separating it into a directory and file name component.
+// If there is no slash in path, Split returns an empty dir and
+// file set to path.
+func Split(path string) (dir, file string) {
+       for i := len(path) - 1; i >= 0; i-- {
+               if path[i] == '/' {
+                       return path[0 : i+1], path[i+1:]
+               }
+       }
+       return "", path
+}
+
+// Join joins any number of path elements into a single path, adding a
+// separating slash if necessary.  All empty strings are ignored.
+func Join(elem ...string) string {
+       for i, e := range elem {
+               if e != "" {
+                       return Clean(strings.Join(elem[i:], "/"))
+               }
+       }
+       return ""
+}
+
+// Ext returns the file name extension used by path.
+// The extension is the suffix beginning at the final dot
+// in the final slash-separated element of path;
+// it is empty if there is no dot.
+func Ext(path string) string {
+       for i := len(path) - 1; i >= 0 && path[i] != '/'; i-- {
+               if path[i] == '.' {
+                       return path[i:]
+               }
+       }
+       return ""
+}
+
+// Visitor methods are invoked for corresponding file tree entries
+// visited by Walk. The parameter path is the full path of f relative
+// to root.
+type Visitor interface {
+       VisitDir(path string, f *os.FileInfo) bool
+       VisitFile(path string, f *os.FileInfo)
+}
+
+func walk(path string, f *os.FileInfo, v Visitor, errors chan<- os.Error) {
+       if !f.IsDirectory() {
+               v.VisitFile(path, f)
+               return
+       }
+
+       if !v.VisitDir(path, f) {
+               return // skip directory entries
+       }
+
+       list, err := ioutil.ReadDir(path)
+       if err != nil {
+               if errors != nil {
+                       errors <- err
+               }
+       }
+
+       for _, e := range list {
+               walk(Join(path, e.Name), e, v, errors)
+       }
+}
+
+// Walk walks the file tree rooted at root, calling v.VisitDir or
+// v.VisitFile for each directory or file in the tree, including root.
+// If v.VisitDir returns false, Walk skips the directory's entries;
+// otherwise it invokes itself for each directory entry in sorted order.
+// An error reading a directory does not abort the Walk.
+// If errors != nil, Walk sends each directory read error
+// to the channel.  Otherwise Walk discards the error.
+func Walk(root string, v Visitor, errors chan<- os.Error) {
+       f, err := os.Lstat(root)
+       if err != nil {
+               if errors != nil {
+                       errors <- err
+               }
+               return // can't progress
+       }
+       walk(root, f, v, errors)
+}
+
+// Base returns the last path element of the slash-separated name.
+// Trailing slashes are removed before extracting the last element.  If the name is
+// empty, "." is returned.  If it consists entirely of slashes, "/" is returned.
+func Base(name string) string {
+       if name == "" {
+               return "."
+       }
+       // Strip trailing slashes.
+       for len(name) > 0 && name[len(name)-1] == '/' {
+               name = name[0 : len(name)-1]
+       }
+       // Find the last element
+       if i := strings.LastIndex(name, "/"); i >= 0 {
+               name = name[i+1:]
+       }
+       // If empty now, it had only slashes.
+       if name == "" {
+               return "/"
+       }
+       return name
+}
+
+// IsAbs returns true if the path is absolute.
+func IsAbs(path string) bool {
+       // TODO: Add Windows support
+       return strings.HasPrefix(path, "/")
+}
diff --git a/libgo/go/path/path_test.go b/libgo/go/path/path_test.go
new file mode 100644 (file)
index 0000000..2bbb924
--- /dev/null
@@ -0,0 +1,333 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path
+
+import (
+       "os"
+       "testing"
+)
+
+type CleanTest struct {
+       path, clean string
+}
+
+var cleantests = []CleanTest{
+       // Already clean
+       {"", "."},
+       {"abc", "abc"},
+       {"abc/def", "abc/def"},
+       {"a/b/c", "a/b/c"},
+       {".", "."},
+       {"..", ".."},
+       {"../..", "../.."},
+       {"../../abc", "../../abc"},
+       {"/abc", "/abc"},
+       {"/", "/"},
+
+       // Remove trailing slash
+       {"abc/", "abc"},
+       {"abc/def/", "abc/def"},
+       {"a/b/c/", "a/b/c"},
+       {"./", "."},
+       {"../", ".."},
+       {"../../", "../.."},
+       {"/abc/", "/abc"},
+
+       // Remove doubled slash
+       {"abc//def//ghi", "abc/def/ghi"},
+       {"//abc", "/abc"},
+       {"///abc", "/abc"},
+       {"//abc//", "/abc"},
+       {"abc//", "abc"},
+
+       // Remove . elements
+       {"abc/./def", "abc/def"},
+       {"/./abc/def", "/abc/def"},
+       {"abc/.", "abc"},
+
+       // Remove .. elements
+       {"abc/def/ghi/../jkl", "abc/def/jkl"},
+       {"abc/def/../ghi/../jkl", "abc/jkl"},
+       {"abc/def/..", "abc"},
+       {"abc/def/../..", "."},
+       {"/abc/def/../..", "/"},
+       {"abc/def/../../..", ".."},
+       {"/abc/def/../../..", "/"},
+       {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
+
+       // Combinations
+       {"abc/./../def", "def"},
+       {"abc//./../def", "def"},
+       {"abc/../../././../def", "../../def"},
+}
+
+func TestClean(t *testing.T) {
+       for _, test := range cleantests {
+               if s := Clean(test.path); s != test.clean {
+                       t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.clean)
+               }
+       }
+}
+
+type SplitTest struct {
+       path, dir, file string
+}
+
+var splittests = []SplitTest{
+       {"a/b", "a/", "b"},
+       {"a/b/", "a/b/", ""},
+       {"a/", "a/", ""},
+       {"a", "", "a"},
+       {"/", "/", ""},
+}
+
+func TestSplit(t *testing.T) {
+       for _, test := range splittests {
+               if d, f := Split(test.path); d != test.dir || f != test.file {
+                       t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
+               }
+       }
+}
+
+type JoinTest struct {
+       elem []string
+       path string
+}
+
+var jointests = []JoinTest{
+       // zero parameters
+       {[]string{}, ""},
+
+       // one parameter
+       {[]string{""}, ""},
+       {[]string{"a"}, "a"},
+
+       // two parameters
+       {[]string{"a", "b"}, "a/b"},
+       {[]string{"a", ""}, "a"},
+       {[]string{"", "b"}, "b"},
+       {[]string{"/", "a"}, "/a"},
+       {[]string{"/", ""}, "/"},
+       {[]string{"a/", "b"}, "a/b"},
+       {[]string{"a/", ""}, "a"},
+       {[]string{"", ""}, ""},
+}
+
+// join takes a []string and passes it to Join.
+func join(elem []string, args ...string) string {
+       args = elem
+       return Join(args...)
+}
+
+func TestJoin(t *testing.T) {
+       for _, test := range jointests {
+               if p := join(test.elem); p != test.path {
+                       t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
+               }
+       }
+}
+
+type ExtTest struct {
+       path, ext string
+}
+
+var exttests = []ExtTest{
+       {"path.go", ".go"},
+       {"path.pb.go", ".go"},
+       {"a.dir/b", ""},
+       {"a.dir/b.go", ".go"},
+       {"a.dir/", ""},
+}
+
+func TestExt(t *testing.T) {
+       for _, test := range exttests {
+               if x := Ext(test.path); x != test.ext {
+                       t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
+               }
+       }
+}
+
+type Node struct {
+       name    string
+       entries []*Node // nil if the entry is a file
+       mark    int
+}
+
+var tree = &Node{
+       "testdata",
+       []*Node{
+               &Node{"a", nil, 0},
+               &Node{"b", []*Node{}, 0},
+               &Node{"c", nil, 0},
+               &Node{
+                       "d",
+                       []*Node{
+                               &Node{"x", nil, 0},
+                               &Node{"y", []*Node{}, 0},
+                               &Node{
+                                       "z",
+                                       []*Node{
+                                               &Node{"u", nil, 0},
+                                               &Node{"v", nil, 0},
+                                       },
+                                       0,
+                               },
+                       },
+                       0,
+               },
+       },
+       0,
+}
+
+func walkTree(n *Node, path string, f func(path string, n *Node)) {
+       f(path, n)
+       for _, e := range n.entries {
+               walkTree(e, Join(path, e.name), f)
+       }
+}
+
+func makeTree(t *testing.T) {
+       walkTree(tree, tree.name, func(path string, n *Node) {
+               if n.entries == nil {
+                       fd, err := os.Open(path, os.O_CREAT, 0660)
+                       if err != nil {
+                               t.Errorf("makeTree: %v", err)
+                       }
+                       fd.Close()
+               } else {
+                       os.Mkdir(path, 0770)
+               }
+       })
+}
+
+func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
+
+func checkMarks(t *testing.T) {
+       walkTree(tree, tree.name, func(path string, n *Node) {
+               if n.mark != 1 {
+                       t.Errorf("node %s mark = %d; expected 1", path, n.mark)
+               }
+               n.mark = 0
+       })
+}
+
+// Assumes that each node name is unique. Good enough for a test.
+func mark(name string) {
+       walkTree(tree, tree.name, func(path string, n *Node) {
+               if n.name == name {
+                       n.mark++
+               }
+       })
+}
+
+type TestVisitor struct{}
+
+func (v *TestVisitor) VisitDir(path string, f *os.FileInfo) bool {
+       mark(f.Name)
+       return true
+}
+
+func (v *TestVisitor) VisitFile(path string, f *os.FileInfo) {
+       mark(f.Name)
+}
+
+func TestWalk(t *testing.T) {
+       makeTree(t)
+
+       // 1) ignore error handling, expect none
+       v := &TestVisitor{}
+       Walk(tree.name, v, nil)
+       checkMarks(t)
+
+       // 2) handle errors, expect none
+       errors := make(chan os.Error, 64)
+       Walk(tree.name, v, errors)
+       if err, ok := <-errors; ok {
+               t.Errorf("no error expected, found: s", err)
+       }
+       checkMarks(t)
+
+       if os.Getuid() != 0 {
+               // introduce 2 errors: chmod top-level directories to 0
+               os.Chmod(Join(tree.name, tree.entries[1].name), 0)
+               os.Chmod(Join(tree.name, tree.entries[3].name), 0)
+               // mark respective subtrees manually
+               markTree(tree.entries[1])
+               markTree(tree.entries[3])
+               // correct double-marking of directory itself
+               tree.entries[1].mark--
+               tree.entries[3].mark--
+
+               // 3) handle errors, expect two
+               errors = make(chan os.Error, 64)
+               os.Chmod(Join(tree.name, tree.entries[1].name), 0)
+               Walk(tree.name, v, errors)
+               for i := 1; i <= 2; i++ {
+                       if _, ok := <-errors; !ok {
+                               t.Errorf("%d. error expected, none found", i)
+                               break
+                       }
+               }
+               if err, ok := <-errors; ok {
+                       t.Errorf("only two errors expected, found 3rd: %v", err)
+               }
+               // the inaccessible subtrees were marked manually
+               checkMarks(t)
+       }
+
+       // cleanup
+       os.Chmod(Join(tree.name, tree.entries[1].name), 0770)
+       os.Chmod(Join(tree.name, tree.entries[3].name), 0770)
+       if err := os.RemoveAll(tree.name); err != nil {
+               t.Errorf("removeTree: %v", err)
+       }
+}
+
+var basetests = []CleanTest{
+       // Already clean
+       {"", "."},
+       {".", "."},
+       {"/.", "."},
+       {"/", "/"},
+       {"////", "/"},
+       {"x/", "x"},
+       {"abc", "abc"},
+       {"abc/def", "def"},
+       {"a/b/.x", ".x"},
+       {"a/b/c.", "c."},
+       {"a/b/c.x", "c.x"},
+}
+
+func TestBase(t *testing.T) {
+       for _, test := range basetests {
+               if s := Base(test.path); s != test.clean {
+                       t.Errorf("Base(%q) = %q, want %q", test.path, s, test.clean)
+               }
+       }
+}
+
+type IsAbsTest struct {
+       path  string
+       isAbs bool
+}
+
+var isAbsTests = []IsAbsTest{
+       {"", false},
+       {"/", true},
+       {"/usr/bin/gcc", true},
+       {"..", false},
+       {"/a/../bb", true},
+       {".", false},
+       {"./", false},
+       {"lala", false},
+}
+
+func TestIsAbs(t *testing.T) {
+       for _, test := range isAbsTests {
+               if r := IsAbs(test.path); r != test.isAbs {
+                       t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
+               }
+       }
+}
diff --git a/libgo/go/rand/exp.go b/libgo/go/rand/exp.go
new file mode 100644 (file)
index 0000000..85da495
--- /dev/null
@@ -0,0 +1,223 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+       "math"
+)
+
+/*
+ * Exponential distribution
+ *
+ * See "The Ziggurat Method for Generating Random Variables"
+ * (Marsaglia & Tsang, 2000)
+ * http://www.jstatsoft.org/v05/i08/paper [pdf]
+ */
+
+const (
+       re = 7.69711747013104972
+)
+
+// ExpFloat64 returns an exponentially distributed float64 in the range
+// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
+// (lambda) is 1 and whose mean is 1/lambda (1).
+// To produce a distribution with a different rate parameter,
+// callers can adjust the output using:
+//
+//  sample = ExpFloat64() / desiredRateParameter
+//
+func (r *Rand) ExpFloat64() float64 {
+       for {
+               j := r.Uint32()
+               i := j & 0xFF
+               x := float64(j) * float64(we[i])
+               if j < ke[i] {
+                       return x
+               }
+               if i == 0 {
+                       return re - math.Log(r.Float64())
+               }
+               if fe[i]+float32(r.Float64())*(fe[i-1]-fe[i]) < float32(math.Exp(-x)) {
+                       return x
+               }
+       }
+       panic("unreachable")
+}
+
+var ke = [256]uint32{
+       0xe290a139, 0x0, 0x9beadebc, 0xc377ac71, 0xd4ddb990,
+       0xde893fb8, 0xe4a8e87c, 0xe8dff16a, 0xebf2deab, 0xee49a6e8,
+       0xf0204efd, 0xf19bdb8e, 0xf2d458bb, 0xf3da104b, 0xf4b86d78,
+       0xf577ad8a, 0xf61de83d, 0xf6afb784, 0xf730a573, 0xf7a37651,
+       0xf80a5bb6, 0xf867189d, 0xf8bb1b4f, 0xf9079062, 0xf94d70ca,
+       0xf98d8c7d, 0xf9c8928a, 0xf9ff175b, 0xfa319996, 0xfa6085f8,
+       0xfa8c3a62, 0xfab5084e, 0xfadb36c8, 0xfaff0410, 0xfb20a6ea,
+       0xfb404fb4, 0xfb5e2951, 0xfb7a59e9, 0xfb95038c, 0xfbae44ba,
+       0xfbc638d8, 0xfbdcf892, 0xfbf29a30, 0xfc0731df, 0xfc1ad1ed,
+       0xfc2d8b02, 0xfc3f6c4d, 0xfc5083ac, 0xfc60ddd1, 0xfc708662,
+       0xfc7f8810, 0xfc8decb4, 0xfc9bbd62, 0xfca9027c, 0xfcb5c3c3,
+       0xfcc20864, 0xfccdd70a, 0xfcd935e3, 0xfce42ab0, 0xfceebace,
+       0xfcf8eb3b, 0xfd02c0a0, 0xfd0c3f59, 0xfd156b7b, 0xfd1e48d6,
+       0xfd26daff, 0xfd2f2552, 0xfd372af7, 0xfd3eeee5, 0xfd4673e7,
+       0xfd4dbc9e, 0xfd54cb85, 0xfd5ba2f2, 0xfd62451b, 0xfd68b415,
+       0xfd6ef1da, 0xfd750047, 0xfd7ae120, 0xfd809612, 0xfd8620b4,
+       0xfd8b8285, 0xfd90bcf5, 0xfd95d15e, 0xfd9ac10b, 0xfd9f8d36,
+       0xfda43708, 0xfda8bf9e, 0xfdad2806, 0xfdb17141, 0xfdb59c46,
+       0xfdb9a9fd, 0xfdbd9b46, 0xfdc170f6, 0xfdc52bd8, 0xfdc8ccac,
+       0xfdcc542d, 0xfdcfc30b, 0xfdd319ef, 0xfdd6597a, 0xfdd98245,
+       0xfddc94e5, 0xfddf91e6, 0xfde279ce, 0xfde54d1f, 0xfde80c52,
+       0xfdeab7de, 0xfded5034, 0xfdefd5be, 0xfdf248e3, 0xfdf4aa06,
+       0xfdf6f984, 0xfdf937b6, 0xfdfb64f4, 0xfdfd818d, 0xfdff8dd0,
+       0xfe018a08, 0xfe03767a, 0xfe05536c, 0xfe07211c, 0xfe08dfc9,
+       0xfe0a8fab, 0xfe0c30fb, 0xfe0dc3ec, 0xfe0f48b1, 0xfe10bf76,
+       0xfe122869, 0xfe1383b4, 0xfe14d17c, 0xfe1611e7, 0xfe174516,
+       0xfe186b2a, 0xfe19843e, 0xfe1a9070, 0xfe1b8fd6, 0xfe1c8289,
+       0xfe1d689b, 0xfe1e4220, 0xfe1f0f26, 0xfe1fcfbc, 0xfe2083ed,
+       0xfe212bc3, 0xfe21c745, 0xfe225678, 0xfe22d95f, 0xfe234ffb,
+       0xfe23ba4a, 0xfe241849, 0xfe2469f2, 0xfe24af3c, 0xfe24e81e,
+       0xfe25148b, 0xfe253474, 0xfe2547c7, 0xfe254e70, 0xfe25485a,
+       0xfe25356a, 0xfe251586, 0xfe24e88f, 0xfe24ae64, 0xfe2466e1,
+       0xfe2411df, 0xfe23af34, 0xfe233eb4, 0xfe22c02c, 0xfe22336b,
+       0xfe219838, 0xfe20ee58, 0xfe20358c, 0xfe1f6d92, 0xfe1e9621,
+       0xfe1daef0, 0xfe1cb7ac, 0xfe1bb002, 0xfe1a9798, 0xfe196e0d,
+       0xfe1832fd, 0xfe16e5fe, 0xfe15869d, 0xfe141464, 0xfe128ed3,
+       0xfe10f565, 0xfe0f478c, 0xfe0d84b1, 0xfe0bac36, 0xfe09bd73,
+       0xfe07b7b5, 0xfe059a40, 0xfe03644c, 0xfe011504, 0xfdfeab88,
+       0xfdfc26e9, 0xfdf98629, 0xfdf6c83b, 0xfdf3ec01, 0xfdf0f04a,
+       0xfdedd3d1, 0xfdea953d, 0xfde7331e, 0xfde3abe9, 0xfddffdfb,
+       0xfddc2791, 0xfdd826cd, 0xfdd3f9a8, 0xfdcf9dfc, 0xfdcb1176,
+       0xfdc65198, 0xfdc15bb3, 0xfdbc2ce2, 0xfdb6c206, 0xfdb117be,
+       0xfdab2a63, 0xfda4f5fd, 0xfd9e7640, 0xfd97a67a, 0xfd908192,
+       0xfd8901f2, 0xfd812182, 0xfd78d98e, 0xfd7022bb, 0xfd66f4ed,
+       0xfd5d4732, 0xfd530f9c, 0xfd48432b, 0xfd3cd59a, 0xfd30b936,
+       0xfd23dea4, 0xfd16349e, 0xfd07a7a3, 0xfcf8219b, 0xfce7895b,
+       0xfcd5c220, 0xfcc2aadb, 0xfcae1d5e, 0xfc97ed4e, 0xfc7fe6d4,
+       0xfc65ccf3, 0xfc495762, 0xfc2a2fc8, 0xfc07ee19, 0xfbe213c1,
+       0xfbb8051a, 0xfb890078, 0xfb5411a5, 0xfb180005, 0xfad33482,
+       0xfa839276, 0xfa263b32, 0xf9b72d1c, 0xf930a1a2, 0xf889f023,
+       0xf7b577d2, 0xf69c650c, 0xf51530f0, 0xf2cb0e3c, 0xeeefb15d,
+       0xe6da6ecf,
+}
+var we = [256]float32{
+       2.0249555e-09, 1.486674e-11, 2.4409617e-11, 3.1968806e-11,
+       3.844677e-11, 4.4228204e-11, 4.9516443e-11, 5.443359e-11,
+       5.905944e-11, 6.344942e-11, 6.7643814e-11, 7.1672945e-11,
+       7.556032e-11, 7.932458e-11, 8.298079e-11, 8.654132e-11,
+       9.0016515e-11, 9.3415074e-11, 9.674443e-11, 1.0001099e-10,
+       1.03220314e-10, 1.06377254e-10, 1.09486115e-10, 1.1255068e-10,
+       1.1557435e-10, 1.1856015e-10, 1.2151083e-10, 1.2442886e-10,
+       1.2731648e-10, 1.3017575e-10, 1.3300853e-10, 1.3581657e-10,
+       1.3860142e-10, 1.4136457e-10, 1.4410738e-10, 1.4683108e-10,
+       1.4953687e-10, 1.5222583e-10, 1.54899e-10, 1.5755733e-10,
+       1.6020171e-10, 1.6283301e-10, 1.6545203e-10, 1.6805951e-10,
+       1.7065617e-10, 1.732427e-10, 1.7581973e-10, 1.7838787e-10,
+       1.8094774e-10, 1.8349985e-10, 1.8604476e-10, 1.8858298e-10,
+       1.9111498e-10, 1.9364126e-10, 1.9616223e-10, 1.9867835e-10,
+       2.0119004e-10, 2.0369768e-10, 2.0620168e-10, 2.087024e-10,
+       2.1120022e-10, 2.136955e-10, 2.1618855e-10, 2.1867974e-10,
+       2.2116936e-10, 2.2365775e-10, 2.261452e-10, 2.2863202e-10,
+       2.311185e-10, 2.3360494e-10, 2.360916e-10, 2.3857874e-10,
+       2.4106667e-10, 2.4355562e-10, 2.4604588e-10, 2.485377e-10,
+       2.5103128e-10, 2.5352695e-10, 2.560249e-10, 2.585254e-10,
+       2.6102867e-10, 2.6353494e-10, 2.6604446e-10, 2.6855745e-10,
+       2.7107416e-10, 2.7359479e-10, 2.761196e-10, 2.7864877e-10,
+       2.8118255e-10, 2.8372119e-10, 2.8626485e-10, 2.888138e-10,
+       2.9136826e-10, 2.939284e-10, 2.9649452e-10, 2.9906677e-10,
+       3.016454e-10, 3.0423064e-10, 3.0682268e-10, 3.0942177e-10,
+       3.1202813e-10, 3.1464195e-10, 3.1726352e-10, 3.19893e-10,
+       3.2253064e-10, 3.251767e-10, 3.2783135e-10, 3.3049485e-10,
+       3.3316744e-10, 3.3584938e-10, 3.3854083e-10, 3.4124212e-10,
+       3.4395342e-10, 3.46675e-10, 3.4940711e-10, 3.5215003e-10,
+       3.5490397e-10, 3.5766917e-10, 3.6044595e-10, 3.6323455e-10,
+       3.660352e-10, 3.6884823e-10, 3.7167386e-10, 3.745124e-10,
+       3.773641e-10, 3.802293e-10, 3.8310827e-10, 3.860013e-10,
+       3.8890866e-10, 3.918307e-10, 3.9476775e-10, 3.9772008e-10,
+       4.0068804e-10, 4.0367196e-10, 4.0667217e-10, 4.09689e-10,
+       4.1272286e-10, 4.1577405e-10, 4.1884296e-10, 4.2192994e-10,
+       4.250354e-10, 4.281597e-10, 4.313033e-10, 4.3446652e-10,
+       4.3764986e-10, 4.408537e-10, 4.4407847e-10, 4.4732465e-10,
+       4.5059267e-10, 4.5388301e-10, 4.571962e-10, 4.6053267e-10,
+       4.6389292e-10, 4.6727755e-10, 4.70687e-10, 4.741219e-10,
+       4.7758275e-10, 4.810702e-10, 4.845848e-10, 4.8812715e-10,
+       4.9169796e-10, 4.9529775e-10, 4.989273e-10, 5.0258725e-10,
+       5.0627835e-10, 5.100013e-10, 5.1375687e-10, 5.1754584e-10,
+       5.21369e-10, 5.2522725e-10, 5.2912136e-10, 5.330522e-10,
+       5.370208e-10, 5.4102806e-10, 5.45075e-10, 5.491625e-10,
+       5.532918e-10, 5.5746385e-10, 5.616799e-10, 5.6594107e-10,
+       5.7024857e-10, 5.746037e-10, 5.7900773e-10, 5.834621e-10,
+       5.8796823e-10, 5.925276e-10, 5.971417e-10, 6.018122e-10,
+       6.065408e-10, 6.113292e-10, 6.1617933e-10, 6.2109295e-10,
+       6.260722e-10, 6.3111916e-10, 6.3623595e-10, 6.4142497e-10,
+       6.4668854e-10, 6.5202926e-10, 6.5744976e-10, 6.6295286e-10,
+       6.6854156e-10, 6.742188e-10, 6.79988e-10, 6.858526e-10,
+       6.9181616e-10, 6.978826e-10, 7.04056e-10, 7.103407e-10,
+       7.167412e-10, 7.2326256e-10, 7.2990985e-10, 7.366886e-10,
+       7.4360473e-10, 7.5066453e-10, 7.5787476e-10, 7.6524265e-10,
+       7.7277595e-10, 7.80483e-10, 7.883728e-10, 7.9645507e-10,
+       8.047402e-10, 8.1323964e-10, 8.219657e-10, 8.309319e-10,
+       8.401528e-10, 8.496445e-10, 8.594247e-10, 8.6951274e-10,
+       8.799301e-10, 8.9070046e-10, 9.018503e-10, 9.134092e-10,
+       9.254101e-10, 9.378904e-10, 9.508923e-10, 9.644638e-10,
+       9.786603e-10, 9.935448e-10, 1.0091913e-09, 1.025686e-09,
+       1.0431306e-09, 1.0616465e-09, 1.08138e-09, 1.1025096e-09,
+       1.1252564e-09, 1.1498986e-09, 1.1767932e-09, 1.206409e-09,
+       1.2393786e-09, 1.276585e-09, 1.3193139e-09, 1.3695435e-09,
+       1.4305498e-09, 1.508365e-09, 1.6160854e-09, 1.7921248e-09,
+}
+var fe = [256]float32{
+       1, 0.9381437, 0.90046996, 0.87170434, 0.8477855, 0.8269933,
+       0.8084217, 0.7915276, 0.77595687, 0.7614634, 0.7478686,
+       0.7350381, 0.72286767, 0.71127474, 0.70019263, 0.6895665,
+       0.67935055, 0.6695063, 0.66000086, 0.65080583, 0.6418967,
+       0.63325197, 0.6248527, 0.6166822, 0.60872537, 0.60096896,
+       0.5934009, 0.58601034, 0.5787874, 0.57172304, 0.5648092,
+       0.5580383, 0.5514034, 0.5448982, 0.5385169, 0.53225386,
+       0.5261042, 0.52006316, 0.5141264, 0.50828975, 0.5025495,
+       0.496902, 0.49134386, 0.485872, 0.48048335, 0.4751752,
+       0.46994483, 0.46478975, 0.45970762, 0.45469615, 0.44975325,
+       0.44487688, 0.44006512, 0.43531612, 0.43062815, 0.42599955,
+       0.42142874, 0.4169142, 0.41245446, 0.40804818, 0.403694,
+       0.3993907, 0.39513698, 0.39093173, 0.38677382, 0.38266218,
+       0.37859577, 0.37457356, 0.37059465, 0.3666581, 0.362763,
+       0.35890847, 0.35509375, 0.351318, 0.3475805, 0.34388044,
+       0.34021714, 0.3365899, 0.33299807, 0.32944095, 0.32591796,
+       0.3224285, 0.3189719, 0.31554767, 0.31215525, 0.30879408,
+       0.3054636, 0.3021634, 0.29889292, 0.2956517, 0.29243928,
+       0.28925523, 0.28609908, 0.28297043, 0.27986884, 0.27679393,
+       0.2737453, 0.2707226, 0.2677254, 0.26475343, 0.26180625,
+       0.25888354, 0.25598502, 0.2531103, 0.25025907, 0.24743107,
+       0.24462597, 0.24184346, 0.23908329, 0.23634516, 0.23362878,
+       0.23093392, 0.2282603, 0.22560766, 0.22297576, 0.22036438,
+       0.21777324, 0.21520215, 0.21265087, 0.21011916, 0.20760682,
+       0.20511365, 0.20263945, 0.20018397, 0.19774707, 0.19532852,
+       0.19292815, 0.19054577, 0.1881812, 0.18583426, 0.18350479,
+       0.1811926, 0.17889754, 0.17661946, 0.17435817, 0.17211354,
+       0.1698854, 0.16767362, 0.16547804, 0.16329853, 0.16113494,
+       0.15898713, 0.15685499, 0.15473837, 0.15263714, 0.15055119,
+       0.14848037, 0.14642459, 0.14438373, 0.14235765, 0.14034624,
+       0.13834943, 0.13636707, 0.13439907, 0.13244532, 0.13050574,
+       0.1285802, 0.12666863, 0.12477092, 0.12288698, 0.12101672,
+       0.119160056, 0.1173169, 0.115487166, 0.11367077, 0.11186763,
+       0.11007768, 0.10830083, 0.10653701, 0.10478614, 0.10304816,
+       0.101323, 0.09961058, 0.09791085, 0.09622374, 0.09454919,
+       0.09288713, 0.091237515, 0.08960028, 0.087975375, 0.08636274,
+       0.08476233, 0.083174095, 0.081597984, 0.08003395, 0.07848195,
+       0.076941945, 0.07541389, 0.07389775, 0.072393484, 0.07090106,
+       0.069420435, 0.06795159, 0.066494495, 0.06504912, 0.063615434,
+       0.062193416, 0.060783047, 0.059384305, 0.057997175,
+       0.05662164, 0.05525769, 0.053905312, 0.052564494, 0.051235236,
+       0.049917534, 0.048611384, 0.047316793, 0.046033762, 0.0447623,
+       0.043502413, 0.042254124, 0.041017443, 0.039792392,
+       0.038578995, 0.037377283, 0.036187284, 0.035009038,
+       0.033842582, 0.032687962, 0.031545233, 0.030414443, 0.02929566,
+       0.02818895, 0.027094385, 0.026012046, 0.024942026, 0.023884421,
+       0.022839336, 0.021806888, 0.020787204, 0.019780423, 0.0187867,
+       0.0178062, 0.016839107, 0.015885621, 0.014945968, 0.014020392,
+       0.013109165, 0.012212592, 0.011331013, 0.01046481, 0.009614414,
+       0.008780315, 0.007963077, 0.0071633533, 0.006381906,
+       0.0056196423, 0.0048776558, 0.004157295, 0.0034602648,
+       0.0027887989, 0.0021459677, 0.0015362998, 0.0009672693,
+       0.00045413437,
+}
diff --git a/libgo/go/rand/normal.go b/libgo/go/rand/normal.go
new file mode 100644 (file)
index 0000000..9ab46db
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+       "math"
+)
+
+/*
+ * Normal distribution
+ *
+ * See "The Ziggurat Method for Generating Random Variables"
+ * (Marsaglia & Tsang, 2000)
+ * http://www.jstatsoft.org/v05/i08/paper [pdf]
+ */
+
+const (
+       rn = 3.442619855899
+)
+
+func absInt32(i int32) uint32 {
+       if i < 0 {
+               return uint32(-i)
+       }
+       return uint32(i)
+}
+
+// NormFloat64 returns a normally distributed float64 in the range
+// [-math.MaxFloat64, +math.MaxFloat64] with
+// standard normal distribution (mean = 0, stddev = 1).
+// To produce a different normal distribution, callers can
+// adjust the output using:
+//
+//  sample = NormFloat64() * desiredStdDev + desiredMean
+//
+func (r *Rand) NormFloat64() float64 {
+       for {
+               j := int32(r.Uint32()) // Possibly negative
+               i := j & 0x7F
+               x := float64(j) * float64(wn[i])
+               if absInt32(j) < kn[i] {
+                       // This case should be hit better than 99% of the time.
+                       return x
+               }
+
+               if i == 0 {
+                       // This extra work is only required for the base strip.
+                       for {
+                               x = -math.Log(r.Float64()) * (1.0 / rn)
+                               y := -math.Log(r.Float64())
+                               if y+y >= x*x {
+                                       break
+                               }
+                       }
+                       if j > 0 {
+                               return rn + x
+                       }
+                       return -rn - x
+               }
+               if fn[i]+float32(r.Float64())*(fn[i-1]-fn[i]) < float32(math.Exp(-.5*x*x)) {
+                       return x
+               }
+       }
+       panic("unreachable")
+}
+
+var kn = [128]uint32{
+       0x76ad2212, 0x0, 0x600f1b53, 0x6ce447a6, 0x725b46a2,
+       0x7560051d, 0x774921eb, 0x789a25bd, 0x799045c3, 0x7a4bce5d,
+       0x7adf629f, 0x7b5682a6, 0x7bb8a8c6, 0x7c0ae722, 0x7c50cce7,
+       0x7c8cec5b, 0x7cc12cd6, 0x7ceefed2, 0x7d177e0b, 0x7d3b8883,
+       0x7d5bce6c, 0x7d78dd64, 0x7d932886, 0x7dab0e57, 0x7dc0dd30,
+       0x7dd4d688, 0x7de73185, 0x7df81cea, 0x7e07c0a3, 0x7e163efa,
+       0x7e23b587, 0x7e303dfd, 0x7e3beec2, 0x7e46db77, 0x7e51155d,
+       0x7e5aabb3, 0x7e63abf7, 0x7e6c222c, 0x7e741906, 0x7e7b9a18,
+       0x7e82adfa, 0x7e895c63, 0x7e8fac4b, 0x7e95a3fb, 0x7e9b4924,
+       0x7ea0a0ef, 0x7ea5b00d, 0x7eaa7ac3, 0x7eaf04f3, 0x7eb3522a,
+       0x7eb765a5, 0x7ebb4259, 0x7ebeeafd, 0x7ec2620a, 0x7ec5a9c4,
+       0x7ec8c441, 0x7ecbb365, 0x7ece78ed, 0x7ed11671, 0x7ed38d62,
+       0x7ed5df12, 0x7ed80cb4, 0x7eda175c, 0x7edc0005, 0x7eddc78e,
+       0x7edf6ebf, 0x7ee0f647, 0x7ee25ebe, 0x7ee3a8a9, 0x7ee4d473,
+       0x7ee5e276, 0x7ee6d2f5, 0x7ee7a620, 0x7ee85c10, 0x7ee8f4cd,
+       0x7ee97047, 0x7ee9ce59, 0x7eea0eca, 0x7eea3147, 0x7eea3568,
+       0x7eea1aab, 0x7ee9e071, 0x7ee98602, 0x7ee90a88, 0x7ee86d08,
+       0x7ee7ac6a, 0x7ee6c769, 0x7ee5bc9c, 0x7ee48a67, 0x7ee32efc,
+       0x7ee1a857, 0x7edff42f, 0x7ede0ffa, 0x7edbf8d9, 0x7ed9ab94,
+       0x7ed7248d, 0x7ed45fae, 0x7ed1585c, 0x7ece095f, 0x7eca6ccb,
+       0x7ec67be2, 0x7ec22eee, 0x7ebd7d1a, 0x7eb85c35, 0x7eb2c075,
+       0x7eac9c20, 0x7ea5df27, 0x7e9e769f, 0x7e964c16, 0x7e8d44ba,
+       0x7e834033, 0x7e781728, 0x7e6b9933, 0x7e5d8a1a, 0x7e4d9ded,
+       0x7e3b737a, 0x7e268c2f, 0x7e0e3ff5, 0x7df1aa5d, 0x7dcf8c72,
+       0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a,
+       0x7ba90bdc, 0x7a722176, 0x77d664e5,
+}
+var wn = [128]float32{
+       1.7290405e-09, 1.2680929e-10, 1.6897518e-10, 1.9862688e-10,
+       2.2232431e-10, 2.4244937e-10, 2.601613e-10, 2.7611988e-10,
+       2.9073963e-10, 3.042997e-10, 3.1699796e-10, 3.289802e-10,
+       3.4035738e-10, 3.5121603e-10, 3.616251e-10, 3.7164058e-10,
+       3.8130857e-10, 3.9066758e-10, 3.9975012e-10, 4.08584e-10,
+       4.1719309e-10, 4.2559822e-10, 4.338176e-10, 4.418672e-10,
+       4.497613e-10, 4.5751258e-10, 4.651324e-10, 4.7263105e-10,
+       4.8001775e-10, 4.87301e-10, 4.944885e-10, 5.015873e-10,
+       5.0860405e-10, 5.155446e-10, 5.2241467e-10, 5.2921934e-10,
+       5.359635e-10, 5.426517e-10, 5.4928817e-10, 5.5587696e-10,
+       5.624219e-10, 5.6892646e-10, 5.753941e-10, 5.818282e-10,
+       5.882317e-10, 5.946077e-10, 6.00959e-10, 6.072884e-10,
+       6.135985e-10, 6.19892e-10, 6.2617134e-10, 6.3243905e-10,
+       6.386974e-10, 6.449488e-10, 6.511956e-10, 6.5744005e-10,
+       6.6368433e-10, 6.699307e-10, 6.7618144e-10, 6.824387e-10,
+       6.8870465e-10, 6.949815e-10, 7.012715e-10, 7.075768e-10,
+       7.1389966e-10, 7.202424e-10, 7.266073e-10, 7.329966e-10,
+       7.394128e-10, 7.4585826e-10, 7.5233547e-10, 7.58847e-10,
+       7.653954e-10, 7.719835e-10, 7.7861395e-10, 7.852897e-10,
+       7.920138e-10, 7.987892e-10, 8.0561924e-10, 8.125073e-10,
+       8.194569e-10, 8.2647167e-10, 8.3355556e-10, 8.407127e-10,
+       8.479473e-10, 8.55264e-10, 8.6266755e-10, 8.7016316e-10,
+       8.777562e-10, 8.8545243e-10, 8.932582e-10, 9.0117996e-10,
+       9.09225e-10, 9.174008e-10, 9.2571584e-10, 9.341788e-10,
+       9.427997e-10, 9.515889e-10, 9.605579e-10, 9.697193e-10,
+       9.790869e-10, 9.88676e-10, 9.985036e-10, 1.0085882e-09,
+       1.0189509e-09, 1.0296151e-09, 1.0406069e-09, 1.0519566e-09,
+       1.063698e-09, 1.0758702e-09, 1.0885183e-09, 1.1016947e-09,
+       1.1154611e-09, 1.1298902e-09, 1.1450696e-09, 1.1611052e-09,
+       1.1781276e-09, 1.1962995e-09, 1.2158287e-09, 1.2369856e-09,
+       1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09,
+       1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09,
+}
+var fn = [128]float32{
+       1, 0.9635997, 0.9362827, 0.9130436, 0.89228165, 0.87324303,
+       0.8555006, 0.8387836, 0.8229072, 0.8077383, 0.793177,
+       0.7791461, 0.7655842, 0.7524416, 0.73967725, 0.7272569,
+       0.7151515, 0.7033361, 0.69178915, 0.68049186, 0.6694277,
+       0.658582, 0.6479418, 0.63749546, 0.6272325, 0.6171434,
+       0.6072195, 0.5974532, 0.58783704, 0.5783647, 0.56903,
+       0.5598274, 0.5507518, 0.54179835, 0.5329627, 0.52424055,
+       0.5156282, 0.50712204, 0.49871865, 0.49041483, 0.48220766,
+       0.4740943, 0.46607214, 0.4581387, 0.45029163, 0.44252872,
+       0.43484783, 0.427247, 0.41972435, 0.41227803, 0.40490642,
+       0.39760786, 0.3903808, 0.3832238, 0.37613547, 0.36911446,
+       0.3621595, 0.35526937, 0.34844297, 0.34167916, 0.33497685,
+       0.3283351, 0.3217529, 0.3152294, 0.30876362, 0.30235484,
+       0.29600215, 0.28970486, 0.2834622, 0.2772735, 0.27113807,
+       0.2650553, 0.25902456, 0.2530453, 0.24711695, 0.241239,
+       0.23541094, 0.22963232, 0.2239027, 0.21822165, 0.21258877,
+       0.20700371, 0.20146611, 0.19597565, 0.19053204, 0.18513499,
+       0.17978427, 0.17447963, 0.1692209, 0.16400786, 0.15884037,
+       0.15371831, 0.14864157, 0.14361008, 0.13862377, 0.13368265,
+       0.12878671, 0.12393598, 0.119130544, 0.11437051, 0.10965602,
+       0.104987256, 0.10036444, 0.095787846, 0.0912578, 0.08677467,
+       0.0823389, 0.077950984, 0.073611505, 0.06932112, 0.06508058,
+       0.06089077, 0.056752663, 0.0526674, 0.048636295, 0.044660863,
+       0.040742867, 0.03688439, 0.033087887, 0.029356318,
+       0.025693292, 0.022103304, 0.018592102, 0.015167298,
+       0.011839478, 0.008624485, 0.005548995, 0.0026696292,
+}
diff --git a/libgo/go/rand/rand.go b/libgo/go/rand/rand.go
new file mode 100644 (file)
index 0000000..8c1219a
--- /dev/null
@@ -0,0 +1,185 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rand implements pseudo-random number generators.
+package rand
+
+import "sync"
+
+// A Source represents a source of uniformly-distributed
+// pseudo-random int64 values in the range [0, 1<<63).
+type Source interface {
+       Int63() int64
+       Seed(seed int64)
+}
+
+// NewSource returns a new pseudo-random Source seeded with the given value.
+func NewSource(seed int64) Source {
+       var rng rngSource
+       rng.Seed(seed)
+       return &rng
+}
+
+// A Rand is a source of random numbers.
+type Rand struct {
+       src Source
+}
+
+// New returns a new Rand that uses random values from src
+// to generate other random values.
+func New(src Source) *Rand { return &Rand{src} }
+
+// Seed uses the provided seed value to initialize the generator to a deterministic state.
+func (r *Rand) Seed(seed int64) { r.src.Seed(seed) }
+
+// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+func (r *Rand) Int63() int64 { return r.src.Int63() }
+
+// Uint32 returns a pseudo-random 32-bit value as a uint32.
+func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) }
+
+// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
+func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) }
+
+// Int returns a non-negative pseudo-random int.
+func (r *Rand) Int() int {
+       u := uint(r.Int63())
+       return int(u << 1 >> 1) // clear sign bit if int == int32
+}
+
+// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+func (r *Rand) Int63n(n int64) int64 {
+       if n <= 0 {
+               return 0
+       }
+       max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
+       v := r.Int63()
+       for v > max {
+               v = r.Int63()
+       }
+       return v % n
+}
+
+// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+func (r *Rand) Int31n(n int32) int32 {
+       if n <= 0 {
+               return 0
+       }
+       max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
+       v := r.Int31()
+       for v > max {
+               v = r.Int31()
+       }
+       return v % n
+}
+
+// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+func (r *Rand) Intn(n int) int {
+       if n <= 1<<31-1 {
+               return int(r.Int31n(int32(n)))
+       }
+       return int(r.Int63n(int64(n)))
+}
+
+// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
+func (r *Rand) Float64() float64 { return float64(r.Int63()) / (1 << 63) }
+
+// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
+func (r *Rand) Float32() float32 { return float32(r.Float64()) }
+
+// Float returns, as a float, a pseudo-random number in [0.0,1.0).
+func (r *Rand) Float() float { return float(r.Float64()) }
+
+// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
+func (r *Rand) Perm(n int) []int {
+       m := make([]int, n)
+       for i := 0; i < n; i++ {
+               m[i] = i
+       }
+       for i := 0; i < n; i++ {
+               j := r.Intn(i + 1)
+               m[i], m[j] = m[j], m[i]
+       }
+       return m
+}
+
+/*
+ * Top-level convenience functions
+ */
+
+var globalRand = New(&lockedSource{src: NewSource(1)})
+
+// Seed uses the provided seed value to initialize the generator to a deterministic state.
+func Seed(seed int64) { globalRand.Seed(seed) }
+
+// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+func Int63() int64 { return globalRand.Int63() }
+
+// Uint32 returns a pseudo-random 32-bit value as a uint32.
+func Uint32() uint32 { return globalRand.Uint32() }
+
+// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
+func Int31() int32 { return globalRand.Int31() }
+
+// Int returns a non-negative pseudo-random int.
+func Int() int { return globalRand.Int() }
+
+// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+func Int63n(n int64) int64 { return globalRand.Int63n(n) }
+
+// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+func Int31n(n int32) int32 { return globalRand.Int31n(n) }
+
+// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+func Intn(n int) int { return globalRand.Intn(n) }
+
+// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
+func Float64() float64 { return globalRand.Float64() }
+
+// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
+func Float32() float32 { return globalRand.Float32() }
+
+// Float returns, as a float, a pseudo-random number in [0.0,1.0).
+func Float() float { return globalRand.Float() }
+
+// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
+func Perm(n int) []int { return globalRand.Perm(n) }
+
+// NormFloat64 returns a normally distributed float64 in the range
+// [-math.MaxFloat64, +math.MaxFloat64] with
+// standard normal distribution (mean = 0, stddev = 1).
+// To produce a different normal distribution, callers can
+// adjust the output using:
+//
+//  sample = NormFloat64() * desiredStdDev + desiredMean
+//
+func NormFloat64() float64 { return globalRand.NormFloat64() }
+
+// ExpFloat64 returns an exponentially distributed float64 in the range
+// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
+// (lambda) is 1 and whose mean is 1/lambda (1).
+// To produce a distribution with a different rate parameter,
+// callers can adjust the output using:
+//
+//  sample = ExpFloat64() / desiredRateParameter
+//
+func ExpFloat64() float64 { return globalRand.ExpFloat64() }
+
+type lockedSource struct {
+       lk  sync.Mutex
+       src Source
+}
+
+func (r *lockedSource) Int63() (n int64) {
+       r.lk.Lock()
+       n = r.src.Int63()
+       r.lk.Unlock()
+       return
+}
+
+func (r *lockedSource) Seed(seed int64) {
+       r.lk.Lock()
+       r.src.Seed(seed)
+       r.lk.Unlock()
+}
diff --git a/libgo/go/rand/rand_test.go b/libgo/go/rand/rand_test.go
new file mode 100644 (file)
index 0000000..b9bf432
--- /dev/null
@@ -0,0 +1,350 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+       "math"
+       "fmt"
+       "os"
+       "testing"
+)
+
+const (
+       numTestSamples = 10000
+)
+
+type statsResults struct {
+       mean        float64
+       stddev      float64
+       closeEnough float64
+       maxError    float64
+}
+
+func max(a, b float64) float64 {
+       if a > b {
+               return a
+       }
+       return b
+}
+
+func nearEqual(a, b, closeEnough, maxError float64) bool {
+       absDiff := math.Fabs(a - b)
+       if absDiff < closeEnough { // Necessary when one value is zero and one value is close to zero.
+               return true
+       }
+       return absDiff/max(math.Fabs(a), math.Fabs(b)) < maxError
+}
+
+var testSeeds = []int64{1, 1754801282, 1698661970, 1550503961}
+
+// checkSimilarDistribution returns success if the mean and stddev of the
+// two statsResults are similar.
+func (this *statsResults) checkSimilarDistribution(expected *statsResults) os.Error {
+       if !nearEqual(this.mean, expected.mean, expected.closeEnough, expected.maxError) {
+               s := fmt.Sprintf("mean %v != %v (allowed error %v, %v)", this.mean, expected.mean, expected.closeEnough, expected.maxError)
+               fmt.Println(s)
+               return os.ErrorString(s)
+       }
+       if !nearEqual(this.stddev, expected.stddev, 0, expected.maxError) {
+               s := fmt.Sprintf("stddev %v != %v (allowed error %v, %v)", this.stddev, expected.stddev, expected.closeEnough, expected.maxError)
+               fmt.Println(s)
+               return os.ErrorString(s)
+       }
+       return nil
+}
+
+func getStatsResults(samples []float64) *statsResults {
+       res := new(statsResults)
+       var sum float64
+       for i := range samples {
+               sum += samples[i]
+       }
+       res.mean = sum / float64(len(samples))
+       var devsum float64
+       for i := range samples {
+               devsum += math.Pow(samples[i]-res.mean, 2)
+       }
+       res.stddev = math.Sqrt(devsum / float64(len(samples)))
+       return res
+}
+
+func checkSampleDistribution(t *testing.T, samples []float64, expected *statsResults) {
+       actual := getStatsResults(samples)
+       err := actual.checkSimilarDistribution(expected)
+       if err != nil {
+               t.Errorf(err.String())
+       }
+}
+
+func checkSampleSliceDistributions(t *testing.T, samples []float64, nslices int, expected *statsResults) {
+       chunk := len(samples) / nslices
+       for i := 0; i < nslices; i++ {
+               low := i * chunk
+               var high int
+               if i == nslices-1 {
+                       high = len(samples) - 1
+               } else {
+                       high = (i + 1) * chunk
+               }
+               checkSampleDistribution(t, samples[low:high], expected)
+       }
+}
+
+//
+// Normal distribution tests
+//
+
+func generateNormalSamples(nsamples int, mean, stddev float64, seed int64) []float64 {
+       r := New(NewSource(seed))
+       samples := make([]float64, nsamples)
+       for i := range samples {
+               samples[i] = r.NormFloat64()*stddev + mean
+       }
+       return samples
+}
+
+func testNormalDistribution(t *testing.T, nsamples int, mean, stddev float64, seed int64) {
+       //fmt.Printf("testing nsamples=%v mean=%v stddev=%v seed=%v\n", nsamples, mean, stddev, seed);
+
+       samples := generateNormalSamples(nsamples, mean, stddev, seed)
+       errorScale := max(1.0, stddev) // Error scales with stddev
+       expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.08 * errorScale}
+
+       // Make sure that the entire set matches the expected distribution.
+       checkSampleDistribution(t, samples, expected)
+
+       // Make sure that each half of the set matches the expected distribution.
+       checkSampleSliceDistributions(t, samples, 2, expected)
+
+       // Make sure that each 7th of the set matches the expected distribution.
+       checkSampleSliceDistributions(t, samples, 7, expected)
+}
+
+// Actual tests
+
+func TestStandardNormalValues(t *testing.T) {
+       for _, seed := range testSeeds {
+               testNormalDistribution(t, numTestSamples, 0, 1, seed)
+       }
+}
+
+func TestNonStandardNormalValues(t *testing.T) {
+       for sd := float64(0.5); sd < 1000; sd *= 2 {
+               for m := float64(0.5); m < 1000; m *= 2 {
+                       for _, seed := range testSeeds {
+                               testNormalDistribution(t, numTestSamples, m, sd, seed)
+                       }
+               }
+       }
+}
+
+//
+// Exponential distribution tests
+//
+
+func generateExponentialSamples(nsamples int, rate float64, seed int64) []float64 {
+       r := New(NewSource(seed))
+       samples := make([]float64, nsamples)
+       for i := range samples {
+               samples[i] = r.ExpFloat64() / rate
+       }
+       return samples
+}
+
+func testExponentialDistribution(t *testing.T, nsamples int, rate float64, seed int64) {
+       //fmt.Printf("testing nsamples=%v rate=%v seed=%v\n", nsamples, rate, seed);
+
+       mean := 1 / rate
+       stddev := mean
+
+       samples := generateExponentialSamples(nsamples, rate, seed)
+       errorScale := max(1.0, 1/rate) // Error scales with the inverse of the rate
+       expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.20 * errorScale}
+
+       // Make sure that the entire set matches the expected distribution.
+       checkSampleDistribution(t, samples, expected)
+
+       // Make sure that each half of the set matches the expected distribution.
+       checkSampleSliceDistributions(t, samples, 2, expected)
+
+       // Make sure that each 7th of the set matches the expected distribution.
+       checkSampleSliceDistributions(t, samples, 7, expected)
+}
+
+// Actual tests
+
+func TestStandardExponentialValues(t *testing.T) {
+       for _, seed := range testSeeds {
+               testExponentialDistribution(t, numTestSamples, 1, seed)
+       }
+}
+
+func TestNonStandardExponentialValues(t *testing.T) {
+       for rate := float64(0.05); rate < 10; rate *= 2 {
+               for _, seed := range testSeeds {
+                       testExponentialDistribution(t, numTestSamples, rate, seed)
+               }
+       }
+}
+
+//
+// Table generation tests
+//
+
+func initNorm() (testKn []uint32, testWn, testFn []float32) {
+       const m1 = 1 << 31
+       var (
+               dn float64 = rn
+               tn = dn
+               vn float64 = 9.91256303526217e-3
+       )
+
+       testKn = make([]uint32, 128)
+       testWn = make([]float32, 128)
+       testFn = make([]float32, 128)
+
+       q := vn / math.Exp(-0.5*dn*dn)
+       testKn[0] = uint32((dn / q) * m1)
+       testKn[1] = 0
+       testWn[0] = float32(q / m1)
+       testWn[127] = float32(dn / m1)
+       testFn[0] = 1.0
+       testFn[127] = float32(math.Exp(-0.5 * dn * dn))
+       for i := 126; i >= 1; i-- {
+               dn = math.Sqrt(-2.0 * math.Log(vn/dn+math.Exp(-0.5*dn*dn)))
+               testKn[i+1] = uint32((dn / tn) * m1)
+               tn = dn
+               testFn[i] = float32(math.Exp(-0.5 * dn * dn))
+               testWn[i] = float32(dn / m1)
+       }
+       return
+}
+
+func initExp() (testKe []uint32, testWe, testFe []float32) {
+       const m2 = 1 << 32
+       var (
+               de float64 = re
+               te = de
+               ve float64 = 3.9496598225815571993e-3
+       )
+
+       testKe = make([]uint32, 256)
+       testWe = make([]float32, 256)
+       testFe = make([]float32, 256)
+
+       q := ve / math.Exp(-de)
+       testKe[0] = uint32((de / q) * m2)
+       testKe[1] = 0
+       testWe[0] = float32(q / m2)
+       testWe[255] = float32(de / m2)
+       testFe[0] = 1.0
+       testFe[255] = float32(math.Exp(-de))
+       for i := 254; i >= 1; i-- {
+               de = -math.Log(ve/de + math.Exp(-de))
+               testKe[i+1] = uint32((de / te) * m2)
+               te = de
+               testFe[i] = float32(math.Exp(-de))
+               testWe[i] = float32(de / m2)
+       }
+       return
+}
+
+// compareUint32Slices returns the first index where the two slices
+// disagree, or <0 if the lengths are the same and all elements
+// are identical.
+func compareUint32Slices(s1, s2 []uint32) int {
+       if len(s1) != len(s2) {
+               if len(s1) > len(s2) {
+                       return len(s2) + 1
+               }
+               return len(s1) + 1
+       }
+       for i := range s1 {
+               if s1[i] != s2[i] {
+                       return i
+               }
+       }
+       return -1
+}
+
+// compareFloat32Slices returns the first index where the two slices
+// disagree, or <0 if the lengths are the same and all elements
+// are identical.
+func compareFloat32Slices(s1, s2 []float32) int {
+       if len(s1) != len(s2) {
+               if len(s1) > len(s2) {
+                       return len(s2) + 1
+               }
+               return len(s1) + 1
+       }
+       for i := range s1 {
+               if !nearEqual(float64(s1[i]), float64(s2[i]), 0, 1e-7) {
+                       return i
+               }
+       }
+       return -1
+}
+
+func TestNormTables(t *testing.T) {
+       testKn, testWn, testFn := initNorm()
+       if i := compareUint32Slices(kn[0:], testKn); i >= 0 {
+               t.Errorf("kn disagrees at index %v; %v != %v", i, kn[i], testKn[i])
+       }
+       if i := compareFloat32Slices(wn[0:], testWn); i >= 0 {
+               t.Errorf("wn disagrees at index %v; %v != %v", i, wn[i], testWn[i])
+       }
+       if i := compareFloat32Slices(fn[0:], testFn); i >= 0 {
+               t.Errorf("fn disagrees at index %v; %v != %v", i, fn[i], testFn[i])
+       }
+}
+
+func TestExpTables(t *testing.T) {
+       testKe, testWe, testFe := initExp()
+       if i := compareUint32Slices(ke[0:], testKe); i >= 0 {
+               t.Errorf("ke disagrees at index %v; %v != %v", i, ke[i], testKe[i])
+       }
+       if i := compareFloat32Slices(we[0:], testWe); i >= 0 {
+               t.Errorf("we disagrees at index %v; %v != %v", i, we[i], testWe[i])
+       }
+       if i := compareFloat32Slices(fe[0:], testFe); i >= 0 {
+               t.Errorf("fe disagrees at index %v; %v != %v", i, fe[i], testFe[i])
+       }
+}
+
+// Benchmarks
+
+func BenchmarkInt63Threadsafe(b *testing.B) {
+       for n := b.N; n > 0; n-- {
+               Int63()
+       }
+}
+
+func BenchmarkInt63Unthreadsafe(b *testing.B) {
+       r := New(NewSource(1))
+       for n := b.N; n > 0; n-- {
+               r.Int63()
+       }
+}
+
+func BenchmarkIntn1000(b *testing.B) {
+       r := New(NewSource(1))
+       for n := b.N; n > 0; n-- {
+               r.Intn(1000)
+       }
+}
+
+func BenchmarkInt63n1000(b *testing.B) {
+       r := New(NewSource(1))
+       for n := b.N; n > 0; n-- {
+               r.Int63n(1000)
+       }
+}
+
+func BenchmarkInt31n1000(b *testing.B) {
+       r := New(NewSource(1))
+       for n := b.N; n > 0; n-- {
+               r.Int31n(1000)
+       }
+}
diff --git a/libgo/go/rand/rng.go b/libgo/go/rand/rng.go
new file mode 100644 (file)
index 0000000..947c49f
--- /dev/null
@@ -0,0 +1,246 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+/*
+ * Uniform distribution
+ *
+ * algorithm by
+ * DP Mitchell and JA Reeds
+ */
+
+const (
+       _LEN  = 607
+       _TAP  = 273
+       _MAX  = 1 << 63
+       _MASK = _MAX - 1
+       _A    = 48271
+       _M    = (1 << 31) - 1
+       _Q    = 44488
+       _R    = 3399
+)
+
+var (
+       // cooked random numbers
+       // the state of the rng
+       // after 780e10 iterations
+       rng_cooked [_LEN]int64 = [...]int64{
+               5041579894721019882, 4646389086726545243, 1395769623340756751, 5333664234075297259,
+               2875692520355975054, 9033628115061424579, 7143218595135194537, 4812947590706362721,
+               7937252194349799378, 5307299880338848416, 8209348851763925077, 2115741599318814044,
+               4593015457530856296, 8140875735541888011, 3319429241265089026, 8619815648190321034,
+               1727074043483619500, 113108499721038619, 4569519971459345583, 5062833859075314731,
+               2387618771259064424, 2716131344356686112, 6559392774825876886, 7650093201692370310,
+               7684323884043752161, 257867835996031390, 6593456519409015164, 271327514973697897,
+               2789386447340118284, 1065192797246149621, 3344507881999356393, 4459797941780066633,
+               7465081662728599889, 1014950805555097187, 4449440729345990775, 3481109366438502643,
+               2418672789110888383, 5796562887576294778, 4484266064449540171, 3738982361971787048,
+               4523597184512354423, 10530508058128498, 8633833783282346118, 2625309929628791628,
+               8660405965245884302, 10162832508971942, 6540714680961817391, 7031802312784620857,
+               6240911277345944669, 831864355460801054, 8004434137542152891, 2116287251661052151,
+               2202309800992166967, 9161020366945053561, 4069299552407763864, 4936383537992622449,
+               457351505131524928, 342195045928179354, 2847771682816600509, 2068020115986376518,
+               4368649989588021065, 887231587095185257, 5563591506886576496, 6816225200251950296,
+               5616972787034086048, 8471809303394836566, 1686575021641186857, 4045484338074262002,
+               4244156215201778923, 7848217333783577387, 5632136521049761902, 833283142057835272,
+               9029726508369077193, 3243583134664087292, 4316371101804477087, 8937849979965997980,
+               6446940406810434101, 1679342092332374735, 6050638460742422078, 6993520719509581582,
+               7640877852514293609, 5881353426285907985, 812786550756860885, 4541845584483343330,
+               2725470216277009086, 4980675660146853729, 5210769080603236061, 8894283318990530821,
+               6326442804750084282, 1495812843684243920, 7069751578799128019, 7370257291860230865,
+               6756929275356942261, 4706794511633873654, 7824520467827898663, 8549875090542453214,
+               33650829478596156, 1328918435751322643, 7297902601803624459, 1011190183918857495,
+               2238025036817854944, 5147159997473910359, 896512091560522982, 2659470849286379941,
+               6097729358393448602, 1731725986304753684, 4106255841983812711, 8327155210721535508,
+               8477511620686074402, 5803876044675762232, 8435417780860221662, 5988852856651071244,
+               4715837297103951910, 7566171971264485114, 505808562678895611, 5070098180695063370,
+               842110666775871513, 572156825025677802, 1791881013492340891, 3393267094866038768,
+               3778721850472236509, 2352769483186201278, 1292459583847367458, 8897907043675088419,
+               5781809037144163536, 2733958794029492513, 5092019688680754699, 8996124554772526841,
+               4234737173186232084, 5027558287275472836, 4635198586344772304, 8687338893267139351,
+               5907508150730407386, 784756255473944452, 972392927514829904, 5422057694808175112,
+               5158420642969283891, 9048531678558643225, 2407211146698877100, 7583282216521099569,
+               3940796514530962282, 3341174631045206375, 3095313889586102949, 7405321895688238710,
+               5832080132947175283, 7890064875145919662, 8184139210799583195, 1149859861409226130,
+               1464597243840211302, 4641648007187991873, 3516491885471466898, 956288521791657692,
+               6657089965014657519, 5220884358887979358, 1796677326474620641, 5340761970648932916,
+               1147977171614181568, 5066037465548252321, 2574765911837859848, 1085848279845204775,
+               3350107529868390359, 6116438694366558490, 2107701075971293812, 1803294065921269267,
+               2469478054175558874, 7368243281019965984, 3791908367843677526, 185046971116456637,
+               2257095756513439648, 7217693971077460129, 909049953079504259, 7196649268545224266,
+               5637660345400869599, 3955544945427965183, 8057528650917418961, 4139268440301127643,
+               6621926588513568059, 1373361136802681441, 6527366231383600011, 3507654575162700890,
+               9202058512774729859, 1954818376891585542, 6640380907130175705, 8299563319178235687,
+               3901867355218954373, 7046310742295574065, 6847195391333990232, 1572638100518868053,
+               8850422670118399721, 3631909142291992901, 5158881091950831288, 2882958317343121593,
+               4763258931815816403, 6280052734341785344, 4243789408204964850, 2043464728020827976,
+               6545300466022085465, 4562580375758598164, 5495451168795427352, 1738312861590151095,
+               553004618757816492, 6895160632757959823, 8233623922264685171, 7139506338801360852,
+               8550891222387991669, 5535668688139305547, 2430933853350256242, 5401941257863201076,
+               8159640039107728799, 6157493831600770366, 7632066283658143750, 6308328381617103346,
+               3681878764086140361, 3289686137190109749, 6587997200611086848, 244714774258135476,
+               4079788377417136100, 8090302575944624335, 2945117363431356361, 864324395848741045,
+               3009039260312620700, 8430027460082534031, 401084700045993341, 7254622446438694921,
+               4707864159563588614, 5640248530963493951, 5982507712689997893, 3315098242282210105,
+               5503847578771918426, 3941971367175193882, 8118566580304798074, 3839261274019871296,
+               7062410411742090847, 741381002980207668, 6027994129690250817, 2497829994150063930,
+               6251390334426228834, 1368930247903518833, 8809096399316380241, 6492004350391900708,
+               2462145737463489636, 404828418920299174, 4153026434231690595, 261785715255475940,
+               5464715384600071357, 592710404378763017, 6764129236657751224, 8513655718539357449,
+               5820343663801914208, 385298524683789911, 5224135003438199467, 6303131641338802145,
+               7150122561309371392, 368107899140673753, 3115186834558311558, 2915636353584281051,
+               4782583894627718279, 6718292300699989587, 8387085186914375220, 3387513132024756289,
+               4654329375432538231, 8930667561363381602, 5374373436876319273, 7623042350483453954,
+               7725442901813263321, 9186225467561587250, 4091027289597503355, 2357631606492579800,
+               2530936820058611833, 1636551876240043639, 5564664674334965799, 1452244145334316253,
+               2061642381019690829, 1279580266495294036, 9108481583171221009, 6023278686734049809,
+               5007630032676973346, 2153168792952589781, 6720334534964750538, 6041546491134794105,
+               3433922409283786309, 2285479922797300912, 3110614940896576130, 6366559590722842893,
+               5418791419666136509, 7163298419643543757, 4891138053923696990, 580618510277907015,
+               1684034065251686769, 4429514767357295841, 330346578555450005, 1119637995812174675,
+               7177515271653460134, 4589042248470800257, 7693288629059004563, 143607045258444228,
+               246994305896273627, 866417324803099287, 6473547110565816071, 3092379936208876896,
+               2058427839513754051, 5133784708526867938, 8785882556301281247, 6149332666841167611,
+               8585842181454472135, 6137678347805511274, 2070447184436970006, 5708223427705576541,
+               5999657892458244504, 4358391411789012426, 325123008708389849, 6837621693887290924,
+               4843721905315627004, 6010651222149276415, 5398352198963874652, 4602025990114250980,
+               1044646352569048800, 9106614159853161675, 829256115228593269, 4919284369102997000,
+               2681532557646850893, 3681559472488511871, 5307999518958214035, 6334130388442829274,
+               2658708232916537604, 1163313865052186287, 581945337509520675, 3648778920718647903,
+               4423673246306544414, 1620799783996955743, 220828013409515943, 8150384699999389761,
+               4287360518296753003, 4590000184845883843, 5513660857261085186, 6964829100392774275,
+               478991688350776035, 8746140185685648781, 228500091334420247, 1356187007457302238,
+               3019253992034194581, 3152601605678500003, 430152752706002213, 5559581553696971176,
+               4916432985369275664, 663574931734554391, 3420773838927732076, 2868348622579915573,
+               1999319134044418520, 3328689518636282723, 2587672709781371173, 1517255313529399333,
+               3092343956317362483, 3662252519007064108, 972445599196498113, 7664865435875959367,
+               1708913533482282562, 6917817162668868494, 3217629022545312900, 2570043027221707107,
+               8739788839543624613, 2488075924621352812, 4694002395387436668, 4559628481798514356,
+               2997203966153298104, 1282559373026354493, 240113143146674385, 8665713329246516443,
+               628141331766346752, 4571950817186770476, 1472811188152235408, 7596648026010355826,
+               6091219417754424743, 7834161864828164065, 7103445518877254909, 4390861237357459201,
+               4442653864240571734, 8903482404847331368, 622261699494173647, 6037261250297213248,
+               504404948065709118, 7275215526217113061, 1011176780856001400, 2194750105623461063,
+               2623071828615234808, 5157313728073836108, 3738405111966602044, 2539767524076729570,
+               2467284396349269342, 5256026990536851868, 7841086888628396109, 6640857538655893162,
+               1202087339038317498, 2113514992440715978, 7534350895342931403, 4925284734898484745,
+               5145623771477493805, 8225140880134972332, 2719520354384050532, 9132346697815513771,
+               4332154495710163773, 7137789594094346916, 6994721091344268833, 6667228574869048934,
+               655440045726677499, 59934747298466858, 6124974028078036405, 8957774780655365418,
+               2332206071942466437, 1701056712286369627, 3154897383618636503, 1637766181387607527,
+               2460521277767576533, 197309393502684135, 643677854385267315, 2543179307861934850,
+               4350769010207485119, 4754652089410667672, 2015595502641514512, 7999059458976458608,
+               4287946071480840813, 8362686366770308971, 6486469209321732151, 3617727845841796026,
+               7554353525834302244, 4450022655153542367, 1605195740213535749, 5327014565305508387,
+               4626575813550328320, 2692222020597705149, 241045573717249868, 5098046974627094010,
+               7916882295460730264, 884817090297530579, 5329160409530630596, 7790979528857726136,
+               4955070238059373407, 4918537275422674302, 3008076183950404629, 3007769226071157901,
+               2470346235617803020, 8928702772696731736, 7856187920214445904, 4474874585391974885,
+               7900176660600710914, 2140571127916226672, 2425445057265199971, 2486055153341847830,
+               4186670094382025798, 1883939007446035042, 8808666044074867985, 3734134241178479257,
+               4065968871360089196, 6953124200385847784, 1305686814738899057, 1637739099014457647,
+               3656125660947993209, 3966759634633167020, 3106378204088556331, 6328899822778449810,
+               4565385105440252958, 1979884289539493806, 2331793186920865425, 3783206694208922581,
+               8464961209802336085, 2843963751609577687, 3030678195484896323, 4793717574095772604,
+               4459239494808162889, 402587895800087237, 8057891408711167515, 4541888170938985079,
+               1042662272908816815, 5557303057122568958, 2647678726283249984, 2144477441549833761,
+               5806352215355387087, 7117771003473903623, 5916597177708541638, 462597715452321361,
+               8833658097025758785, 5970273481425315300, 563813119381731307, 2768349550652697015,
+               1598828206250873866, 5206393647403558110, 6235043485709261823, 3152217402014639496,
+               8469693267274066490, 125672920241807416, 5311079624024060938, 6663754932310491587,
+               8736848295048751716, 4488039774992061878, 5923302823487327109, 140891791083103236,
+               7414942793393574290, 7990420780896957397, 4317817392807076702, 3625184369705367340,
+               2740722765288122703, 5743100009702758344, 5997898640509039159, 8854493341352484163,
+               5242208035432907801, 701338899890987198, 7609280429197514109, 3020985755112334161,
+               6651322707055512866, 2635195723621160615, 5144520864246028816, 1035086515727829828,
+               1567242097116389047, 8172389260191636581, 6337820351429292273, 2163012566996458925,
+               2743190902890262681, 1906367633221323427, 6011544915663598137, 5932255307352610768,
+               2241128460406315459, 895504896216695588, 3094483003111372717, 4583857460292963101,
+               9079887171656594975, 8839289181930711403, 5762740387243057873, 4225072055348026230,
+               1838220598389033063, 3801620336801580414, 8823526620080073856, 1776617605585100335,
+               7899055018877642622, 5421679761463003041, 5521102963086275121, 4248279443559365898,
+               8735487530905098534, 1760527091573692978, 7142485049657745894, 8222656872927218123,
+               4969531564923704323, 3394475942196872480, 6424174453260338141, 359248545074932887,
+               3273651282831730598, 6797106199797138596, 3030918217665093212, 145600834617314036,
+               6036575856065626233, 740416251634527158, 7080427635449935582, 6951781370868335478,
+               399922722363687927, 294902314447253185, 7844950936339178523, 880320858634709042,
+               6192655680808675579, 411604686384710388, 9026808440365124461, 6440783557497587732,
+               4615674634722404292, 539897290441580544, 2096238225866883852, 8751955639408182687,
+               1907224908052289603, 7381039757301768559, 6157238513393239656, 7749994231914157575,
+               8629571604380892756, 5280433031239081479, 7101611890139813254, 2479018537985767835,
+               7169176924412769570, 7942066497793203302, 1357759729055557688, 2278447439451174845,
+               3625338785743880657, 6477479539006708521, 8976185375579272206, 5511371554711836120,
+               1326024180520890843, 7537449876596048829, 5464680203499696154, 3189671183162196045,
+               6346751753565857109, 241159987320630307, 3095793449658682053, 8978332846736310159,
+               2902794662273147216, 7208698530190629697, 7276901792339343736, 1732385229314443140,
+               4133292154170828382, 2918308698224194548, 1519461397937144458, 5293934712616591764,
+               4922828954023452664, 2879211533496425641, 5896236396443472108, 8465043815351752425,
+               7329020396871624740, 8915471717014488588, 2944902635677463047, 7052079073493465134,
+               8382142935188824023, 9103922860780351547, 4152330101494654406,
+       }
+)
+
+type rngSource struct {
+       tap  int         // index into vec
+       feed int         // index into vec
+       vec  [_LEN]int64 // current feedback register
+}
+
+// seed rng x[n+1] = 48271 * x[n] mod (2**31 - 1)
+func seedrand(x int32) int32 {
+       hi := x / _Q
+       lo := x % _Q
+       x = _A*lo - _R*hi
+       if x < 0 {
+               x += _M
+       }
+       return x
+}
+
+// Seed uses the provided seed value to initialize the generator to a deterministic state.
+func (rng *rngSource) Seed(seed int64) {
+       rng.tap = 0
+       rng.feed = _LEN - _TAP
+
+       seed = seed % _M
+       if seed < 0 {
+               seed += _M
+       }
+       if seed == 0 {
+               seed = 89482311
+       }
+
+       x := int32(seed)
+       for i := -20; i < _LEN; i++ {
+               x = seedrand(x)
+               if i >= 0 {
+                       var u int64
+                       u = int64(x) << 40
+                       x = seedrand(x)
+                       u ^= int64(x) << 20
+                       x = seedrand(x)
+                       u ^= int64(x)
+                       u ^= rng_cooked[i]
+                       rng.vec[i] = u & _MASK
+               }
+       }
+}
+
+// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+func (rng *rngSource) Int63() int64 {
+       rng.tap--
+       if rng.tap < 0 {
+               rng.tap += _LEN
+       }
+
+       rng.feed--
+       if rng.feed < 0 {
+               rng.feed += _LEN
+       }
+
+       x := (rng.vec[rng.feed] + rng.vec[rng.tap]) & _MASK
+       rng.vec[rng.feed] = x
+       return x
+}
diff --git a/libgo/go/rand/zipf.go b/libgo/go/rand/zipf.go
new file mode 100644 (file)
index 0000000..c4e7b7d
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// W.Hormann, G.Derflinger:
+// "Rejection-Inversion to Generate Variates
+// from Monotone Discrete Distributions"
+// http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz
+
+package rand
+
+import "math"
+
+// A Zipf generates Zipf distributed variates.
+type Zipf struct {
+       r            *Rand
+       imax         float64
+       v            float64
+       q            float64
+       s            float64
+       oneminusQ    float64
+       oneminusQinv float64
+       hxm          float64
+       hx0minusHxm  float64
+}
+
+func (z *Zipf) h(x float64) float64 {
+       return math.Exp(z.oneminusQ*math.Log(z.v+x)) * z.oneminusQinv
+}
+
+func (z *Zipf) hinv(x float64) float64 {
+       return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v
+}
+
+// NewZipf returns a Zipf generating variates p(k) on [0, imax]
+// proportional to (v+k)**(-s) where s>1 and k>=0, and v>=1.
+//
+func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf {
+       z := new(Zipf)
+       if s <= 1.0 || v < 1 {
+               return nil
+       }
+       z.r = r
+       z.imax = float64(imax)
+       z.v = v
+       z.q = s
+       z.oneminusQ = 1.0 - z.q
+       z.oneminusQinv = 1.0 / z.oneminusQ
+       z.hxm = z.h(z.imax + 0.5)
+       z.hx0minusHxm = z.h(0.5) - math.Exp(math.Log(z.v)*(-z.q)) - z.hxm
+       z.s = 1 - z.hinv(z.h(1.5)-math.Exp(-z.q*math.Log(z.v+1.0)))
+       return z
+}
+
+// Uint64 returns a value drawn from the Zipf distributed described
+// by the Zipf object.
+func (z *Zipf) Uint64() uint64 {
+       k := float64(0.0)
+
+       for {
+               r := z.r.Float64() // r on [0,1]
+               ur := z.hxm + r*z.hx0minusHxm
+               x := z.hinv(ur)
+               k = math.Floor(x + 0.5)
+               if k-x <= z.s {
+                       break
+               }
+               if ur >= z.h(k+0.5)-math.Exp(-math.Log(k+z.v)*z.q) {
+                       break
+               }
+       }
+       return uint64(k)
+}
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
new file mode 100644 (file)
index 0000000..4071a97
--- /dev/null
@@ -0,0 +1,1356 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect_test
+
+import (
+       "container/vector"
+       "fmt"
+       "io"
+       "os"
+       . "reflect"
+       "testing"
+       "unsafe"
+)
+
+type integer int
+type T struct {
+       a int
+       b float64
+       c string
+       d *int
+}
+
+type pair struct {
+       i interface{}
+       s string
+}
+
+func isDigit(c uint8) bool { return '0' <= c && c <= '9' }
+
+func assert(t *testing.T, s, want string) {
+       if s != want {
+               t.Errorf("have %#q want %#q", s, want)
+       }
+}
+
+func typestring(i interface{}) string { return Typeof(i).String() }
+
+var typeTests = []pair{
+       {struct{ x int }{}, "int"},
+       {struct{ x int8 }{}, "int8"},
+       {struct{ x int16 }{}, "int16"},
+       {struct{ x int32 }{}, "int32"},
+       {struct{ x int64 }{}, "int64"},
+       {struct{ x uint }{}, "uint"},
+       {struct{ x uint8 }{}, "uint8"},
+       {struct{ x uint16 }{}, "uint16"},
+       {struct{ x uint32 }{}, "uint32"},
+       {struct{ x uint64 }{}, "uint64"},
+       {struct{ x float }{}, "float"},
+       {struct{ x float32 }{}, "float32"},
+       {struct{ x float64 }{}, "float64"},
+       {struct{ x int8 }{}, "int8"},
+       {struct{ x (**int8) }{}, "**int8"},
+       {struct{ x (**integer) }{}, "**reflect_test.integer"},
+       {struct{ x ([32]int32) }{}, "[32]int32"},
+       {struct{ x ([]int8) }{}, "[]int8"},
+       {struct{ x (map[string]int32) }{}, "map[string] int32"},
+       {struct{ x (chan<- string) }{}, "chan<- string"},
+       {struct {
+               x struct {
+                       c chan *int32
+                       d float32
+               }
+       }{},
+               "struct { c chan *int32; d float32 }",
+       },
+       {struct{ x (func(a int8, b int32)) }{}, "func(int8, int32)"},
+       {struct {
+               x struct {
+                       c func(chan *integer, *int8)
+               }
+       }{},
+               "struct { c func(chan *reflect_test.integer, *int8) }",
+       },
+       {struct {
+               x struct {
+                       a int8
+                       b int32
+               }
+       }{},
+               "struct { a int8; b int32 }",
+       },
+       {struct {
+               x struct {
+                       a int8
+                       b int8
+                       c int32
+               }
+       }{},
+               "struct { a int8; b int8; c int32 }",
+       },
+       {struct {
+               x struct {
+                       a int8
+                       b int8
+                       c int8
+                       d int32
+               }
+       }{},
+               "struct { a int8; b int8; c int8; d int32 }",
+       },
+       {struct {
+               x struct {
+                       a int8
+                       b int8
+                       c int8
+                       d int8
+                       e int32
+               }
+       }{},
+               "struct { a int8; b int8; c int8; d int8; e int32 }",
+       },
+       {struct {
+               x struct {
+                       a int8
+                       b int8
+                       c int8
+                       d int8
+                       e int8
+                       f int32
+               }
+       }{},
+               "struct { a int8; b int8; c int8; d int8; e int8; f int32 }",
+       },
+       {struct {
+               x struct {
+                       a int8 "hi there"
+               }
+       }{},
+               `struct { a int8 "hi there" }`,
+       },
+       {struct {
+               x struct {
+                       a int8 "hi \x00there\t\n\"\\"
+               }
+       }{},
+               `struct { a int8 "hi \x00there\t\n\"\\" }`,
+       },
+       {struct {
+               x struct {
+                       f func(args ...int)
+               }
+       }{},
+               "struct { f func(...int) }",
+       },
+       {struct {
+               x (interface {
+                       a(func(func(int) int) func(func(int)) int)
+                       b()
+               })
+       }{},
+               "interface { a(func(func(int) int) func(func(int)) int); b() }",
+       },
+}
+
+var valueTests = []pair{
+       {(int8)(0), "8"},
+       {(int16)(0), "16"},
+       {(int32)(0), "32"},
+       {(int64)(0), "64"},
+       {(uint8)(0), "8"},
+       {(uint16)(0), "16"},
+       {(uint32)(0), "32"},
+       {(uint64)(0), "64"},
+       {(float32)(0), "256.25"},
+       {(float64)(0), "512.125"},
+       {(string)(""), "stringy cheese"},
+       {(bool)(false), "true"},
+       {(*int8)(nil), "*int8(0)"},
+       {(**int8)(nil), "**int8(0)"},
+       {[5]int32{}, "[5]int32{0, 0, 0, 0, 0}"},
+       {(**integer)(nil), "**reflect_test.integer(0)"},
+       {(map[string]int32)(nil), "map[string] int32{<can't iterate on maps>}"},
+       {(chan<- string)(nil), "chan<- string"},
+       {struct {
+               c chan *int32
+               d float32
+       }{},
+               "struct { c chan *int32; d float32 }{chan *int32, 0}",
+       },
+       {(func(a int8, b int32))(nil), "func(int8, int32)(0)"},
+       {struct{ c func(chan *integer, *int8) }{},
+               "struct { c func(chan *reflect_test.integer, *int8) }{func(chan *reflect_test.integer, *int8)(0)}",
+       },
+       {struct {
+               a int8
+               b int32
+       }{},
+               "struct { a int8; b int32 }{0, 0}",
+       },
+       {struct {
+               a int8
+               b int8
+               c int32
+       }{},
+               "struct { a int8; b int8; c int32 }{0, 0, 0}",
+       },
+}
+
+func testType(t *testing.T, i int, typ Type, want string) {
+       s := typ.String()
+       if s != want {
+               t.Errorf("#%d: have %#q, want %#q", i, s, want)
+       }
+}
+
+func TestTypes(t *testing.T) {
+       for i, tt := range typeTests {
+               testType(t, i, NewValue(tt.i).(*StructValue).Field(0).Type(), tt.s)
+       }
+}
+
+func TestSet(t *testing.T) {
+       for i, tt := range valueTests {
+               v := NewValue(tt.i)
+               switch v := v.(type) {
+               case *IntValue:
+                       switch v.Type().Kind() {
+                       case Int:
+                               v.Set(132)
+                       case Int8:
+                               v.Set(8)
+                       case Int16:
+                               v.Set(16)
+                       case Int32:
+                               v.Set(32)
+                       case Int64:
+                               v.Set(64)
+                       }
+               case *UintValue:
+                       switch v.Type().Kind() {
+                       case Uint:
+                               v.Set(132)
+                       case Uint8:
+                               v.Set(8)
+                       case Uint16:
+                               v.Set(16)
+                       case Uint32:
+                               v.Set(32)
+                       case Uint64:
+                               v.Set(64)
+                       }
+               case *FloatValue:
+                       switch v.Type().Kind() {
+                       case Float:
+                               v.Set(128.5)
+                       case Float32:
+                               v.Set(256.25)
+                       case Float64:
+                               v.Set(512.125)
+                       }
+               case *ComplexValue:
+                       switch v.Type().Kind() {
+                       case Complex:
+                               v.Set(53200.0 + 100i)
+                       case Complex64:
+                               v.Set(532.125 + 10i)
+                       case Complex128:
+                               v.Set(564.25 + 1i)
+                       }
+               case *StringValue:
+                       v.Set("stringy cheese")
+               case *BoolValue:
+                       v.Set(true)
+               }
+               s := valueToString(v)
+               if s != tt.s {
+                       t.Errorf("#%d: have %#q, want %#q", i, s, tt.s)
+               }
+       }
+}
+
+func TestSetValue(t *testing.T) {
+       for i, tt := range valueTests {
+               v := NewValue(tt.i)
+               switch v := v.(type) {
+               case *IntValue:
+                       switch v.Type().Kind() {
+                       case Int:
+                               v.SetValue(NewValue(int(132)))
+                       case Int8:
+                               v.SetValue(NewValue(int8(8)))
+                       case Int16:
+                               v.SetValue(NewValue(int16(16)))
+                       case Int32:
+                               v.SetValue(NewValue(int32(32)))
+                       case Int64:
+                               v.SetValue(NewValue(int64(64)))
+                       }
+               case *UintValue:
+                       switch v.Type().Kind() {
+                       case Uint:
+                               v.SetValue(NewValue(uint(132)))
+                       case Uint8:
+                               v.SetValue(NewValue(uint8(8)))
+                       case Uint16:
+                               v.SetValue(NewValue(uint16(16)))
+                       case Uint32:
+                               v.SetValue(NewValue(uint32(32)))
+                       case Uint64:
+                               v.SetValue(NewValue(uint64(64)))
+                       }
+               case *FloatValue:
+                       switch v.Type().Kind() {
+                       case Float:
+                               v.SetValue(NewValue(float(128.5)))
+                       case Float32:
+                               v.SetValue(NewValue(float32(256.25)))
+                       case Float64:
+                               v.SetValue(NewValue(float64(512.125)))
+                       }
+               case *ComplexValue:
+                       switch v.Type().Kind() {
+                       case Complex:
+                               v.SetValue(NewValue(complex(53200.0 + 100i)))
+                       case Complex64:
+                               v.SetValue(NewValue(complex64(532.125 + 10i)))
+                       case Complex128:
+                               v.SetValue(NewValue(complex128(564.25 + 1i)))
+                       }
+
+               case *StringValue:
+                       v.SetValue(NewValue("stringy cheese"))
+               case *BoolValue:
+                       v.SetValue(NewValue(true))
+               }
+               s := valueToString(v)
+               if s != tt.s {
+                       t.Errorf("#%d: have %#q, want %#q", i, s, tt.s)
+               }
+       }
+}
+
+var _i = 7
+
+var valueToStringTests = []pair{
+       {123, "123"},
+       {123.5, "123.5"},
+       {byte(123), "123"},
+       {"abc", "abc"},
+       {T{123, 456.75, "hello", &_i}, "reflect_test.T{123, 456.75, hello, *int(&7)}"},
+       {new(chan *T), "*chan *reflect_test.T(&chan *reflect_test.T)"},
+       {[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
+       {&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[10]int(&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
+       {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
+       {&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[]int(&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
+}
+
+func TestValueToString(t *testing.T) {
+       for i, test := range valueToStringTests {
+               s := valueToString(NewValue(test.i))
+               if s != test.s {
+                       t.Errorf("#%d: have %#q, want %#q", i, s, test.s)
+               }
+       }
+}
+
+func TestArrayElemSet(t *testing.T) {
+       v := NewValue([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
+       v.(*ArrayValue).Elem(4).(*IntValue).Set(123)
+       s := valueToString(v)
+       const want = "[10]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
+       if s != want {
+               t.Errorf("[10]int: have %#q want %#q", s, want)
+       }
+
+       v = NewValue([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
+       v.(*SliceValue).Elem(4).(*IntValue).Set(123)
+       s = valueToString(v)
+       const want1 = "[]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
+       if s != want1 {
+               t.Errorf("[]int: have %#q want %#q", s, want1)
+       }
+}
+
+func TestPtrPointTo(t *testing.T) {
+       var ip *int32
+       var i int32 = 1234
+       vip := NewValue(&ip)
+       vi := NewValue(i)
+       vip.(*PtrValue).Elem().(*PtrValue).PointTo(vi)
+       if *ip != 1234 {
+               t.Errorf("got %d, want 1234", *ip)
+       }
+
+       ip = nil
+       vp := NewValue(ip).(*PtrValue)
+       vp.PointTo(vp.Elem())
+       if ip != nil {
+               t.Errorf("got non-nil (%p), want nil", ip)
+       }
+}
+
+func TestPtrSetNil(t *testing.T) {
+       var i int32 = 1234
+       ip := &i
+       vip := NewValue(&ip)
+       vip.(*PtrValue).Elem().(*PtrValue).Set(nil)
+       if ip != nil {
+               t.Errorf("got non-nil (%d), want nil", *ip)
+       }
+}
+
+func TestMapSetNil(t *testing.T) {
+       m := make(map[string]int)
+       vm := NewValue(&m)
+       vm.(*PtrValue).Elem().(*MapValue).Set(nil)
+       if m != nil {
+               t.Errorf("got non-nil (%p), want nil", m)
+       }
+}
+
+
+func TestAll(t *testing.T) {
+       testType(t, 1, Typeof((int8)(0)), "int8")
+       testType(t, 2, Typeof((*int8)(nil)).(*PtrType).Elem(), "int8")
+
+       typ := Typeof((*struct {
+               c chan *int32
+               d float32
+       })(nil))
+       testType(t, 3, typ, "*struct { c chan *int32; d float32 }")
+       etyp := typ.(*PtrType).Elem()
+       testType(t, 4, etyp, "struct { c chan *int32; d float32 }")
+       styp := etyp.(*StructType)
+       f := styp.Field(0)
+       testType(t, 5, f.Type, "chan *int32")
+
+       f, present := styp.FieldByName("d")
+       if !present {
+               t.Errorf("FieldByName says present field is absent")
+       }
+       testType(t, 6, f.Type, "float32")
+
+       f, present = styp.FieldByName("absent")
+       if present {
+               t.Errorf("FieldByName says absent field is present")
+       }
+
+       typ = Typeof([32]int32{})
+       testType(t, 7, typ, "[32]int32")
+       testType(t, 8, typ.(*ArrayType).Elem(), "int32")
+
+       typ = Typeof((map[string]*int32)(nil))
+       testType(t, 9, typ, "map[string] *int32")
+       mtyp := typ.(*MapType)
+       testType(t, 10, mtyp.Key(), "string")
+       testType(t, 11, mtyp.Elem(), "*int32")
+
+       typ = Typeof((chan<- string)(nil))
+       testType(t, 12, typ, "chan<- string")
+       testType(t, 13, typ.(*ChanType).Elem(), "string")
+
+       // make sure tag strings are not part of element type
+       typ = Typeof(struct {
+               d []uint32 "TAG"
+       }{}).(*StructType).Field(0).Type
+       testType(t, 14, typ, "[]uint32")
+}
+
+func TestInterfaceGet(t *testing.T) {
+       var inter struct {
+               e interface{}
+       }
+       inter.e = 123.456
+       v1 := NewValue(&inter)
+       v2 := v1.(*PtrValue).Elem().(*StructValue).Field(0)
+       assert(t, v2.Type().String(), "interface { }")
+       i2 := v2.(*InterfaceValue).Interface()
+       v3 := NewValue(i2)
+       assert(t, v3.Type().String(), "float")
+}
+
+func TestInterfaceValue(t *testing.T) {
+       var inter struct {
+               e interface{}
+       }
+       inter.e = 123.456
+       v1 := NewValue(&inter)
+       v2 := v1.(*PtrValue).Elem().(*StructValue).Field(0)
+       assert(t, v2.Type().String(), "interface { }")
+       v3 := v2.(*InterfaceValue).Elem()
+       assert(t, v3.Type().String(), "float")
+
+       i3 := v2.Interface()
+       if _, ok := i3.(float); !ok {
+               t.Error("v2.Interface() did not return float, got ", Typeof(i3))
+       }
+}
+
+func TestFunctionValue(t *testing.T) {
+       v := NewValue(func() {})
+       if v.Interface() != v.Interface() {
+               t.Fatalf("TestFunction != itself")
+       }
+       assert(t, v.Type().String(), "func()")
+}
+
+func TestCopyArray(t *testing.T) {
+       a := []int{1, 2, 3, 4, 10, 9, 8, 7}
+       b := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
+       c := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
+       va := NewValue(&a)
+       vb := NewValue(&b)
+       for i := 0; i < len(b); i++ {
+               if b[i] != c[i] {
+                       t.Fatalf("b != c before test")
+               }
+       }
+       aa := va.(*PtrValue).Elem().(*SliceValue)
+       ab := vb.(*PtrValue).Elem().(*SliceValue)
+       for tocopy := 1; tocopy <= 7; tocopy++ {
+               aa.SetLen(tocopy)
+               ArrayCopy(ab, aa)
+               aa.SetLen(8)
+               for i := 0; i < tocopy; i++ {
+                       if a[i] != b[i] {
+                               t.Errorf("(i) tocopy=%d a[%d]=%d, b[%d]=%d",
+                                       tocopy, i, a[i], i, b[i])
+                       }
+               }
+               for i := tocopy; i < len(b); i++ {
+                       if b[i] != c[i] {
+                               if i < len(a) {
+                                       t.Errorf("(ii) tocopy=%d a[%d]=%d, b[%d]=%d, c[%d]=%d",
+                                               tocopy, i, a[i], i, b[i], i, c[i])
+                               } else {
+                                       t.Errorf("(iii) tocopy=%d b[%d]=%d, c[%d]=%d",
+                                               tocopy, i, b[i], i, c[i])
+                               }
+                       } else {
+                               t.Logf("tocopy=%d elem %d is okay\n", tocopy, i)
+                       }
+               }
+       }
+}
+
+func TestBigUnnamedStruct(t *testing.T) {
+       b := struct{ a, b, c, d int64 }{1, 2, 3, 4}
+       v := NewValue(b)
+       b1 := v.Interface().(struct {
+               a, b, c, d int64
+       })
+       if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d {
+               t.Errorf("NewValue(%v).Interface().(*Big) = %v", b, b1)
+       }
+}
+
+type big struct {
+       a, b, c, d, e int64
+}
+
+func TestBigStruct(t *testing.T) {
+       b := big{1, 2, 3, 4, 5}
+       v := NewValue(b)
+       b1 := v.Interface().(big)
+       if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d || b1.e != b.e {
+               t.Errorf("NewValue(%v).Interface().(big) = %v", b, b1)
+       }
+}
+
+type Basic struct {
+       x int
+       y float32
+}
+
+type NotBasic Basic
+
+type DeepEqualTest struct {
+       a, b interface{}
+       eq   bool
+}
+
+var deepEqualTests = []DeepEqualTest{
+       // Equalities
+       {1, 1, true},
+       {int32(1), int32(1), true},
+       {0.5, 0.5, true},
+       {float32(0.5), float32(0.5), true},
+       {"hello", "hello", true},
+       {make([]int, 10), make([]int, 10), true},
+       {&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true},
+       {Basic{1, 0.5}, Basic{1, 0.5}, true},
+       {os.Error(nil), os.Error(nil), true},
+       {map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true},
+
+       // Inequalities
+       {1, 2, false},
+       {int32(1), int32(2), false},
+       {0.5, 0.6, false},
+       {float32(0.5), float32(0.6), false},
+       {"hello", "hey", false},
+       {make([]int, 10), make([]int, 11), false},
+       {&[3]int{1, 2, 3}, &[3]int{1, 2, 4}, false},
+       {Basic{1, 0.5}, Basic{1, 0.6}, false},
+       {Basic{1, 0}, Basic{2, 0}, false},
+       {map[int]string{1: "one", 3: "two"}, map[int]string{2: "two", 1: "one"}, false},
+       {map[int]string{1: "one", 2: "txo"}, map[int]string{2: "two", 1: "one"}, false},
+       {map[int]string{1: "one"}, map[int]string{2: "two", 1: "one"}, false},
+       {map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false},
+       {nil, 1, false},
+       {1, nil, false},
+
+       // Mismatched types
+       {1, 1.0, false},
+       {int32(1), int64(1), false},
+       {0.5, "hello", false},
+       {[]int{1, 2, 3}, [3]int{1, 2, 3}, false},
+       {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
+       {Basic{1, 0.5}, NotBasic{1, 0.5}, false},
+       {map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
+}
+
+func TestDeepEqual(t *testing.T) {
+       for _, test := range deepEqualTests {
+               if r := DeepEqual(test.a, test.b); r != test.eq {
+                       t.Errorf("DeepEqual(%v, %v) = %v, want %v", test.a, test.b, r, test.eq)
+               }
+       }
+}
+
+func TestTypeof(t *testing.T) {
+       for _, test := range deepEqualTests {
+               v := NewValue(test.a)
+               if v == nil {
+                       continue
+               }
+               typ := Typeof(test.a)
+               if typ != v.Type() {
+                       t.Errorf("Typeof(%v) = %v, but NewValue(%v).Type() = %v", test.a, typ, test.a, v.Type())
+               }
+       }
+}
+
+type Recursive struct {
+       x int
+       r *Recursive
+}
+
+func TestDeepEqualRecursiveStruct(t *testing.T) {
+       a, b := new(Recursive), new(Recursive)
+       *a = Recursive{12, a}
+       *b = Recursive{12, b}
+       if !DeepEqual(a, b) {
+               t.Error("DeepEqual(recursive same) = false, want true")
+       }
+}
+
+type _Complex struct {
+       a int
+       b [3]*_Complex
+       c *string
+       d map[float]float
+}
+
+func TestDeepEqualComplexStruct(t *testing.T) {
+       m := make(map[float]float)
+       stra, strb := "hello", "hello"
+       a, b := new(_Complex), new(_Complex)
+       *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m}
+       *b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m}
+       if !DeepEqual(a, b) {
+               t.Error("DeepEqual(complex same) = false, want true")
+       }
+}
+
+func TestDeepEqualComplexStructInequality(t *testing.T) {
+       m := make(map[float]float)
+       stra, strb := "hello", "helloo" // Difference is here
+       a, b := new(_Complex), new(_Complex)
+       *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m}
+       *b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m}
+       if DeepEqual(a, b) {
+               t.Error("DeepEqual(complex different) = true, want false")
+       }
+}
+
+
+func check2ndField(x interface{}, offs uintptr, t *testing.T) {
+       s := NewValue(x).(*StructValue)
+       f := s.Type().(*StructType).Field(1)
+       if f.Offset != offs {
+               t.Error("mismatched offsets in structure alignment:", f.Offset, offs)
+       }
+}
+
+// Check that structure alignment & offsets viewed through reflect agree with those
+// from the compiler itself.
+func TestAlignment(t *testing.T) {
+       type T1inner struct {
+               a int
+       }
+       type T1 struct {
+               T1inner
+               f int
+       }
+       type T2inner struct {
+               a, b int
+       }
+       type T2 struct {
+               T2inner
+               f int
+       }
+
+       x := T1{T1inner{2}, 17}
+       check2ndField(x, uintptr(unsafe.Pointer(&x.f))-uintptr(unsafe.Pointer(&x)), t)
+
+       x1 := T2{T2inner{2, 3}, 17}
+       check2ndField(x1, uintptr(unsafe.Pointer(&x1.f))-uintptr(unsafe.Pointer(&x1)), t)
+}
+
+type IsNiller interface {
+       IsNil() bool
+}
+
+func Nil(a interface{}, t *testing.T) {
+       n := NewValue(a).(*StructValue).Field(0).(IsNiller)
+       if !n.IsNil() {
+               t.Errorf("%v should be nil", a)
+       }
+}
+
+func NotNil(a interface{}, t *testing.T) {
+       n := NewValue(a).(*StructValue).Field(0).(IsNiller)
+       if n.IsNil() {
+               t.Errorf("value of type %v should not be nil", NewValue(a).Type().String())
+       }
+}
+
+func TestIsNil(t *testing.T) {
+       // These do not implement IsNil
+       doNotNil := []interface{}{int(0), float32(0), struct{ a int }{}}
+       for _, ts := range doNotNil {
+               ty := Typeof(ts)
+               v := MakeZero(ty)
+               if _, ok := v.(IsNiller); ok {
+                       t.Errorf("%s is nilable; should not be", ts)
+               }
+       }
+
+       // These do implement IsNil.
+       // Wrap in extra struct to hide interface type.
+       doNil := []interface{}{
+               struct{ x *int }{},
+               struct{ x interface{} }{},
+               struct{ x map[string]int }{},
+               struct{ x func() bool }{},
+               struct{ x chan int }{},
+               struct{ x []string }{},
+       }
+       for _, ts := range doNil {
+               ty := Typeof(ts).(*StructType).Field(0).Type
+               v := MakeZero(ty)
+               if _, ok := v.(IsNiller); !ok {
+                       t.Errorf("%s %T is not nilable; should be", ts, v)
+               }
+       }
+
+       // Check the implementations
+       var pi struct {
+               x *int
+       }
+       Nil(pi, t)
+       pi.x = new(int)
+       NotNil(pi, t)
+
+       var si struct {
+               x []int
+       }
+       Nil(si, t)
+       si.x = make([]int, 10)
+       NotNil(si, t)
+
+       var ci struct {
+               x chan int
+       }
+       Nil(ci, t)
+       ci.x = make(chan int)
+       NotNil(ci, t)
+
+       var mi struct {
+               x map[int]int
+       }
+       Nil(mi, t)
+       mi.x = make(map[int]int)
+       NotNil(mi, t)
+
+       var ii struct {
+               x interface{}
+       }
+       Nil(ii, t)
+       ii.x = 2
+       NotNil(ii, t)
+
+       var fi struct {
+               x func(t *testing.T)
+       }
+       Nil(fi, t)
+       fi.x = TestIsNil
+       NotNil(fi, t)
+}
+
+func TestInterfaceExtraction(t *testing.T) {
+       var s struct {
+               w io.Writer
+       }
+
+       s.w = os.Stdout
+       v := Indirect(NewValue(&s)).(*StructValue).Field(0).Interface()
+       if v != s.w.(interface{}) {
+               t.Error("Interface() on interface: ", v, s.w)
+       }
+}
+
+func TestInterfaceEditing(t *testing.T) {
+       // strings are bigger than one word,
+       // so the interface conversion allocates
+       // memory to hold a string and puts that
+       // pointer in the interface.
+       var i interface{} = "hello"
+
+       // if i pass the interface value by value
+       // to NewValue, i should get a fresh copy
+       // of the value.
+       v := NewValue(i)
+
+       // and setting that copy to "bye" should
+       // not change the value stored in i.
+       v.(*StringValue).Set("bye")
+       if i.(string) != "hello" {
+               t.Errorf(`Set("bye") changed i to %s`, i.(string))
+       }
+
+       // the same should be true of smaller items.
+       i = 123
+       v = NewValue(i)
+       v.(*IntValue).Set(234)
+       if i.(int) != 123 {
+               t.Errorf("Set(234) changed i to %d", i.(int))
+       }
+}
+
+func TestNilPtrValueSub(t *testing.T) {
+       var pi *int
+       if pv := NewValue(pi).(*PtrValue); pv.Elem() != nil {
+               t.Error("NewValue((*int)(nil)).(*PtrValue).Elem() != nil")
+       }
+}
+
+func TestMap(t *testing.T) {
+       m := map[string]int{"a": 1, "b": 2}
+       mv := NewValue(m).(*MapValue)
+       if n := mv.Len(); n != len(m) {
+               t.Errorf("Len = %d, want %d", n, len(m))
+       }
+       keys := mv.Keys()
+       i := 0
+       newmap := MakeMap(mv.Type().(*MapType))
+       for k, v := range m {
+               // Check that returned Keys match keys in range.
+               // These aren't required to be in the same order,
+               // but they are in this implementation, which makes
+               // the test easier.
+               if i >= len(keys) {
+                       t.Errorf("Missing key #%d %q", i, k)
+               } else if kv := keys[i].(*StringValue); kv.Get() != k {
+                       t.Errorf("Keys[%d] = %q, want %q", i, kv.Get(), k)
+               }
+               i++
+
+               // Check that value lookup is correct.
+               vv := mv.Elem(NewValue(k))
+               if vi := vv.(*IntValue).Get(); vi != int64(v) {
+                       t.Errorf("Key %q: have value %d, want %d", vi, v)
+               }
+
+               // Copy into new map.
+               newmap.SetElem(NewValue(k), NewValue(v))
+       }
+       vv := mv.Elem(NewValue("not-present"))
+       if vv != nil {
+               t.Errorf("Invalid key: got non-nil value %s", valueToString(vv))
+       }
+
+       newm := newmap.Interface().(map[string]int)
+       if len(newm) != len(m) {
+               t.Errorf("length after copy: newm=%d, m=%d", newm, m)
+       }
+
+       for k, v := range newm {
+               mv, ok := m[k]
+               if mv != v {
+                       t.Errorf("newm[%q] = %d, but m[%q] = %d, %v", k, v, k, mv, ok)
+               }
+       }
+
+       newmap.SetElem(NewValue("a"), nil)
+       v, ok := newm["a"]
+       if ok {
+               t.Errorf("newm[\"a\"] = %d after delete", v)
+       }
+
+       mv = NewValue(&m).(*PtrValue).Elem().(*MapValue)
+       mv.Set(nil)
+       if m != nil {
+               t.Errorf("mv.Set(nil) failed")
+       }
+}
+
+func TestChan(t *testing.T) {
+       for loop := 0; loop < 2; loop++ {
+               var c chan int
+               var cv *ChanValue
+
+               // check both ways to allocate channels
+               switch loop {
+               case 1:
+                       c = make(chan int, 1)
+                       cv = NewValue(c).(*ChanValue)
+               case 0:
+                       cv = MakeChan(Typeof(c).(*ChanType), 1)
+                       c = cv.Interface().(chan int)
+               }
+
+               // Send
+               cv.Send(NewValue(2))
+               if i := <-c; i != 2 {
+                       t.Errorf("reflect Send 2, native recv %d", i)
+               }
+
+               // Recv
+               c <- 3
+               if i := cv.Recv().(*IntValue).Get(); i != 3 {
+                       t.Errorf("native send 3, reflect Recv %d", i)
+               }
+
+               // TryRecv fail
+               val := cv.TryRecv()
+               if val != nil {
+                       t.Errorf("TryRecv on empty chan: %s", valueToString(val))
+               }
+
+               // TryRecv success
+               c <- 4
+               val = cv.TryRecv()
+               if val == nil {
+                       t.Errorf("TryRecv on ready chan got nil")
+               } else if i := val.(*IntValue).Get(); i != 4 {
+                       t.Errorf("native send 4, TryRecv %d", i)
+               }
+
+               // TrySend fail
+               c <- 100
+               ok := cv.TrySend(NewValue(5))
+               i := <-c
+               if ok {
+                       t.Errorf("TrySend on full chan succeeded: value %d", i)
+               }
+
+               // TrySend success
+               ok = cv.TrySend(NewValue(6))
+               if !ok {
+                       t.Errorf("TrySend on empty chan failed")
+               } else {
+                       if i = <-c; i != 6 {
+                               t.Errorf("TrySend 6, recv %d", i)
+                       }
+               }
+
+               // Close
+               c <- 123
+               cv.Close()
+               if cv.Closed() {
+                       t.Errorf("closed too soon - 1")
+               }
+               if i := cv.Recv().(*IntValue).Get(); i != 123 {
+                       t.Errorf("send 123 then close; Recv %d", i)
+               }
+               if cv.Closed() {
+                       t.Errorf("closed too soon - 2")
+               }
+               if i := cv.Recv().(*IntValue).Get(); i != 0 {
+                       t.Errorf("after close Recv %d", i)
+               }
+               if !cv.Closed() {
+                       t.Errorf("not closed")
+               }
+       }
+
+       // check creation of unbuffered channel
+       var c chan int
+       cv := MakeChan(Typeof(c).(*ChanType), 0)
+       c = cv.Interface().(chan int)
+       if cv.TrySend(NewValue(7)) {
+               t.Errorf("TrySend on sync chan succeeded")
+       }
+       if cv.TryRecv() != nil {
+               t.Errorf("TryRecv on sync chan succeeded")
+       }
+
+       // len/cap
+       cv = MakeChan(Typeof(c).(*ChanType), 10)
+       c = cv.Interface().(chan int)
+       for i := 0; i < 3; i++ {
+               c <- i
+       }
+       if l, m := cv.Len(), cv.Cap(); l != len(c) || m != cap(c) {
+               t.Errorf("Len/Cap = %d/%d want %d/%d", l, m, len(c), cap(c))
+       }
+
+}
+
+// Difficult test for function call because of
+// implicit padding between arguments.
+func dummy(b byte, c int, d byte) (i byte, j int, k byte) {
+       return b, c, d
+}
+
+func TestFunc(t *testing.T) {
+       ret := NewValue(dummy).(*FuncValue).Call([]Value{NewValue(byte(10)), NewValue(20), NewValue(byte(30))})
+       if len(ret) != 3 {
+               t.Fatalf("Call returned %d values, want 3", len(ret))
+       }
+
+       i := ret[0].(*UintValue).Get()
+       j := ret[1].(*IntValue).Get()
+       k := ret[2].(*UintValue).Get()
+       if i != 10 || j != 20 || k != 30 {
+               t.Errorf("Call returned %d, %d, %d; want 10, 20, 30", i, j, k)
+       }
+}
+
+type Point struct {
+       x, y int
+}
+
+func (p Point) Dist(scale int) int { return p.x*p.x*scale + p.y*p.y*scale }
+
+func TestMethod(t *testing.T) {
+       // Non-curried method of type.
+       p := Point{3, 4}
+       i := Typeof(p).Method(0).Func.Call([]Value{NewValue(p), NewValue(10)})[0].(*IntValue).Get()
+       if i != 250 {
+               t.Errorf("Type Method returned %d; want 250", i)
+       }
+
+       i = Typeof(&p).Method(0).Func.Call([]Value{NewValue(&p), NewValue(10)})[0].(*IntValue).Get()
+       if i != 250 {
+               t.Errorf("Pointer Type Method returned %d; want 250", i)
+       }
+
+       // Curried method of value.
+       i = NewValue(p).Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
+       if i != 250 {
+               t.Errorf("Value Method returned %d; want 250", i)
+       }
+
+       // Curried method of interface value.
+       // Have to wrap interface value in a struct to get at it.
+       // Passing it to NewValue directly would
+       // access the underlying Point, not the interface.
+       var s = struct {
+               x interface {
+                       Dist(int) int
+               }
+       }{p}
+       pv := NewValue(s).(*StructValue).Field(0)
+       i = pv.Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
+       if i != 250 {
+               t.Errorf("Interface Method returned %d; want 250", i)
+       }
+}
+
+func TestInterfaceSet(t *testing.T) {
+       p := &Point{3, 4}
+
+       var s struct {
+               I interface{}
+               P interface {
+                       Dist(int) int
+               }
+       }
+       sv := NewValue(&s).(*PtrValue).Elem().(*StructValue)
+       sv.Field(0).(*InterfaceValue).Set(NewValue(p))
+       if q := s.I.(*Point); q != p {
+               t.Errorf("i: have %p want %p", q, p)
+       }
+
+       pv := sv.Field(1).(*InterfaceValue)
+       pv.Set(NewValue(p))
+       if q := s.P.(*Point); q != p {
+               t.Errorf("i: have %p want %p", q, p)
+       }
+
+       i := pv.Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
+       if i != 250 {
+               t.Errorf("Interface Method returned %d; want 250", i)
+       }
+}
+
+type T1 struct {
+       a string
+       int
+}
+
+func TestAnonymousFields(t *testing.T) {
+       var field StructField
+       var ok bool
+       var t1 T1
+       type1 := Typeof(t1).(*StructType)
+       if field, ok = type1.FieldByName("int"); !ok {
+               t.Error("no field 'int'")
+       }
+       if field.Index[0] != 1 {
+               t.Error("field index should be 1; is", field.Index)
+       }
+}
+
+type FTest struct {
+       s     interface{}
+       name  string
+       index []int
+       value int
+}
+
+type D1 struct {
+       d int
+}
+type D2 struct {
+       d int
+}
+
+type S0 struct {
+       a, b, c int
+       D1
+       D2
+}
+
+type S1 struct {
+       b int
+       S0
+}
+
+type S2 struct {
+       a int
+       *S1
+}
+
+type S1x struct {
+       S1
+}
+
+type S1y struct {
+       S1
+}
+
+type S3 struct {
+       S1x
+       S2
+       d, e int
+       *S1y
+}
+
+type S4 struct {
+       *S4
+       a int
+}
+
+var fieldTests = []FTest{
+       {struct{}{}, "", nil, 0},
+       {struct{}{}, "foo", nil, 0},
+       {S0{a: 'a'}, "a", []int{0}, 'a'},
+       {S0{}, "d", nil, 0},
+       {S1{S0: S0{a: 'a'}}, "a", []int{1, 0}, 'a'},
+       {S1{b: 'b'}, "b", []int{0}, 'b'},
+       {S1{}, "S0", []int{1}, 0},
+       {S1{S0: S0{c: 'c'}}, "c", []int{1, 2}, 'c'},
+       {S2{a: 'a'}, "a", []int{0}, 'a'},
+       {S2{}, "S1", []int{1}, 0},
+       {S2{S1: &S1{b: 'b'}}, "b", []int{1, 0}, 'b'},
+       {S2{S1: &S1{S0: S0{c: 'c'}}}, "c", []int{1, 1, 2}, 'c'},
+       {S2{}, "d", nil, 0},
+       {S3{}, "S1", nil, 0},
+       {S3{S2: S2{a: 'a'}}, "a", []int{1, 0}, 'a'},
+       {S3{}, "b", nil, 0},
+       {S3{d: 'd'}, "d", []int{2}, 0},
+       {S3{e: 'e'}, "e", []int{3}, 'e'},
+       {S4{a: 'a'}, "a", []int{1}, 'a'},
+       {S4{}, "b", nil, 0},
+}
+
+func TestFieldByIndex(t *testing.T) {
+       for _, test := range fieldTests {
+               s := Typeof(test.s).(*StructType)
+               f := s.FieldByIndex(test.index)
+               if f.Name != "" {
+                       if test.index != nil {
+                               if f.Name != test.name {
+                                       t.Errorf("%s.%s found; want %s", s.Name(), f.Name, test.name)
+                               }
+                       } else {
+                               t.Errorf("%s.%s found", s.Name(), f.Name)
+                       }
+               } else if len(test.index) > 0 {
+                       t.Errorf("%s.%s not found", s.Name(), test.name)
+               }
+
+               if test.value != 0 {
+                       v := NewValue(test.s).(*StructValue).FieldByIndex(test.index)
+                       if v != nil {
+                               if x, ok := v.Interface().(int); ok {
+                                       if x != test.value {
+                                               t.Errorf("%s%v is %d; want %d", s.Name(), test.index, x, test.value)
+                                       }
+                               } else {
+                                       t.Errorf("%s%v value not an int", s.Name(), test.index)
+                               }
+                       } else {
+                               t.Errorf("%s%v value not found", s.Name(), test.index)
+                       }
+               }
+       }
+}
+
+func TestFieldByName(t *testing.T) {
+       for _, test := range fieldTests {
+               s := Typeof(test.s).(*StructType)
+               f, found := s.FieldByName(test.name)
+               if found {
+                       if test.index != nil {
+                               // Verify field depth and index.
+                               if len(f.Index) != len(test.index) {
+                                       t.Errorf("%s.%s depth %d; want %d", s.Name(), test.name, len(f.Index), len(test.index))
+                               } else {
+                                       for i, x := range f.Index {
+                                               if x != test.index[i] {
+                                                       t.Errorf("%s.%s.Index[%d] is %d; want %d", s.Name(), test.name, i, x, test.index[i])
+                                               }
+                                       }
+                               }
+                       } else {
+                               t.Errorf("%s.%s found", s.Name(), f.Name)
+                       }
+               } else if len(test.index) > 0 {
+                       t.Errorf("%s.%s not found", s.Name(), test.name)
+               }
+
+               if test.value != 0 {
+                       v := NewValue(test.s).(*StructValue).FieldByName(test.name)
+                       if v != nil {
+                               if x, ok := v.Interface().(int); ok {
+                                       if x != test.value {
+                                               t.Errorf("%s.%s is %d; want %d", s.Name(), test.name, x, test.value)
+                                       }
+                               } else {
+                                       t.Errorf("%s.%s value not an int", s.Name(), test.name)
+                               }
+                       } else {
+                               t.Errorf("%s.%s value not found", s.Name(), test.name)
+                       }
+               }
+       }
+}
+
+func TestImportPath(t *testing.T) {
+       if path := Typeof(vector.Vector{}).PkgPath(); path != "libgo_container.vector" {
+               t.Errorf("Typeof(vector.Vector{}).PkgPath() = %q, want \"libgo_container.vector\"", path)
+       }
+}
+
+func TestDotDotDot(t *testing.T) {
+       // Test example from FuncType.DotDotDot documentation.
+       var f func(x int, y ...float)
+       typ := Typeof(f).(*FuncType)
+       if typ.NumIn() == 2 && typ.In(0) == Typeof(int(0)) {
+               sl, ok := typ.In(1).(*SliceType)
+               if ok {
+                       if sl.Elem() == Typeof(float(0)) {
+                               // ok
+                               return
+                       }
+               }
+       }
+
+       // Failed
+       t.Errorf("want NumIn() = 2, In(0) = int, In(1) = []float")
+       s := fmt.Sprintf("have NumIn() = %d", typ.NumIn())
+       for i := 0; i < typ.NumIn(); i++ {
+               s += fmt.Sprintf(", In(%d) = %s", i, typ.In(i))
+       }
+       t.Error(s)
+}
+
+type inner struct {
+       x int
+}
+
+type outer struct {
+       y int
+       inner
+}
+
+func (*inner) m() {}
+func (*outer) m() {}
+
+func TestNestedMethods(t *testing.T) {
+       typ := Typeof((*outer)(nil))
+       if typ.NumMethod() != 1 || typ.Method(0).Func.Get() != NewValue((*outer).m).(*FuncValue).Get() {
+               t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
+               for i := 0; i < typ.NumMethod(); i++ {
+                       m := typ.Method(i)
+                       t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Get())
+               }
+       }
+}
+
+type innerInt struct {
+       x int
+}
+
+type outerInt struct {
+       y int
+       innerInt
+}
+
+func (i *innerInt) m() int {
+       return i.x
+}
+
+func TestEmbeddedMethods(t *testing.T) {
+       typ := Typeof((*outerInt)(nil))
+       if typ.NumMethod() != 1 || typ.Method(0).Func.Get() != NewValue((*outerInt).m).(*FuncValue).Get() {
+               t.Errorf("Wrong method table for outerInt: (m=%p)", (*outerInt).m)
+               for i := 0; i < typ.NumMethod(); i++ {
+                       m := typ.Method(i)
+                       t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Get())
+               }
+       }
+
+       i := &innerInt{3}
+       if v := NewValue(i).Method(0).Call(nil)[0].(*IntValue).Get(); v != 3 {
+               t.Errorf("i.m() = %d, want 3", v)
+       }
+
+       o := &outerInt{1, innerInt{2}}
+       if v := NewValue(o).Method(0).Call(nil)[0].(*IntValue).Get(); v != 2 {
+               t.Errorf("i.m() = %d, want 2", v)
+       }
+
+       f := (*outerInt).m
+       if v := f(o); v != 2 {
+               t.Errorf("f(o) = %d, want 2", v)
+       }
+}
diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go
new file mode 100644 (file)
index 0000000..a50925e
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Deep equality test via reflection
+
+package reflect
+
+
+// During deepValueEqual, must keep track of checks that are
+// in progress.  The comparison algorithm assumes that all
+// checks in progress are true when it reencounters them.
+// Visited are stored in a map indexed by 17 * a1 + a2;
+type visit struct {
+       a1   uintptr
+       a2   uintptr
+       typ  Type
+       next *visit
+}
+
+// Tests for deep equality using reflected types. The map argument tracks
+// comparisons that have already been seen, which allows short circuiting on
+// recursive types.
+func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) bool {
+       if v1 == nil || v2 == nil {
+               return v1 == v2
+       }
+       if v1.Type() != v2.Type() {
+               return false
+       }
+
+       // if depth > 10 { panic("deepValueEqual") }    // for debugging
+
+       addr1 := v1.Addr()
+       addr2 := v2.Addr()
+       if addr1 > addr2 {
+               // Canonicalize order to reduce number of entries in visited.
+               addr1, addr2 = addr2, addr1
+       }
+
+       // Short circuit if references are identical ...
+       if addr1 == addr2 {
+               return true
+       }
+
+       // ... or already seen
+       h := 17*addr1 + addr2
+       seen := visited[h]
+       typ := v1.Type()
+       for p := seen; p != nil; p = p.next {
+               if p.a1 == addr1 && p.a2 == addr2 && p.typ == typ {
+                       return true
+               }
+       }
+
+       // Remember for later.
+       visited[h] = &visit{addr1, addr2, typ, seen}
+
+       switch v := v1.(type) {
+       case *ArrayValue:
+               arr1 := v
+               arr2 := v2.(*ArrayValue)
+               if arr1.Len() != arr2.Len() {
+                       return false
+               }
+               for i := 0; i < arr1.Len(); i++ {
+                       if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited, depth+1) {
+                               return false
+                       }
+               }
+               return true
+       case *SliceValue:
+               arr1 := v
+               arr2 := v2.(*SliceValue)
+               if arr1.Len() != arr2.Len() {
+                       return false
+               }
+               for i := 0; i < arr1.Len(); i++ {
+                       if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited, depth+1) {
+                               return false
+                       }
+               }
+               return true
+       case *InterfaceValue:
+               i1 := v.Interface()
+               i2 := v2.Interface()
+               if i1 == nil || i2 == nil {
+                       return i1 == i2
+               }
+               return deepValueEqual(NewValue(i1), NewValue(i2), visited, depth+1)
+       case *PtrValue:
+               return deepValueEqual(v.Elem(), v2.(*PtrValue).Elem(), visited, depth+1)
+       case *StructValue:
+               struct1 := v
+               struct2 := v2.(*StructValue)
+               for i, n := 0, v.NumField(); i < n; i++ {
+                       if !deepValueEqual(struct1.Field(i), struct2.Field(i), visited, depth+1) {
+                               return false
+                       }
+               }
+               return true
+       case *MapValue:
+               map1 := v
+               map2 := v2.(*MapValue)
+               if map1.Len() != map2.Len() {
+                       return false
+               }
+               for _, k := range map1.Keys() {
+                       if !deepValueEqual(map1.Elem(k), map2.Elem(k), visited, depth+1) {
+                               return false
+                       }
+               }
+               return true
+       default:
+               // Normal equality suffices
+               return v1.Interface() == v2.Interface()
+       }
+
+       panic("Not reached")
+}
+
+// DeepEqual tests for deep equality. It uses normal == equality where possible
+// but will scan members of arrays, slices, and fields of structs. It correctly
+// handles recursive types.
+func DeepEqual(a1, a2 interface{}) bool {
+       if a1 == nil || a2 == nil {
+               return a1 == a2
+       }
+       v1 := NewValue(a1)
+       v2 := NewValue(a2)
+       if v1.Type() != v2.Type() {
+               return false
+       }
+       return deepValueEqual(v1, v2, make(map[uintptr]*visit), 0)
+}
diff --git a/libgo/go/reflect/tostring_test.go b/libgo/go/reflect/tostring_test.go
new file mode 100644 (file)
index 0000000..a1487fd
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Formatting of reflection types and values for debugging.
+// Not defined as methods so they do not need to be linked into most binaries;
+// the functions are not used by the library itself, only in tests.
+
+package reflect_test
+
+import (
+       . "reflect"
+       "strconv"
+)
+
+// valueToString returns a textual representation of the reflection value val.
+// For debugging only.
+func valueToString(val Value) string {
+       var str string
+       if val == nil {
+               return "<nil>"
+       }
+       typ := val.Type()
+       switch val := val.(type) {
+       case *IntValue:
+               return strconv.Itoa64(val.Get())
+       case *UintValue:
+               return strconv.Uitoa64(val.Get())
+       case *FloatValue:
+               return strconv.Ftoa64(float64(val.Get()), 'g', -1)
+       case *ComplexValue:
+               c := val.Get()
+               return strconv.Ftoa64(float64(real(c)), 'g', -1) + "+" + strconv.Ftoa64(float64(imag(c)), 'g', -1) + "i"
+       case *StringValue:
+               return val.Get()
+       case *BoolValue:
+               if val.Get() {
+                       return "true"
+               } else {
+                       return "false"
+               }
+       case *PtrValue:
+               v := val
+               str = typ.String() + "("
+               if v.IsNil() {
+                       str += "0"
+               } else {
+                       str += "&" + valueToString(v.Elem())
+               }
+               str += ")"
+               return str
+       case ArrayOrSliceValue:
+               v := val
+               str += typ.String()
+               str += "{"
+               for i := 0; i < v.Len(); i++ {
+                       if i > 0 {
+                               str += ", "
+                       }
+                       str += valueToString(v.Elem(i))
+               }
+               str += "}"
+               return str
+       case *MapValue:
+               t := typ.(*MapType)
+               str = t.String()
+               str += "{"
+               str += "<can't iterate on maps>"
+               str += "}"
+               return str
+       case *ChanValue:
+               str = typ.String()
+               return str
+       case *StructValue:
+               t := typ.(*StructType)
+               v := val
+               str += t.String()
+               str += "{"
+               for i, n := 0, v.NumField(); i < n; i++ {
+                       if i > 0 {
+                               str += ", "
+                       }
+                       str += valueToString(v.Field(i))
+               }
+               str += "}"
+               return str
+       case *InterfaceValue:
+               return typ.String() + "(" + valueToString(val.Elem()) + ")"
+       case *FuncValue:
+               v := val
+               return typ.String() + "(" + strconv.Itoa64(int64(v.Get())) + ")"
+       default:
+               panic("valueToString: can't print type " + typ.String())
+       }
+       return "valueToString: can't happen"
+}
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
new file mode 100644 (file)
index 0000000..2a93fd3
--- /dev/null
@@ -0,0 +1,744 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The reflect package implements run-time reflection, allowing a program to
+// manipulate objects with arbitrary types.  The typical use is to take a
+// value with static type interface{} and extract its dynamic type
+// information by calling Typeof, which returns an object with interface
+// type Type.  That contains a pointer to a struct of type *StructType,
+// *IntType, etc. representing the details of the underlying type.  A type
+// switch or type assertion can reveal which.
+//
+// A call to NewValue creates a Value representing the run-time data; it
+// contains a *StructValue, *IntValue, etc.  MakeZero takes a Type and
+// returns a Value representing a zero value for that type.
+package reflect
+
+import (
+       "runtime"
+       "strconv"
+       "sync"
+       "unsafe"
+)
+
+/*
+ * Copy of data structures from ../runtime/type.go.
+ * For comments, see the ones in that file.
+ *
+ * These data structures are known to the compiler and the runtime.
+ *
+ * Putting these types in runtime instead of reflect means that
+ * reflect doesn't need to be autolinked into every binary, which
+ * simplifies bootstrapping and package dependencies.
+ * Unfortunately, it also means that reflect needs its own
+ * copy in order to access the private fields.
+ */
+
+// commonType is the common implementation of most values.
+// It is embedded in other, public struct types, but always
+// with a unique tag like "uint" or "float" so that the client cannot
+// convert from, say, *UintType to *FloatType.
+
+type commonType struct {
+       kind       uint8
+       align      int8
+       fieldAlign uint8
+       size       uintptr
+       hash       uint32
+       hashfn     func(unsafe.Pointer, uintptr)
+       equalfn    func(unsafe.Pointer, unsafe.Pointer, uintptr)
+       string     *string
+       *uncommonType
+}
+
+type method struct {
+       name    *string
+       pkgPath *string
+       mtyp    *runtime.Type
+       typ     *runtime.Type
+       tfn     unsafe.Pointer
+}
+
+type uncommonType struct {
+       name    *string
+       pkgPath *string
+       methods []method
+}
+
+// BoolType represents a boolean type.
+type BoolType struct {
+       commonType "bool"
+}
+
+// FloatType represents a float type.
+type FloatType struct {
+       commonType "float"
+}
+
+// ComplexType represents a complex type.
+type ComplexType struct {
+       commonType "complex"
+}
+
+// IntType represents a signed integer type.
+type IntType struct {
+       commonType "int"
+}
+
+// UintType represents a uint type.
+type UintType struct {
+       commonType "uint"
+}
+
+// StringType represents a string type.
+type StringType struct {
+       commonType "string"
+}
+
+// UnsafePointerType represents an unsafe.Pointer type.
+type UnsafePointerType struct {
+       commonType "unsafe.Pointer"
+}
+
+// ArrayType represents a fixed array type.
+type ArrayType struct {
+       commonType "array"
+       elem       *runtime.Type
+       len        uintptr
+}
+
+// ChanDir represents a channel type's direction.
+type ChanDir int
+
+const (
+       RecvDir ChanDir = 1 << iota
+       SendDir
+       BothDir = RecvDir | SendDir
+)
+
+// ChanType represents a channel type.
+type ChanType struct {
+       commonType "chan"
+       elem       *runtime.Type
+       dir        uintptr
+}
+
+// FuncType represents a function type.
+type FuncType struct {
+       commonType "func"
+       dotdotdot  bool
+       in         []*runtime.Type
+       out        []*runtime.Type
+}
+
+// Method on interface type
+type imethod struct {
+       name    *string
+       pkgPath *string
+       typ     *runtime.Type
+}
+
+// InterfaceType represents an interface type.
+type InterfaceType struct {
+       commonType "interface"
+       methods    []imethod
+}
+
+// MapType represents a map type.
+type MapType struct {
+       commonType "map"
+       key        *runtime.Type
+       elem       *runtime.Type
+}
+
+// PtrType represents a pointer type.
+type PtrType struct {
+       commonType "ptr"
+       elem       *runtime.Type
+}
+
+// SliceType represents a slice type.
+type SliceType struct {
+       commonType "slice"
+       elem       *runtime.Type
+}
+
+// Struct field
+type structField struct {
+       name    *string
+       pkgPath *string
+       typ     *runtime.Type
+       tag     *string
+       offset  uintptr
+}
+
+// StructType represents a struct type.
+type StructType struct {
+       commonType "struct"
+       fields     []structField
+}
+
+
+/*
+ * The compiler knows the exact layout of all the data structures above.
+ * The compiler does not know about the data structures and methods below.
+ */
+
+// Method represents a single method.
+type Method struct {
+       PkgPath string // empty for uppercase Name
+       Name    string
+       Type    *FuncType
+       Func    *FuncValue
+}
+
+// Type is the runtime representation of a Go type.
+// Every type implements the methods listed here.
+// Some types implement additional interfaces;
+// use a type switch to find out what kind of type a Type is.
+// Each type in a program has a unique Type, so == on Types
+// corresponds to Go's type equality.
+type Type interface {
+       // PkgPath returns the type's package path.
+       // The package path is a full package import path like "container/vector".
+       // PkgPath returns an empty string for unnamed types.
+       PkgPath() string
+
+       // Name returns the type's name within its package.
+       // Name returns an empty string for unnamed types.
+       Name() string
+
+       // String returns a string representation of the type.
+       // The string representation may use shortened package names
+       // (e.g., vector instead of "container/vector") and is not
+       // guaranteed to be unique among types.  To test for equality,
+       // compare the Types directly.
+       String() string
+
+       // Size returns the number of bytes needed to store
+       // a value of the given type; it is analogous to unsafe.Sizeof.
+       Size() uintptr
+
+       // Bits returns the size of the type in bits.
+       // It is intended for use with numeric types and may overflow
+       // when used for composite types.
+       Bits() int
+
+       // Align returns the alignment of a value of this type
+       // when allocated in memory.
+       Align() int
+
+       // FieldAlign returns the alignment of a value of this type
+       // when used as a field in a struct.
+       FieldAlign() int
+
+       // Kind returns the specific kind of this type.
+       Kind() Kind
+
+       // For non-interface types, Method returns the i'th method with receiver T.
+       // For interface types, Method returns the i'th method in the interface.
+       // NumMethod returns the number of such methods.
+       Method(int) Method
+       NumMethod() int
+       uncommon() *uncommonType
+}
+
+// A Kind represents the specific kind of type that a Type represents.
+// For numeric types, the Kind gives more information than the Type's
+// dynamic type.  For example, the Type of a float32 is FloatType, but
+// the Kind is Float32.
+//
+// The zero Kind is not a valid kind.
+type Kind uint8
+
+const (
+       Bool Kind = 1 + iota
+       Int
+       Int8
+       Int16
+       Int32
+       Int64
+       Uint
+       Uint8
+       Uint16
+       Uint32
+       Uint64
+       Uintptr
+       Float
+       Float32
+       Float64
+       Complex
+       Complex64
+       Complex128
+       Array
+       Chan
+       Func
+       Interface
+       Map
+       Ptr
+       Slice
+       String
+       Struct
+       UnsafePointer
+)
+
+// High bit says whether type has
+// embedded pointers,to help garbage collector.
+const kindMask = 0x7f
+
+func (k Kind) String() string {
+       if int(k) < len(kindNames) {
+               return kindNames[k]
+       }
+       return "kind" + strconv.Itoa(int(k))
+}
+
+var kindNames = []string{
+       Bool:          "bool",
+       Int:           "int",
+       Int8:          "int8",
+       Int16:         "int16",
+       Int32:         "int32",
+       Int64:         "int64",
+       Uint:          "uint",
+       Uint8:         "uint8",
+       Uint16:        "uint16",
+       Uint32:        "uint32",
+       Uint64:        "uint64",
+       Uintptr:       "uintptr",
+       Float:         "float",
+       Float32:       "float32",
+       Float64:       "float64",
+       Array:         "array",
+       Chan:          "chan",
+       Func:          "func",
+       Interface:     "interface",
+       Map:           "map",
+       Ptr:           "ptr",
+       Slice:         "slice",
+       String:        "string",
+       Struct:        "struct",
+       UnsafePointer: "unsafe.Pointer",
+}
+
+func (t *uncommonType) uncommon() *uncommonType {
+       return t
+}
+
+func (t *uncommonType) PkgPath() string {
+       if t == nil || t.pkgPath == nil {
+               return ""
+       }
+       return *t.pkgPath
+}
+
+func (t *uncommonType) Name() string {
+       if t == nil || t.name == nil {
+               return ""
+       }
+       return *t.name
+}
+
+func (t *commonType) String() string { return *t.string }
+
+func (t *commonType) Size() uintptr { return t.size }
+
+func (t *commonType) Bits() int { return int(t.size * 8) }
+
+func (t *commonType) Align() int { return int(t.align) }
+
+func (t *commonType) FieldAlign() int { return int(t.fieldAlign) }
+
+func (t *commonType) Kind() Kind { return Kind(t.kind & kindMask) }
+
+func (t *uncommonType) Method(i int) (m Method) {
+       if t == nil || i < 0 || i >= len(t.methods) {
+               return
+       }
+       p := &t.methods[i]
+       if p.name != nil {
+               m.Name = *p.name
+       }
+       if p.pkgPath != nil {
+               m.PkgPath = *p.pkgPath
+       }
+       m.Type = runtimeToType(p.typ).(*FuncType)
+       fn := p.tfn
+       m.Func = &FuncValue{value: value{m.Type, addr(&fn), true}}
+       return
+}
+
+func (t *uncommonType) NumMethod() int {
+       if t == nil {
+               return 0
+       }
+       return len(t.methods)
+}
+
+// TODO(rsc): 6g supplies these, but they are not
+// as efficient as they could be: they have commonType
+// as the receiver instead of *commonType.
+func (t *commonType) NumMethod() int { return t.uncommonType.NumMethod() }
+
+func (t *commonType) Method(i int) (m Method) { return t.uncommonType.Method(i) }
+
+func (t *commonType) PkgPath() string { return t.uncommonType.PkgPath() }
+
+func (t *commonType) Name() string { return t.uncommonType.Name() }
+
+// Len returns the number of elements in the array.
+func (t *ArrayType) Len() int { return int(t.len) }
+
+// Elem returns the type of the array's elements.
+func (t *ArrayType) Elem() Type { return runtimeToType(t.elem) }
+
+// Dir returns the channel direction.
+func (t *ChanType) Dir() ChanDir { return ChanDir(t.dir) }
+
+// Elem returns the channel's element type.
+func (t *ChanType) Elem() Type { return runtimeToType(t.elem) }
+
+func (d ChanDir) String() string {
+       switch d {
+       case SendDir:
+               return "chan<-"
+       case RecvDir:
+               return "<-chan"
+       case BothDir:
+               return "chan"
+       }
+       return "ChanDir" + strconv.Itoa(int(d))
+}
+
+// In returns the type of the i'th function input parameter.
+func (t *FuncType) In(i int) Type {
+       if i < 0 || i >= len(t.in) {
+               return nil
+       }
+       return runtimeToType(t.in[i])
+}
+
+// DotDotDot returns true if the final function input parameter
+// is a "..." parameter.  If so, t.In(t.NumIn() - 1) returns the
+// parameter's underlying static type []T.
+//
+// For concreteness, if t is func(x int, y ... float), then
+//
+//     t.NumIn() == 2
+//     t.In(0) is the reflect.Type for "int"
+//     t.In(1) is the reflect.Type for "[]float"
+//     t.DotDotDot() == true
+//
+func (t *FuncType) DotDotDot() bool { return t.dotdotdot }
+
+// NumIn returns the number of input parameters.
+func (t *FuncType) NumIn() int { return len(t.in) }
+
+// Out returns the type of the i'th function output parameter.
+func (t *FuncType) Out(i int) Type {
+       if i < 0 || i >= len(t.out) {
+               return nil
+       }
+       return runtimeToType(t.out[i])
+}
+
+// NumOut returns the number of function output parameters.
+func (t *FuncType) NumOut() int { return len(t.out) }
+
+// Method returns the i'th interface method.
+func (t *InterfaceType) Method(i int) (m Method) {
+       if i < 0 || i >= len(t.methods) {
+               return
+       }
+       p := &t.methods[i]
+       m.Name = *p.name
+       if p.pkgPath != nil {
+               m.PkgPath = *p.pkgPath
+       }
+       m.Type = runtimeToType(p.typ).(*FuncType)
+       return
+}
+
+// NumMethod returns the number of interface methods.
+func (t *InterfaceType) NumMethod() int { return len(t.methods) }
+
+// Key returns the map key type.
+func (t *MapType) Key() Type { return runtimeToType(t.key) }
+
+// Elem returns the map element type.
+func (t *MapType) Elem() Type { return runtimeToType(t.elem) }
+
+// Elem returns the pointer element type.
+func (t *PtrType) Elem() Type { return runtimeToType(t.elem) }
+
+// Elem returns the type of the slice's elements.
+func (t *SliceType) Elem() Type { return runtimeToType(t.elem) }
+
+type StructField struct {
+       PkgPath   string // empty for uppercase Name
+       Name      string
+       Type      Type
+       Tag       string
+       Offset    uintptr
+       Index     []int
+       Anonymous bool
+}
+
+// Field returns the i'th struct field.
+func (t *StructType) Field(i int) (f StructField) {
+       if i < 0 || i >= len(t.fields) {
+               return
+       }
+       p := t.fields[i]
+       f.Type = runtimeToType(p.typ)
+       if p.name != nil {
+               f.Name = *p.name
+       } else {
+               t := f.Type
+               if pt, ok := t.(*PtrType); ok {
+                       t = pt.Elem()
+               }
+               f.Name = t.Name()
+               f.Anonymous = true
+       }
+       if p.pkgPath != nil {
+               f.PkgPath = *p.pkgPath
+       }
+       if p.tag != nil {
+               f.Tag = *p.tag
+       }
+       f.Offset = p.offset
+       f.Index = []int{i}
+       return
+}
+
+// TODO(gri): Should there be an error/bool indicator if the index
+//            is wrong for FieldByIndex?
+
+// FieldByIndex returns the nested field corresponding to index.
+func (t *StructType) FieldByIndex(index []int) (f StructField) {
+       for i, x := range index {
+               if i > 0 {
+                       ft := f.Type
+                       if pt, ok := ft.(*PtrType); ok {
+                               ft = pt.Elem()
+                       }
+                       if st, ok := ft.(*StructType); ok {
+                               t = st
+                       } else {
+                               var f0 StructField
+                               f = f0
+                               return
+                       }
+               }
+               f = t.Field(x)
+       }
+       return
+}
+
+const inf = 1 << 30 // infinity - no struct has that many nesting levels
+
+func (t *StructType) fieldByNameFunc(match func(string) bool, mark map[*StructType]bool, depth int) (ff StructField, fd int) {
+       fd = inf // field depth
+
+       if mark[t] {
+               // Struct already seen.
+               return
+       }
+       mark[t] = true
+
+       var fi int // field index
+       n := 0     // number of matching fields at depth fd
+L:
+       for i, _ := range t.fields {
+               f := t.Field(i)
+               d := inf
+               switch {
+               case match(f.Name):
+                       // Matching top-level field.
+                       d = depth
+               case f.Anonymous:
+                       ft := f.Type
+                       if pt, ok := ft.(*PtrType); ok {
+                               ft = pt.Elem()
+                       }
+                       switch {
+                       case match(ft.Name()):
+                               // Matching anonymous top-level field.
+                               d = depth
+                       case fd > depth:
+                               // No top-level field yet; look inside nested structs.
+                               if st, ok := ft.(*StructType); ok {
+                                       f, d = st.fieldByNameFunc(match, mark, depth+1)
+                               }
+                       }
+               }
+
+               switch {
+               case d < fd:
+                       // Found field at shallower depth.
+                       ff, fi, fd = f, i, d
+                       n = 1
+               case d == fd:
+                       // More than one matching field at the same depth (or d, fd == inf).
+                       // Same as no field found at this depth.
+                       n++
+                       if d == depth {
+                               // Impossible to find a field at lower depth.
+                               break L
+                       }
+               }
+       }
+
+       if n == 1 {
+               // Found matching field.
+               if len(ff.Index) <= depth {
+                       ff.Index = make([]int, depth+1)
+               }
+               ff.Index[depth] = fi
+       } else {
+               // None or more than one matching field found.
+               fd = inf
+       }
+
+       mark[t] = false, false
+       return
+}
+
+// FieldByName returns the struct field with the given name
+// and a boolean to indicate if the field was found.
+func (t *StructType) FieldByName(name string) (f StructField, present bool) {
+       return t.FieldByNameFunc(func(s string) bool { return s == name })
+}
+
+// FieldByNameFunc returns the struct field with a name that satisfies the
+// match function and a boolean to indicate if the field was found.
+func (t *StructType) FieldByNameFunc(match func(string) bool) (f StructField, present bool) {
+       if ff, fd := t.fieldByNameFunc(match, make(map[*StructType]bool), 0); fd < inf {
+               ff.Index = ff.Index[0 : fd+1]
+               f, present = ff, true
+       }
+       return
+}
+
+// NumField returns the number of struct fields.
+func (t *StructType) NumField() int { return len(t.fields) }
+
+// Canonicalize a Type.
+var canonicalType = make(map[string]Type)
+
+var canonicalTypeLock sync.Mutex
+
+func canonicalize(t Type) Type {
+       if t == nil {
+               return nil
+       }
+       u := t.uncommon()
+       var s string
+       if u == nil || u.PkgPath() == "" {
+               s = t.String()
+       } else {
+               s = u.PkgPath() + "." + u.Name()
+       }
+       canonicalTypeLock.Lock()
+       if r, ok := canonicalType[s]; ok {
+               canonicalTypeLock.Unlock()
+               return r
+       }
+       canonicalType[s] = t
+       canonicalTypeLock.Unlock()
+       return t
+}
+
+// Convert runtime type to reflect type.
+// Same memory layouts, different method sets.
+func toType(i interface{}) Type {
+       switch v := i.(type) {
+       case nil:
+               return nil
+       case *runtime.BoolType:
+               return (*BoolType)(unsafe.Pointer(v))
+       case *runtime.FloatType:
+               return (*FloatType)(unsafe.Pointer(v))
+       case *runtime.ComplexType:
+               return (*ComplexType)(unsafe.Pointer(v))
+       case *runtime.IntType:
+               return (*IntType)(unsafe.Pointer(v))
+       case *runtime.StringType:
+               return (*StringType)(unsafe.Pointer(v))
+       case *runtime.UintType:
+               return (*UintType)(unsafe.Pointer(v))
+       case *runtime.UnsafePointerType:
+               return (*UnsafePointerType)(unsafe.Pointer(v))
+       case *runtime.ArrayType:
+               return (*ArrayType)(unsafe.Pointer(v))
+       case *runtime.ChanType:
+               return (*ChanType)(unsafe.Pointer(v))
+       case *runtime.FuncType:
+               return (*FuncType)(unsafe.Pointer(v))
+       case *runtime.InterfaceType:
+               return (*InterfaceType)(unsafe.Pointer(v))
+       case *runtime.MapType:
+               return (*MapType)(unsafe.Pointer(v))
+       case *runtime.PtrType:
+               return (*PtrType)(unsafe.Pointer(v))
+       case *runtime.SliceType:
+               return (*SliceType)(unsafe.Pointer(v))
+       case *runtime.StructType:
+               return (*StructType)(unsafe.Pointer(v))
+       }
+       println(i)
+       panic("toType")
+}
+
+// Convert pointer to runtime Type structure to our Type structure.
+func runtimeToType(v *runtime.Type) Type {
+       var r Type
+       switch Kind(v.Kind) {
+       case Bool:
+               r = (*BoolType)(unsafe.Pointer(v))
+       case Int, Int8, Int16, Int32, Int64:
+               r = (*IntType)(unsafe.Pointer(v))
+       case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
+               r = (*UintType)(unsafe.Pointer(v))
+       case Float, Float32, Float64:
+               r = (*FloatType)(unsafe.Pointer(v))
+       case Complex, Complex64, Complex128:
+               r = (*ComplexType)(unsafe.Pointer(v))
+       case Array:
+               r = (*ArrayType)(unsafe.Pointer(v))
+       case Chan:
+               r = (*ChanType)(unsafe.Pointer(v))
+       case Func:
+               r = (*FuncType)(unsafe.Pointer(v))
+       case Interface:
+               r = (*InterfaceType)(unsafe.Pointer(v))
+       case Map:
+               r = (*MapType)(unsafe.Pointer(v))
+       case Ptr:
+               r = (*PtrType)(unsafe.Pointer(v))
+       case Slice:
+               r = (*SliceType)(unsafe.Pointer(v))
+       case String:
+               r = (*StringType)(unsafe.Pointer(v))
+       case Struct:
+               r = (*StructType)(unsafe.Pointer(v))
+       case UnsafePointer:
+               r = (*UnsafePointerType)(unsafe.Pointer(v))
+       default:
+               panic("runtimeToType")
+       }
+       return canonicalize(r)
+       panic("runtimeToType")
+}
+
+// ArrayOrSliceType is the common interface implemented
+// by both ArrayType and SliceType.
+type ArrayOrSliceType interface {
+       Type
+       Elem() Type
+}
+
+// Typeof returns the reflection Type of the value in the interface{}.
+func Typeof(i interface{}) Type { return canonicalize(toType(unsafe.Typeof(i))) }
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
new file mode 100644 (file)
index 0000000..eda6feb
--- /dev/null
@@ -0,0 +1,1204 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect
+
+import (
+       "math"
+       "runtime"
+       "unsafe"
+)
+
+const ptrSize = uintptr(unsafe.Sizeof((*byte)(nil)))
+const cannotSet = "cannot set value obtained via unexported struct field"
+
+type addr unsafe.Pointer
+
+// TODO: This will have to go away when
+// the new gc goes in.
+func memmove(adst, asrc addr, n uintptr) {
+       dst := uintptr(adst)
+       src := uintptr(asrc)
+       switch {
+       case src < dst && src+n > dst:
+               // byte copy backward
+               // careful: i is unsigned
+               for i := n; i > 0; {
+                       i--
+                       *(*byte)(addr(dst + i)) = *(*byte)(addr(src + i))
+               }
+       case (n|src|dst)&(ptrSize-1) != 0:
+               // byte copy forward
+               for i := uintptr(0); i < n; i++ {
+                       *(*byte)(addr(dst + i)) = *(*byte)(addr(src + i))
+               }
+       default:
+               // word copy forward
+               for i := uintptr(0); i < n; i += ptrSize {
+                       *(*uintptr)(addr(dst + i)) = *(*uintptr)(addr(src + i))
+               }
+       }
+}
+
+// Value is the common interface to reflection values.
+// The implementations of Value (e.g., ArrayValue, StructValue)
+// have additional type-specific methods.
+type Value interface {
+       // Type returns the value's type.
+       Type() Type
+
+       // Interface returns the value as an interface{}.
+       Interface() interface{}
+
+       // CanSet returns whether the value can be changed.
+       // Values obtained by the use of non-exported struct fields
+       // can be used in Get but not Set.
+       // If CanSet() returns false, calling the type-specific Set
+       // will cause a crash.
+       CanSet() bool
+
+       // SetValue assigns v to the value; v must have the same type as the value.
+       SetValue(v Value)
+
+       // Addr returns a pointer to the underlying data.
+       // It is for advanced clients that also
+       // import the "unsafe" package.
+       Addr() uintptr
+
+       // Method returns a FuncValue corresponding to the value's i'th method.
+       // The arguments to a Call on the returned FuncValue
+       // should not include a receiver; the FuncValue will use
+       // the value as the receiver.
+       Method(i int) *FuncValue
+
+       getAddr() addr
+}
+
+// value is the common implementation of most values.
+// It is embedded in other, public struct types, but always
+// with a unique tag like "uint" or "float" so that the client cannot
+// convert from, say, *UintValue to *FloatValue.
+type value struct {
+       typ    Type
+       addr   addr
+       canSet bool
+}
+
+func (v *value) Type() Type { return v.typ }
+
+func (v *value) Addr() uintptr { return uintptr(v.addr) }
+
+func (v *value) getAddr() addr { return v.addr }
+
+func (v *value) Interface() interface{} {
+       if typ, ok := v.typ.(*InterfaceType); ok {
+               // There are two different representations of interface values,
+               // one if the interface type has methods and one if it doesn't.
+               // These two representations require different expressions
+               // to extract correctly.
+               if typ.NumMethod() == 0 {
+                       // Extract as interface value without methods.
+                       return *(*interface{})(v.addr)
+               }
+               // Extract from v.addr as interface value with methods.
+               return *(*interface {
+                       m()
+               })(v.addr)
+       }
+       return unsafe.Unreflect(v.typ, unsafe.Pointer(v.addr))
+}
+
+func (v *value) CanSet() bool { return v.canSet }
+
+/*
+ * basic types
+ */
+
+// BoolValue represents a bool value.
+type BoolValue struct {
+       value "bool"
+}
+
+// Get returns the underlying bool value.
+func (v *BoolValue) Get() bool { return *(*bool)(v.addr) }
+
+// Set sets v to the value x.
+func (v *BoolValue) Set(x bool) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       *(*bool)(v.addr) = x
+}
+
+// Set sets v to the value x.
+func (v *BoolValue) SetValue(x Value) { v.Set(x.(*BoolValue).Get()) }
+
+// FloatValue represents a float value.
+type FloatValue struct {
+       value "float"
+}
+
+// Get returns the underlying int value.
+func (v *FloatValue) Get() float64 {
+       switch v.typ.(*FloatType).Kind() {
+       case Float:
+               return float64(*(*float)(v.addr))
+       case Float32:
+               return float64(*(*float32)(v.addr))
+       case Float64:
+               return *(*float64)(v.addr)
+       }
+       panic("reflect: invalid float kind")
+}
+
+// Set sets v to the value x.
+func (v *FloatValue) Set(x float64) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       switch v.typ.(*FloatType).Kind() {
+       default:
+               panic("reflect: invalid float kind")
+       case Float:
+               *(*float)(v.addr) = float(x)
+       case Float32:
+               *(*float32)(v.addr) = float32(x)
+       case Float64:
+               *(*float64)(v.addr) = x
+       }
+}
+
+// Overflow returns true if x cannot be represented by the type of v.
+func (v *FloatValue) Overflow(x float64) bool {
+       if v.typ.Size() == 8 {
+               return false
+       }
+       if x < 0 {
+               x = -x
+       }
+       return math.MaxFloat32 < x && x <= math.MaxFloat64
+}
+
+// Set sets v to the value x.
+func (v *FloatValue) SetValue(x Value) { v.Set(x.(*FloatValue).Get()) }
+
+// ComplexValue represents a complex value.
+type ComplexValue struct {
+       value "complex"
+}
+
+// Get returns the underlying complex value.
+func (v *ComplexValue) Get() complex128 {
+       switch v.typ.(*ComplexType).Kind() {
+       case Complex:
+               return complex128(*(*complex)(v.addr))
+       case Complex64:
+               return complex128(*(*complex64)(v.addr))
+       case Complex128:
+               return *(*complex128)(v.addr)
+       }
+       panic("reflect: invalid complex kind")
+}
+
+// Set sets v to the value x.
+func (v *ComplexValue) Set(x complex128) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       switch v.typ.(*ComplexType).Kind() {
+       default:
+               panic("reflect: invalid complex kind")
+       case Complex:
+               *(*complex)(v.addr) = complex(x)
+       case Complex64:
+               *(*complex64)(v.addr) = complex64(x)
+       case Complex128:
+               *(*complex128)(v.addr) = x
+       }
+}
+
+// Set sets v to the value x.
+func (v *ComplexValue) SetValue(x Value) { v.Set(x.(*ComplexValue).Get()) }
+
+// IntValue represents an int value.
+type IntValue struct {
+       value "int"
+}
+
+// Get returns the underlying int value.
+func (v *IntValue) Get() int64 {
+       switch v.typ.(*IntType).Kind() {
+       case Int:
+               return int64(*(*int)(v.addr))
+       case Int8:
+               return int64(*(*int8)(v.addr))
+       case Int16:
+               return int64(*(*int16)(v.addr))
+       case Int32:
+               return int64(*(*int32)(v.addr))
+       case Int64:
+               return *(*int64)(v.addr)
+       }
+       panic("reflect: invalid int kind")
+}
+
+// Set sets v to the value x.
+func (v *IntValue) Set(x int64) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       switch v.typ.(*IntType).Kind() {
+       default:
+               panic("reflect: invalid int kind")
+       case Int:
+               *(*int)(v.addr) = int(x)
+       case Int8:
+               *(*int8)(v.addr) = int8(x)
+       case Int16:
+               *(*int16)(v.addr) = int16(x)
+       case Int32:
+               *(*int32)(v.addr) = int32(x)
+       case Int64:
+               *(*int64)(v.addr) = x
+       }
+}
+
+// Set sets v to the value x.
+func (v *IntValue) SetValue(x Value) { v.Set(x.(*IntValue).Get()) }
+
+// Overflow returns true if x cannot be represented by the type of v.
+func (v *IntValue) Overflow(x int64) bool {
+       bitSize := uint(v.typ.Bits())
+       trunc := (x << (64 - bitSize)) >> (64 - bitSize)
+       return x != trunc
+}
+
+// StringHeader is the runtime representation of a string.
+type StringHeader struct {
+       Data uintptr
+       Len  int
+}
+
+// StringValue represents a string value.
+type StringValue struct {
+       value "string"
+}
+
+// Get returns the underlying string value.
+func (v *StringValue) Get() string { return *(*string)(v.addr) }
+
+// Set sets v to the value x.
+func (v *StringValue) Set(x string) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       *(*string)(v.addr) = x
+}
+
+// Set sets v to the value x.
+func (v *StringValue) SetValue(x Value) { v.Set(x.(*StringValue).Get()) }
+
+// UintValue represents a uint value.
+type UintValue struct {
+       value "uint"
+}
+
+// Get returns the underlying uuint value.
+func (v *UintValue) Get() uint64 {
+       switch v.typ.(*UintType).Kind() {
+       case Uint:
+               return uint64(*(*uint)(v.addr))
+       case Uint8:
+               return uint64(*(*uint8)(v.addr))
+       case Uint16:
+               return uint64(*(*uint16)(v.addr))
+       case Uint32:
+               return uint64(*(*uint32)(v.addr))
+       case Uint64:
+               return *(*uint64)(v.addr)
+       case Uintptr:
+               return uint64(*(*uintptr)(v.addr))
+       }
+       panic("reflect: invalid uint kind")
+}
+
+// Set sets v to the value x.
+func (v *UintValue) Set(x uint64) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       switch v.typ.(*UintType).Kind() {
+       default:
+               panic("reflect: invalid uint kind")
+       case Uint:
+               *(*uint)(v.addr) = uint(x)
+       case Uint8:
+               *(*uint8)(v.addr) = uint8(x)
+       case Uint16:
+               *(*uint16)(v.addr) = uint16(x)
+       case Uint32:
+               *(*uint32)(v.addr) = uint32(x)
+       case Uint64:
+               *(*uint64)(v.addr) = x
+       case Uintptr:
+               *(*uintptr)(v.addr) = uintptr(x)
+       }
+}
+
+// Overflow returns true if x cannot be represented by the type of v.
+func (v *UintValue) Overflow(x uint64) bool {
+       bitSize := uint(v.typ.Bits())
+       trunc := (x << (64 - bitSize)) >> (64 - bitSize)
+       return x != trunc
+}
+
+// Set sets v to the value x.
+func (v *UintValue) SetValue(x Value) { v.Set(x.(*UintValue).Get()) }
+
+// UnsafePointerValue represents an unsafe.Pointer value.
+type UnsafePointerValue struct {
+       value "unsafe.Pointer"
+}
+
+// Get returns the underlying uintptr value.
+// Get returns uintptr, not unsafe.Pointer, so that
+// programs that do not import "unsafe" cannot
+// obtain a value of unsafe.Pointer type from "reflect".
+func (v *UnsafePointerValue) Get() uintptr { return uintptr(*(*unsafe.Pointer)(v.addr)) }
+
+// Set sets v to the value x.
+func (v *UnsafePointerValue) Set(x unsafe.Pointer) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       *(*unsafe.Pointer)(v.addr) = x
+}
+
+// Set sets v to the value x.
+func (v *UnsafePointerValue) SetValue(x Value) {
+       v.Set(unsafe.Pointer(x.(*UnsafePointerValue).Get()))
+}
+
+func typesMustMatch(t1, t2 Type) {
+       if t1 != t2 {
+               panic("type mismatch: " + t1.String() + " != " + t2.String())
+       }
+}
+
+/*
+ * array
+ */
+
+// ArrayOrSliceValue is the common interface
+// implemented by both ArrayValue and SliceValue.
+type ArrayOrSliceValue interface {
+       Value
+       Len() int
+       Cap() int
+       Elem(i int) Value
+       addr() addr
+}
+
+// ArrayCopy copies the contents of src into dst until either
+// dst has been filled or src has been exhausted.
+// It returns the number of elements copied.
+// The arrays dst and src must have the same element type.
+func ArrayCopy(dst, src ArrayOrSliceValue) int {
+       // TODO: This will have to move into the runtime
+       // once the real gc goes in.
+       de := dst.Type().(ArrayOrSliceType).Elem()
+       se := src.Type().(ArrayOrSliceType).Elem()
+       typesMustMatch(de, se)
+       n := dst.Len()
+       if xn := src.Len(); n > xn {
+               n = xn
+       }
+       memmove(dst.addr(), src.addr(), uintptr(n)*de.Size())
+       return n
+}
+
+// An ArrayValue represents an array.
+type ArrayValue struct {
+       value "array"
+}
+
+// Len returns the length of the array.
+func (v *ArrayValue) Len() int { return v.typ.(*ArrayType).Len() }
+
+// Cap returns the capacity of the array (equal to Len()).
+func (v *ArrayValue) Cap() int { return v.typ.(*ArrayType).Len() }
+
+// addr returns the base address of the data in the array.
+func (v *ArrayValue) addr() addr { return v.value.addr }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *ArrayValue) Set(x *ArrayValue) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       typesMustMatch(v.typ, x.typ)
+       ArrayCopy(v, x)
+}
+
+// Set sets v to the value x.
+func (v *ArrayValue) SetValue(x Value) { v.Set(x.(*ArrayValue)) }
+
+// Elem returns the i'th element of v.
+func (v *ArrayValue) Elem(i int) Value {
+       typ := v.typ.(*ArrayType).Elem()
+       n := v.Len()
+       if i < 0 || i >= n {
+               panic("array index out of bounds")
+       }
+       p := addr(uintptr(v.addr()) + uintptr(i)*typ.Size())
+       return newValue(typ, p, v.canSet)
+}
+
+/*
+ * slice
+ */
+
+// runtime representation of slice
+type SliceHeader struct {
+       Data uintptr
+       Len  int
+       Cap  int
+}
+
+// A SliceValue represents a slice.
+type SliceValue struct {
+       value "slice"
+}
+
+func (v *SliceValue) slice() *SliceHeader { return (*SliceHeader)(v.value.addr) }
+
+// IsNil returns whether v is a nil slice.
+func (v *SliceValue) IsNil() bool { return v.slice().Data == 0 }
+
+// Len returns the length of the slice.
+func (v *SliceValue) Len() int { return int(v.slice().Len) }
+
+// Cap returns the capacity of the slice.
+func (v *SliceValue) Cap() int { return int(v.slice().Cap) }
+
+// addr returns the base address of the data in the slice.
+func (v *SliceValue) addr() addr { return addr(v.slice().Data) }
+
+// SetLen changes the length of v.
+// The new length n must be between 0 and the capacity, inclusive.
+func (v *SliceValue) SetLen(n int) {
+       s := v.slice()
+       if n < 0 || n > int(s.Cap) {
+               panic("reflect: slice length out of range in SetLen")
+       }
+       s.Len = n
+}
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *SliceValue) Set(x *SliceValue) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       typesMustMatch(v.typ, x.typ)
+       *v.slice() = *x.slice()
+}
+
+// Set sets v to the value x.
+func (v *SliceValue) SetValue(x Value) { v.Set(x.(*SliceValue)) }
+
+// Get returns the uintptr address of the v.Cap()'th element.  This gives
+// the same result for all slices of the same array.
+// It is mainly useful for printing.
+func (v *SliceValue) Get() uintptr {
+       typ := v.typ.(*SliceType)
+       return uintptr(v.addr()) + uintptr(v.Cap())*typ.Elem().Size()
+}
+
+// Slice returns a sub-slice of the slice v.
+func (v *SliceValue) Slice(beg, end int) *SliceValue {
+       cap := v.Cap()
+       if beg < 0 || end < beg || end > cap {
+               panic("slice index out of bounds")
+       }
+       typ := v.typ.(*SliceType)
+       s := new(SliceHeader)
+       s.Data = uintptr(v.addr()) + uintptr(beg)*typ.Elem().Size()
+       s.Len = end - beg
+       s.Cap = cap - beg
+       return newValue(typ, addr(s), v.canSet).(*SliceValue)
+}
+
+// Elem returns the i'th element of v.
+func (v *SliceValue) Elem(i int) Value {
+       typ := v.typ.(*SliceType).Elem()
+       n := v.Len()
+       if i < 0 || i >= n {
+               panic("reflect: slice index out of range")
+       }
+       p := addr(uintptr(v.addr()) + uintptr(i)*typ.Size())
+       return newValue(typ, p, v.canSet)
+}
+
+// MakeSlice creates a new zero-initialized slice value
+// for the specified slice type, length, and capacity.
+func MakeSlice(typ *SliceType, len, cap int) *SliceValue {
+       s := &SliceHeader{
+               Data: uintptr(unsafe.NewArray(typ.Elem(), cap)),
+               Len:  len,
+               Cap:  cap,
+       }
+       return newValue(typ, addr(s), true).(*SliceValue)
+}
+
+/*
+ * chan
+ */
+
+// A ChanValue represents a chan.
+type ChanValue struct {
+       value "chan"
+}
+
+// IsNil returns whether v is a nil channel.
+func (v *ChanValue) IsNil() bool { return *(*uintptr)(v.addr) == 0 }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *ChanValue) Set(x *ChanValue) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       typesMustMatch(v.typ, x.typ)
+       *(*uintptr)(v.addr) = *(*uintptr)(x.addr)
+}
+
+// Set sets v to the value x.
+func (v *ChanValue) SetValue(x Value) { v.Set(x.(*ChanValue)) }
+
+// Get returns the uintptr value of v.
+// It is mainly useful for printing.
+func (v *ChanValue) Get() uintptr { return *(*uintptr)(v.addr) }
+
+// implemented in ../pkg/runtime/reflect.cgo
+func makechan(typ *runtime.ChanType, size uint32) (ch *byte)
+func chansend(ch, val *byte, pres *bool)
+func chanrecv(ch, val *byte, pres *bool)
+func chanclosed(ch *byte) bool
+func chanclose(ch *byte)
+func chanlen(ch *byte) int32
+func chancap(ch *byte) int32
+
+// Closed returns the result of closed(c) on the underlying channel.
+func (v *ChanValue) Closed() bool {
+       ch := *(**byte)(v.addr)
+       return chanclosed(ch)
+}
+
+// Close closes the channel.
+func (v *ChanValue) Close() {
+       ch := *(**byte)(v.addr)
+       chanclose(ch)
+}
+
+func (v *ChanValue) Len() int {
+       ch := *(**byte)(v.addr)
+       return int(chanlen(ch))
+}
+
+func (v *ChanValue) Cap() int {
+       ch := *(**byte)(v.addr)
+       return int(chancap(ch))
+}
+
+// internal send; non-blocking if b != nil
+func (v *ChanValue) send(x Value, b *bool) {
+       t := v.Type().(*ChanType)
+       if t.Dir()&SendDir == 0 {
+               panic("send on recv-only channel")
+       }
+       typesMustMatch(t.Elem(), x.Type())
+       ch := *(**byte)(v.addr)
+       chansend(ch, (*byte)(x.getAddr()), b)
+}
+
+// internal recv; non-blocking if b != nil
+func (v *ChanValue) recv(b *bool) Value {
+       t := v.Type().(*ChanType)
+       if t.Dir()&RecvDir == 0 {
+               panic("recv on send-only channel")
+       }
+       ch := *(**byte)(v.addr)
+       x := MakeZero(t.Elem())
+       chanrecv(ch, (*byte)(x.getAddr()), b)
+       return x
+}
+
+// Send sends x on the channel v.
+func (v *ChanValue) Send(x Value) { v.send(x, nil) }
+
+// Recv receives and returns a value from the channel v.
+func (v *ChanValue) Recv() Value { return v.recv(nil) }
+
+// TrySend attempts to sends x on the channel v but will not block.
+// It returns true if the value was sent, false otherwise.
+func (v *ChanValue) TrySend(x Value) bool {
+       var ok bool
+       v.send(x, &ok)
+       return ok
+}
+
+// TryRecv attempts to receive a value from the channel v but will not block.
+// It returns the value if one is received, nil otherwise.
+func (v *ChanValue) TryRecv() Value {
+       var ok bool
+       x := v.recv(&ok)
+       if !ok {
+               return nil
+       }
+       return x
+}
+
+// MakeChan creates a new channel with the specified type and buffer size.
+func MakeChan(typ *ChanType, buffer int) *ChanValue {
+       if buffer < 0 {
+               panic("MakeChan: negative buffer size")
+       }
+       if typ.Dir() != BothDir {
+               panic("MakeChan: unidirectional channel type")
+       }
+       v := MakeZero(typ).(*ChanValue)
+       *(**byte)(v.addr) = makechan((*runtime.ChanType)(unsafe.Pointer(typ)), uint32(buffer))
+       return v
+}
+
+/*
+ * func
+ */
+
+// A FuncValue represents a function value.
+type FuncValue struct {
+       value       "func"
+       first       *value
+       isInterface bool
+}
+
+// IsNil returns whether v is a nil function.
+func (v *FuncValue) IsNil() bool { return *(*uintptr)(v.addr) == 0 }
+
+// Get returns the uintptr value of v.
+// It is mainly useful for printing.
+func (v *FuncValue) Get() uintptr { return *(*uintptr)(v.addr) }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *FuncValue) Set(x *FuncValue) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       typesMustMatch(v.typ, x.typ)
+       *(*uintptr)(v.addr) = *(*uintptr)(x.addr)
+}
+
+// Set sets v to the value x.
+func (v *FuncValue) SetValue(x Value) { v.Set(x.(*FuncValue)) }
+
+// Method returns a FuncValue corresponding to v's i'th method.
+// The arguments to a Call on the returned FuncValue
+// should not include a receiver; the FuncValue will use v
+// as the receiver.
+func (v *value) Method(i int) *FuncValue {
+       t := v.Type().uncommon()
+       if t == nil || i < 0 || i >= len(t.methods) {
+               return nil
+       }
+       p := &t.methods[i]
+       fn := p.tfn
+       fv := &FuncValue{value: value{runtimeToType(p.typ), addr(&fn), true}, first: v, isInterface: false}
+       return fv
+}
+
+// implemented in ../pkg/runtime/*/asm.s
+func call(typ *FuncType, fnaddr *byte, isInterface bool, params *addr, results *addr)
+
+// Call calls the function fv with input parameters in.
+// It returns the function's output parameters as Values.
+func (fv *FuncValue) Call(in []Value) []Value {
+       t := fv.Type().(*FuncType)
+       nin := len(in)
+       if fv.first != nil && !fv.isInterface {
+               nin++
+       }
+       if nin != t.NumIn() {
+               panic("FuncValue: wrong argument count")
+       }
+       if fv.first != nil && fv.isInterface {
+               nin++
+       }
+       nout := t.NumOut()
+
+       params := make([]addr, nin)
+       delta := 0
+       off := 0
+       if v := fv.first; v != nil {
+               // Hard-wired first argument.
+               if fv.isInterface {
+                       // v is a single uninterpreted word
+                       params[0] = v.getAddr()
+               } else {
+                       // v is a real value
+                       tv := v.Type()
+
+                       // This is a method, so we need to always pass
+                       // a pointer.
+                       vAddr := v.getAddr()
+                       if ptv, ok := tv.(*PtrType); ok {
+                               typesMustMatch(t.In(0), tv)
+                       } else {
+                               p := addr(new(addr))
+                               *(*addr)(p) = vAddr
+                               vAddr = p
+                               typesMustMatch(t.In(0).(*PtrType).Elem(), tv)
+                       }
+
+                       params[0] = vAddr
+                       delta = 1
+               }
+               off = 1
+       }
+       for i, v := range in {
+               tv := v.Type()
+               tf := t.In(i + delta)
+
+               // If this is really a method, and we are explicitly
+               // passing the object, then we need to pass the address
+               // of the object instead.  Unfortunately, we don't
+               // have any way to know that this is a method, so we just
+               // check the type.  FIXME: This is ugly.
+               vAddr := v.getAddr()
+               if i == 0 && tf != tv {
+                       if ptf, ok := tf.(*PtrType); ok {
+                               p := addr(new(addr))
+                               *(*addr)(p) = vAddr
+                               vAddr = p
+                               tf = ptf.Elem()
+                       }
+               }
+
+               typesMustMatch(tf, tv)
+               params[i+off] = vAddr
+       }
+
+       ret := make([]Value, nout)
+       results := make([]addr, nout)
+       for i := 0; i < nout; i++ {
+               tv := t.Out(i)
+               v := MakeZero(tv)
+               results[i] = v.getAddr()
+               ret[i] = v
+       }
+
+       call(t, *(**byte)(fv.addr), fv.isInterface, &params[0], &results[0])
+
+       return ret
+}
+
+/*
+ * interface
+ */
+
+// An InterfaceValue represents an interface value.
+type InterfaceValue struct {
+       value "interface"
+}
+
+// IsNil returns whether v is a nil interface value.
+func (v *InterfaceValue) IsNil() bool { return v.Interface() == nil }
+
+// No single uinptr Get because v.Interface() is available.
+
+// Get returns the two words that represent an interface in the runtime.
+// Those words are useful only when playing unsafe games.
+func (v *InterfaceValue) Get() [2]uintptr {
+       return *(*[2]uintptr)(v.addr)
+}
+
+// Elem returns the concrete value stored in the interface value v.
+func (v *InterfaceValue) Elem() Value { return NewValue(v.Interface()) }
+
+// ../runtime/reflect.cgo
+func setiface(typ *InterfaceType, x *interface{}, addr addr)
+
+// Set assigns x to v.
+func (v *InterfaceValue) Set(x Value) {
+       var i interface{}
+       if x != nil {
+               i = x.Interface()
+       }
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       // Two different representations; see comment in Get.
+       // Empty interface is easy.
+       t := v.typ.(*InterfaceType)
+       if t.NumMethod() == 0 {
+               *(*interface{})(v.addr) = i
+               return
+       }
+
+       // Non-empty interface requires a runtime check.
+       setiface(t, &i, v.addr)
+}
+
+// Set sets v to the value x.
+func (v *InterfaceValue) SetValue(x Value) { v.Set(x) }
+
+// Method returns a FuncValue corresponding to v's i'th method.
+// The arguments to a Call on the returned FuncValue
+// should not include a receiver; the FuncValue will use v
+// as the receiver.
+func (v *InterfaceValue) Method(i int) *FuncValue {
+       t := v.Type().(*InterfaceType)
+       if t == nil || i < 0 || i >= len(t.methods) {
+               return nil
+       }
+       p := &t.methods[i]
+
+       // Interface is two words: itable, data.
+       tab := *(**[10000]addr)(v.addr)
+       data := &value{Typeof((*byte)(nil)), addr(uintptr(v.addr) + ptrSize), true}
+
+       fn := tab[i+1]
+       fv := &FuncValue{value: value{runtimeToType(p.typ), addr(&fn), true}, first: data, isInterface: true}
+       return fv
+}
+
+/*
+ * map
+ */
+
+// A MapValue represents a map value.
+type MapValue struct {
+       value "map"
+}
+
+// IsNil returns whether v is a nil map value.
+func (v *MapValue) IsNil() bool { return *(*uintptr)(v.addr) == 0 }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *MapValue) Set(x *MapValue) {
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       if x == nil {
+               *(**uintptr)(v.addr) = nil
+               return
+       }
+       typesMustMatch(v.typ, x.typ)
+       *(*uintptr)(v.addr) = *(*uintptr)(x.addr)
+}
+
+// Set sets v to the value x.
+func (v *MapValue) SetValue(x Value) {
+       if x == nil {
+               v.Set(nil)
+               return
+       }
+       v.Set(x.(*MapValue))
+}
+
+// Get returns the uintptr value of v.
+// It is mainly useful for printing.
+func (v *MapValue) Get() uintptr { return *(*uintptr)(v.addr) }
+
+// implemented in ../pkg/runtime/reflect.cgo
+func mapaccess(m, key, val *byte) bool
+func mapassign(m, key, val *byte)
+func maplen(m *byte) int32
+func mapiterinit(m *byte) *byte
+func mapiternext(it *byte)
+func mapiterkey(it *byte, key *byte) bool
+func makemap(t *runtime.MapType) *byte
+
+// Elem returns the value associated with key in the map v.
+// It returns nil if key is not found in the map.
+func (v *MapValue) Elem(key Value) Value {
+       t := v.Type().(*MapType)
+       typesMustMatch(t.Key(), key.Type())
+       m := *(**byte)(v.addr)
+       if m == nil {
+               return nil
+       }
+       newval := MakeZero(t.Elem())
+       if !mapaccess(m, (*byte)(key.getAddr()), (*byte)(newval.getAddr())) {
+               return nil
+       }
+       return newval
+}
+
+// SetElem sets the value associated with key in the map v to val.
+// If val is nil, Put deletes the key from map.
+func (v *MapValue) SetElem(key, val Value) {
+       t := v.Type().(*MapType)
+       typesMustMatch(t.Key(), key.Type())
+       var vaddr *byte
+       if val != nil {
+               typesMustMatch(t.Elem(), val.Type())
+               vaddr = (*byte)(val.getAddr())
+       }
+       m := *(**byte)(v.addr)
+       mapassign(m, (*byte)(key.getAddr()), vaddr)
+}
+
+// Len returns the number of keys in the map v.
+func (v *MapValue) Len() int {
+       m := *(**byte)(v.addr)
+       if m == nil {
+               return 0
+       }
+       return int(maplen(m))
+}
+
+// Keys returns a slice containing all the keys present in the map,
+// in unspecified order.
+func (v *MapValue) Keys() []Value {
+       tk := v.Type().(*MapType).Key()
+       m := *(**byte)(v.addr)
+       mlen := int32(0)
+       if m != nil {
+               mlen = maplen(m)
+       }
+       it := mapiterinit(m)
+       a := make([]Value, mlen)
+       var i int
+       for i = 0; i < len(a); i++ {
+               k := MakeZero(tk)
+               if !mapiterkey(it, (*byte)(k.getAddr())) {
+                       break
+               }
+               a[i] = k
+               mapiternext(it)
+       }
+       return a[0:i]
+}
+
+// MakeMap creates a new map of the specified type.
+func MakeMap(typ *MapType) *MapValue {
+       v := MakeZero(typ).(*MapValue)
+       *(**byte)(v.addr) = makemap((*runtime.MapType)(unsafe.Pointer(typ)))
+       return v
+}
+
+/*
+ * ptr
+ */
+
+// A PtrValue represents a pointer.
+type PtrValue struct {
+       value "ptr"
+}
+
+// IsNil returns whether v is a nil pointer.
+func (v *PtrValue) IsNil() bool { return *(*uintptr)(v.addr) == 0 }
+
+// Get returns the uintptr value of v.
+// It is mainly useful for printing.
+func (v *PtrValue) Get() uintptr { return *(*uintptr)(v.addr) }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *PtrValue) Set(x *PtrValue) {
+       if x == nil {
+               *(**uintptr)(v.addr) = nil
+               return
+       }
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       typesMustMatch(v.typ, x.typ)
+       // TODO: This will have to move into the runtime
+       // once the new gc goes in
+       *(*uintptr)(v.addr) = *(*uintptr)(x.addr)
+}
+
+// Set sets v to the value x.
+func (v *PtrValue) SetValue(x Value) {
+       if x == nil {
+               v.Set(nil)
+               return
+       }
+       v.Set(x.(*PtrValue))
+}
+
+// PointTo changes v to point to x.
+// If x is a nil Value, PointTo sets v to nil.
+func (v *PtrValue) PointTo(x Value) {
+       if x == nil {
+               *(**uintptr)(v.addr) = nil
+               return
+       }
+       if !x.CanSet() {
+               panic("cannot set x; cannot point to x")
+       }
+       typesMustMatch(v.typ.(*PtrType).Elem(), x.Type())
+       // TODO: This will have to move into the runtime
+       // once the new gc goes in.
+       *(*uintptr)(v.addr) = x.Addr()
+}
+
+// Elem returns the value that v points to.
+// If v is a nil pointer, Elem returns a nil Value.
+func (v *PtrValue) Elem() Value {
+       if v.IsNil() {
+               return nil
+       }
+       return newValue(v.typ.(*PtrType).Elem(), *(*addr)(v.addr), v.canSet)
+}
+
+// Indirect returns the value that v points to.
+// If v is a nil pointer, Indirect returns a nil Value.
+// If v is not a pointer, Indirect returns v.
+func Indirect(v Value) Value {
+       if pv, ok := v.(*PtrValue); ok {
+               return pv.Elem()
+       }
+       return v
+}
+
+/*
+ * struct
+ */
+
+// A StructValue represents a struct value.
+type StructValue struct {
+       value "struct"
+}
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *StructValue) Set(x *StructValue) {
+       // TODO: This will have to move into the runtime
+       // once the gc goes in.
+       if !v.canSet {
+               panic(cannotSet)
+       }
+       typesMustMatch(v.typ, x.typ)
+       memmove(v.addr, x.addr, v.typ.Size())
+}
+
+// Set sets v to the value x.
+func (v *StructValue) SetValue(x Value) { v.Set(x.(*StructValue)) }
+
+// Field returns the i'th field of the struct.
+func (v *StructValue) Field(i int) Value {
+       t := v.typ.(*StructType)
+       if i < 0 || i >= t.NumField() {
+               return nil
+       }
+       f := t.Field(i)
+       return newValue(f.Type, addr(uintptr(v.addr)+f.Offset), v.canSet && f.PkgPath == "")
+}
+
+// FieldByIndex returns the nested field corresponding to index.
+func (t *StructValue) FieldByIndex(index []int) (v Value) {
+       v = t
+       for i, x := range index {
+               if i > 0 {
+                       if p, ok := v.(*PtrValue); ok {
+                               v = p.Elem()
+                       }
+                       if s, ok := v.(*StructValue); ok {
+                               t = s
+                       } else {
+                               v = nil
+                               return
+                       }
+               }
+               v = t.Field(x)
+       }
+       return
+}
+
+// FieldByName returns the struct field with the given name.
+// The result is nil if no field was found.
+func (t *StructValue) FieldByName(name string) Value {
+       if f, ok := t.Type().(*StructType).FieldByName(name); ok {
+               return t.FieldByIndex(f.Index)
+       }
+       return nil
+}
+
+// FieldByNameFunc returns the struct field with a name that satisfies the
+// match function.
+// The result is nil if no field was found.
+func (t *StructValue) FieldByNameFunc(match func(string) bool) Value {
+       if f, ok := t.Type().(*StructType).FieldByNameFunc(match); ok {
+               return t.FieldByIndex(f.Index)
+       }
+       return nil
+}
+
+// NumField returns the number of fields in the struct.
+func (v *StructValue) NumField() int { return v.typ.(*StructType).NumField() }
+
+/*
+ * constructors
+ */
+
+// NewValue returns a new Value initialized to the concrete value
+// stored in the interface i.  NewValue(nil) returns nil.
+func NewValue(i interface{}) Value {
+       if i == nil {
+               return nil
+       }
+       t, a := unsafe.Reflect(i)
+       return newValue(canonicalize(toType(t)), addr(a), true)
+}
+
+func newValue(typ Type, addr addr, canSet bool) Value {
+       v := value{typ, addr, canSet}
+       switch typ.(type) {
+       case *ArrayType:
+               return &ArrayValue{v}
+       case *BoolType:
+               return &BoolValue{v}
+       case *ChanType:
+               return &ChanValue{v}
+       case *FloatType:
+               return &FloatValue{v}
+       case *FuncType:
+               return &FuncValue{value: v}
+       case *ComplexType:
+               return &ComplexValue{v}
+       case *IntType:
+               return &IntValue{v}
+       case *InterfaceType:
+               return &InterfaceValue{v}
+       case *MapType:
+               return &MapValue{v}
+       case *PtrType:
+               return &PtrValue{v}
+       case *SliceType:
+               return &SliceValue{v}
+       case *StringType:
+               return &StringValue{v}
+       case *StructType:
+               return &StructValue{v}
+       case *UintType:
+               return &UintValue{v}
+       case *UnsafePointerType:
+               return &UnsafePointerValue{v}
+       }
+       panic("newValue" + typ.String())
+}
+
+// MakeZero returns a zero Value for the specified Type.
+func MakeZero(typ Type) Value {
+       if typ == nil {
+               return nil
+       }
+       return newValue(typ, addr(unsafe.New(typ)), true)
+}
diff --git a/libgo/go/regexp/all_test.go b/libgo/go/regexp/all_test.go
new file mode 100644 (file)
index 0000000..d5a0e7d
--- /dev/null
@@ -0,0 +1,362 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+       "os"
+       "strings"
+       "testing"
+)
+
+var good_re = []string{
+       ``,
+       `.`,
+       `^.$`,
+       `a`,
+       `a*`,
+       `a+`,
+       `a?`,
+       `a|b`,
+       `a*|b*`,
+       `(a*|b)(c*|d)`,
+       `[a-z]`,
+       `[a-abc-c\-\]\[]`,
+       `[a-z]+`,
+       `[]`,
+       `[abc]`,
+       `[^1234]`,
+       `[^\n]`,
+       `\!\\`,
+}
+
+type stringError struct {
+       re  string
+       err os.Error
+}
+
+var bad_re = []stringError{
+       {`*`, ErrBareClosure},
+       {`(abc`, ErrUnmatchedLpar},
+       {`abc)`, ErrUnmatchedRpar},
+       {`x[a-z`, ErrUnmatchedLbkt},
+       {`abc]`, ErrUnmatchedRbkt},
+       {`[z-a]`, ErrBadRange},
+       {`abc\`, ErrExtraneousBackslash},
+       {`a**`, ErrBadClosure},
+       {`a*+`, ErrBadClosure},
+       {`a??`, ErrBadClosure},
+       {`*`, ErrBareClosure},
+       {`\x`, ErrBadBackslash},
+}
+
+func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
+       re, err := Compile(expr)
+       if err != error {
+               t.Error("compiling `", expr, "`; unexpected error: ", err.String())
+       }
+       return re
+}
+
+func TestGoodCompile(t *testing.T) {
+       for i := 0; i < len(good_re); i++ {
+               compileTest(t, good_re[i], nil)
+       }
+}
+
+func TestBadCompile(t *testing.T) {
+       for i := 0; i < len(bad_re); i++ {
+               compileTest(t, bad_re[i].re, bad_re[i].err)
+       }
+}
+
+func matchTest(t *testing.T, test *FindTest) {
+       re := compileTest(t, test.pat, nil)
+       if re == nil {
+               return
+       }
+       m := re.MatchString(test.text)
+       if m != (len(test.matches) > 0) {
+               t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+       }
+       // now try bytes
+       m = re.Match([]byte(test.text))
+       if m != (len(test.matches) > 0) {
+               t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+       }
+}
+
+func TestMatch(t *testing.T) {
+       for _, test := range findTests {
+               matchTest(t, &test)
+       }
+}
+
+func matchFunctionTest(t *testing.T, test *FindTest) {
+       m, err := MatchString(test.pat, test.text)
+       if err == nil {
+               return
+       }
+       if m != (len(test.matches) > 0) {
+               t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+       }
+}
+
+func TestMatchFunction(t *testing.T) {
+       for _, test := range findTests {
+               matchFunctionTest(t, &test)
+       }
+}
+
+type ReplaceTest struct {
+       pattern, replacement, input, output string
+}
+
+var replaceTests = []ReplaceTest{
+       // Test empty input and/or replacement, with pattern that matches the empty string.
+       {"", "", "", ""},
+       {"", "x", "", "x"},
+       {"", "", "abc", "abc"},
+       {"", "x", "abc", "xaxbxcx"},
+
+       // Test empty input and/or replacement, with pattern that does not match the empty string.
+       {"b", "", "", ""},
+       {"b", "x", "", ""},
+       {"b", "", "abc", "ac"},
+       {"b", "x", "abc", "axc"},
+       {"y", "", "", ""},
+       {"y", "x", "", ""},
+       {"y", "", "abc", "abc"},
+       {"y", "x", "abc", "abc"},
+
+       // Multibyte characters -- verify that we don't try to match in the middle
+       // of a character.
+       {"[a-c]*", "x", "\u65e5", "x\u65e5x"},
+       {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
+
+       // Start and end of a string.
+       {"^[a-c]*", "x", "abcdabc", "xdabc"},
+       {"[a-c]*$", "x", "abcdabc", "abcdx"},
+       {"^[a-c]*$", "x", "abcdabc", "abcdabc"},
+       {"^[a-c]*", "x", "abc", "x"},
+       {"[a-c]*$", "x", "abc", "x"},
+       {"^[a-c]*$", "x", "abc", "x"},
+       {"^[a-c]*", "x", "dabce", "xdabce"},
+       {"[a-c]*$", "x", "dabce", "dabcex"},
+       {"^[a-c]*$", "x", "dabce", "dabce"},
+       {"^[a-c]*", "x", "", "x"},
+       {"[a-c]*$", "x", "", "x"},
+       {"^[a-c]*$", "x", "", "x"},
+
+       {"^[a-c]+", "x", "abcdabc", "xdabc"},
+       {"[a-c]+$", "x", "abcdabc", "abcdx"},
+       {"^[a-c]+$", "x", "abcdabc", "abcdabc"},
+       {"^[a-c]+", "x", "abc", "x"},
+       {"[a-c]+$", "x", "abc", "x"},
+       {"^[a-c]+$", "x", "abc", "x"},
+       {"^[a-c]+", "x", "dabce", "dabce"},
+       {"[a-c]+$", "x", "dabce", "dabce"},
+       {"^[a-c]+$", "x", "dabce", "dabce"},
+       {"^[a-c]+", "x", "", ""},
+       {"[a-c]+$", "x", "", ""},
+       {"^[a-c]+$", "x", "", ""},
+
+       // Other cases.
+       {"abc", "def", "abcdefg", "defdefg"},
+       {"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
+       {"abc", "", "abcdabc", "d"},
+       {"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
+       {"abc", "d", "", ""},
+       {"abc", "d", "abc", "d"},
+       {".+", "x", "abc", "x"},
+       {"[a-c]*", "x", "def", "xdxexfx"},
+       {"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
+       {"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
+}
+
+type ReplaceFuncTest struct {
+       pattern       string
+       replacement   func(string) string
+       input, output string
+}
+
+var replaceFuncTests = []ReplaceFuncTest{
+       {"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"},
+       {"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"},
+       {"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
+}
+
+func TestReplaceAll(t *testing.T) {
+       for _, tc := range replaceTests {
+               re, err := Compile(tc.pattern)
+               if err != nil {
+                       t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+                       continue
+               }
+               actual := re.ReplaceAllString(tc.input, tc.replacement)
+               if actual != tc.output {
+                       t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+                               tc.pattern, tc.input, tc.replacement, actual, tc.output)
+               }
+               // now try bytes
+               actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement)))
+               if actual != tc.output {
+                       t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+                               tc.pattern, tc.input, tc.replacement, actual, tc.output)
+               }
+       }
+}
+
+func TestReplaceAllFunc(t *testing.T) {
+       for _, tc := range replaceFuncTests {
+               re, err := Compile(tc.pattern)
+               if err != nil {
+                       t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+                       continue
+               }
+               actual := re.ReplaceAllStringFunc(tc.input, tc.replacement)
+               if actual != tc.output {
+                       t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+                               tc.pattern, tc.input, tc.replacement, actual, tc.output)
+               }
+               // now try bytes
+               actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) }))
+               if actual != tc.output {
+                       t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+                               tc.pattern, tc.input, tc.replacement, actual, tc.output)
+               }
+       }
+}
+
+type QuoteMetaTest struct {
+       pattern, output string
+}
+
+var quoteMetaTests = []QuoteMetaTest{
+       {``, ``},
+       {`foo`, `foo`},
+       {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[{\]}\\\|,<\.>/\?~`},
+}
+
+func TestQuoteMeta(t *testing.T) {
+       for _, tc := range quoteMetaTests {
+               // Verify that QuoteMeta returns the expected string.
+               quoted := QuoteMeta(tc.pattern)
+               if quoted != tc.output {
+                       t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
+                               tc.pattern, quoted, tc.output)
+                       continue
+               }
+
+               // Verify that the quoted string is in fact treated as expected
+               // by Compile -- i.e. that it matches the original, unquoted string.
+               if tc.pattern != "" {
+                       re, err := Compile(quoted)
+                       if err != nil {
+                               t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err)
+                               continue
+                       }
+                       src := "abc" + tc.pattern + "def"
+                       repl := "xyz"
+                       replaced := re.ReplaceAllString(src, repl)
+                       expected := "abcxyzdef"
+                       if replaced != expected {
+                               t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
+                                       tc.pattern, src, repl, replaced, expected)
+                       }
+               }
+       }
+}
+
+type numSubexpCase struct {
+       input    string
+       expected int
+}
+
+var numSubexpCases = []numSubexpCase{
+       {``, 0},
+       {`.*`, 0},
+       {`abba`, 0},
+       {`ab(b)a`, 1},
+       {`ab(.*)a`, 1},
+       {`(.*)ab(.*)a`, 2},
+       {`(.*)(ab)(.*)a`, 3},
+       {`(.*)((a)b)(.*)a`, 4},
+       {`(.*)(\(ab)(.*)a`, 3},
+       {`(.*)(\(a\)b)(.*)a`, 3},
+}
+
+func TestNumSubexp(t *testing.T) {
+       for _, c := range numSubexpCases {
+               re := MustCompile(c.input)
+               n := re.NumSubexp()
+               if n != c.expected {
+                       t.Errorf("NumSubexp for %q returned %d, expected %d", c.input, n, c.expected)
+               }
+       }
+}
+
+func BenchmarkLiteral(b *testing.B) {
+       x := strings.Repeat("x", 50)
+       b.StopTimer()
+       re := MustCompile(x)
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               if !re.MatchString(x) {
+                       println("no match!")
+                       break
+               }
+       }
+}
+
+func BenchmarkNotLiteral(b *testing.B) {
+       x := strings.Repeat("x", 49)
+       b.StopTimer()
+       re := MustCompile("^" + x)
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               if !re.MatchString(x) {
+                       println("no match!")
+                       break
+               }
+       }
+}
+
+func BenchmarkMatchClass(b *testing.B) {
+       b.StopTimer()
+       x := strings.Repeat("xxxx", 20) + "w"
+       re := MustCompile("[abcdw]")
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               if !re.MatchString(x) {
+                       println("no match!")
+                       break
+               }
+       }
+}
+
+func BenchmarkMatchClass_InRange(b *testing.B) {
+       b.StopTimer()
+       // 'b' is betwen 'a' and 'c', so the charclass
+       // range checking is no help here.
+       x := strings.Repeat("bbbb", 20) + "c"
+       re := MustCompile("[ac]")
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               if !re.MatchString(x) {
+                       println("no match!")
+                       break
+               }
+       }
+}
+
+func BenchmarkReplaceAll(b *testing.B) {
+       x := "abcdefghijklmnopqrstuvwxyz"
+       b.StopTimer()
+       re := MustCompile("[cjrw]")
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               re.ReplaceAllString(x, "")
+       }
+}
diff --git a/libgo/go/regexp/find_test.go b/libgo/go/regexp/find_test.go
new file mode 100644 (file)
index 0000000..07f5586
--- /dev/null
@@ -0,0 +1,454 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+       "fmt"
+       "testing"
+)
+
+// For each pattern/text pair, what is the expected output of each function?
+// We can derive the textual results from the indexed results, the non-submatch
+// results from the submatched results, the single results from the 'all' results,
+// and the byte results from the string results. Therefore the table includes
+// only the FindAllStringSubmatchIndex result.
+type FindTest struct {
+       pat     string
+       text    string
+       matches [][]int
+}
+
+func (t FindTest) String() string {
+       return fmt.Sprintf("pat: %#q text: %#q", t.pat, t.text)
+}
+
+var findTests = []FindTest{
+       {``, ``, build(1, 0, 0)},
+       {`^abcdefg`, "abcdefg", build(1, 0, 7)},
+       {`a+`, "baaab", build(1, 1, 4)},
+       {"abcd..", "abcdef", build(1, 0, 6)},
+       {`a`, "a", build(1, 0, 1)},
+       {`x`, "y", nil},
+       {`b`, "abc", build(1, 1, 2)},
+       {`.`, "a", build(1, 0, 1)},
+       {`.*`, "abcdef", build(1, 0, 6)},
+       {`^`, "abcde", build(1, 0, 0)},
+       {`$`, "abcde", build(1, 5, 5)},
+       {`^abcd$`, "abcd", build(1, 0, 4)},
+       {`^bcd'`, "abcdef", nil},
+       {`^abcd$`, "abcde", nil},
+       {`a+`, "baaab", build(1, 1, 4)},
+       {`a*`, "baaab", build(3, 0, 0, 1, 4, 5, 5)},
+       {`[a-z]+`, "abcd", build(1, 0, 4)},
+       {`[^a-z]+`, "ab1234cd", build(1, 2, 6)},
+       {`[a\-\]z]+`, "az]-bcz", build(2, 0, 4, 6, 7)},
+       {`[^\n]+`, "abcd\n", build(1, 0, 4)},
+       {`[日本語]+`, "日本語日本語", build(1, 0, 18)},
+       {`日本語+`, "日本語", build(1, 0, 9)},
+       {`日本語+`, "日本語語語語", build(1, 0, 18)},
+       {`()`, "", build(1, 0, 0, 0, 0)},
+       {`(a)`, "a", build(1, 0, 1, 0, 1)},
+       {`(.)(.)`, "日a", build(1, 0, 4, 0, 3, 3, 4)},
+       {`(.*)`, "", build(1, 0, 0, 0, 0)},
+       {`(.*)`, "abcd", build(1, 0, 4, 0, 4)},
+       {`(..)(..)`, "abcd", build(1, 0, 4, 0, 2, 2, 4)},
+       {`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)},
+       {`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)},
+       {`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)},
+       {`\a\b\f\n\r\t\v`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
+       {`[\a\b\f\n\r\t\v]+`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
+
+       {`a*(|(b))c*`, "aacc", build(1, 0, 4, 2, 2, -1, -1)},
+       {`(.*).*`, "ab", build(1, 0, 2, 0, 2)},
+       {`[.]`, ".", build(1, 0, 1)},
+       {`/$`, "/abc/", build(1, 4, 5)},
+       {`/$`, "/abc", nil},
+
+       // multiple matches
+       {`.`, "abc", build(3, 0, 1, 1, 2, 2, 3)},
+       {`(.)`, "abc", build(3, 0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3)},
+       {`.(.)`, "abcd", build(2, 0, 2, 1, 2, 2, 4, 3, 4)},
+       {`ab*`, "abbaab", build(3, 0, 3, 3, 4, 4, 6)},
+       {`a(b*)`, "abbaab", build(3, 0, 3, 1, 3, 3, 4, 4, 4, 4, 6, 5, 6)},
+
+       // fixed bugs
+       {`ab$`, "cab", build(1, 1, 3)},
+       {`axxb$`, "axxcb", nil},
+       {`data`, "daXY data", build(1, 5, 9)},
+       {`da(.)a$`, "daXY data", build(1, 5, 9, 7, 8)},
+
+       // can backslash-escape any punctuation
+       {`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
+               `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+       {`[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~]+`,
+               `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+       {"\\`", "`", build(1, 0, 1)},
+       {"[\\`]+", "`", build(1, 0, 1)},
+
+       // long set of matches (longer than startSize)
+       {
+               ".",
+               "qwertyuiopasdfghjklzxcvbnm1234567890",
+               build(36, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
+                       10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
+                       20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
+                       30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36),
+       },
+}
+
+// build is a helper to construct a [][]int by extracting n sequences from x.
+// This represents n matches with len(x)/n submatches each.
+func build(n int, x ...int) [][]int {
+       ret := make([][]int, n)
+       runLength := len(x) / n
+       j := 0
+       for i := range ret {
+               ret[i] = make([]int, runLength)
+               copy(ret[i], x[j:])
+               j += runLength
+               if j > len(x) {
+                       panic("invalid build entry")
+               }
+       }
+       return ret
+}
+
+// First the simple cases.
+
+func TestFind(t *testing.T) {
+       for _, test := range findTests {
+               result := MustCompile(test.pat).Find([]byte(test.text))
+               switch {
+               case len(test.matches) == 0 && len(result) == 0:
+                       // ok
+               case test.matches == nil && result != nil:
+                       t.Errorf("expected no match; got one: %s", test)
+               case test.matches != nil && result == nil:
+                       t.Errorf("expected match; got none: %s", test)
+               case test.matches != nil && result != nil:
+                       expect := test.text[test.matches[0][0]:test.matches[0][1]]
+                       if expect != string(result) {
+                               t.Errorf("expected %q got %q: %s", expect, result, test)
+                       }
+               }
+       }
+}
+
+func TestFindString(t *testing.T) {
+       for _, test := range findTests {
+               result := MustCompile(test.pat).FindString(test.text)
+               switch {
+               case len(test.matches) == 0 && len(result) == 0:
+                       // ok
+               case test.matches == nil && result != "":
+                       t.Errorf("expected no match; got one: %s", test)
+               case test.matches != nil && result == "":
+                       // Tricky because an empty result has two meanings: no match or empty match.
+                       if test.matches[0][0] != test.matches[0][1] {
+                               t.Errorf("expected match; got none: %s", test)
+                       }
+               case test.matches != nil && result != "":
+                       expect := test.text[test.matches[0][0]:test.matches[0][1]]
+                       if expect != result {
+                               t.Errorf("expected %q got %q: %s", expect, result, test)
+                       }
+               }
+       }
+}
+
+func testFindIndex(test *FindTest, result []int, t *testing.T) {
+       switch {
+       case len(test.matches) == 0 && len(result) == 0:
+               // ok
+       case test.matches == nil && result != nil:
+               t.Errorf("expected no match; got one: %s", test)
+       case test.matches != nil && result == nil:
+               t.Errorf("expected match; got none: %s", test)
+       case test.matches != nil && result != nil:
+               expect := test.matches[0]
+               if expect[0] != result[0] || expect[1] != result[1] {
+                       t.Errorf("expected %v got %v: %s", expect, result, test)
+               }
+       }
+}
+
+func TestFindIndex(t *testing.T) {
+       for _, test := range findTests {
+               testFindIndex(&test, MustCompile(test.pat).FindIndex([]byte(test.text)), t)
+       }
+}
+
+func TestFindStringIndex(t *testing.T) {
+       for _, test := range findTests {
+               testFindIndex(&test, MustCompile(test.pat).FindStringIndex(test.text), t)
+       }
+}
+
+// Now come the simple All cases.
+
+func TestFindAll(t *testing.T) {
+       for _, test := range findTests {
+               result := MustCompile(test.pat).FindAll([]byte(test.text), -1)
+               switch {
+               case test.matches == nil && result == nil:
+                       // ok
+               case test.matches == nil && result != nil:
+                       t.Errorf("expected no match; got one: %s", test)
+               case test.matches != nil && result == nil:
+                       t.Errorf("expected match; got none: %s", test)
+               case test.matches != nil && result != nil:
+                       if len(test.matches) != len(result) {
+                               t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+                               continue
+                       }
+                       for k, e := range test.matches {
+                               expect := test.text[e[0]:e[1]]
+                               if expect != string(result[k]) {
+                                       t.Errorf("match %d: expected %q got %q: %s", k, expect, result[k], test)
+                               }
+                       }
+               }
+       }
+}
+
+func TestFindAllString(t *testing.T) {
+       for _, test := range findTests {
+               result := MustCompile(test.pat).FindAllString(test.text, -1)
+               switch {
+               case test.matches == nil && result == nil:
+                       // ok
+               case test.matches == nil && result != nil:
+                       t.Errorf("expected no match; got one: %s", test)
+               case test.matches != nil && result == nil:
+                       t.Errorf("expected match; got none: %s", test)
+               case test.matches != nil && result != nil:
+                       if len(test.matches) != len(result) {
+                               t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+                               continue
+                       }
+                       for k, e := range test.matches {
+                               expect := test.text[e[0]:e[1]]
+                               if expect != result[k] {
+                                       t.Errorf("expected %q got %q: %s", expect, result, test)
+                               }
+                       }
+               }
+       }
+}
+
+func testFindAllIndex(test *FindTest, result [][]int, t *testing.T) {
+       switch {
+       case test.matches == nil && result == nil:
+               // ok
+       case test.matches == nil && result != nil:
+               t.Errorf("expected no match; got one: %s", test)
+       case test.matches != nil && result == nil:
+               t.Errorf("expected match; got none: %s", test)
+       case test.matches != nil && result != nil:
+               if len(test.matches) != len(result) {
+                       t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+                       return
+               }
+               for k, e := range test.matches {
+                       if e[0] != result[k][0] || e[1] != result[k][1] {
+                               t.Errorf("match %d: expected %v got %v: %s", k, e, result[k], test)
+                       }
+               }
+       }
+}
+
+func TestFindAllIndex(t *testing.T) {
+       for _, test := range findTests {
+               testFindAllIndex(&test, MustCompile(test.pat).FindAllIndex([]byte(test.text), -1), t)
+       }
+}
+
+func TestFindAllStringIndex(t *testing.T) {
+       for _, test := range findTests {
+               testFindAllIndex(&test, MustCompile(test.pat).FindAllStringIndex(test.text, -1), t)
+       }
+}
+
+// Now come the Submatch cases.
+
+func testSubmatchBytes(test *FindTest, n int, submatches []int, result [][]byte, t *testing.T) {
+       if len(submatches) != len(result)*2 {
+               t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+               return
+       }
+       for k := 0; k < len(submatches); k += 2 {
+               if submatches[k] == -1 {
+                       if result[k/2] != nil {
+                               t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+                       }
+                       continue
+               }
+               expect := test.text[submatches[k]:submatches[k+1]]
+               if expect != string(result[k/2]) {
+                       t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+                       return
+               }
+       }
+}
+
+func TestFindSubmatch(t *testing.T) {
+       for _, test := range findTests {
+               result := MustCompile(test.pat).FindSubmatch([]byte(test.text))
+               switch {
+               case test.matches == nil && result == nil:
+                       // ok
+               case test.matches == nil && result != nil:
+                       t.Errorf("expected no match; got one: %s", test)
+               case test.matches != nil && result == nil:
+                       t.Errorf("expected match; got none: %s", test)
+               case test.matches != nil && result != nil:
+                       testSubmatchBytes(&test, 0, test.matches[0], result, t)
+               }
+       }
+}
+
+func testSubmatchString(test *FindTest, n int, submatches []int, result []string, t *testing.T) {
+       if len(submatches) != len(result)*2 {
+               t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+               return
+       }
+       for k := 0; k < len(submatches); k += 2 {
+               if submatches[k] == -1 {
+                       if result[k/2] != "" {
+                               t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+                       }
+                       continue
+               }
+               expect := test.text[submatches[k]:submatches[k+1]]
+               if expect != result[k/2] {
+                       t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+                       return
+               }
+       }
+}
+
+func TestFindStringSubmatch(t *testing.T) {
+       for _, test := range findTests {
+               result := MustCompile(test.pat).FindStringSubmatch(test.text)
+               switch {
+               case test.matches == nil && result == nil:
+                       // ok
+               case test.matches == nil && result != nil:
+                       t.Errorf("expected no match; got one: %s", test)
+               case test.matches != nil && result == nil:
+                       t.Errorf("expected match; got none: %s", test)
+               case test.matches != nil && result != nil:
+                       testSubmatchString(&test, 0, test.matches[0], result, t)
+               }
+       }
+}
+
+func testSubmatchIndices(test *FindTest, n int, expect, result []int, t *testing.T) {
+       if len(expect) != len(result) {
+               t.Errorf("match %d: expected %d matches; got %d: %s", n, len(expect)/2, len(result)/2, test)
+               return
+       }
+       for k, e := range expect {
+               if e != result[k] {
+                       t.Errorf("match %d: submatch error: expected %v got %v: %s", n, expect, result, test)
+               }
+       }
+}
+
+func testFindSubmatchIndex(test *FindTest, result []int, t *testing.T) {
+       switch {
+       case test.matches == nil && result == nil:
+               // ok
+       case test.matches == nil && result != nil:
+               t.Errorf("expected no match; got one: %s", test)
+       case test.matches != nil && result == nil:
+               t.Errorf("expected match; got none: %s", test)
+       case test.matches != nil && result != nil:
+               testSubmatchIndices(test, 0, test.matches[0], result, t)
+       }
+}
+
+func TestFindSubmatchIndex(t *testing.T) {
+       for _, test := range findTests {
+               testFindSubmatchIndex(&test, MustCompile(test.pat).FindSubmatchIndex([]byte(test.text)), t)
+       }
+}
+
+func TestFindStringSubmatchndex(t *testing.T) {
+       for _, test := range findTests {
+               testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
+       }
+}
+
+// Now come the monster AllSubmatch cases.
+
+func TestFindAllSubmatch(t *testing.T) {
+       for _, test := range findTests {
+               result := MustCompile(test.pat).FindAllSubmatch([]byte(test.text), -1)
+               switch {
+               case test.matches == nil && result == nil:
+                       // ok
+               case test.matches == nil && result != nil:
+                       t.Errorf("expected no match; got one: %s", test)
+               case test.matches != nil && result == nil:
+                       t.Errorf("expected match; got none: %s", test)
+               case len(test.matches) != len(result):
+                       t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+               case test.matches != nil && result != nil:
+                       for k, match := range test.matches {
+                               testSubmatchBytes(&test, k, match, result[k], t)
+                       }
+               }
+       }
+}
+
+func TestFindAllStringSubmatch(t *testing.T) {
+       for _, test := range findTests {
+               result := MustCompile(test.pat).FindAllStringSubmatch(test.text, -1)
+               switch {
+               case test.matches == nil && result == nil:
+                       // ok
+               case test.matches == nil && result != nil:
+                       t.Errorf("expected no match; got one: %s", test)
+               case test.matches != nil && result == nil:
+                       t.Errorf("expected match; got none: %s", test)
+               case len(test.matches) != len(result):
+                       t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+               case test.matches != nil && result != nil:
+                       for k, match := range test.matches {
+                               testSubmatchString(&test, k, match, result[k], t)
+                       }
+               }
+       }
+}
+
+func testFindAllSubmatchIndex(test *FindTest, result [][]int, t *testing.T) {
+       switch {
+       case test.matches == nil && result == nil:
+               // ok
+       case test.matches == nil && result != nil:
+               t.Errorf("expected no match; got one: %s", test)
+       case test.matches != nil && result == nil:
+               t.Errorf("expected match; got none: %s", test)
+       case len(test.matches) != len(result):
+               t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+       case test.matches != nil && result != nil:
+               for k, match := range test.matches {
+                       testSubmatchIndices(test, k, match, result[k], t)
+               }
+       }
+}
+
+func TestFindAllSubmatchIndex(t *testing.T) {
+       for _, test := range findTests {
+               testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllSubmatchIndex([]byte(test.text), -1), t)
+       }
+}
+
+func TestFindAllStringSubmatchndex(t *testing.T) {
+       for _, test := range findTests {
+               testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
+       }
+}
diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go
new file mode 100644 (file)
index 0000000..d3f03ad
--- /dev/null
@@ -0,0 +1,1400 @@
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package regexp implements a simple regular expression library.
+//
+// The syntax of the regular expressions accepted is:
+//
+//     regexp:
+//             concatenation { '|' concatenation }
+//     concatenation:
+//             { closure }
+//     closure:
+//             term [ '*' | '+' | '?' ]
+//     term:
+//             '^'
+//             '$'
+//             '.'
+//             character
+//             '[' [ '^' ] { character-range } ']'
+//             '(' regexp ')'
+//     character-range:
+//             character [ '-' character ]
+//
+// All characters are UTF-8-encoded code points.  Backslashes escape special
+// characters, including inside character classes.  The standard Go character
+// escapes are also recognized: \a \b \f \n \r \t \v.
+//
+// There are 16 methods of Regexp that match a regular expression and identify
+// the matched text.  Their names are matched by this regular expression:
+//
+//     Find(All)?(String)?(Submatch)?(Index)?
+//
+// If 'All' is present, the routine matches successive non-overlapping
+// matches of the entire expression.  Empty matches abutting a preceding
+// match are ignored.  The return value is a slice containing the successive
+// return values of the corresponding non-'All' routine.  These routines take
+// an extra integer argument, n; if n >= 0, the function returns at most n
+// matches/submatches.
+//
+// If 'String' is present, the argument is a string; otherwise it is a slice
+// of bytes; return values are adjusted as appropriate.
+//
+// If 'Submatch' is present, the return value is a slice identifying the
+// successive submatches of the expression.  Submatches are matches of
+// parenthesized subexpressions within the regular expression, numbered from
+// left to right in order of opening parenthesis.  Submatch 0 is the match of
+// the entire expression, submatch 1 the match of the first parenthesized
+// subexpression, and so on.
+//
+// If 'Index' is present, matches and submatches are identified by byte index
+// pairs within the input string: result[2*n:2*n+1] identifies the indexes of
+// the nth submatch.  The pair for n==0 identifies the match of the entire
+// expression.  If 'Index' is not present, the match is identified by the
+// text of the match/submatch.  If an index is negative, it means that
+// subexpression did not match any string in the input.
+//
+// (There are a few other methods that do not match this pattern.)
+//
+package regexp
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "strings"
+       "utf8"
+)
+
+var debug = false
+
+// Error is the local type for a parsing error.
+type Error string
+
+func (e Error) String() string {
+       return string(e)
+}
+
+// Error codes returned by failures to parse an expression.
+var (
+       ErrInternal            = Error("internal error")
+       ErrUnmatchedLpar       = Error("unmatched '('")
+       ErrUnmatchedRpar       = Error("unmatched ')'")
+       ErrUnmatchedLbkt       = Error("unmatched '['")
+       ErrUnmatchedRbkt       = Error("unmatched ']'")
+       ErrBadRange            = Error("bad range in character class")
+       ErrExtraneousBackslash = Error("extraneous backslash")
+       ErrBadClosure          = Error("repeated closure (**, ++, etc.)")
+       ErrBareClosure         = Error("closure applies to nothing")
+       ErrBadBackslash        = Error("illegal backslash escape")
+)
+
+// An instruction executed by the NFA
+type instr interface {
+       kind() int   // the type of this instruction: _CHAR, _ANY, etc.
+       next() instr // the instruction to execute after this one
+       setNext(i instr)
+       index() int
+       setIndex(i int)
+       print()
+}
+
+// Fields and methods common to all instructions
+type common struct {
+       _next  instr
+       _index int
+}
+
+func (c *common) next() instr     { return c._next }
+func (c *common) setNext(i instr) { c._next = i }
+func (c *common) index() int      { return c._index }
+func (c *common) setIndex(i int)  { c._index = i }
+
+// Regexp is the representation of a compiled regular expression.
+// The public interface is entirely through methods.
+type Regexp struct {
+       expr        string // the original expression
+       prefix      string // initial plain text string
+       prefixBytes []byte // initial plain text bytes
+       inst        []instr
+       start       instr // first instruction of machine
+       prefixStart instr // where to start if there is a prefix
+       nbra        int   // number of brackets in expression, for subexpressions
+}
+
+const (
+       _START     = iota // beginning of program
+       _END              // end of program: success
+       _BOT              // '^' beginning of text
+       _EOT              // '$' end of text
+       _CHAR             // 'a' regular character
+       _CHARCLASS        // [a-z] character class
+       _ANY              // '.' any character including newline
+       _NOTNL            // [^\n] special case: any character but newline
+       _BRA              // '(' parenthesized expression
+       _EBRA             // ')'; end of '(' parenthesized expression
+       _ALT              // '|' alternation
+       _NOP              // do nothing; makes it easy to link without patching
+)
+
+// --- START start of program
+type _Start struct {
+       common
+}
+
+func (start *_Start) kind() int { return _START }
+func (start *_Start) print()    { print("start") }
+
+// --- END end of program
+type _End struct {
+       common
+}
+
+func (end *_End) kind() int { return _END }
+func (end *_End) print()    { print("end") }
+
+// --- BOT beginning of text
+type _Bot struct {
+       common
+}
+
+func (bot *_Bot) kind() int { return _BOT }
+func (bot *_Bot) print()    { print("bot") }
+
+// --- EOT end of text
+type _Eot struct {
+       common
+}
+
+func (eot *_Eot) kind() int { return _EOT }
+func (eot *_Eot) print()    { print("eot") }
+
+// --- CHAR a regular character
+type _Char struct {
+       common
+       char int
+}
+
+func (char *_Char) kind() int { return _CHAR }
+func (char *_Char) print()    { print("char ", string(char.char)) }
+
+func newChar(char int) *_Char {
+       c := new(_Char)
+       c.char = char
+       return c
+}
+
+// --- CHARCLASS [a-z]
+
+type _CharClass struct {
+       common
+       negate bool // is character class negated? ([^a-z])
+       // slice of int, stored pairwise: [a-z] is (a,z); x is (x,x):
+       ranges     []int
+       cmin, cmax int
+}
+
+func (cclass *_CharClass) kind() int { return _CHARCLASS }
+
+func (cclass *_CharClass) print() {
+       print("charclass")
+       if cclass.negate {
+               print(" (negated)")
+       }
+       for i := 0; i < len(cclass.ranges); i += 2 {
+               l := cclass.ranges[i]
+               r := cclass.ranges[i+1]
+               if l == r {
+                       print(" [", string(l), "]")
+               } else {
+                       print(" [", string(l), "-", string(r), "]")
+               }
+       }
+}
+
+func (cclass *_CharClass) addRange(a, b int) {
+       // range is a through b inclusive
+       cclass.ranges = append(cclass.ranges, a, b)
+       if a < cclass.cmin {
+               cclass.cmin = a
+       }
+       if b > cclass.cmax {
+               cclass.cmax = b
+       }
+}
+
+func (cclass *_CharClass) matches(c int) bool {
+       if c < cclass.cmin || c > cclass.cmax {
+               return cclass.negate
+       }
+       ranges := cclass.ranges
+       for i := 0; i < len(ranges); i = i + 2 {
+               if ranges[i] <= c && c <= ranges[i+1] {
+                       return !cclass.negate
+               }
+       }
+       return cclass.negate
+}
+
+func newCharClass() *_CharClass {
+       c := new(_CharClass)
+       c.ranges = make([]int, 0, 4)
+       c.cmin = 0x10FFFF + 1 // MaxRune + 1
+       c.cmax = -1
+       return c
+}
+
+// --- ANY any character
+type _Any struct {
+       common
+}
+
+func (any *_Any) kind() int { return _ANY }
+func (any *_Any) print()    { print("any") }
+
+// --- NOTNL any character but newline
+type _NotNl struct {
+       common
+}
+
+func (notnl *_NotNl) kind() int { return _NOTNL }
+func (notnl *_NotNl) print()    { print("notnl") }
+
+// --- BRA parenthesized expression
+type _Bra struct {
+       common
+       n int // subexpression number
+}
+
+func (bra *_Bra) kind() int { return _BRA }
+func (bra *_Bra) print()    { print("bra", bra.n) }
+
+// --- EBRA end of parenthesized expression
+type _Ebra struct {
+       common
+       n int // subexpression number
+}
+
+func (ebra *_Ebra) kind() int { return _EBRA }
+func (ebra *_Ebra) print()    { print("ebra ", ebra.n) }
+
+// --- ALT alternation
+type _Alt struct {
+       common
+       left instr // other branch
+}
+
+func (alt *_Alt) kind() int { return _ALT }
+func (alt *_Alt) print()    { print("alt(", alt.left.index(), ")") }
+
+// --- NOP no operation
+type _Nop struct {
+       common
+}
+
+func (nop *_Nop) kind() int { return _NOP }
+func (nop *_Nop) print()    { print("nop") }
+
+func (re *Regexp) add(i instr) instr {
+       i.setIndex(len(re.inst))
+       re.inst = append(re.inst, i)
+       return i
+}
+
+type parser struct {
+       re    *Regexp
+       nlpar int // number of unclosed lpars
+       pos   int
+       ch    int
+}
+
+func (p *parser) error(err Error) {
+       panic(err)
+}
+
+const endOfFile = -1
+
+func (p *parser) c() int { return p.ch }
+
+func (p *parser) nextc() int {
+       if p.pos >= len(p.re.expr) {
+               p.ch = endOfFile
+       } else {
+               c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:])
+               p.ch = c
+               p.pos += w
+       }
+       return p.ch
+}
+
+func newParser(re *Regexp) *parser {
+       p := new(parser)
+       p.re = re
+       p.nextc() // load p.ch
+       return p
+}
+
+func special(c int) bool {
+       for _, r := range `\.+*?()|[]^$` {
+               if c == r {
+                       return true
+               }
+       }
+       return false
+}
+
+func ispunct(c int) bool {
+       for _, r := range "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" {
+               if c == r {
+                       return true
+               }
+       }
+       return false
+}
+
+var escapes = []byte("abfnrtv")
+var escaped = []byte("\a\b\f\n\r\t\v")
+
+func escape(c int) int {
+       for i, b := range escapes {
+               if int(b) == c {
+                       return i
+               }
+       }
+       return -1
+}
+
+func (p *parser) charClass() instr {
+       cc := newCharClass()
+       if p.c() == '^' {
+               cc.negate = true
+               p.nextc()
+       }
+       left := -1
+       for {
+               switch c := p.c(); c {
+               case ']', endOfFile:
+                       if left >= 0 {
+                               p.error(ErrBadRange)
+                       }
+                       // Is it [^\n]?
+                       if cc.negate && len(cc.ranges) == 2 &&
+                               cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+                               nl := new(_NotNl)
+                               p.re.add(nl)
+                               return nl
+                       }
+                       // Special common case: "[a]" -> "a"
+                       if !cc.negate && len(cc.ranges) == 2 && cc.ranges[0] == cc.ranges[1] {
+                               c := newChar(cc.ranges[0])
+                               p.re.add(c)
+                               return c
+                       }
+                       p.re.add(cc)
+                       return cc
+               case '-': // do this before backslash processing
+                       p.error(ErrBadRange)
+               case '\\':
+                       c = p.nextc()
+                       switch {
+                       case c == endOfFile:
+                               p.error(ErrExtraneousBackslash)
+                       case ispunct(c):
+                               // c is as delivered
+                       case escape(c) >= 0:
+                               c = int(escaped[escape(c)])
+                       default:
+                               p.error(ErrBadBackslash)
+                       }
+                       fallthrough
+               default:
+                       p.nextc()
+                       switch {
+                       case left < 0: // first of pair
+                               if p.c() == '-' { // range
+                                       p.nextc()
+                                       left = c
+                               } else { // single char
+                                       cc.addRange(c, c)
+                               }
+                       case left <= c: // second of pair
+                               cc.addRange(left, c)
+                               left = -1
+                       default:
+                               p.error(ErrBadRange)
+                       }
+               }
+       }
+       return nil
+}
+
+func (p *parser) term() (start, end instr) {
+       switch c := p.c(); c {
+       case '|', endOfFile:
+               return nil, nil
+       case '*', '+':
+               p.error(ErrBareClosure)
+       case ')':
+               if p.nlpar == 0 {
+                       p.error(ErrUnmatchedRpar)
+               }
+               return nil, nil
+       case ']':
+               p.error(ErrUnmatchedRbkt)
+       case '^':
+               p.nextc()
+               start = p.re.add(new(_Bot))
+               return start, start
+       case '$':
+               p.nextc()
+               start = p.re.add(new(_Eot))
+               return start, start
+       case '.':
+               p.nextc()
+               start = p.re.add(new(_Any))
+               return start, start
+       case '[':
+               p.nextc()
+               start = p.charClass()
+               if p.c() != ']' {
+                       p.error(ErrUnmatchedLbkt)
+               }
+               p.nextc()
+               return start, start
+       case '(':
+               p.nextc()
+               p.nlpar++
+               p.re.nbra++ // increment first so first subexpr is \1
+               nbra := p.re.nbra
+               start, end = p.regexp()
+               if p.c() != ')' {
+                       p.error(ErrUnmatchedLpar)
+               }
+               p.nlpar--
+               p.nextc()
+               bra := new(_Bra)
+               p.re.add(bra)
+               ebra := new(_Ebra)
+               p.re.add(ebra)
+               bra.n = nbra
+               ebra.n = nbra
+               if start == nil {
+                       if end == nil {
+                               p.error(ErrInternal)
+                               return
+                       }
+                       start = ebra
+               } else {
+                       end.setNext(ebra)
+               }
+               bra.setNext(start)
+               return bra, ebra
+       case '\\':
+               c = p.nextc()
+               switch {
+               case c == endOfFile:
+                       p.error(ErrExtraneousBackslash)
+               case ispunct(c):
+                       // c is as delivered
+               case escape(c) >= 0:
+                       c = int(escaped[escape(c)])
+               default:
+                       p.error(ErrBadBackslash)
+               }
+               fallthrough
+       default:
+               p.nextc()
+               start = newChar(c)
+               p.re.add(start)
+               return start, start
+       }
+       panic("unreachable")
+}
+
+func (p *parser) closure() (start, end instr) {
+       start, end = p.term()
+       if start == nil {
+               return
+       }
+       switch p.c() {
+       case '*':
+               // (start,end)*:
+               alt := new(_Alt)
+               p.re.add(alt)
+               end.setNext(alt) // after end, do alt
+               alt.left = start // alternate brach: return to start
+               start = alt      // alt becomes new (start, end)
+               end = alt
+       case '+':
+               // (start,end)+:
+               alt := new(_Alt)
+               p.re.add(alt)
+               end.setNext(alt) // after end, do alt
+               alt.left = start // alternate brach: return to start
+               end = alt        // start is unchanged; end is alt
+       case '?':
+               // (start,end)?:
+               alt := new(_Alt)
+               p.re.add(alt)
+               nop := new(_Nop)
+               p.re.add(nop)
+               alt.left = start // alternate branch is start
+               alt.setNext(nop) // follow on to nop
+               end.setNext(nop) // after end, go to nop
+               start = alt      // start is now alt
+               end = nop        // end is nop pointed to by both branches
+       default:
+               return
+       }
+       switch p.nextc() {
+       case '*', '+', '?':
+               p.error(ErrBadClosure)
+       }
+       return
+}
+
+func (p *parser) concatenation() (start, end instr) {
+       for {
+               nstart, nend := p.closure()
+               switch {
+               case nstart == nil: // end of this concatenation
+                       if start == nil { // this is the empty string
+                               nop := p.re.add(new(_Nop))
+                               return nop, nop
+                       }
+                       return
+               case start == nil: // this is first element of concatenation
+                       start, end = nstart, nend
+               default:
+                       end.setNext(nstart)
+                       end = nend
+               }
+       }
+       panic("unreachable")
+}
+
+func (p *parser) regexp() (start, end instr) {
+       start, end = p.concatenation()
+       for {
+               switch p.c() {
+               default:
+                       return
+               case '|':
+                       p.nextc()
+                       nstart, nend := p.concatenation()
+                       alt := new(_Alt)
+                       p.re.add(alt)
+                       alt.left = start
+                       alt.setNext(nstart)
+                       nop := new(_Nop)
+                       p.re.add(nop)
+                       end.setNext(nop)
+                       nend.setNext(nop)
+                       start, end = alt, nop
+               }
+       }
+       panic("unreachable")
+}
+
+func unNop(i instr) instr {
+       for i.kind() == _NOP {
+               i = i.next()
+       }
+       return i
+}
+
+func (re *Regexp) eliminateNops() {
+       for _, inst := range re.inst {
+               if inst.kind() == _END {
+                       continue
+               }
+               inst.setNext(unNop(inst.next()))
+               if inst.kind() == _ALT {
+                       alt := inst.(*_Alt)
+                       alt.left = unNop(alt.left)
+               }
+       }
+}
+
+func (re *Regexp) dump() {
+       print("prefix <", re.prefix, ">\n")
+       for _, inst := range re.inst {
+               print(inst.index(), ": ")
+               inst.print()
+               if inst.kind() != _END {
+                       print(" -> ", inst.next().index())
+               }
+               print("\n")
+       }
+}
+
+func (re *Regexp) doParse() {
+       p := newParser(re)
+       start := new(_Start)
+       re.add(start)
+       s, e := p.regexp()
+       start.setNext(s)
+       re.start = start
+       e.setNext(re.add(new(_End)))
+
+       if debug {
+               re.dump()
+               println()
+       }
+
+       re.eliminateNops()
+       if debug {
+               re.dump()
+               println()
+       }
+       re.setPrefix()
+       if debug {
+               re.dump()
+               println()
+       }
+}
+
+// Extract regular text from the beginning of the pattern.
+// That text can be used by doExecute to speed up matching.
+func (re *Regexp) setPrefix() {
+       var b []byte
+       var utf = make([]byte, utf8.UTFMax)
+       // First instruction is start; skip that.
+       i := re.inst[0].next().index()
+Loop:
+       for i < len(re.inst) {
+               inst := re.inst[i]
+               // stop if this is not a char
+               if inst.kind() != _CHAR {
+                       break
+               }
+               // stop if this char can be followed by a match for an empty string,
+               // which includes closures, ^, and $.
+               switch re.inst[inst.next().index()].kind() {
+               case _BOT, _EOT, _ALT:
+                       break Loop
+               }
+               n := utf8.EncodeRune(inst.(*_Char).char, utf)
+               b = bytes.Add(b, utf[0:n])
+               i = inst.next().index()
+       }
+       // point prefixStart instruction to first non-CHAR after prefix
+       re.prefixStart = re.inst[i]
+       re.prefixBytes = b
+       re.prefix = string(b)
+}
+
+// Compile parses a regular expression and returns, if successful, a Regexp
+// object that can be used to match against text.
+func Compile(str string) (regexp *Regexp, error os.Error) {
+       regexp = new(Regexp)
+       // doParse will panic if there is a parse error.
+       defer func() {
+               if e := recover(); e != nil {
+                       regexp = nil
+                       error = e.(Error) // Will re-panic if error was not an Error, e.g. nil-pointer exception
+               }
+       }()
+       regexp.expr = str
+       regexp.inst = make([]instr, 0, 10)
+       regexp.doParse()
+       return
+}
+
+// MustCompile is like Compile but panics if the expression cannot be parsed.
+// It simplifies safe initialization of global variables holding compiled regular
+// expressions.
+func MustCompile(str string) *Regexp {
+       regexp, error := Compile(str)
+       if error != nil {
+               panic(`regexp: compiling "` + str + `": ` + error.String())
+       }
+       return regexp
+}
+
+// NumSubexp returns the number of parenthesized subexpressions in this Regexp.
+func (re *Regexp) NumSubexp() int { return re.nbra }
+
+// The match arena allows us to reduce the garbage generated by tossing
+// match vectors away as we execute.  Matches are ref counted and returned
+// to a free list when no longer active.  Increases a simple benchmark by 22X.
+type matchArena struct {
+       head *matchVec
+       len  int // length of match vector
+}
+
+type matchVec struct {
+       m    []int // pairs of bracketing submatches. 0th is start,end
+       ref  int
+       next *matchVec
+}
+
+func (a *matchArena) new() *matchVec {
+       if a.head == nil {
+               const N = 10
+               block := make([]matchVec, N)
+               for i := 0; i < N; i++ {
+                       b := &block[i]
+                       b.next = a.head
+                       a.head = b
+               }
+       }
+       m := a.head
+       a.head = m.next
+       m.ref = 0
+       if m.m == nil {
+               m.m = make([]int, a.len)
+       }
+       return m
+}
+
+func (a *matchArena) free(m *matchVec) {
+       m.ref--
+       if m.ref == 0 {
+               m.next = a.head
+               a.head = m
+       }
+}
+
+func (a *matchArena) copy(m *matchVec) *matchVec {
+       m1 := a.new()
+       copy(m1.m, m.m)
+       return m1
+}
+
+func (a *matchArena) noMatch() *matchVec {
+       m := a.new()
+       for i := range m.m {
+               m.m[i] = -1 // no match seen; catches cases like "a(b)?c" on "ac"
+       }
+       m.ref = 1
+       return m
+}
+
+type state struct {
+       inst     instr // next instruction to execute
+       prefixed bool  // this match began with a fixed prefix
+       match    *matchVec
+}
+
+// Append new state to to-do list.  Leftmost-longest wins so avoid
+// adding a state that's already active.  The matchVec will be inc-ref'ed
+// if it is assigned to a state.
+func (a *matchArena) addState(s []state, inst instr, prefixed bool, match *matchVec, pos, end int) []state {
+       switch inst.kind() {
+       case _BOT:
+               if pos == 0 {
+                       s = a.addState(s, inst.next(), prefixed, match, pos, end)
+               }
+               return s
+       case _EOT:
+               if pos == end {
+                       s = a.addState(s, inst.next(), prefixed, match, pos, end)
+               }
+               return s
+       case _BRA:
+               n := inst.(*_Bra).n
+               match.m[2*n] = pos
+               s = a.addState(s, inst.next(), prefixed, match, pos, end)
+               return s
+       case _EBRA:
+               n := inst.(*_Ebra).n
+               match.m[2*n+1] = pos
+               s = a.addState(s, inst.next(), prefixed, match, pos, end)
+               return s
+       }
+       index := inst.index()
+       l := len(s)
+       // States are inserted in order so it's sufficient to see if we have the same
+       // instruction; no need to see if existing match is earlier (it is).
+       for i := 0; i < l; i++ {
+               if s[i].inst.index() == index {
+                       return s
+               }
+       }
+       s = append(s, state{inst, prefixed, match})
+       match.ref++
+       if inst.kind() == _ALT {
+               s = a.addState(s, inst.(*_Alt).left, prefixed, a.copy(match), pos, end)
+               // give other branch a copy of this match vector
+               s = a.addState(s, inst.next(), prefixed, a.copy(match), pos, end)
+       }
+       return s
+}
+
+// Accepts either string or bytes - the logic is identical either way.
+// If bytes == nil, scan str.
+func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
+       var s [2][]state
+       s[0] = make([]state, 0, 10)
+       s[1] = make([]state, 0, 10)
+       in, out := 0, 1
+       var final state
+       found := false
+       end := len(str)
+       if bytestr != nil {
+               end = len(bytestr)
+       }
+       // fast check for initial plain substring
+       prefixed := false // has this iteration begun by skipping a prefix?
+       if re.prefix != "" {
+               var advance int
+               if bytestr == nil {
+                       advance = strings.Index(str[pos:], re.prefix)
+               } else {
+                       advance = bytes.Index(bytestr[pos:], re.prefixBytes)
+               }
+               if advance == -1 {
+                       return nil
+               }
+               pos += advance + len(re.prefix)
+               prefixed = true
+       }
+       arena := &matchArena{nil, 2 * (re.nbra + 1)}
+       for pos <= end {
+               if !found {
+                       // prime the pump if we haven't seen a match yet
+                       match := arena.noMatch()
+                       match.m[0] = pos
+                       if prefixed {
+                               s[out] = arena.addState(s[out], re.prefixStart, true, match, pos, end)
+                               prefixed = false // next iteration should start at beginning of machine.
+                       } else {
+                               s[out] = arena.addState(s[out], re.start.next(), false, match, pos, end)
+                       }
+                       arena.free(match) // if addState saved it, ref was incremented
+               }
+               in, out = out, in // old out state is new in state
+               // clear out old state
+               old := s[out]
+               for _, state := range old {
+                       arena.free(state.match)
+               }
+               s[out] = old[0:0] // truncate state vector
+               if found && len(s[in]) == 0 {
+                       // machine has completed
+                       break
+               }
+               charwidth := 1
+               c := endOfFile
+               if pos < end {
+                       if bytestr == nil {
+                               c, charwidth = utf8.DecodeRuneInString(str[pos:end])
+                       } else {
+                               c, charwidth = utf8.DecodeRune(bytestr[pos:end])
+                       }
+               }
+               pos += charwidth
+               for _, st := range s[in] {
+                       switch st.inst.kind() {
+                       case _BOT:
+                       case _EOT:
+                       case _CHAR:
+                               if c == st.inst.(*_Char).char {
+                                       s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
+                               }
+                       case _CHARCLASS:
+                               if st.inst.(*_CharClass).matches(c) {
+                                       s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
+                               }
+                       case _ANY:
+                               if c != endOfFile {
+                                       s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
+                               }
+                       case _NOTNL:
+                               if c != endOfFile && c != '\n' {
+                                       s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
+                               }
+                       case _BRA:
+                       case _EBRA:
+                       case _ALT:
+                       case _END:
+                               // choose leftmost longest
+                               if !found || // first
+                                       st.match.m[0] < final.match.m[0] || // leftmost
+                                       (st.match.m[0] == final.match.m[0] && pos-charwidth > final.match.m[1]) { // longest
+                                       if final.match != nil {
+                                               arena.free(final.match)
+                                       }
+                                       final = st
+                                       final.match.ref++
+                                       final.match.m[1] = pos - charwidth
+                               }
+                               found = true
+                       default:
+                               st.inst.print()
+                               panic("unknown instruction in execute")
+                       }
+               }
+       }
+       if final.match == nil {
+               return nil
+       }
+       // if match found, back up start of match by width of prefix.
+       if final.prefixed && len(final.match.m) > 0 {
+               final.match.m[0] -= len(re.prefix)
+       }
+       return final.match.m
+}
+
+// MatchString returns whether the Regexp matches the string s.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) MatchString(s string) bool { return len(re.doExecute(s, nil, 0)) > 0 }
+
+// Match returns whether the Regexp matches the byte slice b.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) Match(b []byte) bool { return len(re.doExecute("", b, 0)) > 0 }
+
+
+// MatchString checks whether a textual regular expression
+// matches a string.  More complicated queries need
+// to use Compile and the full Regexp interface.
+func MatchString(pattern string, s string) (matched bool, error os.Error) {
+       re, err := Compile(pattern)
+       if err != nil {
+               return false, err
+       }
+       return re.MatchString(s), nil
+}
+
+// Match checks whether a textual regular expression
+// matches a byte slice.  More complicated queries need
+// to use Compile and the full Regexp interface.
+func Match(pattern string, b []byte) (matched bool, error os.Error) {
+       re, err := Compile(pattern)
+       if err != nil {
+               return false, err
+       }
+       return re.Match(b), nil
+}
+
+// ReplaceAllString returns a copy of src in which all matches for the Regexp
+// have been replaced by repl.  No support is provided for expressions
+// (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllString(src, repl string) string {
+       return re.ReplaceAllStringFunc(src, func(string) string { return repl })
+}
+
+// ReplaceAllStringFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched string).  No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
+       lastMatchEnd := 0 // end position of the most recent match
+       searchPos := 0    // position where we next look for a match
+       buf := new(bytes.Buffer)
+       for searchPos <= len(src) {
+               a := re.doExecute(src, nil, searchPos)
+               if len(a) == 0 {
+                       break // no more matches
+               }
+
+               // Copy the unmatched characters before this match.
+               io.WriteString(buf, src[lastMatchEnd:a[0]])
+
+               // Now insert a copy of the replacement string, but not for a
+               // match of the empty string immediately after another match.
+               // (Otherwise, we get double replacement for patterns that
+               // match both empty and nonempty strings.)
+               if a[1] > lastMatchEnd || a[0] == 0 {
+                       io.WriteString(buf, repl(src[a[0]:a[1]]))
+               }
+               lastMatchEnd = a[1]
+
+               // Advance past this match; always advance at least one character.
+               _, width := utf8.DecodeRuneInString(src[searchPos:])
+               if searchPos+width > a[1] {
+                       searchPos += width
+               } else if searchPos+1 > a[1] {
+                       // This clause is only needed at the end of the input
+                       // string.  In that case, DecodeRuneInString returns width=0.
+                       searchPos++
+               } else {
+                       searchPos = a[1]
+               }
+       }
+
+       // Copy the unmatched characters after the last match.
+       io.WriteString(buf, src[lastMatchEnd:])
+
+       return buf.String()
+}
+
+// ReplaceAll returns a copy of src in which all matches for the Regexp
+// have been replaced by repl.  No support is provided for expressions
+// (e.g. \1 or $1) in the replacement text.
+func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
+       return re.ReplaceAllFunc(src, func([]byte) []byte { return repl })
+}
+
+// ReplaceAllFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched []byte).  No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
+       lastMatchEnd := 0 // end position of the most recent match
+       searchPos := 0    // position where we next look for a match
+       buf := new(bytes.Buffer)
+       for searchPos <= len(src) {
+               a := re.doExecute("", src, searchPos)
+               if len(a) == 0 {
+                       break // no more matches
+               }
+
+               // Copy the unmatched characters before this match.
+               buf.Write(src[lastMatchEnd:a[0]])
+
+               // Now insert a copy of the replacement string, but not for a
+               // match of the empty string immediately after another match.
+               // (Otherwise, we get double replacement for patterns that
+               // match both empty and nonempty strings.)
+               if a[1] > lastMatchEnd || a[0] == 0 {
+                       buf.Write(repl(src[a[0]:a[1]]))
+               }
+               lastMatchEnd = a[1]
+
+               // Advance past this match; always advance at least one character.
+               _, width := utf8.DecodeRune(src[searchPos:])
+               if searchPos+width > a[1] {
+                       searchPos += width
+               } else if searchPos+1 > a[1] {
+                       // This clause is only needed at the end of the input
+                       // string.  In that case, DecodeRuneInString returns width=0.
+                       searchPos++
+               } else {
+                       searchPos = a[1]
+               }
+       }
+
+       // Copy the unmatched characters after the last match.
+       buf.Write(src[lastMatchEnd:])
+
+       return buf.Bytes()
+}
+
+// QuoteMeta returns a string that quotes all regular expression metacharacters
+// inside the argument text; the returned string is a regular expression matching
+// the literal text.  For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
+func QuoteMeta(s string) string {
+       b := make([]byte, 2*len(s))
+
+       // A byte loop is correct because all metacharacters are ASCII.
+       j := 0
+       for i := 0; i < len(s); i++ {
+               if special(int(s[i])) {
+                       b[j] = '\\'
+                       j++
+               }
+               b[j] = s[i]
+               j++
+       }
+       return string(b[0:j])
+}
+
+// Find matches in slice b if b is non-nil, otherwise find matches in string s.
+func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
+       var end int
+       if b == nil {
+               end = len(s)
+       } else {
+               end = len(b)
+       }
+
+       for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
+               matches := re.doExecute(s, b, pos)
+               if len(matches) == 0 {
+                       break
+               }
+
+               accept := true
+               if matches[1] == pos {
+                       // We've found an empty match.
+                       if matches[0] == prevMatchEnd {
+                               // We don't allow an empty match right
+                               // after a previous match, so ignore it.
+                               accept = false
+                       }
+                       var width int
+                       if b == nil {
+                               _, width = utf8.DecodeRuneInString(s[pos:end])
+                       } else {
+                               _, width = utf8.DecodeRune(b[pos:end])
+                       }
+                       if width > 0 {
+                               pos += width
+                       } else {
+                               pos = end + 1
+                       }
+               } else {
+                       pos = matches[1]
+               }
+               prevMatchEnd = matches[1]
+
+               if accept {
+                       deliver(matches)
+                       i++
+               }
+       }
+}
+
+// Find returns a slice holding the text of the leftmost match in b of the regular expression.
+// A return value of nil indicates no match.
+func (re *Regexp) Find(b []byte) []byte {
+       a := re.doExecute("", b, 0)
+       if a == nil {
+               return nil
+       }
+       return b[a[0]:a[1]]
+}
+
+// FindIndex returns a two-element slice of integers defining the location of
+// the leftmost match in b of the regular expression.  The match itself is at
+// b[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindIndex(b []byte) (loc []int) {
+       a := re.doExecute("", b, 0)
+       if a == nil {
+               return nil
+       }
+       return a[0:2]
+}
+
+// FindString returns a string holding the text of the leftmost match in s of the regular
+// expression.  If there is no match, the return value is an empty string,
+// but it will also be empty if the regular expression successfully matches
+// an empty string.  Use FindStringIndex or FindStringSubmatch if it is
+// necessary to distinguish these cases.
+func (re *Regexp) FindString(s string) string {
+       a := re.doExecute(s, nil, 0)
+       if a == nil {
+               return ""
+       }
+       return s[a[0]:a[1]]
+}
+
+// FindStringIndex returns a two-element slice of integers defining the
+// location of the leftmost match in s of the regular expression.  The match
+// itself is at s[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringIndex(s string) []int {
+       a := re.doExecute(s, nil, 0)
+       if a == nil {
+               return nil
+       }
+       return a[0:2]
+}
+
+// FindSubmatch returns a slice of slices holding the text of the leftmost
+// match of the regular expression in b and the matches, if any, of its
+// subexpressions, as defined by the 'Submatch' descriptions in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatch(b []byte) [][]byte {
+       a := re.doExecute("", b, 0)
+       if a == nil {
+               return nil
+       }
+       ret := make([][]byte, len(a)/2)
+       for i := range ret {
+               if a[2*i] >= 0 {
+                       ret[i] = b[a[2*i]:a[2*i+1]]
+               }
+       }
+       return ret
+}
+
+// FindSubmatchIndex returns a slice holding the index pairs identifying the
+// leftmost match of the regular expression in b and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatchIndex(b []byte) []int {
+       return re.doExecute("", b, 0)
+}
+
+// FindStringSubmatch returns a slice of strings holding the text of the
+// leftmost match of the regular expression in s and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatch(s string) []string {
+       a := re.doExecute(s, nil, 0)
+       if a == nil {
+               return nil
+       }
+       ret := make([]string, len(a)/2)
+       for i := range ret {
+               if a[2*i] >= 0 {
+                       ret[i] = s[a[2*i]:a[2*i+1]]
+               }
+       }
+       return ret
+}
+
+// FindStringSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression in s and the
+// matches, if any, of its subexpressions, as defined by the 'Submatch' and
+// 'Index' descriptions in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatchIndex(s string) []int {
+       return re.doExecute(s, nil, 0)
+}
+
+const startSize = 10 // The size at which to start a slice in the 'All' routines.
+
+// FindAll is the 'All' version of Find; it returns a slice of all successive
+// matches of the expression, as defined by the 'All' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAll(b []byte, n int) [][]byte {
+       if n < 0 {
+               n = len(b) + 1
+       }
+       result := make([][]byte, 0, startSize)
+       re.allMatches("", b, n, func(match []int) {
+               result = append(result, b[match[0]:match[1]])
+       })
+       if len(result) == 0 {
+               return nil
+       }
+       return result
+}
+
+// FindAllIndex is the 'All' version of FindIndex; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllIndex(b []byte, n int) [][]int {
+       if n < 0 {
+               n = len(b) + 1
+       }
+       result := make([][]int, 0, startSize)
+       re.allMatches("", b, n, func(match []int) {
+               result = append(result, match[0:2])
+       })
+       if len(result) == 0 {
+               return nil
+       }
+       return result
+}
+
+// FindAllString is the 'All' version of FindString; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllString(s string, n int) []string {
+       if n < 0 {
+               n = len(s) + 1
+       }
+       result := make([]string, 0, startSize)
+       re.allMatches(s, nil, n, func(match []int) {
+               result = append(result, s[match[0]:match[1]])
+       })
+       if len(result) == 0 {
+               return nil
+       }
+       return result
+}
+
+// FindAllStringIndex is the 'All' version of FindStringIndex; it returns a
+// slice of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringIndex(s string, n int) [][]int {
+       if n < 0 {
+               n = len(s) + 1
+       }
+       result := make([][]int, 0, startSize)
+       re.allMatches(s, nil, n, func(match []int) {
+               result = append(result, match[0:2])
+       })
+       if len(result) == 0 {
+               return nil
+       }
+       return result
+}
+
+// FindAllSubmatch is the 'All' version of FindSubmatch; it returns a slice
+// of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte {
+       if n < 0 {
+               n = len(b) + 1
+       }
+       result := make([][][]byte, 0, startSize)
+       re.allMatches("", b, n, func(match []int) {
+               slice := make([][]byte, len(match)/2)
+               for j := range slice {
+                       if match[2*j] >= 0 {
+                               slice[j] = b[match[2*j]:match[2*j+1]]
+                       }
+               }
+               result = append(result, slice)
+       })
+       if len(result) == 0 {
+               return nil
+       }
+       return result
+}
+
+// FindAllSubmatchIndex is the 'All' version of FindSubmatchIndex; it returns
+// a slice of all successive matches of the expression, as defined by the
+// 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int {
+       if n < 0 {
+               n = len(b) + 1
+       }
+       result := make([][]int, 0, startSize)
+       re.allMatches("", b, n, func(match []int) {
+               result = append(result, match)
+       })
+       if len(result) == 0 {
+               return nil
+       }
+       return result
+}
+
+// FindAllStringSubmatch is the 'All' version of FindStringSubmatch; it
+// returns a slice of all successive matches of the expression, as defined by
+// the 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string {
+       if n < 0 {
+               n = len(s) + 1
+       }
+       result := make([][]string, 0, startSize)
+       re.allMatches(s, nil, n, func(match []int) {
+               slice := make([]string, len(match)/2)
+               for j := range slice {
+                       if match[2*j] >= 0 {
+                               slice[j] = s[match[2*j]:match[2*j+1]]
+                       }
+               }
+               result = append(result, slice)
+       })
+       if len(result) == 0 {
+               return nil
+       }
+       return result
+}
+
+// FindAllStringSubmatchIndex is the 'All' version of
+// FindStringSubmatchIndex; it returns a slice of all successive matches of
+// the expression, as defined by the 'All' description in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int {
+       if n < 0 {
+               n = len(s) + 1
+       }
+       result := make([][]int, 0, startSize)
+       re.allMatches(s, nil, n, func(match []int) {
+               result = append(result, match)
+       })
+       if len(result) == 0 {
+               return nil
+       }
+       return result
+}
diff --git a/libgo/go/rpc/client.go b/libgo/go/rpc/client.go
new file mode 100644 (file)
index 0000000..601c497
--- /dev/null
@@ -0,0 +1,250 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+import (
+       "bufio"
+       "gob"
+       "http"
+       "io"
+       "log"
+       "net"
+       "os"
+       "sync"
+)
+
+// Call represents an active RPC.
+type Call struct {
+       ServiceMethod string      // The name of the service and method to call.
+       Args          interface{} // The argument to the function (*struct).
+       Reply         interface{} // The reply from the function (*struct).
+       Error         os.Error    // After completion, the error status.
+       Done          chan *Call  // Strobes when call is complete; value is the error status.
+       seq           uint64
+}
+
+// Client represents an RPC Client.
+// There may be multiple outstanding Calls associated
+// with a single Client.
+type Client struct {
+       mutex    sync.Mutex // protects pending, seq
+       shutdown os.Error   // non-nil if the client is shut down
+       sending  sync.Mutex
+       seq      uint64
+       codec    ClientCodec
+       pending  map[uint64]*Call
+       closing  bool
+}
+
+// A ClientCodec implements writing of RPC requests and
+// reading of RPC responses for the client side of an RPC session.
+// The client calls WriteRequest to write a request to the connection
+// and calls ReadResponseHeader and ReadResponseBody in pairs
+// to read responses.  The client calls Close when finished with the
+// connection.
+type ClientCodec interface {
+       WriteRequest(*Request, interface{}) os.Error
+       ReadResponseHeader(*Response) os.Error
+       ReadResponseBody(interface{}) os.Error
+
+       Close() os.Error
+}
+
+func (client *Client) send(c *Call) {
+       // Register this call.
+       client.mutex.Lock()
+       if client.shutdown != nil {
+               c.Error = client.shutdown
+               client.mutex.Unlock()
+               _ = c.Done <- c // do not block
+               return
+       }
+       c.seq = client.seq
+       client.seq++
+       client.pending[c.seq] = c
+       client.mutex.Unlock()
+
+       // Encode and send the request.
+       request := new(Request)
+       client.sending.Lock()
+       defer client.sending.Unlock()
+       request.Seq = c.seq
+       request.ServiceMethod = c.ServiceMethod
+       if err := client.codec.WriteRequest(request, c.Args); err != nil {
+               panic("rpc: client encode error: " + err.String())
+       }
+}
+
+func (client *Client) input() {
+       var err os.Error
+       for err == nil {
+               response := new(Response)
+               err = client.codec.ReadResponseHeader(response)
+               if err != nil {
+                       if err == os.EOF && !client.closing {
+                               err = io.ErrUnexpectedEOF
+                       }
+                       break
+               }
+               seq := response.Seq
+               client.mutex.Lock()
+               c := client.pending[seq]
+               client.pending[seq] = c, false
+               client.mutex.Unlock()
+               err = client.codec.ReadResponseBody(c.Reply)
+               if response.Error != "" {
+                       c.Error = os.ErrorString(response.Error)
+               } else if err != nil {
+                       c.Error = err
+               } else {
+                       // Empty strings should turn into nil os.Errors
+                       c.Error = nil
+               }
+               // We don't want to block here.  It is the caller's responsibility to make
+               // sure the channel has enough buffer space. See comment in Go().
+               _ = c.Done <- c // do not block
+       }
+       // Terminate pending calls.
+       client.mutex.Lock()
+       client.shutdown = err
+       for _, call := range client.pending {
+               call.Error = err
+               _ = call.Done <- call // do not block
+       }
+       client.mutex.Unlock()
+       if err != os.EOF || !client.closing {
+               log.Println("rpc: client protocol error:", err)
+       }
+}
+
+// NewClient returns a new Client to handle requests to the
+// set of services at the other end of the connection.
+func NewClient(conn io.ReadWriteCloser) *Client {
+       return NewClientWithCodec(&gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)})
+}
+
+// NewClientWithCodec is like NewClient but uses the specified
+// codec to encode requests and decode responses.
+func NewClientWithCodec(codec ClientCodec) *Client {
+       client := &Client{
+               codec:   codec,
+               pending: make(map[uint64]*Call),
+       }
+       go client.input()
+       return client
+}
+
+type gobClientCodec struct {
+       rwc io.ReadWriteCloser
+       dec *gob.Decoder
+       enc *gob.Encoder
+}
+
+func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) os.Error {
+       if err := c.enc.Encode(r); err != nil {
+               return err
+       }
+       return c.enc.Encode(body)
+}
+
+func (c *gobClientCodec) ReadResponseHeader(r *Response) os.Error {
+       return c.dec.Decode(r)
+}
+
+func (c *gobClientCodec) ReadResponseBody(body interface{}) os.Error {
+       return c.dec.Decode(body)
+}
+
+func (c *gobClientCodec) Close() os.Error {
+       return c.rwc.Close()
+}
+
+
+// DialHTTP connects to an HTTP RPC server at the specified network address
+// listening on the default HTTP RPC path.
+func DialHTTP(network, address string) (*Client, os.Error) {
+       return DialHTTPPath(network, address, DefaultRPCPath)
+}
+
+// DialHTTPPath connects to an HTTP RPC server 
+// at the specified network address and path.
+func DialHTTPPath(network, address, path string) (*Client, os.Error) {
+       var err os.Error
+       conn, err := net.Dial(network, "", address)
+       if err != nil {
+               return nil, err
+       }
+       io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")
+
+       // Require successful HTTP response
+       // before switching to RPC protocol.
+       resp, err := http.ReadResponse(bufio.NewReader(conn), "CONNECT")
+       if err == nil && resp.Status == connected {
+               return NewClient(conn), nil
+       }
+       if err == nil {
+               err = os.ErrorString("unexpected HTTP response: " + resp.Status)
+       }
+       conn.Close()
+       return nil, &net.OpError{"dial-http", network + " " + address, nil, err}
+}
+
+// Dial connects to an RPC server at the specified network address.
+func Dial(network, address string) (*Client, os.Error) {
+       conn, err := net.Dial(network, "", address)
+       if err != nil {
+               return nil, err
+       }
+       return NewClient(conn), nil
+}
+
+func (client *Client) Close() os.Error {
+       if client.shutdown != nil || client.closing {
+               return os.ErrorString("rpc: already closed")
+       }
+       client.mutex.Lock()
+       client.closing = true
+       client.mutex.Unlock()
+       return client.codec.Close()
+}
+
+// Go invokes the function asynchronously.  It returns the Call structure representing
+// the invocation.  The done channel will signal when the call is complete by returning
+// the same Call object.  If done is nil, Go will allocate a new channel.
+// If non-nil, done must be buffered or Go will deliberately crash.
+func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
+       c := new(Call)
+       c.ServiceMethod = serviceMethod
+       c.Args = args
+       c.Reply = reply
+       if done == nil {
+               done = make(chan *Call, 10) // buffered.
+       } else {
+               // If caller passes done != nil, it must arrange that
+               // done has enough buffer for the number of simultaneous
+               // RPCs that will be using that channel.  If the channel
+               // is totally unbuffered, it's best not to run at all.
+               if cap(done) == 0 {
+                       log.Panic("rpc: done channel is unbuffered")
+               }
+       }
+       c.Done = done
+       if client.shutdown != nil {
+               c.Error = client.shutdown
+               _ = c.Done <- c // do not block
+               return c
+       }
+       client.send(c)
+       return c
+}
+
+// Call invokes the named function, waits for it to complete, and returns its error status.
+func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) os.Error {
+       if client.shutdown != nil {
+               return client.shutdown
+       }
+       call := <-client.Go(serviceMethod, args, reply, nil).Done
+       return call.Error
+}
diff --git a/libgo/go/rpc/debug.go b/libgo/go/rpc/debug.go
new file mode 100644 (file)
index 0000000..6bd8a91
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+/*
+       Some HTML presented at http://machine:port/debug/rpc
+       Lists services, their methods, and some statistics, still rudimentary.
+*/
+
+import (
+       "fmt"
+       "http"
+       "sort"
+       "template"
+)
+
+const debugText = `<html>
+       <body>
+       <title>Services</title>
+       {.repeated section @}
+       <hr>
+       Service {name}
+       <hr>
+               <table>
+               <th align=center>Method</th><th align=center>Calls</th>
+               {.repeated section meth}
+                       <tr>
+                       <td align=left font=fixed>{name}({m.argType}, {m.replyType}) os.Error</td>
+                       <td align=center>{m.numCalls}</td>
+                       </tr>
+               {.end}
+               </table>
+       {.end}
+       </body>
+       </html>`
+
+var debug = template.MustParse(debugText, nil)
+
+type debugMethod struct {
+       m    *methodType
+       name string
+}
+
+type methodArray []debugMethod
+
+type debugService struct {
+       s    *service
+       name string
+       meth methodArray
+}
+
+type serviceArray []debugService
+
+func (s serviceArray) Len() int           { return len(s) }
+func (s serviceArray) Less(i, j int) bool { return s[i].name < s[j].name }
+func (s serviceArray) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+
+func (m methodArray) Len() int           { return len(m) }
+func (m methodArray) Less(i, j int) bool { return m[i].name < m[j].name }
+func (m methodArray) Swap(i, j int)      { m[i], m[j] = m[j], m[i] }
+
+type debugHTTP struct {
+       *Server
+}
+
+// Runs at /debug/rpc
+func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+       // Build a sorted version of the data.
+       var services = make(serviceArray, len(server.serviceMap))
+       i := 0
+       server.Lock()
+       for sname, service := range server.serviceMap {
+               services[i] = debugService{service, sname, make(methodArray, len(service.method))}
+               j := 0
+               for mname, method := range service.method {
+                       services[i].meth[j] = debugMethod{method, mname}
+                       j++
+               }
+               sort.Sort(services[i].meth)
+               i++
+       }
+       server.Unlock()
+       sort.Sort(services)
+       err := debug.Execute(services, w)
+       if err != nil {
+               fmt.Fprintln(w, "rpc: error executing template:", err.String())
+       }
+}
diff --git a/libgo/go/rpc/jsonrpc/all_test.go b/libgo/go/rpc/jsonrpc/all_test.go
new file mode 100644 (file)
index 0000000..764ee7f
--- /dev/null
@@ -0,0 +1,156 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jsonrpc
+
+import (
+       "fmt"
+       "json"
+       "net"
+       "os"
+       "rpc"
+       "testing"
+)
+
+type Args struct {
+       A, B int
+}
+
+type Reply struct {
+       C int
+}
+
+type Arith int
+
+func (t *Arith) Add(args *Args, reply *Reply) os.Error {
+       reply.C = args.A + args.B
+       return nil
+}
+
+func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
+       reply.C = args.A * args.B
+       return nil
+}
+
+func (t *Arith) Div(args *Args, reply *Reply) os.Error {
+       if args.B == 0 {
+               return os.ErrorString("divide by zero")
+       }
+       reply.C = args.A / args.B
+       return nil
+}
+
+func (t *Arith) Error(args *Args, reply *Reply) os.Error {
+       panic("ERROR")
+}
+
+func init() {
+       rpc.Register(new(Arith))
+}
+
+func TestServer(t *testing.T) {
+       type addResp struct {
+               Id     interface{} "id"
+               Result Reply       "result"
+               Error  interface{} "error"
+       }
+
+       cli, srv := net.Pipe()
+       defer cli.Close()
+       go ServeConn(srv)
+       dec := json.NewDecoder(cli)
+
+       // Send hand-coded requests to server, parse responses.
+       for i := 0; i < 10; i++ {
+               fmt.Fprintf(cli, `{"method": "Arith.Add", "id": "\u%04d", "params": [{"A": %d, "B": %d}]}`, i, i, i+1)
+               var resp addResp
+               err := dec.Decode(&resp)
+               if err != nil {
+                       t.Fatalf("Decode: %s", err)
+               }
+               if resp.Error != nil {
+                       t.Fatalf("resp.Error: %s", resp.Error)
+               }
+               if resp.Id.(string) != string(i) {
+                       t.Fatalf("resp: bad id %q want %q", resp.Id.(string), string(i))
+               }
+               if resp.Result.C != 2*i+1 {
+                       t.Fatalf("resp: bad result: %d+%d=%d", i, i+1, resp.Result.C)
+               }
+       }
+
+       fmt.Fprintf(cli, "{}\n")
+       var resp addResp
+       if err := dec.Decode(&resp); err != nil {
+               t.Fatalf("Decode after empty: %s", err)
+       }
+       if resp.Error == nil {
+               t.Fatalf("Expected error, got nil")
+       }
+}
+
+func TestClient(t *testing.T) {
+       // Assume server is okay (TestServer is above).
+       // Test client against server.
+       cli, srv := net.Pipe()
+       go ServeConn(srv)
+
+       client := NewClient(cli)
+       defer client.Close()
+
+       // Synchronous calls
+       args := &Args{7, 8}
+       reply := new(Reply)
+       err := client.Call("Arith.Add", args, reply)
+       if err != nil {
+               t.Errorf("Add: expected no error but got string %q", err.String())
+       }
+       if reply.C != args.A+args.B {
+               t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+       }
+
+       args = &Args{7, 8}
+       reply = new(Reply)
+       err = client.Call("Arith.Mul", args, reply)
+       if err != nil {
+               t.Errorf("Mul: expected no error but got string %q", err.String())
+       }
+       if reply.C != args.A*args.B {
+               t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
+       }
+
+       // Out of order.
+       args = &Args{7, 8}
+       mulReply := new(Reply)
+       mulCall := client.Go("Arith.Mul", args, mulReply, nil)
+       addReply := new(Reply)
+       addCall := client.Go("Arith.Add", args, addReply, nil)
+
+       addCall = <-addCall.Done
+       if addCall.Error != nil {
+               t.Errorf("Add: expected no error but got string %q", addCall.Error.String())
+       }
+       if addReply.C != args.A+args.B {
+               t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B)
+       }
+
+       mulCall = <-mulCall.Done
+       if mulCall.Error != nil {
+               t.Errorf("Mul: expected no error but got string %q", mulCall.Error.String())
+       }
+       if mulReply.C != args.A*args.B {
+               t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B)
+       }
+
+       // Error test
+       args = &Args{7, 0}
+       reply = new(Reply)
+       err = client.Call("Arith.Div", args, reply)
+       // expect an error: zero divide
+       if err == nil {
+               t.Error("Div: expected error")
+       } else if err.String() != "divide by zero" {
+               t.Error("Div: expected divide by zero error; got", err)
+       }
+}
diff --git a/libgo/go/rpc/jsonrpc/client.go b/libgo/go/rpc/jsonrpc/client.go
new file mode 100644 (file)
index 0000000..dcaa69f
--- /dev/null
@@ -0,0 +1,121 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package jsonrpc implements a JSON-RPC ClientCodec and ServerCodec
+// for the rpc package.
+package jsonrpc
+
+import (
+       "fmt"
+       "io"
+       "json"
+       "net"
+       "os"
+       "rpc"
+       "sync"
+)
+
+type clientCodec struct {
+       dec *json.Decoder // for reading JSON values
+       enc *json.Encoder // for writing JSON values
+       c   io.Closer
+
+       // temporary work space
+       req  clientRequest
+       resp clientResponse
+
+       // JSON-RPC responses include the request id but not the request method.
+       // Package rpc expects both.
+       // We save the request method in pending when sending a request
+       // and then look it up by request ID when filling out the rpc Response.
+       mutex   sync.Mutex        // protects pending
+       pending map[uint64]string // map request id to method name
+}
+
+// NewClientCodec returns a new rpc.ClientCodec using JSON-RPC on conn.
+func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
+       return &clientCodec{
+               dec:     json.NewDecoder(conn),
+               enc:     json.NewEncoder(conn),
+               c:       conn,
+               pending: make(map[uint64]string),
+       }
+}
+
+type clientRequest struct {
+       Method string         "method"
+       Params [1]interface{} "params"
+       Id     uint64         "id"
+}
+
+func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) os.Error {
+       c.mutex.Lock()
+       c.pending[r.Seq] = r.ServiceMethod
+       c.mutex.Unlock()
+       c.req.Method = r.ServiceMethod
+       c.req.Params[0] = param
+       c.req.Id = r.Seq
+       return c.enc.Encode(&c.req)
+}
+
+type clientResponse struct {
+       Id     uint64           "id"
+       Result *json.RawMessage "result"
+       Error  interface{}      "error"
+}
+
+func (r *clientResponse) reset() {
+       r.Id = 0
+       r.Result = nil
+       r.Error = nil
+}
+
+func (c *clientCodec) ReadResponseHeader(r *rpc.Response) os.Error {
+       c.resp.reset()
+       if err := c.dec.Decode(&c.resp); err != nil {
+               return err
+       }
+
+       c.mutex.Lock()
+       r.ServiceMethod = c.pending[c.resp.Id]
+       c.pending[c.resp.Id] = "", false
+       c.mutex.Unlock()
+
+       r.Error = ""
+       r.Seq = c.resp.Id
+       if c.resp.Error != nil {
+               x, ok := c.resp.Error.(string)
+               if !ok {
+                       return fmt.Errorf("invalid error %v", c.resp.Error)
+               }
+               if x == "" {
+                       x = "unspecified error"
+               }
+               r.Error = x
+       }
+       return nil
+}
+
+func (c *clientCodec) ReadResponseBody(x interface{}) os.Error {
+       return json.Unmarshal(*c.resp.Result, x)
+}
+
+func (c *clientCodec) Close() os.Error {
+       return c.c.Close()
+}
+
+// NewClient returns a new rpc.Client to handle requests to the
+// set of services at the other end of the connection.
+func NewClient(conn io.ReadWriteCloser) *rpc.Client {
+       return rpc.NewClientWithCodec(NewClientCodec(conn))
+}
+
+// Dial connects to a JSON-RPC server at the specified network address.
+func Dial(network, address string) (*rpc.Client, os.Error) {
+       conn, err := net.Dial(network, "", address)
+       if err != nil {
+               return nil, err
+       }
+       return NewClient(conn), err
+}
diff --git a/libgo/go/rpc/jsonrpc/server.go b/libgo/go/rpc/jsonrpc/server.go
new file mode 100644 (file)
index 0000000..bf53bda
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jsonrpc
+
+import (
+       "io"
+       "json"
+       "os"
+       "rpc"
+       "sync"
+)
+
+type serverCodec struct {
+       dec *json.Decoder // for reading JSON values
+       enc *json.Encoder // for writing JSON values
+       c   io.Closer
+
+       // temporary work space
+       req  serverRequest
+       resp serverResponse
+
+       // JSON-RPC clients can use arbitrary json values as request IDs.
+       // Package rpc expects uint64 request IDs.
+       // We assign uint64 sequence numbers to incoming requests
+       // but save the original request ID in the pending map.
+       // When rpc responds, we use the sequence number in
+       // the response to find the original request ID.
+       mutex   sync.Mutex // protects seq, pending
+       seq     uint64
+       pending map[uint64]*json.RawMessage
+}
+
+// NewServerCodec returns a new rpc.ServerCodec using JSON-RPC on conn.
+func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
+       return &serverCodec{
+               dec:     json.NewDecoder(conn),
+               enc:     json.NewEncoder(conn),
+               c:       conn,
+               pending: make(map[uint64]*json.RawMessage),
+       }
+}
+
+type serverRequest struct {
+       Method string           "method"
+       Params *json.RawMessage "params"
+       Id     *json.RawMessage "id"
+}
+
+func (r *serverRequest) reset() {
+       r.Method = ""
+       if r.Params != nil {
+               *r.Params = (*r.Params)[0:0]
+       }
+       if r.Id != nil {
+               *r.Id = (*r.Id)[0:0]
+       }
+}
+
+type serverResponse struct {
+       Id     *json.RawMessage "id"
+       Result interface{}      "result"
+       Error  interface{}      "error"
+}
+
+func (c *serverCodec) ReadRequestHeader(r *rpc.Request) os.Error {
+       c.req.reset()
+       if err := c.dec.Decode(&c.req); err != nil {
+               return err
+       }
+       r.ServiceMethod = c.req.Method
+
+       // JSON request id can be any JSON value;
+       // RPC package expects uint64.  Translate to
+       // internal uint64 and save JSON on the side.
+       c.mutex.Lock()
+       c.seq++
+       c.pending[c.seq] = c.req.Id
+       c.req.Id = nil
+       r.Seq = c.seq
+       c.mutex.Unlock()
+
+       return nil
+}
+
+func (c *serverCodec) ReadRequestBody(x interface{}) os.Error {
+       // JSON params is array value.
+       // RPC params is struct.
+       // Unmarshal into array containing struct for now.
+       // Should think about making RPC more general.
+       var params [1]interface{}
+       params[0] = x
+       return json.Unmarshal(*c.req.Params, &params)
+}
+
+var null = json.RawMessage([]byte("null"))
+
+func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) os.Error {
+       var resp serverResponse
+       c.mutex.Lock()
+       b, ok := c.pending[r.Seq]
+       if !ok {
+               c.mutex.Unlock()
+               return os.NewError("invalid sequence number in response")
+       }
+       c.pending[r.Seq] = nil, false
+       c.mutex.Unlock()
+
+       if b == nil {
+               // Invalid request so no id.  Use JSON null.
+               b = &null
+       }
+       resp.Id = b
+       resp.Result = x
+       if r.Error == "" {
+               resp.Error = nil
+       } else {
+               resp.Error = r.Error
+       }
+       return c.enc.Encode(resp)
+}
+
+func (c *serverCodec) Close() os.Error {
+       return c.c.Close()
+}
+
+// ServeConn runs the JSON-RPC server on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+func ServeConn(conn io.ReadWriteCloser) {
+       rpc.ServeCodec(NewServerCodec(conn))
+}
diff --git a/libgo/go/rpc/server.go b/libgo/go/rpc/server.go
new file mode 100644 (file)
index 0000000..dbb68dd
--- /dev/null
@@ -0,0 +1,508 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+       The rpc package provides access to the exported methods of an object across a
+       network or other I/O connection.  A server registers an object, making it visible
+       as a service with the name of the type of the object.  After registration, exported
+       methods of the object will be accessible remotely.  A server may register multiple
+       objects (services) of different types but it is an error to register multiple
+       objects of the same type.
+
+       Only methods that satisfy these criteria will be made available for remote access;
+       other methods will be ignored:
+
+               - the method receiver and name are exported, that is, begin with an upper case letter.
+               - the method has two arguments, both pointers to exported types.
+               - the method has return type os.Error.
+
+       The method's first argument represents the arguments provided by the caller; the
+       second argument represents the result parameters to be returned to the caller.
+       The method's return value, if non-nil, is passed back as a string that the client
+       sees as an os.ErrorString.
+
+       The server may handle requests on a single connection by calling ServeConn.  More
+       typically it will create a network listener and call Accept or, for an HTTP
+       listener, HandleHTTP and http.Serve.
+
+       A client wishing to use the service establishes a connection and then invokes
+       NewClient on the connection.  The convenience function Dial (DialHTTP) performs
+       both steps for a raw network connection (an HTTP connection).  The resulting
+       Client object has two methods, Call and Go, that specify the service and method to
+       call, a pointer containing the arguments, and a pointer to receive the result
+       parameters.
+
+       Call waits for the remote call to complete; Go launches the call asynchronously
+       and returns a channel that will signal completion.
+
+       Package "gob" is used to transport the data.
+
+       Here is a simple example.  A server wishes to export an object of type Arith:
+
+               package server
+
+               type Args struct {
+                       A, B int
+               }
+
+               type Quotient struct {
+                       Quo, Rem int
+               }
+
+               type Arith int
+
+               func (t *Arith) Multiply(args *Args, reply *int) os.Error {
+                       *reply = args.A * args.B
+                       return nil
+               }
+
+               func (t *Arith) Divide(args *Args, quo *Quotient) os.Error {
+                       if args.B == 0 {
+                               return os.ErrorString("divide by zero")
+                       }
+                       quo.Quo = args.A / args.B
+                       quo.Rem = args.A % args.B
+                       return nil
+               }
+
+       The server calls (for HTTP service):
+
+               arith := new(Arith)
+               rpc.Register(arith)
+               rpc.HandleHTTP()
+               l, e := net.Listen("tcp", ":1234")
+               if e != nil {
+                       log.Exit("listen error:", e)
+               }
+               go http.Serve(l, nil)
+
+       At this point, clients can see a service "Arith" with methods "Arith.Multiply" and
+       "Arith.Divide".  To invoke one, a client first dials the server:
+
+               client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
+               if err != nil {
+                       log.Exit("dialing:", err)
+               }
+
+       Then it can make a remote call:
+
+               // Synchronous call
+               args := &server.Args{7,8}
+               var reply int
+               err = client.Call("Arith.Multiply", args, &reply)
+               if err != nil {
+                       log.Exit("arith error:", err)
+               }
+               fmt.Printf("Arith: %d*%d=%d", args.A, args.B, *reply)
+
+       or
+
+               // Asynchronous call
+               quotient := new(Quotient)
+               divCall := client.Go("Arith.Divide", args, &quotient, nil)
+               replyCall := <-divCall.Done     // will be equal to divCall
+               // check errors, print, etc.
+
+       A server implementation will often provide a simple, type-safe wrapper for the
+       client.
+*/
+package rpc
+
+import (
+       "gob"
+       "http"
+       "log"
+       "io"
+       "net"
+       "os"
+       "reflect"
+       "strings"
+       "sync"
+       "unicode"
+       "utf8"
+)
+
+const (
+       // Defaults used by HandleHTTP
+       DefaultRPCPath   = "/_goRPC_"
+       DefaultDebugPath = "/debug/rpc"
+)
+
+// Precompute the reflect type for os.Error.  Can't use os.Error directly
+// because Typeof takes an empty interface value.  This is annoying.
+var unusedError *os.Error
+var typeOfOsError = reflect.Typeof(unusedError).(*reflect.PtrType).Elem()
+
+type methodType struct {
+       sync.Mutex // protects counters
+       method     reflect.Method
+       argType    *reflect.PtrType
+       replyType  *reflect.PtrType
+       numCalls   uint
+}
+
+type service struct {
+       name   string                 // name of service
+       rcvr   reflect.Value          // receiver of methods for the service
+       typ    reflect.Type           // type of the receiver
+       method map[string]*methodType // registered methods
+}
+
+// Request is a header written before every RPC call.  It is used internally
+// but documented here as an aid to debugging, such as when analyzing
+// network traffic.
+type Request struct {
+       ServiceMethod string // format: "Service.Method"
+       Seq           uint64 // sequence number chosen by client
+}
+
+// Response is a header written before every RPC return.  It is used internally
+// but documented here as an aid to debugging, such as when analyzing
+// network traffic.
+type Response struct {
+       ServiceMethod string // echoes that of the Request
+       Seq           uint64 // echoes that of the request
+       Error         string // error, if any.
+}
+
+// ClientInfo records information about an RPC client connection.
+type ClientInfo struct {
+       LocalAddr  string
+       RemoteAddr string
+}
+
+// Server represents an RPC Server.
+type Server struct {
+       sync.Mutex // protects the serviceMap
+       serviceMap map[string]*service
+}
+
+// NewServer returns a new Server.
+func NewServer() *Server {
+       return &Server{serviceMap: make(map[string]*service)}
+}
+
+// DefaultServer is the default instance of *Server.
+var DefaultServer = NewServer()
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+       rune, _ := utf8.DecodeRuneInString(name)
+       return unicode.IsUpper(rune)
+}
+
+// Register publishes in the server the set of methods of the
+// receiver value that satisfy the following conditions:
+//     - exported method
+//     - two arguments, both pointers to exported structs
+//     - one return value, of type os.Error
+// It returns an error if the receiver is not an exported type or has no
+// suitable methods.
+func (server *Server) Register(rcvr interface{}) os.Error {
+       server.Lock()
+       defer server.Unlock()
+       if server.serviceMap == nil {
+               server.serviceMap = make(map[string]*service)
+       }
+       s := new(service)
+       s.typ = reflect.Typeof(rcvr)
+       s.rcvr = reflect.NewValue(rcvr)
+       sname := reflect.Indirect(s.rcvr).Type().Name()
+       if sname == "" {
+               log.Exit("rpc: no service name for type", s.typ.String())
+       }
+       if s.typ.PkgPath() != "" && !isExported(sname) {
+               s := "rpc Register: type " + sname + " is not exported"
+               log.Print(s)
+               return os.ErrorString(s)
+       }
+       if _, present := server.serviceMap[sname]; present {
+               return os.ErrorString("rpc: service already defined: " + sname)
+       }
+       s.name = sname
+       s.method = make(map[string]*methodType)
+
+       // Install the methods
+       for m := 0; m < s.typ.NumMethod(); m++ {
+               method := s.typ.Method(m)
+               mtype := method.Type
+               mname := method.Name
+               if mtype.PkgPath() != "" || !isExported(mname) {
+                       continue
+               }
+               // Method needs three ins: receiver, *args, *reply.
+               if mtype.NumIn() != 3 {
+                       log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
+                       continue
+               }
+               argType, ok := mtype.In(1).(*reflect.PtrType)
+               if !ok {
+                       log.Println(mname, "arg type not a pointer:", mtype.In(1))
+                       continue
+               }
+               replyType, ok := mtype.In(2).(*reflect.PtrType)
+               if !ok {
+                       log.Println(mname, "reply type not a pointer:", mtype.In(2))
+                       continue
+               }
+               if argType.Elem().PkgPath() != "" && !isExported(argType.Elem().Name()) {
+                       log.Println(mname, "argument type not exported:", argType)
+                       continue
+               }
+               if replyType.Elem().PkgPath() != "" && !isExported(replyType.Elem().Name()) {
+                       log.Println(mname, "reply type not exported:", replyType)
+                       continue
+               }
+               if mtype.NumIn() == 4 {
+                       t := mtype.In(3)
+                       if t != reflect.Typeof((*ClientInfo)(nil)) {
+                               log.Println(mname, "last argument not *ClientInfo")
+                               continue
+                       }
+               }
+               // Method needs one out: os.Error.
+               if mtype.NumOut() != 1 {
+                       log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
+                       continue
+               }
+               if returnType := mtype.Out(0); returnType != typeOfOsError {
+                       log.Println("method", mname, "returns", returnType.String(), "not os.Error")
+                       continue
+               }
+               s.method[mname] = &methodType{method: method, argType: argType, replyType: replyType}
+       }
+
+       if len(s.method) == 0 {
+               s := "rpc Register: type " + sname + " has no exported methods of suitable type"
+               log.Print(s)
+               return os.ErrorString(s)
+       }
+       server.serviceMap[s.name] = s
+       return nil
+}
+
+// A value sent as a placeholder for the response when the server receives an invalid request.
+type InvalidRequest struct {
+       marker int
+}
+
+var invalidRequest = InvalidRequest{1}
+
+func _new(t *reflect.PtrType) *reflect.PtrValue {
+       v := reflect.MakeZero(t).(*reflect.PtrValue)
+       v.PointTo(reflect.MakeZero(t.Elem()))
+       return v
+}
+
+func sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec ServerCodec, errmsg string) {
+       resp := new(Response)
+       // Encode the response header
+       resp.ServiceMethod = req.ServiceMethod
+       if errmsg != "" {
+               resp.Error = errmsg
+       }
+       resp.Seq = req.Seq
+       sending.Lock()
+       err := codec.WriteResponse(resp, reply)
+       if err != nil {
+               log.Println("rpc: writing response:", err)
+       }
+       sending.Unlock()
+}
+
+func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) {
+       mtype.Lock()
+       mtype.numCalls++
+       mtype.Unlock()
+       function := mtype.method.Func
+       // Invoke the method, providing a new value for the reply.
+       returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
+       // The return value for the method is an os.Error.
+       errInter := returnValues[0].Interface()
+       errmsg := ""
+       if errInter != nil {
+               errmsg = errInter.(os.Error).String()
+       }
+       sendResponse(sending, req, replyv.Interface(), codec, errmsg)
+}
+
+type gobServerCodec struct {
+       rwc io.ReadWriteCloser
+       dec *gob.Decoder
+       enc *gob.Encoder
+}
+
+func (c *gobServerCodec) ReadRequestHeader(r *Request) os.Error {
+       return c.dec.Decode(r)
+}
+
+func (c *gobServerCodec) ReadRequestBody(body interface{}) os.Error {
+       return c.dec.Decode(body)
+}
+
+func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) os.Error {
+       if err := c.enc.Encode(r); err != nil {
+               return err
+       }
+       return c.enc.Encode(body)
+}
+
+func (c *gobServerCodec) Close() os.Error {
+       return c.rwc.Close()
+}
+
+
+// ServeConn runs the server on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+// ServeConn uses the gob wire format (see package gob) on the
+// connection.  To use an alternate codec, use ServeCodec.
+func (server *Server) ServeConn(conn io.ReadWriteCloser) {
+       server.ServeCodec(&gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)})
+}
+
+// ServeCodec is like ServeConn but uses the specified codec to
+// decode requests and encode responses.
+func (server *Server) ServeCodec(codec ServerCodec) {
+       sending := new(sync.Mutex)
+       for {
+               // Grab the request header.
+               req := new(Request)
+               err := codec.ReadRequestHeader(req)
+               if err != nil {
+                       if err == os.EOF || err == io.ErrUnexpectedEOF {
+                               if err == io.ErrUnexpectedEOF {
+                                       log.Println("rpc:", err)
+                               }
+                               break
+                       }
+                       s := "rpc: server cannot decode request: " + err.String()
+                       sendResponse(sending, req, invalidRequest, codec, s)
+                       break
+               }
+               serviceMethod := strings.Split(req.ServiceMethod, ".", -1)
+               if len(serviceMethod) != 2 {
+                       s := "rpc: service/method request ill-formed: " + req.ServiceMethod
+                       sendResponse(sending, req, invalidRequest, codec, s)
+                       continue
+               }
+               // Look up the request.
+               server.Lock()
+               service, ok := server.serviceMap[serviceMethod[0]]
+               server.Unlock()
+               if !ok {
+                       s := "rpc: can't find service " + req.ServiceMethod
+                       sendResponse(sending, req, invalidRequest, codec, s)
+                       continue
+               }
+               mtype, ok := service.method[serviceMethod[1]]
+               if !ok {
+                       s := "rpc: can't find method " + req.ServiceMethod
+                       sendResponse(sending, req, invalidRequest, codec, s)
+                       continue
+               }
+               // Decode the argument value.
+               argv := _new(mtype.argType)
+               replyv := _new(mtype.replyType)
+               err = codec.ReadRequestBody(argv.Interface())
+               if err != nil {
+                       log.Println("rpc: tearing down", serviceMethod[0], "connection:", err)
+                       sendResponse(sending, req, replyv.Interface(), codec, err.String())
+                       break
+               }
+               go service.call(sending, mtype, req, argv, replyv, codec)
+       }
+       codec.Close()
+}
+
+// Accept accepts connections on the listener and serves requests
+// for each incoming connection.  Accept blocks; the caller typically
+// invokes it in a go statement.
+func (server *Server) Accept(lis net.Listener) {
+       for {
+               conn, err := lis.Accept()
+               if err != nil {
+                       log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit?
+               }
+               go server.ServeConn(conn)
+       }
+}
+
+// Register publishes in the DefaultServer the set of methods 
+// of the receiver value that satisfy the following conditions:
+//     - exported method
+//     - two arguments, both pointers to exported structs
+//     - one return value, of type os.Error
+// It returns an error if the receiver is not an exported type or has no
+// suitable methods.
+func Register(rcvr interface{}) os.Error { return DefaultServer.Register(rcvr) }
+
+// A ServerCodec implements reading of RPC requests and writing of
+// RPC responses for the server side of an RPC session.
+// The server calls ReadRequestHeader and ReadRequestBody in pairs
+// to read requests from the connection, and it calls WriteResponse to
+// write a response back.  The server calls Close when finished with the
+// connection.
+type ServerCodec interface {
+       ReadRequestHeader(*Request) os.Error
+       ReadRequestBody(interface{}) os.Error
+       WriteResponse(*Response, interface{}) os.Error
+
+       Close() os.Error
+}
+
+// ServeConn runs the DefaultServer on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+// ServeConn uses the gob wire format (see package gob) on the
+// connection.  To use an alternate codec, use ServeCodec.
+func ServeConn(conn io.ReadWriteCloser) {
+       DefaultServer.ServeConn(conn)
+}
+
+// ServeCodec is like ServeConn but uses the specified codec to
+// decode requests and encode responses.
+func ServeCodec(codec ServerCodec) {
+       DefaultServer.ServeCodec(codec)
+}
+
+// Accept accepts connections on the listener and serves requests
+// to DefaultServer for each incoming connection.  
+// Accept blocks; the caller typically invokes it in a go statement.
+func Accept(lis net.Listener) { DefaultServer.Accept(lis) }
+
+// Can connect to RPC service using HTTP CONNECT to rpcPath.
+var connected = "200 Connected to Go RPC"
+
+// ServeHTTP implements an http.Handler that answers RPC requests.
+func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+       if req.Method != "CONNECT" {
+               w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+               w.WriteHeader(http.StatusMethodNotAllowed)
+               io.WriteString(w, "405 must CONNECT\n")
+               return
+       }
+       conn, _, err := w.Hijack()
+       if err != nil {
+               log.Print("rpc hijacking ", w.RemoteAddr(), ": ", err.String())
+               return
+       }
+       io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
+       server.ServeConn(conn)
+}
+
+// HandleHTTP registers an HTTP handler for RPC messages on rpcPath,
+// and a debugging handler on debugPath.
+// It is still necessary to invoke http.Serve(), typically in a go statement.
+func (server *Server) HandleHTTP(rpcPath, debugPath string) {
+       http.Handle(rpcPath, server)
+       http.Handle(debugPath, debugHTTP{server})
+}
+
+// HandleHTTP registers an HTTP handler for RPC messages to DefaultServer
+// on DefaultRPCPath and a debugging handler on DefaultDebugPath.
+// It is still necessary to invoke http.Serve(), typically in a go statement.
+func HandleHTTP() {
+       DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
+}
diff --git a/libgo/go/rpc/server_test.go b/libgo/go/rpc/server_test.go
new file mode 100644 (file)
index 0000000..355d51c
--- /dev/null
@@ -0,0 +1,384 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+import (
+       "fmt"
+       "http"
+       "log"
+       "net"
+       "os"
+       "strings"
+       "sync"
+       "testing"
+       "time"
+)
+
+var (
+       serverAddr, newServerAddr string
+       httpServerAddr            string
+       once, newOnce, httpOnce   sync.Once
+)
+
+const (
+       second      = 1e9
+       newHttpPath = "/foo"
+)
+
+type Args struct {
+       A, B int
+}
+
+type Reply struct {
+       C int
+}
+
+type Arith int
+
+func (t *Arith) Add(args *Args, reply *Reply) os.Error {
+       reply.C = args.A + args.B
+       return nil
+}
+
+func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
+       reply.C = args.A * args.B
+       return nil
+}
+
+func (t *Arith) Div(args *Args, reply *Reply) os.Error {
+       if args.B == 0 {
+               return os.ErrorString("divide by zero")
+       }
+       reply.C = args.A / args.B
+       return nil
+}
+
+func (t *Arith) String(args *Args, reply *string) os.Error {
+       *reply = fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
+       return nil
+}
+
+func (t *Arith) Scan(args *string, reply *Reply) (err os.Error) {
+       _, err = fmt.Sscan(*args, &reply.C)
+       return
+}
+
+func (t *Arith) Error(args *Args, reply *Reply) os.Error {
+       panic("ERROR")
+}
+
+func listenTCP() (net.Listener, string) {
+       l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
+       if e != nil {
+               log.Exitf("net.Listen tcp :0: %v", e)
+       }
+       return l, l.Addr().String()
+}
+
+func startServer() {
+       Register(new(Arith))
+
+       var l net.Listener
+       l, serverAddr = listenTCP()
+       log.Println("Test RPC server listening on", serverAddr)
+       go Accept(l)
+
+       HandleHTTP()
+       httpOnce.Do(startHttpServer)
+}
+
+func startNewServer() {
+       s := NewServer()
+       s.Register(new(Arith))
+
+       var l net.Listener
+       l, newServerAddr = listenTCP()
+       log.Println("NewServer test RPC server listening on", newServerAddr)
+       go Accept(l)
+
+       s.HandleHTTP(newHttpPath, "/bar")
+       httpOnce.Do(startHttpServer)
+}
+
+func startHttpServer() {
+       var l net.Listener
+       l, httpServerAddr = listenTCP()
+       httpServerAddr = l.Addr().String()
+       log.Println("Test HTTP RPC server listening on", httpServerAddr)
+       go http.Serve(l, nil)
+}
+
+func TestRPC(t *testing.T) {
+       once.Do(startServer)
+       testRPC(t, serverAddr)
+       newOnce.Do(startNewServer)
+       testRPC(t, newServerAddr)
+}
+
+func testRPC(t *testing.T, addr string) {
+       client, err := Dial("tcp", addr)
+       if err != nil {
+               t.Fatal("dialing", err)
+       }
+
+       // Synchronous calls
+       args := &Args{7, 8}
+       reply := new(Reply)
+       err = client.Call("Arith.Add", args, reply)
+       if err != nil {
+               t.Errorf("Add: expected no error but got string %q", err.String())
+       }
+       if reply.C != args.A+args.B {
+               t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+       }
+
+       args = &Args{7, 8}
+       reply = new(Reply)
+       err = client.Call("Arith.Mul", args, reply)
+       if err != nil {
+               t.Errorf("Mul: expected no error but got string %q", err.String())
+       }
+       if reply.C != args.A*args.B {
+               t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
+       }
+
+       // Out of order.
+       args = &Args{7, 8}
+       mulReply := new(Reply)
+       mulCall := client.Go("Arith.Mul", args, mulReply, nil)
+       addReply := new(Reply)
+       addCall := client.Go("Arith.Add", args, addReply, nil)
+
+       addCall = <-addCall.Done
+       if addCall.Error != nil {
+               t.Errorf("Add: expected no error but got string %q", addCall.Error.String())
+       }
+       if addReply.C != args.A+args.B {
+               t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B)
+       }
+
+       mulCall = <-mulCall.Done
+       if mulCall.Error != nil {
+               t.Errorf("Mul: expected no error but got string %q", mulCall.Error.String())
+       }
+       if mulReply.C != args.A*args.B {
+               t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B)
+       }
+
+       // Error test
+       args = &Args{7, 0}
+       reply = new(Reply)
+       err = client.Call("Arith.Div", args, reply)
+       // expect an error: zero divide
+       if err == nil {
+               t.Error("Div: expected error")
+       } else if err.String() != "divide by zero" {
+               t.Error("Div: expected divide by zero error; got", err)
+       }
+
+       // Non-struct argument
+       const Val = 12345
+       str := fmt.Sprint(Val)
+       reply = new(Reply)
+       err = client.Call("Arith.Scan", &str, reply)
+       if err != nil {
+               t.Errorf("Scan: expected no error but got string %q", err.String())
+       } else if reply.C != Val {
+               t.Errorf("Scan: expected %d got %d", Val, reply.C)
+       }
+
+       // Non-struct reply
+       args = &Args{27, 35}
+       str = ""
+       err = client.Call("Arith.String", args, &str)
+       if err != nil {
+               t.Errorf("String: expected no error but got string %q", err.String())
+       }
+       expect := fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
+       if str != expect {
+               t.Errorf("String: expected %s got %s", expect, str)
+       }
+}
+
+func TestHTTPRPC(t *testing.T) {
+       once.Do(startServer)
+       testHTTPRPC(t, "")
+       newOnce.Do(startNewServer)
+       testHTTPRPC(t, newHttpPath)
+}
+
+func testHTTPRPC(t *testing.T, path string) {
+       var client *Client
+       var err os.Error
+       if path == "" {
+               client, err = DialHTTP("tcp", httpServerAddr)
+       } else {
+               client, err = DialHTTPPath("tcp", httpServerAddr, path)
+       }
+       if err != nil {
+               t.Fatal("dialing", err)
+       }
+
+       // Synchronous calls
+       args := &Args{7, 8}
+       reply := new(Reply)
+       err = client.Call("Arith.Add", args, reply)
+       if err != nil {
+               t.Errorf("Add: expected no error but got string %q", err.String())
+       }
+       if reply.C != args.A+args.B {
+               t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+       }
+}
+
+func TestCheckUnknownService(t *testing.T) {
+       once.Do(startServer)
+
+       conn, err := net.Dial("tcp", "", serverAddr)
+       if err != nil {
+               t.Fatal("dialing:", err)
+       }
+
+       client := NewClient(conn)
+
+       args := &Args{7, 8}
+       reply := new(Reply)
+       err = client.Call("Unknown.Add", args, reply)
+       if err == nil {
+               t.Error("expected error calling unknown service")
+       } else if strings.Index(err.String(), "service") < 0 {
+               t.Error("expected error about service; got", err)
+       }
+}
+
+func TestCheckUnknownMethod(t *testing.T) {
+       once.Do(startServer)
+
+       conn, err := net.Dial("tcp", "", serverAddr)
+       if err != nil {
+               t.Fatal("dialing:", err)
+       }
+
+       client := NewClient(conn)
+
+       args := &Args{7, 8}
+       reply := new(Reply)
+       err = client.Call("Arith.Unknown", args, reply)
+       if err == nil {
+               t.Error("expected error calling unknown service")
+       } else if strings.Index(err.String(), "method") < 0 {
+               t.Error("expected error about method; got", err)
+       }
+}
+
+func TestCheckBadType(t *testing.T) {
+       once.Do(startServer)
+
+       conn, err := net.Dial("tcp", "", serverAddr)
+       if err != nil {
+               t.Fatal("dialing:", err)
+       }
+
+       client := NewClient(conn)
+
+       reply := new(Reply)
+       err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
+       if err == nil {
+               t.Error("expected error calling Arith.Add with wrong arg type")
+       } else if strings.Index(err.String(), "type") < 0 {
+               t.Error("expected error about type; got", err)
+       }
+}
+
+type ArgNotPointer int
+type ReplyNotPointer int
+type ArgNotPublic int
+type ReplyNotPublic int
+type local struct{}
+
+func (t *ArgNotPointer) ArgNotPointer(args Args, reply *Reply) os.Error {
+       return nil
+}
+
+func (t *ReplyNotPointer) ReplyNotPointer(args *Args, reply Reply) os.Error {
+       return nil
+}
+
+func (t *ArgNotPublic) ArgNotPublic(args *local, reply *Reply) os.Error {
+       return nil
+}
+
+func (t *ReplyNotPublic) ReplyNotPublic(args *Args, reply *local) os.Error {
+       return nil
+}
+
+// Check that registration handles lots of bad methods and a type with no suitable methods.
+func TestRegistrationError(t *testing.T) {
+       err := Register(new(ArgNotPointer))
+       if err == nil {
+               t.Errorf("expected error registering ArgNotPointer")
+       }
+       err = Register(new(ReplyNotPointer))
+       if err == nil {
+               t.Errorf("expected error registering ReplyNotPointer")
+       }
+       err = Register(new(ArgNotPublic))
+       if err == nil {
+               t.Errorf("expected error registering ArgNotPublic")
+       }
+       err = Register(new(ReplyNotPublic))
+       if err == nil {
+               t.Errorf("expected error registering ReplyNotPublic")
+       }
+}
+
+type WriteFailCodec int
+
+func (WriteFailCodec) WriteRequest(*Request, interface{}) os.Error {
+       // the panic caused by this error used to not unlock a lock.
+       return os.NewError("fail")
+}
+
+func (WriteFailCodec) ReadResponseHeader(*Response) os.Error {
+       time.Sleep(60e9)
+       panic("unreachable")
+}
+
+func (WriteFailCodec) ReadResponseBody(interface{}) os.Error {
+       time.Sleep(60e9)
+       panic("unreachable")
+}
+
+func (WriteFailCodec) Close() os.Error {
+       return nil
+}
+
+func TestSendDeadlock(t *testing.T) {
+       client := NewClientWithCodec(WriteFailCodec(0))
+
+       done := make(chan bool)
+       go func() {
+               testSendDeadlock(client)
+               testSendDeadlock(client)
+               done <- true
+       }()
+       for i := 0; i < 50; i++ {
+               time.Sleep(100 * 1e6)
+               _, ok := <-done
+               if ok {
+                       return
+               }
+       }
+       t.Fatal("deadlock")
+}
+
+func testSendDeadlock(client *Client) {
+       defer func() {
+               recover()
+       }()
+       args := &Args{7, 8}
+       reply := new(Reply)
+       client.Call("Arith.Add", args, reply)
+}
diff --git a/libgo/go/runtime/debug.go b/libgo/go/runtime/debug.go
new file mode 100644 (file)
index 0000000..b5f6571
--- /dev/null
@@ -0,0 +1,143 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// Breakpoint() executes a breakpoint trap.
+func Breakpoint()
+
+// LockOSThread wires the calling goroutine to its current operating system thread.
+// Until the calling goroutine exits or calls UnlockOSThread, it will always
+// execute in that thread, and no other goroutine can.
+// LockOSThread cannot be used during init functions.
+func LockOSThread()
+
+// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
+// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
+func UnlockOSThread()
+
+// GOMAXPROCS sets the maximum number of CPUs that can be executing
+// simultaneously and returns the previous setting.  If n < 1, it does not
+// change the current setting.
+// This call will go away when the scheduler improves.
+func GOMAXPROCS(n int) int
+
+// Cgocalls returns the number of cgo calls made by the current process.
+func Cgocalls() int64
+
+type MemStatsType struct {
+       // General statistics.
+       // Not locked during update; approximate.
+       Alloc      uint64 // bytes allocated and still in use
+       TotalAlloc uint64 // bytes allocated (even if freed)
+       Sys        uint64 // bytes obtained from system (should be sum of XxxSys below)
+       Lookups    uint64 // number of pointer lookups
+       Mallocs    uint64 // number of mallocs
+
+       // Main allocation heap statistics.
+       HeapAlloc   uint64 // bytes allocated and still in use
+       HeapSys     uint64 // bytes obtained from system
+       HeapIdle    uint64 // bytes in idle spans
+       HeapInuse   uint64 // bytes in non-idle span
+       HeapObjects uint64 // total number of allocated objects
+
+       // Low-level fixed-size structure allocator statistics.
+       //      Inuse is bytes used now.
+       //      Sys is bytes obtained from system.
+       StackInuse  uint64 // bootstrap stacks
+       StackSys    uint64
+       MSpanInuse  uint64 // mspan structures
+       MSpanSys    uint64
+       MCacheInuse uint64 // mcache structures
+       MCacheSys   uint64
+       MHeapMapSys uint64 // heap map
+       BuckHashSys uint64 // profiling bucket hash table
+
+       // Garbage collector statistics.
+       NextGC   uint64
+       PauseNs  uint64
+       NumGC    uint32
+       EnableGC bool
+       DebugGC  bool
+
+       // Per-size allocation statistics.
+       // Not locked during update; approximate.
+       BySize [67]struct {
+               Size    uint32
+               Mallocs uint64
+               Frees   uint64
+       }
+}
+
+// MemStats holds statistics about the memory system.
+// The statistics are only approximate, as they are not interlocked on update.
+var MemStats MemStatsType
+
+// Alloc allocates a block of the given size.
+// FOR TESTING AND DEBUGGING ONLY.
+func Alloc(uintptr) *byte
+
+// Free frees the block starting at the given pointer.
+// FOR TESTING AND DEBUGGING ONLY.
+func Free(*byte)
+
+// Lookup returns the base and size of the block containing the given pointer.
+// FOR TESTING AND DEBUGGING ONLY.
+func Lookup(*byte) (*byte, uintptr)
+
+// GC runs a garbage collection.
+func GC()
+
+// MemProfileRate controls the fraction of memory allocations
+// that are recorded and reported in the memory profile.
+// The profiler aims to sample an average of
+// one allocation per MemProfileRate bytes allocated.
+//
+// To include every allocated block in the profile, set MemProfileRate to 1.
+// To turn off profiling entirely, set MemProfileRate to 0.
+//
+// The tools that process the memory profiles assume that the
+// profile rate is constant across the lifetime of the program
+// and equal to the current value.  Programs that change the
+// memory profiling rate should do so just once, as early as
+// possible in the execution of the program (for example,
+// at the beginning of main).
+var MemProfileRate int = 512 * 1024
+
+// A MemProfileRecord describes the live objects allocated
+// by a particular call sequence (stack trace).
+type MemProfileRecord struct {
+       AllocBytes, FreeBytes     int64       // number of bytes allocated, freed
+       AllocObjects, FreeObjects int64       // number of objects allocated, freed
+       Stack0                    [32]uintptr // stack trace for this record; ends at first 0 entry
+}
+
+// InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes).
+func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes }
+
+// InUseObjects returns the number of objects in use (AllocObjects - FreeObjects).
+func (r *MemProfileRecord) InUseObjects() int64 {
+       return r.AllocObjects - r.FreeObjects
+}
+
+// Stack returns the stack trace associated with the record,
+// a prefix of r.Stack0.
+func (r *MemProfileRecord) Stack() []uintptr {
+       for i, v := range r.Stack0 {
+               if v == 0 {
+                       return r.Stack0[0:i]
+               }
+       }
+       return r.Stack0[0:]
+}
+
+// MemProfile returns n, the number of records in the current memory profile.
+// If len(p) >= n, MemProfile copies the profile into p and returns n, true.
+// If len(p) < n, MemProfile does not change p and returns n, false.
+//
+// If inuseZero is true, the profile includes allocation records
+// where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes.
+// These are sites where memory was allocated, but it has all
+// been released back to the runtime.
+func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool)
diff --git a/libgo/go/runtime/error.go b/libgo/go/runtime/error.go
new file mode 100644 (file)
index 0000000..2515722
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// The Error interface identifies a run time error.
+type Error interface {
+       String() string
+
+       // RuntimeError is a no-op function but
+       // serves to distinguish types that are runtime
+       // errors from ordinary os.Errors: a type is a
+       // runtime error if it has a RuntimeError method.
+       RuntimeError()
+}
+
+// A TypeAssertionError explains a failed type assertion.
+type TypeAssertionError struct {
+       interfaceType   *Type // interface had this type
+       concreteType    *Type // concrete value had this type
+       assertedType    *Type // asserted type
+       interfaceString string
+       concreteString  string
+       assertedString  string
+       missingMethod   string // one method needed by Interface, missing from Concrete
+}
+
+func (*TypeAssertionError) RuntimeError() {}
+
+func (e *TypeAssertionError) String() string {
+       inter := e.interfaceString
+       if inter == "" {
+               inter = "interface"
+       }
+       if e.concreteType == nil {
+               return "interface conversion: " + inter + " is nil, not " + e.assertedString
+       }
+       if e.missingMethod == "" {
+               return "interface conversion: " + inter + " is " + e.concreteString +
+                       ", not " + e.assertedString
+       }
+       return "interface conversion: " + e.concreteString + " is not " + e.assertedString +
+               ": missing method " + e.missingMethod
+}
+
+// Concrete returns the type of the concrete value in the failed type assertion.
+// If the interface value was nil, Concrete returns nil.
+func (e *TypeAssertionError) Concrete() *Type {
+       return e.concreteType
+}
+
+// Asserted returns the type incorrectly asserted by the type assertion.
+func (e *TypeAssertionError) Asserted() *Type {
+       return e.assertedType
+}
+
+// If the type assertion is to an interface type, MissingMethod returns the
+// name of a method needed to satisfy that interface type but not implemented
+// by Concrete.  If there are multiple such methods,
+// MissingMethod returns one; which one is unspecified.
+// If the type assertion is not to an interface type, MissingMethod returns an empty string.
+func (e *TypeAssertionError) MissingMethod() string {
+       return e.missingMethod
+}
+
+// For calling from C.
+func NewTypeAssertionError(pt1, pt2, pt3 *Type, ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
+       var t1, t2, t3 *Type
+       var s1, s2, s3, meth string
+
+       if pt1 != nil {
+               t1 = pt1
+       }
+       if pt2 != nil {
+               t2 = pt2
+       }
+       if pt3 != nil {
+               t3 = pt3
+       }
+       if ps1 != nil {
+               s1 = *ps1
+       }
+       if ps2 != nil {
+               s2 = *ps2
+       }
+       if ps3 != nil {
+               s3 = *ps3
+       }
+       if pmeth != nil {
+               meth = *pmeth
+       }
+       *ret = &TypeAssertionError{t1, t2, t3, s1, s2, s3, meth}
+}
+
+// An errorString represents a runtime error described by a single string.
+type errorString string
+
+func (e errorString) RuntimeError() {}
+
+func (e errorString) String() string {
+       return "runtime error: " + string(e)
+}
+
+// For calling from C.
+func NewErrorString(s string, ret *interface{}) {
+       *ret = errorString(s)
+}
+
+type stringer interface {
+       String() string
+}
+
+func typestring(interface{}) string
+
+// For calling from C.
+// Prints an argument passed to panic.
+// There's room for arbitrary complexity here, but we keep it
+// simple and handle just a few important cases: int, string, and Stringer.
+func Printany(i interface{}) {
+       switch v := i.(type) {
+       case nil:
+               print("nil")
+       case stringer:
+               print(v.String())
+       case int:
+               print(v)
+       case string:
+               print(v)
+       default:
+               print("(", typestring(i), ") ", i)
+       }
+}
diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go
new file mode 100644 (file)
index 0000000..58631c7
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Export guts for testing.
+
+package runtime
+
+var Fadd64 = fadd64
+var Fsub64 = fsub64
+var Fmul64 = fmul64
+var Fdiv64 = fdiv64
+var F64to32 = f64to32
+var F32to64 = f32to64
+var Fcmp64 = fcmp64
+var Fintto64 = fintto64
+var F64toint = f64toint
diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go
new file mode 100644 (file)
index 0000000..8ab57d0
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+       The runtime package contains operations that interact with Go's runtime system,
+       such as functions to control goroutines. It also includes the low-level type information
+       used by the reflect package; see reflect's documentation for the programmable
+       interface to the run-time type system.
+*/
+package runtime
+
+// Gosched yields the processor, allowing other goroutines to run.  It does not
+// suspend the current goroutine, so execution resumes automatically.
+func Gosched()
+
+// Goexit terminates the goroutine that calls it.  No other goroutine is affected.
+// Goexit runs all deferred calls before terminating the goroutine.
+func Goexit()
+
+// Caller reports file and line number information about function invocations on
+// the calling goroutine's stack.  The argument skip is the number of stack frames to
+// ascend, with 0 identifying the the caller of Caller.  The return values report the
+// program counter, file name, and line number within the file of the corresponding
+// call.  The boolean ok is false if it was not possible to recover the information.
+func Caller(skip int) (pc uintptr, file string, line int, ok bool)
+
+// Callers fills the slice pc with the program counters of function invocations
+// on the calling goroutine's stack.  The argument skip is the number of stack frames
+// to skip before recording in pc, with 0 starting at the caller of Caller.
+// It returns the number of entries written to pc.
+func Callers(skip int, pc []uintptr) int
+
+// FuncForPC returns a *Func describing the function that contains the
+// given program counter address, or else nil.
+func FuncForPC(pc uintptr) *Func
+
+// NOTE(rsc): Func must match struct Func in runtime.h
+
+// Func records information about a function in the program,
+// in particular  the mapping from program counters to source
+// line numbers within that function.
+type Func struct {
+       name   string
+       typ    string
+       src    string
+       pcln   []byte
+       entry  uintptr
+       pc0    uintptr
+       ln0    int32
+       frame  int32
+       args   int32
+       locals int32
+}
+
+// Name returns the name of the function.
+func (f *Func) Name() string { return f.name }
+
+// Entry returns the entry address of the function.
+func (f *Func) Entry() uintptr { return f.entry }
+
+// FileLine returns the file name and line number of the
+// source code corresponding to the program counter pc.
+// The result will not be accurate if pc is not a program
+// counter within f.
+func (f *Func) FileLine(pc uintptr) (file string, line int) {
+       // NOTE(rsc): If you edit this function, also edit
+       // symtab.c:/^funcline.
+       var pcQuant uintptr = 1
+       if GOARCH == "arm" {
+               pcQuant = 4
+       }
+
+       targetpc := pc
+       p := f.pcln
+       pc = f.pc0
+       line = int(f.ln0)
+       file = f.src
+       for i := 0; i < len(p) && pc <= targetpc; i++ {
+               switch {
+               case p[i] == 0:
+                       line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4])
+                       i += 4
+               case p[i] <= 64:
+                       line += int(p[i])
+               case p[i] <= 128:
+                       line -= int(p[i] - 64)
+               default:
+                       pc += pcQuant * uintptr(p[i]-129)
+               }
+               pc += pcQuant
+       }
+       return
+}
+
+// mid returns the current os thread (m) id.
+func mid() uint32
+
+// Semacquire waits until *s > 0 and then atomically decrements it.
+// It is intended as a simple sleep primitive for use by the synchronization
+// library and should not be used directly.
+func Semacquire(s *uint32)
+
+// Semrelease atomically increments *s and notifies a waiting goroutine
+// if one is blocked in Semacquire.
+// It is intended as a simple wakeup primitive for use by the synchronization
+// library and should not be used directly.
+func Semrelease(s *uint32)
+
+// SetFinalizer sets the finalizer associated with x to f.
+// When the garbage collector finds an unreachable block
+// with an associated finalizer, it clears the association and runs
+// f(x) in a separate goroutine.  This makes x reachable again, but
+// now without an associated finalizer.  Assuming that SetFinalizer
+// is not called again, the next time the garbage collector sees
+// that x is unreachable, it will free x.
+//
+// SetFinalizer(x, nil) clears any finalizer associated with x.
+//
+// The argument x must be a pointer to an object allocated by
+// calling new or by taking the address of a composite literal.
+// The argument f must be a function that takes a single argument
+// of x's type and returns no arguments.  If either of these is not
+// true, SetFinalizer aborts the program.
+//
+// Finalizers are run in dependency order: if A points at B, both have
+// finalizers, and they are otherwise unreachable, only the finalizer
+// for A runs; once A is freed, the finalizer for B can run.
+// If a cyclic structure includes a block with a finalizer, that
+// cycle is not guaranteed to be garbage collected and the finalizer
+// is not guaranteed to run, because there is no ordering that
+// respects the dependencies.
+//
+// The finalizer for x is scheduled to run at some arbitrary time after
+// x becomes unreachable.
+// There is no guarantee that finalizers will run before a program exits,
+// so typically they are useful only for releasing non-memory resources
+// associated with an object during a long-running program.
+// For example, an os.File object could use a finalizer to close the
+// associated operating system file descriptor when a program discards
+// an os.File without calling Close, but it would be a mistake
+// to depend on a finalizer to flush an in-memory I/O buffer such as a
+// bufio.Writer, because the buffer would not be flushed at program exit.
+//
+// A single goroutine runs all finalizers for a program, sequentially.
+// If a finalizer must run for a long time, it should do so by starting
+// a new goroutine.
+//
+// TODO(rsc): allow f to have (ignored) return values
+//
+func SetFinalizer(x, f interface{})
+
+func getgoroot() string
+
+// GOROOT returns the root of the Go tree.
+// It uses the GOROOT environment variable, if set,
+// or else the root used during the Go build.
+func GOROOT() string {
+       s := getgoroot()
+       if s != "" {
+               return s
+       }
+       return defaultGoroot
+}
+
+// Version returns the Go tree's version string.
+// It is either a sequence number or, when possible,
+// a release tag like "release.2010-03-04".
+// A trailing + indicates that the tree had local modifications
+// at the time of the build.
+func Version() string {
+       return theVersion
+}
+
+// GOOS is the Go tree's operating system target:
+// one of darwin, freebsd, linux, and so on.
+const GOOS string = theGoos
+
+// GOARCH is the Go tree's architecture target:
+// 386, amd64, or arm.
+const GOARCH string = theGoarch
diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go
new file mode 100644 (file)
index 0000000..d0cc730
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pprof writes runtime profiling data in the format expected
+// by the pprof visualization tool.
+// For more information about pprof, see
+// http://code.google.com/p/google-perftools/.
+package pprof
+
+import (
+       "bufio"
+       "fmt"
+       "io"
+       "os"
+       "runtime"
+)
+
+// WriteHeapProfile writes a pprof-formatted heap profile to w.
+// If a write to w returns an error, WriteHeapProfile returns that error.
+// Otherwise, WriteHeapProfile returns nil.
+func WriteHeapProfile(w io.Writer) os.Error {
+       // Find out how many records there are (MemProfile(nil, false)),
+       // allocate that many records, and get the data.
+       // There's a race—more records might be added between
+       // the two calls—so allocate a few extra records for safety
+       // and also try again if we're very unlucky.
+       // The loop should only execute one iteration in the common case.
+       var p []runtime.MemProfileRecord
+       n, ok := runtime.MemProfile(nil, false)
+       for {
+               // Allocate room for a slightly bigger profile,
+               // in case a few more entries have been added
+               // since the call to MemProfile.
+               p = make([]runtime.MemProfileRecord, n+50)
+               n, ok = runtime.MemProfile(p, false)
+               if ok {
+                       p = p[0:n]
+                       break
+               }
+               // Profile grew; try again.
+       }
+
+       var total runtime.MemProfileRecord
+       for i := range p {
+               r := &p[i]
+               total.AllocBytes += r.AllocBytes
+               total.AllocObjects += r.AllocObjects
+               total.FreeBytes += r.FreeBytes
+               total.FreeObjects += r.FreeObjects
+       }
+
+       // Technically the rate is MemProfileRate not 2*MemProfileRate,
+       // but early versions of the C++ heap profiler reported 2*MemProfileRate,
+       // so that's what pprof has come to expect.
+       b := bufio.NewWriter(w)
+       fmt.Fprintf(b, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
+               total.InUseObjects(), total.InUseBytes(),
+               total.AllocObjects, total.AllocBytes,
+               2*runtime.MemProfileRate)
+
+       for i := range p {
+               r := &p[i]
+               fmt.Fprintf(b, "%d: %d [%d: %d] @",
+                       r.InUseObjects(), r.InUseBytes(),
+                       r.AllocObjects, r.AllocBytes)
+               for _, pc := range r.Stack() {
+                       fmt.Fprintf(b, " %#x", pc)
+               }
+               fmt.Fprintf(b, "\n")
+       }
+
+       // Print memstats information too.
+       // Pprof will ignore, but useful for people.
+       s := &runtime.MemStats
+       fmt.Fprintf(b, "\n# runtime.MemStats\n")
+       fmt.Fprintf(b, "# Alloc = %d\n", s.Alloc)
+       fmt.Fprintf(b, "# TotalAlloc = %d\n", s.TotalAlloc)
+       fmt.Fprintf(b, "# Sys = %d\n", s.Sys)
+       fmt.Fprintf(b, "# Lookups = %d\n", s.Lookups)
+       fmt.Fprintf(b, "# Mallocs = %d\n", s.Mallocs)
+
+       fmt.Fprintf(b, "# HeapAlloc = %d\n", s.HeapAlloc)
+       fmt.Fprintf(b, "# HeapSys = %d\n", s.HeapSys)
+       fmt.Fprintf(b, "# HeapIdle = %d\n", s.HeapIdle)
+       fmt.Fprintf(b, "# HeapInuse = %d\n", s.HeapInuse)
+
+       fmt.Fprintf(b, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
+       fmt.Fprintf(b, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
+       fmt.Fprintf(b, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
+       fmt.Fprintf(b, "# MHeapMapSys = %d\n", s.MHeapMapSys)
+       fmt.Fprintf(b, "# BuckHashSys = %d\n", s.BuckHashSys)
+
+       fmt.Fprintf(b, "# NextGC = %d\n", s.NextGC)
+       fmt.Fprintf(b, "# PauseNs = %d\n", s.PauseNs)
+       fmt.Fprintf(b, "# NumGC = %d\n", s.NumGC)
+       fmt.Fprintf(b, "# EnableGC = %v\n", s.EnableGC)
+       fmt.Fprintf(b, "# DebugGC = %v\n", s.DebugGC)
+
+       fmt.Fprintf(b, "# BySize = Size * (Active = Mallocs - Frees)\n")
+       fmt.Fprintf(b, "# (Excluding large blocks.)\n")
+       for _, t := range s.BySize {
+               if t.Mallocs > 0 {
+                       fmt.Fprintf(b, "#   %d * (%d = %d - %d)\n", t.Size, t.Mallocs-t.Frees, t.Mallocs, t.Frees)
+               }
+       }
+       return b.Flush()
+}
diff --git a/libgo/go/runtime/sig.go b/libgo/go/runtime/sig.go
new file mode 100644 (file)
index 0000000..6d560b9
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// Sigrecv returns a bitmask of signals that have arrived since the last call to Sigrecv.
+// It blocks until at least one signal arrives.
+func Sigrecv() uint32
+
+// Signame returns a string describing the signal, or "" if the signal is unknown.
+func Signame(sig int32) string
+
+// Siginit enables receipt of signals via Sigrecv.  It should typically
+// be called during initialization.
+func Siginit()
diff --git a/libgo/go/runtime/softfloat64.go b/libgo/go/runtime/softfloat64.go
new file mode 100644 (file)
index 0000000..d9bbe5d
--- /dev/null
@@ -0,0 +1,498 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Software IEEE754 64-bit floating point.
+// Only referred to (and thus linked in) by arm port
+// and by gotest in this directory.
+
+package runtime
+
+const (
+       mantbits64 uint = 52
+       expbits64  uint = 11
+       bias64     = -1<<(expbits64-1) + 1
+
+       nan64 uint64 = (1<<expbits64-1)<<mantbits64 + 1
+       inf64 uint64 = (1<<expbits64 - 1) << mantbits64
+       neg64 uint64 = 1 << (expbits64 + mantbits64)
+
+       mantbits32 uint = 23
+       expbits32  uint = 8
+       bias32     = -1<<(expbits32-1) + 1
+
+       nan32 uint32 = (1<<expbits32-1)<<mantbits32 + 1
+       inf32 uint32 = (1<<expbits32 - 1) << mantbits32
+       neg32 uint32 = 1 << (expbits32 + mantbits32)
+)
+
+func funpack64(f uint64) (sign, mant uint64, exp int, inf, nan bool) {
+       sign = f & (1 << (mantbits64 + expbits64))
+       mant = f & (1<<mantbits64 - 1)
+       exp = int(f>>mantbits64) & (1<<expbits64 - 1)
+
+       switch exp {
+       case 1<<expbits64 - 1:
+               if mant != 0 {
+                       nan = true
+                       return
+               }
+               inf = true
+               return
+
+       case 0:
+               // denormalized
+               if mant != 0 {
+                       exp += bias64 + 1
+                       for mant < 1<<mantbits64 {
+                               mant <<= 1
+                               exp--
+                       }
+               }
+
+       default:
+               // add implicit top bit
+               mant |= 1 << mantbits64
+               exp += bias64
+       }
+       return
+}
+
+func funpack32(f uint32) (sign, mant uint32, exp int, inf, nan bool) {
+       sign = f & (1 << (mantbits32 + expbits32))
+       mant = f & (1<<mantbits32 - 1)
+       exp = int(f>>mantbits32) & (1<<expbits32 - 1)
+
+       switch exp {
+       case 1<<expbits32 - 1:
+               if mant != 0 {
+                       nan = true
+                       return
+               }
+               inf = true
+               return
+
+       case 0:
+               // denormalized
+               if mant != 0 {
+                       exp += bias32 + 1
+                       for mant < 1<<mantbits32 {
+                               mant <<= 1
+                               exp--
+                       }
+               }
+
+       default:
+               // add implicit top bit
+               mant |= 1 << mantbits32
+               exp += bias32
+       }
+       return
+}
+
+func fpack64(sign, mant uint64, exp int, trunc uint64) uint64 {
+       mant0, exp0, trunc0 := mant, exp, trunc
+       if mant == 0 {
+               return sign
+       }
+       for mant < 1<<mantbits64 {
+               mant <<= 1
+               exp--
+       }
+       for mant >= 4<<mantbits64 {
+               trunc |= mant & 1
+               mant >>= 1
+               exp++
+       }
+       if mant >= 2<<mantbits64 {
+               if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+                       mant++
+                       if mant >= 4<<mantbits64 {
+                               mant >>= 1
+                               exp++
+                       }
+               }
+               mant >>= 1
+               exp++
+       }
+       if exp >= 1<<expbits64-1+bias64 {
+               return sign ^ inf64
+       }
+       if exp < bias64+1 {
+               if exp < bias64-int(mantbits64) {
+                       return sign | 0
+               }
+               // repeat expecting denormal
+               mant, exp, trunc = mant0, exp0, trunc0
+               for exp < bias64 {
+                       trunc |= mant & 1
+                       mant >>= 1
+                       exp++
+               }
+               if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+                       mant++
+               }
+               mant >>= 1
+               exp++
+               if mant < 1<<mantbits64 {
+                       return sign | mant
+               }
+       }
+       return sign | uint64(exp-bias64)<<mantbits64 | mant&(1<<mantbits64-1)
+}
+
+func fpack32(sign, mant uint32, exp int, trunc uint32) uint32 {
+       mant0, exp0, trunc0 := mant, exp, trunc
+       if mant == 0 {
+               return sign
+       }
+       for mant < 1<<mantbits32 {
+               mant <<= 1
+               exp--
+       }
+       for mant >= 4<<mantbits32 {
+               trunc |= mant & 1
+               mant >>= 1
+               exp++
+       }
+       if mant >= 2<<mantbits32 {
+               if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+                       mant++
+                       if mant >= 4<<mantbits32 {
+                               mant >>= 1
+                               exp++
+                       }
+               }
+               mant >>= 1
+               exp++
+       }
+       if exp >= 1<<expbits32-1+bias32 {
+               return sign ^ inf32
+       }
+       if exp < bias32+1 {
+               if exp < bias32-int(mantbits32) {
+                       return sign | 0
+               }
+               // repeat expecting denormal
+               mant, exp, trunc = mant0, exp0, trunc0
+               for exp < bias32 {
+                       trunc |= mant & 1
+                       mant >>= 1
+                       exp++
+               }
+               if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+                       mant++
+               }
+               mant >>= 1
+               exp++
+               if mant < 1<<mantbits32 {
+                       return sign | mant
+               }
+       }
+       return sign | uint32(exp-bias32)<<mantbits32 | mant&(1<<mantbits32-1)
+}
+
+func fadd64(f, g uint64) uint64 {
+       fs, fm, fe, fi, fn := funpack64(f)
+       gs, gm, ge, gi, gn := funpack64(g)
+
+       // Special cases.
+       switch {
+       case fn || gn: // NaN + x or x + NaN = NaN
+               return nan64
+
+       case fi && gi && fs != gs: // +Inf + -Inf or -Inf + +Inf = NaN
+               return nan64
+
+       case fi: // ±Inf + g = ±Inf
+               return f
+
+       case gi: // f + ±Inf = ±Inf
+               return g
+
+       case fm == 0 && gm == 0 && fs != 0 && gs != 0: // -0 + -0 = -0
+               return f
+
+       case fm == 0: // 0 + g = g but 0 + -0 = +0
+               if gm == 0 {
+                       g ^= gs
+               }
+               return g
+
+       case gm == 0: // f + 0 = f
+               return f
+
+       }
+
+       if fe < ge || fe == ge && fm < gm {
+               f, g, fs, fm, fe, gs, gm, ge = g, f, gs, gm, ge, fs, fm, fe
+       }
+
+       shift := uint(fe - ge)
+       fm <<= 2
+       gm <<= 2
+       trunc := gm & (1<<shift - 1)
+       gm >>= shift
+       if fs == gs {
+               fm += gm
+       } else {
+               fm -= gm
+               if trunc != 0 {
+                       fm--
+               }
+       }
+       if fm == 0 {
+               fs = 0
+       }
+       return fpack64(fs, fm, fe-2, trunc)
+}
+
+func fsub64(f, g uint64) uint64 {
+       return fadd64(f, fneg64(g))
+}
+
+func fneg64(f uint64) uint64 {
+       return f ^ (1 << (mantbits64 + expbits64))
+}
+
+func fmul64(f, g uint64) uint64 {
+       fs, fm, fe, fi, fn := funpack64(f)
+       gs, gm, ge, gi, gn := funpack64(g)
+
+       // Special cases.
+       switch {
+       case fn || gn: // NaN * g or f * NaN = NaN
+               return nan64
+
+       case fi && gi: // Inf * Inf = Inf (with sign adjusted)
+               return f ^ gs
+
+       case fi && gm == 0, fm == 0 && gi: // 0 * Inf = Inf * 0 = NaN
+               return nan64
+
+       case fm == 0: // 0 * x = 0 (with sign adjusted)
+               return f ^ gs
+
+       case gm == 0: // x * 0 = 0 (with sign adjusted)
+               return g ^ fs
+       }
+
+       // 53-bit * 53-bit = 107- or 108-bit
+       lo, hi := mullu(fm, gm)
+       shift := mantbits64 - 1
+       trunc := lo & (1<<shift - 1)
+       mant := hi<<(64-shift) | lo>>shift
+       return fpack64(fs^gs, mant, fe+ge-1, trunc)
+}
+
+func fdiv64(f, g uint64) uint64 {
+       fs, fm, fe, fi, fn := funpack64(f)
+       gs, gm, ge, gi, gn := funpack64(g)
+
+       // Special cases.
+       switch {
+       case fn || gn: // NaN / g = f / NaN = NaN
+               return nan64
+
+       case fi && gi: // ±Inf / ±Inf = NaN
+               return nan64
+
+       case !fi && !gi && fm == 0 && gm == 0: // 0 / 0 = NaN
+               return nan64
+
+       case fi, !gi && gm == 0: // Inf / g = f / 0 = Inf
+               return fs ^ gs ^ inf64
+
+       case gi, fm == 0: // f / Inf = 0 / g = Inf
+               return fs ^ gs ^ 0
+       }
+       _, _, _, _ = fi, fn, gi, gn
+
+       // 53-bit<<54 / 53-bit = 53- or 54-bit.
+       shift := mantbits64 + 2
+       q, r := divlu(fm>>(64-shift), fm<<shift, gm)
+       return fpack64(fs^gs, q, fe-ge-2, r)
+}
+
+func f64to32(f uint64) uint32 {
+       fs, fm, fe, fi, fn := funpack64(f)
+       if fn {
+               return nan32
+       }
+       fs32 := uint32(fs >> 32)
+       if fi {
+               return fs32 ^ inf32
+       }
+       const d = mantbits64 - mantbits32 - 1
+       return fpack32(fs32, uint32(fm>>d), fe-1, uint32(fm&(1<<d-1)))
+}
+
+func f32to64(f uint32) uint64 {
+       const d = mantbits64 - mantbits32
+       fs, fm, fe, fi, fn := funpack32(f)
+       if fn {
+               return nan64
+       }
+       fs64 := uint64(fs) << 32
+       if fi {
+               return fs64 ^ inf64
+       }
+       return fpack64(fs64, uint64(fm)<<d, fe, 0)
+}
+
+func fcmp64(f, g uint64) (cmp int, isnan bool) {
+       fs, fm, _, fi, fn := funpack64(f)
+       gs, gm, _, gi, gn := funpack64(g)
+
+       switch {
+       case fn, gn: // flag NaN
+               return 0, true
+
+       case !fi && !gi && fm == 0 && gm == 0: // ±0 == ±0
+               return 0, false
+
+       case fs > gs: // f < 0, g > 0
+               return -1, false
+
+       case fs < gs: // f > 0, g < 0
+               return +1, false
+
+       // Same sign, not NaN.
+       // Can compare encodings directly now.
+       // Reverse for sign.
+       case fs == 0 && f < g, fs != 0 && f > g:
+               return -1, false
+
+       case fs == 0 && f > g, fs != 0 && f < g:
+               return +1, false
+       }
+
+       // f == g
+       return 0, false
+}
+
+func f64toint(f uint64) (val int64, ok bool) {
+       fs, fm, fe, fi, fn := funpack64(f)
+
+       switch {
+       case fi, fn: // NaN
+               return 0, false
+
+       case fe < -1: // f < 0.5
+               return 0, false
+
+       case fe > 63: // f >= 2^63
+               if fs != 0 && fm == 0 { // f == -2^63
+                       return -1 << 63, true
+               }
+               if fs != 0 {
+                       return 0, false
+               }
+               return 0, false
+       }
+
+       for fe > int(mantbits64) {
+               fe--
+               fm <<= 1
+       }
+       for fe < int(mantbits64) {
+               fe++
+               fm >>= 1
+       }
+       val = int64(fm)
+       if fs != 0 {
+               val = -val
+       }
+       return val, true
+}
+
+func fintto64(val int64) (f uint64) {
+       fs := uint64(val) & (1 << 63)
+       mant := uint64(val)
+       if fs != 0 {
+               mant = -mant
+       }
+       return fpack64(fs, mant, int(mantbits64), 0)
+}
+
+// 64x64 -> 128 multiply.
+// adapted from hacker's delight.
+func mullu(u, v uint64) (lo, hi uint64) {
+       const (
+               s    = 32
+               mask = 1<<s - 1
+       )
+       u0 := u & mask
+       u1 := u >> s
+       v0 := v & mask
+       v1 := v >> s
+       w0 := u0 * v0
+       t := u1*v0 + w0>>s
+       w1 := t & mask
+       w2 := t >> s
+       w1 += u0 * v1
+       return u * v, u1*v1 + w2 + w1>>s
+}
+
+// 128/64 -> 64 quotient, 64 remainder.
+// adapted from hacker's delight
+func divlu(u1, u0, v uint64) (q, r uint64) {
+       const b = 1 << 32
+
+       if u1 >= v {
+               return 1<<64 - 1, 1<<64 - 1
+       }
+
+       // s = nlz(v); v <<= s
+       s := uint(0)
+       for v&(1<<63) == 0 {
+               s++
+               v <<= 1
+       }
+
+       vn1 := v >> 32
+       vn0 := v & (1<<32 - 1)
+       un32 := u1<<s | u0>>(64-s)
+       un10 := u0 << s
+       un1 := un10 >> 32
+       un0 := un10 & (1<<32 - 1)
+       q1 := un32 / vn1
+       rhat := un32 - q1*vn1
+
+again1:
+       if q1 >= b || q1*vn0 > b*rhat+un1 {
+               q1--
+               rhat += vn1
+               if rhat < b {
+                       goto again1
+               }
+       }
+
+       un21 := un32*b + un1 - q1*v
+       q0 := un21 / vn1
+       rhat = un21 - q0*vn1
+
+again2:
+       if q0 >= b || q0*vn0 > b*rhat+un0 {
+               q0--
+               rhat += vn1
+               if rhat < b {
+                       goto again2
+               }
+       }
+
+       return q1*b + q0, (un21*b + un0 - q0*v) >> s
+}
+
+// callable from C
+
+func fadd64c(f, g uint64, ret *uint64)            { *ret = fadd64(f, g) }
+func fsub64c(f, g uint64, ret *uint64)            { *ret = fsub64(f, g) }
+func fmul64c(f, g uint64, ret *uint64)            { *ret = fmul64(f, g) }
+func fdiv64c(f, g uint64, ret *uint64)            { *ret = fdiv64(f, g) }
+func fneg64c(f uint64, ret *uint64)               { *ret = fneg64(f) }
+func f32to64c(f uint32, ret *uint64)              { *ret = f32to64(f) }
+func f64to32c(f uint64, ret *uint32)              { *ret = f64to32(f) }
+func fcmp64c(f, g uint64, ret *int, retnan *bool) { *ret, *retnan = fcmp64(f, g) }
+func fintto64c(val int64, ret *uint64)            { *ret = fintto64(val) }
+func f64tointc(f uint64, ret *int64, retok *bool) { *ret, *retok = f64toint(f) }
diff --git a/libgo/go/runtime/softfloat64_test.go b/libgo/go/runtime/softfloat64_test.go
new file mode 100644 (file)
index 0000000..fb7f3d3
--- /dev/null
@@ -0,0 +1,198 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+       "math"
+       "rand"
+       . "runtime"
+       "testing"
+)
+
+// turn uint64 op into float64 op
+func fop(f func(x, y uint64) uint64) func(x, y float64) float64 {
+       return func(x, y float64) float64 {
+               bx := math.Float64bits(x)
+               by := math.Float64bits(y)
+               return math.Float64frombits(f(bx, by))
+       }
+}
+
+func add(x, y float64) float64 { return x + y }
+func sub(x, y float64) float64 { return x - y }
+func mul(x, y float64) float64 { return x * y }
+func div(x, y float64) float64 { return x / y }
+
+func TestFloat64(t *testing.T) {
+       base := []float64{
+               0,
+               math.Copysign(0, -1),
+               -1,
+               1,
+               math.NaN(),
+               math.Inf(+1),
+               math.Inf(-1),
+               0.1,
+               1.5,
+               1.9999999999999998,     // all 1s mantissa
+               1.3333333333333333,     // 1.010101010101...
+               1.1428571428571428,     // 1.001001001001...
+               1.112536929253601e-308, // first normal
+               2,
+               4,
+               8,
+               16,
+               32,
+               64,
+               128,
+               256,
+               3,
+               12,
+               1234,
+               123456,
+               -0.1,
+               -1.5,
+               -1.9999999999999998,
+               -1.3333333333333333,
+               -1.1428571428571428,
+               -2,
+               -3,
+               1e-200,
+               1e-300,
+               1e-310,
+               5e-324,
+               1e-105,
+               1e-305,
+               1e+200,
+               1e+306,
+               1e+307,
+               1e+308,
+       }
+       all := make([]float64, 200)
+       copy(all, base)
+       for i := len(base); i < len(all); i++ {
+               all[i] = rand.NormFloat64()
+       }
+
+       test(t, "+", add, fop(Fadd64), all)
+       test(t, "-", sub, fop(Fsub64), all)
+       if GOARCH != "386" { // 386 is not precise!
+               test(t, "*", mul, fop(Fmul64), all)
+               test(t, "/", div, fop(Fdiv64), all)
+       }
+}
+
+// 64 -hw-> 32 -hw-> 64
+func trunc32(f float64) float64 {
+       return float64(float32(f))
+}
+
+// 64 -sw->32 -hw-> 64
+func to32sw(f float64) float64 {
+       return float64(math.Float32frombits(F64to32(math.Float64bits(f))))
+}
+
+// 64 -hw->32 -sw-> 64
+func to64sw(f float64) float64 {
+       return math.Float64frombits(F32to64(math.Float32bits(float32(f))))
+}
+
+// float64 -hw-> int64 -hw-> float64
+func hwint64(f float64) float64 {
+       return float64(int64(f))
+}
+
+// float64 -hw-> int32 -hw-> float64
+func hwint32(f float64) float64 {
+       return float64(int32(f))
+}
+
+// float64 -sw-> int64 -hw-> float64
+func toint64sw(f float64) float64 {
+       i, ok := F64toint(math.Float64bits(f))
+       if !ok {
+               // There's no right answer for out of range.
+               // Match the hardware to pass the test.
+               i = int64(f)
+       }
+       return float64(i)
+}
+
+// float64 -hw-> int64 -sw-> float64
+func fromint64sw(f float64) float64 {
+       return math.Float64frombits(Fintto64(int64(f)))
+}
+
+var nerr int
+
+func err(t *testing.T, format string, args ...interface{}) {
+       t.Errorf(format, args...)
+
+       // cut errors off after a while.
+       // otherwise we spend all our time
+       // allocating memory to hold the
+       // formatted output.
+       if nerr++; nerr >= 10 {
+               t.Fatal("too many errors")
+       }
+}
+
+func test(t *testing.T, op string, hw, sw func(float64, float64) float64, all []float64) {
+       for _, f := range all {
+               for _, g := range all {
+                       h := hw(f, g)
+                       s := sw(f, g)
+                       if !same(h, s) {
+                               err(t, "%g %s %g = sw %g, hw %g\n", f, op, g, s, h)
+                       }
+                       testu(t, "to32", trunc32, to32sw, h)
+                       testu(t, "to64", trunc32, to64sw, h)
+                       testu(t, "toint64", hwint64, toint64sw, h)
+                       testu(t, "fromint64", hwint64, fromint64sw, h)
+                       testcmp(t, f, h)
+                       testcmp(t, h, f)
+                       testcmp(t, g, h)
+                       testcmp(t, h, g)
+               }
+       }
+}
+
+func testu(t *testing.T, op string, hw, sw func(float64) float64, v float64) {
+       h := hw(v)
+       s := sw(v)
+       if !same(h, s) {
+               err(t, "%s %g = sw %g, hw %g\n", op, v, s, h)
+       }
+}
+
+func hwcmp(f, g float64) (cmp int, isnan bool) {
+       switch {
+       case f < g:
+               return -1, false
+       case f > g:
+               return +1, false
+       case f == g:
+               return 0, false
+       }
+       return 0, true // must be NaN
+}
+
+func testcmp(t *testing.T, f, g float64) {
+       hcmp, hisnan := hwcmp(f, g)
+       scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g))
+       if hcmp != scmp || hisnan != sisnan {
+               err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan)
+       }
+}
+
+func same(f, g float64) bool {
+       if math.IsNaN(f) && math.IsNaN(g) {
+               return true
+       }
+       if math.Copysign(1, f) != math.Copysign(1, g) {
+               return false
+       }
+       return f == g
+}
diff --git a/libgo/go/runtime/type.go b/libgo/go/runtime/type.go
new file mode 100644 (file)
index 0000000..a16809f
--- /dev/null
@@ -0,0 +1,206 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Runtime type representation.
+ *
+ * The following files know the exact layout of these
+ * data structures and must be kept in sync with this file:
+ *
+ *     ../../cmd/gc/reflect.c
+ *     ../../cmd/ld/dwarf.c
+ *     ../reflect/type.go
+ *     type.h
+ */
+
+package runtime
+
+import "unsafe"
+
+// All types begin with a few common fields needed for
+// the interface runtime.
+type commonType struct {
+       Kind       uint8   // type kind
+       align      uint8   // alignment of variable with this type
+       fieldAlign uint8   // alignment of struct field with this type
+       size       uintptr // size in bytes
+       hash       uint32  // hash of type; avoids computation in hash tables
+
+       hashfn  func(unsafe.Pointer, uintptr) uintptr              // hash function
+       equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool // equality function
+
+       string        *string // string form; unnecessary  but undeniably useful
+       *uncommonType         // (relatively) uncommon fields
+}
+
+// Values for commonType.kind.
+const (
+       kindBool = 1 + iota
+       kindInt
+       kindInt8
+       kindInt16
+       kindInt32
+       kindInt64
+       kindUint
+       kindUint8
+       kindUint16
+       kindUint32
+       kindUint64
+       kindUintptr
+       kindFloat
+       kindFloat32
+       kindFloat64
+       kindComplex
+       kindComplex64
+       kindComplex128
+       kindArray
+       kindChan
+       kindFunc
+       kindInterface
+       kindMap
+       kindPtr
+       kindSlice
+       kindString
+       kindStruct
+       kindUnsafePointer
+
+       // Not currently generated by gccgo.
+       // kindNoPointers = 1 << 7 // OR'ed into kind
+)
+
+// Externally visible name.
+type Type commonType
+
+// Method on non-interface type
+type method struct {
+       name    *string        // name of method
+       pkgPath *string        // nil for exported Names; otherwise import path
+       mtyp    *Type          // method type (without receiver)
+       typ     *Type          // .(*FuncType) underneath (with receiver)
+       tfn     unsafe.Pointer // fn used for normal method call
+}
+
+// uncommonType is present only for types with names or methods
+// (if T is a named type, the uncommonTypes for T and *T have methods).
+// Using a pointer to this struct reduces the overall size required
+// to describe an unnamed type with no methods.
+type uncommonType struct {
+       name    *string  // name of type
+       pkgPath *string  // import path; nil for built-in types like int, string
+       methods []method // methods associated with type
+}
+
+// BoolType represents a boolean type.
+type BoolType commonType
+
+// FloatType represents a float type.
+type FloatType commonType
+
+// ComplexType represents a complex type.
+type ComplexType commonType
+
+// IntType represents an int type.
+type IntType commonType
+
+// UintType represents a uint type.
+type UintType commonType
+
+// StringType represents a string type.
+type StringType commonType
+
+// UintptrType represents a uintptr type.
+type UintptrType commonType
+
+// UnsafePointerType represents an unsafe.Pointer type.
+type UnsafePointerType commonType
+
+// ArrayType represents a fixed array type.
+type ArrayType struct {
+       commonType
+       elem *Type // array element type
+       len  uintptr
+}
+
+// SliceType represents a slice type.
+type SliceType struct {
+       commonType
+       elem *Type // slice element type
+}
+
+// ChanDir represents a channel type's direction.
+type ChanDir int
+
+const (
+       RecvDir ChanDir             = 1 << iota // <-chan
+       SendDir                                 // chan<-
+       BothDir = RecvDir | SendDir             // chan
+)
+
+// ChanType represents a channel type.
+type ChanType struct {
+       commonType
+       elem *Type   // channel element type
+       dir  uintptr // channel direction (ChanDir)
+}
+
+// FuncType represents a function type.
+type FuncType struct {
+       commonType
+       dotdotdot bool    // last input parameter is ...
+       in        []*Type // input parameter types
+       out       []*Type // output parameter types
+}
+
+// Method on interface type
+type imethod struct {
+       name    *string // name of method
+       pkgPath *string // nil for exported Names; otherwise import path
+       typ     *Type   // .(*FuncType) underneath
+}
+
+// InterfaceType represents an interface type.
+type InterfaceType struct {
+       commonType
+       methods []imethod // sorted by hash
+}
+
+// MapType represents a map type.
+type MapType struct {
+       commonType
+       key  *Type // map key type
+       elem *Type // map element (value) type
+}
+
+// PtrType represents a pointer type.
+type PtrType struct {
+       commonType
+       elem *Type // pointer element (pointed at) type
+}
+
+// Struct field
+type structField struct {
+       name    *string // nil for embedded fields
+       pkgPath *string // nil for exported Names; otherwise import path
+       typ     *Type   // type of field
+       tag     *string // nil if no tag
+       offset  uintptr // byte offset of field within struct
+}
+
+// StructType represents a struct type.
+type StructType struct {
+       commonType
+       fields []structField // sorted by offset
+}
+
+/*
+ * Must match iface.c:/Itab and compilers.
+ */
+type Itable struct {
+       Itype  *Type // (*tab.inter).(*InterfaceType) is the interface type
+       Type   *Type
+       link   *Itable
+       bad    int32
+       unused int32
+       Fn     [100000]uintptr // bigger than we'll ever see
+}
diff --git a/libgo/go/scanner/scanner.go b/libgo/go/scanner/scanner.go
new file mode 100644 (file)
index 0000000..11aa9f4
--- /dev/null
@@ -0,0 +1,644 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A scanner and tokenizer for UTF-8-encoded text.  Takes an io.Reader
+// providing the source, which then can be tokenized through repeated calls
+// to the Scan function.  For compatibility with existing tools, the NUL
+// character is not allowed (implementation restriction).
+//
+// By default, a Scanner skips white space and Go comments and recognizes all
+// literals as defined by the Go language specification.  It may be
+// customized to recognize only a subset of those literals and to recognize
+// different white space characters.
+//
+// Basic usage pattern:
+//
+//     var s scanner.Scanner
+//     s.Init(src)
+//     tok := s.Scan()
+//     for tok != scanner.EOF {
+//             // do something with tok
+//             tok = s.Scan()
+//     }
+//
+package scanner
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "os"
+       "unicode"
+       "utf8"
+)
+
+
+// A source position is represented by a Position value.
+// A position is valid if Line > 0.
+type Position struct {
+       Filename string // filename, if any
+       Offset   int    // byte offset, starting at 0
+       Line     int    // line number, starting at 1
+       Column   int    // column number, starting at 0 (character count per line)
+}
+
+
+// IsValid returns true if the position is valid.
+func (pos *Position) IsValid() bool { return pos.Line > 0 }
+
+
+func (pos Position) String() string {
+       s := pos.Filename
+       if pos.IsValid() {
+               if s != "" {
+                       s += ":"
+               }
+               s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
+       }
+       if s == "" {
+               s = "???"
+       }
+       return s
+}
+
+
+// Predefined mode bits to control recognition of tokens. For instance,
+// to configure a Scanner such that it only recognizes (Go) identifiers,
+// integers, and skips comments, set the Scanner's Mode field to:
+//
+//     ScanIdents | ScanInts | SkipComments
+//
+const (
+       ScanIdents     = 1 << -Ident
+       ScanInts       = 1 << -Int
+       ScanFloats     = 1 << -Float // includes Ints
+       ScanChars      = 1 << -Char
+       ScanStrings    = 1 << -String
+       ScanRawStrings = 1 << -RawString
+       ScanComments   = 1 << -Comment
+       SkipComments   = 1 << -skipComment // if set with ScanComments, comments become white space
+       GoTokens       = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments
+)
+
+
+// The result of Scan is one of the following tokens or a Unicode character.
+const (
+       EOF = -(iota + 1)
+       Ident
+       Int
+       Float
+       Char
+       String
+       RawString
+       Comment
+       skipComment
+)
+
+
+var tokenString = map[int]string{
+       EOF:       "EOF",
+       Ident:     "Ident",
+       Int:       "Int",
+       Float:     "Float",
+       Char:      "Char",
+       String:    "String",
+       RawString: "RawString",
+       Comment:   "Comment",
+}
+
+
+// TokenString returns a (visible) string for a token or Unicode character.
+func TokenString(tok int) string {
+       if s, found := tokenString[tok]; found {
+               return s
+       }
+       return fmt.Sprintf("U+%04X", tok)
+}
+
+
+// GoWhitespace is the default value for the Scanner's Whitespace field.
+// Its value selects Go's white space characters.
+const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '
+
+
+const bufLen = 1024 // at least utf8.UTFMax
+
+// A Scanner implements reading of Unicode characters and tokens from an io.Reader.
+type Scanner struct {
+       // Input
+       src io.Reader
+
+       // Source buffer
+       srcBuf [bufLen + 1]byte // +1 for sentinel for common case of s.next()
+       srcPos int              // reading position (srcBuf index)
+       srcEnd int              // source end (srcBuf index)
+
+       // Source position
+       srcBufOffset int // byte offset of srcBuf[0] in source
+       line         int // newline count + 1
+       column       int // character count on line
+
+       // Token text buffer
+       // Typically, token text is stored completely in srcBuf, but in general
+       // the token text's head may be buffered in tokBuf while the token text's
+       // tail is stored in srcBuf.
+       tokBuf bytes.Buffer // token text head that is not in srcBuf anymore
+       tokPos int          // token text tail position (srcBuf index)
+       tokEnd int          // token text tail end (srcBuf index)
+
+       // One character look-ahead
+       ch int // character before current srcPos
+
+       // Error is called for each error encountered. If no Error
+       // function is set, the error is reported to os.Stderr.
+       Error func(s *Scanner, msg string)
+
+       // ErrorCount is incremented by one for each error encountered.
+       ErrorCount int
+
+       // The Mode field controls which tokens are recognized. For instance,
+       // to recognize Ints, set the ScanInts bit in Mode. The field may be
+       // changed at any time.
+       Mode uint
+
+       // The Whitespace field controls which characters are recognized
+       // as white space. To recognize a character ch <= ' ' as white space,
+       // set the ch'th bit in Whitespace (the Scanner's behavior is undefined
+       // for values ch > ' '). The field may be changed at any time.
+       Whitespace uint64
+
+       // Current token position. The Offset, Line, and Column fields
+       // are set by Scan(); the Filename field is left untouched by the
+       // Scanner.
+       Position
+}
+
+
+// Init initializes a Scanner with a new source and returns itself.
+// Error is set to nil, ErrorCount is set to 0, Mode is set to GoTokens,
+// and Whitespace is set to GoWhitespace.
+func (s *Scanner) Init(src io.Reader) *Scanner {
+       s.src = src
+
+       // initialize source buffer
+       s.srcBuf[0] = utf8.RuneSelf // sentinel
+       s.srcPos = 0
+       s.srcEnd = 0
+
+       // initialize source position
+       s.srcBufOffset = 0
+       s.line = 1
+       s.column = 0
+
+       // initialize token text buffer
+       s.tokPos = -1
+
+       // initialize one character look-ahead
+       s.ch = s.next()
+
+       // initialize public fields
+       s.Error = nil
+       s.ErrorCount = 0
+       s.Mode = GoTokens
+       s.Whitespace = GoWhitespace
+
+       return s
+}
+
+
+// next reads and returns the next Unicode character. It is designed such
+// that only a minimal amount of work needs to be done in the common ASCII
+// case (one test to check for both ASCII and end-of-buffer, and one test
+// to check for newlines).
+func (s *Scanner) next() int {
+       ch := int(s.srcBuf[s.srcPos])
+
+       if ch >= utf8.RuneSelf {
+               // uncommon case: not ASCII or not enough bytes
+               for s.srcPos+utf8.UTFMax > s.srcEnd && !utf8.FullRune(s.srcBuf[s.srcPos:s.srcEnd]) {
+                       // not enough bytes: read some more, but first
+                       // save away token text if any
+                       if s.tokPos >= 0 {
+                               s.tokBuf.Write(s.srcBuf[s.tokPos:s.srcPos])
+                               s.tokPos = 0
+                       }
+                       // move unread bytes to beginning of buffer
+                       copy(s.srcBuf[0:], s.srcBuf[s.srcPos:s.srcEnd])
+                       s.srcBufOffset += s.srcPos
+                       // read more bytes
+                       i := s.srcEnd - s.srcPos
+                       n, err := s.src.Read(s.srcBuf[i:bufLen])
+                       s.srcEnd = i + n
+                       s.srcPos = 0
+                       s.srcBuf[s.srcEnd] = utf8.RuneSelf // sentinel
+                       if err != nil {
+                               if s.srcEnd == 0 {
+                                       return EOF
+                               }
+                               if err != os.EOF {
+                                       s.error(err.String())
+                                       break
+                               }
+                       }
+               }
+               // at least one byte
+               ch = int(s.srcBuf[s.srcPos])
+               if ch >= utf8.RuneSelf {
+                       // uncommon case: not ASCII
+                       var width int
+                       ch, width = utf8.DecodeRune(s.srcBuf[s.srcPos:s.srcEnd])
+                       if ch == utf8.RuneError && width == 1 {
+                               s.error("illegal UTF-8 encoding")
+                       }
+                       s.srcPos += width - 1
+               }
+       }
+
+       s.srcPos++
+       s.column++
+       switch ch {
+       case 0:
+               // implementation restriction for compatibility with other tools
+               s.error("illegal character NUL")
+       case '\n':
+               s.line++
+               s.column = 0
+       }
+
+       return ch
+}
+
+
+// Next reads and returns the next Unicode character.
+// It returns EOF at the end of the source. It reports
+// a read error by calling s.Error, if set, or else
+// prints an error message to os.Stderr. Next does not
+// update the Scanner's Position field; use Pos() to
+// get the current position.
+func (s *Scanner) Next() int {
+       s.tokPos = -1 // don't collect token text
+       ch := s.ch
+       s.ch = s.next()
+       return ch
+}
+
+
+// Peek returns the next Unicode character in the source without advancing
+// the scanner. It returns EOF if the scanner's position is at the last
+// character of the source.
+func (s *Scanner) Peek() int {
+       return s.ch
+}
+
+
+func (s *Scanner) error(msg string) {
+       s.ErrorCount++
+       if s.Error != nil {
+               s.Error(s, msg)
+               return
+       }
+       fmt.Fprintf(os.Stderr, "%s: %s", s.Position, msg)
+}
+
+
+func (s *Scanner) scanIdentifier() int {
+       ch := s.next() // read character after first '_' or letter
+       for ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch) {
+               ch = s.next()
+       }
+       return ch
+}
+
+
+func digitVal(ch int) int {
+       switch {
+       case '0' <= ch && ch <= '9':
+               return ch - '0'
+       case 'a' <= ch && ch <= 'f':
+               return ch - 'a' + 10
+       case 'A' <= ch && ch <= 'F':
+               return ch - 'A' + 10
+       }
+       return 16 // larger than any legal digit val
+}
+
+
+func isDecimal(ch int) bool { return '0' <= ch && ch <= '9' }
+
+
+func (s *Scanner) scanMantissa(ch int) int {
+       for isDecimal(ch) {
+               ch = s.next()
+       }
+       return ch
+}
+
+
+func (s *Scanner) scanFraction(ch int) int {
+       if ch == '.' {
+               ch = s.scanMantissa(s.next())
+       }
+       return ch
+}
+
+
+func (s *Scanner) scanExponent(ch int) int {
+       if ch == 'e' || ch == 'E' {
+               ch = s.next()
+               if ch == '-' || ch == '+' {
+                       ch = s.next()
+               }
+               ch = s.scanMantissa(ch)
+       }
+       return ch
+}
+
+
+func (s *Scanner) scanNumber(ch int) (int, int) {
+       // isDecimal(ch)
+       if ch == '0' {
+               // int or float
+               ch = s.next()
+               if ch == 'x' || ch == 'X' {
+                       // hexadecimal int
+                       ch = s.next()
+                       for digitVal(ch) < 16 {
+                               ch = s.next()
+                       }
+               } else {
+                       // octal int or float
+                       seenDecimalDigit := false
+                       for isDecimal(ch) {
+                               if ch > '7' {
+                                       seenDecimalDigit = true
+                               }
+                               ch = s.next()
+                       }
+                       if s.Mode&ScanFloats != 0 && (ch == '.' || ch == 'e' || ch == 'E') {
+                               // float
+                               ch = s.scanFraction(ch)
+                               ch = s.scanExponent(ch)
+                               return Float, ch
+                       }
+                       // octal int
+                       if seenDecimalDigit {
+                               s.error("illegal octal number")
+                       }
+               }
+               return Int, ch
+       }
+       // decimal int or float
+       ch = s.scanMantissa(ch)
+       if s.Mode&ScanFloats != 0 && (ch == '.' || ch == 'e' || ch == 'E') {
+               // float
+               ch = s.scanFraction(ch)
+               ch = s.scanExponent(ch)
+               return Float, ch
+       }
+       return Int, ch
+}
+
+
+func (s *Scanner) scanDigits(ch, base, n int) int {
+       for n > 0 && digitVal(ch) < base {
+               ch = s.next()
+               n--
+       }
+       if n > 0 {
+               s.error("illegal char escape")
+       }
+       return ch
+}
+
+
+func (s *Scanner) scanEscape(quote int) int {
+       ch := s.next() // read character after '/'
+       switch ch {
+       case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
+               // nothing to do
+               ch = s.next()
+       case '0', '1', '2', '3', '4', '5', '6', '7':
+               ch = s.scanDigits(ch, 8, 3)
+       case 'x':
+               ch = s.scanDigits(s.next(), 16, 2)
+       case 'u':
+               ch = s.scanDigits(s.next(), 16, 4)
+       case 'U':
+               ch = s.scanDigits(s.next(), 16, 8)
+       default:
+               s.error("illegal char escape")
+       }
+       return ch
+}
+
+
+func (s *Scanner) scanString(quote int) (n int) {
+       ch := s.next() // read character after quote
+       for ch != quote {
+               if ch == '\n' || ch < 0 {
+                       s.error("literal not terminated")
+                       return
+               }
+               if ch == '\\' {
+                       ch = s.scanEscape(quote)
+               } else {
+                       ch = s.next()
+               }
+               n++
+       }
+       return
+}
+
+
+func (s *Scanner) scanRawString() {
+       ch := s.next() // read character after '`'
+       for ch != '`' {
+               if ch < 0 {
+                       s.error("literal not terminated")
+                       return
+               }
+               ch = s.next()
+       }
+}
+
+
+func (s *Scanner) scanChar() {
+       if s.scanString('\'') != 1 {
+               s.error("illegal char literal")
+       }
+}
+
+
+func (s *Scanner) scanLineComment() {
+       ch := s.next() // read character after "//"
+       for ch != '\n' {
+               if ch < 0 {
+                       s.error("comment not terminated")
+                       return
+               }
+               ch = s.next()
+       }
+}
+
+
+func (s *Scanner) scanGeneralComment() {
+       ch := s.next() // read character after "/*"
+       for {
+               if ch < 0 {
+                       s.error("comment not terminated")
+                       return
+               }
+               ch0 := ch
+               ch = s.next()
+               if ch0 == '*' && ch == '/' {
+                       break
+               }
+       }
+}
+
+
+func (s *Scanner) scanComment(ch int) {
+       // ch == '/' || ch == '*'
+       if ch == '/' {
+               s.scanLineComment()
+               return
+       }
+       s.scanGeneralComment()
+}
+
+
+// Scan reads the next token or Unicode character from source and returns it.
+// It only recognizes tokens t for which the respective Mode bit (1<<-t) is set.
+// It returns EOF at the end of the source. It reports scanner errors (read and
+// token errors) by calling s.Error, if set; otherwise it prints an error message
+// to os.Stderr.
+func (s *Scanner) Scan() int {
+       ch := s.ch
+
+       // reset token text position
+       s.tokPos = -1
+
+redo:
+       // skip white space
+       for s.Whitespace&(1<<uint(ch)) != 0 {
+               ch = s.next()
+       }
+
+       // start collecting token text
+       s.tokBuf.Reset()
+       s.tokPos = s.srcPos - 1
+
+       // set token position
+       s.Offset = s.srcBufOffset + s.tokPos
+       s.Line = s.line
+       s.Column = s.column
+
+       // determine token value
+       tok := ch
+       switch {
+       case unicode.IsLetter(ch) || ch == '_':
+               if s.Mode&ScanIdents != 0 {
+                       tok = Ident
+                       ch = s.scanIdentifier()
+               } else {
+                       ch = s.next()
+               }
+       case isDecimal(ch):
+               if s.Mode&(ScanInts|ScanFloats) != 0 {
+                       tok, ch = s.scanNumber(ch)
+               } else {
+                       ch = s.next()
+               }
+       default:
+               switch ch {
+               case '"':
+                       if s.Mode&ScanStrings != 0 {
+                               s.scanString('"')
+                               tok = String
+                       }
+                       ch = s.next()
+               case '\'':
+                       if s.Mode&ScanChars != 0 {
+                               s.scanChar()
+                               tok = Char
+                       }
+                       ch = s.next()
+               case '.':
+                       ch = s.next()
+                       if isDecimal(ch) && s.Mode&ScanFloats != 0 {
+                               tok = Float
+                               ch = s.scanMantissa(ch)
+                               ch = s.scanExponent(ch)
+                       }
+               case '/':
+                       ch = s.next()
+                       if (ch == '/' || ch == '*') && s.Mode&ScanComments != 0 {
+                               if s.Mode&SkipComments != 0 {
+                                       s.tokPos = -1 // don't collect token text
+                                       s.scanComment(ch)
+                                       ch = s.next()
+                                       goto redo
+                               }
+                               s.scanComment(ch)
+                               tok = Comment
+                               ch = s.next()
+                       }
+               case '`':
+                       if s.Mode&ScanRawStrings != 0 {
+                               s.scanRawString()
+                               tok = String
+                       }
+                       ch = s.next()
+               default:
+                       ch = s.next()
+               }
+       }
+
+       // end of token text
+       s.tokEnd = s.srcPos - 1
+
+       s.ch = ch
+       return tok
+}
+
+
+// Position returns the current source position. If called before Next()
+// or Scan(), it returns the position of the next Unicode character or token
+// returned by these functions. If called afterwards, it returns the position
+// immediately after the last character of the most recent token or character
+// scanned.
+func (s *Scanner) Pos() Position {
+       return Position{
+               s.Filename,
+               s.srcBufOffset + s.srcPos - 1,
+               s.line,
+               s.column,
+       }
+}
+
+
+// TokenText returns the string corresponding to the most recently scanned token.
+// Valid after calling Scan().
+func (s *Scanner) TokenText() string {
+       if s.tokPos < 0 {
+               // no token text
+               return ""
+       }
+
+       if s.tokEnd < 0 {
+               // if EOF was reached, s.tokEnd is set to -1 (s.srcPos == 0)
+               s.tokEnd = s.tokPos
+       }
+
+       if s.tokBuf.Len() == 0 {
+               // common case: the entire token text is still in srcBuf
+               return string(s.srcBuf[s.tokPos:s.tokEnd])
+       }
+
+       // part of the token text was saved in tokBuf: save the rest in
+       // tokBuf as well and return its content
+       s.tokBuf.Write(s.srcBuf[s.tokPos:s.tokEnd])
+       s.tokPos = s.tokEnd // ensure idempotency of TokenText() call
+       return s.tokBuf.String()
+}
diff --git a/libgo/go/scanner/scanner_test.go b/libgo/go/scanner/scanner_test.go
new file mode 100644 (file)
index 0000000..506f434
--- /dev/null
@@ -0,0 +1,482 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package scanner
+
+import (
+       "bytes"
+       "fmt"
+       "os"
+       "strings"
+       "testing"
+)
+
+
+// A StringReader delivers its data one string segment at a time via Read.
+type StringReader struct {
+       data []string
+       step int
+}
+
+
+func (r *StringReader) Read(p []byte) (n int, err os.Error) {
+       if r.step < len(r.data) {
+               s := r.data[r.step]
+               n = copy(p, s)
+               r.step++
+       } else {
+               err = os.EOF
+       }
+       return
+}
+
+
+func readRuneSegments(t *testing.T, segments []string) {
+       got := ""
+       want := strings.Join(segments, "")
+       s := new(Scanner).Init(&StringReader{data: segments})
+       for {
+               ch := s.Next()
+               if ch == EOF {
+                       break
+               }
+               got += string(ch)
+       }
+       if got != want {
+               t.Errorf("segments=%v got=%s want=%s", segments, got, want)
+       }
+}
+
+
+var segmentList = [][]string{
+       {},
+       {""},
+       {"日", "本語"},
+       {"\u65e5", "\u672c", "\u8a9e"},
+       {"\U000065e5", " ", "\U0000672c", "\U00008a9e"},
+       {"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
+       {"Hello", ", ", "World", "!"},
+       {"Hello", ", ", "", "World", "!"},
+}
+
+
+func TestNext(t *testing.T) {
+       for _, s := range segmentList {
+               readRuneSegments(t, s)
+       }
+}
+
+
+type token struct {
+       tok  int
+       text string
+}
+
+var f100 = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+
+var tokenList = []token{
+       {Comment, "// line comments\n"},
+       {Comment, "//\n"},
+       {Comment, "////\n"},
+       {Comment, "// comment\n"},
+       {Comment, "// /* comment */\n"},
+       {Comment, "// // comment //\n"},
+       {Comment, "//" + f100 + "\n"},
+
+       {Comment, "// general comments\n"},
+       {Comment, "/**/"},
+       {Comment, "/***/"},
+       {Comment, "/* comment */"},
+       {Comment, "/* // comment */"},
+       {Comment, "/* /* comment */"},
+       {Comment, "/*\n comment\n*/"},
+       {Comment, "/*" + f100 + "*/"},
+
+       {Comment, "// identifiers\n"},
+       {Ident, "a"},
+       {Ident, "a0"},
+       {Ident, "foobar"},
+       {Ident, "abc123"},
+       {Ident, "LGTM"},
+       {Ident, "_"},
+       {Ident, "_abc123"},
+       {Ident, "abc123_"},
+       {Ident, "_abc_123_"},
+       {Ident, "_äöü"},
+       {Ident, "_本"},
+       // TODO for unknown reasons these fail when checking the literals
+       /*
+               token{Ident, "äöü"},
+               token{Ident, "本"},
+       */
+       {Ident, "a۰۱۸"},
+       {Ident, "foo६४"},
+       {Ident, "bar9876"},
+       {Ident, f100},
+
+       {Comment, "// decimal ints\n"},
+       {Int, "0"},
+       {Int, "1"},
+       {Int, "9"},
+       {Int, "42"},
+       {Int, "1234567890"},
+
+       {Comment, "// octal ints\n"},
+       {Int, "00"},
+       {Int, "01"},
+       {Int, "07"},
+       {Int, "042"},
+       {Int, "01234567"},
+
+       {Comment, "// hexadecimal ints\n"},
+       {Int, "0x0"},
+       {Int, "0x1"},
+       {Int, "0xf"},
+       {Int, "0x42"},
+       {Int, "0x123456789abcDEF"},
+       {Int, "0x" + f100},
+       {Int, "0X0"},
+       {Int, "0X1"},
+       {Int, "0XF"},
+       {Int, "0X42"},
+       {Int, "0X123456789abcDEF"},
+       {Int, "0X" + f100},
+
+       {Comment, "// floats\n"},
+       {Float, "0."},
+       {Float, "1."},
+       {Float, "42."},
+       {Float, "01234567890."},
+       {Float, ".0"},
+       {Float, ".1"},
+       {Float, ".42"},
+       {Float, ".0123456789"},
+       {Float, "0.0"},
+       {Float, "1.0"},
+       {Float, "42.0"},
+       {Float, "01234567890.0"},
+       {Float, "0e0"},
+       {Float, "1e0"},
+       {Float, "42e0"},
+       {Float, "01234567890e0"},
+       {Float, "0E0"},
+       {Float, "1E0"},
+       {Float, "42E0"},
+       {Float, "01234567890E0"},
+       {Float, "0e+10"},
+       {Float, "1e-10"},
+       {Float, "42e+10"},
+       {Float, "01234567890e-10"},
+       {Float, "0E+10"},
+       {Float, "1E-10"},
+       {Float, "42E+10"},
+       {Float, "01234567890E-10"},
+
+       {Comment, "// chars\n"},
+       {Char, `' '`},
+       {Char, `'a'`},
+       {Char, `'本'`},
+       {Char, `'\a'`},
+       {Char, `'\b'`},
+       {Char, `'\f'`},
+       {Char, `'\n'`},
+       {Char, `'\r'`},
+       {Char, `'\t'`},
+       {Char, `'\v'`},
+       {Char, `'\''`},
+       {Char, `'\000'`},
+       {Char, `'\777'`},
+       {Char, `'\x00'`},
+       {Char, `'\xff'`},
+       {Char, `'\u0000'`},
+       {Char, `'\ufA16'`},
+       {Char, `'\U00000000'`},
+       {Char, `'\U0000ffAB'`},
+
+       {Comment, "// strings\n"},
+       {String, `" "`},
+       {String, `"a"`},
+       {String, `"本"`},
+       {String, `"\a"`},
+       {String, `"\b"`},
+       {String, `"\f"`},
+       {String, `"\n"`},
+       {String, `"\r"`},
+       {String, `"\t"`},
+       {String, `"\v"`},
+       {String, `"\""`},
+       {String, `"\000"`},
+       {String, `"\777"`},
+       {String, `"\x00"`},
+       {String, `"\xff"`},
+       {String, `"\u0000"`},
+       {String, `"\ufA16"`},
+       {String, `"\U00000000"`},
+       {String, `"\U0000ffAB"`},
+       {String, `"` + f100 + `"`},
+
+       {Comment, "// raw strings\n"},
+       {String, "``"},
+       {String, "`\\`"},
+       {String, "`" + "\n\n/* foobar */\n\n" + "`"},
+       {String, "`" + f100 + "`"},
+
+       {Comment, "// individual characters\n"},
+       // NUL character is not allowed
+       {'\x01', "\x01"},
+       {' ' - 1, string(' ' - 1)},
+       {'+', "+"},
+       {'/', "/"},
+       {'.', "."},
+       {'~', "~"},
+       {'(', "("},
+}
+
+
+func makeSource(pattern string) *bytes.Buffer {
+       var buf bytes.Buffer
+       for _, k := range tokenList {
+               fmt.Fprintf(&buf, pattern, k.text)
+       }
+       return &buf
+}
+
+
+func checkTok(t *testing.T, s *Scanner, line, got, want int, text string) {
+       if got != want {
+               t.Fatalf("tok = %s, want %s for %q", TokenString(got), TokenString(want), text)
+       }
+       if s.Line != line {
+               t.Errorf("line = %d, want %d for %q", s.Line, line, text)
+       }
+       stext := s.TokenText()
+       if stext != text {
+               t.Errorf("text = %q, want %q", stext, text)
+       } else {
+               // check idempotency of TokenText() call
+               stext = s.TokenText()
+               if stext != text {
+                       t.Errorf("text = %q, want %q (idempotency check)", stext, text)
+               }
+       }
+}
+
+
+func countNewlines(s string) int {
+       n := 0
+       for _, ch := range s {
+               if ch == '\n' {
+                       n++
+               }
+       }
+       return n
+}
+
+
+func testScan(t *testing.T, mode uint) {
+       s := new(Scanner).Init(makeSource(" \t%s\t\n\r"))
+       s.Mode = mode
+       tok := s.Scan()
+       line := 1
+       for _, k := range tokenList {
+               if mode&SkipComments == 0 || k.tok != Comment {
+                       checkTok(t, s, line, tok, k.tok, k.text)
+                       tok = s.Scan()
+               }
+               line += countNewlines(k.text) + 1 // each token is on a new line
+       }
+       checkTok(t, s, line, tok, -1, "")
+}
+
+
+func TestScan(t *testing.T) {
+       testScan(t, GoTokens)
+       testScan(t, GoTokens&^SkipComments)
+}
+
+
+func TestPosition(t *testing.T) {
+       src := makeSource("\t\t\t\t%s\n")
+       s := new(Scanner).Init(src)
+       s.Mode = GoTokens &^ SkipComments
+       s.Scan()
+       pos := Position{"", 4, 1, 5}
+       for _, k := range tokenList {
+               if s.Offset != pos.Offset {
+                       t.Errorf("offset = %d, want %d for %q", s.Offset, pos.Offset, k.text)
+               }
+               if s.Line != pos.Line {
+                       t.Errorf("line = %d, want %d for %q", s.Line, pos.Line, k.text)
+               }
+               if s.Column != pos.Column {
+                       t.Errorf("column = %d, want %d for %q", s.Column, pos.Column, k.text)
+               }
+               pos.Offset += 4 + len(k.text) + 1     // 4 tabs + token bytes + newline
+               pos.Line += countNewlines(k.text) + 1 // each token is on a new line
+               s.Scan()
+       }
+}
+
+
+func TestScanZeroMode(t *testing.T) {
+       src := makeSource("%s\n")
+       str := src.String()
+       s := new(Scanner).Init(src)
+       s.Mode = 0       // don't recognize any token classes
+       s.Whitespace = 0 // don't skip any whitespace
+       tok := s.Scan()
+       for i, ch := range str {
+               if tok != ch {
+                       t.Fatalf("%d. tok = %s, want %s", i, TokenString(tok), TokenString(ch))
+               }
+               tok = s.Scan()
+       }
+       if tok != EOF {
+               t.Fatalf("tok = %s, want EOF", TokenString(tok))
+       }
+}
+
+
+func testScanSelectedMode(t *testing.T, mode uint, class int) {
+       src := makeSource("%s\n")
+       s := new(Scanner).Init(src)
+       s.Mode = mode
+       tok := s.Scan()
+       for tok != EOF {
+               if tok < 0 && tok != class {
+                       t.Fatalf("tok = %s, want %s", TokenString(tok), TokenString(class))
+               }
+               tok = s.Scan()
+       }
+}
+
+
+func TestScanSelectedMask(t *testing.T) {
+       testScanSelectedMode(t, 0, 0)
+       testScanSelectedMode(t, ScanIdents, Ident)
+       // Don't test ScanInts and ScanNumbers since some parts of
+       // the floats in the source look like (illegal) octal ints
+       // and ScanNumbers may return either Int or Float.
+       testScanSelectedMode(t, ScanChars, Char)
+       testScanSelectedMode(t, ScanStrings, String)
+       testScanSelectedMode(t, SkipComments, 0)
+       testScanSelectedMode(t, ScanComments, Comment)
+}
+
+
+func TestScanNext(t *testing.T) {
+       s := new(Scanner).Init(bytes.NewBufferString("if a == bcd /* comment */ {\n\ta += c\n}"))
+       checkTok(t, s, 1, s.Scan(), Ident, "if")
+       checkTok(t, s, 1, s.Scan(), Ident, "a")
+       checkTok(t, s, 1, s.Scan(), '=', "=")
+       checkTok(t, s, 1, s.Next(), '=', "")
+       checkTok(t, s, 1, s.Next(), ' ', "")
+       checkTok(t, s, 1, s.Next(), 'b', "")
+       checkTok(t, s, 1, s.Scan(), Ident, "cd")
+       checkTok(t, s, 1, s.Scan(), '{', "{")
+       checkTok(t, s, 2, s.Scan(), Ident, "a")
+       checkTok(t, s, 2, s.Scan(), '+', "+")
+       checkTok(t, s, 2, s.Next(), '=', "")
+       checkTok(t, s, 2, s.Scan(), Ident, "c")
+       checkTok(t, s, 3, s.Scan(), '}', "}")
+       checkTok(t, s, 3, s.Scan(), -1, "")
+}
+
+
+func TestScanWhitespace(t *testing.T) {
+       var buf bytes.Buffer
+       var ws uint64
+       // start at 1, NUL character is not allowed
+       for ch := byte(1); ch < ' '; ch++ {
+               buf.WriteByte(ch)
+               ws |= 1 << ch
+       }
+       const orig = 'x'
+       buf.WriteByte(orig)
+
+       s := new(Scanner).Init(&buf)
+       s.Mode = 0
+       s.Whitespace = ws
+       tok := s.Scan()
+       if tok != orig {
+               t.Errorf("tok = %s, want %s", TokenString(tok), TokenString(orig))
+       }
+}
+
+
+func testError(t *testing.T, src, msg string, tok int) {
+       s := new(Scanner).Init(bytes.NewBufferString(src))
+       errorCalled := false
+       s.Error = func(s *Scanner, m string) {
+               if !errorCalled {
+                       // only look at first error
+                       if m != msg {
+                               t.Errorf("msg = %q, want %q for %q", m, msg, src)
+                       }
+                       errorCalled = true
+               }
+       }
+       tk := s.Scan()
+       if tk != tok {
+               t.Errorf("tok = %s, want %s for %q", TokenString(tk), TokenString(tok), src)
+       }
+       if !errorCalled {
+               t.Errorf("error handler not called for %q", src)
+       }
+       if s.ErrorCount == 0 {
+               t.Errorf("count = %d, want > 0 for %q", s.ErrorCount, src)
+       }
+}
+
+
+func TestError(t *testing.T) {
+       testError(t, `01238`, "illegal octal number", Int)
+       testError(t, `'\"'`, "illegal char escape", Char)
+       testError(t, `'aa'`, "illegal char literal", Char)
+       testError(t, `'`, "literal not terminated", Char)
+       testError(t, `"\'"`, "illegal char escape", String)
+       testError(t, `"abc`, "literal not terminated", String)
+       testError(t, "`abc", "literal not terminated", String)
+       testError(t, `//`, "comment not terminated", EOF)
+       testError(t, `/*/`, "comment not terminated", EOF)
+       testError(t, `"abc`+"\x00"+`def"`, "illegal character NUL", String)
+       testError(t, `"abc`+"\xff"+`def"`, "illegal UTF-8 encoding", String)
+}
+
+
+func checkPos(t *testing.T, s *Scanner, offset, line, column, char int) {
+       pos := s.Pos()
+       if pos.Offset != offset {
+               t.Errorf("offset = %d, want %d", pos.Offset, offset)
+       }
+       if pos.Line != line {
+               t.Errorf("line = %d, want %d", pos.Line, line)
+       }
+       if pos.Column != column {
+               t.Errorf("column = %d, want %d", pos.Column, column)
+       }
+       ch := s.Scan()
+       if ch != char {
+               t.Errorf("ch = %s, want %s", TokenString(ch), TokenString(char))
+       }
+}
+
+
+func TestPos(t *testing.T) {
+       s := new(Scanner).Init(bytes.NewBufferString("abc\n012\n\nx"))
+       s.Mode = 0
+       s.Whitespace = 0
+       checkPos(t, s, 0, 1, 1, 'a')
+       checkPos(t, s, 1, 1, 2, 'b')
+       checkPos(t, s, 2, 1, 3, 'c')
+       checkPos(t, s, 3, 2, 0, '\n')
+       checkPos(t, s, 4, 2, 1, '0')
+       checkPos(t, s, 5, 2, 2, '1')
+       checkPos(t, s, 6, 2, 3, '2')
+       checkPos(t, s, 7, 3, 0, '\n')
+       checkPos(t, s, 8, 4, 0, '\n')
+       checkPos(t, s, 9, 4, 1, 'x')
+       checkPos(t, s, 9, 4, 1, EOF)
+       checkPos(t, s, 9, 4, 1, EOF) // after EOF, position doesn't change
+}
diff --git a/libgo/go/smtp/auth.go b/libgo/go/smtp/auth.go
new file mode 100644 (file)
index 0000000..dd27f8e
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package smtp
+
+import (
+       "os"
+)
+
+// Auth is implemented by an SMTP authentication mechanism.
+type Auth interface {
+       // Start begins an authentication with a server.
+       // It returns the name of the authentication protocol
+       // and optionally data to include in the initial AUTH message
+       // sent to the server. It can return proto == "" to indicate
+       // that the authentication should be skipped.
+       // If it returns a non-nil os.Error, the SMTP client aborts
+       // the authentication attempt and closes the connection.
+       Start(server *ServerInfo) (proto string, toServer []byte, err os.Error)
+
+       // Next continues the authentication. The server has just sent
+       // the fromServer data. If more is true, the server expects a
+       // response, which Next should return as toServer; otherwise
+       // Next should return toServer == nil.
+       // If Next returns a non-nil os.Error, the SMTP client aborts
+       // the authentication attempt and closes the connection.
+       Next(fromServer []byte, more bool) (toServer []byte, err os.Error)
+}
+
+// ServerInfo records information about an SMTP server.
+type ServerInfo struct {
+       Name string   // SMTP server name
+       TLS  bool     // using TLS, with valid certificate for Name
+       Auth []string // advertised authentication mechanisms
+}
+
+type plainAuth struct {
+       identity, username, password string
+       host                         string
+}
+
+// PlainAuth returns an Auth that implements the PLAIN authentication
+// mechanism as defined in RFC 4616.
+// The returned Auth uses the given username and password to authenticate
+// on TLS connections to host and act as identity. Usually identity will be
+// left blank to act as username.
+func PlainAuth(identity, username, password, host string) Auth {
+       return &plainAuth{identity, username, password, host}
+}
+
+func (a *plainAuth) Start(server *ServerInfo) (string, []byte, os.Error) {
+       if !server.TLS {
+               return "", nil, os.NewError("unencrypted connection")
+       }
+       if server.Name != a.host {
+               return "", nil, os.NewError("wrong host name")
+       }
+       resp := []byte(a.identity + "\x00" + a.username + "\x00" + a.password)
+       return "PLAIN", resp, nil
+}
+
+func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, os.Error) {
+       if more {
+               // We've already sent everything.
+               return nil, os.NewError("unexpected server challenge")
+       }
+       return nil, nil
+}
diff --git a/libgo/go/smtp/smtp.go b/libgo/go/smtp/smtp.go
new file mode 100644 (file)
index 0000000..3b80516
--- /dev/null
@@ -0,0 +1,295 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package smtp implements the Simple Mail Transfer Protocol as defined in RFC 5321.
+// It also implements the following extensions:
+//     8BITMIME  RFC 1652
+//     AUTH      RFC 2554
+//     STARTTLS  RFC 3207
+// Additional extensions may be handled by clients.
+package smtp
+
+import (
+       "crypto/tls"
+       "encoding/base64"
+       "io"
+       "os"
+       "net"
+       "net/textproto"
+       "strings"
+)
+
+// A Client represents a client connection to an SMTP server.
+type Client struct {
+       // Text is the textproto.Conn used by the Client. It is exported to allow for
+       // clients to add extensions.
+       Text *textproto.Conn
+       // keep a reference to the connection so it can be used to create a TLS
+       // connection later
+       conn net.Conn
+       // whether the Client is using TLS
+       tls        bool
+       serverName string
+       // map of supported extensions
+       ext map[string]string
+       // supported auth mechanisms
+       auth []string
+}
+
+// Dial returns a new Client connected to an SMTP server at addr.
+func Dial(addr string) (*Client, os.Error) {
+       conn, err := net.Dial("tcp", "", addr)
+       if err != nil {
+               return nil, err
+       }
+       host := addr[:strings.Index(addr, ":")]
+       return NewClient(conn, host)
+}
+
+// NewClient returns a new Client using an existing connection and host as a
+// server name to be used when authenticating.
+func NewClient(conn net.Conn, host string) (*Client, os.Error) {
+       text := textproto.NewConn(conn)
+       _, msg, err := text.ReadResponse(220)
+       if err != nil {
+               text.Close()
+               return nil, err
+       }
+       c := &Client{Text: text, conn: conn, serverName: host}
+       if strings.Contains(msg, "ESMTP") {
+               err = c.ehlo()
+       } else {
+               err = c.helo()
+       }
+       return c, err
+}
+
+// cmd is a convenience function that sends a command and returns the response
+func (c *Client) cmd(expectCode int, format string, args ...interface{}) (int, string, os.Error) {
+       id, err := c.Text.Cmd(format, args...)
+       if err != nil {
+               return 0, "", err
+       }
+       c.Text.StartResponse(id)
+       defer c.Text.EndResponse(id)
+       code, msg, err := c.Text.ReadResponse(expectCode)
+       return code, msg, err
+}
+
+// helo sends the HELO greeting to the server. It should be used only when the
+// server does not support ehlo.
+func (c *Client) helo() os.Error {
+       c.ext = nil
+       _, _, err := c.cmd(250, "HELO localhost")
+       return err
+}
+
+// ehlo sends the EHLO (extended hello) greeting to the server. It
+// should be the preferred greeting for servers that support it.
+func (c *Client) ehlo() os.Error {
+       _, msg, err := c.cmd(250, "EHLO localhost")
+       if err != nil {
+               return err
+       }
+       ext := make(map[string]string)
+       extList := strings.Split(msg, "\n", -1)
+       if len(extList) > 1 {
+               extList = extList[1:]
+               for _, line := range extList {
+                       args := strings.Split(line, " ", 2)
+                       if len(args) > 1 {
+                               ext[args[0]] = args[1]
+                       } else {
+                               ext[args[0]] = ""
+                       }
+               }
+       }
+       if mechs, ok := ext["AUTH"]; ok {
+               c.auth = strings.Split(mechs, " ", -1)
+       }
+       c.ext = ext
+       return err
+}
+
+// StartTLS sends the STARTTLS command and encrypts all further communication.
+// Only servers that advertise the STARTTLS extension support this function.
+func (c *Client) StartTLS() os.Error {
+       _, _, err := c.cmd(220, "STARTTLS")
+       if err != nil {
+               return err
+       }
+       c.conn = tls.Client(c.conn, nil)
+       c.Text = textproto.NewConn(c.conn)
+       c.tls = true
+       return c.ehlo()
+}
+
+// Verify checks the validity of an email address on the server.
+// If Verify returns nil, the address is valid. A non-nil return
+// does not necessarily indicate an invalid address. Many servers
+// will not verify addresses for security reasons.
+func (c *Client) Verify(addr string) os.Error {
+       _, _, err := c.cmd(250, "VRFY %s", addr)
+       return err
+}
+
+// Auth authenticates a client using the provided authentication mechanism.
+// A failed authentication closes the connection.
+// Only servers that advertise the AUTH extension support this function.
+func (c *Client) Auth(a Auth) os.Error {
+       encoding := base64.StdEncoding
+       mech, resp, err := a.Start(&ServerInfo{c.serverName, c.tls, c.auth})
+       if err != nil {
+               c.Quit()
+               return err
+       }
+       resp64 := make([]byte, encoding.EncodedLen(len(resp)))
+       encoding.Encode(resp64, resp)
+       code, msg64, err := c.cmd(0, "AUTH %s %s", mech, resp64)
+       for err == nil {
+               var msg []byte
+               switch code {
+               case 334:
+                       msg = make([]byte, encoding.DecodedLen(len(msg64)))
+                       _, err = encoding.Decode(msg, []byte(msg64))
+               case 235:
+                       // the last message isn't base64 because it isn't a challenge
+                       msg = []byte(msg64)
+               default:
+                       err = &textproto.Error{code, msg64}
+               }
+               resp, err = a.Next(msg, code == 334)
+               if err != nil {
+                       // abort the AUTH
+                       c.cmd(501, "*")
+                       c.Quit()
+                       break
+               }
+               if resp == nil {
+                       break
+               }
+               resp64 = make([]byte, encoding.EncodedLen(len(resp)))
+               encoding.Encode(resp64, resp)
+               code, msg64, err = c.cmd(0, string(resp64))
+       }
+       return err
+}
+
+// Mail issues a MAIL command to the server using the provided email address.
+// If the server supports the 8BITMIME extension, Mail adds the BODY=8BITMIME
+// parameter.
+// This initiates a mail transaction and is followed by one or more Rcpt calls.
+func (c *Client) Mail(from string) os.Error {
+       cmdStr := "MAIL FROM:<%s>"
+       if c.ext != nil {
+               if _, ok := c.ext["8BITMIME"]; ok {
+                       cmdStr += " BODY=8BITMIME"
+               }
+       }
+       _, _, err := c.cmd(250, cmdStr, from)
+       return err
+}
+
+// Rcpt issues a RCPT command to the server using the provided email address.
+// A call to Rcpt must be preceded by a call to Mail and may be followed by
+// a Data call or another Rcpt call.
+func (c *Client) Rcpt(to string) os.Error {
+       _, _, err := c.cmd(25, "RCPT TO:<%s>", to)
+       return err
+}
+
+type dataCloser struct {
+       c *Client
+       io.WriteCloser
+}
+
+func (d *dataCloser) Close() os.Error {
+       d.WriteCloser.Close()
+       _, _, err := d.c.Text.ReadResponse(250)
+       return err
+}
+
+// Data issues a DATA command to the server and returns a writer that
+// can be used to write the data. The caller should close the writer
+// before calling any more methods on c.
+// A call to Data must be preceded by one or more calls to Rcpt.
+func (c *Client) Data() (io.WriteCloser, os.Error) {
+       _, _, err := c.cmd(354, "DATA")
+       if err != nil {
+               return nil, err
+       }
+       return &dataCloser{c, c.Text.DotWriter()}, nil
+}
+
+// SendMail connects to the server at addr, switches to TLS if possible,
+// authenticates with mechanism a if possible, and then sends an email from
+// address from, to addresses to, with message msg.
+func SendMail(addr string, a Auth, from string, to []string, msg []byte) os.Error {
+       c, err := Dial(addr)
+       if err != nil {
+               return err
+       }
+       if ok, _ := c.Extension("STARTTLS"); ok {
+               if err = c.StartTLS(); err != nil {
+                       return err
+               }
+       }
+       if a != nil && c.ext != nil {
+               if _, ok := c.ext["AUTH"]; ok {
+                       if err = c.Auth(a); err != nil {
+                               return err
+                       }
+               }
+       }
+       if err = c.Mail(from); err != nil {
+               return err
+       }
+       for _, addr := range to {
+               if err = c.Rcpt(addr); err != nil {
+                       return err
+               }
+       }
+       w, err := c.Data()
+       if err != nil {
+               return err
+       }
+       _, err = w.Write(msg)
+       if err != nil {
+               return err
+       }
+       err = w.Close()
+       if err != nil {
+               return err
+       }
+       return c.Quit()
+}
+
+// Extension reports whether an extension is support by the server.
+// The extension name is case-insensitive. If the extension is supported,
+// Extension also returns a string that contains any parameters the
+// server specifies for the extension.
+func (c *Client) Extension(ext string) (bool, string) {
+       if c.ext == nil {
+               return false, ""
+       }
+       ext = strings.ToUpper(ext)
+       param, ok := c.ext[ext]
+       return ok, param
+}
+
+// Reset sends the RSET command to the server, aborting the current mail
+// transaction.
+func (c *Client) Reset() os.Error {
+       _, _, err := c.cmd(250, "RSET")
+       return err
+}
+
+// Quit sends the QUIT command and closes the connection to the server.
+func (c *Client) Quit() os.Error {
+       _, _, err := c.cmd(221, "QUIT")
+       if err != nil {
+               return err
+       }
+       return c.Text.Close()
+}
diff --git a/libgo/go/smtp/smtp_test.go b/libgo/go/smtp/smtp_test.go
new file mode 100644 (file)
index 0000000..49363ad
--- /dev/null
@@ -0,0 +1,182 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package smtp
+
+import (
+       "bufio"
+       "bytes"
+       "io"
+       "net/textproto"
+       "os"
+       "strings"
+       "testing"
+)
+
+type authTest struct {
+       auth       Auth
+       challenges []string
+       name       string
+       responses  []string
+}
+
+var authTests = []authTest{
+       {PlainAuth("", "user", "pass", "testserver"), []string{}, "PLAIN", []string{"\x00user\x00pass"}},
+       {PlainAuth("foo", "bar", "baz", "testserver"), []string{}, "PLAIN", []string{"foo\x00bar\x00baz"}},
+}
+
+func TestAuth(t *testing.T) {
+testLoop:
+       for i, test := range authTests {
+               name, resp, err := test.auth.Start(&ServerInfo{"testserver", true, nil})
+               if name != test.name {
+                       t.Errorf("#%d got name %s, expected %s", i, name, test.name)
+               }
+               if !bytes.Equal(resp, []byte(test.responses[0])) {
+                       t.Errorf("#%d got response %s, expected %s", i, resp, test.responses[0])
+               }
+               if err != nil {
+                       t.Errorf("#%d error: %s", i, err.String())
+               }
+               for j := range test.challenges {
+                       challenge := []byte(test.challenges[j])
+                       expected := []byte(test.responses[j+1])
+                       resp, err := test.auth.Next(challenge, true)
+                       if err != nil {
+                               t.Errorf("#%d error: %s", i, err.String())
+                               continue testLoop
+                       }
+                       if !bytes.Equal(resp, expected) {
+                               t.Errorf("#%d got %s, expected %s", i, resp, expected)
+                               continue testLoop
+                       }
+               }
+       }
+}
+
+type faker struct {
+       io.ReadWriter
+}
+
+func (f faker) Close() os.Error {
+       return nil
+}
+
+func TestBasic(t *testing.T) {
+       basicServer = strings.Join(strings.Split(basicServer, "\n", -1), "\r\n")
+       basicClient = strings.Join(strings.Split(basicClient, "\n", -1), "\r\n")
+
+       var cmdbuf bytes.Buffer
+       bcmdbuf := bufio.NewWriter(&cmdbuf)
+       var fake faker
+       fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(basicServer)), bcmdbuf)
+       c := &Client{Text: textproto.NewConn(fake)}
+
+       if err := c.helo(); err != nil {
+               t.Fatalf("HELO failed: %s", err.String())
+       }
+       if err := c.ehlo(); err == nil {
+               t.Fatalf("Expected first EHLO to fail")
+       }
+       if err := c.ehlo(); err != nil {
+               t.Fatalf("Second EHLO failed: %s", err.String())
+       }
+
+       if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" {
+               t.Fatalf("Expected AUTH supported")
+       }
+       if ok, _ := c.Extension("DSN"); ok {
+               t.Fatalf("Shouldn't support DSN")
+       }
+
+       if err := c.Mail("user@gmail.com"); err == nil {
+               t.Fatalf("MAIL should require authentication")
+       }
+
+       if err := c.Verify("user1@gmail.com"); err == nil {
+               t.Fatalf("First VRFY: expected no verification")
+       }
+       if err := c.Verify("user2@gmail.com"); err != nil {
+               t.Fatalf("Second VRFY: expected verification, got %s", err)
+       }
+
+       // fake TLS so authentication won't complain
+       c.tls = true
+       c.serverName = "smtp.google.com"
+       if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")); err != nil {
+               t.Fatalf("AUTH failed: %s", err.String())
+       }
+
+       if err := c.Mail("user@gmail.com"); err != nil {
+               t.Fatalf("MAIL failed: %s", err.String())
+       }
+       if err := c.Rcpt("golang-nuts@googlegroups.com"); err != nil {
+               t.Fatalf("RCPT failed: %s", err.String())
+       }
+       msg := `From: user@gmail.com
+To: golang-nuts@googlegroups.com
+Subject: Hooray for Go
+
+Line 1
+.Leading dot line .
+Goodbye.`
+       w, err := c.Data()
+       if err != nil {
+               t.Fatalf("DATA failed: %s", err.String())
+       }
+       if _, err := w.Write([]byte(msg)); err != nil {
+               t.Fatalf("Data write failed: %s", err.String())
+       }
+       if err := w.Close(); err != nil {
+               t.Fatalf("Bad data response: %s", err.String())
+       }
+
+       if err := c.Quit(); err != nil {
+               t.Fatalf("QUIT failed: %s", err.String())
+       }
+
+       bcmdbuf.Flush()
+       actualcmds := cmdbuf.String()
+       if basicClient != actualcmds {
+               t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, basicClient)
+       }
+}
+
+var basicServer = `250 mx.google.com at your service
+502 Unrecognized command.
+250-mx.google.com at your service
+250-SIZE 35651584
+250-AUTH LOGIN PLAIN
+250 8BITMIME
+530 Authentication required
+252 Send some mail, I'll try my best
+250 User is valid
+235 Accepted
+250 Sender OK
+250 Receiver OK
+354 Go ahead
+250 Data OK
+221 OK
+`
+
+var basicClient = `HELO localhost
+EHLO localhost
+EHLO localhost
+MAIL FROM:<user@gmail.com> BODY=8BITMIME
+VRFY user1@gmail.com
+VRFY user2@gmail.com
+AUTH PLAIN AHVzZXIAcGFzcw==
+MAIL FROM:<user@gmail.com> BODY=8BITMIME
+RCPT TO:<golang-nuts@googlegroups.com>
+DATA
+From: user@gmail.com
+To: golang-nuts@googlegroups.com
+Subject: Hooray for Go
+
+Line 1
+..Leading dot line .
+Goodbye.
+.
+QUIT
+`
diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go
new file mode 100644 (file)
index 0000000..c5b8484
--- /dev/null
@@ -0,0 +1,198 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The sort package provides primitives for sorting arrays
+// and user-defined collections.
+package sort
+
+// A type, typically a collection, that satisfies sort.Interface can be
+// sorted by the routines in this package.  The methods require that the
+// elements of the collection be enumerated by an integer index.
+type Interface interface {
+       // Len is the number of elements in the collection.
+       Len() int
+       // Less returns whether the element with index i should sort
+       // before the element with index j.
+       Less(i, j int) bool
+       // Swap swaps the elements with indexes i and j.
+       Swap(i, j int)
+}
+
+func min(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+// Insertion sort
+func insertionSort(data Interface, a, b int) {
+       for i := a + 1; i < b; i++ {
+               for j := i; j > a && data.Less(j, j-1); j-- {
+                       data.Swap(j, j-1)
+               }
+       }
+}
+
+// Quicksort, following Bentley and McIlroy,
+// ``Engineering a Sort Function,'' SP&E November 1993.
+
+// Move the median of the three values data[a], data[b], data[c] into data[a].
+func medianOfThree(data Interface, a, b, c int) {
+       m0 := b
+       m1 := a
+       m2 := c
+       // bubble sort on 3 elements
+       if data.Less(m1, m0) {
+               data.Swap(m1, m0)
+       }
+       if data.Less(m2, m1) {
+               data.Swap(m2, m1)
+       }
+       if data.Less(m1, m0) {
+               data.Swap(m1, m0)
+       }
+       // now data[m0] <= data[m1] <= data[m2]
+}
+
+func swapRange(data Interface, a, b, n int) {
+       for i := 0; i < n; i++ {
+               data.Swap(a+i, b+i)
+       }
+}
+
+func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
+       m := (lo + hi) / 2
+       if hi-lo > 40 {
+               // Tukey's ``Ninther,'' median of three medians of three.
+               s := (hi - lo) / 8
+               medianOfThree(data, lo, lo+s, lo+2*s)
+               medianOfThree(data, m, m-s, m+s)
+               medianOfThree(data, hi-1, hi-1-s, hi-1-2*s)
+       }
+       medianOfThree(data, lo, m, hi-1)
+
+       // Invariants are:
+       //      data[lo] = pivot (set up by ChoosePivot)
+       //      data[lo <= i < a] = pivot
+       //      data[a <= i < b] < pivot
+       //      data[b <= i < c] is unexamined
+       //      data[c <= i < d] > pivot
+       //      data[d <= i < hi] = pivot
+       //
+       // Once b meets c, can swap the "= pivot" sections
+       // into the middle of the array.
+       pivot := lo
+       a, b, c, d := lo+1, lo+1, hi, hi
+       for b < c {
+               if data.Less(b, pivot) { // data[b] < pivot
+                       b++
+                       continue
+               }
+               if !data.Less(pivot, b) { // data[b] = pivot
+                       data.Swap(a, b)
+                       a++
+                       b++
+                       continue
+               }
+               if data.Less(pivot, c-1) { // data[c-1] > pivot
+                       c--
+                       continue
+               }
+               if !data.Less(c-1, pivot) { // data[c-1] = pivot
+                       data.Swap(c-1, d-1)
+                       c--
+                       d--
+                       continue
+               }
+               // data[b] > pivot; data[c-1] < pivot
+               data.Swap(b, c-1)
+               b++
+               c--
+       }
+
+       n := min(b-a, a-lo)
+       swapRange(data, lo, b-n, n)
+
+       n = min(hi-d, d-c)
+       swapRange(data, c, hi-n, n)
+
+       return lo + b - a, hi - (d - c)
+}
+
+func quickSort(data Interface, a, b int) {
+       if b-a > 7 {
+               mlo, mhi := doPivot(data, a, b)
+               quickSort(data, a, mlo)
+               quickSort(data, mhi, b)
+       } else if b-a > 1 {
+               insertionSort(data, a, b)
+       }
+}
+
+func Sort(data Interface) { quickSort(data, 0, data.Len()) }
+
+
+func IsSorted(data Interface) bool {
+       n := data.Len()
+       for i := n - 1; i > 0; i-- {
+               if data.Less(i, i-1) {
+                       return false
+               }
+       }
+       return true
+}
+
+
+// Convenience types for common cases
+
+// IntArray attaches the methods of Interface to []int, sorting in increasing order.
+type IntArray []int
+
+func (p IntArray) Len() int           { return len(p) }
+func (p IntArray) Less(i, j int) bool { return p[i] < p[j] }
+func (p IntArray) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+
+// Sort is a convenience method.
+func (p IntArray) Sort() { Sort(p) }
+
+
+// FloatArray attaches the methods of Interface to []float, sorting in increasing order.
+type FloatArray []float
+
+func (p FloatArray) Len() int           { return len(p) }
+func (p FloatArray) Less(i, j int) bool { return p[i] < p[j] }
+func (p FloatArray) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+
+// Sort is a convenience method.
+func (p FloatArray) Sort() { Sort(p) }
+
+
+// StringArray attaches the methods of Interface to []string, sorting in increasing order.
+type StringArray []string
+
+func (p StringArray) Len() int           { return len(p) }
+func (p StringArray) Less(i, j int) bool { return p[i] < p[j] }
+func (p StringArray) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+
+// Sort is a convenience method.
+func (p StringArray) Sort() { Sort(p) }
+
+
+// Convenience wrappers for common cases
+
+// SortInts sorts an array of ints in increasing order.
+func SortInts(a []int) { Sort(IntArray(a)) }
+// SortFloats sorts an array of floats in increasing order.
+func SortFloats(a []float) { Sort(FloatArray(a)) }
+// SortStrings sorts an array of strings in increasing order.
+func SortStrings(a []string) { Sort(StringArray(a)) }
+
+
+// IntsAreSorted tests whether an array of ints is sorted in increasing order.
+func IntsAreSorted(a []int) bool { return IsSorted(IntArray(a)) }
+// FloatsAreSorted tests whether an array of floats is sorted in increasing order.
+func FloatsAreSorted(a []float) bool { return IsSorted(FloatArray(a)) }
+// StringsAreSorted tests whether an array of strings is sorted in increasing order.
+func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)) }
diff --git a/libgo/go/sort/sort_test.go b/libgo/go/sort/sort_test.go
new file mode 100644 (file)
index 0000000..2085a67
--- /dev/null
@@ -0,0 +1,267 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort
+
+import (
+       "fmt"
+       "rand"
+       "strconv"
+       "testing"
+)
+
+
+var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
+var floats = [...]float{74.3, 59.0, 238.2, -784.0, 2.3, 9845.768, -959.7485, 905, 7.8, 7.8}
+var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
+
+func TestSortIntArray(t *testing.T) {
+       data := ints
+       a := IntArray(data[0:])
+       Sort(a)
+       if !IsSorted(a) {
+               t.Errorf("sorted %v", ints)
+               t.Errorf("   got %v", data)
+       }
+}
+
+func TestSortFloatArray(t *testing.T) {
+       data := floats
+       a := FloatArray(data[0:])
+       Sort(a)
+       if !IsSorted(a) {
+               t.Errorf("sorted %v", floats)
+               t.Errorf("   got %v", data)
+       }
+}
+
+func TestSortStringArray(t *testing.T) {
+       data := strings
+       a := StringArray(data[0:])
+       Sort(a)
+       if !IsSorted(a) {
+               t.Errorf("sorted %v", strings)
+               t.Errorf("   got %v", data)
+       }
+}
+
+func TestSortInts(t *testing.T) {
+       data := ints
+       SortInts(data[0:])
+       if !IntsAreSorted(data[0:]) {
+               t.Errorf("sorted %v", ints)
+               t.Errorf("   got %v", data)
+       }
+}
+
+func TestSortFloats(t *testing.T) {
+       data := floats
+       SortFloats(data[0:])
+       if !FloatsAreSorted(data[0:]) {
+               t.Errorf("sorted %v", floats)
+               t.Errorf("   got %v", data)
+       }
+}
+
+func TestSortStrings(t *testing.T) {
+       data := strings
+       SortStrings(data[0:])
+       if !StringsAreSorted(data[0:]) {
+               t.Errorf("sorted %v", strings)
+               t.Errorf("   got %v", data)
+       }
+}
+
+func TestSortLarge_Random(t *testing.T) {
+       data := make([]int, 1000000)
+       for i := 0; i < len(data); i++ {
+               data[i] = rand.Intn(100)
+       }
+       if IntsAreSorted(data) {
+               t.Fatalf("terrible rand.rand")
+       }
+       SortInts(data)
+       if !IntsAreSorted(data) {
+               t.Errorf("sort didn't sort - 1M ints")
+       }
+}
+
+func BenchmarkSortString1K(b *testing.B) {
+       b.StopTimer()
+       for i := 0; i < b.N; i++ {
+               data := make([]string, 1<<10)
+               for i := 0; i < len(data); i++ {
+                       data[i] = strconv.Itoa(i ^ 0x2cc)
+               }
+               b.StartTimer()
+               SortStrings(data)
+               b.StopTimer()
+       }
+}
+
+func BenchmarkSortInt1K(b *testing.B) {
+       b.StopTimer()
+       for i := 0; i < b.N; i++ {
+               data := make([]int, 1<<10)
+               for i := 0; i < len(data); i++ {
+                       data[i] = i ^ 0x2cc
+               }
+               b.StartTimer()
+               SortInts(data)
+               b.StopTimer()
+       }
+}
+
+func BenchmarkSortInt64K(b *testing.B) {
+       b.StopTimer()
+       for i := 0; i < b.N; i++ {
+               data := make([]int, 1<<16)
+               for i := 0; i < len(data); i++ {
+                       data[i] = i ^ 0xcccc
+               }
+               b.StartTimer()
+               SortInts(data)
+               b.StopTimer()
+       }
+}
+
+const (
+       _Sawtooth = iota
+       _Rand
+       _Stagger
+       _Plateau
+       _Shuffle
+       _NDist
+)
+
+const (
+       _Copy = iota
+       _Reverse
+       _ReverseFirstHalf
+       _ReverseSecondHalf
+       _Sorted
+       _Dither
+       _NMode
+)
+
+type testingData struct {
+       desc    string
+       t       *testing.T
+       data    []int
+       maxswap int // number of swaps allowed
+       nswap   int
+}
+
+func (d *testingData) Len() int           { return len(d.data) }
+func (d *testingData) Less(i, j int) bool { return d.data[i] < d.data[j] }
+func (d *testingData) Swap(i, j int) {
+       if d.nswap >= d.maxswap {
+               d.t.Errorf("%s: used %d swaps sorting array of %d", d.desc, d.nswap, len(d.data))
+               d.t.FailNow()
+       }
+       d.nswap++
+       d.data[i], d.data[j] = d.data[j], d.data[i]
+}
+
+func lg(n int) int {
+       i := 0
+       for 1<<uint(i) < n {
+               i++
+       }
+       return i
+}
+
+func TestBentleyMcIlroy(t *testing.T) {
+       sizes := []int{100, 1023, 1024, 1025}
+       dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"}
+       modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"}
+       var tmp1, tmp2 [1025]int
+       for ni := 0; ni < len(sizes); ni++ {
+               n := sizes[ni]
+               for m := 1; m < 2*n; m *= 2 {
+                       for dist := 0; dist < _NDist; dist++ {
+                               j := 0
+                               k := 1
+                               data := tmp1[0:n]
+                               for i := 0; i < n; i++ {
+                                       switch dist {
+                                       case _Sawtooth:
+                                               data[i] = i % m
+                                       case _Rand:
+                                               data[i] = rand.Intn(m)
+                                       case _Stagger:
+                                               data[i] = (i*m + i) % n
+                                       case _Plateau:
+                                               data[i] = min(i, m)
+                                       case _Shuffle:
+                                               if rand.Intn(m) != 0 {
+                                                       j += 2
+                                                       data[i] = j
+                                               } else {
+                                                       k += 2
+                                                       data[i] = k
+                                               }
+                                       }
+                               }
+
+                               mdata := tmp2[0:n]
+                               for mode := 0; mode < _NMode; mode++ {
+                                       switch mode {
+                                       case _Copy:
+                                               for i := 0; i < n; i++ {
+                                                       mdata[i] = data[i]
+                                               }
+                                       case _Reverse:
+                                               for i := 0; i < n; i++ {
+                                                       mdata[i] = data[n-i-1]
+                                               }
+                                       case _ReverseFirstHalf:
+                                               for i := 0; i < n/2; i++ {
+                                                       mdata[i] = data[n/2-i-1]
+                                               }
+                                               for i := n / 2; i < n; i++ {
+                                                       mdata[i] = data[i]
+                                               }
+                                       case _ReverseSecondHalf:
+                                               for i := 0; i < n/2; i++ {
+                                                       mdata[i] = data[i]
+                                               }
+                                               for i := n / 2; i < n; i++ {
+                                                       mdata[i] = data[n-(i-n/2)-1]
+                                               }
+                                       case _Sorted:
+                                               for i := 0; i < n; i++ {
+                                                       mdata[i] = data[i]
+                                               }
+                                               // SortInts is known to be correct
+                                               // because mode Sort runs after mode _Copy.
+                                               SortInts(mdata)
+                                       case _Dither:
+                                               for i := 0; i < n; i++ {
+                                                       mdata[i] = data[i] + i%5
+                                               }
+                                       }
+
+                                       desc := fmt.Sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode])
+                                       d := &testingData{desc, t, mdata[0:n], n * lg(n) * 12 / 10, 0}
+                                       Sort(d)
+
+                                       // If we were testing C qsort, we'd have to make a copy
+                                       // of the array and sort it ourselves and then compare
+                                       // x against it, to ensure that qsort was only permuting
+                                       // the data, not (for example) overwriting it with zeros.
+                                       //
+                                       // In go, we don't have to be so paranoid: since the only
+                                       // mutating method Sort can call is TestingData.swap,
+                                       // it suffices here just to check that the final array is sorted.
+                                       if !IntsAreSorted(mdata) {
+                                               t.Errorf("%s: ints not sorted", desc)
+                                               t.Errorf("\t%v", mdata)
+                                               t.FailNow()
+                                       }
+                               }
+                       }
+               }
+       }
+}
diff --git a/libgo/go/strconv/atob.go b/libgo/go/strconv/atob.go
new file mode 100644 (file)
index 0000000..69fa229
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import "os"
+
+// Atob returns the boolean value represented by the string.
+// It accepts 1, t, T, TRUE, true, 0, f, F, FALSE, false.  Any other value returns
+// an error.
+func Atob(str string) (value bool, err os.Error) {
+       switch str {
+       case "1", "t", "T", "true", "TRUE", "True":
+               return true, nil
+       case "0", "f", "F", "false", "FALSE", "False":
+               return false, nil
+       }
+       return false, &NumError{str, os.EINVAL}
+}
+
+// Btoa returns "true" or "false" according to the value of the boolean argument
+func Btoa(b bool) string {
+       if b {
+               return "true"
+       }
+       return "false"
+}
diff --git a/libgo/go/strconv/atob_test.go b/libgo/go/strconv/atob_test.go
new file mode 100644 (file)
index 0000000..7a95456
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+       "os"
+       . "strconv"
+       "testing"
+)
+
+type atobTest struct {
+       in  string
+       out bool
+       err os.Error
+}
+
+var atobtests = []atobTest{
+       {"", false, os.EINVAL},
+       {"asdf", false, os.EINVAL},
+       {"0", false, nil},
+       {"f", false, nil},
+       {"F", false, nil},
+       {"FALSE", false, nil},
+       {"false", false, nil},
+       {"1", true, nil},
+       {"t", true, nil},
+       {"T", true, nil},
+       {"TRUE", true, nil},
+       {"true", true, nil},
+}
+
+func TestAtob(t *testing.T) {
+       for _, test := range atobtests {
+               b, e := Atob(test.in)
+               if test.err != nil {
+                       // expect an error
+                       if e == nil {
+                               t.Errorf("%s: expected %s but got nil", test.in, test.err)
+                       } else {
+                               // NumError assertion must succeed; it's the only thing we return.
+                               if test.err != e.(*NumError).Error {
+                                       t.Errorf("%s: expected %s but got %s", test.in, test.err, e)
+                               }
+                       }
+               } else {
+                       if e != nil {
+                               t.Errorf("%s: expected no error but got %s", test.in, test.err, e)
+                       }
+                       if b != test.out {
+                               t.Errorf("%s: expected %t but got %t", test.in, test.out, b)
+                       }
+               }
+       }
+}
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go
new file mode 100644 (file)
index 0000000..262a8b5
--- /dev/null
@@ -0,0 +1,382 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// decimal to binary floating point conversion.
+// Algorithm:
+//   1) Store input in multiprecision decimal.
+//   2) Multiply/divide decimal by powers of two until in range [0.5, 1)
+//   3) Multiply by 2^precision and round to get mantissa.
+
+// The strconv package implements conversions to and from
+// string representations of basic data types.
+package strconv
+
+import (
+       "math"
+       "os"
+)
+
+var optimize = true // can change for testing
+
+// TODO(rsc): Better truncation handling.
+func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
+       i := 0
+
+       // optional sign
+       if i >= len(s) {
+               return
+       }
+       switch {
+       case s[i] == '+':
+               i++
+       case s[i] == '-':
+               neg = true
+               i++
+       }
+
+       // digits
+       b := new(decimal)
+       sawdot := false
+       sawdigits := false
+       for ; i < len(s); i++ {
+               switch {
+               case s[i] == '.':
+                       if sawdot {
+                               return
+                       }
+                       sawdot = true
+                       b.dp = b.nd
+                       continue
+
+               case '0' <= s[i] && s[i] <= '9':
+                       sawdigits = true
+                       if s[i] == '0' && b.nd == 0 { // ignore leading zeros
+                               b.dp--
+                               continue
+                       }
+                       b.d[b.nd] = s[i]
+                       b.nd++
+                       continue
+               }
+               break
+       }
+       if !sawdigits {
+               return
+       }
+       if !sawdot {
+               b.dp = b.nd
+       }
+
+       // optional exponent moves decimal point.
+       // if we read a very large, very long number,
+       // just be sure to move the decimal point by
+       // a lot (say, 100000).  it doesn't matter if it's
+       // not the exact number.
+       if i < len(s) && s[i] == 'e' {
+               i++
+               if i >= len(s) {
+                       return
+               }
+               esign := 1
+               if s[i] == '+' {
+                       i++
+               } else if s[i] == '-' {
+                       i++
+                       esign = -1
+               }
+               if i >= len(s) || s[i] < '0' || s[i] > '9' {
+                       return
+               }
+               e := 0
+               for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+                       if e < 10000 {
+                               e = e*10 + int(s[i]) - '0'
+                       }
+               }
+               b.dp += e * esign
+       }
+
+       if i != len(s) {
+               return
+       }
+
+       d = b
+       ok = true
+       return
+}
+
+// decimal power of ten to binary power of two.
+var powtab = []int{1, 3, 6, 9, 13, 16, 19, 23, 26}
+
+func decimalToFloatBits(neg bool, d *decimal, trunc bool, flt *floatInfo) (b uint64, overflow bool) {
+       var exp int
+       var mant uint64
+
+       // Zero is always a special case.
+       if d.nd == 0 {
+               mant = 0
+               exp = flt.bias
+               goto out
+       }
+
+       // Obvious overflow/underflow.
+       // These bounds are for 64-bit floats.
+       // Will have to change if we want to support 80-bit floats in the future.
+       if d.dp > 310 {
+               goto overflow
+       }
+       if d.dp < -330 {
+               // zero
+               mant = 0
+               exp = flt.bias
+               goto out
+       }
+
+       // Scale by powers of two until in range [0.5, 1.0)
+       exp = 0
+       for d.dp > 0 {
+               var n int
+               if d.dp >= len(powtab) {
+                       n = 27
+               } else {
+                       n = powtab[d.dp]
+               }
+               d.Shift(-n)
+               exp += n
+       }
+       for d.dp < 0 || d.dp == 0 && d.d[0] < '5' {
+               var n int
+               if -d.dp >= len(powtab) {
+                       n = 27
+               } else {
+                       n = powtab[-d.dp]
+               }
+               d.Shift(n)
+               exp -= n
+       }
+
+       // Our range is [0.5,1) but floating point range is [1,2).
+       exp--
+
+       // Minimum representable exponent is flt.bias+1.
+       // If the exponent is smaller, move it up and
+       // adjust d accordingly.
+       if exp < flt.bias+1 {
+               n := flt.bias + 1 - exp
+               d.Shift(-n)
+               exp += n
+       }
+
+       if exp-flt.bias >= 1<<flt.expbits-1 {
+               goto overflow
+       }
+
+       // Extract 1+flt.mantbits bits.
+       mant = d.Shift(int(1 + flt.mantbits)).RoundedInteger()
+
+       // Rounding might have added a bit; shift down.
+       if mant == 2<<flt.mantbits {
+               mant >>= 1
+               exp++
+               if exp-flt.bias >= 1<<flt.expbits-1 {
+                       goto overflow
+               }
+       }
+
+       // Denormalized?
+       if mant&(1<<flt.mantbits) == 0 {
+               exp = flt.bias
+       }
+       goto out
+
+overflow:
+       // ±Inf
+       mant = 0
+       exp = 1<<flt.expbits - 1 + flt.bias
+       overflow = true
+
+out:
+       // Assemble bits.
+       bits := mant & (uint64(1)<<flt.mantbits - 1)
+       bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
+       if neg {
+               bits |= 1 << flt.mantbits << flt.expbits
+       }
+       return bits, overflow
+}
+
+// Compute exact floating-point integer from d's digits.
+// Caller is responsible for avoiding overflow.
+func decimalAtof64Int(neg bool, d *decimal) float64 {
+       f := float64(0)
+       for i := 0; i < d.nd; i++ {
+               f = f*10 + float64(d.d[i]-'0')
+       }
+       if neg {
+               f *= -1 // BUG work around 6g f = -f.
+       }
+       return f
+}
+
+func decimalAtof32Int(neg bool, d *decimal) float32 {
+       f := float32(0)
+       for i := 0; i < d.nd; i++ {
+               f = f*10 + float32(d.d[i]-'0')
+       }
+       if neg {
+               f *= -1 // BUG work around 6g f = -f.
+       }
+       return f
+}
+
+// Exact powers of 10.
+var float64pow10 = []float64{
+       1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+       1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+       1e20, 1e21, 1e22,
+}
+var float32pow10 = []float32{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10}
+
+// If possible to convert decimal d to 64-bit float f exactly,
+// entirely in floating-point math, do so, avoiding the expense of decimalToFloatBits.
+// Three common cases:
+//     value is exact integer
+//     value is exact integer * exact power of ten
+//     value is exact integer / exact power of ten
+// These all produce potentially inexact but correctly rounded answers.
+func decimalAtof64(neg bool, d *decimal, trunc bool) (f float64, ok bool) {
+       // Exact integers are <= 10^15.
+       // Exact powers of ten are <= 10^22.
+       if d.nd > 15 {
+               return
+       }
+       switch {
+       case d.dp == d.nd: // int
+               f := decimalAtof64Int(neg, d)
+               return f, true
+
+       case d.dp > d.nd && d.dp <= 15+22: // int * 10^k
+               f := decimalAtof64Int(neg, d)
+               k := d.dp - d.nd
+               // If exponent is big but number of digits is not,
+               // can move a few zeros into the integer part.
+               if k > 22 {
+                       f *= float64pow10[k-22]
+                       k = 22
+               }
+               return f * float64pow10[k], true
+
+       case d.dp < d.nd && d.nd-d.dp <= 22: // int / 10^k
+               f := decimalAtof64Int(neg, d)
+               return f / float64pow10[d.nd-d.dp], true
+       }
+       return
+}
+
+// If possible to convert decimal d to 32-bit float f exactly,
+// entirely in floating-point math, do so, avoiding the machinery above.
+func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
+       // Exact integers are <= 10^7.
+       // Exact powers of ten are <= 10^10.
+       if d.nd > 7 {
+               return
+       }
+       switch {
+       case d.dp == d.nd: // int
+               f := decimalAtof32Int(neg, d)
+               return f, true
+
+       case d.dp > d.nd && d.dp <= 7+10: // int * 10^k
+               f := decimalAtof32Int(neg, d)
+               k := d.dp - d.nd
+               // If exponent is big but number of digits is not,
+               // can move a few zeros into the integer part.
+               if k > 10 {
+                       f *= float32pow10[k-10]
+                       k = 10
+               }
+               return f * float32pow10[k], true
+
+       case d.dp < d.nd && d.nd-d.dp <= 10: // int / 10^k
+               f := decimalAtof32Int(neg, d)
+               return f / float32pow10[d.nd-d.dp], true
+       }
+       return
+}
+
+// Atof32 converts the string s to a 32-bit floating-point number.
+//
+// If s is well-formed and near a valid floating point number,
+// Atof32 returns the nearest floating point number rounded
+// using IEEE754 unbiased rounding.
+//
+// The errors that Atof32 returns have concrete type *NumError
+// and include err.Num = s.
+//
+// If s is not syntactically well-formed, Atof32 returns err.Error = os.EINVAL.
+//
+// If s is syntactically well-formed but is more than 1/2 ULP
+// away from the largest floating point number of the given size,
+// Atof32 returns f = ±Inf, err.Error = os.ERANGE.
+func Atof32(s string) (f float32, err os.Error) {
+       neg, d, trunc, ok := stringToDecimal(s)
+       if !ok {
+               return 0, &NumError{s, os.EINVAL}
+       }
+       if optimize {
+               if f, ok := decimalAtof32(neg, d, trunc); ok {
+                       return f, nil
+               }
+       }
+       b, ovf := decimalToFloatBits(neg, d, trunc, &float32info)
+       f = math.Float32frombits(uint32(b))
+       if ovf {
+               err = &NumError{s, os.ERANGE}
+       }
+       return f, err
+}
+
+// Atof64 converts the string s to a 64-bit floating-point number.
+// Except for the type of its result, its definition is the same as that
+// of Atof32.
+func Atof64(s string) (f float64, err os.Error) {
+       neg, d, trunc, ok := stringToDecimal(s)
+       if !ok {
+               return 0, &NumError{s, os.EINVAL}
+       }
+       if optimize {
+               if f, ok := decimalAtof64(neg, d, trunc); ok {
+                       return f, nil
+               }
+       }
+       b, ovf := decimalToFloatBits(neg, d, trunc, &float64info)
+       f = math.Float64frombits(b)
+       if ovf {
+               err = &NumError{s, os.ERANGE}
+       }
+       return f, err
+}
+
+// Atof is like Atof32 or Atof64, depending on the size of float.
+func Atof(s string) (f float, err os.Error) {
+       if FloatSize == 32 {
+               f1, err1 := Atof32(s)
+               return float(f1), err1
+       }
+       f1, err1 := Atof64(s)
+       return float(f1), err1
+}
+
+
+// AtofN converts the string s to a 64-bit floating-point number,
+// but it rounds the result assuming that it will be stored in a value
+// of n bits (32 or 64).
+func AtofN(s string, n int) (f float64, err os.Error) {
+       if n == 32 {
+               f1, err1 := Atof32(s)
+               return float64(f1), err1
+       }
+       f1, err1 := Atof64(s)
+       return f1, err1
+}
diff --git a/libgo/go/strconv/atof_test.go b/libgo/go/strconv/atof_test.go
new file mode 100644 (file)
index 0000000..1f75438
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+       "os"
+       "reflect"
+       . "strconv"
+       "testing"
+)
+
+type atofTest struct {
+       in  string
+       out string
+       err os.Error
+}
+
+var atoftests = []atofTest{
+       {"", "0", os.EINVAL},
+       {"1", "1", nil},
+       {"+1", "1", nil},
+       {"1x", "0", os.EINVAL},
+       {"1.1.", "0", os.EINVAL},
+       {"1e23", "1e+23", nil},
+       {"100000000000000000000000", "1e+23", nil},
+       {"1e-100", "1e-100", nil},
+       {"123456700", "1.234567e+08", nil},
+       {"99999999999999974834176", "9.999999999999997e+22", nil},
+       {"100000000000000000000001", "1.0000000000000001e+23", nil},
+       {"100000000000000008388608", "1.0000000000000001e+23", nil},
+       {"100000000000000016777215", "1.0000000000000001e+23", nil},
+       {"100000000000000016777216", "1.0000000000000003e+23", nil},
+       {"-1", "-1", nil},
+       {"-0", "-0", nil},
+       {"1e-20", "1e-20", nil},
+       {"625e-3", "0.625", nil},
+
+       // largest float64
+       {"1.7976931348623157e308", "1.7976931348623157e+308", nil},
+       {"-1.7976931348623157e308", "-1.7976931348623157e+308", nil},
+       // next float64 - too large
+       {"1.7976931348623159e308", "+Inf", os.ERANGE},
+       {"-1.7976931348623159e308", "-Inf", os.ERANGE},
+       // the border is ...158079
+       // borderline - okay
+       {"1.7976931348623158e308", "1.7976931348623157e+308", nil},
+       {"-1.7976931348623158e308", "-1.7976931348623157e+308", nil},
+       // borderline - too large
+       {"1.797693134862315808e308", "+Inf", os.ERANGE},
+       {"-1.797693134862315808e308", "-Inf", os.ERANGE},
+
+       // a little too large
+       {"1e308", "1e+308", nil},
+       {"2e308", "+Inf", os.ERANGE},
+       {"1e309", "+Inf", os.ERANGE},
+
+       // way too large
+       {"1e310", "+Inf", os.ERANGE},
+       {"-1e310", "-Inf", os.ERANGE},
+       {"1e400", "+Inf", os.ERANGE},
+       {"-1e400", "-Inf", os.ERANGE},
+       {"1e400000", "+Inf", os.ERANGE},
+       {"-1e400000", "-Inf", os.ERANGE},
+
+       // denormalized
+       {"1e-305", "1e-305", nil},
+       {"1e-306", "1e-306", nil},
+       {"1e-307", "1e-307", nil},
+       {"1e-308", "1e-308", nil},
+       {"1e-309", "1e-309", nil},
+       {"1e-310", "1e-310", nil},
+       {"1e-322", "1e-322", nil},
+       // smallest denormal
+       {"5e-324", "5e-324", nil},
+       {"4e-324", "5e-324", nil},
+       {"3e-324", "5e-324", nil},
+       // too small
+       {"2e-324", "0", nil},
+       // way too small
+       {"1e-350", "0", nil},
+       {"1e-400000", "0", nil},
+
+       // try to overflow exponent
+       {"1e-4294967296", "0", nil},
+       {"1e+4294967296", "+Inf", os.ERANGE},
+       {"1e-18446744073709551616", "0", nil},
+       {"1e+18446744073709551616", "+Inf", os.ERANGE},
+
+       // Parse errors
+       {"1e", "0", os.EINVAL},
+       {"1e-", "0", os.EINVAL},
+       {".e-1", "0", os.EINVAL},
+}
+
+func init() {
+       // The atof routines return NumErrors wrapping
+       // the error and the string.  Convert the table above.
+       for i := range atoftests {
+               test := &atoftests[i]
+               if test.err != nil {
+                       test.err = &NumError{test.in, test.err}
+               }
+       }
+}
+
+func testAtof(t *testing.T, opt bool) {
+       oldopt := SetOptimize(opt)
+       for i := 0; i < len(atoftests); i++ {
+               test := &atoftests[i]
+               out, err := Atof64(test.in)
+               outs := Ftoa64(out, 'g', -1)
+               if outs != test.out || !reflect.DeepEqual(err, test.err) {
+                       t.Errorf("Atof64(%v) = %v, %v want %v, %v",
+                               test.in, out, err, test.out, test.err)
+               }
+
+               out, err = AtofN(test.in, 64)
+               outs = FtoaN(out, 'g', -1, 64)
+               if outs != test.out || !reflect.DeepEqual(err, test.err) {
+                       t.Errorf("AtofN(%v, 64) = %v, %v want %v, %v",
+                               test.in, out, err, test.out, test.err)
+               }
+
+               if float64(float32(out)) == out {
+                       out32, err := Atof32(test.in)
+                       outs := Ftoa32(out32, 'g', -1)
+                       if outs != test.out || !reflect.DeepEqual(err, test.err) {
+                               t.Errorf("Atof32(%v) = %v, %v want %v, %v  # %v",
+                                       test.in, out32, err, test.out, test.err, out)
+                       }
+
+                       out, err := AtofN(test.in, 32)
+                       out32 = float32(out)
+                       outs = FtoaN(float64(out32), 'g', -1, 32)
+                       if outs != test.out || !reflect.DeepEqual(err, test.err) {
+                               t.Errorf("AtofN(%v, 32) = %v, %v want %v, %v  # %v",
+                                       test.in, out32, err, test.out, test.err, out)
+                       }
+               }
+
+               if FloatSize == 64 || float64(float32(out)) == out {
+                       outf, err := Atof(test.in)
+                       outs := Ftoa(outf, 'g', -1)
+                       if outs != test.out || !reflect.DeepEqual(err, test.err) {
+                               t.Errorf("Ftoa(%v) = %v, %v want %v, %v  # %v",
+                                       test.in, outf, err, test.out, test.err, out)
+                       }
+               }
+       }
+       SetOptimize(oldopt)
+}
+
+func TestAtof(t *testing.T) { testAtof(t, true) }
+
+func TestAtofSlow(t *testing.T) { testAtof(t, false) }
+
+func BenchmarkAtofDecimal(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atof("33909")
+       }
+}
+
+func BenchmarkAtofFloat(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atof("339.7784")
+       }
+}
+
+func BenchmarkAtofFloatExp(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atof("-5.09e75")
+       }
+}
+
+func BenchmarkAtofBig(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atof("123456789123456789123456789")
+       }
+}
diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go
new file mode 100644 (file)
index 0000000..f7b8456
--- /dev/null
@@ -0,0 +1,202 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import "os"
+
+type NumError struct {
+       Num   string
+       Error os.Error
+}
+
+func (e *NumError) String() string { return `parsing "` + e.Num + `": ` + e.Error.String() }
+
+
+func computeIntsize() uint {
+       siz := uint(8)
+       for 1<<siz != 0 {
+               siz *= 2
+       }
+       return siz
+}
+
+var IntSize = computeIntsize()
+
+// Return the first number n such that n*base >= 1<<64.
+func cutoff64(base int) uint64 {
+       if base < 2 {
+               return 0
+       }
+       return (1<<64-1)/uint64(base) + 1
+}
+
+// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
+// and returns the corresponding value n.  If b == 0, the base
+// is taken from the string prefix: base 16 for "0x", base 8 for "0",
+// and base 10 otherwise.
+//
+// The errors that Btoui64 returns have concrete type *NumError
+// and include err.Num = s.  If s is empty or contains invalid
+// digits, err.Error = os.EINVAL; if the value corresponding
+// to s cannot be represented by a uint64, err.Error = os.ERANGE.
+func Btoui64(s string, b int) (n uint64, err os.Error) {
+       s0 := s
+       switch {
+       case len(s) < 1:
+               err = os.EINVAL
+               goto Error
+
+       case 2 <= b && b <= 36:
+               // valid base; nothing to do
+
+       case b == 0:
+               // Look for octal, hex prefix.
+               switch {
+               case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
+                       b = 16
+                       s = s[2:]
+                       if len(s) < 1 {
+                               err = os.EINVAL
+                               goto Error
+                       }
+               case s[0] == '0':
+                       b = 8
+               default:
+                       b = 10
+               }
+
+       default:
+               err = os.ErrorString("invalid base " + Itoa(b))
+               goto Error
+       }
+
+       n = 0
+       cutoff := cutoff64(b)
+
+       for i := 0; i < len(s); i++ {
+               var v byte
+               d := s[i]
+               switch {
+               case '0' <= d && d <= '9':
+                       v = d - '0'
+               case 'a' <= d && d <= 'z':
+                       v = d - 'a' + 10
+               case 'A' <= d && d <= 'Z':
+                       v = d - 'A' + 10
+               default:
+                       n = 0
+                       err = os.EINVAL
+                       goto Error
+               }
+               if int(v) >= b {
+                       n = 0
+                       err = os.EINVAL
+                       goto Error
+               }
+
+               if n >= cutoff {
+                       // n*b overflows
+                       n = 1<<64 - 1
+                       err = os.ERANGE
+                       goto Error
+               }
+               n *= uint64(b)
+
+               n1 := n + uint64(v)
+               if n1 < n {
+                       // n+v overflows
+                       n = 1<<64 - 1
+                       err = os.ERANGE
+                       goto Error
+               }
+               n = n1
+       }
+
+       return n, nil
+
+Error:
+       return n, &NumError{s0, err}
+}
+
+// Atoui64 interprets a string s as a decimal number and
+// returns the corresponding value n.
+//
+// Atoui64 returns err == os.EINVAL if s is empty or contains invalid digits.
+// It returns err == os.ERANGE if s cannot be represented by a uint64.
+func Atoui64(s string) (n uint64, err os.Error) {
+       return Btoui64(s, 10)
+}
+
+// Btoi64 is like Btoui64 but allows signed numbers and
+// returns its result in an int64.
+func Btoi64(s string, base int) (i int64, err os.Error) {
+       // Empty string bad.
+       if len(s) == 0 {
+               return 0, &NumError{s, os.EINVAL}
+       }
+
+       // Pick off leading sign.
+       s0 := s
+       neg := false
+       if s[0] == '+' {
+               s = s[1:]
+       } else if s[0] == '-' {
+               neg = true
+               s = s[1:]
+       }
+
+       // Convert unsigned and check range.
+       var un uint64
+       un, err = Btoui64(s, base)
+       if err != nil && err.(*NumError).Error != os.ERANGE {
+               err.(*NumError).Num = s0
+               return 0, err
+       }
+       if !neg && un >= 1<<63 {
+               return 1<<63 - 1, &NumError{s0, os.ERANGE}
+       }
+       if neg && un > 1<<63 {
+               return -1 << 63, &NumError{s0, os.ERANGE}
+       }
+       n := int64(un)
+       if neg {
+               n = -n
+       }
+       return n, nil
+}
+
+// Atoi64 is like Atoui64 but allows signed numbers and
+// returns its result in an int64.
+func Atoi64(s string) (i int64, err os.Error) { return Btoi64(s, 10) }
+
+
+// Atoui is like Atoui64 but returns its result as a uint.
+func Atoui(s string) (i uint, err os.Error) {
+       i1, e1 := Atoui64(s)
+       if e1 != nil && e1.(*NumError).Error != os.ERANGE {
+               return 0, e1
+       }
+       i = uint(i1)
+       if uint64(i) != i1 {
+               return ^uint(0), &NumError{s, os.ERANGE}
+       }
+       return i, nil
+}
+
+// Atoi is like Atoi64 but returns its result as an int.
+func Atoi(s string) (i int, err os.Error) {
+       i1, e1 := Atoi64(s)
+       if e1 != nil && e1.(*NumError).Error != os.ERANGE {
+               return 0, e1
+       }
+       i = int(i1)
+       if int64(i) != i1 {
+               if i1 < 0 {
+                       return -1 << (IntSize - 1), &NumError{s, os.ERANGE}
+               }
+               return 1<<(IntSize-1) - 1, &NumError{s, os.ERANGE}
+       }
+       return i, nil
+}
diff --git a/libgo/go/strconv/atoi_test.go b/libgo/go/strconv/atoi_test.go
new file mode 100644 (file)
index 0000000..0b9f295
--- /dev/null
@@ -0,0 +1,303 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+       "os"
+       "reflect"
+       . "strconv"
+       "testing"
+)
+
+type atoui64Test struct {
+       in  string
+       out uint64
+       err os.Error
+}
+
+var atoui64tests = []atoui64Test{
+       {"", 0, os.EINVAL},
+       {"0", 0, nil},
+       {"1", 1, nil},
+       {"12345", 12345, nil},
+       {"012345", 12345, nil},
+       {"12345x", 0, os.EINVAL},
+       {"98765432100", 98765432100, nil},
+       {"18446744073709551615", 1<<64 - 1, nil},
+       {"18446744073709551616", 1<<64 - 1, os.ERANGE},
+       {"18446744073709551620", 1<<64 - 1, os.ERANGE},
+}
+
+var btoui64tests = []atoui64Test{
+       {"", 0, os.EINVAL},
+       {"0", 0, nil},
+       {"1", 1, nil},
+       {"12345", 12345, nil},
+       {"012345", 012345, nil},
+       {"0x12345", 0x12345, nil},
+       {"0X12345", 0x12345, nil},
+       {"12345x", 0, os.EINVAL},
+       {"98765432100", 98765432100, nil},
+       {"18446744073709551615", 1<<64 - 1, nil},
+       {"18446744073709551616", 1<<64 - 1, os.ERANGE},
+       {"18446744073709551620", 1<<64 - 1, os.ERANGE},
+       {"0xFFFFFFFFFFFFFFFF", 1<<64 - 1, nil},
+       {"0x10000000000000000", 1<<64 - 1, os.ERANGE},
+       {"01777777777777777777777", 1<<64 - 1, nil},
+       {"01777777777777777777778", 0, os.EINVAL},
+       {"02000000000000000000000", 1<<64 - 1, os.ERANGE},
+       {"0200000000000000000000", 1 << 61, nil},
+}
+
+type atoi64Test struct {
+       in  string
+       out int64
+       err os.Error
+}
+
+var atoi64tests = []atoi64Test{
+       {"", 0, os.EINVAL},
+       {"0", 0, nil},
+       {"-0", 0, nil},
+       {"1", 1, nil},
+       {"-1", -1, nil},
+       {"12345", 12345, nil},
+       {"-12345", -12345, nil},
+       {"012345", 12345, nil},
+       {"-012345", -12345, nil},
+       {"98765432100", 98765432100, nil},
+       {"-98765432100", -98765432100, nil},
+       {"9223372036854775807", 1<<63 - 1, nil},
+       {"-9223372036854775807", -(1<<63 - 1), nil},
+       {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+       {"-9223372036854775808", -1 << 63, nil},
+       {"9223372036854775809", 1<<63 - 1, os.ERANGE},
+       {"-9223372036854775809", -1 << 63, os.ERANGE},
+}
+
+var btoi64tests = []atoi64Test{
+       {"", 0, os.EINVAL},
+       {"0", 0, nil},
+       {"-0", 0, nil},
+       {"1", 1, nil},
+       {"-1", -1, nil},
+       {"12345", 12345, nil},
+       {"-12345", -12345, nil},
+       {"012345", 012345, nil},
+       {"-012345", -012345, nil},
+       {"0x12345", 0x12345, nil},
+       {"-0X12345", -0x12345, nil},
+       {"12345x", 0, os.EINVAL},
+       {"-12345x", 0, os.EINVAL},
+       {"98765432100", 98765432100, nil},
+       {"-98765432100", -98765432100, nil},
+       {"9223372036854775807", 1<<63 - 1, nil},
+       {"-9223372036854775807", -(1<<63 - 1), nil},
+       {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+       {"-9223372036854775808", -1 << 63, nil},
+       {"9223372036854775809", 1<<63 - 1, os.ERANGE},
+       {"-9223372036854775809", -1 << 63, os.ERANGE},
+}
+
+type atoui32Test struct {
+       in  string
+       out uint32
+       err os.Error
+}
+
+var atoui32tests = []atoui32Test{
+       {"", 0, os.EINVAL},
+       {"0", 0, nil},
+       {"1", 1, nil},
+       {"12345", 12345, nil},
+       {"012345", 12345, nil},
+       {"12345x", 0, os.EINVAL},
+       {"987654321", 987654321, nil},
+       {"4294967295", 1<<32 - 1, nil},
+       {"4294967296", 1<<32 - 1, os.ERANGE},
+}
+
+type atoi32Test struct {
+       in  string
+       out int32
+       err os.Error
+}
+
+var atoi32tests = []atoi32Test{
+       {"", 0, os.EINVAL},
+       {"0", 0, nil},
+       {"-0", 0, nil},
+       {"1", 1, nil},
+       {"-1", -1, nil},
+       {"12345", 12345, nil},
+       {"-12345", -12345, nil},
+       {"012345", 12345, nil},
+       {"-012345", -12345, nil},
+       {"12345x", 0, os.EINVAL},
+       {"-12345x", 0, os.EINVAL},
+       {"987654321", 987654321, nil},
+       {"-987654321", -987654321, nil},
+       {"2147483647", 1<<31 - 1, nil},
+       {"-2147483647", -(1<<31 - 1), nil},
+       {"2147483648", 1<<31 - 1, os.ERANGE},
+       {"-2147483648", -1 << 31, nil},
+       {"2147483649", 1<<31 - 1, os.ERANGE},
+       {"-2147483649", -1 << 31, os.ERANGE},
+}
+
+func init() {
+       // The atoi routines return NumErrors wrapping
+       // the error and the string.  Convert the tables above.
+       for i := range atoui64tests {
+               test := &atoui64tests[i]
+               if test.err != nil {
+                       test.err = &NumError{test.in, test.err}
+               }
+       }
+       for i := range btoui64tests {
+               test := &btoui64tests[i]
+               if test.err != nil {
+                       test.err = &NumError{test.in, test.err}
+               }
+       }
+       for i := range atoi64tests {
+               test := &atoi64tests[i]
+               if test.err != nil {
+                       test.err = &NumError{test.in, test.err}
+               }
+       }
+       for i := range btoi64tests {
+               test := &btoi64tests[i]
+               if test.err != nil {
+                       test.err = &NumError{test.in, test.err}
+               }
+       }
+       for i := range atoui32tests {
+               test := &atoui32tests[i]
+               if test.err != nil {
+                       test.err = &NumError{test.in, test.err}
+               }
+       }
+       for i := range atoi32tests {
+               test := &atoi32tests[i]
+               if test.err != nil {
+                       test.err = &NumError{test.in, test.err}
+               }
+       }
+}
+
+func TestAtoui64(t *testing.T) {
+       for i := range atoui64tests {
+               test := &atoui64tests[i]
+               out, err := Atoui64(test.in)
+               if test.out != out || !reflect.DeepEqual(test.err, err) {
+                       t.Errorf("Atoui64(%q) = %v, %v want %v, %v",
+                               test.in, out, err, test.out, test.err)
+               }
+       }
+}
+
+func TestBtoui64(t *testing.T) {
+       for i := range btoui64tests {
+               test := &btoui64tests[i]
+               out, err := Btoui64(test.in, 0)
+               if test.out != out || !reflect.DeepEqual(test.err, err) {
+                       t.Errorf("Btoui64(%q) = %v, %v want %v, %v",
+                               test.in, out, err, test.out, test.err)
+               }
+       }
+}
+
+func TestAtoi64(t *testing.T) {
+       for i := range atoi64tests {
+               test := &atoi64tests[i]
+               out, err := Atoi64(test.in)
+               if test.out != out || !reflect.DeepEqual(test.err, err) {
+                       t.Errorf("Atoi64(%q) = %v, %v want %v, %v",
+                               test.in, out, err, test.out, test.err)
+               }
+       }
+}
+
+func TestBtoi64(t *testing.T) {
+       for i := range btoi64tests {
+               test := &btoi64tests[i]
+               out, err := Btoi64(test.in, 0)
+               if test.out != out || !reflect.DeepEqual(test.err, err) {
+                       t.Errorf("Btoi64(%q) = %v, %v want %v, %v",
+                               test.in, out, err, test.out, test.err)
+               }
+       }
+}
+
+func TestAtoui(t *testing.T) {
+       switch IntSize {
+       case 32:
+               for i := range atoui32tests {
+                       test := &atoui32tests[i]
+                       out, err := Atoui(test.in)
+                       if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) {
+                               t.Errorf("Atoui(%q) = %v, %v want %v, %v",
+                                       test.in, out, err, test.out, test.err)
+                       }
+               }
+       case 64:
+               for i := range atoui64tests {
+                       test := &atoui64tests[i]
+                       out, err := Atoui(test.in)
+                       if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) {
+                               t.Errorf("Atoui(%q) = %v, %v want %v, %v",
+                                       test.in, out, err, test.out, test.err)
+                       }
+               }
+       }
+}
+
+func TestAtoi(t *testing.T) {
+       switch IntSize {
+       case 32:
+               for i := range atoi32tests {
+                       test := &atoi32tests[i]
+                       out, err := Atoi(test.in)
+                       if test.out != int32(out) || !reflect.DeepEqual(test.err, err) {
+                               t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+                                       test.in, out, err, test.out, test.err)
+                       }
+               }
+       case 64:
+               for i := range atoi64tests {
+                       test := &atoi64tests[i]
+                       out, err := Atoi(test.in)
+                       if test.out != int64(out) || !reflect.DeepEqual(test.err, err) {
+                               t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+                                       test.in, out, err, test.out, test.err)
+                       }
+               }
+       }
+}
+
+func BenchmarkAtoi(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atoi("12345678")
+       }
+}
+
+func BenchmarkAtoiNeg(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atoi("-12345678")
+       }
+}
+
+func BenchmarkAtoi64(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atoi64("12345678901234")
+       }
+}
+
+func BenchmarkAtoi64Neg(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Atoi64("-12345678901234")
+       }
+}
diff --git a/libgo/go/strconv/decimal.go b/libgo/go/strconv/decimal.go
new file mode 100644 (file)
index 0000000..3a5cf1b
--- /dev/null
@@ -0,0 +1,371 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Multiprecision decimal numbers.
+// For floating-point formatting only; not general purpose.
+// Only operations are assign and (binary) left/right shift.
+// Can do binary floating point in multiprecision decimal precisely
+// because 2 divides 10; cannot do decimal floating point
+// in multiprecision binary precisely.
+
+package strconv
+
+type decimal struct {
+       // TODO(rsc): Can make d[] a bit smaller and add
+       // truncated bool;
+       d  [2000]byte // digits
+       nd int        // number of digits used
+       dp int        // decimal point
+}
+
+func (a *decimal) String() string {
+       n := 10 + a.nd
+       if a.dp > 0 {
+               n += a.dp
+       }
+       if a.dp < 0 {
+               n += -a.dp
+       }
+
+       buf := make([]byte, n)
+       w := 0
+       switch {
+       case a.nd == 0:
+               return "0"
+
+       case a.dp <= 0:
+               // zeros fill space between decimal point and digits
+               buf[w] = '0'
+               w++
+               buf[w] = '.'
+               w++
+               w += digitZero(buf[w : w+-a.dp])
+               w += copy(buf[w:], a.d[0:a.nd])
+
+       case a.dp < a.nd:
+               // decimal point in middle of digits
+               w += copy(buf[w:], a.d[0:a.dp])
+               buf[w] = '.'
+               w++
+               w += copy(buf[w:], a.d[a.dp:a.nd])
+
+       default:
+               // zeros fill space between digits and decimal point
+               w += copy(buf[w:], a.d[0:a.nd])
+               w += digitZero(buf[w : w+a.dp-a.nd])
+       }
+       return string(buf[0:w])
+}
+
+func digitZero(dst []byte) int {
+       for i := range dst {
+               dst[i] = '0'
+       }
+       return len(dst)
+}
+
+// trim trailing zeros from number.
+// (They are meaningless; the decimal point is tracked
+// independent of the number of digits.)
+func trim(a *decimal) {
+       for a.nd > 0 && a.d[a.nd-1] == '0' {
+               a.nd--
+       }
+       if a.nd == 0 {
+               a.dp = 0
+       }
+}
+
+// Assign v to a.
+func (a *decimal) Assign(v uint64) {
+       var buf [50]byte
+
+       // Write reversed decimal in buf.
+       n := 0
+       for v > 0 {
+               v1 := v / 10
+               v -= 10 * v1
+               buf[n] = byte(v + '0')
+               n++
+               v = v1
+       }
+
+       // Reverse again to produce forward decimal in a.d.
+       a.nd = 0
+       for n--; n >= 0; n-- {
+               a.d[a.nd] = buf[n]
+               a.nd++
+       }
+       a.dp = a.nd
+       trim(a)
+}
+
+func newDecimal(i uint64) *decimal {
+       a := new(decimal)
+       a.Assign(i)
+       return a
+}
+
+// Maximum shift that we can do in one pass without overflow.
+// Signed int has 31 bits, and we have to be able to accomodate 9<<k.
+const maxShift = 27
+
+// Binary shift right (* 2) by k bits.  k <= maxShift to avoid overflow.
+func rightShift(a *decimal, k uint) {
+       r := 0 // read pointer
+       w := 0 // write pointer
+
+       // Pick up enough leading digits to cover first shift.
+       n := 0
+       for ; n>>k == 0; r++ {
+               if r >= a.nd {
+                       if n == 0 {
+                               // a == 0; shouldn't get here, but handle anyway.
+                               a.nd = 0
+                               return
+                       }
+                       for n>>k == 0 {
+                               n = n * 10
+                               r++
+                       }
+                       break
+               }
+               c := int(a.d[r])
+               n = n*10 + c - '0'
+       }
+       a.dp -= r - 1
+
+       // Pick up a digit, put down a digit.
+       for ; r < a.nd; r++ {
+               c := int(a.d[r])
+               dig := n >> k
+               n -= dig << k
+               a.d[w] = byte(dig + '0')
+               w++
+               n = n*10 + c - '0'
+       }
+
+       // Put down extra digits.
+       for n > 0 {
+               dig := n >> k
+               n -= dig << k
+               a.d[w] = byte(dig + '0')
+               w++
+               n = n * 10
+       }
+
+       a.nd = w
+       trim(a)
+}
+
+// Cheat sheet for left shift: table indexed by shift count giving
+// number of new digits that will be introduced by that shift.
+//
+// For example, leftcheats[4] = {2, "625"}.  That means that
+// if we are shifting by 4 (multiplying by 16), it will add 2 digits
+// when the string prefix is "625" through "999", and one fewer digit
+// if the string prefix is "000" through "624".
+//
+// Credit for this trick goes to Ken.
+
+type leftCheat struct {
+       delta  int    // number of new digits
+       cutoff string //   minus one digit if original < a.
+}
+
+var leftcheats = []leftCheat{
+       // Leading digits of 1/2^i = 5^i.
+       // 5^23 is not an exact 64-bit floating point number,
+       // so have to use bc for the math.
+       /*
+               seq 27 | sed 's/^/5^/' | bc |
+               awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," }
+               {
+                       log2 = log(2)/log(10)
+                       printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n",
+                               int(log2*NR+1), $0, 2**NR)
+               }'
+       */
+       {0, ""},
+       {1, "5"},                   // * 2
+       {1, "25"},                  // * 4
+       {1, "125"},                 // * 8
+       {2, "625"},                 // * 16
+       {2, "3125"},                // * 32
+       {2, "15625"},               // * 64
+       {3, "78125"},               // * 128
+       {3, "390625"},              // * 256
+       {3, "1953125"},             // * 512
+       {4, "9765625"},             // * 1024
+       {4, "48828125"},            // * 2048
+       {4, "244140625"},           // * 4096
+       {4, "1220703125"},          // * 8192
+       {5, "6103515625"},          // * 16384
+       {5, "30517578125"},         // * 32768
+       {5, "152587890625"},        // * 65536
+       {6, "762939453125"},        // * 131072
+       {6, "3814697265625"},       // * 262144
+       {6, "19073486328125"},      // * 524288
+       {7, "95367431640625"},      // * 1048576
+       {7, "476837158203125"},     // * 2097152
+       {7, "2384185791015625"},    // * 4194304
+       {7, "11920928955078125"},   // * 8388608
+       {8, "59604644775390625"},   // * 16777216
+       {8, "298023223876953125"},  // * 33554432
+       {8, "1490116119384765625"}, // * 67108864
+       {9, "7450580596923828125"}, // * 134217728
+}
+
+// Is the leading prefix of b lexicographically less than s?
+func prefixIsLessThan(b []byte, s string) bool {
+       for i := 0; i < len(s); i++ {
+               if i >= len(b) {
+                       return true
+               }
+               if b[i] != s[i] {
+                       return b[i] < s[i]
+               }
+       }
+       return false
+}
+
+// Binary shift left (/ 2) by k bits.  k <= maxShift to avoid overflow.
+func leftShift(a *decimal, k uint) {
+       delta := leftcheats[k].delta
+       if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
+               delta--
+       }
+
+       r := a.nd         // read index
+       w := a.nd + delta // write index
+       n := 0
+
+       // Pick up a digit, put down a digit.
+       for r--; r >= 0; r-- {
+               n += (int(a.d[r]) - '0') << k
+               quo := n / 10
+               rem := n - 10*quo
+               w--
+               a.d[w] = byte(rem + '0')
+               n = quo
+       }
+
+       // Put down extra digits.
+       for n > 0 {
+               quo := n / 10
+               rem := n - 10*quo
+               w--
+               a.d[w] = byte(rem + '0')
+               n = quo
+       }
+
+       a.nd += delta
+       a.dp += delta
+       trim(a)
+}
+
+// Binary shift left (k > 0) or right (k < 0).
+// Returns receiver for convenience.
+func (a *decimal) Shift(k int) *decimal {
+       switch {
+       case a.nd == 0:
+               // nothing to do: a == 0
+       case k > 0:
+               for k > maxShift {
+                       leftShift(a, maxShift)
+                       k -= maxShift
+               }
+               leftShift(a, uint(k))
+       case k < 0:
+               for k < -maxShift {
+                       rightShift(a, maxShift)
+                       k += maxShift
+               }
+               rightShift(a, uint(-k))
+       }
+       return a
+}
+
+// If we chop a at nd digits, should we round up?
+func shouldRoundUp(a *decimal, nd int) bool {
+       if nd < 0 || nd >= a.nd {
+               return false
+       }
+       if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even
+               return nd > 0 && (a.d[nd-1]-'0')%2 != 0
+       }
+       // not halfway - digit tells all
+       return a.d[nd] >= '5'
+}
+
+// Round a to nd digits (or fewer).
+// Returns receiver for convenience.
+// If nd is zero, it means we're rounding
+// just to the left of the digits, as in
+// 0.09 -> 0.1.
+func (a *decimal) Round(nd int) *decimal {
+       if nd < 0 || nd >= a.nd {
+               return a
+       }
+       if shouldRoundUp(a, nd) {
+               return a.RoundUp(nd)
+       }
+       return a.RoundDown(nd)
+}
+
+// Round a down to nd digits (or fewer).
+// Returns receiver for convenience.
+func (a *decimal) RoundDown(nd int) *decimal {
+       if nd < 0 || nd >= a.nd {
+               return a
+       }
+       a.nd = nd
+       trim(a)
+       return a
+}
+
+// Round a up to nd digits (or fewer).
+// Returns receiver for convenience.
+func (a *decimal) RoundUp(nd int) *decimal {
+       if nd < 0 || nd >= a.nd {
+               return a
+       }
+
+       // round up
+       for i := nd - 1; i >= 0; i-- {
+               c := a.d[i]
+               if c < '9' { // can stop after this digit
+                       a.d[i]++
+                       a.nd = i + 1
+                       return a
+               }
+       }
+
+       // Number is all 9s.
+       // Change to single 1 with adjusted decimal point.
+       a.d[0] = '1'
+       a.nd = 1
+       a.dp++
+       return a
+}
+
+// Extract integer part, rounded appropriately.
+// No guarantees about overflow.
+func (a *decimal) RoundedInteger() uint64 {
+       if a.dp > 20 {
+               return 0xFFFFFFFFFFFFFFFF
+       }
+       var i int
+       n := uint64(0)
+       for i = 0; i < a.dp && i < a.nd; i++ {
+               n = n*10 + uint64(a.d[i]-'0')
+       }
+       for ; i < a.dp; i++ {
+               n *= 10
+       }
+       if shouldRoundUp(a, a.dp) {
+               n++
+       }
+       return n
+}
diff --git a/libgo/go/strconv/decimal_test.go b/libgo/go/strconv/decimal_test.go
new file mode 100644 (file)
index 0000000..9b79035
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+       . "strconv"
+       "testing"
+)
+
+type shiftTest struct {
+       i     uint64
+       shift int
+       out   string
+}
+
+var shifttests = []shiftTest{
+       {0, -100, "0"},
+       {0, 100, "0"},
+       {1, 100, "1267650600228229401496703205376"},
+       {1, -100,
+               "0.00000000000000000000000000000078886090522101180541" +
+                       "17285652827862296732064351090230047702789306640625",
+       },
+       {12345678, 8, "3160493568"},
+       {12345678, -8, "48225.3046875"},
+       {195312, 9, "99999744"},
+       {1953125, 9, "1000000000"},
+}
+
+func TestDecimalShift(t *testing.T) {
+       for i := 0; i < len(shifttests); i++ {
+               test := &shifttests[i]
+               s := NewDecimal(test.i).Shift(test.shift).String()
+               if s != test.out {
+                       t.Errorf("Decimal %v << %v = %v, want %v",
+                               test.i, test.shift, s, test.out)
+               }
+       }
+}
+
+type roundTest struct {
+       i               uint64
+       nd              int
+       down, round, up string
+       int             uint64
+}
+
+var roundtests = []roundTest{
+       {0, 4, "0", "0", "0", 0},
+       {12344999, 4, "12340000", "12340000", "12350000", 12340000},
+       {12345000, 4, "12340000", "12340000", "12350000", 12340000},
+       {12345001, 4, "12340000", "12350000", "12350000", 12350000},
+       {23454999, 4, "23450000", "23450000", "23460000", 23450000},
+       {23455000, 4, "23450000", "23460000", "23460000", 23460000},
+       {23455001, 4, "23450000", "23460000", "23460000", 23460000},
+
+       {99994999, 4, "99990000", "99990000", "100000000", 99990000},
+       {99995000, 4, "99990000", "100000000", "100000000", 100000000},
+       {99999999, 4, "99990000", "100000000", "100000000", 100000000},
+
+       {12994999, 4, "12990000", "12990000", "13000000", 12990000},
+       {12995000, 4, "12990000", "13000000", "13000000", 13000000},
+       {12999999, 4, "12990000", "13000000", "13000000", 13000000},
+}
+
+func TestDecimalRound(t *testing.T) {
+       for i := 0; i < len(roundtests); i++ {
+               test := &roundtests[i]
+               s := NewDecimal(test.i).RoundDown(test.nd).String()
+               if s != test.down {
+                       t.Errorf("Decimal %v RoundDown %d = %v, want %v",
+                               test.i, test.nd, s, test.down)
+               }
+               s = NewDecimal(test.i).Round(test.nd).String()
+               if s != test.round {
+                       t.Errorf("Decimal %v Round %d = %v, want %v",
+                               test.i, test.nd, s, test.down)
+               }
+               s = NewDecimal(test.i).RoundUp(test.nd).String()
+               if s != test.up {
+                       t.Errorf("Decimal %v RoundUp %d = %v, want %v",
+                               test.i, test.nd, s, test.up)
+               }
+       }
+}
+
+type roundIntTest struct {
+       i     uint64
+       shift int
+       int   uint64
+}
+
+var roundinttests = []roundIntTest{
+       {0, 100, 0},
+       {512, -8, 2},
+       {513, -8, 2},
+       {640, -8, 2},
+       {641, -8, 3},
+       {384, -8, 2},
+       {385, -8, 2},
+       {383, -8, 1},
+       {1, 100, 1<<64 - 1},
+       {1000, 0, 1000},
+}
+
+func TestDecimalRoundedInteger(t *testing.T) {
+       for i := 0; i < len(roundinttests); i++ {
+               test := roundinttests[i]
+               int := NewDecimal(test.i).Shift(test.shift).RoundedInteger()
+               if int != test.int {
+                       t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v",
+                               test.i, test.shift, int, test.int)
+               }
+       }
+}
diff --git a/libgo/go/strconv/fp_test.go b/libgo/go/strconv/fp_test.go
new file mode 100644 (file)
index 0000000..305adcc
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+       "bufio"
+       "fmt"
+       "os"
+       "strconv"
+       "strings"
+       "testing"
+)
+
+func pow2(i int) float64 {
+       switch {
+       case i < 0:
+               return 1 / pow2(-i)
+       case i == 0:
+               return 1
+       case i == 1:
+               return 2
+       }
+       return pow2(i/2) * pow2(i-i/2)
+}
+
+// Wrapper around strconv.Atof64.  Handles dddddp+ddd (binary exponent)
+// itself, passes the rest on to strconv.Atof64.
+func myatof64(s string) (f float64, ok bool) {
+       a := strings.Split(s, "p", 2)
+       if len(a) == 2 {
+               n, err := strconv.Atoi64(a[0])
+               if err != nil {
+                       return 0, false
+               }
+               e, err1 := strconv.Atoi(a[1])
+               if err1 != nil {
+                       println("bad e", a[1])
+                       return 0, false
+               }
+               v := float64(n)
+               // We expect that v*pow2(e) fits in a float64,
+               // but pow2(e) by itself may not.  Be careful.
+               if e <= -1000 {
+                       v *= pow2(-1000)
+                       e += 1000
+                       for e < 0 {
+                               v /= 2
+                               e++
+                       }
+                       return v, true
+               }
+               if e >= 1000 {
+                       v *= pow2(1000)
+                       e -= 1000
+                       for e > 0 {
+                               v *= 2
+                               e--
+                       }
+                       return v, true
+               }
+               return v * pow2(e), true
+       }
+       f1, err := strconv.Atof64(s)
+       if err != nil {
+               return 0, false
+       }
+       return f1, true
+}
+
+// Wrapper around strconv.Atof32.  Handles dddddp+ddd (binary exponent)
+// itself, passes the rest on to strconv.Atof32.
+func myatof32(s string) (f float32, ok bool) {
+       a := strings.Split(s, "p", 2)
+       if len(a) == 2 {
+               n, err := strconv.Atoi(a[0])
+               if err != nil {
+                       println("bad n", a[0])
+                       return 0, false
+               }
+               e, err1 := strconv.Atoi(a[1])
+               if err1 != nil {
+                       println("bad p", a[1])
+                       return 0, false
+               }
+               return float32(float64(n) * pow2(e)), true
+       }
+       f1, err1 := strconv.Atof32(s)
+       if err1 != nil {
+               return 0, false
+       }
+       return f1, true
+}
+
+func TestFp(t *testing.T) {
+       f, err := os.Open("testfp.txt", os.O_RDONLY, 0)
+       if err != nil {
+               t.Fatal("testfp: open testfp.txt:", err.String())
+       }
+       defer f.Close()
+
+       b := bufio.NewReader(f)
+
+       lineno := 0
+       for {
+               line, err2 := b.ReadString('\n')
+               if err2 == os.EOF {
+                       break
+               }
+               if err2 != nil {
+                       t.Fatal("testfp: read testfp.txt: " + err2.String())
+               }
+               line = line[0 : len(line)-1]
+               lineno++
+               if len(line) == 0 || line[0] == '#' {
+                       continue
+               }
+               a := strings.Split(line, " ", -1)
+               if len(a) != 4 {
+                       t.Error("testfp.txt:", lineno, ": wrong field count")
+                       continue
+               }
+               var s string
+               var v float64
+               switch a[0] {
+               case "float64":
+                       var ok bool
+                       v, ok = myatof64(a[2])
+                       if !ok {
+                               t.Error("testfp.txt:", lineno, ": cannot atof64 ", a[2])
+                               continue
+                       }
+                       s = fmt.Sprintf(a[1], v)
+               case "float32":
+                       v1, ok := myatof32(a[2])
+                       if !ok {
+                               t.Error("testfp.txt:", lineno, ": cannot atof32 ", a[2])
+                               continue
+                       }
+                       s = fmt.Sprintf(a[1], v1)
+                       v = float64(v1)
+               }
+               if s != a[3] {
+                       t.Error("testfp.txt:", lineno, ": ", a[0], " ", a[1], " ", a[2], " (", v, ") ",
+                               "want ", a[3], " got ", s)
+               }
+       }
+}
diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go
new file mode 100644 (file)
index 0000000..3659243
--- /dev/null
@@ -0,0 +1,425 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Binary to decimal floating point conversion.
+// Algorithm:
+//   1) store mantissa in multiprecision decimal
+//   2) shift decimal by exponent
+//   3) read digits out & format
+
+package strconv
+
+import "math"
+
+// TODO: move elsewhere?
+type floatInfo struct {
+       mantbits uint
+       expbits  uint
+       bias     int
+}
+
+var float32info = floatInfo{23, 8, -127}
+var float64info = floatInfo{52, 11, -1023}
+
+func floatsize() int {
+       // Figure out whether float is float32 or float64.
+       // 1e-35 is representable in both, but 1e-70
+       // is too small for a float32.
+       var f float = 1e-35
+       if f*f == 0 {
+               return 32
+       }
+       return 64
+}
+
+// Floatsize gives the size of the float type, either 32 or 64.
+var FloatSize = floatsize()
+
+// Ftoa32 converts the 32-bit floating-point number f to a string,
+// according to the format fmt and precision prec.
+//
+// The format fmt is one of
+// 'b' (-ddddp±ddd, a binary exponent),
+// 'e' (-d.dddde±dd, a decimal exponent),
+// 'f' (-ddd.dddd, no exponent), or
+// 'g' ('e' for large exponents, 'f' otherwise).
+//
+// The precision prec controls the number of digits
+// (excluding the exponent) printed by the 'e', 'f', and 'g' formats.
+// For 'e' and 'f' it is the number of digits after the decimal point.
+// For 'g' it is the total number of digits.
+// The special precision -1 uses the smallest number of digits
+// necessary such that Atof32 will return f exactly.
+//
+// Ftoa32(f) is not the same as Ftoa64(float32(f)),
+// because correct rounding and the number of digits
+// needed to identify f depend on the precision of the representation.
+func Ftoa32(f float32, fmt byte, prec int) string {
+       return genericFtoa(uint64(math.Float32bits(f)), fmt, prec, &float32info)
+}
+
+// Ftoa64 is like Ftoa32 but converts a 64-bit floating-point number.
+func Ftoa64(f float64, fmt byte, prec int) string {
+       return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
+}
+
+// FtoaN converts the 64-bit floating-point number f to a string,
+// according to the format fmt and precision prec, but it rounds the
+// result assuming that it was obtained from a floating-point value
+// of n bits (32 or 64).
+func FtoaN(f float64, fmt byte, prec int, n int) string {
+       if n == 32 {
+               return Ftoa32(float32(f), fmt, prec)
+       }
+       return Ftoa64(f, fmt, prec)
+}
+
+// Ftoa behaves as Ftoa32 or Ftoa64, depending on the size of the float type.
+func Ftoa(f float, fmt byte, prec int) string {
+       if FloatSize == 32 {
+               return Ftoa32(float32(f), fmt, prec)
+       }
+       return Ftoa64(float64(f), fmt, prec)
+}
+
+func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
+       neg := bits>>flt.expbits>>flt.mantbits != 0
+       exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
+       mant := bits & (uint64(1)<<flt.mantbits - 1)
+
+       switch exp {
+       case 1<<flt.expbits - 1:
+               // Inf, NaN
+               if mant != 0 {
+                       return "NaN"
+               }
+               if neg {
+                       return "-Inf"
+               }
+               return "+Inf"
+
+       case 0:
+               // denormalized
+               exp++
+
+       default:
+               // add implicit top bit
+               mant |= uint64(1) << flt.mantbits
+       }
+       exp += flt.bias
+
+       // Pick off easy binary format.
+       if fmt == 'b' {
+               return fmtB(neg, mant, exp, flt)
+       }
+
+       // Create exact decimal representation.
+       // The shift is exp - flt.mantbits because mant is a 1-bit integer
+       // followed by a flt.mantbits fraction, and we are treating it as
+       // a 1+flt.mantbits-bit integer.
+       d := newDecimal(mant).Shift(exp - int(flt.mantbits))
+
+       // Round appropriately.
+       // Negative precision means "only as much as needed to be exact."
+       shortest := false
+       if prec < 0 {
+               shortest = true
+               roundShortest(d, mant, exp, flt)
+               switch fmt {
+               case 'e', 'E':
+                       prec = d.nd - 1
+               case 'f':
+                       prec = max(d.nd-d.dp, 0)
+               case 'g', 'G':
+                       prec = d.nd
+               }
+       } else {
+               switch fmt {
+               case 'e', 'E':
+                       d.Round(prec + 1)
+               case 'f':
+                       d.Round(d.dp + prec)
+               case 'g', 'G':
+                       if prec == 0 {
+                               prec = 1
+                       }
+                       d.Round(prec)
+               }
+       }
+
+       switch fmt {
+       case 'e', 'E':
+               return fmtE(neg, d, prec, fmt)
+       case 'f':
+               return fmtF(neg, d, prec)
+       case 'g', 'G':
+               // trailing fractional zeros in 'e' form will be trimmed.
+               eprec := prec
+               if eprec > d.nd && d.nd >= d.dp {
+                       eprec = d.nd
+               }
+               // %e is used if the exponent from the conversion
+               // is less than -4 or greater than or equal to the precision.
+               // if precision was the shortest possible, use precision 6 for this decision.
+               if shortest {
+                       eprec = 6
+               }
+               exp := d.dp - 1
+               if exp < -4 || exp >= eprec {
+                       if prec > d.nd {
+                               prec = d.nd
+                       }
+                       return fmtE(neg, d, prec-1, fmt+'e'-'g')
+               }
+               if prec > d.dp {
+                       prec = d.nd
+               }
+               return fmtF(neg, d, max(prec-d.dp, 0))
+       }
+
+       return "%" + string(fmt)
+}
+
+// Round d (= mant * 2^exp) to the shortest number of digits
+// that will let the original floating point value be precisely
+// reconstructed.  Size is original floating point size (64 or 32).
+func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
+       // If mantissa is zero, the number is zero; stop now.
+       if mant == 0 {
+               d.nd = 0
+               return
+       }
+
+       // TODO(rsc): Unless exp == minexp, if the number of digits in d
+       // is less than 17, it seems likely that it would be
+       // the shortest possible number already.  So maybe we can
+       // bail out without doing the extra multiprecision math here.
+
+       // Compute upper and lower such that any decimal number
+       // between upper and lower (possibly inclusive)
+       // will round to the original floating point number.
+
+       // d = mant << (exp - mantbits)
+       // Next highest floating point number is mant+1 << exp-mantbits.
+       // Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
+       upper := newDecimal(mant*2 + 1).Shift(exp - int(flt.mantbits) - 1)
+
+       // d = mant << (exp - mantbits)
+       // Next lowest floating point number is mant-1 << exp-mantbits,
+       // unless mant-1 drops the significant bit and exp is not the minimum exp,
+       // in which case the next lowest is mant*2-1 << exp-mantbits-1.
+       // Either way, call it mantlo << explo-mantbits.
+       // Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
+       minexp := flt.bias + 1 // minimum possible exponent
+       var mantlo uint64
+       var explo int
+       if mant > 1<<flt.mantbits || exp == minexp {
+               mantlo = mant - 1
+               explo = exp
+       } else {
+               mantlo = mant*2 - 1
+               explo = exp - 1
+       }
+       lower := newDecimal(mantlo*2 + 1).Shift(explo - int(flt.mantbits) - 1)
+
+       // The upper and lower bounds are possible outputs only if
+       // the original mantissa is even, so that IEEE round-to-even
+       // would round to the original mantissa and not the neighbors.
+       inclusive := mant%2 == 0
+
+       // Now we can figure out the minimum number of digits required.
+       // Walk along until d has distinguished itself from upper and lower.
+       for i := 0; i < d.nd; i++ {
+               var l, m, u byte // lower, middle, upper digits
+               if i < lower.nd {
+                       l = lower.d[i]
+               } else {
+                       l = '0'
+               }
+               m = d.d[i]
+               if i < upper.nd {
+                       u = upper.d[i]
+               } else {
+                       u = '0'
+               }
+
+               // Okay to round down (truncate) if lower has a different digit
+               // or if lower is inclusive and is exactly the result of rounding down.
+               okdown := l != m || (inclusive && l == m && i+1 == lower.nd)
+
+               // Okay to round up if upper has a different digit and
+               // either upper is inclusive or upper is bigger than the result of rounding up.
+               okup := m != u && (inclusive || i+1 < upper.nd)
+
+               // If it's okay to do either, then round to the nearest one.
+               // If it's okay to do only one, do it.
+               switch {
+               case okdown && okup:
+                       d.Round(i + 1)
+                       return
+               case okdown:
+                       d.RoundDown(i + 1)
+                       return
+               case okup:
+                       d.RoundUp(i + 1)
+                       return
+               }
+       }
+}
+
+// %e: -d.ddddde±dd
+func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
+       buf := make([]byte, 3+max(prec, 0)+30) // "-0." + prec digits + exp
+       w := 0                                 // write index
+
+       // sign
+       if neg {
+               buf[w] = '-'
+               w++
+       }
+
+       // first digit
+       if d.nd == 0 {
+               buf[w] = '0'
+       } else {
+               buf[w] = d.d[0]
+       }
+       w++
+
+       // .moredigits
+       if prec > 0 {
+               buf[w] = '.'
+               w++
+               for i := 0; i < prec; i++ {
+                       if 1+i < d.nd {
+                               buf[w] = d.d[1+i]
+                       } else {
+                               buf[w] = '0'
+                       }
+                       w++
+               }
+       }
+
+       // e±
+       buf[w] = fmt
+       w++
+       exp := d.dp - 1
+       if d.nd == 0 { // special case: 0 has exponent 0
+               exp = 0
+       }
+       if exp < 0 {
+               buf[w] = '-'
+               exp = -exp
+       } else {
+               buf[w] = '+'
+       }
+       w++
+
+       // dddd
+       // count digits
+       n := 0
+       for e := exp; e > 0; e /= 10 {
+               n++
+       }
+       // leading zeros
+       for i := n; i < 2; i++ {
+               buf[w] = '0'
+               w++
+       }
+       // digits
+       w += n
+       n = 0
+       for e := exp; e > 0; e /= 10 {
+               n++
+               buf[w-n] = byte(e%10 + '0')
+       }
+
+       return string(buf[0:w])
+}
+
+// %f: -ddddddd.ddddd
+func fmtF(neg bool, d *decimal, prec int) string {
+       buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0))
+       w := 0
+
+       // sign
+       if neg {
+               buf[w] = '-'
+               w++
+       }
+
+       // integer, padded with zeros as needed.
+       if d.dp > 0 {
+               var i int
+               for i = 0; i < d.dp && i < d.nd; i++ {
+                       buf[w] = d.d[i]
+                       w++
+               }
+               for ; i < d.dp; i++ {
+                       buf[w] = '0'
+                       w++
+               }
+       } else {
+               buf[w] = '0'
+               w++
+       }
+
+       // fraction
+       if prec > 0 {
+               buf[w] = '.'
+               w++
+               for i := 0; i < prec; i++ {
+                       if d.dp+i < 0 || d.dp+i >= d.nd {
+                               buf[w] = '0'
+                       } else {
+                               buf[w] = d.d[d.dp+i]
+                       }
+                       w++
+               }
+       }
+
+       return string(buf[0:w])
+}
+
+// %b: -ddddddddp+ddd
+func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
+       var buf [50]byte
+       w := len(buf)
+       exp -= int(flt.mantbits)
+       esign := byte('+')
+       if exp < 0 {
+               esign = '-'
+               exp = -exp
+       }
+       n := 0
+       for exp > 0 || n < 1 {
+               n++
+               w--
+               buf[w] = byte(exp%10 + '0')
+               exp /= 10
+       }
+       w--
+       buf[w] = esign
+       w--
+       buf[w] = 'p'
+       n = 0
+       for mant > 0 || n < 1 {
+               n++
+               w--
+               buf[w] = byte(mant%10 + '0')
+               mant /= 10
+       }
+       if neg {
+               w--
+               buf[w] = '-'
+       }
+       return string(buf[w:])
+}
+
+func max(a, b int) int {
+       if a > b {
+               return a
+       }
+       return b
+}
diff --git a/libgo/go/strconv/ftoa_test.go b/libgo/go/strconv/ftoa_test.go
new file mode 100644 (file)
index 0000000..6044afd
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+       "math"
+       . "strconv"
+       "testing"
+)
+
+type ftoaTest struct {
+       f    float64
+       fmt  byte
+       prec int
+       s    string
+}
+
+func fdiv(a, b float64) float64 { return a / b } // keep compiler in the dark
+
+const (
+       below1e23 = 99999999999999974834176
+       above1e23 = 100000000000000008388608
+)
+
+var ftoatests = []ftoaTest{
+       {1, 'e', 5, "1.00000e+00"},
+       {1, 'f', 5, "1.00000"},
+       {1, 'g', 5, "1"},
+       {1, 'g', -1, "1"},
+       {20, 'g', -1, "20"},
+       {1234567.8, 'g', -1, "1.2345678e+06"},
+       {200000, 'g', -1, "200000"},
+       {2000000, 'g', -1, "2e+06"},
+
+       // g conversion and zero suppression
+       {400, 'g', 2, "4e+02"},
+       {40, 'g', 2, "40"},
+       {4, 'g', 2, "4"},
+       {.4, 'g', 2, "0.4"},
+       {.04, 'g', 2, "0.04"},
+       {.004, 'g', 2, "0.004"},
+       {.0004, 'g', 2, "0.0004"},
+       {.00004, 'g', 2, "4e-05"},
+       {.000004, 'g', 2, "4e-06"},
+
+       {0, 'e', 5, "0.00000e+00"},
+       {0, 'f', 5, "0.00000"},
+       {0, 'g', 5, "0"},
+       {0, 'g', -1, "0"},
+
+       {-1, 'e', 5, "-1.00000e+00"},
+       {-1, 'f', 5, "-1.00000"},
+       {-1, 'g', 5, "-1"},
+       {-1, 'g', -1, "-1"},
+
+       {12, 'e', 5, "1.20000e+01"},
+       {12, 'f', 5, "12.00000"},
+       {12, 'g', 5, "12"},
+       {12, 'g', -1, "12"},
+
+       {123456700, 'e', 5, "1.23457e+08"},
+       {123456700, 'f', 5, "123456700.00000"},
+       {123456700, 'g', 5, "1.2346e+08"},
+       {123456700, 'g', -1, "1.234567e+08"},
+
+       {1.2345e6, 'e', 5, "1.23450e+06"},
+       {1.2345e6, 'f', 5, "1234500.00000"},
+       {1.2345e6, 'g', 5, "1.2345e+06"},
+
+       {1e23, 'e', 17, "9.99999999999999916e+22"},
+       {1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
+       {1e23, 'g', 17, "9.9999999999999992e+22"},
+
+       {1e23, 'e', -1, "1e+23"},
+       {1e23, 'f', -1, "100000000000000000000000"},
+       {1e23, 'g', -1, "1e+23"},
+
+       {below1e23, 'e', 17, "9.99999999999999748e+22"},
+       {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
+       {below1e23, 'g', 17, "9.9999999999999975e+22"},
+
+       {below1e23, 'e', -1, "9.999999999999997e+22"},
+       {below1e23, 'f', -1, "99999999999999970000000"},
+       {below1e23, 'g', -1, "9.999999999999997e+22"},
+
+       {above1e23, 'e', 17, "1.00000000000000008e+23"},
+       {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
+       {above1e23, 'g', 17, "1.0000000000000001e+23"},
+
+       {above1e23, 'e', -1, "1.0000000000000001e+23"},
+       {above1e23, 'f', -1, "100000000000000010000000"},
+       {above1e23, 'g', -1, "1.0000000000000001e+23"},
+
+       {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
+       {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+
+       {32, 'g', -1, "32"},
+       {32, 'g', 0, "3e+01"},
+
+       {100, 'x', -1, "%x"},
+
+       {math.NaN(), 'g', -1, "NaN"},
+       {-math.NaN(), 'g', -1, "NaN"},
+       {math.Inf(0), 'g', -1, "+Inf"},
+       {math.Inf(-1), 'g', -1, "-Inf"},
+       {-math.Inf(0), 'g', -1, "-Inf"},
+
+       {-1, 'b', -1, "-4503599627370496p-52"},
+
+       // fixed bugs
+       {0.9, 'f', 1, "0.9"},
+       {0.09, 'f', 1, "0.1"},
+       {0.0999, 'f', 1, "0.1"},
+       {0.05, 'f', 1, "0.1"},
+       {0.05, 'f', 0, "0"},
+       {0.5, 'f', 1, "0.5"},
+       {0.5, 'f', 0, "0"},
+       {1.5, 'f', 0, "2"},
+}
+
+func TestFtoa(t *testing.T) {
+       if FloatSize != 32 {
+               println("floatsize: ", FloatSize)
+               panic("floatsize")
+       }
+       for i := 0; i < len(ftoatests); i++ {
+               test := &ftoatests[i]
+               s := Ftoa64(test.f, test.fmt, test.prec)
+               if s != test.s {
+                       t.Error("test", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+               }
+               s = FtoaN(test.f, test.fmt, test.prec, 64)
+               if s != test.s {
+                       t.Error("testN=64", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+               }
+               if float64(float32(test.f)) == test.f && test.fmt != 'b' {
+                       s := Ftoa32(float32(test.f), test.fmt, test.prec)
+                       if s != test.s {
+                               t.Error("test32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+                       }
+                       s = FtoaN(test.f, test.fmt, test.prec, 32)
+                       if s != test.s {
+                               t.Error("testN=32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+                       }
+               }
+       }
+}
diff --git a/libgo/go/strconv/internal_test.go b/libgo/go/strconv/internal_test.go
new file mode 100644 (file)
index 0000000..9a7f4f0
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// export access to strconv internals for tests
+
+package strconv
+
+func NewDecimal(i uint64) *decimal { return newDecimal(i) }
+
+func SetOptimize(b bool) bool {
+       old := optimize
+       optimize = b
+       return old
+}
diff --git a/libgo/go/strconv/itoa.go b/libgo/go/strconv/itoa.go
new file mode 100644 (file)
index 0000000..a0a7496
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+// Uitob64 returns the string representation of i in the given base.
+func Uitob64(u uint64, base uint) string {
+       if base < 2 || 36 < base {
+               panic("invalid base " + Uitoa(base))
+       }
+       if u == 0 {
+               return "0"
+       }
+
+       // Assemble decimal in reverse order.
+       var buf [64]byte
+       j := len(buf)
+       b := uint64(base)
+       for u > 0 {
+               j--
+               buf[j] = "0123456789abcdefghijklmnopqrstuvwxyz"[u%b]
+               u /= b
+       }
+
+       return string(buf[j:])
+}
+
+// Itob64 returns the string representation of i in the given base.
+func Itob64(i int64, base uint) string {
+       if i == 0 {
+               return "0"
+       }
+
+       if i < 0 {
+               return "-" + Uitob64(-uint64(i), base)
+       }
+       return Uitob64(uint64(i), base)
+}
+
+// Itoa64 returns the decimal string representation of i.
+func Itoa64(i int64) string { return Itob64(i, 10) }
+
+// Uitoa64 returns the decimal string representation of i.
+func Uitoa64(i uint64) string { return Uitob64(i, 10) }
+
+// Uitob returns the string representation of i in the given base.
+func Uitob(i uint, base uint) string { return Uitob64(uint64(i), base) }
+
+// Itob returns the string representation of i in the given base.
+func Itob(i int, base uint) string { return Itob64(int64(i), base) }
+
+// Itoa returns the decimal string representation of i.
+func Itoa(i int) string { return Itob64(int64(i), 10) }
+
+// Uitoa returns the decimal string representation of i.
+func Uitoa(i uint) string { return Uitob64(uint64(i), 10) }
diff --git a/libgo/go/strconv/itoa_test.go b/libgo/go/strconv/itoa_test.go
new file mode 100644 (file)
index 0000000..8514b21
--- /dev/null
@@ -0,0 +1,174 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+       . "strconv"
+       "testing"
+)
+
+type itob64Test struct {
+       in   int64
+       base uint
+       out  string
+}
+
+var itob64tests = []itob64Test{
+       {0, 10, "0"},
+       {1, 10, "1"},
+       {-1, 10, "-1"},
+       {12345678, 10, "12345678"},
+       {-987654321, 10, "-987654321"},
+       {1<<31 - 1, 10, "2147483647"},
+       {-1<<31 + 1, 10, "-2147483647"},
+       {1 << 31, 10, "2147483648"},
+       {-1 << 31, 10, "-2147483648"},
+       {1<<31 + 1, 10, "2147483649"},
+       {-1<<31 - 1, 10, "-2147483649"},
+       {1<<32 - 1, 10, "4294967295"},
+       {-1<<32 + 1, 10, "-4294967295"},
+       {1 << 32, 10, "4294967296"},
+       {-1 << 32, 10, "-4294967296"},
+       {1<<32 + 1, 10, "4294967297"},
+       {-1<<32 - 1, 10, "-4294967297"},
+       {1 << 50, 10, "1125899906842624"},
+       {1<<63 - 1, 10, "9223372036854775807"},
+       {-1<<63 + 1, 10, "-9223372036854775807"},
+       {-1 << 63, 10, "-9223372036854775808"},
+
+       {0, 2, "0"},
+       {10, 2, "1010"},
+       {-1, 2, "-1"},
+       {1 << 15, 2, "1000000000000000"},
+
+       {-8, 8, "-10"},
+       {057635436545, 8, "57635436545"},
+       {1 << 24, 8, "100000000"},
+
+       {16, 16, "10"},
+       {-0x123456789abcdef, 16, "-123456789abcdef"},
+       {1<<63 - 1, 16, "7fffffffffffffff"},
+       {1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"},
+
+       {16, 17, "g"},
+       {25, 25, "10"},
+       {(((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, 35, "holycow"},
+       {(((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, 36, "holycow"},
+}
+
+func TestItoa(t *testing.T) {
+       for _, test := range itob64tests {
+               s := Itob64(test.in, test.base)
+               if s != test.out {
+                       t.Errorf("Itob64(%v, %v) = %v want %v",
+                               test.in, test.base, s, test.out)
+               }
+
+               if test.in >= 0 {
+                       s := Uitob64(uint64(test.in), test.base)
+                       if s != test.out {
+                               t.Errorf("Uitob64(%v, %v) = %v want %v",
+                                       test.in, test.base, s, test.out)
+                       }
+               }
+
+               if int64(int(test.in)) == test.in {
+                       s := Itob(int(test.in), test.base)
+                       if s != test.out {
+                               t.Errorf("Itob(%v, %v) = %v want %v",
+                                       test.in, test.base, s, test.out)
+                       }
+
+                       if test.in >= 0 {
+                               s := Uitob(uint(test.in), test.base)
+                               if s != test.out {
+                                       t.Errorf("Uitob(%v, %v) = %v want %v",
+                                               test.in, test.base, s, test.out)
+                               }
+                       }
+               }
+
+               if test.base == 10 {
+                       s := Itoa64(test.in)
+                       if s != test.out {
+                               t.Errorf("Itoa64(%v) = %v want %v",
+                                       test.in, s, test.out)
+                       }
+
+                       if test.in >= 0 {
+                               s := Uitob64(uint64(test.in), test.base)
+                               if s != test.out {
+                                       t.Errorf("Uitob64(%v, %v) = %v want %v",
+                                               test.in, test.base, s, test.out)
+                               }
+                       }
+
+                       if int64(int(test.in)) == test.in {
+                               s := Itoa(int(test.in))
+                               if s != test.out {
+                                       t.Errorf("Itoa(%v) = %v want %v",
+                                               test.in, s, test.out)
+                               }
+
+                               if test.in >= 0 {
+                                       s := Uitoa(uint(test.in))
+                                       if s != test.out {
+                                               t.Errorf("Uitoa(%v) = %v want %v",
+                                                       test.in, s, test.out)
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+type uitob64Test struct {
+       in   uint64
+       base uint
+       out  string
+}
+
+var uitob64tests = []uitob64Test{
+       {1<<63 - 1, 10, "9223372036854775807"},
+       {1 << 63, 10, "9223372036854775808"},
+       {1<<63 + 1, 10, "9223372036854775809"},
+       {1<<64 - 2, 10, "18446744073709551614"},
+       {1<<64 - 1, 10, "18446744073709551615"},
+       {1<<64 - 1, 2, "1111111111111111111111111111111111111111111111111111111111111111"},
+}
+
+func TestUitoa(t *testing.T) {
+       for _, test := range uitob64tests {
+               s := Uitob64(test.in, test.base)
+               if s != test.out {
+                       t.Errorf("Uitob64(%v, %v) = %v want %v",
+                               test.in, test.base, s, test.out)
+               }
+
+               if uint64(uint(test.in)) == test.in {
+                       s := Uitob(uint(test.in), test.base)
+                       if s != test.out {
+                               t.Errorf("Uitob(%v, %v) = %v want %v",
+                                       test.in, test.base, s, test.out)
+                       }
+               }
+
+               if test.base == 10 {
+                       s := Uitoa64(test.in)
+                       if s != test.out {
+                               t.Errorf("Uitoa64(%v) = %v want %v",
+                                       test.in, s, test.out)
+                       }
+
+                       if uint64(uint(test.in)) == test.in {
+                               s := Uitoa(uint(test.in))
+                               if s != test.out {
+                                       t.Errorf("Uitoa(%v) = %v want %v",
+                                               test.in, s, test.out)
+                               }
+                       }
+               }
+       }
+}
diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go
new file mode 100644 (file)
index 0000000..ed58897
--- /dev/null
@@ -0,0 +1,264 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import (
+       "bytes"
+       "os"
+       "strings"
+       "unicode"
+       "utf8"
+)
+
+const lowerhex = "0123456789abcdef"
+
+// Quote returns a double-quoted Go string literal
+// representing s.  The returned string s uses Go escape
+// sequences (\t, \n, \xFF, \u0100) for control characters
+// and non-ASCII characters.
+func Quote(s string) string {
+       var buf bytes.Buffer
+       buf.WriteByte('"')
+       for ; len(s) > 0; s = s[1:] {
+               switch c := s[0]; {
+               case c == '"':
+                       buf.WriteString(`\"`)
+               case c == '\\':
+                       buf.WriteString(`\\`)
+               case ' ' <= c && c <= '~':
+                       buf.WriteString(string(c))
+               case c == '\a':
+                       buf.WriteString(`\a`)
+               case c == '\b':
+                       buf.WriteString(`\b`)
+               case c == '\f':
+                       buf.WriteString(`\f`)
+               case c == '\n':
+                       buf.WriteString(`\n`)
+               case c == '\r':
+                       buf.WriteString(`\r`)
+               case c == '\t':
+                       buf.WriteString(`\t`)
+               case c == '\v':
+                       buf.WriteString(`\v`)
+
+               case c >= utf8.RuneSelf && utf8.FullRuneInString(s):
+                       r, size := utf8.DecodeRuneInString(s)
+                       if r == utf8.RuneError && size == 1 {
+                               goto EscX
+                       }
+                       s = s[size-1:] // next iteration will slice off 1 more
+                       if r < 0x10000 {
+                               buf.WriteString(`\u`)
+                               for j := uint(0); j < 4; j++ {
+                                       buf.WriteByte(lowerhex[(r>>(12-4*j))&0xF])
+                               }
+                       } else {
+                               buf.WriteString(`\U`)
+                               for j := uint(0); j < 8; j++ {
+                                       buf.WriteByte(lowerhex[(r>>(28-4*j))&0xF])
+                               }
+                       }
+
+               default:
+               EscX:
+                       buf.WriteString(`\x`)
+                       buf.WriteByte(lowerhex[c>>4])
+                       buf.WriteByte(lowerhex[c&0xF])
+               }
+       }
+       buf.WriteByte('"')
+       return buf.String()
+}
+
+// CanBackquote returns whether the string s would be
+// a valid Go string literal if enclosed in backquotes.
+func CanBackquote(s string) bool {
+       for i := 0; i < len(s); i++ {
+               if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
+                       return false
+               }
+       }
+       return true
+}
+
+func unhex(b byte) (v int, ok bool) {
+       c := int(b)
+       switch {
+       case '0' <= c && c <= '9':
+               return c - '0', true
+       case 'a' <= c && c <= 'f':
+               return c - 'a' + 10, true
+       case 'A' <= c && c <= 'F':
+               return c - 'A' + 10, true
+       }
+       return
+}
+
+// UnquoteChar decodes the first character or byte in the escaped string
+// or character literal represented by the string s.
+// It returns four values:
+//
+//     1) value, the decoded Unicode code point or byte value;
+//     2) multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation;
+//     3) tail, the remainder of the string after the character; and
+//     4) an error that will be nil if the character is syntactically valid.
+//
+// The second argument, quote, specifies the type of literal being parsed
+// and therefore which escaped quote character is permitted.
+// If set to a single quote, it permits the sequence \' and disallows unescaped '.
+// If set to a double quote, it permits \" and disallows unescaped ".
+// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.
+func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string, err os.Error) {
+       // easy cases
+       switch c := s[0]; {
+       case c == quote && (quote == '\'' || quote == '"'):
+               err = os.EINVAL
+               return
+       case c >= utf8.RuneSelf:
+               r, size := utf8.DecodeRuneInString(s)
+               return r, true, s[size:], nil
+       case c != '\\':
+               return int(s[0]), false, s[1:], nil
+       }
+
+       // hard case: c is backslash
+       if len(s) <= 1 {
+               err = os.EINVAL
+               return
+       }
+       c := s[1]
+       s = s[2:]
+
+       switch c {
+       case 'a':
+               value = '\a'
+       case 'b':
+               value = '\b'
+       case 'f':
+               value = '\f'
+       case 'n':
+               value = '\n'
+       case 'r':
+               value = '\r'
+       case 't':
+               value = '\t'
+       case 'v':
+               value = '\v'
+       case 'x', 'u', 'U':
+               n := 0
+               switch c {
+               case 'x':
+                       n = 2
+               case 'u':
+                       n = 4
+               case 'U':
+                       n = 8
+               }
+               v := 0
+               if len(s) < n {
+                       err = os.EINVAL
+                       return
+               }
+               for j := 0; j < n; j++ {
+                       x, ok := unhex(s[j])
+                       if !ok {
+                               err = os.EINVAL
+                               return
+                       }
+                       v = v<<4 | x
+               }
+               s = s[n:]
+               if c == 'x' {
+                       // single-byte string, possibly not UTF-8
+                       value = v
+                       break
+               }
+               if v > unicode.MaxRune {
+                       err = os.EINVAL
+                       return
+               }
+               value = v
+               multibyte = true
+       case '0', '1', '2', '3', '4', '5', '6', '7':
+               v := int(c) - '0'
+               if len(s) < 2 {
+                       err = os.EINVAL
+                       return
+               }
+               for j := 0; j < 2; j++ { // one digit already; two more
+                       x := int(s[j]) - '0'
+                       if x < 0 || x > 7 {
+                               return
+                       }
+                       v = (v << 3) | x
+               }
+               s = s[2:]
+               if v > 255 {
+                       err = os.EINVAL
+                       return
+               }
+               value = v
+       case '\\':
+               value = '\\'
+       case '\'', '"':
+               if c != quote {
+                       err = os.EINVAL
+                       return
+               }
+               value = int(c)
+       default:
+               err = os.EINVAL
+               return
+       }
+       tail = s
+       return
+}
+
+// Unquote interprets s as a single-quoted, double-quoted,
+// or backquoted Go string literal, returning the string value
+// that s quotes.  (If s is single-quoted, it would be a Go
+// character literal; Unquote returns the corresponding
+// one-character string.)
+func Unquote(s string) (t string, err os.Error) {
+       n := len(s)
+       if n < 2 {
+               return "", os.EINVAL
+       }
+       quote := s[0]
+       if quote != s[n-1] {
+               return "", os.EINVAL
+       }
+       s = s[1 : n-1]
+
+       if quote == '`' {
+               if strings.Contains(s, "`") {
+                       return "", os.EINVAL
+               }
+               return s, nil
+       }
+       if quote != '"' && quote != '\'' {
+               return "", os.EINVAL
+       }
+
+       var buf bytes.Buffer
+       for len(s) > 0 {
+               c, multibyte, ss, err := UnquoteChar(s, quote)
+               if err != nil {
+                       return "", err
+               }
+               s = ss
+               if c < utf8.RuneSelf || !multibyte {
+                       buf.WriteByte(byte(c))
+               } else {
+                       buf.WriteString(string(c))
+               }
+               if quote == '\'' && len(s) != 0 {
+                       // single-quoted must be single character
+                       return "", os.EINVAL
+               }
+       }
+       return buf.String(), nil
+}
diff --git a/libgo/go/strconv/quote_test.go b/libgo/go/strconv/quote_test.go
new file mode 100644 (file)
index 0000000..1235fcb
--- /dev/null
@@ -0,0 +1,170 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+       "os"
+       . "strconv"
+       "testing"
+)
+
+type quoteTest struct {
+       in  string
+       out string
+}
+
+var quotetests = []quoteTest{
+       {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+       {"\\", `"\\"`},
+       {"abc\xffdef", `"abc\xffdef"`},
+       {"\u263a", `"\u263a"`},
+       {"\U0010ffff", `"\U0010ffff"`},
+       {"\x04", `"\x04"`},
+}
+
+func TestQuote(t *testing.T) {
+       for i := 0; i < len(quotetests); i++ {
+               tt := quotetests[i]
+               if out := Quote(tt.in); out != tt.out {
+                       t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out)
+               }
+       }
+}
+
+type canBackquoteTest struct {
+       in  string
+       out bool
+}
+
+var canbackquotetests = []canBackquoteTest{
+       {"`", false},
+       {string(0), false},
+       {string(1), false},
+       {string(2), false},
+       {string(3), false},
+       {string(4), false},
+       {string(5), false},
+       {string(6), false},
+       {string(7), false},
+       {string(8), false},
+       {string(9), true}, // \t
+       {string(10), false},
+       {string(11), false},
+       {string(12), false},
+       {string(13), false},
+       {string(14), false},
+       {string(15), false},
+       {string(16), false},
+       {string(17), false},
+       {string(18), false},
+       {string(19), false},
+       {string(20), false},
+       {string(21), false},
+       {string(22), false},
+       {string(23), false},
+       {string(24), false},
+       {string(25), false},
+       {string(26), false},
+       {string(27), false},
+       {string(28), false},
+       {string(29), false},
+       {string(30), false},
+       {string(31), false},
+       {`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
+       {`0123456789`, true},
+       {`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
+       {`abcdefghijklmnopqrstuvwxyz`, true},
+       {`☺`, true},
+}
+
+func TestCanBackquote(t *testing.T) {
+       for i := 0; i < len(canbackquotetests); i++ {
+               tt := canbackquotetests[i]
+               if out := CanBackquote(tt.in); out != tt.out {
+                       t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out)
+               }
+       }
+}
+
+var unquotetests = []quoteTest{
+       {`""`, ""},
+       {`"a"`, "a"},
+       {`"abc"`, "abc"},
+       {`"☺"`, "☺"},
+       {`"hello world"`, "hello world"},
+       {`"\xFF"`, "\xFF"},
+       {`"\377"`, "\377"},
+       {`"\u1234"`, "\u1234"},
+       {`"\U00010111"`, "\U00010111"},
+       {`"\U0001011111"`, "\U0001011111"},
+       {`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""},
+       {`"'"`, "'"},
+
+       {`'a'`, "a"},
+       {`'☹'`, "☹"},
+       {`'\a'`, "\a"},
+       {`'\x10'`, "\x10"},
+       {`'\377'`, "\377"},
+       {`'\u1234'`, "\u1234"},
+       {`'\U00010111'`, "\U00010111"},
+       {`'\t'`, "\t"},
+       {`' '`, " "},
+       {`'\''`, "'"},
+       {`'"'`, "\""},
+
+       {"``", ``},
+       {"`a`", `a`},
+       {"`abc`", `abc`},
+       {"`☺`", `☺`},
+       {"`hello world`", `hello world`},
+       {"`\\xFF`", `\xFF`},
+       {"`\\377`", `\377`},
+       {"`\\`", `\`},
+       {"`     `", `   `},
+       {"` `", ` `},
+}
+
+var misquoted = []string{
+       ``,
+       `"`,
+       `"a`,
+       `"'`,
+       `b"`,
+       `"\"`,
+       `'\'`,
+       `'ab'`,
+       `"\x1!"`,
+       `"\U12345678"`,
+       `"\z"`,
+       "`",
+       "`xxx",
+       "`\"",
+       `"\'"`,
+       `'\"'`,
+}
+
+func TestUnquote(t *testing.T) {
+       for i := 0; i < len(unquotetests); i++ {
+               tt := unquotetests[i]
+               if out, err := Unquote(tt.in); err != nil && out != tt.out {
+                       t.Errorf("Unquote(%#q) = %q, %v want %q, nil", tt.in, out, err, tt.out)
+               }
+       }
+
+       // run the quote tests too, backward
+       for i := 0; i < len(quotetests); i++ {
+               tt := quotetests[i]
+               if in, err := Unquote(tt.out); in != tt.in {
+                       t.Errorf("Unquote(%#q) = %q, %v, want %q, nil", tt.out, in, err, tt.in)
+               }
+       }
+
+       for i := 0; i < len(misquoted); i++ {
+               s := misquoted[i]
+               if out, err := Unquote(s); out != "" || err != os.EINVAL {
+                       t.Errorf("Unquote(%#q) = %q, %v want %q, %v", s, out, err, "", os.EINVAL)
+               }
+       }
+}
diff --git a/libgo/go/strconv/testfp.txt b/libgo/go/strconv/testfp.txt
new file mode 100644 (file)
index 0000000..08d3c4e
--- /dev/null
@@ -0,0 +1,181 @@
+# Floating-point conversion test cases.
+# Empty lines and lines beginning with # are ignored.
+# The rest have four fields per line: type, format, input, and output.
+# The input is given either in decimal or binary scientific notation.
+# The output is the string that should be produced by formatting the
+# input with the given format.
+#
+# The formats are as in C's printf, except that %b means print
+# binary scientific notation: NpE = N x 2^E.
+
+# TODO:
+#      Powers of 10.
+#      Powers of 2.
+#      %.20g versions.
+#      random sources
+#      random targets
+#      random targets ± half a ULP
+
+# Difficult boundary cases, derived from tables given in
+#      Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion
+#      ftp://ftp.ee.lbl.gov/testbase-report.ps.Z
+
+# Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
+float64 %b 5e+125 6653062250012735p+365
+float64 %b 69e+267 4705683757438170p+841
+float64 %b 999e-026 6798841691080350p-129
+float64 %b 7861e-034 8975675289889240p-153
+float64 %b 75569e-254 6091718967192243p-880
+float64 %b 928609e-261 7849264900213743p-900
+float64 %b 9210917e+080 8341110837370930p+236
+float64 %b 84863171e+114 4625202867375927p+353
+float64 %b 653777767e+273 5068902999763073p+884
+float64 %b 5232604057e-298 5741343011915040p-1010
+float64 %b 27235667517e-109 6707124626673586p-380
+float64 %b 653532977297e-123 7078246407265384p-422
+float64 %b 3142213164987e-294 8219991337640559p-988
+float64 %b 46202199371337e-072 5224462102115359p-246
+float64 %b 231010996856685e-073 5224462102115359p-247
+float64 %b 9324754620109615e+212 5539753864394442p+705
+float64 %b 78459735791271921e+049 8388176519442766p+166
+float64 %b 272104041512242479e+200 5554409530847367p+670
+float64 %b 6802601037806061975e+198 5554409530847367p+668
+float64 %b 20505426358836677347e-221 4524032052079546p-722
+float64 %b 836168422905420598437e-234 5070963299887562p-760
+float64 %b 4891559871276714924261e+222 6452687840519111p+757
+
+# Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
+float64 %b 9e-265 8168427841980010p-930
+float64 %b 85e-037 6360455125664090p-169
+float64 %b 623e+100 6263531988747231p+289
+float64 %b 3571e+263 6234526311072170p+833
+float64 %b 81661e+153 6696636728760206p+472
+float64 %b 920657e-023 5975405561110124p-109
+float64 %b 4603285e-024 5975405561110124p-110
+float64 %b 87575437e-309 8452160731874668p-1053
+float64 %b 245540327e+122 4985336549131723p+381
+float64 %b 6138508175e+120 4985336549131723p+379
+float64 %b 83356057653e+193 5986732817132056p+625
+float64 %b 619534293513e+124 4798406992060657p+399
+float64 %b 2335141086879e+218 5419088166961646p+713
+float64 %b 36167929443327e-159 8135819834632444p-536
+float64 %b 609610927149051e-255 4576664294594737p-850
+float64 %b 3743626360493413e-165 6898586531774201p-549
+float64 %b 94080055902682397e-242 6273271706052298p-800
+float64 %b 899810892172646163e+283 7563892574477827p+947
+float64 %b 7120190517612959703e+120 5385467232557565p+409
+float64 %b 25188282901709339043e-252 5635662608542340p-825
+float64 %b 308984926168550152811e-052 5644774693823803p-157
+float64 %b 6372891218502368041059e+064 4616868614322430p+233
+
+# Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP
+float64 %.0e 8511030020275656p-342 9e-88
+float64 %.1e 5201988407066741p-824 4.6e-233
+float64 %.2e 6406892948269899p+237 1.41e+87
+float64 %.3e 8431154198732492p+72 3.981e+37
+float64 %.4e 6475049196144587p+99 4.1040e+45
+float64 %.5e 8274307542972842p+726 2.92084e+234
+float64 %.6e 5381065484265332p-456 2.891946e-122
+float64 %.7e 6761728585499734p-1057 4.3787718e-303
+float64 %.8e 7976538478610756p+376 1.22770163e+129
+float64 %.9e 5982403858958067p+377 1.841552452e+129
+float64 %.10e 5536995190630837p+93 5.4835744350e+43
+float64 %.11e 7225450889282194p+710 3.89190181146e+229
+float64 %.12e 7225450889282194p+709 1.945950905732e+229
+float64 %.13e 8703372741147379p+117 1.4460958381605e+51
+float64 %.14e 8944262675275217p-1001 4.17367747458531e-286
+float64 %.15e 7459803696087692p-707 1.107950772878888e-197
+float64 %.16e 6080469016670379p-381 1.2345501366327440e-99
+float64 %.17e 8385515147034757p+721 9.25031711960365024e+232
+float64 %.18e 7514216811389786p-828 4.198047150284889840e-234
+float64 %.19e 8397297803260511p-345 1.1716315319786511046e-88
+float64 %.20e 6733459239310543p+202 4.32810072844612493629e+76
+float64 %.21e 8091450587292794p-473 3.317710118160031081518e-127
+
+# Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP
+float64 %.0e 6567258882077402p+952 3e+302
+float64 %.1e 6712731423444934p+535 7.6e+176
+float64 %.2e 6712731423444934p+534 3.78e+176
+float64 %.3e 5298405411573037p-957 4.350e-273
+float64 %.4e 5137311167659507p-144 2.3037e-28
+float64 %.5e 6722280709661868p+363 1.26301e+125
+float64 %.6e 5344436398034927p-169 7.142211e-36
+float64 %.7e 8369123604277281p-853 1.3934574e-241
+float64 %.8e 8995822108487663p-780 1.41463449e-219
+float64 %.9e 8942832835564782p-383 4.539277920e-100
+float64 %.10e 8942832835564782p-384 2.2696389598e-100
+float64 %.11e 8942832835564782p-385 1.13481947988e-100
+float64 %.12e 6965949469487146p-249 7.700366561890e-60
+float64 %.13e 6965949469487146p-250 3.8501832809448e-60
+float64 %.14e 6965949469487146p-251 1.92509164047238e-60
+float64 %.15e 7487252720986826p+548 6.898586531774201e+180
+float64 %.16e 5592117679628511p+164 1.3076622631878654e+65
+float64 %.17e 8887055249355788p+665 1.36052020756121240e+216
+float64 %.18e 6994187472632449p+690 3.592810217475959676e+223
+float64 %.19e 8797576579012143p+588 8.9125197712484551899e+192
+float64 %.20e 7363326733505337p+272 5.58769757362301140950e+97
+float64 %.21e 8549497411294502p-448 1.176257830728540379990e-119
+
+# Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
+# NOTE: The lines with exponent p-149 have been changed from the
+# paper.  Those entries originally read p-150 and had a mantissa
+# twice as large (and even), but IEEE single-precision has no p-150:
+# that's the start of the denormals.
+float32 %b 5e-20 15474250p-88
+float32 %b 67e+14 12479722p+29
+float32 %b 985e+15 14333636p+36
+# float32 %b 7693e-42 10979816p-150
+float32 %b 7693e-42 5489908p-149
+float32 %b 55895e-16 12888509p-61
+# float32 %b 996622e-44 14224264p-150
+float32 %b 996622e-44 7112132p-149
+float32 %b 7038531e-32 11420669p-107
+# float32 %b 60419369e-46 8623340p-150
+float32 %b 60419369e-46 4311670p-149
+float32 %b 702990899e-20 16209866p-61
+# float32 %b 6930161142e-48 9891056p-150
+float32 %b 6930161142e-48 4945528p-149
+float32 %b 25933168707e+13 14395800p+54
+float32 %b 596428896559e+20 12333860p+82
+
+# Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
+float32 %b 3e-23 9507380p-98
+float32 %b 57e+18 12960300p+42
+float32 %b 789e-35 10739312p-130
+float32 %b 2539e-18 11990089p-72
+float32 %b 76173e+28 9845130p+86
+float32 %b 887745e-11 9760860p-40
+float32 %b 5382571e-37 11447463p-124
+float32 %b 82381273e-35 8554961p-113
+float32 %b 750486563e-38 9975678p-120
+float32 %b 3752432815e-39 9975678p-121
+float32 %b 75224575729e-45 13105970p-137
+float32 %b 459926601011e+15 12466336p+65
+
+# Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP
+float32 %.0e 12676506p-102 2e-24
+float32 %.1e 12676506p-103 1.2e-24
+float32 %.2e 15445013p+86 1.19e+33
+float32 %.3e 13734123p-138 3.941e-35
+float32 %.4e 12428269p-130 9.1308e-33
+float32 %.5e 15334037p-146 1.71900e-37
+float32 %.6e 11518287p-41 5.237910e-06
+float32 %.7e 12584953p-145 2.8216440e-37
+float32 %.8e 15961084p-125 3.75243281e-31
+float32 %.9e 14915817p-146 1.672120916e-37
+float32 %.10e 10845484p-102 2.1388945814e-24
+float32 %.11e 16431059p-61 7.12583594561e-12
+
+# Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP
+float32 %.0e 16093626p+69 1e+28
+float32 %.1e 9983778p+25 3.4e+14
+float32 %.2e 12745034p+104 2.59e+38
+float32 %.3e 12706553p+72 6.001e+28
+float32 %.4e 11005028p+45 3.8721e+20
+float32 %.5e 15059547p+71 3.55584e+28
+float32 %.6e 16015691p-99 2.526831e-23
+float32 %.7e 8667859p+56 6.2458507e+23
+float32 %.8e 14855922p-82 3.07213267e-18
+float32 %.9e 14855922p-83 1.536066333e-18
+float32 %.10e 10144164p-110 7.8147796834e-27
+float32 %.11e 13248074p+95 5.24810279937e+35
diff --git a/libgo/go/strings/reader.go b/libgo/go/strings/reader.go
new file mode 100644 (file)
index 0000000..914faa0
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings
+
+import (
+       "os"
+       "utf8"
+)
+
+// A Reader satisfies calls to Read, ReadByte, and ReadRune by
+// reading from a string.
+type Reader string
+
+func (r *Reader) Read(b []byte) (n int, err os.Error) {
+       s := *r
+       if len(s) == 0 {
+               return 0, os.EOF
+       }
+       for n < len(s) && n < len(b) {
+               b[n] = s[n]
+               n++
+       }
+       *r = s[n:]
+       return
+}
+
+func (r *Reader) ReadByte() (b byte, err os.Error) {
+       s := *r
+       if len(s) == 0 {
+               return 0, os.EOF
+       }
+       b = s[0]
+       *r = s[1:]
+       return
+}
+
+// ReadRune reads and returns the next UTF-8-encoded
+// Unicode code point from the buffer.
+// If no bytes are available, the error returned is os.EOF.
+// If the bytes are an erroneous UTF-8 encoding, it
+// consumes one byte and returns U+FFFD, 1.
+func (r *Reader) ReadRune() (rune int, size int, err os.Error) {
+       s := *r
+       if len(s) == 0 {
+               return 0, 0, os.EOF
+       }
+       c := s[0]
+       if c < utf8.RuneSelf {
+               *r = s[1:]
+               return int(c), 1, nil
+       }
+       rune, size = utf8.DecodeRuneInString(string(s))
+       *r = s[size:]
+       return
+}
+
+// NewReader returns a new Reader reading from s.
+// It is similar to bytes.NewBufferString but more efficient and read-only.
+func NewReader(s string) *Reader { return (*Reader)(&s) }
diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go
new file mode 100644 (file)
index 0000000..f08b855
--- /dev/null
@@ -0,0 +1,541 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A package of simple functions to manipulate strings.
+package strings
+
+import (
+       "unicode"
+       "utf8"
+)
+
+// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n < 0 means no limit).
+// Invalid UTF-8 sequences become correct encodings of U+FFF8.
+func explode(s string, n int) []string {
+       if n == 0 {
+               return nil
+       }
+       l := utf8.RuneCountInString(s)
+       if n <= 0 || n > l {
+               n = l
+       }
+       a := make([]string, n)
+       var size, rune int
+       i, cur := 0, 0
+       for ; i+1 < n; i++ {
+               rune, size = utf8.DecodeRuneInString(s[cur:])
+               a[i] = string(rune)
+               cur += size
+       }
+       // add the rest, if there is any
+       if cur < len(s) {
+               a[i] = s[cur:]
+       }
+       return a
+}
+
+// Count counts the number of non-overlapping instances of sep in s.
+func Count(s, sep string) int {
+       if sep == "" {
+               return utf8.RuneCountInString(s) + 1
+       }
+       c := sep[0]
+       l := len(sep)
+       n := 0
+       if l == 1 {
+               // special case worth making fast
+               for i := 0; i < len(s); i++ {
+                       if s[i] == c {
+                               n++
+                       }
+               }
+               return n
+       }
+       for i := 0; i+l <= len(s); i++ {
+               if s[i] == c && s[i:i+l] == sep {
+                       n++
+                       i += l - 1
+               }
+       }
+       return n
+}
+
+// Contains returns true if substr is within s.
+func Contains(s, substr string) bool {
+       return Index(s, substr) != -1
+}
+
+// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
+func Index(s, sep string) int {
+       n := len(sep)
+       if n == 0 {
+               return 0
+       }
+       c := sep[0]
+       if n == 1 {
+               // special case worth making fast
+               for i := 0; i < len(s); i++ {
+                       if s[i] == c {
+                               return i
+                       }
+               }
+               return -1
+       }
+       // n > 1
+       for i := 0; i+n <= len(s); i++ {
+               if s[i] == c && s[i:i+n] == sep {
+                       return i
+               }
+       }
+       return -1
+}
+
+// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
+func LastIndex(s, sep string) int {
+       n := len(sep)
+       if n == 0 {
+               return len(s)
+       }
+       c := sep[0]
+       if n == 1 {
+               // special case worth making fast
+               for i := len(s) - 1; i >= 0; i-- {
+                       if s[i] == c {
+                               return i
+                       }
+               }
+               return -1
+       }
+       // n > 1
+       for i := len(s) - n; i >= 0; i-- {
+               if s[i] == c && s[i:i+n] == sep {
+                       return i
+               }
+       }
+       return -1
+}
+
+// IndexRune returns the index of the first instance of the Unicode code point
+// rune, or -1 if rune is not present in s.
+func IndexRune(s string, rune int) int {
+       for i, c := range s {
+               if c == rune {
+                       return i
+               }
+       }
+       return -1
+}
+
+// IndexAny returns the index of the first instance of any Unicode code point
+// from chars in s, or -1 if no Unicode code point from chars is present in s.
+func IndexAny(s, chars string) int {
+       if len(chars) > 0 {
+               for i, c := range s {
+                       for _, m := range chars {
+                               if c == m {
+                                       return i
+                               }
+                       }
+               }
+       }
+       return -1
+}
+
+// Generic split: splits after each instance of sep,
+// including sepSave bytes of sep in the subarrays.
+func genSplit(s, sep string, sepSave, n int) []string {
+       if n == 0 {
+               return nil
+       }
+       if sep == "" {
+               return explode(s, n)
+       }
+       if n < 0 {
+               n = Count(s, sep) + 1
+       }
+       c := sep[0]
+       start := 0
+       a := make([]string, n)
+       na := 0
+       for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
+               if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
+                       a[na] = s[start : i+sepSave]
+                       na++
+                       start = i + len(sep)
+                       i += len(sep) - 1
+               }
+       }
+       a[na] = s[start:]
+       return a[0 : na+1]
+}
+
+// Split slices s into substrings separated by sep and returns a slice of
+// the substrings between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of substrings to return:
+//   n > 0: at most n substrings; the last substring will be the unsplit remainder.
+//   n == 0: the result is nil (zero substrings)
+//   n < 0: all substrings
+func Split(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
+
+// SplitAfter slices s into substrings after each instance of sep and
+// returns a slice of those substrings.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of substrings to return:
+//   n > 0: at most n substrings; the last substring will be the unsplit remainder.
+//   n == 0: the result is nil (zero substrings)
+//   n < 0: all substrings
+func SplitAfter(s, sep string, n int) []string {
+       return genSplit(s, sep, len(sep), n)
+}
+
+// Fields splits the string s around each instance of one or more consecutive white space
+// characters, returning an array of substrings of s or an empty list if s contains only white space.
+func Fields(s string) []string {
+       return FieldsFunc(s, unicode.IsSpace)
+}
+
+// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)
+// and returns an array of slices of s. If no code points in s satisfy f(c), an empty slice
+// is returned.
+func FieldsFunc(s string, f func(int) bool) []string {
+       // First count the fields.
+       n := 0
+       inField := false
+       for _, rune := range s {
+               wasInField := inField
+               inField = !f(rune)
+               if inField && !wasInField {
+                       n++
+               }
+       }
+
+       // Now create them.
+       a := make([]string, n)
+       na := 0
+       fieldStart := -1 // Set to -1 when looking for start of field.
+       for i, rune := range s {
+               if f(rune) {
+                       if fieldStart >= 0 {
+                               a[na] = s[fieldStart:i]
+                               na++
+                               fieldStart = -1
+                       }
+               } else if fieldStart == -1 {
+                       fieldStart = i
+               }
+       }
+       if fieldStart != -1 { // Last field might end at EOF.
+               a[na] = s[fieldStart:]
+       }
+       return a
+}
+
+// Join concatenates the elements of a to create a single string.   The separator string
+// sep is placed between elements in the resulting string.
+func Join(a []string, sep string) string {
+       if len(a) == 0 {
+               return ""
+       }
+       if len(a) == 1 {
+               return a[0]
+       }
+       n := len(sep) * (len(a) - 1)
+       for i := 0; i < len(a); i++ {
+               n += len(a[i])
+       }
+
+       b := make([]byte, n)
+       bp := 0
+       for i := 0; i < len(a); i++ {
+               s := a[i]
+               for j := 0; j < len(s); j++ {
+                       b[bp] = s[j]
+                       bp++
+               }
+               if i+1 < len(a) {
+                       s = sep
+                       for j := 0; j < len(s); j++ {
+                               b[bp] = s[j]
+                               bp++
+                       }
+               }
+       }
+       return string(b)
+}
+
+// HasPrefix tests whether the string s begins with prefix.
+func HasPrefix(s, prefix string) bool {
+       return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
+}
+
+// HasSuffix tests whether the string s ends with suffix.
+func HasSuffix(s, suffix string) bool {
+       return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
+}
+
+// Map returns a copy of the string s with all its characters modified
+// according to the mapping function. If mapping returns a negative value, the character is
+// dropped from the string with no replacement.
+func Map(mapping func(rune int) int, s string) string {
+       // In the worst case, the string can grow when mapped, making
+       // things unpleasant.  But it's so rare we barge in assuming it's
+       // fine.  It could also shrink but that falls out naturally.
+       maxbytes := len(s) // length of b
+       nbytes := 0        // number of bytes encoded in b
+       b := make([]byte, maxbytes)
+       for _, c := range s {
+               rune := mapping(c)
+               if rune >= 0 {
+                       wid := 1
+                       if rune >= utf8.RuneSelf {
+                               wid = utf8.RuneLen(rune)
+                       }
+                       if nbytes+wid > maxbytes {
+                               // Grow the buffer.
+                               maxbytes = maxbytes*2 + utf8.UTFMax
+                               nb := make([]byte, maxbytes)
+                               copy(nb, b[0:nbytes])
+                               b = nb
+                       }
+                       nbytes += utf8.EncodeRune(rune, b[nbytes:maxbytes])
+               }
+       }
+       return string(b[0:nbytes])
+}
+
+// Repeat returns a new string consisting of count copies of the string s.
+func Repeat(s string, count int) string {
+       b := make([]byte, len(s)*count)
+       bp := 0
+       for i := 0; i < count; i++ {
+               for j := 0; j < len(s); j++ {
+                       b[bp] = s[j]
+                       bp++
+               }
+       }
+       return string(b)
+}
+
+
+// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
+func ToUpper(s string) string { return Map(unicode.ToUpper, s) }
+
+// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.
+func ToLower(s string) string { return Map(unicode.ToLower, s) }
+
+// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case.
+func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
+
+// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
+// upper case, giving priority to the special casing rules.
+func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
+       return Map(func(r int) int { return _case.ToUpper(r) }, s)
+}
+
+// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their
+// lower case, giving priority to the special casing rules.
+func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
+       return Map(func(r int) int { return _case.ToLower(r) }, s)
+}
+
+// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
+// title case, giving priority to the special casing rules.
+func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
+       return Map(func(r int) int { return _case.ToTitle(r) }, s)
+}
+
+// isSeparator reports whether the rune could mark a word boundary.
+// TODO: update when package unicode captures more of the properties.
+func isSeparator(rune int) bool {
+       // ASCII alphanumerics and underscore are not separators
+       if rune <= 0x7F {
+               switch {
+               case '0' <= rune && rune <= '9':
+                       return false
+               case 'a' <= rune && rune <= 'z':
+                       return false
+               case 'A' <= rune && rune <= 'Z':
+                       return false
+               case rune == '_':
+                       return false
+               }
+               return true
+       }
+       // Letters and digits are not separators
+       if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+               return false
+       }
+       // Otherwise, all we can do for now is treat spaces as separators.
+       return unicode.IsSpace(rune)
+}
+
+// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+
+// Title returns a copy of the string s with all Unicode letters that begin words
+// mapped to their title case.
+func Title(s string) string {
+       // Use a closure here to remember state.
+       // Hackish but effective. Depends on Map scanning in order and calling
+       // the closure once per rune.
+       prev := ' '
+       return Map(
+               func(r int) int {
+                       if isSeparator(prev) {
+                               prev = r
+                               return unicode.ToTitle(r)
+                       }
+                       prev = r
+                       return r
+               },
+               s)
+}
+
+// TrimLeftFunc returns a slice of the string s with all leading
+// Unicode code points c satisfying f(c) removed.
+func TrimLeftFunc(s string, f func(r int) bool) string {
+       i := indexFunc(s, f, false)
+       if i == -1 {
+               return ""
+       }
+       return s[i:]
+}
+
+// TrimRightFunc returns a slice of the string s with all trailing
+// Unicode code points c satisfying f(c) removed.
+func TrimRightFunc(s string, f func(r int) bool) string {
+       i := lastIndexFunc(s, f, false)
+       if i >= 0 && s[i] >= utf8.RuneSelf {
+               _, wid := utf8.DecodeRuneInString(s[i:])
+               i += wid
+       } else {
+               i++
+       }
+       return s[0:i]
+}
+
+// TrimFunc returns a slice of the string s with all leading
+// and trailing Unicode code points c satisfying f(c) removed.
+func TrimFunc(s string, f func(r int) bool) string {
+       return TrimRightFunc(TrimLeftFunc(s, f), f)
+}
+
+// IndexFunc returns the index into s of the first Unicode
+// code point satisfying f(c), or -1 if none do.
+func IndexFunc(s string, f func(r int) bool) int {
+       return indexFunc(s, f, true)
+}
+
+// LastIndexFunc returns the index into s of the last
+// Unicode code point satisfying f(c), or -1 if none do.
+func LastIndexFunc(s string, f func(r int) bool) int {
+       return lastIndexFunc(s, f, true)
+}
+
+// indexFunc is the same as IndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func indexFunc(s string, f func(r int) bool, truth bool) int {
+       start := 0
+       for start < len(s) {
+               wid := 1
+               rune := int(s[start])
+               if rune >= utf8.RuneSelf {
+                       rune, wid = utf8.DecodeRuneInString(s[start:])
+               }
+               if f(rune) == truth {
+                       return start
+               }
+               start += wid
+       }
+       return -1
+}
+
+// lastIndexFunc is the same as LastIndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func lastIndexFunc(s string, f func(r int) bool, truth bool) int {
+       for i := len(s); i > 0; {
+               rune, size := utf8.DecodeLastRuneInString(s[0:i])
+               i -= size
+               if f(rune) == truth {
+                       return i
+               }
+       }
+       return -1
+}
+
+func makeCutsetFunc(cutset string) func(rune int) bool {
+       return func(rune int) bool { return IndexRune(cutset, rune) != -1 }
+}
+
+// Trim returns a slice of the string s with all leading and
+// trailing Unicode code points contained in cutset removed.
+func Trim(s string, cutset string) string {
+       if s == "" || cutset == "" {
+               return s
+       }
+       return TrimFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimLeft returns a slice of the string s with all leading
+// Unicode code points contained in cutset removed.
+func TrimLeft(s string, cutset string) string {
+       if s == "" || cutset == "" {
+               return s
+       }
+       return TrimLeftFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimRight returns a slice of the string s, with all trailing
+// Unicode code points contained in cutset removed.
+func TrimRight(s string, cutset string) string {
+       if s == "" || cutset == "" {
+               return s
+       }
+       return TrimRightFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimSpace returns a slice of the string s, with all leading
+// and trailing white space removed, as defined by Unicode.
+func TrimSpace(s string) string {
+       return TrimFunc(s, unicode.IsSpace)
+}
+
+// Replace returns a copy of the string s with the first n
+// non-overlapping instances of old replaced by new.
+// If n < 0, there is no limit on the number of replacements.
+func Replace(s, old, new string, n int) string {
+       if old == new || n == 0 {
+               return s // avoid allocation
+       }
+
+       // Compute number of replacements.
+       if m := Count(s, old); m == 0 {
+               return s // avoid allocation
+       } else if n < 0 || m < n {
+               n = m
+       }
+
+       // Apply replacements to buffer.
+       t := make([]byte, len(s)+n*(len(new)-len(old)))
+       w := 0
+       start := 0
+       for i := 0; i < n; i++ {
+               j := start
+               if len(old) == 0 {
+                       if i > 0 {
+                               _, wid := utf8.DecodeRuneInString(s[start:])
+                               j += wid
+                       }
+               } else {
+                       j += Index(s[start:], old)
+               }
+               w += copy(t[w:], s[start:j])
+               w += copy(t[w:], new)
+               start = j + len(old)
+       }
+       w += copy(t[w:], s[start:])
+       return string(t[0:w])
+}
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go
new file mode 100644 (file)
index 0000000..657c8e8
--- /dev/null
@@ -0,0 +1,762 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings_test
+
+import (
+       "os"
+       . "strings"
+       "testing"
+       "unicode"
+       "utf8"
+)
+
+func eq(a, b []string) bool {
+       if len(a) != len(b) {
+               return false
+       }
+       for i := 0; i < len(a); i++ {
+               if a[i] != b[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+var abcd = "abcd"
+var faces = "☺☻☹"
+var commas = "1,2,3,4"
+var dots = "1....2....3....4"
+
+type IndexTest struct {
+       s   string
+       sep string
+       out int
+}
+
+var indexTests = []IndexTest{
+       {"", "", 0},
+       {"", "a", -1},
+       {"", "foo", -1},
+       {"fo", "foo", -1},
+       {"foo", "foo", 0},
+       {"oofofoofooo", "f", 2},
+       {"oofofoofooo", "foo", 4},
+       {"barfoobarfoo", "foo", 3},
+       {"foo", "", 0},
+       {"foo", "o", 1},
+       {"abcABCabc", "A", 3},
+       // cases with one byte strings - test special case in Index()
+       {"", "a", -1},
+       {"x", "a", -1},
+       {"x", "x", 0},
+       {"abc", "a", 0},
+       {"abc", "b", 1},
+       {"abc", "c", 2},
+       {"abc", "x", -1},
+}
+
+var lastIndexTests = []IndexTest{
+       {"", "", 0},
+       {"", "a", -1},
+       {"", "foo", -1},
+       {"fo", "foo", -1},
+       {"foo", "foo", 0},
+       {"foo", "f", 0},
+       {"oofofoofooo", "f", 7},
+       {"oofofoofooo", "foo", 7},
+       {"barfoobarfoo", "foo", 9},
+       {"foo", "", 3},
+       {"foo", "o", 2},
+       {"abcABCabc", "A", 3},
+       {"abcABCabc", "a", 6},
+}
+
+var indexAnyTests = []IndexTest{
+       {"", "", -1},
+       {"", "a", -1},
+       {"", "abc", -1},
+       {"a", "", -1},
+       {"a", "a", 0},
+       {"aaa", "a", 0},
+       {"abc", "xyz", -1},
+       {"abc", "xcz", 2},
+       {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+       {"aRegExp*", ".(|)*+?^$[]", 7},
+       {dots + dots + dots, " ", -1},
+}
+
+// Execute f on each test case.  funcName should be the name of f; it's used
+// in failure reports.
+func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, testCases []IndexTest) {
+       for _, test := range testCases {
+               actual := f(test.s, test.sep)
+               if actual != test.out {
+                       t.Errorf("%s(%q,%q) = %v; want %v", funcName, test.s, test.sep, actual, test.out)
+               }
+       }
+}
+
+func TestIndex(t *testing.T)     { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T)  { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
+
+type ExplodeTest struct {
+       s string
+       n int
+       a []string
+}
+
+var explodetests = []ExplodeTest{
+       {"", -1, []string{}},
+       {abcd, 4, []string{"a", "b", "c", "d"}},
+       {faces, 3, []string{"☺", "☻", "☹"}},
+       {abcd, 2, []string{"a", "bcd"}},
+}
+
+func TestExplode(t *testing.T) {
+       for _, tt := range explodetests {
+               a := Split(tt.s, "", tt.n)
+               if !eq(a, tt.a) {
+                       t.Errorf("explode(%q, %d) = %v; want %v", tt.s, tt.n, a, tt.a)
+                       continue
+               }
+               s := Join(a, "")
+               if s != tt.s {
+                       t.Errorf(`Join(explode(%q, %d), "") = %q`, tt.s, tt.n, s)
+               }
+       }
+}
+
+type SplitTest struct {
+       s   string
+       sep string
+       n   int
+       a   []string
+}
+
+var splittests = []SplitTest{
+       {abcd, "a", 0, nil},
+       {abcd, "a", -1, []string{"", "bcd"}},
+       {abcd, "z", -1, []string{"abcd"}},
+       {abcd, "", -1, []string{"a", "b", "c", "d"}},
+       {commas, ",", -1, []string{"1", "2", "3", "4"}},
+       {dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
+       {faces, "☹", -1, []string{"☺☻", ""}},
+       {faces, "~", -1, []string{faces}},
+       {faces, "", -1, []string{"☺", "☻", "☹"}},
+       {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
+       {"1 2", " ", 3, []string{"1", "2"}},
+       {"123", "", 2, []string{"1", "23"}},
+       {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplit(t *testing.T) {
+       for _, tt := range splittests {
+               a := Split(tt.s, tt.sep, tt.n)
+               if !eq(a, tt.a) {
+                       t.Errorf("Split(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, a, tt.a)
+                       continue
+               }
+               if tt.n == 0 {
+                       continue
+               }
+               s := Join(a, tt.sep)
+               if s != tt.s {
+                       t.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt.s, tt.sep, tt.n, tt.sep, s)
+               }
+       }
+}
+
+var splitaftertests = []SplitTest{
+       {abcd, "a", -1, []string{"a", "bcd"}},
+       {abcd, "z", -1, []string{"abcd"}},
+       {abcd, "", -1, []string{"a", "b", "c", "d"}},
+       {commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
+       {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
+       {faces, "☹", -1, []string{"☺☻☹", ""}},
+       {faces, "~", -1, []string{faces}},
+       {faces, "", -1, []string{"☺", "☻", "☹"}},
+       {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
+       {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
+       {"1 2", " ", 3, []string{"1 ", "2"}},
+       {"123", "", 2, []string{"1", "23"}},
+       {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplitAfter(t *testing.T) {
+       for _, tt := range splitaftertests {
+               a := SplitAfter(tt.s, tt.sep, tt.n)
+               if !eq(a, tt.a) {
+                       t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, a, tt.a)
+                       continue
+               }
+               s := Join(a, "")
+               if s != tt.s {
+                       t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
+               }
+       }
+}
+
+type FieldsTest struct {
+       s string
+       a []string
+}
+
+var fieldstests = []FieldsTest{
+       {"", []string{}},
+       {" ", []string{}},
+       {" \t ", []string{}},
+       {"  abc  ", []string{"abc"}},
+       {"1 2 3 4", []string{"1", "2", "3", "4"}},
+       {"1  2  3  4", []string{"1", "2", "3", "4"}},
+       {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+       {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+       {"\u2000\u2001\u2002", []string{}},
+       {"\n™\t™\n", []string{"™", "™"}},
+       {faces, []string{faces}},
+}
+
+func TestFields(t *testing.T) {
+       for _, tt := range fieldstests {
+               a := Fields(tt.s)
+               if !eq(a, tt.a) {
+                       t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
+                       continue
+               }
+       }
+}
+
+func TestFieldsFunc(t *testing.T) {
+       pred := func(c int) bool { return c == 'X' }
+       var fieldsFuncTests = []FieldsTest{
+               {"", []string{}},
+               {"XX", []string{}},
+               {"XXhiXXX", []string{"hi"}},
+               {"aXXbXXXcX", []string{"a", "b", "c"}},
+       }
+       for _, tt := range fieldsFuncTests {
+               a := FieldsFunc(tt.s, pred)
+               if !eq(a, tt.a) {
+                       t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
+               }
+       }
+}
+
+
+// Test case for any function which accepts and returns a single string.
+type StringTest struct {
+       in, out string
+}
+
+// Execute f on each test case.  funcName should be the name of f; it's used
+// in failure reports.
+func runStringTests(t *testing.T, f func(string) string, funcName string, testCases []StringTest) {
+       for _, tc := range testCases {
+               actual := f(tc.in)
+               if actual != tc.out {
+                       t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)
+               }
+       }
+}
+
+var upperTests = []StringTest{
+       {"", ""},
+       {"abc", "ABC"},
+       {"AbC123", "ABC123"},
+       {"azAZ09_", "AZAZ09_"},
+       {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
+}
+
+var lowerTests = []StringTest{
+       {"", ""},
+       {"abc", "abc"},
+       {"AbC123", "abc123"},
+       {"azAZ09_", "azaz09_"},
+       {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
+}
+
+const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
+
+var trimSpaceTests = []StringTest{
+       {"", ""},
+       {"abc", "abc"},
+       {space + "abc" + space, "abc"},
+       {" ", ""},
+       {" \t\r\n \t\t\r\r\n\n ", ""},
+       {" \t\r\n x\t\t\r\r\n\n ", "x"},
+       {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
+       {"1 \t\r\n2", "1 \t\r\n2"},
+       {" x\x80", "x\x80"},
+       {" x\xc0", "x\xc0"},
+       {"x \xc0\xc0 ", "x \xc0\xc0"},
+       {"x \xc0", "x \xc0"},
+       {"x \xc0 ", "x \xc0"},
+       {"x \xc0\xc0 ", "x \xc0\xc0"},
+       {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
+       {"x ☺ ", "x ☺"},
+}
+
+func tenRunes(rune int) string {
+       r := make([]int, 10)
+       for i := range r {
+               r[i] = rune
+       }
+       return string(r)
+}
+
+// User-defined self-inverse mapping function
+func rot13(rune int) int {
+       step := 13
+       if rune >= 'a' && rune <= 'z' {
+               return ((rune - 'a' + step) % 26) + 'a'
+       }
+       if rune >= 'A' && rune <= 'Z' {
+               return ((rune - 'A' + step) % 26) + 'A'
+       }
+       return rune
+}
+
+func TestMap(t *testing.T) {
+       // Run a couple of awful growth/shrinkage tests
+       a := tenRunes('a')
+       // 1.  Grow.  This triggers two reallocations in Map.
+       maxRune := func(rune int) int { return unicode.MaxRune }
+       m := Map(maxRune, a)
+       expect := tenRunes(unicode.MaxRune)
+       if m != expect {
+               t.Errorf("growing: expected %q got %q", expect, m)
+       }
+
+       // 2. Shrink
+       minRune := func(rune int) int { return 'a' }
+       m = Map(minRune, tenRunes(unicode.MaxRune))
+       expect = a
+       if m != expect {
+               t.Errorf("shrinking: expected %q got %q", expect, m)
+       }
+
+       // 3. Rot13
+       m = Map(rot13, "a to zed")
+       expect = "n gb mrq"
+       if m != expect {
+               t.Errorf("rot13: expected %q got %q", expect, m)
+       }
+
+       // 4. Rot13^2
+       m = Map(rot13, Map(rot13, "a to zed"))
+       expect = "a to zed"
+       if m != expect {
+               t.Errorf("rot13: expected %q got %q", expect, m)
+       }
+
+       // 5. Drop
+       dropNotLatin := func(rune int) int {
+               if unicode.Is(unicode.Latin, rune) {
+                       return rune
+               }
+               return -1
+       }
+       m = Map(dropNotLatin, "Hello, 세계")
+       expect = "Hello"
+       if m != expect {
+               t.Errorf("drop: expected %q got %q", expect, m)
+       }
+}
+
+func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
+
+func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
+
+func TestSpecialCase(t *testing.T) {
+       lower := "abcçdefgğhıijklmnoöprsştuüvyz"
+       upper := "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ"
+       u := ToUpperSpecial(unicode.TurkishCase, upper)
+       if u != upper {
+               t.Errorf("Upper(upper) is %s not %s", u, upper)
+       }
+       u = ToUpperSpecial(unicode.TurkishCase, lower)
+       if u != upper {
+               t.Errorf("Upper(lower) is %s not %s", u, upper)
+       }
+       l := ToLowerSpecial(unicode.TurkishCase, lower)
+       if l != lower {
+               t.Errorf("Lower(lower) is %s not %s", l, lower)
+       }
+       l = ToLowerSpecial(unicode.TurkishCase, upper)
+       if l != lower {
+               t.Errorf("Lower(upper) is %s not %s", l, lower)
+       }
+}
+
+func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
+
+type TrimTest struct {
+       f               func(string, string) string
+       in, cutset, out string
+}
+
+var trimTests = []TrimTest{
+       {Trim, "abba", "a", "bb"},
+       {Trim, "abba", "ab", ""},
+       {TrimLeft, "abba", "ab", ""},
+       {TrimRight, "abba", "ab", ""},
+       {TrimLeft, "abba", "a", "bba"},
+       {TrimRight, "abba", "a", "abb"},
+       {Trim, "<tag>", "<>", "tag"},
+       {Trim, "* listitem", " *", "listitem"},
+       {Trim, `"quote"`, `"`, "quote"},
+       {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+       //empty string tests
+       {Trim, "abba", "", "abba"},
+       {Trim, "", "123", ""},
+       {Trim, "", "", ""},
+       {TrimLeft, "abba", "", "abba"},
+       {TrimLeft, "", "123", ""},
+       {TrimLeft, "", "", ""},
+       {TrimRight, "abba", "", "abba"},
+       {TrimRight, "", "123", ""},
+       {TrimRight, "", "", ""},
+       {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+}
+
+func TestTrim(t *testing.T) {
+       for _, tc := range trimTests {
+               actual := tc.f(tc.in, tc.cutset)
+               var name string
+               switch tc.f {
+               case Trim:
+                       name = "Trim"
+               case TrimLeft:
+                       name = "TrimLeft"
+               case TrimRight:
+                       name = "TrimRight"
+               default:
+                       t.Error("Undefined trim function")
+               }
+               if actual != tc.out {
+                       t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
+               }
+       }
+}
+
+type predicate struct {
+       f    func(r int) bool
+       name string
+}
+
+var isSpace = predicate{unicode.IsSpace, "IsSpace"}
+var isDigit = predicate{unicode.IsDigit, "IsDigit"}
+var isUpper = predicate{unicode.IsUpper, "IsUpper"}
+var isValidRune = predicate{
+       func(r int) bool {
+               return r != utf8.RuneError
+       },
+       "IsValidRune",
+}
+
+type TrimFuncTest struct {
+       f       predicate
+       in, out string
+}
+
+func not(p predicate) predicate {
+       return predicate{
+               func(r int) bool {
+                       return !p.f(r)
+               },
+               "not " + p.name,
+       }
+}
+
+var trimFuncTests = []TrimFuncTest{
+       {isSpace, space + " hello " + space, "hello"},
+       {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
+       {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
+       {not(isSpace), "hello" + space + "hello", space},
+       {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
+       {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"},
+       {not(isValidRune), "\xc0a\xc0", "a"},
+}
+
+func TestTrimFunc(t *testing.T) {
+       for _, tc := range trimFuncTests {
+               actual := TrimFunc(tc.in, tc.f.f)
+               if actual != tc.out {
+                       t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out)
+               }
+       }
+}
+
+type IndexFuncTest struct {
+       in          string
+       f           predicate
+       first, last int
+}
+
+var indexFuncTests = []IndexFuncTest{
+       {"", isValidRune, -1, -1},
+       {"abc", isDigit, -1, -1},
+       {"0123", isDigit, 0, 3},
+       {"a1b", isDigit, 1, 1},
+       {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes
+       {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
+       {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
+       {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
+
+       // tests of invalid UTF-8
+       {"\x801", isDigit, 1, 1},
+       {"\x80abc", isDigit, -1, -1},
+       {"\xc0a\xc0", isValidRune, 1, 1},
+       {"\xc0a\xc0", not(isValidRune), 0, 2},
+       {"\xc0☺\xc0", not(isValidRune), 0, 4},
+       {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
+       {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
+       {"a\xe0\x80cd", not(isValidRune), 1, 2},
+       {"\x80\x80\x80\x80", not(isValidRune), 0, 3},
+}
+
+func TestIndexFunc(t *testing.T) {
+       for _, tc := range indexFuncTests {
+               first := IndexFunc(tc.in, tc.f.f)
+               if first != tc.first {
+                       t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)
+               }
+               last := LastIndexFunc(tc.in, tc.f.f)
+               if last != tc.last {
+                       t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)
+               }
+       }
+}
+
+func equal(m string, s1, s2 string, t *testing.T) bool {
+       if s1 == s2 {
+               return true
+       }
+       e1 := Split(s1, "", -1)
+       e2 := Split(s2, "", -1)
+       for i, c1 := range e1 {
+               if i > len(e2) {
+                       break
+               }
+               r1, _ := utf8.DecodeRuneInString(c1)
+               r2, _ := utf8.DecodeRuneInString(e2[i])
+               if r1 != r2 {
+                       t.Errorf("%s diff at %d: U+%04X U+%04X", m, i, r1, r2)
+               }
+       }
+       return false
+}
+
+func TestCaseConsistency(t *testing.T) {
+       // Make a string of all the runes.
+       a := make([]int, unicode.MaxRune+1)
+       for i := range a {
+               a[i] = i
+       }
+       s := string(a)
+       // convert the cases.
+       upper := ToUpper(s)
+       lower := ToLower(s)
+
+       // Consistency checks
+       if n := utf8.RuneCountInString(upper); n != unicode.MaxRune+1 {
+               t.Error("rune count wrong in upper:", n)
+       }
+       if n := utf8.RuneCountInString(lower); n != unicode.MaxRune+1 {
+               t.Error("rune count wrong in lower:", n)
+       }
+       if !equal("ToUpper(upper)", ToUpper(upper), upper, t) {
+               t.Error("ToUpper(upper) consistency fail")
+       }
+       if !equal("ToLower(lower)", ToLower(lower), lower, t) {
+               t.Error("ToLower(lower) consistency fail")
+       }
+       /*
+                 These fail because of non-one-to-oneness of the data, such as multiple
+                 upper case 'I' mapping to 'i'.  We comment them out but keep them for
+                 interest.
+                 For instance: CAPITAL LETTER I WITH DOT ABOVE:
+                       unicode.ToUpper(unicode.ToLower('\u0130')) != '\u0130'
+
+               if !equal("ToUpper(lower)", ToUpper(lower), upper, t) {
+                       t.Error("ToUpper(lower) consistency fail");
+               }
+               if !equal("ToLower(upper)", ToLower(upper), lower, t) {
+                       t.Error("ToLower(upper) consistency fail");
+               }
+       */
+}
+
+type RepeatTest struct {
+       in, out string
+       count   int
+}
+
+var RepeatTests = []RepeatTest{
+       {"", "", 0},
+       {"", "", 1},
+       {"", "", 2},
+       {"-", "", 0},
+       {"-", "-", 1},
+       {"-", "----------", 10},
+       {"abc ", "abc abc abc ", 3},
+}
+
+func TestRepeat(t *testing.T) {
+       for _, tt := range RepeatTests {
+               a := Repeat(tt.in, tt.count)
+               if !equal("Repeat(s)", a, tt.out, t) {
+                       t.Errorf("Repeat(%v, %d) = %v; want %v", tt.in, tt.count, a, tt.out)
+                       continue
+               }
+       }
+}
+
+func runesEqual(a, b []int) bool {
+       if len(a) != len(b) {
+               return false
+       }
+       for i, r := range a {
+               if r != b[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+type RunesTest struct {
+       in    string
+       out   []int
+       lossy bool
+}
+
+var RunesTests = []RunesTest{
+       {"", []int{}, false},
+       {" ", []int{32}, false},
+       {"ABC", []int{65, 66, 67}, false},
+       {"abc", []int{97, 98, 99}, false},
+       {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
+       {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
+       {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+}
+
+func TestRunes(t *testing.T) {
+       for _, tt := range RunesTests {
+               a := []int(tt.in)
+               if !runesEqual(a, tt.out) {
+                       t.Errorf("[]int(%q) = %v; want %v", tt.in, a, tt.out)
+                       continue
+               }
+               if !tt.lossy {
+                       // can only test reassembly if we didn't lose information
+                       s := string(a)
+                       if s != tt.in {
+                               t.Errorf("string([]int(%q)) = %x; want %x", tt.in, s, tt.in)
+                       }
+               }
+       }
+}
+
+func TestReadRune(t *testing.T) {
+       testStrings := []string{"", abcd, faces, commas}
+       for _, s := range testStrings {
+               reader := NewReader(s)
+               res := ""
+               for {
+                       r, _, e := reader.ReadRune()
+                       if e == os.EOF {
+                               break
+                       }
+                       if e != nil {
+                               t.Errorf("Reading %q: %s", s, e)
+                               break
+                       }
+                       res += string(r)
+               }
+               if res != s {
+                       t.Errorf("Reader(%q).ReadRune() produced %q", s, res)
+               }
+       }
+}
+
+type ReplaceTest struct {
+       in       string
+       old, new string
+       n        int
+       out      string
+}
+
+var ReplaceTests = []ReplaceTest{
+       {"hello", "l", "L", 0, "hello"},
+       {"hello", "l", "L", -1, "heLLo"},
+       {"hello", "x", "X", -1, "hello"},
+       {"", "x", "X", -1, ""},
+       {"radar", "r", "<r>", -1, "<r>ada<r>"},
+       {"", "", "<>", -1, "<>"},
+       {"banana", "a", "<>", -1, "b<>n<>n<>"},
+       {"banana", "a", "<>", 1, "b<>nana"},
+       {"banana", "a", "<>", 1000, "b<>n<>n<>"},
+       {"banana", "an", "<>", -1, "b<><>a"},
+       {"banana", "ana", "<>", -1, "b<>na"},
+       {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
+       {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
+       {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
+       {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
+       {"banana", "", "<>", 1, "<>banana"},
+       {"banana", "a", "a", -1, "banana"},
+       {"banana", "a", "a", 1, "banana"},
+       {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
+}
+
+func TestReplace(t *testing.T) {
+       for _, tt := range ReplaceTests {
+               if s := Replace(tt.in, tt.old, tt.new, tt.n); s != tt.out {
+                       t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
+               }
+       }
+}
+
+type TitleTest struct {
+       in, out string
+}
+
+var TitleTests = []TitleTest{
+       {"", ""},
+       {"a", "A"},
+       {" aaa aaa aaa ", " Aaa Aaa Aaa "},
+       {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
+       {"123a456", "123a456"},
+       {"double-blind", "Double-Blind"},
+       {"ÿøû", "Ÿøû"},
+}
+
+func TestTitle(t *testing.T) {
+       for _, tt := range TitleTests {
+               if s := Title(tt.in); s != tt.out {
+                       t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
+               }
+       }
+}
+
+type ContainsTest struct {
+       str, substr string
+       expected    bool
+}
+
+var ContainsTests = []ContainsTest{
+       {"abc", "bc", true},
+       {"abc", "bcd", false},
+       {"abc", "", true},
+       {"", "a", false},
+}
+
+func TestContains(t *testing.T) {
+       for _, ct := range ContainsTests {
+               if Contains(ct.str, ct.substr) != ct.expected {
+                       t.Errorf("Contains(%s, %s) = %v, want %v",
+                               ct.str, ct.substr, !ct.expected, ct.expected)
+               }
+       }
+}
diff --git a/libgo/go/sync/cas.c b/libgo/go/sync/cas.c
new file mode 100644 (file)
index 0000000..ffcd133
--- /dev/null
@@ -0,0 +1,15 @@
+/* cas.c -- implement sync.cas for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+_Bool cas (int32_t *, int32_t, int32_t) asm ("libgo_sync.sync.cas");
+
+_Bool
+cas (int32_t *ptr, int32_t old, int32_t new)
+{
+  return __sync_bool_compare_and_swap (ptr, old, new);
+}
diff --git a/libgo/go/sync/mutex.go b/libgo/go/sync/mutex.go
new file mode 100644 (file)
index 0000000..9a2bb2b
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The sync package provides basic synchronization primitives
+// such as mutual exclusion locks.  Other than the Once type,
+// most are intended for use by low-level library routines.
+// Higher-level synchronization  is better done via channels
+// and communication.
+package sync
+
+import "runtime"
+
+func cas(val *uint32, old, new uint32) bool
+
+// A Mutex is a mutual exclusion lock.
+// Mutexes can be created as part of other structures;
+// the zero value for a Mutex is an unlocked mutex.
+type Mutex struct {
+       key  uint32
+       sema uint32
+}
+
+// Add delta to *val, and return the new *val in a thread-safe way. If multiple
+// goroutines call xadd on the same val concurrently, the changes will be
+// serialized, and all the deltas will be added in an undefined order.
+func xadd(val *uint32, delta int32) (new uint32) {
+       for {
+               v := *val
+               nv := v + uint32(delta)
+               if cas(val, v, nv) {
+                       return nv
+               }
+       }
+       panic("unreached")
+}
+
+// Lock locks m.
+// If the lock is already in use, the calling goroutine
+// blocks until the mutex is available.
+func (m *Mutex) Lock() {
+       if xadd(&m.key, 1) == 1 {
+               // changed from 0 to 1; we hold lock
+               return
+       }
+       runtime.Semacquire(&m.sema)
+}
+
+// Unlock unlocks m.
+// It is a run-time error if m is not locked on entry to Unlock.
+//
+// A locked Mutex is not associated with a particular goroutine.
+// It is allowed for one goroutine to lock a Mutex and then
+// arrange for another goroutine to unlock it.
+func (m *Mutex) Unlock() {
+       if xadd(&m.key, -1) == 0 {
+               // changed from 1 to 0; no contention
+               return
+       }
+       runtime.Semrelease(&m.sema)
+}
diff --git a/libgo/go/sync/mutex_test.go b/libgo/go/sync/mutex_test.go
new file mode 100644 (file)
index 0000000..d0e048e
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// GOMAXPROCS=10 gotest
+
+package sync_test
+
+import (
+       "runtime"
+       . "sync"
+       "testing"
+)
+
+func HammerSemaphore(s *uint32, loops int, cdone chan bool) {
+       for i := 0; i < loops; i++ {
+               runtime.Semacquire(s)
+               runtime.Semrelease(s)
+       }
+       cdone <- true
+}
+
+func TestSemaphore(t *testing.T) {
+       s := new(uint32)
+       *s = 1
+       c := make(chan bool)
+       for i := 0; i < 10; i++ {
+               go HammerSemaphore(s, 1000, c)
+       }
+       for i := 0; i < 10; i++ {
+               <-c
+       }
+}
+
+func BenchmarkUncontendedSemaphore(b *testing.B) {
+       s := new(uint32)
+       *s = 1
+       HammerSemaphore(s, b.N, make(chan bool, 2))
+}
+
+func BenchmarkContendedSemaphore(b *testing.B) {
+       b.StopTimer()
+       s := new(uint32)
+       *s = 1
+       c := make(chan bool)
+       runtime.GOMAXPROCS(2)
+       b.StartTimer()
+
+       go HammerSemaphore(s, b.N/2, c)
+       go HammerSemaphore(s, b.N/2, c)
+       <-c
+       <-c
+}
+
+
+func HammerMutex(m *Mutex, loops int, cdone chan bool) {
+       for i := 0; i < loops; i++ {
+               m.Lock()
+               m.Unlock()
+       }
+       cdone <- true
+}
+
+func TestMutex(t *testing.T) {
+       m := new(Mutex)
+       c := make(chan bool)
+       for i := 0; i < 10; i++ {
+               go HammerMutex(m, 1000, c)
+       }
+       for i := 0; i < 10; i++ {
+               <-c
+       }
+}
+
+func BenchmarkUncontendedMutex(b *testing.B) {
+       m := new(Mutex)
+       HammerMutex(m, b.N, make(chan bool, 2))
+}
+
+func BenchmarkContendedMutex(b *testing.B) {
+       b.StopTimer()
+       m := new(Mutex)
+       c := make(chan bool)
+       runtime.GOMAXPROCS(2)
+       b.StartTimer()
+
+       go HammerMutex(m, b.N/2, c)
+       go HammerMutex(m, b.N/2, c)
+       <-c
+       <-c
+}
diff --git a/libgo/go/sync/once.go b/libgo/go/sync/once.go
new file mode 100644 (file)
index 0000000..8c877cd
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+// Once is an object that will perform exactly one action.
+type Once struct {
+       m    Mutex
+       done bool
+}
+
+// Do calls the function f if and only if the method is being called for the
+// first time with this receiver.  In other words, given
+//     var once Once
+// if Do(f) is called multiple times, only the first call will invoke f,
+// even if f has a different value in each invocation.  A new instance of
+// Once is required for each function to execute.
+//
+// Do is intended for initialization that must be run exactly once.  Since f
+// is niladic, it may be necessary to use a function literal to capture the
+// arguments to a function to be invoked by Do:
+//     config.once.Do(func() { config.init(filename) })
+//
+// Because no call to Do returns until the one call to f returns, if f causes
+// Do to be called, it will deadlock.
+//
+func (o *Once) Do(f func()) {
+       o.m.Lock()
+       defer o.m.Unlock()
+       if !o.done {
+               o.done = true
+               f()
+       }
+}
diff --git a/libgo/go/sync/once_test.go b/libgo/go/sync/once_test.go
new file mode 100644 (file)
index 0000000..155954a
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync_test
+
+import (
+       . "sync"
+       "testing"
+)
+
+type one int
+
+func (o *one) Increment() {
+       *o++
+}
+
+func run(once *Once, o *one, c chan bool) {
+       once.Do(func() { o.Increment() })
+       c <- true
+}
+
+func TestOnce(t *testing.T) {
+       o := new(one)
+       once := new(Once)
+       c := make(chan bool)
+       const N = 10
+       for i := 0; i < N; i++ {
+               go run(once, o, c)
+       }
+       for i := 0; i < N; i++ {
+               <-c
+       }
+       if *o != 1 {
+               t.Errorf("once failed: %d is not 1", *o)
+       }
+}
diff --git a/libgo/go/sync/rwmutex.go b/libgo/go/sync/rwmutex.go
new file mode 100644 (file)
index 0000000..06fd0b0
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+// An RWMutex is a reader/writer mutual exclusion lock.
+// The lock can be held by an arbitrary number of readers
+// or a single writer.
+// RWMutexes can be created as part of other
+// structures; the zero value for a RWMutex is
+// an unlocked mutex.
+//
+// Writers take priority over Readers: no new RLocks
+// are granted while a blocked Lock call is waiting.
+type RWMutex struct {
+       w           Mutex  // held if there are pending readers or writers
+       r           Mutex  // held if the w is being rd
+       readerCount uint32 // number of pending readers
+}
+
+// RLock locks rw for reading.
+// If the lock is already locked for writing or there is a writer already waiting
+// to release the lock, RLock blocks until the writer has released the lock.
+func (rw *RWMutex) RLock() {
+       // Use rw.r.Lock() to block granting the RLock if a goroutine
+       // is waiting for its Lock. This is the prevent starvation of W in
+       // this situation:
+       //   A: rw.RLock()  // granted
+       //   W: rw.Lock()   // waiting for rw.w().Lock()
+       //   B: rw.RLock()  // granted
+       //   C: rw.RLock()  // granted
+       //   B: rw.RUnlock()
+       //   ... (new readers come and go indefinitely, W is starving)
+       rw.r.Lock()
+       if xadd(&rw.readerCount, 1) == 1 {
+               // The first reader locks rw.w, so writers will be blocked
+               // while the readers have the RLock.
+               rw.w.Lock()
+       }
+       rw.r.Unlock()
+}
+
+// RUnlock undoes a single RLock call;
+// it does not affect other simultaneous readers.
+// It is a run-time error if rw is not locked for reading
+// on entry to RUnlock.
+func (rw *RWMutex) RUnlock() {
+       if xadd(&rw.readerCount, -1) == 0 {
+               // last reader finished, enable writers
+               rw.w.Unlock()
+       }
+}
+
+// Lock locks rw for writing.
+// If the lock is already locked for reading or writing,
+// Lock blocks until the lock is available.
+// To ensure that the lock eventually becomes available,
+// a blocked Lock call excludes new readers from acquiring
+// the lock.
+func (rw *RWMutex) Lock() {
+       rw.r.Lock()
+       rw.w.Lock()
+       rw.r.Unlock()
+}
+
+// Unlock unlocks rw for writing.
+// It is a run-time error if rw is not locked for writing
+// on entry to Unlock.
+//
+// Like for Mutexes,
+// a locked RWMutex is not associated with a particular goroutine.
+// It is allowed for one goroutine to RLock (Lock) an RWMutex and then
+// arrange for another goroutine to RUnlock (Unlock) it.
+func (rw *RWMutex) Unlock() { rw.w.Unlock() }
diff --git a/libgo/go/sync/rwmutex_test.go b/libgo/go/sync/rwmutex_test.go
new file mode 100644 (file)
index 0000000..111bca1
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// GOMAXPROCS=10 gotest
+
+package sync_test
+
+import (
+       "fmt"
+       "runtime"
+       . "sync"
+       "testing"
+)
+
+func parallelReader(m *RWMutex, clocked, cunlock, cdone chan bool) {
+       m.RLock()
+       clocked <- true
+       <-cunlock
+       m.RUnlock()
+       cdone <- true
+}
+
+func doTestParallelReaders(numReaders, gomaxprocs int) {
+       runtime.GOMAXPROCS(gomaxprocs)
+       var m RWMutex
+       clocked := make(chan bool)
+       cunlock := make(chan bool)
+       cdone := make(chan bool)
+       for i := 0; i < numReaders; i++ {
+               go parallelReader(&m, clocked, cunlock, cdone)
+       }
+       // Wait for all parallel RLock()s to succeed.
+       for i := 0; i < numReaders; i++ {
+               <-clocked
+       }
+       for i := 0; i < numReaders; i++ {
+               cunlock <- true
+       }
+       // Wait for the goroutines to finish.
+       for i := 0; i < numReaders; i++ {
+               <-cdone
+       }
+}
+
+func TestParallelReaders(t *testing.T) {
+       doTestParallelReaders(1, 4)
+       doTestParallelReaders(3, 4)
+       doTestParallelReaders(4, 2)
+}
+
+func reader(rwm *RWMutex, num_iterations int, activity *uint32, cdone chan bool) {
+       for i := 0; i < num_iterations; i++ {
+               rwm.RLock()
+               n := Xadd(activity, 1)
+               if n < 1 || n >= 10000 {
+                       panic(fmt.Sprintf("wlock(%d)\n", n))
+               }
+               for i := 0; i < 100; i++ {
+               }
+               Xadd(activity, -1)
+               rwm.RUnlock()
+       }
+       cdone <- true
+}
+
+func writer(rwm *RWMutex, num_iterations int, activity *uint32, cdone chan bool) {
+       for i := 0; i < num_iterations; i++ {
+               rwm.Lock()
+               n := Xadd(activity, 10000)
+               if n != 10000 {
+                       panic(fmt.Sprintf("wlock(%d)\n", n))
+               }
+               for i := 0; i < 100; i++ {
+               }
+               Xadd(activity, -10000)
+               rwm.Unlock()
+       }
+       cdone <- true
+}
+
+func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
+       runtime.GOMAXPROCS(gomaxprocs)
+       // Number of active readers + 10000 * number of active writers.
+       var activity uint32
+       var rwm RWMutex
+       cdone := make(chan bool)
+       go writer(&rwm, num_iterations, &activity, cdone)
+       var i int
+       for i = 0; i < numReaders/2; i++ {
+               go reader(&rwm, num_iterations, &activity, cdone)
+       }
+       go writer(&rwm, num_iterations, &activity, cdone)
+       for ; i < numReaders; i++ {
+               go reader(&rwm, num_iterations, &activity, cdone)
+       }
+       // Wait for the 2 writers and all readers to finish.
+       for i := 0; i < 2+numReaders; i++ {
+               <-cdone
+       }
+}
+
+func TestRWMutex(t *testing.T) {
+       HammerRWMutex(1, 1, 1000)
+       HammerRWMutex(1, 3, 1000)
+       HammerRWMutex(1, 10, 1000)
+       HammerRWMutex(4, 1, 1000)
+       HammerRWMutex(4, 3, 1000)
+       HammerRWMutex(4, 10, 1000)
+       HammerRWMutex(10, 1, 1000)
+       HammerRWMutex(10, 3, 1000)
+       HammerRWMutex(10, 10, 1000)
+       HammerRWMutex(10, 5, 10000)
+}
diff --git a/libgo/go/sync/xadd_test.go b/libgo/go/sync/xadd_test.go
new file mode 100644 (file)
index 0000000..8b2ef76
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+func Xadd(val *uint32, delta int32) (new uint32) {
+       return xadd(val, delta)
+}
diff --git a/libgo/go/syslog/syslog.go b/libgo/go/syslog/syslog.go
new file mode 100644 (file)
index 0000000..4924a76
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The syslog package provides a simple interface to
+// the system log service. It can send messages to the
+// syslog daemon using UNIX domain sockets, UDP, or
+// TCP connections.
+package syslog
+
+import (
+       "fmt"
+       "log"
+       "net"
+       "os"
+)
+
+type Priority int
+
+const (
+       // From /usr/include/sys/syslog.h.
+       // These are the same on Linux, BSD, and OS X.
+       LOG_EMERG Priority = iota
+       LOG_ALERT
+       LOG_CRIT
+       LOG_ERR
+       LOG_WARNING
+       LOG_NOTICE
+       LOG_INFO
+       LOG_DEBUG
+)
+
+// A Writer is a connection to a syslog server.
+type Writer struct {
+       priority Priority
+       prefix   string
+       conn     net.Conn
+}
+
+// New establishes a new connection to the system log daemon.
+// Each write to the returned writer sends a log message with
+// the given priority and prefix.
+func New(priority Priority, prefix string) (w *Writer, err os.Error) {
+       return Dial("", "", priority, prefix)
+}
+
+// Dial establishes a connection to a log daemon by connecting
+// to address raddr on the network net.
+// Each write to the returned writer sends a log message with
+// the given priority and prefix.
+func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, err os.Error) {
+       if prefix == "" {
+               prefix = os.Args[0]
+       }
+       var conn net.Conn
+       if network == "" {
+               conn, err = unixSyslog()
+       } else {
+               conn, err = net.Dial(network, "", raddr)
+       }
+       return &Writer{priority, prefix, conn}, err
+}
+
+func unixSyslog() (conn net.Conn, err os.Error) {
+       logTypes := []string{"unixgram", "unix"}
+       logPaths := []string{"/dev/log", "/var/run/syslog"}
+       var raddr string
+       for _, network := range logTypes {
+               for _, path := range logPaths {
+                       raddr = path
+                       conn, err := net.Dial(network, "", raddr)
+                       if err != nil {
+                               continue
+                       } else {
+                               return conn, nil
+                       }
+               }
+       }
+       return nil, os.ErrorString("Unix syslog delivery error")
+}
+
+// Write sends a log message to the syslog daemon.
+func (w *Writer) Write(b []byte) (int, os.Error) {
+       if w.priority > LOG_DEBUG || w.priority < LOG_EMERG {
+               return 0, os.EINVAL
+       }
+       return fmt.Fprintf(w.conn, "<%d>%s: %s\n", w.priority, w.prefix, b)
+}
+
+func (w *Writer) writeString(p Priority, s string) (int, os.Error) {
+       return fmt.Fprintf(w.conn, "<%d>%s: %s\n", p, w.prefix, s)
+}
+
+func (w *Writer) Close() os.Error { return w.conn.Close() }
+
+// Emerg logs a message using the LOG_EMERG priority.
+func (w *Writer) Emerg(m string) (err os.Error) {
+       _, err = w.writeString(LOG_EMERG, m)
+       return err
+}
+// Crit logs a message using the LOG_CRIT priority.
+func (w *Writer) Crit(m string) (err os.Error) {
+       _, err = w.writeString(LOG_CRIT, m)
+       return err
+}
+// ERR logs a message using the LOG_ERR priority.
+func (w *Writer) Err(m string) (err os.Error) {
+       _, err = w.writeString(LOG_ERR, m)
+       return err
+}
+
+// Warning logs a message using the LOG_WARNING priority.
+func (w *Writer) Warning(m string) (err os.Error) {
+       _, err = w.writeString(LOG_WARNING, m)
+       return err
+}
+
+// Notice logs a message using the LOG_NOTICE priority.
+func (w *Writer) Notice(m string) (err os.Error) {
+       _, err = w.writeString(LOG_NOTICE, m)
+       return err
+}
+// Info logs a message using the LOG_INFO priority.
+func (w *Writer) Info(m string) (err os.Error) {
+       _, err = w.writeString(LOG_INFO, m)
+       return err
+}
+// Debug logs a message using the LOG_DEBUG priority.
+func (w *Writer) Debug(m string) (err os.Error) {
+       _, err = w.writeString(LOG_DEBUG, m)
+       return err
+}
+
+// NewLogger provides an object that implements the full log.Logger interface,
+// but sends messages to Syslog instead; flag is passed as is to Logger;
+// priority will be used for all messages sent using this interface.
+// All messages are logged with priority p.
+func NewLogger(p Priority, flag int) *log.Logger {
+       s, err := New(p, "")
+       if err != nil {
+               return nil
+       }
+       return log.New(s, "", flag)
+}
diff --git a/libgo/go/syslog/syslog_test.go b/libgo/go/syslog/syslog_test.go
new file mode 100644 (file)
index 0000000..eeae102
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package syslog
+
+import (
+       "io"
+       "log"
+       "net"
+       "testing"
+)
+
+var serverAddr string
+
+func runSyslog(c net.PacketConn, done chan<- string) {
+       var buf [4096]byte
+       var rcvd string = ""
+       for {
+               n, _, err := c.ReadFrom(buf[0:])
+               if err != nil || n == 0 {
+                       break
+               }
+               rcvd += string(buf[0:n])
+       }
+       done <- rcvd
+}
+
+func startServer(done chan<- string) {
+       c, e := net.ListenPacket("udp", "127.0.0.1:0")
+       if e != nil {
+               log.Exitf("net.ListenPacket failed udp :0 %v", e)
+       }
+       serverAddr = c.LocalAddr().String()
+       c.SetReadTimeout(100e6) // 100ms
+       go runSyslog(c, done)
+}
+
+func TestNew(t *testing.T) {
+       s, err := New(LOG_INFO, "")
+       if err != nil {
+               t.Fatalf("New() failed: %s", err)
+       }
+       // Don't send any messages.
+       s.Close()
+}
+
+func TestNewLogger(t *testing.T) {
+       f := NewLogger(LOG_INFO, 0)
+       if f == nil {
+               t.Errorf("NewLogger() failed")
+       }
+}
+
+func TestDial(t *testing.T) {
+       l, err := Dial("", "", LOG_ERR, "syslog_test")
+       if err != nil {
+               t.Fatalf("Dial() failed: %s", err)
+       }
+       l.Close()
+}
+
+func TestUDPDial(t *testing.T) {
+       done := make(chan string)
+       startServer(done)
+       l, err := Dial("udp", serverAddr, LOG_INFO, "syslog_test")
+       if err != nil {
+               t.Fatalf("syslog.Dial() failed: %s", err)
+       }
+       msg := "udp test"
+       l.Info(msg)
+       expected := "<6>syslog_test: udp test\n"
+       rcvd := <-done
+       if rcvd != expected {
+               t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
+       }
+}
+
+func TestWrite(t *testing.T) {
+       done := make(chan string)
+       startServer(done)
+       l, err := Dial("udp", serverAddr, LOG_ERR, "syslog_test")
+       if err != nil {
+               t.Fatalf("syslog.Dial() failed: %s", err)
+       }
+       msg := "write test"
+       _, err = io.WriteString(l, msg)
+       if err != nil {
+               t.Fatalf("WriteString() failed: %s", err)
+       }
+       expected := "<3>syslog_test: write test\n"
+       rcvd := <-done
+       if rcvd != expected {
+               t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
+       }
+}
diff --git a/libgo/go/tabwriter/tabwriter.go b/libgo/go/tabwriter/tabwriter.go
new file mode 100644 (file)
index 0000000..848703e
--- /dev/null
@@ -0,0 +1,586 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The tabwriter package implements a write filter (tabwriter.Writer)
+// that translates tabbed columns in input into properly aligned text.
+//
+// The package is using the Elastic Tabstops algorithm described at
+// http://nickgravgaard.com/elastictabstops/index.html.
+//
+package tabwriter
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "utf8"
+)
+
+
+// ----------------------------------------------------------------------------
+// Filter implementation
+
+// A cell represents a segment of text terminated by tabs or line breaks.
+// The text itself is stored in a separate buffer; cell only describes the
+// segment's size in bytes, its width in runes, and whether it's an htab
+// ('\t') terminated cell.
+//
+type cell struct {
+       size  int  // cell size in bytes
+       width int  // cell width in runes
+       htab  bool // true if the cell is terminated by an htab ('\t')
+}
+
+
+// A Writer is a filter that inserts padding around tab-delimited
+// columns in its input to align them in the output.
+//
+// The Writer treats incoming bytes as UTF-8 encoded text consisting
+// of cells terminated by (horizontal or vertical) tabs or line
+// breaks (newline or formfeed characters). Cells in adjacent lines
+// constitute a column. The Writer inserts padding as needed to
+// make all cells in a column have the same width, effectively
+// aligning the columns. It assumes that all characters have the
+// same width except for tabs for which a tabwidth must be specified.
+// Note that cells are tab-terminated, not tab-separated: trailing
+// non-tab text at the end of a line does not form a column cell.
+//
+// The Writer assumes that all Unicode code points have the same width;
+// this may not be true in some fonts.
+//
+// If DiscardEmptyColumns is set, empty columns that are terminated
+// entirely by vertical (or "soft") tabs are discarded. Columns
+// terminated by horizontal (or "hard") tabs are not affected by
+// this flag.
+//
+// If a Writer is configured to filter HTML, HTML tags and entities
+// are simply passed through. The widths of tags and entities are
+// assumed to be zero (tags) and one (entities) for formatting purposes.
+//
+// A segment of text may be escaped by bracketing it with Escape
+// characters. The tabwriter passes escaped text segments through
+// unchanged. In particular, it does not interpret any tabs or line
+// breaks within the segment. If the StripEscape flag is set, the
+// Escape characters are stripped from the output; otherwise they
+// are passed through as well. For the purpose of formatting, the
+// width of the escaped text is always computed excluding the Escape
+// characters.
+//
+// The formfeed character ('\f') acts like a newline but it also
+// terminates all columns in the current line (effectively calling
+// Flush). Cells in the next line start new columns. Unless found
+// inside an HTML tag or inside an escaped text segment, formfeed
+// characters appear as newlines in the output.
+//
+// The Writer must buffer input internally, because proper spacing
+// of one line may depend on the cells in future lines. Clients must
+// call Flush when done calling Write.
+//
+type Writer struct {
+       // configuration
+       output   io.Writer
+       minwidth int
+       tabwidth int
+       padding  int
+       padbytes [8]byte
+       flags    uint
+
+       // current state
+       buf     bytes.Buffer // collected text excluding tabs or line breaks
+       pos     int          // buffer position up to which cell.width of incomplete cell has been computed
+       cell    cell         // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
+       endChar byte         // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
+       lines   [][]cell     // list of lines; each line is a list of cells
+       widths  []int        // list of column widths in runes - re-used during formatting
+}
+
+
+func (b *Writer) addLine() { b.lines = append(b.lines, []cell{}) }
+
+
+// Reset the current state.
+func (b *Writer) reset() {
+       b.buf.Reset()
+       b.pos = 0
+       b.cell = cell{}
+       b.endChar = 0
+       b.lines = b.lines[0:0]
+       b.widths = b.widths[0:0]
+       b.addLine()
+}
+
+
+// Internal representation (current state):
+//
+// - all text written is appended to buf; tabs and line breaks are stripped away
+// - at any given time there is a (possibly empty) incomplete cell at the end
+//   (the cell starts after a tab or line break)
+// - cell.size is the number of bytes belonging to the cell so far
+// - cell.width is text width in runes of that cell from the start of the cell to
+//   position pos; html tags and entities are excluded from this width if html
+//   filtering is enabled
+// - the sizes and widths of processed text are kept in the lines list
+//   which contains a list of cells for each line
+// - the widths list is a temporary list with current widths used during
+//   formatting; it is kept in Writer because it's re-used
+//
+//                    |<---------- size ---------->|
+//                    |                            |
+//                    |<- width ->|<- ignored ->|  |
+//                    |           |             |  |
+// [---processed---tab------------<tag>...</tag>...]
+// ^                  ^                         ^
+// |                  |                         |
+// buf                start of incomplete cell  pos
+
+
+// Formatting can be controlled with these flags.
+const (
+       // Ignore html tags and treat entities (starting with '&'
+       // and ending in ';') as single characters (width = 1).
+       FilterHTML uint = 1 << iota
+
+       // Strip Escape characters bracketing escaped text segments
+       // instead of passing them through unchanged with the text.
+       StripEscape
+
+       // Force right-alignment of cell content.
+       // Default is left-alignment.
+       AlignRight
+
+       // Handle empty columns as if they were not present in
+       // the input in the first place.
+       DiscardEmptyColumns
+
+       // Always use tabs for indentation columns (i.e., padding of
+       // leading empty cells on the left) independent of padchar.
+       TabIndent
+
+       // Print a vertical bar ('|') between columns (after formatting).
+       // Discarded colums appear as zero-width columns ("||").
+       Debug
+)
+
+
+// A Writer must be initialized with a call to Init. The first parameter (output)
+// specifies the filter output. The remaining parameters control the formatting:
+//
+//     minwidth        minimal cell width including any padding
+//     tabwidth        width of tab characters (equivalent number of spaces)
+//     padding         padding added to a cell before computing its width
+//     padchar         ASCII char used for padding
+//                     if padchar == '\t', the Writer will assume that the
+//                     width of a '\t' in the formatted output is tabwidth,
+//                     and cells are left-aligned independent of align_left
+//                     (for correct-looking results, tabwidth must correspond
+//                     to the tab width in the viewer displaying the result)
+//     flags           formatting control
+//
+// To format in tab-separated columns with a tab stop of 8:
+//     b.Init(w, 8, 1, 8, '\t', 0);
+//
+// To format in space-separated columns with at least 4 spaces between columns:
+//     b.Init(w, 0, 4, 8, ' ', 0);
+//
+func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
+       if minwidth < 0 || tabwidth < 0 || padding < 0 {
+               panic("negative minwidth, tabwidth, or padding")
+       }
+       b.output = output
+       b.minwidth = minwidth
+       b.tabwidth = tabwidth
+       b.padding = padding
+       for i := range b.padbytes {
+               b.padbytes[i] = padchar
+       }
+       if padchar == '\t' {
+               // tab padding enforces left-alignment
+               flags &^= AlignRight
+       }
+       b.flags = flags
+
+       b.reset()
+
+       return b
+}
+
+
+// debugging support (keep code around)
+func (b *Writer) dump() {
+       pos := 0
+       for i, line := range b.lines {
+               print("(", i, ") ")
+               for _, c := range line {
+                       print("[", string(b.buf.Bytes()[pos:pos+c.size]), "]")
+                       pos += c.size
+               }
+               print("\n")
+       }
+       print("\n")
+}
+
+
+// local error wrapper so we can distinguish os.Errors we want to return
+// as errors from genuine panics (which we don't want to return as errors)
+type osError struct {
+       err os.Error
+}
+
+
+func (b *Writer) write0(buf []byte) {
+       n, err := b.output.Write(buf)
+       if n != len(buf) && err == nil {
+               err = os.EIO
+       }
+       if err != nil {
+               panic(osError{err})
+       }
+}
+
+
+func (b *Writer) writeN(src []byte, n int) {
+       for n > len(src) {
+               b.write0(src)
+               n -= len(src)
+       }
+       b.write0(src[0:n])
+}
+
+
+var (
+       newline = []byte{'\n'}
+       tabs    = []byte("\t\t\t\t\t\t\t\t")
+)
+
+
+func (b *Writer) writePadding(textw, cellw int, useTabs bool) {
+       if b.padbytes[0] == '\t' || useTabs {
+               // padding is done with tabs
+               if b.tabwidth == 0 {
+                       return // tabs have no width - can't do any padding
+               }
+               // make cellw the smallest multiple of b.tabwidth
+               cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth
+               n := cellw - textw // amount of padding
+               if n < 0 {
+                       panic("internal error")
+               }
+               b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth)
+               return
+       }
+
+       // padding is done with non-tab characters
+       b.writeN(b.padbytes[0:], cellw-textw)
+}
+
+
+var vbar = []byte{'|'}
+
+func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
+       pos = pos0
+       for i := line0; i < line1; i++ {
+               line := b.lines[i]
+
+               // if TabIndent is set, use tabs to pad leading empty cells
+               useTabs := b.flags&TabIndent != 0
+
+               for j, c := range line {
+                       if j > 0 && b.flags&Debug != 0 {
+                               // indicate column break
+                               b.write0(vbar)
+                       }
+
+                       if c.size == 0 {
+                               // empty cell
+                               if j < len(b.widths) {
+                                       b.writePadding(c.width, b.widths[j], useTabs)
+                               }
+                       } else {
+                               // non-empty cell
+                               useTabs = false
+                               if b.flags&AlignRight == 0 { // align left
+                                       b.write0(b.buf.Bytes()[pos : pos+c.size])
+                                       pos += c.size
+                                       if j < len(b.widths) {
+                                               b.writePadding(c.width, b.widths[j], false)
+                                       }
+                               } else { // align right
+                                       if j < len(b.widths) {
+                                               b.writePadding(c.width, b.widths[j], false)
+                                       }
+                                       b.write0(b.buf.Bytes()[pos : pos+c.size])
+                                       pos += c.size
+                               }
+                       }
+               }
+
+               if i+1 == len(b.lines) {
+                       // last buffered line - we don't have a newline, so just write
+                       // any outstanding buffered data
+                       b.write0(b.buf.Bytes()[pos : pos+b.cell.size])
+                       pos += b.cell.size
+               } else {
+                       // not the last line - write newline
+                       b.write0(newline)
+               }
+       }
+       return
+}
+
+
+// Format the text between line0 and line1 (excluding line1); pos
+// is the buffer position corresponding to the beginning of line0.
+// Returns the buffer position corresponding to the beginning of
+// line1 and an error, if any.
+//
+func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
+       pos = pos0
+       column := len(b.widths)
+       for this := line0; this < line1; this++ {
+               line := b.lines[this]
+
+               if column < len(line)-1 {
+                       // cell exists in this column => this line
+                       // has more cells than the previous line
+                       // (the last cell per line is ignored because cells are
+                       // tab-terminated; the last cell per line describes the
+                       // text before the newline/formfeed and does not belong
+                       // to a column)
+
+                       // print unprinted lines until beginning of block
+                       pos = b.writeLines(pos, line0, this)
+                       line0 = this
+
+                       // column block begin
+                       width := b.minwidth // minimal column width
+                       discardable := true // true if all cells in this column are empty and "soft"
+                       for ; this < line1; this++ {
+                               line = b.lines[this]
+                               if column < len(line)-1 {
+                                       // cell exists in this column
+                                       c := line[column]
+                                       // update width
+                                       if w := c.width + b.padding; w > width {
+                                               width = w
+                                       }
+                                       // update discardable
+                                       if c.width > 0 || c.htab {
+                                               discardable = false
+                                       }
+                               } else {
+                                       break
+                               }
+                       }
+                       // column block end
+
+                       // discard empty columns if necessary
+                       if discardable && b.flags&DiscardEmptyColumns != 0 {
+                               width = 0
+                       }
+
+                       // format and print all columns to the right of this column
+                       // (we know the widths of this column and all columns to the left)
+                       b.widths = append(b.widths, width) // push width
+                       pos = b.format(pos, line0, this)
+                       b.widths = b.widths[0 : len(b.widths)-1] // pop width
+                       line0 = this
+               }
+       }
+
+       // print unprinted lines until end
+       return b.writeLines(pos, line0, line1)
+}
+
+
+// Append text to current cell.
+func (b *Writer) append(text []byte) {
+       b.buf.Write(text)
+       b.cell.size += len(text)
+}
+
+
+// Update the cell width.
+func (b *Writer) updateWidth() {
+       b.cell.width += utf8.RuneCount(b.buf.Bytes()[b.pos:b.buf.Len()])
+       b.pos = b.buf.Len()
+}
+
+
+// To escape a text segment, bracket it with Escape characters.
+// For instance, the tab in this string "Ignore this tab: \xff\t\xff"
+// does not terminate a cell and constitutes a single character of
+// width one for formatting purposes.
+//
+// The value 0xff was chosen because it cannot appear in a valid UTF-8 sequence.
+//
+const Escape = '\xff'
+
+
+// Start escaped mode.
+func (b *Writer) startEscape(ch byte) {
+       switch ch {
+       case Escape:
+               b.endChar = Escape
+       case '<':
+               b.endChar = '>'
+       case '&':
+               b.endChar = ';'
+       }
+}
+
+
+// Terminate escaped mode. If the escaped text was an HTML tag, its width
+// is assumed to be zero for formatting purposes; if it was an HTML entity,
+// its width is assumed to be one. In all other cases, the width is the
+// unicode width of the text.
+//
+func (b *Writer) endEscape() {
+       switch b.endChar {
+       case Escape:
+               b.updateWidth()
+               if b.flags&StripEscape == 0 {
+                       b.cell.width -= 2 // don't count the Escape chars
+               }
+       case '>': // tag of zero width
+       case ';':
+               b.cell.width++ // entity, count as one rune
+       }
+       b.pos = b.buf.Len()
+       b.endChar = 0
+}
+
+
+// Terminate the current cell by adding it to the list of cells of the
+// current line. Returns the number of cells in that line.
+//
+func (b *Writer) terminateCell(htab bool) int {
+       b.cell.htab = htab
+       line := &b.lines[len(b.lines)-1]
+       *line = append(*line, b.cell)
+       b.cell = cell{}
+       return len(*line)
+}
+
+
+func handlePanic(err *os.Error) {
+       if e := recover(); e != nil {
+               *err = e.(osError).err // re-panics if it's not a local osError
+       }
+}
+
+
+// Flush should be called after the last call to Write to ensure
+// that any data buffered in the Writer is written to output. Any
+// incomplete escape sequence at the end is simply considered
+// complete for formatting purposes.
+//
+func (b *Writer) Flush() (err os.Error) {
+       defer b.reset() // even in the presence of errors
+       defer handlePanic(&err)
+
+       // add current cell if not empty
+       if b.cell.size > 0 {
+               if b.endChar != 0 {
+                       // inside escape - terminate it even if incomplete
+                       b.endEscape()
+               }
+               b.terminateCell(false)
+       }
+
+       // format contents of buffer
+       b.format(0, 0, len(b.lines))
+
+       return
+}
+
+
+var hbar = []byte("---\n")
+
+// Write writes buf to the writer b.
+// The only errors returned are ones encountered
+// while writing to the underlying output stream.
+//
+func (b *Writer) Write(buf []byte) (n int, err os.Error) {
+       defer handlePanic(&err)
+
+       // split text into cells
+       n = 0
+       for i, ch := range buf {
+               if b.endChar == 0 {
+                       // outside escape
+                       switch ch {
+                       case '\t', '\v', '\n', '\f':
+                               // end of cell
+                               b.append(buf[n:i])
+                               b.updateWidth()
+                               n = i + 1 // ch consumed
+                               ncells := b.terminateCell(ch == '\t')
+                               if ch == '\n' || ch == '\f' {
+                                       // terminate line
+                                       b.addLine()
+                                       if ch == '\f' || ncells == 1 {
+                                               // A '\f' always forces a flush. Otherwise, if the previous
+                                               // line has only one cell which does not have an impact on
+                                               // the formatting of the following lines (the last cell per
+                                               // line is ignored by format()), thus we can flush the
+                                               // Writer contents.
+                                               if err = b.Flush(); err != nil {
+                                                       return
+                                               }
+                                               if ch == '\f' && b.flags&Debug != 0 {
+                                                       // indicate section break
+                                                       b.write0(hbar)
+                                               }
+                                       }
+                               }
+
+                       case Escape:
+                               // start of escaped sequence
+                               b.append(buf[n:i])
+                               b.updateWidth()
+                               n = i
+                               if b.flags&StripEscape != 0 {
+                                       n++ // strip Escape
+                               }
+                               b.startEscape(Escape)
+
+                       case '<', '&':
+                               // possibly an html tag/entity
+                               if b.flags&FilterHTML != 0 {
+                                       // begin of tag/entity
+                                       b.append(buf[n:i])
+                                       b.updateWidth()
+                                       n = i
+                                       b.startEscape(ch)
+                               }
+                       }
+
+               } else {
+                       // inside escape
+                       if ch == b.endChar {
+                               // end of tag/entity
+                               j := i + 1
+                               if ch == Escape && b.flags&StripEscape != 0 {
+                                       j = i // strip Escape
+                               }
+                               b.append(buf[n:j])
+                               n = i + 1 // ch consumed
+                               b.endEscape()
+                       }
+               }
+       }
+
+       // append leftover text
+       b.append(buf[n:])
+       n = len(buf)
+       return
+}
+
+
+// NewWriter allocates and initializes a new tabwriter.Writer.
+// The parameters are the same as for the the Init function.
+//
+func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
+       return new(Writer).Init(output, minwidth, tabwidth, padding, padchar, flags)
+}
diff --git a/libgo/go/tabwriter/tabwriter_test.go b/libgo/go/tabwriter/tabwriter_test.go
new file mode 100644 (file)
index 0000000..043d915
--- /dev/null
@@ -0,0 +1,625 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tabwriter
+
+import (
+       "io"
+       "os"
+       "testing"
+)
+
+
+type buffer struct {
+       a []byte
+}
+
+
+func (b *buffer) init(n int) { b.a = make([]byte, n)[0:0] }
+
+
+func (b *buffer) clear() { b.a = b.a[0:0] }
+
+
+func (b *buffer) Write(buf []byte) (written int, err os.Error) {
+       n := len(b.a)
+       m := len(buf)
+       if n+m <= cap(b.a) {
+               b.a = b.a[0 : n+m]
+               for i := 0; i < m; i++ {
+                       b.a[n+i] = buf[i]
+               }
+       } else {
+               panic("buffer.Write: buffer too small")
+       }
+       return len(buf), nil
+}
+
+
+func (b *buffer) String() string { return string(b.a) }
+
+
+func write(t *testing.T, testname string, w *Writer, src string) {
+       written, err := io.WriteString(w, src)
+       if err != nil {
+               t.Errorf("--- test: %s\n--- src:\n%q\n--- write error: %v\n", testname, src, err)
+       }
+       if written != len(src) {
+               t.Errorf("--- test: %s\n--- src:\n%q\n--- written = %d, len(src) = %d\n", testname, src, written, len(src))
+       }
+}
+
+
+func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) {
+       err := w.Flush()
+       if err != nil {
+               t.Errorf("--- test: %s\n--- src:\n%q\n--- flush error: %v\n", testname, src, err)
+       }
+
+       res := b.String()
+       if res != expected {
+               t.Errorf("--- test: %s\n--- src:\n%q\n--- found:\n%q\n--- expected:\n%q\n", testname, src, res, expected)
+       }
+}
+
+
+func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
+       var b buffer
+       b.init(1000)
+
+       var w Writer
+       w.Init(&b, minwidth, tabwidth, padding, padchar, flags)
+
+       // write all at once
+       title := testname + " (written all at once)"
+       b.clear()
+       write(t, title, &w, src)
+       verify(t, title, &w, &b, src, expected)
+
+       // write byte-by-byte
+       title = testname + " (written byte-by-byte)"
+       b.clear()
+       for i := 0; i < len(src); i++ {
+               write(t, title, &w, src[i:i+1])
+       }
+       verify(t, title, &w, &b, src, expected)
+
+       // write using Fibonacci slice sizes
+       title = testname + " (written in fibonacci slices)"
+       b.clear()
+       for i, d := 0, 0; i < len(src); {
+               write(t, title, &w, src[i:i+d])
+               i, d = i+d, d+1
+               if i+d > len(src) {
+                       d = len(src) - i
+               }
+       }
+       verify(t, title, &w, &b, src, expected)
+}
+
+
+var tests = []struct {
+       testname                    string
+       minwidth, tabwidth, padding int
+       padchar                     byte
+       flags                       uint
+       src, expected               string
+}{
+       {
+               "1a",
+               8, 0, 1, '.', 0,
+               "",
+               "",
+       },
+
+       {
+               "1a debug",
+               8, 0, 1, '.', Debug,
+               "",
+               "",
+       },
+
+       {
+               "1b esc stripped",
+               8, 0, 1, '.', StripEscape,
+               "\xff\xff",
+               "",
+       },
+
+       {
+               "1b esc",
+               8, 0, 1, '.', 0,
+               "\xff\xff",
+               "\xff\xff",
+       },
+
+       {
+               "1c esc stripped",
+               8, 0, 1, '.', StripEscape,
+               "\xff\t\xff",
+               "\t",
+       },
+
+       {
+               "1c esc",
+               8, 0, 1, '.', 0,
+               "\xff\t\xff",
+               "\xff\t\xff",
+       },
+
+       {
+               "1d esc stripped",
+               8, 0, 1, '.', StripEscape,
+               "\xff\"foo\t\n\tbar\"\xff",
+               "\"foo\t\n\tbar\"",
+       },
+
+       {
+               "1d esc",
+               8, 0, 1, '.', 0,
+               "\xff\"foo\t\n\tbar\"\xff",
+               "\xff\"foo\t\n\tbar\"\xff",
+       },
+
+       {
+               "1e esc stripped",
+               8, 0, 1, '.', StripEscape,
+               "abc\xff\tdef", // unterminated escape
+               "abc\tdef",
+       },
+
+       {
+               "1e esc",
+               8, 0, 1, '.', 0,
+               "abc\xff\tdef", // unterminated escape
+               "abc\xff\tdef",
+       },
+
+       {
+               "2",
+               8, 0, 1, '.', 0,
+               "\n\n\n",
+               "\n\n\n",
+       },
+
+       {
+               "3",
+               8, 0, 1, '.', 0,
+               "a\nb\nc",
+               "a\nb\nc",
+       },
+
+       {
+               "4a",
+               8, 0, 1, '.', 0,
+               "\t", // '\t' terminates an empty cell on last line - nothing to print
+               "",
+       },
+
+       {
+               "4b",
+               8, 0, 1, '.', AlignRight,
+               "\t", // '\t' terminates an empty cell on last line - nothing to print
+               "",
+       },
+
+       {
+               "5",
+               8, 0, 1, '.', 0,
+               "*\t*",
+               "*.......*",
+       },
+
+       {
+               "5b",
+               8, 0, 1, '.', 0,
+               "*\t*\n",
+               "*.......*\n",
+       },
+
+       {
+               "5c",
+               8, 0, 1, '.', 0,
+               "*\t*\t",
+               "*.......*",
+       },
+
+       {
+               "5c debug",
+               8, 0, 1, '.', Debug,
+               "*\t*\t",
+               "*.......|*",
+       },
+
+       {
+               "5d",
+               8, 0, 1, '.', AlignRight,
+               "*\t*\t",
+               ".......**",
+       },
+
+       {
+               "6",
+               8, 0, 1, '.', 0,
+               "\t\n",
+               "........\n",
+       },
+
+       {
+               "7a",
+               8, 0, 1, '.', 0,
+               "a) foo",
+               "a) foo",
+       },
+
+       {
+               "7b",
+               8, 0, 1, ' ', 0,
+               "b) foo\tbar",
+               "b) foo  bar",
+       },
+
+       {
+               "7c",
+               8, 0, 1, '.', 0,
+               "c) foo\tbar\t",
+               "c) foo..bar",
+       },
+
+       {
+               "7d",
+               8, 0, 1, '.', 0,
+               "d) foo\tbar\n",
+               "d) foo..bar\n",
+       },
+
+       {
+               "7e",
+               8, 0, 1, '.', 0,
+               "e) foo\tbar\t\n",
+               "e) foo..bar.....\n",
+       },
+
+       {
+               "7f",
+               8, 0, 1, '.', FilterHTML,
+               "f) f&lt;o\t<b>bar</b>\t\n",
+               "f) f&lt;o..<b>bar</b>.....\n",
+       },
+
+       {
+               "7g",
+               8, 0, 1, '.', FilterHTML,
+               "g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
+               "g) f&lt;o..<b>bar</b>..... non-terminated entity &amp",
+       },
+
+       {
+               "7g debug",
+               8, 0, 1, '.', FilterHTML | Debug,
+               "g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
+               "g) f&lt;o..|<b>bar</b>.....| non-terminated entity &amp",
+       },
+
+       {
+               "8",
+               8, 0, 1, '*', 0,
+               "Hello, world!\n",
+               "Hello, world!\n",
+       },
+
+       {
+               "9a",
+               1, 0, 0, '.', 0,
+               "1\t2\t3\t4\n" +
+                       "11\t222\t3333\t44444\n",
+
+               "1.2..3...4\n" +
+                       "11222333344444\n",
+       },
+
+       {
+               "9b",
+               1, 0, 0, '.', FilterHTML,
+               "1\t2<!---\f--->\t3\t4\n" + // \f inside HTML is ignored
+                       "11\t222\t3333\t44444\n",
+
+               "1.2<!---\f--->..3...4\n" +
+                       "11222333344444\n",
+       },
+
+       {
+               "9c",
+               1, 0, 0, '.', 0,
+               "1\t2\t3\t4\f" + // \f causes a newline and flush
+                       "11\t222\t3333\t44444\n",
+
+               "1234\n" +
+                       "11222333344444\n",
+       },
+
+       {
+               "9c debug",
+               1, 0, 0, '.', Debug,
+               "1\t2\t3\t4\f" + // \f causes a newline and flush
+                       "11\t222\t3333\t44444\n",
+
+               "1|2|3|4\n" +
+                       "---\n" +
+                       "11|222|3333|44444\n",
+       },
+
+       {
+               "10a",
+               5, 0, 0, '.', 0,
+               "1\t2\t3\t4\n",
+               "1....2....3....4\n",
+       },
+
+       {
+               "10b",
+               5, 0, 0, '.', 0,
+               "1\t2\t3\t4\t\n",
+               "1....2....3....4....\n",
+       },
+
+       {
+               "11",
+               8, 0, 1, '.', 0,
+               "本\tb\tc\n" +
+                       "aa\t\u672c\u672c\u672c\tcccc\tddddd\n" +
+                       "aaa\tbbbb\n",
+
+               "本.......b.......c\n" +
+                       "aa......本本本.....cccc....ddddd\n" +
+                       "aaa.....bbbb\n",
+       },
+
+       {
+               "12a",
+               8, 0, 1, ' ', AlignRight,
+               "a\tè\tc\t\n" +
+                       "aa\tèèè\tcccc\tddddd\t\n" +
+                       "aaa\tèèèè\t\n",
+
+               "       a       è       c\n" +
+                       "      aa     èèè    cccc   ddddd\n" +
+                       "     aaa    èèèè\n",
+       },
+
+       {
+               "12b",
+               2, 0, 0, ' ', 0,
+               "a\tb\tc\n" +
+                       "aa\tbbb\tcccc\n" +
+                       "aaa\tbbbb\n",
+
+               "a  b  c\n" +
+                       "aa bbbcccc\n" +
+                       "aaabbbb\n",
+       },
+
+       {
+               "12c",
+               8, 0, 1, '_', 0,
+               "a\tb\tc\n" +
+                       "aa\tbbb\tcccc\n" +
+                       "aaa\tbbbb\n",
+
+               "a_______b_______c\n" +
+                       "aa______bbb_____cccc\n" +
+                       "aaa_____bbbb\n",
+       },
+
+       {
+               "13a",
+               4, 0, 1, '-', 0,
+               "4444\t日本語\t22\t1\t333\n" +
+                       "999999999\t22\n" +
+                       "7\t22\n" +
+                       "\t\t\t88888888\n" +
+                       "\n" +
+                       "666666\t666666\t666666\t4444\n" +
+                       "1\t1\t999999999\t0000000000\n",
+
+               "4444------日本語-22--1---333\n" +
+                       "999999999-22\n" +
+                       "7---------22\n" +
+                       "------------------88888888\n" +
+                       "\n" +
+                       "666666-666666-666666----4444\n" +
+                       "1------1------999999999-0000000000\n",
+       },
+
+       {
+               "13b",
+               4, 0, 3, '.', 0,
+               "4444\t333\t22\t1\t333\n" +
+                       "999999999\t22\n" +
+                       "7\t22\n" +
+                       "\t\t\t88888888\n" +
+                       "\n" +
+                       "666666\t666666\t666666\t4444\n" +
+                       "1\t1\t999999999\t0000000000\n",
+
+               "4444........333...22...1...333\n" +
+                       "999999999...22\n" +
+                       "7...........22\n" +
+                       "....................88888888\n" +
+                       "\n" +
+                       "666666...666666...666666......4444\n" +
+                       "1........1........999999999...0000000000\n",
+       },
+
+       {
+               "13c",
+               8, 8, 1, '\t', FilterHTML,
+               "4444\t333\t22\t1\t333\n" +
+                       "999999999\t22\n" +
+                       "7\t22\n" +
+                       "\t\t\t88888888\n" +
+                       "\n" +
+                       "666666\t666666\t666666\t4444\n" +
+                       "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
+
+               "4444\t\t333\t22\t1\t333\n" +
+                       "999999999\t22\n" +
+                       "7\t\t22\n" +
+                       "\t\t\t\t88888888\n" +
+                       "\n" +
+                       "666666\t666666\t666666\t\t4444\n" +
+                       "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
+       },
+
+       {
+               "14",
+               1, 0, 2, ' ', AlignRight,
+               ".0\t.3\t2.4\t-5.1\t\n" +
+                       "23.0\t12345678.9\t2.4\t-989.4\t\n" +
+                       "5.1\t12.0\t2.4\t-7.0\t\n" +
+                       ".0\t0.0\t332.0\t8908.0\t\n" +
+                       ".0\t-.3\t456.4\t22.1\t\n" +
+                       ".0\t1.2\t44.4\t-13.3\t\t",
+
+               "    .0          .3    2.4    -5.1\n" +
+                       "  23.0  12345678.9    2.4  -989.4\n" +
+                       "   5.1        12.0    2.4    -7.0\n" +
+                       "    .0         0.0  332.0  8908.0\n" +
+                       "    .0         -.3  456.4    22.1\n" +
+                       "    .0         1.2   44.4   -13.3",
+       },
+
+       {
+               "14 debug",
+               1, 0, 2, ' ', AlignRight | Debug,
+               ".0\t.3\t2.4\t-5.1\t\n" +
+                       "23.0\t12345678.9\t2.4\t-989.4\t\n" +
+                       "5.1\t12.0\t2.4\t-7.0\t\n" +
+                       ".0\t0.0\t332.0\t8908.0\t\n" +
+                       ".0\t-.3\t456.4\t22.1\t\n" +
+                       ".0\t1.2\t44.4\t-13.3\t\t",
+
+               "    .0|          .3|    2.4|    -5.1|\n" +
+                       "  23.0|  12345678.9|    2.4|  -989.4|\n" +
+                       "   5.1|        12.0|    2.4|    -7.0|\n" +
+                       "    .0|         0.0|  332.0|  8908.0|\n" +
+                       "    .0|         -.3|  456.4|    22.1|\n" +
+                       "    .0|         1.2|   44.4|   -13.3|",
+       },
+
+       {
+               "15a",
+               4, 0, 0, '.', 0,
+               "a\t\tb",
+               "a.......b",
+       },
+
+       {
+               "15b",
+               4, 0, 0, '.', DiscardEmptyColumns,
+               "a\t\tb", // htabs - do not discard column
+               "a.......b",
+       },
+
+       {
+               "15c",
+               4, 0, 0, '.', DiscardEmptyColumns,
+               "a\v\vb",
+               "a...b",
+       },
+
+       {
+               "15d",
+               4, 0, 0, '.', AlignRight | DiscardEmptyColumns,
+               "a\v\vb",
+               "...ab",
+       },
+
+       {
+               "16a",
+               100, 100, 0, '\t', 0,
+               "a\tb\t\td\n" +
+                       "a\tb\t\td\te\n" +
+                       "a\n" +
+                       "a\tb\tc\td\n" +
+                       "a\tb\tc\td\te\n",
+
+               "a\tb\t\td\n" +
+                       "a\tb\t\td\te\n" +
+                       "a\n" +
+                       "a\tb\tc\td\n" +
+                       "a\tb\tc\td\te\n",
+       },
+
+       {
+               "16b",
+               100, 100, 0, '\t', DiscardEmptyColumns,
+               "a\vb\v\vd\n" +
+                       "a\vb\v\vd\ve\n" +
+                       "a\n" +
+                       "a\vb\vc\vd\n" +
+                       "a\vb\vc\vd\ve\n",
+
+               "a\tb\td\n" +
+                       "a\tb\td\te\n" +
+                       "a\n" +
+                       "a\tb\tc\td\n" +
+                       "a\tb\tc\td\te\n",
+       },
+
+       {
+               "16b debug",
+               100, 100, 0, '\t', DiscardEmptyColumns | Debug,
+               "a\vb\v\vd\n" +
+                       "a\vb\v\vd\ve\n" +
+                       "a\n" +
+                       "a\vb\vc\vd\n" +
+                       "a\vb\vc\vd\ve\n",
+
+               "a\t|b\t||d\n" +
+                       "a\t|b\t||d\t|e\n" +
+                       "a\n" +
+                       "a\t|b\t|c\t|d\n" +
+                       "a\t|b\t|c\t|d\t|e\n",
+       },
+
+       {
+               "16c",
+               100, 100, 0, '\t', DiscardEmptyColumns,
+               "a\tb\t\td\n" + // hard tabs - do not discard column
+                       "a\tb\t\td\te\n" +
+                       "a\n" +
+                       "a\tb\tc\td\n" +
+                       "a\tb\tc\td\te\n",
+
+               "a\tb\t\td\n" +
+                       "a\tb\t\td\te\n" +
+                       "a\n" +
+                       "a\tb\tc\td\n" +
+                       "a\tb\tc\td\te\n",
+       },
+
+       {
+               "16c debug",
+               100, 100, 0, '\t', DiscardEmptyColumns | Debug,
+               "a\tb\t\td\n" + // hard tabs - do not discard column
+                       "a\tb\t\td\te\n" +
+                       "a\n" +
+                       "a\tb\tc\td\n" +
+                       "a\tb\tc\td\te\n",
+
+               "a\t|b\t|\t|d\n" +
+                       "a\t|b\t|\t|d\t|e\n" +
+                       "a\n" +
+                       "a\t|b\t|c\t|d\n" +
+                       "a\t|b\t|c\t|d\t|e\n",
+       },
+}
+
+
+func Test(t *testing.T) {
+       for _, e := range tests {
+               check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
+       }
+}
diff --git a/libgo/go/template/format.go b/libgo/go/template/format.go
new file mode 100644 (file)
index 0000000..8a31de9
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Template library: default formatters
+
+package template
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+)
+
+// StringFormatter formats into the default string representation.
+// It is stored under the name "str" and is the default formatter.
+// You can override the default formatter by storing your default
+// under the name "" in your custom formatter map.
+func StringFormatter(w io.Writer, value interface{}, format string) {
+       if b, ok := value.([]byte); ok {
+               w.Write(b)
+               return
+       }
+       fmt.Fprint(w, value)
+}
+
+var (
+       esc_quot = []byte("&#34;") // shorter than "&quot;"
+       esc_apos = []byte("&#39;") // shorter than "&apos;"
+       esc_amp  = []byte("&amp;")
+       esc_lt   = []byte("&lt;")
+       esc_gt   = []byte("&gt;")
+)
+
+// HTMLEscape writes to w the properly escaped HTML equivalent
+// of the plain text data s.
+func HTMLEscape(w io.Writer, s []byte) {
+       var esc []byte
+       last := 0
+       for i, c := range s {
+               switch c {
+               case '"':
+                       esc = esc_quot
+               case '\'':
+                       esc = esc_apos
+               case '&':
+                       esc = esc_amp
+               case '<':
+                       esc = esc_lt
+               case '>':
+                       esc = esc_gt
+               default:
+                       continue
+               }
+               w.Write(s[last:i])
+               w.Write(esc)
+               last = i + 1
+       }
+       w.Write(s[last:])
+}
+
+// HTMLFormatter formats arbitrary values for HTML
+func HTMLFormatter(w io.Writer, value interface{}, format string) {
+       b, ok := value.([]byte)
+       if !ok {
+               var buf bytes.Buffer
+               fmt.Fprint(&buf, value)
+               b = buf.Bytes()
+       }
+       HTMLEscape(w, b)
+}
diff --git a/libgo/go/template/template.go b/libgo/go/template/template.go
new file mode 100644 (file)
index 0000000..082c062
--- /dev/null
@@ -0,0 +1,968 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+       Data-driven templates for generating textual output such as
+       HTML.
+
+       Templates are executed by applying them to a data structure.
+       Annotations in the template refer to elements of the data
+       structure (typically a field of a struct or a key in a map)
+       to control execution and derive values to be displayed.
+       The template walks the structure as it executes and the
+       "cursor" @ represents the value at the current location
+       in the structure.
+
+       Data items may be values or pointers; the interface hides the
+       indirection.
+
+       In the following, 'field' is one of several things, according to the data.
+
+               - The name of a field of a struct (result = data.field),
+               - The value stored in a map under that key (result = data[field]), or
+               - The result of invoking a niladic single-valued method with that name
+                 (result = data.field())
+
+       Major constructs ({} are metacharacters; [] marks optional elements):
+
+               {# comment }
+
+       A one-line comment.
+
+               {.section field} XXX [ {.or} YYY ] {.end}
+
+       Set @ to the value of the field.  It may be an explicit @
+       to stay at the same point in the data. If the field is nil
+       or empty, execute YYY; otherwise execute XXX.
+
+               {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
+
+       Like .section, but field must be an array or slice.  XXX
+       is executed for each element.  If the array is nil or empty,
+       YYY is executed instead.  If the {.alternates with} marker
+       is present, ZZZ is executed between iterations of XXX.
+
+               {field}
+               {field|formatter}
+
+       Insert the value of the field into the output. Field is
+       first looked for in the cursor, as in .section and .repeated.
+       If it is not found, the search continues in outer sections
+       until the top level is reached.
+
+       If a formatter is specified, it must be named in the formatter
+       map passed to the template set up routines or in the default
+       set ("html","str","") and is used to process the data for
+       output.  The formatter function has signature
+               func(wr io.Writer, data interface{}, formatter string)
+       where wr is the destination for output, data is the field
+       value, and formatter is its name at the invocation site.
+*/
+package template
+
+import (
+       "container/vector"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "os"
+       "reflect"
+       "strings"
+)
+
+// Errors returned during parsing and execution.  Users may extract the information and reformat
+// if they desire.
+type Error struct {
+       Line int
+       Msg  string
+}
+
+func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
+
+// Most of the literals are aces.
+var lbrace = []byte{'{'}
+var rbrace = []byte{'}'}
+var space = []byte{' '}
+var tab = []byte{'\t'}
+
+// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
+const (
+       tokAlternates = iota
+       tokComment
+       tokEnd
+       tokLiteral
+       tokOr
+       tokRepeated
+       tokSection
+       tokText
+       tokVariable
+)
+
+// FormatterMap is the type describing the mapping from formatter
+// names to the functions that implement them.
+type FormatterMap map[string]func(io.Writer, interface{}, string)
+
+// Built-in formatters.
+var builtins = FormatterMap{
+       "html": HTMLFormatter,
+       "str":  StringFormatter,
+       "":     StringFormatter,
+}
+
+// The parsed state of a template is a vector of xxxElement structs.
+// Sections have line numbers so errors can be reported better during execution.
+
+// Plain text.
+type textElement struct {
+       text []byte
+}
+
+// A literal such as .meta-left or .meta-right
+type literalElement struct {
+       text []byte
+}
+
+// A variable to be evaluated
+type variableElement struct {
+       linenum   int
+       name      string
+       formatter string // TODO(r): implement pipelines
+}
+
+// A .section block, possibly with a .or
+type sectionElement struct {
+       linenum int    // of .section itself
+       field   string // cursor field for this block
+       start   int    // first element
+       or      int    // first element of .or block
+       end     int    // one beyond last element
+}
+
+// A .repeated block, possibly with a .or and a .alternates
+type repeatedElement struct {
+       sectionElement     // It has the same structure...
+       altstart       int // ... except for alternates
+       altend         int
+}
+
+// Template is the type that represents a template definition.
+// It is unchanged after parsing.
+type Template struct {
+       fmap FormatterMap // formatters for variables
+       // Used during parsing:
+       ldelim, rdelim []byte // delimiters; default {}
+       buf            []byte // input text to process
+       p              int    // position in buf
+       linenum        int    // position in input
+       // Parsed results:
+       elems *vector.Vector
+}
+
+// Internal state for executing a Template.  As we evaluate the struct,
+// the data item descends into the fields associated with sections, etc.
+// Parent is used to walk upwards to find variables higher in the tree.
+type state struct {
+       parent *state        // parent in hierarchy
+       data   reflect.Value // the driver data for this section etc.
+       wr     io.Writer     // where to send output
+}
+
+func (parent *state) clone(data reflect.Value) *state {
+       return &state{parent, data, parent.wr}
+}
+
+// New creates a new template with the specified formatter map (which
+// may be nil) to define auxiliary functions for formatting variables.
+func New(fmap FormatterMap) *Template {
+       t := new(Template)
+       t.fmap = fmap
+       t.ldelim = lbrace
+       t.rdelim = rbrace
+       t.elems = new(vector.Vector)
+       return t
+}
+
+// Report error and stop executing.  The line number must be provided explicitly.
+func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
+       panic(&Error{line, fmt.Sprintf(err, args...)})
+}
+
+// Report error, panic to terminate parsing.
+// The line number comes from the template state.
+func (t *Template) parseError(err string, args ...interface{}) {
+       panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
+}
+
+// -- Lexical analysis
+
+// Is c a white space character?
+func white(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
+
+// Safely, does s[n:n+len(t)] == t?
+func equal(s []byte, n int, t []byte) bool {
+       b := s[n:]
+       if len(t) > len(b) { // not enough space left for a match.
+               return false
+       }
+       for i, c := range t {
+               if c != b[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+// nextItem returns the next item from the input buffer.  If the returned
+// item is empty, we are at EOF.  The item will be either a
+// delimited string or a non-empty string between delimited
+// strings. Tokens stop at (but include, if plain text) a newline.
+// Action tokens on a line by themselves drop any space on
+// either side, up to and including the newline.
+func (t *Template) nextItem() []byte {
+       startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
+       start := t.p
+       var i int
+       newline := func() {
+               t.linenum++
+               i++
+       }
+       // Leading white space up to but not including newline
+       for i = start; i < len(t.buf); i++ {
+               if t.buf[i] == '\n' || !white(t.buf[i]) {
+                       break
+               }
+       }
+       leadingSpace := i > start
+       // What's left is nothing, newline, delimited string, or plain text
+Switch:
+       switch {
+       case i == len(t.buf):
+               // EOF; nothing to do
+       case t.buf[i] == '\n':
+               newline()
+       case equal(t.buf, i, t.ldelim):
+               left := i         // Start of left delimiter.
+               right := -1       // Will be (immediately after) right delimiter.
+               haveText := false // Delimiters contain text.
+               i += len(t.ldelim)
+               // Find the end of the action.
+               for ; i < len(t.buf); i++ {
+                       if t.buf[i] == '\n' {
+                               break
+                       }
+                       if equal(t.buf, i, t.rdelim) {
+                               i += len(t.rdelim)
+                               right = i
+                               break
+                       }
+                       haveText = true
+               }
+               if right < 0 {
+                       t.parseError("unmatched opening delimiter")
+                       return nil
+               }
+               // Is this a special action (starts with '.' or '#') and the only thing on the line?
+               if startOfLine && haveText {
+                       firstChar := t.buf[left+len(t.ldelim)]
+                       if firstChar == '.' || firstChar == '#' {
+                               // It's special and the first thing on the line. Is it the last?
+                               for j := right; j < len(t.buf) && white(t.buf[j]); j++ {
+                                       if t.buf[j] == '\n' {
+                                               // Yes it is. Drop the surrounding space and return the {.foo}
+                                               t.linenum++
+                                               t.p = j + 1
+                                               return t.buf[left:right]
+                                       }
+                               }
+                       }
+               }
+               // No it's not. If there's leading space, return that.
+               if leadingSpace {
+                       // not trimming space: return leading white space if there is some.
+                       t.p = left
+                       return t.buf[start:left]
+               }
+               // Return the word, leave the trailing space.
+               start = left
+               break
+       default:
+               for ; i < len(t.buf); i++ {
+                       if t.buf[i] == '\n' {
+                               newline()
+                               break
+                       }
+                       if equal(t.buf, i, t.ldelim) {
+                               break
+                       }
+               }
+       }
+       item := t.buf[start:i]
+       t.p = i
+       return item
+}
+
+// Turn a byte array into a white-space-split array of strings.
+func words(buf []byte) []string {
+       s := make([]string, 0, 5)
+       p := 0 // position in buf
+       // one word per loop
+       for i := 0; ; i++ {
+               // skip white space
+               for ; p < len(buf) && white(buf[p]); p++ {
+               }
+               // grab word
+               start := p
+               for ; p < len(buf) && !white(buf[p]); p++ {
+               }
+               if start == p { // no text left
+                       break
+               }
+               s = append(s, string(buf[start:p]))
+       }
+       return s
+}
+
+// Analyze an item and return its token type and, if it's an action item, an array of
+// its constituent words.
+func (t *Template) analyze(item []byte) (tok int, w []string) {
+       // item is known to be non-empty
+       if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
+               tok = tokText
+               return
+       }
+       if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
+               t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
+               return
+       }
+       if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
+               t.parseError("empty directive")
+               return
+       }
+       // Comment
+       if item[len(t.ldelim)] == '#' {
+               tok = tokComment
+               return
+       }
+       // Split into words
+       w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
+       if len(w) == 0 {
+               t.parseError("empty directive")
+               return
+       }
+       if len(w) == 1 && w[0][0] != '.' {
+               tok = tokVariable
+               return
+       }
+       switch w[0] {
+       case ".meta-left", ".meta-right", ".space", ".tab":
+               tok = tokLiteral
+               return
+       case ".or":
+               tok = tokOr
+               return
+       case ".end":
+               tok = tokEnd
+               return
+       case ".section":
+               if len(w) != 2 {
+                       t.parseError("incorrect fields for .section: %s", item)
+                       return
+               }
+               tok = tokSection
+               return
+       case ".repeated":
+               if len(w) != 3 || w[1] != "section" {
+                       t.parseError("incorrect fields for .repeated: %s", item)
+                       return
+               }
+               tok = tokRepeated
+               return
+       case ".alternates":
+               if len(w) != 2 || w[1] != "with" {
+                       t.parseError("incorrect fields for .alternates: %s", item)
+                       return
+               }
+               tok = tokAlternates
+               return
+       }
+       t.parseError("bad directive: %s", item)
+       return
+}
+
+// -- Parsing
+
+// Allocate a new variable-evaluation element.
+func (t *Template) newVariable(name_formatter string) (v *variableElement) {
+       name := name_formatter
+       formatter := ""
+       bar := strings.Index(name_formatter, "|")
+       if bar >= 0 {
+               name = name_formatter[0:bar]
+               formatter = name_formatter[bar+1:]
+       }
+       // Probably ok, so let's build it.
+       v = &variableElement{t.linenum, name, formatter}
+
+       // We could remember the function address here and avoid the lookup later,
+       // but it's more dynamic to let the user change the map contents underfoot.
+       // We do require the name to be present, though.
+
+       // Is it in user-supplied map?
+       if t.fmap != nil {
+               if _, ok := t.fmap[formatter]; ok {
+                       return
+               }
+       }
+       // Is it in builtin map?
+       if _, ok := builtins[formatter]; ok {
+               return
+       }
+       t.parseError("unknown formatter: %s", formatter)
+       return
+}
+
+// Grab the next item.  If it's simple, just append it to the template.
+// Otherwise return its details.
+func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
+       tok, w = t.analyze(item)
+       done = true // assume for simplicity
+       switch tok {
+       case tokComment:
+               return
+       case tokText:
+               t.elems.Push(&textElement{item})
+               return
+       case tokLiteral:
+               switch w[0] {
+               case ".meta-left":
+                       t.elems.Push(&literalElement{t.ldelim})
+               case ".meta-right":
+                       t.elems.Push(&literalElement{t.rdelim})
+               case ".space":
+                       t.elems.Push(&literalElement{space})
+               case ".tab":
+                       t.elems.Push(&literalElement{tab})
+               default:
+                       t.parseError("internal error: unknown literal: %s", w[0])
+               }
+               return
+       case tokVariable:
+               t.elems.Push(t.newVariable(w[0]))
+               return
+       }
+       return false, tok, w
+}
+
+// parseRepeated and parseSection are mutually recursive
+
+func (t *Template) parseRepeated(words []string) *repeatedElement {
+       r := new(repeatedElement)
+       t.elems.Push(r)
+       r.linenum = t.linenum
+       r.field = words[2]
+       // Scan section, collecting true and false (.or) blocks.
+       r.start = t.elems.Len()
+       r.or = -1
+       r.altstart = -1
+       r.altend = -1
+Loop:
+       for {
+               item := t.nextItem()
+               if len(item) == 0 {
+                       t.parseError("missing .end for .repeated section")
+                       break
+               }
+               done, tok, w := t.parseSimple(item)
+               if done {
+                       continue
+               }
+               switch tok {
+               case tokEnd:
+                       break Loop
+               case tokOr:
+                       if r.or >= 0 {
+                               t.parseError("extra .or in .repeated section")
+                               break Loop
+                       }
+                       r.altend = t.elems.Len()
+                       r.or = t.elems.Len()
+               case tokSection:
+                       t.parseSection(w)
+               case tokRepeated:
+                       t.parseRepeated(w)
+               case tokAlternates:
+                       if r.altstart >= 0 {
+                               t.parseError("extra .alternates in .repeated section")
+                               break Loop
+                       }
+                       if r.or >= 0 {
+                               t.parseError(".alternates inside .or block in .repeated section")
+                               break Loop
+                       }
+                       r.altstart = t.elems.Len()
+               default:
+                       t.parseError("internal error: unknown repeated section item: %s", item)
+                       break Loop
+               }
+       }
+       if r.altend < 0 {
+               r.altend = t.elems.Len()
+       }
+       r.end = t.elems.Len()
+       return r
+}
+
+func (t *Template) parseSection(words []string) *sectionElement {
+       s := new(sectionElement)
+       t.elems.Push(s)
+       s.linenum = t.linenum
+       s.field = words[1]
+       // Scan section, collecting true and false (.or) blocks.
+       s.start = t.elems.Len()
+       s.or = -1
+Loop:
+       for {
+               item := t.nextItem()
+               if len(item) == 0 {
+                       t.parseError("missing .end for .section")
+                       break
+               }
+               done, tok, w := t.parseSimple(item)
+               if done {
+                       continue
+               }
+               switch tok {
+               case tokEnd:
+                       break Loop
+               case tokOr:
+                       if s.or >= 0 {
+                               t.parseError("extra .or in .section")
+                               break Loop
+                       }
+                       s.or = t.elems.Len()
+               case tokSection:
+                       t.parseSection(w)
+               case tokRepeated:
+                       t.parseRepeated(w)
+               case tokAlternates:
+                       t.parseError(".alternates not in .repeated")
+               default:
+                       t.parseError("internal error: unknown section item: %s", item)
+               }
+       }
+       s.end = t.elems.Len()
+       return s
+}
+
+func (t *Template) parse() {
+       for {
+               item := t.nextItem()
+               if len(item) == 0 {
+                       break
+               }
+               done, tok, w := t.parseSimple(item)
+               if done {
+                       continue
+               }
+               switch tok {
+               case tokOr, tokEnd, tokAlternates:
+                       t.parseError("unexpected %s", w[0])
+               case tokSection:
+                       t.parseSection(w)
+               case tokRepeated:
+                       t.parseRepeated(w)
+               default:
+                       t.parseError("internal error: bad directive in parse: %s", item)
+               }
+       }
+}
+
+// -- Execution
+
+// Evaluate interfaces and pointers looking for a value that can look up the name, via a
+// struct field, method, or map key, and return the result of the lookup.
+func lookup(v reflect.Value, name string) reflect.Value {
+       for v != nil {
+               typ := v.Type()
+               if n := v.Type().NumMethod(); n > 0 {
+                       for i := 0; i < n; i++ {
+                               m := typ.Method(i)
+                               mtyp := m.Type
+                               if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
+                                       return v.Method(i).Call(nil)[0]
+                               }
+                       }
+               }
+               switch av := v.(type) {
+               case *reflect.PtrValue:
+                       v = av.Elem()
+               case *reflect.InterfaceValue:
+                       v = av.Elem()
+               case *reflect.StructValue:
+                       return av.FieldByName(name)
+               case *reflect.MapValue:
+                       return av.Elem(reflect.NewValue(name))
+               default:
+                       return nil
+               }
+       }
+       return v
+}
+
+// Walk v through pointers and interfaces, extracting the elements within.
+func indirect(v reflect.Value) reflect.Value {
+loop:
+       for v != nil {
+               switch av := v.(type) {
+               case *reflect.PtrValue:
+                       v = av.Elem()
+               case *reflect.InterfaceValue:
+                       v = av.Elem()
+               default:
+                       break loop
+               }
+       }
+       return v
+}
+
+// If the data for this template is a struct, find the named variable.
+// Names of the form a.b.c are walked down the data tree.
+// The special name "@" (the "cursor") denotes the current data.
+// The value coming in (st.data) might need indirecting to reach
+// a struct while the return value is not indirected - that is,
+// it represents the actual named field.
+func (st *state) findVar(s string) reflect.Value {
+       if s == "@" {
+               return st.data
+       }
+       data := st.data
+       for _, elem := range strings.Split(s, ".", -1) {
+               // Look up field; data must be a struct or map.
+               data = lookup(data, elem)
+               if data == nil {
+                       return nil
+               }
+       }
+       return data
+}
+
+// Is there no data to look at?
+func empty(v reflect.Value) bool {
+       v = indirect(v)
+       if v == nil {
+               return true
+       }
+       switch v := v.(type) {
+       case *reflect.BoolValue:
+               return v.Get() == false
+       case *reflect.StringValue:
+               return v.Get() == ""
+       case *reflect.StructValue:
+               return false
+       case *reflect.MapValue:
+               return false
+       case *reflect.ArrayValue:
+               return v.Len() == 0
+       case *reflect.SliceValue:
+               return v.Len() == 0
+       }
+       return true
+}
+
+// Look up a variable or method, up through the parent if necessary.
+func (t *Template) varValue(name string, st *state) reflect.Value {
+       field := st.findVar(name)
+       if field == nil {
+               if st.parent == nil {
+                       t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
+               }
+               return t.varValue(name, st.parent)
+       }
+       return field
+}
+
+// Evaluate a variable, looking up through the parent if necessary.
+// If it has a formatter attached ({var|formatter}) run that too.
+func (t *Template) writeVariable(v *variableElement, st *state) {
+       formatter := v.formatter
+       val := t.varValue(v.name, st).Interface()
+       // is it in user-supplied map?
+       if t.fmap != nil {
+               if fn, ok := t.fmap[formatter]; ok {
+                       fn(st.wr, val, formatter)
+                       return
+               }
+       }
+       // is it in builtin map?
+       if fn, ok := builtins[formatter]; ok {
+               fn(st.wr, val, formatter)
+               return
+       }
+       t.execError(st, v.linenum, "missing formatter %s for variable %s", formatter, v.name)
+}
+
+// Execute element i.  Return next index to execute.
+func (t *Template) executeElement(i int, st *state) int {
+       switch elem := t.elems.At(i).(type) {
+       case *textElement:
+               st.wr.Write(elem.text)
+               return i + 1
+       case *literalElement:
+               st.wr.Write(elem.text)
+               return i + 1
+       case *variableElement:
+               t.writeVariable(elem, st)
+               return i + 1
+       case *sectionElement:
+               t.executeSection(elem, st)
+               return elem.end
+       case *repeatedElement:
+               t.executeRepeated(elem, st)
+               return elem.end
+       }
+       e := t.elems.At(i)
+       t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.NewValue(e).Interface(), e)
+       return 0
+}
+
+// Execute the template.
+func (t *Template) execute(start, end int, st *state) {
+       for i := start; i < end; {
+               i = t.executeElement(i, st)
+       }
+}
+
+// Execute a .section
+func (t *Template) executeSection(s *sectionElement, st *state) {
+       // Find driver data for this section.  It must be in the current struct.
+       field := t.varValue(s.field, st)
+       if field == nil {
+               t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
+       }
+       st = st.clone(field)
+       start, end := s.start, s.or
+       if !empty(field) {
+               // Execute the normal block.
+               if end < 0 {
+                       end = s.end
+               }
+       } else {
+               // Execute the .or block.  If it's missing, do nothing.
+               start, end = s.or, s.end
+               if start < 0 {
+                       return
+               }
+       }
+       for i := start; i < end; {
+               i = t.executeElement(i, st)
+       }
+}
+
+// Return the result of calling the Iter method on v, or nil.
+func iter(v reflect.Value) *reflect.ChanValue {
+       for j := 0; j < v.Type().NumMethod(); j++ {
+               mth := v.Type().Method(j)
+               fv := v.Method(j)
+               ft := fv.Type().(*reflect.FuncType)
+               // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
+               if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
+                       continue
+               }
+               ct, ok := ft.Out(0).(*reflect.ChanType)
+               if !ok || ct.Dir()&reflect.RecvDir == 0 {
+                       continue
+               }
+               return fv.Call(nil)[0].(*reflect.ChanValue)
+       }
+       return nil
+}
+
+// Execute a .repeated section
+func (t *Template) executeRepeated(r *repeatedElement, st *state) {
+       // Find driver data for this section.  It must be in the current struct.
+       field := t.varValue(r.field, st)
+       if field == nil {
+               t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
+       }
+       field = indirect(field)
+
+       start, end := r.start, r.or
+       if end < 0 {
+               end = r.end
+       }
+       if r.altstart >= 0 {
+               end = r.altstart
+       }
+       first := true
+
+       // Code common to all the loops.
+       loopBody := func(newst *state) {
+               // .alternates between elements
+               if !first && r.altstart >= 0 {
+                       for i := r.altstart; i < r.altend; {
+                               i = t.executeElement(i, newst)
+                       }
+               }
+               first = false
+               for i := start; i < end; {
+                       i = t.executeElement(i, newst)
+               }
+       }
+
+       if array, ok := field.(reflect.ArrayOrSliceValue); ok {
+               for j := 0; j < array.Len(); j++ {
+                       loopBody(st.clone(array.Elem(j)))
+               }
+       } else if m, ok := field.(*reflect.MapValue); ok {
+               for _, key := range m.Keys() {
+                       loopBody(st.clone(m.Elem(key)))
+               }
+       } else if ch := iter(field); ch != nil {
+               for {
+                       e := ch.Recv()
+                       if ch.Closed() {
+                               break
+                       }
+                       loopBody(st.clone(e))
+               }
+       } else {
+               t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
+                       r.field, field.Type())
+       }
+
+       if first {
+               // Empty. Execute the .or block, once.  If it's missing, do nothing.
+               start, end := r.or, r.end
+               if start >= 0 {
+                       newst := st.clone(field)
+                       for i := start; i < end; {
+                               i = t.executeElement(i, newst)
+                       }
+               }
+               return
+       }
+}
+
+// A valid delimiter must contain no white space and be non-empty.
+func validDelim(d []byte) bool {
+       if len(d) == 0 {
+               return false
+       }
+       for _, c := range d {
+               if white(c) {
+                       return false
+               }
+       }
+       return true
+}
+
+// checkError is a deferred function to turn a panic with type *Error into a plain error return.
+// Other panics are unexpected and so are re-enabled.
+func checkError(error *os.Error) {
+       if v := recover(); v != nil {
+               if e, ok := v.(*Error); ok {
+                       *error = e
+               } else {
+                       // runtime errors should crash
+                       panic(v)
+               }
+       }
+}
+
+// -- Public interface
+
+// Parse initializes a Template by parsing its definition.  The string
+// s contains the template text.  If any errors occur, Parse returns
+// the error.
+func (t *Template) Parse(s string) (err os.Error) {
+       if t.elems == nil {
+               return &Error{1, "template not allocated with New"}
+       }
+       if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
+               return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
+       }
+       defer checkError(&err)
+       t.buf = []byte(s)
+       t.p = 0
+       t.linenum = 1
+       t.parse()
+       return nil
+}
+
+// ParseFile is like Parse but reads the template definition from the
+// named file.
+func (t *Template) ParseFile(filename string) (err os.Error) {
+       b, err := ioutil.ReadFile(filename)
+       if err != nil {
+               return err
+       }
+       return t.Parse(string(b))
+}
+
+// Execute applies a parsed template to the specified data object,
+// generating output to wr.
+func (t *Template) Execute(data interface{}, wr io.Writer) (err os.Error) {
+       // Extract the driver data.
+       val := reflect.NewValue(data)
+       defer checkError(&err)
+       t.p = 0
+       t.execute(0, t.elems.Len(), &state{nil, val, wr})
+       return nil
+}
+
+// SetDelims sets the left and right delimiters for operations in the
+// template.  They are validated during parsing.  They could be
+// validated here but it's better to keep the routine simple.  The
+// delimiters are very rarely invalid and Parse has the necessary
+// error-handling interface already.
+func (t *Template) SetDelims(left, right string) {
+       t.ldelim = []byte(left)
+       t.rdelim = []byte(right)
+}
+
+// Parse creates a Template with default parameters (such as {} for
+// metacharacters).  The string s contains the template text while
+// the formatter map fmap, which may be nil, defines auxiliary functions
+// for formatting variables.  The template is returned. If any errors
+// occur, err will be non-nil.
+func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
+       t = New(fmap)
+       err = t.Parse(s)
+       if err != nil {
+               t = nil
+       }
+       return
+}
+
+// ParseFile is a wrapper function that creates a Template with default
+// parameters (such as {} for metacharacters).  The filename identifies
+// a file containing the template text, while the formatter map fmap, which
+// may be nil, defines auxiliary functions for formatting variables.
+// The template is returned. If any errors occur, err will be non-nil.
+func ParseFile(filename string, fmap FormatterMap) (t *Template, err os.Error) {
+       b, err := ioutil.ReadFile(filename)
+       if err != nil {
+               return nil, err
+       }
+       return Parse(string(b), fmap)
+}
+
+// MustParse is like Parse but panics if the template cannot be parsed.
+func MustParse(s string, fmap FormatterMap) *Template {
+       t, err := Parse(s, fmap)
+       if err != nil {
+               panic("template.MustParse error: " + err.String())
+       }
+       return t
+}
+
+// MustParseFile is like ParseFile but panics if the file cannot be read
+// or the template cannot be parsed.
+func MustParseFile(filename string, fmap FormatterMap) *Template {
+       b, err := ioutil.ReadFile(filename)
+       if err != nil {
+               panic("template.MustParseFile error: " + err.String())
+       }
+       return MustParse(string(b), fmap)
+}
diff --git a/libgo/go/template/template_test.go b/libgo/go/template/template_test.go
new file mode 100644 (file)
index 0000000..00fd69a
--- /dev/null
@@ -0,0 +1,609 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+       "bytes"
+       "container/vector"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "json"
+       "os"
+       "testing"
+)
+
+type Test struct {
+       in, out, err string
+}
+
+type T struct {
+       item  string
+       value string
+}
+
+type U struct {
+       mp map[string]int
+}
+
+type S struct {
+       header        string
+       integer       int
+       raw           string
+       innerT        T
+       innerPointerT *T
+       data          []T
+       pdata         []*T
+       empty         []*T
+       emptystring   string
+       null          []*T
+       vec           *vector.Vector
+       true          bool
+       false         bool
+       mp            map[string]string
+       json          interface{}
+       innermap      U
+       stringmap     map[string]string
+       bytes         []byte
+       iface         interface{}
+       ifaceptr      interface{}
+}
+
+func (s *S) pointerMethod() string { return "ptrmethod!" }
+
+func (s S) valueMethod() string { return "valmethod!" }
+
+var t1 = T{"ItemNumber1", "ValueNumber1"}
+var t2 = T{"ItemNumber2", "ValueNumber2"}
+
+func uppercase(v interface{}) string {
+       s := v.(string)
+       t := ""
+       for i := 0; i < len(s); i++ {
+               c := s[i]
+               if 'a' <= c && c <= 'z' {
+                       c = c + 'A' - 'a'
+               }
+               t += string(c)
+       }
+       return t
+}
+
+func plus1(v interface{}) string {
+       i := v.(int)
+       return fmt.Sprint(i + 1)
+}
+
+func writer(f func(interface{}) string) func(io.Writer, interface{}, string) {
+       return func(w io.Writer, v interface{}, format string) {
+               io.WriteString(w, f(v))
+       }
+}
+
+
+var formatters = FormatterMap{
+       "uppercase": writer(uppercase),
+       "+1":        writer(plus1),
+}
+
+var tests = []*Test{
+       // Simple
+       &Test{"", "", ""},
+       &Test{"abc", "abc", ""},
+       &Test{"abc\ndef\n", "abc\ndef\n", ""},
+       &Test{" {.meta-left}   \n", "{", ""},
+       &Test{" {.meta-right}   \n", "}", ""},
+       &Test{" {.space}   \n", " ", ""},
+       &Test{" {.tab}   \n", "\t", ""},
+       &Test{"     {#comment}   \n", "", ""},
+       &Test{"\tSome Text\t\n", "\tSome Text\t\n", ""},
+       &Test{" {.meta-right} {.meta-right} {.meta-right} \n", " } } } \n", ""},
+
+       // Variables at top level
+       &Test{
+               in: "{header}={integer}\n",
+
+               out: "Header=77\n",
+       },
+
+       // Method at top level
+       &Test{
+               in: "ptrmethod={pointerMethod}\n",
+
+               out: "ptrmethod=ptrmethod!\n",
+       },
+
+       &Test{
+               in: "valmethod={valueMethod}\n",
+
+               out: "valmethod=valmethod!\n",
+       },
+
+       // Section
+       &Test{
+               in: "{.section data }\n" +
+                       "some text for the section\n" +
+                       "{.end}\n",
+
+               out: "some text for the section\n",
+       },
+       &Test{
+               in: "{.section data }\n" +
+                       "{header}={integer}\n" +
+                       "{.end}\n",
+
+               out: "Header=77\n",
+       },
+       &Test{
+               in: "{.section pdata }\n" +
+                       "{header}={integer}\n" +
+                       "{.end}\n",
+
+               out: "Header=77\n",
+       },
+       &Test{
+               in: "{.section pdata }\n" +
+                       "data present\n" +
+                       "{.or}\n" +
+                       "data not present\n" +
+                       "{.end}\n",
+
+               out: "data present\n",
+       },
+       &Test{
+               in: "{.section empty }\n" +
+                       "data present\n" +
+                       "{.or}\n" +
+                       "data not present\n" +
+                       "{.end}\n",
+
+               out: "data not present\n",
+       },
+       &Test{
+               in: "{.section null }\n" +
+                       "data present\n" +
+                       "{.or}\n" +
+                       "data not present\n" +
+                       "{.end}\n",
+
+               out: "data not present\n",
+       },
+       &Test{
+               in: "{.section pdata }\n" +
+                       "{header}={integer}\n" +
+                       "{.section @ }\n" +
+                       "{header}={integer}\n" +
+                       "{.end}\n" +
+                       "{.end}\n",
+
+               out: "Header=77\n" +
+                       "Header=77\n",
+       },
+
+       &Test{
+               in: "{.section data}{.end} {header}\n",
+
+               out: " Header\n",
+       },
+
+       // Repeated
+       &Test{
+               in: "{.section pdata }\n" +
+                       "{.repeated section @ }\n" +
+                       "{item}={value}\n" +
+                       "{.end}\n" +
+                       "{.end}\n",
+
+               out: "ItemNumber1=ValueNumber1\n" +
+                       "ItemNumber2=ValueNumber2\n",
+       },
+       &Test{
+               in: "{.section pdata }\n" +
+                       "{.repeated section @ }\n" +
+                       "{item}={value}\n" +
+                       "{.or}\n" +
+                       "this should not appear\n" +
+                       "{.end}\n" +
+                       "{.end}\n",
+
+               out: "ItemNumber1=ValueNumber1\n" +
+                       "ItemNumber2=ValueNumber2\n",
+       },
+       &Test{
+               in: "{.section @ }\n" +
+                       "{.repeated section empty }\n" +
+                       "{item}={value}\n" +
+                       "{.or}\n" +
+                       "this should appear: empty field\n" +
+                       "{.end}\n" +
+                       "{.end}\n",
+
+               out: "this should appear: empty field\n",
+       },
+       &Test{
+               in: "{.repeated section pdata }\n" +
+                       "{item}\n" +
+                       "{.alternates with}\n" +
+                       "is\nover\nmultiple\nlines\n" +
+                       "{.end}\n",
+
+               out: "ItemNumber1\n" +
+                       "is\nover\nmultiple\nlines\n" +
+                       "ItemNumber2\n",
+       },
+       &Test{
+               in: "{.repeated section pdata }\n" +
+                       "{item}\n" +
+                       "{.alternates with}\n" +
+                       "is\nover\nmultiple\nlines\n" +
+                       " {.end}\n",
+
+               out: "ItemNumber1\n" +
+                       "is\nover\nmultiple\nlines\n" +
+                       "ItemNumber2\n",
+       },
+       &Test{
+               in: "{.section pdata }\n" +
+                       "{.repeated section @ }\n" +
+                       "{item}={value}\n" +
+                       "{.alternates with}DIVIDER\n" +
+                       "{.or}\n" +
+                       "this should not appear\n" +
+                       "{.end}\n" +
+                       "{.end}\n",
+
+               out: "ItemNumber1=ValueNumber1\n" +
+                       "DIVIDER\n" +
+                       "ItemNumber2=ValueNumber2\n",
+       },
+       &Test{
+               in: "{.repeated section vec }\n" +
+                       "{@}\n" +
+                       "{.end}\n",
+
+               out: "elt1\n" +
+                       "elt2\n",
+       },
+       // Same but with a space before {.end}: was a bug.
+       &Test{
+               in: "{.repeated section vec }\n" +
+                       "{@} {.end}\n",
+
+               out: "elt1 elt2 \n",
+       },
+       &Test{
+               in: "{.repeated section integer}{.end}",
+
+               err: "line 1: .repeated: cannot repeat integer (type int)",
+       },
+
+       // Nested names
+       &Test{
+               in: "{.section @ }\n" +
+                       "{innerT.item}={innerT.value}\n" +
+                       "{.end}",
+
+               out: "ItemNumber1=ValueNumber1\n",
+       },
+       &Test{
+               in: "{.section @ }\n" +
+                       "{innerT.item}={.section innerT}{.section value}{@}{.end}{.end}\n" +
+                       "{.end}",
+
+               out: "ItemNumber1=ValueNumber1\n",
+       },
+
+
+       // Formatters
+       &Test{
+               in: "{.section pdata }\n" +
+                       "{header|uppercase}={integer|+1}\n" +
+                       "{header|html}={integer|str}\n" +
+                       "{.end}\n",
+
+               out: "HEADER=78\n" +
+                       "Header=77\n",
+       },
+
+       &Test{
+               in: "{raw}\n" +
+                       "{raw|html}\n",
+
+               out: "&<>!@ #$%^\n" +
+                       "&amp;&lt;&gt;!@ #$%^\n",
+       },
+
+       &Test{
+               in: "{.section emptystring}emptystring{.end}\n" +
+                       "{.section header}header{.end}\n",
+
+               out: "\nheader\n",
+       },
+
+       &Test{
+               in: "{.section true}1{.or}2{.end}\n" +
+                       "{.section false}3{.or}4{.end}\n",
+
+               out: "1\n4\n",
+       },
+
+       &Test{
+               in: "{bytes}",
+
+               out: "hello",
+       },
+
+       // Maps
+
+       &Test{
+               in: "{mp.mapkey}\n",
+
+               out: "Ahoy!\n",
+       },
+       &Test{
+               in: "{innermap.mp.innerkey}\n",
+
+               out: "55\n",
+       },
+       &Test{
+               in: "{.section innermap}{.section mp}{innerkey}{.end}{.end}\n",
+
+               out: "55\n",
+       },
+       &Test{
+               in: "{.section json}{.repeated section maps}{a}{b}{.end}{.end}\n",
+
+               out: "1234\n",
+       },
+       &Test{
+               in: "{stringmap.stringkey1}\n",
+
+               out: "stringresult\n",
+       },
+       &Test{
+               in: "{.repeated section stringmap}\n" +
+                       "{@}\n" +
+                       "{.end}",
+
+               out: "stringresult\n" +
+                       "stringresult\n",
+       },
+       &Test{
+               in: "{.repeated section stringmap}\n" +
+                       "\t{@}\n" +
+                       "{.end}",
+
+               out: "\tstringresult\n" +
+                       "\tstringresult\n",
+       },
+
+       // Interface values
+
+       &Test{
+               in: "{iface}",
+
+               out: "[1 2 3]",
+       },
+       &Test{
+               in: "{.repeated section iface}{@}{.alternates with} {.end}",
+
+               out: "1 2 3",
+       },
+       &Test{
+               in: "{.section iface}{@}{.end}",
+
+               out: "[1 2 3]",
+       },
+       &Test{
+               in: "{.section ifaceptr}{item} {value}{.end}",
+
+               out: "Item Value",
+       },
+}
+
+func TestAll(t *testing.T) {
+       // Parse
+       testAll(t, func(test *Test) (*Template, os.Error) { return Parse(test.in, formatters) })
+       // ParseFile
+       testAll(t, func(test *Test) (*Template, os.Error) {
+               err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+               if err != nil {
+                       t.Error("unexpected write error:", err)
+                       return nil, err
+               }
+               return ParseFile("_test/test.tmpl", formatters)
+       })
+       // tmpl.ParseFile
+       testAll(t, func(test *Test) (*Template, os.Error) {
+               err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+               if err != nil {
+                       t.Error("unexpected write error:", err)
+                       return nil, err
+               }
+               tmpl := New(formatters)
+               return tmpl, tmpl.ParseFile("_test/test.tmpl")
+       })
+}
+
+func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
+       s := new(S)
+       // initialized by hand for clarity.
+       s.header = "Header"
+       s.integer = 77
+       s.raw = "&<>!@ #$%^"
+       s.innerT = t1
+       s.data = []T{t1, t2}
+       s.pdata = []*T{&t1, &t2}
+       s.empty = []*T{}
+       s.null = nil
+       s.vec = new(vector.Vector)
+       s.vec.Push("elt1")
+       s.vec.Push("elt2")
+       s.true = true
+       s.false = false
+       s.mp = make(map[string]string)
+       s.mp["mapkey"] = "Ahoy!"
+       json.Unmarshal([]byte(`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`), &s.json)
+       s.innermap.mp = make(map[string]int)
+       s.innermap.mp["innerkey"] = 55
+       s.stringmap = make(map[string]string)
+       s.stringmap["stringkey1"] = "stringresult" // the same value so repeated section is order-independent
+       s.stringmap["stringkey2"] = "stringresult"
+       s.bytes = []byte("hello")
+       s.iface = []int{1, 2, 3}
+       s.ifaceptr = &T{"Item", "Value"}
+
+       var buf bytes.Buffer
+       for _, test := range tests {
+               buf.Reset()
+               tmpl, err := parseFunc(test)
+               if err != nil {
+                       t.Error("unexpected parse error: ", err)
+                       continue
+               }
+               err = tmpl.Execute(s, &buf)
+               if test.err == "" {
+                       if err != nil {
+                               t.Error("unexpected execute error:", err)
+                       }
+               } else {
+                       if err == nil {
+                               t.Errorf("expected execute error %q, got nil", test.err)
+                       } else if err.String() != test.err {
+                               t.Errorf("expected execute error %q, got %q", test.err, err.String())
+                       }
+               }
+               if buf.String() != test.out {
+                       t.Errorf("for %q: expected %q got %q", test.in, test.out, buf.String())
+               }
+       }
+}
+
+func TestMapDriverType(t *testing.T) {
+       mp := map[string]string{"footer": "Ahoy!"}
+       tmpl, err := Parse("template: {footer}", nil)
+       if err != nil {
+               t.Error("unexpected parse error:", err)
+       }
+       var b bytes.Buffer
+       err = tmpl.Execute(mp, &b)
+       if err != nil {
+               t.Error("unexpected execute error:", err)
+       }
+       s := b.String()
+       expected := "template: Ahoy!"
+       if s != expected {
+               t.Errorf("failed passing string as data: expected %q got %q", "template: Ahoy!", s)
+       }
+}
+
+func TestStringDriverType(t *testing.T) {
+       tmpl, err := Parse("template: {@}", nil)
+       if err != nil {
+               t.Error("unexpected parse error:", err)
+       }
+       var b bytes.Buffer
+       err = tmpl.Execute("hello", &b)
+       if err != nil {
+               t.Error("unexpected execute error:", err)
+       }
+       s := b.String()
+       if s != "template: hello" {
+               t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s)
+       }
+}
+
+func TestTwice(t *testing.T) {
+       tmpl, err := Parse("template: {@}", nil)
+       if err != nil {
+               t.Error("unexpected parse error:", err)
+       }
+       var b bytes.Buffer
+       err = tmpl.Execute("hello", &b)
+       if err != nil {
+               t.Error("unexpected parse error:", err)
+       }
+       s := b.String()
+       text := "template: hello"
+       if s != text {
+               t.Errorf("failed passing string as data: expected %q got %q", text, s)
+       }
+       err = tmpl.Execute("hello", &b)
+       if err != nil {
+               t.Error("unexpected parse error:", err)
+       }
+       s = b.String()
+       text += text
+       if s != text {
+               t.Errorf("failed passing string as data: expected %q got %q", text, s)
+       }
+}
+
+func TestCustomDelims(t *testing.T) {
+       // try various lengths.  zero should catch error.
+       for i := 0; i < 7; i++ {
+               for j := 0; j < 7; j++ {
+                       tmpl := New(nil)
+                       // first two chars deliberately the same to test equal left and right delims
+                       ldelim := "$!#$%^&"[0:i]
+                       rdelim := "$*&^%$!"[0:j]
+                       tmpl.SetDelims(ldelim, rdelim)
+                       // if braces, this would be template: {@}{.meta-left}{.meta-right}
+                       text := "template: " +
+                               ldelim + "@" + rdelim +
+                               ldelim + ".meta-left" + rdelim +
+                               ldelim + ".meta-right" + rdelim
+                       err := tmpl.Parse(text)
+                       if err != nil {
+                               if i == 0 || j == 0 { // expected
+                                       continue
+                               }
+                               t.Error("unexpected parse error:", err)
+                       } else if i == 0 || j == 0 {
+                               t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim)
+                               continue
+                       }
+                       var b bytes.Buffer
+                       err = tmpl.Execute("hello", &b)
+                       s := b.String()
+                       if s != "template: hello"+ldelim+rdelim {
+                               t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
+                       }
+               }
+       }
+}
+
+// Test that a variable evaluates to the field itself and does not further indirection
+func TestVarIndirection(t *testing.T) {
+       s := new(S)
+       // initialized by hand for clarity.
+       s.innerPointerT = &t1
+
+       var buf bytes.Buffer
+       input := "{.section @}{innerPointerT}{.end}"
+       tmpl, err := Parse(input, nil)
+       if err != nil {
+               t.Fatal("unexpected parse error:", err)
+       }
+       err = tmpl.Execute(s, &buf)
+       if err != nil {
+               t.Fatal("unexpected execute error:", err)
+       }
+       expect := fmt.Sprintf("%v", &t1) // output should be hex address of t1
+       if buf.String() != expect {
+               t.Errorf("for %q: expected %q got %q", input, expect, buf.String())
+       }
+}
+
+func TestHTMLFormatterWithByte(t *testing.T) {
+       s := "Test string."
+       b := []byte(s)
+       var buf bytes.Buffer
+       HTMLFormatter(&buf, b, "")
+       bs := buf.String()
+       if bs != s {
+               t.Errorf("munged []byte, expected: %s got: %s", s, bs)
+       }
+}
diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go
new file mode 100644 (file)
index 0000000..7c30e4e
--- /dev/null
@@ -0,0 +1,195 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing
+
+import (
+       "flag"
+       "fmt"
+       "os"
+       "time"
+)
+
+var matchBenchmarks = flag.String("benchmarks", "", "regular expression to select benchmarks to run")
+
+// An internal type but exported because it is cross-package; part of the implementation
+// of gotest.
+type InternalBenchmark struct {
+       Name string
+       F    func(b *B)
+}
+
+// B is a type passed to Benchmark functions to manage benchmark
+// timing and to specify the number of iterations to run.
+type B struct {
+       N         int
+       benchmark InternalBenchmark
+       ns        int64
+       bytes     int64
+       start     int64
+}
+
+// StartTimer starts timing a test.  This function is called automatically
+// before a benchmark starts, but it can also used to resume timing after
+// a call to StopTimer.
+func (b *B) StartTimer() { b.start = time.Nanoseconds() }
+
+// StopTimer stops timing a test.  This can be used to pause the timer
+// while performing complex initialization that you don't
+// want to measure.
+func (b *B) StopTimer() {
+       if b.start > 0 {
+               b.ns += time.Nanoseconds() - b.start
+       }
+       b.start = 0
+}
+
+// ResetTimer stops the timer and sets the elapsed benchmark time to zero.
+func (b *B) ResetTimer() {
+       b.start = 0
+       b.ns = 0
+}
+
+// SetBytes records the number of bytes processed in a single operation.
+// If this is called, the benchmark will report ns/op and MB/s.
+func (b *B) SetBytes(n int64) { b.bytes = n }
+
+func (b *B) nsPerOp() int64 {
+       if b.N <= 0 {
+               return 0
+       }
+       return b.ns / int64(b.N)
+}
+
+// runN runs a single benchmark for the specified number of iterations.
+func (b *B) runN(n int) {
+       b.N = n
+       b.ResetTimer()
+       b.StartTimer()
+       b.benchmark.F(b)
+       b.StopTimer()
+}
+
+func min(x, y int) int {
+       if x > y {
+               return y
+       }
+       return x
+}
+
+func max(x, y int) int {
+       if x < y {
+               return y
+       }
+       return x
+}
+
+// roundDown10 rounds a number down to the nearest power of 10.
+func roundDown10(n int) int {
+       var tens = 0
+       // tens = floor(log_10(n))
+       for n > 10 {
+               n = n / 10
+               tens++
+       }
+       // result = 10^tens
+       result := 1
+       for i := 0; i < tens; i++ {
+               result *= 10
+       }
+       return result
+}
+
+// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
+func roundUp(n int) int {
+       base := roundDown10(n)
+       if n < (2 * base) {
+               return 2 * base
+       }
+       if n < (5 * base) {
+               return 5 * base
+       }
+       return 10 * base
+}
+
+// run times the benchmark function.  It gradually increases the number
+// of benchmark iterations until the benchmark runs for a second in order
+// to get a reasonable measurement.  It prints timing information in this form
+//             testing.BenchmarkHello  100000          19 ns/op
+func (b *B) run() BenchmarkResult {
+       // Run the benchmark for a single iteration in case it's expensive.
+       n := 1
+       b.runN(n)
+       // Run the benchmark for at least a second.
+       for b.ns < 1e9 && n < 1e9 {
+               last := n
+               // Predict iterations/sec.
+               if b.nsPerOp() == 0 {
+                       n = 1e9
+               } else {
+                       n = 1e9 / int(b.nsPerOp())
+               }
+               // Run more iterations than we think we'll need for a second (1.5x).
+               // Don't grow too fast in case we had timing errors previously.
+               // Be sure to run at least one more than last time.
+               n = max(min(n+n/2, 100*last), last+1)
+               // Round up to something easy to read.
+               n = roundUp(n)
+               b.runN(n)
+       }
+       return BenchmarkResult{b.N, b.ns, b.bytes}
+
+}
+
+// The results of a benchmark run.
+type BenchmarkResult struct {
+       N     int   // The number of iterations.
+       Ns    int64 // The total time taken.
+       Bytes int64 // The total number of bytes processed.
+}
+
+func (r BenchmarkResult) NsPerOp() int64 {
+       if r.N <= 0 {
+               return 0
+       }
+       return r.Ns / int64(r.N)
+}
+
+func (r BenchmarkResult) String() string {
+       ns := r.NsPerOp()
+       mb := ""
+       if ns > 0 && r.Bytes > 0 {
+               mb = fmt.Sprintf("\t%7.2f MB/s", (float64(r.Bytes)/1e6)/(float64(ns)/1e9))
+       }
+       return fmt.Sprintf("%8d\t%10d ns/op%s", r.N, ns, mb)
+}
+
+// An internal function but exported because it is cross-package; part of the implementation
+// of gotest.
+func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmarks []InternalBenchmark) {
+       // If no flag was specified, don't run benchmarks.
+       if len(*matchBenchmarks) == 0 {
+               return
+       }
+       for _, Benchmark := range benchmarks {
+               matched, err := matchString(*matchBenchmarks, Benchmark.Name)
+               if err != nil {
+                       println("invalid regexp for -benchmarks:", err)
+                       os.Exit(1)
+               }
+               if !matched {
+                       continue
+               }
+               b := &B{benchmark: Benchmark}
+               r := b.run()
+               fmt.Printf("%s\t%v\n", Benchmark.Name, r)
+       }
+}
+
+// Benchmark benchmarks a single function. Useful for creating
+// custom benchmarks that do not use gotest.
+func Benchmark(name string, f func(b *B)) BenchmarkResult {
+       b := &B{benchmark: InternalBenchmark{name, f}}
+       return b.run()
+}
diff --git a/libgo/go/testing/iotest/logger.go b/libgo/go/testing/iotest/logger.go
new file mode 100644 (file)
index 0000000..c3bf5df
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package iotest
+
+import (
+       "io"
+       "log"
+       "os"
+)
+
+type writeLogger struct {
+       prefix string
+       w      io.Writer
+}
+
+func (l *writeLogger) Write(p []byte) (n int, err os.Error) {
+       n, err = l.w.Write(p)
+       if err != nil {
+               log.Printf("%s %x: %v", l.prefix, p[0:n], err)
+       } else {
+               log.Printf("%s %x", l.prefix, p[0:n])
+       }
+       return
+}
+
+// NewWriteLogger returns a writer that behaves like w except
+// that it logs (using log.Printf) each write to standard error,
+// printing the prefix and the hexadecimal data written.
+func NewWriteLogger(prefix string, w io.Writer) io.Writer {
+       return &writeLogger{prefix, w}
+}
+
+type readLogger struct {
+       prefix string
+       r      io.Reader
+}
+
+func (l *readLogger) Read(p []byte) (n int, err os.Error) {
+       n, err = l.r.Read(p)
+       if err != nil {
+               log.Printf("%s %x: %v", l.prefix, p[0:n], err)
+       } else {
+               log.Printf("%s %x", l.prefix, p[0:n])
+       }
+       return
+}
+
+// NewReadLogger returns a reader that behaves like r except
+// that it logs (using log.Print) each read to standard error,
+// printing the prefix and the hexadecimal data written.
+func NewReadLogger(prefix string, r io.Reader) io.Reader {
+       return &readLogger{prefix, r}
+}
diff --git a/libgo/go/testing/iotest/reader.go b/libgo/go/testing/iotest/reader.go
new file mode 100644 (file)
index 0000000..647520a
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The iotest package implements Readers and Writers
+// useful only for testing.
+package iotest
+
+import (
+       "io"
+       "os"
+)
+
+// OneByteReader returns a Reader that implements
+// each non-empty Read by reading one byte from r.
+func OneByteReader(r io.Reader) io.Reader { return &oneByteReader{r} }
+
+type oneByteReader struct {
+       r io.Reader
+}
+
+func (r *oneByteReader) Read(p []byte) (int, os.Error) {
+       if len(p) == 0 {
+               return 0, nil
+       }
+       return r.r.Read(p[0:1])
+}
+
+// HalfReader returns a Reader that implements Read
+// by reading half as many requested bytes from r.
+func HalfReader(r io.Reader) io.Reader { return &halfReader{r} }
+
+type halfReader struct {
+       r io.Reader
+}
+
+func (r *halfReader) Read(p []byte) (int, os.Error) {
+       return r.r.Read(p[0 : (len(p)+1)/2])
+}
+
+
+// DataErrReader returns a Reader that returns the final
+// error with the last data read, instead of by itself with
+// zero bytes of data.
+func DataErrReader(r io.Reader) io.Reader { return &dataErrReader{r, nil, make([]byte, 1024)} }
+
+type dataErrReader struct {
+       r      io.Reader
+       unread []byte
+       data   []byte
+}
+
+func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
+       // loop because first call needs two reads:
+       // one to get data and a second to look for an error.
+       for {
+               if len(r.unread) == 0 {
+                       n1, err1 := r.r.Read(r.data)
+                       r.unread = r.data[0:n1]
+                       err = err1
+               }
+               if n > 0 {
+                       break
+               }
+               n = copy(p, r.unread)
+               r.unread = r.unread[n:]
+       }
+       return
+}
diff --git a/libgo/go/testing/iotest/writer.go b/libgo/go/testing/iotest/writer.go
new file mode 100644 (file)
index 0000000..71f504c
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package iotest
+
+import (
+       "io"
+       "os"
+)
+
+// TruncateWriter returns a Writer that writes to w
+// but stops silently after n bytes.
+func TruncateWriter(w io.Writer, n int64) io.Writer {
+       return &truncateWriter{w, n}
+}
+
+type truncateWriter struct {
+       w io.Writer
+       n int64
+}
+
+func (t *truncateWriter) Write(p []byte) (n int, err os.Error) {
+       if t.n <= 0 {
+               return len(p), nil
+       }
+       // real write
+       n = len(p)
+       if int64(n) > t.n {
+               n = int(t.n)
+       }
+       n, err = t.w.Write(p[0:n])
+       t.n -= int64(n)
+       if err == nil {
+               n = len(p)
+       }
+       return
+}
diff --git a/libgo/go/testing/quick/quick.go b/libgo/go/testing/quick/quick.go
new file mode 100644 (file)
index 0000000..0b16597
--- /dev/null
@@ -0,0 +1,366 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements utility functions to help with black box testing.
+package quick
+
+import (
+       "flag"
+       "fmt"
+       "math"
+       "os"
+       "rand"
+       "reflect"
+       "strings"
+)
+
+var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
+
+// A Generator can generate random values of its own type.
+type Generator interface {
+       // Generate returns a random instance of the type on which it is a
+       // method using the size as a size hint.
+       Generate(rand *rand.Rand, size int) reflect.Value
+}
+
+// randFloat32 generates a random float taking the full range of a float32.
+func randFloat32(rand *rand.Rand) float32 {
+       f := rand.Float64() * math.MaxFloat32
+       if rand.Int()&1 == 1 {
+               f = -f
+       }
+       return float32(f)
+}
+
+// randFloat64 generates a random float taking the full range of a float64.
+func randFloat64(rand *rand.Rand) float64 {
+       f := rand.Float64()
+       if rand.Int()&1 == 1 {
+               f = -f
+       }
+       return f
+}
+
+// randInt64 returns a random integer taking half the range of an int64.
+func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }
+
+// complexSize is the maximum length of arbitrary values that contain other
+// values.
+const complexSize = 50
+
+// Value returns an arbitrary value of the given type.
+// If the type implements the Generator interface, that will be used.
+// Note: in order to create arbitrary values for structs, all the members must be public.
+func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
+       if m, ok := reflect.MakeZero(t).Interface().(Generator); ok {
+               return m.Generate(rand, complexSize), true
+       }
+
+       switch concrete := t.(type) {
+       case *reflect.BoolType:
+               return reflect.NewValue(rand.Int()&1 == 0), true
+       case *reflect.FloatType, *reflect.IntType, *reflect.UintType:
+               switch t.Kind() {
+               case reflect.Float32:
+                       return reflect.NewValue(randFloat32(rand)), true
+               case reflect.Float64:
+                       return reflect.NewValue(randFloat64(rand)), true
+               case reflect.Float:
+                       if t.Size() == 4 {
+                               return reflect.NewValue(float(randFloat32(rand))), true
+                       } else {
+                               return reflect.NewValue(float(randFloat64(rand))), true
+                       }
+               case reflect.Int16:
+                       return reflect.NewValue(int16(randInt64(rand))), true
+               case reflect.Int32:
+                       return reflect.NewValue(int32(randInt64(rand))), true
+               case reflect.Int64:
+                       return reflect.NewValue(randInt64(rand)), true
+               case reflect.Int8:
+                       return reflect.NewValue(int8(randInt64(rand))), true
+               case reflect.Int:
+                       return reflect.NewValue(int(randInt64(rand))), true
+               case reflect.Uint16:
+                       return reflect.NewValue(uint16(randInt64(rand))), true
+               case reflect.Uint32:
+                       return reflect.NewValue(uint32(randInt64(rand))), true
+               case reflect.Uint64:
+                       return reflect.NewValue(uint64(randInt64(rand))), true
+               case reflect.Uint8:
+                       return reflect.NewValue(uint8(randInt64(rand))), true
+               case reflect.Uint:
+                       return reflect.NewValue(uint(randInt64(rand))), true
+               case reflect.Uintptr:
+                       return reflect.NewValue(uintptr(randInt64(rand))), true
+               }
+       case *reflect.MapType:
+               numElems := rand.Intn(complexSize)
+               m := reflect.MakeMap(concrete)
+               for i := 0; i < numElems; i++ {
+                       key, ok1 := Value(concrete.Key(), rand)
+                       value, ok2 := Value(concrete.Elem(), rand)
+                       if !ok1 || !ok2 {
+                               return nil, false
+                       }
+                       m.SetElem(key, value)
+               }
+               return m, true
+       case *reflect.PtrType:
+               v, ok := Value(concrete.Elem(), rand)
+               if !ok {
+                       return nil, false
+               }
+               p := reflect.MakeZero(concrete)
+               p.(*reflect.PtrValue).PointTo(v)
+               return p, true
+       case *reflect.SliceType:
+               numElems := rand.Intn(complexSize)
+               s := reflect.MakeSlice(concrete, numElems, numElems)
+               for i := 0; i < numElems; i++ {
+                       v, ok := Value(concrete.Elem(), rand)
+                       if !ok {
+                               return nil, false
+                       }
+                       s.Elem(i).SetValue(v)
+               }
+               return s, true
+       case *reflect.StringType:
+               numChars := rand.Intn(complexSize)
+               codePoints := make([]int, numChars)
+               for i := 0; i < numChars; i++ {
+                       codePoints[i] = rand.Intn(0x10ffff)
+               }
+               return reflect.NewValue(string(codePoints)), true
+       case *reflect.StructType:
+               s := reflect.MakeZero(t).(*reflect.StructValue)
+               for i := 0; i < s.NumField(); i++ {
+                       v, ok := Value(concrete.Field(i).Type, rand)
+                       if !ok {
+                               return nil, false
+                       }
+                       s.Field(i).SetValue(v)
+               }
+               return s, true
+       default:
+               return nil, false
+       }
+
+       return
+}
+
+// A Config structure contains options for running a test.
+type Config struct {
+       // MaxCount sets the maximum number of iterations. If zero,
+       // MaxCountScale is used.
+       MaxCount int
+       // MaxCountScale is a non-negative scale factor applied to the default
+       // maximum. If zero, the default is unchanged.
+       MaxCountScale float
+       // If non-nil, rand is a source of random numbers. Otherwise a default
+       // pseudo-random source will be used.
+       Rand *rand.Rand
+       // If non-nil, Values is a function which generates a slice of arbitrary
+       // Values that are congruent with the arguments to the function being
+       // tested. Otherwise, Values is used to generate the values.
+       Values func([]reflect.Value, *rand.Rand)
+}
+
+var defaultConfig Config
+
+// getRand returns the *rand.Rand to use for a given Config.
+func (c *Config) getRand() *rand.Rand {
+       if c.Rand == nil {
+               return rand.New(rand.NewSource(0))
+       }
+       return c.Rand
+}
+
+// getMaxCount returns the maximum number of iterations to run for a given
+// Config.
+func (c *Config) getMaxCount() (maxCount int) {
+       maxCount = c.MaxCount
+       if maxCount == 0 {
+               if c.MaxCountScale != 0 {
+                       maxCount = int(c.MaxCountScale * float(*defaultMaxCount))
+               } else {
+                       maxCount = *defaultMaxCount
+               }
+       }
+
+       return
+}
+
+// A SetupError is the result of an error in the way that check is being
+// used, independent of the functions being tested.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+// A CheckError is the result of Check finding an error.
+type CheckError struct {
+       Count int
+       In    []interface{}
+}
+
+func (s *CheckError) String() string {
+       return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
+}
+
+// A CheckEqualError is the result CheckEqual finding an error.
+type CheckEqualError struct {
+       CheckError
+       Out1 []interface{}
+       Out2 []interface{}
+}
+
+func (s *CheckEqualError) String() string {
+       return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
+}
+
+// Check looks for an input to f, any function that returns bool,
+// such that f returns false.  It calls f repeatedly, with arbitrary
+// values for each argument.  If f returns false on a given input,
+// Check returns that input as a *CheckError.
+// For example:
+//
+//     func TestOddMultipleOfThree(t *testing.T) {
+//             f := func(x int) bool {
+//                     y := OddMultipleOfThree(x)
+//                     return y%2 == 1 && y%3 == 0
+//             }
+//             if err := quick.Check(f, nil); err != nil {
+//                     t.Error(err)
+//             }
+//     }
+func Check(function interface{}, config *Config) (err os.Error) {
+       if config == nil {
+               config = &defaultConfig
+       }
+
+       f, fType, ok := functionAndType(function)
+       if !ok {
+               err = SetupError("argument is not a function")
+               return
+       }
+
+       if fType.NumOut() != 1 {
+               err = SetupError("function returns more than one value.")
+               return
+       }
+       if _, ok := fType.Out(0).(*reflect.BoolType); !ok {
+               err = SetupError("function does not return a bool")
+               return
+       }
+
+       arguments := make([]reflect.Value, fType.NumIn())
+       rand := config.getRand()
+       maxCount := config.getMaxCount()
+
+       for i := 0; i < maxCount; i++ {
+               err = arbitraryValues(arguments, fType, config, rand)
+               if err != nil {
+                       return
+               }
+
+               if !f.Call(arguments)[0].(*reflect.BoolValue).Get() {
+                       err = &CheckError{i + 1, toInterfaces(arguments)}
+                       return
+               }
+       }
+
+       return
+}
+
+// CheckEqual looks for an input on which f and g return different results.
+// It calls f and g repeatedly with arbitrary values for each argument.
+// If f and g return different answers, CheckEqual returns a *CheckEqualError
+// describing the input and the outputs.
+func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
+       if config == nil {
+               config = &defaultConfig
+       }
+
+       x, xType, ok := functionAndType(f)
+       if !ok {
+               err = SetupError("f is not a function")
+               return
+       }
+       y, yType, ok := functionAndType(g)
+       if !ok {
+               err = SetupError("g is not a function")
+               return
+       }
+
+       if xType != yType {
+               err = SetupError("functions have different types")
+               return
+       }
+
+       arguments := make([]reflect.Value, xType.NumIn())
+       rand := config.getRand()
+       maxCount := config.getMaxCount()
+
+       for i := 0; i < maxCount; i++ {
+               err = arbitraryValues(arguments, xType, config, rand)
+               if err != nil {
+                       return
+               }
+
+               xOut := toInterfaces(x.Call(arguments))
+               yOut := toInterfaces(y.Call(arguments))
+
+               if !reflect.DeepEqual(xOut, yOut) {
+                       err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
+                       return
+               }
+       }
+
+       return
+}
+
+// arbitraryValues writes Values to args such that args contains Values
+// suitable for calling f.
+func arbitraryValues(args []reflect.Value, f *reflect.FuncType, config *Config, rand *rand.Rand) (err os.Error) {
+       if config.Values != nil {
+               config.Values(args, rand)
+               return
+       }
+
+       for j := 0; j < len(args); j++ {
+               var ok bool
+               args[j], ok = Value(f.In(j), rand)
+               if !ok {
+                       err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
+                       return
+               }
+       }
+
+       return
+}
+
+func functionAndType(f interface{}) (v *reflect.FuncValue, t *reflect.FuncType, ok bool) {
+       v, ok = reflect.NewValue(f).(*reflect.FuncValue)
+       if !ok {
+               return
+       }
+       t = v.Type().(*reflect.FuncType)
+       return
+}
+
+func toInterfaces(values []reflect.Value) []interface{} {
+       ret := make([]interface{}, len(values))
+       for i, v := range values {
+               ret[i] = v.Interface()
+       }
+       return ret
+}
+
+func toString(interfaces []interface{}) string {
+       s := make([]string, len(interfaces))
+       for i, v := range interfaces {
+               s[i] = fmt.Sprintf("%#v", v)
+       }
+       return strings.Join(s, ", ")
+}
diff --git a/libgo/go/testing/quick/quick_test.go b/libgo/go/testing/quick/quick_test.go
new file mode 100644 (file)
index 0000000..c7bff96
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quick
+
+import (
+       "rand"
+       "reflect"
+       "testing"
+       "os"
+)
+
+func fBool(a bool) bool { return a }
+
+func fFloat32(a float32) float32 { return a }
+
+func fFloat64(a float64) float64 { return a }
+
+func fFloat(a float) float { return a }
+
+func fInt16(a int16) int16 { return a }
+
+func fInt32(a int32) int32 { return a }
+
+func fInt64(a int64) int64 { return a }
+
+func fInt8(a int8) int8 { return a }
+
+func fInt(a int) int { return a }
+
+func fUInt8(a uint8) uint8 { return a }
+
+func fMap(a map[int]int) map[int]int { return a }
+
+func fSlice(a []byte) []byte { return a }
+
+func fString(a string) string { return a }
+
+type TestStruct struct {
+       A int
+       B string
+}
+
+func fStruct(a TestStruct) TestStruct { return a }
+
+func fUint16(a uint16) uint16 { return a }
+
+func fUint32(a uint32) uint32 { return a }
+
+func fUint64(a uint64) uint64 { return a }
+
+func fUint8(a uint8) uint8 { return a }
+
+func fUint(a uint) uint { return a }
+
+func fUintptr(a uintptr) uintptr { return a }
+
+func fIntptr(a *int) *int {
+       b := *a
+       return &b
+}
+
+func reportError(property string, err os.Error, t *testing.T) {
+       if err != nil {
+               t.Errorf("%s: %s", property, err)
+       }
+}
+
+func TestCheckEqual(t *testing.T) {
+       reportError("fBool", CheckEqual(fBool, fBool, nil), t)
+       reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t)
+       reportError("fFloat64", CheckEqual(fFloat64, fFloat64, nil), t)
+       reportError("fFloat", CheckEqual(fFloat, fFloat, nil), t)
+       reportError("fInt16", CheckEqual(fInt16, fInt16, nil), t)
+       reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
+       reportError("fInt64", CheckEqual(fInt64, fInt64, nil), t)
+       reportError("fInt8", CheckEqual(fInt8, fInt8, nil), t)
+       reportError("fInt", CheckEqual(fInt, fInt, nil), t)
+       reportError("fUInt8", CheckEqual(fUInt8, fUInt8, nil), t)
+       reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
+       reportError("fMap", CheckEqual(fMap, fMap, nil), t)
+       reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t)
+       reportError("fString", CheckEqual(fString, fString, nil), t)
+       reportError("fStruct", CheckEqual(fStruct, fStruct, nil), t)
+       reportError("fUint16", CheckEqual(fUint16, fUint16, nil), t)
+       reportError("fUint32", CheckEqual(fUint32, fUint32, nil), t)
+       reportError("fUint64", CheckEqual(fUint64, fUint64, nil), t)
+       reportError("fUint8", CheckEqual(fUint8, fUint8, nil), t)
+       reportError("fUint", CheckEqual(fUint, fUint, nil), t)
+       reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t)
+       reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t)
+}
+
+// This tests that ArbitraryValue is working by checking that all the arbitrary
+// values of type MyStruct have x = 42.
+type myStruct struct {
+       x int
+}
+
+func (m myStruct) Generate(r *rand.Rand, _ int) reflect.Value {
+       return reflect.NewValue(myStruct{x: 42})
+}
+
+func myStructProperty(in myStruct) bool { return in.x == 42 }
+
+func TestCheckProperty(t *testing.T) {
+       reportError("myStructProperty", Check(myStructProperty, nil), t)
+}
+
+func TestFailure(t *testing.T) {
+       f := func(x int) bool { return false }
+       err := Check(f, nil)
+       if err == nil {
+               t.Errorf("Check didn't return an error")
+       }
+       if _, ok := err.(*CheckError); !ok {
+               t.Errorf("Error was not a CheckError: %s", err)
+       }
+
+       err = CheckEqual(fUint, fUint32, nil)
+       if err == nil {
+               t.Errorf("#1 CheckEqual didn't return an error")
+       }
+       if _, ok := err.(SetupError); !ok {
+               t.Errorf("#1 Error was not a SetupError: %s", err)
+       }
+
+       err = CheckEqual(func(x, y int) {}, func(x int) {}, nil)
+       if err == nil {
+               t.Errorf("#2 CheckEqual didn't return an error")
+       }
+       if _, ok := err.(SetupError); !ok {
+               t.Errorf("#2 Error was not a SetupError: %s", err)
+       }
+
+       err = CheckEqual(func(x int) int { return 0 }, func(x int) int32 { return 0 }, nil)
+       if err == nil {
+               t.Errorf("#3 CheckEqual didn't return an error")
+       }
+       if _, ok := err.(SetupError); !ok {
+               t.Errorf("#3 Error was not a SetupError: %s", err)
+       }
+}
diff --git a/libgo/go/testing/script/script.go b/libgo/go/testing/script/script.go
new file mode 100644 (file)
index 0000000..11f5a74
--- /dev/null
@@ -0,0 +1,359 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package aids in the testing of code that uses channels.
+package script
+
+import (
+       "fmt"
+       "os"
+       "rand"
+       "reflect"
+       "strings"
+)
+
+// An Event is an element in a partially ordered set that either sends a value
+// to a channel or expects a value from a channel.
+type Event struct {
+       name         string
+       occurred     bool
+       predecessors []*Event
+       action       action
+}
+
+type action interface {
+       // getSend returns nil if the action is not a send action.
+       getSend() sendAction
+       // getRecv returns nil if the action is not a receive action.
+       getRecv() recvAction
+       // getChannel returns the channel that the action operates on.
+       getChannel() interface{}
+}
+
+type recvAction interface {
+       recvMatch(interface{}) bool
+}
+
+type sendAction interface {
+       send()
+}
+
+// isReady returns true if all the predecessors of an Event have occurred.
+func (e Event) isReady() bool {
+       for _, predecessor := range e.predecessors {
+               if !predecessor.occurred {
+                       return false
+               }
+       }
+
+       return true
+}
+
+// A Recv action reads a value from a channel and uses reflect.DeepMatch to
+// compare it with an expected value.
+type Recv struct {
+       Channel  interface{}
+       Expected interface{}
+}
+
+func (r Recv) getRecv() recvAction { return r }
+
+func (Recv) getSend() sendAction { return nil }
+
+func (r Recv) getChannel() interface{} { return r.Channel }
+
+func (r Recv) recvMatch(chanEvent interface{}) bool {
+       c, ok := chanEvent.(channelRecv)
+       if !ok || c.channel != r.Channel {
+               return false
+       }
+
+       return reflect.DeepEqual(c.value, r.Expected)
+}
+
+// A RecvMatch action reads a value from a channel and calls a function to
+// determine if the value matches.
+type RecvMatch struct {
+       Channel interface{}
+       Match   func(interface{}) bool
+}
+
+func (r RecvMatch) getRecv() recvAction { return r }
+
+func (RecvMatch) getSend() sendAction { return nil }
+
+func (r RecvMatch) getChannel() interface{} { return r.Channel }
+
+func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
+       c, ok := chanEvent.(channelRecv)
+       if !ok || c.channel != r.Channel {
+               return false
+       }
+
+       return r.Match(c.value)
+}
+
+// A Closed action matches if the given channel is closed. The closing is
+// treated as an event, not a state, thus Closed will only match once for a
+// given channel.
+type Closed struct {
+       Channel interface{}
+}
+
+func (r Closed) getRecv() recvAction { return r }
+
+func (Closed) getSend() sendAction { return nil }
+
+func (r Closed) getChannel() interface{} { return r.Channel }
+
+func (r Closed) recvMatch(chanEvent interface{}) bool {
+       c, ok := chanEvent.(channelClosed)
+       if !ok || c.channel != r.Channel {
+               return false
+       }
+
+       return true
+}
+
+// A Send action sends a value to a channel. The value must match the
+// type of the channel exactly unless the channel if of type chan interface{}.
+type Send struct {
+       Channel interface{}
+       Value   interface{}
+}
+
+func (Send) getRecv() recvAction { return nil }
+
+func (s Send) getSend() sendAction { return s }
+
+func (s Send) getChannel() interface{} { return s.Channel }
+
+type empty struct {
+       x interface{}
+}
+
+func newEmptyInterface(e empty) reflect.Value {
+       return reflect.NewValue(e).(*reflect.StructValue).Field(0)
+}
+
+func (s Send) send() {
+       // With reflect.ChanValue.Send, we must match the types exactly. So, if
+       // s.Channel is a chan interface{} we convert s.Value to an interface{}
+       // first.
+       c := reflect.NewValue(s.Channel).(*reflect.ChanValue)
+       var v reflect.Value
+       if iface, ok := c.Type().(*reflect.ChanType).Elem().(*reflect.InterfaceType); ok && iface.NumMethod() == 0 {
+               v = newEmptyInterface(empty{s.Value})
+       } else {
+               v = reflect.NewValue(s.Value)
+       }
+       c.Send(v)
+}
+
+// A Close action closes the given channel.
+type Close struct {
+       Channel interface{}
+}
+
+func (Close) getRecv() recvAction { return nil }
+
+func (s Close) getSend() sendAction { return s }
+
+func (s Close) getChannel() interface{} { return s.Channel }
+
+func (s Close) send() { reflect.NewValue(s.Channel).(*reflect.ChanValue).Close() }
+
+// A ReceivedUnexpected error results if no active Events match a value
+// received from a channel.
+type ReceivedUnexpected struct {
+       Value interface{}
+       ready []*Event
+}
+
+func (r ReceivedUnexpected) String() string {
+       names := make([]string, len(r.ready))
+       for i, v := range r.ready {
+               names[i] = v.name
+       }
+       return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))
+}
+
+// A SetupError results if there is a error with the configuration of a set of
+// Events.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+func NewEvent(name string, predecessors []*Event, action action) *Event {
+       e := &Event{name, false, predecessors, action}
+       return e
+}
+
+// Given a set of Events, Perform repeatedly iterates over the set and finds the
+// subset of ready Events (that is, all of their predecessors have
+// occurred). From that subset, it pseudo-randomly selects an Event to perform.
+// If the Event is a send event, the send occurs and Perform recalculates the ready
+// set. If the event is a receive event, Perform waits for a value from any of the
+// channels that are contained in any of the events. That value is then matched
+// against the ready events. The first event that matches is considered to
+// have occurred and Perform recalculates the ready set.
+//
+// Perform continues this until all Events have occurred.
+//
+// Note that uncollected goroutines may still be reading from any of the
+// channels read from after Perform returns.
+//
+// For example, consider the problem of testing a function that reads values on
+// one channel and echos them to two output channels. To test this we would
+// create three events: a send event and two receive events. Each of the
+// receive events must list the send event as a predecessor but there is no
+// ordering between the receive events.
+//
+//  send := NewEvent("send", nil, Send{c, 1})
+//  recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1})
+//  recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1})
+//  Perform(0, []*Event{send, recv1, recv2})
+//
+// At first, only the send event would be in the ready set and thus Perform will
+// send a value to the input channel. Now the two receive events are ready and
+// Perform will match each of them against the values read from the output channels.
+//
+// It would be invalid to list one of the receive events as a predecessor of
+// the other. At each receive step, all the receive channels are considered,
+// thus Perform may see a value from a channel that is not in the current ready
+// set and fail.
+func Perform(seed int64, events []*Event) (err os.Error) {
+       r := rand.New(rand.NewSource(seed))
+
+       channels, err := getChannels(events)
+       if err != nil {
+               return
+       }
+       multiplex := make(chan interface{})
+       for _, channel := range channels {
+               go recvValues(multiplex, channel)
+       }
+
+Outer:
+       for {
+               ready, err := readyEvents(events)
+               if err != nil {
+                       return err
+               }
+
+               if len(ready) == 0 {
+                       // All events occurred.
+                       break
+               }
+
+               event := ready[r.Intn(len(ready))]
+               if send := event.action.getSend(); send != nil {
+                       send.send()
+                       event.occurred = true
+                       continue
+               }
+
+               v := <-multiplex
+               for _, event := range ready {
+                       if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
+                               event.occurred = true
+                               continue Outer
+                       }
+               }
+
+               return ReceivedUnexpected{v, ready}
+       }
+
+       return nil
+}
+
+// getChannels returns all the channels listed in any receive events.
+func getChannels(events []*Event) ([]interface{}, os.Error) {
+       channels := make([]interface{}, len(events))
+
+       j := 0
+       for _, event := range events {
+               if recv := event.action.getRecv(); recv == nil {
+                       continue
+               }
+               c := event.action.getChannel()
+               if _, ok := reflect.NewValue(c).(*reflect.ChanValue); !ok {
+                       return nil, SetupError("one of the channel values is not a channel")
+               }
+
+               duplicate := false
+               for _, other := range channels[0:j] {
+                       if c == other {
+                               duplicate = true
+                               break
+                       }
+               }
+
+               if !duplicate {
+                       channels[j] = c
+                       j++
+               }
+       }
+
+       return channels[0:j], nil
+}
+
+// recvValues is a multiplexing helper function. It reads values from the given
+// channel repeatedly, wrapping them up as either a channelRecv or
+// channelClosed structure, and forwards them to the multiplex channel.
+func recvValues(multiplex chan<- interface{}, channel interface{}) {
+       c := reflect.NewValue(channel).(*reflect.ChanValue)
+
+       for {
+               v := c.Recv()
+               if c.Closed() {
+                       multiplex <- channelClosed{channel}
+                       return
+               }
+
+               multiplex <- channelRecv{channel, v.Interface()}
+       }
+}
+
+type channelClosed struct {
+       channel interface{}
+}
+
+type channelRecv struct {
+       channel interface{}
+       value   interface{}
+}
+
+// readyEvents returns the subset of events that are ready.
+func readyEvents(events []*Event) ([]*Event, os.Error) {
+       ready := make([]*Event, len(events))
+
+       j := 0
+       eventsWaiting := false
+       for _, event := range events {
+               if event.occurred {
+                       continue
+               }
+
+               eventsWaiting = true
+               if event.isReady() {
+                       ready[j] = event
+                       j++
+               }
+       }
+
+       if j == 0 && eventsWaiting {
+               names := make([]string, len(events))
+               for _, event := range events {
+                       if event.occurred {
+                               continue
+                       }
+                       names[j] = event.name
+               }
+
+               return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))
+       }
+
+       return ready[0:j], nil
+}
diff --git a/libgo/go/testing/script/script_test.go b/libgo/go/testing/script/script_test.go
new file mode 100644 (file)
index 0000000..e9ab142
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package script
+
+import (
+       "testing"
+)
+
+func TestNoop(t *testing.T) {
+       err := Perform(0, nil)
+       if err != nil {
+               t.Errorf("Got error: %s", err)
+       }
+}
+
+func TestSimple(t *testing.T) {
+       c := make(chan int)
+       defer close(c)
+
+       a := NewEvent("send", nil, Send{c, 1})
+       b := NewEvent("recv", []*Event{a}, Recv{c, 1})
+
+       err := Perform(0, []*Event{a, b})
+       if err != nil {
+               t.Errorf("Got error: %s", err)
+       }
+}
+
+func TestFail(t *testing.T) {
+       c := make(chan int)
+       defer close(c)
+
+       a := NewEvent("send", nil, Send{c, 2})
+       b := NewEvent("recv", []*Event{a}, Recv{c, 1})
+
+       err := Perform(0, []*Event{a, b})
+       if err == nil {
+               t.Errorf("Failed to get expected error")
+       } else if _, ok := err.(ReceivedUnexpected); !ok {
+               t.Errorf("Error returned was of the wrong type: %s", err)
+       }
+}
+
+func TestClose(t *testing.T) {
+       c := make(chan int)
+
+       a := NewEvent("close", nil, Close{c})
+       b := NewEvent("closed", []*Event{a}, Closed{c})
+
+       err := Perform(0, []*Event{a, b})
+       if err != nil {
+               t.Errorf("Got error: %s", err)
+       }
+}
+
+func matchOne(v interface{}) bool {
+       if i, ok := v.(int); ok && i == 1 {
+               return true
+       }
+       return false
+}
+
+func TestRecvMatch(t *testing.T) {
+       c := make(chan int)
+
+       a := NewEvent("send", nil, Send{c, 1})
+       b := NewEvent("recv", []*Event{a}, RecvMatch{c, matchOne})
+
+       err := Perform(0, []*Event{a, b})
+       if err != nil {
+               t.Errorf("Got error: %s", err)
+       }
+}
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
new file mode 100644 (file)
index 0000000..ae6d034
--- /dev/null
@@ -0,0 +1,174 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The testing package provides support for automated testing of Go packages.
+// It is intended to be used in concert with the ``gotest'' utility, which automates
+// execution of any function of the form
+//     func TestXxx(*testing.T)
+// where Xxx can be any alphanumeric string (but the first letter must not be in
+// [a-z]) and serves to identify the test routine.
+// These TestXxx routines should be declared within the package they are testing.
+//
+// Functions of the form
+//     func BenchmarkXxx(*testing.B)
+// are considered benchmarks, and are executed by gotest when the -benchmarks
+// flag is provided.
+//
+// A sample benchmark function looks like this:
+//     func BenchmarkHello(b *testing.B) {
+//         for i := 0; i < b.N; i++ {
+//             fmt.Sprintf("hello")
+//         }
+//     }
+// The benchmark package will vary b.N until the benchmark function lasts
+// long enough to be timed reliably.  The output
+//     testing.BenchmarkHello  500000        4076 ns/op
+// means that the loop ran 500000 times at a speed of 4076 ns per loop.
+//
+// If a benchmark needs some expensive setup before running, the timer
+// may be stopped:
+//     func BenchmarkBigLen(b *testing.B) {
+//         b.StopTimer()
+//         big := NewBig()
+//         b.StartTimer()
+//         for i := 0; i < b.N; i++ {
+//             big.Len()
+//         }
+//     }
+package testing
+
+import (
+       "flag"
+       "fmt"
+       "os"
+       "runtime"
+)
+
+// Report as tests are run; default is silent for success.
+var chatty = flag.Bool("v", false, "verbose: print additional output")
+var match = flag.String("match", "", "regular expression to select tests to run")
+
+
+// Insert final newline if needed and tabs after internal newlines.
+func tabify(s string) string {
+       n := len(s)
+       if n > 0 && s[n-1] != '\n' {
+               s += "\n"
+               n++
+       }
+       for i := 0; i < n-1; i++ { // -1 to avoid final newline
+               if s[i] == '\n' {
+                       return s[0:i+1] + "\t" + tabify(s[i+1:n])
+               }
+       }
+       return s
+}
+
+// T is a type passed to Test functions to manage test state and support formatted test logs.
+// Logs are accumulated during execution and dumped to standard error when done.
+type T struct {
+       errors string
+       failed bool
+       ch     chan *T
+}
+
+// Fail marks the Test function as having failed but continues execution.
+func (t *T) Fail() { t.failed = true }
+
+// Failed returns whether the Test function has failed.
+func (t *T) Failed() bool { return t.failed }
+
+// FailNow marks the Test function as having failed and stops its execution.
+// Execution will continue at the next Test.
+func (t *T) FailNow() {
+       t.Fail()
+       t.ch <- t
+       runtime.Goexit()
+}
+
+// Log formats its arguments using default formatting, analogous to Print(),
+// and records the text in the error log.
+func (t *T) Log(args ...interface{}) { t.errors += "\t" + tabify(fmt.Sprintln(args...)) }
+
+// Log formats its arguments according to the format, analogous to Printf(),
+// and records the text in the error log.
+func (t *T) Logf(format string, args ...interface{}) {
+       t.errors += "\t" + tabify(fmt.Sprintf(format, args...))
+}
+
+// Error is equivalent to Log() followed by Fail().
+func (t *T) Error(args ...interface{}) {
+       t.Log(args...)
+       t.Fail()
+}
+
+// Errorf is equivalent to Logf() followed by Fail().
+func (t *T) Errorf(format string, args ...interface{}) {
+       t.Logf(format, args...)
+       t.Fail()
+}
+
+// Fatal is equivalent to Log() followed by FailNow().
+func (t *T) Fatal(args ...interface{}) {
+       t.Log(args...)
+       t.FailNow()
+}
+
+// Fatalf is equivalent to Logf() followed by FailNow().
+func (t *T) Fatalf(format string, args ...interface{}) {
+       t.Logf(format, args...)
+       t.FailNow()
+}
+
+// An internal type but exported because it is cross-package; part of the implementation
+// of gotest.
+type InternalTest struct {
+       Name string
+       F    func(*T)
+}
+
+func tRunner(t *T, test *InternalTest) {
+       test.F(t)
+       t.ch <- t
+}
+
+// An internal function but exported because it is cross-package; part of the implementation
+// of gotest.
+func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest) {
+       flag.Parse()
+       ok := true
+       if len(tests) == 0 {
+               println("testing: warning: no tests to run")
+       }
+       for i := 0; i < len(tests); i++ {
+               matched, err := matchString(*match, tests[i].Name)
+               if err != nil {
+                       println("invalid regexp for -match:", err)
+                       os.Exit(1)
+               }
+               if !matched {
+                       continue
+               }
+               if *chatty {
+                       println("=== RUN ", tests[i].Name)
+               }
+               t := new(T)
+               t.ch = make(chan *T)
+               go tRunner(t, &tests[i])
+               <-t.ch
+               if t.failed {
+                       println("--- FAIL:", tests[i].Name)
+                       print(t.errors)
+                       ok = false
+               } else if *chatty {
+                       println("--- PASS:", tests[i].Name)
+                       print(t.errors)
+               }
+       }
+       if !ok {
+               println("FAIL")
+               os.Exit(1)
+       }
+       println("PASS")
+}
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
new file mode 100644 (file)
index 0000000..355721e
--- /dev/null
@@ -0,0 +1,614 @@
+package time
+
+import (
+       "bytes"
+       "os"
+       "strconv"
+)
+
+const (
+       numeric = iota
+       alphabetic
+       separator
+       plus
+       minus
+)
+
+// These are predefined layouts for use in Time.Format.
+// The standard time used in the layouts is:
+//     Mon Jan 2 15:04:05 MST 2006  (MST is GMT-0700)
+// which is Unix time 1136243045.
+// (Think of it as 01/02 03:04:05PM '06 -0700.)
+// An underscore _ represents a space that
+// may be replaced by a digit if the following number
+// (a day) has two digits; for compatibility with
+// fixed-width Unix time formats.
+//
+// Numeric time zone offsets format as follows:
+//     -0700  ±hhmm
+//     -07:00 ±hh:mm
+// Replacing the sign in the format with a Z triggers
+// the ISO 8601 behavior of printing Z instead of an
+// offset for the UTC zone.  Thus:
+//     Z0700  Z or ±hhmm
+//     Z07:00 Z or ±hh:mm
+const (
+       ANSIC    = "Mon Jan _2 15:04:05 2006"
+       UnixDate = "Mon Jan _2 15:04:05 MST 2006"
+       RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
+       RFC822   = "02 Jan 06 1504 MST"
+       // RFC822 with Zulu time.
+       RFC822Z = "02 Jan 06 1504 -0700"
+       RFC850  = "Monday, 02-Jan-06 15:04:05 MST"
+       RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
+       Kitchen = "3:04PM"
+       RFC3339 = "2006-01-02T15:04:05Z07:00"
+)
+
+const (
+       stdLongMonth      = "January"
+       stdMonth          = "Jan"
+       stdNumMonth       = "1"
+       stdZeroMonth      = "01"
+       stdLongWeekDay    = "Monday"
+       stdWeekDay        = "Mon"
+       stdDay            = "2"
+       stdUnderDay       = "_2"
+       stdZeroDay        = "02"
+       stdHour           = "15"
+       stdHour12         = "3"
+       stdZeroHour12     = "03"
+       stdMinute         = "4"
+       stdZeroMinute     = "04"
+       stdSecond         = "5"
+       stdZeroSecond     = "05"
+       stdLongYear       = "2006"
+       stdYear           = "06"
+       stdPM             = "PM"
+       stdpm             = "pm"
+       stdTZ             = "MST"
+       stdISO8601TZ      = "Z0700"  // prints Z for UTC
+       stdISO8601ColonTZ = "Z07:00" // prints Z for UTC
+       stdNumTZ          = "-0700"  // always numeric
+       stdNumShortTZ     = "-07"    // always numeric
+       stdNumColonTZ     = "-07:00" // always numeric
+)
+
+// nextStdChunk finds the first occurrence of a std string in
+// layout and returns the text before, the std string, and the text after.
+func nextStdChunk(layout string) (prefix, std, suffix string) {
+       for i := 0; i < len(layout); i++ {
+               switch layout[i] {
+               case 'J': // January, Jan
+                       if len(layout) >= i+7 && layout[i:i+7] == stdLongMonth {
+                               return layout[0:i], stdLongMonth, layout[i+7:]
+                       }
+                       if len(layout) >= i+3 && layout[i:i+3] == stdMonth {
+                               return layout[0:i], stdMonth, layout[i+3:]
+                       }
+
+               case 'M': // Monday, Mon, MST
+                       if len(layout) >= i+6 && layout[i:i+6] == stdLongWeekDay {
+                               return layout[0:i], stdLongWeekDay, layout[i+6:]
+                       }
+                       if len(layout) >= i+3 {
+                               if layout[i:i+3] == stdWeekDay {
+                                       return layout[0:i], stdWeekDay, layout[i+3:]
+                               }
+                               if layout[i:i+3] == stdTZ {
+                                       return layout[0:i], stdTZ, layout[i+3:]
+                               }
+                       }
+
+               case '0': // 01, 02, 03, 04, 05, 06
+                       if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' {
+                               return layout[0:i], layout[i : i+2], layout[i+2:]
+                       }
+
+               case '1': // 15, 1
+                       if len(layout) >= i+2 && layout[i+1] == '5' {
+                               return layout[0:i], stdHour, layout[i+2:]
+                       }
+                       return layout[0:i], stdNumMonth, layout[i+1:]
+
+               case '2': // 2006, 2
+                       if len(layout) >= i+4 && layout[i:i+4] == stdLongYear {
+                               return layout[0:i], stdLongYear, layout[i+4:]
+                       }
+                       return layout[0:i], stdDay, layout[i+1:]
+
+               case '_': // _2
+                       if len(layout) >= i+2 && layout[i+1] == '2' {
+                               return layout[0:i], stdUnderDay, layout[i+2:]
+                       }
+
+               case '3', '4', '5': // 3, 4, 5
+                       return layout[0:i], layout[i : i+1], layout[i+1:]
+
+               case 'P': // PM
+                       if len(layout) >= i+2 && layout[i+1] == 'M' {
+                               return layout[0:i], layout[i : i+2], layout[i+2:]
+                       }
+
+               case 'p': // pm
+                       if len(layout) >= i+2 && layout[i+1] == 'm' {
+                               return layout[0:i], layout[i : i+2], layout[i+2:]
+                       }
+
+               case '-': // -0700, -07:00, -07
+                       if len(layout) >= i+5 && layout[i:i+5] == stdNumTZ {
+                               return layout[0:i], layout[i : i+5], layout[i+5:]
+                       }
+                       if len(layout) >= i+6 && layout[i:i+6] == stdNumColonTZ {
+                               return layout[0:i], layout[i : i+6], layout[i+6:]
+                       }
+                       if len(layout) >= i+3 && layout[i:i+3] == stdNumShortTZ {
+                               return layout[0:i], layout[i : i+3], layout[i+3:]
+                       }
+               case 'Z': // Z0700, Z07:00
+                       if len(layout) >= i+5 && layout[i:i+5] == stdISO8601TZ {
+                               return layout[0:i], layout[i : i+5], layout[i+5:]
+                       }
+                       if len(layout) >= i+6 && layout[i:i+6] == stdISO8601ColonTZ {
+                               return layout[0:i], layout[i : i+6], layout[i+6:]
+                       }
+               }
+       }
+       return layout, "", ""
+}
+
+var longDayNames = []string{
+       "Sunday",
+       "Monday",
+       "Tuesday",
+       "Wednesday",
+       "Thursday",
+       "Friday",
+       "Saturday",
+}
+
+var shortDayNames = []string{
+       "Sun",
+       "Mon",
+       "Tue",
+       "Wed",
+       "Thu",
+       "Fri",
+       "Sat",
+}
+
+var shortMonthNames = []string{
+       "---",
+       "Jan",
+       "Feb",
+       "Mar",
+       "Apr",
+       "May",
+       "Jun",
+       "Jul",
+       "Aug",
+       "Sep",
+       "Oct",
+       "Nov",
+       "Dec",
+}
+
+var longMonthNames = []string{
+       "---",
+       "January",
+       "February",
+       "March",
+       "April",
+       "May",
+       "June",
+       "July",
+       "August",
+       "September",
+       "October",
+       "November",
+       "December",
+}
+
+func lookup(tab []string, val string) (int, string, os.Error) {
+       for i, v := range tab {
+               if len(val) >= len(v) && val[0:len(v)] == v {
+                       return i, val[len(v):], nil
+               }
+       }
+       return -1, val, errBad
+}
+
+func pad(i int, padding string) string {
+       s := strconv.Itoa(i)
+       if i < 10 {
+               s = padding + s
+       }
+       return s
+}
+
+func zeroPad(i int) string { return pad(i, "0") }
+
+// Format returns a textual representation of the time value formatted
+// according to layout.  The layout defines the format by showing the
+// representation of a standard time, which is then used to describe
+// the time to be formatted.  Predefined layouts ANSIC, UnixDate,
+// RFC3339 and others describe standard representations.
+func (t *Time) Format(layout string) string {
+       b := new(bytes.Buffer)
+       // Each iteration generates one std value.
+       for {
+               prefix, std, suffix := nextStdChunk(layout)
+               b.WriteString(prefix)
+               if std == "" {
+                       break
+               }
+               var p string
+               switch std {
+               case stdYear:
+                       p = strconv.Itoa64(t.Year % 100)
+               case stdLongYear:
+                       p = strconv.Itoa64(t.Year)
+               case stdMonth:
+                       p = shortMonthNames[t.Month]
+               case stdLongMonth:
+                       p = longMonthNames[t.Month]
+               case stdNumMonth:
+                       p = strconv.Itoa(t.Month)
+               case stdZeroMonth:
+                       p = zeroPad(t.Month)
+               case stdWeekDay:
+                       p = shortDayNames[t.Weekday]
+               case stdLongWeekDay:
+                       p = longDayNames[t.Weekday]
+               case stdDay:
+                       p = strconv.Itoa(t.Day)
+               case stdUnderDay:
+                       p = pad(t.Day, " ")
+               case stdZeroDay:
+                       p = zeroPad(t.Day)
+               case stdHour:
+                       p = zeroPad(t.Hour)
+               case stdHour12:
+                       p = strconv.Itoa(t.Hour % 12)
+               case stdZeroHour12:
+                       p = zeroPad(t.Hour % 12)
+               case stdMinute:
+                       p = strconv.Itoa(t.Minute)
+               case stdZeroMinute:
+                       p = zeroPad(t.Minute)
+               case stdSecond:
+                       p = strconv.Itoa(t.Second)
+               case stdZeroSecond:
+                       p = zeroPad(t.Second)
+               case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ:
+                       // Ugly special case.  We cheat and take the "Z" variants
+                       // to mean "the time zone as formatted for ISO 8601".
+                       if t.ZoneOffset == 0 && std[0] == 'Z' {
+                               p = "Z"
+                               break
+                       }
+                       zone := t.ZoneOffset / 60 // convert to minutes
+                       if zone < 0 {
+                               p = "-"
+                               zone = -zone
+                       } else {
+                               p = "+"
+                       }
+                       p += zeroPad(zone / 60)
+                       if std == stdISO8601ColonTZ || std == stdNumColonTZ {
+                               p += ":"
+                       }
+                       p += zeroPad(zone % 60)
+               case stdPM:
+                       if t.Hour >= 12 {
+                               p = "PM"
+                       } else {
+                               p = "AM"
+                       }
+               case stdpm:
+                       if t.Hour >= 12 {
+                               p = "pm"
+                       } else {
+                               p = "am"
+                       }
+               case stdTZ:
+                       if t.Zone != "" {
+                               p = t.Zone
+                       } else {
+                               // No time zone known for this time, but we must print one.
+                               // Use the -0700 format.
+                               zone := t.ZoneOffset / 60 // convert to minutes
+                               if zone < 0 {
+                                       p = "-"
+                                       zone = -zone
+                               } else {
+                                       p = "+"
+                               }
+                               p += zeroPad(zone / 60)
+                               p += zeroPad(zone % 60)
+                       }
+               }
+               b.WriteString(p)
+               layout = suffix
+       }
+       return b.String()
+}
+
+// String returns a Unix-style representation of the time value.
+func (t *Time) String() string {
+       if t == nil {
+               return "<nil>"
+       }
+       return t.Format(UnixDate)
+}
+
+var errBad = os.ErrorString("bad") // just a marker; not returned to user
+
+// ParseError describes a problem parsing a time string.
+type ParseError struct {
+       Layout     string
+       Value      string
+       LayoutElem string
+       ValueElem  string
+       Message    string
+}
+
+// String is the string representation of a ParseError.
+func (e *ParseError) String() string {
+       if e.Message == "" {
+               return "parsing time " +
+                       strconv.Quote(e.Value) + " as " +
+                       strconv.Quote(e.Layout) + ": cannot parse " +
+                       strconv.Quote(e.ValueElem) + " as " +
+                       strconv.Quote(e.LayoutElem)
+       }
+       return "parsing time " +
+               strconv.Quote(e.Value) + e.Message
+}
+
+// getnum parses s[0:1] or s[0:2] (fixed forces the latter)
+// as a decimal integer and returns the integer and the
+// remainder of the string.
+func getnum(s string, fixed bool) (int, string, os.Error) {
+       if len(s) == 0 || s[0] < '0' || s[0] > '9' {
+               return 0, s, errBad
+       }
+       if len(s) == 1 || s[1] < '0' || s[1] > '9' {
+               if fixed {
+                       return 0, s, errBad
+               }
+               return int(s[0] - '0'), s[1:], nil
+       }
+       return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil
+}
+
+func cutspace(s string) string {
+       for len(s) > 0 && s[0] == ' ' {
+               s = s[1:]
+       }
+       return s
+}
+
+// skip removes the given prefix from value,
+// treating runs of space characters as equivalent.
+func skip(value, prefix string) (string, os.Error) {
+       for len(prefix) > 0 {
+               if prefix[0] == ' ' {
+                       if len(value) > 0 && value[0] != ' ' {
+                               return "", errBad
+                       }
+                       prefix = cutspace(prefix)
+                       value = cutspace(value)
+                       continue
+               }
+               if len(value) == 0 || value[0] != prefix[0] {
+                       return "", errBad
+               }
+               prefix = prefix[1:]
+               value = value[1:]
+       }
+       return value, nil
+}
+
+// Parse parses a formatted string and returns the time value it represents.
+// The layout defines the format by showing the representation of a standard
+// time, which is then used to describe the string to be parsed.  Predefined
+// layouts ANSIC, UnixDate, RFC3339 and others describe standard
+// representations.
+//
+// Only those elements present in the value will be set in the returned time
+// structure.  Also, if the input string represents an inconsistent time
+// (such as having the wrong day of the week), the returned value will also
+// be inconsistent.  In any case, the elements of the returned time will be
+// sane: hours in 0..23, minutes in 0..59, day of month in 0..31, etc.
+// Years must be in the range 0000..9999.
+func Parse(alayout, avalue string) (*Time, os.Error) {
+       var t Time
+       rangeErrString := "" // set if a value is out of range
+       pmSet := false       // do we need to add 12 to the hour?
+       layout, value := alayout, avalue
+       // Each iteration processes one std value.
+       for {
+               var err os.Error
+               prefix, std, suffix := nextStdChunk(layout)
+               value, err = skip(value, prefix)
+               if err != nil {
+                       return nil, &ParseError{alayout, avalue, prefix, value, ""}
+               }
+               if len(std) == 0 {
+                       if len(value) != 0 {
+                               return nil, &ParseError{alayout, avalue, "", value, ": extra text: " + value}
+                       }
+                       break
+               }
+               layout = suffix
+               var p string
+               switch std {
+               case stdYear:
+                       if len(value) < 2 {
+                               err = errBad
+                               break
+                       }
+                       p, value = value[0:2], value[2:]
+                       t.Year, err = strconv.Atoi64(p)
+                       if t.Year >= 69 { // Unix time starts Dec 31 1969 in some time zones
+                               t.Year += 1900
+                       } else {
+                               t.Year += 2000
+                       }
+               case stdLongYear:
+                       if len(value) < 4 || value[0] < '0' || value[0] > '9' {
+                               err = errBad
+                               break
+                       }
+                       p, value = value[0:4], value[4:]
+                       t.Year, err = strconv.Atoi64(p)
+               case stdMonth:
+                       t.Month, value, err = lookup(shortMonthNames, value)
+               case stdLongMonth:
+                       t.Month, value, err = lookup(longMonthNames, value)
+               case stdNumMonth, stdZeroMonth:
+                       t.Month, value, err = getnum(value, std == stdZeroMonth)
+                       if t.Month <= 0 || 12 < t.Month {
+                               rangeErrString = "month"
+                       }
+               case stdWeekDay:
+                       t.Weekday, value, err = lookup(shortDayNames, value)
+               case stdLongWeekDay:
+                       t.Weekday, value, err = lookup(longDayNames, value)
+               case stdDay, stdUnderDay, stdZeroDay:
+                       if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
+                               value = value[1:]
+                       }
+                       t.Day, value, err = getnum(value, std == stdZeroDay)
+                       if t.Day < 0 || 31 < t.Day {
+                               // TODO: be more thorough in date check?
+                               rangeErrString = "day"
+                       }
+               case stdHour:
+                       t.Hour, value, err = getnum(value, false)
+                       if t.Hour < 0 || 24 <= t.Hour {
+                               rangeErrString = "hour"
+                       }
+               case stdHour12, stdZeroHour12:
+                       t.Hour, value, err = getnum(value, std == stdZeroHour12)
+                       if t.Hour < 0 || 12 < t.Hour {
+                               rangeErrString = "hour"
+                       }
+               case stdMinute, stdZeroMinute:
+                       t.Minute, value, err = getnum(value, std == stdZeroMinute)
+                       if t.Minute < 0 || 60 <= t.Minute {
+                               rangeErrString = "minute"
+                       }
+               case stdSecond, stdZeroSecond:
+                       t.Second, value, err = getnum(value, std == stdZeroSecond)
+                       if t.Second < 0 || 60 <= t.Second {
+                               rangeErrString = "second"
+                       }
+               case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ:
+                       if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' {
+                               value = value[1:]
+                               t.Zone = "UTC"
+                               break
+                       }
+                       var sign, hh, mm string
+                       if std == stdISO8601ColonTZ || std == stdNumColonTZ {
+                               if len(value) < 6 {
+                                       err = errBad
+                                       break
+                               }
+                               if value[3] != ':' {
+                                       err = errBad
+                                       break
+                               }
+                               sign, hh, mm, value = value[0:1], value[1:3], value[4:6], value[6:]
+                       } else if std == stdNumShortTZ {
+                               if len(value) < 3 {
+                                       err = errBad
+                                       break
+                               }
+                               sign, hh, mm, value = value[0:1], value[1:3], "00", value[3:]
+                       } else {
+                               if len(value) < 5 {
+                                       err = errBad
+                                       break
+                               }
+                               sign, hh, mm, value = value[0:1], value[1:3], value[3:5], value[5:]
+                       }
+                       var hr, min int
+                       hr, err = strconv.Atoi(hh)
+                       if err == nil {
+                               min, err = strconv.Atoi(mm)
+                       }
+                       t.ZoneOffset = (hr*60 + min) * 60 // offset is in seconds
+                       switch sign[0] {
+                       case '+':
+                       case '-':
+                               t.ZoneOffset = -t.ZoneOffset
+                       default:
+                               err = errBad
+                       }
+               case stdPM:
+                       if len(value) < 2 {
+                               err = errBad
+                               break
+                       }
+                       p, value = value[0:2], value[2:]
+                       if p == "PM" {
+                               pmSet = true
+                       } else if p != "AM" {
+                               err = errBad
+                       }
+               case stdpm:
+                       if len(value) < 2 {
+                               err = errBad
+                               break
+                       }
+                       p, value = value[0:2], value[2:]
+                       if p == "pm" {
+                               pmSet = true
+                       } else if p != "am" {
+                               err = errBad
+                       }
+               case stdTZ:
+                       // Does it look like a time zone?
+                       if len(value) >= 3 && value[0:3] == "UTC" {
+                               t.Zone, value = value[0:3], value[3:]
+                               break
+                       }
+
+                       if len(value) >= 3 && value[2] == 'T' {
+                               p, value = value[0:3], value[3:]
+                       } else if len(value) >= 4 && value[3] == 'T' {
+                               p, value = value[0:4], value[4:]
+                       } else {
+                               err = errBad
+                               break
+                       }
+                       for i := 0; i < len(p); i++ {
+                               if p[i] < 'A' || 'Z' < p[i] {
+                                       err = errBad
+                               }
+                       }
+                       if err != nil {
+                               break
+                       }
+                       // It's a valid format.
+                       t.Zone = p
+                       // Can we find its offset?
+                       if offset, found := lookupByName(p); found {
+                               t.ZoneOffset = offset
+                       }
+               }
+               if rangeErrString != "" {
+                       return nil, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"}
+               }
+               if err != nil {
+                       return nil, &ParseError{alayout, avalue, std, value, ""}
+               }
+       }
+       if pmSet && t.Hour < 12 {
+               t.Hour += 12
+       }
+       return &t, nil
+}
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
new file mode 100644 (file)
index 0000000..702ced1
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+       "os"
+       "syscall"
+)
+
+// Sleep pauses the current goroutine for at least ns nanoseconds.
+// Higher resolution sleeping may be provided by syscall.Nanosleep 
+// on some operating systems.
+func Sleep(ns int64) os.Error {
+       _, err := sleep(Nanoseconds(), ns)
+       return err
+}
+
+// After waits at least ns nanoseconds before sending the current time
+// on the returned channel.
+func After(ns int64) <-chan int64 {
+       t := Nanoseconds()
+       ch := make(chan int64, 1)
+       go func() {
+               t, _ = sleep(t, ns)
+               ch <- t
+       }()
+       return ch
+}
+
+// sleep takes the current time and a duration,
+// pauses for at least ns nanoseconds, and
+// returns the current time and an error.
+func sleep(t, ns int64) (int64, os.Error) {
+       // TODO(cw): use monotonic-time once it's available
+       end := t + ns
+       for t < end {
+               errno := syscall.Sleep(end - t)
+               if errno != 0 && errno != syscall.EINTR {
+                       return 0, os.NewSyscallError("sleep", errno)
+               }
+               t = Nanoseconds()
+       }
+       return t, nil
+}
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
new file mode 100644 (file)
index 0000000..4934a38
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+       "os"
+       "syscall"
+       "testing"
+       . "time"
+)
+
+func TestSleep(t *testing.T) {
+       const delay = int64(100e6)
+       go func() {
+               Sleep(delay / 2)
+               syscall.Kill(os.Getpid(), syscall.SIGCHLD)
+       }()
+       start := Nanoseconds()
+       Sleep(delay)
+       duration := Nanoseconds() - start
+       if duration < delay {
+               t.Fatalf("Sleep(%d) slept for only %d ns", delay, duration)
+       }
+}
+
+func TestAfter(t *testing.T) {
+       const delay = int64(100e6)
+       start := Nanoseconds()
+       end := <-After(delay)
+       if duration := Nanoseconds() - start; duration < delay {
+               t.Fatalf("After(%d) slept for only %d ns", delay, duration)
+       }
+       if min := start + delay; end < min {
+               t.Fatalf("After(%d) expect >= %d, got %d", delay, min, end)
+       }
+}
diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go
new file mode 100644 (file)
index 0000000..9fb3083
--- /dev/null
@@ -0,0 +1,174 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+       "sync"
+)
+
+// A Ticker holds a synchronous channel that delivers `ticks' of a clock
+// at intervals.
+type Ticker struct {
+       C        <-chan int64 // The channel on which the ticks are delivered.
+       c        chan<- int64 // The same channel, but the end we use.
+       ns       int64
+       shutdown bool
+       nextTick int64
+       next     *Ticker
+}
+
+// Stop turns off a ticker.  After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() { t.shutdown = true }
+
+// Tick is a convenience wrapper for NewTicker providing access to the ticking
+// channel only.  Useful for clients that have no need to shut down the ticker.
+func Tick(ns int64) <-chan int64 {
+       if ns <= 0 {
+               return nil
+       }
+       return NewTicker(ns).C
+}
+
+type alarmer struct {
+       wakeUp   chan bool // wakeup signals sent/received here
+       wakeMeAt chan int64
+       wakeTime int64
+}
+
+// Set alarm to go off at time ns, if not already set earlier.
+func (a *alarmer) set(ns int64) {
+       switch {
+       case a.wakeTime > ns:
+               // Next tick we expect is too late; shut down the late runner
+               // and (after fallthrough) start a new wakeLoop.
+               a.wakeMeAt <- -1
+               fallthrough
+       case a.wakeMeAt == nil:
+               // There's no wakeLoop, start one.
+               a.wakeMeAt = make(chan int64, 10)
+               go wakeLoop(a.wakeMeAt, a.wakeUp)
+               fallthrough
+       case a.wakeTime == 0:
+               // Nobody else is waiting; it's just us.
+               a.wakeTime = ns
+               a.wakeMeAt <- ns
+       default:
+               // There's already someone scheduled.
+       }
+}
+
+// Channel to notify tickerLoop of new Tickers being created.
+var newTicker chan *Ticker
+
+func startTickerLoop() {
+       newTicker = make(chan *Ticker)
+       go tickerLoop()
+}
+
+// wakeLoop delivers ticks at scheduled times, sleeping until the right moment.
+// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new
+// wakeLoop but they will share the wakeUp channel and signal that this one
+// is done by giving it a negative time request.
+func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
+       for {
+               wakeAt := <-wakeMeAt
+               if wakeAt < 0 { // tickerLoop has started another wakeLoop
+                       return
+               }
+               now := Nanoseconds()
+               if wakeAt > now {
+                       Sleep(wakeAt - now)
+                       now = Nanoseconds()
+               }
+               wakeUp <- true
+       }
+}
+
+// A single tickerLoop serves all ticks to Tickers.  It waits for two events:
+// either the creation of a new Ticker or a tick from the alarm,
+// signalling a time to wake up one or more Tickers.
+func tickerLoop() {
+       // Represents the next alarm to be delivered.
+       var alarm alarmer
+       // All wakeLoops deliver wakeups to this channel.
+       alarm.wakeUp = make(chan bool, 10)
+       var now, prevTime, wakeTime int64
+       var tickers *Ticker
+       for {
+               select {
+               case t := <-newTicker:
+                       // Add Ticker to list
+                       t.next = tickers
+                       tickers = t
+                       // Arrange for a new alarm if this one precedes the existing one.
+                       alarm.set(t.nextTick)
+               case <-alarm.wakeUp:
+                       now = Nanoseconds()
+                       // Ignore an old time due to a dying wakeLoop
+                       if now < prevTime {
+                               continue
+                       }
+                       wakeTime = now + 1e15 // very long in the future
+                       var prev *Ticker = nil
+                       // Scan list of tickers, delivering updates to those
+                       // that need it and determining the next wake time.
+                       // TODO(r): list should be sorted in time order.
+                       for t := tickers; t != nil; t = t.next {
+                               if t.shutdown {
+                                       // Ticker is done; remove it from list.
+                                       if prev == nil {
+                                               tickers = t.next
+                                       } else {
+                                               prev.next = t.next
+                                       }
+                                       continue
+                               }
+                               if t.nextTick <= now {
+                                       if len(t.c) == 0 {
+                                               // Only send if there's room.  We must not block.
+                                               // The channel is allocated with a one-element
+                                               // buffer, which is sufficient: if he hasn't picked
+                                               // up the last tick, no point in sending more.
+                                               t.c <- now
+                                       }
+                                       t.nextTick += t.ns
+                                       if t.nextTick <= now {
+                                               // Still behind; advance in one big step.
+                                               t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns
+                                       }
+                               }
+                               if t.nextTick < wakeTime {
+                                       wakeTime = t.nextTick
+                               }
+                               prev = t
+                       }
+                       if tickers != nil {
+                               // Please send wakeup at earliest required time.
+                               // If there are no tickers, don't bother.
+                               alarm.wakeMeAt <- wakeTime
+                       } else {
+                               alarm.wakeTime = 0
+                       }
+               }
+               prevTime = now
+       }
+}
+
+var onceStartTickerLoop sync.Once
+
+// NewTicker returns a new Ticker containing a channel that will
+// send the time, in nanoseconds, every ns nanoseconds.  It adjusts the
+// intervals to make up for pauses in delivery of the ticks.
+func NewTicker(ns int64) *Ticker {
+       if ns <= 0 {
+               return nil
+       }
+       c := make(chan int64, 1) //  See comment on send in tickerLoop
+       t := &Ticker{c, c, ns, false, Nanoseconds() + ns, nil}
+       onceStartTickerLoop.Do(startTickerLoop)
+       // must be run in background so global Tickers can be created
+       go func() { newTicker <- t }()
+       return t
+}
diff --git a/libgo/go/time/tick_test.go b/libgo/go/time/tick_test.go
new file mode 100644 (file)
index 0000000..d089a9b
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+       "testing"
+       . "time"
+)
+
+func TestTicker(t *testing.T) {
+       const (
+               Delta = 100 * 1e6
+               Count = 10
+       )
+       ticker := NewTicker(Delta)
+       t0 := Nanoseconds()
+       for i := 0; i < Count; i++ {
+               <-ticker.C
+       }
+       ticker.Stop()
+       t1 := Nanoseconds()
+       ns := t1 - t0
+       target := int64(Delta * Count)
+       slop := target * 2 / 10
+       if ns < target-slop || ns > target+slop {
+               t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
+       }
+       // Now test that the ticker stopped
+       Sleep(2 * Delta)
+       _, received := <-ticker.C
+       if received {
+               t.Fatalf("Ticker did not shut down")
+       }
+}
+
+// Test that a bug tearing down a ticker has been fixed.  This routine should not deadlock.
+func TestTeardown(t *testing.T) {
+       for i := 0; i < 3; i++ {
+               ticker := NewTicker(1e8)
+               <-ticker.C
+               ticker.Stop()
+       }
+}
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
new file mode 100644 (file)
index 0000000..4abd112
--- /dev/null
@@ -0,0 +1,229 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The time package provides functionality for measuring and
+// displaying time.
+package time
+
+import (
+       "os"
+)
+
+// Seconds reports the number of seconds since the Unix epoch,
+// January 1, 1970 00:00:00 UTC.
+func Seconds() int64 {
+       sec, _, err := os.Time()
+       if err != nil {
+               panic(err)
+       }
+       return sec
+}
+
+// Nanoseconds reports the number of nanoseconds since the Unix epoch,
+// January 1, 1970 00:00:00 UTC.
+func Nanoseconds() int64 {
+       sec, nsec, err := os.Time()
+       if err != nil {
+               panic(err)
+       }
+       return sec*1e9 + nsec
+}
+
+// Days of the week.
+const (
+       Sunday = iota
+       Monday
+       Tuesday
+       Wednesday
+       Thursday
+       Friday
+       Saturday
+)
+
+// Time is the struct representing a parsed time value.
+type Time struct {
+       Year                 int64  // 2006 is 2006
+       Month, Day           int    // Jan-2 is 1, 2
+       Hour, Minute, Second int    // 15:04:05 is 15, 4, 5.
+       Weekday              int    // Sunday, Monday, ...
+       ZoneOffset           int    // seconds east of UTC, e.g. -7*60 for -0700
+       Zone                 string // e.g., "MST"
+}
+
+var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+var leapyear = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+
+func months(year int64) []int {
+       if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
+               return leapyear
+       }
+       return nonleapyear
+}
+
+const (
+       secondsPerDay   = 24 * 60 * 60
+       daysPer400Years = 365*400 + 97
+       daysPer100Years = 365*100 + 24
+       daysPer4Years   = 365*4 + 1
+       days1970To2001  = 31*365 + 8
+)
+
+// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
+// into a parsed Time value in the UTC time zone.
+func SecondsToUTC(sec int64) *Time {
+       t := new(Time)
+
+       // Split into time and day.
+       day := sec / secondsPerDay
+       sec -= day * secondsPerDay
+       if sec < 0 {
+               day--
+               sec += secondsPerDay
+       }
+
+       // Time
+       t.Hour = int(sec / 3600)
+       t.Minute = int((sec / 60) % 60)
+       t.Second = int(sec % 60)
+
+       // Day 0 = January 1, 1970 was a Thursday
+       t.Weekday = int((day + Thursday) % 7)
+       if t.Weekday < 0 {
+               t.Weekday += 7
+       }
+
+       // Change day from 0 = 1970 to 0 = 2001,
+       // to make leap year calculations easier
+       // (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
+       day -= days1970To2001
+
+       year := int64(2001)
+       if day < 0 {
+               // Go back enough 400 year cycles to make day positive.
+               n := -day/daysPer400Years + 1
+               year -= 400 * n
+               day += daysPer400Years * n
+       }
+
+       // Cut off 400 year cycles.
+       n := day / daysPer400Years
+       year += 400 * n
+       day -= daysPer400Years * n
+
+       // Cut off 100-year cycles
+       n = day / daysPer100Years
+       if n > 3 { // happens on last day of 400th year
+               n = 3
+       }
+       year += 100 * n
+       day -= daysPer100Years * n
+
+       // Cut off 4-year cycles
+       n = day / daysPer4Years
+       if n > 24 { // happens on last day of 100th year
+               n = 24
+       }
+       year += 4 * n
+       day -= daysPer4Years * n
+
+       // Cut off non-leap years.
+       n = day / 365
+       if n > 3 { // happens on last day of 4th year
+               n = 3
+       }
+       year += n
+       day -= 365 * n
+
+       t.Year = year
+
+       // If someone ever needs yearday,
+       // tyearday = day (+1?)
+
+       months := months(year)
+       var m int
+       yday := int(day)
+       for m = 0; m < 12 && yday >= months[m]; m++ {
+               yday -= months[m]
+       }
+       t.Month = m + 1
+       t.Day = yday + 1
+       t.Zone = "UTC"
+
+       return t
+}
+
+// UTC returns the current time as a parsed Time value in the UTC time zone.
+func UTC() *Time { return SecondsToUTC(Seconds()) }
+
+// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
+// into a parsed Time value in the local time zone.
+func SecondsToLocalTime(sec int64) *Time {
+       z, offset := lookupTimezone(sec)
+       t := SecondsToUTC(sec + int64(offset))
+       t.Zone = z
+       t.ZoneOffset = offset
+       return t
+}
+
+// LocalTime returns the current time as a parsed Time value in the local time zone.
+func LocalTime() *Time { return SecondsToLocalTime(Seconds()) }
+
+// Seconds returns the number of seconds since January 1, 1970 represented by the
+// parsed Time value.
+func (t *Time) Seconds() int64 {
+       // First, accumulate days since January 1, 2001.
+       // Using 2001 instead of 1970 makes the leap-year
+       // handling easier (see SecondsToUTC), because
+       // it is at the beginning of the 4-, 100-, and 400-year cycles.
+       day := int64(0)
+
+       // Rewrite year to be >= 2001.
+       year := t.Year
+       if year < 2001 {
+               n := (2001-year)/400 + 1
+               year += 400 * n
+               day -= daysPer400Years * n
+       }
+
+       // Add in days from 400-year cycles.
+       n := (year - 2001) / 400
+       year -= 400 * n
+       day += daysPer400Years * n
+
+       // Add in 100-year cycles.
+       n = (year - 2001) / 100
+       year -= 100 * n
+       day += daysPer100Years * n
+
+       // Add in 4-year cycles.
+       n = (year - 2001) / 4
+       year -= 4 * n
+       day += daysPer4Years * n
+
+       // Add in non-leap years.
+       n = year - 2001
+       day += 365 * n
+
+       // Add in days this year.
+       months := months(t.Year)
+       for m := 0; m < t.Month-1; m++ {
+               day += int64(months[m])
+       }
+       day += int64(t.Day - 1)
+
+       // Convert days to seconds since January 1, 2001.
+       sec := day * secondsPerDay
+
+       // Add in time elapsed today.
+       sec += int64(t.Hour) * 3600
+       sec += int64(t.Minute) * 60
+       sec += int64(t.Second)
+
+       // Convert from seconds since 2001 to seconds since 1970.
+       sec += days1970To2001 * secondsPerDay
+
+       // Account for local time zone.
+       sec -= int64(t.ZoneOffset)
+       return sec
+}
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
new file mode 100644 (file)
index 0000000..c86bca1
--- /dev/null
@@ -0,0 +1,341 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+       "os"
+       "strings"
+       "testing"
+       "testing/quick"
+       . "time"
+)
+
+func init() {
+       // Force US Pacific time for daylight-savings
+       // tests below (localtests).  Needs to be set
+       // before the first call into the time library.
+       os.Setenv("TZ", "America/Los_Angeles")
+}
+
+type TimeTest struct {
+       seconds int64
+       golden  Time
+}
+
+var utctests = []TimeTest{
+       {0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC"}},
+       {1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}},
+       {-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC"}},
+       {-11644473600, Time{1601, 1, 1, 0, 0, 0, Monday, 0, "UTC"}},
+       {599529660, Time{1988, 12, 31, 0, 1, 0, Saturday, 0, "UTC"}},
+       {978220860, Time{2000, 12, 31, 0, 1, 0, Sunday, 0, "UTC"}},
+       {1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC"}},
+       {-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC"}},
+       {0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC"}},
+       {-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"}},
+}
+
+var localtests = []TimeTest{
+       {0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
+       {1221681866, Time{2008, 9, 17, 13, 4, 26, Wednesday, -7 * 60 * 60, "PDT"}},
+}
+
+func same(t, u *Time) bool {
+       return t.Year == u.Year &&
+               t.Month == u.Month &&
+               t.Day == u.Day &&
+               t.Hour == u.Hour &&
+               t.Minute == u.Minute &&
+               t.Second == u.Second &&
+               t.Weekday == u.Weekday &&
+               t.ZoneOffset == u.ZoneOffset &&
+               t.Zone == u.Zone
+}
+
+func TestSecondsToUTC(t *testing.T) {
+       for i := 0; i < len(utctests); i++ {
+               sec := utctests[i].seconds
+               golden := &utctests[i].golden
+               tm := SecondsToUTC(sec)
+               newsec := tm.Seconds()
+               if newsec != sec {
+                       t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec)
+               }
+               if !same(tm, golden) {
+                       t.Errorf("SecondsToUTC(%d):", sec)
+                       t.Errorf("  want=%+v", *golden)
+                       t.Errorf("  have=%+v", *tm)
+               }
+       }
+}
+
+func TestSecondsToLocalTime(t *testing.T) {
+       for i := 0; i < len(localtests); i++ {
+               sec := localtests[i].seconds
+               golden := &localtests[i].golden
+               tm := SecondsToLocalTime(sec)
+               newsec := tm.Seconds()
+               if newsec != sec {
+                       t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec)
+               }
+               if !same(tm, golden) {
+                       t.Errorf("SecondsToLocalTime(%d):", sec)
+                       t.Errorf("  want=%+v", *golden)
+                       t.Errorf("  have=%+v", *tm)
+               }
+       }
+}
+
+func TestSecondsToUTCAndBack(t *testing.T) {
+       f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec }
+       f32 := func(sec int32) bool { return f(int64(sec)) }
+       cfg := &quick.Config{MaxCount: 10000}
+
+       // Try a reasonable date first, then the huge ones.
+       if err := quick.Check(f32, cfg); err != nil {
+               t.Fatal(err)
+       }
+       if err := quick.Check(f, cfg); err != nil {
+               t.Fatal(err)
+       }
+}
+
+type TimeFormatTest struct {
+       time           Time
+       formattedValue string
+}
+
+var rfc3339Formats = []TimeFormatTest{
+       {Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}, "2008-09-17T20:04:26Z"},
+       {Time{1994, 9, 17, 20, 4, 26, Wednesday, -18000, "EST"}, "1994-09-17T20:04:26-05:00"},
+       {Time{2000, 12, 26, 1, 15, 6, Wednesday, 15600, "OTO"}, "2000-12-26T01:15:06+04:20"},
+}
+
+func TestRFC3339Conversion(t *testing.T) {
+       for _, f := range rfc3339Formats {
+               if f.time.Format(RFC3339) != f.formattedValue {
+                       t.Error("RFC3339:")
+                       t.Errorf("  want=%+v", f.formattedValue)
+                       t.Errorf("  have=%+v", f.time.Format(RFC3339))
+               }
+       }
+}
+
+type FormatTest struct {
+       name   string
+       format string
+       result string
+}
+
+var formatTests = []FormatTest{
+       {"ANSIC", ANSIC, "Thu Feb  4 21:00:57 2010"},
+       {"UnixDate", UnixDate, "Thu Feb  4 21:00:57 PST 2010"},
+       {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010"},
+       {"RFC822", RFC822, "04 Feb 10 2100 PST"},
+       {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST"},
+       {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST"},
+       {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00"},
+       {"Kitchen", Kitchen, "9:00PM"},
+       {"am/pm", "3pm", "9pm"},
+       {"AM/PM", "3PM", "9PM"},
+}
+
+func TestFormat(t *testing.T) {
+       // The numeric time represents Thu Feb  4 21:00:57 PST 2010
+       time := SecondsToLocalTime(1265346057)
+       for _, test := range formatTests {
+               result := time.Format(test.format)
+               if result != test.result {
+                       t.Errorf("%s expected %q got %q", test.name, test.result, result)
+               }
+       }
+}
+
+type ParseTest struct {
+       name     string
+       format   string
+       value    string
+       hasTZ    bool  // contains a time zone
+       hasWD    bool  // contains a weekday
+       yearSign int64 // sign of year
+}
+
+var parseTests = []ParseTest{
+       {"ANSIC", ANSIC, "Thu Feb  4 21:00:57 2010", false, true, 1},
+       {"UnixDate", UnixDate, "Thu Feb  4 21:00:57 PST 2010", true, true, 1},
+       {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1},
+       {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1},
+       {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1},
+       {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1},
+       {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1},
+       // Amount of white space should not matter.
+       {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
+       {"ANSIC", ANSIC, "Thu      Feb     4     21:00:57     2010", false, true, 1},
+}
+
+func TestParse(t *testing.T) {
+       for _, test := range parseTests {
+               time, err := Parse(test.format, test.value)
+               if err != nil {
+                       t.Errorf("%s error: %v", test.name, err)
+               } else {
+                       checkTime(time, &test, t)
+               }
+       }
+}
+
+var rubyTests = []ParseTest{
+       {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1},
+       // Ignore the time zone in the test. If it parses, it'll be OK.
+       {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1},
+       {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1},
+       {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1},
+}
+
+// Problematic time zone format needs special tests.
+func TestRubyParse(t *testing.T) {
+       for _, test := range rubyTests {
+               time, err := Parse(test.format, test.value)
+               if err != nil {
+                       t.Errorf("%s error: %v", test.name, err)
+               } else {
+                       checkTime(time, &test, t)
+               }
+       }
+}
+
+func checkTime(time *Time, test *ParseTest, t *testing.T) {
+       // The time should be Thu Feb  4 21:00:57 PST 2010
+       if test.yearSign*time.Year != 2010 {
+               t.Errorf("%s: bad year: %d not %d", test.name, time.Year, 2010)
+       }
+       if time.Month != 2 {
+               t.Errorf("%s: bad month: %d not %d", test.name, time.Month, 2)
+       }
+       if time.Day != 4 {
+               t.Errorf("%s: bad day: %d not %d", test.name, time.Day, 4)
+       }
+       if time.Hour != 21 {
+               t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour, 21)
+       }
+       if time.Minute != 0 {
+               t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute, 0)
+       }
+       if time.Second != 57 {
+               t.Errorf("%s: bad second: %d not %d", test.name, time.Second, 57)
+       }
+       if test.hasTZ && time.ZoneOffset != -28800 {
+               t.Errorf("%s: bad tz offset: %d not %d", test.name, time.ZoneOffset, -28800)
+       }
+       if test.hasWD && time.Weekday != 4 {
+               t.Errorf("%s: bad weekday: %d not %d", test.name, time.Weekday, 4)
+       }
+}
+
+func TestFormatAndParse(t *testing.T) {
+       const fmt = "Mon MST " + RFC3339 // all fields
+       f := func(sec int64) bool {
+               t1 := SecondsToLocalTime(sec)
+               if t1.Year < 1000 || t1.Year > 9999 {
+                       // not required to work
+                       return true
+               }
+               t2, err := Parse(fmt, t1.Format(fmt))
+               if err != nil {
+                       t.Errorf("error: %s", err)
+                       return false
+               }
+               if !same(t1, t2) {
+                       t.Errorf("different: %q %q", t1, t2)
+                       return false
+               }
+               return true
+       }
+       f32 := func(sec int32) bool { return f(int64(sec)) }
+       cfg := &quick.Config{MaxCount: 10000}
+
+       // Try a reasonable date first, then the huge ones.
+       if err := quick.Check(f32, cfg); err != nil {
+               t.Fatal(err)
+       }
+       if err := quick.Check(f, cfg); err != nil {
+               t.Fatal(err)
+       }
+}
+
+type ParseErrorTest struct {
+       format string
+       value  string
+       expect string // must appear within the error
+}
+
+var parseErrorTests = []ParseErrorTest{
+       {ANSIC, "Feb  4 21:00:60 2010", "parse"}, // cannot parse Feb as Mon
+       {ANSIC, "Thu Feb  4 21:00:57 @2010", "parse"},
+       {ANSIC, "Thu Feb  4 21:00:60 2010", "second out of range"},
+       {ANSIC, "Thu Feb  4 21:61:57 2010", "minute out of range"},
+       {ANSIC, "Thu Feb  4 24:00:60 2010", "hour out of range"},
+}
+
+func TestParseErrors(t *testing.T) {
+       for _, test := range parseErrorTests {
+               _, err := Parse(test.format, test.value)
+               if err == nil {
+                       t.Errorf("expected error for %q %q", test.format, test.value)
+               } else if strings.Index(err.String(), test.expect) < 0 {
+                       t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
+               }
+       }
+}
+
+// Check that a time without a Zone still produces a (numeric) time zone
+// when formatted with MST as a requested zone.
+func TestMissingZone(t *testing.T) {
+       time, err := Parse(RubyDate, "Tue Feb 02 16:10:03 -0500 2006")
+       if err != nil {
+               t.Fatal("error parsing date:", err)
+       }
+       expect := "Tue Feb  2 16:10:03 -0500 2006" // -0500 not EST
+       str := time.Format(UnixDate)               // uses MST as its time zone
+       if str != expect {
+               t.Errorf("expected %q got %q", expect, str)
+       }
+}
+
+func TestMinutesInTimeZone(t *testing.T) {
+       time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
+       if err != nil {
+               t.Fatal("error parsing date:", err)
+       }
+       expected := (1*60 + 23) * 60
+       if time.ZoneOffset != expected {
+               t.Errorf("ZoneOffset incorrect, expected %d got %d", expected, time.ZoneOffset)
+       }
+}
+
+func BenchmarkSeconds(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Seconds()
+       }
+}
+
+func BenchmarkNanoseconds(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Nanoseconds()
+       }
+}
+
+func BenchmarkFormat(b *testing.B) {
+       time := SecondsToLocalTime(1265346057)
+       for i := 0; i < b.N; i++ {
+               time.Format("Mon Jan  2 15:04:05 2006")
+       }
+}
+
+func BenchmarkParse(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Parse(ANSIC, "Mon Jan  2 15:04:05 2006")
+       }
+}
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
new file mode 100644 (file)
index 0000000..26c86ab
--- /dev/null
@@ -0,0 +1,262 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse "zoneinfo" time zone file.
+// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
+// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
+// and ftp://munnari.oz.au/pub/oldtz/
+
+package time
+
+import (
+       "io/ioutil"
+       "os"
+       "sync"
+)
+
+const (
+       headerSize = 4 + 16 + 4*7
+       zoneDir    = "/usr/share/zoneinfo/"
+)
+
+// Simple I/O interface to binary blob of data.
+type data struct {
+       p     []byte
+       error bool
+}
+
+
+func (d *data) read(n int) []byte {
+       if len(d.p) < n {
+               d.p = nil
+               d.error = true
+               return nil
+       }
+       p := d.p[0:n]
+       d.p = d.p[n:]
+       return p
+}
+
+func (d *data) big4() (n uint32, ok bool) {
+       p := d.read(4)
+       if len(p) < 4 {
+               d.error = true
+               return 0, false
+       }
+       return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
+}
+
+func (d *data) byte() (n byte, ok bool) {
+       p := d.read(1)
+       if len(p) < 1 {
+               d.error = true
+               return 0, false
+       }
+       return p[0], true
+}
+
+
+// Make a string by stopping at the first NUL
+func byteString(p []byte) string {
+       for i := 0; i < len(p); i++ {
+               if p[i] == 0 {
+                       return string(p[0:i])
+               }
+       }
+       return string(p)
+}
+
+// Parsed representation
+type zone struct {
+       utcoff int
+       isdst  bool
+       name   string
+}
+
+type zonetime struct {
+       time         int32 // transition time, in seconds since 1970 GMT
+       zone         *zone // the zone that goes into effect at that time
+       isstd, isutc bool  // ignored - no idea what these mean
+}
+
+func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
+       d := data{bytes, false}
+
+       // 4-byte magic "TZif"
+       if magic := d.read(4); string(magic) != "TZif" {
+               return nil, false
+       }
+
+       // 1-byte version, then 15 bytes of padding
+       var p []byte
+       if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
+               return nil, false
+       }
+
+       // six big-endian 32-bit integers:
+       //      number of UTC/local indicators
+       //      number of standard/wall indicators
+       //      number of leap seconds
+       //      number of transition times
+       //      number of local time zones
+       //      number of characters of time zone abbrev strings
+       const (
+               NUTCLocal = iota
+               NStdWall
+               NLeap
+               NTime
+               NZone
+               NChar
+       )
+       var n [6]int
+       for i := 0; i < 6; i++ {
+               nn, ok := d.big4()
+               if !ok {
+                       return nil, false
+               }
+               n[i] = int(nn)
+       }
+
+       // Transition times.
+       txtimes := data{d.read(n[NTime] * 4), false}
+
+       // Time zone indices for transition times.
+       txzones := d.read(n[NTime])
+
+       // Zone info structures
+       zonedata := data{d.read(n[NZone] * 6), false}
+
+       // Time zone abbreviations.
+       abbrev := d.read(n[NChar])
+
+       // Leap-second time pairs
+       d.read(n[NLeap] * 8)
+
+       // Whether tx times associated with local time types
+       // are specified as standard time or wall time.
+       isstd := d.read(n[NStdWall])
+
+       // Whether tx times associated with local time types
+       // are specified as UTC or local time.
+       isutc := d.read(n[NUTCLocal])
+
+       if d.error { // ran out of data
+               return nil, false
+       }
+
+       // If version == 2, the entire file repeats, this time using
+       // 8-byte ints for txtimes and leap seconds.
+       // We won't need those until 2106.
+
+       // Now we can build up a useful data structure.
+       // First the zone information.
+       //      utcoff[4] isdst[1] nameindex[1]
+       z := make([]zone, n[NZone])
+       for i := 0; i < len(z); i++ {
+               var ok bool
+               var n uint32
+               if n, ok = zonedata.big4(); !ok {
+                       return nil, false
+               }
+               z[i].utcoff = int(n)
+               var b byte
+               if b, ok = zonedata.byte(); !ok {
+                       return nil, false
+               }
+               z[i].isdst = b != 0
+               if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
+                       return nil, false
+               }
+               z[i].name = byteString(abbrev[b:])
+       }
+
+       // Now the transition time info.
+       zt = make([]zonetime, n[NTime])
+       for i := 0; i < len(zt); i++ {
+               var ok bool
+               var n uint32
+               if n, ok = txtimes.big4(); !ok {
+                       return nil, false
+               }
+               zt[i].time = int32(n)
+               if int(txzones[i]) >= len(z) {
+                       return nil, false
+               }
+               zt[i].zone = &z[txzones[i]]
+               if i < len(isstd) {
+                       zt[i].isstd = isstd[i] != 0
+               }
+               if i < len(isutc) {
+                       zt[i].isutc = isutc[i] != 0
+               }
+       }
+       return zt, true
+}
+
+func readinfofile(name string) ([]zonetime, bool) {
+       buf, err := ioutil.ReadFile(name)
+       if err != nil {
+               return nil, false
+       }
+       return parseinfo(buf)
+}
+
+var zones []zonetime
+var onceSetupZone sync.Once
+
+func setupZone() {
+       // consult $TZ to find the time zone to use.
+       // no $TZ means use the system default /etc/localtime.
+       // $TZ="" means use UTC.
+       // $TZ="foo" means use /usr/share/zoneinfo/foo.
+
+       tz, err := os.Getenverror("TZ")
+       switch {
+       case err == os.ENOENV:
+               zones, _ = readinfofile("/etc/localtime")
+       case len(tz) > 0:
+               zones, _ = readinfofile(zoneDir + tz)
+       case len(tz) == 0:
+               // do nothing: use UTC
+       }
+}
+
+// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
+func lookupTimezone(sec int64) (zone string, offset int) {
+       onceSetupZone.Do(setupZone)
+       if len(zones) == 0 {
+               return "UTC", 0
+       }
+
+       // Binary search for entry with largest time <= sec
+       tz := zones
+       for len(tz) > 1 {
+               m := len(tz) / 2
+               if sec < int64(tz[m].time) {
+                       tz = tz[0:m]
+               } else {
+                       tz = tz[m:]
+               }
+       }
+       z := tz[0].zone
+       return z.name, z.utcoff
+}
+
+// lookupByName returns the time offset for the
+// time zone with the given abbreviation. It only considers
+// time zones that apply to the current system.
+// For example, for a system configured as being in New York,
+// it only recognizes "EST" and "EDT".
+// For a system in San Francisco, "PST" and "PDT".
+// For a system in Sydney, "EST" and "EDT", though they have
+// different meanings than they do in New York.
+func lookupByName(name string) (off int, found bool) {
+       onceSetupZone.Do(setupZone)
+       for _, z := range zones {
+               if name == z.zone.name {
+                       return z.zone.utcoff, true
+               }
+       }
+       return 0, false
+}
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
new file mode 100644 (file)
index 0000000..c357eec
--- /dev/null
@@ -0,0 +1,192 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+       "syscall"
+       "sync"
+       "os"
+)
+
+// BUG(brainman): The Windows implementation assumes that
+// this year's rules for daylight savings time apply to all previous
+// and future years as well.
+
+// TODO(brainman): use GetDynamicTimeZoneInformation, whenever posible (Vista and up),
+// to improve on situation described in the bug above.
+
+type zone struct {
+       name                  string
+       offset                int
+       year                  int64
+       month, day, dayofweek int
+       hour, minute, second  int
+       abssec                int64
+       prev                  *zone
+}
+
+// Populate zone struct with Windows supplied information. Returns true, if data is valid.
+func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uint16) (dateisgood bool) {
+       z.name = syscall.UTF16ToString(name)
+       z.offset = int(bias)
+       z.year = int64(d.Year)
+       z.month = int(d.Month)
+       z.day = int(d.Day)
+       z.dayofweek = int(d.DayOfWeek)
+       z.hour = int(d.Hour)
+       z.minute = int(d.Minute)
+       z.second = int(d.Second)
+       dateisgood = d.Month != 0
+       if dateisgood {
+               z.offset += int(biasdelta)
+       }
+       z.offset = -z.offset * 60
+       return
+}
+
+// Pre-calculte cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format.
+func (z *zone) preCalculateAbsSec() {
+       if z.year != 0 {
+               z.abssec = (&Time{z.year, int(z.month), int(z.day), int(z.hour), int(z.minute), int(z.second), 0, 0, ""}).Seconds()
+               // Time given is in "local" time. Adjust it for "utc".
+               z.abssec -= int64(z.prev.offset)
+       }
+}
+
+// Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particualar year.
+func (z *zone) cutoffSeconds(year int64) int64 {
+       // Windows specifies daylight savings information in "day in month" format:
+       // z.month is month number (1-12)
+       // z.dayofweek is appropriate weekday (Sunday=0 to Saturday=6)
+       // z.day is week within the month (1 to 5, where 5 is last week of the month)
+       // z.hour, z.minute and z.second are absolute time
+       t := &Time{year, int(z.month), 1, int(z.hour), int(z.minute), int(z.second), 0, 0, ""}
+       t = SecondsToUTC(t.Seconds())
+       i := int(z.dayofweek) - t.Weekday
+       if i < 0 {
+               i += 7
+       }
+       t.Day += i
+       if week := int(z.day) - 1; week < 4 {
+               t.Day += week * 7
+       } else {
+               // "Last" instance of the day.
+               t.Day += 4 * 7
+               if t.Day > months(year)[t.Month] {
+                       t.Day -= 7
+               }
+       }
+       // Result is in "local" time. Adjust it for "utc".
+       return t.Seconds() - int64(z.prev.offset)
+}
+
+// Is t before the cutoff for switching to z?
+func (z *zone) isBeforeCutoff(t *Time) bool {
+       var coff int64
+       if z.year == 0 {
+               // "day in month" format used
+               coff = z.cutoffSeconds(t.Year)
+       } else {
+               // "absolute" format used
+               coff = z.abssec
+       }
+       return t.Seconds() < coff
+}
+
+type zoneinfo struct {
+       disabled         bool // daylight saving time is not used localy
+       offsetIfDisabled int
+       januaryIsStd     bool // is january 1 standard time?
+       std, dst         zone
+}
+
+// Pick zone (std or dst) t time belongs to.
+func (zi *zoneinfo) pickZone(t *Time) *zone {
+       z := &zi.std
+       if tz.januaryIsStd {
+               if !zi.dst.isBeforeCutoff(t) && zi.std.isBeforeCutoff(t) {
+                       // after switch to daylight time and before the switch back to standard
+                       z = &zi.dst
+               }
+       } else {
+               if zi.std.isBeforeCutoff(t) || !zi.dst.isBeforeCutoff(t) {
+                       // before switch to standard time or after the switch back to daylight
+                       z = &zi.dst
+               }
+       }
+       return z
+}
+
+var tz zoneinfo
+var initError os.Error
+var onceSetupZone sync.Once
+
+func setupZone() {
+       var i syscall.Timezoneinformation
+       if _, e := syscall.GetTimeZoneInformation(&i); e != 0 {
+               initError = os.NewSyscallError("GetTimeZoneInformation", e)
+               return
+       }
+       if !tz.std.populate(i.Bias, i.StandardBias, &i.StandardDate, i.StandardName[0:]) {
+               tz.disabled = true
+               tz.offsetIfDisabled = tz.std.offset
+               return
+       }
+       tz.std.prev = &tz.dst
+       tz.dst.populate(i.Bias, i.DaylightBias, &i.DaylightDate, i.DaylightName[0:])
+       tz.dst.prev = &tz.std
+       tz.std.preCalculateAbsSec()
+       tz.dst.preCalculateAbsSec()
+       // Is january 1 standard time this year?
+       t := UTC()
+       tz.januaryIsStd = tz.dst.cutoffSeconds(t.Year) < tz.std.cutoffSeconds(t.Year)
+}
+
+// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
+func lookupTimezone(sec int64) (zone string, offset int) {
+       onceSetupZone.Do(setupZone)
+       if initError != nil {
+               return "", 0
+       }
+       if tz.disabled {
+               return "", tz.offsetIfDisabled
+       }
+       t := SecondsToUTC(sec)
+       z := &tz.std
+       if tz.std.year == 0 {
+               // "day in month" format used
+               z = tz.pickZone(t)
+       } else {
+               // "absolute" format used
+               if tz.std.year == t.Year {
+                       // we have rule for the year in question
+                       z = tz.pickZone(t)
+               } else {
+                       // we do not have any information for that year,
+                       // will assume standard offset all year around
+               }
+       }
+       return z.name, z.offset
+}
+
+// lookupByName returns the time offset for the
+// time zone with the given abbreviation. It only considers
+// time zones that apply to the current system.
+func lookupByName(name string) (off int, found bool) {
+       onceSetupZone.Do(setupZone)
+       if initError != nil {
+               return 0, false
+       }
+       if tz.disabled {
+               return tz.offsetIfDisabled, false
+       }
+       switch name {
+       case tz.std.name:
+               return tz.std.offset, true
+       case tz.dst.name:
+               return tz.dst.offset, true
+       }
+       return 0, false
+}
diff --git a/libgo/go/try/try.go b/libgo/go/try/try.go
new file mode 100644 (file)
index 0000000..af31d0d
--- /dev/null
@@ -0,0 +1,174 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package try contains the executable part of the gotry command.
+// It is not intended for general use.
+package try
+
+import (
+       "fmt"
+       "io"
+       "os"
+       "reflect"
+       "unicode"
+)
+
+var output io.Writer = os.Stdout // redirected when testing
+
+// Main is called directly from the gotry-generated Go source file to perform
+// the evaluations.
+func Main(pkg, firstArg string, functions map[string]interface{}, args []interface{}) {
+       switch len(args) {
+       case 0:
+               // Nothing to do.
+       case 1:
+               // Compiler has already evaluated the expression; just print the result.
+               printSlice(firstArg, args)
+       default:
+               // See if methods satisfy the expressions.
+               tryMethods(pkg, firstArg, args)
+               // See if functions satisfy the expressions.
+               for name, fn := range functions {
+                       tryFunction(pkg, name, fn, args)
+               }
+       }
+}
+
+// printSlice prints the zeroth element of the args slice, which should (by construction)
+// itself be a slice of interface{}.
+func printSlice(firstArg string, args []interface{}) {
+       // Args should be length 1 and a slice.
+       if len(args) != 1 {
+               return
+       }
+       arg, ok := args[0].([]interface{})
+       if !ok {
+               return
+       }
+       fmt.Fprintf(output, "%s = ", firstArg)
+       if len(arg) > 1 {
+               fmt.Fprint(output, "(")
+       }
+       for i, a := range arg {
+               if i > 0 {
+                       fmt.Fprint(output, ", ")
+               }
+               fmt.Fprintf(output, "%#v", a)
+       }
+       if len(arg) > 1 {
+               fmt.Fprint(output, ")")
+       }
+       fmt.Fprint(output, "\n")
+}
+
+// tryMethods sees if the zeroth arg has methods, and if so treats them as potential
+// functions to satisfy the remaining arguments.
+func tryMethods(pkg, firstArg string, args []interface{}) {
+       defer func() { recover() }()
+       // Is the first argument something with methods?
+       v := reflect.NewValue(args[0])
+       typ := v.Type()
+       if typ.NumMethod() == 0 {
+               return
+       }
+       for i := 0; i < typ.NumMethod(); i++ {
+               if unicode.IsUpper(int(typ.Method(i).Name[0])) {
+                       tryMethod(pkg, firstArg, typ.Method(i), args)
+               }
+       }
+}
+
+// tryMethod converts a method to a function for tryOneFunction.
+func tryMethod(pkg, firstArg string, method reflect.Method, args []interface{}) {
+       rfn := method.Func
+       typ := method.Type
+       name := method.Name
+       tryOneFunction(pkg, firstArg, name, typ, rfn, args)
+}
+
+// tryFunction sees if fn satisfies the arguments.
+func tryFunction(pkg, name string, fn interface{}, args []interface{}) {
+       defer func() { recover() }()
+       rfn := reflect.NewValue(fn).(*reflect.FuncValue)
+       typ := rfn.Type().(*reflect.FuncType)
+       tryOneFunction(pkg, "", name, typ, rfn, args)
+}
+
+// tryOneFunction is the common code for tryMethod and tryFunction.
+func tryOneFunction(pkg, firstArg, name string, typ *reflect.FuncType, rfn *reflect.FuncValue, args []interface{}) {
+       // Any results?
+       if typ.NumOut() == 0 {
+               return // Nothing to do.
+       }
+       // Right number of arguments + results?
+       if typ.NumIn()+typ.NumOut() != len(args) {
+               return
+       }
+       // Right argument and result types?
+       for i, a := range args {
+               if i < typ.NumIn() {
+                       if !compatible(a, typ.In(i)) {
+                               return
+                       }
+               } else {
+                       if !compatible(a, typ.Out(i-typ.NumIn())) {
+                               return
+                       }
+               }
+       }
+       // Build the call args.
+       argsVal := make([]reflect.Value, typ.NumIn()+typ.NumOut())
+       for i, a := range args {
+               argsVal[i] = reflect.NewValue(a)
+       }
+       // Call the function and see if the results are as expected.
+       resultVal := rfn.Call(argsVal[:typ.NumIn()])
+       for i, v := range resultVal {
+               if !reflect.DeepEqual(v.Interface(), args[i+typ.NumIn()]) {
+                       return
+               }
+       }
+       // Present the result including a godoc command to get more information.
+       firstIndex := 0
+       if firstArg != "" {
+               fmt.Fprintf(output, "%s.%s(", firstArg, name)
+               firstIndex = 1
+       } else {
+               fmt.Fprintf(output, "%s.%s(", pkg, name)
+       }
+       for i := firstIndex; i < typ.NumIn(); i++ {
+               if i > firstIndex {
+                       fmt.Fprint(output, ", ")
+               }
+               fmt.Fprintf(output, "%#v", args[i])
+       }
+       fmt.Fprint(output, ") = ")
+       if typ.NumOut() > 1 {
+               fmt.Fprint(output, "(")
+       }
+       for i := 0; i < typ.NumOut(); i++ {
+               if i > 0 {
+                       fmt.Fprint(output, ", ")
+               }
+               fmt.Fprintf(output, "%#v", resultVal[i].Interface())
+       }
+       if typ.NumOut() > 1 {
+               fmt.Fprint(output, ")")
+       }
+       fmt.Fprintf(output, "  // godoc %s %s\n", pkg, name)
+}
+
+// compatible reports whether the argument is compatible with the type.
+func compatible(arg interface{}, typ reflect.Type) bool {
+       if reflect.Typeof(arg) == typ {
+               return true
+       }
+       if arg == nil {
+               // nil is OK if the type is an interface.
+               if _, ok := typ.(*reflect.InterfaceType); ok {
+                       return true
+               }
+       }
+       return false
+}
diff --git a/libgo/go/try/try_test.go b/libgo/go/try/try_test.go
new file mode 100644 (file)
index 0000000..617b2c7
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package try
+
+import (
+       "bytes"
+       "regexp" // Used as the package to try.
+       "testing"
+)
+
+// The global functions in package regexp at time of writing.
+// Doesn't need to be updated unless the entries in this list become invalid.
+var functions = map[string]interface{}{
+       "Compile":     regexp.Compile,
+       "Match":       regexp.Match,
+       "MatchString": regexp.MatchString,
+       "MustCompile": regexp.MustCompile,
+       "QuoteMeta":   regexp.QuoteMeta,
+}
+
+// A wraps arguments to make the test cases nicer to read.
+func A(args ...interface{}) []interface{} {
+       return args
+}
+
+type Test struct {
+       firstArg string // only needed if there is exactly one argument
+       result   string // minus final newline; might be just the godoc string
+       args     []interface{}
+}
+
+var testRE = regexp.MustCompile("a(.)(.)d")
+
+var tests = []Test{
+       // A simple expression.  The final value is a slice in case the expression is multivalue.
+       {"3+4", "3+4 = 7", A([]interface{}{7})},
+       // A search for a function.
+       {"", "regexp QuoteMeta", A("([])", `\(\[\]\)`)},
+       // A search for a function with multiple return values.
+       {"", "regexp MatchString", A("abc", "xabcd", true, nil)},
+       // Searches for methods.
+       {"", "regexp MatchString", A(testRE, "xabcde", true)},
+       {"", "regexp NumSubexp", A(testRE, 2)},
+}
+
+func TestAll(t *testing.T) {
+       re := regexp.MustCompile(".*// godoc ")
+       for _, test := range tests {
+               b := new(bytes.Buffer)
+               output = b
+               Main("regexp", test.firstArg, functions, test.args)
+               expect := test.result + "\n"
+               got := re.ReplaceAllString(b.String(), "")
+               if got != expect {
+                       t.Errorf("expected %q; got %q", expect, got)
+               }
+       }
+}
diff --git a/libgo/go/unicode/casetables.go b/libgo/go/unicode/casetables.go
new file mode 100644 (file)
index 0000000..6644070
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: This file contains the special casing rules for Turkish and Azeri only.
+// It should encompass all the languages with special casing rules
+// and be generated automatically, but that requires some API
+// development first.
+
+package unicode
+
+
+var TurkishCase = _TurkishCase
+var _TurkishCase = SpecialCase{
+       CaseRange{0x0049, 0x0049, d{0, 0x131 - 0x49, 0}},
+       CaseRange{0x0069, 0x0069, d{0x130 - 0x69, 0, 0x130 - 0x69}},
+       CaseRange{0x0130, 0x0130, d{0, 0x69 - 0x130, 0}},
+       CaseRange{0x0131, 0x0131, d{0x49 - 0x131, 0, 0x49 - 0x131}},
+}
+
+var AzeriCase = _TurkishCase
diff --git a/libgo/go/unicode/digit.go b/libgo/go/unicode/digit.go
new file mode 100644 (file)
index 0000000..471c4df
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode
+
+// IsDigit reports whether the rune is a decimal digit.
+func IsDigit(rune int) bool {
+       if rune < 0x100 { // quick ASCII (Latin-1, really) check
+               return '0' <= rune && rune <= '9'
+       }
+       return Is(Digit, rune)
+}
diff --git a/libgo/go/unicode/digit_test.go b/libgo/go/unicode/digit_test.go
new file mode 100644 (file)
index 0000000..9bbccde
--- /dev/null
@@ -0,0 +1,126 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode_test
+
+import (
+       "testing"
+       . "unicode"
+)
+
+var testDigit = []int{
+       0x0030,
+       0x0039,
+       0x0661,
+       0x06F1,
+       0x07C9,
+       0x0966,
+       0x09EF,
+       0x0A66,
+       0x0AEF,
+       0x0B66,
+       0x0B6F,
+       0x0BE6,
+       0x0BEF,
+       0x0C66,
+       0x0CEF,
+       0x0D66,
+       0x0D6F,
+       0x0E50,
+       0x0E59,
+       0x0ED0,
+       0x0ED9,
+       0x0F20,
+       0x0F29,
+       0x1040,
+       0x1049,
+       0x1090,
+       0x1091,
+       0x1099,
+       0x17E0,
+       0x17E9,
+       0x1810,
+       0x1819,
+       0x1946,
+       0x194F,
+       0x19D0,
+       0x19D9,
+       0x1B50,
+       0x1B59,
+       0x1BB0,
+       0x1BB9,
+       0x1C40,
+       0x1C49,
+       0x1C50,
+       0x1C59,
+       0xA620,
+       0xA629,
+       0xA8D0,
+       0xA8D9,
+       0xA900,
+       0xA909,
+       0xAA50,
+       0xAA59,
+       0xFF10,
+       0xFF19,
+       0x104A1,
+       0x1D7CE,
+}
+
+var testLetter = []int{
+       0x0041,
+       0x0061,
+       0x00AA,
+       0x00BA,
+       0x00C8,
+       0x00DB,
+       0x00F9,
+       0x02EC,
+       0x0535,
+       0x06E6,
+       0x093D,
+       0x0A15,
+       0x0B99,
+       0x0DC0,
+       0x0EDD,
+       0x1000,
+       0x1200,
+       0x1312,
+       0x1401,
+       0x1885,
+       0x2C00,
+       0xA800,
+       0xF900,
+       0xFA30,
+       0xFFDA,
+       0xFFDC,
+       0x10000,
+       0x10300,
+       0x10400,
+       0x20000,
+       0x2F800,
+       0x2FA1D,
+}
+
+func TestDigit(t *testing.T) {
+       for _, r := range testDigit {
+               if !IsDigit(r) {
+                       t.Errorf("IsDigit(U+%04X) = false, want true", r)
+               }
+       }
+       for _, r := range testLetter {
+               if IsDigit(r) {
+                       t.Errorf("IsDigit(U+%04X) = true, want false", r)
+               }
+       }
+}
+
+// Test that the special case in IsDigit agrees with the table
+func TestDigitOptimization(t *testing.T) {
+       for i := 0; i < 0x100; i++ {
+               if Is(Digit, i) != IsDigit(i) {
+                       t.Errorf("IsDigit(U+%04X) disagrees with Is(Digit)", i)
+               }
+       }
+}
diff --git a/libgo/go/unicode/letter.go b/libgo/go/unicode/letter.go
new file mode 100644 (file)
index 0000000..9380624
--- /dev/null
@@ -0,0 +1,241 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package provides data and functions to test some properties of Unicode code points.
+package unicode
+
+const (
+       MaxRune         = 0x10FFFF // Maximum valid Unicode code point.
+       ReplacementChar = 0xFFFD   // Represents invalid code points.
+)
+
+
+// The representation of a range of Unicode code points.  The range runs from Lo to Hi
+// inclusive and has the specified stride.
+type Range struct {
+       Lo     int
+       Hi     int
+       Stride int
+}
+
+// CaseRange represents a range of Unicode code points for simple (one
+// code point to one code point) case conversion.
+// The range runs from Lo to Hi inclusive, with a fixed stride of 1.  Deltas
+// are the number to add to the code point to reach the code point for a
+// different case for that character.  They may be negative.  If zero, it
+// means the character is in the corresponding case. There is a special
+// case representing sequences of alternating corresponding Upper and Lower
+// pairs.  It appears with a fixed Delta of
+//     {UpperLower, UpperLower, UpperLower}
+// The constant UpperLower has an otherwise impossible delta value.
+type CaseRange struct {
+       Lo    int
+       Hi    int
+       Delta d
+}
+
+// SpecialCase represents language-specific case mappings such as Turkish.
+// Methods of SpecialCase customize (by overriding) the standard mappings.
+type SpecialCase []CaseRange
+
+//BUG(r): Provide a mechanism for full case folding (those that involve
+// multiple runes in the input or output).
+
+// Indices into the Delta arrays inside CaseRanges for case mapping.
+const (
+       UpperCase = iota
+       LowerCase
+       TitleCase
+       MaxCase
+)
+
+type d [MaxCase]int32 // to make the CaseRanges text shorter
+
+// If the Delta field of a CaseRange is UpperLower or LowerUpper, it means
+// this CaseRange represents a sequence of the form (say)
+// Upper Lower Upper Lower.
+const (
+       UpperLower = MaxRune + 1 // (Cannot be a valid delta.)
+)
+
+// Is tests whether rune is in the specified table of ranges.
+func Is(ranges []Range, rune int) bool {
+       // common case: rune is ASCII or Latin-1
+       if rune < 0x100 {
+               for _, r := range ranges {
+                       if rune > r.Hi {
+                               continue
+                       }
+                       if rune < r.Lo {
+                               return false
+                       }
+                       return (rune-r.Lo)%r.Stride == 0
+               }
+               return false
+       }
+
+       // binary search over ranges
+       lo := 0
+       hi := len(ranges)
+       for lo < hi {
+               m := lo + (hi-lo)/2
+               r := ranges[m]
+               if r.Lo <= rune && rune <= r.Hi {
+                       return (rune-r.Lo)%r.Stride == 0
+               }
+               if rune < r.Lo {
+                       hi = m
+               } else {
+                       lo = m + 1
+               }
+       }
+       return false
+}
+
+// IsUpper reports whether the rune is an upper case letter.
+func IsUpper(rune int) bool {
+       if rune < 0x80 { // quick ASCII check
+               return 'A' <= rune && rune <= 'Z'
+       }
+       return Is(Upper, rune)
+}
+
+// IsLower reports whether the rune is a lower case letter.
+func IsLower(rune int) bool {
+       if rune < 0x80 { // quick ASCII check
+               return 'a' <= rune && rune <= 'z'
+       }
+       return Is(Lower, rune)
+}
+
+// IsTitle reports whether the rune is a title case letter.
+func IsTitle(rune int) bool {
+       if rune < 0x80 { // quick ASCII check
+               return false
+       }
+       return Is(Title, rune)
+}
+
+// IsLetter reports whether the rune is a letter.
+func IsLetter(rune int) bool {
+       if rune < 0x80 { // quick ASCII check
+               rune &^= 'a' - 'A'
+               return 'A' <= rune && rune <= 'Z'
+       }
+       return Is(Letter, rune)
+}
+
+// IsSpace reports whether the rune is a white space character.
+func IsSpace(rune int) bool {
+       if rune <= 0xFF { // quick Latin-1 check
+               switch rune {
+               case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
+                       return true
+               }
+               return false
+       }
+       return Is(White_Space, rune)
+}
+
+// to maps the rune using the specified case mapping.
+func to(_case int, rune int, caseRange []CaseRange) int {
+       if _case < 0 || MaxCase <= _case {
+               return ReplacementChar // as reasonable an error as any
+       }
+       // binary search over ranges
+       lo := 0
+       hi := len(caseRange)
+       for lo < hi {
+               m := lo + (hi-lo)/2
+               r := caseRange[m]
+               if r.Lo <= rune && rune <= r.Hi {
+                       delta := int(r.Delta[_case])
+                       if delta > MaxRune {
+                               // In an Upper-Lower sequence, which always starts with
+                               // an UpperCase letter, the real deltas always look like:
+                               //      {0, 1, 0}    UpperCase (Lower is next)
+                               //      {-1, 0, -1}  LowerCase (Upper, Title are previous)
+                               // The characters at even offsets from the beginning of the
+                               // sequence are upper case; the ones at odd offsets are lower.
+                               // The correct mapping can be done by clearing or setting the low
+                               // bit in the sequence offset.
+                               // The constants UpperCase and TitleCase are even while LowerCase
+                               // is odd so we take the low bit from _case.
+                               return r.Lo + ((rune-r.Lo)&^1 | _case&1)
+                       }
+                       return rune + delta
+               }
+               if rune < r.Lo {
+                       hi = m
+               } else {
+                       lo = m + 1
+               }
+       }
+       return rune
+}
+
+// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase.
+func To(_case int, rune int) int {
+       return to(_case, rune, CaseRanges)
+}
+
+// ToUpper maps the rune to upper case.
+func ToUpper(rune int) int {
+       if rune < 0x80 { // quick ASCII check
+               if 'a' <= rune && rune <= 'z' {
+                       rune -= 'a' - 'A'
+               }
+               return rune
+       }
+       return To(UpperCase, rune)
+}
+
+// ToLower maps the rune to lower case.
+func ToLower(rune int) int {
+       if rune < 0x80 { // quick ASCII check
+               if 'A' <= rune && rune <= 'Z' {
+                       rune += 'a' - 'A'
+               }
+               return rune
+       }
+       return To(LowerCase, rune)
+}
+
+// ToTitle maps the rune to title case.
+func ToTitle(rune int) int {
+       if rune < 0x80 { // quick ASCII check
+               if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
+                       rune -= 'a' - 'A'
+               }
+               return rune
+       }
+       return To(TitleCase, rune)
+}
+
+// ToUpper maps the rune to upper case giving priority to the special mapping.
+func (special SpecialCase) ToUpper(rune int) int {
+       r := to(UpperCase, rune, []CaseRange(special))
+       if r == rune {
+               r = ToUpper(rune)
+       }
+       return r
+}
+
+// ToTitle maps the rune to title case giving priority to the special mapping.
+func (special SpecialCase) ToTitle(rune int) int {
+       r := to(TitleCase, rune, []CaseRange(special))
+       if r == rune {
+               r = ToTitle(rune)
+       }
+       return r
+}
+
+// ToLower maps the rune to lower case giving priority to the special mapping.
+func (special SpecialCase) ToLower(rune int) int {
+       r := to(LowerCase, rune, []CaseRange(special))
+       if r == rune {
+               r = ToLower(rune)
+       }
+       return r
+}
diff --git a/libgo/go/unicode/letter_test.go b/libgo/go/unicode/letter_test.go
new file mode 100644 (file)
index 0000000..b8ef648
--- /dev/null
@@ -0,0 +1,377 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode_test
+
+import (
+       "testing"
+       . "unicode"
+)
+
+var upperTest = []int{
+       0x41,
+       0xc0,
+       0xd8,
+       0x100,
+       0x139,
+       0x14a,
+       0x178,
+       0x181,
+       0x376,
+       0x3cf,
+       0x1f2a,
+       0x2102,
+       0x2c00,
+       0x2c10,
+       0x2c20,
+       0xa650,
+       0xa722,
+       0xff3a,
+       0x10400,
+       0x1d400,
+       0x1d7ca,
+}
+
+var notupperTest = []int{
+       0x40,
+       0x5b,
+       0x61,
+       0x185,
+       0x1b0,
+       0x377,
+       0x387,
+       0x2150,
+       0xffff,
+       0x10000,
+}
+
+var letterTest = []int{
+       0x41,
+       0x61,
+       0xaa,
+       0xba,
+       0xc8,
+       0xdb,
+       0xf9,
+       0x2ec,
+       0x535,
+       0x6e6,
+       0x93d,
+       0xa15,
+       0xb99,
+       0xdc0,
+       0xedd,
+       0x1000,
+       0x1200,
+       0x1312,
+       0x1401,
+       0x1885,
+       0x2c00,
+       0xa800,
+       0xf900,
+       0xfa30,
+       0xffda,
+       0xffdc,
+       0x10000,
+       0x10300,
+       0x10400,
+       0x20000,
+       0x2f800,
+       0x2fa1d,
+}
+
+var notletterTest = []int{
+       0x20,
+       0x35,
+       0x375,
+       0x620,
+       0x700,
+       0xfffe,
+       0x1ffff,
+       0x10ffff,
+}
+
+// Contains all the special cased Latin-1 chars.
+var spaceTest = []int{
+       0x09,
+       0x0a,
+       0x0b,
+       0x0c,
+       0x0d,
+       0x20,
+       0x85,
+       0xA0,
+       0x2000,
+       0x3000,
+}
+
+type caseT struct {
+       cas, in, out int
+}
+
+var caseTest = []caseT{
+       // errors
+       {-1, '\n', 0xFFFD},
+       {UpperCase, -1, -1},
+       {UpperCase, 1 << 30, 1 << 30},
+
+       // ASCII (special-cased so test carefully)
+       {UpperCase, '\n', '\n'},
+       {UpperCase, 'a', 'A'},
+       {UpperCase, 'A', 'A'},
+       {UpperCase, '7', '7'},
+       {LowerCase, '\n', '\n'},
+       {LowerCase, 'a', 'a'},
+       {LowerCase, 'A', 'a'},
+       {LowerCase, '7', '7'},
+       {TitleCase, '\n', '\n'},
+       {TitleCase, 'a', 'A'},
+       {TitleCase, 'A', 'A'},
+       {TitleCase, '7', '7'},
+
+       // Latin-1: easy to read the tests!
+       {UpperCase, 0x80, 0x80},
+       {UpperCase, 'Å', 'Å'},
+       {UpperCase, 'å', 'Å'},
+       {LowerCase, 0x80, 0x80},
+       {LowerCase, 'Å', 'å'},
+       {LowerCase, 'å', 'å'},
+       {TitleCase, 0x80, 0x80},
+       {TitleCase, 'Å', 'Å'},
+       {TitleCase, 'å', 'Å'},
+
+       // 0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049
+       {UpperCase, 0x0131, 'I'},
+       {LowerCase, 0x0131, 0x0131},
+       {TitleCase, 0x0131, 'I'},
+
+       // 0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132
+       {UpperCase, 0x0133, 0x0132},
+       {LowerCase, 0x0133, 0x0133},
+       {TitleCase, 0x0133, 0x0132},
+
+       // 212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;
+       {UpperCase, 0x212A, 0x212A},
+       {LowerCase, 0x212A, 'k'},
+       {TitleCase, 0x212A, 0x212A},
+
+       // From an UpperLower sequence
+       // A640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641;
+       {UpperCase, 0xA640, 0xA640},
+       {LowerCase, 0xA640, 0xA641},
+       {TitleCase, 0xA640, 0xA640},
+       // A641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640
+       {UpperCase, 0xA641, 0xA640},
+       {LowerCase, 0xA641, 0xA641},
+       {TitleCase, 0xA641, 0xA640},
+       // A64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F;
+       {UpperCase, 0xA64E, 0xA64E},
+       {LowerCase, 0xA64E, 0xA64F},
+       {TitleCase, 0xA64E, 0xA64E},
+       // A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E
+       {UpperCase, 0xA65F, 0xA65E},
+       {LowerCase, 0xA65F, 0xA65F},
+       {TitleCase, 0xA65F, 0xA65E},
+
+       // From another UpperLower sequence
+       // 0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;
+       {UpperCase, 0x0139, 0x0139},
+       {LowerCase, 0x0139, 0x013A},
+       {TitleCase, 0x0139, 0x0139},
+       // 013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;
+       {UpperCase, 0x013f, 0x013f},
+       {LowerCase, 0x013f, 0x0140},
+       {TitleCase, 0x013f, 0x013f},
+       // 0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147
+       {UpperCase, 0x0148, 0x0147},
+       {LowerCase, 0x0148, 0x0148},
+       {TitleCase, 0x0148, 0x0147},
+
+       // Last block in the 5.1.0 table
+       // 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
+       {UpperCase, 0x10400, 0x10400},
+       {LowerCase, 0x10400, 0x10428},
+       {TitleCase, 0x10400, 0x10400},
+       // 10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F;
+       {UpperCase, 0x10427, 0x10427},
+       {LowerCase, 0x10427, 0x1044F},
+       {TitleCase, 0x10427, 0x10427},
+       // 10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400
+       {UpperCase, 0x10428, 0x10400},
+       {LowerCase, 0x10428, 0x10428},
+       {TitleCase, 0x10428, 0x10400},
+       // 1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427
+       {UpperCase, 0x1044F, 0x10427},
+       {LowerCase, 0x1044F, 0x1044F},
+       {TitleCase, 0x1044F, 0x10427},
+
+       // First one not in the 5.1.0 table
+       // 10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;;
+       {UpperCase, 0x10450, 0x10450},
+       {LowerCase, 0x10450, 0x10450},
+       {TitleCase, 0x10450, 0x10450},
+}
+
+func TestIsLetter(t *testing.T) {
+       for _, r := range upperTest {
+               if !IsLetter(r) {
+                       t.Errorf("IsLetter(U+%04X) = false, want true", r)
+               }
+       }
+       for _, r := range letterTest {
+               if !IsLetter(r) {
+                       t.Errorf("IsLetter(U+%04X) = false, want true", r)
+               }
+       }
+       for _, r := range notletterTest {
+               if IsLetter(r) {
+                       t.Errorf("IsLetter(U+%04X) = true, want false", r)
+               }
+       }
+}
+
+func TestIsUpper(t *testing.T) {
+       for _, r := range upperTest {
+               if !IsUpper(r) {
+                       t.Errorf("IsUpper(U+%04X) = false, want true", r)
+               }
+       }
+       for _, r := range notupperTest {
+               if IsUpper(r) {
+                       t.Errorf("IsUpper(U+%04X) = true, want false", r)
+               }
+       }
+       for _, r := range notletterTest {
+               if IsUpper(r) {
+                       t.Errorf("IsUpper(U+%04X) = true, want false", r)
+               }
+       }
+}
+
+func caseString(c int) string {
+       switch c {
+       case UpperCase:
+               return "UpperCase"
+       case LowerCase:
+               return "LowerCase"
+       case TitleCase:
+               return "TitleCase"
+       }
+       return "ErrorCase"
+}
+
+func TestTo(t *testing.T) {
+       for _, c := range caseTest {
+               r := To(c.cas, c.in)
+               if c.out != r {
+                       t.Errorf("To(U+%04X, %s) = U+%04X want U+%04X", c.in, caseString(c.cas), r, c.out)
+               }
+       }
+}
+
+func TestToUpperCase(t *testing.T) {
+       for _, c := range caseTest {
+               if c.cas != UpperCase {
+                       continue
+               }
+               r := ToUpper(c.in)
+               if c.out != r {
+                       t.Errorf("ToUpper(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
+               }
+       }
+}
+
+func TestToLowerCase(t *testing.T) {
+       for _, c := range caseTest {
+               if c.cas != LowerCase {
+                       continue
+               }
+               r := ToLower(c.in)
+               if c.out != r {
+                       t.Errorf("ToLower(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
+               }
+       }
+}
+
+func TestToTitleCase(t *testing.T) {
+       for _, c := range caseTest {
+               if c.cas != TitleCase {
+                       continue
+               }
+               r := ToTitle(c.in)
+               if c.out != r {
+                       t.Errorf("ToTitle(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
+               }
+       }
+}
+
+func TestIsSpace(t *testing.T) {
+       for _, c := range spaceTest {
+               if !IsSpace(c) {
+                       t.Errorf("IsSpace(U+%04X) = false; want true", c)
+               }
+       }
+       for _, c := range letterTest {
+               if IsSpace(c) {
+                       t.Errorf("IsSpace(U+%04X) = true; want false", c)
+               }
+       }
+}
+
+// Check that the optimizations for IsLetter etc. agree with the tables.
+// We only need to check the Latin-1 range.
+func TestLetterOptimizations(t *testing.T) {
+       for i := 0; i < 0x100; i++ {
+               if Is(Letter, i) != IsLetter(i) {
+                       t.Errorf("IsLetter(U+%04X) disagrees with Is(Letter)", i)
+               }
+               if Is(Upper, i) != IsUpper(i) {
+                       t.Errorf("IsUpper(U+%04X) disagrees with Is(Upper)", i)
+               }
+               if Is(Lower, i) != IsLower(i) {
+                       t.Errorf("IsLower(U+%04X) disagrees with Is(Lower)", i)
+               }
+               if Is(Title, i) != IsTitle(i) {
+                       t.Errorf("IsTitle(U+%04X) disagrees with Is(Title)", i)
+               }
+               if Is(White_Space, i) != IsSpace(i) {
+                       t.Errorf("IsSpace(U+%04X) disagrees with Is(White_Space)", i)
+               }
+               if To(UpperCase, i) != ToUpper(i) {
+                       t.Errorf("ToUpper(U+%04X) disagrees with To(Upper)", i)
+               }
+               if To(LowerCase, i) != ToLower(i) {
+                       t.Errorf("ToLower(U+%04X) disagrees with To(Lower)", i)
+               }
+               if To(TitleCase, i) != ToTitle(i) {
+                       t.Errorf("ToTitle(U+%04X) disagrees with To(Title)", i)
+               }
+       }
+}
+
+func TestTurkishCase(t *testing.T) {
+       lower := []int("abcçdefgğhıijklmnoöprsştuüvyz")
+       upper := []int("ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ")
+       for i, l := range lower {
+               u := upper[i]
+               if TurkishCase.ToLower(l) != l {
+                       t.Errorf("lower(U+%04X) is U+%04X not U+%04X", l, TurkishCase.ToLower(l), l)
+               }
+               if TurkishCase.ToUpper(u) != u {
+                       t.Errorf("upper(U+%04X) is U+%04X not U+%04X", u, TurkishCase.ToUpper(u), u)
+               }
+               if TurkishCase.ToUpper(l) != u {
+                       t.Errorf("upper(U+%04X) is U+%04X not U+%04X", l, TurkishCase.ToUpper(l), u)
+               }
+               if TurkishCase.ToLower(u) != l {
+                       t.Errorf("lower(U+%04X) is U+%04X not U+%04X", u, TurkishCase.ToLower(l), l)
+               }
+               if TurkishCase.ToTitle(u) != u {
+                       t.Errorf("title(U+%04X) is U+%04X not U+%04X", u, TurkishCase.ToTitle(u), u)
+               }
+               if TurkishCase.ToTitle(l) != u {
+                       t.Errorf("title(U+%04X) is U+%04X not U+%04X", l, TurkishCase.ToTitle(l), u)
+               }
+       }
+}
diff --git a/libgo/go/unicode/script_test.go b/libgo/go/unicode/script_test.go
new file mode 100644 (file)
index 0000000..ffdc40d
--- /dev/null
@@ -0,0 +1,247 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode_test
+
+import (
+       "testing"
+       . "unicode"
+)
+
+type T struct {
+       rune   int
+       script string
+}
+
+// Hand-chosen tests from Unicode 5.1.0, mostly to discover when new
+// scripts and categories arise.
+var inTest = []T{
+       {0x06e2, "Arabic"},
+       {0x0567, "Armenian"},
+       {0x10b20, "Avestan"},
+       {0x1b37, "Balinese"},
+       {0xa6af, "Bamum"},
+       {0x09c2, "Bengali"},
+       {0x3115, "Bopomofo"},
+       {0x282d, "Braille"},
+       {0x1a1a, "Buginese"},
+       {0x1747, "Buhid"},
+       {0x156d, "Canadian_Aboriginal"},
+       {0x102a9, "Carian"},
+       {0xaa4d, "Cham"},
+       {0x13c2, "Cherokee"},
+       {0x0020, "Common"},
+       {0x1d4a5, "Common"},
+       {0x2cfc, "Coptic"},
+       {0x12420, "Cuneiform"},
+       {0x1080c, "Cypriot"},
+       {0xa663, "Cyrillic"},
+       {0x10430, "Deseret"},
+       {0x094a, "Devanagari"},
+       {0x13001, "Egyptian_Hieroglyphs"},
+       {0x1271, "Ethiopic"},
+       {0x10fc, "Georgian"},
+       {0x2c40, "Glagolitic"},
+       {0x10347, "Gothic"},
+       {0x03ae, "Greek"},
+       {0x0abf, "Gujarati"},
+       {0x0a24, "Gurmukhi"},
+       {0x3028, "Han"},
+       {0x11b8, "Hangul"},
+       {0x1727, "Hanunoo"},
+       {0x05a0, "Hebrew"},
+       {0x3058, "Hiragana"},
+       {0x10841, "Imperial_Aramaic"},
+       {0x20e6, "Inherited"},
+       {0x10b70, "Inscriptional_Pahlavi"},
+       {0x10b5a, "Inscriptional_Parthian"},
+       {0xa9d0, "Javanese"},
+       {0x1109f, "Kaithi"},
+       {0x0cbd, "Kannada"},
+       {0x30a6, "Katakana"},
+       {0xa928, "Kayah_Li"},
+       {0x10a11, "Kharoshthi"},
+       {0x17c6, "Khmer"},
+       {0x0eaa, "Lao"},
+       {0x1d79, "Latin"},
+       {0x1c10, "Lepcha"},
+       {0x1930, "Limbu"},
+       {0x1003c, "Linear_B"},
+       {0xa4e1, "Lisu"},
+       {0x10290, "Lycian"},
+       {0x10930, "Lydian"},
+       {0x0d42, "Malayalam"},
+       {0xabd0, "Meetei_Mayek"},
+       {0x1822, "Mongolian"},
+       {0x104c, "Myanmar"},
+       {0x19c3, "New_Tai_Lue"},
+       {0x07f8, "Nko"},
+       {0x169b, "Ogham"},
+       {0x1c6a, "Ol_Chiki"},
+       {0x10310, "Old_Italic"},
+       {0x103c9, "Old_Persian"},
+       {0x10a6f, "Old_South_Arabian"},
+       {0x10c20, "Old_Turkic"},
+       {0x0b3e, "Oriya"},
+       {0x10491, "Osmanya"},
+       {0xa860, "Phags_Pa"},
+       {0x10918, "Phoenician"},
+       {0xa949, "Rejang"},
+       {0x16c0, "Runic"},
+       {0x081d, "Samaritan"},
+       {0xa892, "Saurashtra"},
+       {0x10463, "Shavian"},
+       {0x0dbd, "Sinhala"},
+       {0x1ba3, "Sundanese"},
+       {0xa803, "Syloti_Nagri"},
+       {0x070f, "Syriac"},
+       {0x170f, "Tagalog"},
+       {0x176f, "Tagbanwa"},
+       {0x1972, "Tai_Le"},
+       {0x1a62, "Tai_Tham"},
+       {0xaadc, "Tai_Viet"},
+       {0x0bbf, "Tamil"},
+       {0x0c55, "Telugu"},
+       {0x07a7, "Thaana"},
+       {0x0e46, "Thai"},
+       {0x0f36, "Tibetan"},
+       {0x2d55, "Tifinagh"},
+       {0x10388, "Ugaritic"},
+       {0xa60e, "Vai"},
+       {0xa216, "Yi"},
+}
+
+var outTest = []T{ // not really worth being thorough
+       {0x20, "Telugu"},
+}
+
+var inCategoryTest = []T{
+       {0x0081, "Cc"},
+       {0x17b4, "Cf"},
+       {0xf0000, "Co"},
+       {0xdb80, "Cs"},
+       {0x0236, "Ll"},
+       {0x1d9d, "Lm"},
+       {0x07cf, "Lo"},
+       {0x1f8a, "Lt"},
+       {0x03ff, "Lu"},
+       {0x0bc1, "Mc"},
+       {0x20df, "Me"},
+       {0x07f0, "Mn"},
+       {0x1bb2, "Nd"},
+       {0x10147, "Nl"},
+       {0x2478, "No"},
+       {0xfe33, "Pc"},
+       {0x2011, "Pd"},
+       {0x301e, "Pe"},
+       {0x2e03, "Pf"},
+       {0x2e02, "Pi"},
+       {0x0022, "Po"},
+       {0x2770, "Ps"},
+       {0x00a4, "Sc"},
+       {0xa711, "Sk"},
+       {0x25f9, "Sm"},
+       {0x2108, "So"},
+       {0x2028, "Zl"},
+       {0x2029, "Zp"},
+       {0x202f, "Zs"},
+       {0x04aa, "letter"},
+}
+
+var inPropTest = []T{
+       {0x0046, "ASCII_Hex_Digit"},
+       {0x200F, "Bidi_Control"},
+       {0x2212, "Dash"},
+       {0xE0001, "Deprecated"},
+       {0x00B7, "Diacritic"},
+       {0x30FE, "Extender"},
+       {0xFF46, "Hex_Digit"},
+       {0x2E17, "Hyphen"},
+       {0x2FFB, "IDS_Binary_Operator"},
+       {0x2FF3, "IDS_Trinary_Operator"},
+       {0xFA6A, "Ideographic"},
+       {0x200D, "Join_Control"},
+       {0x0EC4, "Logical_Order_Exception"},
+       {0x2FFFF, "Noncharacter_Code_Point"},
+       {0x065E, "Other_Alphabetic"},
+       {0x2069, "Other_Default_Ignorable_Code_Point"},
+       {0x0BD7, "Other_Grapheme_Extend"},
+       {0x0387, "Other_ID_Continue"},
+       {0x212E, "Other_ID_Start"},
+       {0x2094, "Other_Lowercase"},
+       {0x2040, "Other_Math"},
+       {0x216F, "Other_Uppercase"},
+       {0x0027, "Pattern_Syntax"},
+       {0x0020, "Pattern_White_Space"},
+       {0x300D, "Quotation_Mark"},
+       {0x2EF3, "Radical"},
+       {0x061F, "STerm"},
+       {0x2071, "Soft_Dotted"},
+       {0x003A, "Terminal_Punctuation"},
+       {0x9FC3, "Unified_Ideograph"},
+       {0xFE0F, "Variation_Selector"},
+       {0x0020, "White_Space"},
+}
+
+func TestScripts(t *testing.T) {
+       notTested := make(map[string]bool)
+       for k := range Scripts {
+               notTested[k] = true
+       }
+       for _, test := range inTest {
+               if _, ok := Scripts[test.script]; !ok {
+                       t.Fatal(test.script, "not a known script")
+               }
+               if !Is(Scripts[test.script], test.rune) {
+                       t.Errorf("IsScript(%#x, %s) = false, want true", test.rune, test.script)
+               }
+               notTested[test.script] = false, false
+       }
+       for _, test := range outTest {
+               if Is(Scripts[test.script], test.rune) {
+                       t.Errorf("IsScript(%#x, %s) = true, want false", test.rune, test.script)
+               }
+       }
+       for k := range notTested {
+               t.Error("not tested:", k)
+       }
+}
+
+func TestCategories(t *testing.T) {
+       notTested := make(map[string]bool)
+       for k := range Categories {
+               notTested[k] = true
+       }
+       for _, test := range inCategoryTest {
+               if _, ok := Categories[test.script]; !ok {
+                       t.Fatal(test.script, "not a known category")
+               }
+               if !Is(Categories[test.script], test.rune) {
+                       t.Errorf("IsCategory(%#x, %s) = false, want true", test.rune, test.script)
+               }
+               notTested[test.script] = false, false
+       }
+       for k := range notTested {
+               t.Error("not tested:", k)
+       }
+}
+
+func TestProperties(t *testing.T) {
+       notTested := make(map[string]bool)
+       for k := range Properties {
+               notTested[k] = true
+       }
+       for _, test := range inPropTest {
+               if _, ok := Properties[test.script]; !ok {
+                       t.Fatal(test.script, "not a known prop")
+               }
+               if !Is(Properties[test.script], test.rune) {
+                       t.Errorf("IsCategory(%#x, %s) = false, want true", test.rune, test.script)
+               }
+               notTested[test.script] = false, false
+       }
+       for k := range notTested {
+               t.Error("not tested:", k)
+       }
+}
diff --git a/libgo/go/unicode/tables.go b/libgo/go/unicode/tables.go
new file mode 100644 (file)
index 0000000..b56c9bd
--- /dev/null
@@ -0,0 +1,4238 @@
+// Generated by running
+//     maketables --tables=all --data=http://www.unicode.org/Public/5.2.0/ucd/UnicodeData.txt
+// DO NOT EDIT
+
+package unicode
+
+// Version is the Unicode edition from which the tables are derived.
+const Version = "5.2.0"
+
+// Categories is the set of Unicode data tables.
+var Categories = map[string][]Range{
+       "Lm":     Lm,
+       "Ll":     Ll,
+       "Me":     Me,
+       "Mc":     Mc,
+       "Mn":     Mn,
+       "Zl":     Zl,
+       "letter": letter,
+       "Zp":     Zp,
+       "Zs":     Zs,
+       "Cs":     Cs,
+       "Co":     Co,
+       "Cf":     Cf,
+       "Cc":     Cc,
+       "Po":     Po,
+       "Pi":     Pi,
+       "Pf":     Pf,
+       "Pe":     Pe,
+       "Pd":     Pd,
+       "Pc":     Pc,
+       "Ps":     Ps,
+       "Nd":     Nd,
+       "Nl":     Nl,
+       "No":     No,
+       "So":     So,
+       "Sm":     Sm,
+       "Sk":     Sk,
+       "Sc":     Sc,
+       "Lu":     Lu,
+       "Lt":     Lt,
+       "Lo":     Lo,
+}
+
+var _Lm = []Range{
+       {0x02b0, 0x02c1, 1},
+       {0x02c6, 0x02d1, 1},
+       {0x02e0, 0x02e4, 1},
+       {0x02ec, 0x02ee, 2},
+       {0x0374, 0x037a, 6},
+       {0x0559, 0x0640, 231},
+       {0x06e5, 0x06e6, 1},
+       {0x07f4, 0x07f5, 1},
+       {0x07fa, 0x081a, 32},
+       {0x0824, 0x0828, 4},
+       {0x0971, 0x0e46, 1237},
+       {0x0ec6, 0x10fc, 566},
+       {0x17d7, 0x1843, 108},
+       {0x1aa7, 0x1c78, 465},
+       {0x1c79, 0x1c7d, 1},
+       {0x1d2c, 0x1d61, 1},
+       {0x1d78, 0x1d9b, 35},
+       {0x1d9c, 0x1dbf, 1},
+       {0x2071, 0x207f, 14},
+       {0x2090, 0x2094, 1},
+       {0x2c7d, 0x2d6f, 242},
+       {0x2e2f, 0x3005, 470},
+       {0x3031, 0x3035, 1},
+       {0x303b, 0x309d, 98},
+       {0x309e, 0x30fc, 94},
+       {0x30fd, 0x30fe, 1},
+       {0xa015, 0xa4f8, 1251},
+       {0xa4f9, 0xa4fd, 1},
+       {0xa60c, 0xa67f, 115},
+       {0xa717, 0xa71f, 1},
+       {0xa770, 0xa788, 24},
+       {0xa9cf, 0xaa70, 161},
+       {0xaadd, 0xff70, 21651},
+       {0xff9e, 0xff9f, 1},
+}
+
+var _Ll = []Range{
+       {0x0061, 0x007a, 1},
+       {0x00aa, 0x00b5, 11},
+       {0x00ba, 0x00df, 37},
+       {0x00e0, 0x00f6, 1},
+       {0x00f8, 0x00ff, 1},
+       {0x0101, 0x0137, 2},
+       {0x0138, 0x0148, 2},
+       {0x0149, 0x0177, 2},
+       {0x017a, 0x017e, 2},
+       {0x017f, 0x0180, 1},
+       {0x0183, 0x0185, 2},
+       {0x0188, 0x018c, 4},
+       {0x018d, 0x0192, 5},
+       {0x0195, 0x0199, 4},
+       {0x019a, 0x019b, 1},
+       {0x019e, 0x01a1, 3},
+       {0x01a3, 0x01a5, 2},
+       {0x01a8, 0x01aa, 2},
+       {0x01ab, 0x01ad, 2},
+       {0x01b0, 0x01b4, 4},
+       {0x01b6, 0x01b9, 3},
+       {0x01ba, 0x01bd, 3},
+       {0x01be, 0x01bf, 1},
+       {0x01c6, 0x01cc, 3},
+       {0x01ce, 0x01dc, 2},
+       {0x01dd, 0x01ef, 2},
+       {0x01f0, 0x01f3, 3},
+       {0x01f5, 0x01f9, 4},
+       {0x01fb, 0x0233, 2},
+       {0x0234, 0x0239, 1},
+       {0x023c, 0x023f, 3},
+       {0x0240, 0x0242, 2},
+       {0x0247, 0x024f, 2},
+       {0x0250, 0x0293, 1},
+       {0x0295, 0x02af, 1},
+       {0x0371, 0x0373, 2},
+       {0x0377, 0x037b, 4},
+       {0x037c, 0x037d, 1},
+       {0x0390, 0x03ac, 28},
+       {0x03ad, 0x03ce, 1},
+       {0x03d0, 0x03d1, 1},
+       {0x03d5, 0x03d7, 1},
+       {0x03d9, 0x03ef, 2},
+       {0x03f0, 0x03f3, 1},
+       {0x03f5, 0x03fb, 3},
+       {0x03fc, 0x0430, 52},
+       {0x0431, 0x045f, 1},
+       {0x0461, 0x0481, 2},
+       {0x048b, 0x04bf, 2},
+       {0x04c2, 0x04ce, 2},
+       {0x04cf, 0x0525, 2},
+       {0x0561, 0x0587, 1},
+       {0x1d00, 0x1d2b, 1},
+       {0x1d62, 0x1d77, 1},
+       {0x1d79, 0x1d9a, 1},
+       {0x1e01, 0x1e95, 2},
+       {0x1e96, 0x1e9d, 1},
+       {0x1e9f, 0x1eff, 2},
+       {0x1f00, 0x1f07, 1},
+       {0x1f10, 0x1f15, 1},
+       {0x1f20, 0x1f27, 1},
+       {0x1f30, 0x1f37, 1},
+       {0x1f40, 0x1f45, 1},
+       {0x1f50, 0x1f57, 1},
+       {0x1f60, 0x1f67, 1},
+       {0x1f70, 0x1f7d, 1},
+       {0x1f80, 0x1f87, 1},
+       {0x1f90, 0x1f97, 1},
+       {0x1fa0, 0x1fa7, 1},
+       {0x1fb0, 0x1fb4, 1},
+       {0x1fb6, 0x1fb7, 1},
+       {0x1fbe, 0x1fc2, 4},
+       {0x1fc3, 0x1fc4, 1},
+       {0x1fc6, 0x1fc7, 1},
+       {0x1fd0, 0x1fd3, 1},
+       {0x1fd6, 0x1fd7, 1},
+       {0x1fe0, 0x1fe7, 1},
+       {0x1ff2, 0x1ff4, 1},
+       {0x1ff6, 0x1ff7, 1},
+       {0x210a, 0x210e, 4},
+       {0x210f, 0x2113, 4},
+       {0x212f, 0x2139, 5},
+       {0x213c, 0x213d, 1},
+       {0x2146, 0x2149, 1},
+       {0x214e, 0x2184, 54},
+       {0x2c30, 0x2c5e, 1},
+       {0x2c61, 0x2c65, 4},
+       {0x2c66, 0x2c6c, 2},
+       {0x2c71, 0x2c73, 2},
+       {0x2c74, 0x2c76, 2},
+       {0x2c77, 0x2c7c, 1},
+       {0x2c81, 0x2ce3, 2},
+       {0x2ce4, 0x2cec, 8},
+       {0x2cee, 0x2d00, 18},
+       {0x2d01, 0x2d25, 1},
+       {0xa641, 0xa65f, 2},
+       {0xa663, 0xa66d, 2},
+       {0xa681, 0xa697, 2},
+       {0xa723, 0xa72f, 2},
+       {0xa730, 0xa731, 1},
+       {0xa733, 0xa771, 2},
+       {0xa772, 0xa778, 1},
+       {0xa77a, 0xa77c, 2},
+       {0xa77f, 0xa787, 2},
+       {0xa78c, 0xfb00, 21364},
+       {0xfb01, 0xfb06, 1},
+       {0xfb13, 0xfb17, 1},
+       {0xff41, 0xff5a, 1},
+       {0x10428, 0x1044f, 1},
+       {0x1d41a, 0x1d433, 1},
+       {0x1d44e, 0x1d454, 1},
+       {0x1d456, 0x1d467, 1},
+       {0x1d482, 0x1d49b, 1},
+       {0x1d4b6, 0x1d4b9, 1},
+       {0x1d4bb, 0x1d4bd, 2},
+       {0x1d4be, 0x1d4c3, 1},
+       {0x1d4c5, 0x1d4cf, 1},
+       {0x1d4ea, 0x1d503, 1},
+       {0x1d51e, 0x1d537, 1},
+       {0x1d552, 0x1d56b, 1},
+       {0x1d586, 0x1d59f, 1},
+       {0x1d5ba, 0x1d5d3, 1},
+       {0x1d5ee, 0x1d607, 1},
+       {0x1d622, 0x1d63b, 1},
+       {0x1d656, 0x1d66f, 1},
+       {0x1d68a, 0x1d6a5, 1},
+       {0x1d6c2, 0x1d6da, 1},
+       {0x1d6dc, 0x1d6e1, 1},
+       {0x1d6fc, 0x1d714, 1},
+       {0x1d716, 0x1d71b, 1},
+       {0x1d736, 0x1d74e, 1},
+       {0x1d750, 0x1d755, 1},
+       {0x1d770, 0x1d788, 1},
+       {0x1d78a, 0x1d78f, 1},
+       {0x1d7aa, 0x1d7c2, 1},
+       {0x1d7c4, 0x1d7c9, 1},
+       {0x1d7cb, 0x1d7cb, 1},
+}
+
+var _Me = []Range{
+       {0x0488, 0x0489, 1},
+       {0x06de, 0x20dd, 6655},
+       {0x20de, 0x20e0, 1},
+       {0x20e2, 0x20e4, 1},
+       {0xa670, 0xa672, 1},
+}
+
+var _Mc = []Range{
+       {0x0903, 0x093e, 59},
+       {0x093f, 0x0940, 1},
+       {0x0949, 0x094c, 1},
+       {0x094e, 0x0982, 52},
+       {0x0983, 0x09be, 59},
+       {0x09bf, 0x09c0, 1},
+       {0x09c7, 0x09c8, 1},
+       {0x09cb, 0x09cc, 1},
+       {0x09d7, 0x0a03, 44},
+       {0x0a3e, 0x0a40, 1},
+       {0x0a83, 0x0abe, 59},
+       {0x0abf, 0x0ac0, 1},
+       {0x0ac9, 0x0acb, 2},
+       {0x0acc, 0x0b02, 54},
+       {0x0b03, 0x0b3e, 59},
+       {0x0b40, 0x0b47, 7},
+       {0x0b48, 0x0b4b, 3},
+       {0x0b4c, 0x0b57, 11},
+       {0x0bbe, 0x0bbf, 1},
+       {0x0bc1, 0x0bc2, 1},
+       {0x0bc6, 0x0bc8, 1},
+       {0x0bca, 0x0bcc, 1},
+       {0x0bd7, 0x0c01, 42},
+       {0x0c02, 0x0c03, 1},
+       {0x0c41, 0x0c44, 1},
+       {0x0c82, 0x0c83, 1},
+       {0x0cbe, 0x0cc0, 2},
+       {0x0cc1, 0x0cc4, 1},
+       {0x0cc7, 0x0cc8, 1},
+       {0x0cca, 0x0ccb, 1},
+       {0x0cd5, 0x0cd6, 1},
+       {0x0d02, 0x0d03, 1},
+       {0x0d3e, 0x0d40, 1},
+       {0x0d46, 0x0d48, 1},
+       {0x0d4a, 0x0d4c, 1},
+       {0x0d57, 0x0d82, 43},
+       {0x0d83, 0x0dcf, 76},
+       {0x0dd0, 0x0dd1, 1},
+       {0x0dd8, 0x0ddf, 1},
+       {0x0df2, 0x0df3, 1},
+       {0x0f3e, 0x0f3f, 1},
+       {0x0f7f, 0x102b, 172},
+       {0x102c, 0x1031, 5},
+       {0x1038, 0x103b, 3},
+       {0x103c, 0x1056, 26},
+       {0x1057, 0x1062, 11},
+       {0x1063, 0x1064, 1},
+       {0x1067, 0x106d, 1},
+       {0x1083, 0x1084, 1},
+       {0x1087, 0x108c, 1},
+       {0x108f, 0x109a, 11},
+       {0x109b, 0x109c, 1},
+       {0x17b6, 0x17be, 8},
+       {0x17bf, 0x17c5, 1},
+       {0x17c7, 0x17c8, 1},
+       {0x1923, 0x1926, 1},
+       {0x1929, 0x192b, 1},
+       {0x1930, 0x1931, 1},
+       {0x1933, 0x1938, 1},
+       {0x19b0, 0x19c0, 1},
+       {0x19c8, 0x19c9, 1},
+       {0x1a19, 0x1a1b, 1},
+       {0x1a55, 0x1a57, 2},
+       {0x1a61, 0x1a63, 2},
+       {0x1a64, 0x1a6d, 9},
+       {0x1a6e, 0x1a72, 1},
+       {0x1b04, 0x1b35, 49},
+       {0x1b3b, 0x1b3d, 2},
+       {0x1b3e, 0x1b41, 1},
+       {0x1b43, 0x1b44, 1},
+       {0x1b82, 0x1ba1, 31},
+       {0x1ba6, 0x1ba7, 1},
+       {0x1baa, 0x1c24, 122},
+       {0x1c25, 0x1c2b, 1},
+       {0x1c34, 0x1c35, 1},
+       {0x1ce1, 0x1cf2, 17},
+       {0xa823, 0xa824, 1},
+       {0xa827, 0xa880, 89},
+       {0xa881, 0xa8b4, 51},
+       {0xa8b5, 0xa8c3, 1},
+       {0xa952, 0xa953, 1},
+       {0xa983, 0xa9b4, 49},
+       {0xa9b5, 0xa9ba, 5},
+       {0xa9bb, 0xa9bd, 2},
+       {0xa9be, 0xa9c0, 1},
+       {0xaa2f, 0xaa30, 1},
+       {0xaa33, 0xaa34, 1},
+       {0xaa4d, 0xaa7b, 46},
+       {0xabe3, 0xabe4, 1},
+       {0xabe6, 0xabe7, 1},
+       {0xabe9, 0xabea, 1},
+       {0xabec, 0x11082, 25750},
+       {0x110b0, 0x110b2, 1},
+       {0x110b7, 0x110b8, 1},
+       {0x1d165, 0x1d166, 1},
+       {0x1d16d, 0x1d172, 1},
+}
+
+var _Mn = []Range{
+       {0x0300, 0x036f, 1},
+       {0x0483, 0x0487, 1},
+       {0x0591, 0x05bd, 1},
+       {0x05bf, 0x05c1, 2},
+       {0x05c2, 0x05c4, 2},
+       {0x05c5, 0x05c7, 2},
+       {0x0610, 0x061a, 1},
+       {0x064b, 0x065e, 1},
+       {0x0670, 0x06d6, 102},
+       {0x06d7, 0x06dc, 1},
+       {0x06df, 0x06e4, 1},
+       {0x06e7, 0x06e8, 1},
+       {0x06ea, 0x06ed, 1},
+       {0x0711, 0x0730, 31},
+       {0x0731, 0x074a, 1},
+       {0x07a6, 0x07b0, 1},
+       {0x07eb, 0x07f3, 1},
+       {0x0816, 0x0819, 1},
+       {0x081b, 0x0823, 1},
+       {0x0825, 0x0827, 1},
+       {0x0829, 0x082d, 1},
+       {0x0900, 0x0902, 1},
+       {0x093c, 0x0941, 5},
+       {0x0942, 0x0948, 1},
+       {0x094d, 0x0951, 4},
+       {0x0952, 0x0955, 1},
+       {0x0962, 0x0963, 1},
+       {0x0981, 0x09bc, 59},
+       {0x09c1, 0x09c4, 1},
+       {0x09cd, 0x09e2, 21},
+       {0x09e3, 0x0a01, 30},
+       {0x0a02, 0x0a3c, 58},
+       {0x0a41, 0x0a42, 1},
+       {0x0a47, 0x0a48, 1},
+       {0x0a4b, 0x0a4d, 1},
+       {0x0a51, 0x0a70, 31},
+       {0x0a71, 0x0a75, 4},
+       {0x0a81, 0x0a82, 1},
+       {0x0abc, 0x0ac1, 5},
+       {0x0ac2, 0x0ac5, 1},
+       {0x0ac7, 0x0ac8, 1},
+       {0x0acd, 0x0ae2, 21},
+       {0x0ae3, 0x0b01, 30},
+       {0x0b3c, 0x0b3f, 3},
+       {0x0b41, 0x0b44, 1},
+       {0x0b4d, 0x0b56, 9},
+       {0x0b62, 0x0b63, 1},
+       {0x0b82, 0x0bc0, 62},
+       {0x0bcd, 0x0c3e, 113},
+       {0x0c3f, 0x0c40, 1},
+       {0x0c46, 0x0c48, 1},
+       {0x0c4a, 0x0c4d, 1},
+       {0x0c55, 0x0c56, 1},
+       {0x0c62, 0x0c63, 1},
+       {0x0cbc, 0x0cbf, 3},
+       {0x0cc6, 0x0ccc, 6},
+       {0x0ccd, 0x0ce2, 21},
+       {0x0ce3, 0x0d41, 94},
+       {0x0d42, 0x0d44, 1},
+       {0x0d4d, 0x0d62, 21},
+       {0x0d63, 0x0dca, 103},
+       {0x0dd2, 0x0dd4, 1},
+       {0x0dd6, 0x0e31, 91},
+       {0x0e34, 0x0e3a, 1},
+       {0x0e47, 0x0e4e, 1},
+       {0x0eb1, 0x0eb4, 3},
+       {0x0eb5, 0x0eb9, 1},
+       {0x0ebb, 0x0ebc, 1},
+       {0x0ec8, 0x0ecd, 1},
+       {0x0f18, 0x0f19, 1},
+       {0x0f35, 0x0f39, 2},
+       {0x0f71, 0x0f7e, 1},
+       {0x0f80, 0x0f84, 1},
+       {0x0f86, 0x0f87, 1},
+       {0x0f90, 0x0f97, 1},
+       {0x0f99, 0x0fbc, 1},
+       {0x0fc6, 0x102d, 103},
+       {0x102e, 0x1030, 1},
+       {0x1032, 0x1037, 1},
+       {0x1039, 0x103a, 1},
+       {0x103d, 0x103e, 1},
+       {0x1058, 0x1059, 1},
+       {0x105e, 0x1060, 1},
+       {0x1071, 0x1074, 1},
+       {0x1082, 0x1085, 3},
+       {0x1086, 0x108d, 7},
+       {0x109d, 0x135f, 706},
+       {0x1712, 0x1714, 1},
+       {0x1732, 0x1734, 1},
+       {0x1752, 0x1753, 1},
+       {0x1772, 0x1773, 1},
+       {0x17b7, 0x17bd, 1},
+       {0x17c6, 0x17c9, 3},
+       {0x17ca, 0x17d3, 1},
+       {0x17dd, 0x180b, 46},
+       {0x180c, 0x180d, 1},
+       {0x18a9, 0x1920, 119},
+       {0x1921, 0x1922, 1},
+       {0x1927, 0x1928, 1},
+       {0x1932, 0x1939, 7},
+       {0x193a, 0x193b, 1},
+       {0x1a17, 0x1a18, 1},
+       {0x1a56, 0x1a58, 2},
+       {0x1a59, 0x1a5e, 1},
+       {0x1a60, 0x1a62, 2},
+       {0x1a65, 0x1a6c, 1},
+       {0x1a73, 0x1a7c, 1},
+       {0x1a7f, 0x1b00, 129},
+       {0x1b01, 0x1b03, 1},
+       {0x1b34, 0x1b36, 2},
+       {0x1b37, 0x1b3a, 1},
+       {0x1b3c, 0x1b42, 6},
+       {0x1b6b, 0x1b73, 1},
+       {0x1b80, 0x1b81, 1},
+       {0x1ba2, 0x1ba5, 1},
+       {0x1ba8, 0x1ba9, 1},
+       {0x1c2c, 0x1c33, 1},
+       {0x1c36, 0x1c37, 1},
+       {0x1cd0, 0x1cd2, 1},
+       {0x1cd4, 0x1ce0, 1},
+       {0x1ce2, 0x1ce8, 1},
+       {0x1ced, 0x1dc0, 211},
+       {0x1dc1, 0x1de6, 1},
+       {0x1dfd, 0x1dff, 1},
+       {0x20d0, 0x20dc, 1},
+       {0x20e1, 0x20e5, 4},
+       {0x20e6, 0x20f0, 1},
+       {0x2cef, 0x2cf1, 1},
+       {0x2de0, 0x2dff, 1},
+       {0x302a, 0x302f, 1},
+       {0x3099, 0x309a, 1},
+       {0xa66f, 0xa67c, 13},
+       {0xa67d, 0xa6f0, 115},
+       {0xa6f1, 0xa802, 273},
+       {0xa806, 0xa80b, 5},
+       {0xa825, 0xa826, 1},
+       {0xa8c4, 0xa8e0, 28},
+       {0xa8e1, 0xa8f1, 1},
+       {0xa926, 0xa92d, 1},
+       {0xa947, 0xa951, 1},
+       {0xa980, 0xa982, 1},
+       {0xa9b3, 0xa9b6, 3},
+       {0xa9b7, 0xa9b9, 1},
+       {0xa9bc, 0xaa29, 109},
+       {0xaa2a, 0xaa2e, 1},
+       {0xaa31, 0xaa32, 1},
+       {0xaa35, 0xaa36, 1},
+       {0xaa43, 0xaa4c, 9},
+       {0xaab0, 0xaab2, 2},
+       {0xaab3, 0xaab4, 1},
+       {0xaab7, 0xaab8, 1},
+       {0xaabe, 0xaabf, 1},
+       {0xaac1, 0xabe5, 292},
+       {0xabe8, 0xabed, 5},
+       {0xfb1e, 0xfe00, 738},
+       {0xfe01, 0xfe0f, 1},
+       {0xfe20, 0xfe26, 1},
+       {0x101fd, 0x10a01, 2052},
+       {0x10a02, 0x10a03, 1},
+       {0x10a05, 0x10a06, 1},
+       {0x10a0c, 0x10a0f, 1},
+       {0x10a38, 0x10a3a, 1},
+       {0x10a3f, 0x11080, 1601},
+       {0x11081, 0x110b3, 50},
+       {0x110b4, 0x110b6, 1},
+       {0x110b9, 0x110ba, 1},
+       {0x1d167, 0x1d169, 1},
+       {0x1d17b, 0x1d182, 1},
+       {0x1d185, 0x1d18b, 1},
+       {0x1d1aa, 0x1d1ad, 1},
+       {0x1d242, 0x1d244, 1},
+       {0xe0100, 0xe01ef, 1},
+}
+
+var _Zl = []Range{
+       {0x2028, 0x2028, 1},
+}
+
+var letter = []Range{
+       {0x0041, 0x005a, 1},
+       {0x0061, 0x007a, 1},
+       {0x00aa, 0x00b5, 11},
+       {0x00ba, 0x00c0, 6},
+       {0x00c1, 0x00d6, 1},
+       {0x00d8, 0x00f6, 1},
+       {0x00f8, 0x02c1, 1},
+       {0x02c6, 0x02d1, 1},
+       {0x02e0, 0x02e4, 1},
+       {0x02ec, 0x02ee, 2},
+       {0x0370, 0x0374, 1},
+       {0x0376, 0x0377, 1},
+       {0x037a, 0x037d, 1},
+       {0x0386, 0x0388, 2},
+       {0x0389, 0x038a, 1},
+       {0x038c, 0x038e, 2},
+       {0x038f, 0x03a1, 1},
+       {0x03a3, 0x03f5, 1},
+       {0x03f7, 0x0481, 1},
+       {0x048a, 0x0525, 1},
+       {0x0531, 0x0556, 1},
+       {0x0559, 0x0561, 8},
+       {0x0562, 0x0587, 1},
+       {0x05d0, 0x05ea, 1},
+       {0x05f0, 0x05f2, 1},
+       {0x0621, 0x064a, 1},
+       {0x066e, 0x066f, 1},
+       {0x0671, 0x06d3, 1},
+       {0x06d5, 0x06e5, 16},
+       {0x06e6, 0x06ee, 8},
+       {0x06ef, 0x06fa, 11},
+       {0x06fb, 0x06fc, 1},
+       {0x06ff, 0x0710, 17},
+       {0x0712, 0x072f, 1},
+       {0x074d, 0x07a5, 1},
+       {0x07b1, 0x07ca, 25},
+       {0x07cb, 0x07ea, 1},
+       {0x07f4, 0x07f5, 1},
+       {0x07fa, 0x0800, 6},
+       {0x0801, 0x0815, 1},
+       {0x081a, 0x0824, 10},
+       {0x0828, 0x0904, 220},
+       {0x0905, 0x0939, 1},
+       {0x093d, 0x0950, 19},
+       {0x0958, 0x0961, 1},
+       {0x0971, 0x0972, 1},
+       {0x0979, 0x097f, 1},
+       {0x0985, 0x098c, 1},
+       {0x098f, 0x0990, 1},
+       {0x0993, 0x09a8, 1},
+       {0x09aa, 0x09b0, 1},
+       {0x09b2, 0x09b6, 4},
+       {0x09b7, 0x09b9, 1},
+       {0x09bd, 0x09ce, 17},
+       {0x09dc, 0x09dd, 1},
+       {0x09df, 0x09e1, 1},
+       {0x09f0, 0x09f1, 1},
+       {0x0a05, 0x0a0a, 1},
+       {0x0a0f, 0x0a10, 1},
+       {0x0a13, 0x0a28, 1},
+       {0x0a2a, 0x0a30, 1},
+       {0x0a32, 0x0a33, 1},
+       {0x0a35, 0x0a36, 1},
+       {0x0a38, 0x0a39, 1},
+       {0x0a59, 0x0a5c, 1},
+       {0x0a5e, 0x0a72, 20},
+       {0x0a73, 0x0a74, 1},
+       {0x0a85, 0x0a8d, 1},
+       {0x0a8f, 0x0a91, 1},
+       {0x0a93, 0x0aa8, 1},
+       {0x0aaa, 0x0ab0, 1},
+       {0x0ab2, 0x0ab3, 1},
+       {0x0ab5, 0x0ab9, 1},
+       {0x0abd, 0x0ad0, 19},
+       {0x0ae0, 0x0ae1, 1},
+       {0x0b05, 0x0b0c, 1},
+       {0x0b0f, 0x0b10, 1},
+       {0x0b13, 0x0b28, 1},
+       {0x0b2a, 0x0b30, 1},
+       {0x0b32, 0x0b33, 1},
+       {0x0b35, 0x0b39, 1},
+       {0x0b3d, 0x0b5c, 31},
+       {0x0b5d, 0x0b5f, 2},
+       {0x0b60, 0x0b61, 1},
+       {0x0b71, 0x0b83, 18},
+       {0x0b85, 0x0b8a, 1},
+       {0x0b8e, 0x0b90, 1},
+       {0x0b92, 0x0b95, 1},
+       {0x0b99, 0x0b9a, 1},
+       {0x0b9c, 0x0b9e, 2},
+       {0x0b9f, 0x0ba3, 4},
+       {0x0ba4, 0x0ba8, 4},
+       {0x0ba9, 0x0baa, 1},
+       {0x0bae, 0x0bb9, 1},
+       {0x0bd0, 0x0c05, 53},
+       {0x0c06, 0x0c0c, 1},
+       {0x0c0e, 0x0c10, 1},
+       {0x0c12, 0x0c28, 1},
+       {0x0c2a, 0x0c33, 1},
+       {0x0c35, 0x0c39, 1},
+       {0x0c3d, 0x0c58, 27},
+       {0x0c59, 0x0c60, 7},
+       {0x0c61, 0x0c85, 36},
+       {0x0c86, 0x0c8c, 1},
+       {0x0c8e, 0x0c90, 1},
+       {0x0c92, 0x0ca8, 1},
+       {0x0caa, 0x0cb3, 1},
+       {0x0cb5, 0x0cb9, 1},
+       {0x0cbd, 0x0cde, 33},
+       {0x0ce0, 0x0ce1, 1},
+       {0x0d05, 0x0d0c, 1},
+       {0x0d0e, 0x0d10, 1},
+       {0x0d12, 0x0d28, 1},
+       {0x0d2a, 0x0d39, 1},
+       {0x0d3d, 0x0d60, 35},
+       {0x0d61, 0x0d7a, 25},
+       {0x0d7b, 0x0d7f, 1},
+       {0x0d85, 0x0d96, 1},
+       {0x0d9a, 0x0db1, 1},
+       {0x0db3, 0x0dbb, 1},
+       {0x0dbd, 0x0dc0, 3},
+       {0x0dc1, 0x0dc6, 1},
+       {0x0e01, 0x0e30, 1},
+       {0x0e32, 0x0e33, 1},
+       {0x0e40, 0x0e46, 1},
+       {0x0e81, 0x0e82, 1},
+       {0x0e84, 0x0e87, 3},
+       {0x0e88, 0x0e8a, 2},
+       {0x0e8d, 0x0e94, 7},
+       {0x0e95, 0x0e97, 1},
+       {0x0e99, 0x0e9f, 1},
+       {0x0ea1, 0x0ea3, 1},
+       {0x0ea5, 0x0ea7, 2},
+       {0x0eaa, 0x0eab, 1},
+       {0x0ead, 0x0eb0, 1},
+       {0x0eb2, 0x0eb3, 1},
+       {0x0ebd, 0x0ec0, 3},
+       {0x0ec1, 0x0ec4, 1},
+       {0x0ec6, 0x0edc, 22},
+       {0x0edd, 0x0f00, 35},
+       {0x0f40, 0x0f47, 1},
+       {0x0f49, 0x0f6c, 1},
+       {0x0f88, 0x0f8b, 1},
+       {0x1000, 0x102a, 1},
+       {0x103f, 0x1050, 17},
+       {0x1051, 0x1055, 1},
+       {0x105a, 0x105d, 1},
+       {0x1061, 0x1065, 4},
+       {0x1066, 0x106e, 8},
+       {0x106f, 0x1070, 1},
+       {0x1075, 0x1081, 1},
+       {0x108e, 0x10a0, 18},
+       {0x10a1, 0x10c5, 1},
+       {0x10d0, 0x10fa, 1},
+       {0x10fc, 0x1100, 4},
+       {0x1101, 0x1248, 1},
+       {0x124a, 0x124d, 1},
+       {0x1250, 0x1256, 1},
+       {0x1258, 0x125a, 2},
+       {0x125b, 0x125d, 1},
+       {0x1260, 0x1288, 1},
+       {0x128a, 0x128d, 1},
+       {0x1290, 0x12b0, 1},
+       {0x12b2, 0x12b5, 1},
+       {0x12b8, 0x12be, 1},
+       {0x12c0, 0x12c2, 2},
+       {0x12c3, 0x12c5, 1},
+       {0x12c8, 0x12d6, 1},
+       {0x12d8, 0x1310, 1},
+       {0x1312, 0x1315, 1},
+       {0x1318, 0x135a, 1},
+       {0x1380, 0x138f, 1},
+       {0x13a0, 0x13f4, 1},
+       {0x1401, 0x166c, 1},
+       {0x166f, 0x167f, 1},
+       {0x1681, 0x169a, 1},
+       {0x16a0, 0x16ea, 1},
+       {0x1700, 0x170c, 1},
+       {0x170e, 0x1711, 1},
+       {0x1720, 0x1731, 1},
+       {0x1740, 0x1751, 1},
+       {0x1760, 0x176c, 1},
+       {0x176e, 0x1770, 1},
+       {0x1780, 0x17b3, 1},
+       {0x17d7, 0x17dc, 5},
+       {0x1820, 0x1877, 1},
+       {0x1880, 0x18a8, 1},
+       {0x18aa, 0x18b0, 6},
+       {0x18b1, 0x18f5, 1},
+       {0x1900, 0x191c, 1},
+       {0x1950, 0x196d, 1},
+       {0x1970, 0x1974, 1},
+       {0x1980, 0x19ab, 1},
+       {0x19c1, 0x19c7, 1},
+       {0x1a00, 0x1a16, 1},
+       {0x1a20, 0x1a54, 1},
+       {0x1aa7, 0x1b05, 94},
+       {0x1b06, 0x1b33, 1},
+       {0x1b45, 0x1b4b, 1},
+       {0x1b83, 0x1ba0, 1},
+       {0x1bae, 0x1baf, 1},
+       {0x1c00, 0x1c23, 1},
+       {0x1c4d, 0x1c4f, 1},
+       {0x1c5a, 0x1c7d, 1},
+       {0x1ce9, 0x1cec, 1},
+       {0x1cee, 0x1cf1, 1},
+       {0x1d00, 0x1dbf, 1},
+       {0x1e00, 0x1f15, 1},
+       {0x1f18, 0x1f1d, 1},
+       {0x1f20, 0x1f45, 1},
+       {0x1f48, 0x1f4d, 1},
+       {0x1f50, 0x1f57, 1},
+       {0x1f59, 0x1f5f, 2},
+       {0x1f60, 0x1f7d, 1},
+       {0x1f80, 0x1fb4, 1},
+       {0x1fb6, 0x1fbc, 1},
+       {0x1fbe, 0x1fc2, 4},
+       {0x1fc3, 0x1fc4, 1},
+       {0x1fc6, 0x1fcc, 1},
+       {0x1fd0, 0x1fd3, 1},
+       {0x1fd6, 0x1fdb, 1},
+       {0x1fe0, 0x1fec, 1},
+       {0x1ff2, 0x1ff4, 1},
+       {0x1ff6, 0x1ffc, 1},
+       {0x2071, 0x207f, 14},
+       {0x2090, 0x2094, 1},
+       {0x2102, 0x2107, 5},
+       {0x210a, 0x2113, 1},
+       {0x2115, 0x2119, 4},
+       {0x211a, 0x211d, 1},
+       {0x2124, 0x212a, 2},
+       {0x212b, 0x212d, 1},
+       {0x212f, 0x2139, 1},
+       {0x213c, 0x213f, 1},
+       {0x2145, 0x2149, 1},
+       {0x214e, 0x2183, 53},
+       {0x2184, 0x2c00, 2684},
+       {0x2c01, 0x2c2e, 1},
+       {0x2c30, 0x2c5e, 1},
+       {0x2c60, 0x2ce4, 1},
+       {0x2ceb, 0x2cee, 1},
+       {0x2d00, 0x2d25, 1},
+       {0x2d30, 0x2d65, 1},
+       {0x2d6f, 0x2d80, 17},
+       {0x2d81, 0x2d96, 1},
+       {0x2da0, 0x2da6, 1},
+       {0x2da8, 0x2dae, 1},
+       {0x2db0, 0x2db6, 1},
+       {0x2db8, 0x2dbe, 1},
+       {0x2dc0, 0x2dc6, 1},
+       {0x2dc8, 0x2dce, 1},
+       {0x2dd0, 0x2dd6, 1},
+       {0x2dd8, 0x2dde, 1},
+       {0x2e2f, 0x3005, 470},
+       {0x3006, 0x3031, 43},
+       {0x3032, 0x3035, 1},
+       {0x303b, 0x303c, 1},
+       {0x3041, 0x3096, 1},
+       {0x309d, 0x309f, 1},
+       {0x30a1, 0x30fa, 1},
+       {0x30fc, 0x30ff, 1},
+       {0x3105, 0x312d, 1},
+       {0x3131, 0x318e, 1},
+       {0x31a0, 0x31b7, 1},
+       {0x31f0, 0x31ff, 1},
+       {0x3400, 0x4db5, 1},
+       {0x4e00, 0x9fcb, 1},
+       {0xa000, 0xa48c, 1},
+       {0xa4d0, 0xa4fd, 1},
+       {0xa500, 0xa60c, 1},
+       {0xa610, 0xa61f, 1},
+       {0xa62a, 0xa62b, 1},
+       {0xa640, 0xa65f, 1},
+       {0xa662, 0xa66e, 1},
+       {0xa67f, 0xa697, 1},
+       {0xa6a0, 0xa6e5, 1},
+       {0xa717, 0xa71f, 1},
+       {0xa722, 0xa788, 1},
+       {0xa78b, 0xa78c, 1},
+       {0xa7fb, 0xa801, 1},
+       {0xa803, 0xa805, 1},
+       {0xa807, 0xa80a, 1},
+       {0xa80c, 0xa822, 1},
+       {0xa840, 0xa873, 1},
+       {0xa882, 0xa8b3, 1},
+       {0xa8f2, 0xa8f7, 1},
+       {0xa8fb, 0xa90a, 15},
+       {0xa90b, 0xa925, 1},
+       {0xa930, 0xa946, 1},
+       {0xa960, 0xa97c, 1},
+       {0xa984, 0xa9b2, 1},
+       {0xa9cf, 0xaa00, 49},
+       {0xaa01, 0xaa28, 1},
+       {0xaa40, 0xaa42, 1},
+       {0xaa44, 0xaa4b, 1},
+       {0xaa60, 0xaa76, 1},
+       {0xaa7a, 0xaa80, 6},
+       {0xaa81, 0xaaaf, 1},
+       {0xaab1, 0xaab5, 4},
+       {0xaab6, 0xaab9, 3},
+       {0xaaba, 0xaabd, 1},
+       {0xaac0, 0xaac2, 2},
+       {0xaadb, 0xaadd, 1},
+       {0xabc0, 0xabe2, 1},
+       {0xac00, 0xd7a3, 1},
+       {0xd7b0, 0xd7c6, 1},
+       {0xd7cb, 0xd7fb, 1},
+       {0xf900, 0xfa2d, 1},
+       {0xfa30, 0xfa6d, 1},
+       {0xfa70, 0xfad9, 1},
+       {0xfb00, 0xfb06, 1},
+       {0xfb13, 0xfb17, 1},
+       {0xfb1d, 0xfb1f, 2},
+       {0xfb20, 0xfb28, 1},
+       {0xfb2a, 0xfb36, 1},
+       {0xfb38, 0xfb3c, 1},
+       {0xfb3e, 0xfb40, 2},
+       {0xfb41, 0xfb43, 2},
+       {0xfb44, 0xfb46, 2},
+       {0xfb47, 0xfbb1, 1},
+       {0xfbd3, 0xfd3d, 1},
+       {0xfd50, 0xfd8f, 1},
+       {0xfd92, 0xfdc7, 1},
+       {0xfdf0, 0xfdfb, 1},
+       {0xfe70, 0xfe74, 1},
+       {0xfe76, 0xfefc, 1},
+       {0xff21, 0xff3a, 1},
+       {0xff41, 0xff5a, 1},
+       {0xff66, 0xffbe, 1},
+       {0xffc2, 0xffc7, 1},
+       {0xffca, 0xffcf, 1},
+       {0xffd2, 0xffd7, 1},
+       {0xffda, 0xffdc, 1},
+       {0x10000, 0x1000b, 1},
+       {0x1000d, 0x10026, 1},
+       {0x10028, 0x1003a, 1},
+       {0x1003c, 0x1003d, 1},
+       {0x1003f, 0x1004d, 1},
+       {0x10050, 0x1005d, 1},
+       {0x10080, 0x100fa, 1},
+       {0x10280, 0x1029c, 1},
+       {0x102a0, 0x102d0, 1},
+       {0x10300, 0x1031e, 1},
+       {0x10330, 0x10340, 1},
+       {0x10342, 0x10349, 1},
+       {0x10380, 0x1039d, 1},
+       {0x103a0, 0x103c3, 1},
+       {0x103c8, 0x103cf, 1},
+       {0x10400, 0x1049d, 1},
+       {0x10800, 0x10805, 1},
+       {0x10808, 0x1080a, 2},
+       {0x1080b, 0x10835, 1},
+       {0x10837, 0x10838, 1},
+       {0x1083c, 0x1083f, 3},
+       {0x10840, 0x10855, 1},
+       {0x10900, 0x10915, 1},
+       {0x10920, 0x10939, 1},
+       {0x10a00, 0x10a10, 16},
+       {0x10a11, 0x10a13, 1},
+       {0x10a15, 0x10a17, 1},
+       {0x10a19, 0x10a33, 1},
+       {0x10a60, 0x10a7c, 1},
+       {0x10b00, 0x10b35, 1},
+       {0x10b40, 0x10b55, 1},
+       {0x10b60, 0x10b72, 1},
+       {0x10c00, 0x10c48, 1},
+       {0x11083, 0x110af, 1},
+       {0x12000, 0x1236e, 1},
+       {0x13000, 0x1342e, 1},
+       {0x1d400, 0x1d454, 1},
+       {0x1d456, 0x1d49c, 1},
+       {0x1d49e, 0x1d49f, 1},
+       {0x1d4a2, 0x1d4a5, 3},
+       {0x1d4a6, 0x1d4a9, 3},
+       {0x1d4aa, 0x1d4ac, 1},
+       {0x1d4ae, 0x1d4b9, 1},
+       {0x1d4bb, 0x1d4bd, 2},
+       {0x1d4be, 0x1d4c3, 1},
+       {0x1d4c5, 0x1d505, 1},
+       {0x1d507, 0x1d50a, 1},
+       {0x1d50d, 0x1d514, 1},
+       {0x1d516, 0x1d51c, 1},
+       {0x1d51e, 0x1d539, 1},
+       {0x1d53b, 0x1d53e, 1},
+       {0x1d540, 0x1d544, 1},
+       {0x1d546, 0x1d54a, 4},
+       {0x1d54b, 0x1d550, 1},
+       {0x1d552, 0x1d6a5, 1},
+       {0x1d6a8, 0x1d6c0, 1},
+       {0x1d6c2, 0x1d6da, 1},
+       {0x1d6dc, 0x1d6fa, 1},
+       {0x1d6fc, 0x1d714, 1},
+       {0x1d716, 0x1d734, 1},
+       {0x1d736, 0x1d74e, 1},
+       {0x1d750, 0x1d76e, 1},
+       {0x1d770, 0x1d788, 1},
+       {0x1d78a, 0x1d7a8, 1},
+       {0x1d7aa, 0x1d7c2, 1},
+       {0x1d7c4, 0x1d7cb, 1},
+       {0x20000, 0x2a6d6, 1},
+       {0x2a700, 0x2b734, 1},
+       {0x2f800, 0x2fa1d, 1},
+}
+
+var _Zp = []Range{
+       {0x2029, 0x2029, 1},
+}
+
+var _Zs = []Range{
+       {0x0020, 0x00a0, 128},
+       {0x1680, 0x180e, 398},
+       {0x2000, 0x200a, 1},
+       {0x202f, 0x205f, 48},
+       {0x3000, 0x3000, 1},
+}
+
+var _Cs = []Range{
+       {0xd800, 0xdfff, 1},
+}
+
+var _Co = []Range{
+       {0xe000, 0xf8ff, 1},
+       {0xf0000, 0xffffd, 1},
+       {0x100000, 0x10fffd, 1},
+}
+
+var _Cf = []Range{
+       {0x00ad, 0x0600, 1363},
+       {0x0601, 0x0603, 1},
+       {0x06dd, 0x070f, 50},
+       {0x17b4, 0x17b5, 1},
+       {0x200b, 0x200f, 1},
+       {0x202a, 0x202e, 1},
+       {0x2060, 0x2064, 1},
+       {0x206a, 0x206f, 1},
+       {0xfeff, 0xfff9, 250},
+       {0xfffa, 0xfffb, 1},
+       {0x110bd, 0x1d173, 49334},
+       {0x1d174, 0x1d17a, 1},
+       {0xe0001, 0xe0020, 31},
+       {0xe0021, 0xe007f, 1},
+}
+
+var _Cc = []Range{
+       {0x0001, 0x001f, 1},
+       {0x007f, 0x009f, 1},
+}
+
+var _Po = []Range{
+       {0x0021, 0x0023, 1},
+       {0x0025, 0x0027, 1},
+       {0x002a, 0x002e, 2},
+       {0x002f, 0x003a, 11},
+       {0x003b, 0x003f, 4},
+       {0x0040, 0x005c, 28},
+       {0x00a1, 0x00b7, 22},
+       {0x00bf, 0x037e, 703},
+       {0x0387, 0x055a, 467},
+       {0x055b, 0x055f, 1},
+       {0x0589, 0x05c0, 55},
+       {0x05c3, 0x05c6, 3},
+       {0x05f3, 0x05f4, 1},
+       {0x0609, 0x060a, 1},
+       {0x060c, 0x060d, 1},
+       {0x061b, 0x061e, 3},
+       {0x061f, 0x066a, 75},
+       {0x066b, 0x066d, 1},
+       {0x06d4, 0x0700, 44},
+       {0x0701, 0x070d, 1},
+       {0x07f7, 0x07f9, 1},
+       {0x0830, 0x083e, 1},
+       {0x0964, 0x0965, 1},
+       {0x0970, 0x0df4, 1156},
+       {0x0e4f, 0x0e5a, 11},
+       {0x0e5b, 0x0f04, 169},
+       {0x0f05, 0x0f12, 1},
+       {0x0f85, 0x0fd0, 75},
+       {0x0fd1, 0x0fd4, 1},
+       {0x104a, 0x104f, 1},
+       {0x10fb, 0x1361, 614},
+       {0x1362, 0x1368, 1},
+       {0x166d, 0x166e, 1},
+       {0x16eb, 0x16ed, 1},
+       {0x1735, 0x1736, 1},
+       {0x17d4, 0x17d6, 1},
+       {0x17d8, 0x17da, 1},
+       {0x1800, 0x1805, 1},
+       {0x1807, 0x180a, 1},
+       {0x1944, 0x1945, 1},
+       {0x19de, 0x19df, 1},
+       {0x1a1e, 0x1a1f, 1},
+       {0x1aa0, 0x1aa6, 1},
+       {0x1aa8, 0x1aad, 1},
+       {0x1b5a, 0x1b60, 1},
+       {0x1c3b, 0x1c3f, 1},
+       {0x1c7e, 0x1c7f, 1},
+       {0x1cd3, 0x2016, 835},
+       {0x2017, 0x2020, 9},
+       {0x2021, 0x2027, 1},
+       {0x2030, 0x2038, 1},
+       {0x203b, 0x203e, 1},
+       {0x2041, 0x2043, 1},
+       {0x2047, 0x2051, 1},
+       {0x2053, 0x2055, 2},
+       {0x2056, 0x205e, 1},
+       {0x2cf9, 0x2cfc, 1},
+       {0x2cfe, 0x2cff, 1},
+       {0x2e00, 0x2e01, 1},
+       {0x2e06, 0x2e08, 1},
+       {0x2e0b, 0x2e0e, 3},
+       {0x2e0f, 0x2e16, 1},
+       {0x2e18, 0x2e19, 1},
+       {0x2e1b, 0x2e1e, 3},
+       {0x2e1f, 0x2e2a, 11},
+       {0x2e2b, 0x2e2e, 1},
+       {0x2e30, 0x2e31, 1},
+       {0x3001, 0x3003, 1},
+       {0x303d, 0x30fb, 190},
+       {0xa4fe, 0xa4ff, 1},
+       {0xa60d, 0xa60f, 1},
+       {0xa673, 0xa67e, 11},
+       {0xa6f2, 0xa6f7, 1},
+       {0xa874, 0xa877, 1},
+       {0xa8ce, 0xa8cf, 1},
+       {0xa8f8, 0xa8fa, 1},
+       {0xa92e, 0xa92f, 1},
+       {0xa95f, 0xa9c1, 98},
+       {0xa9c2, 0xa9cd, 1},
+       {0xa9de, 0xa9df, 1},
+       {0xaa5c, 0xaa5f, 1},
+       {0xaade, 0xaadf, 1},
+       {0xabeb, 0xfe10, 21029},
+       {0xfe11, 0xfe16, 1},
+       {0xfe19, 0xfe30, 23},
+       {0xfe45, 0xfe46, 1},
+       {0xfe49, 0xfe4c, 1},
+       {0xfe50, 0xfe52, 1},
+       {0xfe54, 0xfe57, 1},
+       {0xfe5f, 0xfe61, 1},
+       {0xfe68, 0xfe6a, 2},
+       {0xfe6b, 0xff01, 150},
+       {0xff02, 0xff03, 1},
+       {0xff05, 0xff07, 1},
+       {0xff0a, 0xff0e, 2},
+       {0xff0f, 0xff1a, 11},
+       {0xff1b, 0xff1f, 4},
+       {0xff20, 0xff3c, 28},
+       {0xff61, 0xff64, 3},
+       {0xff65, 0x10100, 411},
+       {0x10101, 0x1039f, 670},
+       {0x103d0, 0x10857, 1159},
+       {0x1091f, 0x1093f, 32},
+       {0x10a50, 0x10a58, 1},
+       {0x10a7f, 0x10b39, 186},
+       {0x10b3a, 0x10b3f, 1},
+       {0x110bb, 0x110bc, 1},
+       {0x110be, 0x110c1, 1},
+       {0x12470, 0x12473, 1},
+}
+
+var _Pi = []Range{
+       {0x00ab, 0x2018, 8045},
+       {0x201b, 0x201c, 1},
+       {0x201f, 0x2039, 26},
+       {0x2e02, 0x2e04, 2},
+       {0x2e09, 0x2e0c, 3},
+       {0x2e1c, 0x2e20, 4},
+}
+
+var _Pf = []Range{
+       {0x00bb, 0x2019, 8030},
+       {0x201d, 0x203a, 29},
+       {0x2e03, 0x2e05, 2},
+       {0x2e0a, 0x2e0d, 3},
+       {0x2e1d, 0x2e21, 4},
+}
+
+var _Pe = []Range{
+       {0x0029, 0x005d, 52},
+       {0x007d, 0x0f3b, 3774},
+       {0x0f3d, 0x169c, 1887},
+       {0x2046, 0x207e, 56},
+       {0x208e, 0x232a, 668},
+       {0x2769, 0x2775, 2},
+       {0x27c6, 0x27e7, 33},
+       {0x27e9, 0x27ef, 2},
+       {0x2984, 0x2998, 2},
+       {0x29d9, 0x29db, 2},
+       {0x29fd, 0x2e23, 1062},
+       {0x2e25, 0x2e29, 2},
+       {0x3009, 0x3011, 2},
+       {0x3015, 0x301b, 2},
+       {0x301e, 0x301f, 1},
+       {0xfd3f, 0xfe18, 217},
+       {0xfe36, 0xfe44, 2},
+       {0xfe48, 0xfe5a, 18},
+       {0xfe5c, 0xfe5e, 2},
+       {0xff09, 0xff3d, 52},
+       {0xff5d, 0xff63, 3},
+}
+
+var _Pd = []Range{
+       {0x002d, 0x058a, 1373},
+       {0x05be, 0x1400, 3650},
+       {0x1806, 0x2010, 2058},
+       {0x2011, 0x2015, 1},
+       {0x2e17, 0x2e1a, 3},
+       {0x301c, 0x3030, 20},
+       {0x30a0, 0xfe31, 52625},
+       {0xfe32, 0xfe58, 38},
+       {0xfe63, 0xff0d, 170},
+}
+
+var _Pc = []Range{
+       {0x005f, 0x203f, 8160},
+       {0x2040, 0x2054, 20},
+       {0xfe33, 0xfe34, 1},
+       {0xfe4d, 0xfe4f, 1},
+       {0xff3f, 0xff3f, 1},
+}
+
+var _Ps = []Range{
+       {0x0028, 0x005b, 51},
+       {0x007b, 0x0f3a, 3775},
+       {0x0f3c, 0x169b, 1887},
+       {0x201a, 0x201e, 4},
+       {0x2045, 0x207d, 56},
+       {0x208d, 0x2329, 668},
+       {0x2768, 0x2774, 2},
+       {0x27c5, 0x27e6, 33},
+       {0x27e8, 0x27ee, 2},
+       {0x2983, 0x2997, 2},
+       {0x29d8, 0x29da, 2},
+       {0x29fc, 0x2e22, 1062},
+       {0x2e24, 0x2e28, 2},
+       {0x3008, 0x3010, 2},
+       {0x3014, 0x301a, 2},
+       {0x301d, 0xfd3e, 52513},
+       {0xfe17, 0xfe35, 30},
+       {0xfe37, 0xfe43, 2},
+       {0xfe47, 0xfe59, 18},
+       {0xfe5b, 0xfe5d, 2},
+       {0xff08, 0xff3b, 51},
+       {0xff5b, 0xff5f, 4},
+       {0xff62, 0xff62, 1},
+}
+
+var _Nd = []Range{
+       {0x0030, 0x0039, 1},
+       {0x0660, 0x0669, 1},
+       {0x06f0, 0x06f9, 1},
+       {0x07c0, 0x07c9, 1},
+       {0x0966, 0x096f, 1},
+       {0x09e6, 0x09ef, 1},
+       {0x0a66, 0x0a6f, 1},
+       {0x0ae6, 0x0aef, 1},
+       {0x0b66, 0x0b6f, 1},
+       {0x0be6, 0x0bef, 1},
+       {0x0c66, 0x0c6f, 1},
+       {0x0ce6, 0x0cef, 1},
+       {0x0d66, 0x0d6f, 1},
+       {0x0e50, 0x0e59, 1},
+       {0x0ed0, 0x0ed9, 1},
+       {0x0f20, 0x0f29, 1},
+       {0x1040, 0x1049, 1},
+       {0x1090, 0x1099, 1},
+       {0x17e0, 0x17e9, 1},
+       {0x1810, 0x1819, 1},
+       {0x1946, 0x194f, 1},
+       {0x19d0, 0x19da, 1},
+       {0x1a80, 0x1a89, 1},
+       {0x1a90, 0x1a99, 1},
+       {0x1b50, 0x1b59, 1},
+       {0x1bb0, 0x1bb9, 1},
+       {0x1c40, 0x1c49, 1},
+       {0x1c50, 0x1c59, 1},
+       {0xa620, 0xa629, 1},
+       {0xa8d0, 0xa8d9, 1},
+       {0xa900, 0xa909, 1},
+       {0xa9d0, 0xa9d9, 1},
+       {0xaa50, 0xaa59, 1},
+       {0xabf0, 0xabf9, 1},
+       {0xff10, 0xff19, 1},
+       {0x104a0, 0x104a9, 1},
+       {0x1d7ce, 0x1d7ff, 1},
+}
+
+var _Nl = []Range{
+       {0x16ee, 0x16f0, 1},
+       {0x2160, 0x2182, 1},
+       {0x2185, 0x2188, 1},
+       {0x3007, 0x3021, 26},
+       {0x3022, 0x3029, 1},
+       {0x3038, 0x303a, 1},
+       {0xa6e6, 0xa6ef, 1},
+       {0x10140, 0x10174, 1},
+       {0x10341, 0x1034a, 9},
+       {0x103d1, 0x103d5, 1},
+       {0x12400, 0x12462, 1},
+}
+
+var _No = []Range{
+       {0x00b2, 0x00b3, 1},
+       {0x00b9, 0x00bc, 3},
+       {0x00bd, 0x00be, 1},
+       {0x09f4, 0x09f9, 1},
+       {0x0bf0, 0x0bf2, 1},
+       {0x0c78, 0x0c7e, 1},
+       {0x0d70, 0x0d75, 1},
+       {0x0f2a, 0x0f33, 1},
+       {0x1369, 0x137c, 1},
+       {0x17f0, 0x17f9, 1},
+       {0x2070, 0x2074, 4},
+       {0x2075, 0x2079, 1},
+       {0x2080, 0x2089, 1},
+       {0x2150, 0x215f, 1},
+       {0x2189, 0x2460, 727},
+       {0x2461, 0x249b, 1},
+       {0x24ea, 0x24ff, 1},
+       {0x2776, 0x2793, 1},
+       {0x2cfd, 0x3192, 1173},
+       {0x3193, 0x3195, 1},
+       {0x3220, 0x3229, 1},
+       {0x3251, 0x325f, 1},
+       {0x3280, 0x3289, 1},
+       {0x32b1, 0x32bf, 1},
+       {0xa830, 0xa835, 1},
+       {0x10107, 0x10133, 1},
+       {0x10175, 0x10178, 1},
+       {0x1018a, 0x10320, 406},
+       {0x10321, 0x10323, 1},
+       {0x10858, 0x1085f, 1},
+       {0x10916, 0x1091b, 1},
+       {0x10a40, 0x10a47, 1},
+       {0x10a7d, 0x10a7e, 1},
+       {0x10b58, 0x10b5f, 1},
+       {0x10b78, 0x10b7f, 1},
+       {0x10e60, 0x10e7e, 1},
+       {0x1d360, 0x1d371, 1},
+       {0x1f100, 0x1f10a, 1},
+}
+
+var _So = []Range{
+       {0x00a6, 0x00a7, 1},
+       {0x00a9, 0x00ae, 5},
+       {0x00b0, 0x00b6, 6},
+       {0x0482, 0x060e, 396},
+       {0x060f, 0x06e9, 218},
+       {0x06fd, 0x06fe, 1},
+       {0x07f6, 0x09fa, 516},
+       {0x0b70, 0x0bf3, 131},
+       {0x0bf4, 0x0bf8, 1},
+       {0x0bfa, 0x0c7f, 133},
+       {0x0cf1, 0x0cf2, 1},
+       {0x0d79, 0x0f01, 392},
+       {0x0f02, 0x0f03, 1},
+       {0x0f13, 0x0f17, 1},
+       {0x0f1a, 0x0f1f, 1},
+       {0x0f34, 0x0f38, 2},
+       {0x0fbe, 0x0fc5, 1},
+       {0x0fc7, 0x0fcc, 1},
+       {0x0fce, 0x0fcf, 1},
+       {0x0fd5, 0x0fd8, 1},
+       {0x109e, 0x109f, 1},
+       {0x1360, 0x1390, 48},
+       {0x1391, 0x1399, 1},
+       {0x1940, 0x19e0, 160},
+       {0x19e1, 0x19ff, 1},
+       {0x1b61, 0x1b6a, 1},
+       {0x1b74, 0x1b7c, 1},
+       {0x2100, 0x2101, 1},
+       {0x2103, 0x2106, 1},
+       {0x2108, 0x2109, 1},
+       {0x2114, 0x2116, 2},
+       {0x2117, 0x2118, 1},
+       {0x211e, 0x2123, 1},
+       {0x2125, 0x2129, 2},
+       {0x212e, 0x213a, 12},
+       {0x213b, 0x214a, 15},
+       {0x214c, 0x214d, 1},
+       {0x214f, 0x2195, 70},
+       {0x2196, 0x2199, 1},
+       {0x219c, 0x219f, 1},
+       {0x21a1, 0x21a2, 1},
+       {0x21a4, 0x21a5, 1},
+       {0x21a7, 0x21ad, 1},
+       {0x21af, 0x21cd, 1},
+       {0x21d0, 0x21d1, 1},
+       {0x21d3, 0x21d5, 2},
+       {0x21d6, 0x21f3, 1},
+       {0x2300, 0x2307, 1},
+       {0x230c, 0x231f, 1},
+       {0x2322, 0x2328, 1},
+       {0x232b, 0x237b, 1},
+       {0x237d, 0x239a, 1},
+       {0x23b4, 0x23db, 1},
+       {0x23e2, 0x23e8, 1},
+       {0x2400, 0x2426, 1},
+       {0x2440, 0x244a, 1},
+       {0x249c, 0x24e9, 1},
+       {0x2500, 0x25b6, 1},
+       {0x25b8, 0x25c0, 1},
+       {0x25c2, 0x25f7, 1},
+       {0x2600, 0x266e, 1},
+       {0x2670, 0x26cd, 1},
+       {0x26cf, 0x26e1, 1},
+       {0x26e3, 0x26e8, 5},
+       {0x26e9, 0x26ff, 1},
+       {0x2701, 0x2704, 1},
+       {0x2706, 0x2709, 1},
+       {0x270c, 0x2727, 1},
+       {0x2729, 0x274b, 1},
+       {0x274d, 0x274f, 2},
+       {0x2750, 0x2752, 1},
+       {0x2756, 0x275e, 1},
+       {0x2761, 0x2767, 1},
+       {0x2794, 0x2798, 4},
+       {0x2799, 0x27af, 1},
+       {0x27b1, 0x27be, 1},
+       {0x2800, 0x28ff, 1},
+       {0x2b00, 0x2b2f, 1},
+       {0x2b45, 0x2b46, 1},
+       {0x2b50, 0x2b59, 1},
+       {0x2ce5, 0x2cea, 1},
+       {0x2e80, 0x2e99, 1},
+       {0x2e9b, 0x2ef3, 1},
+       {0x2f00, 0x2fd5, 1},
+       {0x2ff0, 0x2ffb, 1},
+       {0x3004, 0x3012, 14},
+       {0x3013, 0x3020, 13},
+       {0x3036, 0x3037, 1},
+       {0x303e, 0x303f, 1},
+       {0x3190, 0x3191, 1},
+       {0x3196, 0x319f, 1},
+       {0x31c0, 0x31e3, 1},
+       {0x3200, 0x321e, 1},
+       {0x322a, 0x3250, 1},
+       {0x3260, 0x327f, 1},
+       {0x328a, 0x32b0, 1},
+       {0x32c0, 0x32fe, 1},
+       {0x3300, 0x33ff, 1},
+       {0x4dc0, 0x4dff, 1},
+       {0xa490, 0xa4c6, 1},
+       {0xa828, 0xa82b, 1},
+       {0xa836, 0xa837, 1},
+       {0xa839, 0xaa77, 574},
+       {0xaa78, 0xaa79, 1},
+       {0xfdfd, 0xffe4, 487},
+       {0xffe8, 0xffed, 5},
+       {0xffee, 0xfffc, 14},
+       {0xfffd, 0x10102, 261},
+       {0x10137, 0x1013f, 1},
+       {0x10179, 0x10189, 1},
+       {0x10190, 0x1019b, 1},
+       {0x101d0, 0x101fc, 1},
+       {0x1d000, 0x1d0f5, 1},
+       {0x1d100, 0x1d126, 1},
+       {0x1d129, 0x1d164, 1},
+       {0x1d16a, 0x1d16c, 1},
+       {0x1d183, 0x1d184, 1},
+       {0x1d18c, 0x1d1a9, 1},
+       {0x1d1ae, 0x1d1dd, 1},
+       {0x1d200, 0x1d241, 1},
+       {0x1d245, 0x1d300, 187},
+       {0x1d301, 0x1d356, 1},
+       {0x1f000, 0x1f02b, 1},
+       {0x1f030, 0x1f093, 1},
+       {0x1f110, 0x1f12e, 1},
+       {0x1f131, 0x1f13d, 12},
+       {0x1f13f, 0x1f142, 3},
+       {0x1f146, 0x1f14a, 4},
+       {0x1f14b, 0x1f14e, 1},
+       {0x1f157, 0x1f15f, 8},
+       {0x1f179, 0x1f17b, 2},
+       {0x1f17c, 0x1f17f, 3},
+       {0x1f18a, 0x1f18d, 1},
+       {0x1f190, 0x1f200, 112},
+       {0x1f210, 0x1f231, 1},
+       {0x1f240, 0x1f248, 1},
+}
+
+var _Sm = []Range{
+       {0x002b, 0x003c, 17},
+       {0x003d, 0x003e, 1},
+       {0x007c, 0x007e, 2},
+       {0x00ac, 0x00b1, 5},
+       {0x00d7, 0x00f7, 32},
+       {0x03f6, 0x0606, 528},
+       {0x0607, 0x0608, 1},
+       {0x2044, 0x2052, 14},
+       {0x207a, 0x207c, 1},
+       {0x208a, 0x208c, 1},
+       {0x2140, 0x2144, 1},
+       {0x214b, 0x2190, 69},
+       {0x2191, 0x2194, 1},
+       {0x219a, 0x219b, 1},
+       {0x21a0, 0x21a6, 3},
+       {0x21ae, 0x21ce, 32},
+       {0x21cf, 0x21d2, 3},
+       {0x21d4, 0x21f4, 32},
+       {0x21f5, 0x22ff, 1},
+       {0x2308, 0x230b, 1},
+       {0x2320, 0x2321, 1},
+       {0x237c, 0x239b, 31},
+       {0x239c, 0x23b3, 1},
+       {0x23dc, 0x23e1, 1},
+       {0x25b7, 0x25c1, 10},
+       {0x25f8, 0x25ff, 1},
+       {0x266f, 0x27c0, 337},
+       {0x27c1, 0x27c4, 1},
+       {0x27c7, 0x27ca, 1},
+       {0x27cc, 0x27d0, 4},
+       {0x27d1, 0x27e5, 1},
+       {0x27f0, 0x27ff, 1},
+       {0x2900, 0x2982, 1},
+       {0x2999, 0x29d7, 1},
+       {0x29dc, 0x29fb, 1},
+       {0x29fe, 0x2aff, 1},
+       {0x2b30, 0x2b44, 1},
+       {0x2b47, 0x2b4c, 1},
+       {0xfb29, 0xfe62, 825},
+       {0xfe64, 0xfe66, 1},
+       {0xff0b, 0xff1c, 17},
+       {0xff1d, 0xff1e, 1},
+       {0xff5c, 0xff5e, 2},
+       {0xffe2, 0xffe9, 7},
+       {0xffea, 0xffec, 1},
+       {0x1d6c1, 0x1d6db, 26},
+       {0x1d6fb, 0x1d715, 26},
+       {0x1d735, 0x1d74f, 26},
+       {0x1d76f, 0x1d789, 26},
+       {0x1d7a9, 0x1d7c3, 26},
+}
+
+var _Sk = []Range{
+       {0x005e, 0x0060, 2},
+       {0x00a8, 0x00af, 7},
+       {0x00b4, 0x00b8, 4},
+       {0x02c2, 0x02c5, 1},
+       {0x02d2, 0x02df, 1},
+       {0x02e5, 0x02eb, 1},
+       {0x02ed, 0x02ef, 2},
+       {0x02f0, 0x02ff, 1},
+       {0x0375, 0x0384, 15},
+       {0x0385, 0x1fbd, 7224},
+       {0x1fbf, 0x1fc1, 1},
+       {0x1fcd, 0x1fcf, 1},
+       {0x1fdd, 0x1fdf, 1},
+       {0x1fed, 0x1fef, 1},
+       {0x1ffd, 0x1ffe, 1},
+       {0x309b, 0x309c, 1},
+       {0xa700, 0xa716, 1},
+       {0xa720, 0xa721, 1},
+       {0xa789, 0xa78a, 1},
+       {0xff3e, 0xff40, 2},
+       {0xffe3, 0xffe3, 1},
+}
+
+var _Sc = []Range{
+       {0x0024, 0x00a2, 126},
+       {0x00a3, 0x00a5, 1},
+       {0x060b, 0x09f2, 999},
+       {0x09f3, 0x09fb, 8},
+       {0x0af1, 0x0bf9, 264},
+       {0x0e3f, 0x17db, 2460},
+       {0x20a0, 0x20b8, 1},
+       {0xa838, 0xfdfc, 21956},
+       {0xfe69, 0xff04, 155},
+       {0xffe0, 0xffe1, 1},
+       {0xffe5, 0xffe6, 1},
+}
+
+var _Lu = []Range{
+       {0x0041, 0x005a, 1},
+       {0x00c0, 0x00d6, 1},
+       {0x00d8, 0x00de, 1},
+       {0x0100, 0x0136, 2},
+       {0x0139, 0x0147, 2},
+       {0x014a, 0x0178, 2},
+       {0x0179, 0x017d, 2},
+       {0x0181, 0x0182, 1},
+       {0x0184, 0x0186, 2},
+       {0x0187, 0x0189, 2},
+       {0x018a, 0x018b, 1},
+       {0x018e, 0x0191, 1},
+       {0x0193, 0x0194, 1},
+       {0x0196, 0x0198, 1},
+       {0x019c, 0x019d, 1},
+       {0x019f, 0x01a0, 1},
+       {0x01a2, 0x01a6, 2},
+       {0x01a7, 0x01a9, 2},
+       {0x01ac, 0x01ae, 2},
+       {0x01af, 0x01b1, 2},
+       {0x01b2, 0x01b3, 1},
+       {0x01b5, 0x01b7, 2},
+       {0x01b8, 0x01bc, 4},
+       {0x01c4, 0x01cd, 3},
+       {0x01cf, 0x01db, 2},
+       {0x01de, 0x01ee, 2},
+       {0x01f1, 0x01f4, 3},
+       {0x01f6, 0x01f8, 1},
+       {0x01fa, 0x0232, 2},
+       {0x023a, 0x023b, 1},
+       {0x023d, 0x023e, 1},
+       {0x0241, 0x0243, 2},
+       {0x0244, 0x0246, 1},
+       {0x0248, 0x024e, 2},
+       {0x0370, 0x0372, 2},
+       {0x0376, 0x0386, 16},
+       {0x0388, 0x038a, 1},
+       {0x038c, 0x038e, 2},
+       {0x038f, 0x0391, 2},
+       {0x0392, 0x03a1, 1},
+       {0x03a3, 0x03ab, 1},
+       {0x03cf, 0x03d2, 3},
+       {0x03d3, 0x03d4, 1},
+       {0x03d8, 0x03ee, 2},
+       {0x03f4, 0x03f7, 3},
+       {0x03f9, 0x03fa, 1},
+       {0x03fd, 0x042f, 1},
+       {0x0460, 0x0480, 2},
+       {0x048a, 0x04c0, 2},
+       {0x04c1, 0x04cd, 2},
+       {0x04d0, 0x0524, 2},
+       {0x0531, 0x0556, 1},
+       {0x10a0, 0x10c5, 1},
+       {0x1e00, 0x1e94, 2},
+       {0x1e9e, 0x1efe, 2},
+       {0x1f08, 0x1f0f, 1},
+       {0x1f18, 0x1f1d, 1},
+       {0x1f28, 0x1f2f, 1},
+       {0x1f38, 0x1f3f, 1},
+       {0x1f48, 0x1f4d, 1},
+       {0x1f59, 0x1f5f, 2},
+       {0x1f68, 0x1f6f, 1},
+       {0x1fb8, 0x1fbb, 1},
+       {0x1fc8, 0x1fcb, 1},
+       {0x1fd8, 0x1fdb, 1},
+       {0x1fe8, 0x1fec, 1},
+       {0x1ff8, 0x1ffb, 1},
+       {0x2102, 0x2107, 5},
+       {0x210b, 0x210d, 1},
+       {0x2110, 0x2112, 1},
+       {0x2115, 0x2119, 4},
+       {0x211a, 0x211d, 1},
+       {0x2124, 0x212a, 2},
+       {0x212b, 0x212d, 1},
+       {0x2130, 0x2133, 1},
+       {0x213e, 0x213f, 1},
+       {0x2145, 0x2183, 62},
+       {0x2c00, 0x2c2e, 1},
+       {0x2c60, 0x2c62, 2},
+       {0x2c63, 0x2c64, 1},
+       {0x2c67, 0x2c6d, 2},
+       {0x2c6e, 0x2c70, 1},
+       {0x2c72, 0x2c75, 3},
+       {0x2c7e, 0x2c80, 1},
+       {0x2c82, 0x2ce2, 2},
+       {0x2ceb, 0x2ced, 2},
+       {0xa640, 0xa65e, 2},
+       {0xa662, 0xa66c, 2},
+       {0xa680, 0xa696, 2},
+       {0xa722, 0xa72e, 2},
+       {0xa732, 0xa76e, 2},
+       {0xa779, 0xa77d, 2},
+       {0xa77e, 0xa786, 2},
+       {0xa78b, 0xff21, 22422},
+       {0xff22, 0xff3a, 1},
+       {0x10400, 0x10427, 1},
+       {0x1d400, 0x1d419, 1},
+       {0x1d434, 0x1d44d, 1},
+       {0x1d468, 0x1d481, 1},
+       {0x1d49c, 0x1d49e, 2},
+       {0x1d49f, 0x1d4a5, 3},
+       {0x1d4a6, 0x1d4a9, 3},
+       {0x1d4aa, 0x1d4ac, 1},
+       {0x1d4ae, 0x1d4b5, 1},
+       {0x1d4d0, 0x1d4e9, 1},
+       {0x1d504, 0x1d505, 1},
+       {0x1d507, 0x1d50a, 1},
+       {0x1d50d, 0x1d514, 1},
+       {0x1d516, 0x1d51c, 1},
+       {0x1d538, 0x1d539, 1},
+       {0x1d53b, 0x1d53e, 1},
+       {0x1d540, 0x1d544, 1},
+       {0x1d546, 0x1d54a, 4},
+       {0x1d54b, 0x1d550, 1},
+       {0x1d56c, 0x1d585, 1},
+       {0x1d5a0, 0x1d5b9, 1},
+       {0x1d5d4, 0x1d5ed, 1},
+       {0x1d608, 0x1d621, 1},
+       {0x1d63c, 0x1d655, 1},
+       {0x1d670, 0x1d689, 1},
+       {0x1d6a8, 0x1d6c0, 1},
+       {0x1d6e2, 0x1d6fa, 1},
+       {0x1d71c, 0x1d734, 1},
+       {0x1d756, 0x1d76e, 1},
+       {0x1d790, 0x1d7a8, 1},
+       {0x1d7ca, 0x1d7ca, 1},
+}
+
+var _Lt = []Range{
+       {0x01c5, 0x01cb, 3},
+       {0x01f2, 0x1f88, 7574},
+       {0x1f89, 0x1f8f, 1},
+       {0x1f98, 0x1f9f, 1},
+       {0x1fa8, 0x1faf, 1},
+       {0x1fbc, 0x1fcc, 16},
+       {0x1ffc, 0x1ffc, 1},
+}
+
+var _Lo = []Range{
+       {0x01bb, 0x01c0, 5},
+       {0x01c1, 0x01c3, 1},
+       {0x0294, 0x05d0, 828},
+       {0x05d1, 0x05ea, 1},
+       {0x05f0, 0x05f2, 1},
+       {0x0621, 0x063f, 1},
+       {0x0641, 0x064a, 1},
+       {0x066e, 0x066f, 1},
+       {0x0671, 0x06d3, 1},
+       {0x06d5, 0x06ee, 25},
+       {0x06ef, 0x06fa, 11},
+       {0x06fb, 0x06fc, 1},
+       {0x06ff, 0x0710, 17},
+       {0x0712, 0x072f, 1},
+       {0x074d, 0x07a5, 1},
+       {0x07b1, 0x07ca, 25},
+       {0x07cb, 0x07ea, 1},
+       {0x0800, 0x0815, 1},
+       {0x0904, 0x0939, 1},
+       {0x093d, 0x0950, 19},
+       {0x0958, 0x0961, 1},
+       {0x0972, 0x0979, 7},
+       {0x097a, 0x097f, 1},
+       {0x0985, 0x098c, 1},
+       {0x098f, 0x0990, 1},
+       {0x0993, 0x09a8, 1},
+       {0x09aa, 0x09b0, 1},
+       {0x09b2, 0x09b6, 4},
+       {0x09b7, 0x09b9, 1},
+       {0x09bd, 0x09ce, 17},
+       {0x09dc, 0x09dd, 1},
+       {0x09df, 0x09e1, 1},
+       {0x09f0, 0x09f1, 1},
+       {0x0a05, 0x0a0a, 1},
+       {0x0a0f, 0x0a10, 1},
+       {0x0a13, 0x0a28, 1},
+       {0x0a2a, 0x0a30, 1},
+       {0x0a32, 0x0a33, 1},
+       {0x0a35, 0x0a36, 1},
+       {0x0a38, 0x0a39, 1},
+       {0x0a59, 0x0a5c, 1},
+       {0x0a5e, 0x0a72, 20},
+       {0x0a73, 0x0a74, 1},
+       {0x0a85, 0x0a8d, 1},
+       {0x0a8f, 0x0a91, 1},
+       {0x0a93, 0x0aa8, 1},
+       {0x0aaa, 0x0ab0, 1},
+       {0x0ab2, 0x0ab3, 1},
+       {0x0ab5, 0x0ab9, 1},
+       {0x0abd, 0x0ad0, 19},
+       {0x0ae0, 0x0ae1, 1},
+       {0x0b05, 0x0b0c, 1},
+       {0x0b0f, 0x0b10, 1},
+       {0x0b13, 0x0b28, 1},
+       {0x0b2a, 0x0b30, 1},
+       {0x0b32, 0x0b33, 1},
+       {0x0b35, 0x0b39, 1},
+       {0x0b3d, 0x0b5c, 31},
+       {0x0b5d, 0x0b5f, 2},
+       {0x0b60, 0x0b61, 1},
+       {0x0b71, 0x0b83, 18},
+       {0x0b85, 0x0b8a, 1},
+       {0x0b8e, 0x0b90, 1},
+       {0x0b92, 0x0b95, 1},
+       {0x0b99, 0x0b9a, 1},
+       {0x0b9c, 0x0b9e, 2},
+       {0x0b9f, 0x0ba3, 4},
+       {0x0ba4, 0x0ba8, 4},
+       {0x0ba9, 0x0baa, 1},
+       {0x0bae, 0x0bb9, 1},
+       {0x0bd0, 0x0c05, 53},
+       {0x0c06, 0x0c0c, 1},
+       {0x0c0e, 0x0c10, 1},
+       {0x0c12, 0x0c28, 1},
+       {0x0c2a, 0x0c33, 1},
+       {0x0c35, 0x0c39, 1},
+       {0x0c3d, 0x0c58, 27},
+       {0x0c59, 0x0c60, 7},
+       {0x0c61, 0x0c85, 36},
+       {0x0c86, 0x0c8c, 1},
+       {0x0c8e, 0x0c90, 1},
+       {0x0c92, 0x0ca8, 1},
+       {0x0caa, 0x0cb3, 1},
+       {0x0cb5, 0x0cb9, 1},
+       {0x0cbd, 0x0cde, 33},
+       {0x0ce0, 0x0ce1, 1},
+       {0x0d05, 0x0d0c, 1},
+       {0x0d0e, 0x0d10, 1},
+       {0x0d12, 0x0d28, 1},
+       {0x0d2a, 0x0d39, 1},
+       {0x0d3d, 0x0d60, 35},
+       {0x0d61, 0x0d7a, 25},
+       {0x0d7b, 0x0d7f, 1},
+       {0x0d85, 0x0d96, 1},
+       {0x0d9a, 0x0db1, 1},
+       {0x0db3, 0x0dbb, 1},
+       {0x0dbd, 0x0dc0, 3},
+       {0x0dc1, 0x0dc6, 1},
+       {0x0e01, 0x0e30, 1},
+       {0x0e32, 0x0e33, 1},
+       {0x0e40, 0x0e45, 1},
+       {0x0e81, 0x0e82, 1},
+       {0x0e84, 0x0e87, 3},
+       {0x0e88, 0x0e8a, 2},
+       {0x0e8d, 0x0e94, 7},
+       {0x0e95, 0x0e97, 1},
+       {0x0e99, 0x0e9f, 1},
+       {0x0ea1, 0x0ea3, 1},
+       {0x0ea5, 0x0ea7, 2},
+       {0x0eaa, 0x0eab, 1},
+       {0x0ead, 0x0eb0, 1},
+       {0x0eb2, 0x0eb3, 1},
+       {0x0ebd, 0x0ec0, 3},
+       {0x0ec1, 0x0ec4, 1},
+       {0x0edc, 0x0edd, 1},
+       {0x0f00, 0x0f40, 64},
+       {0x0f41, 0x0f47, 1},
+       {0x0f49, 0x0f6c, 1},
+       {0x0f88, 0x0f8b, 1},
+       {0x1000, 0x102a, 1},
+       {0x103f, 0x1050, 17},
+       {0x1051, 0x1055, 1},
+       {0x105a, 0x105d, 1},
+       {0x1061, 0x1065, 4},
+       {0x1066, 0x106e, 8},
+       {0x106f, 0x1070, 1},
+       {0x1075, 0x1081, 1},
+       {0x108e, 0x10d0, 66},
+       {0x10d1, 0x10fa, 1},
+       {0x1100, 0x1248, 1},
+       {0x124a, 0x124d, 1},
+       {0x1250, 0x1256, 1},
+       {0x1258, 0x125a, 2},
+       {0x125b, 0x125d, 1},
+       {0x1260, 0x1288, 1},
+       {0x128a, 0x128d, 1},
+       {0x1290, 0x12b0, 1},
+       {0x12b2, 0x12b5, 1},
+       {0x12b8, 0x12be, 1},
+       {0x12c0, 0x12c2, 2},
+       {0x12c3, 0x12c5, 1},
+       {0x12c8, 0x12d6, 1},
+       {0x12d8, 0x1310, 1},
+       {0x1312, 0x1315, 1},
+       {0x1318, 0x135a, 1},
+       {0x1380, 0x138f, 1},
+       {0x13a0, 0x13f4, 1},
+       {0x1401, 0x166c, 1},
+       {0x166f, 0x167f, 1},
+       {0x1681, 0x169a, 1},
+       {0x16a0, 0x16ea, 1},
+       {0x1700, 0x170c, 1},
+       {0x170e, 0x1711, 1},
+       {0x1720, 0x1731, 1},
+       {0x1740, 0x1751, 1},
+       {0x1760, 0x176c, 1},
+       {0x176e, 0x1770, 1},
+       {0x1780, 0x17b3, 1},
+       {0x17dc, 0x1820, 68},
+       {0x1821, 0x1842, 1},
+       {0x1844, 0x1877, 1},
+       {0x1880, 0x18a8, 1},
+       {0x18aa, 0x18b0, 6},
+       {0x18b1, 0x18f5, 1},
+       {0x1900, 0x191c, 1},
+       {0x1950, 0x196d, 1},
+       {0x1970, 0x1974, 1},
+       {0x1980, 0x19ab, 1},
+       {0x19c1, 0x19c7, 1},
+       {0x1a00, 0x1a16, 1},
+       {0x1a20, 0x1a54, 1},
+       {0x1b05, 0x1b33, 1},
+       {0x1b45, 0x1b4b, 1},
+       {0x1b83, 0x1ba0, 1},
+       {0x1bae, 0x1baf, 1},
+       {0x1c00, 0x1c23, 1},
+       {0x1c4d, 0x1c4f, 1},
+       {0x1c5a, 0x1c77, 1},
+       {0x1ce9, 0x1cec, 1},
+       {0x1cee, 0x1cf1, 1},
+       {0x2135, 0x2138, 1},
+       {0x2d30, 0x2d65, 1},
+       {0x2d80, 0x2d96, 1},
+       {0x2da0, 0x2da6, 1},
+       {0x2da8, 0x2dae, 1},
+       {0x2db0, 0x2db6, 1},
+       {0x2db8, 0x2dbe, 1},
+       {0x2dc0, 0x2dc6, 1},
+       {0x2dc8, 0x2dce, 1},
+       {0x2dd0, 0x2dd6, 1},
+       {0x2dd8, 0x2dde, 1},
+       {0x3006, 0x303c, 54},
+       {0x3041, 0x3096, 1},
+       {0x309f, 0x30a1, 2},
+       {0x30a2, 0x30fa, 1},
+       {0x30ff, 0x3105, 6},
+       {0x3106, 0x312d, 1},
+       {0x3131, 0x318e, 1},
+       {0x31a0, 0x31b7, 1},
+       {0x31f0, 0x31ff, 1},
+       {0x3400, 0x4db5, 1},
+       {0x4e00, 0x9fcb, 1},
+       {0xa000, 0xa014, 1},
+       {0xa016, 0xa48c, 1},
+       {0xa4d0, 0xa4f7, 1},
+       {0xa500, 0xa60b, 1},
+       {0xa610, 0xa61f, 1},
+       {0xa62a, 0xa62b, 1},
+       {0xa66e, 0xa6a0, 50},
+       {0xa6a1, 0xa6e5, 1},
+       {0xa7fb, 0xa801, 1},
+       {0xa803, 0xa805, 1},
+       {0xa807, 0xa80a, 1},
+       {0xa80c, 0xa822, 1},
+       {0xa840, 0xa873, 1},
+       {0xa882, 0xa8b3, 1},
+       {0xa8f2, 0xa8f7, 1},
+       {0xa8fb, 0xa90a, 15},
+       {0xa90b, 0xa925, 1},
+       {0xa930, 0xa946, 1},
+       {0xa960, 0xa97c, 1},
+       {0xa984, 0xa9b2, 1},
+       {0xaa00, 0xaa28, 1},
+       {0xaa40, 0xaa42, 1},
+       {0xaa44, 0xaa4b, 1},
+       {0xaa60, 0xaa6f, 1},
+       {0xaa71, 0xaa76, 1},
+       {0xaa7a, 0xaa80, 6},
+       {0xaa81, 0xaaaf, 1},
+       {0xaab1, 0xaab5, 4},
+       {0xaab6, 0xaab9, 3},
+       {0xaaba, 0xaabd, 1},
+       {0xaac0, 0xaac2, 2},
+       {0xaadb, 0xaadc, 1},
+       {0xabc0, 0xabe2, 1},
+       {0xac00, 0xd7a3, 1},
+       {0xd7b0, 0xd7c6, 1},
+       {0xd7cb, 0xd7fb, 1},
+       {0xf900, 0xfa2d, 1},
+       {0xfa30, 0xfa6d, 1},
+       {0xfa70, 0xfad9, 1},
+       {0xfb1d, 0xfb1f, 2},
+       {0xfb20, 0xfb28, 1},
+       {0xfb2a, 0xfb36, 1},
+       {0xfb38, 0xfb3c, 1},
+       {0xfb3e, 0xfb40, 2},
+       {0xfb41, 0xfb43, 2},
+       {0xfb44, 0xfb46, 2},
+       {0xfb47, 0xfbb1, 1},
+       {0xfbd3, 0xfd3d, 1},
+       {0xfd50, 0xfd8f, 1},
+       {0xfd92, 0xfdc7, 1},
+       {0xfdf0, 0xfdfb, 1},
+       {0xfe70, 0xfe74, 1},
+       {0xfe76, 0xfefc, 1},
+       {0xff66, 0xff6f, 1},
+       {0xff71, 0xff9d, 1},
+       {0xffa0, 0xffbe, 1},
+       {0xffc2, 0xffc7, 1},
+       {0xffca, 0xffcf, 1},
+       {0xffd2, 0xffd7, 1},
+       {0xffda, 0xffdc, 1},
+       {0x10000, 0x1000b, 1},
+       {0x1000d, 0x10026, 1},
+       {0x10028, 0x1003a, 1},
+       {0x1003c, 0x1003d, 1},
+       {0x1003f, 0x1004d, 1},
+       {0x10050, 0x1005d, 1},
+       {0x10080, 0x100fa, 1},
+       {0x10280, 0x1029c, 1},
+       {0x102a0, 0x102d0, 1},
+       {0x10300, 0x1031e, 1},
+       {0x10330, 0x10340, 1},
+       {0x10342, 0x10349, 1},
+       {0x10380, 0x1039d, 1},
+       {0x103a0, 0x103c3, 1},
+       {0x103c8, 0x103cf, 1},
+       {0x10450, 0x1049d, 1},
+       {0x10800, 0x10805, 1},
+       {0x10808, 0x1080a, 2},
+       {0x1080b, 0x10835, 1},
+       {0x10837, 0x10838, 1},
+       {0x1083c, 0x1083f, 3},
+       {0x10840, 0x10855, 1},
+       {0x10900, 0x10915, 1},
+       {0x10920, 0x10939, 1},
+       {0x10a00, 0x10a10, 16},
+       {0x10a11, 0x10a13, 1},
+       {0x10a15, 0x10a17, 1},
+       {0x10a19, 0x10a33, 1},
+       {0x10a60, 0x10a7c, 1},
+       {0x10b00, 0x10b35, 1},
+       {0x10b40, 0x10b55, 1},
+       {0x10b60, 0x10b72, 1},
+       {0x10c00, 0x10c48, 1},
+       {0x11083, 0x110af, 1},
+       {0x12000, 0x1236e, 1},
+       {0x13000, 0x1342e, 1},
+       {0x20000, 0x2a6d6, 1},
+       {0x2a700, 0x2b734, 1},
+       {0x2f800, 0x2fa1d, 1},
+}
+
+var (
+       Cc     = _Cc    // Cc is the set of Unicode characters in category Cc.
+       Cf     = _Cf    // Cf is the set of Unicode characters in category Cf.
+       Co     = _Co    // Co is the set of Unicode characters in category Co.
+       Cs     = _Cs    // Cs is the set of Unicode characters in category Cs.
+       Digit  = _Nd    // Digit is the set of Unicode characters with the "decimal digit" property.
+       Nd     = _Nd    // Nd is the set of Unicode characters in category Nd.
+       Letter = letter // Letter is the set of Unicode letters.
+       Lm     = _Lm    // Lm is the set of Unicode characters in category Lm.
+       Lo     = _Lo    // Lo is the set of Unicode characters in category Lo.
+       Lower  = _Ll    // Lower is the set of Unicode lower case letters.
+       Ll     = _Ll    // Ll is the set of Unicode characters in category Ll.
+       Mc     = _Mc    // Mc is the set of Unicode characters in category Mc.
+       Me     = _Me    // Me is the set of Unicode characters in category Me.
+       Mn     = _Mn    // Mn is the set of Unicode characters in category Mn.
+       Nl     = _Nl    // Nl is the set of Unicode characters in category Nl.
+       No     = _No    // No is the set of Unicode characters in category No.
+       Pc     = _Pc    // Pc is the set of Unicode characters in category Pc.
+       Pd     = _Pd    // Pd is the set of Unicode characters in category Pd.
+       Pe     = _Pe    // Pe is the set of Unicode characters in category Pe.
+       Pf     = _Pf    // Pf is the set of Unicode characters in category Pf.
+       Pi     = _Pi    // Pi is the set of Unicode characters in category Pi.
+       Po     = _Po    // Po is the set of Unicode characters in category Po.
+       Ps     = _Ps    // Ps is the set of Unicode characters in category Ps.
+       Sc     = _Sc    // Sc is the set of Unicode characters in category Sc.
+       Sk     = _Sk    // Sk is the set of Unicode characters in category Sk.
+       Sm     = _Sm    // Sm is the set of Unicode characters in category Sm.
+       So     = _So    // So is the set of Unicode characters in category So.
+       Title  = _Lt    // Title is the set of Unicode title case letters.
+       Lt     = _Lt    // Lt is the set of Unicode characters in category Lt.
+       Upper  = _Lu    // Upper is the set of Unicode upper case letters.
+       Lu     = _Lu    // Lu is the set of Unicode characters in category Lu.
+       Zl     = _Zl    // Zl is the set of Unicode characters in category Zl.
+       Zp     = _Zp    // Zp is the set of Unicode characters in category Zp.
+       Zs     = _Zs    // Zs is the set of Unicode characters in category Zs.
+)
+
+// Generated by running
+//     maketables --scripts=all --url=http://www.unicode.org/Public/5.2.0/ucd/
+// DO NOT EDIT
+
+// Scripts is the set of Unicode script tables.
+var Scripts = map[string][]Range{
+       "Katakana":               Katakana,
+       "Malayalam":              Malayalam,
+       "Phags_Pa":               Phags_Pa,
+       "Inscriptional_Parthian": Inscriptional_Parthian,
+       "Latin":                  Latin,
+       "Inscriptional_Pahlavi":  Inscriptional_Pahlavi,
+       "Osmanya":                Osmanya,
+       "Khmer":                  Khmer,
+       "Inherited":              Inherited,
+       "Telugu":                 Telugu,
+       "Samaritan":              Samaritan,
+       "Bopomofo":               Bopomofo,
+       "Imperial_Aramaic":       Imperial_Aramaic,
+       "Kaithi":                 Kaithi,
+       "Old_South_Arabian":      Old_South_Arabian,
+       "Kayah_Li":               Kayah_Li,
+       "New_Tai_Lue":            New_Tai_Lue,
+       "Tai_Le":                 Tai_Le,
+       "Kharoshthi":             Kharoshthi,
+       "Common":                 Common,
+       "Kannada":                Kannada,
+       "Old_Turkic":             Old_Turkic,
+       "Tamil":                  Tamil,
+       "Tagalog":                Tagalog,
+       "Arabic":                 Arabic,
+       "Tagbanwa":               Tagbanwa,
+       "Canadian_Aboriginal":    Canadian_Aboriginal,
+       "Tibetan":                Tibetan,
+       "Coptic":                 Coptic,
+       "Hiragana":               Hiragana,
+       "Limbu":                  Limbu,
+       "Egyptian_Hieroglyphs":   Egyptian_Hieroglyphs,
+       "Avestan":                Avestan,
+       "Myanmar":                Myanmar,
+       "Armenian":               Armenian,
+       "Sinhala":                Sinhala,
+       "Bengali":                Bengali,
+       "Greek":                  Greek,
+       "Cham":                   Cham,
+       "Hebrew":                 Hebrew,
+       "Meetei_Mayek":           Meetei_Mayek,
+       "Saurashtra":             Saurashtra,
+       "Hangul":                 Hangul,
+       "Runic":                  Runic,
+       "Deseret":                Deseret,
+       "Lisu":                   Lisu,
+       "Sundanese":              Sundanese,
+       "Glagolitic":             Glagolitic,
+       "Oriya":                  Oriya,
+       "Buhid":                  Buhid,
+       "Ethiopic":               Ethiopic,
+       "Javanese":               Javanese,
+       "Syloti_Nagri":           Syloti_Nagri,
+       "Vai":                    Vai,
+       "Cherokee":               Cherokee,
+       "Ogham":                  Ogham,
+       "Syriac":                 Syriac,
+       "Gurmukhi":               Gurmukhi,
+       "Tai_Tham":               Tai_Tham,
+       "Ol_Chiki":               Ol_Chiki,
+       "Mongolian":              Mongolian,
+       "Hanunoo":                Hanunoo,
+       "Cypriot":                Cypriot,
+       "Buginese":               Buginese,
+       "Bamum":                  Bamum,
+       "Lepcha":                 Lepcha,
+       "Thaana":                 Thaana,
+       "Old_Persian":            Old_Persian,
+       "Cuneiform":              Cuneiform,
+       "Rejang":                 Rejang,
+       "Georgian":               Georgian,
+       "Shavian":                Shavian,
+       "Lycian":                 Lycian,
+       "Nko":                    Nko,
+       "Yi":                     Yi,
+       "Lao":                    Lao,
+       "Linear_B":               Linear_B,
+       "Old_Italic":             Old_Italic,
+       "Tai_Viet":               Tai_Viet,
+       "Devanagari":             Devanagari,
+       "Lydian":                 Lydian,
+       "Tifinagh":               Tifinagh,
+       "Ugaritic":               Ugaritic,
+       "Thai":                   Thai,
+       "Cyrillic":               Cyrillic,
+       "Gujarati":               Gujarati,
+       "Carian":                 Carian,
+       "Phoenician":             Phoenician,
+       "Balinese":               Balinese,
+       "Braille":                Braille,
+       "Han":                    Han,
+       "Gothic":                 Gothic,
+}
+
+var _Katakana = []Range{
+       {0x30a1, 0x30fa, 1},
+       {0x30fd, 0x30ff, 1},
+       {0x31f0, 0x31ff, 1},
+       {0x32d0, 0x32fe, 1},
+       {0x3300, 0x3357, 1},
+       {0xff66, 0xff6f, 1},
+       {0xff71, 0xff9d, 1},
+}
+
+var _Malayalam = []Range{
+       {0x0d02, 0x0d03, 1},
+       {0x0d05, 0x0d0c, 1},
+       {0x0d0e, 0x0d10, 1},
+       {0x0d12, 0x0d28, 1},
+       {0x0d2a, 0x0d39, 1},
+       {0x0d3d, 0x0d44, 1},
+       {0x0d46, 0x0d48, 1},
+       {0x0d4a, 0x0d4d, 1},
+       {0x0d57, 0x0d57, 1},
+       {0x0d60, 0x0d63, 1},
+       {0x0d66, 0x0d75, 1},
+       {0x0d79, 0x0d7f, 1},
+}
+
+var _Phags_Pa = []Range{
+       {0xa840, 0xa877, 1},
+}
+
+var _Inscriptional_Parthian = []Range{
+       {0x10b40, 0x10b55, 1},
+       {0x10b58, 0x10b5f, 1},
+}
+
+var _Latin = []Range{
+       {0x0041, 0x005a, 1},
+       {0x0061, 0x007a, 1},
+       {0x00aa, 0x00aa, 1},
+       {0x00ba, 0x00ba, 1},
+       {0x00c0, 0x00d6, 1},
+       {0x00d8, 0x00f6, 1},
+       {0x00f8, 0x02b8, 1},
+       {0x02e0, 0x02e4, 1},
+       {0x1d00, 0x1d25, 1},
+       {0x1d2c, 0x1d5c, 1},
+       {0x1d62, 0x1d65, 1},
+       {0x1d6b, 0x1d77, 1},
+       {0x1d79, 0x1dbe, 1},
+       {0x1e00, 0x1eff, 1},
+       {0x2071, 0x2071, 1},
+       {0x207f, 0x207f, 1},
+       {0x2090, 0x2094, 1},
+       {0x212a, 0x212b, 1},
+       {0x2132, 0x2132, 1},
+       {0x214e, 0x214e, 1},
+       {0x2160, 0x2188, 1},
+       {0x2c60, 0x2c7f, 1},
+       {0xa722, 0xa787, 1},
+       {0xa78b, 0xa78c, 1},
+       {0xa7fb, 0xa7ff, 1},
+       {0xfb00, 0xfb06, 1},
+       {0xff21, 0xff3a, 1},
+       {0xff41, 0xff5a, 1},
+}
+
+var _Inscriptional_Pahlavi = []Range{
+       {0x10b60, 0x10b72, 1},
+       {0x10b78, 0x10b7f, 1},
+}
+
+var _Osmanya = []Range{
+       {0x10480, 0x1049d, 1},
+       {0x104a0, 0x104a9, 1},
+}
+
+var _Khmer = []Range{
+       {0x1780, 0x17dd, 1},
+       {0x17e0, 0x17e9, 1},
+       {0x17f0, 0x17f9, 1},
+       {0x19e0, 0x19ff, 1},
+}
+
+var _Inherited = []Range{
+       {0x0300, 0x036f, 1},
+       {0x0485, 0x0486, 1},
+       {0x064b, 0x0655, 1},
+       {0x0670, 0x0670, 1},
+       {0x0951, 0x0952, 1},
+       {0x1cd0, 0x1cd2, 1},
+       {0x1cd4, 0x1ce0, 1},
+       {0x1ce2, 0x1ce8, 1},
+       {0x1ced, 0x1ced, 1},
+       {0x1dc0, 0x1de6, 1},
+       {0x1dfd, 0x1dff, 1},
+       {0x200c, 0x200d, 1},
+       {0x20d0, 0x20f0, 1},
+       {0x302a, 0x302f, 1},
+       {0x3099, 0x309a, 1},
+       {0xfe00, 0xfe0f, 1},
+       {0xfe20, 0xfe26, 1},
+       {0x101fd, 0x101fd, 1},
+       {0x1d167, 0x1d169, 1},
+       {0x1d17b, 0x1d182, 1},
+       {0x1d185, 0x1d18b, 1},
+       {0x1d1aa, 0x1d1ad, 1},
+       {0xe0100, 0xe01ef, 1},
+}
+
+var _Telugu = []Range{
+       {0x0c01, 0x0c03, 1},
+       {0x0c05, 0x0c0c, 1},
+       {0x0c0e, 0x0c10, 1},
+       {0x0c12, 0x0c28, 1},
+       {0x0c2a, 0x0c33, 1},
+       {0x0c35, 0x0c39, 1},
+       {0x0c3d, 0x0c44, 1},
+       {0x0c46, 0x0c48, 1},
+       {0x0c4a, 0x0c4d, 1},
+       {0x0c55, 0x0c56, 1},
+       {0x0c58, 0x0c59, 1},
+       {0x0c60, 0x0c63, 1},
+       {0x0c66, 0x0c6f, 1},
+       {0x0c78, 0x0c7f, 1},
+}
+
+var _Samaritan = []Range{
+       {0x0800, 0x082d, 1},
+       {0x0830, 0x083e, 1},
+}
+
+var _Bopomofo = []Range{
+       {0x3105, 0x312d, 1},
+       {0x31a0, 0x31b7, 1},
+}
+
+var _Imperial_Aramaic = []Range{
+       {0x10840, 0x10855, 1},
+       {0x10857, 0x1085f, 1},
+}
+
+var _Kaithi = []Range{
+       {0x11080, 0x110c1, 1},
+}
+
+var _Old_South_Arabian = []Range{
+       {0x10a60, 0x10a7f, 1},
+}
+
+var _Kayah_Li = []Range{
+       {0xa900, 0xa92f, 1},
+}
+
+var _New_Tai_Lue = []Range{
+       {0x1980, 0x19ab, 1},
+       {0x19b0, 0x19c9, 1},
+       {0x19d0, 0x19da, 1},
+       {0x19de, 0x19df, 1},
+}
+
+var _Tai_Le = []Range{
+       {0x1950, 0x196d, 1},
+       {0x1970, 0x1974, 1},
+}
+
+var _Kharoshthi = []Range{
+       {0x10a00, 0x10a03, 1},
+       {0x10a05, 0x10a06, 1},
+       {0x10a0c, 0x10a13, 1},
+       {0x10a15, 0x10a17, 1},
+       {0x10a19, 0x10a33, 1},
+       {0x10a38, 0x10a3a, 1},
+       {0x10a3f, 0x10a47, 1},
+       {0x10a50, 0x10a58, 1},
+}
+
+var _Common = []Range{
+       {0x0000, 0x0040, 1},
+       {0x005b, 0x0060, 1},
+       {0x007b, 0x00a9, 1},
+       {0x00ab, 0x00b9, 1},
+       {0x00bb, 0x00bf, 1},
+       {0x00d7, 0x00d7, 1},
+       {0x00f7, 0x00f7, 1},
+       {0x02b9, 0x02df, 1},
+       {0x02e5, 0x02ff, 1},
+       {0x0374, 0x0374, 1},
+       {0x037e, 0x037e, 1},
+       {0x0385, 0x0385, 1},
+       {0x0387, 0x0387, 1},
+       {0x0589, 0x0589, 1},
+       {0x0600, 0x0603, 1},
+       {0x060c, 0x060c, 1},
+       {0x061b, 0x061b, 1},
+       {0x061f, 0x061f, 1},
+       {0x0640, 0x0640, 1},
+       {0x0660, 0x0669, 1},
+       {0x06dd, 0x06dd, 1},
+       {0x0964, 0x0965, 1},
+       {0x0970, 0x0970, 1},
+       {0x0cf1, 0x0cf2, 1},
+       {0x0e3f, 0x0e3f, 1},
+       {0x0fd5, 0x0fd8, 1},
+       {0x10fb, 0x10fb, 1},
+       {0x16eb, 0x16ed, 1},
+       {0x1735, 0x1736, 1},
+       {0x1802, 0x1803, 1},
+       {0x1805, 0x1805, 1},
+       {0x1cd3, 0x1cd3, 1},
+       {0x1ce1, 0x1ce1, 1},
+       {0x1ce9, 0x1cec, 1},
+       {0x1cee, 0x1cf2, 1},
+       {0x2000, 0x200b, 1},
+       {0x200e, 0x2064, 1},
+       {0x206a, 0x2070, 1},
+       {0x2074, 0x207e, 1},
+       {0x2080, 0x208e, 1},
+       {0x20a0, 0x20b8, 1},
+       {0x2100, 0x2125, 1},
+       {0x2127, 0x2129, 1},
+       {0x212c, 0x2131, 1},
+       {0x2133, 0x214d, 1},
+       {0x214f, 0x215f, 1},
+       {0x2189, 0x2189, 1},
+       {0x2190, 0x23e8, 1},
+       {0x2400, 0x2426, 1},
+       {0x2440, 0x244a, 1},
+       {0x2460, 0x26cd, 1},
+       {0x26cf, 0x26e1, 1},
+       {0x26e3, 0x26e3, 1},
+       {0x26e8, 0x26ff, 1},
+       {0x2701, 0x2704, 1},
+       {0x2706, 0x2709, 1},
+       {0x270c, 0x2727, 1},
+       {0x2729, 0x274b, 1},
+       {0x274d, 0x274d, 1},
+       {0x274f, 0x2752, 1},
+       {0x2756, 0x275e, 1},
+       {0x2761, 0x2794, 1},
+       {0x2798, 0x27af, 1},
+       {0x27b1, 0x27be, 1},
+       {0x27c0, 0x27ca, 1},
+       {0x27cc, 0x27cc, 1},
+       {0x27d0, 0x27ff, 1},
+       {0x2900, 0x2b4c, 1},
+       {0x2b50, 0x2b59, 1},
+       {0x2e00, 0x2e31, 1},
+       {0x2ff0, 0x2ffb, 1},
+       {0x3000, 0x3004, 1},
+       {0x3006, 0x3006, 1},
+       {0x3008, 0x3020, 1},
+       {0x3030, 0x3037, 1},
+       {0x303c, 0x303f, 1},
+       {0x309b, 0x309c, 1},
+       {0x30a0, 0x30a0, 1},
+       {0x30fb, 0x30fc, 1},
+       {0x3190, 0x319f, 1},
+       {0x31c0, 0x31e3, 1},
+       {0x3220, 0x325f, 1},
+       {0x327f, 0x32cf, 1},
+       {0x3358, 0x33ff, 1},
+       {0x4dc0, 0x4dff, 1},
+       {0xa700, 0xa721, 1},
+       {0xa788, 0xa78a, 1},
+       {0xa830, 0xa839, 1},
+       {0xfd3e, 0xfd3f, 1},
+       {0xfdfd, 0xfdfd, 1},
+       {0xfe10, 0xfe19, 1},
+       {0xfe30, 0xfe52, 1},
+       {0xfe54, 0xfe66, 1},
+       {0xfe68, 0xfe6b, 1},
+       {0xfeff, 0xfeff, 1},
+       {0xff01, 0xff20, 1},
+       {0xff3b, 0xff40, 1},
+       {0xff5b, 0xff65, 1},
+       {0xff70, 0xff70, 1},
+       {0xff9e, 0xff9f, 1},
+       {0xffe0, 0xffe6, 1},
+       {0xffe8, 0xffee, 1},
+       {0xfff9, 0xfffd, 1},
+       {0x10100, 0x10102, 1},
+       {0x10107, 0x10133, 1},
+       {0x10137, 0x1013f, 1},
+       {0x10190, 0x1019b, 1},
+       {0x101d0, 0x101fc, 1},
+       {0x1d000, 0x1d0f5, 1},
+       {0x1d100, 0x1d126, 1},
+       {0x1d129, 0x1d166, 1},
+       {0x1d16a, 0x1d17a, 1},
+       {0x1d183, 0x1d184, 1},
+       {0x1d18c, 0x1d1a9, 1},
+       {0x1d1ae, 0x1d1dd, 1},
+       {0x1d300, 0x1d356, 1},
+       {0x1d360, 0x1d371, 1},
+       {0x1d400, 0x1d454, 1},
+       {0x1d456, 0x1d49c, 1},
+       {0x1d49e, 0x1d49f, 1},
+       {0x1d4a2, 0x1d4a2, 1},
+       {0x1d4a5, 0x1d4a6, 1},
+       {0x1d4a9, 0x1d4ac, 1},
+       {0x1d4ae, 0x1d4b9, 1},
+       {0x1d4bb, 0x1d4bb, 1},
+       {0x1d4bd, 0x1d4c3, 1},
+       {0x1d4c5, 0x1d505, 1},
+       {0x1d507, 0x1d50a, 1},
+       {0x1d50d, 0x1d514, 1},
+       {0x1d516, 0x1d51c, 1},
+       {0x1d51e, 0x1d539, 1},
+       {0x1d53b, 0x1d53e, 1},
+       {0x1d540, 0x1d544, 1},
+       {0x1d546, 0x1d546, 1},
+       {0x1d54a, 0x1d550, 1},
+       {0x1d552, 0x1d6a5, 1},
+       {0x1d6a8, 0x1d7cb, 1},
+       {0x1d7ce, 0x1d7ff, 1},
+       {0x1f000, 0x1f02b, 1},
+       {0x1f030, 0x1f093, 1},
+       {0x1f100, 0x1f10a, 1},
+       {0x1f110, 0x1f12e, 1},
+       {0x1f131, 0x1f131, 1},
+       {0x1f13d, 0x1f13d, 1},
+       {0x1f13f, 0x1f13f, 1},
+       {0x1f142, 0x1f142, 1},
+       {0x1f146, 0x1f146, 1},
+       {0x1f14a, 0x1f14e, 1},
+       {0x1f157, 0x1f157, 1},
+       {0x1f15f, 0x1f15f, 1},
+       {0x1f179, 0x1f179, 1},
+       {0x1f17b, 0x1f17c, 1},
+       {0x1f17f, 0x1f17f, 1},
+       {0x1f18a, 0x1f18d, 1},
+       {0x1f190, 0x1f190, 1},
+       {0x1f210, 0x1f231, 1},
+       {0x1f240, 0x1f248, 1},
+       {0xe0001, 0xe0001, 1},
+       {0xe0020, 0xe007f, 1},
+}
+
+var _Kannada = []Range{
+       {0x0c82, 0x0c83, 1},
+       {0x0c85, 0x0c8c, 1},
+       {0x0c8e, 0x0c90, 1},
+       {0x0c92, 0x0ca8, 1},
+       {0x0caa, 0x0cb3, 1},
+       {0x0cb5, 0x0cb9, 1},
+       {0x0cbc, 0x0cc4, 1},
+       {0x0cc6, 0x0cc8, 1},
+       {0x0cca, 0x0ccd, 1},
+       {0x0cd5, 0x0cd6, 1},
+       {0x0cde, 0x0cde, 1},
+       {0x0ce0, 0x0ce3, 1},
+       {0x0ce6, 0x0cef, 1},
+}
+
+var _Old_Turkic = []Range{
+       {0x10c00, 0x10c48, 1},
+}
+
+var _Tamil = []Range{
+       {0x0b82, 0x0b83, 1},
+       {0x0b85, 0x0b8a, 1},
+       {0x0b8e, 0x0b90, 1},
+       {0x0b92, 0x0b95, 1},
+       {0x0b99, 0x0b9a, 1},
+       {0x0b9c, 0x0b9c, 1},
+       {0x0b9e, 0x0b9f, 1},
+       {0x0ba3, 0x0ba4, 1},
+       {0x0ba8, 0x0baa, 1},
+       {0x0bae, 0x0bb9, 1},
+       {0x0bbe, 0x0bc2, 1},
+       {0x0bc6, 0x0bc8, 1},
+       {0x0bca, 0x0bcd, 1},
+       {0x0bd0, 0x0bd0, 1},
+       {0x0bd7, 0x0bd7, 1},
+       {0x0be6, 0x0bfa, 1},
+}
+
+var _Tagalog = []Range{
+       {0x1700, 0x170c, 1},
+       {0x170e, 0x1714, 1},
+}
+
+var _Arabic = []Range{
+       {0x0606, 0x060b, 1},
+       {0x060d, 0x061a, 1},
+       {0x061e, 0x061e, 1},
+       {0x0621, 0x063f, 1},
+       {0x0641, 0x064a, 1},
+       {0x0656, 0x065e, 1},
+       {0x066a, 0x066f, 1},
+       {0x0671, 0x06dc, 1},
+       {0x06de, 0x06ff, 1},
+       {0x0750, 0x077f, 1},
+       {0xfb50, 0xfbb1, 1},
+       {0xfbd3, 0xfd3d, 1},
+       {0xfd50, 0xfd8f, 1},
+       {0xfd92, 0xfdc7, 1},
+       {0xfdf0, 0xfdfc, 1},
+       {0xfe70, 0xfe74, 1},
+       {0xfe76, 0xfefc, 1},
+       {0x10e60, 0x10e7e, 1},
+}
+
+var _Tagbanwa = []Range{
+       {0x1760, 0x176c, 1},
+       {0x176e, 0x1770, 1},
+       {0x1772, 0x1773, 1},
+}
+
+var _Canadian_Aboriginal = []Range{
+       {0x1400, 0x167f, 1},
+       {0x18b0, 0x18f5, 1},
+}
+
+var _Tibetan = []Range{
+       {0x0f00, 0x0f47, 1},
+       {0x0f49, 0x0f6c, 1},
+       {0x0f71, 0x0f8b, 1},
+       {0x0f90, 0x0f97, 1},
+       {0x0f99, 0x0fbc, 1},
+       {0x0fbe, 0x0fcc, 1},
+       {0x0fce, 0x0fd4, 1},
+}
+
+var _Coptic = []Range{
+       {0x03e2, 0x03ef, 1},
+       {0x2c80, 0x2cf1, 1},
+       {0x2cf9, 0x2cff, 1},
+}
+
+var _Hiragana = []Range{
+       {0x3041, 0x3096, 1},
+       {0x309d, 0x309f, 1},
+       {0x1f200, 0x1f200, 1},
+}
+
+var _Limbu = []Range{
+       {0x1900, 0x191c, 1},
+       {0x1920, 0x192b, 1},
+       {0x1930, 0x193b, 1},
+       {0x1940, 0x1940, 1},
+       {0x1944, 0x194f, 1},
+}
+
+var _Egyptian_Hieroglyphs = []Range{
+       {0x13000, 0x1342e, 1},
+}
+
+var _Avestan = []Range{
+       {0x10b00, 0x10b35, 1},
+       {0x10b39, 0x10b3f, 1},
+}
+
+var _Myanmar = []Range{
+       {0x1000, 0x109f, 1},
+       {0xaa60, 0xaa7b, 1},
+}
+
+var _Armenian = []Range{
+       {0x0531, 0x0556, 1},
+       {0x0559, 0x055f, 1},
+       {0x0561, 0x0587, 1},
+       {0x058a, 0x058a, 1},
+       {0xfb13, 0xfb17, 1},
+}
+
+var _Sinhala = []Range{
+       {0x0d82, 0x0d83, 1},
+       {0x0d85, 0x0d96, 1},
+       {0x0d9a, 0x0db1, 1},
+       {0x0db3, 0x0dbb, 1},
+       {0x0dbd, 0x0dbd, 1},
+       {0x0dc0, 0x0dc6, 1},
+       {0x0dca, 0x0dca, 1},
+       {0x0dcf, 0x0dd4, 1},
+       {0x0dd6, 0x0dd6, 1},
+       {0x0dd8, 0x0ddf, 1},
+       {0x0df2, 0x0df4, 1},
+}
+
+var _Bengali = []Range{
+       {0x0981, 0x0983, 1},
+       {0x0985, 0x098c, 1},
+       {0x098f, 0x0990, 1},
+       {0x0993, 0x09a8, 1},
+       {0x09aa, 0x09b0, 1},
+       {0x09b2, 0x09b2, 1},
+       {0x09b6, 0x09b9, 1},
+       {0x09bc, 0x09c4, 1},
+       {0x09c7, 0x09c8, 1},
+       {0x09cb, 0x09ce, 1},
+       {0x09d7, 0x09d7, 1},
+       {0x09dc, 0x09dd, 1},
+       {0x09df, 0x09e3, 1},
+       {0x09e6, 0x09fb, 1},
+}
+
+var _Greek = []Range{
+       {0x0370, 0x0373, 1},
+       {0x0375, 0x0377, 1},
+       {0x037a, 0x037d, 1},
+       {0x0384, 0x0384, 1},
+       {0x0386, 0x0386, 1},
+       {0x0388, 0x038a, 1},
+       {0x038c, 0x038c, 1},
+       {0x038e, 0x03a1, 1},
+       {0x03a3, 0x03e1, 1},
+       {0x03f0, 0x03ff, 1},
+       {0x1d26, 0x1d2a, 1},
+       {0x1d5d, 0x1d61, 1},
+       {0x1d66, 0x1d6a, 1},
+       {0x1dbf, 0x1dbf, 1},
+       {0x1f00, 0x1f15, 1},
+       {0x1f18, 0x1f1d, 1},
+       {0x1f20, 0x1f45, 1},
+       {0x1f48, 0x1f4d, 1},
+       {0x1f50, 0x1f57, 1},
+       {0x1f59, 0x1f59, 1},
+       {0x1f5b, 0x1f5b, 1},
+       {0x1f5d, 0x1f5d, 1},
+       {0x1f5f, 0x1f7d, 1},
+       {0x1f80, 0x1fb4, 1},
+       {0x1fb6, 0x1fc4, 1},
+       {0x1fc6, 0x1fd3, 1},
+       {0x1fd6, 0x1fdb, 1},
+       {0x1fdd, 0x1fef, 1},
+       {0x1ff2, 0x1ff4, 1},
+       {0x1ff6, 0x1ffe, 1},
+       {0x2126, 0x2126, 1},
+       {0x10140, 0x1018a, 1},
+       {0x1d200, 0x1d245, 1},
+}
+
+var _Cham = []Range{
+       {0xaa00, 0xaa36, 1},
+       {0xaa40, 0xaa4d, 1},
+       {0xaa50, 0xaa59, 1},
+       {0xaa5c, 0xaa5f, 1},
+}
+
+var _Hebrew = []Range{
+       {0x0591, 0x05c7, 1},
+       {0x05d0, 0x05ea, 1},
+       {0x05f0, 0x05f4, 1},
+       {0xfb1d, 0xfb36, 1},
+       {0xfb38, 0xfb3c, 1},
+       {0xfb3e, 0xfb3e, 1},
+       {0xfb40, 0xfb41, 1},
+       {0xfb43, 0xfb44, 1},
+       {0xfb46, 0xfb4f, 1},
+}
+
+var _Meetei_Mayek = []Range{
+       {0xabc0, 0xabed, 1},
+       {0xabf0, 0xabf9, 1},
+}
+
+var _Saurashtra = []Range{
+       {0xa880, 0xa8c4, 1},
+       {0xa8ce, 0xa8d9, 1},
+}
+
+var _Hangul = []Range{
+       {0x1100, 0x11ff, 1},
+       {0x3131, 0x318e, 1},
+       {0x3200, 0x321e, 1},
+       {0x3260, 0x327e, 1},
+       {0xa960, 0xa97c, 1},
+       {0xac00, 0xd7a3, 1},
+       {0xd7b0, 0xd7c6, 1},
+       {0xd7cb, 0xd7fb, 1},
+       {0xffa0, 0xffbe, 1},
+       {0xffc2, 0xffc7, 1},
+       {0xffca, 0xffcf, 1},
+       {0xffd2, 0xffd7, 1},
+       {0xffda, 0xffdc, 1},
+}
+
+var _Runic = []Range{
+       {0x16a0, 0x16ea, 1},
+       {0x16ee, 0x16f0, 1},
+}
+
+var _Deseret = []Range{
+       {0x10400, 0x1044f, 1},
+}
+
+var _Lisu = []Range{
+       {0xa4d0, 0xa4ff, 1},
+}
+
+var _Sundanese = []Range{
+       {0x1b80, 0x1baa, 1},
+       {0x1bae, 0x1bb9, 1},
+}
+
+var _Glagolitic = []Range{
+       {0x2c00, 0x2c2e, 1},
+       {0x2c30, 0x2c5e, 1},
+}
+
+var _Oriya = []Range{
+       {0x0b01, 0x0b03, 1},
+       {0x0b05, 0x0b0c, 1},
+       {0x0b0f, 0x0b10, 1},
+       {0x0b13, 0x0b28, 1},
+       {0x0b2a, 0x0b30, 1},
+       {0x0b32, 0x0b33, 1},
+       {0x0b35, 0x0b39, 1},
+       {0x0b3c, 0x0b44, 1},
+       {0x0b47, 0x0b48, 1},
+       {0x0b4b, 0x0b4d, 1},
+       {0x0b56, 0x0b57, 1},
+       {0x0b5c, 0x0b5d, 1},
+       {0x0b5f, 0x0b63, 1},
+       {0x0b66, 0x0b71, 1},
+}
+
+var _Buhid = []Range{
+       {0x1740, 0x1753, 1},
+}
+
+var _Ethiopic = []Range{
+       {0x1200, 0x1248, 1},
+       {0x124a, 0x124d, 1},
+       {0x1250, 0x1256, 1},
+       {0x1258, 0x1258, 1},
+       {0x125a, 0x125d, 1},
+       {0x1260, 0x1288, 1},
+       {0x128a, 0x128d, 1},
+       {0x1290, 0x12b0, 1},
+       {0x12b2, 0x12b5, 1},
+       {0x12b8, 0x12be, 1},
+       {0x12c0, 0x12c0, 1},
+       {0x12c2, 0x12c5, 1},
+       {0x12c8, 0x12d6, 1},
+       {0x12d8, 0x1310, 1},
+       {0x1312, 0x1315, 1},
+       {0x1318, 0x135a, 1},
+       {0x135f, 0x137c, 1},
+       {0x1380, 0x1399, 1},
+       {0x2d80, 0x2d96, 1},
+       {0x2da0, 0x2da6, 1},
+       {0x2da8, 0x2dae, 1},
+       {0x2db0, 0x2db6, 1},
+       {0x2db8, 0x2dbe, 1},
+       {0x2dc0, 0x2dc6, 1},
+       {0x2dc8, 0x2dce, 1},
+       {0x2dd0, 0x2dd6, 1},
+       {0x2dd8, 0x2dde, 1},
+}
+
+var _Javanese = []Range{
+       {0xa980, 0xa9cd, 1},
+       {0xa9cf, 0xa9d9, 1},
+       {0xa9de, 0xa9df, 1},
+}
+
+var _Syloti_Nagri = []Range{
+       {0xa800, 0xa82b, 1},
+}
+
+var _Vai = []Range{
+       {0xa500, 0xa62b, 1},
+}
+
+var _Cherokee = []Range{
+       {0x13a0, 0x13f4, 1},
+}
+
+var _Ogham = []Range{
+       {0x1680, 0x169c, 1},
+}
+
+var _Syriac = []Range{
+       {0x0700, 0x070d, 1},
+       {0x070f, 0x074a, 1},
+       {0x074d, 0x074f, 1},
+}
+
+var _Gurmukhi = []Range{
+       {0x0a01, 0x0a03, 1},
+       {0x0a05, 0x0a0a, 1},
+       {0x0a0f, 0x0a10, 1},
+       {0x0a13, 0x0a28, 1},
+       {0x0a2a, 0x0a30, 1},
+       {0x0a32, 0x0a33, 1},
+       {0x0a35, 0x0a36, 1},
+       {0x0a38, 0x0a39, 1},
+       {0x0a3c, 0x0a3c, 1},
+       {0x0a3e, 0x0a42, 1},
+       {0x0a47, 0x0a48, 1},
+       {0x0a4b, 0x0a4d, 1},
+       {0x0a51, 0x0a51, 1},
+       {0x0a59, 0x0a5c, 1},
+       {0x0a5e, 0x0a5e, 1},
+       {0x0a66, 0x0a75, 1},
+}
+
+var _Tai_Tham = []Range{
+       {0x1a20, 0x1a5e, 1},
+       {0x1a60, 0x1a7c, 1},
+       {0x1a7f, 0x1a89, 1},
+       {0x1a90, 0x1a99, 1},
+       {0x1aa0, 0x1aad, 1},
+}
+
+var _Ol_Chiki = []Range{
+       {0x1c50, 0x1c7f, 1},
+}
+
+var _Mongolian = []Range{
+       {0x1800, 0x1801, 1},
+       {0x1804, 0x1804, 1},
+       {0x1806, 0x180e, 1},
+       {0x1810, 0x1819, 1},
+       {0x1820, 0x1877, 1},
+       {0x1880, 0x18aa, 1},
+}
+
+var _Hanunoo = []Range{
+       {0x1720, 0x1734, 1},
+}
+
+var _Cypriot = []Range{
+       {0x10800, 0x10805, 1},
+       {0x10808, 0x10808, 1},
+       {0x1080a, 0x10835, 1},
+       {0x10837, 0x10838, 1},
+       {0x1083c, 0x1083c, 1},
+       {0x1083f, 0x1083f, 1},
+}
+
+var _Buginese = []Range{
+       {0x1a00, 0x1a1b, 1},
+       {0x1a1e, 0x1a1f, 1},
+}
+
+var _Bamum = []Range{
+       {0xa6a0, 0xa6f7, 1},
+}
+
+var _Lepcha = []Range{
+       {0x1c00, 0x1c37, 1},
+       {0x1c3b, 0x1c49, 1},
+       {0x1c4d, 0x1c4f, 1},
+}
+
+var _Thaana = []Range{
+       {0x0780, 0x07b1, 1},
+}
+
+var _Old_Persian = []Range{
+       {0x103a0, 0x103c3, 1},
+       {0x103c8, 0x103d5, 1},
+}
+
+var _Cuneiform = []Range{
+       {0x12000, 0x1236e, 1},
+       {0x12400, 0x12462, 1},
+       {0x12470, 0x12473, 1},
+}
+
+var _Rejang = []Range{
+       {0xa930, 0xa953, 1},
+       {0xa95f, 0xa95f, 1},
+}
+
+var _Georgian = []Range{
+       {0x10a0, 0x10c5, 1},
+       {0x10d0, 0x10fa, 1},
+       {0x10fc, 0x10fc, 1},
+       {0x2d00, 0x2d25, 1},
+}
+
+var _Shavian = []Range{
+       {0x10450, 0x1047f, 1},
+}
+
+var _Lycian = []Range{
+       {0x10280, 0x1029c, 1},
+}
+
+var _Nko = []Range{
+       {0x07c0, 0x07fa, 1},
+}
+
+var _Yi = []Range{
+       {0xa000, 0xa48c, 1},
+       {0xa490, 0xa4c6, 1},
+}
+
+var _Lao = []Range{
+       {0x0e81, 0x0e82, 1},
+       {0x0e84, 0x0e84, 1},
+       {0x0e87, 0x0e88, 1},
+       {0x0e8a, 0x0e8a, 1},
+       {0x0e8d, 0x0e8d, 1},
+       {0x0e94, 0x0e97, 1},
+       {0x0e99, 0x0e9f, 1},
+       {0x0ea1, 0x0ea3, 1},
+       {0x0ea5, 0x0ea5, 1},
+       {0x0ea7, 0x0ea7, 1},
+       {0x0eaa, 0x0eab, 1},
+       {0x0ead, 0x0eb9, 1},
+       {0x0ebb, 0x0ebd, 1},
+       {0x0ec0, 0x0ec4, 1},
+       {0x0ec6, 0x0ec6, 1},
+       {0x0ec8, 0x0ecd, 1},
+       {0x0ed0, 0x0ed9, 1},
+       {0x0edc, 0x0edd, 1},
+}
+
+var _Linear_B = []Range{
+       {0x10000, 0x1000b, 1},
+       {0x1000d, 0x10026, 1},
+       {0x10028, 0x1003a, 1},
+       {0x1003c, 0x1003d, 1},
+       {0x1003f, 0x1004d, 1},
+       {0x10050, 0x1005d, 1},
+       {0x10080, 0x100fa, 1},
+}
+
+var _Old_Italic = []Range{
+       {0x10300, 0x1031e, 1},
+       {0x10320, 0x10323, 1},
+}
+
+var _Tai_Viet = []Range{
+       {0xaa80, 0xaac2, 1},
+       {0xaadb, 0xaadf, 1},
+}
+
+var _Devanagari = []Range{
+       {0x0900, 0x0939, 1},
+       {0x093c, 0x094e, 1},
+       {0x0950, 0x0950, 1},
+       {0x0953, 0x0955, 1},
+       {0x0958, 0x0963, 1},
+       {0x0966, 0x096f, 1},
+       {0x0971, 0x0972, 1},
+       {0x0979, 0x097f, 1},
+       {0xa8e0, 0xa8fb, 1},
+}
+
+var _Lydian = []Range{
+       {0x10920, 0x10939, 1},
+       {0x1093f, 0x1093f, 1},
+}
+
+var _Tifinagh = []Range{
+       {0x2d30, 0x2d65, 1},
+       {0x2d6f, 0x2d6f, 1},
+}
+
+var _Ugaritic = []Range{
+       {0x10380, 0x1039d, 1},
+       {0x1039f, 0x1039f, 1},
+}
+
+var _Thai = []Range{
+       {0x0e01, 0x0e3a, 1},
+       {0x0e40, 0x0e5b, 1},
+}
+
+var _Cyrillic = []Range{
+       {0x0400, 0x0484, 1},
+       {0x0487, 0x0525, 1},
+       {0x1d2b, 0x1d2b, 1},
+       {0x1d78, 0x1d78, 1},
+       {0x2de0, 0x2dff, 1},
+       {0xa640, 0xa65f, 1},
+       {0xa662, 0xa673, 1},
+       {0xa67c, 0xa697, 1},
+}
+
+var _Gujarati = []Range{
+       {0x0a81, 0x0a83, 1},
+       {0x0a85, 0x0a8d, 1},
+       {0x0a8f, 0x0a91, 1},
+       {0x0a93, 0x0aa8, 1},
+       {0x0aaa, 0x0ab0, 1},
+       {0x0ab2, 0x0ab3, 1},
+       {0x0ab5, 0x0ab9, 1},
+       {0x0abc, 0x0ac5, 1},
+       {0x0ac7, 0x0ac9, 1},
+       {0x0acb, 0x0acd, 1},
+       {0x0ad0, 0x0ad0, 1},
+       {0x0ae0, 0x0ae3, 1},
+       {0x0ae6, 0x0aef, 1},
+       {0x0af1, 0x0af1, 1},
+}
+
+var _Carian = []Range{
+       {0x102a0, 0x102d0, 1},
+}
+
+var _Phoenician = []Range{
+       {0x10900, 0x1091b, 1},
+       {0x1091f, 0x1091f, 1},
+}
+
+var _Balinese = []Range{
+       {0x1b00, 0x1b4b, 1},
+       {0x1b50, 0x1b7c, 1},
+}
+
+var _Braille = []Range{
+       {0x2800, 0x28ff, 1},
+}
+
+var _Han = []Range{
+       {0x2e80, 0x2e99, 1},
+       {0x2e9b, 0x2ef3, 1},
+       {0x2f00, 0x2fd5, 1},
+       {0x3005, 0x3005, 1},
+       {0x3007, 0x3007, 1},
+       {0x3021, 0x3029, 1},
+       {0x3038, 0x303b, 1},
+       {0x3400, 0x4db5, 1},
+       {0x4e00, 0x9fcb, 1},
+       {0xf900, 0xfa2d, 1},
+       {0xfa30, 0xfa6d, 1},
+       {0xfa70, 0xfad9, 1},
+       {0x20000, 0x2a6d6, 1},
+       {0x2a700, 0x2b734, 1},
+       {0x2f800, 0x2fa1d, 1},
+}
+
+var _Gothic = []Range{
+       {0x10330, 0x1034a, 1},
+}
+
+var (
+       Arabic                 = _Arabic                 // Arabic is the set of Unicode characters in script Arabic.
+       Armenian               = _Armenian               // Armenian is the set of Unicode characters in script Armenian.
+       Avestan                = _Avestan                // Avestan is the set of Unicode characters in script Avestan.
+       Balinese               = _Balinese               // Balinese is the set of Unicode characters in script Balinese.
+       Bamum                  = _Bamum                  // Bamum is the set of Unicode characters in script Bamum.
+       Bengali                = _Bengali                // Bengali is the set of Unicode characters in script Bengali.
+       Bopomofo               = _Bopomofo               // Bopomofo is the set of Unicode characters in script Bopomofo.
+       Braille                = _Braille                // Braille is the set of Unicode characters in script Braille.
+       Buginese               = _Buginese               // Buginese is the set of Unicode characters in script Buginese.
+       Buhid                  = _Buhid                  // Buhid is the set of Unicode characters in script Buhid.
+       Canadian_Aboriginal    = _Canadian_Aboriginal    // Canadian_Aboriginal is the set of Unicode characters in script Canadian_Aboriginal.
+       Carian                 = _Carian                 // Carian is the set of Unicode characters in script Carian.
+       Cham                   = _Cham                   // Cham is the set of Unicode characters in script Cham.
+       Cherokee               = _Cherokee               // Cherokee is the set of Unicode characters in script Cherokee.
+       Common                 = _Common                 // Common is the set of Unicode characters in script Common.
+       Coptic                 = _Coptic                 // Coptic is the set of Unicode characters in script Coptic.
+       Cuneiform              = _Cuneiform              // Cuneiform is the set of Unicode characters in script Cuneiform.
+       Cypriot                = _Cypriot                // Cypriot is the set of Unicode characters in script Cypriot.
+       Cyrillic               = _Cyrillic               // Cyrillic is the set of Unicode characters in script Cyrillic.
+       Deseret                = _Deseret                // Deseret is the set of Unicode characters in script Deseret.
+       Devanagari             = _Devanagari             // Devanagari is the set of Unicode characters in script Devanagari.
+       Egyptian_Hieroglyphs   = _Egyptian_Hieroglyphs   // Egyptian_Hieroglyphs is the set of Unicode characters in script Egyptian_Hieroglyphs.
+       Ethiopic               = _Ethiopic               // Ethiopic is the set of Unicode characters in script Ethiopic.
+       Georgian               = _Georgian               // Georgian is the set of Unicode characters in script Georgian.
+       Glagolitic             = _Glagolitic             // Glagolitic is the set of Unicode characters in script Glagolitic.
+       Gothic                 = _Gothic                 // Gothic is the set of Unicode characters in script Gothic.
+       Greek                  = _Greek                  // Greek is the set of Unicode characters in script Greek.
+       Gujarati               = _Gujarati               // Gujarati is the set of Unicode characters in script Gujarati.
+       Gurmukhi               = _Gurmukhi               // Gurmukhi is the set of Unicode characters in script Gurmukhi.
+       Han                    = _Han                    // Han is the set of Unicode characters in script Han.
+       Hangul                 = _Hangul                 // Hangul is the set of Unicode characters in script Hangul.
+       Hanunoo                = _Hanunoo                // Hanunoo is the set of Unicode characters in script Hanunoo.
+       Hebrew                 = _Hebrew                 // Hebrew is the set of Unicode characters in script Hebrew.
+       Hiragana               = _Hiragana               // Hiragana is the set of Unicode characters in script Hiragana.
+       Imperial_Aramaic       = _Imperial_Aramaic       // Imperial_Aramaic is the set of Unicode characters in script Imperial_Aramaic.
+       Inherited              = _Inherited              // Inherited is the set of Unicode characters in script Inherited.
+       Inscriptional_Pahlavi  = _Inscriptional_Pahlavi  // Inscriptional_Pahlavi is the set of Unicode characters in script Inscriptional_Pahlavi.
+       Inscriptional_Parthian = _Inscriptional_Parthian // Inscriptional_Parthian is the set of Unicode characters in script Inscriptional_Parthian.
+       Javanese               = _Javanese               // Javanese is the set of Unicode characters in script Javanese.
+       Kaithi                 = _Kaithi                 // Kaithi is the set of Unicode characters in script Kaithi.
+       Kannada                = _Kannada                // Kannada is the set of Unicode characters in script Kannada.
+       Katakana               = _Katakana               // Katakana is the set of Unicode characters in script Katakana.
+       Kayah_Li               = _Kayah_Li               // Kayah_Li is the set of Unicode characters in script Kayah_Li.
+       Kharoshthi             = _Kharoshthi             // Kharoshthi is the set of Unicode characters in script Kharoshthi.
+       Khmer                  = _Khmer                  // Khmer is the set of Unicode characters in script Khmer.
+       Lao                    = _Lao                    // Lao is the set of Unicode characters in script Lao.
+       Latin                  = _Latin                  // Latin is the set of Unicode characters in script Latin.
+       Lepcha                 = _Lepcha                 // Lepcha is the set of Unicode characters in script Lepcha.
+       Limbu                  = _Limbu                  // Limbu is the set of Unicode characters in script Limbu.
+       Linear_B               = _Linear_B               // Linear_B is the set of Unicode characters in script Linear_B.
+       Lisu                   = _Lisu                   // Lisu is the set of Unicode characters in script Lisu.
+       Lycian                 = _Lycian                 // Lycian is the set of Unicode characters in script Lycian.
+       Lydian                 = _Lydian                 // Lydian is the set of Unicode characters in script Lydian.
+       Malayalam              = _Malayalam              // Malayalam is the set of Unicode characters in script Malayalam.
+       Meetei_Mayek           = _Meetei_Mayek           // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek.
+       Mongolian              = _Mongolian              // Mongolian is the set of Unicode characters in script Mongolian.
+       Myanmar                = _Myanmar                // Myanmar is the set of Unicode characters in script Myanmar.
+       New_Tai_Lue            = _New_Tai_Lue            // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue.
+       Nko                    = _Nko                    // Nko is the set of Unicode characters in script Nko.
+       Ogham                  = _Ogham                  // Ogham is the set of Unicode characters in script Ogham.
+       Ol_Chiki               = _Ol_Chiki               // Ol_Chiki is the set of Unicode characters in script Ol_Chiki.
+       Old_Italic             = _Old_Italic             // Old_Italic is the set of Unicode characters in script Old_Italic.
+       Old_Persian            = _Old_Persian            // Old_Persian is the set of Unicode characters in script Old_Persian.
+       Old_South_Arabian      = _Old_South_Arabian      // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian.
+       Old_Turkic             = _Old_Turkic             // Old_Turkic is the set of Unicode characters in script Old_Turkic.
+       Oriya                  = _Oriya                  // Oriya is the set of Unicode characters in script Oriya.
+       Osmanya                = _Osmanya                // Osmanya is the set of Unicode characters in script Osmanya.
+       Phags_Pa               = _Phags_Pa               // Phags_Pa is the set of Unicode characters in script Phags_Pa.
+       Phoenician             = _Phoenician             // Phoenician is the set of Unicode characters in script Phoenician.
+       Rejang                 = _Rejang                 // Rejang is the set of Unicode characters in script Rejang.
+       Runic                  = _Runic                  // Runic is the set of Unicode characters in script Runic.
+       Samaritan              = _Samaritan              // Samaritan is the set of Unicode characters in script Samaritan.
+       Saurashtra             = _Saurashtra             // Saurashtra is the set of Unicode characters in script Saurashtra.
+       Shavian                = _Shavian                // Shavian is the set of Unicode characters in script Shavian.
+       Sinhala                = _Sinhala                // Sinhala is the set of Unicode characters in script Sinhala.
+       Sundanese              = _Sundanese              // Sundanese is the set of Unicode characters in script Sundanese.
+       Syloti_Nagri           = _Syloti_Nagri           // Syloti_Nagri is the set of Unicode characters in script Syloti_Nagri.
+       Syriac                 = _Syriac                 // Syriac is the set of Unicode characters in script Syriac.
+       Tagalog                = _Tagalog                // Tagalog is the set of Unicode characters in script Tagalog.
+       Tagbanwa               = _Tagbanwa               // Tagbanwa is the set of Unicode characters in script Tagbanwa.
+       Tai_Le                 = _Tai_Le                 // Tai_Le is the set of Unicode characters in script Tai_Le.
+       Tai_Tham               = _Tai_Tham               // Tai_Tham is the set of Unicode characters in script Tai_Tham.
+       Tai_Viet               = _Tai_Viet               // Tai_Viet is the set of Unicode characters in script Tai_Viet.
+       Tamil                  = _Tamil                  // Tamil is the set of Unicode characters in script Tamil.
+       Telugu                 = _Telugu                 // Telugu is the set of Unicode characters in script Telugu.
+       Thaana                 = _Thaana                 // Thaana is the set of Unicode characters in script Thaana.
+       Thai                   = _Thai                   // Thai is the set of Unicode characters in script Thai.
+       Tibetan                = _Tibetan                // Tibetan is the set of Unicode characters in script Tibetan.
+       Tifinagh               = _Tifinagh               // Tifinagh is the set of Unicode characters in script Tifinagh.
+       Ugaritic               = _Ugaritic               // Ugaritic is the set of Unicode characters in script Ugaritic.
+       Vai                    = _Vai                    // Vai is the set of Unicode characters in script Vai.
+       Yi                     = _Yi                     // Yi is the set of Unicode characters in script Yi.
+)
+
+// Generated by running
+//     maketables --props=all --url=http://www.unicode.org/Public/5.2.0/ucd/
+// DO NOT EDIT
+
+// Properties is the set of Unicode property tables.
+var Properties = map[string][]Range{
+       "Pattern_Syntax":                     Pattern_Syntax,
+       "Other_ID_Start":                     Other_ID_Start,
+       "Pattern_White_Space":                Pattern_White_Space,
+       "Other_Lowercase":                    Other_Lowercase,
+       "Soft_Dotted":                        Soft_Dotted,
+       "Hex_Digit":                          Hex_Digit,
+       "ASCII_Hex_Digit":                    ASCII_Hex_Digit,
+       "Deprecated":                         Deprecated,
+       "Terminal_Punctuation":               Terminal_Punctuation,
+       "Quotation_Mark":                     Quotation_Mark,
+       "Other_ID_Continue":                  Other_ID_Continue,
+       "Bidi_Control":                       Bidi_Control,
+       "Variation_Selector":                 Variation_Selector,
+       "Noncharacter_Code_Point":            Noncharacter_Code_Point,
+       "Other_Math":                         Other_Math,
+       "Unified_Ideograph":                  Unified_Ideograph,
+       "Hyphen":                             Hyphen,
+       "IDS_Binary_Operator":                IDS_Binary_Operator,
+       "Logical_Order_Exception":            Logical_Order_Exception,
+       "Radical":                            Radical,
+       "Other_Uppercase":                    Other_Uppercase,
+       "STerm":                              STerm,
+       "Other_Alphabetic":                   Other_Alphabetic,
+       "Diacritic":                          Diacritic,
+       "Extender":                           Extender,
+       "Join_Control":                       Join_Control,
+       "Ideographic":                        Ideographic,
+       "Dash":                               Dash,
+       "IDS_Trinary_Operator":               IDS_Trinary_Operator,
+       "Other_Grapheme_Extend":              Other_Grapheme_Extend,
+       "Other_Default_Ignorable_Code_Point": Other_Default_Ignorable_Code_Point,
+       "White_Space":                        White_Space,
+}
+
+var _Pattern_Syntax = []Range{
+       {0x0021, 0x002f, 1},
+       {0x003a, 0x0040, 1},
+       {0x005b, 0x005e, 1},
+       {0x0060, 0x0060, 1},
+       {0x007b, 0x007e, 1},
+       {0x00a1, 0x00a7, 1},
+       {0x00a9, 0x00a9, 1},
+       {0x00ab, 0x00ac, 1},
+       {0x00ae, 0x00ae, 1},
+       {0x00b0, 0x00b1, 1},
+       {0x00b6, 0x00b6, 1},
+       {0x00bb, 0x00bb, 1},
+       {0x00bf, 0x00bf, 1},
+       {0x00d7, 0x00d7, 1},
+       {0x00f7, 0x00f7, 1},
+       {0x2010, 0x2027, 1},
+       {0x2030, 0x203e, 1},
+       {0x2041, 0x2053, 1},
+       {0x2055, 0x205e, 1},
+       {0x2190, 0x245f, 1},
+       {0x2500, 0x2775, 1},
+       {0x2794, 0x2bff, 1},
+       {0x2e00, 0x2e7f, 1},
+       {0x3001, 0x3003, 1},
+       {0x3008, 0x3020, 1},
+       {0x3030, 0x3030, 1},
+       {0xfd3e, 0xfd3f, 1},
+       {0xfe45, 0xfe46, 1},
+}
+
+var _Other_ID_Start = []Range{
+       {0x2118, 0x2118, 1},
+       {0x212e, 0x212e, 1},
+       {0x309b, 0x309c, 1},
+}
+
+var _Pattern_White_Space = []Range{
+       {0x0009, 0x000d, 1},
+       {0x0020, 0x0020, 1},
+       {0x0085, 0x0085, 1},
+       {0x200e, 0x200f, 1},
+       {0x2028, 0x2029, 1},
+}
+
+var _Other_Lowercase = []Range{
+       {0x02b0, 0x02b8, 1},
+       {0x02c0, 0x02c1, 1},
+       {0x02e0, 0x02e4, 1},
+       {0x0345, 0x0345, 1},
+       {0x037a, 0x037a, 1},
+       {0x1d2c, 0x1d61, 1},
+       {0x1d78, 0x1d78, 1},
+       {0x1d9b, 0x1dbf, 1},
+       {0x2090, 0x2094, 1},
+       {0x2170, 0x217f, 1},
+       {0x24d0, 0x24e9, 1},
+       {0x2c7d, 0x2c7d, 1},
+       {0xa770, 0xa770, 1},
+}
+
+var _Soft_Dotted = []Range{
+       {0x0069, 0x006a, 1},
+       {0x012f, 0x012f, 1},
+       {0x0249, 0x0249, 1},
+       {0x0268, 0x0268, 1},
+       {0x029d, 0x029d, 1},
+       {0x02b2, 0x02b2, 1},
+       {0x03f3, 0x03f3, 1},
+       {0x0456, 0x0456, 1},
+       {0x0458, 0x0458, 1},
+       {0x1d62, 0x1d62, 1},
+       {0x1d96, 0x1d96, 1},
+       {0x1da4, 0x1da4, 1},
+       {0x1da8, 0x1da8, 1},
+       {0x1e2d, 0x1e2d, 1},
+       {0x1ecb, 0x1ecb, 1},
+       {0x2071, 0x2071, 1},
+       {0x2148, 0x2149, 1},
+       {0x2c7c, 0x2c7c, 1},
+       {0x1d422, 0x1d423, 1},
+       {0x1d456, 0x1d457, 1},
+       {0x1d48a, 0x1d48b, 1},
+       {0x1d4be, 0x1d4bf, 1},
+       {0x1d4f2, 0x1d4f3, 1},
+       {0x1d526, 0x1d527, 1},
+       {0x1d55a, 0x1d55b, 1},
+       {0x1d58e, 0x1d58f, 1},
+       {0x1d5c2, 0x1d5c3, 1},
+       {0x1d5f6, 0x1d5f7, 1},
+       {0x1d62a, 0x1d62b, 1},
+       {0x1d65e, 0x1d65f, 1},
+       {0x1d692, 0x1d693, 1},
+}
+
+var _Hex_Digit = []Range{
+       {0x0030, 0x0039, 1},
+       {0x0041, 0x0046, 1},
+       {0x0061, 0x0066, 1},
+       {0xff10, 0xff19, 1},
+       {0xff21, 0xff26, 1},
+       {0xff41, 0xff46, 1},
+}
+
+var _ASCII_Hex_Digit = []Range{
+       {0x0030, 0x0039, 1},
+       {0x0041, 0x0046, 1},
+       {0x0061, 0x0066, 1},
+}
+
+var _Deprecated = []Range{
+       {0x0149, 0x0149, 1},
+       {0x0f77, 0x0f77, 1},
+       {0x0f79, 0x0f79, 1},
+       {0x17a3, 0x17a4, 1},
+       {0x206a, 0x206f, 1},
+       {0x2329, 0x232a, 1},
+       {0xe0001, 0xe0001, 1},
+       {0xe0020, 0xe007f, 1},
+}
+
+var _Terminal_Punctuation = []Range{
+       {0x0021, 0x0021, 1},
+       {0x002c, 0x002c, 1},
+       {0x002e, 0x002e, 1},
+       {0x003a, 0x003b, 1},
+       {0x003f, 0x003f, 1},
+       {0x037e, 0x037e, 1},
+       {0x0387, 0x0387, 1},
+       {0x0589, 0x0589, 1},
+       {0x05c3, 0x05c3, 1},
+       {0x060c, 0x060c, 1},
+       {0x061b, 0x061b, 1},
+       {0x061f, 0x061f, 1},
+       {0x06d4, 0x06d4, 1},
+       {0x0700, 0x070a, 1},
+       {0x070c, 0x070c, 1},
+       {0x07f8, 0x07f9, 1},
+       {0x0830, 0x083e, 1},
+       {0x0964, 0x0965, 1},
+       {0x0e5a, 0x0e5b, 1},
+       {0x0f08, 0x0f08, 1},
+       {0x0f0d, 0x0f12, 1},
+       {0x104a, 0x104b, 1},
+       {0x1361, 0x1368, 1},
+       {0x166d, 0x166e, 1},
+       {0x16eb, 0x16ed, 1},
+       {0x17d4, 0x17d6, 1},
+       {0x17da, 0x17da, 1},
+       {0x1802, 0x1805, 1},
+       {0x1808, 0x1809, 1},
+       {0x1944, 0x1945, 1},
+       {0x1aa8, 0x1aab, 1},
+       {0x1b5a, 0x1b5b, 1},
+       {0x1b5d, 0x1b5f, 1},
+       {0x1c3b, 0x1c3f, 1},
+       {0x1c7e, 0x1c7f, 1},
+       {0x203c, 0x203d, 1},
+       {0x2047, 0x2049, 1},
+       {0x2e2e, 0x2e2e, 1},
+       {0x3001, 0x3002, 1},
+       {0xa4fe, 0xa4ff, 1},
+       {0xa60d, 0xa60f, 1},
+       {0xa6f3, 0xa6f7, 1},
+       {0xa876, 0xa877, 1},
+       {0xa8ce, 0xa8cf, 1},
+       {0xa92f, 0xa92f, 1},
+       {0xa9c7, 0xa9c9, 1},
+       {0xaa5d, 0xaa5f, 1},
+       {0xaadf, 0xaadf, 1},
+       {0xabeb, 0xabeb, 1},
+       {0xfe50, 0xfe52, 1},
+       {0xfe54, 0xfe57, 1},
+       {0xff01, 0xff01, 1},
+       {0xff0c, 0xff0c, 1},
+       {0xff0e, 0xff0e, 1},
+       {0xff1a, 0xff1b, 1},
+       {0xff1f, 0xff1f, 1},
+       {0xff61, 0xff61, 1},
+       {0xff64, 0xff64, 1},
+       {0x1039f, 0x1039f, 1},
+       {0x103d0, 0x103d0, 1},
+       {0x10857, 0x10857, 1},
+       {0x1091f, 0x1091f, 1},
+       {0x10b3a, 0x10b3f, 1},
+       {0x110be, 0x110c1, 1},
+       {0x12470, 0x12473, 1},
+}
+
+var _Quotation_Mark = []Range{
+       {0x0022, 0x0022, 1},
+       {0x0027, 0x0027, 1},
+       {0x00ab, 0x00ab, 1},
+       {0x00bb, 0x00bb, 1},
+       {0x2018, 0x201f, 1},
+       {0x2039, 0x203a, 1},
+       {0x300c, 0x300f, 1},
+       {0x301d, 0x301f, 1},
+       {0xfe41, 0xfe44, 1},
+       {0xff02, 0xff02, 1},
+       {0xff07, 0xff07, 1},
+       {0xff62, 0xff63, 1},
+}
+
+var _Other_ID_Continue = []Range{
+       {0x00b7, 0x00b7, 1},
+       {0x0387, 0x0387, 1},
+       {0x1369, 0x1371, 1},
+}
+
+var _Bidi_Control = []Range{
+       {0x200e, 0x200f, 1},
+       {0x202a, 0x202e, 1},
+}
+
+var _Variation_Selector = []Range{
+       {0x180b, 0x180d, 1},
+       {0xfe00, 0xfe0f, 1},
+       {0xe0100, 0xe01ef, 1},
+}
+
+var _Noncharacter_Code_Point = []Range{
+       {0xfdd0, 0xfdef, 1},
+       {0xfffe, 0xffff, 1},
+       {0x1fffe, 0x1ffff, 1},
+       {0x2fffe, 0x2ffff, 1},
+       {0x3fffe, 0x3ffff, 1},
+       {0x4fffe, 0x4ffff, 1},
+       {0x5fffe, 0x5ffff, 1},
+       {0x6fffe, 0x6ffff, 1},
+       {0x7fffe, 0x7ffff, 1},
+       {0x8fffe, 0x8ffff, 1},
+       {0x9fffe, 0x9ffff, 1},
+       {0xafffe, 0xaffff, 1},
+       {0xbfffe, 0xbffff, 1},
+       {0xcfffe, 0xcffff, 1},
+       {0xdfffe, 0xdffff, 1},
+       {0xefffe, 0xeffff, 1},
+       {0xffffe, 0xfffff, 1},
+       {0x10fffe, 0x10ffff, 1},
+}
+
+var _Other_Math = []Range{
+       {0x005e, 0x005e, 1},
+       {0x03d0, 0x03d2, 1},
+       {0x03d5, 0x03d5, 1},
+       {0x03f0, 0x03f1, 1},
+       {0x03f4, 0x03f5, 1},
+       {0x2016, 0x2016, 1},
+       {0x2032, 0x2034, 1},
+       {0x2040, 0x2040, 1},
+       {0x2061, 0x2064, 1},
+       {0x207d, 0x207e, 1},
+       {0x208d, 0x208e, 1},
+       {0x20d0, 0x20dc, 1},
+       {0x20e1, 0x20e1, 1},
+       {0x20e5, 0x20e6, 1},
+       {0x20eb, 0x20ef, 1},
+       {0x2102, 0x2102, 1},
+       {0x210a, 0x2113, 1},
+       {0x2115, 0x2115, 1},
+       {0x2119, 0x211d, 1},
+       {0x2124, 0x2124, 1},
+       {0x2128, 0x2129, 1},
+       {0x212c, 0x212d, 1},
+       {0x212f, 0x2131, 1},
+       {0x2133, 0x2138, 1},
+       {0x213c, 0x213f, 1},
+       {0x2145, 0x2149, 1},
+       {0x2195, 0x2199, 1},
+       {0x219c, 0x219f, 1},
+       {0x21a1, 0x21a2, 1},
+       {0x21a4, 0x21a5, 1},
+       {0x21a7, 0x21a7, 1},
+       {0x21a9, 0x21ad, 1},
+       {0x21b0, 0x21b1, 1},
+       {0x21b6, 0x21b7, 1},
+       {0x21bc, 0x21cd, 1},
+       {0x21d0, 0x21d1, 1},
+       {0x21d3, 0x21d3, 1},
+       {0x21d5, 0x21db, 1},
+       {0x21dd, 0x21dd, 1},
+       {0x21e4, 0x21e5, 1},
+       {0x23b4, 0x23b5, 1},
+       {0x23b7, 0x23b7, 1},
+       {0x23d0, 0x23d0, 1},
+       {0x23e2, 0x23e2, 1},
+       {0x25a0, 0x25a1, 1},
+       {0x25ae, 0x25b6, 1},
+       {0x25bc, 0x25c0, 1},
+       {0x25c6, 0x25c7, 1},
+       {0x25ca, 0x25cb, 1},
+       {0x25cf, 0x25d3, 1},
+       {0x25e2, 0x25e2, 1},
+       {0x25e4, 0x25e4, 1},
+       {0x25e7, 0x25ec, 1},
+       {0x2605, 0x2606, 1},
+       {0x2640, 0x2640, 1},
+       {0x2642, 0x2642, 1},
+       {0x2660, 0x2663, 1},
+       {0x266d, 0x266e, 1},
+       {0x27c5, 0x27c6, 1},
+       {0x27e6, 0x27ef, 1},
+       {0x2983, 0x2998, 1},
+       {0x29d8, 0x29db, 1},
+       {0x29fc, 0x29fd, 1},
+       {0xfe61, 0xfe61, 1},
+       {0xfe63, 0xfe63, 1},
+       {0xfe68, 0xfe68, 1},
+       {0xff3c, 0xff3c, 1},
+       {0xff3e, 0xff3e, 1},
+       {0x1d400, 0x1d454, 1},
+       {0x1d456, 0x1d49c, 1},
+       {0x1d49e, 0x1d49f, 1},
+       {0x1d4a2, 0x1d4a2, 1},
+       {0x1d4a5, 0x1d4a6, 1},
+       {0x1d4a9, 0x1d4ac, 1},
+       {0x1d4ae, 0x1d4b9, 1},
+       {0x1d4bb, 0x1d4bb, 1},
+       {0x1d4bd, 0x1d4c3, 1},
+       {0x1d4c5, 0x1d505, 1},
+       {0x1d507, 0x1d50a, 1},
+       {0x1d50d, 0x1d514, 1},
+       {0x1d516, 0x1d51c, 1},
+       {0x1d51e, 0x1d539, 1},
+       {0x1d53b, 0x1d53e, 1},
+       {0x1d540, 0x1d544, 1},
+       {0x1d546, 0x1d546, 1},
+       {0x1d54a, 0x1d550, 1},
+       {0x1d552, 0x1d6a5, 1},
+       {0x1d6a8, 0x1d6c0, 1},
+       {0x1d6c2, 0x1d6da, 1},
+       {0x1d6dc, 0x1d6fa, 1},
+       {0x1d6fc, 0x1d714, 1},
+       {0x1d716, 0x1d734, 1},
+       {0x1d736, 0x1d74e, 1},
+       {0x1d750, 0x1d76e, 1},
+       {0x1d770, 0x1d788, 1},
+       {0x1d78a, 0x1d7a8, 1},
+       {0x1d7aa, 0x1d7c2, 1},
+       {0x1d7c4, 0x1d7cb, 1},
+       {0x1d7ce, 0x1d7ff, 1},
+}
+
+var _Unified_Ideograph = []Range{
+       {0x3400, 0x4db5, 1},
+       {0x4e00, 0x9fcb, 1},
+       {0xfa0e, 0xfa0f, 1},
+       {0xfa11, 0xfa11, 1},
+       {0xfa13, 0xfa14, 1},
+       {0xfa1f, 0xfa1f, 1},
+       {0xfa21, 0xfa21, 1},
+       {0xfa23, 0xfa24, 1},
+       {0xfa27, 0xfa29, 1},
+       {0x20000, 0x2a6d6, 1},
+       {0x2a700, 0x2b734, 1},
+}
+
+var _Hyphen = []Range{
+       {0x002d, 0x002d, 1},
+       {0x00ad, 0x00ad, 1},
+       {0x058a, 0x058a, 1},
+       {0x1806, 0x1806, 1},
+       {0x2010, 0x2011, 1},
+       {0x2e17, 0x2e17, 1},
+       {0x30fb, 0x30fb, 1},
+       {0xfe63, 0xfe63, 1},
+       {0xff0d, 0xff0d, 1},
+       {0xff65, 0xff65, 1},
+}
+
+var _IDS_Binary_Operator = []Range{
+       {0x2ff0, 0x2ff1, 1},
+       {0x2ff4, 0x2ffb, 1},
+}
+
+var _Logical_Order_Exception = []Range{
+       {0x0e40, 0x0e44, 1},
+       {0x0ec0, 0x0ec4, 1},
+       {0xaab5, 0xaab6, 1},
+       {0xaab9, 0xaab9, 1},
+       {0xaabb, 0xaabc, 1},
+}
+
+var _Radical = []Range{
+       {0x2e80, 0x2e99, 1},
+       {0x2e9b, 0x2ef3, 1},
+       {0x2f00, 0x2fd5, 1},
+}
+
+var _Other_Uppercase = []Range{
+       {0x2160, 0x216f, 1},
+       {0x24b6, 0x24cf, 1},
+}
+
+var _STerm = []Range{
+       {0x0021, 0x0021, 1},
+       {0x002e, 0x002e, 1},
+       {0x003f, 0x003f, 1},
+       {0x055c, 0x055c, 1},
+       {0x055e, 0x055e, 1},
+       {0x0589, 0x0589, 1},
+       {0x061f, 0x061f, 1},
+       {0x06d4, 0x06d4, 1},
+       {0x0700, 0x0702, 1},
+       {0x07f9, 0x07f9, 1},
+       {0x0964, 0x0965, 1},
+       {0x104a, 0x104b, 1},
+       {0x1362, 0x1362, 1},
+       {0x1367, 0x1368, 1},
+       {0x166e, 0x166e, 1},
+       {0x1803, 0x1803, 1},
+       {0x1809, 0x1809, 1},
+       {0x1944, 0x1945, 1},
+       {0x1b5a, 0x1b5b, 1},
+       {0x1b5e, 0x1b5f, 1},
+       {0x1c3b, 0x1c3c, 1},
+       {0x1c7e, 0x1c7f, 1},
+       {0x203c, 0x203d, 1},
+       {0x2047, 0x2049, 1},
+       {0x2e2e, 0x2e2e, 1},
+       {0x3002, 0x3002, 1},
+       {0xa4ff, 0xa4ff, 1},
+       {0xa60e, 0xa60f, 1},
+       {0xa6f3, 0xa6f3, 1},
+       {0xa6f7, 0xa6f7, 1},
+       {0xa876, 0xa877, 1},
+       {0xa8ce, 0xa8cf, 1},
+       {0xa92f, 0xa92f, 1},
+       {0xa9c8, 0xa9c9, 1},
+       {0xaa5d, 0xaa5f, 1},
+       {0xabeb, 0xabeb, 1},
+       {0xfe52, 0xfe52, 1},
+       {0xfe56, 0xfe57, 1},
+       {0xff01, 0xff01, 1},
+       {0xff0e, 0xff0e, 1},
+       {0xff1f, 0xff1f, 1},
+       {0xff61, 0xff61, 1},
+       {0x110be, 0x110c1, 1},
+}
+
+var _Other_Alphabetic = []Range{
+       {0x0345, 0x0345, 1},
+       {0x05b0, 0x05bd, 1},
+       {0x05bf, 0x05bf, 1},
+       {0x05c1, 0x05c2, 1},
+       {0x05c4, 0x05c5, 1},
+       {0x05c7, 0x05c7, 1},
+       {0x0610, 0x061a, 1},
+       {0x064b, 0x0657, 1},
+       {0x0659, 0x065e, 1},
+       {0x0670, 0x0670, 1},
+       {0x06d6, 0x06dc, 1},
+       {0x06e1, 0x06e4, 1},
+       {0x06e7, 0x06e8, 1},
+       {0x06ed, 0x06ed, 1},
+       {0x0711, 0x0711, 1},
+       {0x0730, 0x073f, 1},
+       {0x07a6, 0x07b0, 1},
+       {0x0816, 0x0817, 1},
+       {0x081b, 0x0823, 1},
+       {0x0825, 0x0827, 1},
+       {0x0829, 0x082c, 1},
+       {0x0900, 0x0903, 1},
+       {0x093e, 0x094c, 1},
+       {0x094e, 0x094e, 1},
+       {0x0955, 0x0955, 1},
+       {0x0962, 0x0963, 1},
+       {0x0981, 0x0983, 1},
+       {0x09be, 0x09c4, 1},
+       {0x09c7, 0x09c8, 1},
+       {0x09cb, 0x09cc, 1},
+       {0x09d7, 0x09d7, 1},
+       {0x09e2, 0x09e3, 1},
+       {0x0a01, 0x0a03, 1},
+       {0x0a3e, 0x0a42, 1},
+       {0x0a47, 0x0a48, 1},
+       {0x0a4b, 0x0a4c, 1},
+       {0x0a51, 0x0a51, 1},
+       {0x0a70, 0x0a71, 1},
+       {0x0a75, 0x0a75, 1},
+       {0x0a81, 0x0a83, 1},
+       {0x0abe, 0x0ac5, 1},
+       {0x0ac7, 0x0ac9, 1},
+       {0x0acb, 0x0acc, 1},
+       {0x0ae2, 0x0ae3, 1},
+       {0x0b01, 0x0b03, 1},
+       {0x0b3e, 0x0b44, 1},
+       {0x0b47, 0x0b48, 1},
+       {0x0b4b, 0x0b4c, 1},
+       {0x0b56, 0x0b57, 1},
+       {0x0b62, 0x0b63, 1},
+       {0x0b82, 0x0b82, 1},
+       {0x0bbe, 0x0bc2, 1},
+       {0x0bc6, 0x0bc8, 1},
+       {0x0bca, 0x0bcc, 1},
+       {0x0bd7, 0x0bd7, 1},
+       {0x0c01, 0x0c03, 1},
+       {0x0c3e, 0x0c44, 1},
+       {0x0c46, 0x0c48, 1},
+       {0x0c4a, 0x0c4c, 1},
+       {0x0c55, 0x0c56, 1},
+       {0x0c62, 0x0c63, 1},
+       {0x0c82, 0x0c83, 1},
+       {0x0cbe, 0x0cc4, 1},
+       {0x0cc6, 0x0cc8, 1},
+       {0x0cca, 0x0ccc, 1},
+       {0x0cd5, 0x0cd6, 1},
+       {0x0ce2, 0x0ce3, 1},
+       {0x0d02, 0x0d03, 1},
+       {0x0d3e, 0x0d44, 1},
+       {0x0d46, 0x0d48, 1},
+       {0x0d4a, 0x0d4c, 1},
+       {0x0d57, 0x0d57, 1},
+       {0x0d62, 0x0d63, 1},
+       {0x0d82, 0x0d83, 1},
+       {0x0dcf, 0x0dd4, 1},
+       {0x0dd6, 0x0dd6, 1},
+       {0x0dd8, 0x0ddf, 1},
+       {0x0df2, 0x0df3, 1},
+       {0x0e31, 0x0e31, 1},
+       {0x0e34, 0x0e3a, 1},
+       {0x0e4d, 0x0e4d, 1},
+       {0x0eb1, 0x0eb1, 1},
+       {0x0eb4, 0x0eb9, 1},
+       {0x0ebb, 0x0ebc, 1},
+       {0x0ecd, 0x0ecd, 1},
+       {0x0f71, 0x0f81, 1},
+       {0x0f90, 0x0f97, 1},
+       {0x0f99, 0x0fbc, 1},
+       {0x102b, 0x1036, 1},
+       {0x1038, 0x1038, 1},
+       {0x103b, 0x103e, 1},
+       {0x1056, 0x1059, 1},
+       {0x105e, 0x1060, 1},
+       {0x1062, 0x1062, 1},
+       {0x1067, 0x1068, 1},
+       {0x1071, 0x1074, 1},
+       {0x1082, 0x1086, 1},
+       {0x109c, 0x109d, 1},
+       {0x135f, 0x135f, 1},
+       {0x1712, 0x1713, 1},
+       {0x1732, 0x1733, 1},
+       {0x1752, 0x1753, 1},
+       {0x1772, 0x1773, 1},
+       {0x17b6, 0x17c8, 1},
+       {0x18a9, 0x18a9, 1},
+       {0x1920, 0x192b, 1},
+       {0x1930, 0x1938, 1},
+       {0x19b0, 0x19c0, 1},
+       {0x19c8, 0x19c9, 1},
+       {0x1a17, 0x1a1b, 1},
+       {0x1a55, 0x1a5e, 1},
+       {0x1a61, 0x1a74, 1},
+       {0x1b00, 0x1b04, 1},
+       {0x1b35, 0x1b43, 1},
+       {0x1b80, 0x1b82, 1},
+       {0x1ba1, 0x1ba9, 1},
+       {0x1c24, 0x1c35, 1},
+       {0x1cf2, 0x1cf2, 1},
+       {0x24b6, 0x24e9, 1},
+       {0x2de0, 0x2dff, 1},
+       {0xa823, 0xa827, 1},
+       {0xa880, 0xa881, 1},
+       {0xa8b4, 0xa8c3, 1},
+       {0xa926, 0xa92a, 1},
+       {0xa947, 0xa952, 1},
+       {0xa980, 0xa983, 1},
+       {0xa9b3, 0xa9bf, 1},
+       {0xaa29, 0xaa36, 1},
+       {0xaa43, 0xaa43, 1},
+       {0xaa4c, 0xaa4d, 1},
+       {0xaab0, 0xaab0, 1},
+       {0xaab2, 0xaab4, 1},
+       {0xaab7, 0xaab8, 1},
+       {0xaabe, 0xaabe, 1},
+       {0xabe3, 0xabea, 1},
+       {0xfb1e, 0xfb1e, 1},
+       {0x10a01, 0x10a03, 1},
+       {0x10a05, 0x10a06, 1},
+       {0x10a0c, 0x10a0f, 1},
+       {0x11082, 0x11082, 1},
+       {0x110b0, 0x110b8, 1},
+}
+
+var _Diacritic = []Range{
+       {0x005e, 0x005e, 1},
+       {0x0060, 0x0060, 1},
+       {0x00a8, 0x00a8, 1},
+       {0x00af, 0x00af, 1},
+       {0x00b4, 0x00b4, 1},
+       {0x00b7, 0x00b8, 1},
+       {0x02b0, 0x034e, 1},
+       {0x0350, 0x0357, 1},
+       {0x035d, 0x0362, 1},
+       {0x0374, 0x0375, 1},
+       {0x037a, 0x037a, 1},
+       {0x0384, 0x0385, 1},
+       {0x0483, 0x0487, 1},
+       {0x0559, 0x0559, 1},
+       {0x0591, 0x05a1, 1},
+       {0x05a3, 0x05bd, 1},
+       {0x05bf, 0x05bf, 1},
+       {0x05c1, 0x05c2, 1},
+       {0x05c4, 0x05c4, 1},
+       {0x064b, 0x0652, 1},
+       {0x0657, 0x0658, 1},
+       {0x06df, 0x06e0, 1},
+       {0x06e5, 0x06e6, 1},
+       {0x06ea, 0x06ec, 1},
+       {0x0730, 0x074a, 1},
+       {0x07a6, 0x07b0, 1},
+       {0x07eb, 0x07f5, 1},
+       {0x0818, 0x0819, 1},
+       {0x093c, 0x093c, 1},
+       {0x094d, 0x094d, 1},
+       {0x0951, 0x0954, 1},
+       {0x0971, 0x0971, 1},
+       {0x09bc, 0x09bc, 1},
+       {0x09cd, 0x09cd, 1},
+       {0x0a3c, 0x0a3c, 1},
+       {0x0a4d, 0x0a4d, 1},
+       {0x0abc, 0x0abc, 1},
+       {0x0acd, 0x0acd, 1},
+       {0x0b3c, 0x0b3c, 1},
+       {0x0b4d, 0x0b4d, 1},
+       {0x0bcd, 0x0bcd, 1},
+       {0x0c4d, 0x0c4d, 1},
+       {0x0cbc, 0x0cbc, 1},
+       {0x0ccd, 0x0ccd, 1},
+       {0x0d4d, 0x0d4d, 1},
+       {0x0dca, 0x0dca, 1},
+       {0x0e47, 0x0e4c, 1},
+       {0x0e4e, 0x0e4e, 1},
+       {0x0ec8, 0x0ecc, 1},
+       {0x0f18, 0x0f19, 1},
+       {0x0f35, 0x0f35, 1},
+       {0x0f37, 0x0f37, 1},
+       {0x0f39, 0x0f39, 1},
+       {0x0f3e, 0x0f3f, 1},
+       {0x0f82, 0x0f84, 1},
+       {0x0f86, 0x0f87, 1},
+       {0x0fc6, 0x0fc6, 1},
+       {0x1037, 0x1037, 1},
+       {0x1039, 0x103a, 1},
+       {0x1087, 0x108d, 1},
+       {0x108f, 0x108f, 1},
+       {0x109a, 0x109b, 1},
+       {0x17c9, 0x17d3, 1},
+       {0x17dd, 0x17dd, 1},
+       {0x1939, 0x193b, 1},
+       {0x1a75, 0x1a7c, 1},
+       {0x1a7f, 0x1a7f, 1},
+       {0x1b34, 0x1b34, 1},
+       {0x1b44, 0x1b44, 1},
+       {0x1b6b, 0x1b73, 1},
+       {0x1baa, 0x1baa, 1},
+       {0x1c36, 0x1c37, 1},
+       {0x1c78, 0x1c7d, 1},
+       {0x1cd0, 0x1ce8, 1},
+       {0x1ced, 0x1ced, 1},
+       {0x1d2c, 0x1d6a, 1},
+       {0x1dc4, 0x1dcf, 1},
+       {0x1dfd, 0x1dff, 1},
+       {0x1fbd, 0x1fbd, 1},
+       {0x1fbf, 0x1fc1, 1},
+       {0x1fcd, 0x1fcf, 1},
+       {0x1fdd, 0x1fdf, 1},
+       {0x1fed, 0x1fef, 1},
+       {0x1ffd, 0x1ffe, 1},
+       {0x2cef, 0x2cf1, 1},
+       {0x2e2f, 0x2e2f, 1},
+       {0x302a, 0x302f, 1},
+       {0x3099, 0x309c, 1},
+       {0x30fc, 0x30fc, 1},
+       {0xa66f, 0xa66f, 1},
+       {0xa67c, 0xa67d, 1},
+       {0xa67f, 0xa67f, 1},
+       {0xa6f0, 0xa6f1, 1},
+       {0xa717, 0xa721, 1},
+       {0xa788, 0xa788, 1},
+       {0xa8c4, 0xa8c4, 1},
+       {0xa8e0, 0xa8f1, 1},
+       {0xa92b, 0xa92e, 1},
+       {0xa953, 0xa953, 1},
+       {0xa9b3, 0xa9b3, 1},
+       {0xa9c0, 0xa9c0, 1},
+       {0xaa7b, 0xaa7b, 1},
+       {0xaabf, 0xaac2, 1},
+       {0xabec, 0xabed, 1},
+       {0xfb1e, 0xfb1e, 1},
+       {0xfe20, 0xfe26, 1},
+       {0xff3e, 0xff3e, 1},
+       {0xff40, 0xff40, 1},
+       {0xff70, 0xff70, 1},
+       {0xff9e, 0xff9f, 1},
+       {0xffe3, 0xffe3, 1},
+       {0x110b9, 0x110ba, 1},
+       {0x1d167, 0x1d169, 1},
+       {0x1d16d, 0x1d172, 1},
+       {0x1d17b, 0x1d182, 1},
+       {0x1d185, 0x1d18b, 1},
+       {0x1d1aa, 0x1d1ad, 1},
+}
+
+var _Extender = []Range{
+       {0x00b7, 0x00b7, 1},
+       {0x02d0, 0x02d1, 1},
+       {0x0640, 0x0640, 1},
+       {0x07fa, 0x07fa, 1},
+       {0x0e46, 0x0e46, 1},
+       {0x0ec6, 0x0ec6, 1},
+       {0x1843, 0x1843, 1},
+       {0x1aa7, 0x1aa7, 1},
+       {0x1c36, 0x1c36, 1},
+       {0x1c7b, 0x1c7b, 1},
+       {0x3005, 0x3005, 1},
+       {0x3031, 0x3035, 1},
+       {0x309d, 0x309e, 1},
+       {0x30fc, 0x30fe, 1},
+       {0xa015, 0xa015, 1},
+       {0xa60c, 0xa60c, 1},
+       {0xa9cf, 0xa9cf, 1},
+       {0xaa70, 0xaa70, 1},
+       {0xaadd, 0xaadd, 1},
+       {0xff70, 0xff70, 1},
+}
+
+var _Join_Control = []Range{
+       {0x200c, 0x200d, 1},
+}
+
+var _Ideographic = []Range{
+       {0x3006, 0x3007, 1},
+       {0x3021, 0x3029, 1},
+       {0x3038, 0x303a, 1},
+       {0x3400, 0x4db5, 1},
+       {0x4e00, 0x9fcb, 1},
+       {0xf900, 0xfa2d, 1},
+       {0xfa30, 0xfa6d, 1},
+       {0xfa70, 0xfad9, 1},
+       {0x20000, 0x2a6d6, 1},
+       {0x2a700, 0x2b734, 1},
+       {0x2f800, 0x2fa1d, 1},
+}
+
+var _Dash = []Range{
+       {0x002d, 0x002d, 1},
+       {0x058a, 0x058a, 1},
+       {0x05be, 0x05be, 1},
+       {0x1400, 0x1400, 1},
+       {0x1806, 0x1806, 1},
+       {0x2010, 0x2015, 1},
+       {0x2053, 0x2053, 1},
+       {0x207b, 0x207b, 1},
+       {0x208b, 0x208b, 1},
+       {0x2212, 0x2212, 1},
+       {0x2e17, 0x2e17, 1},
+       {0x2e1a, 0x2e1a, 1},
+       {0x301c, 0x301c, 1},
+       {0x3030, 0x3030, 1},
+       {0x30a0, 0x30a0, 1},
+       {0xfe31, 0xfe32, 1},
+       {0xfe58, 0xfe58, 1},
+       {0xfe63, 0xfe63, 1},
+       {0xff0d, 0xff0d, 1},
+}
+
+var _IDS_Trinary_Operator = []Range{
+       {0x2ff2, 0x2ff3, 1},
+}
+
+var _Other_Grapheme_Extend = []Range{
+       {0x09be, 0x09be, 1},
+       {0x09d7, 0x09d7, 1},
+       {0x0b3e, 0x0b3e, 1},
+       {0x0b57, 0x0b57, 1},
+       {0x0bbe, 0x0bbe, 1},
+       {0x0bd7, 0x0bd7, 1},
+       {0x0cc2, 0x0cc2, 1},
+       {0x0cd5, 0x0cd6, 1},
+       {0x0d3e, 0x0d3e, 1},
+       {0x0d57, 0x0d57, 1},
+       {0x0dcf, 0x0dcf, 1},
+       {0x0ddf, 0x0ddf, 1},
+       {0x200c, 0x200d, 1},
+       {0xff9e, 0xff9f, 1},
+       {0x1d165, 0x1d165, 1},
+       {0x1d16e, 0x1d172, 1},
+}
+
+var _Other_Default_Ignorable_Code_Point = []Range{
+       {0x034f, 0x034f, 1},
+       {0x115f, 0x1160, 1},
+       {0x2065, 0x2069, 1},
+       {0x3164, 0x3164, 1},
+       {0xffa0, 0xffa0, 1},
+       {0xfff0, 0xfff8, 1},
+       {0xe0000, 0xe0000, 1},
+       {0xe0002, 0xe001f, 1},
+       {0xe0080, 0xe00ff, 1},
+       {0xe01f0, 0xe0fff, 1},
+}
+
+var _White_Space = []Range{
+       {0x0009, 0x000d, 1},
+       {0x0020, 0x0020, 1},
+       {0x0085, 0x0085, 1},
+       {0x00a0, 0x00a0, 1},
+       {0x1680, 0x1680, 1},
+       {0x180e, 0x180e, 1},
+       {0x2000, 0x200a, 1},
+       {0x2028, 0x2029, 1},
+       {0x202f, 0x202f, 1},
+       {0x205f, 0x205f, 1},
+       {0x3000, 0x3000, 1},
+}
+
+var (
+       ASCII_Hex_Digit                    = _ASCII_Hex_Digit                    // ASCII_Hex_Digit is the set of Unicode characters with property ASCII_Hex_Digit.
+       Bidi_Control                       = _Bidi_Control                       // Bidi_Control is the set of Unicode characters with property Bidi_Control.
+       Dash                               = _Dash                               // Dash is the set of Unicode characters with property Dash.
+       Deprecated                         = _Deprecated                         // Deprecated is the set of Unicode characters with property Deprecated.
+       Diacritic                          = _Diacritic                          // Diacritic is the set of Unicode characters with property Diacritic.
+       Extender                           = _Extender                           // Extender is the set of Unicode characters with property Extender.
+       Hex_Digit                          = _Hex_Digit                          // Hex_Digit is the set of Unicode characters with property Hex_Digit.
+       Hyphen                             = _Hyphen                             // Hyphen is the set of Unicode characters with property Hyphen.
+       IDS_Binary_Operator                = _IDS_Binary_Operator                // IDS_Binary_Operator is the set of Unicode characters with property IDS_Binary_Operator.
+       IDS_Trinary_Operator               = _IDS_Trinary_Operator               // IDS_Trinary_Operator is the set of Unicode characters with property IDS_Trinary_Operator.
+       Ideographic                        = _Ideographic                        // Ideographic is the set of Unicode characters with property Ideographic.
+       Join_Control                       = _Join_Control                       // Join_Control is the set of Unicode characters with property Join_Control.
+       Logical_Order_Exception            = _Logical_Order_Exception            // Logical_Order_Exception is the set of Unicode characters with property Logical_Order_Exception.
+       Noncharacter_Code_Point            = _Noncharacter_Code_Point            // Noncharacter_Code_Point is the set of Unicode characters with property Noncharacter_Code_Point.
+       Other_Alphabetic                   = _Other_Alphabetic                   // Other_Alphabetic is the set of Unicode characters with property Other_Alphabetic.
+       Other_Default_Ignorable_Code_Point = _Other_Default_Ignorable_Code_Point // Other_Default_Ignorable_Code_Point is the set of Unicode characters with property Other_Default_Ignorable_Code_Point.
+       Other_Grapheme_Extend              = _Other_Grapheme_Extend              // Other_Grapheme_Extend is the set of Unicode characters with property Other_Grapheme_Extend.
+       Other_ID_Continue                  = _Other_ID_Continue                  // Other_ID_Continue is the set of Unicode characters with property Other_ID_Continue.
+       Other_ID_Start                     = _Other_ID_Start                     // Other_ID_Start is the set of Unicode characters with property Other_ID_Start.
+       Other_Lowercase                    = _Other_Lowercase                    // Other_Lowercase is the set of Unicode characters with property Other_Lowercase.
+       Other_Math                         = _Other_Math                         // Other_Math is the set of Unicode characters with property Other_Math.
+       Other_Uppercase                    = _Other_Uppercase                    // Other_Uppercase is the set of Unicode characters with property Other_Uppercase.
+       Pattern_Syntax                     = _Pattern_Syntax                     // Pattern_Syntax is the set of Unicode characters with property Pattern_Syntax.
+       Pattern_White_Space                = _Pattern_White_Space                // Pattern_White_Space is the set of Unicode characters with property Pattern_White_Space.
+       Quotation_Mark                     = _Quotation_Mark                     // Quotation_Mark is the set of Unicode characters with property Quotation_Mark.
+       Radical                            = _Radical                            // Radical is the set of Unicode characters with property Radical.
+       STerm                              = _STerm                              // STerm is the set of Unicode characters with property STerm.
+       Soft_Dotted                        = _Soft_Dotted                        // Soft_Dotted is the set of Unicode characters with property Soft_Dotted.
+       Terminal_Punctuation               = _Terminal_Punctuation               // Terminal_Punctuation is the set of Unicode characters with property Terminal_Punctuation.
+       Unified_Ideograph                  = _Unified_Ideograph                  // Unified_Ideograph is the set of Unicode characters with property Unified_Ideograph.
+       Variation_Selector                 = _Variation_Selector                 // Variation_Selector is the set of Unicode characters with property Variation_Selector.
+       White_Space                        = _White_Space                        // White_Space is the set of Unicode characters with property White_Space.
+)
+
+// Generated by running
+//     maketables --data=http://www.unicode.org/Public/5.2.0/ucd/UnicodeData.txt
+// DO NOT EDIT
+
+// CaseRanges is the table describing case mappings for all letters with
+// non-self mappings.
+var CaseRanges = _CaseRanges
+var _CaseRanges = []CaseRange{
+       {0x0041, 0x005A, d{0, 32, 0}},
+       {0x0061, 0x007A, d{-32, 0, -32}},
+       {0x00B5, 0x00B5, d{743, 0, 743}},
+       {0x00C0, 0x00D6, d{0, 32, 0}},
+       {0x00D8, 0x00DE, d{0, 32, 0}},
+       {0x00E0, 0x00F6, d{-32, 0, -32}},
+       {0x00F8, 0x00FE, d{-32, 0, -32}},
+       {0x00FF, 0x00FF, d{121, 0, 121}},
+       {0x0100, 0x012F, d{UpperLower, UpperLower, UpperLower}},
+       {0x0130, 0x0130, d{0, -199, 0}},
+       {0x0131, 0x0131, d{-232, 0, -232}},
+       {0x0132, 0x0137, d{UpperLower, UpperLower, UpperLower}},
+       {0x0139, 0x0148, d{UpperLower, UpperLower, UpperLower}},
+       {0x014A, 0x0177, d{UpperLower, UpperLower, UpperLower}},
+       {0x0178, 0x0178, d{0, -121, 0}},
+       {0x0179, 0x017E, d{UpperLower, UpperLower, UpperLower}},
+       {0x017F, 0x017F, d{-300, 0, -300}},
+       {0x0180, 0x0180, d{195, 0, 195}},
+       {0x0181, 0x0181, d{0, 210, 0}},
+       {0x0182, 0x0185, d{UpperLower, UpperLower, UpperLower}},
+       {0x0186, 0x0186, d{0, 206, 0}},
+       {0x0187, 0x0188, d{UpperLower, UpperLower, UpperLower}},
+       {0x0189, 0x018A, d{0, 205, 0}},
+       {0x018B, 0x018C, d{UpperLower, UpperLower, UpperLower}},
+       {0x018E, 0x018E, d{0, 79, 0}},
+       {0x018F, 0x018F, d{0, 202, 0}},
+       {0x0190, 0x0190, d{0, 203, 0}},
+       {0x0191, 0x0192, d{UpperLower, UpperLower, UpperLower}},
+       {0x0193, 0x0193, d{0, 205, 0}},
+       {0x0194, 0x0194, d{0, 207, 0}},
+       {0x0195, 0x0195, d{97, 0, 97}},
+       {0x0196, 0x0196, d{0, 211, 0}},
+       {0x0197, 0x0197, d{0, 209, 0}},
+       {0x0198, 0x0199, d{UpperLower, UpperLower, UpperLower}},
+       {0x019A, 0x019A, d{163, 0, 163}},
+       {0x019C, 0x019C, d{0, 211, 0}},
+       {0x019D, 0x019D, d{0, 213, 0}},
+       {0x019E, 0x019E, d{130, 0, 130}},
+       {0x019F, 0x019F, d{0, 214, 0}},
+       {0x01A0, 0x01A5, d{UpperLower, UpperLower, UpperLower}},
+       {0x01A6, 0x01A6, d{0, 218, 0}},
+       {0x01A7, 0x01A8, d{UpperLower, UpperLower, UpperLower}},
+       {0x01A9, 0x01A9, d{0, 218, 0}},
+       {0x01AC, 0x01AD, d{UpperLower, UpperLower, UpperLower}},
+       {0x01AE, 0x01AE, d{0, 218, 0}},
+       {0x01AF, 0x01B0, d{UpperLower, UpperLower, UpperLower}},
+       {0x01B1, 0x01B2, d{0, 217, 0}},
+       {0x01B3, 0x01B6, d{UpperLower, UpperLower, UpperLower}},
+       {0x01B7, 0x01B7, d{0, 219, 0}},
+       {0x01B8, 0x01B9, d{UpperLower, UpperLower, UpperLower}},
+       {0x01BC, 0x01BD, d{UpperLower, UpperLower, UpperLower}},
+       {0x01BF, 0x01BF, d{56, 0, 56}},
+       {0x01C4, 0x01C4, d{0, 2, 1}},
+       {0x01C5, 0x01C5, d{-1, 1, 0}},
+       {0x01C6, 0x01C6, d{-2, 0, -1}},
+       {0x01C7, 0x01C7, d{0, 2, 1}},
+       {0x01C8, 0x01C8, d{-1, 1, 0}},
+       {0x01C9, 0x01C9, d{-2, 0, -1}},
+       {0x01CA, 0x01CA, d{0, 2, 1}},
+       {0x01CB, 0x01CB, d{-1, 1, 0}},
+       {0x01CC, 0x01CC, d{-2, 0, -1}},
+       {0x01CD, 0x01DC, d{UpperLower, UpperLower, UpperLower}},
+       {0x01DD, 0x01DD, d{-79, 0, -79}},
+       {0x01DE, 0x01EF, d{UpperLower, UpperLower, UpperLower}},
+       {0x01F1, 0x01F1, d{0, 2, 1}},
+       {0x01F2, 0x01F2, d{-1, 1, 0}},
+       {0x01F3, 0x01F3, d{-2, 0, -1}},
+       {0x01F4, 0x01F5, d{UpperLower, UpperLower, UpperLower}},
+       {0x01F6, 0x01F6, d{0, -97, 0}},
+       {0x01F7, 0x01F7, d{0, -56, 0}},
+       {0x01F8, 0x021F, d{UpperLower, UpperLower, UpperLower}},
+       {0x0220, 0x0220, d{0, -130, 0}},
+       {0x0222, 0x0233, d{UpperLower, UpperLower, UpperLower}},
+       {0x023A, 0x023A, d{0, 10795, 0}},
+       {0x023B, 0x023C, d{UpperLower, UpperLower, UpperLower}},
+       {0x023D, 0x023D, d{0, -163, 0}},
+       {0x023E, 0x023E, d{0, 10792, 0}},
+       {0x023F, 0x0240, d{10815, 0, 10815}},
+       {0x0241, 0x0242, d{UpperLower, UpperLower, UpperLower}},
+       {0x0243, 0x0243, d{0, -195, 0}},
+       {0x0244, 0x0244, d{0, 69, 0}},
+       {0x0245, 0x0245, d{0, 71, 0}},
+       {0x0246, 0x024F, d{UpperLower, UpperLower, UpperLower}},
+       {0x0250, 0x0250, d{10783, 0, 10783}},
+       {0x0251, 0x0251, d{10780, 0, 10780}},
+       {0x0252, 0x0252, d{10782, 0, 10782}},
+       {0x0253, 0x0253, d{-210, 0, -210}},
+       {0x0254, 0x0254, d{-206, 0, -206}},
+       {0x0256, 0x0257, d{-205, 0, -205}},
+       {0x0259, 0x0259, d{-202, 0, -202}},
+       {0x025B, 0x025B, d{-203, 0, -203}},
+       {0x0260, 0x0260, d{-205, 0, -205}},
+       {0x0263, 0x0263, d{-207, 0, -207}},
+       {0x0268, 0x0268, d{-209, 0, -209}},
+       {0x0269, 0x0269, d{-211, 0, -211}},
+       {0x026B, 0x026B, d{10743, 0, 10743}},
+       {0x026F, 0x026F, d{-211, 0, -211}},
+       {0x0271, 0x0271, d{10749, 0, 10749}},
+       {0x0272, 0x0272, d{-213, 0, -213}},
+       {0x0275, 0x0275, d{-214, 0, -214}},
+       {0x027D, 0x027D, d{10727, 0, 10727}},
+       {0x0280, 0x0280, d{-218, 0, -218}},
+       {0x0283, 0x0283, d{-218, 0, -218}},
+       {0x0288, 0x0288, d{-218, 0, -218}},
+       {0x0289, 0x0289, d{-69, 0, -69}},
+       {0x028A, 0x028B, d{-217, 0, -217}},
+       {0x028C, 0x028C, d{-71, 0, -71}},
+       {0x0292, 0x0292, d{-219, 0, -219}},
+       {0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}},
+       {0x0376, 0x0377, d{UpperLower, UpperLower, UpperLower}},
+       {0x037B, 0x037D, d{130, 0, 130}},
+       {0x0386, 0x0386, d{0, 38, 0}},
+       {0x0388, 0x038A, d{0, 37, 0}},
+       {0x038C, 0x038C, d{0, 64, 0}},
+       {0x038E, 0x038F, d{0, 63, 0}},
+       {0x0391, 0x03A1, d{0, 32, 0}},
+       {0x03A3, 0x03AB, d{0, 32, 0}},
+       {0x03AC, 0x03AC, d{-38, 0, -38}},
+       {0x03AD, 0x03AF, d{-37, 0, -37}},
+       {0x03B1, 0x03C1, d{-32, 0, -32}},
+       {0x03C2, 0x03C2, d{-31, 0, -31}},
+       {0x03C3, 0x03CB, d{-32, 0, -32}},
+       {0x03CC, 0x03CC, d{-64, 0, -64}},
+       {0x03CD, 0x03CE, d{-63, 0, -63}},
+       {0x03CF, 0x03CF, d{0, 8, 0}},
+       {0x03D0, 0x03D0, d{-62, 0, -62}},
+       {0x03D1, 0x03D1, d{-57, 0, -57}},
+       {0x03D5, 0x03D5, d{-47, 0, -47}},
+       {0x03D6, 0x03D6, d{-54, 0, -54}},
+       {0x03D7, 0x03D7, d{-8, 0, -8}},
+       {0x03D8, 0x03EF, d{UpperLower, UpperLower, UpperLower}},
+       {0x03F0, 0x03F0, d{-86, 0, -86}},
+       {0x03F1, 0x03F1, d{-80, 0, -80}},
+       {0x03F2, 0x03F2, d{7, 0, 7}},
+       {0x03F4, 0x03F4, d{0, -60, 0}},
+       {0x03F5, 0x03F5, d{-96, 0, -96}},
+       {0x03F7, 0x03F8, d{UpperLower, UpperLower, UpperLower}},
+       {0x03F9, 0x03F9, d{0, -7, 0}},
+       {0x03FA, 0x03FB, d{UpperLower, UpperLower, UpperLower}},
+       {0x03FD, 0x03FF, d{0, -130, 0}},
+       {0x0400, 0x040F, d{0, 80, 0}},
+       {0x0410, 0x042F, d{0, 32, 0}},
+       {0x0430, 0x044F, d{-32, 0, -32}},
+       {0x0450, 0x045F, d{-80, 0, -80}},
+       {0x0460, 0x0481, d{UpperLower, UpperLower, UpperLower}},
+       {0x048A, 0x04BF, d{UpperLower, UpperLower, UpperLower}},
+       {0x04C0, 0x04C0, d{0, 15, 0}},
+       {0x04C1, 0x04CE, d{UpperLower, UpperLower, UpperLower}},
+       {0x04CF, 0x04CF, d{-15, 0, -15}},
+       {0x04D0, 0x0525, d{UpperLower, UpperLower, UpperLower}},
+       {0x0531, 0x0556, d{0, 48, 0}},
+       {0x0561, 0x0586, d{-48, 0, -48}},
+       {0x10A0, 0x10C5, d{0, 7264, 0}},
+       {0x1D79, 0x1D79, d{35332, 0, 35332}},
+       {0x1D7D, 0x1D7D, d{3814, 0, 3814}},
+       {0x1E00, 0x1E95, d{UpperLower, UpperLower, UpperLower}},
+       {0x1E9B, 0x1E9B, d{-59, 0, -59}},
+       {0x1E9E, 0x1E9E, d{0, -7615, 0}},
+       {0x1EA0, 0x1EFF, d{UpperLower, UpperLower, UpperLower}},
+       {0x1F00, 0x1F07, d{8, 0, 8}},
+       {0x1F08, 0x1F0F, d{0, -8, 0}},
+       {0x1F10, 0x1F15, d{8, 0, 8}},
+       {0x1F18, 0x1F1D, d{0, -8, 0}},
+       {0x1F20, 0x1F27, d{8, 0, 8}},
+       {0x1F28, 0x1F2F, d{0, -8, 0}},
+       {0x1F30, 0x1F37, d{8, 0, 8}},
+       {0x1F38, 0x1F3F, d{0, -8, 0}},
+       {0x1F40, 0x1F45, d{8, 0, 8}},
+       {0x1F48, 0x1F4D, d{0, -8, 0}},
+       {0x1F51, 0x1F51, d{8, 0, 8}},
+       {0x1F53, 0x1F53, d{8, 0, 8}},
+       {0x1F55, 0x1F55, d{8, 0, 8}},
+       {0x1F57, 0x1F57, d{8, 0, 8}},
+       {0x1F59, 0x1F59, d{0, -8, 0}},
+       {0x1F5B, 0x1F5B, d{0, -8, 0}},
+       {0x1F5D, 0x1F5D, d{0, -8, 0}},
+       {0x1F5F, 0x1F5F, d{0, -8, 0}},
+       {0x1F60, 0x1F67, d{8, 0, 8}},
+       {0x1F68, 0x1F6F, d{0, -8, 0}},
+       {0x1F70, 0x1F71, d{74, 0, 74}},
+       {0x1F72, 0x1F75, d{86, 0, 86}},
+       {0x1F76, 0x1F77, d{100, 0, 100}},
+       {0x1F78, 0x1F79, d{128, 0, 128}},
+       {0x1F7A, 0x1F7B, d{112, 0, 112}},
+       {0x1F7C, 0x1F7D, d{126, 0, 126}},
+       {0x1F80, 0x1F87, d{8, 0, 8}},
+       {0x1F88, 0x1F8F, d{0, -8, 0}},
+       {0x1F90, 0x1F97, d{8, 0, 8}},
+       {0x1F98, 0x1F9F, d{0, -8, 0}},
+       {0x1FA0, 0x1FA7, d{8, 0, 8}},
+       {0x1FA8, 0x1FAF, d{0, -8, 0}},
+       {0x1FB0, 0x1FB1, d{8, 0, 8}},
+       {0x1FB3, 0x1FB3, d{9, 0, 9}},
+       {0x1FB8, 0x1FB9, d{0, -8, 0}},
+       {0x1FBA, 0x1FBB, d{0, -74, 0}},
+       {0x1FBC, 0x1FBC, d{0, -9, 0}},
+       {0x1FBE, 0x1FBE, d{-7205, 0, -7205}},
+       {0x1FC3, 0x1FC3, d{9, 0, 9}},
+       {0x1FC8, 0x1FCB, d{0, -86, 0}},
+       {0x1FCC, 0x1FCC, d{0, -9, 0}},
+       {0x1FD0, 0x1FD1, d{8, 0, 8}},
+       {0x1FD8, 0x1FD9, d{0, -8, 0}},
+       {0x1FDA, 0x1FDB, d{0, -100, 0}},
+       {0x1FE0, 0x1FE1, d{8, 0, 8}},
+       {0x1FE5, 0x1FE5, d{7, 0, 7}},
+       {0x1FE8, 0x1FE9, d{0, -8, 0}},
+       {0x1FEA, 0x1FEB, d{0, -112, 0}},
+       {0x1FEC, 0x1FEC, d{0, -7, 0}},
+       {0x1FF3, 0x1FF3, d{9, 0, 9}},
+       {0x1FF8, 0x1FF9, d{0, -128, 0}},
+       {0x1FFA, 0x1FFB, d{0, -126, 0}},
+       {0x1FFC, 0x1FFC, d{0, -9, 0}},
+       {0x2126, 0x2126, d{0, -7517, 0}},
+       {0x212A, 0x212A, d{0, -8383, 0}},
+       {0x212B, 0x212B, d{0, -8262, 0}},
+       {0x2132, 0x2132, d{0, 28, 0}},
+       {0x214E, 0x214E, d{-28, 0, -28}},
+       {0x2183, 0x2184, d{UpperLower, UpperLower, UpperLower}},
+       {0x2C00, 0x2C2E, d{0, 48, 0}},
+       {0x2C30, 0x2C5E, d{-48, 0, -48}},
+       {0x2C60, 0x2C61, d{UpperLower, UpperLower, UpperLower}},
+       {0x2C62, 0x2C62, d{0, -10743, 0}},
+       {0x2C63, 0x2C63, d{0, -3814, 0}},
+       {0x2C64, 0x2C64, d{0, -10727, 0}},
+       {0x2C65, 0x2C65, d{-10795, 0, -10795}},
+       {0x2C66, 0x2C66, d{-10792, 0, -10792}},
+       {0x2C67, 0x2C6C, d{UpperLower, UpperLower, UpperLower}},
+       {0x2C6D, 0x2C6D, d{0, -10780, 0}},
+       {0x2C6E, 0x2C6E, d{0, -10749, 0}},
+       {0x2C6F, 0x2C6F, d{0, -10783, 0}},
+       {0x2C70, 0x2C70, d{0, -10782, 0}},
+       {0x2C72, 0x2C73, d{UpperLower, UpperLower, UpperLower}},
+       {0x2C75, 0x2C76, d{UpperLower, UpperLower, UpperLower}},
+       {0x2C7E, 0x2C7F, d{0, -10815, 0}},
+       {0x2C80, 0x2CE3, d{UpperLower, UpperLower, UpperLower}},
+       {0x2CEB, 0x2CEE, d{UpperLower, UpperLower, UpperLower}},
+       {0x2D00, 0x2D25, d{-7264, 0, -7264}},
+       {0xA640, 0xA65F, d{UpperLower, UpperLower, UpperLower}},
+       {0xA662, 0xA66D, d{UpperLower, UpperLower, UpperLower}},
+       {0xA680, 0xA697, d{UpperLower, UpperLower, UpperLower}},
+       {0xA722, 0xA72F, d{UpperLower, UpperLower, UpperLower}},
+       {0xA732, 0xA76F, d{UpperLower, UpperLower, UpperLower}},
+       {0xA779, 0xA77C, d{UpperLower, UpperLower, UpperLower}},
+       {0xA77D, 0xA77D, d{0, -35332, 0}},
+       {0xA77E, 0xA787, d{UpperLower, UpperLower, UpperLower}},
+       {0xA78B, 0xA78C, d{UpperLower, UpperLower, UpperLower}},
+       {0xFF21, 0xFF3A, d{0, 32, 0}},
+       {0xFF41, 0xFF5A, d{-32, 0, -32}},
+       {0x10400, 0x10427, d{0, 40, 0}},
+       {0x10428, 0x1044F, d{-40, 0, -40}},
+}
diff --git a/libgo/go/utf16/utf16.go b/libgo/go/utf16/utf16.go
new file mode 100644 (file)
index 0000000..372e38a
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package utf16 implements encoding and decoding of UTF-16 sequences.
+package utf16
+
+import "unicode"
+
+const (
+       // 0xd800-0xdc00 encodes the high 10 bits of a pair.
+       // 0xdc00-0xe000 encodes the low 10 bits of a pair.
+       // the value is those 20 bits plus 0x10000.
+       surr1 = 0xd800
+       surr2 = 0xdc00
+       surr3 = 0xe000
+
+       surrSelf = 0x10000
+)
+
+// IsSurrogate returns true if the specified Unicode code point
+// can appear in a surrogate pair.
+func IsSurrogate(rune int) bool {
+       return surr1 <= rune && rune < surr3
+}
+
+// DecodeRune returns the UTF-16 decoding of a surrogate pair.
+// If the pair is not a valid UTF-16 surrogate pair, DecodeRune returns
+// the Unicode replacement code point U+FFFD.
+func DecodeRune(r1, r2 int) int {
+       if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
+               return (int(r1)-surr1)<<10 | (int(r2) - surr2) + 0x10000
+       }
+       return unicode.ReplacementChar
+}
+
+// EncodeRune returns the UTF-16 surrogate pair r1, r2 for the given rune.
+// If the rune is not a valid Unicode code point or does not need encoding,
+// EncodeRune returns U+FFFD, U+FFFD.
+func EncodeRune(rune int) (r1, r2 int) {
+       if rune < surrSelf || rune > unicode.MaxRune || IsSurrogate(rune) {
+               return unicode.ReplacementChar, unicode.ReplacementChar
+       }
+       rune -= surrSelf
+       return surr1 + (rune>>10)&0x3ff, surr2 + rune&0x3ff
+}
+
+// Encode returns the UTF-16 encoding of the Unicode code point sequence s.
+func Encode(s []int) []uint16 {
+       n := len(s)
+       for _, v := range s {
+               if v >= surrSelf {
+                       n++
+               }
+       }
+
+       a := make([]uint16, n)
+       n = 0
+       for _, v := range s {
+               switch {
+               case v < 0, surr1 <= v && v < surr3, v > unicode.MaxRune:
+                       v = unicode.ReplacementChar
+                       fallthrough
+               case v < surrSelf:
+                       a[n] = uint16(v)
+                       n++
+               default:
+                       r1, r2 := EncodeRune(v)
+                       a[n] = uint16(r1)
+                       a[n+1] = uint16(r2)
+                       n += 2
+               }
+       }
+       return a[0:n]
+}
+
+// Decode returns the Unicode code point sequence represented
+// by the UTF-16 encoding s.
+func Decode(s []uint16) []int {
+       a := make([]int, len(s))
+       n := 0
+       for i := 0; i < len(s); i++ {
+               switch r := s[i]; {
+               case surr1 <= r && r < surr2 && i+1 < len(s) &&
+                       surr2 <= s[i+1] && s[i+1] < surr3:
+                       // valid surrogate sequence
+                       a[n] = DecodeRune(int(r), int(s[i+1]))
+                       i++
+                       n++
+               case surr1 <= r && r < surr3:
+                       // invalid surrogate sequence
+                       a[n] = unicode.ReplacementChar
+                       n++
+               default:
+                       // normal rune
+                       a[n] = int(r)
+                       n++
+               }
+       }
+       return a[0:n]
+}
diff --git a/libgo/go/utf16/utf16_test.go b/libgo/go/utf16/utf16_test.go
new file mode 100644 (file)
index 0000000..2b9fb3d
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf16_test
+
+import (
+       "fmt"
+       "reflect"
+       "testing"
+       "unicode"
+       . "utf16"
+)
+
+type encodeTest struct {
+       in  []int
+       out []uint16
+}
+
+var encodeTests = []encodeTest{
+       {[]int{1, 2, 3, 4}, []uint16{1, 2, 3, 4}},
+       {[]int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff},
+               []uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff}},
+       {[]int{'a', 'b', 0xd7ff, 0xd800, 0xdfff, 0xe000, 0x110000, -1},
+               []uint16{'a', 'b', 0xd7ff, 0xfffd, 0xfffd, 0xe000, 0xfffd, 0xfffd}},
+}
+
+func TestEncode(t *testing.T) {
+       for _, tt := range encodeTests {
+               out := Encode(tt.in)
+               if !reflect.DeepEqual(out, tt.out) {
+                       t.Errorf("Encode(%v) = %v; want %v", hex(tt.in), hex16(out), hex16(tt.out))
+               }
+       }
+}
+
+func TestEncodeRune(t *testing.T) {
+       for i, tt := range encodeTests {
+               j := 0
+               for _, r := range tt.in {
+                       r1, r2 := EncodeRune(r)
+                       if r < 0x10000 || r > unicode.MaxRune {
+                               if j >= len(tt.out) {
+                                       t.Errorf("#%d: ran out of tt.out", i)
+                                       break
+                               }
+                               if r1 != unicode.ReplacementChar || r2 != unicode.ReplacementChar {
+                                       t.Errorf("EncodeRune(%#x) = %#x, %#x; want 0xfffd, 0xfffd", r, r1, r2)
+                               }
+                               j++
+                       } else {
+                               if j+1 >= len(tt.out) {
+                                       t.Errorf("#%d: ran out of tt.out", i)
+                                       break
+                               }
+                               if r1 != int(tt.out[j]) || r2 != int(tt.out[j+1]) {
+                                       t.Errorf("EncodeRune(%#x) = %#x, %#x; want %#x, %#x", r, r1, r2, tt.out[j], tt.out[j+1])
+                               }
+                               j += 2
+                               dec := DecodeRune(r1, r2)
+                               if dec != r {
+                                       t.Errorf("DecodeRune(%#x, %#x) = %#x; want %#x", r1, r2, dec, r)
+                               }
+                       }
+               }
+               if j != len(tt.out) {
+                       t.Errorf("#%d: EncodeRune didn't generate enough output", i)
+               }
+       }
+}
+
+type decodeTest struct {
+       in  []uint16
+       out []int
+}
+
+var decodeTests = []decodeTest{
+       {[]uint16{1, 2, 3, 4}, []int{1, 2, 3, 4}},
+       {[]uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff},
+               []int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff}},
+       {[]uint16{0xd800, 'a'}, []int{0xfffd, 'a'}},
+       {[]uint16{0xdfff}, []int{0xfffd}},
+}
+
+func TestDecode(t *testing.T) {
+       for _, tt := range decodeTests {
+               out := Decode(tt.in)
+               if !reflect.DeepEqual(out, tt.out) {
+                       t.Errorf("Decode(%v) = %v; want %v", hex16(tt.in), hex(out), hex(tt.out))
+               }
+       }
+}
+
+type hex []int
+
+func (h hex) Format(f fmt.State, c int) {
+       fmt.Fprint(f, "[")
+       for i, v := range h {
+               if i > 0 {
+                       fmt.Fprint(f, " ")
+               }
+               fmt.Fprintf(f, "%x", v)
+       }
+       fmt.Fprint(f, "]")
+}
+
+type hex16 []uint16
+
+func (h hex16) Format(f fmt.State, c int) {
+       fmt.Fprint(f, "[")
+       for i, v := range h {
+               if i > 0 {
+                       fmt.Fprint(f, " ")
+               }
+               fmt.Fprintf(f, "%x", v)
+       }
+       fmt.Fprint(f, "]")
+}
diff --git a/libgo/go/utf8/string.go b/libgo/go/utf8/string.go
new file mode 100644 (file)
index 0000000..83b56b9
--- /dev/null
@@ -0,0 +1,211 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8
+
+// String wraps a regular string with a small structure that provides more
+// efficient indexing by code point index, as opposed to byte index.
+// Scanning incrementally forwards or backwards is O(1) per index operation
+// (although not as fast a range clause going forwards).  Random access is
+// O(N) in the length of the string, but the overhead is less than always
+// scanning from the beginning.
+// If the string is ASCII, random access is O(1).
+// Unlike the built-in string type, String has internal mutable state and
+// is not thread-safe.
+type String struct {
+       str      string
+       numRunes int
+       // If width > 0, the rune at runePos starts at bytePos and has the specified width.
+       width    int
+       bytePos  int
+       runePos  int
+       nonASCII int // byte index of the first non-ASCII rune.
+}
+
+// NewString returns a new UTF-8 string with the provided contents.
+func NewString(contents string) *String {
+       return new(String).Init(contents)
+}
+
+// Init initializes an existing String to hold the provided contents.
+// It returns a pointer to the initialized String.
+func (s *String) Init(contents string) *String {
+       s.str = contents
+       s.bytePos = 0
+       s.runePos = 0
+       for i := 0; i < len(contents); i++ {
+               if contents[i] >= RuneSelf {
+                       // Not ASCII.
+                       s.numRunes = RuneCountInString(contents)
+                       _, s.width = DecodeRuneInString(contents)
+                       s.nonASCII = i
+                       return s
+               }
+       }
+       // ASCII is simple.  Also, the empty string is ASCII.
+       s.numRunes = len(contents)
+       s.width = 0
+       s.nonASCII = len(contents)
+       return s
+}
+
+// String returns the contents of the String.  This method also means the
+// String is directly printable by fmt.Print.
+func (s *String) String() string {
+       return s.str
+}
+
+// RuneCount returns the number of runes (Unicode code points) in the String.
+func (s *String) RuneCount() int {
+       return s.numRunes
+}
+
+// IsASCII returns a boolean indicating whether the String contains only ASCII bytes.
+func (s *String) IsASCII() bool {
+       return s.width == 0
+}
+
+// Slice returns the string sliced at rune positions [i:j].
+func (s *String) Slice(i, j int) string {
+       // ASCII is easy.  Let the compiler catch the indexing error if there is one.
+       if j < s.nonASCII {
+               return s.str[i:j]
+       }
+       if i < 0 || j > s.numRunes || i > j {
+               panic(sliceOutOfRange)
+       }
+       if i == j {
+               return ""
+       }
+       // For non-ASCII, after At(i), bytePos is always the position of the indexed character.
+       var low, high int
+       switch {
+       case i < s.nonASCII:
+               low = i
+       case i == s.numRunes:
+               low = len(s.str)
+       default:
+               s.At(i)
+               low = s.bytePos
+       }
+       switch {
+       case j == s.numRunes:
+               high = len(s.str)
+       default:
+               s.At(j)
+               high = s.bytePos
+       }
+       return s.str[low:high]
+}
+
+// At returns the rune with index i in the String.  The sequence of runes is the same
+// as iterating over the contents with a "for range" clause.
+func (s *String) At(i int) int {
+       // ASCII is easy.  Let the compiler catch the indexing error if there is one.
+       if i < s.nonASCII {
+               return int(s.str[i])
+       }
+
+       // Now we do need to know the index is valid.
+       if i < 0 || i >= s.numRunes {
+               panic(outOfRange)
+       }
+
+       var rune int
+
+       // Five easy common cases: within 1 spot of bytePos/runePos, or the beginning, or the end.
+       // With these cases, all scans from beginning or end work in O(1) time per rune.
+       switch {
+
+       case i == s.runePos-1: // backing up one rune
+               rune, s.width = DecodeLastRuneInString(s.str[0:s.bytePos])
+               s.runePos = i
+               s.bytePos -= s.width
+               return rune
+       case i == s.runePos+1: // moving ahead one rune
+               s.runePos = i
+               s.bytePos += s.width
+               fallthrough
+       case i == s.runePos:
+               rune, s.width = DecodeRuneInString(s.str[s.bytePos:])
+               return rune
+       case i == 0: // start of string
+               rune, s.width = DecodeRuneInString(s.str)
+               s.runePos = 0
+               s.bytePos = 0
+               return rune
+
+       case i == s.numRunes-1: // last rune in string
+               rune, s.width = DecodeLastRuneInString(s.str)
+               s.runePos = i
+               s.bytePos = len(s.str) - s.width
+               return rune
+       }
+
+       // We need to do a linear scan.  There are three places to start from:
+       // 1) The beginning
+       // 2) bytePos/runePos.
+       // 3) The end
+       // Choose the closest in rune count, scanning backwards if necessary.
+       forward := true
+       if i < s.runePos {
+               // Between beginning and pos.  Which is closer?
+               // Since both i and runePos are guaranteed >= nonASCII, that's the
+               // lowest location we need to start from.
+               if i < (s.runePos-s.nonASCII)/2 {
+                       // Scan forward from beginning
+                       s.bytePos, s.runePos = s.nonASCII, s.nonASCII
+               } else {
+                       // Scan backwards from where we are
+                       forward = false
+               }
+       } else {
+               // Between pos and end.  Which is closer?
+               if i-s.runePos < (s.numRunes-s.runePos)/2 {
+                       // Scan forward from pos
+               } else {
+                       // Scan backwards from end
+                       s.bytePos, s.runePos = len(s.str), s.numRunes
+                       forward = false
+               }
+       }
+       if forward {
+               // TODO: Is it much faster to use a range loop for this scan?
+               for {
+                       rune, s.width = DecodeRuneInString(s.str[s.bytePos:])
+                       if s.runePos == i {
+                               break
+                       }
+                       s.runePos++
+                       s.bytePos += s.width
+               }
+       } else {
+               for {
+                       rune, s.width = DecodeLastRuneInString(s.str[0:s.bytePos])
+                       s.runePos--
+                       s.bytePos -= s.width
+                       if s.runePos == i {
+                               break
+                       }
+               }
+       }
+       return rune
+}
+
+// We want the panic in At(i) to satisfy os.Error, because that's what
+// runtime panics satisfy, but we can't import os.  This is our solution.
+
+// error is the type of the error returned if a user calls String.At(i) with i out of range.
+// It satisfies os.Error and runtime.Error.
+type error string
+
+func (err error) String() string {
+       return string(err)
+}
+
+func (err error) RunTimeError() {
+}
+
+var outOfRange = error("utf8.String: index out of range")
+var sliceOutOfRange = error("utf8.String: slice index out of range")
diff --git a/libgo/go/utf8/string_test.go b/libgo/go/utf8/string_test.go
new file mode 100644 (file)
index 0000000..484d46f
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8_test
+
+import (
+       "rand"
+       "testing"
+       . "utf8"
+)
+
+func TestScanForwards(t *testing.T) {
+       for _, s := range testStrings {
+               runes := []int(s)
+               str := NewString(s)
+               if str.RuneCount() != len(runes) {
+                       t.Error("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+                       break
+               }
+               for i, expect := range runes {
+                       got := str.At(i)
+                       if got != expect {
+                               t.Errorf("%s[%d]: expected %c (U+%04x); got %c (U+%04x)", s, i, expect, expect, got, got)
+                       }
+               }
+       }
+}
+
+func TestScanBackwards(t *testing.T) {
+       for _, s := range testStrings {
+               runes := []int(s)
+               str := NewString(s)
+               if str.RuneCount() != len(runes) {
+                       t.Error("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+                       break
+               }
+               for i := len(runes) - 1; i >= 0; i-- {
+                       expect := runes[i]
+                       got := str.At(i)
+                       if got != expect {
+                               t.Errorf("%s[%d]: expected %c (U+%04x); got %c (U+%04x)", s, i, expect, expect, got, got)
+                       }
+               }
+       }
+}
+
+const randCount = 100000
+
+func TestRandomAccess(t *testing.T) {
+       for _, s := range testStrings {
+               if len(s) == 0 {
+                       continue
+               }
+               runes := []int(s)
+               str := NewString(s)
+               if str.RuneCount() != len(runes) {
+                       t.Error("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+                       break
+               }
+               for j := 0; j < randCount; j++ {
+                       i := rand.Intn(len(runes))
+                       expect := runes[i]
+                       got := str.At(i)
+                       if got != expect {
+                               t.Errorf("%s[%d]: expected %c (U+%04x); got %c (U+%04x)", s, i, expect, expect, got, got)
+                       }
+               }
+       }
+}
+
+func TestRandomSliceAccess(t *testing.T) {
+       for _, s := range testStrings {
+               if len(s) == 0 || s[0] == '\x80' { // the bad-UTF-8 string fools this simple test
+                       continue
+               }
+               runes := []int(s)
+               str := NewString(s)
+               if str.RuneCount() != len(runes) {
+                       t.Error("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+                       break
+               }
+               for k := 0; k < randCount; k++ {
+                       i := rand.Intn(len(runes))
+                       j := rand.Intn(len(runes) + 1)
+                       if i > j { // include empty strings
+                               continue
+                       }
+                       expect := string(runes[i:j])
+                       got := str.Slice(i, j)
+                       if got != expect {
+                               t.Errorf("%s[%d:%d]: expected %q got %q", s, i, j, expect, got)
+                       }
+               }
+       }
+}
+
+func TestLimitSliceAccess(t *testing.T) {
+       for _, s := range testStrings {
+               str := NewString(s)
+               if str.Slice(0, 0) != "" {
+                       t.Error("failure with empty slice at beginning")
+               }
+               nr := RuneCountInString(s)
+               if str.Slice(nr, nr) != "" {
+                       t.Error("failure with empty slice at end")
+               }
+       }
+}
diff --git a/libgo/go/utf8/utf8.go b/libgo/go/utf8/utf8.go
new file mode 100644 (file)
index 0000000..dfcdef9
--- /dev/null
@@ -0,0 +1,356 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Functions and constants to support text encoded in UTF-8.
+// This package calls a Unicode character a rune for brevity.
+package utf8
+
+import "unicode" // only needed for a couple of constants
+
+// Numbers fundamental to the encoding.
+const (
+       RuneError = unicode.ReplacementChar // the "error" Rune or "replacement character".
+       RuneSelf  = 0x80                    // characters below Runeself are represented as themselves in a single byte.
+       UTFMax    = 4                       // maximum number of bytes of a UTF-8 encoded Unicode character.
+)
+
+const (
+       _T1 = 0x00 // 0000 0000
+       _Tx = 0x80 // 1000 0000
+       _T2 = 0xC0 // 1100 0000
+       _T3 = 0xE0 // 1110 0000
+       _T4 = 0xF0 // 1111 0000
+       _T5 = 0xF8 // 1111 1000
+
+       _Maskx = 0x3F // 0011 1111
+       _Mask2 = 0x1F // 0001 1111
+       _Mask3 = 0x0F // 0000 1111
+       _Mask4 = 0x07 // 0000 0111
+
+       _Rune1Max = 1<<7 - 1
+       _Rune2Max = 1<<11 - 1
+       _Rune3Max = 1<<16 - 1
+       _Rune4Max = 1<<21 - 1
+)
+
+func decodeRuneInternal(p []byte) (rune, size int, short bool) {
+       n := len(p)
+       if n < 1 {
+               return RuneError, 0, true
+       }
+       c0 := p[0]
+
+       // 1-byte, 7-bit sequence?
+       if c0 < _Tx {
+               return int(c0), 1, false
+       }
+
+       // unexpected continuation byte?
+       if c0 < _T2 {
+               return RuneError, 1, false
+       }
+
+       // need first continuation byte
+       if n < 2 {
+               return RuneError, 1, true
+       }
+       c1 := p[1]
+       if c1 < _Tx || _T2 <= c1 {
+               return RuneError, 1, false
+       }
+
+       // 2-byte, 11-bit sequence?
+       if c0 < _T3 {
+               rune = int(c0&_Mask2)<<6 | int(c1&_Maskx)
+               if rune <= _Rune1Max {
+                       return RuneError, 1, false
+               }
+               return rune, 2, false
+       }
+
+       // need second continuation byte
+       if n < 3 {
+               return RuneError, 1, true
+       }
+       c2 := p[2]
+       if c2 < _Tx || _T2 <= c2 {
+               return RuneError, 1, false
+       }
+
+       // 3-byte, 16-bit sequence?
+       if c0 < _T4 {
+               rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx)
+               if rune <= _Rune2Max {
+                       return RuneError, 1, false
+               }
+               return rune, 3, false
+       }
+
+       // need third continuation byte
+       if n < 4 {
+               return RuneError, 1, true
+       }
+       c3 := p[3]
+       if c3 < _Tx || _T2 <= c3 {
+               return RuneError, 1, false
+       }
+
+       // 4-byte, 21-bit sequence?
+       if c0 < _T5 {
+               rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+               if rune <= _Rune3Max {
+                       return RuneError, 1, false
+               }
+               return rune, 4, false
+       }
+
+       // error
+       return RuneError, 1, false
+}
+
+func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
+       n := len(s)
+       if n < 1 {
+               return RuneError, 0, true
+       }
+       c0 := s[0]
+
+       // 1-byte, 7-bit sequence?
+       if c0 < _Tx {
+               return int(c0), 1, false
+       }
+
+       // unexpected continuation byte?
+       if c0 < _T2 {
+               return RuneError, 1, false
+       }
+
+       // need first continuation byte
+       if n < 2 {
+               return RuneError, 1, true
+       }
+       c1 := s[1]
+       if c1 < _Tx || _T2 <= c1 {
+               return RuneError, 1, false
+       }
+
+       // 2-byte, 11-bit sequence?
+       if c0 < _T3 {
+               rune = int(c0&_Mask2)<<6 | int(c1&_Maskx)
+               if rune <= _Rune1Max {
+                       return RuneError, 1, false
+               }
+               return rune, 2, false
+       }
+
+       // need second continuation byte
+       if n < 3 {
+               return RuneError, 1, true
+       }
+       c2 := s[2]
+       if c2 < _Tx || _T2 <= c2 {
+               return RuneError, 1, false
+       }
+
+       // 3-byte, 16-bit sequence?
+       if c0 < _T4 {
+               rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx)
+               if rune <= _Rune2Max {
+                       return RuneError, 1, false
+               }
+               return rune, 3, false
+       }
+
+       // need third continuation byte
+       if n < 4 {
+               return RuneError, 1, true
+       }
+       c3 := s[3]
+       if c3 < _Tx || _T2 <= c3 {
+               return RuneError, 1, false
+       }
+
+       // 4-byte, 21-bit sequence?
+       if c0 < _T5 {
+               rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+               if rune <= _Rune3Max {
+                       return RuneError, 1, false
+               }
+               return rune, 4, false
+       }
+
+       // error
+       return RuneError, 1, false
+}
+
+// FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
+// An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
+func FullRune(p []byte) bool {
+       _, _, short := decodeRuneInternal(p)
+       return !short
+}
+
+// FullRuneInString is like FullRune but its input is a string.
+func FullRuneInString(s string) bool {
+       _, _, short := decodeRuneInStringInternal(s)
+       return !short
+}
+
+// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
+func DecodeRune(p []byte) (rune, size int) {
+       rune, size, _ = decodeRuneInternal(p)
+       return
+}
+
+// DecodeRuneInString is like DecodeRune but its input is a string.
+func DecodeRuneInString(s string) (rune, size int) {
+       rune, size, _ = decodeRuneInStringInternal(s)
+       return
+}
+
+// DecodeLastRune unpacks the last UTF-8 encoding in p
+// and returns the rune and its width in bytes.
+func DecodeLastRune(p []byte) (rune, size int) {
+       end := len(p)
+       if end == 0 {
+               return RuneError, 0
+       }
+       start := end - 1
+       rune = int(p[start])
+       if rune < RuneSelf {
+               return rune, 1
+       }
+       // guard against O(n^2) behavior when traversing
+       // backwards through strings with long sequences of
+       // invalid UTF-8.
+       lim := end - UTFMax
+       if lim < 0 {
+               lim = 0
+       }
+       for start--; start >= lim; start-- {
+               if RuneStart(p[start]) {
+                       break
+               }
+       }
+       if start < 0 {
+               start = 0
+       }
+       rune, size = DecodeRune(p[start:end])
+       if start+size != end {
+               return RuneError, 1
+       }
+       return rune, size
+}
+
+// DecodeLastRuneInString is like DecodeLastRune but its input is a string.
+func DecodeLastRuneInString(s string) (rune, size int) {
+       end := len(s)
+       if end == 0 {
+               return RuneError, 0
+       }
+       start := end - 1
+       rune = int(s[start])
+       if rune < RuneSelf {
+               return rune, 1
+       }
+       // guard against O(n^2) behavior when traversing
+       // backwards through strings with long sequences of
+       // invalid UTF-8.
+       lim := end - UTFMax
+       if lim < 0 {
+               lim = 0
+       }
+       for start--; start >= lim; start-- {
+               if RuneStart(s[start]) {
+                       break
+               }
+       }
+       if start < 0 {
+               start = 0
+       }
+       rune, size = DecodeRuneInString(s[start:end])
+       if start+size != end {
+               return RuneError, 1
+       }
+       return rune, size
+}
+
+// RuneLen returns the number of bytes required to encode the rune.
+func RuneLen(rune int) int {
+       switch {
+       case rune <= _Rune1Max:
+               return 1
+       case rune <= _Rune2Max:
+               return 2
+       case rune <= _Rune3Max:
+               return 3
+       case rune <= _Rune4Max:
+               return 4
+       }
+       return -1
+}
+
+// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
+// It returns the number of bytes written.
+func EncodeRune(rune int, p []byte) int {
+       // Negative values are erroneous.  Making it unsigned addresses the problem.
+       r := uint(rune)
+
+       if r <= _Rune1Max {
+               p[0] = byte(r)
+               return 1
+       }
+
+       if r <= _Rune2Max {
+               p[0] = _T2 | byte(r>>6)
+               p[1] = _Tx | byte(r)&_Maskx
+               return 2
+       }
+
+       if r > unicode.MaxRune {
+               r = RuneError
+       }
+
+       if r <= _Rune3Max {
+               p[0] = _T3 | byte(r>>12)
+               p[1] = _Tx | byte(r>>6)&_Maskx
+               p[2] = _Tx | byte(r)&_Maskx
+               return 3
+       }
+
+       p[0] = _T4 | byte(r>>18)
+       p[1] = _Tx | byte(r>>12)&_Maskx
+       p[2] = _Tx | byte(r>>6)&_Maskx
+       p[3] = _Tx | byte(r)&_Maskx
+       return 4
+}
+
+// RuneCount returns the number of runes in p.  Erroneous and short
+// encodings are treated as single runes of width 1 byte.
+func RuneCount(p []byte) int {
+       i := 0
+       var n int
+       for n = 0; i < len(p); n++ {
+               if p[i] < RuneSelf {
+                       i++
+               } else {
+                       _, size := DecodeRune(p[i:])
+                       i += size
+               }
+       }
+       return n
+}
+
+// RuneCountInString is like RuneCount but its input is a string.
+func RuneCountInString(s string) (n int) {
+       for _ = range s {
+               n++
+       }
+       return
+}
+
+// RuneStart reports whether the byte could be the first byte of
+// an encoded rune.  Second and subsequent bytes always have the top
+// two bits set to 10.
+func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
diff --git a/libgo/go/utf8/utf8_test.go b/libgo/go/utf8/utf8_test.go
new file mode 100644 (file)
index 0000000..dc130f6
--- /dev/null
@@ -0,0 +1,315 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8_test
+
+import (
+       "bytes"
+       "testing"
+       . "utf8"
+)
+
+type Utf8Map struct {
+       rune int
+       str  string
+}
+
+var utf8map = []Utf8Map{
+       {0x0000, "\x00"},
+       {0x0001, "\x01"},
+       {0x007e, "\x7e"},
+       {0x007f, "\x7f"},
+       {0x0080, "\xc2\x80"},
+       {0x0081, "\xc2\x81"},
+       {0x00bf, "\xc2\xbf"},
+       {0x00c0, "\xc3\x80"},
+       {0x00c1, "\xc3\x81"},
+       {0x00c8, "\xc3\x88"},
+       {0x00d0, "\xc3\x90"},
+       {0x00e0, "\xc3\xa0"},
+       {0x00f0, "\xc3\xb0"},
+       {0x00f8, "\xc3\xb8"},
+       {0x00ff, "\xc3\xbf"},
+       {0x0100, "\xc4\x80"},
+       {0x07ff, "\xdf\xbf"},
+       {0x0800, "\xe0\xa0\x80"},
+       {0x0801, "\xe0\xa0\x81"},
+       {0xfffe, "\xef\xbf\xbe"},
+       {0xffff, "\xef\xbf\xbf"},
+       {0x10000, "\xf0\x90\x80\x80"},
+       {0x10001, "\xf0\x90\x80\x81"},
+       {0x10fffe, "\xf4\x8f\xbf\xbe"},
+       {0x10ffff, "\xf4\x8f\xbf\xbf"},
+       {0xFFFD, "\xef\xbf\xbd"},
+}
+
+var testStrings = []string{
+       "",
+       "abcd",
+       "☺☻☹",
+       "日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+       "日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+       "\x80\x80\x80\x80",
+}
+
+func TestFullRune(t *testing.T) {
+       for i := 0; i < len(utf8map); i++ {
+               m := utf8map[i]
+               b := []byte(m.str)
+               if !FullRune(b) {
+                       t.Errorf("FullRune(%q) (rune %04x) = false, want true", b, m.rune)
+               }
+               s := m.str
+               if !FullRuneInString(s) {
+                       t.Errorf("FullRuneInString(%q) (rune %04x) = false, want true", s, m.rune)
+               }
+               b1 := b[0 : len(b)-1]
+               if FullRune(b1) {
+                       t.Errorf("FullRune(%q) = true, want false", b1)
+               }
+               s1 := string(b1)
+               if FullRuneInString(s1) {
+                       t.Errorf("FullRune(%q) = true, want false", s1)
+               }
+       }
+}
+
+func TestEncodeRune(t *testing.T) {
+       for i := 0; i < len(utf8map); i++ {
+               m := utf8map[i]
+               b := []byte(m.str)
+               var buf [10]byte
+               n := EncodeRune(m.rune, buf[0:])
+               b1 := buf[0:n]
+               if !bytes.Equal(b, b1) {
+                       t.Errorf("EncodeRune(%#04x) = %q want %q", m.rune, b1, b)
+               }
+       }
+}
+
+func TestDecodeRune(t *testing.T) {
+       for i := 0; i < len(utf8map); i++ {
+               m := utf8map[i]
+               b := []byte(m.str)
+               rune, size := DecodeRune(b)
+               if rune != m.rune || size != len(b) {
+                       t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
+               }
+               s := m.str
+               rune, size = DecodeRuneInString(s)
+               if rune != m.rune || size != len(b) {
+                       t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
+               }
+
+               // there's an extra byte that bytes left behind - make sure trailing byte works
+               rune, size = DecodeRune(b[0:cap(b)])
+               if rune != m.rune || size != len(b) {
+                       t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
+               }
+               s = m.str + "\x00"
+               rune, size = DecodeRuneInString(s)
+               if rune != m.rune || size != len(b) {
+                       t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
+               }
+
+               // make sure missing bytes fail
+               wantsize := 1
+               if wantsize >= len(b) {
+                       wantsize = 0
+               }
+               rune, size = DecodeRune(b[0 : len(b)-1])
+               if rune != RuneError || size != wantsize {
+                       t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize)
+               }
+               s = m.str[0 : len(m.str)-1]
+               rune, size = DecodeRuneInString(s)
+               if rune != RuneError || size != wantsize {
+                       t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, wantsize)
+               }
+
+               // make sure bad sequences fail
+               if len(b) == 1 {
+                       b[0] = 0x80
+               } else {
+                       b[len(b)-1] = 0x7F
+               }
+               rune, size = DecodeRune(b)
+               if rune != RuneError || size != 1 {
+                       t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, RuneError, 1)
+               }
+               s = string(b)
+               rune, size = DecodeRune(b)
+               if rune != RuneError || size != 1 {
+                       t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, 1)
+               }
+
+       }
+}
+
+// Check that DecodeRune and DecodeLastRune correspond to
+// the equivalent range loop.
+func TestSequencing(t *testing.T) {
+       for _, ts := range testStrings {
+               for _, m := range utf8map {
+                       for _, s := range []string{ts + m.str, m.str + ts, ts + m.str + ts} {
+                               testSequence(t, s)
+                       }
+               }
+       }
+}
+
+// Check that a range loop and a []int conversion visit the same runes.
+// Not really a test of this package, but the assumption is used here and
+// it's good to verify
+func TestIntConversion(t *testing.T) {
+       for _, ts := range testStrings {
+               runes := []int(ts)
+               if RuneCountInString(ts) != len(runes) {
+                       t.Error("%q: expected %d runes; got %d", ts, len(runes), RuneCountInString(ts))
+                       break
+               }
+               i := 0
+               for _, r := range ts {
+                       if r != runes[i] {
+                               t.Errorf("%q[%d]: expected %c (U+%04x); got %c (U+%04x)", ts, i, runes[i], runes[i], r, r)
+                       }
+                       i++
+               }
+       }
+}
+
+func testSequence(t *testing.T, s string) {
+       type info struct {
+               index int
+               rune  int
+       }
+       index := make([]info, len(s))
+       b := []byte(s)
+       si := 0
+       j := 0
+       for i, r := range s {
+               if si != i {
+                       t.Errorf("Sequence(%q) mismatched index %d, want %d", s, si, i)
+                       return
+               }
+               index[j] = info{i, r}
+               j++
+               rune1, size1 := DecodeRune(b[i:])
+               if r != rune1 {
+                       t.Errorf("DecodeRune(%q) = %#04x, want %#04x", s[i:], rune1, r)
+                       return
+               }
+               rune2, size2 := DecodeRuneInString(s[i:])
+               if r != rune2 {
+                       t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s[i:], rune2, r)
+                       return
+               }
+               if size1 != size2 {
+                       t.Errorf("DecodeRune/DecodeRuneInString(%q) size mismatch %d/%d", s[i:], size1, size2)
+                       return
+               }
+               si += size1
+       }
+       j--
+       for si = len(s); si > 0; {
+               rune1, size1 := DecodeLastRune(b[0:si])
+               rune2, size2 := DecodeLastRuneInString(s[0:si])
+               if size1 != size2 {
+                       t.Errorf("DecodeLastRune/DecodeLastRuneInString(%q, %d) size mismatch %d/%d", s, si, size1, size2)
+                       return
+               }
+               if rune1 != index[j].rune {
+                       t.Errorf("DecodeLastRune(%q, %d) = %#04x, want %#04x", s, si, rune1, index[j].rune)
+                       return
+               }
+               if rune2 != index[j].rune {
+                       t.Errorf("DecodeLastRuneInString(%q, %d) = %#04x, want %#04x", s, si, rune2, index[j].rune)
+                       return
+               }
+               si -= size1
+               if si != index[j].index {
+                       t.Errorf("DecodeLastRune(%q) index mismatch at %d, want %d", s, si, index[j].index)
+                       return
+               }
+               j--
+       }
+       if si != 0 {
+               t.Errorf("DecodeLastRune(%q) finished at %d, not 0", s, si)
+       }
+}
+
+// Check that negative runes encode as U+FFFD.
+func TestNegativeRune(t *testing.T) {
+       errorbuf := make([]byte, UTFMax)
+       errorbuf = errorbuf[0:EncodeRune(RuneError, errorbuf)]
+       buf := make([]byte, UTFMax)
+       buf = buf[0:EncodeRune(-1, buf)]
+       if !bytes.Equal(buf, errorbuf) {
+               t.Errorf("incorrect encoding [% x] for -1; expected [% x]", buf, errorbuf)
+       }
+}
+
+type RuneCountTest struct {
+       in  string
+       out int
+}
+
+var runecounttests = []RuneCountTest{
+       {"abcd", 4},
+       {"☺☻☹", 3},
+       {"1,2,3,4", 7},
+       {"\xe2\x00", 2},
+}
+
+func TestRuneCount(t *testing.T) {
+       for i := 0; i < len(runecounttests); i++ {
+               tt := runecounttests[i]
+               if out := RuneCountInString(tt.in); out != tt.out {
+                       t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out)
+               }
+               if out := RuneCount([]byte(tt.in)); out != tt.out {
+                       t.Errorf("RuneCount(%q) = %d, want %d", tt.in, out, tt.out)
+               }
+       }
+}
+
+func BenchmarkRuneCountTenASCIIChars(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               RuneCountInString("0123456789")
+       }
+}
+
+func BenchmarkRuneCountTenJapaneseChars(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               RuneCountInString("日本語日本語日本語日")
+       }
+}
+
+func BenchmarkEncodeASCIIRune(b *testing.B) {
+       buf := make([]byte, UTFMax)
+       for i := 0; i < b.N; i++ {
+               EncodeRune('a', buf)
+       }
+}
+
+func BenchmarkEncodeJapaneseRune(b *testing.B) {
+       buf := make([]byte, UTFMax)
+       for i := 0; i < b.N; i++ {
+               EncodeRune('本', buf)
+       }
+}
+
+func BenchmarkDecodeASCIIRune(b *testing.B) {
+       a := []byte{'a'}
+       for i := 0; i < b.N; i++ {
+               DecodeRune(a)
+       }
+}
+
+func BenchmarkDecodeJapaneseRune(b *testing.B) {
+       nihon := []byte("本")
+       for i := 0; i < b.N; i++ {
+               DecodeRune(nihon)
+       }
+}
diff --git a/libgo/go/websocket/client.go b/libgo/go/websocket/client.go
new file mode 100644 (file)
index 0000000..caf63f1
--- /dev/null
@@ -0,0 +1,321 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+       "bufio"
+       "bytes"
+       "container/vector"
+       "crypto/tls"
+       "fmt"
+       "http"
+       "io"
+       "net"
+       "os"
+       "rand"
+       "strings"
+)
+
+type ProtocolError struct {
+       os.ErrorString
+}
+
+var (
+       ErrBadScheme            = os.ErrorString("bad scheme")
+       ErrBadStatus            = &ProtocolError{"bad status"}
+       ErrBadUpgrade           = &ProtocolError{"missing or bad upgrade"}
+       ErrBadWebSocketOrigin   = &ProtocolError{"missing or bad WebSocket-Origin"}
+       ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
+       ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
+       ErrChallengeResponse    = &ProtocolError{"mismatch challange/response"}
+       secKeyRandomChars       [0x30 - 0x21 + 0x7F - 0x3A]byte
+)
+
+type DialError struct {
+       URL      string
+       Protocol string
+       Origin   string
+       Error    os.Error
+}
+
+func (e *DialError) String() string {
+       return "websocket.Dial " + e.URL + ": " + e.Error.String()
+}
+
+func init() {
+       i := 0
+       for ch := byte(0x21); ch < 0x30; ch++ {
+               secKeyRandomChars[i] = ch
+               i++
+       }
+       for ch := byte(0x3a); ch < 0x7F; ch++ {
+               secKeyRandomChars[i] = ch
+               i++
+       }
+}
+
+type handshaker func(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) os.Error
+
+// newClient creates a new Web Socket client connection.
+func newClient(resourceName, host, origin, location, protocol string, rwc io.ReadWriteCloser, handshake handshaker) (ws *Conn, err os.Error) {
+       br := bufio.NewReader(rwc)
+       bw := bufio.NewWriter(rwc)
+       err = handshake(resourceName, host, origin, location, protocol, br, bw)
+       if err != nil {
+               return
+       }
+       buf := bufio.NewReadWriter(br, bw)
+       ws = newConn(origin, location, protocol, buf, rwc)
+       return
+}
+
+/*
+Dial opens a new client connection to a Web Socket.
+
+A trivial example client:
+
+       package main
+
+       import (
+               "websocket"
+               "strings"
+       )
+
+       func main() {
+               ws, err := websocket.Dial("ws://localhost/ws", "", "http://localhost/");
+               if err != nil {
+                       panic("Dial: " + err.String())
+               }
+               if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
+                       panic("Write: " + err.String())
+               }
+               var msg = make([]byte, 512);
+               if n, err := ws.Read(msg); err != nil {
+                       panic("Read: " + err.String())
+               }
+               // use msg[0:n]
+       }
+*/
+func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
+       var client net.Conn
+
+       parsedUrl, err := http.ParseURL(url)
+       if err != nil {
+               goto Error
+       }
+
+       switch parsedUrl.Scheme {
+       case "ws":
+               client, err = net.Dial("tcp", "", parsedUrl.Host)
+
+       case "wss":
+               client, err = tls.Dial("tcp", "", parsedUrl.Host)
+
+       default:
+               err = ErrBadScheme
+       }
+       if err != nil {
+               goto Error
+       }
+
+       ws, err = newClient(parsedUrl.RawPath, parsedUrl.Host, origin, url, protocol, client, handshake)
+       if err != nil {
+               goto Error
+       }
+       return
+
+Error:
+       return nil, &DialError{url, protocol, origin, err}
+}
+
+/*
+Generates handshake key as described in 4.1 Opening handshake step 16 to 22.
+cf. http://www.whatwg.org/specs/web-socket-protocol/
+*/
+func generateKeyNumber() (key string, number uint32) {
+       // 16.  Let /spaces_n/ be a random integer from 1 to 12 inclusive.
+       spaces := rand.Intn(12) + 1
+
+       // 17. Let /max_n/ be the largest integer not greater than
+       //     4,294,967,295 divided by /spaces_n/
+       max := int(4294967295 / uint32(spaces))
+
+       // 18. Let /number_n/ be a random integer from 0 to /max_n/ inclusive.
+       number = uint32(rand.Intn(max + 1))
+
+       // 19. Let /product_n/ be the result of multiplying /number_n/ and
+       //     /spaces_n/ together.
+       product := number * uint32(spaces)
+
+       // 20. Let /key_n/ be a string consisting of /product_n/, expressed
+       // in base ten using the numerals in the range U+0030 DIGIT ZERO (0)
+       // to U+0039 DIGIT NINE (9).
+       key = fmt.Sprintf("%d", product)
+
+       // 21. Insert between one and twelve random characters from the ranges
+       //     U+0021 to U+002F and U+003A to U+007E into /key_n/ at random
+       //     positions.
+       n := rand.Intn(12) + 1
+       for i := 0; i < n; i++ {
+               pos := rand.Intn(len(key)) + 1
+               ch := secKeyRandomChars[rand.Intn(len(secKeyRandomChars))]
+               key = key[0:pos] + string(ch) + key[pos:]
+       }
+
+       // 22. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random
+       //     positions other than the start or end of the string.
+       for i := 0; i < spaces; i++ {
+               pos := rand.Intn(len(key)-1) + 1
+               key = key[0:pos] + " " + key[pos:]
+       }
+
+       return
+}
+
+/*
+Generates handshake key_3 as described in 4.1 Opening handshake step 26.
+cf. http://www.whatwg.org/specs/web-socket-protocol/
+*/
+func generateKey3() (key []byte) {
+       // 26. Let /key3/ be a string consisting of eight random bytes (or
+       //  equivalently, a random 64 bit integer encoded in big-endian order).
+       key = make([]byte, 8)
+       for i := 0; i < 8; i++ {
+               key[i] = byte(rand.Intn(256))
+       }
+       return
+}
+
+/*
+Web Socket protocol handshake based on
+http://www.whatwg.org/specs/web-socket-protocol/
+(draft of http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol)
+*/
+func handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
+       // 4.1. Opening handshake.
+       // Step 5.  send a request line.
+       bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
+
+       // Step 6-14. push request headers in fields.
+       var fields vector.StringVector
+       fields.Push("Upgrade: WebSocket\r\n")
+       fields.Push("Connection: Upgrade\r\n")
+       fields.Push("Host: " + host + "\r\n")
+       fields.Push("Origin: " + origin + "\r\n")
+       if protocol != "" {
+               fields.Push("Sec-WebSocket-Protocol: " + protocol + "\r\n")
+       }
+       // TODO(ukai): Step 15. send cookie if any.
+
+       // Step 16-23. generate keys and push Sec-WebSocket-Key<n> in fields.
+       key1, number1 := generateKeyNumber()
+       key2, number2 := generateKeyNumber()
+       fields.Push("Sec-WebSocket-Key1: " + key1 + "\r\n")
+       fields.Push("Sec-WebSocket-Key2: " + key2 + "\r\n")
+
+       // Step 24. shuffle fields and send them out.
+       for i := 1; i < len(fields); i++ {
+               j := rand.Intn(i)
+               fields[i], fields[j] = fields[j], fields[i]
+       }
+       for i := 0; i < len(fields); i++ {
+               bw.WriteString(fields[i])
+       }
+       // Step 25. send CRLF.
+       bw.WriteString("\r\n")
+
+       // Step 26. genearte 8 bytes random key.
+       key3 := generateKey3()
+       // Step 27. send it out.
+       bw.Write(key3)
+       if err = bw.Flush(); err != nil {
+               return
+       }
+
+       // Step 28-29, 32-40. read response from server.
+       resp, err := http.ReadResponse(br, "GET")
+       if err != nil {
+               return err
+       }
+       // Step 30. check response code is 101.
+       if resp.StatusCode != 101 {
+               return ErrBadStatus
+       }
+
+       // Step 41. check websocket headers.
+       if resp.Header["Upgrade"] != "WebSocket" ||
+               strings.ToLower(resp.Header["Connection"]) != "upgrade" {
+               return ErrBadUpgrade
+       }
+
+       if resp.Header["Sec-Websocket-Origin"] != origin {
+               return ErrBadWebSocketOrigin
+       }
+
+       if resp.Header["Sec-Websocket-Location"] != location {
+               return ErrBadWebSocketLocation
+       }
+
+       if protocol != "" && resp.Header["Sec-Websocket-Protocol"] != protocol {
+               return ErrBadWebSocketProtocol
+       }
+
+       // Step 42-43. get expected data from challange data.
+       expected, err := getChallengeResponse(number1, number2, key3)
+       if err != nil {
+               return err
+       }
+
+       // Step 44. read 16 bytes from server.
+       reply := make([]byte, 16)
+       if _, err = io.ReadFull(br, reply); err != nil {
+               return err
+       }
+
+       // Step 45. check the reply equals to expected data.
+       if !bytes.Equal(expected, reply) {
+               return ErrChallengeResponse
+       }
+       // WebSocket connection is established.
+       return
+}
+
+/*
+Handhake described in (soon obsolete)
+draft-hixie-thewebsocket-protocol-75.
+*/
+func draft75handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
+       bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
+       bw.WriteString("Upgrade: WebSocket\r\n")
+       bw.WriteString("Connection: Upgrade\r\n")
+       bw.WriteString("Host: " + host + "\r\n")
+       bw.WriteString("Origin: " + origin + "\r\n")
+       if protocol != "" {
+               bw.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
+       }
+       bw.WriteString("\r\n")
+       bw.Flush()
+       resp, err := http.ReadResponse(br, "GET")
+       if err != nil {
+               return
+       }
+       if resp.Status != "101 Web Socket Protocol Handshake" {
+               return ErrBadStatus
+       }
+       if resp.Header["Upgrade"] != "WebSocket" ||
+               resp.Header["Connection"] != "Upgrade" {
+               return ErrBadUpgrade
+       }
+       if resp.Header["Websocket-Origin"] != origin {
+               return ErrBadWebSocketOrigin
+       }
+       if resp.Header["Websocket-Location"] != location {
+               return ErrBadWebSocketLocation
+       }
+       if protocol != "" && resp.Header["Websocket-Protocol"] != protocol {
+               return ErrBadWebSocketProtocol
+       }
+       return
+}
diff --git a/libgo/go/websocket/server.go b/libgo/go/websocket/server.go
new file mode 100644 (file)
index 0000000..dd797f2
--- /dev/null
@@ -0,0 +1,219 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+       "http"
+       "io"
+       "strings"
+)
+
+/*
+Handler is an interface to a WebSocket.
+
+A trivial example server:
+
+       package main
+
+       import (
+               "http"
+               "io"
+               "websocket"
+       )
+
+       // Echo the data received on the Web Socket.
+       func EchoServer(ws *websocket.Conn) {
+               io.Copy(ws, ws);
+       }
+
+       func main() {
+               http.Handle("/echo", websocket.Handler(EchoServer));
+               err := http.ListenAndServe(":12345", nil);
+               if err != nil {
+                       panic("ListenAndServe: " + err.String())
+               }
+       }
+*/
+type Handler func(*Conn)
+
+/*
+Gets key number from Sec-WebSocket-Key<n>: field as described
+in 5.2 Sending the server's opening handshake, 4.
+*/
+func getKeyNumber(s string) (r uint32) {
+       // 4. Let /key-number_n/ be the digits (characters in the range
+       // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_1/,
+       // interpreted as a base ten integer, ignoring all other characters
+       // in /key_n/.
+       r = 0
+       for i := 0; i < len(s); i++ {
+               if s[i] >= '0' && s[i] <= '9' {
+                       r = r*10 + uint32(s[i]) - '0'
+               }
+       }
+       return
+}
+
+// ServeHTTP implements the http.Handler interface for a Web Socket
+func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+       rwc, buf, err := w.Hijack()
+       if err != nil {
+               panic("Hijack failed: " + err.String())
+               return
+       }
+       // The server should abort the WebSocket connection if it finds
+       // the client did not send a handshake that matches with protocol
+       // specification.
+       defer rwc.Close()
+
+       if req.Method != "GET" {
+               return
+       }
+       // HTTP version can be safely ignored.
+
+       if strings.ToLower(req.Header["Upgrade"]) != "websocket" ||
+               strings.ToLower(req.Header["Connection"]) != "upgrade" {
+               return
+       }
+
+       // TODO(ukai): check Host
+       origin, found := req.Header["Origin"]
+       if !found {
+               return
+       }
+
+       key1, found := req.Header["Sec-Websocket-Key1"]
+       if !found {
+               return
+       }
+       key2, found := req.Header["Sec-Websocket-Key2"]
+       if !found {
+               return
+       }
+       key3 := make([]byte, 8)
+       if _, err := io.ReadFull(buf, key3); err != nil {
+               return
+       }
+
+       var location string
+       if w.UsingTLS() {
+               location = "wss://" + req.Host + req.URL.RawPath
+       } else {
+               location = "ws://" + req.Host + req.URL.RawPath
+       }
+
+       // Step 4. get key number in Sec-WebSocket-Key<n> fields.
+       keyNumber1 := getKeyNumber(key1)
+       keyNumber2 := getKeyNumber(key2)
+
+       // Step 5. get number of spaces in Sec-WebSocket-Key<n> fields.
+       space1 := uint32(strings.Count(key1, " "))
+       space2 := uint32(strings.Count(key2, " "))
+       if space1 == 0 || space2 == 0 {
+               return
+       }
+
+       // Step 6. key number must be an integral multiple of spaces.
+       if keyNumber1%space1 != 0 || keyNumber2%space2 != 0 {
+               return
+       }
+
+       // Step 7. let part be key number divided by spaces.
+       part1 := keyNumber1 / space1
+       part2 := keyNumber2 / space2
+
+       // Step 8. let challenge to be concatination of part1, part2 and key3.
+       // Step 9. get MD5 fingerprint of challenge.
+       response, err := getChallengeResponse(part1, part2, key3)
+       if err != nil {
+               return
+       }
+
+       // Step 10. send response status line.
+       buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
+       // Step 11. send response headers.
+       buf.WriteString("Upgrade: WebSocket\r\n")
+       buf.WriteString("Connection: Upgrade\r\n")
+       buf.WriteString("Sec-WebSocket-Location: " + location + "\r\n")
+       buf.WriteString("Sec-WebSocket-Origin: " + origin + "\r\n")
+       protocol, found := req.Header["Sec-Websocket-Protocol"]
+       if found {
+               buf.WriteString("Sec-WebSocket-Protocol: " + protocol + "\r\n")
+       }
+       // Step 12. send CRLF.
+       buf.WriteString("\r\n")
+       // Step 13. send response data.
+       buf.Write(response)
+       if err := buf.Flush(); err != nil {
+               return
+       }
+       ws := newConn(origin, location, protocol, buf, rwc)
+       f(ws)
+}
+
+
+/*
+Draft75Handler is an interface to a WebSocket based on the
+(soon obsolete) draft-hixie-thewebsocketprotocol-75.
+*/
+type Draft75Handler func(*Conn)
+
+// ServeHTTP implements the http.Handler interface for a Web Socket.
+func (f Draft75Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+       if req.Method != "GET" || req.Proto != "HTTP/1.1" {
+               w.WriteHeader(http.StatusBadRequest)
+               io.WriteString(w, "Unexpected request")
+               return
+       }
+       if req.Header["Upgrade"] != "WebSocket" {
+               w.WriteHeader(http.StatusBadRequest)
+               io.WriteString(w, "missing Upgrade: WebSocket header")
+               return
+       }
+       if req.Header["Connection"] != "Upgrade" {
+               w.WriteHeader(http.StatusBadRequest)
+               io.WriteString(w, "missing Connection: Upgrade header")
+               return
+       }
+       origin, found := req.Header["Origin"]
+       if !found {
+               w.WriteHeader(http.StatusBadRequest)
+               io.WriteString(w, "missing Origin header")
+               return
+       }
+
+       rwc, buf, err := w.Hijack()
+       if err != nil {
+               panic("Hijack failed: " + err.String())
+               return
+       }
+       defer rwc.Close()
+
+       var location string
+       if w.UsingTLS() {
+               location = "wss://" + req.Host + req.URL.RawPath
+       } else {
+               location = "ws://" + req.Host + req.URL.RawPath
+       }
+
+       // TODO(ukai): verify origin,location,protocol.
+
+       buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
+       buf.WriteString("Upgrade: WebSocket\r\n")
+       buf.WriteString("Connection: Upgrade\r\n")
+       buf.WriteString("WebSocket-Origin: " + origin + "\r\n")
+       buf.WriteString("WebSocket-Location: " + location + "\r\n")
+       protocol, found := req.Header["Websocket-Protocol"]
+       // canonical header key of WebSocket-Protocol.
+       if found {
+               buf.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
+       }
+       buf.WriteString("\r\n")
+       if err := buf.Flush(); err != nil {
+               return
+       }
+       ws := newConn(origin, location, protocol, buf, rwc)
+       f(ws)
+}
diff --git a/libgo/go/websocket/websocket.go b/libgo/go/websocket/websocket.go
new file mode 100644 (file)
index 0000000..d5996ab
--- /dev/null
@@ -0,0 +1,189 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The websocket package implements a client and server for the Web Socket protocol.
+// The protocol is defined at http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
+package websocket
+
+// TODO(ukai):
+//   better logging.
+
+import (
+       "bufio"
+       "crypto/md5"
+       "encoding/binary"
+       "io"
+       "net"
+       "os"
+)
+
+// WebSocketAddr is an implementation of net.Addr for Web Sockets.
+type WebSocketAddr string
+
+// Network returns the network type for a Web Socket, "websocket".
+func (addr WebSocketAddr) Network() string { return "websocket" }
+
+// String returns the network address for a Web Socket.
+func (addr WebSocketAddr) String() string { return string(addr) }
+
+const (
+       stateFrameByte = iota
+       stateFrameLength
+       stateFrameData
+       stateFrameTextData
+)
+
+// Conn is a channel to communicate to a Web Socket.
+// It implements the net.Conn interface.
+type Conn struct {
+       // The origin URI for the Web Socket.
+       Origin string
+       // The location URI for the Web Socket.
+       Location string
+       // The subprotocol for the Web Socket.
+       Protocol string
+
+       buf *bufio.ReadWriter
+       rwc io.ReadWriteCloser
+
+       // It holds text data in previous Read() that failed with small buffer.
+       data    []byte
+       reading bool
+}
+
+// newConn creates a new Web Socket.
+func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
+       if buf == nil {
+               br := bufio.NewReader(rwc)
+               bw := bufio.NewWriter(rwc)
+               buf = bufio.NewReadWriter(br, bw)
+       }
+       ws := &Conn{Origin: origin, Location: location, Protocol: protocol, buf: buf, rwc: rwc}
+       return ws
+}
+
+// Read implements the io.Reader interface for a Conn.
+func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
+Frame:
+       for !ws.reading && len(ws.data) == 0 {
+               // Beginning of frame, possibly.
+               b, err := ws.buf.ReadByte()
+               if err != nil {
+                       return 0, err
+               }
+               if b&0x80 == 0x80 {
+                       // Skip length frame.
+                       length := 0
+                       for {
+                               c, err := ws.buf.ReadByte()
+                               if err != nil {
+                                       return 0, err
+                               }
+                               length = length*128 + int(c&0x7f)
+                               if c&0x80 == 0 {
+                                       break
+                               }
+                       }
+                       for length > 0 {
+                               _, err := ws.buf.ReadByte()
+                               if err != nil {
+                                       return 0, err
+                               }
+                       }
+                       continue Frame
+               }
+               // In text mode
+               if b != 0 {
+                       // Skip this frame
+                       for {
+                               c, err := ws.buf.ReadByte()
+                               if err != nil {
+                                       return 0, err
+                               }
+                               if c == '\xff' {
+                                       break
+                               }
+                       }
+                       continue Frame
+               }
+               ws.reading = true
+       }
+       if len(ws.data) == 0 {
+               ws.data, err = ws.buf.ReadSlice('\xff')
+               if err == nil {
+                       ws.reading = false
+                       ws.data = ws.data[:len(ws.data)-1] // trim \xff
+               }
+       }
+       n = copy(msg, ws.data)
+       ws.data = ws.data[n:]
+       return n, err
+}
+
+// Write implements the io.Writer interface for a Conn.
+func (ws *Conn) Write(msg []byte) (n int, err os.Error) {
+       ws.buf.WriteByte(0)
+       ws.buf.Write(msg)
+       ws.buf.WriteByte(0xff)
+       err = ws.buf.Flush()
+       return len(msg), err
+}
+
+// Close implements the io.Closer interface for a Conn.
+func (ws *Conn) Close() os.Error { return ws.rwc.Close() }
+
+// LocalAddr returns the WebSocket Origin for the connection.
+func (ws *Conn) LocalAddr() net.Addr { return WebSocketAddr(ws.Origin) }
+
+// RemoteAddr returns the WebSocket locations for the connection.
+func (ws *Conn) RemoteAddr() net.Addr { return WebSocketAddr(ws.Location) }
+
+// SetTimeout sets the connection's network timeout in nanoseconds.
+func (ws *Conn) SetTimeout(nsec int64) os.Error {
+       if conn, ok := ws.rwc.(net.Conn); ok {
+               return conn.SetTimeout(nsec)
+       }
+       return os.EINVAL
+}
+
+// SetReadTimeout sets the connection's network read timeout in nanoseconds.
+func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
+       if conn, ok := ws.rwc.(net.Conn); ok {
+               return conn.SetReadTimeout(nsec)
+       }
+       return os.EINVAL
+}
+
+// SetWritetTimeout sets the connection's network write timeout in nanoseconds.
+func (ws *Conn) SetWriteTimeout(nsec int64) os.Error {
+       if conn, ok := ws.rwc.(net.Conn); ok {
+               return conn.SetWriteTimeout(nsec)
+       }
+       return os.EINVAL
+}
+
+// getChallengeResponse computes the expected response from the
+// challenge as described in section 5.1 Opening Handshake steps 42 to
+// 43 of http://www.whatwg.org/specs/web-socket-protocol/
+func getChallengeResponse(number1, number2 uint32, key3 []byte) (expected []byte, err os.Error) {
+       // 41. Let /challenge/ be the concatenation of /number_1/, expressed
+       // a big-endian 32 bit integer, /number_2/, expressed in a big-
+       // endian 32 bit integer, and the eight bytes of /key_3/ in the
+       // order they were sent to the wire.
+       challenge := make([]byte, 16)
+       binary.BigEndian.PutUint32(challenge[0:], number1)
+       binary.BigEndian.PutUint32(challenge[4:], number2)
+       copy(challenge[8:], key3)
+
+       // 42. Let /expected/ be the MD5 fingerprint of /challenge/ as a big-
+       // endian 128 bit string.
+       h := md5.New()
+       if _, err = h.Write(challenge); err != nil {
+               return
+       }
+       expected = h.Sum()
+       return
+}
+
+var _ net.Conn = (*Conn)(nil) // compile-time check that *Conn implements net.Conn.
diff --git a/libgo/go/websocket/websocket_test.go b/libgo/go/websocket/websocket_test.go
new file mode 100644 (file)
index 0000000..c66c114
--- /dev/null
@@ -0,0 +1,272 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "http"
+       "io"
+       "log"
+       "net"
+       "sync"
+       "testing"
+)
+
+var serverAddr string
+var once sync.Once
+
+func echoServer(ws *Conn) { io.Copy(ws, ws) }
+
+func startServer() {
+       l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
+       if e != nil {
+               log.Exitf("net.Listen tcp :0 %v", e)
+       }
+       serverAddr = l.Addr().String()
+       log.Print("Test WebSocket server listening on ", serverAddr)
+       http.Handle("/echo", Handler(echoServer))
+       http.Handle("/echoDraft75", Draft75Handler(echoServer))
+       go http.Serve(l, nil)
+}
+
+// Test the getChallengeResponse function with values from section
+// 5.1 of the specification steps 18, 26, and 43 from
+// http://www.whatwg.org/specs/web-socket-protocol/
+func TestChallenge(t *testing.T) {
+       var part1 uint32 = 777007543
+       var part2 uint32 = 114997259
+       key3 := []byte{0x47, 0x30, 0x22, 0x2D, 0x5A, 0x3F, 0x47, 0x58}
+       expected := []byte("0st3Rl&q-2ZU^weu")
+
+       response, err := getChallengeResponse(part1, part2, key3)
+       if err != nil {
+               t.Errorf("getChallengeResponse: returned error %v", err)
+               return
+       }
+       if !bytes.Equal(expected, response) {
+               t.Errorf("getChallengeResponse: expected %q got %q", expected, response)
+       }
+}
+
+func TestEcho(t *testing.T) {
+       once.Do(startServer)
+
+       // websocket.Dial()
+       client, err := net.Dial("tcp", "", serverAddr)
+       if err != nil {
+               t.Fatal("dialing", err)
+       }
+       ws, err := newClient("/echo", "localhost", "http://localhost",
+               "ws://localhost/echo", "", client, handshake)
+       if err != nil {
+               t.Errorf("WebSocket handshake error: %v", err)
+               return
+       }
+
+       msg := []byte("hello, world\n")
+       if _, err := ws.Write(msg); err != nil {
+               t.Errorf("Write: %v", err)
+       }
+       var actual_msg = make([]byte, 512)
+       n, err := ws.Read(actual_msg)
+       if err != nil {
+               t.Errorf("Read: %v", err)
+       }
+       actual_msg = actual_msg[0:n]
+       if !bytes.Equal(msg, actual_msg) {
+               t.Errorf("Echo: expected %q got %q", msg, actual_msg)
+       }
+       ws.Close()
+}
+
+func TestEchoDraft75(t *testing.T) {
+       once.Do(startServer)
+
+       // websocket.Dial()
+       client, err := net.Dial("tcp", "", serverAddr)
+       if err != nil {
+               t.Fatal("dialing", err)
+       }
+       ws, err := newClient("/echoDraft75", "localhost", "http://localhost",
+               "ws://localhost/echoDraft75", "", client, draft75handshake)
+       if err != nil {
+               t.Errorf("WebSocket handshake: %v", err)
+               return
+       }
+
+       msg := []byte("hello, world\n")
+       if _, err := ws.Write(msg); err != nil {
+               t.Errorf("Write: error %v", err)
+       }
+       var actual_msg = make([]byte, 512)
+       n, err := ws.Read(actual_msg)
+       if err != nil {
+               t.Errorf("Read: error %v", err)
+       }
+       actual_msg = actual_msg[0:n]
+       if !bytes.Equal(msg, actual_msg) {
+               t.Errorf("Echo: expected %q got %q", msg, actual_msg)
+       }
+       ws.Close()
+}
+
+func TestWithQuery(t *testing.T) {
+       once.Do(startServer)
+
+       client, err := net.Dial("tcp", "", serverAddr)
+       if err != nil {
+               t.Fatal("dialing", err)
+       }
+
+       ws, err := newClient("/echo?q=v", "localhost", "http://localhost",
+               "ws://localhost/echo?q=v", "", client, handshake)
+       if err != nil {
+               t.Errorf("WebSocket handshake: %v", err)
+               return
+       }
+       ws.Close()
+}
+
+func TestWithProtocol(t *testing.T) {
+       once.Do(startServer)
+
+       client, err := net.Dial("tcp", "", serverAddr)
+       if err != nil {
+               t.Fatal("dialing", err)
+       }
+
+       ws, err := newClient("/echo", "localhost", "http://localhost",
+               "ws://localhost/echo", "test", client, handshake)
+       if err != nil {
+               t.Errorf("WebSocket handshake: %v", err)
+               return
+       }
+       ws.Close()
+}
+
+func TestHTTP(t *testing.T) {
+       once.Do(startServer)
+
+       // If the client did not send a handshake that matches the protocol
+       // specification, the server should abort the WebSocket connection.
+       _, _, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
+       if err == nil {
+               t.Errorf("Get: unexpected success")
+               return
+       }
+       urlerr, ok := err.(*http.URLError)
+       if !ok {
+               t.Errorf("Get: not URLError %#v", err)
+               return
+       }
+       if urlerr.Error != io.ErrUnexpectedEOF {
+               t.Errorf("Get: error %#v", err)
+               return
+       }
+}
+
+func TestHTTPDraft75(t *testing.T) {
+       once.Do(startServer)
+
+       r, _, err := http.Get(fmt.Sprintf("http://%s/echoDraft75", serverAddr))
+       if err != nil {
+               t.Errorf("Get: error %#v", err)
+               return
+       }
+       if r.StatusCode != http.StatusBadRequest {
+               t.Errorf("Get: got status %d", r.StatusCode)
+       }
+}
+
+func TestTrailingSpaces(t *testing.T) {
+       // http://code.google.com/p/go/issues/detail?id=955
+       // The last runs of this create keys with trailing spaces that should not be
+       // generated by the client.
+       once.Do(startServer)
+       for i := 0; i < 30; i++ {
+               // body
+               _, err := Dial(fmt.Sprintf("ws://%s/echo", serverAddr), "",
+                       "http://localhost/")
+               if err != nil {
+                       panic("Dial failed: " + err.String())
+               }
+       }
+}
+
+func TestSmallBuffer(t *testing.T) {
+       // http://code.google.com/p/go/issues/detail?id=1145
+       // Read should be able to handle reading a fragment of a frame.
+       once.Do(startServer)
+
+       // websocket.Dial()
+       client, err := net.Dial("tcp", "", serverAddr)
+       if err != nil {
+               t.Fatal("dialing", err)
+       }
+       ws, err := newClient("/echo", "localhost", "http://localhost",
+               "ws://localhost/echo", "", client, handshake)
+       if err != nil {
+               t.Errorf("WebSocket handshake error: %v", err)
+               return
+       }
+
+       msg := []byte("hello, world\n")
+       if _, err := ws.Write(msg); err != nil {
+               t.Errorf("Write: %v", err)
+       }
+       var small_msg = make([]byte, 8)
+       n, err := ws.Read(small_msg)
+       if err != nil {
+               t.Errorf("Read: %v", err)
+       }
+       if !bytes.Equal(msg[:len(small_msg)], small_msg) {
+               t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg)
+       }
+       var second_msg = make([]byte, len(msg))
+       n, err = ws.Read(second_msg)
+       if err != nil {
+               t.Errorf("Read: %v", err)
+       }
+       second_msg = second_msg[0:n]
+       if !bytes.Equal(msg[len(small_msg):], second_msg) {
+               t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg)
+       }
+       ws.Close()
+
+}
+
+func testSkipLengthFrame(t *testing.T) {
+       b := []byte{'\x80', '\x01', 'x', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
+       buf := bytes.NewBuffer(b)
+       br := bufio.NewReader(buf)
+       bw := bufio.NewWriter(buf)
+       ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
+       msg := make([]byte, 5)
+       n, err := ws.Read(msg)
+       if err != nil {
+               t.Errorf("Read: %v", err)
+       }
+       if !bytes.Equal(b[4:8], msg[0:n]) {
+               t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
+       }
+}
+
+func testSkipNoUTF8Frame(t *testing.T) {
+       b := []byte{'\x01', 'n', '\xff', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
+       buf := bytes.NewBuffer(b)
+       br := bufio.NewReader(buf)
+       bw := bufio.NewWriter(buf)
+       ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
+       msg := make([]byte, 5)
+       n, err := ws.Read(msg)
+       if err != nil {
+               t.Errorf("Read: %v", err)
+       }
+       if !bytes.Equal(b[4:8], msg[0:n]) {
+               t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
+       }
+}
diff --git a/libgo/go/xml/embed_test.go b/libgo/go/xml/embed_test.go
new file mode 100644 (file)
index 0000000..abfe781
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import "testing"
+
+type C struct {
+       Name string
+       Open bool
+}
+
+type A struct {
+       XMLName Name "http://domain a"
+       C
+       B      B
+       FieldA string
+}
+
+type B struct {
+       XMLName Name "b"
+       C
+       FieldB string
+}
+
+const _1a = `
+<?xml version="1.0" encoding="UTF-8"?>
+<a xmlns="http://domain">
+  <name>KmlFile</name>
+  <open>1</open>
+  <b>
+    <name>Absolute</name>
+    <open>0</open>
+    <fieldb>bar</fieldb>
+  </b>
+  <fielda>foo</fielda>
+</a>
+`
+
+// Tests that embedded structs are marshalled.
+func TestEmbedded1(t *testing.T) {
+       var a A
+       if e := Unmarshal(StringReader(_1a), &a); e != nil {
+               t.Fatalf("Unmarshal: %s", e)
+       }
+       if a.FieldA != "foo" {
+               t.Fatalf("Unmarshal: expected 'foo' but found '%s'", a.FieldA)
+       }
+       if a.Name != "KmlFile" {
+               t.Fatalf("Unmarshal: expected 'KmlFile' but found '%s'", a.Name)
+       }
+       if !a.Open {
+               t.Fatal("Unmarshal: expected 'true' but found otherwise")
+       }
+       if a.B.FieldB != "bar" {
+               t.Fatalf("Unmarshal: expected 'bar' but found '%s'", a.B.FieldB)
+       }
+       if a.B.Name != "Absolute" {
+               t.Fatalf("Unmarshal: expected 'Absolute' but found '%s'", a.B.Name)
+       }
+       if a.B.Open {
+               t.Fatal("Unmarshal: expected 'false' but found otherwise")
+       }
+}
+
+type A2 struct {
+       XMLName Name "http://domain a"
+       XY      string
+       Xy      string
+}
+
+const _2a = `
+<?xml version="1.0" encoding="UTF-8"?>
+<a xmlns="http://domain">
+  <xy>foo</xy>
+</a>
+`
+
+// Tests that conflicting field names get excluded.
+func TestEmbedded2(t *testing.T) {
+       var a A2
+       if e := Unmarshal(StringReader(_2a), &a); e != nil {
+               t.Fatalf("Unmarshal: %s", e)
+       }
+       if a.XY != "" {
+               t.Fatalf("Unmarshal: expected empty string but found '%s'", a.XY)
+       }
+       if a.Xy != "" {
+               t.Fatalf("Unmarshal: expected empty string but found '%s'", a.Xy)
+       }
+}
+
+type A3 struct {
+       XMLName Name "http://domain a"
+       xy      string
+}
+
+// Tests that private fields are not set.
+func TestEmbedded3(t *testing.T) {
+       var a A3
+       if e := Unmarshal(StringReader(_2a), &a); e != nil {
+               t.Fatalf("Unmarshal: %s", e)
+       }
+       if a.xy != "" {
+               t.Fatalf("Unmarshal: expected empty string but found '%s'", a.xy)
+       }
+}
+
+type A4 struct {
+       XMLName Name "http://domain a"
+       Any     string
+}
+
+// Tests that private fields are not set.
+func TestEmbedded4(t *testing.T) {
+       var a A4
+       if e := Unmarshal(StringReader(_2a), &a); e != nil {
+               t.Fatalf("Unmarshal: %s", e)
+       }
+       if a.Any != "foo" {
+               t.Fatalf("Unmarshal: expected 'foo' but found '%s'", a.Any)
+       }
+}
diff --git a/libgo/go/xml/read.go b/libgo/go/xml/read.go
new file mode 100644 (file)
index 0000000..bbceda6
--- /dev/null
@@ -0,0 +1,493 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "reflect"
+       "strconv"
+       "strings"
+       "unicode"
+       "utf8"
+)
+
+// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
+// an XML element is an order-dependent collection of anonymous
+// values, while a data structure is an order-independent collection
+// of named values.
+// See package json for a textual representation more suitable
+// to data structures.
+
+// Unmarshal parses an XML element from r and uses the
+// reflect library to fill in an arbitrary struct, slice, or string
+// pointed at by val.  Well-formed data that does not fit
+// into val is discarded.
+//
+// For example, given these definitions:
+//
+//     type Email struct {
+//             Where string "attr"
+//             Addr  string
+//     }
+//
+//     type Result struct {
+//             XMLName xml.Name "result"
+//             Name    string
+//             Phone   string
+//             Email   []Email
+//     }
+//
+//     result := Result{Name: "name", Phone: "phone", Email: nil}
+//
+// unmarshalling the XML input
+//
+//     <result>
+//             <email where="home">
+//                     <addr>gre@example.com</addr>
+//             </email>
+//             <email where='work'>
+//                     <addr>gre@work.com</addr>
+//             </email>
+//             <name>Grace R. Emlin</name>
+//             <address>123 Main Street</address>
+//     </result>
+//
+// via Unmarshal(r, &result) is equivalent to assigning
+//
+//     r = Result{xml.Name{"", "result"},
+//             "Grace R. Emlin", // name
+//             "phone",          // no phone given
+//             []Email{
+//                     Email{"home", "gre@example.com"},
+//                     Email{"work", "gre@work.com"},
+//             },
+//     }
+//
+// Note that the field r.Phone has not been modified and
+// that the XML <address> element was discarded.
+//
+// Because Unmarshal uses the reflect package, it can only
+// assign to upper case fields.  Unmarshal uses a case-insensitive
+// comparison to match XML element names to struct field names.
+//
+// Unmarshal maps an XML element to a struct using the following rules:
+//
+//   * If the struct has a field of type []byte or string with tag "innerxml",
+//      Unmarshal accumulates the raw XML nested inside the element
+//      in that field.  The rest of the rules still apply.
+//
+//   * If the struct has a field named XMLName of type xml.Name,
+//      Unmarshal records the element name in that field.
+//
+//   * If the XMLName field has an associated tag string of the form
+//      "tag" or "namespace-URL tag", the XML element must have
+//      the given tag (and, optionally, name space) or else Unmarshal
+//      returns an error.
+//
+//   * If the XML element has an attribute whose name matches a
+//      struct field of type string with tag "attr", Unmarshal records
+//      the attribute value in that field.
+//
+//   * If the XML element contains character data, that data is
+//      accumulated in the first struct field that has tag "chardata".
+//      The struct field may have type []byte or string.
+//      If there is no such field, the character data is discarded.
+//
+//   * If the XML element contains a sub-element whose name
+//      matches a struct field whose tag is neither "attr" nor "chardata",
+//      Unmarshal maps the sub-element to that struct field.
+//      Otherwise, if the struct has a field named Any, unmarshal
+//      maps the sub-element to that struct field.
+//
+// Unmarshal maps an XML element to a string or []byte by saving the
+// concatenation of that elements character data in the string or []byte.
+//
+// Unmarshal maps an XML element to a slice by extending the length
+// of the slice and mapping the element to the newly created value.
+//
+// Unmarshal maps an XML element to a bool by setting it to the boolean
+// value represented by the string.
+//
+// Unmarshal maps an XML element to an integer or floating-point
+// field by setting the field to the result of interpreting the string
+// value in decimal.  There is no check for overflow.
+//
+// Unmarshal maps an XML element to an xml.Name by recording the
+// element name.
+//
+// Unmarshal maps an XML element to a pointer by setting the pointer
+// to a freshly allocated value and then mapping the element to that value.
+//
+func Unmarshal(r io.Reader, val interface{}) os.Error {
+       v, ok := reflect.NewValue(val).(*reflect.PtrValue)
+       if !ok {
+               return os.NewError("non-pointer passed to Unmarshal")
+       }
+       p := NewParser(r)
+       elem := v.Elem()
+       err := p.unmarshal(elem, nil)
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+// An UnmarshalError represents an error in the unmarshalling process.
+type UnmarshalError string
+
+func (e UnmarshalError) String() string { return string(e) }
+
+// The Parser's Unmarshal method is like xml.Unmarshal
+// except that it can be passed a pointer to the initial start element,
+// useful when a client reads some raw XML tokens itself
+// but also defers to Unmarshal for some elements.
+// Passing a nil start element indicates that Unmarshal should
+// read the token stream to find the start element.
+func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
+       v, ok := reflect.NewValue(val).(*reflect.PtrValue)
+       if !ok {
+               return os.NewError("non-pointer passed to Unmarshal")
+       }
+       return p.unmarshal(v.Elem(), start)
+}
+
+// fieldName strips invalid characters from an XML name
+// to create a valid Go struct name.  It also converts the
+// name to lower case letters.
+func fieldName(original string) string {
+
+       var i int
+       //remove leading underscores
+       for i = 0; i < len(original) && original[i] == '_'; i++ {
+       }
+
+       return strings.Map(
+               func(x int) int {
+                       if x == '_' || unicode.IsDigit(x) || unicode.IsLetter(x) {
+                               return unicode.ToLower(x)
+                       }
+                       return -1
+               },
+               original[i:])
+}
+
+// Unmarshal a single XML element into val.
+func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
+       // Find start element if we need it.
+       if start == nil {
+               for {
+                       tok, err := p.Token()
+                       if err != nil {
+                               return err
+                       }
+                       if t, ok := tok.(StartElement); ok {
+                               start = &t
+                               break
+                       }
+               }
+       }
+
+       if pv, ok := val.(*reflect.PtrValue); ok {
+               if pv.Get() == 0 {
+                       zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
+                       pv.PointTo(zv)
+                       val = zv
+               } else {
+                       val = pv.Elem()
+               }
+       }
+
+       var (
+               data         []byte
+               saveData     reflect.Value
+               comment      []byte
+               saveComment  reflect.Value
+               saveXML      reflect.Value
+               saveXMLIndex int
+               saveXMLData  []byte
+               sv           *reflect.StructValue
+               styp         *reflect.StructType
+       )
+       switch v := val.(type) {
+       default:
+               return os.ErrorString("unknown type " + v.Type().String())
+
+       case *reflect.SliceValue:
+               typ := v.Type().(*reflect.SliceType)
+               if typ.Elem().Kind() == reflect.Uint8 {
+                       // []byte
+                       saveData = v
+                       break
+               }
+
+               // Slice of element values.
+               // Grow slice.
+               n := v.Len()
+               if n >= v.Cap() {
+                       ncap := 2 * n
+                       if ncap < 4 {
+                               ncap = 4
+                       }
+                       new := reflect.MakeSlice(typ, n, ncap)
+                       reflect.ArrayCopy(new, v)
+                       v.Set(new)
+               }
+               v.SetLen(n + 1)
+
+               // Recur to read element into slice.
+               if err := p.unmarshal(v.Elem(n), start); err != nil {
+                       v.SetLen(n)
+                       return err
+               }
+               return nil
+
+       case *reflect.BoolValue, *reflect.FloatValue, *reflect.IntValue, *reflect.UintValue, *reflect.StringValue:
+               saveData = v
+
+       case *reflect.StructValue:
+               if _, ok := v.Interface().(Name); ok {
+                       v.Set(reflect.NewValue(start.Name).(*reflect.StructValue))
+                       break
+               }
+
+               sv = v
+               typ := sv.Type().(*reflect.StructType)
+               styp = typ
+               // Assign name.
+               if f, ok := typ.FieldByName("XMLName"); ok {
+                       // Validate element name.
+                       if f.Tag != "" {
+                               tag := f.Tag
+                               ns := ""
+                               i := strings.LastIndex(tag, " ")
+                               if i >= 0 {
+                                       ns, tag = tag[0:i], tag[i+1:]
+                               }
+                               if tag != start.Name.Local {
+                                       return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
+                               }
+                               if ns != "" && ns != start.Name.Space {
+                                       e := "expected element <" + tag + "> in name space " + ns + " but have "
+                                       if start.Name.Space == "" {
+                                               e += "no name space"
+                                       } else {
+                                               e += start.Name.Space
+                                       }
+                                       return UnmarshalError(e)
+                               }
+                       }
+
+                       // Save
+                       v := sv.FieldByIndex(f.Index)
+                       if _, ok := v.Interface().(Name); !ok {
+                               return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
+                       }
+                       v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue))
+               }
+
+               // Assign attributes.
+               // Also, determine whether we need to save character data or comments.
+               for i, n := 0, typ.NumField(); i < n; i++ {
+                       f := typ.Field(i)
+                       switch f.Tag {
+                       case "attr":
+                               strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue)
+                               if !ok {
+                                       return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
+                               }
+                               // Look for attribute.
+                               val := ""
+                               k := strings.ToLower(f.Name)
+                               for _, a := range start.Attr {
+                                       if fieldName(a.Name.Local) == k {
+                                               val = a.Value
+                                               break
+                                       }
+                               }
+                               strv.Set(val)
+
+                       case "comment":
+                               if saveComment == nil {
+                                       saveComment = sv.FieldByIndex(f.Index)
+                               }
+
+                       case "chardata":
+                               if saveData == nil {
+                                       saveData = sv.FieldByIndex(f.Index)
+                               }
+
+                       case "innerxml":
+                               if saveXML == nil {
+                                       saveXML = sv.FieldByIndex(f.Index)
+                                       if p.saved == nil {
+                                               saveXMLIndex = 0
+                                               p.saved = new(bytes.Buffer)
+                                       } else {
+                                               saveXMLIndex = p.savedOffset()
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // Find end element.
+       // Process sub-elements along the way.
+Loop:
+       for {
+               var savedOffset int
+               if saveXML != nil {
+                       savedOffset = p.savedOffset()
+               }
+               tok, err := p.Token()
+               if err != nil {
+                       return err
+               }
+               switch t := tok.(type) {
+               case StartElement:
+                       // Sub-element.
+                       // Look up by tag name.
+                       if sv != nil {
+                               k := fieldName(t.Name.Local)
+                               match := func(s string) bool {
+                                       // check if the name matches ignoring case
+                                       if strings.ToLower(s) != strings.ToLower(k) {
+                                               return false
+                                       }
+                                       // now check that it's public
+                                       c, _ := utf8.DecodeRuneInString(s)
+                                       return unicode.IsUpper(c)
+                               }
+
+                               f, found := styp.FieldByNameFunc(match)
+                               if !found { // fall back to mop-up field named "Any"
+                                       f, found = styp.FieldByName("Any")
+                               }
+                               if found {
+                                       if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
+                                               return err
+                                       }
+                                       continue Loop
+                               }
+                       }
+                       // Not saving sub-element but still have to skip over it.
+                       if err := p.Skip(); err != nil {
+                               return err
+                       }
+
+               case EndElement:
+                       if saveXML != nil {
+                               saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
+                               if saveXMLIndex == 0 {
+                                       p.saved = nil
+                               }
+                       }
+                       break Loop
+
+               case CharData:
+                       if saveData != nil {
+                               data = bytes.Add(data, t)
+                       }
+
+               case Comment:
+                       if saveComment != nil {
+                               comment = bytes.Add(comment, t)
+                       }
+               }
+       }
+
+       var err os.Error
+       // Helper functions for integer and unsigned integer conversions
+       var itmp int64
+       getInt64 := func() bool {
+               itmp, err = strconv.Atoi64(string(data))
+               // TODO: should check sizes
+               return err == nil
+       }
+       var utmp uint64
+       getUint64 := func() bool {
+               utmp, err = strconv.Atoui64(string(data))
+               // TODO: check for overflow?
+               return err == nil
+       }
+       var ftmp float64
+       getFloat64 := func() bool {
+               ftmp, err = strconv.Atof64(string(data))
+               // TODO: check for overflow?
+               return err == nil
+       }
+
+       // Save accumulated data and comments
+       switch t := saveData.(type) {
+       case nil:
+               // Probably a comment, handled below
+       default:
+               return os.ErrorString("cannot happen: unknown type " + t.Type().String())
+       case *reflect.IntValue:
+               if !getInt64() {
+                       return err
+               }
+               t.Set(itmp)
+       case *reflect.UintValue:
+               if !getUint64() {
+                       return err
+               }
+               t.Set(utmp)
+       case *reflect.FloatValue:
+               if !getFloat64() {
+                       return err
+               }
+               t.Set(ftmp)
+       case *reflect.BoolValue:
+               value, err := strconv.Atob(strings.TrimSpace(string(data)))
+               if err != nil {
+                       return err
+               }
+               t.Set(value)
+       case *reflect.StringValue:
+               t.Set(string(data))
+       case *reflect.SliceValue:
+               t.Set(reflect.NewValue(data).(*reflect.SliceValue))
+       }
+
+       switch t := saveComment.(type) {
+       case *reflect.StringValue:
+               t.Set(string(comment))
+       case *reflect.SliceValue:
+               t.Set(reflect.NewValue(comment).(*reflect.SliceValue))
+       }
+
+       switch t := saveXML.(type) {
+       case *reflect.StringValue:
+               t.Set(string(saveXMLData))
+       case *reflect.SliceValue:
+               t.Set(reflect.NewValue(saveXMLData).(*reflect.SliceValue))
+       }
+
+       return nil
+}
+
+// Have already read a start element.
+// Read tokens until we find the end element.
+// Token is taking care of making sure the
+// end element matches the start element we saw.
+func (p *Parser) Skip() os.Error {
+       for {
+               tok, err := p.Token()
+               if err != nil {
+                       return err
+               }
+               switch t := tok.(type) {
+               case StartElement:
+                       if err := p.Skip(); err != nil {
+                               return err
+                       }
+               case EndElement:
+                       return nil
+               }
+       }
+       panic("unreachable")
+}
diff --git a/libgo/go/xml/read_test.go b/libgo/go/xml/read_test.go
new file mode 100644 (file)
index 0000000..9ec1065
--- /dev/null
@@ -0,0 +1,232 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+       "reflect"
+       "testing"
+)
+
+// Stripped down Atom feed data structures.
+
+func TestUnmarshalFeed(t *testing.T) {
+       var f Feed
+       if err := Unmarshal(StringReader(rssFeedString), &f); err != nil {
+               t.Fatalf("Unmarshal: %s", err)
+       }
+       if !reflect.DeepEqual(f, rssFeed) {
+               t.Fatalf("have %#v\nwant %#v", f, rssFeed)
+       }
+}
+
+// hget http://codereview.appspot.com/rss/mine/rsc
+const rssFeedString = `
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><li-nk href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></li-nk><id>http://codereview.appspot.com/</id><updated>2009-10-04T01:35:58+00:00</updated><author><name>rietveld&lt;&gt;</name></author><entry><title>rietveld: an attempt at pubsubhubbub
+</title><link hre-f="http://codereview.appspot.com/126085" rel="alternate"></link><updated>2009-10-04T01:35:58+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:134d9179c41f806be79b3a5f7877d19a</id><summary type="html">
+  An attempt at adding pubsubhubbub support to Rietveld.
+http://code.google.com/p/pubsubhubbub
+http://code.google.com/p/rietveld/issues/detail?id=155
+
+The server side of the protocol is trivial:
+  1. add a &amp;lt;link rel=&amp;quot;hub&amp;quot; href=&amp;quot;hub-server&amp;quot;&amp;gt; tag to all
+     feeds that will be pubsubhubbubbed.
+  2. every time one of those feeds changes, tell the hub
+     with a simple POST request.
+
+I have tested this by adding debug prints to a local hub
+server and checking that the server got the right publish
+requests.
+
+I can&amp;#39;t quite get the server to work, but I think the bug
+is not in my code.  I think that the server expects to be
+able to grab the feed and see the feed&amp;#39;s actual URL in
+the link rel=&amp;quot;self&amp;quot;, but the default value for that drops
+the :port from the URL, and I cannot for the life of me
+figure out how to get the Atom generator deep inside
+django not to do that, or even where it is doing that,
+or even what code is running to generate the Atom feed.
+(I thought I knew but I added some assert False statements
+and it kept running!)
+
+Ignoring that particular problem, I would appreciate
+feedback on the right way to get the two values at
+the top of feeds.py marked NOTE(rsc).
+
+
+</summary></entry><entry><title>rietveld: correct tab handling
+</title><link href="http://codereview.appspot.com/124106" rel="alternate"></link><updated>2009-10-03T23:02:17+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:0a2a4f19bb815101f0ba2904aed7c35a</id><summary type="html">
+  This fixes the buggy tab rendering that can be seen at
+http://codereview.appspot.com/116075/diff/1/2
+
+The fundamental problem was that the tab code was
+not being told what column the text began in, so it
+didn&amp;#39;t know where to put the tab stops.  Another problem
+was that some of the code assumed that string byte
+offsets were the same as column offsets, which is only
+true if there are no tabs.
+
+In the process of fixing this, I cleaned up the arguments
+to Fold and ExpandTabs and renamed them Break and
+_ExpandTabs so that I could be sure that I found all the
+call sites.  I also wanted to verify that ExpandTabs was
+not being used from outside intra_region_diff.py.
+
+
+</summary></entry></feed>         `
+
+type Feed struct {
+       XMLName Name "http://www.w3.org/2005/Atom feed"
+       Title   string
+       Id      string
+       Link    []Link
+       Updated Time
+       Author  Person
+       Entry   []Entry
+}
+
+type Entry struct {
+       Title   string
+       Id      string
+       Link    []Link
+       Updated Time
+       Author  Person
+       Summary Text
+}
+
+type Link struct {
+       Rel  string "attr"
+       Href string "attr"
+}
+
+type Person struct {
+       Name     string
+       URI      string
+       Email    string
+       InnerXML string "innerxml"
+}
+
+type Text struct {
+       Type string "attr"
+       Body string "chardata"
+}
+
+type Time string
+
+var rssFeed = Feed{
+       XMLName: Name{"http://www.w3.org/2005/Atom", "feed"},
+       Title:   "Code Review - My issues",
+       Link: []Link{
+               {Rel: "alternate", Href: "http://codereview.appspot.com/"},
+               {Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
+       },
+       Id:      "http://codereview.appspot.com/",
+       Updated: "2009-10-04T01:35:58+00:00",
+       Author: Person{
+               Name:     "rietveld<>",
+               InnerXML: "<name>rietveld&lt;&gt;</name>",
+       },
+       Entry: []Entry{
+               {
+                       Title: "rietveld: an attempt at pubsubhubbub\n",
+                       Link: []Link{
+                               {Rel: "alternate", Href: "http://codereview.appspot.com/126085"},
+                       },
+                       Updated: "2009-10-04T01:35:58+00:00",
+                       Author: Person{
+                               Name:     "email-address-removed",
+                               InnerXML: "<name>email-address-removed</name>",
+                       },
+                       Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a",
+                       Summary: Text{
+                               Type: "html",
+                               Body: `
+  An attempt at adding pubsubhubbub support to Rietveld.
+http://code.google.com/p/pubsubhubbub
+http://code.google.com/p/rietveld/issues/detail?id=155
+
+The server side of the protocol is trivial:
+  1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all
+     feeds that will be pubsubhubbubbed.
+  2. every time one of those feeds changes, tell the hub
+     with a simple POST request.
+
+I have tested this by adding debug prints to a local hub
+server and checking that the server got the right publish
+requests.
+
+I can&#39;t quite get the server to work, but I think the bug
+is not in my code.  I think that the server expects to be
+able to grab the feed and see the feed&#39;s actual URL in
+the link rel=&quot;self&quot;, but the default value for that drops
+the :port from the URL, and I cannot for the life of me
+figure out how to get the Atom generator deep inside
+django not to do that, or even where it is doing that,
+or even what code is running to generate the Atom feed.
+(I thought I knew but I added some assert False statements
+and it kept running!)
+
+Ignoring that particular problem, I would appreciate
+feedback on the right way to get the two values at
+the top of feeds.py marked NOTE(rsc).
+
+
+`,
+                       },
+               },
+               {
+                       Title: "rietveld: correct tab handling\n",
+                       Link: []Link{
+                               {Rel: "alternate", Href: "http://codereview.appspot.com/124106"},
+                       },
+                       Updated: "2009-10-03T23:02:17+00:00",
+                       Author: Person{
+                               Name:     "email-address-removed",
+                               InnerXML: "<name>email-address-removed</name>",
+                       },
+                       Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a",
+                       Summary: Text{
+                               Type: "html",
+                               Body: `
+  This fixes the buggy tab rendering that can be seen at
+http://codereview.appspot.com/116075/diff/1/2
+
+The fundamental problem was that the tab code was
+not being told what column the text began in, so it
+didn&#39;t know where to put the tab stops.  Another problem
+was that some of the code assumed that string byte
+offsets were the same as column offsets, which is only
+true if there are no tabs.
+
+In the process of fixing this, I cleaned up the arguments
+to Fold and ExpandTabs and renamed them Break and
+_ExpandTabs so that I could be sure that I found all the
+call sites.  I also wanted to verify that ExpandTabs was
+not being used from outside intra_region_diff.py.
+
+
+`,
+                       },
+               },
+       },
+}
+
+type FieldNameTest struct {
+       in, out string
+}
+
+var FieldNameTests = []FieldNameTest{
+       {"Profile-Image", "profileimage"},
+       {"_score", "score"},
+}
+
+func TestFieldName(t *testing.T) {
+       for _, tt := range FieldNameTests {
+               a := fieldName(tt.in)
+               if a != tt.out {
+                       t.Fatalf("have %#v\nwant %#v\n\n", a, tt.out)
+               }
+       }
+}
diff --git a/libgo/go/xml/xml.go b/libgo/go/xml/xml.go
new file mode 100644 (file)
index 0000000..eed9355
--- /dev/null
@@ -0,0 +1,1589 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package xml implements a simple XML 1.0 parser that
+// understands XML name spaces.
+package xml
+
+// References:
+//    Annotated XML spec: http://www.xml.com/axml/testaxml.htm
+//    XML name spaces: http://www.w3.org/TR/REC-xml-names/
+
+// TODO(rsc):
+//     Test error handling.
+
+import (
+       "bufio"
+       "bytes"
+       "io"
+       "os"
+       "strconv"
+       "strings"
+       "unicode"
+       "utf8"
+)
+
+// A SyntaxError represents a syntax error in the XML input stream.
+type SyntaxError struct {
+       Msg  string
+       Line int
+}
+
+func (e *SyntaxError) String() string {
+       return "XML syntax error on line " + strconv.Itoa(e.Line) + ": " + e.Msg
+}
+
+// A Name represents an XML name (Local) annotated
+// with a name space identifier (Space).
+// In tokens returned by Parser.Token, the Space identifier
+// is given as a canonical URL, not the short prefix used
+// in the document being parsed.
+type Name struct {
+       Space, Local string
+}
+
+// An Attr represents an attribute in an XML element (Name=Value).
+type Attr struct {
+       Name  Name
+       Value string
+}
+
+// A Token is an interface holding one of the token types:
+// StartElement, EndElement, CharData, Comment, ProcInst, or Directive.
+type Token interface{}
+
+// A StartElement represents an XML start element.
+type StartElement struct {
+       Name Name
+       Attr []Attr
+}
+
+func (e StartElement) Copy() StartElement {
+       attrs := make([]Attr, len(e.Attr))
+       copy(e.Attr, attrs)
+       e.Attr = attrs
+       return e
+}
+
+// An EndElement represents an XML end element.
+type EndElement struct {
+       Name Name
+}
+
+// A CharData represents XML character data (raw text),
+// in which XML escape sequences have been replaced by
+// the characters they represent.
+type CharData []byte
+
+func makeCopy(b []byte) []byte {
+       b1 := make([]byte, len(b))
+       copy(b1, b)
+       return b1
+}
+
+func (c CharData) Copy() CharData { return CharData(makeCopy(c)) }
+
+// A Comment represents an XML comment of the form <!--comment-->.
+// The bytes do not include the <!-- and --> comment markers.
+type Comment []byte
+
+func (c Comment) Copy() Comment { return Comment(makeCopy(c)) }
+
+// A ProcInst represents an XML processing instruction of the form <?target inst?>
+type ProcInst struct {
+       Target string
+       Inst   []byte
+}
+
+func (p ProcInst) Copy() ProcInst {
+       p.Inst = makeCopy(p.Inst)
+       return p
+}
+
+// A Directive represents an XML directive of the form <!text>.
+// The bytes do not include the <! and > markers.
+type Directive []byte
+
+func (d Directive) Copy() Directive { return Directive(makeCopy(d)) }
+
+// CopyToken returns a copy of a Token.
+func CopyToken(t Token) Token {
+       switch v := t.(type) {
+       case CharData:
+               return v.Copy()
+       case Comment:
+               return v.Copy()
+       case Directive:
+               return v.Copy()
+       case ProcInst:
+               return v.Copy()
+       case StartElement:
+               return v.Copy()
+       }
+       return t
+}
+
+// A Parser represents an XML parser reading a particular input stream.
+// The parser assumes that its input is encoded in UTF-8.
+type Parser struct {
+       // Strict defaults to true, enforcing the requirements
+       // of the XML specification.
+       // If set to false, the parser allows input containing common
+       // mistakes:
+       //      * If an element is missing an end tag, the parser invents
+       //        end tags as necessary to keep the return values from Token
+       //        properly balanced.
+       //      * In attribute values and character data, unknown or malformed
+       //        character entities (sequences beginning with &) are left alone.
+       //
+       // Setting:
+       //
+       //      p.Strict = false;
+       //      p.AutoClose = HTMLAutoClose;
+       //      p.Entity = HTMLEntity
+       //
+       // creates a parser that can handle typical HTML.
+       Strict bool
+
+       // When Strict == false, AutoClose indicates a set of elements to
+       // consider closed immediately after they are opened, regardless
+       // of whether an end element is present.
+       AutoClose []string
+
+       // Entity can be used to map non-standard entity names to string replacements.
+       // The parser behaves as if these standard mappings are present in the map,
+       // regardless of the actual map content:
+       //
+       //      "lt": "<",
+       //      "gt": ">",
+       //      "amp": "&",
+       //      "apos": "'",
+       //      "quot": `"`,
+       Entity map[string]string
+
+       r         io.ReadByter
+       buf       bytes.Buffer
+       saved     *bytes.Buffer
+       stk       *stack
+       free      *stack
+       needClose bool
+       toClose   Name
+       nextToken Token
+       nextByte  int
+       ns        map[string]string
+       err       os.Error
+       line      int
+       tmp       [32]byte
+}
+
+// NewParser creates a new XML parser reading from r.
+func NewParser(r io.Reader) *Parser {
+       p := &Parser{
+               ns:       make(map[string]string),
+               nextByte: -1,
+               line:     1,
+               Strict:   true,
+       }
+
+       // Get efficient byte at a time reader.
+       // Assume that if reader has its own
+       // ReadByte, it's efficient enough.
+       // Otherwise, use bufio.
+       if rb, ok := r.(io.ReadByter); ok {
+               p.r = rb
+       } else {
+               p.r = bufio.NewReader(r)
+       }
+
+       return p
+}
+
+// Token returns the next XML token in the input stream.
+// At the end of the input stream, Token returns nil, os.EOF.
+//
+// Slices of bytes in the returned token data refer to the
+// parser's internal buffer and remain valid only until the next
+// call to Token.  To acquire a copy of the bytes, call CopyToken
+// or the token's Copy method.
+//
+// Token expands self-closing elements such as <br/>
+// into separate start and end elements returned by successive calls.
+//
+// Token guarantees that the StartElement and EndElement
+// tokens it returns are properly nested and matched:
+// if Token encounters an unexpected end element,
+// it will return an error.
+//
+// Token implements XML name spaces as described by
+// http://www.w3.org/TR/REC-xml-names/.  Each of the
+// Name structures contained in the Token has the Space
+// set to the URL identifying its name space when known.
+// If Token encounters an unrecognized name space prefix,
+// it uses the prefix as the Space rather than report an error.
+func (p *Parser) Token() (t Token, err os.Error) {
+       if p.nextToken != nil {
+               t = p.nextToken
+               p.nextToken = nil
+       } else if t, err = p.RawToken(); err != nil {
+               return
+       }
+
+       if !p.Strict {
+               if t1, ok := p.autoClose(t); ok {
+                       p.nextToken = t
+                       t = t1
+               }
+       }
+       switch t1 := t.(type) {
+       case StartElement:
+               // In XML name spaces, the translations listed in the
+               // attributes apply to the element name and
+               // to the other attribute names, so process
+               // the translations first.
+               for _, a := range t1.Attr {
+                       if a.Name.Space == "xmlns" {
+                               v, ok := p.ns[a.Name.Local]
+                               p.pushNs(a.Name.Local, v, ok)
+                               p.ns[a.Name.Local] = a.Value
+                       }
+                       if a.Name.Space == "" && a.Name.Local == "xmlns" {
+                               // Default space for untagged names
+                               v, ok := p.ns[""]
+                               p.pushNs("", v, ok)
+                               p.ns[""] = a.Value
+                       }
+               }
+
+               p.translate(&t1.Name, true)
+               for i := range t1.Attr {
+                       p.translate(&t1.Attr[i].Name, false)
+               }
+               p.pushElement(t1.Name)
+               t = t1
+
+       case EndElement:
+               p.translate(&t1.Name, true)
+               if !p.popElement(&t1) {
+                       return nil, p.err
+               }
+               t = t1
+       }
+       return
+}
+
+// Apply name space translation to name n.
+// The default name space (for Space=="")
+// applies only to element names, not to attribute names.
+func (p *Parser) translate(n *Name, isElementName bool) {
+       switch {
+       case n.Space == "xmlns":
+               return
+       case n.Space == "" && !isElementName:
+               return
+       case n.Space == "" && n.Local == "xmlns":
+               return
+       }
+       if v, ok := p.ns[n.Space]; ok {
+               n.Space = v
+       }
+}
+
+// Parsing state - stack holds old name space translations
+// and the current set of open elements.  The translations to pop when
+// ending a given tag are *below* it on the stack, which is
+// more work but forced on us by XML.
+type stack struct {
+       next *stack
+       kind int
+       name Name
+       ok   bool
+}
+
+const (
+       stkStart = iota
+       stkNs
+)
+
+func (p *Parser) push(kind int) *stack {
+       s := p.free
+       if s != nil {
+               p.free = s.next
+       } else {
+               s = new(stack)
+       }
+       s.next = p.stk
+       s.kind = kind
+       p.stk = s
+       return s
+}
+
+func (p *Parser) pop() *stack {
+       s := p.stk
+       if s != nil {
+               p.stk = s.next
+               s.next = p.free
+               p.free = s
+       }
+       return s
+}
+
+// Record that we are starting an element with the given name.
+func (p *Parser) pushElement(name Name) {
+       s := p.push(stkStart)
+       s.name = name
+}
+
+// Record that we are changing the value of ns[local].
+// The old value is url, ok.
+func (p *Parser) pushNs(local string, url string, ok bool) {
+       s := p.push(stkNs)
+       s.name.Local = local
+       s.name.Space = url
+       s.ok = ok
+}
+
+// Creates a SyntaxError with the current line number.
+func (p *Parser) syntaxError(msg string) os.Error {
+       return &SyntaxError{Msg: msg, Line: p.line}
+}
+
+// Record that we are ending an element with the given name.
+// The name must match the record at the top of the stack,
+// which must be a pushElement record.
+// After popping the element, apply any undo records from
+// the stack to restore the name translations that existed
+// before we saw this element.
+func (p *Parser) popElement(t *EndElement) bool {
+       s := p.pop()
+       name := t.Name
+       switch {
+       case s == nil || s.kind != stkStart:
+               p.err = p.syntaxError("unexpected end element </" + name.Local + ">")
+               return false
+       case s.name.Local != name.Local:
+               if !p.Strict {
+                       p.needClose = true
+                       p.toClose = t.Name
+                       t.Name = s.name
+                       return true
+               }
+               p.err = p.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">")
+               return false
+       case s.name.Space != name.Space:
+               p.err = p.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space +
+                       "closed by </" + name.Local + "> in space " + name.Space)
+               return false
+       }
+
+       // Pop stack until a Start is on the top, undoing the
+       // translations that were associated with the element we just closed.
+       for p.stk != nil && p.stk.kind != stkStart {
+               s := p.pop()
+               p.ns[s.name.Local] = s.name.Space, s.ok
+       }
+
+       return true
+}
+
+// If the top element on the stack is autoclosing and
+// t is not the end tag, invent the end tag.
+func (p *Parser) autoClose(t Token) (Token, bool) {
+       if p.stk == nil || p.stk.kind != stkStart {
+               return nil, false
+       }
+       name := strings.ToLower(p.stk.name.Local)
+       for _, s := range p.AutoClose {
+               if strings.ToLower(s) == name {
+                       // This one should be auto closed if t doesn't close it.
+                       et, ok := t.(EndElement)
+                       if !ok || et.Name.Local != name {
+                               return EndElement{p.stk.name}, true
+                       }
+                       break
+               }
+       }
+       return nil, false
+}
+
+
+// RawToken is like Token but does not verify that
+// start and end elements match and does not translate
+// name space prefixes to their corresponding URLs.
+func (p *Parser) RawToken() (Token, os.Error) {
+       if p.err != nil {
+               return nil, p.err
+       }
+       if p.needClose {
+               // The last element we read was self-closing and
+               // we returned just the StartElement half.
+               // Return the EndElement half now.
+               p.needClose = false
+               return EndElement{p.toClose}, nil
+       }
+
+       b, ok := p.getc()
+       if !ok {
+               return nil, p.err
+       }
+
+       if b != '<' {
+               // Text section.
+               p.ungetc(b)
+               data := p.text(-1, false)
+               if data == nil {
+                       return nil, p.err
+               }
+               return CharData(data), nil
+       }
+
+       if b, ok = p.mustgetc(); !ok {
+               return nil, p.err
+       }
+       switch b {
+       case '/':
+               // </: End element
+               var name Name
+               if name, ok = p.nsname(); !ok {
+                       if p.err == nil {
+                               p.err = p.syntaxError("expected element name after </")
+                       }
+                       return nil, p.err
+               }
+               p.space()
+               if b, ok = p.mustgetc(); !ok {
+                       return nil, p.err
+               }
+               if b != '>' {
+                       p.err = p.syntaxError("invalid characters between </" + name.Local + " and >")
+                       return nil, p.err
+               }
+               return EndElement{name}, nil
+
+       case '?':
+               // <?: Processing instruction.
+               // TODO(rsc): Should parse the <?xml declaration to make sure
+               // the version is 1.0 and the encoding is UTF-8.
+               var target string
+               if target, ok = p.name(); !ok {
+                       if p.err == nil {
+                               p.err = p.syntaxError("expected target name after <?")
+                       }
+                       return nil, p.err
+               }
+               p.space()
+               p.buf.Reset()
+               var b0 byte
+               for {
+                       if b, ok = p.mustgetc(); !ok {
+                               return nil, p.err
+                       }
+                       p.buf.WriteByte(b)
+                       if b0 == '?' && b == '>' {
+                               break
+                       }
+                       b0 = b
+               }
+               data := p.buf.Bytes()
+               data = data[0 : len(data)-2] // chop ?>
+               return ProcInst{target, data}, nil
+
+       case '!':
+               // <!: Maybe comment, maybe CDATA.
+               if b, ok = p.mustgetc(); !ok {
+                       return nil, p.err
+               }
+               switch b {
+               case '-': // <!-
+                       // Probably <!-- for a comment.
+                       if b, ok = p.mustgetc(); !ok {
+                               return nil, p.err
+                       }
+                       if b != '-' {
+                               p.err = p.syntaxError("invalid sequence <!- not part of <!--")
+                               return nil, p.err
+                       }
+                       // Look for terminator.
+                       p.buf.Reset()
+                       var b0, b1 byte
+                       for {
+                               if b, ok = p.mustgetc(); !ok {
+                                       return nil, p.err
+                               }
+                               p.buf.WriteByte(b)
+                               if b0 == '-' && b1 == '-' && b == '>' {
+                                       break
+                               }
+                               b0, b1 = b1, b
+                       }
+                       data := p.buf.Bytes()
+                       data = data[0 : len(data)-3] // chop -->
+                       return Comment(data), nil
+
+               case '[': // <![
+                       // Probably <![CDATA[.
+                       for i := 0; i < 6; i++ {
+                               if b, ok = p.mustgetc(); !ok {
+                                       return nil, p.err
+                               }
+                               if b != "CDATA["[i] {
+                                       p.err = p.syntaxError("invalid <![ sequence")
+                                       return nil, p.err
+                               }
+                       }
+                       // Have <![CDATA[.  Read text until ]]>.
+                       data := p.text(-1, true)
+                       if data == nil {
+                               return nil, p.err
+                       }
+                       return CharData(data), nil
+               }
+
+               // Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc.
+               // We don't care, but accumulate for caller.
+               p.buf.Reset()
+               p.buf.WriteByte(b)
+               for {
+                       if b, ok = p.mustgetc(); !ok {
+                               return nil, p.err
+                       }
+                       if b == '>' {
+                               break
+                       }
+                       p.buf.WriteByte(b)
+               }
+               return Directive(p.buf.Bytes()), nil
+       }
+
+       // Must be an open element like <a href="foo">
+       p.ungetc(b)
+
+       var (
+               name  Name
+               empty bool
+               attr  []Attr
+       )
+       if name, ok = p.nsname(); !ok {
+               if p.err == nil {
+                       p.err = p.syntaxError("expected element name after <")
+               }
+               return nil, p.err
+       }
+
+       attr = make([]Attr, 0, 4)
+       for {
+               p.space()
+               if b, ok = p.mustgetc(); !ok {
+                       return nil, p.err
+               }
+               if b == '/' {
+                       empty = true
+                       if b, ok = p.mustgetc(); !ok {
+                               return nil, p.err
+                       }
+                       if b != '>' {
+                               p.err = p.syntaxError("expected /> in element")
+                               return nil, p.err
+                       }
+                       break
+               }
+               if b == '>' {
+                       break
+               }
+               p.ungetc(b)
+
+               n := len(attr)
+               if n >= cap(attr) {
+                       nattr := make([]Attr, n, 2*cap(attr))
+                       copy(nattr, attr)
+                       attr = nattr
+               }
+               attr = attr[0 : n+1]
+               a := &attr[n]
+               if a.Name, ok = p.nsname(); !ok {
+                       if p.err == nil {
+                               p.err = p.syntaxError("expected attribute name in element")
+                       }
+                       return nil, p.err
+               }
+               p.space()
+               if b, ok = p.mustgetc(); !ok {
+                       return nil, p.err
+               }
+               if b != '=' {
+                       p.err = p.syntaxError("attribute name without = in element")
+                       return nil, p.err
+               }
+               p.space()
+               data := p.attrval()
+               if data == nil {
+                       return nil, p.err
+               }
+               a.Value = string(data)
+       }
+
+       if empty {
+               p.needClose = true
+               p.toClose = name
+       }
+       return StartElement{name, attr}, nil
+}
+
+func (p *Parser) attrval() []byte {
+       b, ok := p.mustgetc()
+       if !ok {
+               return nil
+       }
+       // Handle quoted attribute values
+       if b == '"' || b == '\'' {
+               return p.text(int(b), false)
+       }
+       // Handle unquoted attribute values for strict parsers
+       if p.Strict {
+               p.err = p.syntaxError("unquoted or missing attribute value in element")
+               return nil
+       }
+       // Handle unquoted attribute values for unstrict parsers
+       p.ungetc(b)
+       p.buf.Reset()
+       for {
+               b, ok = p.mustgetc()
+               if !ok {
+                       return nil
+               }
+               // http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2
+               if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' ||
+                       '0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' {
+                       p.buf.WriteByte(b)
+               } else {
+                       p.ungetc(b)
+                       break
+               }
+       }
+       return p.buf.Bytes()
+}
+
+// Skip spaces if any
+func (p *Parser) space() {
+       for {
+               b, ok := p.getc()
+               if !ok {
+                       return
+               }
+               switch b {
+               case ' ', '\r', '\n', '\t':
+               default:
+                       p.ungetc(b)
+                       return
+               }
+       }
+}
+
+// Read a single byte.
+// If there is no byte to read, return ok==false
+// and leave the error in p.err.
+// Maintain line number.
+func (p *Parser) getc() (b byte, ok bool) {
+       if p.err != nil {
+               return 0, false
+       }
+       if p.nextByte >= 0 {
+               b = byte(p.nextByte)
+               p.nextByte = -1
+       } else {
+               b, p.err = p.r.ReadByte()
+               if p.err != nil {
+                       return 0, false
+               }
+               if p.saved != nil {
+                       p.saved.WriteByte(b)
+               }
+       }
+       if b == '\n' {
+               p.line++
+       }
+       return b, true
+}
+
+// Return saved offset.
+// If we did ungetc (nextByte >= 0), have to back up one.
+func (p *Parser) savedOffset() int {
+       n := p.saved.Len()
+       if p.nextByte >= 0 {
+               n--
+       }
+       return n
+}
+
+// Must read a single byte.
+// If there is no byte to read,
+// set p.err to SyntaxError("unexpected EOF")
+// and return ok==false
+func (p *Parser) mustgetc() (b byte, ok bool) {
+       if b, ok = p.getc(); !ok {
+               if p.err == os.EOF {
+                       p.err = p.syntaxError("unexpected EOF")
+               }
+       }
+       return
+}
+
+// Unread a single byte.
+func (p *Parser) ungetc(b byte) {
+       if b == '\n' {
+               p.line--
+       }
+       p.nextByte = int(b)
+}
+
+var entity = map[string]int{
+       "lt":   '<',
+       "gt":   '>',
+       "amp":  '&',
+       "apos": '\'',
+       "quot": '"',
+}
+
+// Read plain text section (XML calls it character data).
+// If quote >= 0, we are in a quoted string and need to find the matching quote.
+// If cdata == true, we are in a <![CDATA[ section and need to find ]]>.
+// On failure return nil and leave the error in p.err.
+func (p *Parser) text(quote int, cdata bool) []byte {
+       var b0, b1 byte
+       var trunc int
+       p.buf.Reset()
+Input:
+       for {
+               b, ok := p.getc()
+               if !ok {
+                       if cdata {
+                               if p.err == os.EOF {
+                                       p.err = p.syntaxError("unexpected EOF in CDATA section")
+                               }
+                               return nil
+                       }
+                       break Input
+               }
+
+               // <![CDATA[ section ends with ]]>.
+               // It is an error for ]]> to appear in ordinary text.
+               if b0 == ']' && b1 == ']' && b == '>' {
+                       if cdata {
+                               trunc = 2
+                               break Input
+                       }
+                       p.err = p.syntaxError("unescaped ]]> not in CDATA section")
+                       return nil
+               }
+
+               // Stop reading text if we see a <.
+               if b == '<' && !cdata {
+                       if quote >= 0 {
+                               p.err = p.syntaxError("unescaped < inside quoted string")
+                               return nil
+                       }
+                       p.ungetc('<')
+                       break Input
+               }
+               if quote >= 0 && b == byte(quote) {
+                       break Input
+               }
+               if b == '&' && !cdata {
+                       // Read escaped character expression up to semicolon.
+                       // XML in all its glory allows a document to define and use
+                       // its own character names with <!ENTITY ...> directives.
+                       // Parsers are required to recognize lt, gt, amp, apos, and quot
+                       // even if they have not been declared.  That's all we allow.
+                       var i int
+               CharLoop:
+                       for i = 0; i < len(p.tmp); i++ {
+                               var ok bool
+                               p.tmp[i], ok = p.getc()
+                               if !ok {
+                                       if p.err == os.EOF {
+                                               p.err = p.syntaxError("unexpected EOF")
+                                       }
+                                       return nil
+                               }
+                               c := p.tmp[i]
+                               if c == ';' {
+                                       break
+                               }
+                               if 'a' <= c && c <= 'z' ||
+                                       'A' <= c && c <= 'Z' ||
+                                       '0' <= c && c <= '9' ||
+                                       c == '_' || c == '#' {
+                                       continue
+                               }
+                               p.ungetc(c)
+                               break
+                       }
+                       s := string(p.tmp[0:i])
+                       if i >= len(p.tmp) {
+                               if !p.Strict {
+                                       b0, b1 = 0, 0
+                                       p.buf.WriteByte('&')
+                                       p.buf.Write(p.tmp[0:i])
+                                       continue Input
+                               }
+                               p.err = p.syntaxError("character entity expression &" + s + "... too long")
+                               return nil
+                       }
+                       var haveText bool
+                       var text string
+                       if i >= 2 && s[0] == '#' {
+                               var n uint64
+                               var err os.Error
+                               if i >= 3 && s[1] == 'x' {
+                                       n, err = strconv.Btoui64(s[2:], 16)
+                               } else {
+                                       n, err = strconv.Btoui64(s[1:], 10)
+                               }
+                               if err == nil && n <= unicode.MaxRune {
+                                       text = string(n)
+                                       haveText = true
+                               }
+                       } else {
+                               if r, ok := entity[s]; ok {
+                                       text = string(r)
+                                       haveText = true
+                               } else if p.Entity != nil {
+                                       text, haveText = p.Entity[s]
+                               }
+                       }
+                       if !haveText {
+                               if !p.Strict {
+                                       b0, b1 = 0, 0
+                                       p.buf.WriteByte('&')
+                                       p.buf.Write(p.tmp[0:i])
+                                       continue Input
+                               }
+                               p.err = p.syntaxError("invalid character entity &" + s + ";")
+                               return nil
+                       }
+                       p.buf.Write([]byte(text))
+                       b0, b1 = 0, 0
+                       continue Input
+               }
+               p.buf.WriteByte(b)
+               b0, b1 = b1, b
+       }
+       data := p.buf.Bytes()
+       data = data[0 : len(data)-trunc]
+
+       // Must rewrite \r and \r\n into \n.
+       w := 0
+       for r := 0; r < len(data); r++ {
+               b := data[r]
+               if b == '\r' {
+                       if r+1 < len(data) && data[r+1] == '\n' {
+                               continue
+                       }
+                       b = '\n'
+               }
+               data[w] = b
+               w++
+       }
+       return data[0:w]
+}
+
+// Get name space name: name with a : stuck in the middle.
+// The part before the : is the name space identifier.
+func (p *Parser) nsname() (name Name, ok bool) {
+       s, ok := p.name()
+       if !ok {
+               return
+       }
+       i := strings.Index(s, ":")
+       if i < 0 {
+               name.Local = s
+       } else {
+               name.Space = s[0:i]
+               name.Local = s[i+1:]
+       }
+       return name, true
+}
+
+// Get name: /first(first|second)*/
+// Do not set p.err if the name is missing (unless unexpected EOF is received):
+// let the caller provide better context.
+func (p *Parser) name() (s string, ok bool) {
+       var b byte
+       if b, ok = p.mustgetc(); !ok {
+               return
+       }
+
+       // As a first approximation, we gather the bytes [A-Za-z_:.-\x80-\xFF]*
+       if b < utf8.RuneSelf && !isNameByte(b) {
+               p.ungetc(b)
+               return "", false
+       }
+       p.buf.Reset()
+       p.buf.WriteByte(b)
+       for {
+               if b, ok = p.mustgetc(); !ok {
+                       return
+               }
+               if b < utf8.RuneSelf && !isNameByte(b) {
+                       p.ungetc(b)
+                       break
+               }
+               p.buf.WriteByte(b)
+       }
+
+       // Then we check the characters.
+       s = p.buf.String()
+       for i, c := range s {
+               if !unicode.Is(first, c) && (i == 0 || !unicode.Is(second, c)) {
+                       p.err = p.syntaxError("invalid XML name: " + s)
+                       return "", false
+               }
+       }
+       return s, true
+}
+
+func isNameByte(c byte) bool {
+       return 'A' <= c && c <= 'Z' ||
+               'a' <= c && c <= 'z' ||
+               '0' <= c && c <= '9' ||
+               c == '_' || c == ':' || c == '.' || c == '-'
+}
+
+// These tables were generated by cut and paste from Appendix B of
+// the XML spec at http://www.xml.com/axml/testaxml.htm
+// and then reformatting.  First corresponds to (Letter | '_' | ':')
+// and second corresponds to NameChar.
+
+var first = []unicode.Range{
+       {0x003A, 0x003A, 1},
+       {0x0041, 0x005A, 1},
+       {0x005F, 0x005F, 1},
+       {0x0061, 0x007A, 1},
+       {0x00C0, 0x00D6, 1},
+       {0x00D8, 0x00F6, 1},
+       {0x00F8, 0x00FF, 1},
+       {0x0100, 0x0131, 1},
+       {0x0134, 0x013E, 1},
+       {0x0141, 0x0148, 1},
+       {0x014A, 0x017E, 1},
+       {0x0180, 0x01C3, 1},
+       {0x01CD, 0x01F0, 1},
+       {0x01F4, 0x01F5, 1},
+       {0x01FA, 0x0217, 1},
+       {0x0250, 0x02A8, 1},
+       {0x02BB, 0x02C1, 1},
+       {0x0386, 0x0386, 1},
+       {0x0388, 0x038A, 1},
+       {0x038C, 0x038C, 1},
+       {0x038E, 0x03A1, 1},
+       {0x03A3, 0x03CE, 1},
+       {0x03D0, 0x03D6, 1},
+       {0x03DA, 0x03E0, 2},
+       {0x03E2, 0x03F3, 1},
+       {0x0401, 0x040C, 1},
+       {0x040E, 0x044F, 1},
+       {0x0451, 0x045C, 1},
+       {0x045E, 0x0481, 1},
+       {0x0490, 0x04C4, 1},
+       {0x04C7, 0x04C8, 1},
+       {0x04CB, 0x04CC, 1},
+       {0x04D0, 0x04EB, 1},
+       {0x04EE, 0x04F5, 1},
+       {0x04F8, 0x04F9, 1},
+       {0x0531, 0x0556, 1},
+       {0x0559, 0x0559, 1},
+       {0x0561, 0x0586, 1},
+       {0x05D0, 0x05EA, 1},
+       {0x05F0, 0x05F2, 1},
+       {0x0621, 0x063A, 1},
+       {0x0641, 0x064A, 1},
+       {0x0671, 0x06B7, 1},
+       {0x06BA, 0x06BE, 1},
+       {0x06C0, 0x06CE, 1},
+       {0x06D0, 0x06D3, 1},
+       {0x06D5, 0x06D5, 1},
+       {0x06E5, 0x06E6, 1},
+       {0x0905, 0x0939, 1},
+       {0x093D, 0x093D, 1},
+       {0x0958, 0x0961, 1},
+       {0x0985, 0x098C, 1},
+       {0x098F, 0x0990, 1},
+       {0x0993, 0x09A8, 1},
+       {0x09AA, 0x09B0, 1},
+       {0x09B2, 0x09B2, 1},
+       {0x09B6, 0x09B9, 1},
+       {0x09DC, 0x09DD, 1},
+       {0x09DF, 0x09E1, 1},
+       {0x09F0, 0x09F1, 1},
+       {0x0A05, 0x0A0A, 1},
+       {0x0A0F, 0x0A10, 1},
+       {0x0A13, 0x0A28, 1},
+       {0x0A2A, 0x0A30, 1},
+       {0x0A32, 0x0A33, 1},
+       {0x0A35, 0x0A36, 1},
+       {0x0A38, 0x0A39, 1},
+       {0x0A59, 0x0A5C, 1},
+       {0x0A5E, 0x0A5E, 1},
+       {0x0A72, 0x0A74, 1},
+       {0x0A85, 0x0A8B, 1},
+       {0x0A8D, 0x0A8D, 1},
+       {0x0A8F, 0x0A91, 1},
+       {0x0A93, 0x0AA8, 1},
+       {0x0AAA, 0x0AB0, 1},
+       {0x0AB2, 0x0AB3, 1},
+       {0x0AB5, 0x0AB9, 1},
+       {0x0ABD, 0x0AE0, 0x23},
+       {0x0B05, 0x0B0C, 1},
+       {0x0B0F, 0x0B10, 1},
+       {0x0B13, 0x0B28, 1},
+       {0x0B2A, 0x0B30, 1},
+       {0x0B32, 0x0B33, 1},
+       {0x0B36, 0x0B39, 1},
+       {0x0B3D, 0x0B3D, 1},
+       {0x0B5C, 0x0B5D, 1},
+       {0x0B5F, 0x0B61, 1},
+       {0x0B85, 0x0B8A, 1},
+       {0x0B8E, 0x0B90, 1},
+       {0x0B92, 0x0B95, 1},
+       {0x0B99, 0x0B9A, 1},
+       {0x0B9C, 0x0B9C, 1},
+       {0x0B9E, 0x0B9F, 1},
+       {0x0BA3, 0x0BA4, 1},
+       {0x0BA8, 0x0BAA, 1},
+       {0x0BAE, 0x0BB5, 1},
+       {0x0BB7, 0x0BB9, 1},
+       {0x0C05, 0x0C0C, 1},
+       {0x0C0E, 0x0C10, 1},
+       {0x0C12, 0x0C28, 1},
+       {0x0C2A, 0x0C33, 1},
+       {0x0C35, 0x0C39, 1},
+       {0x0C60, 0x0C61, 1},
+       {0x0C85, 0x0C8C, 1},
+       {0x0C8E, 0x0C90, 1},
+       {0x0C92, 0x0CA8, 1},
+       {0x0CAA, 0x0CB3, 1},
+       {0x0CB5, 0x0CB9, 1},
+       {0x0CDE, 0x0CDE, 1},
+       {0x0CE0, 0x0CE1, 1},
+       {0x0D05, 0x0D0C, 1},
+       {0x0D0E, 0x0D10, 1},
+       {0x0D12, 0x0D28, 1},
+       {0x0D2A, 0x0D39, 1},
+       {0x0D60, 0x0D61, 1},
+       {0x0E01, 0x0E2E, 1},
+       {0x0E30, 0x0E30, 1},
+       {0x0E32, 0x0E33, 1},
+       {0x0E40, 0x0E45, 1},
+       {0x0E81, 0x0E82, 1},
+       {0x0E84, 0x0E84, 1},
+       {0x0E87, 0x0E88, 1},
+       {0x0E8A, 0x0E8D, 3},
+       {0x0E94, 0x0E97, 1},
+       {0x0E99, 0x0E9F, 1},
+       {0x0EA1, 0x0EA3, 1},
+       {0x0EA5, 0x0EA7, 2},
+       {0x0EAA, 0x0EAB, 1},
+       {0x0EAD, 0x0EAE, 1},
+       {0x0EB0, 0x0EB0, 1},
+       {0x0EB2, 0x0EB3, 1},
+       {0x0EBD, 0x0EBD, 1},
+       {0x0EC0, 0x0EC4, 1},
+       {0x0F40, 0x0F47, 1},
+       {0x0F49, 0x0F69, 1},
+       {0x10A0, 0x10C5, 1},
+       {0x10D0, 0x10F6, 1},
+       {0x1100, 0x1100, 1},
+       {0x1102, 0x1103, 1},
+       {0x1105, 0x1107, 1},
+       {0x1109, 0x1109, 1},
+       {0x110B, 0x110C, 1},
+       {0x110E, 0x1112, 1},
+       {0x113C, 0x1140, 2},
+       {0x114C, 0x1150, 2},
+       {0x1154, 0x1155, 1},
+       {0x1159, 0x1159, 1},
+       {0x115F, 0x1161, 1},
+       {0x1163, 0x1169, 2},
+       {0x116D, 0x116E, 1},
+       {0x1172, 0x1173, 1},
+       {0x1175, 0x119E, 0x119E - 0x1175},
+       {0x11A8, 0x11AB, 0x11AB - 0x11A8},
+       {0x11AE, 0x11AF, 1},
+       {0x11B7, 0x11B8, 1},
+       {0x11BA, 0x11BA, 1},
+       {0x11BC, 0x11C2, 1},
+       {0x11EB, 0x11F0, 0x11F0 - 0x11EB},
+       {0x11F9, 0x11F9, 1},
+       {0x1E00, 0x1E9B, 1},
+       {0x1EA0, 0x1EF9, 1},
+       {0x1F00, 0x1F15, 1},
+       {0x1F18, 0x1F1D, 1},
+       {0x1F20, 0x1F45, 1},
+       {0x1F48, 0x1F4D, 1},
+       {0x1F50, 0x1F57, 1},
+       {0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
+       {0x1F5D, 0x1F5D, 1},
+       {0x1F5F, 0x1F7D, 1},
+       {0x1F80, 0x1FB4, 1},
+       {0x1FB6, 0x1FBC, 1},
+       {0x1FBE, 0x1FBE, 1},
+       {0x1FC2, 0x1FC4, 1},
+       {0x1FC6, 0x1FCC, 1},
+       {0x1FD0, 0x1FD3, 1},
+       {0x1FD6, 0x1FDB, 1},
+       {0x1FE0, 0x1FEC, 1},
+       {0x1FF2, 0x1FF4, 1},
+       {0x1FF6, 0x1FFC, 1},
+       {0x2126, 0x2126, 1},
+       {0x212A, 0x212B, 1},
+       {0x212E, 0x212E, 1},
+       {0x2180, 0x2182, 1},
+       {0x3007, 0x3007, 1},
+       {0x3021, 0x3029, 1},
+       {0x3041, 0x3094, 1},
+       {0x30A1, 0x30FA, 1},
+       {0x3105, 0x312C, 1},
+       {0x4E00, 0x9FA5, 1},
+       {0xAC00, 0xD7A3, 1},
+}
+
+var second = []unicode.Range{
+       {0x002D, 0x002E, 1},
+       {0x0030, 0x0039, 1},
+       {0x00B7, 0x00B7, 1},
+       {0x02D0, 0x02D1, 1},
+       {0x0300, 0x0345, 1},
+       {0x0360, 0x0361, 1},
+       {0x0387, 0x0387, 1},
+       {0x0483, 0x0486, 1},
+       {0x0591, 0x05A1, 1},
+       {0x05A3, 0x05B9, 1},
+       {0x05BB, 0x05BD, 1},
+       {0x05BF, 0x05BF, 1},
+       {0x05C1, 0x05C2, 1},
+       {0x05C4, 0x0640, 0x0640 - 0x05C4},
+       {0x064B, 0x0652, 1},
+       {0x0660, 0x0669, 1},
+       {0x0670, 0x0670, 1},
+       {0x06D6, 0x06DC, 1},
+       {0x06DD, 0x06DF, 1},
+       {0x06E0, 0x06E4, 1},
+       {0x06E7, 0x06E8, 1},
+       {0x06EA, 0x06ED, 1},
+       {0x06F0, 0x06F9, 1},
+       {0x0901, 0x0903, 1},
+       {0x093C, 0x093C, 1},
+       {0x093E, 0x094C, 1},
+       {0x094D, 0x094D, 1},
+       {0x0951, 0x0954, 1},
+       {0x0962, 0x0963, 1},
+       {0x0966, 0x096F, 1},
+       {0x0981, 0x0983, 1},
+       {0x09BC, 0x09BC, 1},
+       {0x09BE, 0x09BF, 1},
+       {0x09C0, 0x09C4, 1},
+       {0x09C7, 0x09C8, 1},
+       {0x09CB, 0x09CD, 1},
+       {0x09D7, 0x09D7, 1},
+       {0x09E2, 0x09E3, 1},
+       {0x09E6, 0x09EF, 1},
+       {0x0A02, 0x0A3C, 0x3A},
+       {0x0A3E, 0x0A3F, 1},
+       {0x0A40, 0x0A42, 1},
+       {0x0A47, 0x0A48, 1},
+       {0x0A4B, 0x0A4D, 1},
+       {0x0A66, 0x0A6F, 1},
+       {0x0A70, 0x0A71, 1},
+       {0x0A81, 0x0A83, 1},
+       {0x0ABC, 0x0ABC, 1},
+       {0x0ABE, 0x0AC5, 1},
+       {0x0AC7, 0x0AC9, 1},
+       {0x0ACB, 0x0ACD, 1},
+       {0x0AE6, 0x0AEF, 1},
+       {0x0B01, 0x0B03, 1},
+       {0x0B3C, 0x0B3C, 1},
+       {0x0B3E, 0x0B43, 1},
+       {0x0B47, 0x0B48, 1},
+       {0x0B4B, 0x0B4D, 1},
+       {0x0B56, 0x0B57, 1},
+       {0x0B66, 0x0B6F, 1},
+       {0x0B82, 0x0B83, 1},
+       {0x0BBE, 0x0BC2, 1},
+       {0x0BC6, 0x0BC8, 1},
+       {0x0BCA, 0x0BCD, 1},
+       {0x0BD7, 0x0BD7, 1},
+       {0x0BE7, 0x0BEF, 1},
+       {0x0C01, 0x0C03, 1},
+       {0x0C3E, 0x0C44, 1},
+       {0x0C46, 0x0C48, 1},
+       {0x0C4A, 0x0C4D, 1},
+       {0x0C55, 0x0C56, 1},
+       {0x0C66, 0x0C6F, 1},
+       {0x0C82, 0x0C83, 1},
+       {0x0CBE, 0x0CC4, 1},
+       {0x0CC6, 0x0CC8, 1},
+       {0x0CCA, 0x0CCD, 1},
+       {0x0CD5, 0x0CD6, 1},
+       {0x0CE6, 0x0CEF, 1},
+       {0x0D02, 0x0D03, 1},
+       {0x0D3E, 0x0D43, 1},
+       {0x0D46, 0x0D48, 1},
+       {0x0D4A, 0x0D4D, 1},
+       {0x0D57, 0x0D57, 1},
+       {0x0D66, 0x0D6F, 1},
+       {0x0E31, 0x0E31, 1},
+       {0x0E34, 0x0E3A, 1},
+       {0x0E46, 0x0E46, 1},
+       {0x0E47, 0x0E4E, 1},
+       {0x0E50, 0x0E59, 1},
+       {0x0EB1, 0x0EB1, 1},
+       {0x0EB4, 0x0EB9, 1},
+       {0x0EBB, 0x0EBC, 1},
+       {0x0EC6, 0x0EC6, 1},
+       {0x0EC8, 0x0ECD, 1},
+       {0x0ED0, 0x0ED9, 1},
+       {0x0F18, 0x0F19, 1},
+       {0x0F20, 0x0F29, 1},
+       {0x0F35, 0x0F39, 2},
+       {0x0F3E, 0x0F3F, 1},
+       {0x0F71, 0x0F84, 1},
+       {0x0F86, 0x0F8B, 1},
+       {0x0F90, 0x0F95, 1},
+       {0x0F97, 0x0F97, 1},
+       {0x0F99, 0x0FAD, 1},
+       {0x0FB1, 0x0FB7, 1},
+       {0x0FB9, 0x0FB9, 1},
+       {0x20D0, 0x20DC, 1},
+       {0x20E1, 0x3005, 0x3005 - 0x20E1},
+       {0x302A, 0x302F, 1},
+       {0x3031, 0x3035, 1},
+       {0x3099, 0x309A, 1},
+       {0x309D, 0x309E, 1},
+       {0x30FC, 0x30FE, 1},
+}
+
+// HTMLEntity is an entity map containing translations for the
+// standard HTML entity characters.
+var HTMLEntity = htmlEntity
+
+var htmlEntity = map[string]string{
+       /*
+               hget http://www.w3.org/TR/html4/sgml/entities.html |
+               ssam '
+                       ,y /\&gt;/ x/\&lt;(.|\n)+/ s/\n/ /g
+                       ,x v/^\&lt;!ENTITY/d
+                       ,s/\&lt;!ENTITY ([^ ]+) .*U\+([0-9A-F][0-9A-F][0-9A-F][0-9A-F]) .+/     "\1": "\\u\2",/g
+               '
+       */
+       "nbsp":     "\u00A0",
+       "iexcl":    "\u00A1",
+       "cent":     "\u00A2",
+       "pound":    "\u00A3",
+       "curren":   "\u00A4",
+       "yen":      "\u00A5",
+       "brvbar":   "\u00A6",
+       "sect":     "\u00A7",
+       "uml":      "\u00A8",
+       "copy":     "\u00A9",
+       "ordf":     "\u00AA",
+       "laquo":    "\u00AB",
+       "not":      "\u00AC",
+       "shy":      "\u00AD",
+       "reg":      "\u00AE",
+       "macr":     "\u00AF",
+       "deg":      "\u00B0",
+       "plusmn":   "\u00B1",
+       "sup2":     "\u00B2",
+       "sup3":     "\u00B3",
+       "acute":    "\u00B4",
+       "micro":    "\u00B5",
+       "para":     "\u00B6",
+       "middot":   "\u00B7",
+       "cedil":    "\u00B8",
+       "sup1":     "\u00B9",
+       "ordm":     "\u00BA",
+       "raquo":    "\u00BB",
+       "frac14":   "\u00BC",
+       "frac12":   "\u00BD",
+       "frac34":   "\u00BE",
+       "iquest":   "\u00BF",
+       "Agrave":   "\u00C0",
+       "Aacute":   "\u00C1",
+       "Acirc":    "\u00C2",
+       "Atilde":   "\u00C3",
+       "Auml":     "\u00C4",
+       "Aring":    "\u00C5",
+       "AElig":    "\u00C6",
+       "Ccedil":   "\u00C7",
+       "Egrave":   "\u00C8",
+       "Eacute":   "\u00C9",
+       "Ecirc":    "\u00CA",
+       "Euml":     "\u00CB",
+       "Igrave":   "\u00CC",
+       "Iacute":   "\u00CD",
+       "Icirc":    "\u00CE",
+       "Iuml":     "\u00CF",
+       "ETH":      "\u00D0",
+       "Ntilde":   "\u00D1",
+       "Ograve":   "\u00D2",
+       "Oacute":   "\u00D3",
+       "Ocirc":    "\u00D4",
+       "Otilde":   "\u00D5",
+       "Ouml":     "\u00D6",
+       "times":    "\u00D7",
+       "Oslash":   "\u00D8",
+       "Ugrave":   "\u00D9",
+       "Uacute":   "\u00DA",
+       "Ucirc":    "\u00DB",
+       "Uuml":     "\u00DC",
+       "Yacute":   "\u00DD",
+       "THORN":    "\u00DE",
+       "szlig":    "\u00DF",
+       "agrave":   "\u00E0",
+       "aacute":   "\u00E1",
+       "acirc":    "\u00E2",
+       "atilde":   "\u00E3",
+       "auml":     "\u00E4",
+       "aring":    "\u00E5",
+       "aelig":    "\u00E6",
+       "ccedil":   "\u00E7",
+       "egrave":   "\u00E8",
+       "eacute":   "\u00E9",
+       "ecirc":    "\u00EA",
+       "euml":     "\u00EB",
+       "igrave":   "\u00EC",
+       "iacute":   "\u00ED",
+       "icirc":    "\u00EE",
+       "iuml":     "\u00EF",
+       "eth":      "\u00F0",
+       "ntilde":   "\u00F1",
+       "ograve":   "\u00F2",
+       "oacute":   "\u00F3",
+       "ocirc":    "\u00F4",
+       "otilde":   "\u00F5",
+       "ouml":     "\u00F6",
+       "divide":   "\u00F7",
+       "oslash":   "\u00F8",
+       "ugrave":   "\u00F9",
+       "uacute":   "\u00FA",
+       "ucirc":    "\u00FB",
+       "uuml":     "\u00FC",
+       "yacute":   "\u00FD",
+       "thorn":    "\u00FE",
+       "yuml":     "\u00FF",
+       "fnof":     "\u0192",
+       "Alpha":    "\u0391",
+       "Beta":     "\u0392",
+       "Gamma":    "\u0393",
+       "Delta":    "\u0394",
+       "Epsilon":  "\u0395",
+       "Zeta":     "\u0396",
+       "Eta":      "\u0397",
+       "Theta":    "\u0398",
+       "Iota":     "\u0399",
+       "Kappa":    "\u039A",
+       "Lambda":   "\u039B",
+       "Mu":       "\u039C",
+       "Nu":       "\u039D",
+       "Xi":       "\u039E",
+       "Omicron":  "\u039F",
+       "Pi":       "\u03A0",
+       "Rho":      "\u03A1",
+       "Sigma":    "\u03A3",
+       "Tau":      "\u03A4",
+       "Upsilon":  "\u03A5",
+       "Phi":      "\u03A6",
+       "Chi":      "\u03A7",
+       "Psi":      "\u03A8",
+       "Omega":    "\u03A9",
+       "alpha":    "\u03B1",
+       "beta":     "\u03B2",
+       "gamma":    "\u03B3",
+       "delta":    "\u03B4",
+       "epsilon":  "\u03B5",
+       "zeta":     "\u03B6",
+       "eta":      "\u03B7",
+       "theta":    "\u03B8",
+       "iota":     "\u03B9",
+       "kappa":    "\u03BA",
+       "lambda":   "\u03BB",
+       "mu":       "\u03BC",
+       "nu":       "\u03BD",
+       "xi":       "\u03BE",
+       "omicron":  "\u03BF",
+       "pi":       "\u03C0",
+       "rho":      "\u03C1",
+       "sigmaf":   "\u03C2",
+       "sigma":    "\u03C3",
+       "tau":      "\u03C4",
+       "upsilon":  "\u03C5",
+       "phi":      "\u03C6",
+       "chi":      "\u03C7",
+       "psi":      "\u03C8",
+       "omega":    "\u03C9",
+       "thetasym": "\u03D1",
+       "upsih":    "\u03D2",
+       "piv":      "\u03D6",
+       "bull":     "\u2022",
+       "hellip":   "\u2026",
+       "prime":    "\u2032",
+       "Prime":    "\u2033",
+       "oline":    "\u203E",
+       "frasl":    "\u2044",
+       "weierp":   "\u2118",
+       "image":    "\u2111",
+       "real":     "\u211C",
+       "trade":    "\u2122",
+       "alefsym":  "\u2135",
+       "larr":     "\u2190",
+       "uarr":     "\u2191",
+       "rarr":     "\u2192",
+       "darr":     "\u2193",
+       "harr":     "\u2194",
+       "crarr":    "\u21B5",
+       "lArr":     "\u21D0",
+       "uArr":     "\u21D1",
+       "rArr":     "\u21D2",
+       "dArr":     "\u21D3",
+       "hArr":     "\u21D4",
+       "forall":   "\u2200",
+       "part":     "\u2202",
+       "exist":    "\u2203",
+       "empty":    "\u2205",
+       "nabla":    "\u2207",
+       "isin":     "\u2208",
+       "notin":    "\u2209",
+       "ni":       "\u220B",
+       "prod":     "\u220F",
+       "sum":      "\u2211",
+       "minus":    "\u2212",
+       "lowast":   "\u2217",
+       "radic":    "\u221A",
+       "prop":     "\u221D",
+       "infin":    "\u221E",
+       "ang":      "\u2220",
+       "and":      "\u2227",
+       "or":       "\u2228",
+       "cap":      "\u2229",
+       "cup":      "\u222A",
+       "int":      "\u222B",
+       "there4":   "\u2234",
+       "sim":      "\u223C",
+       "cong":     "\u2245",
+       "asymp":    "\u2248",
+       "ne":       "\u2260",
+       "equiv":    "\u2261",
+       "le":       "\u2264",
+       "ge":       "\u2265",
+       "sub":      "\u2282",
+       "sup":      "\u2283",
+       "nsub":     "\u2284",
+       "sube":     "\u2286",
+       "supe":     "\u2287",
+       "oplus":    "\u2295",
+       "otimes":   "\u2297",
+       "perp":     "\u22A5",
+       "sdot":     "\u22C5",
+       "lceil":    "\u2308",
+       "rceil":    "\u2309",
+       "lfloor":   "\u230A",
+       "rfloor":   "\u230B",
+       "lang":     "\u2329",
+       "rang":     "\u232A",
+       "loz":      "\u25CA",
+       "spades":   "\u2660",
+       "clubs":    "\u2663",
+       "hearts":   "\u2665",
+       "diams":    "\u2666",
+       "quot":     "\u0022",
+       "amp":      "\u0026",
+       "lt":       "\u003C",
+       "gt":       "\u003E",
+       "OElig":    "\u0152",
+       "oelig":    "\u0153",
+       "Scaron":   "\u0160",
+       "scaron":   "\u0161",
+       "Yuml":     "\u0178",
+       "circ":     "\u02C6",
+       "tilde":    "\u02DC",
+       "ensp":     "\u2002",
+       "emsp":     "\u2003",
+       "thinsp":   "\u2009",
+       "zwnj":     "\u200C",
+       "zwj":      "\u200D",
+       "lrm":      "\u200E",
+       "rlm":      "\u200F",
+       "ndash":    "\u2013",
+       "mdash":    "\u2014",
+       "lsquo":    "\u2018",
+       "rsquo":    "\u2019",
+       "sbquo":    "\u201A",
+       "ldquo":    "\u201C",
+       "rdquo":    "\u201D",
+       "bdquo":    "\u201E",
+       "dagger":   "\u2020",
+       "Dagger":   "\u2021",
+       "permil":   "\u2030",
+       "lsaquo":   "\u2039",
+       "rsaquo":   "\u203A",
+       "euro":     "\u20AC",
+}
+
+// HTMLAutoClose is the set of HTML elements that
+// should be considered to close automatically.
+var HTMLAutoClose = htmlAutoClose
+
+var htmlAutoClose = []string{
+       /*
+               hget http://www.w3.org/TR/html4/loose.dtd |
+               9 sed -n 's/<!ELEMENT (.*) - O EMPTY.+/ "\1",/p' | tr A-Z a-z
+       */
+       "basefont",
+       "br",
+       "area",
+       "link",
+       "img",
+       "param",
+       "hr",
+       "input",
+       "col     ",
+       "frame",
+       "isindex",
+       "base",
+       "meta",
+}
+
+var (
+       esc_quot = []byte("&#34;") // shorter than "&quot;"
+       esc_apos = []byte("&#39;") // shorter than "&apos;"
+       esc_amp  = []byte("&amp;")
+       esc_lt   = []byte("&lt;")
+       esc_gt   = []byte("&gt;")
+)
+
+// Escape writes to w the properly escaped XML equivalent
+// of the plain text data s.
+func Escape(w io.Writer, s []byte) {
+       var esc []byte
+       last := 0
+       for i, c := range s {
+               switch c {
+               case '"':
+                       esc = esc_quot
+               case '\'':
+                       esc = esc_apos
+               case '&':
+                       esc = esc_amp
+               case '<':
+                       esc = esc_lt
+               case '>':
+                       esc = esc_gt
+               default:
+                       continue
+               }
+               w.Write(s[last:i])
+               w.Write(esc)
+               last = i + 1
+       }
+       w.Write(s[last:])
+}
diff --git a/libgo/go/xml/xml_test.go b/libgo/go/xml/xml_test.go
new file mode 100644 (file)
index 0000000..0068896
--- /dev/null
@@ -0,0 +1,400 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+       "bytes"
+       "io"
+       "os"
+       "reflect"
+       "testing"
+)
+
+const testInput = `
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" ` +
+       "\r\n\t" + `  >
+  <hello lang="en">World &lt;&gt;&apos;&quot; &#x767d;&#40300;翔</hello>
+  <goodbye />
+  <outer foo:attr="value" xmlns:tag="ns4">
+    <inner/>
+  </outer>
+  <tag:name>
+    <![CDATA[Some text here.]]>
+  </tag:name>
+</body><!-- missing final newline -->`
+
+var rawTokens = []Token{
+       CharData([]byte("\n")),
+       ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
+       CharData([]byte("\n")),
+       Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
+       ),
+       CharData([]byte("\n")),
+       StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
+       CharData([]byte("\n  ")),
+       StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
+       CharData([]byte("World <>'\" 白鵬翔")),
+       EndElement{Name{"", "hello"}},
+       CharData([]byte("\n  ")),
+       StartElement{Name{"", "goodbye"}, nil},
+       EndElement{Name{"", "goodbye"}},
+       CharData([]byte("\n  ")),
+       StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
+       CharData([]byte("\n    ")),
+       StartElement{Name{"", "inner"}, nil},
+       EndElement{Name{"", "inner"}},
+       CharData([]byte("\n  ")),
+       EndElement{Name{"", "outer"}},
+       CharData([]byte("\n  ")),
+       StartElement{Name{"tag", "name"}, nil},
+       CharData([]byte("\n    ")),
+       CharData([]byte("Some text here.")),
+       CharData([]byte("\n  ")),
+       EndElement{Name{"tag", "name"}},
+       CharData([]byte("\n")),
+       EndElement{Name{"", "body"}},
+       Comment([]byte(" missing final newline ")),
+}
+
+var cookedTokens = []Token{
+       CharData([]byte("\n")),
+       ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
+       CharData([]byte("\n")),
+       Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
+       ),
+       CharData([]byte("\n")),
+       StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
+       CharData([]byte("\n  ")),
+       StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
+       CharData([]byte("World <>'\" 白鵬翔")),
+       EndElement{Name{"ns2", "hello"}},
+       CharData([]byte("\n  ")),
+       StartElement{Name{"ns2", "goodbye"}, nil},
+       EndElement{Name{"ns2", "goodbye"}},
+       CharData([]byte("\n  ")),
+       StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
+       CharData([]byte("\n    ")),
+       StartElement{Name{"ns2", "inner"}, nil},
+       EndElement{Name{"ns2", "inner"}},
+       CharData([]byte("\n  ")),
+       EndElement{Name{"ns2", "outer"}},
+       CharData([]byte("\n  ")),
+       StartElement{Name{"ns3", "name"}, nil},
+       CharData([]byte("\n    ")),
+       CharData([]byte("Some text here.")),
+       CharData([]byte("\n  ")),
+       EndElement{Name{"ns3", "name"}},
+       CharData([]byte("\n")),
+       EndElement{Name{"ns2", "body"}},
+       Comment([]byte(" missing final newline ")),
+}
+
+var xmlInput = []string{
+       // unexpected EOF cases
+       "<",
+       "<t",
+       "<t ",
+       "<t/",
+       "<!",
+       "<!-",
+       "<!--",
+       "<!--c-",
+       "<!--c--",
+       "<!d",
+       "<t></",
+       "<t></t",
+       "<?",
+       "<?p",
+       "<t a",
+       "<t a=",
+       "<t a='",
+       "<t a=''",
+       "<t/><![",
+       "<t/><![C",
+       "<t/><![CDATA[d",
+       "<t/><![CDATA[d]",
+       "<t/><![CDATA[d]]",
+
+       // other Syntax errors
+       "<>",
+       "<t/a",
+       "<0 />",
+       "<?0 >",
+       //      "<!0 >",        // let the Token() caller handle
+       "</0>",
+       "<t 0=''>",
+       "<t a='&'>",
+       "<t a='<'>",
+       "<t>&nbspc;</t>",
+       "<t a>",
+       "<t a=>",
+       "<t a=v>",
+       //      "<![CDATA[d]]>",        // let the Token() caller handle
+       "<t></e>",
+       "<t></>",
+       "<t></t!",
+       "<t>cdata]]></t>",
+}
+
+type stringReader struct {
+       s   string
+       off int
+}
+
+func (r *stringReader) Read(b []byte) (n int, err os.Error) {
+       if r.off >= len(r.s) {
+               return 0, os.EOF
+       }
+       for r.off < len(r.s) && n < len(b) {
+               b[n] = r.s[r.off]
+               n++
+               r.off++
+       }
+       return
+}
+
+func (r *stringReader) ReadByte() (b byte, err os.Error) {
+       if r.off >= len(r.s) {
+               return 0, os.EOF
+       }
+       b = r.s[r.off]
+       r.off++
+       return
+}
+
+func StringReader(s string) io.Reader { return &stringReader{s, 0} }
+
+func TestRawToken(t *testing.T) {
+       p := NewParser(StringReader(testInput))
+
+       for i, want := range rawTokens {
+               have, err := p.RawToken()
+               if err != nil {
+                       t.Fatalf("token %d: unexpected error: %s", i, err)
+               }
+               if !reflect.DeepEqual(have, want) {
+                       t.Errorf("token %d = %#v want %#v", i, have, want)
+               }
+       }
+}
+
+func TestToken(t *testing.T) {
+       p := NewParser(StringReader(testInput))
+
+       for i, want := range cookedTokens {
+               have, err := p.Token()
+               if err != nil {
+                       t.Fatalf("token %d: unexpected error: %s", i, err)
+               }
+               if !reflect.DeepEqual(have, want) {
+                       t.Errorf("token %d = %#v want %#v", i, have, want)
+               }
+       }
+}
+
+func TestSyntax(t *testing.T) {
+       for i := range xmlInput {
+               p := NewParser(StringReader(xmlInput[i]))
+               var err os.Error
+               for _, err = p.Token(); err == nil; _, err = p.Token() {
+               }
+               if _, ok := err.(*SyntaxError); !ok {
+                       t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i])
+               }
+       }
+}
+
+type allScalars struct {
+       True1   bool
+       True2   bool
+       False1  bool
+       False2  bool
+       Int     int
+       Int8    int8
+       Int16   int16
+       Int32   int32
+       Int64   int64
+       Uint    int
+       Uint8   uint8
+       Uint16  uint16
+       Uint32  uint32
+       Uint64  uint64
+       Uintptr uintptr
+       Float   float
+       Float32 float32
+       Float64 float64
+       String  string
+}
+
+var all = allScalars{
+       True1:   true,
+       True2:   true,
+       False1:  false,
+       False2:  false,
+       Int:     1,
+       Int8:    -2,
+       Int16:   3,
+       Int32:   -4,
+       Int64:   5,
+       Uint:    6,
+       Uint8:   7,
+       Uint16:  8,
+       Uint32:  9,
+       Uint64:  10,
+       Uintptr: 11,
+       Float:   12.0,
+       Float32: 13.0,
+       Float64: 14.0,
+       String:  "15",
+}
+
+const testScalarsInput = `<allscalars>
+       <true1>true</true1>
+       <true2>1</true2>
+       <false1>false</false1>
+       <false2>0</false2>
+       <int>1</int>
+       <int8>-2</int8>
+       <int16>3</int16>
+       <int32>-4</int32>
+       <int64>5</int64>
+       <uint>6</uint>
+       <uint8>7</uint8>
+       <uint16>8</uint16>
+       <uint32>9</uint32>
+       <uint64>10</uint64>
+       <uintptr>11</uintptr>
+       <float>12.0</float>
+       <float32>13.0</float32>
+       <float64>14.0</float64>
+       <string>15</string>
+</allscalars>`
+
+func TestAllScalars(t *testing.T) {
+       var a allScalars
+       buf := bytes.NewBufferString(testScalarsInput)
+       err := Unmarshal(buf, &a)
+
+       if err != nil {
+               t.Fatal(err)
+       }
+       if !reflect.DeepEqual(a, all) {
+               t.Errorf("expected %+v got %+v", all, a)
+       }
+}
+
+type item struct {
+       Field_a string
+}
+
+func TestIssue569(t *testing.T) {
+       data := `<item><field_a>abcd</field_a></item>`
+       var i item
+       buf := bytes.NewBufferString(data)
+       err := Unmarshal(buf, &i)
+
+       if err != nil || i.Field_a != "abcd" {
+               t.Fatalf("Expecting abcd")
+       }
+}
+
+func TestUnquotedAttrs(t *testing.T) {
+       data := "<tag attr=azAZ09:-_\t>"
+       p := NewParser(StringReader(data))
+       p.Strict = false
+       token, err := p.Token()
+       if _, ok := err.(*SyntaxError); ok {
+               t.Errorf("Unexpected error: %v", err)
+       }
+       if token.(StartElement).Name.Local != "tag" {
+               t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
+       }
+       attr := token.(StartElement).Attr[0]
+       if attr.Value != "azAZ09:-_" {
+               t.Errorf("Unexpected attribute value: %v", attr.Value)
+       }
+       if attr.Name.Local != "attr" {
+               t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
+       }
+}
+
+func TestCopyTokenCharData(t *testing.T) {
+       data := []byte("same data")
+       var tok1 Token = CharData(data)
+       tok2 := CopyToken(tok1)
+       if !reflect.DeepEqual(tok1, tok2) {
+               t.Error("CopyToken(CharData) != CharData")
+       }
+       data[1] = 'o'
+       if reflect.DeepEqual(tok1, tok2) {
+               t.Error("CopyToken(CharData) uses same buffer.")
+       }
+}
+
+func TestCopyTokenStartElement(t *testing.T) {
+       elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}
+       var tok1 Token = elt
+       tok2 := CopyToken(tok1)
+       if !reflect.DeepEqual(tok1, tok2) {
+               t.Error("CopyToken(StartElement) != StartElement")
+       }
+       elt.Attr[0] = Attr{Name{"", "lang"}, "de"}
+       if reflect.DeepEqual(tok1, tok2) {
+               t.Error("CopyToken(CharData) uses same buffer.")
+       }
+}
+
+func TestSyntaxErrorLineNum(t *testing.T) {
+       testInput := "<P>Foo<P>\n\n<P>Bar</>\n"
+       p := NewParser(StringReader(testInput))
+       var err os.Error
+       for _, err = p.Token(); err == nil; _, err = p.Token() {
+       }
+       synerr, ok := err.(*SyntaxError)
+       if !ok {
+               t.Error("Expected SyntaxError.")
+       }
+       if synerr.Line != 3 {
+               t.Error("SyntaxError didn't have correct line number.")
+       }
+}
+
+func TestTrailingRawToken(t *testing.T) {
+       input := `<FOO></FOO>  `
+       p := NewParser(StringReader(input))
+       var err os.Error
+       for _, err = p.RawToken(); err == nil; _, err = p.RawToken() {
+       }
+       if err != os.EOF {
+               t.Fatalf("p.RawToken() = _, %v, want _, os.EOF", err)
+       }
+}
+
+func TestTrailingToken(t *testing.T) {
+       input := `<FOO></FOO>  `
+       p := NewParser(StringReader(input))
+       var err os.Error
+       for _, err = p.Token(); err == nil; _, err = p.Token() {
+       }
+       if err != os.EOF {
+               t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
+       }
+}
+
+func TestEntityInsideCDATA(t *testing.T) {
+       input := `<test><![CDATA[ &val=foo ]]></test>`
+       p := NewParser(StringReader(input))
+       var err os.Error
+       for _, err = p.Token(); err == nil; _, err = p.Token() {
+       }
+       if err != os.EOF {
+               t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
+       }
+}
diff --git a/libgo/merge.sh b/libgo/merge.sh
new file mode 100644 (file)
index 0000000..17dc573
--- /dev/null
@@ -0,0 +1,173 @@
+#!/bin/sh
+
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This script merges changes from the master copy of the Go library
+# into the libgo library.  This does the easy stuff; the hard stuff is
+# left to the user.
+
+# The file MERGE should hold the Mercurial revision number of the last
+# revision which was merged into these sources.  Given that, and given
+# the current sources, we can run the usual diff3 algorithm to merge
+# all changes into our sources.
+
+set -e
+
+TMPDIR=${TMPDIR:-/tmp}
+
+OLDDIR=${TMPDIR}/libgo-merge-old
+NEWDIR=${TMPDIR}/libgo-merge-new
+
+if ! test -f MERGE; then
+  echo 1>&2 "merge.sh: must be run in libgo source directory"
+  exit 1
+fi
+
+if test $# -ne 1; then
+  echo 1>&2 "merge.sh: Usage: merge.sh mercurial-repository"
+  exit 1
+fi
+
+repository=$1
+
+merge_rev=`sed 1q MERGE`
+
+rm -rf ${OLDDIR}
+hg clone -r ${merge_rev} ${repository} ${OLDDIR}
+
+rm -rf ${NEWDIR}
+hg clone ${repository} ${NEWDIR}
+
+new_rev=`cd ${NEWDIR} && hg log | sed 1q | sed -e 's/.*://'`
+
+merge() {
+  name=$1
+  old=$2
+  new=$3
+  libgo=$4
+  if ! test -f ${new}; then
+    # The file does not exist in the new version.
+    if ! test -f ${old}; then
+      echo 1>&2 "merge.sh internal error no files $old $new"
+      exit 1
+    fi
+    if ! test -f ${libgo}; then
+      # File removed in new version and libgo.
+      :;
+    else
+      echo "merge.sh: ${name}: REMOVED"
+      rm -f ${libgo}
+      hg rm ${libgo}
+    fi
+  elif test -f ${old}; then
+    # The file exists in the old version.
+    if ! test -f ${libgo}; then
+      echo "merge.sh: $name: skipping: exists in old and new hg, but not in libgo"
+      continue
+    fi
+    if cmp -s ${old} ${libgo}; then
+      # The libgo file is unchanged from the old version.
+      if cmp -s ${new} ${libgo}; then
+        # File is unchanged from old to new version.
+        continue
+      fi
+      # Update file in libgo.
+      echo "merge.sh: $name: updating"
+      cp ${new} ${libgo}
+    else
+      # The libgo file has local changes.
+      set +e
+      diff3 -m -E ${libgo} ${old} ${new} > ${libgo}.tmp
+      status=$?
+      set -e
+      case $status in
+      0)
+        echo "merge.sh: $name: updating"
+        mv ${libgo}.tmp ${libgo}
+        ;;
+      1)
+        echo "merge.sh: $name: CONFLICTS"
+        mv ${libgo}.tmp ${libgo}
+        hg resolve -u ${libgo}
+        ;;
+      *)
+        echo 1>&2 "merge.sh: $name: diff3 failure"
+        exit 1
+        ;;
+      esac
+    fi
+  else
+    # The file does not exist in the old version.
+    if test -f ${libgo}; then
+      if ! cmp -s ${new} ${libgo}; then
+        echo 1>&2 "merge.sh: $name: IN NEW AND LIBGO BUT NOT OLD"
+      fi
+    else
+      echo "merge.sh: $name: NEW"
+      dir=`dirname ${libgo}`
+      if ! test -d ${dir}; then
+        mkdir -p ${dir}
+      fi
+      cp ${new} ${libgo}
+      hg add ${libgo}
+    fi
+  fi
+}
+
+(cd ${NEWDIR}/src/pkg && find . -name '*.go' -print) | while read f; do
+  if test `dirname $f` = "./syscall"; then
+    continue
+  fi
+  oldfile=${OLDDIR}/src/pkg/$f
+  newfile=${NEWDIR}/src/pkg/$f
+  libgofile=go/$f
+  merge $f ${oldfile} ${newfile} ${libgofile}
+done
+
+(cd ${NEWDIR}/src/pkg && find . -name testdata -print) | while read d; do
+  oldtd=${OLDDIR}/src/pkg/$d
+  newtd=${NEWDIR}/src/pkg/$d
+  libgotd=go/$d
+  if ! test -d ${oldtd}; then
+    continue
+  fi
+  (cd ${oldtd} && hg status -A .) | while read f; do
+    if test "`basename $f`" = ".hgignore"; then
+      continue
+    fi
+    f=`echo $f | sed -e 's/^..//'`
+    name=$d/$f
+    oldfile=${oldtd}/$f
+    newfile=${newtd}/$f
+    libgofile=${libgotd}/$f
+    merge ${name} ${oldfile} ${newfile} ${libgofile}
+  done
+done
+
+runtime="goc2c.c mcache.c mcentral.c mfinal.c mfixalloc.c mgc0.c mheap.c mheapmap32.c mheapmap64.c msize.c malloc.h mheapmap32.h mheapmap64.h malloc.goc mprof.goc"
+for f in $runtime; do
+  oldfile=${OLDDIR}/src/pkg/runtime/$f
+  newfile=${NEWDIR}/src/pkg/runtime/$f
+  libgofile=runtime/$f
+  merge $f ${oldfile} ${newfile} ${libgofile}
+done
+
+(cd ${OLDDIR}/src/pkg && find . -name '*.go' -print) | while read f; do
+  oldfile=${OLDDIR}/src/pkg/$f
+  newfile=${NEWDIR}/src/pkg/$f
+  libgofile=go/$f
+  if test -f ${newfile}; then
+    continue
+  fi
+  if ! test -f ${libgofile}; then
+    continue
+  fi
+  echo "merge.sh: ${libgofile}: REMOVED"
+  rm -f ${libgofile}
+  hg rm ${libgofile}
+done
+
+(echo ${new_rev}; sed -ne '2,$p' MERGE) > MERGE.tmp
+mv MERGE.tmp MERGE
diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh
new file mode 100755 (executable)
index 0000000..d28f7ff
--- /dev/null
@@ -0,0 +1,333 @@
+#!/bin/sh
+
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Create sysinfo.go.
+
+# This shell script creates the sysinfo.go file which holds types and
+# constants extracted from the system header files.  This relies on a
+# hook in gcc: the -ggo option will generate debugging information in
+# Go syntax.
+
+# We currently #include all the files at once, which works, but leads
+# to exposing some names which ideally should not be exposed, as they
+# match grep patterns.  E.g., WCHAR_MIN gets exposed because it starts
+# with W, like the wait flags.
+
+CC=${CC:-gcc}
+OUT=tmp-sysinfo.go
+
+set -e
+
+rm -f sysinfo.go
+
+rm -f sysinfo.c
+cat > sysinfo.c <<EOF
+#include "config.h"
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#if defined(HAVE_SYSCALL_H)
+#include <syscall.h>
+#endif
+#if defined(HAVE_SYS_EPOLL_H)
+#include <sys/epoll.h>
+#endif
+#if defined(HAVE_SYS_PTRACE_H)
+#include <sys/ptrace.h>
+#endif
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#if defined(HAVE_SYS_USER_H)
+#include <sys/user.h>
+#endif
+#if defined(HAVE_SYS_UTSNAME_H)
+#include <sys/utsname.h>
+#endif
+#include <unistd.h>
+EOF
+
+${CC} -D_GNU_SOURCE -fdump-go-spec=gen-sysinfo.go -S -o sysinfo.s sysinfo.c
+
+echo 'package syscall' > ${OUT}
+
+# Get all the consts and types, skipping ones which could not be
+# represented in Go and ones which we need to rewrite.  We also skip
+# function declarations, as we don't need them here.  All the symbols
+# will all have a leading underscore.
+grep -v '^// ' gen-sysinfo.go | \
+  grep -v '^func' | \
+  grep -v '^type _timeval ' | \
+  grep -v '^type _timespec ' | \
+  grep -v '^type _epoll_' | \
+  grep -v 'in6_addr' | \
+  grep -v 'sockaddr_in6' | \
+  sed -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1Timeval\2/g' \
+      -e 's/\([^a-zA-Z0-9_]\)_timespec\([^a-zA-Z0-9_]\)/\1Timespec\2/g' \
+    >> ${OUT}
+
+# The errno constants.
+grep '^const _E' gen-sysinfo.go | \
+  sed -e 's/^\(const \)_\(E[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# The O_xxx flags.
+grep '^const _\(O\|F\|FD\)_' gen-sysinfo.go | \
+  sed -e 's/^\(const \)_\([^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+if ! grep '^const O_CLOEXEC' ${OUT} >/dev/null 2>&1; then
+  echo "const O_CLOEXEC = 0" >> ${OUT}
+fi
+
+# The signal numbers.
+grep '^const _SIG[^_]' gen-sysinfo.go | \
+  grep -v '^const _SIGEV_' | \
+  sed -e 's/^\(const \)_\(SIG[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# The syscall numbers.  We force the names to upper case.
+grep '^const _SYS_' gen-sysinfo.go | \
+  sed -e 's/const _\(SYS_[^= ]*\).*$/\1/' | \
+  while read sys; do
+    sup=`echo $sys | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
+    echo "const $sup = _$sys" >> ${OUT}
+  done
+
+# Stat constants.
+grep '^const _S_' gen-sysinfo.go | \
+  sed -e 's/^\(const \)_\(S_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# Process status constants.
+grep '^const _W' gen-sysinfo.go |
+  sed -e 's/^\(const \)_\(W[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+# WSTOPPED was introduced in glibc 2.3.4.
+if ! grep '^const _WSTOPPED = ' gen-sysinfo.go >/dev/null 2>&1; then
+  if grep '^const _WUNTRACED = ' gen-sysinfo.go > /dev/null 2>&1; then
+    echo 'const WSTOPPED = _WUNTRACED' >> ${OUT}
+  else
+    echo 'const WSTOPPED = 2' >> ${OUT}
+  fi
+fi
+if grep '^const ___WALL = ' gen-sysinfo.go >/dev/null 2>&1 \
+   && ! grep '^const _WALL = ' gen-sysinfo.go >/dev/null 2>&1; then
+  echo 'const WALL = ___WALL' >> ${OUT}
+fi
+
+# Networking constants.
+grep '^const _\(AF\|SOCK\|SOL\|SO\|IPPROTO\|TCP\|IP\|IPV6\)_' gen-sysinfo.go |
+  sed -e 's/^\(const \)_\([^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+grep '^const _SOMAXCONN' gen-sysinfo.go |
+  sed -e 's/^\(const \)_\(SOMAXCONN[^= ]*\)\(.*\)$/\1\2 = _\2/' \
+    >> ${OUT}
+grep '^const _SHUT_' gen-sysinfo.go |
+  sed -e 's/^\(const \)_\(SHUT[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# pathconf constants.
+grep '^const __PC' gen-sysinfo.go |
+  sed -e 's/^\(const \)__\(PC[^= ]*\)\(.*\)$/\1\2 = __\2/' >> ${OUT}
+
+# The epoll constants were picked up by the errno constants, but we
+# need to be sure the EPOLLRDHUP is defined.
+if ! grep '^const EPOLLRDHUP' ${OUT} >/dev/null 2>&1; then
+  echo "const EPOLLRDHUP = 0x2000" >> ${OUT}
+fi
+
+# Ptrace constants.  We don't expose all the PTRACE flags, just the
+# PTRACE_O_xxx and PTRACE_EVENT_xxx ones.
+grep '^const _PTRACE_O' gen-sysinfo.go |
+  sed -e 's/^\(const \)_\(PTRACE_O[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+grep '^const _PTRACE_EVENT' gen-sysinfo.go |
+  sed -e 's/^\(const \)_\(PTRACE_EVENT[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+# We need PTRACE_SETOPTIONS and PTRACE_GETEVENTMSG, but they are not
+# defined in older versions of glibc.
+if ! grep '^const _PTRACE_SETOPTIONS' ${OUT} > /dev/null 2>&1; then
+  echo "const _PTRACE_SETOPTIONS = 0x4200" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACESYSGOOD' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_O_TRACESYSGOOD = 0x1" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEFORK' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_O_TRACEFORK = 0x2" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEVFORK' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_O_TRACEVFORK = 0x4" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACECLONE' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_O_TRACECLONE = 0x8" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEEXEC' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_O_TRACEEXEC = 0x10" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEVFORKDONE' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_O_TRACEVFORKDONE = 0x20" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEEXIT' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_O_TRACEEXIT = 0x40" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_MASK' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_O_MASK = 0x7f" >> ${OUT}
+fi
+if ! grep '^const _PTRACE_GETEVENTMSG' ${OUT} > /dev/null 2>&1; then
+  echo "const _PTRACE_GETEVENTMSG = 0x4201" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_FORK' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_EVENT_FORK = 1" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_VFORK' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_EVENT_VFORK = 2" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_CLONE' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_EVENT_CLONE = 3" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_EXEC' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_EVENT_EXEC = 4" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_VFORK_DONE' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_EVENT_VFORK_DONE = 5" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_EXIT' ${OUT} > /dev/null 2>&1; then
+  echo "const PTRACE_EVENT_EXIT = 6" >> ${OUT}
+fi
+
+# The registers returned by PTRACE_GETREGS.  This is probably
+# GNU/Linux specific.
+regs=`grep '^type _user_regs_struct struct' gen-sysinfo.go`
+if test "$regs" != ""; then
+  regs=`echo $regs | sed -e 's/type _user_regs_struct struct //' -e 's/[{}]//g'`
+  regs=`echo $regs | sed -e s'/^ *//'`
+  nregs=
+  while test -n "$regs"; do
+    field=`echo $regs | sed -e 's/^\([^;]*\);.*$/\1/'`
+    regs=`echo $regs | sed -e 's/^[^;]*; *\(.*\)$/\1/'`
+    # Capitalize the first character of the field.
+    f=`echo $field | sed -e 's/^\(.\).*$/\1/'`
+    r=`echo $field | sed -e 's/^.\(.*\)$/\1/'`
+    f=`echo $f | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
+    field="$f$r"
+    nregs="$nregs $field;"
+  done
+  echo "type PtraceRegs struct {$nregs }" >> ${OUT}
+fi
+
+# Some basic types.
+echo 'type Size_t _size_t' >> ${OUT}
+echo "type Ssize_t _ssize_t" >> ${OUT}
+if grep '^const _HAVE_OFF64_T = ' gen-sysinfo.go > /dev/null 2>&1; then
+  echo "type Offset_t _off64_t" >> ${OUT}
+else
+  echo "type Offset_t _off_t" >> ${OUT}
+fi
+echo "type Mode_t _mode_t" >> ${OUT}
+echo "type Pid_t _pid_t" >> ${OUT}
+echo "type Uid_t _uid_t" >> ${OUT}
+echo "type Gid_t _gid_t" >> ${OUT}
+echo "type Socklen_t _socklen_t" >> ${OUT}
+
+# The long type, needed because that is the type that ptrace returns.
+sizeof_long=`grep '^const ___SIZEOF_LONG__ = ' gen-sysinfo.go | sed -e 's/.*= //'`
+if test "$sizeof_long" = "4"; then
+  echo "type _C_long int32" >> ${OUT}
+elif test "$sizeof_long" = "8"; then
+  echo "type _C_long int64" >> ${OUT}
+else
+  echo 1>&2 "mksysinfo.sh: could not determine size of long (got $sizeof_long)"
+  exit 1
+fi
+
+# The time structures need special handling: we need to name the
+# types, so that we can cast integers to the right types when
+# assigning to the structures.
+timeval=`grep '^type _timeval ' gen-sysinfo.go`
+timeval_sec=`echo $timeval | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'`
+timeval_usec=`echo $timeval | sed -n -e 's/^.*tv_usec \([^ ]*\);.*$/\1/p'`
+echo "type Timeval_sec_t $timeval_sec" >> ${OUT}
+echo "type Timeval_usec_t $timeval_usec" >> ${OUT}
+echo $timeval | \
+  sed -e 's/type _timeval /type Timeval /' \
+      -e 's/tv_sec *[a-zA-Z0-9_]*/Sec Timeval_sec_t/' \
+      -e 's/tv_usec *[a-zA-Z0-9_]*/Usec Timeval_usec_t/' >> ${OUT}
+timespec=`grep '^type _timespec ' gen-sysinfo.go`
+timespec_sec=`echo $timespec | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'`
+timespec_nsec=`echo $timespec | sed -n -e 's/^.*tv_nsec \([^ ]*\);.*$/\1/p'`
+echo "type Timespec_sec_t $timespec_sec" >> ${OUT}
+echo "type Timespec_nsec_t $timespec_nsec" >> ${OUT}
+echo $timespec | \
+  sed -e 's/^type _timespec /type Timespec /' \
+      -e 's/tv_sec *[a-zA-Z0-9_]*/Sec Timespec_sec_t/' \
+      -e 's/tv_nsec *[a-zA-Z0-9_]*/Nsec Timespec_nsec_t/' >> ${OUT}
+
+# The stat type.
+grep 'type _stat ' gen-sysinfo.go | \
+  sed -e 's/type _stat/type Stat_t/' \
+      -e 's/st_dev/Dev/' \
+      -e 's/st_ino/Ino/' \
+      -e 's/st_nlink/Nlink/' \
+      -e 's/st_mode/Mode/' \
+      -e 's/st_uid/Uid/' \
+      -e 's/st_gid/Gid/' \
+      -e 's/st_rdev/Rdev/' \
+      -e 's/st_size/Size/' \
+      -e 's/st_blksize/Blksize/' \
+      -e 's/st_blocks/Blocks/' \
+      -e 's/st_atim/Atime/' \
+      -e 's/st_mtim/Mtime/' \
+      -e 's/st_ctim/Ctime/' \
+      -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1Timeval\2/g' \
+      -e 's/\([^a-zA-Z0-9_]\)_timespec\([^a-zA-Z0-9_]\)/\1Timespec\2/g' \
+    >> ${OUT}
+
+# The directory searching types.
+grep '^type _dirent ' gen-sysinfo.go | \
+  sed -e 's/type _dirent/type Dirent/' \
+      -e 's/d_name/Name/' \
+      -e 's/]int8/]byte/' \
+      -e 's/d_ino/Ino/' \
+      -e 's/d_off/Off/' \
+      -e 's/d_reclen/Reclen/' \
+      -e 's/d_type/Type/' \
+    >> ${OUT}
+echo "type DIR _DIR" >> ${OUT}
+
+# The rusage struct.
+rusage=`grep '^type _rusage struct' gen-sysinfo.go`
+if test "$rusage" != ""; then
+  rusage=`echo $rusage | sed -e 's/type _rusage struct //' -e 's/[{}]//g'`
+  rusage=`echo $rusage | sed -e 's/^ *//'`
+  nrusage=
+  while test -n "$rusage"; do
+    field=`echo $rusage | sed -e 's/^\([^;]*\);.*$/\1/'`
+    rusage=`echo $rusage | sed -e 's/^[^;]*; *\(.*\)$/\1/'`
+    # Drop the leading ru_, capitalize the next character.
+    field=`echo $field | sed -e 's/^ru_//'`
+    f=`echo $field | sed -e 's/^\(.\).*$/\1/'`
+    r=`echo $field | sed -e 's/^.\(.*\)$/\1/'`
+    f=`echo $f | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
+    # Fix _timeval and _timespec.
+    r=`echo $r | sed -e s'/ _timeval$/ Timeval/'`
+    r=`echo $r | sed -e s'/ _timespec$/ Timespec/'`
+    field="$f$r"
+    nrusage="$nrusage $field;"
+  done
+  echo "type Rusage struct {$nrusage }" >> ${OUT}
+fi
+
+# The utsname struct.
+grep '^type _utsname ' gen-sysinfo.go | \
+    sed -e 's/_utsname/Utsname/' \
+      -e 's/sysname/Sysname/' \
+      -e 's/nodename/Nodename/' \
+      -e 's/release/Release/' \
+      -e 's/version/Version/' \
+      -e 's/machine/Machine/' \
+      -e 's/domainname/Domainname/' \
+    >> ${OUT}
+
+mv -f ${OUT} sysinfo.go
+exit $?
diff --git a/libgo/runtime/array.h b/libgo/runtime/array.h
new file mode 100644 (file)
index 0000000..f6d0261
--- /dev/null
@@ -0,0 +1,28 @@
+/* array.h -- the open array type for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#ifndef LIBGO_ARRAY_H
+#define LIBGO_ARRAY_H
+
+/* An open array is an instance of this structure.  */
+
+struct __go_open_array
+{
+  /* The elements of the array.  In use in the compiler this is a
+     pointer to the element type.  */
+  void* __values;
+  /* The number of elements in the array.  Note that this is "int",
+     not "size_t".  The language definition says that "int" is large
+     enough to hold the size of any allocated object.  Using "int"
+     saves 8 bytes per slice header on a 64-bit system with 32-bit
+     ints.  */
+  int __count;
+  /* The capacity of the array--the number of elements that can fit in
+     the __VALUES field.  */
+  int __capacity;
+};
+
+#endif /* !defined(LIBGO_ARRAY_H) */
diff --git a/libgo/runtime/chan.goc b/libgo/runtime/chan.goc
new file mode 100644 (file)
index 0000000..da0bbfc
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "config.h"
+#include "channel.h"
+
+typedef _Bool bool;
+typedef unsigned char byte;
+typedef struct __go_channel chan;
+
+/* Do a nonblocking channel receive.  */
+
+func chanrecv2(c *chan, val *byte) (pres bool) {
+       if (c->element_size > 8) {
+               return __go_receive_nonblocking_big(c, val);
+       } else {
+               struct __go_receive_nonblocking_small rs;
+               union {
+                       char b[8];
+                       uint64_t v;
+               } u;
+
+               rs = __go_receive_nonblocking_small (c);
+               if (!rs.__success) {
+                       __builtin_memset(val, 0, c->element_size);
+                       return 0;
+               }
+               u.v = rs.__val;
+#ifndef WORDS_BIGENDIAN
+               __builtin_memcpy(val, u.b, c->element_size);
+#else
+               __builtin_memcpy(val, u.b + 8 - c->element_size,
+                                c->element_size);
+#endif
+               return 1;
+       }
+}
diff --git a/libgo/runtime/channel.h b/libgo/runtime/channel.h
new file mode 100644 (file)
index 0000000..b0d1347
--- /dev/null
@@ -0,0 +1,147 @@
+/* channel.h -- the channel type for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+#include <pthread.h>
+
+/* This structure is used when a select is waiting for a synchronous
+   channel.  */
+
+struct __go_channel_select
+{
+  /* A pointer to the next select waiting for this channel.  */
+  struct __go_channel_select *next;
+  /* A pointer to the channel which this select will use.  This starts
+     out as NULL and is set to the first channel which synchs up with
+     this one.  This variable to which this points may only be
+     accessed when __go_select_data_mutex is held.  */
+  struct __go_channel **selected;
+  /* A pointer to a variable which must be set to true if the
+     goroutine which sets *SELECTED wants to read from the channel,
+     false if it wants to write to it.  */
+  _Bool *is_read;
+};
+
+/* A channel is a pointer to this structure.  */
+
+struct __go_channel
+{
+  /* A mutex to control access to the channel.  */
+  pthread_mutex_t lock;
+  /* A condition variable.  This is signalled when data is added to
+     the channel and when data is removed from the channel.  */
+  pthread_cond_t cond;
+  /* The size of elements on this channel.  */
+  size_t element_size;
+  /* Number of operations on closed channel.  */
+  unsigned short closed_op_count;
+  /* True if a goroutine is waiting to send on a synchronous
+     channel.  */
+  _Bool waiting_to_send;
+  /* True if a goroutine is waiting to receive on a synchronous
+     channel.  */
+  _Bool waiting_to_receive;
+  /* True if this channel was selected for send in a select statement.
+     This looks out all other sends.  */
+  _Bool selected_for_send;
+  /* True if this channel was selected for receive in a select
+     statement.  This locks out all other receives.  */
+  _Bool selected_for_receive;
+  /* True if this channel has been closed.  */
+  _Bool is_closed;
+  /* True if at least one null value has been read from a closed
+     channel.  */
+  _Bool saw_close;
+  /* The list of select statements waiting to send on a synchronous
+     channel.  */
+  struct __go_channel_select *select_send_queue;
+  /* The list of select statements waiting to receive on a synchronous
+     channel.  */
+  struct __go_channel_select *select_receive_queue;
+  /* If a select statement is waiting for this channel, it sets these
+     pointers.  When something happens on the channel, the channel
+     locks the mutex, signals the condition, and unlocks the
+     mutex.  */
+  pthread_mutex_t *select_mutex;
+  pthread_cond_t *select_cond;
+  /* The number of entries in the circular buffer.  */
+  unsigned int num_entries;
+  /* Where to store the next value.  */
+  unsigned int next_store;
+  /* Where to fetch the next value.  If next_fetch == next_store, the
+     buffer is empty.  If next_store + 1 == next_fetch, the buffer is
+     full.  */
+  unsigned int next_fetch;
+  /* The circular buffer.  */
+  uint64_t data[];
+};
+
+/* The mutex used to control access to the value pointed to by the
+   __go_channel_select selected field.  No additional mutexes may be
+   acquired while this mutex is held.  */
+extern pthread_mutex_t __go_select_data_mutex;
+
+/* Maximum permitted number of operations on a closed channel.  */
+#define MAX_CLOSED_OPERATIONS (0x100)
+
+extern struct __go_channel *__go_new_channel (size_t, size_t);
+
+extern _Bool __go_synch_with_select (struct __go_channel *, _Bool);
+
+extern void __go_broadcast_to_select (struct __go_channel *);
+
+extern _Bool __go_send_acquire (struct __go_channel *, _Bool);
+
+#define SEND_NONBLOCKING_ACQUIRE_SPACE 0
+#define SEND_NONBLOCKING_ACQUIRE_NOSPACE 1
+#define SEND_NONBLOCKING_ACQUIRE_CLOSED 2
+
+extern int __go_send_nonblocking_acquire (struct __go_channel *);
+
+extern void __go_send_release (struct __go_channel *);
+
+extern void __go_send_small (struct __go_channel *, uint64_t, _Bool);
+
+extern _Bool __go_send_nonblocking_small (struct __go_channel *, uint64_t);
+
+extern void __go_send_big (struct __go_channel *, const void *, _Bool);
+
+extern _Bool __go_send_nonblocking_big (struct __go_channel *, const void *);
+
+extern _Bool __go_receive_acquire (struct __go_channel *, _Bool);
+
+#define RECEIVE_NONBLOCKING_ACQUIRE_DATA 0
+#define RECEIVE_NONBLOCKING_ACQUIRE_NODATA 1
+#define RECEIVE_NONBLOCKING_ACQUIRE_CLOSED 2
+
+extern int __go_receive_nonblocking_acquire (struct __go_channel *);
+
+extern uint64_t __go_receive_small (struct __go_channel *, _Bool);
+
+extern void __go_receive_release (struct __go_channel *);
+
+struct __go_receive_nonblocking_small
+{
+  uint64_t __val;
+  _Bool __success;
+};
+
+extern struct __go_receive_nonblocking_small
+__go_receive_nonblocking_small (struct __go_channel *);
+
+extern void __go_receive_big (struct __go_channel *, void *, _Bool);
+
+extern _Bool __go_receive_nonblocking_big (struct __go_channel *, void *);
+
+extern void __go_unlock_and_notify_selects (struct __go_channel *);
+
+extern _Bool __go_builtin_closed (struct __go_channel *);
+
+extern void __go_builtin_close (struct __go_channel *);
+
+extern size_t __go_chan_len (struct __go_channel *);
+
+extern size_t __go_chan_cap (struct __go_channel *);
diff --git a/libgo/runtime/defs.h b/libgo/runtime/defs.h
new file mode 100644 (file)
index 0000000..67ad212
--- /dev/null
@@ -0,0 +1,12 @@
+/* defs.h -- runtime definitions for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+/* The gc library uses this file for system defines, and generates it
+   automatically using the godefs program.  The logical thing to put
+   here for gccgo would be #include statements for system header
+   files.  We can't do that, though, because runtime.h #define's the
+   standard types.  So we #include the system headers from runtime.h
+   instead.  */
diff --git a/libgo/runtime/go-alloc.h b/libgo/runtime/go-alloc.h
new file mode 100644 (file)
index 0000000..c880a04
--- /dev/null
@@ -0,0 +1,11 @@
+/* go-alloc.h -- allocate memory for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+#include <stdint.h>
+
+extern void *__go_alloc (unsigned int __attribute__ ((mode (pointer))));
+extern void __go_free (void *);
diff --git a/libgo/runtime/go-append.c b/libgo/runtime/go-append.c
new file mode 100644 (file)
index 0000000..aa8f4a1
--- /dev/null
@@ -0,0 +1,62 @@
+/* go-append.c -- the go builtin append function.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-assert.h"
+#include "go-type.h"
+#include "array.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_open_array
+__go_append (const struct __go_slice_type *type,
+            struct __go_open_array a, struct __go_open_array b)
+{
+  size_t element_size;
+  unsigned int ucount;
+  int count;
+
+  if (b.__values == NULL || b.__count == 0)
+    return a;
+
+  __go_assert (type->__common.__code == GO_SLICE);
+  element_size = type->__element_type->__size;
+
+  ucount = (unsigned int) a.__count + (unsigned int) b.__count;
+  count = (int) ucount;
+  __go_assert (ucount == (unsigned int) count && count >= a.__count);
+  if (count > a.__capacity)
+    {
+      int m;
+      struct __go_open_array n;
+
+      m = a.__capacity;
+      if (m == 0)
+       m = b.__count;
+      else
+       {
+         do
+           {
+             if (a.__count < 1024)
+               m += m;
+             else
+               m += m / 4;
+           }
+         while (m < count);
+       }
+
+      n.__values = __go_alloc (m * element_size);
+      n.__count = a.__count;
+      n.__capacity = m;
+      __builtin_memcpy (n.__values, a.__values, n.__count * element_size);
+
+      a = n;
+    }
+
+  __builtin_memmove ((char *) a.__values + a.__count * element_size,
+                    b.__values, b.__count * element_size);
+  a.__count = count;
+  return a;
+}
diff --git a/libgo/runtime/go-assert-interface.c b/libgo/runtime/go-assert-interface.c
new file mode 100644 (file)
index 0000000..57a092d
--- /dev/null
@@ -0,0 +1,49 @@
+/* go-assert-interface.c -- interface type assertion for Go.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "go-panic.h"
+#include "interface.h"
+
+/* This is called by the compiler to implement a type assertion from
+   one interface type to another.  This returns the value that should
+   go in the first field of the result tuple.  The result may be an
+   empty or a non-empty interface.  */
+
+const void *
+__go_assert_interface (const struct __go_type_descriptor *lhs_descriptor,
+                      const struct __go_type_descriptor *rhs_descriptor)
+{
+  const struct __go_interface_type *lhs_interface;
+
+  if (rhs_descriptor == NULL)
+    {
+      struct __go_empty_interface panic_arg;
+
+      /* A type assertion is not permitted with a nil interface.  */
+
+      newTypeAssertionError (NULL,
+                            NULL,
+                            lhs_descriptor,
+                            NULL,
+                            NULL,
+                            lhs_descriptor->__reflection,
+                            NULL,
+                            &panic_arg);
+      __go_panic (panic_arg);
+    }
+
+  /* A type assertion to an empty interface just returns the object
+     descriptor.  */
+
+  __go_assert (lhs_descriptor->__code == GO_INTERFACE);
+  lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
+  if (lhs_interface->__methods.__count == 0)
+    return rhs_descriptor;
+
+  return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
+}
diff --git a/libgo/runtime/go-assert.c b/libgo/runtime/go-assert.c
new file mode 100644 (file)
index 0000000..48aa072
--- /dev/null
@@ -0,0 +1,18 @@
+/* go-assert.c -- libgo specific assertions
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "go-assert.h"
+
+void
+__go_assert_fail (const char *file, unsigned int lineno)
+{
+  /* FIXME: Eventually we should dump a stack trace here.  */
+  fprintf (stderr, "%s:%u: libgo assertion failure\n", file, lineno);
+  abort ();
+}
diff --git a/libgo/runtime/go-assert.h b/libgo/runtime/go-assert.h
new file mode 100644 (file)
index 0000000..6365595
--- /dev/null
@@ -0,0 +1,18 @@
+/* go-assert.h -- libgo specific assertions
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#ifndef LIBGO_GO_ASSERT_H
+#define LIBGO_GO_ASSERT_H
+
+/* We use a Go specific assert function so that functions which call
+   assert aren't required to always split the stack.  */
+
+extern void __go_assert_fail (const char *file, unsigned int lineno)
+  __attribute__ ((noreturn));
+
+#define __go_assert(e) ((e) ? (void) 0 : __go_assert_fail (__FILE__, __LINE__))
+
+#endif /* !defined(LIBGO_GO_ASSERT_H) */
diff --git a/libgo/runtime/go-breakpoint.c b/libgo/runtime/go-breakpoint.c
new file mode 100644 (file)
index 0000000..bb6eddc
--- /dev/null
@@ -0,0 +1,15 @@
+/* go-breakpoint.c -- the runtime.Breakpoint function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <sched.h>
+
+void Breakpoint (void) asm ("libgo_runtime.runtime.Breakpoint");
+
+void
+Breakpoint (void)
+{
+  __builtin_trap ();
+}
diff --git a/libgo/runtime/go-byte-array-to-string.c b/libgo/runtime/go-byte-array-to-string.c
new file mode 100644 (file)
index 0000000..5317306
--- /dev/null
@@ -0,0 +1,24 @@
+/* go-byte-array-to-string.c -- convert an array of bytes to a string in Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-string.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_byte_array_to_string (const void* p, size_t len)
+{
+  const unsigned char *bytes;
+  unsigned char *retdata;
+  struct __go_string ret;
+
+  bytes = (const unsigned char *) p;
+  retdata = runtime_mallocgc (len, RefNoPointers, 1, 0);
+  __builtin_memcpy (retdata, bytes, len);
+  ret.__data = retdata;
+  ret.__length = len;
+  return ret;
+}
diff --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c
new file mode 100644 (file)
index 0000000..8402958
--- /dev/null
@@ -0,0 +1,51 @@
+/* go-caller.c -- runtime.Caller and runtime.FuncForPC for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+/* Implement runtime.Caller.  */
+
+#include <stdint.h>
+
+#include "go-string.h"
+
+/* The values returned by runtime.Caller.  */
+
+struct caller_ret
+{
+  uintptr_t pc;
+  struct __go_string file;
+  int line;
+  _Bool ok;
+};
+
+/* Implement runtime.Caller.  */
+
+struct caller_ret Caller (int n) asm ("libgo_runtime.runtime.Caller");
+
+struct caller_ret
+Caller (int n __attribute__ ((unused)))
+{
+  struct caller_ret ret;
+
+  /* A proper implementation needs to dig through the debugging
+     information.  */
+  ret.pc = (uint64_t) (uintptr_t) __builtin_return_address (1);
+  ret.file.__data = NULL;
+  ret.file.__length = 0;
+  ret.line = 0;
+  ret.ok = 0;
+
+  return ret;
+}
+
+/* Implement runtime.FuncForPC.  */
+
+void *FuncForPC (uintptr_t) asm ("libgo_runtime.runtime.FuncForPC");
+
+void *
+FuncForPC(uintptr_t pc __attribute__ ((unused)))
+{
+  return NULL;
+}
diff --git a/libgo/runtime/go-can-convert-interface.c b/libgo/runtime/go-can-convert-interface.c
new file mode 100644 (file)
index 0000000..83217ab
--- /dev/null
@@ -0,0 +1,76 @@
+/* go-can-convert-interface.c -- can we convert to an interface?
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-assert.h"
+#include "go-type.h"
+#include "interface.h"
+
+/* Return whether we can convert from the type in FROM_DESCRIPTOR to
+   the interface in TO_DESCRIPTOR.  This is used for type
+   switches.  */
+
+_Bool
+__go_can_convert_to_interface (
+    const struct __go_type_descriptor *to_descriptor,
+    const struct __go_type_descriptor *from_descriptor)
+{
+  const struct __go_interface_type *to_interface;
+  int to_method_count;
+  const struct __go_interface_method *to_method;
+  const struct __go_uncommon_type *from_uncommon;
+  int from_method_count;
+  const struct __go_method *from_method;
+  int i;
+
+  /* In a type switch FROM_DESCRIPTOR can be NULL.  */
+  if (from_descriptor == NULL)
+    return 0;
+
+  __go_assert (to_descriptor->__code == GO_INTERFACE);
+  to_interface = (const struct __go_interface_type *) to_descriptor;
+  to_method_count = to_interface->__methods.__count;
+  to_method = ((const struct __go_interface_method *)
+              to_interface->__methods.__values);
+
+  from_uncommon = from_descriptor->__uncommon;
+  if (from_uncommon == NULL)
+    {
+      from_method_count = 0;
+      from_method = NULL;
+    }
+  else
+    {
+      from_method_count = from_uncommon->__methods.__count;
+      from_method = ((const struct __go_method *)
+                    from_uncommon->__methods.__values);
+    }
+
+  for (i = 0; i < to_method_count; ++i)
+    {
+      while (from_method_count > 0
+            && (!__go_ptr_strings_equal (from_method->__name,
+                                         to_method->__name)
+                || !__go_ptr_strings_equal (from_method->__pkg_path,
+                                            to_method->__pkg_path)))
+       {
+         ++from_method;
+         --from_method_count;
+       }
+
+      if (from_method_count == 0)
+       return 0;
+
+      if (!__go_type_descriptors_equal (from_method->__mtype,
+                                       to_method->__type))
+       return 0;
+
+      ++to_method;
+      ++from_method;
+      --from_method_count;
+    }
+
+  return 1;
+}
diff --git a/libgo/runtime/go-chan-cap.c b/libgo/runtime/go-chan-cap.c
new file mode 100644 (file)
index 0000000..df603bf
--- /dev/null
@@ -0,0 +1,41 @@
+/* go-chan-cap.c -- the cap function applied to a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-assert.h"
+#include "channel.h"
+
+/* Return the cap function applied to a channel--the size of the
+   buffer.  This could be done inline but I'm doing it as a function
+   for now to make it easy to change the channel structure.  */
+
+size_t
+__go_chan_cap (struct __go_channel *channel)
+{
+  int i;
+  size_t ret;
+
+  if (channel == NULL)
+    return 0;
+
+  i = pthread_mutex_lock (&channel->lock);
+  __go_assert (i == 0);
+
+  if (channel->num_entries == 0)
+    ret = 0;
+  else
+    {
+      /* One slot is always unused.  We added 1 when we created the
+        channel.  */
+      ret = channel->num_entries - 1;
+    }
+
+  i = pthread_mutex_unlock (&channel->lock);
+  __go_assert  (i == 0);
+
+  return ret;
+}
diff --git a/libgo/runtime/go-chan-len.c b/libgo/runtime/go-chan-len.c
new file mode 100644 (file)
index 0000000..5aebae1
--- /dev/null
@@ -0,0 +1,41 @@
+/* go-chan-len.c -- the len function applied to a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-assert.h"
+#include "channel.h"
+
+/* Return the len function applied to a channel--the number of
+   elements in the buffer.  This could be done inline but I'm doing it
+   as a function for now to make it easy to change the channel
+   structure.  */
+
+size_t
+__go_chan_len (struct __go_channel *channel)
+{
+  int i;
+  size_t ret;
+
+  if (channel == NULL)
+    return 0;
+
+  i = pthread_mutex_lock (&channel->lock);
+  __go_assert (i == 0);
+
+  if (channel->num_entries == 0)
+    ret = 0;
+  else if (channel->next_fetch == channel->next_store)
+    ret = 0;
+  else
+    ret = ((channel->next_store + channel->num_entries - channel->next_fetch)
+          % channel->num_entries);
+
+  i = pthread_mutex_unlock (&channel->lock);
+  __go_assert  (i == 0);
+
+  return ret;
+}
diff --git a/libgo/runtime/go-check-interface.c b/libgo/runtime/go-check-interface.c
new file mode 100644 (file)
index 0000000..d2258a8
--- /dev/null
@@ -0,0 +1,46 @@
+/* go-check-interface.c -- check an interface type for a conversion
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-panic.h"
+#include "interface.h"
+
+/* Check that an interface type matches for a conversion to a
+   non-interface type.  This panics if the types are bad.  The actual
+   extraction of the object is inlined.  */
+
+void
+__go_check_interface_type (
+    const struct __go_type_descriptor *lhs_descriptor,
+    const struct __go_type_descriptor *rhs_descriptor,
+    const struct __go_type_descriptor *rhs_inter_descriptor)
+{
+  if (rhs_descriptor == NULL)
+    {
+      struct __go_empty_interface panic_arg;
+
+      newTypeAssertionError(NULL, NULL, lhs_descriptor, NULL, NULL,
+                           lhs_descriptor->__reflection, NULL, &panic_arg);
+      __go_panic(panic_arg);
+    }
+
+  if (lhs_descriptor != rhs_descriptor
+      && !__go_type_descriptors_equal (lhs_descriptor, rhs_descriptor)
+      && (lhs_descriptor->__code != GO_UNSAFE_POINTER
+         || !__go_is_pointer_type (rhs_descriptor))
+      && (rhs_descriptor->__code != GO_UNSAFE_POINTER
+         || !__go_is_pointer_type (lhs_descriptor)))
+    {
+      struct __go_empty_interface panic_arg;
+
+      newTypeAssertionError(rhs_inter_descriptor, rhs_descriptor,
+                           lhs_descriptor,
+                           rhs_inter_descriptor->__reflection,
+                           rhs_descriptor->__reflection,
+                           lhs_descriptor->__reflection,
+                           NULL, &panic_arg);
+      __go_panic(panic_arg);
+    }
+}
diff --git a/libgo/runtime/go-close.c b/libgo/runtime/go-close.c
new file mode 100644 (file)
index 0000000..ced7429
--- /dev/null
@@ -0,0 +1,33 @@
+/* go-close.c -- the builtin close function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-assert.h"
+#include "channel.h"
+
+/* Close a channel.  After a channel is closed, sends are no longer
+   permitted.  Receives always return zero.  */
+
+void
+__go_builtin_close (struct __go_channel *channel)
+{
+  int i;
+
+  i = pthread_mutex_lock (&channel->lock);
+  __go_assert (i == 0);
+
+  while (channel->selected_for_send)
+    {
+      i = pthread_cond_wait (&channel->cond, &channel->lock);
+      __go_assert (i == 0);
+    }
+
+  channel->is_closed = 1;
+
+  i = pthread_cond_broadcast (&channel->cond);
+  __go_assert (i == 0);
+
+  __go_unlock_and_notify_selects (channel);
+}
diff --git a/libgo/runtime/go-closed.c b/libgo/runtime/go-closed.c
new file mode 100644 (file)
index 0000000..bfa9cd6
--- /dev/null
@@ -0,0 +1,34 @@
+/* go-closed.c -- the builtin closed function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-assert.h"
+#include "channel.h"
+
+/* Return whether a channel is closed.  We only return true after at
+   least one nil value has been read from the channel.  */
+
+_Bool
+__go_builtin_closed (struct __go_channel *channel)
+{
+  int i;
+  _Bool ret;
+
+  i = pthread_mutex_lock (&channel->lock);
+  __go_assert (i == 0);
+
+  while (channel->selected_for_receive)
+    {
+      i = pthread_cond_wait (&channel->cond, &channel->lock);
+      __go_assert (i == 0);
+    }
+
+  ret = channel->saw_close;
+
+  i = pthread_mutex_unlock (&channel->lock);
+  __go_assert (i == 0);
+
+  return ret;
+}
diff --git a/libgo/runtime/go-construct-map.c b/libgo/runtime/go-construct-map.c
new file mode 100644 (file)
index 0000000..15497ea
--- /dev/null
@@ -0,0 +1,32 @@
+/* go-construct-map.c -- construct a map from an initializer.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "map.h"
+
+struct __go_map *
+__go_construct_map (const struct __go_map_descriptor *descriptor,
+                   size_t count, size_t entry_size, size_t val_offset,
+                   size_t val_size, const void *ventries)
+{
+  struct __go_map *ret;
+  const unsigned char *entries;
+  size_t i;
+
+  ret = __go_new_map (descriptor, count);
+
+  entries = (const unsigned char *) ventries;
+  for (i = 0; i < count; ++i)
+    {
+      void *val = __go_map_index (ret, entries, 1);
+      __builtin_memcpy (val, entries + val_offset, val_size);
+      entries += entry_size;
+    }
+
+  return ret;
+}
diff --git a/libgo/runtime/go-convert-interface.c b/libgo/runtime/go-convert-interface.c
new file mode 100644 (file)
index 0000000..259456c
--- /dev/null
@@ -0,0 +1,138 @@
+/* go-convert-interface.c -- convert interfaces for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "go-panic.h"
+#include "interface.h"
+
+/* This is called when converting one interface type into another
+   interface type.  LHS_DESCRIPTOR is the type descriptor of the
+   resulting interface.  RHS_DESCRIPTOR is the type descriptor of the
+   object being converted.  This builds and returns a new interface
+   method table.  If any method in the LHS_DESCRIPTOR interface is not
+   implemented by the object, the conversion fails.  If the conversion
+   fails, then if MAY_FAIL is true this returns NULL; otherwise, it
+   panics.  */
+
+void *
+__go_convert_interface_2 (const struct __go_type_descriptor *lhs_descriptor,
+                         const struct __go_type_descriptor *rhs_descriptor,
+                         _Bool may_fail)
+{
+  const struct __go_interface_type *lhs_interface;
+  int lhs_method_count;
+  const struct __go_interface_method* lhs_methods;
+  const void **methods;
+  const struct __go_uncommon_type *rhs_uncommon;
+  int rhs_method_count;
+  const struct __go_method *p_rhs_method;
+  int i;
+
+  if (rhs_descriptor == NULL)
+    {
+      /* A nil value always converts to nil.  */
+      return NULL;
+    }
+
+  __go_assert (lhs_descriptor->__code == GO_INTERFACE);
+  lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
+  lhs_method_count = lhs_interface->__methods.__count;
+  lhs_methods = ((const struct __go_interface_method *)
+                lhs_interface->__methods.__values);
+
+  /* This should not be called for an empty interface.  */
+  __go_assert (lhs_method_count > 0);
+
+  rhs_uncommon = rhs_descriptor->__uncommon;
+  if (rhs_uncommon == NULL || rhs_uncommon->__methods.__count == 0)
+    {
+      struct __go_empty_interface panic_arg;
+
+      if (may_fail)
+       return NULL;
+
+      newTypeAssertionError (NULL,
+                            rhs_descriptor,
+                            lhs_descriptor,
+                            NULL,
+                            rhs_descriptor->__reflection,
+                            lhs_descriptor->__reflection,
+                            lhs_methods[0].__name,
+                            &panic_arg);
+      __go_panic (panic_arg);
+    }
+
+  rhs_method_count = rhs_uncommon->__methods.__count;
+  p_rhs_method = ((const struct __go_method *)
+                 rhs_uncommon->__methods.__values);
+
+  methods = NULL;
+
+  for (i = 0; i < lhs_method_count; ++i)
+    {
+      const struct __go_interface_method *p_lhs_method;
+
+      p_lhs_method = &lhs_methods[i];
+
+      while (rhs_method_count > 0
+            && (!__go_ptr_strings_equal (p_lhs_method->__name,
+                                         p_rhs_method->__name)
+                || !__go_ptr_strings_equal (p_lhs_method->__pkg_path,
+                                            p_rhs_method->__pkg_path)))
+       {
+         ++p_rhs_method;
+         --rhs_method_count;
+       }
+
+      if (rhs_method_count == 0
+         || !__go_type_descriptors_equal (p_lhs_method->__type,
+                                          p_rhs_method->__mtype))
+       {
+         struct __go_empty_interface panic_arg;
+
+         if (methods != NULL)
+           __go_free (methods);
+
+         if (may_fail)
+           return NULL;
+
+         newTypeAssertionError (NULL,
+                                rhs_descriptor,
+                                lhs_descriptor,
+                                NULL,
+                                rhs_descriptor->__reflection,
+                                lhs_descriptor->__reflection,
+                                p_lhs_method->__name,
+                                &panic_arg);
+         __go_panic (panic_arg);
+       }
+
+      if (methods == NULL)
+       {
+         methods = (const void **) __go_alloc ((lhs_method_count + 1)
+                                               * sizeof (void *));
+
+         /* The first field in the method table is always the type of
+            the object.  */
+         methods[0] = rhs_descriptor;
+       }
+
+      methods[i + 1] = p_rhs_method->__function;
+    }
+
+  return methods;
+}
+
+/* This is called by the compiler to convert a value from one
+   interface type to another.  */
+
+void *
+__go_convert_interface (const struct __go_type_descriptor *lhs_descriptor,
+                       const struct __go_type_descriptor *rhs_descriptor)
+{
+  return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
+}
diff --git a/libgo/runtime/go-defer.c b/libgo/runtime/go-defer.c
new file mode 100644 (file)
index 0000000..6425f05
--- /dev/null
@@ -0,0 +1,69 @@
+/* go-defer.c -- manage the defer stack.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-alloc.h"
+#include "go-panic.h"
+#include "go-defer.h"
+
+/* This function is called each time we need to defer a call.  */
+
+void
+__go_defer (void *frame, void (*pfn) (void *), void *arg)
+{
+  struct __go_defer_stack *n;
+
+  if (__go_panic_defer == NULL)
+    __go_panic_defer = ((struct __go_panic_defer_struct *)
+                       __go_alloc (sizeof (struct __go_panic_defer_struct)));
+
+  n = (struct __go_defer_stack *) __go_alloc (sizeof (struct __go_defer_stack));
+  n->__next = __go_panic_defer->__defer;
+  n->__frame = frame;
+  n->__panic = __go_panic_defer->__panic;
+  n->__pfn = pfn;
+  n->__arg = arg;
+  n->__retaddr = NULL;
+  __go_panic_defer->__defer = n;
+}
+
+/* This function is called when we want to undefer the stack.  */
+
+void
+__go_undefer (void *frame)
+{
+  if (__go_panic_defer == NULL)
+    return;
+  while (__go_panic_defer->__defer != NULL
+        && __go_panic_defer->__defer->__frame == frame)
+    {
+      struct __go_defer_stack *d;
+      void (*pfn) (void *);
+
+      d = __go_panic_defer->__defer;
+      pfn = d->__pfn;
+      d->__pfn = NULL;
+
+      if (pfn != NULL)
+       (*pfn) (d->__arg);
+
+      __go_panic_defer->__defer = d->__next;
+      __go_free (d);
+    }
+}
+
+/* This function is called to record the address to which the deferred
+   function returns.  This may in turn be checked by __go_can_recover.
+   The frontend relies on this function returning false.  */
+
+_Bool
+__go_set_defer_retaddr (void *retaddr)
+{
+  if (__go_panic_defer != NULL && __go_panic_defer->__defer != NULL)
+    __go_panic_defer->__defer->__retaddr = retaddr;
+  return 0;
+}
diff --git a/libgo/runtime/go-defer.h b/libgo/runtime/go-defer.h
new file mode 100644 (file)
index 0000000..f8924f3
--- /dev/null
@@ -0,0 +1,36 @@
+/* go-defer.h -- the defer stack.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+struct __go_panic_stack;
+
+/* The defer stack is a list of these structures.  */
+
+struct __go_defer_stack
+{
+  /* The next entry in the stack.  */
+  struct __go_defer_stack *__next;
+
+  /* The frame pointer for the function which called this defer
+     statement.  */
+  void *__frame;
+
+  /* The value of the panic stack when this function is deferred.
+     This function can not recover this value from the panic stack.
+     This can happen if a deferred function uses its own defer
+     statement.  */
+  struct __go_panic_stack *__panic;
+
+  /* The function to call.  */
+  void (*__pfn) (void *);
+
+  /* The argument to pass to the function.  */
+  void *__arg;
+
+  /* The return address that a recover thunk matches against.  This is
+     set by __go_set_defer_retaddr which is called by the thunks
+     created by defer statements.  */
+  const void *__retaddr;
+};
diff --git a/libgo/runtime/go-deferred-recover.c b/libgo/runtime/go-deferred-recover.c
new file mode 100644 (file)
index 0000000..2d9ca14
--- /dev/null
@@ -0,0 +1,92 @@
+/* go-deferred-recover.c -- support for a deferred recover function.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-panic.h"
+#include "go-defer.h"
+
+/* This is called when a call to recover is deferred.  That is,
+   something like
+     defer recover()
+
+   We need to handle this specially.  In 6g/8g, the recover function
+   looks up the stack frame.  In particular, that means that a
+   deferred recover will not recover a panic thrown in the same
+   function that defers the recover.  It will only recover a panic
+   thrown in a function that defers the deferred call to recover.
+
+   In other words:
+
+   func f1() {
+       defer recover() // does not stop panic
+       panic(0)
+   }
+
+   func f2() {
+       defer func() {
+               defer recover() // stops panic(0)
+       }()
+       panic(0)
+   }
+
+   func f3() {
+       defer func() {
+               defer recover() // does not stop panic
+               panic(0)
+       }()
+       panic(1)
+   }
+
+   func f4() {
+       defer func() {
+               defer func() {
+                       defer recover() // stops panic(0)
+               }()
+               panic(0)
+       }()
+       panic(1)
+   }
+
+   The interesting case here is f3.  As can be seen from f2, the
+   deferred recover could pick up panic(1).  However, this does not
+   happen because it is blocked by the panic(0).
+
+   When a function calls recover, then when we invoke it we pass a
+   hidden parameter indicating whether it should recover something.
+   This parameter is set based on whether the function is being
+   invoked directly from defer.  The parameter winds up determining
+   whether __go_recover or __go_deferred_recover is called at all.
+
+   In the case of a deferred recover, the hidden parameter which
+   controls the call is actually the one set up for the function which
+   runs the defer recover() statement.  That is the right thing in all
+   the cases above except for f3.  In f3 the function is permitted to
+   call recover, but the deferred recover call is not.  We address
+   that here by checking for that specific case before calling
+   recover.  If this function was deferred when there is already a
+   panic on the panic stack, then we can only recover that panic, not
+   any other.
+
+   Note that we can get away with using a special function here
+   because you are not permitted to take the address of a predeclared
+   function like recover.  */
+
+struct __go_empty_interface
+__go_deferred_recover ()
+{
+  if (__go_panic_defer == NULL
+      || __go_panic_defer->__defer == NULL
+      || __go_panic_defer->__defer->__panic != __go_panic_defer->__panic)
+    {
+      struct __go_empty_interface ret;
+
+      ret.__type_descriptor = NULL;
+      ret.__object = NULL;
+      return ret;
+    }
+  return __go_recover();
+}
diff --git a/libgo/runtime/go-eface-compare.c b/libgo/runtime/go-eface-compare.c
new file mode 100644 (file)
index 0000000..c90177e
--- /dev/null
@@ -0,0 +1,32 @@
+/* go-eface-compare.c -- compare two empty values.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "interface.h"
+
+/* Compare two interface values.  Return 0 for equal, not zero for not
+   equal (return value is like strcmp).  */
+
+int
+__go_empty_interface_compare (struct __go_empty_interface left,
+                             struct __go_empty_interface right)
+{
+  const struct __go_type_descriptor *left_descriptor;
+
+  left_descriptor = left.__type_descriptor;
+  if (left_descriptor == NULL && right.__type_descriptor == NULL)
+    return 0;
+  if (left_descriptor == NULL || right.__type_descriptor == NULL)
+    return 1;
+  if (!__go_type_descriptors_equal (left_descriptor,
+                                   right.__type_descriptor))
+    return 1;
+  if (__go_is_pointer_type (left_descriptor))
+    return left.__object == right.__object ? 0 : 1;
+  if (!left_descriptor->__equalfn (left.__object, right.__object,
+                                  left_descriptor->__size))
+    return 1;
+  return 0;
+}
diff --git a/libgo/runtime/go-eface-val-compare.c b/libgo/runtime/go-eface-val-compare.c
new file mode 100644 (file)
index 0000000..319ede2
--- /dev/null
@@ -0,0 +1,32 @@
+/* go-eface-val-compare.c -- compare an empty interface with a value.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-type.h"
+#include "interface.h"
+
+/* Compare an empty interface with a value.  Return 0 for equal, not
+   zero for not equal (return value is like strcmp).  */
+
+int
+__go_empty_interface_value_compare (
+    struct __go_empty_interface left,
+    const struct __go_type_descriptor *right_descriptor,
+    const void *val)
+{
+  const struct __go_type_descriptor *left_descriptor;
+
+  left_descriptor = left.__type_descriptor;
+  if (left_descriptor == NULL)
+    return 1;
+  if (!__go_type_descriptors_equal (left_descriptor, right_descriptor))
+    return 1;
+  if (__go_is_pointer_type (left_descriptor))
+    return left.__object == val ? 0 : 1;
+  if (!left_descriptor->__equalfn (left.__object, val,
+                                  left_descriptor->__size))
+    return 1;
+  return 0;
+}
diff --git a/libgo/runtime/go-getgoroot.c b/libgo/runtime/go-getgoroot.c
new file mode 100644 (file)
index 0000000..e74fee8
--- /dev/null
@@ -0,0 +1,26 @@
+/* go-getgoroot.c -- getgoroot function for runtime package.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdlib.h>
+
+#include "go-string.h"
+
+struct __go_string getgoroot (void) asm ("libgo_runtime.runtime.getgoroot");
+
+struct __go_string
+getgoroot ()
+{
+  const char *p;
+  struct __go_string ret;
+
+  p = getenv ("GOROOT");
+  ret.__data = (const unsigned char *) p;
+  if (ret.__data == NULL)
+    ret.__length = 0;
+  else
+    ret.__length = __builtin_strlen (p);
+  return ret;
+}
diff --git a/libgo/runtime/go-go.c b/libgo/runtime/go-go.c
new file mode 100644 (file)
index 0000000..a97b7af
--- /dev/null
@@ -0,0 +1,649 @@
+/* go-go.c -- the go function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include "config.h"
+#include "go-assert.h"
+#include "go-panic.h"
+#include "go-alloc.h"
+#include "runtime.h"
+#include "malloc.h"
+
+#ifdef USING_SPLIT_STACK
+/* FIXME: This is not declared anywhere.  */
+extern void *__splitstack_find (void *, void *, size_t *, void **, void **,
+                               void **);
+#endif
+
+/* We need to ensure that all callee-saved registers are stored on the
+   stack, in case they hold pointers.  */
+
+#if defined(__i386__)
+ #ifndef __PIC__
+  #define SAVE_REGS asm ("" : : : "esi", "edi", "ebx")
+ #else
+  #define SAVE_REGS asm ("" : : : "esi", "edi")
+ #endif
+#elif defined(__x86_64__)
+ #define SAVE_REGS asm ("" : : : "r12", "r13", "r14", "r15", "rbp", "rbx")
+#else
+ #error must define SAVE_REGS
+#endif
+
+/* We stop the threads by sending them the signal GO_SIG_STOP and we
+   start them by sending them the signal GO_SIG_START.  */
+
+#define GO_SIG_START (SIGRTMIN + 1)
+#define GO_SIG_STOP (SIGRTMIN + 2)
+
+#ifndef SA_RESTART
+  #define SA_RESTART 0
+#endif
+
+/* A doubly linked list of the threads we have started.  */
+
+struct __go_thread_id
+{
+  /* Links.  */
+  struct __go_thread_id *prev;
+  struct __go_thread_id *next;
+  /* True if the thread ID has not yet been filled in.  */
+  _Bool tentative;
+  /* Thread ID.  */
+  pthread_t id;
+  /* Thread's M structure.  */
+  struct M *m;
+  /* If the thread ID has not been filled in, the function we are
+     running.  */
+  void (*pfn) (void *);
+  /* If the thread ID has not been filled in, the argument to the
+     function.  */
+  void *arg;
+};
+
+static struct __go_thread_id *__go_all_thread_ids;
+
+/* A lock to control access to ALL_THREAD_IDS.  */
+
+static pthread_mutex_t __go_thread_ids_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* A semaphore used to wait until all the threads have stopped.  */
+
+static sem_t __go_thread_ready_sem;
+
+/* A signal set used to wait until garbage collection is complete.  */
+
+static sigset_t __go_thread_wait_sigset;
+
+/* Remove the current thread from the list of threads.  */
+
+static void
+remove_current_thread (void)
+{
+  struct __go_thread_id *list_entry;
+  MCache *mcache;
+  int i;
+  
+  list_entry = m->list_entry;
+  mcache = m->mcache;
+
+  i = pthread_mutex_lock (&__go_thread_ids_lock);
+  __go_assert (i == 0);
+
+  if (list_entry->prev != NULL)
+    list_entry->prev->next = list_entry->next;
+  else
+    __go_all_thread_ids = list_entry->next;
+  if (list_entry->next != NULL)
+    list_entry->next->prev = list_entry->prev;
+
+  i = pthread_mutex_unlock (&__go_thread_ids_lock);
+  __go_assert (i == 0);
+
+  runtime_MCache_ReleaseAll (mcache);
+
+  runtime_lock (&runtime_mheap);
+  mstats.heap_alloc += mcache->local_alloc;
+  mstats.heap_objects += mcache->local_objects;
+  __builtin_memset (mcache, 0, sizeof (struct MCache));
+  runtime_FixAlloc_Free (&runtime_mheap.cachealloc, mcache);
+  runtime_unlock (&runtime_mheap);
+
+  free (list_entry);
+}
+
+/* Start the thread.  */
+
+static void *
+start_go_thread (void *thread_arg)
+{
+  struct M *newm = (struct M *) thread_arg;
+  void (*pfn) (void *);
+  void *arg;
+  struct __go_thread_id *list_entry;
+  int i;
+
+#ifdef __rtems__
+  __wrap_rtems_task_variable_add ((void **) &m);
+  __wrap_rtems_task_variable_add ((void **) &__go_panic_defer);
+#endif
+
+  m = newm;
+
+  list_entry = newm->list_entry;
+
+  pfn = list_entry->pfn;
+  arg = list_entry->arg;
+
+#ifndef USING_SPLIT_STACK
+  /* If we don't support split stack, record the current stack as the
+     top of the stack.  There shouldn't be anything relevant to the
+     garbage collector above this point.  */
+  m->gc_sp = (void *) &arg;
+#endif
+
+  /* Finish up the entry on the thread list.  */
+
+  i = pthread_mutex_lock (&__go_thread_ids_lock);
+  __go_assert (i == 0);
+
+  list_entry->id = pthread_self ();
+  list_entry->pfn = NULL;
+  list_entry->arg = NULL;
+  list_entry->tentative = 0;
+
+  i = pthread_mutex_unlock (&__go_thread_ids_lock);
+  __go_assert (i == 0);
+
+  (*pfn) (arg);
+
+  remove_current_thread ();
+
+  return NULL;
+}
+
+/* The runtime.Goexit function.  */
+
+void Goexit (void) asm ("libgo_runtime.runtime.Goexit");
+
+void
+Goexit (void)
+{
+  remove_current_thread ();
+  pthread_exit (NULL);
+  abort ();
+}
+
+/* Implement the go statement.  */
+
+void
+__go_go (void (*pfn) (void*), void *arg)
+{
+  int i;
+  pthread_attr_t attr;
+  struct M *newm;
+  struct __go_thread_id *list_entry;
+  pthread_t tid;
+
+  i = pthread_attr_init (&attr);
+  __go_assert (i == 0);
+  i = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+  __go_assert (i == 0);
+
+#ifdef LINKER_SUPPORTS_SPLIT_STACK
+  /* The linker knows how to handle calls between code which uses
+     -fsplit-stack and code which does not.  That means that we can
+     run with a smaller stack and rely on the -fsplit-stack support to
+     save us.  The GNU/Linux glibc library won't let us have a very
+     small stack, but we make it as small as we can.  */
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN 8192
+#endif
+  i = pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
+  __go_assert (i == 0);
+#endif
+
+  newm = __go_alloc (sizeof (M));
+
+  list_entry = malloc (sizeof (struct __go_thread_id));
+  list_entry->prev = NULL;
+  list_entry->next = NULL;
+  list_entry->tentative = 1;
+  list_entry->m = newm;
+  list_entry->pfn = pfn;
+  list_entry->arg = arg;
+
+  newm->list_entry = list_entry;
+
+  /* Add the thread to the list of all threads, marked as tentative
+     since it is not yet ready to go.  */
+  i = pthread_mutex_lock (&__go_thread_ids_lock);
+  __go_assert (i == 0);
+
+  /* We use __go_thread_ids_lock as a lock for mheap.cachealloc.  */
+  newm->mcache = runtime_allocmcache ();
+
+  if (__go_all_thread_ids != NULL)
+    __go_all_thread_ids->prev = list_entry;
+  list_entry->next = __go_all_thread_ids;
+  __go_all_thread_ids = list_entry;
+
+  i = pthread_mutex_unlock (&__go_thread_ids_lock);
+  __go_assert (i == 0);
+
+  /* Start the thread.  */
+  i = pthread_create (&tid, &attr, start_go_thread, newm);
+  __go_assert (i == 0);
+
+  i = pthread_attr_destroy (&attr);
+  __go_assert (i == 0);
+}
+
+/* This is the signal handler for GO_SIG_START.  The garbage collector
+   will send this signal to a thread when it wants the thread to
+   start.  We don't have to actually do anything here, but we need a
+   signal handler since ignoring the signal will mean that the
+   sigsuspend will never see it.  */
+
+static void
+gc_start_handler (int sig __attribute__ ((unused)))
+{
+}
+
+/* Tell the garbage collector that we are ready, and wait for the
+   garbage collector to tell us that it is done.  This may be called
+   by a signal handler, so it is restricted to using functions which
+   are async cancel safe.  */
+
+static void
+stop_for_gc (void)
+{
+  int i;
+
+  /* Tell the garbage collector about our stack.  */
+#ifdef USING_SPLIT_STACK
+  m->gc_sp = __splitstack_find (NULL, NULL, &m->gc_len,
+                               &m->gc_next_segment, &m->gc_next_sp,
+                               &m->gc_initial_sp);
+#else
+  {
+    uintptr_t top = (uintptr_t) m->gc_sp;
+    uintptr_t bottom = (uintptr_t) &top;
+    if (top < bottom)
+      {
+       m->gc_next_sp = m->gc_sp;
+       m->gc_len = bottom - top;
+      }
+    else
+      {
+       m->gc_next_sp = (void *) bottom;
+       m->gc_len = top - bottom;
+      }
+  }
+#endif
+
+  /* FIXME: Perhaps we should just move __go_panic_defer into M.  */
+  m->gc_panic_defer = __go_panic_defer;
+
+  /* Tell the garbage collector that we are ready by posting to the
+     semaphore.  */
+  i = sem_post (&__go_thread_ready_sem);
+  __go_assert (i == 0);
+
+  /* Wait for the garbage collector to tell us to continue.  */
+  sigsuspend (&__go_thread_wait_sigset);
+}
+
+/* This is the signal handler for GO_SIG_STOP.  The garbage collector
+   will send this signal to a thread when it wants the thread to
+   stop.  */
+
+static void
+gc_stop_handler (int sig __attribute__ ((unused)))
+{
+  struct M *pm = m;
+
+  if (__sync_bool_compare_and_swap (&pm->mallocing, 1, 1))
+    {
+      /* m->mallocing was already non-zero.  We can't interrupt the
+        thread while it is running an malloc.  Instead, tell it to
+        call back to us when done.  */
+      __sync_bool_compare_and_swap (&pm->gcing, 0, 1);
+      return;
+    }
+
+  if (__sync_bool_compare_and_swap (&pm->nomemprof, 1, 1))
+    {
+      /* Similarly, we can't interrupt the thread while it is building
+        profiling information.  Otherwise we can get into a deadlock
+        when sweepspan calls MProf_Free.  */
+      __sync_bool_compare_and_swap (&pm->gcing_for_prof, 0, 1);
+      return;
+    }
+
+  stop_for_gc ();
+}
+
+/* This is called by malloc when it gets a signal during the malloc
+   call itself.  */
+
+int
+__go_run_goroutine_gc (int r)
+{
+  /* Force callee-saved registers to be saved on the stack.  This is
+     not needed if we are invoked from the signal handler, but it is
+     needed if we are called directly, since otherwise we might miss
+     something that a function somewhere up the call stack is holding
+     in a register.  */
+  SAVE_REGS;
+
+  stop_for_gc ();
+
+  /* This avoids tail recursion, to make sure that the saved registers
+     are on the stack.  */
+  return r;
+}
+
+/* Stop all the other threads for garbage collection.  */
+
+void
+runtime_stoptheworld (void)
+{
+  int i;
+  pthread_t me;
+  int c;
+  struct __go_thread_id *p;
+
+  i = pthread_mutex_lock (&__go_thread_ids_lock);
+  __go_assert (i == 0);
+
+  me = pthread_self ();
+  c = 0;
+  p = __go_all_thread_ids;
+  while (p != NULL)
+    {
+      if (p->tentative || pthread_equal (me, p->id))
+       p = p->next;
+      else
+       {
+         i = pthread_kill (p->id, GO_SIG_STOP);
+         if (i == 0)
+           {
+             ++c;
+             p = p->next;
+           }
+         else if (i == ESRCH)
+           {
+             struct __go_thread_id *next;
+
+             /* This thread died somehow.  Remove it from the
+                list.  */
+             next = p->next;
+             if (p->prev != NULL)
+               p->prev->next = next;
+             else
+               __go_all_thread_ids = next;
+             if (next != NULL)
+               next->prev = p->prev;
+             free (p);
+             p = next;
+           }
+         else
+           abort ();
+       }
+    }
+
+  /* Wait for each thread to receive the signal and post to the
+     semaphore.  If a thread receives the signal but contrives to die
+     before it posts to the semaphore, then we will hang forever
+     here.  */
+
+  while (c > 0)
+    {
+      i = sem_wait (&__go_thread_ready_sem);
+      if (i < 0 && errno == EINTR)
+       continue;
+      __go_assert (i == 0);
+      --c;
+    }
+
+  /* The gc_panic_defer field should now be set for all M's except the
+     one in this thread.  Set this one now.  */
+  m->gc_panic_defer = __go_panic_defer;
+
+  /* Leave with __go_thread_ids_lock held.  */
+}
+
+/* Scan all the stacks for garbage collection.  This should be called
+   with __go_thread_ids_lock held.  */
+
+void
+__go_scanstacks (void (*scan) (byte *, int64))
+{
+  pthread_t me;
+  struct __go_thread_id *p;
+
+  /* Make sure all the registers for this thread are on the stack.  */
+  SAVE_REGS;
+
+  me = pthread_self ();
+  for (p = __go_all_thread_ids; p != NULL; p = p->next)
+    {
+      if (p->tentative)
+       {
+         /* The goroutine function and argument can be allocated on
+            the heap, so we have to scan them for a thread that has
+            not yet started.  */
+         scan ((void *) &p->pfn, sizeof (void *));
+         scan ((void *) &p->arg, sizeof (void *));
+         scan ((void *) &p->m, sizeof (void *));
+         continue;
+       }
+
+#ifdef USING_SPLIT_STACK
+
+      void *sp;
+      size_t len;
+      void *next_segment;
+      void *next_sp;
+      void *initial_sp;
+
+      if (pthread_equal (me, p->id))
+       {
+         next_segment = NULL;
+         next_sp = NULL;
+         initial_sp = NULL;
+         sp = __splitstack_find (NULL, NULL, &len, &next_segment,
+                                 &next_sp, &initial_sp);
+       }
+      else
+       {
+         sp = p->m->gc_sp;
+         len = p->m->gc_len;
+         next_segment = p->m->gc_next_segment;
+         next_sp = p->m->gc_next_sp;
+         initial_sp = p->m->gc_initial_sp;
+       }
+
+      while (sp != NULL)
+       {
+         scan (sp, len);
+         sp = __splitstack_find (next_segment, next_sp, &len,
+                                 &next_segment, &next_sp, &initial_sp);
+       }
+
+#else /* !defined(USING_SPLIT_STACK) */
+
+      if (pthread_equal (me, p->id))
+       {
+         uintptr_t top = (uintptr_t) m->gc_sp;
+         uintptr_t bottom = (uintptr_t) &top;
+         if (top < bottom)
+           scan (m->gc_sp, bottom - top);
+         else
+           scan ((void *) bottom, top - bottom);
+       }
+      else
+       {
+         scan (p->m->gc_next_sp, p->m->gc_len);
+       }
+       
+#endif /* !defined(USING_SPLIT_STACK) */
+
+      /* Also scan the M structure while we're at it.  */
+
+      scan ((void *) &p->m, sizeof (void *));
+    }
+}
+
+/* Release all the memory caches.  This is called with
+   __go_thread_ids_lock held.  */
+
+void
+__go_stealcache (void)
+{
+  struct __go_thread_id *p;
+
+  for (p = __go_all_thread_ids; p != NULL; p = p->next)
+    runtime_MCache_ReleaseAll (p->m->mcache);
+}
+
+/* Gather memory cache statistics.  This is called with
+   __go_thread_ids_lock held.  */
+
+void
+__go_cachestats (void)
+{
+  struct __go_thread_id *p;
+
+  for (p = __go_all_thread_ids; p != NULL; p = p->next)
+    {
+      MCache *c;
+
+      c = p->m->mcache;
+      mstats.heap_alloc += c->local_alloc;
+      c->local_alloc = 0;
+      mstats.heap_objects += c->local_objects;
+      c->local_objects = 0;
+    }
+}
+
+/* Start the other threads after garbage collection.  */
+
+void
+runtime_starttheworld (void)
+{
+  int i;
+  pthread_t me;
+  struct __go_thread_id *p;
+
+  /* Here __go_thread_ids_lock should be held.  */
+
+  me = pthread_self ();
+  p = __go_all_thread_ids;
+  while (p != NULL)
+    {
+      if (p->tentative || pthread_equal (me, p->id))
+       p = p->next;
+      else
+       {
+         i = pthread_kill (p->id, GO_SIG_START);
+         if (i == 0)
+           p = p->next;
+         else
+           abort ();
+       }
+    }
+
+  i = pthread_mutex_unlock (&__go_thread_ids_lock);
+  __go_assert (i == 0);
+}
+
+/* Initialize the interaction between goroutines and the garbage
+   collector.  */
+
+void
+__go_gc_goroutine_init (void *sp __attribute__ ((unused)))
+{
+  struct __go_thread_id *list_entry;
+  int i;
+  sigset_t sset;
+  struct sigaction act;
+
+  /* Add the initial thread to the list of all threads.  */
+
+  list_entry = malloc (sizeof (struct __go_thread_id));
+  list_entry->prev = NULL;
+  list_entry->next = NULL;
+  list_entry->tentative = 0;
+  list_entry->id = pthread_self ();
+  list_entry->m = m;
+  list_entry->pfn = NULL;
+  list_entry->arg = NULL;
+  __go_all_thread_ids = list_entry;
+
+  /* Initialize the semaphore which signals when threads are ready for
+     GC.  */
+
+  i = sem_init (&__go_thread_ready_sem, 0, 0);
+  __go_assert (i == 0);
+
+  /* Fetch the current signal mask.  */
+
+  i = sigemptyset (&sset);
+  __go_assert (i == 0);
+  i = sigprocmask (SIG_BLOCK, NULL, &sset);
+  __go_assert (i == 0);
+
+  /* Make sure that GO_SIG_START is not blocked and GO_SIG_STOP is
+     blocked, and save that set for use with later calls to sigsuspend
+     while waiting for GC to complete.  */
+
+  i = sigdelset (&sset, GO_SIG_START);
+  __go_assert (i == 0);
+  i = sigaddset (&sset, GO_SIG_STOP);
+  __go_assert (i == 0);
+  __go_thread_wait_sigset = sset;
+
+  /* Block SIG_SET_START and unblock SIG_SET_STOP, and use that for
+     the process signal mask.  */
+
+  i = sigaddset (&sset, GO_SIG_START);
+  __go_assert (i == 0);
+  i = sigdelset (&sset, GO_SIG_STOP);
+  __go_assert (i == 0);
+  i = sigprocmask (SIG_SETMASK, &sset, NULL);
+  __go_assert (i == 0);
+
+  /* Install the signal handlers.  */
+  memset (&act, 0, sizeof act);
+  i = sigemptyset (&act.sa_mask);
+  __go_assert (i == 0);
+
+  act.sa_handler = gc_start_handler;
+  act.sa_flags = SA_RESTART;
+  i = sigaction (GO_SIG_START, &act, NULL);
+  __go_assert (i == 0);
+
+  /* We could consider using an alternate signal stack for this.  The
+     function does not use much stack space, so it may be OK.  */
+  act.sa_handler = gc_stop_handler;
+  i = sigaction (GO_SIG_STOP, &act, NULL);
+  __go_assert (i == 0);
+
+#ifndef USING_SPLIT_STACK
+  /* If we don't support split stack, record the current stack as the
+     top of the stack.  */
+  m->gc_sp = sp;
+#endif
+}
diff --git a/libgo/runtime/go-gomaxprocs.c b/libgo/runtime/go-gomaxprocs.c
new file mode 100644 (file)
index 0000000..04dc448
--- /dev/null
@@ -0,0 +1,15 @@
+/* go-gomaxprocs.c -- runtime.GOMAXPROCS.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+/* This is the runtime.GOMAXPROCS function.  This currently does
+   nothing, since each goroutine runs in a separate thread anyhow.  */
+
+void GOMAXPROCS (int) asm ("libgo_runtime.runtime.GOMAXPROCS");
+
+void
+GOMAXPROCS (int n __attribute__ ((unused)))
+{
+}
diff --git a/libgo/runtime/go-int-array-to-string.c b/libgo/runtime/go-int-array-to-string.c
new file mode 100644 (file)
index 0000000..46a33da
--- /dev/null
@@ -0,0 +1,85 @@
+/* go-int-array-to-string.c -- convert an array of ints to a string in Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-assert.h"
+#include "go-string.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_int_array_to_string (const void* p, size_t len)
+{
+  const int *ints;
+  size_t slen;
+  size_t i;
+  unsigned char *retdata;
+  struct __go_string ret;
+  unsigned char *s;
+
+  ints = (const int *) p;
+
+  slen = 0;
+  for (i = 0; i < len; ++i)
+    {
+      int v;
+
+      v = ints[i];
+
+      if (v > 0x10ffff)
+       v = 0xfffd;
+
+      if (v <= 0x7f)
+       slen += 1;
+      else if (v <= 0x7ff)
+       slen += 2;
+      else if (v <= 0xffff)
+       slen += 3;
+      else
+       slen += 4;
+    }
+
+  retdata = runtime_mallocgc (slen, RefNoPointers, 1, 0);
+  ret.__data = retdata;
+  ret.__length = slen;
+
+  s = retdata;
+  for (i = 0; i < len; ++i)
+    {
+      int v;
+
+      v = ints[i];
+
+      /* If V is out of range for UTF-8, substitute the replacement
+        character.  */
+      if (v > 0x10ffff)
+       v = 0xfffd;
+
+      if (v <= 0x7f)
+       *s++ = v;
+      else if (v <= 0x7ff)
+       {
+         *s++ = 0xc0 | ((v >> 6) & 0x1f);
+         *s++ = 0x80 | (v & 0x3f);
+       }
+      else if (v <= 0xffff)
+       {
+         *s++ = 0xe0 | ((v >> 12) & 0xf);
+         *s++ = 0x80 | ((v >> 6) & 0x3f);
+         *s++ = 0x80 | (v & 0x3f);
+       }
+      else
+       {
+         *s++ = 0xf0 | ((v >> 18) & 0x7);
+         *s++ = 0x80 | ((v >> 12) & 0x3f);
+         *s++ = 0x80 | ((v >> 6) & 0x3f);
+         *s++ = 0x80 | (v & 0x3f);
+       }
+    }
+
+  __go_assert ((size_t) (s - retdata) == slen);
+
+  return ret;
+}
diff --git a/libgo/runtime/go-int-to-string.c b/libgo/runtime/go-int-to-string.c
new file mode 100644 (file)
index 0000000..24d729c
--- /dev/null
@@ -0,0 +1,60 @@
+/* go-int-to-string.c -- convert an integer to a string in Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-string.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_int_to_string (int v)
+{
+  char buf[4];
+  int len;
+  unsigned char *retdata;
+  struct __go_string ret;
+
+  if (v <= 0x7f)
+    {
+      buf[0] = v;
+      len = 1;
+    }
+  else if (v <= 0x7ff)
+    {
+      buf[0] = 0xc0 + (v >> 6);
+      buf[1] = 0x80 + (v & 0x3f);
+      len = 2;
+    }
+  else
+    {
+      /* If the value is out of range for UTF-8, turn it into the
+        "replacement character".  */
+      if (v > 0x10ffff)
+       v = 0xfffd;
+
+      if (v <= 0xffff)
+       {
+         buf[0] = 0xe0 + (v >> 12);
+         buf[1] = 0x80 + ((v >> 6) & 0x3f);
+         buf[2] = 0x80 + (v & 0x3f);
+         len = 3;
+       }
+      else
+       {
+         buf[0] = 0xf0 + (v >> 18);
+         buf[1] = 0x80 + ((v >> 12) & 0x3f);
+         buf[2] = 0x80 + ((v >> 6) & 0x3f);
+         buf[3] = 0x80 + (v & 0x3f);
+         len = 4;
+       }
+    }
+
+  retdata = runtime_mallocgc (len, RefNoPointers, 1, 0);
+  __builtin_memcpy (retdata, buf, len);
+  ret.__data = retdata;
+  ret.__length = len;
+
+  return ret;
+}
diff --git a/libgo/runtime/go-interface-compare.c b/libgo/runtime/go-interface-compare.c
new file mode 100644 (file)
index 0000000..11c75e8
--- /dev/null
@@ -0,0 +1,31 @@
+/* go-interface-compare.c -- compare two interface values.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "interface.h"
+
+/* Compare two interface values.  Return 0 for equal, not zero for not
+   equal (return value is like strcmp).  */
+
+int
+__go_interface_compare (struct __go_interface left,
+                       struct __go_interface right)
+{
+  const struct __go_type_descriptor *left_descriptor;
+
+  if (left.__methods == NULL && right.__methods == NULL)
+    return 0;
+  if (left.__methods == NULL || right.__methods == NULL)
+    return 1;
+  left_descriptor = left.__methods[0];
+  if (!__go_type_descriptors_equal (left_descriptor, right.__methods[0]))
+    return 1;
+  if (__go_is_pointer_type (left_descriptor))
+    return left.__object == right.__object ? 0 : 1;
+  if (!left_descriptor->__equalfn (left.__object, right.__object,
+                                  left_descriptor->__size))
+    return 1;
+  return 0;
+}
diff --git a/libgo/runtime/go-interface-val-compare.c b/libgo/runtime/go-interface-val-compare.c
new file mode 100644 (file)
index 0000000..1589892
--- /dev/null
@@ -0,0 +1,32 @@
+/* go-interface-val-compare.c -- compare an interface to a value.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-type.h"
+#include "interface.h"
+
+/* Compare two interface values.  Return 0 for equal, not zero for not
+   equal (return value is like strcmp).  */
+
+int
+__go_interface_value_compare (
+    struct __go_interface left,
+    const struct __go_type_descriptor *right_descriptor,
+    const void *val)
+{
+  const struct __go_type_descriptor *left_descriptor;
+
+  if (left.__methods == NULL)
+    return 1;
+  left_descriptor = left.__methods[0];
+  if (!__go_type_descriptors_equal (left_descriptor, right_descriptor))
+    return 1;
+  if (__go_is_pointer_type (left_descriptor))
+    return left.__object == val ? 0 : 1;
+  if (!left_descriptor->__equalfn (left.__object, val,
+                                  left_descriptor->__size))
+    return 1;
+  return 0;
+}
diff --git a/libgo/runtime/go-lock-os-thread.c b/libgo/runtime/go-lock-os-thread.c
new file mode 100644 (file)
index 0000000..204f11d
--- /dev/null
@@ -0,0 +1,24 @@
+/* go-lock-os-thread.c -- the LockOSThread and UnlockOSThread functions.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+/* The runtime.LockOSThread and runtime.UnlockOSThread functions are
+   meaningless in the current implementation, since for us a goroutine
+   always stays on a single OS thread.  */
+
+extern void LockOSThread (void) __asm__ ("libgo_runtime.runtime.LockOSThread");
+
+void
+LockOSThread (void)
+{
+}
+
+extern void UnlockOSThread (void)
+  __asm__ ("libgo_runtime.runtime.UnlockOSThread");
+
+void
+UnlockOSThread (void)
+{
+}
diff --git a/libgo/runtime/go-main.c b/libgo/runtime/go-main.c
new file mode 100644 (file)
index 0000000..a6dbf34
--- /dev/null
@@ -0,0 +1,89 @@
+/* go-main.c -- the main function for a Go program.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef HAVE_FPU_CONTROL_H
+#include <fpu_control.h>
+#endif
+
+#include "go-alloc.h"
+#include "array.h"
+#include "go-signal.h"
+#include "go-string.h"
+
+#include "runtime.h"
+#include "malloc.h"
+
+#undef int
+#undef char
+#undef unsigned
+
+/* The main function for a Go program.  This records the command line
+   parameters, calls the real main function, and returns a zero status
+   if the real main function returns.  */
+
+extern char **environ;
+
+extern struct __go_open_array Args asm ("libgo_os.os.Args");
+
+extern struct __go_open_array Envs asm ("libgo_os.os.Envs");
+
+/* These functions are created for the main package.  */
+extern void __go_init_main (void);
+extern void real_main (void) asm ("main.main");
+
+/* The main function.  */
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  struct __go_string *values;
+
+  runtime_mallocinit ();
+  __go_gc_goroutine_init (&argc);
+
+  Args.__count = argc;
+  Args.__capacity = argc;
+  values = __go_alloc (argc * sizeof (struct __go_string));
+  for (i = 0; i < argc; ++i)
+    {
+      values[i].__data = (unsigned char *) argv[i];
+      values[i].__length = __builtin_strlen (argv[i]);
+    }
+  Args.__values = values;
+
+  for (i = 0; environ[i] != NULL; ++i)
+    ;
+  Envs.__count = i;
+  Envs.__capacity = i;
+  values = __go_alloc (i * sizeof (struct __go_string));
+  for (i = 0; environ[i] != NULL; ++i)
+    {
+      values[i].__data = (unsigned char *) environ[i];
+      values[i].__length = __builtin_strlen (environ[i]);
+    }
+  Envs.__values = values;
+
+  __initsig ();
+
+#if defined(HAVE_SRANDOM)
+  srandom ((unsigned int) time (NULL));
+#else
+  srand ((unsigned int) time (NULL));
+#endif
+  __go_init_main ();
+
+  __go_enable_gc ();
+
+  real_main ();
+
+  return 0;
+}
diff --git a/libgo/runtime/go-map-delete.c b/libgo/runtime/go-map-delete.c
new file mode 100644 (file)
index 0000000..ec851e5
--- /dev/null
@@ -0,0 +1,52 @@
+/* go-map-delete.c -- delete an entry from a map.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "map.h"
+
+/* Delete the entry matching KEY from MAP.  */
+
+void
+__go_map_delete (struct __go_map *map, const void *key)
+{
+  const struct __go_map_descriptor *descriptor;
+  const struct __go_type_descriptor *key_descriptor;
+  size_t key_offset;
+  _Bool (*equalfn) (const void*, const void*, size_t);
+  size_t key_hash;
+  size_t key_size;
+  size_t bucket_index;
+  void **pentry;
+
+  descriptor = map->__descriptor;
+
+  key_descriptor = descriptor->__map_descriptor->__key_type;
+  key_offset = descriptor->__key_offset;
+  key_size = key_descriptor->__size;
+  __go_assert (key_size != 0 && key_size != -1UL);
+  equalfn = key_descriptor->__equalfn;
+
+  key_hash = key_descriptor->__hashfn (key, key_size);
+  bucket_index = key_hash % map->__bucket_count;
+
+  pentry = map->__buckets + bucket_index;
+  while (*pentry != NULL)
+    {
+      char *entry = (char *) *pentry;
+      if (equalfn (key, entry + key_offset, key_size))
+       {
+         *pentry = *(void **) entry;
+         __go_free (entry);
+         map->__element_count -= 1;
+         break;
+       }
+      pentry = (void **) entry;
+    }
+}
diff --git a/libgo/runtime/go-map-index.c b/libgo/runtime/go-map-index.c
new file mode 100644 (file)
index 0000000..1561c97
--- /dev/null
@@ -0,0 +1,127 @@
+/* go-map-index.c -- find or insert an entry in a map.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "map.h"
+
+/* Rehash MAP to a larger size.  */
+
+static void
+__go_map_rehash (struct __go_map *map)
+{
+  const struct __go_map_descriptor *descriptor;
+  const struct __go_type_descriptor *key_descriptor;
+  size_t key_offset;
+  size_t key_size;
+  size_t (*hashfn) (const void *, size_t);
+  size_t old_bucket_count;
+  void **old_buckets;
+  size_t new_bucket_count;
+  void **new_buckets;
+  size_t i;
+
+  descriptor = map->__descriptor;
+
+  key_descriptor = descriptor->__map_descriptor->__key_type;
+  key_offset = descriptor->__key_offset;
+  key_size = key_descriptor->__size;
+  hashfn = key_descriptor->__hashfn;
+
+  old_bucket_count = map->__bucket_count;
+  old_buckets = map->__buckets;
+
+  new_bucket_count = __go_map_next_prime (old_bucket_count * 2);
+  new_buckets = (void **) __go_alloc (new_bucket_count * sizeof (void *));
+  __builtin_memset (new_buckets, 0, new_bucket_count * sizeof (void *));
+
+  for (i = 0; i < old_bucket_count; ++i)
+    {
+      char* entry;
+      char* next;
+
+      for (entry = old_buckets[i]; entry != NULL; entry = next)
+       {
+         size_t key_hash;
+         size_t new_bucket_index;
+
+         /* We could speed up rehashing at the cost of memory space
+            by caching the hash code.  */
+         key_hash = hashfn (entry + key_offset, key_size);
+         new_bucket_index = key_hash % new_bucket_count;
+
+         next = *(char **) entry;
+         *(char **) entry = new_buckets[new_bucket_index];
+         new_buckets[new_bucket_index] = entry;
+       }
+    }
+
+  __go_free (old_buckets);
+
+  map->__bucket_count = new_bucket_count;
+  map->__buckets = new_buckets;
+}
+
+/* Find KEY in MAP, return a pointer to the value.  If KEY is not
+   present, then if INSERT is false, return NULL, and if INSERT is
+   true, insert a new value and zero-initialize it before returning a
+   pointer to it.  */
+
+void *
+__go_map_index (struct __go_map *map, const void *key, _Bool insert)
+{
+  const struct __go_map_descriptor *descriptor;
+  const struct __go_type_descriptor *key_descriptor;
+  size_t key_offset;
+  _Bool (*equalfn) (const void*, const void*, size_t);
+  size_t key_hash;
+  size_t key_size;
+  size_t bucket_index;
+  char *entry;
+
+  descriptor = map->__descriptor;
+
+  key_descriptor = descriptor->__map_descriptor->__key_type;
+  key_offset = descriptor->__key_offset;
+  key_size = key_descriptor->__size;
+  __go_assert (key_size != 0 && key_size != -1UL);
+  equalfn = key_descriptor->__equalfn;
+
+  key_hash = key_descriptor->__hashfn (key, key_size);
+  bucket_index = key_hash % map->__bucket_count;
+
+  entry = (char *) map->__buckets[bucket_index];
+  while (entry != NULL)
+    {
+      if (equalfn (key, entry + key_offset, key_size))
+       return entry + descriptor->__val_offset;
+      entry = *(char **) entry;
+    }
+
+  if (!insert)
+    return NULL;
+
+  if (map->__element_count >= map->__bucket_count)
+    {
+      __go_map_rehash (map);
+      bucket_index = key_hash % map->__bucket_count;
+    }
+
+  entry = (char *) __go_alloc (descriptor->__entry_size);
+  __builtin_memset (entry, 0, descriptor->__entry_size);
+
+  __builtin_memcpy (entry + key_offset, key, key_size);
+
+  *(char **) entry = map->__buckets[bucket_index];
+  map->__buckets[bucket_index] = entry;
+
+  map->__element_count += 1;
+
+  return entry + descriptor->__val_offset;
+}
diff --git a/libgo/runtime/go-map-len.c b/libgo/runtime/go-map-len.c
new file mode 100644 (file)
index 0000000..75b7473
--- /dev/null
@@ -0,0 +1,21 @@
+/* go-map-len.c -- return the length of a map.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "map.h"
+
+/* Return the length of a map.  This could be done inline, of course,
+   but I'm doing it as a function for now to make it easy to chang the
+   map structure.  */
+
+size_t
+__go_map_len (struct __go_map *map)
+{
+  if (map == NULL)
+    return 0;
+  return map->__element_count;
+}
diff --git a/libgo/runtime/go-map-range.c b/libgo/runtime/go-map-range.c
new file mode 100644 (file)
index 0000000..364cda9
--- /dev/null
@@ -0,0 +1,102 @@
+/* go-map-range.c -- implement a range clause over a map.
+
+   Copyright 2009, 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-assert.h"
+#include "map.h"
+
+/* Initialize a range over a map.  */
+
+void
+__go_mapiterinit (const struct __go_map *h, struct __go_hash_iter *it)
+{
+  it->entry = NULL;
+  if (h != NULL)
+    {
+      it->map = h;
+      it->next_entry = NULL;
+      it->bucket = 0;
+      --it->bucket;
+      __go_mapiternext(it);
+    }
+}
+
+/* Move to the next iteration, updating *HITER.  */
+
+void
+__go_mapiternext (struct __go_hash_iter *it)
+{
+  const void *entry;
+
+  entry = it->next_entry;
+  if (entry == NULL)
+    {
+      const struct __go_map *map;
+      size_t bucket;
+
+      map = it->map;
+      bucket = it->bucket;
+      while (1)
+       {
+         ++bucket;
+         if (bucket >= map->__bucket_count)
+           {
+             /* Map iteration is complete.  */
+             it->entry = NULL;
+             return;
+           }
+         entry = map->__buckets[bucket];
+         if (entry != NULL)
+           break;
+       }
+      it->bucket = bucket;
+    }
+  it->entry = entry;
+  it->next_entry = *(const void * const *) entry;
+}
+
+/* Get the key of the current iteration.  */
+
+void
+__go_mapiter1 (struct __go_hash_iter *it, unsigned char *key)
+{
+  const struct __go_map *map;
+  const struct __go_map_descriptor *descriptor;
+  const struct __go_type_descriptor *key_descriptor;
+  const char *p;
+
+  map = it->map;
+  descriptor = map->__descriptor;
+  key_descriptor = descriptor->__map_descriptor->__key_type;
+  p = it->entry;
+  __go_assert (p != NULL);
+  __builtin_memcpy (key, p + descriptor->__key_offset, key_descriptor->__size);
+}
+
+/* Get the key and value of the current iteration.  */
+
+void
+__go_mapiter2 (struct __go_hash_iter *it, unsigned char *key,
+              unsigned char *val)
+{
+  const struct __go_map *map;
+  const struct __go_map_descriptor *descriptor;
+  const struct __go_map_type *map_descriptor;
+  const struct __go_type_descriptor *key_descriptor;
+  const struct __go_type_descriptor *val_descriptor;
+  const char *p;
+
+  map = it->map;
+  descriptor = map->__descriptor;
+  map_descriptor = descriptor->__map_descriptor;
+  key_descriptor = map_descriptor->__key_type;
+  val_descriptor = map_descriptor->__val_type;
+  p = it->entry;
+  __go_assert (p != NULL);
+  __builtin_memcpy (key, p + descriptor->__key_offset,
+                   key_descriptor->__size);
+  __builtin_memcpy (val, p + descriptor->__val_offset,
+                   val_descriptor->__size);
+}
diff --git a/libgo/runtime/go-nanotime.c b/libgo/runtime/go-nanotime.c
new file mode 100644 (file)
index 0000000..8cd4230
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Return time in nanoseconds.  This is only used for computing runtime.
+
+#include <sys/time.h>
+
+#include "go-assert.h"
+#include "runtime.h"
+
+int64
+runtime_nanotime (void)
+{
+  int i;
+  struct timeval tv;
+
+  i = gettimeofday (&tv, NULL);
+  __go_assert (i == 0);
+
+  return (int64) tv.tv_sec * 1000000000 + (int64) tv.tv_usec * 1000;
+}
diff --git a/libgo/runtime/go-new-channel.c b/libgo/runtime/go-new-channel.c
new file mode 100644 (file)
index 0000000..d57f52c
--- /dev/null
@@ -0,0 +1,57 @@
+/* go-new-channel.c -- allocate a new channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+struct __go_channel*
+__go_new_channel (size_t element_size, size_t entries)
+{
+  struct __go_channel* ret;
+  size_t alloc_size;
+  int i;
+
+  if ((size_t) (int) entries != entries || entries > (size_t) -1 / element_size)
+    __go_panic_msg ("chan size out of range");
+
+  alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t);
+
+  /* We use a circular buffer which means that when next_fetch ==
+     next_store we don't know whether the buffer is empty or full.  So
+     we allocate an extra space, and always leave a space open.
+     FIXME.  */
+  if (entries != 0)
+    ++entries;
+
+  ret = (struct __go_channel*) __go_alloc (sizeof (struct __go_channel)
+                                          + ((entries == 0 ? 1 : entries)
+                                             * alloc_size
+                                             * sizeof (uint64_t)));
+  i = pthread_mutex_init (&ret->lock, NULL);
+  __go_assert (i == 0);
+  i = pthread_cond_init (&ret->cond, NULL);
+  __go_assert (i == 0);
+  ret->element_size = element_size;
+  ret->closed_op_count = 0;
+  ret->waiting_to_send = 0;
+  ret->waiting_to_receive = 0;
+  ret->selected_for_send = 0;
+  ret->selected_for_receive = 0;
+  ret->is_closed = 0;
+  ret->saw_close = 0;
+  ret->select_send_queue = NULL;
+  ret->select_receive_queue = NULL;
+  ret->select_mutex = NULL;
+  ret->select_cond = NULL;
+  ret->num_entries = entries;
+  ret->next_store = 0;
+  ret->next_fetch = 0;
+  return ret;
+}
diff --git a/libgo/runtime/go-new-map.c b/libgo/runtime/go-new-map.c
new file mode 100644 (file)
index 0000000..8ea6c71
--- /dev/null
@@ -0,0 +1,125 @@
+/* go-new-map.c -- allocate a new map.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-alloc.h"
+#include "go-panic.h"
+#include "map.h"
+
+/* List of prime numbers, copied from libstdc++/src/hashtable.c.  */
+
+static const unsigned long prime_list[] = /* 256 + 1 or 256 + 48 + 1 */
+{
+  2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul,
+  37ul, 41ul, 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul,
+  83ul, 89ul, 97ul, 103ul, 109ul, 113ul, 127ul, 137ul, 139ul, 149ul,
+  157ul, 167ul, 179ul, 193ul, 199ul, 211ul, 227ul, 241ul, 257ul,
+  277ul, 293ul, 313ul, 337ul, 359ul, 383ul, 409ul, 439ul, 467ul,
+  503ul, 541ul, 577ul, 619ul, 661ul, 709ul, 761ul, 823ul, 887ul,
+  953ul, 1031ul, 1109ul, 1193ul, 1289ul, 1381ul, 1493ul, 1613ul,
+  1741ul, 1879ul, 2029ul, 2179ul, 2357ul, 2549ul, 2753ul, 2971ul,
+  3209ul, 3469ul, 3739ul, 4027ul, 4349ul, 4703ul, 5087ul, 5503ul,
+  5953ul, 6427ul, 6949ul, 7517ul, 8123ul, 8783ul, 9497ul, 10273ul,
+  11113ul, 12011ul, 12983ul, 14033ul, 15173ul, 16411ul, 17749ul,
+  19183ul, 20753ul, 22447ul, 24281ul, 26267ul, 28411ul, 30727ul,
+  33223ul, 35933ul, 38873ul, 42043ul, 45481ul, 49201ul, 53201ul,
+  57557ul, 62233ul, 67307ul, 72817ul, 78779ul, 85229ul, 92203ul,
+  99733ul, 107897ul, 116731ul, 126271ul, 136607ul, 147793ul,
+  159871ul, 172933ul, 187091ul, 202409ul, 218971ul, 236897ul,
+  256279ul, 277261ul, 299951ul, 324503ul, 351061ul, 379787ul,
+  410857ul, 444487ul, 480881ul, 520241ul, 562841ul, 608903ul,
+  658753ul, 712697ul, 771049ul, 834181ul, 902483ul, 976369ul,
+  1056323ul, 1142821ul, 1236397ul, 1337629ul, 1447153ul, 1565659ul,
+  1693859ul, 1832561ul, 1982627ul, 2144977ul, 2320627ul, 2510653ul,
+  2716249ul, 2938679ul, 3179303ul, 3439651ul, 3721303ul, 4026031ul,
+  4355707ul, 4712381ul, 5098259ul, 5515729ul, 5967347ul, 6456007ul,
+  6984629ul, 7556579ul, 8175383ul, 8844859ul, 9569143ul, 10352717ul,
+  11200489ul, 12117689ul, 13109983ul, 14183539ul, 15345007ul,
+  16601593ul, 17961079ul, 19431899ul, 21023161ul, 22744717ul,
+  24607243ul, 26622317ul, 28802401ul, 31160981ul, 33712729ul,
+  36473443ul, 39460231ul, 42691603ul, 46187573ul, 49969847ul,
+  54061849ul, 58488943ul, 63278561ul, 68460391ul, 74066549ul,
+  80131819ul, 86693767ul, 93793069ul, 101473717ul, 109783337ul,
+  118773397ul, 128499677ul, 139022417ul, 150406843ul, 162723577ul,
+  176048909ul, 190465427ul, 206062531ul, 222936881ul, 241193053ul,
+  260944219ul, 282312799ul, 305431229ul, 330442829ul, 357502601ul,
+  386778277ul, 418451333ul, 452718089ul, 489790921ul, 529899637ul,
+  573292817ul, 620239453ul, 671030513ul, 725980837ul, 785430967ul,
+  849749479ul, 919334987ul, 994618837ul, 1076067617ul, 1164186217ul,
+  1259520799ul, 1362662261ul, 1474249943ul, 1594975441ul, 1725587117ul,
+  1866894511ul, 2019773507ul, 2185171673ul, 2364114217ul, 2557710269ul,
+  2767159799ul, 2993761039ul, 3238918481ul, 3504151727ul, 3791104843ul,
+  4101556399ul, 4294967291ul,
+#if __SIZEOF_LONG__ >= 8
+  6442450933ul, 8589934583ul, 12884901857ul, 17179869143ul,
+  25769803693ul, 34359738337ul, 51539607367ul, 68719476731ul,
+  103079215087ul, 137438953447ul, 206158430123ul, 274877906899ul,
+  412316860387ul, 549755813881ul, 824633720731ul, 1099511627689ul,
+  1649267441579ul, 2199023255531ul, 3298534883309ul, 4398046511093ul,
+  6597069766607ul, 8796093022151ul, 13194139533241ul, 17592186044399ul,
+  26388279066581ul, 35184372088777ul, 52776558133177ul, 70368744177643ul,
+  105553116266399ul, 140737488355213ul, 211106232532861ul, 281474976710597ul,
+  562949953421231ul, 1125899906842597ul, 2251799813685119ul,
+  4503599627370449ul, 9007199254740881ul, 18014398509481951ul,
+  36028797018963913ul, 72057594037927931ul, 144115188075855859ul,
+  288230376151711717ul, 576460752303423433ul,
+  1152921504606846883ul, 2305843009213693951ul,
+  4611686018427387847ul, 9223372036854775783ul,
+  18446744073709551557ul
+#endif
+};
+
+/* Return the next number from PRIME_LIST >= N.  */
+
+unsigned long
+__go_map_next_prime (unsigned long n)
+{
+  size_t low;
+  size_t high;
+
+  low = 0;
+  high = sizeof prime_list / sizeof prime_list[0];
+  while (low < high)
+    {
+      size_t mid;
+
+      mid = (low + high / 2);
+
+      /* Here LOW <= MID < HIGH.  */
+
+      if (prime_list[mid] < n)
+       high = mid;
+      else if (prime_list[mid] > n)
+       low = mid + 1;
+      else
+       return n;
+    }
+  if (low >= sizeof prime_list / sizeof prime_list[0])
+    return n;
+  return prime_list[low];
+}
+
+/* Allocate a new map.  */
+
+struct __go_map *
+__go_new_map (const struct __go_map_descriptor *descriptor, size_t entries)
+{
+  struct __go_map *ret;
+
+  if ((size_t) (int) entries != entries)
+    __go_panic_msg ("map size out of range");
+
+  if (entries == 0)
+    entries = 5;
+  else
+    entries = __go_map_next_prime (entries);
+  ret = (struct __go_map *) __go_alloc (sizeof (struct __go_map));
+  ret->__descriptor = descriptor;
+  ret->__element_count = 0;
+  ret->__bucket_count = entries;
+  ret->__buckets = (void **) __go_alloc (entries * sizeof (void *));
+  __builtin_memset (ret->__buckets, 0, entries * sizeof (void *));
+  return ret;
+}
diff --git a/libgo/runtime/go-new.c b/libgo/runtime/go-new.c
new file mode 100644 (file)
index 0000000..e673d14
--- /dev/null
@@ -0,0 +1,21 @@
+/* go-new.c -- the generic go new() function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-alloc.h"
+#include "runtime.h"
+#include "malloc.h"
+
+void *
+__go_new (size_t size)
+{
+  return __go_alloc (size);
+}
+
+void *
+__go_new_nopointers (size_t size)
+{
+  return runtime_mallocgc (size, RefNoPointers, 1, 1);
+}
diff --git a/libgo/runtime/go-note.c b/libgo/runtime/go-note.c
new file mode 100644 (file)
index 0000000..3b750f3
--- /dev/null
@@ -0,0 +1,74 @@
+/* go-note.c -- implement notesleep, notewakeup and noteclear.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+/* A note is a one-time notification.  noteclear clears the note.
+   notesleep waits for a call to notewakeup.  notewakeup wakes up
+   every thread waiting on the note.  */
+
+#include "go-assert.h"
+#include "runtime.h"
+
+/* We use a single global lock and condition variable.  It would be
+   better to use a futex on Linux.  */
+
+static pthread_mutex_t note_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t note_cond = PTHREAD_COND_INITIALIZER;
+
+/* noteclear is called before any calls to notesleep or
+   notewakeup.  */
+
+void
+noteclear (Note* n)
+{
+  int32 i;
+
+  i = pthread_mutex_lock (&note_lock);
+  __go_assert (i == 0);
+
+  n->woken = 0;
+
+  i = pthread_mutex_unlock (&note_lock);
+  __go_assert (i == 0);
+}
+
+/* Wait until notewakeup is called.  */
+
+void
+notesleep (Note* n)
+{
+  int32 i;
+
+  i = pthread_mutex_lock (&note_lock);
+  __go_assert (i == 0);
+
+  while (!n->woken)
+    {
+      i = pthread_cond_wait (&note_cond, &note_lock);
+      __go_assert (i == 0);
+    }
+
+  i = pthread_mutex_unlock (&note_lock);
+  __go_assert (i == 0);
+}
+
+/* Wake up every thread sleeping on the note.  */
+
+void
+notewakeup (Note *n)
+{
+  int32 i;
+
+  i = pthread_mutex_lock (&note_lock);
+  __go_assert (i == 0);
+
+  n->woken = 1;
+
+  i = pthread_cond_broadcast (&note_cond);
+  __go_assert (i == 0);
+
+  i = pthread_mutex_unlock (&note_lock);
+  __go_assert (i == 0);
+}
diff --git a/libgo/runtime/go-panic-defer.c b/libgo/runtime/go-panic-defer.c
new file mode 100644 (file)
index 0000000..64773bb
--- /dev/null
@@ -0,0 +1,13 @@
+/* go-panic-stack.c -- The panic/defer stack.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-panic.h"
+
+#ifdef __rtems__
+#define __thread
+#endif
+
+__thread struct __go_panic_defer_struct *__go_panic_defer;
diff --git a/libgo/runtime/go-panic.c b/libgo/runtime/go-panic.c
new file mode 100644 (file)
index 0000000..48d6441
--- /dev/null
@@ -0,0 +1,121 @@
+/* go-panic.c -- support for the go panic function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "runtime.h"
+#include "malloc.h"
+#include "go-alloc.h"
+#include "go-defer.h"
+#include "go-panic.h"
+#include "go-string.h"
+#include "interface.h"
+
+/* Print the panic stack.  This is used when there is no recover.  */
+
+static void
+__printpanics (struct __go_panic_stack *p)
+{
+  if (p->__next != NULL)
+    {
+      __printpanics (p->__next);
+      printf ("\t");
+    }
+  printf ("panic: ");
+  printany (p->__arg);
+  if (p->__was_recovered)
+    printf (" [recovered]");
+  putchar ('\n');
+}
+
+/* This implements __go_panic which is used for the panic
+   function.  */
+
+void
+__go_panic (struct __go_empty_interface arg)
+{
+  struct __go_panic_stack *n;
+
+  if (__go_panic_defer == NULL)
+    __go_panic_defer = ((struct __go_panic_defer_struct *)
+                       __go_alloc (sizeof (struct __go_panic_defer_struct)));
+
+  n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack));
+  n->__arg = arg;
+  n->__next = __go_panic_defer->__panic;
+  __go_panic_defer->__panic = n;
+
+  /* Run all the defer functions.  */
+
+  while (1)
+    {
+      struct __go_defer_stack *d;
+      void (*pfn) (void *);
+
+      d = __go_panic_defer->__defer;
+      if (d == NULL)
+       break;
+
+      pfn = d->__pfn;
+      d->__pfn = NULL;
+
+      if (pfn != NULL)
+       {
+         (*pfn) (d->__arg);
+
+         if (n->__was_recovered)
+           {
+             /* Some defer function called recover.  That means that
+                we should stop running this panic.  */
+
+             __go_panic_defer->__panic = n->__next;
+             __go_free (n);
+
+             /* Now unwind the stack by throwing an exception.  The
+                compiler has arranged to create exception handlers in
+                each function which uses a defer statement.  These
+                exception handlers will check whether the entry on
+                the top of the defer stack is from the current
+                function.  If it is, we have unwound the stack far
+                enough.  */
+             __go_unwind_stack ();
+
+             /* __go_unwind_stack should not return.  */
+             abort ();
+           }
+       }
+
+      __go_panic_defer->__defer = d->__next;
+      __go_free (d);
+    }
+
+  /* The panic was not recovered.  */
+
+  __printpanics (__go_panic_defer->__panic);
+
+  /* FIXME: We should dump a call stack here.  */
+  abort ();
+}
+
+/* This is used by the runtime library.  */
+
+void
+__go_panic_msg (const char* msg)
+{
+  size_t len;
+  unsigned char *sdata;
+  struct __go_string s;
+  struct __go_empty_interface arg;
+
+  len = __builtin_strlen (msg);
+  sdata = runtime_mallocgc (len, RefNoPointers, 0, 0);
+  __builtin_memcpy (sdata, msg, len);
+  s.__data = sdata;
+  s.__length = len;
+  newErrorString(s, &arg);
+  __go_panic (arg);
+}
diff --git a/libgo/runtime/go-panic.h b/libgo/runtime/go-panic.h
new file mode 100644 (file)
index 0000000..2836c46
--- /dev/null
@@ -0,0 +1,94 @@
+/* go-panic.h -- declare the go panic functions.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#ifndef LIBGO_GO_PANIC_H
+#define LIBGO_GO_PANIC_H
+
+#include "interface.h"
+
+struct __go_string;
+struct __go_type_descriptor;
+struct __go_defer_stack;
+
+/* The stack of panic calls.  */
+
+struct __go_panic_stack
+{
+  /* The next entry in the stack.  */
+  struct __go_panic_stack *__next;
+
+  /* The value associated with this panic.  */
+  struct __go_empty_interface __arg;
+
+  /* Whether this panic has been recovered.  */
+  _Bool __was_recovered;
+
+  /* Whether this panic was pushed on the stack because of an
+     exception thrown in some other language.  */
+  _Bool __is_foreign;
+};
+
+/* The panic and defer stacks, grouped together into a single thread
+   local variable for convenience for systems without TLS.  */
+
+struct __go_panic_defer_struct
+{
+  /* The list of defers to execute.  */
+  struct __go_defer_stack *__defer;
+
+  /* The list of currently active panics.  There will be more than one
+     if a deferred function calls panic.  */
+  struct __go_panic_stack *__panic;
+
+  /* The current exception being thrown when unwinding after a call to
+     panic .  This is really struct _UnwindException *.  */
+  void *__exception;
+
+  /* Whether the current exception is from some other language.  */
+  _Bool __is_foreign;
+};
+
+#ifdef __rtems__
+#define __thread
+#endif
+
+extern __thread struct __go_panic_defer_struct *__go_panic_defer;
+
+#ifdef __rtems__
+#undef __thread
+#endif
+
+extern void __go_panic (struct __go_empty_interface)
+  __attribute__ ((noreturn));
+
+extern void __go_panic_msg (const char* msg)
+  __attribute__ ((noreturn));
+
+extern void __go_print_string (struct __go_string);
+
+extern struct __go_empty_interface __go_recover (void);
+
+extern void __go_unwind_stack (void);
+
+/* Functions defined in libgo/go/runtime/error.go.  */
+
+extern void newTypeAssertionError(const struct __go_type_descriptor *pt1,
+                                 const struct __go_type_descriptor *pt2,
+                                 const struct __go_type_descriptor *pt3,
+                                 const struct __go_string *ps1,
+                                 const struct __go_string *ps2,
+                                 const struct __go_string *ps3,
+                                 const struct __go_string *pmeth,
+                                 struct __go_empty_interface *ret)
+  __asm__ ("libgo_runtime.runtime.NewTypeAssertionError");
+
+extern void newErrorString(struct __go_string, struct __go_empty_interface *)
+  __asm__ ("libgo_runtime.runtime.NewErrorString");
+
+extern void printany(struct __go_empty_interface)
+  __asm__ ("libgo_runtime.runtime.Printany");
+
+#endif /* !defined(LIBGO_GO_PANIC_H) */
diff --git a/libgo/runtime/go-print.c b/libgo/runtime/go-print.c
new file mode 100644 (file)
index 0000000..095909d
--- /dev/null
@@ -0,0 +1,93 @@
+/* go-print.c -- support for the go print statement.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "array.h"
+#include "go-panic.h"
+#include "go-string.h"
+#include "interface.h"
+
+/* This implements the various little functions which are called by
+   the predeclared functions print/println/panic/panicln.  */
+
+void
+__go_print_space ()
+{
+  putchar (' ');
+}
+
+void
+__go_print_nl ()
+{
+  putchar ('\n');
+}
+
+void
+__go_print_string (struct __go_string val)
+{
+  printf ("%.*s", (int) val.__length, (const char *) val.__data);
+}
+
+void
+__go_print_uint64 (uint64_t val)
+{
+  printf ("%llu", (unsigned long long) val);
+}
+
+void
+__go_print_int64 (int64_t val)
+{
+  printf ("%lld", (long long) val);
+}
+
+void
+__go_print_double (double val)
+{
+  printf ("%.24g", val);
+}
+
+void
+__go_print_complex (__complex double val)
+{
+  printf ("(%.24g%s%.24gi)",
+         __builtin_creal (val),
+         (__builtin_cimag (val) >= 0 || __builtin_isnan (__builtin_cimag(val))
+          ? "+"
+          : ""),
+         __builtin_cimag (val));
+}
+
+void
+__go_print_bool (_Bool val)
+{
+  fputs (val ? "true" : "false", stdout);
+}
+
+void
+__go_print_pointer (void *val)
+{
+  printf ("%p", val);
+}
+
+void
+__go_print_empty_interface (struct __go_empty_interface e)
+{
+  printf ("(%p,%p)", e.__type_descriptor, e.__object);
+}
+
+void
+__go_print_interface (struct __go_interface i)
+{
+  printf ("(%p,%p)", i.__methods, i.__object);
+}
+
+void
+__go_print_slice (struct __go_open_array val)
+{
+  printf ("[%d/%d]%p", val.__count, val.__capacity, val.__values);
+}
diff --git a/libgo/runtime/go-rec-big.c b/libgo/runtime/go-rec-big.c
new file mode 100644 (file)
index 0000000..23d6529
--- /dev/null
@@ -0,0 +1,34 @@
+/* go-rec-big.c -- receive something larger than 64 bits on a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+#include "go-panic.h"
+#include "channel.h"
+
+void
+__go_receive_big (struct __go_channel *channel, void *val, _Bool for_select)
+{
+  size_t alloc_size;
+  size_t offset;
+
+  if (channel == NULL)
+    __go_panic_msg ("receive from nil channel");
+
+  alloc_size = ((channel->element_size + sizeof (uint64_t) - 1)
+               / sizeof (uint64_t));
+
+  if (!__go_receive_acquire (channel, for_select))
+    {
+      __builtin_memset (val, 0, channel->element_size);
+      return;
+    }
+
+  offset = channel->next_fetch * alloc_size;
+  __builtin_memcpy (val, &channel->data[offset], channel->element_size);
+
+  __go_receive_release (channel);
+}
diff --git a/libgo/runtime/go-rec-nb-big.c b/libgo/runtime/go-rec-nb-big.c
new file mode 100644 (file)
index 0000000..53ffe48
--- /dev/null
@@ -0,0 +1,39 @@
+/* go-rec-nb-big.c -- nonblocking receive of something big on a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+#include "channel.h"
+
+_Bool
+__go_receive_nonblocking_big (struct __go_channel* channel, void *val)
+{
+  size_t alloc_size;
+  size_t offset;
+
+  alloc_size = ((channel->element_size + sizeof (uint64_t) - 1)
+               / sizeof (uint64_t));
+
+  int data = __go_receive_nonblocking_acquire (channel);
+  if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA)
+    {
+      __builtin_memset (val, 0, channel->element_size);
+      if (data == RECEIVE_NONBLOCKING_ACQUIRE_NODATA)
+       return 0;
+      else
+       {
+         /* Channel is closed.  */
+         return 1;
+       }
+    }
+
+  offset = channel->next_fetch * alloc_size;
+  __builtin_memcpy (val, &channel->data[offset], channel->element_size);
+
+  __go_receive_release (channel);
+
+  return 1;
+}
diff --git a/libgo/runtime/go-rec-nb-small.c b/libgo/runtime/go-rec-nb-small.c
new file mode 100644 (file)
index 0000000..9983d34
--- /dev/null
@@ -0,0 +1,127 @@
+/* go-rec-nb-small.c -- nonblocking receive of something smal on a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+/* Prepare to receive something on a nonblocking channel.  */
+
+int
+__go_receive_nonblocking_acquire (struct __go_channel *channel)
+{
+  int i;
+  _Bool has_data;
+
+  i = pthread_mutex_lock (&channel->lock);
+  __go_assert (i == 0);
+
+  while (channel->selected_for_receive)
+    {
+      i = pthread_cond_wait (&channel->cond, &channel->lock);
+      __go_assert (i == 0);
+    }
+
+  if (channel->is_closed
+      && (channel->num_entries == 0
+         ? channel->next_store == 0
+         : channel->next_fetch == channel->next_store))
+    {
+      if (channel->saw_close)
+       {
+         ++channel->closed_op_count;
+         if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
+           {
+             i = pthread_mutex_unlock (&channel->lock);
+             __go_assert (i == 0);
+             __go_panic_msg ("too many operations on closed channel");
+           }
+       }
+      channel->saw_close = 1;
+      __go_unlock_and_notify_selects (channel);
+      return RECEIVE_NONBLOCKING_ACQUIRE_CLOSED;
+    }
+
+  if (channel->num_entries > 0)
+    has_data = channel->next_fetch != channel->next_store;
+  else
+    {
+      if (channel->waiting_to_receive)
+       {
+         /* Some other goroutine is already waiting for data on this
+            channel, so we can't pick it up.  */
+         has_data = 0;
+       }
+      else if (channel->next_store > 0)
+       {
+         /* There is data on the channel.  */
+         has_data = 1;
+       }
+      else if (__go_synch_with_select (channel, 0))
+       {
+         /* We synched up with a select sending data, so there will
+            be data for us shortly.  Tell the select to go, and then
+            wait for the data.  */
+         __go_broadcast_to_select (channel);
+
+         while (channel->next_store == 0)
+           {
+             i = pthread_cond_wait (&channel->cond, &channel->lock);
+             __go_assert (i == 0);
+           }
+
+         has_data = 1;
+       }
+      else
+       {
+         /* Otherwise there is no data.  */
+         has_data = 0;
+       }
+
+      if (has_data)
+       {
+         channel->waiting_to_receive = 1;
+         __go_assert (channel->next_store == 1);
+       }
+    }
+
+  if (!has_data)
+    {
+      i = pthread_mutex_unlock (&channel->lock);
+      __go_assert (i == 0);
+      return RECEIVE_NONBLOCKING_ACQUIRE_NODATA;
+    }
+
+  return RECEIVE_NONBLOCKING_ACQUIRE_DATA;
+}
+
+/* Receive something 64 bits or smaller on a nonblocking channel.  */
+
+struct __go_receive_nonblocking_small
+__go_receive_nonblocking_small (struct __go_channel *channel)
+{
+  struct __go_receive_nonblocking_small ret;
+
+  __go_assert (channel->element_size <= sizeof (uint64_t));
+
+  int data = __go_receive_nonblocking_acquire (channel);
+  if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA)
+    {
+      ret.__val = 0;
+      ret.__success = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED;
+      return ret;
+    }
+
+  ret.__val = channel->data[channel->next_fetch];
+
+  __go_receive_release (channel);
+
+  ret.__success = 1;
+
+  return ret;
+}
diff --git a/libgo/runtime/go-rec-small.c b/libgo/runtime/go-rec-small.c
new file mode 100644 (file)
index 0000000..765e8d3
--- /dev/null
@@ -0,0 +1,289 @@
+/* go-rec-small.c -- receive something smaller than 64 bits on a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+/* This mutex controls access to the selected field of struct
+   __go_channel_select.  While this mutex is held, no other mutexes
+   may be acquired.  */
+
+pthread_mutex_t __go_select_data_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Try to synchronize with a select waiting on a sychronized channel.
+   This is used by a send or receive.  The channel is locked.  This
+   returns true if it was able to synch.  */
+
+_Bool
+__go_synch_with_select (struct __go_channel *channel, _Bool is_send)
+{
+  struct __go_channel_select *p;
+  int i;
+
+  __go_assert (channel->num_entries == 0);
+
+  i = pthread_mutex_lock (&__go_select_data_mutex);
+  __go_assert (i == 0);
+
+  for (p = (is_send
+           ? channel->select_receive_queue
+           : channel->select_send_queue);
+       p != NULL;
+       p = p->next)
+    {
+      if (*p->selected == NULL)
+       {
+         *p->selected = channel;
+         *p->is_read = !is_send;
+         if (is_send)
+           channel->selected_for_receive = 1;
+         else
+           channel->selected_for_send = 1;
+         break;
+       }
+    }
+
+  i = pthread_mutex_unlock (&__go_select_data_mutex);
+  __go_assert (i == 0);
+
+  /* The caller is responsible for signalling the select condition
+     variable so that the other select knows that something has
+     changed.  We can't signal it here because we can't acquire the
+     select mutex while we hold a channel lock.  */
+
+  return p != NULL;
+}
+
+/* If we synch with a select, then we need to signal the select that
+   something has changed.  This requires grabbing the select mutex,
+   which can only be done when the channel is unlocked.  This routine
+   does the signalling.  It is called with the channel locked.  It
+   unlocks the channel, broadcasts the signal and relocks the
+   channel.  */
+
+void
+__go_broadcast_to_select (struct __go_channel *channel)
+{
+  pthread_mutex_t *select_mutex;
+  pthread_cond_t *select_cond;
+  int i;
+
+  select_mutex = channel->select_mutex;
+  select_cond = channel->select_cond;
+
+  i = pthread_mutex_unlock (&channel->lock);
+  __go_assert (i == 0);
+
+  __go_assert (select_mutex != NULL && select_cond != NULL);
+
+  i = pthread_mutex_lock (select_mutex);
+  __go_assert (i == 0);
+
+  i = pthread_cond_broadcast (select_cond);
+  __go_assert (i == 0);
+
+  i = pthread_mutex_unlock (select_mutex);
+  __go_assert (i == 0);
+
+  i = pthread_mutex_lock (&channel->lock);
+  __go_assert (i == 0);
+}
+
+/* Prepare to receive something on a channel.  Return true if the
+   channel is acquired, false if it is closed.  */
+
+_Bool
+__go_receive_acquire (struct __go_channel *channel, _Bool for_select)
+{
+  int i;
+  _Bool my_wait_lock;
+  _Bool synched_with_select;
+
+  my_wait_lock = 0;
+  synched_with_select = 0;
+
+  i = pthread_mutex_lock (&channel->lock);
+  __go_assert (i == 0);
+
+  while (1)
+    {
+      _Bool need_broadcast;
+
+      need_broadcast = 0;
+
+      /* Check whether the channel is closed.  */
+      if (channel->is_closed
+         && (channel->num_entries == 0
+             ? channel->next_store == 0
+             : channel->next_fetch == channel->next_store))
+       {
+         if (channel->saw_close)
+           {
+             ++channel->closed_op_count;
+             if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
+               __go_panic_msg ("too many operations on closed channel");
+           }
+         channel->saw_close = 1;
+         channel->selected_for_receive = 0;
+         __go_unlock_and_notify_selects (channel);
+         return 0;
+       }
+
+      /* If somebody else has the channel locked for receiving, we
+        have to wait.  If FOR_SELECT is true, then we are the one
+        with the lock.  */
+      if (!channel->selected_for_receive || for_select)
+       {
+         if (channel->num_entries == 0)
+           {
+             /* If somebody else is waiting to receive, we have to
+                wait.  */
+             if (!channel->waiting_to_receive || my_wait_lock)
+               {
+                 _Bool was_marked;
+
+                 /* Lock the channel so that we get to receive
+                    next.  */
+                 was_marked = channel->waiting_to_receive;
+                 channel->waiting_to_receive = 1;
+                 my_wait_lock = 1;
+
+                 /* See if there is a value to receive.  */
+                 if (channel->next_store > 0)
+                   return 1;
+
+                 /* If we haven't already done so, try to synch with
+                    a select waiting to send on this channel.  If we
+                    have already synched with a select, we are just
+                    looping until the select eventually causes
+                    something to be sent.  */
+                 if (!synched_with_select && !for_select)
+                   {
+                     if (__go_synch_with_select (channel, 0))
+                       {
+                         synched_with_select = 1;
+                         need_broadcast = 1;
+                       }
+                   }
+
+                 /* If we marked the channel as waiting, we need to
+                    signal, because something changed.  It needs to
+                    be a broadcast since there might be other
+                    receivers waiting.  */
+                 if (!was_marked)
+                   {
+                     i = pthread_cond_broadcast (&channel->cond);
+                     __go_assert (i == 0);
+                   }
+               }
+           }
+         else
+           {
+             /* If there is a value on the channel, we are OK.  */
+             if (channel->next_fetch != channel->next_store)
+               return 1;
+           }
+       }
+
+      /* If we just synched with a select, then we need to signal the
+        select condition variable.  We can only do that if we unlock
+        the channel.  So we need to unlock, signal, lock, and go
+        around the loop again without waiting.  */
+      if (need_broadcast)
+       {
+         __go_broadcast_to_select (channel);
+         continue;
+       }
+
+      /* Wait for something to change, then loop around and try
+        again.  */
+
+      i = pthread_cond_wait (&channel->cond, &channel->lock);
+      __go_assert (i == 0);
+    }
+}
+
+/* Finished receiving something on a channel.  */
+
+void
+__go_receive_release (struct __go_channel *channel)
+{
+  int i;
+
+  if (channel->num_entries != 0)
+    channel->next_fetch = (channel->next_fetch + 1) % channel->num_entries;
+  else
+    {
+      /* For a synchronous receiver, we tell the sender that we picked
+        up the value by setting the next_store field back to 0.
+        Using the mutexes should implement a memory barrier.  */
+      __go_assert (channel->next_store == 1);
+      channel->next_store = 0;
+
+      channel->waiting_to_receive = 0;
+    }
+
+  channel->selected_for_receive = 0;
+
+  /* This is a broadcast to make sure that a synchronous sender sees
+     it.  */
+  i = pthread_cond_broadcast (&channel->cond);
+  __go_assert (i == 0);
+
+  __go_unlock_and_notify_selects (channel);
+}
+
+/* Unlock a channel and notify any waiting selects that something
+   happened.  */
+
+void
+__go_unlock_and_notify_selects (struct __go_channel *channel)
+{
+  pthread_mutex_t* select_mutex;
+  pthread_cond_t* select_cond;
+  int i;
+
+  select_mutex = channel->select_mutex;
+  select_cond = channel->select_cond;
+
+  i = pthread_mutex_unlock (&channel->lock);
+  __go_assert (i == 0);
+
+  if (select_mutex != NULL)
+    {
+      i = pthread_mutex_lock (select_mutex);
+      __go_assert (i == 0);
+      i = pthread_cond_broadcast (select_cond);
+      __go_assert (i == 0);
+      i = pthread_mutex_unlock (select_mutex);
+      __go_assert (i == 0);
+    }
+}
+
+/* Receive something 64 bits or smaller on a channel.  */
+
+uint64_t
+__go_receive_small (struct __go_channel *channel, _Bool for_select)
+{
+  uint64_t ret;
+
+  if (channel == NULL)
+    __go_panic_msg ("receive from nil channel");
+
+  __go_assert (channel->element_size <= sizeof (uint64_t));
+
+  if (!__go_receive_acquire (channel, for_select))
+    return 0;
+
+  ret = channel->data[channel->next_fetch];
+
+  __go_receive_release (channel);
+
+  return ret;
+}
diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c
new file mode 100644 (file)
index 0000000..4de122e
--- /dev/null
@@ -0,0 +1,69 @@
+/* go-recover.c -- support for the go recover function.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "interface.h"
+#include "go-panic.h"
+#include "go-defer.h"
+
+/* This is called by a thunk to see if the real function should be
+   permitted to recover a panic value.  Recovering a value is
+   permitted if the thunk was called directly by defer.  RETADDR is
+   the return address of the function which is calling
+   __go_can_recover--this is, the thunk.  */
+
+_Bool
+__go_can_recover (const void* retaddr)
+{
+  struct __go_defer_stack *d;
+  const char* ret;
+  const char* dret;
+
+  if (__go_panic_defer == NULL)
+    return 0;
+  d = __go_panic_defer->__defer;
+  if (d == NULL)
+    return 0;
+
+  /* The panic which this function would recover is the one on the top
+     of the panic stack.  We do not want to recover it if that panic
+     was on the top of the panic stack when this function was
+     deferred.  */
+  if (d->__panic == __go_panic_defer->__panic)
+    return 0;
+
+  /* D->__RETADDR is the address of a label immediately following the
+     call to the thunk.  We can recover a panic if that is the same as
+     the return address of the thunk.  We permit a bit of slack in
+     case there is any code between the function return and the label,
+     such as an instruction to adjust the stack pointer.  */
+
+  ret = (const char *) retaddr;
+  dret = (const char *) d->__retaddr;
+  return ret <= dret && ret + 16 >= dret;
+}
+
+/* This is only called when it is valid for the caller to recover the
+   value on top of the panic stack, if there is one.  */
+
+struct __go_empty_interface
+__go_recover ()
+{
+  struct __go_panic_stack *p;
+
+  if (__go_panic_defer == NULL
+      || __go_panic_defer->__panic == NULL
+      || __go_panic_defer->__panic->__was_recovered)
+    {
+      struct __go_empty_interface ret;
+
+      ret.__type_descriptor = NULL;
+      ret.__object = NULL;
+      return ret;
+    }
+  p = __go_panic_defer->__panic;
+  p->__was_recovered = 1;
+  return p->__arg;
+}
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c
new file mode 100644 (file)
index 0000000..610fabf
--- /dev/null
@@ -0,0 +1,358 @@
+/* go-reflect-call.c -- call reflection support for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ffi.h"
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "go-type.h"
+#include "runtime.h"
+
+/* Forward declaration.  */
+
+static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *);
+
+/* Return an ffi_type for a Go array type.  The libffi library does
+   not have any builtin support for passing arrays as values.  We work
+   around this by pretending that the array is a struct.  */
+
+static ffi_type *
+go_array_to_ffi (const struct __go_array_type *descriptor)
+{
+  ffi_type *ret;
+  uintptr_t len;
+  ffi_type *element;
+  uintptr_t i;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  __builtin_memset (ret, 0, sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  len = descriptor->__len;
+  ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *));
+  element = go_type_to_ffi (descriptor->__element_type);
+  for (i = 0; i < len; ++i)
+    ret->elements[i] = element;
+  ret->elements[len] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a Go slice type.  This describes the
+   __go_open_array type defines in array.h.  */
+
+static ffi_type *
+go_slice_to_ffi (
+    const struct __go_slice_type *descriptor __attribute__ ((unused)))
+{
+  ffi_type *ret;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  __builtin_memset (ret, 0, sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *));
+  ret->elements[0] = &ffi_type_pointer;
+  ret->elements[1] = &ffi_type_sint;
+  ret->elements[2] = &ffi_type_sint;
+  ret->elements[3] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a Go struct type.  */
+
+static ffi_type *
+go_struct_to_ffi (const struct __go_struct_type *descriptor)
+{
+  ffi_type *ret;
+  int field_count;
+  const struct __go_struct_field *fields;
+  int i;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  __builtin_memset (ret, 0, sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  field_count = descriptor->__fields.__count;
+  fields = (const struct __go_struct_field *) descriptor->__fields.__values;
+  ret->elements = (ffi_type **) __go_alloc ((field_count + 1)
+                                           * sizeof (ffi_type *));
+  for (i = 0; i < field_count; ++i)
+    ret->elements[i] = go_type_to_ffi (fields[i].__type);
+  ret->elements[field_count] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a Go string type.  This describes the
+   __go_string struct.  */
+
+static ffi_type *
+go_string_to_ffi (void)
+{
+  ffi_type *ret;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+  ret->elements[0] = &ffi_type_pointer;
+  ret->elements[1] = &ffi_type_sint;
+  ret->elements[2] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a Go interface type.  This describes the
+   __go_interface and __go_empty_interface structs.  */
+
+static ffi_type *
+go_interface_to_ffi (void)
+{
+  ffi_type *ret;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+  ret->elements[0] = &ffi_type_pointer;
+  ret->elements[1] = &ffi_type_pointer;
+  ret->elements[2] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a type described by a
+   __go_type_descriptor.  */
+
+static ffi_type *
+go_type_to_ffi (const struct __go_type_descriptor *descriptor)
+{
+  switch (descriptor->__code)
+    {
+    case GO_BOOL:
+      if (sizeof (_Bool) == 1)
+       return &ffi_type_uint8;
+      else if (sizeof (_Bool) == sizeof (int))
+       return &ffi_type_uint;
+      abort ();
+    case GO_FLOAT32:
+      if (sizeof (float) == 4)
+       return &ffi_type_float;
+      abort ();
+    case GO_FLOAT64:
+      if (sizeof (double) == 8)
+       return &ffi_type_double;
+      abort ();
+    case GO_FLOAT:
+      return &ffi_type_float;
+    case GO_COMPLEX64:
+    case GO_COMPLEX128:
+    case GO_COMPLEX:
+      /* FIXME.  */
+      abort ();
+    case GO_INT16:
+      return &ffi_type_sint16;
+    case GO_INT32:
+      return &ffi_type_sint32;
+    case GO_INT64:
+      return &ffi_type_sint64;
+    case GO_INT8:
+      return &ffi_type_sint8;
+    case GO_INT:
+      return &ffi_type_sint;
+    case GO_UINT16:
+      return &ffi_type_uint16;
+    case GO_UINT32:
+      return &ffi_type_uint32;
+    case GO_UINT64:
+      return &ffi_type_uint64;
+    case GO_UINT8:
+      return &ffi_type_uint8;
+    case GO_UINT:
+      return &ffi_type_uint;
+    case GO_UINTPTR:
+      if (sizeof (void *) == 2)
+       return &ffi_type_uint16;
+      else if (sizeof (void *) == 4)
+       return &ffi_type_uint32;
+      else if (sizeof (void *) == 8)
+       return &ffi_type_uint64;
+      abort ();
+    case GO_ARRAY:
+      return go_array_to_ffi ((const struct __go_array_type *) descriptor);
+    case GO_SLICE:
+      return go_slice_to_ffi ((const struct __go_slice_type *) descriptor);
+    case GO_STRUCT:
+      return go_struct_to_ffi ((const struct __go_struct_type *) descriptor);
+    case GO_STRING:
+      return go_string_to_ffi ();
+    case GO_INTERFACE:
+      return go_interface_to_ffi ();
+    case GO_CHAN:
+    case GO_FUNC:
+    case GO_MAP:
+    case GO_PTR:
+    case GO_UNSAFE_POINTER:
+      /* These types are always pointers, and for FFI purposes nothing
+        else matters.  */
+      return &ffi_type_pointer;
+    default:
+      abort ();
+    }
+}
+
+/* Return the return type for a function, given the number of out
+   parameters and their types.  */
+
+static ffi_type *
+go_func_return_ffi (const struct __go_func_type *func)
+{
+  int count;
+  const struct __go_type_descriptor **types;
+  ffi_type *ret;
+  int i;
+
+  count = func->__out.__count;
+  if (count == 0)
+    return &ffi_type_void;
+
+  types = (const struct __go_type_descriptor **) func->__out.__values;
+
+  if (count == 1)
+    return go_type_to_ffi (types[0]);
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  __builtin_memset (ret, 0, sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *));
+  for (i = 0; i < count; ++i)
+    ret->elements[i] = go_type_to_ffi (types[i]);
+  ret->elements[count] = NULL;
+  return ret;
+}
+
+/* Build an ffi_cif structure for a function described by a
+   __go_func_type structure.  */
+
+static void
+go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
+               ffi_cif *cif)
+{
+  int num_params;
+  const struct __go_type_descriptor **in_types;
+  size_t num_args;
+  ffi_type **args;
+  int off;
+  int i;
+  ffi_type *rettype;
+  ffi_status status;
+
+  num_params = func->__in.__count;
+  in_types = ((const struct __go_type_descriptor **)
+             func->__in.__values);
+
+  num_args = num_params + (is_interface ? 1 : 0);
+  args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
+  if (is_interface)
+    args[0] = &ffi_type_pointer;
+  off = is_interface ? 1 : 0;
+  for (i = 0; i < num_params; ++i)
+    args[i + off] = go_type_to_ffi (in_types[i]);
+
+  rettype = go_func_return_ffi (func);
+
+  status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
+  __go_assert (status == FFI_OK);
+}
+
+/* Get the total size required for the result parameters of a
+   function.  */
+
+static size_t
+go_results_size (const struct __go_func_type *func)
+{
+  int count;
+  const struct __go_type_descriptor **types;
+  size_t off;
+  size_t maxalign;
+  int i;
+
+  count = func->__out.__count;
+  if (count == 0)
+    return 0;
+
+  types = (const struct __go_type_descriptor **) func->__out.__values;
+
+  off = 0;
+  maxalign = 0;
+  for (i = 0; i < count; ++i)
+    {
+      size_t align;
+
+      align = types[i]->__field_align;
+      if (align > maxalign)
+       maxalign = align;
+      off = (off + align - 1) & ~ (align - 1);
+      off += types[i]->__size;
+    }
+
+  off = (off + maxalign - 1) & ~ (maxalign - 1);
+
+  return off;
+}
+
+/* Copy the results of calling a function via FFI from CALL_RESULT
+   into the addresses in RESULTS.  */
+
+static void
+go_set_results (const struct __go_func_type *func, unsigned char *call_result,
+               void **results)
+{
+  int count;
+  const struct __go_type_descriptor **types;
+  size_t off;
+  int i;
+
+  count = func->__out.__count;
+  if (count == 0)
+    return;
+
+  types = (const struct __go_type_descriptor **) func->__out.__values;
+
+  off = 0;
+  for (i = 0; i < count; ++i)
+    {
+      size_t align;
+      size_t size;
+
+      align = types[i]->__field_align;
+      size = types[i]->__size;
+      off = (off + align - 1) & ~ (align - 1);
+      __builtin_memcpy (results[i], call_result + off, size);
+      off += size;
+    }
+}
+
+/* Call a function.  The type of the function is FUNC_TYPE, and the
+   address is FUNC_ADDR.  PARAMS is an array of parameter addresses.
+   RESULTS is an array of result addresses.  */
+
+void
+reflect_call (const struct __go_func_type *func_type, const void *func_addr,
+             _Bool is_interface, void **params, void **results)
+{
+  ffi_cif cif;
+  unsigned char *call_result;
+
+  __go_assert (func_type->__common.__code == GO_FUNC);
+  go_func_to_cif (func_type, is_interface, &cif);
+
+  call_result = (unsigned char *) malloc (go_results_size (func_type));
+
+  ffi_call (&cif, func_addr, call_result, params);
+
+  /* Some day we may need to free result values if RESULTS is
+     NULL.  */
+  if (results != NULL)
+    go_set_results (func_type, call_result, results);
+
+  free (call_result);
+}
diff --git a/libgo/runtime/go-reflect-chan.c b/libgo/runtime/go-reflect-chan.c
new file mode 100644 (file)
index 0000000..412cfee
--- /dev/null
@@ -0,0 +1,148 @@
+/* go-reflect-chan.c -- channel reflection support for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "config.h"
+#include "go-type.h"
+#include "channel.h"
+
+/* This file implements support for reflection on channels.  These
+   functions are called from reflect/value.go.  */
+
+extern unsigned char *makechan (const struct __go_type_descriptor *, uint32_t)
+  asm ("libgo_reflect.reflect.makechan");
+
+unsigned char *
+makechan (const struct __go_type_descriptor *typ, uint32_t size)
+{
+  return (unsigned char *) __go_new_channel (typ->__size, size);
+}
+
+extern void chansend (unsigned char *, unsigned char *, _Bool *)
+  asm ("libgo_reflect.reflect.chansend");
+
+void
+chansend (unsigned char *ch, unsigned char *val, _Bool *pres)
+{
+  struct __go_channel *channel = (struct __go_channel *) ch;
+
+  if (channel->element_size <= sizeof (uint64_t))
+    {
+      union
+      {
+       char b[sizeof (uint64_t)];
+       uint64_t v;
+      } u;
+
+      __builtin_memset (u.b, 0, sizeof (uint64_t));
+#ifndef WORDS_BIGENDIAN
+      __builtin_memcpy (u.b, val, channel->element_size);
+#else
+      __builtin_memcpy (u.b + sizeof (uint64_t) - channel->element_size, val,
+                       channel->element_size);
+#endif
+      if (pres == NULL)
+       __go_send_small (channel, u.v, 0);
+      else
+       *pres = __go_send_nonblocking_small (channel, u.v);
+    }
+  else
+    {
+      if (pres == NULL)
+       __go_send_big (channel, val, 0);
+      else
+       *pres = __go_send_nonblocking_big (channel, val);
+    }
+}
+
+extern void chanrecv (unsigned char *, unsigned char *, _Bool *)
+  asm ("libgo_reflect.reflect.chanrecv");
+
+void
+chanrecv (unsigned char *ch, unsigned char *val, _Bool *pres)
+{
+  struct __go_channel *channel = (struct __go_channel *) ch;
+
+  if (channel->element_size <= sizeof (uint64_t))
+    {
+      union
+      {
+       char b[sizeof (uint64_t)];
+       uint64_t v;
+      } u;
+
+      if (pres == NULL)
+       u.v = __go_receive_small (channel, 0);
+      else
+       {
+         struct __go_receive_nonblocking_small s;
+
+         s = __go_receive_nonblocking_small (channel);
+         *pres = s.__success;
+         if (!s.__success)
+           return;
+         u.v = s.__val;
+       }
+
+#ifndef WORDS_BIGENDIAN
+      __builtin_memcpy (val, u.b, channel->element_size);
+#else
+      __builtin_memcpy (val, u.b + sizeof (uint64_t) - channel->element_size,
+                       channel->element_size);
+#endif
+    }
+  else
+    {
+      if (pres == NULL)
+       __go_receive_big (channel, val, 0);
+      else
+       *pres = __go_receive_nonblocking_big (channel, val);
+    }
+}
+
+extern _Bool chanclosed (unsigned char *)
+  asm ("libgo_reflect.reflect.chanclosed");
+
+_Bool
+chanclosed (unsigned char *ch)
+{
+  struct __go_channel *channel = (struct __go_channel *) ch;
+
+  return __go_builtin_closed (channel);
+}
+
+extern void chanclose (unsigned char *)
+  asm ("libgo_reflect.reflect.chanclose");
+
+void
+chanclose (unsigned char *ch)
+{
+  struct __go_channel *channel = (struct __go_channel *) ch;
+
+  __go_builtin_close (channel);
+}
+
+extern int32_t chanlen (unsigned char *) asm ("libgo_reflect.reflect.chanlen");
+
+int32_t
+chanlen (unsigned char *ch)
+{
+  struct __go_channel *channel = (struct __go_channel *) ch;
+
+  return (int32_t) __go_chan_len (channel);
+}
+
+extern int32_t chancap (unsigned char *) asm ("libgo_reflect.reflect.chancap");
+
+int32_t
+chancap (unsigned char *ch)
+{
+  struct __go_channel *channel = (struct __go_channel *) ch;
+
+  return (int32_t) __go_chan_cap (channel);
+}
diff --git a/libgo/runtime/go-reflect-map.c b/libgo/runtime/go-reflect-map.c
new file mode 100644 (file)
index 0000000..67960de
--- /dev/null
@@ -0,0 +1,139 @@
+/* go-reflect-map.c -- map reflection support for Go.
+
+   Copyright 2009, 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "go-alloc.h"
+#include "go-type.h"
+#include "map.h"
+
+/* This file implements support for reflection on maps.  These
+   functions are called from reflect/value.go.  */
+
+extern _Bool mapaccess (unsigned char *, unsigned char *, unsigned char *)
+  asm ("libgo_reflect.reflect.mapaccess");
+
+_Bool
+mapaccess (unsigned char *m, unsigned char *key, unsigned char *val)
+{
+  struct __go_map *map = (struct __go_map *) m;
+  void *p;
+  const struct __go_type_descriptor *val_descriptor;
+
+  p = __go_map_index (map, key, 0);
+  if (p == NULL)
+    return 0;
+  else
+    {
+      val_descriptor = map->__descriptor->__map_descriptor->__val_type;
+      __builtin_memcpy (val, p, val_descriptor->__size);
+      return 1;
+    }
+}
+
+extern void mapassign (unsigned char *, unsigned char *, unsigned char *)
+  asm ("libgo_reflect.reflect.mapassign");
+
+void
+mapassign (unsigned char *m, unsigned char *key, unsigned char *val)
+{
+  struct __go_map *map = (struct __go_map *) m;
+
+  if (val == NULL)
+    __go_map_delete (map, key);
+  else
+    {
+      void *p;
+      const struct __go_type_descriptor *val_descriptor;
+
+      p = __go_map_index (map, key, 1);
+      val_descriptor = map->__descriptor->__map_descriptor->__val_type;
+      __builtin_memcpy (p, val, val_descriptor->__size);
+    }
+}
+
+extern int32_t maplen (unsigned char *)
+  asm ("libgo_reflect.reflect.maplen");
+
+int32_t
+maplen (unsigned char *m __attribute__ ((unused)))
+{
+  struct __go_map *map = (struct __go_map *) m;
+  return (int32_t) map->__element_count;
+}
+
+extern unsigned char *mapiterinit (unsigned char *)
+  asm ("libgo_reflect.reflect.mapiterinit");
+
+unsigned char *
+mapiterinit (unsigned char *m)
+{
+  struct __go_hash_iter *it;
+
+  it = __go_alloc (sizeof (struct __go_hash_iter));
+  __go_mapiterinit ((struct __go_map *) m, it);
+  return (unsigned char *) it;
+}
+
+extern void mapiternext (unsigned char *)
+  asm ("libgo_reflect.reflect.mapiternext");
+
+void
+mapiternext (unsigned char *it)
+{
+  __go_mapiternext ((struct __go_hash_iter *) it);
+}
+
+extern _Bool mapiterkey (unsigned char *, unsigned char *)
+  asm ("libgo_reflect.reflect.mapiterkey");
+
+_Bool
+mapiterkey (unsigned char *ita, unsigned char *key)
+{
+  struct __go_hash_iter *it = (struct __go_hash_iter *) ita;
+
+  if (it->entry == NULL)
+    return 0;
+  else
+    {
+      __go_mapiter1 (it, key);
+      return 1;
+    }
+}
+
+/* Make a new map.  We have to build our own map descriptor.  */
+
+extern unsigned char *makemap (const struct __go_map_type *)
+  asm ("libgo_reflect.reflect.makemap");
+
+unsigned char *
+makemap (const struct __go_map_type *t)
+{
+  struct __go_map_descriptor *md;
+  unsigned int o;
+  const struct __go_type_descriptor *kt;
+  const struct __go_type_descriptor *vt;
+
+  /* FIXME: Reference count.  */
+  md = (struct __go_map_descriptor *) __go_alloc (sizeof (*md));
+  md->__map_descriptor = t;
+  o = sizeof (void *);
+  kt = t->__key_type;
+  o = (o + kt->__field_align - 1) & ~ (kt->__field_align - 1);
+  md->__key_offset = o;
+  o += kt->__size;
+  vt = t->__val_type;
+  o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1);
+  md->__val_offset = o;
+  o += vt->__size;
+  o = (o + sizeof (void *) - 1) & ~ (sizeof (void *) - 1);
+  o = (o + kt->__field_align - 1) & ~ (kt->__field_align - 1);
+  o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1);
+  md->__entry_size = o;
+
+  return (unsigned char *) __go_new_map (md, 0);
+}
diff --git a/libgo/runtime/go-reflect.c b/libgo/runtime/go-reflect.c
new file mode 100644 (file)
index 0000000..e608df7
--- /dev/null
@@ -0,0 +1,188 @@
+/* go-reflect.c -- implement unsafe.Reflect and unsafe.Typeof for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "interface.h"
+#include "go-alloc.h"
+#include "go-panic.h"
+#include "go-string.h"
+#include "go-type.h"
+
+/* For field alignment.  */
+
+struct field_align
+{
+  char c;
+  struct __go_type_descriptor *p;
+};
+
+/* The type descriptors in the runtime package.  */
+
+extern const struct __go_type_descriptor ptr_bool_descriptor
+  asm ("__go_td_pN30_libgo_runtime.runtime.BoolType");
+extern const struct __go_type_descriptor ptr_float_descriptor
+  asm ("__go_td_pN31_libgo_runtime.runtime.FloatType");
+extern const struct __go_type_descriptor ptr_complex_descriptor
+  asm ("__go_td_pN33_libgo_runtime.runtime.ComplexType");
+extern const struct __go_type_descriptor ptr_int_descriptor
+  asm ("__go_td_pN29_libgo_runtime.runtime.IntType");
+extern const struct __go_type_descriptor ptr_uint_descriptor
+  asm ("__go_td_pN30_libgo_runtime.runtime.UintType");
+extern const struct __go_type_descriptor ptr_string_descriptor
+  asm ("__go_td_pN32_libgo_runtime.runtime.StringType");
+extern const struct __go_type_descriptor ptr_unsafe_pointer_decriptor
+  asm ("__go_td_pN39_libgo_runtime.runtime.UnsafePointerType");
+extern const struct __go_type_descriptor ptr_array_descriptor
+  asm ("__go_td_pN31_libgo_runtime.runtime.ArrayType");
+extern const struct __go_type_descriptor ptr_slice_descriptor
+  asm ("__go_td_pN31_libgo_runtime.runtime.SliceType");
+extern const struct __go_type_descriptor ptr_chan_descriptor
+  asm ("__go_td_pN30_libgo_runtime.runtime.ChanType");
+extern const struct __go_type_descriptor ptr_func_descriptor
+  asm ("__go_td_pN30_libgo_runtime.runtime.FuncType");
+extern const struct __go_type_descriptor ptr_interface_descriptor
+  asm ("__go_td_pN35_libgo_runtime.runtime.InterfaceType");
+extern const struct __go_type_descriptor ptr_map_descriptor
+  asm ("__go_td_pN29_libgo_runtime.runtime.MapType");
+extern const struct __go_type_descriptor ptr_ptr_descriptor
+  asm ("__go_td_pN29_libgo_runtime.runtime.PtrType");
+extern const struct __go_type_descriptor ptr_struct_descriptor
+  asm ("__go_td_pN32_libgo_runtime.runtime.StructType");
+
+const struct __go_type_descriptor *
+get_descriptor (int code)
+{
+  switch (code)
+    {
+    case GO_BOOL:
+      return &ptr_bool_descriptor;
+    case GO_FLOAT32:
+    case GO_FLOAT64:
+    case GO_FLOAT:
+      return &ptr_float_descriptor;
+    case GO_COMPLEX64:
+    case GO_COMPLEX128:
+    case GO_COMPLEX:
+      return &ptr_complex_descriptor;
+    case GO_INT16:
+    case GO_INT32:
+    case GO_INT64:
+    case GO_INT8:
+    case GO_INT:
+      return &ptr_int_descriptor;
+    case GO_UINT16:
+    case GO_UINT32:
+    case GO_UINT64:
+    case GO_UINT8:
+    case GO_UINTPTR:
+    case GO_UINT:
+      return &ptr_uint_descriptor;
+    case GO_STRING:
+      return &ptr_string_descriptor;
+    case GO_UNSAFE_POINTER:
+      return &ptr_unsafe_pointer_decriptor;
+    case GO_ARRAY:
+      return &ptr_array_descriptor;
+    case GO_SLICE:
+      return &ptr_slice_descriptor;
+    case GO_CHAN:
+      return &ptr_chan_descriptor;
+    case GO_FUNC:
+      return &ptr_func_descriptor;
+    case GO_INTERFACE:
+      return &ptr_interface_descriptor;
+    case GO_MAP:
+      return &ptr_map_descriptor;
+    case GO_PTR:
+      return &ptr_ptr_descriptor;
+    case GO_STRUCT:
+      return &ptr_struct_descriptor;
+    default:
+      abort ();
+    }
+}
+
+/* Implement unsafe.Reflect.  */
+
+struct reflect_ret
+{
+  struct __go_empty_interface rettype;
+  void *addr;
+};
+
+struct reflect_ret Reflect (struct __go_empty_interface)
+  asm ("libgo_unsafe.unsafe.Reflect");
+
+struct reflect_ret
+Reflect (struct __go_empty_interface e)
+{
+  struct reflect_ret ret;
+
+  if (e.__type_descriptor == NULL)
+    {
+      ret.rettype.__type_descriptor = NULL;
+      ret.rettype.__object = NULL;
+      ret.addr = NULL;
+    }
+  else
+    {
+      size_t size;
+
+      ret.rettype.__type_descriptor =
+       get_descriptor (e.__type_descriptor->__code);
+
+      /* This memcpy is really just an assignment of a const pointer
+        to a non-const pointer.  FIXME: We should canonicalize this
+        pointer, so that for a given type we always return the same
+        pointer.  */
+      __builtin_memcpy (&ret.rettype.__object, &e.__type_descriptor,
+                       sizeof (void *));
+
+      /* Make a copy of the value.  */
+      size = e.__type_descriptor->__size;
+      if (size <= sizeof (uint64_t))
+       ret.addr = __go_alloc (sizeof (uint64_t));
+      else
+       ret.addr = __go_alloc (size);
+      if (__go_is_pointer_type (e.__type_descriptor))
+       *(void **) ret.addr = e.__object;
+      else
+       __builtin_memcpy (ret.addr, e.__object, size);
+    }
+
+  return ret;
+}
+
+/* Implement unsafe.Typeof.  */
+
+struct __go_empty_interface Typeof (struct __go_empty_interface)
+  asm ("libgo_unsafe.unsafe.Typeof");
+
+struct __go_empty_interface
+Typeof (const struct __go_empty_interface e)
+{
+  struct __go_empty_interface ret;
+
+  if (e.__type_descriptor == NULL)
+    {
+      ret.__type_descriptor = NULL;
+      ret.__object = NULL;
+    }
+  else
+    {
+      ret.__type_descriptor = get_descriptor (e.__type_descriptor->__code);
+
+      /* This memcpy is really just an assignment of a const pointer
+        to a non-const pointer.  FIXME: We should canonicalize this
+        pointer, so that for a given type we always return the same
+        pointer.  */
+      __builtin_memcpy (&ret.__object, &e.__type_descriptor, sizeof (void *));
+    }
+
+  return ret;
+}
diff --git a/libgo/runtime/go-rune.c b/libgo/runtime/go-rune.c
new file mode 100644 (file)
index 0000000..7e31eb8
--- /dev/null
@@ -0,0 +1,77 @@
+/* go-rune.c -- rune functions for Go.
+
+   Copyright 2009, 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-string.h"
+
+/* Get a character from the UTF-8 string STR, of length LEN.  Store
+   the Unicode character, if any, in *RUNE.  Return the number of
+   characters used from STR.  */
+
+int
+__go_get_rune (const unsigned char *str, size_t len, int *rune)
+{
+  int c, c1, c2, c3;
+
+  /* Default to the "replacement character".  */
+  *rune = 0xfffd;
+
+  if (len <= 0)
+    return 1;
+
+  c = *str;
+  if (c <= 0x7f)
+    {
+      *rune = c;
+      return 1;
+    }
+
+  if (len <= 1)
+    return 1;
+
+  c1 = str[1];
+  if ((c & 0xe0) == 0xc0
+      && (c1 & 0xc0) == 0x80)
+    {
+      *rune = (((c & 0x1f) << 6)
+              + (c1 & 0x3f));
+      return 2;
+    }
+
+  if (len <= 2)
+    return 1;
+
+  c2 = str[2];
+  if ((c & 0xf0) == 0xe0
+      && (c1 & 0xc0) == 0x80
+      && (c2 & 0xc0) == 0x80)
+    {
+      *rune = (((c & 0xf) << 12)
+              + ((c1 & 0x3f) << 6)
+              + (c2 & 0x3f));
+      return 3;
+    }
+
+  if (len <= 3)
+    return 1;
+
+  c3 = str[3];
+  if ((c & 0xf8) == 0xf0
+      && (c1 & 0xc0) == 0x80
+      && (c2 & 0xc0) == 0x80
+      && (c3 & 0xc0) == 0x80)
+    {
+      *rune = (((c & 0x7) << 18)
+              + ((c1 & 0x3f) << 12)
+              + ((c2 & 0x3f) << 6)
+              + (c3 & 0x3f));
+      return 4;
+    }
+
+  /* Invalid encoding.  Return 1 so that we advance.  */
+  return 1;
+}
diff --git a/libgo/runtime/go-runtime-error.c b/libgo/runtime/go-runtime-error.c
new file mode 100644 (file)
index 0000000..ceba2d6
--- /dev/null
@@ -0,0 +1,84 @@
+/* go-runtime-error.c -- Go runtime error.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-panic.h"
+
+/* The compiler generates calls to this function.  This enum values
+   are known to the compiler and used by compiled code.  Any change
+   here must be reflected in the compiler.  */
+
+enum
+{
+  /* Slice index out of bounds: negative or larger than the length of
+     the slice.  */
+  SLICE_INDEX_OUT_OF_BOUNDS = 0,
+
+  /* Array index out of bounds.  */
+  ARRAY_INDEX_OUT_OF_BOUNDS = 1,
+
+  /* String index out of bounds.  */
+  STRING_INDEX_OUT_OF_BOUNDS = 2,
+
+  /* Slice slice out of bounds: negative or larger than the length of
+     the slice or high bound less than low bound.  */
+  SLICE_SLICE_OUT_OF_BOUNDS = 3,
+
+  /* Array slice out of bounds.  */
+  ARRAY_SLICE_OUT_OF_BOUNDS = 4,
+
+  /* String slice out of bounds.  */
+  STRING_SLICE_OUT_OF_BOUNDS = 5,
+
+  /* Dereference of nil pointer.  This is used when there is a
+     dereference of a pointer to a very large struct or array, to
+     ensure that a gigantic array is not used a proxy to access random
+     memory locations.  */
+  NIL_DEREFERENCE = 6,
+
+  /* Slice length or capacity out of bounds in make: negative or
+     overflow or length greater than capacity.  */
+  MAKE_SLICE_OUT_OF_BOUNDS = 7,
+
+  /* Map capacity out of bounds in make: negative or overflow.  */
+  MAKE_MAP_OUT_OF_BOUNDS = 8,
+
+  /* Channel capacity out of bounds in make: negative or overflow.  */
+  MAKE_CHAN_OUT_OF_BOUNDS = 9
+};
+
+extern void __go_runtime_error () __attribute__ ((noreturn));
+
+void
+__go_runtime_error (int i)
+{
+  switch (i)
+    {
+    case SLICE_INDEX_OUT_OF_BOUNDS:
+    case ARRAY_INDEX_OUT_OF_BOUNDS:
+    case STRING_INDEX_OUT_OF_BOUNDS:
+      __go_panic_msg ("index out of range");
+
+    case SLICE_SLICE_OUT_OF_BOUNDS:
+    case ARRAY_SLICE_OUT_OF_BOUNDS:
+    case STRING_SLICE_OUT_OF_BOUNDS:
+      __go_panic_msg ("slice bounds out of range");
+
+    case NIL_DEREFERENCE:
+      __go_panic_msg ("nil pointer dereference");
+
+    case MAKE_SLICE_OUT_OF_BOUNDS:
+      __go_panic_msg ("make slice len or cap out of range");
+
+    case MAKE_MAP_OUT_OF_BOUNDS:
+      __go_panic_msg ("make map len out of range");
+
+    case MAKE_CHAN_OUT_OF_BOUNDS:
+      __go_panic_msg ("make chan len out of range");
+
+    default:
+      __go_panic_msg ("unknown runtime error");
+    }
+}
diff --git a/libgo/runtime/go-sched.c b/libgo/runtime/go-sched.c
new file mode 100644 (file)
index 0000000..2e36d31
--- /dev/null
@@ -0,0 +1,15 @@
+/* go-sched.c -- the runtime.Gosched function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <sched.h>
+
+void Gosched (void) asm ("libgo_runtime.runtime.Gosched");
+
+void
+Gosched (void)
+{
+  sched_yield ();
+}
diff --git a/libgo/runtime/go-select.c b/libgo/runtime/go-select.c
new file mode 100644 (file)
index 0000000..9d9f728
--- /dev/null
@@ -0,0 +1,758 @@
+/* go-select.c -- implement select.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <pthread.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "go-assert.h"
+#include "channel.h"
+
+/* __go_select builds an array of these structures.  */
+
+struct select_channel
+{
+  /* The channel being selected.  */
+  struct __go_channel* channel;
+  /* If this channel is selected, the value to return.  */
+  size_t retval;
+  /* If this channel is a duplicate of one which appears earlier in
+     the array, this is the array index of the earlier channel.  This
+     is -1UL if this is not a dup.  */
+  size_t dup_index;
+  /* An entry to put on the send or receive queue.  */
+  struct __go_channel_select queue_entry;
+  /* True if selected for send.  */
+  _Bool is_send;
+  /* True if channel is ready--it has data to receive or space to
+     send.  */
+  _Bool is_ready;
+};
+
+/* This mutex controls access to __go_select_cond.  This mutex may not
+   be acquired if any channel locks are held.  */
+
+static pthread_mutex_t __go_select_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* When we have to wait for channels, we tell them to trigger this
+   condition variable when they send or receive something.  */
+
+static pthread_cond_t __go_select_cond = PTHREAD_COND_INITIALIZER;
+
+/* Sort the channels by address.  This avoids deadlock when multiple
+   selects are running on overlapping sets of channels.  */
+
+static int
+channel_sort (const void *p1, const void *p2)
+{
+  const struct select_channel *c1 = (const struct select_channel *) p1;
+  const struct select_channel *c2 = (const struct select_channel *) p2;
+
+  if ((uintptr_t) c1->channel < (uintptr_t) c2->channel)
+    return -1;
+  else if ((uintptr_t) c1->channel > (uintptr_t) c2->channel)
+    return 1;
+  else
+    return 0;
+}
+
+/* Return whether there is an entry on QUEUE which can be used for a
+   synchronous send or receive.  */
+
+static _Bool
+is_queue_ready (struct __go_channel_select *queue)
+{
+  int x;
+
+  if (queue == NULL)
+    return 0;
+
+  x = pthread_mutex_lock (&__go_select_data_mutex);
+  __go_assert (x == 0);
+
+  while (queue != NULL)
+    {
+      if (*queue->selected == NULL)
+       break;
+      queue = queue->next;
+    }
+
+  x = pthread_mutex_unlock (&__go_select_data_mutex);
+  __go_assert (x == 0);
+
+  return queue != NULL;
+}
+
+/* Return whether CHAN is ready.  If IS_SEND is true check whether it
+   has space to send, otherwise check whether it has a value to
+   receive.  */
+
+static _Bool
+is_channel_ready (struct __go_channel* channel, _Bool is_send)
+{
+  if (is_send)
+    {
+      if (channel->selected_for_send)
+       return 0;
+      if (channel->is_closed)
+       return 1;
+      if (channel->num_entries > 0)
+       {
+         /* An asynchronous channel is ready for sending if there is
+            room in the buffer.  */
+         return ((channel->next_store + 1) % channel->num_entries
+                 != channel->next_fetch);
+       }
+      else
+       {
+         if (channel->waiting_to_send)
+           {
+             /* Some other goroutine is waiting to send on this
+                channel, so we can't.  */
+             return 0;
+           }
+         if (channel->waiting_to_receive)
+           {
+             /* Some other goroutine is waiting to receive a value,
+                so we can send one.  */
+             return 1;
+           }
+         if (is_queue_ready (channel->select_receive_queue))
+           {
+             /* There is a select statement waiting to synchronize
+                with this one.  */
+             return 1;
+           }
+         return 0;
+       }
+    }
+  else
+    {
+      if (channel->selected_for_receive)
+       return 0;
+      if (channel->is_closed)
+       return 1;
+      if (channel->num_entries > 0)
+       {
+         /* An asynchronous channel is ready for receiving if there
+            is a value in the buffer.  */
+         return channel->next_fetch != channel->next_store;
+       }
+      else
+       {
+         if (channel->waiting_to_receive)
+           {
+             /* Some other goroutine is waiting to receive from this
+                channel, so it is not ready for us to receive.  */
+             return 0;
+           }
+         if (channel->next_store > 0)
+           {
+             /* There is data on the channel.  */
+             return 1;
+           }
+         if (is_queue_ready (channel->select_send_queue))
+           {
+             /* There is a select statement waiting to synchronize
+                with this one.  */
+             return 1;
+           }
+         return 0;
+       }
+    }
+}
+
+/* Mark a channel as selected.  The channel is locked.  IS_SELECTED is
+   true if the channel was selected for us by another goroutine.  We
+   set *NEEDS_BROADCAST if we need to broadcast on the select
+   condition variable.  Return true if we got it.  */
+
+static _Bool
+mark_channel_selected (struct __go_channel *channel, _Bool is_send,
+                      _Bool is_selected, _Bool *needs_broadcast)
+{
+  if (channel->num_entries == 0)
+    {
+      /* This is a synchronous channel.  If there is no goroutine
+        currently waiting, but there is another select waiting, then
+        we need to tell that select to use this channel.  That may
+        fail--there may be no other goroutines currently waiting--as
+        a third goroutine may already have claimed the select.  */
+      if (!is_selected
+         && !channel->is_closed
+         && (is_send
+             ? !channel->waiting_to_receive
+             : channel->next_store == 0))
+       {
+         int x;
+         struct __go_channel_select *queue;
+
+         x = pthread_mutex_lock (&__go_select_data_mutex);
+         __go_assert (x == 0);
+
+         queue = (is_send
+                  ? channel->select_receive_queue
+                  : channel->select_send_queue);
+         __go_assert (queue != NULL);
+
+         while (queue != NULL)
+           {
+             if (*queue->selected == NULL)
+               {
+                 *queue->selected = channel;
+                 *queue->is_read = !is_send;
+                 break;
+               }
+             queue = queue->next;
+           }
+
+         x = pthread_mutex_unlock (&__go_select_data_mutex);
+         __go_assert (x == 0);
+
+         if (queue == NULL)
+           return 0;
+
+         if (is_send)
+           channel->selected_for_receive = 1;
+         else
+           channel->selected_for_send = 1;
+
+         /* We are going to have to tell the other select that there
+            is something to do.  */
+         *needs_broadcast = 1;
+       }
+    }
+
+  if (is_send)
+    channel->selected_for_send = 1;
+  else
+    channel->selected_for_receive = 1;
+
+  return 1;
+}
+
+/* Mark a channel to indicate that a select is waiting.  The channel
+   is locked.  */
+
+static void
+mark_select_waiting (struct select_channel *sc,
+                    struct __go_channel **selected_pointer,
+                    _Bool *selected_for_read_pointer)
+{
+  struct __go_channel *channel = sc->channel;
+  _Bool is_send = sc->is_send;
+
+  if (channel->num_entries == 0)
+    {
+      struct __go_channel_select **pp;
+
+      pp = (is_send
+           ? &channel->select_send_queue
+           : &channel->select_receive_queue);
+
+      /* Add an entry to the queue of selects on this channel.  */
+      sc->queue_entry.next = *pp;
+      sc->queue_entry.selected = selected_pointer;
+      sc->queue_entry.is_read = selected_for_read_pointer;
+
+      *pp = &sc->queue_entry;
+    }
+
+  channel->select_mutex = &__go_select_mutex;
+  channel->select_cond = &__go_select_cond;
+
+  /* We never actually clear the select_mutex and select_cond fields.
+     In order to clear them safely, we would need to have some way of
+     knowing when no select is waiting for the channel.  Thus we
+     introduce a bit of inefficiency for every channel that select
+     needs to wait for.  This is harmless other than the performance
+     cost.  */
+}
+
+/* Remove the entry for this select waiting on this channel.  The
+   channel is locked.  We check both queues, because the channel may
+   be selected for both reading and writing.  */
+
+static void
+clear_select_waiting (struct select_channel *sc,
+                     struct __go_channel **selected_pointer)
+{
+  struct __go_channel *channel = sc->channel;
+
+  if (channel->num_entries == 0)
+    {
+      _Bool found;
+      struct __go_channel_select **pp;
+
+      found = 0;
+
+      for (pp = &channel->select_send_queue; *pp != NULL; pp = &(*pp)->next)
+       {
+         if ((*pp)->selected == selected_pointer)
+           {
+             *pp = (*pp)->next;
+             found = 1;
+             break;
+           }
+       }
+
+      for (pp = &channel->select_receive_queue; *pp != NULL; pp = &(*pp)->next)
+       {
+         if ((*pp)->selected == selected_pointer)
+           {
+             *pp = (*pp)->next;
+             found = 1;
+             break;
+           }
+       }
+
+      __go_assert (found);
+    }
+}
+
+/* Look through the list of channels to see which ones are ready.
+   Lock each channels, and set the is_ready flag.  Return the number
+   of ready channels.  */
+
+static size_t
+lock_channels_find_ready (struct select_channel *channels, size_t count)
+{
+  size_t ready_count;
+  size_t i;
+
+  ready_count = 0;
+  for (i = 0; i < count; ++i)
+    {
+      struct __go_channel *channel = channels[i].channel;
+      _Bool is_send = channels[i].is_send;
+      size_t dup_index = channels[i].dup_index;
+      int x;
+
+      if (channel == NULL)
+       continue;
+
+      if (dup_index != (size_t) -1UL)
+       {
+         if (channels[dup_index].is_ready)
+           {
+             channels[i].is_ready = 1;
+             ++ready_count;
+           }
+         continue;
+       }
+
+      x = pthread_mutex_lock (&channel->lock);
+      __go_assert (x == 0);
+
+      if (is_channel_ready (channel, is_send))
+       {
+         channels[i].is_ready = 1;
+         ++ready_count;
+       }
+    }
+
+  return ready_count;
+}
+
+/* The channel we are going to select has been forced by some other
+   goroutine.  SELECTED_CHANNEL is the channel we will use,
+   SELECTED_FOR_READ is whether the other goroutine wants to read from
+   the channel.  Note that the channel could be specified multiple
+   times in this select, so we must mark each appropriate entry for
+   this channel as ready.  Every other channel is marked as not ready.
+   All the channels are locked before this routine is called.  This
+   returns the number of ready channels.  */
+
+size_t
+force_selected_channel_ready (struct select_channel *channels, size_t count,
+                             struct __go_channel *selected_channel,
+                             _Bool selected_for_read)
+{
+  size_t ready_count;
+  size_t i;
+
+  ready_count = 0;
+  for (i = 0; i < count; ++i)
+    {
+      struct __go_channel *channel = channels[i].channel;
+      _Bool is_send = channels[i].is_send;
+
+      if (channel == NULL)
+       continue;
+
+      if (channel != selected_channel
+         || (is_send ? !selected_for_read : selected_for_read))
+       channels[i].is_ready = 0;
+      else
+       {
+         channels[i].is_ready = 1;
+         ++ready_count;
+       }
+    }
+  __go_assert (ready_count > 0);
+  return ready_count;
+}
+
+/* Unlock all the channels.  */
+
+static void
+unlock_channels (struct select_channel *channels, size_t count)
+{
+  size_t i;
+  int x;
+
+  for (i = 0; i < count; ++i)
+    {
+      struct __go_channel *channel = channels[i].channel;
+
+      if (channel == NULL)
+       continue;
+
+      if (channels[i].dup_index != (size_t) -1UL)
+       continue;
+
+      x = pthread_mutex_unlock (&channel->lock);
+      __go_assert (x == 0);
+    }
+}
+
+/* At least one channel is ready.  Randomly pick a channel to return.
+   Unlock all the channels.  IS_SELECTED is true if the channel was
+   picked for us by some other goroutine.  If SELECTED_POINTER is not
+   NULL, remove it from the queue for all the channels.  Return the
+   retval field of the selected channel.  This will return 0 if we
+   can't use the selected channel, because it relied on synchronizing
+   with some other select, and that select already synchronized with a
+   different channel.  */
+
+static size_t
+unlock_channels_and_select (struct select_channel *channels,
+                           size_t count, size_t ready_count,
+                           _Bool is_selected,
+                           struct __go_channel **selected_pointer)
+{
+  size_t selected;
+  size_t ret;
+  _Bool needs_broadcast;
+  size_t i;
+  int x;
+
+  /* Pick which channel we are going to return.  */
+#if defined(HAVE_RANDOM)
+  selected = (size_t) random () % ready_count;
+#else
+  selected = (size_t) rand () % ready_count;
+#endif
+  ret = 0;
+  needs_broadcast = 0;
+
+  /* Look at the channels in reverse order so that we don't unlock a
+     duplicated channel until we have seen all its dups.  */
+  for (i = 0; i < count; ++i)
+    {
+      size_t j = count - i - 1;
+      struct __go_channel *channel = channels[j].channel;
+      _Bool is_send = channels[j].is_send;
+
+      if (channel == NULL)
+       continue;
+
+      if (channels[j].is_ready)
+       {
+         if (selected == 0)
+           {
+             if (mark_channel_selected (channel, is_send, is_selected,
+                                        &needs_broadcast))
+               ret = channels[j].retval;
+           }
+
+         --selected;
+       }
+
+      if (channels[j].dup_index == (size_t) -1UL)
+       {
+         if (selected_pointer != NULL)
+           clear_select_waiting (&channels[j], selected_pointer);
+
+         x = pthread_mutex_unlock (&channel->lock);
+         __go_assert (x == 0);
+       }
+    }
+
+  /* The NEEDS_BROADCAST variable is set if we are synchronizing with
+     some other select statement.  We can't do the actual broadcast
+     until we have unlocked all the channels.  */
+
+  if (needs_broadcast)
+    {
+      x = pthread_mutex_lock (&__go_select_mutex);
+      __go_assert (x == 0);
+
+      x = pthread_cond_broadcast (&__go_select_cond);
+      __go_assert (x == 0);
+
+      x = pthread_mutex_unlock (&__go_select_mutex);
+      __go_assert (x == 0);
+    }
+
+  return ret;
+}
+
+/* Mark all channels to show that we are waiting for them.  This is
+   called with the select mutex held, but none of the channels are
+   locked.  This returns true if some channel was found to be
+   ready.  */
+
+static _Bool
+mark_all_channels_waiting (struct select_channel* channels, size_t count,
+                          struct __go_channel **selected_pointer,
+                          _Bool *selected_for_read_pointer)
+{
+  _Bool ret;
+  int x;
+  size_t i;
+
+  ret = 0;
+  for (i = 0; i < count; ++i)
+    {
+      struct __go_channel *channel = channels[i].channel;
+      _Bool is_send = channels[i].is_send;
+
+      if (channel == NULL)
+       continue;
+
+      if (channels[i].dup_index != (size_t) -1UL)
+       {
+         size_t j;
+
+         /* A channel may be selected for both read and write.  */
+         if (channels[channels[i].dup_index].is_send != is_send)
+           {
+             for (j = channels[i].dup_index + 1; j < i; ++j)
+               {
+                 if (channels[j].channel == channel
+                     && channels[j].is_send == is_send)
+                   break;
+               }
+             if (j < i)
+               continue;
+           }
+       }
+
+      x = pthread_mutex_lock (&channel->lock);
+      __go_assert (x == 0);
+
+      /* To avoid a race condition, we have to check again whether the
+        channel is ready.  It may have become ready since we did the
+        first set of checks but before we acquired the select mutex.
+        If we don't check here, we could sleep forever on the select
+        condition variable.  */
+      if (is_channel_ready (channel, is_send))
+       ret = 1;
+
+      /* If SELECTED_POINTER is NULL, then we have already marked the
+        channel as waiting.  */
+      if (selected_pointer != NULL)
+       mark_select_waiting (&channels[i], selected_pointer,
+                            selected_for_read_pointer);
+
+      x = pthread_mutex_unlock (&channel->lock);
+      __go_assert (x == 0);
+    }
+
+  return ret;
+}
+
+/* Implement select.  This is called by the compiler-generated code
+   with pairs of arguments: a pointer to a channel, and an int which
+   is non-zero for send, zero for receive.  */
+
+size_t
+__go_select (size_t count, _Bool has_default,
+            struct __go_channel **channel_args, _Bool *is_send_args)
+{
+  struct select_channel stack_buffer[16];
+  struct select_channel *allocated_buffer;
+  struct select_channel *channels;
+  size_t i;
+  int x;
+  struct __go_channel *selected_channel;
+  _Bool selected_for_read;
+  _Bool is_queued;
+
+  if (count < sizeof stack_buffer / sizeof stack_buffer[0])
+    {
+      channels = &stack_buffer[0];
+      allocated_buffer = NULL;
+    }
+  else
+    {
+      allocated_buffer = ((struct select_channel *)
+                         malloc (count * sizeof (struct select_channel)));
+      channels = allocated_buffer;
+    }
+
+  for (i = 0; i < count; ++i)
+    {
+      struct __go_channel *channel_arg = channel_args[i];
+      _Bool is_send = is_send_args[i];
+
+      channels[i].channel = (struct __go_channel*) channel_arg;
+      channels[i].retval = i + 1;
+      channels[i].dup_index = (size_t) -1UL;
+      channels[i].queue_entry.next = NULL;
+      channels[i].queue_entry.selected = NULL;
+      channels[i].is_send = is_send;
+      channels[i].is_ready = 0;
+    }
+
+  qsort (channels, count, sizeof (struct select_channel), channel_sort);
+
+  for (i = 0; i < count; ++i)
+    {
+      size_t j;
+
+      for (j = 0; j < i; ++j)
+       {
+         if (channels[j].channel == channels[i].channel)
+           {
+             channels[i].dup_index = j;
+             break;
+           }
+       }
+    }
+
+  /* SELECT_CHANNEL is used to select synchronized channels.  If no
+     channels are ready, we store a pointer to this variable on the
+     select queue for each synchronized channel.  Because the variable
+     may be set by channel operations running in other goroutines,
+     SELECT_CHANNEL may only be accessed when all the channels are
+     locked and/or when the select_data_mutex is locked.  */
+  selected_channel = NULL;
+
+  /* SELECTED_FOR_READ is set to true if SELECTED_CHANNEL was set by a
+     goroutine which wants to read from the channel.  The access
+     restrictions for this are like those for SELECTED_CHANNEL.  */
+  selected_for_read = 0;
+
+  /* IS_QUEUED is true if we have queued up this select on the queues
+     for any associated synchronous channels.  We only do this if no
+     channels are ready the first time around the loop.  */
+  is_queued = 0;
+
+  while (1)
+    {
+      int ready_count;
+      _Bool is_selected;
+
+      /* Lock all channels, identify which ones are ready.  */
+      ready_count = lock_channels_find_ready (channels, count);
+
+      /* All the channels are locked, so we can look at
+        SELECTED_CHANNEL.  If it is not NULL, then our choice has
+        been forced by some other goroutine.  This can only happen
+        after the first time through the loop.  */
+      is_selected = selected_channel != NULL;
+      if (is_selected)
+       ready_count = force_selected_channel_ready (channels, count,
+                                                   selected_channel,
+                                                   selected_for_read);
+
+      if (ready_count > 0)
+       {
+         size_t ret;
+
+         ret = unlock_channels_and_select (channels, count, ready_count,
+                                           is_selected,
+                                           (is_queued
+                                            ? &selected_channel
+                                            : NULL));
+
+         /* If RET is zero, it means that the channel we picked
+            turned out not to be ready, because some other select
+            grabbed it during our traversal.  Loop around and try
+            again.  */
+         if (ret == 0)
+           {
+             is_queued = 0;
+             /* We are no longer on any channel queues, so it is safe
+                to touch SELECTED_CHANNEL here.  It must be NULL,
+                because otherwise that would somebody has promised to
+                synch up with us and then failed to do so.  */
+             __go_assert (selected_channel == NULL);
+             continue;
+           }
+
+         if (allocated_buffer != NULL)
+           free (allocated_buffer);
+
+         return ret;
+       }
+
+      /* No channels were ready.  */
+
+      unlock_channels (channels, count);
+
+      if (has_default)
+       {
+         /* Use the default clause.  */
+         if (allocated_buffer != NULL)
+           free (allocated_buffer);
+         return 0;
+       }
+
+      /* This is a blocking select.  Grab the select lock, tell all
+        the channels to notify us when something happens, and wait
+        for something to happen.  */
+
+      x = pthread_mutex_lock (&__go_select_mutex);
+      __go_assert (x == 0);
+
+      /* Check whether CHANNEL_SELECTED was set while the channels
+        were unlocked.  If it was set, then we can simply loop around
+        again.  We need to check this while the select mutex is held.
+        It is possible that something will set CHANNEL_SELECTED while
+        we mark the channels as waiting.  If this happens, that
+        goroutine is required to signal the select condition
+        variable, which means acquiring the select mutex.  Since we
+        have the select mutex locked ourselves, we can not miss that
+        signal.  */
+
+      x = pthread_mutex_lock (&__go_select_data_mutex);
+      __go_assert (x == 0);
+
+      is_selected = selected_channel != NULL;
+
+      x = pthread_mutex_unlock (&__go_select_data_mutex);
+      __go_assert (x == 0);
+
+      if (!is_selected)
+       {
+         /* Mark the channels as waiting, and check whether they have
+            become ready.  */
+         if (!mark_all_channels_waiting (channels, count,
+                                         (is_queued
+                                          ? NULL
+                                          : &selected_channel),
+                                         (is_queued
+                                          ? NULL
+                                          : &selected_for_read)))
+           {
+             x = pthread_cond_wait (&__go_select_cond, &__go_select_mutex);
+             __go_assert (x == 0);
+           }
+
+         is_queued = 1;
+       }
+
+      x = pthread_mutex_unlock (&__go_select_mutex);
+      __go_assert (x == 0);
+    }
+}
diff --git a/libgo/runtime/go-semacquire.c b/libgo/runtime/go-semacquire.c
new file mode 100644 (file)
index 0000000..67a86ef
--- /dev/null
@@ -0,0 +1,119 @@
+/* go-semacquire.c -- implement runtime.Semacquire and runtime.Semrelease.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+#include <pthread.h>
+
+#include "go-assert.h"
+#include "runtime.h"
+
+/* We use a single global lock and condition variable.  This is
+   painful, since it will cause unnecessary contention, but is hard to
+   avoid in a portable manner.  On Linux we can use futexes, but they
+   are unfortunately not exposed by libc and are thus also hard to use
+   portably.  */
+
+static pthread_mutex_t sem_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t sem_cond = PTHREAD_COND_INITIALIZER;
+
+/* If the value in *ADDR is positive, and we are able to atomically
+   decrement it, return true.  Otherwise do nothing and return
+   false.  */
+
+static _Bool
+acquire (uint32 *addr)
+{
+  while (1)
+    {
+      uint32 val;
+
+      val = *addr;
+      if (val == 0)
+       return 0;
+      if (__sync_bool_compare_and_swap (addr, val, val - 1))
+       return 1;
+    }
+}
+
+/* Implement runtime.Semacquire.  ADDR points to a semaphore count.
+   We have acquired the semaphore when we have decremented the count
+   and it remains nonnegative.  */
+
+void
+semacquire (uint32 *addr)
+{
+  while (1)
+    {
+      int i;
+
+      /* If the current count is positive, and we are able to atomically
+        decrement it, then we have acquired the semaphore.  */
+      if (acquire (addr))
+       return;
+
+      /* Lock the mutex.  */
+      i = pthread_mutex_lock (&sem_lock);
+      __go_assert (i == 0);
+
+      /* Check the count again with the mutex locked.  */
+      if (acquire (addr))
+       {
+         i = pthread_mutex_unlock (&sem_lock);
+         __go_assert (i == 0);
+         return;
+       }
+
+      /* The count is zero.  Even if a call to runtime.Semrelease
+        increments it to become positive, that call will try to
+        acquire the mutex and block, so we are sure to see the signal
+        of the condition variable.  */
+      i = pthread_cond_wait (&sem_cond, &sem_lock);
+      __go_assert (i == 0);
+
+      /* Unlock the mutex and try again.  */
+      i = pthread_mutex_unlock (&sem_lock);
+      __go_assert (i == 0);
+    }
+}
+
+/* Implement runtime.Semrelease.  ADDR points to a semaphore count.  We
+   must atomically increment the count.  If the count becomes
+   positive, we signal the condition variable to wake up another
+   process.  */
+
+void
+semrelease (uint32 *addr)
+{
+  int32_t val;
+
+  val = __sync_fetch_and_add (addr, 1);
+
+  /* VAL is the old value.  It should never be negative.  If it is
+     negative, that implies that Semacquire somehow decremented a zero
+     value, or that the count has overflowed.  */
+  __go_assert (val >= 0);
+
+  /* If the old value was zero, then we have now released a count, and
+     we signal the condition variable.  If the old value was positive,
+     then nobody can be waiting.  We have to use
+     pthread_cond_broadcast, not pthread_cond_signal, because
+     otherwise there would be a race condition when the count is
+     incremented twice before any locker manages to decrement it.  */
+  if (val == 0)
+    {
+      int i;
+
+      i = pthread_mutex_lock (&sem_lock);
+      __go_assert (i == 0);
+
+      i = pthread_cond_broadcast (&sem_cond);
+      __go_assert (i == 0);
+
+      i = pthread_mutex_unlock (&sem_lock);
+      __go_assert (i == 0);
+    }
+}
diff --git a/libgo/runtime/go-send-big.c b/libgo/runtime/go-send-big.c
new file mode 100644 (file)
index 0000000..f58ffb6
--- /dev/null
@@ -0,0 +1,31 @@
+/* go-send-big.c -- send something bigger than uint64_t on a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+#include "go-panic.h"
+#include "channel.h"
+
+void
+__go_send_big (struct __go_channel* channel, const void *val, _Bool for_select)
+{
+  size_t alloc_size;
+  size_t offset;
+
+  if (channel == NULL)
+    __go_panic_msg ("send to nil channel");
+
+  alloc_size = ((channel->element_size + sizeof (uint64_t) - 1)
+               / sizeof (uint64_t));
+
+  if (!__go_send_acquire (channel, for_select))
+    return;
+
+  offset = channel->next_store * alloc_size;
+  __builtin_memcpy (&channel->data[offset], val, channel->element_size);
+
+  __go_send_release (channel);
+}
diff --git a/libgo/runtime/go-send-nb-big.c b/libgo/runtime/go-send-nb-big.c
new file mode 100644 (file)
index 0000000..288ce7f
--- /dev/null
@@ -0,0 +1,30 @@
+/* go-send-nb-big.c -- nonblocking send of something big on a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+#include "channel.h"
+
+_Bool
+__go_send_nonblocking_big (struct __go_channel* channel, const void *val)
+{
+  size_t alloc_size;
+  size_t offset;
+
+  alloc_size = ((channel->element_size + sizeof (uint64_t) - 1)
+               / sizeof (uint64_t));
+
+  int data = __go_send_nonblocking_acquire (channel);
+  if (data != SEND_NONBLOCKING_ACQUIRE_SPACE)
+    return data == SEND_NONBLOCKING_ACQUIRE_CLOSED;
+
+  offset = channel->next_store * alloc_size;
+  __builtin_memcpy (&channel->data[offset], val, channel->element_size);
+
+  __go_send_release (channel);
+
+  return 1;
+}
diff --git a/libgo/runtime/go-send-nb-small.c b/libgo/runtime/go-send-nb-small.c
new file mode 100644 (file)
index 0000000..f23ae01
--- /dev/null
@@ -0,0 +1,112 @@
+/* go-send-nb-small.c -- nonblocking send of something small on a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+/* Prepare to send something on a nonblocking channel.  */
+
+int
+__go_send_nonblocking_acquire (struct __go_channel *channel)
+{
+  int i;
+  _Bool has_space;
+
+  i = pthread_mutex_lock (&channel->lock);
+  __go_assert (i == 0);
+
+  while (channel->selected_for_send)
+    {
+      i = pthread_cond_wait (&channel->cond, &channel->lock);
+      __go_assert (i == 0);
+    }
+
+  if (channel->is_closed)
+    {
+      ++channel->closed_op_count;
+      if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
+       {
+         i = pthread_mutex_unlock (&channel->lock);
+         __go_assert (i == 0);
+         __go_panic_msg ("too many operations on closed channel");
+       }
+      i = pthread_mutex_unlock (&channel->lock);
+      __go_assert (i == 0);
+      return SEND_NONBLOCKING_ACQUIRE_CLOSED;
+    }
+
+  if (channel->num_entries > 0)
+      has_space = ((channel->next_store + 1) % channel->num_entries
+                  != channel->next_fetch);
+  else
+    {
+      /* This is a synchronous channel.  If somebody is current
+        sending, then we can't send.  Otherwise, see if somebody is
+        waiting to receive, or see if we can synch with a select.  */
+      if (channel->waiting_to_send)
+       {
+         /* Some other goroutine is currently sending on this
+            channel, which means that we can't.  */
+         has_space = 0;
+       }
+      else if (channel->waiting_to_receive)
+       {
+         /* Some other goroutine is waiting to receive a value, so we
+            can send directly to them.  */
+         has_space = 1;
+       }
+      else if (__go_synch_with_select (channel, 1))
+       {
+         /* We found a select waiting to receive data, so we can send
+            to that.  */
+         __go_broadcast_to_select (channel);
+         has_space = 1;
+       }
+      else
+       {
+         /* Otherwise, we can't send, because nobody is waiting to
+            receive.  */
+         has_space = 0;
+       }
+
+      if (has_space)
+       {
+         channel->waiting_to_send = 1;
+         __go_assert (channel->next_store == 0);
+       }
+    }
+
+  if (!has_space)
+    {
+      i = pthread_mutex_unlock (&channel->lock);
+      __go_assert (i == 0);
+
+      return SEND_NONBLOCKING_ACQUIRE_NOSPACE;
+    }
+
+  return SEND_NONBLOCKING_ACQUIRE_SPACE;
+}
+
+/* Send something 64 bits or smaller on a channel.  */
+
+_Bool
+__go_send_nonblocking_small (struct __go_channel *channel, uint64_t val)
+{
+  __go_assert (channel->element_size <= sizeof (uint64_t));
+
+  int data = __go_send_nonblocking_acquire (channel);
+  if (data != SEND_NONBLOCKING_ACQUIRE_SPACE)
+    return data == SEND_NONBLOCKING_ACQUIRE_CLOSED;
+
+  channel->data[channel->next_store] = val;
+
+  __go_send_release (channel);
+
+  return 1;
+}
diff --git a/libgo/runtime/go-send-small.c b/libgo/runtime/go-send-small.c
new file mode 100644 (file)
index 0000000..506c90e
--- /dev/null
@@ -0,0 +1,165 @@
+/* go-send-small.c -- send something 64 bits or smaller on a channel.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stdint.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+/* Prepare to send something on a channel.  Return true if the channel
+   is acquired, false, if it is closed.  FOR_SELECT is true if this
+   call is being made after a select statement returned with this
+   channel selected.  */
+
+_Bool
+__go_send_acquire (struct __go_channel *channel, _Bool for_select)
+{
+  int i;
+
+  i = pthread_mutex_lock (&channel->lock);
+  __go_assert (i == 0);
+
+  while (1)
+    {
+      /* Check whether the channel is closed.  */
+      if (channel->is_closed)
+       {
+         ++channel->closed_op_count;
+         if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
+           {
+             i = pthread_mutex_unlock (&channel->lock);
+             __go_assert (i == 0);
+             __go_panic_msg ("too many operations on closed channel");
+           }
+         channel->selected_for_send = 0;
+         __go_unlock_and_notify_selects (channel);
+         return 0;
+       }
+
+      /* If somebody else has the channel locked for sending, we have
+        to wait.  If FOR_SELECT is true, then we are the one with the
+        lock.  */
+      if (!channel->selected_for_send || for_select)
+       {
+         if (channel->num_entries == 0)
+           {
+             /* This is a synchronous channel.  If nobody else is
+                waiting to send, we grab the channel and tell the
+                caller to send the data.  We will then wait for a
+                receiver.  */
+             if (!channel->waiting_to_send)
+               {
+                 __go_assert (channel->next_store == 0);
+                 return 1;
+               }
+           }
+         else
+           {
+             /* If there is room on the channel, we are OK.  */
+             if ((channel->next_store + 1) % channel->num_entries
+                 != channel->next_fetch)
+               return 1;
+           }
+       }
+
+      /* Wait for something to change, then loop around and try
+        again.  */
+
+      i = pthread_cond_wait (&channel->cond, &channel->lock);
+      __go_assert (i == 0);
+    }
+}
+
+/* Finished sending something on a channel.  */
+
+void
+__go_send_release (struct __go_channel *channel)
+{
+  int i;
+
+  if (channel->num_entries != 0)
+    {
+      /* This is a buffered channel.  Bump the store count and signal
+        the condition variable.  */
+      channel->next_store = (channel->next_store + 1) % channel->num_entries;
+
+      i = pthread_cond_signal (&channel->cond);
+      __go_assert (i == 0);
+    }
+  else
+    {
+      _Bool synched_with_select;
+
+      /* This is a synchronous channel.  Indicate that we have a value
+        waiting.  */
+      channel->next_store = 1;
+      channel->waiting_to_send = 1;
+
+      /* Tell everybody else to do something.  This has to be a
+        broadcast because we might have both senders and receivers
+        waiting on the condition, but senders won't send another
+        signal.  */
+      i = pthread_cond_broadcast (&channel->cond);
+      __go_assert (i == 0);
+
+      /* Wait until the value is received.  */
+      synched_with_select = 0;
+      while (1)
+       {
+         if (channel->next_store == 0)
+           break;
+
+         /* If nobody is currently waiting to receive, try to synch
+            up with a select.  */
+         if (!channel->waiting_to_receive && !synched_with_select)
+           {
+             if (__go_synch_with_select (channel, 1))
+               {
+                 synched_with_select = 1;
+                 __go_broadcast_to_select (channel);
+                 continue;
+               }
+           }
+
+         i = pthread_cond_wait (&channel->cond, &channel->lock);
+         __go_assert (i == 0);
+       }
+
+      channel->waiting_to_send = 0;
+
+      /* Using the mutexes should implement a memory barrier.  */
+
+      /* We have to signal again since we cleared the waiting_to_send
+        field.  This has to be a broadcast because both senders and
+        receivers might be waiting, but only senders will be able to
+        act.  */
+      i = pthread_cond_broadcast (&channel->cond);
+      __go_assert (i == 0);
+    }
+
+  channel->selected_for_send = 0;
+
+  __go_unlock_and_notify_selects (channel);
+}
+
+/* Send something 64 bits or smaller on a channel.  */
+
+void
+__go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select)
+{
+  if (channel == NULL)
+    __go_panic_msg ("send to nil channel");
+
+  __go_assert (channel->element_size <= sizeof (uint64_t));
+
+  if (!__go_send_acquire (channel, for_select))
+    return;
+
+  channel->data[channel->next_store] = val;
+
+  __go_send_release (channel);
+}
diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c
new file mode 100644 (file)
index 0000000..8f44970
--- /dev/null
@@ -0,0 +1,194 @@
+/* go-signal.c -- signal handling for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <signal.h>
+#include <stdlib.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "go-signal.h"
+
+#include "runtime.h"
+
+#undef int 
+
+#ifndef SA_ONSTACK
+#define SA_ONSTACK 0
+#endif
+
+/* What to do for a signal.  */
+
+struct sigtab
+{
+  /* Signal number.  */
+  int sig;
+  /* Nonzero if the signal should be ignored.  */
+  _Bool ignore;
+};
+
+/* What to do for signals.  */
+
+static struct sigtab signals[] =
+{
+  { SIGHUP, 0 },
+  { SIGINT, 0 },
+  { SIGALRM, 1 },
+  { SIGTERM, 0 },
+#ifdef SIGBUS
+  { SIGBUS, 0 },
+#endif
+#ifdef SIGFPE
+  { SIGFPE, 0 },
+#endif
+#ifdef SIGUSR1
+  { SIGUSR1, 1 },
+#endif
+#ifdef SIGSEGV
+  { SIGSEGV, 0 },
+#endif
+#ifdef SIGUSR2
+  { SIGUSR2, 1 },
+#endif
+#ifdef SIGPIPE
+  { SIGPIPE, 1 },
+#endif
+#ifdef SIGCHLD
+  { SIGCHLD, 1 },
+#endif
+#ifdef SIGTSTP
+  { SIGTSTP, 1 },
+#endif
+#ifdef SIGTTIN
+  { SIGTTIN, 1 },
+#endif
+#ifdef SIGTTOU
+  { SIGTTOU, 1 },
+#endif
+#ifdef SIGURG
+  { SIGURG, 1 },
+#endif
+#ifdef SIGXCPU
+  { SIGXCPU, 1 },
+#endif
+#ifdef SIGXFSZ
+  { SIGXFSZ, 1 },
+#endif
+#ifdef SIGVTARLM
+  { SIGVTALRM, 1 },
+#endif
+#ifdef SIGPROF
+  { SIGPROF, 1 },
+#endif
+#ifdef SIGWINCH
+  { SIGWINCH, 1 },
+#endif
+#ifdef SIGIO
+  { SIGIO, 1 },
+#endif
+#ifdef SIGPWR
+  { SIGPWR, 1 },
+#endif
+  { -1, 0 }
+};
+
+/* The Go signal handler.  */
+
+static void
+sighandler (int sig)
+{
+  const char *msg;
+  int i;
+
+  /* FIXME: Should check siginfo for more information when
+     available.  */
+  msg = NULL;
+  switch (sig)
+    {
+#ifdef SIGBUS
+    case SIGBUS:
+      msg = "invalid memory address or nil pointer dereference";
+      break;
+#endif
+
+#ifdef SIGFPE
+    case SIGFPE:
+      msg = "integer divide by zero or floating point error";
+      break;
+#endif
+
+#ifdef SIGSEGV
+    case SIGSEGV:
+      msg = "invalid memory address or nil pointer dereference";
+      break;
+#endif
+
+    default:
+      break;
+    }
+
+  if (msg != NULL)
+    {
+      sigset_t clear;
+
+      /* The signal handler blocked signals; unblock them.  */
+      i = sigfillset (&clear);
+      __go_assert (i == 0);
+      i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
+      __go_assert (i == 0);
+
+      __go_panic_msg (msg);
+    }
+
+  if (__go_sigsend (sig))
+    return;
+  for (i = 0; signals[i].sig != -1; ++i)
+    {
+      if (signals[i].sig == sig)
+       {
+         struct sigaction sa;
+
+         if (signals[i].ignore)
+           return;
+
+         memset (&sa, 0, sizeof sa);
+
+         sa.sa_handler = SIG_DFL;
+
+         i = sigemptyset (&sa.sa_mask);
+         __go_assert (i == 0);
+
+         if (sigaction (sig, &sa, NULL) != 0)
+           abort ();
+
+         raise (sig);
+         exit (2);
+       }
+    }
+  abort ();
+}
+
+/* Initialize signal handling for Go.  This is called when the program
+   starts.  */
+
+void
+__initsig ()
+{
+  struct sigaction sa;
+  int i;
+
+  siginit ();
+
+  memset (&sa, 0, sizeof sa);
+
+  sa.sa_handler = sighandler;
+
+  i = sigfillset (&sa.sa_mask);
+  __go_assert (i == 0);
+
+  for (i = 0; signals[i].sig != -1; ++i)
+    if (sigaction (signals[i].sig, &sa, NULL) != 0)
+      __go_assert (0);
+}
diff --git a/libgo/runtime/go-signal.h b/libgo/runtime/go-signal.h
new file mode 100644 (file)
index 0000000..a30173a
--- /dev/null
@@ -0,0 +1,7 @@
+/* go-signal.h -- signal handling for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+extern void __initsig (void);
diff --git a/libgo/runtime/go-strcmp.c b/libgo/runtime/go-strcmp.c
new file mode 100644 (file)
index 0000000..8e6cb18
--- /dev/null
@@ -0,0 +1,27 @@
+/* go-strcmp.c -- the go string comparison function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-string.h"
+
+int
+__go_strcmp(struct __go_string s1, struct __go_string s2)
+{
+  int i;
+
+  i = __builtin_memcmp(s1.__data, s2.__data,
+                      (s1.__length < s2.__length
+                       ? s1.__length
+                       : s2.__length));
+  if (i != 0)
+    return i;
+
+  if (s1.__length < s2.__length)
+    return -1;
+  else if (s1.__length > s2.__length)
+    return 1;
+  else
+    return 0;
+}
diff --git a/libgo/runtime/go-string-to-byte-array.c b/libgo/runtime/go-string-to-byte-array.c
new file mode 100644 (file)
index 0000000..3b646c8
--- /dev/null
@@ -0,0 +1,24 @@
+/* go-string-to-byte-array.c -- convert a string to an array of bytes in Go.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-string.h"
+#include "array.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_open_array
+__go_string_to_byte_array (struct __go_string str)
+{
+  unsigned char *data;
+  struct __go_open_array ret;
+
+  data = (unsigned char *) runtime_mallocgc (str.__length, RefNoPointers, 1, 0);
+  __builtin_memcpy (data, str.__data, str.__length);
+  ret.__values = (void *) data;
+  ret.__count = str.__length;
+  ret.__capacity = str.__length;
+  return ret;
+}
diff --git a/libgo/runtime/go-string-to-int-array.c b/libgo/runtime/go-string-to-int-array.c
new file mode 100644 (file)
index 0000000..8d7f94f
--- /dev/null
@@ -0,0 +1,50 @@
+/* go-string-to-int-array.c -- convert a string to an array of ints in Go.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-alloc.h"
+#include "go-string.h"
+#include "array.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_open_array
+__go_string_to_int_array (struct __go_string str)
+{
+  size_t c;
+  const unsigned char *p;
+  const unsigned char *pend;
+  uint32_t *data;
+  uint32_t *pd;
+  struct __go_open_array ret;
+
+  c = 0;
+  p = str.__data;
+  pend = p + str.__length;
+  while (p < pend)
+    {
+      int rune;
+
+      ++c;
+      p += __go_get_rune (p, pend - p, &rune);
+    }
+
+  data = (uint32_t *) runtime_mallocgc (c * sizeof (uint32_t), RefNoPointers,
+                                       1, 0);
+  p = str.__data;
+  pd = data;
+  while (p < pend)
+    {
+      int rune;
+
+      p += __go_get_rune (p, pend - p, &rune);
+      *pd++ = rune;
+    }
+
+  ret.__values = (void *) data;
+  ret.__count = c;
+  ret.__capacity = c;
+  return ret;
+}
diff --git a/libgo/runtime/go-string.h b/libgo/runtime/go-string.h
new file mode 100644 (file)
index 0000000..2c8e1ac
--- /dev/null
@@ -0,0 +1,42 @@
+/* go-string.h -- the string type for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#ifndef LIBGO_GO_STRING_H
+#define LIBGO_GO_STRING_H
+
+#include <stddef.h>
+
+/* A string is an instance of this structure.  */
+
+struct __go_string
+{
+  /* The bytes.  */
+  const unsigned char *__data;
+  /* The length.  */
+  int __length;
+};
+
+static inline _Bool
+__go_strings_equal (struct __go_string s1, struct __go_string s2)
+{
+  return (s1.__length == s2.__length
+         && __builtin_memcmp (s1.__data, s2.__data, s1.__length) == 0);
+}
+
+static inline _Bool
+__go_ptr_strings_equal (const struct __go_string *ps1,
+                       const struct __go_string *ps2)
+{
+  if (ps1 == NULL)
+    return ps2 == NULL;
+  if (ps2 == NULL)
+    return 0;
+  return __go_strings_equal (*ps1, *ps2);
+}
+
+extern int __go_get_rune (const unsigned char *, size_t, int *);
+
+#endif /* !defined(LIBGO_GO_STRING_H) */
diff --git a/libgo/runtime/go-strplus.c b/libgo/runtime/go-strplus.c
new file mode 100644 (file)
index 0000000..c0cd356
--- /dev/null
@@ -0,0 +1,30 @@
+/* go-strplus.c -- the go string append function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-string.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_string_plus (struct __go_string s1, struct __go_string s2)
+{
+  int len;
+  unsigned char *retdata;
+  struct __go_string ret;
+
+  if (s1.__length == 0)
+    return s2;
+  else if (s2.__length == 0)
+    return s1;
+
+  len = s1.__length + s2.__length;
+  retdata = runtime_mallocgc (len, RefNoPointers, 1, 0);
+  __builtin_memcpy (retdata, s1.__data, s1.__length);
+  __builtin_memcpy (retdata + s1.__length, s2.__data, s2.__length);
+  ret.__data = retdata;
+  ret.__length = len;
+  return ret;
+}
diff --git a/libgo/runtime/go-strslice.c b/libgo/runtime/go-strslice.c
new file mode 100644 (file)
index 0000000..94ecee9
--- /dev/null
@@ -0,0 +1,26 @@
+/* go-strslice.c -- the go string slice function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-string.h"
+#include "go-panic.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_string_slice (struct __go_string s, int start, int end)
+{
+  int len;
+  struct __go_string ret;
+
+  len = s.__length;
+  if (end == -1)
+    end = len;
+  if (start > len || end < start || end > len)
+    __go_panic_msg ("string index out of bounds");
+  ret.__data = s.__data + start;
+  ret.__length = end - start;
+  return ret;
+}
diff --git a/libgo/runtime/go-trampoline.c b/libgo/runtime/go-trampoline.c
new file mode 100644 (file)
index 0000000..43003e8
--- /dev/null
@@ -0,0 +1,53 @@
+/* go-trampoline.c -- allocate a trampoline for a nested function.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "go-alloc.h"
+#include "go-assert.h"
+
+/* In order to build a trampoline we need space which is both writable
+   and executable.  We currently just allocate a whole page.  This
+   needs to be more system dependent.  */
+
+void *
+__go_allocate_trampoline (size_t size, void *closure)
+{
+  unsigned int page_size;
+  void *ret;
+  size_t off;
+
+  page_size = getpagesize ();
+  __go_assert (page_size >= size);
+  ret = __go_alloc (2 * page_size - 1);
+  ret = (void *) (((uintptr_t) ret + page_size - 1)
+                 & ~ ((uintptr_t) page_size - 1));
+
+  /* Because the garbage collector only looks at correct address
+     offsets, we need to ensure that it will see the closure
+     address.  */
+  off = ((size + sizeof (void *) - 1) / sizeof (void *)) * sizeof (void *);
+  __go_assert (size + off + sizeof (void *) <= page_size);
+  __builtin_memcpy (ret + off, &closure, sizeof (void *));
+
+#ifdef HAVE_SYS_MMAN_H
+  {
+    int i;
+    i = mprotect (ret, size, PROT_READ | PROT_WRITE | PROT_EXEC);
+    __go_assert (i == 0);
+  }
+#endif
+
+  return ret;
+}
diff --git a/libgo/runtime/go-type-eface.c b/libgo/runtime/go-type-eface.c
new file mode 100644 (file)
index 0000000..84ca05e
--- /dev/null
@@ -0,0 +1,55 @@
+/* go-type-eface.c -- hash and equality empty interface functions.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "interface.h"
+#include "go-type.h"
+
+/* A hash function for an empty interface.  */
+
+size_t
+__go_type_hash_empty_interface (const void *vval,
+                               size_t key_size __attribute__ ((unused)))
+{
+  const struct __go_empty_interface *val;
+  const struct __go_type_descriptor *descriptor;
+  size_t size;
+
+  val = (const struct __go_empty_interface *) vval;
+  descriptor = val->__type_descriptor;
+  if (descriptor == NULL)
+    return 0;
+  size = descriptor->__size;
+  if (__go_is_pointer_type (descriptor))
+    return descriptor->__hashfn (&val->__object, size);
+  else
+    return descriptor->__hashfn (val->__object, size);
+}
+
+/* An equality function for an empty interface.  */
+
+_Bool
+__go_type_equal_empty_interface (const void *vv1, const void *vv2,
+                                size_t key_size __attribute__ ((unused)))
+{
+  const struct __go_empty_interface *v1;
+  const struct __go_empty_interface *v2;
+  const struct __go_type_descriptor* v1_descriptor;
+  const struct __go_type_descriptor* v2_descriptor;
+
+  v1 = (const struct __go_empty_interface *) vv1;
+  v2 = (const struct __go_empty_interface *) vv2;
+  v1_descriptor = v1->__type_descriptor;
+  v2_descriptor = v2->__type_descriptor;
+  if (v1_descriptor == NULL || v2_descriptor == NULL)
+    return v1_descriptor == v2_descriptor;
+  if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor))
+    return 0;
+  if (__go_is_pointer_type (v1_descriptor))
+    return v1->__object == v2->__object;
+  else
+    return v1_descriptor->__equalfn (v1->__object, v2->__object,
+                                    v1_descriptor->__size);
+}
diff --git a/libgo/runtime/go-type-error.c b/libgo/runtime/go-type-error.c
new file mode 100644 (file)
index 0000000..865850c
--- /dev/null
@@ -0,0 +1,28 @@
+/* go-type-error.c -- invalid hash and equality functions.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-type.h"
+#include "go-panic.h"
+
+/* A hash function used for a type which does not support hash
+   functions.  */
+
+size_t
+__go_type_hash_error (const void *val __attribute__ ((unused)),
+                     size_t key_size __attribute__ ((unused)))
+{
+  __go_panic_msg ("hash of unhashable type");
+}
+
+/* An equality function for an interface.  */
+
+_Bool
+__go_type_equal_error (const void *v1 __attribute__ ((unused)),
+                      const void *v2 __attribute__ ((unused)),
+                      size_t key_size __attribute__ ((unused)))
+{
+  __go_panic_msg ("comparing uncomparable types");
+}
diff --git a/libgo/runtime/go-type-identity.c b/libgo/runtime/go-type-identity.c
new file mode 100644 (file)
index 0000000..f1de3c2
--- /dev/null
@@ -0,0 +1,50 @@
+/* go-type-identity.c -- hash and equality identity functions.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-type.h"
+
+/* Typedefs for accesses of different sizes.  */
+
+typedef int QItype __attribute__ ((mode (QI)));
+typedef int HItype __attribute__ ((mode (HI)));
+typedef int SItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+
+/* An identity hash function for a type.  This is used for types where
+   we can simply use the type value itself as a hash code.  This is
+   true of, e.g., integers and pointers.  */
+
+size_t
+__go_type_hash_identity (const void *key, size_t key_size)
+{
+  switch (key_size)
+    {
+    case 1:
+      return *(const QItype *) key;
+    case 2:
+      return *(const HItype *) key;
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+      return *(const SItype *) key;
+    default:
+      return *(const DItype *) key;
+    }
+}
+
+/* An identity equality function for a type.  This is used for types
+   where we can check for equality by checking that the values have
+   the same bits.  */
+
+_Bool
+__go_type_equal_identity (const void *k1, const void *k2, size_t key_size)
+{
+  return __builtin_memcmp (k1, k2, key_size) == 0;
+}
diff --git a/libgo/runtime/go-type-interface.c b/libgo/runtime/go-type-interface.c
new file mode 100644 (file)
index 0000000..9750b84
--- /dev/null
@@ -0,0 +1,55 @@
+/* go-type-interface.c -- hash and equality interface functions.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "interface.h"
+#include "go-type.h"
+
+/* A hash function for an interface.  */
+
+size_t
+__go_type_hash_interface (const void *vval,
+                         size_t key_size __attribute__ ((unused)))
+{
+  const struct __go_interface *val;
+  const struct __go_type_descriptor *descriptor;
+  size_t size;
+
+  val = (const struct __go_interface *) vval;
+  if (val->__methods == NULL)
+    return 0;
+  descriptor = (const struct __go_type_descriptor *) val->__methods[0];
+  size = descriptor->__size;
+  if (__go_is_pointer_type (descriptor))
+    return descriptor->__hashfn (&val->__object, size);
+  else
+    return descriptor->__hashfn (val->__object, size);
+}
+
+/* An equality function for an interface.  */
+
+_Bool
+__go_type_equal_interface (const void *vv1, const void *vv2,
+                          size_t key_size __attribute__ ((unused)))
+{
+  const struct __go_interface *v1;
+  const struct __go_interface *v2;
+  const struct __go_type_descriptor* v1_descriptor;
+  const struct __go_type_descriptor* v2_descriptor;
+
+  v1 = (const struct __go_interface *) vv1;
+  v2 = (const struct __go_interface *) vv2;
+  if (v1->__methods == NULL || v2->__methods == NULL)
+    return v1->__methods == v2->__methods;
+  v1_descriptor = (const struct __go_type_descriptor *) v1->__methods[0];
+  v2_descriptor = (const struct __go_type_descriptor *) v2->__methods[0];
+  if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor))
+    return 0;
+  if (__go_is_pointer_type (v1_descriptor))
+    return v1->__object == v2->__object;
+  else
+    return v1_descriptor->__equalfn (v1->__object, v2->__object,
+                                    v1_descriptor->__size);
+}
diff --git a/libgo/runtime/go-type-string.c b/libgo/runtime/go-type-string.c
new file mode 100644 (file)
index 0000000..998955d
--- /dev/null
@@ -0,0 +1,45 @@
+/* go-type-string.c -- hash and equality string functions.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-string.h"
+#include "go-type.h"
+
+/* A string hash function for a map.  */
+
+size_t
+__go_type_hash_string (const void *vkey,
+                      size_t key_size __attribute__ ((unused)))
+{
+  size_t ret;
+  const struct __go_string *key;
+  size_t len;
+  size_t i;
+  const unsigned char *p;
+
+  ret = 5381;
+  key = (const struct __go_string *) vkey;
+  len = key->__length;
+  for (i = 0, p = key->__data; i < len; i++, p++)
+    ret = ret * 33 + *p;
+  return ret;
+}
+
+/* A string equality function for a map.  */
+
+_Bool
+__go_type_equal_string (const void *vk1, const void *vk2,
+                       size_t key_size __attribute__ ((unused)))
+{
+  const struct __go_string *k1;
+  const struct __go_string *k2;
+
+  k1 = (const struct __go_string *) vk1;
+  k2 = (const struct __go_string *) vk2;
+  return (k1->__length == k2->__length
+         && __builtin_memcmp (k1->__data, k2->__data, k1->__length) == 0);
+}
diff --git a/libgo/runtime/go-type.h b/libgo/runtime/go-type.h
new file mode 100644 (file)
index 0000000..d8785b6
--- /dev/null
@@ -0,0 +1,311 @@
+/* go-type.h -- basic information for a Go type.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#ifndef LIBGO_GO_TYPE_H
+#define LIBGO_GO_TYPE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "go-string.h"
+#include "array.h"
+
+/* Many of the types in this file must match the data structures
+   generated by the compiler, and must also match the Go types which
+   appear in go/runtime/type.go and go/reflect/type.go.  */
+
+/* Type kinds.  These are used to get the type descriptor to use for
+   the type itself, when using unsafe.Typeof or unsafe.Reflect.  The
+   values here must match the values generated by the compiler (the
+   RUNTIME_TYPE_KIND_xxx values in gcc/go/types.h).  These are macros
+   rather than an enum to make it easy to change values in the future
+   and hard to get confused about it.
+
+   These correspond to the kind values used by the gc compiler.  */
+
+#define GO_BOOL 1
+#define GO_INT 2
+#define GO_INT8 3
+#define GO_INT16 4
+#define GO_INT32 5
+#define GO_INT64 6
+#define GO_UINT 7
+#define GO_UINT8 8
+#define GO_UINT16 9
+#define GO_UINT32 10
+#define GO_UINT64 11
+#define GO_UINTPTR 12
+#define GO_FLOAT 13
+#define GO_FLOAT32 14
+#define GO_FLOAT64 15
+#define GO_COMPLEX 16
+#define GO_COMPLEX64 17
+#define GO_COMPLEX128 18
+#define GO_ARRAY 19
+#define GO_CHAN 20
+#define GO_FUNC 21
+#define GO_INTERFACE 22
+#define GO_MAP 23
+#define GO_PTR 24
+#define GO_SLICE 25
+#define GO_STRING 26
+#define GO_STRUCT 27
+#define GO_UNSAFE_POINTER 28
+
+/* For each Go type the compiler constructs one of these structures.
+   This is used for type reflectin, interfaces, maps, and reference
+   counting.  */
+
+struct __go_type_descriptor
+{
+  /* The type code for this type, a value in enum __go_type_codes.
+     This is used by unsafe.Reflect and unsafe.Typeof to determine the
+     type descriptor to return for this type itself.  It is also used
+     by reflect.toType when mapping to a reflect Type structure.  */
+  unsigned char __code;
+
+  /* The alignment in bytes of a variable with this type.  */
+  unsigned char __align;
+
+  /* The alignment in bytes of a struct field with this type.  */
+  unsigned char __field_align;
+
+  /* The size in bytes of a value of this type.  Note that all types
+     in Go have a fixed size.  */
+  uintptr_t __size;
+
+  /* The type's hash code.  */
+  uint32_t __hash;
+
+  /* This function takes a pointer to a value of this type, and the
+     size of this type, and returns a hash code.  We pass the size
+     explicitly becaues it means that we can share a single instance
+     of this function for various different types.  */
+  size_t (*__hashfn) (const void *, size_t);
+
+  /* This function takes two pointers to values of this type, and the
+     size of this type, and returns whether the values are equal.  */
+  _Bool (*__equalfn) (const void *, const void *, size_t);
+
+  /* A string describing this type.  This is only used for
+     debugging.  */
+  const struct __go_string *__reflection;
+
+  /* A pointer to fields which are only used for some types.  */
+  const struct __go_uncommon_type *__uncommon;
+};
+
+/* The information we store for each method of a type.  */
+
+struct __go_method
+{
+  /* The name of the method.  */
+  const struct __go_string *__name;
+
+  /* This is NULL for an exported method, or the name of the package
+     where it lives.  */
+  const struct __go_string *__pkg_path;
+
+  /* The type of the method, without the receiver.  This will be a
+     function type.  */
+  const struct __go_type_descriptor *__mtype;
+
+  /* The type of the method, with the receiver.  This will be a
+     function type.  */
+  const struct __go_type_descriptor *__type;
+
+  /* A pointer to the code which implements the method.  This is
+     really a function pointer.  */
+  const void *__function;
+};
+
+/* Additional information that we keep for named types and for types
+   with methods.  */
+
+struct __go_uncommon_type
+{
+  /* The name of the type.  */
+  const struct __go_string *__name;
+
+  /* The type's package.  This is NULL for builtin types.  */
+  const struct __go_string *__pkg_path;
+
+  /* The type's methods.  This is an array of struct __go_method.  */
+  struct __go_open_array __methods;
+};
+
+/* The type descriptor for a fixed array type.  */
+
+struct __go_array_type
+{
+  /* Starts like all type descriptors.  */
+  struct __go_type_descriptor __common;
+
+  /* The element type.  */
+  struct __go_type_descriptor *__element_type;
+
+  /* The length of the array.  */
+  uintptr_t __len;
+};
+
+/* The type descriptor for a slice.  */
+
+struct __go_slice_type
+{
+  /* Starts like all other type descriptors.  */
+  struct __go_type_descriptor __common;
+
+  /* The element type.  */
+  struct __go_type_descriptor *__element_type;
+};
+
+/* The direction of a channel.  */
+#define CHANNEL_RECV_DIR 1
+#define CHANNEL_SEND_DIR 2
+#define CHANNEL_BOTH_DIR (CHANNEL_RECV_DIR | CHANNEL_SEND_DIR)
+
+/* The type descriptor for a channel.  */
+
+struct __go_channel_type
+{
+  /* Starts like all other type descriptors.  */
+  struct __go_type_descriptor __common;
+
+  /* The element type.  */
+  const struct __go_type_descriptor *__element_type;
+
+  /* The direction.  */
+  uintptr_t __dir;
+};
+
+/* The type descriptor for a function.  */
+
+struct __go_func_type
+{
+  /* Starts like all other type descriptors.  */
+  struct __go_type_descriptor __common;
+
+  /* Whether this is a varargs function.  If this is true, there will
+     be at least one parameter.  For "..." the last parameter type is
+     "interface{}".  For "... T" the last parameter type is "[]T".  */
+  _Bool __dotdotdot;
+
+  /* The input parameter types.  This is an array of pointers to
+     struct __go_type_descriptor.  */
+  struct __go_open_array __in;
+
+  /* The output parameter types.  This is an array of pointers to
+     struct __go_type_descriptor.  */
+  struct __go_open_array __out;
+};
+
+/* A method on an interface type.  */
+
+struct __go_interface_method
+{
+  /* The name of the method.  */
+  const struct __go_string *__name;
+
+  /* This is NULL for an exported method, or the name of the package
+     where it lives.  */
+  const struct __go_string *__pkg_path;
+
+  /* The real type of the method.  */
+  struct __go_type_descriptor *__type;
+};
+
+/* An interface type.  */
+
+struct __go_interface_type
+{
+  /* Starts like all other type descriptors.  */
+  struct __go_type_descriptor __common;
+
+  /* Array of __go_interface_method .  The methods are sorted in the
+     same order that they appear in the definition of the
+     interface.  */
+  struct __go_open_array __methods;
+};
+
+/* A map type.  */
+
+struct __go_map_type
+{
+  /* Starts like all other type descriptors.  */
+  struct __go_type_descriptor __common;
+
+  /* The map key type.  */
+  const struct __go_type_descriptor *__key_type;
+
+  /* The map value type.  */
+  const struct __go_type_descriptor *__val_type;
+};
+
+/* A pointer type.  */
+
+struct __go_ptr_type
+{
+  /* Starts like all other type descriptors.  */
+  struct __go_type_descriptor __common;
+
+  /* The type to which this points.  */
+  const struct __go_type_descriptor *__element_type;
+};
+
+/* A field in a structure.  */
+
+struct __go_struct_field
+{
+  /* The name of the field--NULL for an anonymous field.  */
+  const struct __go_string *__name;
+
+  /* This is NULL for an exported method, or the name of the package
+     where it lives.  */
+  const struct __go_string *__pkg_path;
+
+  /* The type of the field.  */
+  const struct __go_type_descriptor *__type;
+
+  /* The field tag, or NULL.  */
+  const struct __go_string *__tag;
+
+  /* The offset of the field in the struct.  */
+  uintptr_t __offset;
+};
+
+/* A struct type.  */
+
+struct __go_struct_type
+{
+  /* Starts like all other type descriptors.  */
+  struct __go_type_descriptor __common;
+
+  /* An array of struct __go_struct_field.  */
+  struct __go_open_array __fields;
+};
+
+/* Whether a type descriptor is a pointer.  */
+
+static inline _Bool
+__go_is_pointer_type (const struct __go_type_descriptor *td)
+{
+  return td->__code == GO_PTR || td->__code == GO_UNSAFE_POINTER;
+}
+
+extern _Bool
+__go_type_descriptors_equal(const struct __go_type_descriptor*,
+                           const struct __go_type_descriptor*);
+
+extern size_t __go_type_hash_identity (const void *, size_t);
+extern _Bool __go_type_equal_identity (const void *, const void *, size_t);
+extern size_t __go_type_hash_string (const void *, size_t);
+extern _Bool __go_type_equal_string (const void *, const void *, size_t);
+extern size_t __go_type_hash_interface (const void *, size_t);
+extern _Bool __go_type_equal_interface (const void *, const void *, size_t);
+extern size_t __go_type_hash_error (const void *, size_t);
+extern _Bool __go_type_equal_error (const void *, const void *, size_t);
+
+#endif /* !defined(LIBGO_GO_TYPE_H) */
diff --git a/libgo/runtime/go-typedesc-equal.c b/libgo/runtime/go-typedesc-equal.c
new file mode 100644 (file)
index 0000000..932519a
--- /dev/null
@@ -0,0 +1,38 @@
+/* go-typedesc-equal.c -- return whether two type descriptors are equal.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-string.h"
+#include "go-type.h"
+
+/* Compare type descriptors for equality.  This is necessary because
+   types may have different descriptors in different shared libraries.
+   Also, unnamed types may have multiple type descriptors even in a
+   single shared library.  */
+
+_Bool
+__go_type_descriptors_equal (const struct __go_type_descriptor *td1,
+                            const struct __go_type_descriptor *td2)
+{
+  if (td1 == td2)
+    return 1;
+  /* In a type switch we can get a NULL descriptor.  */
+  if (td1 == NULL || td2 == NULL)
+    return 0;
+  if (td1->__code != td2->__code || td1->__hash != td2->__hash)
+    return 0;
+  if (td1->__uncommon != NULL && td1->__uncommon->__name != NULL)
+    {
+      if (td2->__uncommon == NULL || td2->__uncommon->__name == NULL)
+       return 0;
+      return (__go_ptr_strings_equal (td1->__uncommon->__name,
+                                     td2->__uncommon->__name)
+             && __go_ptr_strings_equal (td1->__uncommon->__pkg_path,
+                                        td2->__uncommon->__pkg_path));
+    }
+  if (td2->__uncommon != NULL && td2->__uncommon->__name != NULL)
+    return 0;
+  return __go_ptr_strings_equal (td1->__reflection, td2->__reflection);
+}
diff --git a/libgo/runtime/go-typestring.c b/libgo/runtime/go-typestring.c
new file mode 100644 (file)
index 0000000..dcbbc65
--- /dev/null
@@ -0,0 +1,18 @@
+/* go-typestring.c -- the runtime.typestring function.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "interface.h"
+#include "go-type.h"
+#include "go-string.h"
+
+struct __go_string typestring(struct __go_empty_interface)
+  asm ("libgo_runtime.runtime.typestring");
+
+struct __go_string
+typestring (struct __go_empty_interface e)
+{
+  return *e.__type_descriptor->__reflection;
+}
diff --git a/libgo/runtime/go-unreflect.c b/libgo/runtime/go-unreflect.c
new file mode 100644 (file)
index 0000000..8860485
--- /dev/null
@@ -0,0 +1,30 @@
+/* go-unreflect.c -- implement unsafe.Unreflect for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-alloc.h"
+#include "go-type.h"
+#include "interface.h"
+
+/* Implement unsafe.Unreflect.  */
+
+struct __go_empty_interface Unreflect (struct __go_empty_interface type,
+                                      void *object)
+  asm ("libgo_unsafe.unsafe.Unreflect");
+
+struct __go_empty_interface
+Unreflect (struct __go_empty_interface type, void *object)
+{
+  struct __go_empty_interface ret;
+
+  /* FIXME: We should check __type_descriptor to verify that this is
+     really a type descriptor.  */
+  ret.__type_descriptor = type.__object;
+  if (__go_is_pointer_type (ret.__type_descriptor))
+    ret.__object = *(void **) object;
+  else
+    ret.__object = object;
+  return ret;
+}
diff --git a/libgo/runtime/go-unsafe-new.c b/libgo/runtime/go-unsafe-new.c
new file mode 100644 (file)
index 0000000..e55d415
--- /dev/null
@@ -0,0 +1,27 @@
+/* go-unsafe-new.c -- unsafe.New function for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-alloc.h"
+#include "go-type.h"
+#include "interface.h"
+
+/* Implement unsafe.New.  */
+
+void *New (struct __go_empty_interface type) asm ("libgo_unsafe.unsafe.New");
+
+/* The dynamic type of the argument will be a pointer to a type
+   descriptor.  */
+
+void *
+New (struct __go_empty_interface type)
+{
+  const struct __go_type_descriptor *descriptor;
+
+  /* FIXME: We should check __type_descriptor to verify that this is
+     really a type descriptor.  */
+  descriptor = (const struct __go_type_descriptor *) type.__object;
+  return __go_alloc (descriptor->__size);
+}
diff --git a/libgo/runtime/go-unsafe-newarray.c b/libgo/runtime/go-unsafe-newarray.c
new file mode 100644 (file)
index 0000000..3bea282
--- /dev/null
@@ -0,0 +1,28 @@
+/* go-unsafe-newarray.c -- unsafe.NewArray function for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "go-alloc.h"
+#include "go-type.h"
+#include "interface.h"
+
+/* Implement unsafe.NewArray.  */
+
+void *NewArray (struct __go_empty_interface type, int n)
+  asm ("libgo_unsafe.unsafe.NewArray");
+
+/* The dynamic type of the argument will be a pointer to a type
+   descriptor.  */
+
+void *
+NewArray (struct __go_empty_interface type, int n)
+{
+  const struct __go_type_descriptor *descriptor;
+
+  /* FIXME: We should check __type_descriptor to verify that this is
+     really a type descriptor.  */
+  descriptor = (const struct __go_type_descriptor *) type.__object;
+  return __go_alloc (descriptor->__size * n);
+}
diff --git a/libgo/runtime/go-unsafe-pointer.c b/libgo/runtime/go-unsafe-pointer.c
new file mode 100644 (file)
index 0000000..804360f
--- /dev/null
@@ -0,0 +1,97 @@
+/* go-unsafe-pointer.c -- unsafe.Pointer type descriptor for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-string.h"
+#include "go-type.h"
+
+/* This file provides the type descriptor for the unsafe.Pointer type.
+   The unsafe package is defined by the compiler itself, which means
+   that there is no package to compile to define the type
+   descriptor.  */
+
+extern const struct __go_type_descriptor unsafe_Pointer
+  asm ("__go_tdn_libgo_unsafe.unsafe.Pointer");
+
+/* Used to determine the field alignment.  */
+struct field_align
+{
+  char c;
+  void *p;
+};
+
+/* The reflection string.  */
+#define REFLECTION "unsafe.Pointer"
+static const struct __go_string reflection_string =
+{
+  (const unsigned char *) REFLECTION,
+  sizeof REFLECTION - 1
+};
+
+const struct __go_type_descriptor unsafe_Pointer =
+{
+  /* __code */
+  GO_UNSAFE_POINTER,
+  /* __align */
+  __alignof (void *),
+  /* __field_align */
+  offsetof (struct field_align, p) - 1,
+  /* __size */
+  sizeof (void *),
+  /* __hash */
+  78501163U,
+  /* __hashfn */
+  __go_type_hash_identity,
+  /* __equalfn */
+  __go_type_equal_identity,
+  /* __reflection */
+  &reflection_string,
+  /* __uncommon */
+  NULL
+};
+
+/* We also need the type descriptor for the pointer to unsafe.Pointer,
+   since any package which refers to that type descriptor will expect
+   it to be defined elsewhere.  */
+
+extern const struct __go_ptr_type pointer_unsafe_Pointer
+  asm ("__go_td_pN27_libgo_unsafe.unsafe.Pointer");
+
+/* The reflection string.  */
+#define PREFLECTION "*unsafe.Pointer"
+static const struct __go_string preflection_string =
+{
+  (const unsigned char *) PREFLECTION,
+  sizeof PREFLECTION - 1,
+};
+
+const struct __go_ptr_type pointer_unsafe_Pointer =
+{
+  /* __common */
+  {
+    /* __code */
+    GO_PTR,
+    /* __align */
+    __alignof (void *),
+    /* __field_align */
+    offsetof (struct field_align, p) - 1,
+    /* __size */
+    sizeof (void *),
+    /* __hash */
+    1256018616U,
+    /* __hashfn */
+    __go_type_hash_identity,
+    /* __equalfn */
+    __go_type_equal_identity,
+    /* __reflection */
+    &preflection_string,
+    /* __uncommon */
+    NULL
+  },
+  /* __element_type */
+  &unsafe_Pointer
+};
diff --git a/libgo/runtime/go-unwind.c b/libgo/runtime/go-unwind.c
new file mode 100644 (file)
index 0000000..cf586bb
--- /dev/null
@@ -0,0 +1,426 @@
+/* go-unwind.c -- unwind the stack for panic/recover.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "unwind.h"
+#define NO_SIZE_OF_ENCODED_VALUE
+#include "unwind-pe.h"
+
+#include "go-alloc.h"
+#include "go-defer.h"
+#include "go-panic.h"
+
+/* The code for a Go exception.  */
+
+#ifdef __ARM_EABI_UNWINDER__
+static const _Unwind_Exception_Class __go_exception_class =
+  { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
+#else
+static const _Unwind_Exception_Class __go_exception_class =
+  ((((((((_Unwind_Exception_Class) 'G' 
+         << 8 | (_Unwind_Exception_Class) 'N')
+        << 8 | (_Unwind_Exception_Class) 'U')
+       << 8 | (_Unwind_Exception_Class) 'C')
+      << 8 | (_Unwind_Exception_Class) 'G')
+     << 8 | (_Unwind_Exception_Class) 'O')
+    << 8 | (_Unwind_Exception_Class) '\0')
+   << 8 | (_Unwind_Exception_Class) '\0');
+#endif
+
+
+/* This function is called by exception handlers used when unwinding
+   the stack after a recovered panic.  The exception handler looks
+   like this:
+     __go_check_defer (frame);
+     return;
+   If we have not yet reached the frame we are looking for, we
+   continue unwinding.  */
+
+void
+__go_check_defer (void *frame)
+{
+  struct _Unwind_Exception *hdr;
+
+  if (__go_panic_defer == NULL)
+    {
+      /* Some other language has thrown an exception.  We know there
+        are no defer handlers, so there is nothing to do.  */
+    }
+  else if (__go_panic_defer->__is_foreign)
+    {
+      struct __go_panic_stack *n;
+      _Bool was_recovered;
+
+      /* Some other language has thrown an exception.  We need to run
+        the local defer handlers.  If they call recover, we stop
+        unwinding the stack here.  */
+
+      n = ((struct __go_panic_stack *)
+          __go_alloc (sizeof (struct __go_panic_stack)));
+
+      n->__arg.__type_descriptor = NULL;
+      n->__arg.__object = NULL;
+      n->__was_recovered = 0;
+      n->__is_foreign = 1;
+      n->__next = __go_panic_defer->__panic;
+      __go_panic_defer->__panic = n;
+
+      while (1)
+       {
+         struct __go_defer_stack *d;
+         void (*pfn) (void *);
+
+         d = __go_panic_defer->__defer;
+         if (d == NULL || d->__frame != frame || d->__pfn == NULL)
+           break;
+
+         pfn = d->__pfn;
+         __go_panic_defer->__defer = d->__next;
+
+         (*pfn) (d->__arg);
+
+         __go_free (d);
+
+         if (n->__was_recovered)
+           {
+             /* The recover function caught the panic thrown by some
+                other language.  */
+             break;
+           }
+       }
+
+      was_recovered = n->__was_recovered;
+      __go_panic_defer->__panic = n->__next;
+      __go_free (n);
+
+      if (was_recovered)
+       {
+         /* Just return and continue executing Go code.  */
+         return;
+       }
+    }
+  else if (__go_panic_defer->__defer != NULL
+          && __go_panic_defer->__defer->__pfn == NULL
+          && __go_panic_defer->__defer->__frame == frame)
+    {
+      struct __go_defer_stack *d;
+
+      /* This is the defer function which called recover.  Simply
+        return to stop the stack unwind, and let the Go code continue
+        to execute.  */
+      d = __go_panic_defer->__defer;
+      __go_panic_defer->__defer = d->__next;
+      __go_free (d);
+      return;
+    }
+
+  /* This is some other defer function.  It was already run by the
+     call to panic, or just above.  Rethrow the exception.  */
+
+  hdr = (struct _Unwind_Exception *) __go_panic_defer->__exception;
+
+#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
+  _Unwind_SjLj_Resume_or_Rethrow (hdr);
+#else
+#if defined(_LIBUNWIND_STD_ABI)
+  _Unwind_RaiseException (hdr);
+#else
+  _Unwind_Resume_or_Rethrow (hdr);
+#endif
+#endif
+
+  /* Rethrowing the exception should not return.  */
+  abort();
+}
+
+/* Unwind function calls until we reach the one which used a defer
+   function which called recover.  Each function which uses a defer
+   statement will have an exception handler, as shown above.  */
+
+void
+__go_unwind_stack ()
+{
+  struct _Unwind_Exception *hdr;
+
+  hdr = ((struct _Unwind_Exception *)
+        __go_alloc (sizeof (struct _Unwind_Exception)));
+  __builtin_memcpy (&hdr->exception_class, &__go_exception_class,
+                   sizeof hdr->exception_class);
+  hdr->exception_cleanup = NULL;
+
+  __go_panic_defer->__exception = hdr;
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+  _Unwind_SjLj_RaiseException (hdr);
+#else
+  _Unwind_RaiseException (hdr);
+#endif
+
+  /* Raising an exception should not return.  */
+  abort ();
+}
+
+/* The rest of this code is really similar to gcc/unwind-c.c and
+   libjava/exception.cc.  */
+
+typedef struct
+{
+  _Unwind_Ptr Start;
+  _Unwind_Ptr LPStart;
+  _Unwind_Ptr ttype_base;
+  const unsigned char *TType;
+  const unsigned char *action_table;
+  unsigned char ttype_encoding;
+  unsigned char call_site_encoding;
+} lsda_header_info;
+
+static const unsigned char *
+parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
+                  lsda_header_info *info)
+{
+  _uleb128_t tmp;
+  unsigned char lpstart_encoding;
+
+  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
+
+  /* Find @LPStart, the base to which landing pad offsets are relative.  */
+  lpstart_encoding = *p++;
+  if (lpstart_encoding != DW_EH_PE_omit)
+    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
+  else
+    info->LPStart = info->Start;
+
+  /* Find @TType, the base of the handler and exception spec type data.  */
+  info->ttype_encoding = *p++;
+  if (info->ttype_encoding != DW_EH_PE_omit)
+    {
+      p = read_uleb128 (p, &tmp);
+      info->TType = p + tmp;
+    }
+  else
+    info->TType = 0;
+
+  /* The encoding and length of the call-site table; the action table
+     immediately follows.  */
+  info->call_site_encoding = *p++;
+  p = read_uleb128 (p, &tmp);
+  info->action_table = p + tmp;
+
+  return p;
+}
+
+/* The personality function is invoked when unwinding the stack due to
+   a panic.  Its job is to find the cleanup and exception handlers to
+   run.  We can't split the stack here, because we won't be able to
+   unwind from that split.  */
+
+#ifdef __ARM_EABI_UNWINDER__
+/* ARM EABI personality routines must also unwind the stack.  */
+#define CONTINUE_UNWINDING \
+  do                                                           \
+    {                                                          \
+      if (__gnu_unwind_frame (ue_header, context) != _URC_OK)  \
+       return _URC_FAILURE;                                    \
+      return _URC_CONTINUE_UNWIND;                             \
+    }                                                          \
+  while (0)
+#else
+#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
+#endif
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+#define PERSONALITY_FUNCTION    __gccgo_personality_sj0
+#define __builtin_eh_return_data_regno(x) x
+#else
+#define PERSONALITY_FUNCTION    __gccgo_personality_v0
+#endif
+
+#ifdef __ARM_EABI_UNWINDER__
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
+                     struct _Unwind_Context *)
+  __attribute__ ((no_split_stack, flatten));
+
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (_Unwind_State state,
+                     struct _Unwind_Exception * ue_header,
+                     struct _Unwind_Context * context)
+#else
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
+                     struct _Unwind_Exception *, struct _Unwind_Context *)
+  __attribute__ ((no_split_stack, flatten));
+
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (int version,
+                     _Unwind_Action actions,
+                     _Unwind_Exception_Class exception_class,
+                     struct _Unwind_Exception *ue_header,
+                     struct _Unwind_Context *context)
+#endif
+{
+  lsda_header_info info;
+  const unsigned char *language_specific_data, *p, *action_record;
+  _Unwind_Ptr landing_pad, ip;
+  int ip_before_insn = 0;
+  _Bool is_foreign;
+
+#ifdef __ARM_EABI_UNWINDER__
+  _Unwind_Action actions;
+
+  switch (state & _US_ACTION_MASK)
+    {
+    case _US_VIRTUAL_UNWIND_FRAME:
+      actions = _UA_SEARCH_PHASE;
+      break;
+
+    case _US_UNWIND_FRAME_STARTING:
+      actions = _UA_CLEANUP_PHASE;
+      if (!(state & _US_FORCE_UNWIND)
+         && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
+       actions |= _UA_HANDLER_FRAME;
+      break;
+
+    case _US_UNWIND_FRAME_RESUME:
+      CONTINUE_UNWINDING;
+      break;
+
+    default:
+      std::abort();
+    }
+  actions |= state & _US_FORCE_UNWIND;
+
+  is_foreign = 0;
+
+  /* The dwarf unwinder assumes the context structure holds things like the
+     function and LSDA pointers.  The ARM implementation caches these in
+     the exception header (UCB).  To avoid rewriting everything we make the
+     virtual IP register point at the UCB.  */
+  ip = (_Unwind_Ptr) ue_header;
+  _Unwind_SetGR (context, 12, ip);
+#else
+  if (version != 1)
+    return _URC_FATAL_PHASE1_ERROR;
+
+  is_foreign = exception_class != __go_exception_class;
+#endif
+
+  language_specific_data = (const unsigned char *)
+    _Unwind_GetLanguageSpecificData (context);
+
+  /* If no LSDA, then there are no handlers or cleanups.  */
+  if (! language_specific_data)
+    CONTINUE_UNWINDING;
+
+  /* Parse the LSDA header.  */
+  p = parse_lsda_header (context, language_specific_data, &info);
+#ifdef HAVE_GETIPINFO
+  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
+#else
+  ip = _Unwind_GetIP (context);
+#endif
+  if (! ip_before_insn)
+    --ip;
+  landing_pad = 0;
+  action_record = NULL;
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+  /* The given "IP" is an index into the call-site table, with two
+     exceptions -- -1 means no-action, and 0 means terminate.  But
+     since we're using uleb128 values, we've not got random access
+     to the array.  */
+  if ((int) ip <= 0)
+    return _URC_CONTINUE_UNWIND;
+  else
+    {
+      _uleb128_t cs_lp, cs_action;
+      do
+       {
+         p = read_uleb128 (p, &cs_lp);
+         p = read_uleb128 (p, &cs_action);
+       }
+      while (--ip);
+
+      /* Can never have null landing pad for sjlj -- that would have
+        been indicated by a -1 call site index.  */
+      landing_pad = (_Unwind_Ptr)cs_lp + 1;
+      if (cs_action)
+       action_record = info.action_table + cs_action - 1;
+      goto found_something;
+    }
+#else
+  /* Search the call-site table for the action associated with this IP.  */
+  while (p < info.action_table)
+    {
+      _Unwind_Ptr cs_start, cs_len, cs_lp;
+      _uleb128_t cs_action;
+
+      /* Note that all call-site encodings are "absolute" displacements.  */
+      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
+      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
+      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
+      p = read_uleb128 (p, &cs_action);
+
+      /* The table is sorted, so if we've passed the ip, stop.  */
+      if (ip < info.Start + cs_start)
+       p = info.action_table;
+      else if (ip < info.Start + cs_start + cs_len)
+       {
+         if (cs_lp)
+           landing_pad = info.LPStart + cs_lp;
+         if (cs_action)
+           action_record = info.action_table + cs_action - 1;
+         goto found_something;
+       }
+    }
+#endif
+
+  /* IP is not in table.  No associated cleanups.  */
+  CONTINUE_UNWINDING;
+
+ found_something:
+  if (landing_pad == 0)
+    {
+      /* IP is present, but has a null landing pad.
+        No handler to be run.  */
+      CONTINUE_UNWINDING;
+    }
+
+  if (actions & _UA_SEARCH_PHASE)
+    {
+      if (action_record == 0)
+       {
+         /* This indicates a cleanup rather than an exception
+            handler.  */
+         CONTINUE_UNWINDING;
+       }
+
+      return _URC_HANDLER_FOUND;
+    }
+
+  /* It's possible for __go_panic_defer to be NULL here for an
+     exception thrown by a language other than Go.  */
+  if (__go_panic_defer == NULL)
+    {
+      if (!is_foreign)
+       abort ();
+    }
+  else
+    {
+      __go_panic_defer->__exception = ue_header;
+      __go_panic_defer->__is_foreign = is_foreign;
+    }
+
+  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
+                (_Unwind_Ptr) ue_header);
+  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
+  _Unwind_SetIP (context, landing_pad);
+  return _URC_INSTALL_CONTEXT;
+}
diff --git a/libgo/runtime/goc2c.c b/libgo/runtime/goc2c.c
new file mode 100644 (file)
index 0000000..bf74833
--- /dev/null
@@ -0,0 +1,735 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/* Translate a .goc file into a .c file.  A .goc file is a combination
+   of a limited form of Go with C.  */
+
+/*
+   package PACKAGENAME
+   {# line}
+   func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
+     C code with proper brace nesting
+   \}
+*/
+
+/* We generate C code which implements the function such that it can
+   be called from Go and executes the C code.  */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* Whether we're emitting for gcc */
+static int gcc;
+
+/* Package prefix to use; only meaningful for gcc */
+static const char *prefix;
+
+/* File and line number */
+static const char *file;
+static unsigned int lineno = 1;
+
+/* List of names and types.  */
+struct params {
+       struct params *next;
+       char *name;
+       char *type;
+};
+
+/* index into type_table */
+enum {
+       Bool,
+       Float,
+       Int,
+       Uint,
+       Uintptr,
+       String,
+       Slice,
+       Eface,
+};
+
+static struct {
+       char *name;
+       int size;
+} type_table[] = {
+       /* variable sized first, for easy replacement */
+       /* order matches enum above */
+       /* default is 32-bit architecture sizes */
+       "bool",         1,
+       "float",        4,
+       "int",          4,
+       "uint",         4,
+       "uintptr",      4,
+       "String",       8,
+       "Slice",        12,
+       "Eface",        8,
+
+       /* fixed size */
+       "float32",      4,
+       "float64",      8,
+       "byte",         1,
+       "int8",         1,
+       "uint8",        1,
+       "int16",        2,
+       "uint16",       2,
+       "int32",        4,
+       "uint32",       4,
+       "int64",        8,
+       "uint64",       8,
+
+       NULL,
+};
+
+/* Fixed structure alignment (non-gcc only) */
+int structround = 4;
+
+/* Unexpected EOF.  */
+static void
+bad_eof(void)
+{
+       fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno);
+       exit(1);
+}
+
+/* Out of memory.  */
+static void
+bad_mem(void)
+{
+       fprintf(stderr, "%s:%u: out of memory\n", file, lineno);
+       exit(1);
+}
+
+/* Allocate memory without fail.  */
+static void *
+xmalloc(unsigned int size)
+{
+       void *ret = malloc(size);
+       if (ret == NULL)
+               bad_mem();
+       return ret;
+}
+
+/* Reallocate memory without fail.  */
+static void*
+xrealloc(void *buf, unsigned int size)
+{
+       void *ret = realloc(buf, size);
+       if (ret == NULL)
+               bad_mem();
+       return ret;
+}
+
+/* Free a list of parameters.  */
+static void
+free_params(struct params *p)
+{
+       while (p != NULL) {
+               struct params *next;
+
+               next = p->next;
+               free(p->name);
+               free(p->type);
+               free(p);
+               p = next;
+       }
+}
+
+/* Read a character, tracking lineno.  */
+static int
+getchar_update_lineno(void)
+{
+       int c;
+
+       c = getchar();
+       if (c == '\n')
+               ++lineno;
+       return c;
+}
+
+/* Read a character, giving an error on EOF, tracking lineno.  */
+static int
+getchar_no_eof(void)
+{
+       int c;
+
+       c = getchar_update_lineno();
+       if (c == EOF)
+               bad_eof();
+       return c;
+}
+
+/* Read a character, skipping comments.  */
+static int
+getchar_skipping_comments(void)
+{
+       int c;
+
+       while (1) {
+               c = getchar_update_lineno();
+               if (c != '/')
+                       return c;
+
+               c = getchar();
+               if (c == '/') {
+                       do {
+                               c = getchar_update_lineno();
+                       } while (c != EOF && c != '\n');
+                       return c;
+               } else if (c == '*') {
+                       while (1) {
+                               c = getchar_update_lineno();
+                               if (c == EOF)
+                                       return EOF;
+                               if (c == '*') {
+                                       do {
+                                               c = getchar_update_lineno();
+                                       } while (c == '*');
+                                       if (c == '/')
+                                               break;
+                               }
+                       }
+               } else {
+                       ungetc(c, stdin);
+                       return '/';
+               }
+       }
+}
+
+/* Read and return a token.  Tokens are delimited by whitespace or by
+   [(),{}].  The latter are all returned as single characters.  */
+static char *
+read_token(void)
+{
+       int c;
+       char *buf;
+       unsigned int alc, off;
+       const char* delims = "(),{}";
+
+       while (1) {
+               c = getchar_skipping_comments();
+               if (c == EOF)
+                       return NULL;
+               if (!isspace(c))
+                       break;
+       }
+       alc = 16;
+       buf = xmalloc(alc + 1);
+       off = 0;
+       if (strchr(delims, c) != NULL) {
+               buf[off] = c;
+               ++off;
+       } else {
+               while (1) {
+                       if (off >= alc) {
+                               alc *= 2;
+                               buf = xrealloc(buf, alc + 1);
+                       }
+                       buf[off] = c;
+                       ++off;
+                       c = getchar_skipping_comments();
+                       if (c == EOF)
+                               break;
+                       if (isspace(c) || strchr(delims, c) != NULL) {
+                               if (c == '\n')
+                                       lineno--;
+                               ungetc(c, stdin);
+                               break;
+                       }
+               }
+       }
+       buf[off] = '\0';
+       return buf;
+}
+
+/* Read a token, giving an error on EOF.  */
+static char *
+read_token_no_eof(void)
+{
+       char *token = read_token();
+       if (token == NULL)
+               bad_eof();
+       return token;
+}
+
+/* Read the package clause, and return the package name.  */
+static char *
+read_package(void)
+{
+       char *token;
+
+       token = read_token_no_eof();
+       if (strcmp(token, "package") != 0) {
+               fprintf(stderr,
+                       "%s:%u: expected \"package\", got \"%s\"\n",
+                       file, lineno, token);
+               exit(1);
+       }
+       return read_token_no_eof();
+}
+
+/* Read and copy preprocessor lines.  */
+static void
+read_preprocessor_lines(void)
+{
+       while (1) {
+               int c;
+
+               do {
+                       c = getchar_skipping_comments();
+               } while (isspace(c));
+               if (c != '#') {
+                       ungetc(c, stdin);
+                       break;
+               }
+               putchar(c);
+               do {
+                       c = getchar_update_lineno();
+                       putchar(c);
+               } while (c != '\n');
+       }
+}
+
+/* Read a type in Go syntax and return a type in C syntax.  We only
+   permit basic types and pointers.  */
+static char *
+read_type(void)
+{
+       char *p, *op, *q;
+       int pointer_count;
+       unsigned int len;
+
+       p = read_token_no_eof();
+       if (*p != '*')
+               return p;
+       op = p;
+       pointer_count = 0;
+       while (*p == '*') {
+               ++pointer_count;
+               ++p;
+       }
+       len = strlen(p);
+       q = xmalloc(len + pointer_count + 1);
+       memcpy(q, p, len);
+       while (pointer_count > 0) {
+               q[len] = '*';
+               ++len;
+               --pointer_count;
+       }
+       q[len] = '\0';
+       free(op);
+       return q;
+}
+
+/* Return the size of the given type. */
+static int
+type_size(char *p)
+{
+       int i;
+
+       if(p[strlen(p)-1] == '*')
+               return type_table[Uintptr].size;
+
+       for(i=0; type_table[i].name; i++)
+               if(strcmp(type_table[i].name, p) == 0)
+                       return type_table[i].size;
+       if(!gcc) {
+               fprintf(stderr, "%s:%u: unknown type %s\n", file, lineno, p);
+               exit(1);
+       }
+       return 1;
+}
+
+/* Read a list of parameters.  Each parameter is a name and a type.
+   The list ends with a ')'.  We have already read the '('.  */
+static struct params *
+read_params(int *poffset)
+{
+       char *token;
+       struct params *ret, **pp, *p;
+       int offset, size, rnd;
+
+       ret = NULL;
+       pp = &ret;
+       token = read_token_no_eof();
+       offset = 0;
+       if (strcmp(token, ")") != 0) {
+               while (1) {
+                       p = xmalloc(sizeof(struct params));
+                       p->name = token;
+                       p->type = read_type();
+                       p->next = NULL;
+                       *pp = p;
+                       pp = &p->next;
+
+                       size = type_size(p->type);
+                       rnd = size;
+                       if(rnd > structround)
+                               rnd = structround;
+                       if(offset%rnd)
+                               offset += rnd - offset%rnd;
+                       offset += size;
+
+                       token = read_token_no_eof();
+                       if (strcmp(token, ",") != 0)
+                               break;
+                       token = read_token_no_eof();
+               }
+       }
+       if (strcmp(token, ")") != 0) {
+               fprintf(stderr, "%s:%u: expected '('\n",
+                       file, lineno);
+               exit(1);
+       }
+       if (poffset != NULL)
+               *poffset = offset;
+       return ret;
+}
+
+/* Read a function header.  This reads up to and including the initial
+   '{' character.  Returns 1 if it read a header, 0 at EOF.  */
+static int
+read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
+{
+       int lastline;
+       char *token;
+
+       lastline = -1;
+       while (1) {
+               token = read_token();
+               if (token == NULL)
+                       return 0;
+               if (strcmp(token, "func") == 0) {
+                       if(lastline != -1)
+                               printf("\n");
+                       break;
+               }
+               if (lastline != lineno) {
+                       if (lastline == lineno-1)
+                               printf("\n");
+                       else
+                               printf("\n#line %d \"%s\"\n", lineno, file);
+                       lastline = lineno;
+               }
+               printf("%s ", token);
+       }
+
+       *name = read_token_no_eof();
+
+       token = read_token();
+       if (token == NULL || strcmp(token, "(") != 0) {
+               fprintf(stderr, "%s:%u: expected \"(\"\n",
+                       file, lineno);
+               exit(1);
+       }
+       *params = read_params(paramwid);
+
+       token = read_token();
+       if (token == NULL || strcmp(token, "(") != 0)
+               *rets = NULL;
+       else {
+               *rets = read_params(NULL);
+               token = read_token();
+       }
+       if (token == NULL || strcmp(token, "{") != 0) {
+               fprintf(stderr, "%s:%u: expected \"{\"\n",
+                       file, lineno);
+               exit(1);
+       }
+       return 1;
+}
+
+/* Write out parameters.  */
+static void
+write_params(struct params *params, int *first)
+{
+       struct params *p;
+
+       for (p = params; p != NULL; p = p->next) {
+               if (*first)
+                       *first = 0;
+               else
+                       printf(", ");
+               printf("%s %s", p->type, p->name);
+       }
+}
+
+/* Write a 6g function header.  */
+static void
+write_6g_func_header(char *package, char *name, struct params *params,
+                    int paramwid, struct params *rets)
+{
+       int first, n;
+
+       printf("void\n%s·%s(", package, name);
+       first = 1;
+       write_params(params, &first);
+
+       /* insert padding to align output struct */
+       if(rets != NULL && paramwid%structround != 0) {
+               n = structround - paramwid%structround;
+               if(n & 1)
+                       printf(", uint8");
+               if(n & 2)
+                       printf(", uint16");
+               if(n & 4)
+                       printf(", uint32");
+       }
+
+       write_params(rets, &first);
+       printf(")\n{\n");
+}
+
+/* Write a 6g function trailer.  */
+static void
+write_6g_func_trailer(struct params *rets)
+{
+       struct params *p;
+
+       for (p = rets; p != NULL; p = p->next)
+               printf("\tFLUSH(&%s);\n", p->name);
+       printf("}\n");
+}
+
+/* Define the gcc function return type if necessary.  */
+static void
+define_gcc_return_type(char *package, char *name, struct params *rets)
+{
+       struct params *p;
+
+       if (rets == NULL || rets->next == NULL)
+               return;
+       printf("struct %s_%s_ret {\n", package, name);
+       for (p = rets; p != NULL; p = p->next)
+               printf("  %s %s;\n", p->type, p->name);
+       printf("};\n");
+}
+
+/* Write out the gcc function return type.  */
+static void
+write_gcc_return_type(char *package, char *name, struct params *rets)
+{
+       if (rets == NULL)
+               printf("void");
+       else if (rets->next == NULL)
+               printf("%s", rets->type);
+       else
+               printf("struct %s_%s_ret", package, name);
+}
+
+/* Write out a gcc function header.  */
+static void
+write_gcc_func_header(char *package, char *name, struct params *params,
+                     struct params *rets)
+{
+       int first;
+       struct params *p;
+
+       define_gcc_return_type(package, name, rets);
+       write_gcc_return_type(package, name, rets);
+       printf(" %s_%s(", package, name);
+       first = 1;
+       write_params(params, &first);
+       printf(") asm (\"");
+       if (prefix != NULL)
+         printf("%s.", prefix);
+       printf("%s.%s\");\n", package, name);
+       write_gcc_return_type(package, name, rets);
+       printf(" %s_%s(", package, name);
+       first = 1;
+       write_params(params, &first);
+       printf(")\n{\n");
+       for (p = rets; p != NULL; p = p->next)
+               printf("  %s %s;\n", p->type, p->name);
+}
+
+/* Write out a gcc function trailer.  */
+static void
+write_gcc_func_trailer(char *package, char *name, struct params *rets)
+{
+       if (rets == NULL)
+               ;
+       else if (rets->next == NULL)
+               printf("return %s;\n", rets->name);
+       else {
+               struct params *p;
+
+               printf("  {\n    struct %s_%s_ret __ret;\n", package, name);
+               for (p = rets; p != NULL; p = p->next)
+                       printf("    __ret.%s = %s;\n", p->name, p->name);
+               printf("    return __ret;\n  }\n");
+       }
+       printf("}\n");
+}
+
+/* Write out a function header.  */
+static void
+write_func_header(char *package, char *name,
+                 struct params *params, int paramwid,
+                 struct params *rets)
+{
+       if (gcc)
+               write_gcc_func_header(package, name, params, rets);
+       else
+               write_6g_func_header(package, name, params, paramwid, rets);
+       printf("#line %d \"%s\"\n", lineno, file);
+}
+
+/* Write out a function trailer.  */
+static void
+write_func_trailer(char *package, char *name,
+                  struct params *rets)
+{
+       if (gcc)
+               write_gcc_func_trailer(package, name, rets);
+       else
+               write_6g_func_trailer(rets);
+}
+
+/* Read and write the body of the function, ending in an unnested }
+   (which is read but not written).  */
+static void
+copy_body(void)
+{
+       int nesting = 0;
+       while (1) {
+               int c;
+
+               c = getchar_no_eof();
+               if (c == '}' && nesting == 0)
+                       return;
+               putchar(c);
+               switch (c) {
+               default:
+                       break;
+               case '{':
+                       ++nesting;
+                       break;
+               case '}':
+                       --nesting;
+                       break;
+               case '/':
+                       c = getchar_update_lineno();
+                       putchar(c);
+                       if (c == '/') {
+                               do {
+                                       c = getchar_no_eof();
+                                       putchar(c);
+                               } while (c != '\n');
+                       } else if (c == '*') {
+                               while (1) {
+                                       c = getchar_no_eof();
+                                       putchar(c);
+                                       if (c == '*') {
+                                               do {
+                                                       c = getchar_no_eof();
+                                                       putchar(c);
+                                               } while (c == '*');
+                                               if (c == '/')
+                                                       break;
+                                       }
+                               }
+                       }
+                       break;
+               case '"':
+               case '\'':
+                       {
+                               int delim = c;
+                               do {
+                                       c = getchar_no_eof();
+                                       putchar(c);
+                                       if (c == '\\') {
+                                               c = getchar_no_eof();
+                                               putchar(c);
+                                               c = '\0';
+                                       }
+                               } while (c != delim);
+                       }
+                       break;
+               }
+       }
+}
+
+/* Process the entire file.  */
+static void
+process_file(void)
+{
+       char *package, *name;
+       struct params *params, *rets;
+       int paramwid;
+
+       package = read_package();
+       read_preprocessor_lines();
+       while (read_func_header(&name, &params, &paramwid, &rets)) {
+               write_func_header(package, name, params, paramwid, rets);
+               copy_body();
+               write_func_trailer(package, name, rets);
+               free(name);
+               free_params(params);
+               free_params(rets);
+       }
+       free(package);
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n");
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       char *goarch;
+
+       while(argc > 1 && argv[1][0] == '-') {
+               if(strcmp(argv[1], "-") == 0)
+                       break;
+               if(strcmp(argv[1], "--6g") == 0)
+                       gcc = 0;
+               else if(strcmp(argv[1], "--gcc") == 0)
+                       gcc = 1;
+               else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
+                       prefix = argv[2];
+                       argc--;
+                       argv++;
+               } else
+                       usage();
+               argc--;
+               argv++;
+       }
+
+       if(argc <= 1 || strcmp(argv[1], "-") == 0) {
+               file = "<stdin>";
+               process_file();
+               return 0;
+       }
+
+       if(argc > 2)
+               usage();
+
+       file = argv[1];
+       if(freopen(file, "r", stdin) == 0) {
+               fprintf(stderr, "open %s: %s\n", file, strerror(errno));
+               exit(1);
+       }
+
+       if(!gcc) {
+               // 6g etc; update size table
+               goarch = getenv("GOARCH");
+               if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
+                       type_table[Uintptr].size = 8;
+                       type_table[String].size = 16;
+                       type_table[Slice].size = 8+4+4;
+                       type_table[Eface].size = 8+8;
+                       structround = 8;
+               }
+       }
+
+       process_file();
+       return 0;
+}
diff --git a/libgo/runtime/iface.goc b/libgo/runtime/iface.goc
new file mode 100644 (file)
index 0000000..356b318
--- /dev/null
@@ -0,0 +1,131 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "go-type.h"
+#include "interface.h"
+#define nil NULL
+
+typedef _Bool bool;
+typedef struct __go_type_descriptor descriptor;
+typedef const struct __go_type_descriptor const_descriptor;
+typedef struct __go_interface interface;
+typedef struct __go_empty_interface empty_interface;
+
+// Compare two type descriptors.
+func ifacetypeeq(a *descriptor, b *descriptor) (eq bool) {
+       eq = __go_type_descriptors_equal(a, b);
+}
+
+// Return the descriptor for an empty interface type.n
+func efacetype(e empty_interface) (d *const_descriptor) {
+       return e.__type_descriptor;
+}
+
+// Return the descriptor for a non-empty interface type.
+func ifacetype(i interface) (d *const_descriptor) {
+       if (i.__methods == nil) {
+               return nil;
+       }
+       d = i.__methods[0];
+}
+
+// Convert an empty interface to an empty interface.
+func ifaceE2E2(e empty_interface) (ret empty_interface, ok bool) {
+       ret = e;
+       ok = ret.__type_descriptor != nil;
+}
+
+// Convert a non-empty interface to an empty interface.
+func ifaceI2E2(i interface) (ret empty_interface, ok bool) {
+       if (i.__methods == nil) {
+               ret.__type_descriptor = nil;
+               ret.__object = nil;
+               ok = 0;
+       } else {
+               ret.__type_descriptor = i.__methods[0];
+               ret.__object = i.__object;
+               ok = 1;
+       }
+}
+
+// Convert an empty interface to a non-empty interface.
+func ifaceE2I2(inter *descriptor, e empty_interface) (ret interface, ok bool) {
+       if (e.__type_descriptor == nil) {
+               ret.__methods = nil;
+               ret.__object = nil;
+               ok = 0;
+       } else {
+               ret.__methods = __go_convert_interface_2(inter,
+                                                        e.__type_descriptor,
+                                                        1);
+               ret.__object = e.__object;
+               ok = ret.__methods != nil;
+       }
+}
+
+// Convert a non-empty interface to a non-empty interface.
+func ifaceI2I2(inter *descriptor, i interface) (ret interface, ok bool) {
+       if (i.__methods == nil) {
+               ret.__methods = nil;
+               ret.__object = nil;
+               ok = 0;
+       } else {
+               ret.__methods = __go_convert_interface_2(inter,
+                                                        i.__methods[0], 1);
+               ret.__object = i.__object;
+               ok = ret.__methods != nil;
+       }
+}
+
+// Convert an empty interface to a pointer type.
+func ifaceE2T2P(inter *descriptor, e empty_interface) (ret *void, ok bool) {
+       if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
+               ret = nil;
+               ok = 0;
+       } else {
+               ret = e.__object;
+               ok = 1;
+       }
+}
+
+// Convert a non-empty interface to a pointer type.
+func ifaceI2T2P(inter *descriptor, i interface) (ret *void, ok bool) {
+       if (i.__methods == nil
+           || !__go_type_descriptors_equal(inter, i.__methods[0])) {
+               ret = nil;
+               ok = 0;
+       } else {
+               ret = i.__object;
+               ok = 1;
+       }
+}
+
+// Convert an empty interface to a non-pointer type.
+func ifaceE2T2(inter *descriptor, e empty_interface, ret *void) (ok bool) {
+       if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
+               __builtin_memset(ret, 0, inter->__size);
+               ok = 0;
+       } else {
+               __builtin_memcpy(ret, e.__object, inter->__size);
+               ok = 1;
+       }
+}
+
+// Convert a non-empty interface to a non-pointer type.
+func ifaceI2T2(inter *descriptor, i interface, ret *void) (ok bool) {
+       if (i.__methods == nil
+           || !__go_type_descriptors_equal(inter, i.__methods[0])) {
+               __builtin_memset(ret, 0, inter->__size);
+               ok = 0;
+       } else {
+               __builtin_memcpy(ret, i.__object, inter->__size);
+               ok = 1;
+       }
+}
+
+// Return whether we can convert an interface to a type.
+func ifaceI2Tp(to *descriptor, from *descriptor) (ok bool) {
+       ok = __go_can_convert_to_interface(to, from);
+}
diff --git a/libgo/runtime/interface.h b/libgo/runtime/interface.h
new file mode 100644 (file)
index 0000000..610f208
--- /dev/null
@@ -0,0 +1,57 @@
+/* interface.h -- the interface type for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#ifndef LIBGO_INTERFACE_H
+#define LIBGO_INTERFACE_H
+
+#include "go-type.h"
+
+/* A variable of interface type is an instance of this struct, if the
+   interface has any methods.  */
+
+struct __go_interface
+{
+  /* A pointer to the interface method table.  The first pointer is
+     the type descriptor of the object.  Subsequent pointers are
+     pointers to functions.  This is effectively the vtable for this
+     interface.  The function pointers are in the same order as the
+     list in the internal representation of the interface, which sorts
+     them by name.  */
+  const void **__methods;
+
+  /* The object.  If the object is a pointer--if the type descriptor
+     code is GO_PTR or GO_UNSAFE_POINTER--then this field is the value
+     of the object itself.  Otherwise this is a pointer to memory
+     which holds the value.  */
+  void *__object;
+};
+
+/* A variable of an empty interface type is an instance of this
+   struct.  */
+
+struct __go_empty_interface
+{
+  /* The type descriptor of the object.  */
+  const struct __go_type_descriptor *__type_descriptor;
+
+  /* The object.  This is the same as __go_interface above.  */
+  void *__object;
+};
+
+extern void *
+__go_convert_interface (const struct __go_type_descriptor *,
+                       const struct __go_type_descriptor *);
+
+extern void *
+__go_convert_interface_2 (const struct __go_type_descriptor *,
+                         const struct __go_type_descriptor *,
+                         _Bool may_fail);
+
+extern _Bool
+__go_can_convert_to_interface(const struct __go_type_descriptor *,
+                             const struct __go_type_descriptor *);
+
+#endif /* !defined(LIBGO_INTERFACE_H) */
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
new file mode 100644 (file)
index 0000000..cde09aa
--- /dev/null
@@ -0,0 +1,341 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// See malloc.h for overview.
+//
+// TODO(rsc): double-check stats.
+
+package runtime
+#include <stddef.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "go-alloc.h"
+#include "runtime.h"
+#include "malloc.h"
+#include "go-string.h"
+#include "interface.h"
+#include "go-type.h"
+typedef struct __go_empty_interface Eface;
+typedef struct __go_type_descriptor Type;
+typedef struct __go_func_type FuncType;
+
+MHeap runtime_mheap;
+extern MStats mstats;  // defined in extern.go
+
+extern volatile int32 runtime_MemProfileRate
+  __asm__ ("libgo_runtime.runtime.MemProfileRate");
+
+// Same algorithm from chan.c, but a different
+// instance of the static uint32 x.
+// Not protected by a lock - let the threads use
+// the same random number if they like.
+static uint32
+fastrand1(void)
+{
+       static uint32 x = 0x49f6428aUL;
+
+       x += x;
+       if(x & 0x80000000L)
+               x ^= 0x88888eefUL;
+       return x;
+}
+
+// Allocate an object of at least size bytes.
+// Small objects are allocated from the per-thread cache's free lists.
+// Large objects (> 32 kB) are allocated straight from the heap.
+void*
+runtime_mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
+{
+       int32 sizeclass, rate;
+       MCache *c;
+       uintptr npages;
+       MSpan *s;
+       void *v;
+       uint32 *ref;
+
+       if(!__sync_bool_compare_and_swap(&m->mallocing, 0, 1))
+               runtime_throw("malloc/free - deadlock");
+       if(size == 0)
+               size = 1;
+
+       mstats.nmalloc++;
+       if(size <= MaxSmallSize) {
+               // Allocate from mcache free lists.
+               sizeclass = runtime_SizeToClass(size);
+               size = runtime_class_to_size[sizeclass];
+               c = m->mcache;
+               v = runtime_MCache_Alloc(c, sizeclass, size, zeroed);
+               if(v == nil)
+                       runtime_throw("out of memory");
+               mstats.alloc += size;
+               mstats.total_alloc += size;
+               mstats.by_size[sizeclass].nmalloc++;
+
+               if(!runtime_mlookup(v, nil, nil, nil, &ref)) {
+                       // runtime_printf("malloc %D; runtime_mlookup failed\n", (uint64)size);
+                       runtime_throw("malloc runtime_mlookup");
+               }
+               *ref = RefNone | refflag;
+       } else {
+               // TODO(rsc): Report tracebacks for very large allocations.
+
+               // Allocate directly from heap.
+               npages = size >> PageShift;
+               if((size & PageMask) != 0)
+                       npages++;
+               s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1);
+               if(s == nil)
+                       runtime_throw("out of memory");
+               size = npages<<PageShift;
+               mstats.alloc += size;
+               mstats.total_alloc += size;
+               v = (void*)(s->start << PageShift);
+
+               // setup for mark sweep
+               s->gcref0 = RefNone | refflag;
+               ref = &s->gcref0;
+       }
+
+       __sync_bool_compare_and_swap(&m->mallocing, 1, 0);
+
+       if(__sync_bool_compare_and_swap(&m->gcing, 1, 0)) {
+               if(!(refflag & RefNoProfiling))
+                       __go_run_goroutine_gc(0);
+               else {
+                       // We are being called from the profiler.  Tell it
+                       // to invoke the garbage collector when it is
+                       // done.  No need to use a sync function here.
+                       m->gcing_for_prof = 1;
+               }
+       }
+
+       if(!(refflag & RefNoProfiling) && (rate = runtime_MemProfileRate) > 0) {
+               if(size >= (uint32) rate)
+                       goto profile;
+               if((uint32) m->mcache->next_sample > size)
+                       m->mcache->next_sample -= size;
+               else {
+                       // pick next profile time
+                       if(rate > 0x3fffffff)   // make 2*rate not overflow
+                               rate = 0x3fffffff;
+                       m->mcache->next_sample = fastrand1() % (2*rate);
+               profile:
+                       *ref |= RefProfiled;
+                       runtime_MProf_Malloc(v, size);
+               }
+       }
+
+       if(dogc && mstats.heap_alloc >= mstats.next_gc)
+               runtime_gc(0);
+       return v;
+}
+
+void*
+__go_alloc(uintptr size)
+{
+       return runtime_mallocgc(size, 0, 0, 1);
+}
+
+// Free the object whose base pointer is v.
+void
+__go_free(void *v)
+{
+       int32 sizeclass, size;
+       MSpan *s;
+       MCache *c;
+       uint32 prof, *ref;
+
+       if(v == nil)
+               return;
+
+       if(!__sync_bool_compare_and_swap(&m->mallocing, 0, 1))
+               runtime_throw("malloc/free - deadlock");
+
+       if(!runtime_mlookup(v, nil, nil, &s, &ref)) {
+               // runtime_printf("free %p: not an allocated block\n", v);
+               runtime_throw("free runtime_mlookup");
+       }
+       prof = *ref & RefProfiled;
+       *ref = RefFree;
+
+       // Find size class for v.
+       sizeclass = s->sizeclass;
+       if(sizeclass == 0) {
+               // Large object.
+               if(prof)
+                       runtime_MProf_Free(v, s->npages<<PageShift);
+               mstats.alloc -= s->npages<<PageShift;
+               runtime_memclr(v, s->npages<<PageShift);
+               runtime_MHeap_Free(&runtime_mheap, s, 1);
+       } else {
+               // Small object.
+               c = m->mcache;
+               size = runtime_class_to_size[sizeclass];
+               if(size > (int32)sizeof(uintptr))
+                       ((uintptr*)v)[1] = 1;   // mark as "needs to be zeroed"
+               if(prof)
+                       runtime_MProf_Free(v, size);
+               mstats.alloc -= size;
+               mstats.by_size[sizeclass].nfree++;
+               runtime_MCache_Free(c, v, sizeclass, size);
+       }
+       __sync_bool_compare_and_swap(&m->mallocing, 1, 0);
+
+       if(__sync_bool_compare_and_swap(&m->gcing, 1, 0))
+               __go_run_goroutine_gc(1);
+}
+
+int32
+runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
+{
+       uintptr n, nobj, i;
+       byte *p;
+       MSpan *s;
+
+       mstats.nlookup++;
+       s = runtime_MHeap_LookupMaybe(&runtime_mheap, (uintptr)v>>PageShift);
+       if(sp)
+               *sp = s;
+       if(s == nil) {
+               if(base)
+                       *base = nil;
+               if(size)
+                       *size = 0;
+               if(ref)
+                       *ref = 0;
+               return 0;
+       }
+
+       p = (byte*)((uintptr)s->start<<PageShift);
+       if(s->sizeclass == 0) {
+               // Large object.
+               if(base)
+                       *base = p;
+               if(size)
+                       *size = s->npages<<PageShift;
+               if(ref)
+                       *ref = &s->gcref0;
+               return 1;
+       }
+
+       if((byte*)v >= (byte*)s->gcref) {
+               // pointers into the gc ref counts
+               // do not count as pointers.
+               return 0;
+       }
+
+       n = runtime_class_to_size[s->sizeclass];
+       i = ((byte*)v - p)/n;
+       if(base)
+               *base = p + i*n;
+       if(size)
+               *size = n;
+
+       // good for error checking, but expensive
+       if(0) {
+               nobj = (s->npages << PageShift) / (n + RefcountOverhead);
+               if((byte*)s->gcref < p || (byte*)(s->gcref+nobj) > p+(s->npages<<PageShift)) {
+                       // runtime_printf("odd span state=%d span=%p base=%p sizeclass=%d n=%D size=%D npages=%D\n",
+                       //      s->state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages);
+                       // runtime_printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n",
+                       //      s->sizeclass, v, p, s->gcref, (uint64)s->npages<<PageShift,
+                       //      (uint64)nobj, (uint64)n, s->gcref + nobj, p+(s->npages<<PageShift));
+                       runtime_throw("bad gcref");
+               }
+       }
+       if(ref)
+               *ref = &s->gcref[i];
+
+       return 1;
+}
+
+MCache*
+runtime_allocmcache(void)
+{
+       MCache *c;
+
+       runtime_lock(&runtime_mheap);
+       c = runtime_FixAlloc_Alloc(&runtime_mheap.cachealloc);
+
+       // Clear the free list used by FixAlloc; assume the rest is zeroed.
+       c->list[0].list = nil;
+
+       mstats.mcache_inuse = runtime_mheap.cachealloc.inuse;
+       mstats.mcache_sys = runtime_mheap.cachealloc.sys;
+       runtime_unlock(&runtime_mheap);
+       return c;
+}
+
+void
+runtime_mallocinit(void)
+{
+       runtime_SysMemInit();
+       runtime_InitSizes();
+       runtime_MHeap_Init(&runtime_mheap, runtime_SysAlloc);
+       m->mcache = runtime_allocmcache();
+
+       // See if it works.
+       runtime_free(runtime_malloc(1));
+}
+
+// Runtime stubs.
+
+void*
+runtime_mal(uintptr n)
+{
+       return runtime_mallocgc(n, 0, 1, 1);
+}
+
+func Alloc(n uintptr) (p *byte) {
+       p = runtime_malloc(n);
+}
+
+func Free(p *byte) {
+       runtime_free(p);
+}
+
+func Lookup(p *byte) (base *byte, size uintptr) {
+       runtime_mlookup(p, &base, &size, nil, nil);
+}
+
+func GC() {
+       runtime_gc(1);
+}
+
+func SetFinalizer(obj Eface, finalizer Eface) {
+       byte *base;
+       uintptr size;
+       const FuncType *ft;
+
+       if(obj.__type_descriptor == nil) {
+               // runtime_printf("runtime.SetFinalizer: first argument is nil interface\n");
+       throw:
+               runtime_throw("runtime.SetFinalizer");
+       }
+       if(obj.__type_descriptor->__code != GO_PTR) {
+               // runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
+               goto throw;
+       }
+       if(!runtime_mlookup(obj.__object, &base, &size, nil, nil) || obj.__object != base) {
+               // runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
+               goto throw;
+       }
+       ft = nil;
+       if(finalizer.__type_descriptor != nil) {
+               if(finalizer.__type_descriptor->__code != GO_FUNC) {
+               badfunc:
+                       // runtime_printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
+                       goto throw;
+               }
+               ft = (const FuncType*)finalizer.__type_descriptor;
+               if(ft->__dotdotdot || ft->__in.__count != 1 || !__go_type_descriptors_equal(*(Type**)ft->__in.__values, obj.__type_descriptor))
+                       goto badfunc;
+
+               if(runtime_getfinalizer(obj.__object, 0)) {
+                       // runtime_printf("runtime.SetFinalizer: finalizer already set");
+                       goto throw;
+               }
+       }
+       runtime_addfinalizer(obj.__object, finalizer.__type_descriptor != nil ? *(void**)finalizer.__object : nil, ft);
+}
diff --git a/libgo/runtime/malloc.h b/libgo/runtime/malloc.h
new file mode 100644 (file)
index 0000000..600b3b1
--- /dev/null
@@ -0,0 +1,400 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Memory allocator, based on tcmalloc.
+// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
+
+// The main allocator works in runs of pages.
+// Small allocation sizes (up to and including 32 kB) are
+// rounded to one of about 100 size classes, each of which
+// has its own free list of objects of exactly that size.
+// Any free page of memory can be split into a set of objects
+// of one size class, which are then managed using free list
+// allocators.
+//
+// The allocator's data structures are:
+//
+//     FixAlloc: a free-list allocator for fixed-size objects,
+//             used to manage storage used by the allocator.
+//     MHeap: the malloc heap, managed at page (4096-byte) granularity.
+//     MSpan: a run of pages managed by the MHeap.
+//     MHeapMap: a mapping from page IDs to MSpans.
+//     MCentral: a shared free list for a given size class.
+//     MCache: a per-thread (in Go, per-M) cache for small objects.
+//     MStats: allocation statistics.
+//
+// Allocating a small object proceeds up a hierarchy of caches:
+//
+//     1. Round the size up to one of the small size classes
+//        and look in the corresponding MCache free list.
+//        If the list is not empty, allocate an object from it.
+//        This can all be done without acquiring a lock.
+//
+//     2. If the MCache free list is empty, replenish it by
+//        taking a bunch of objects from the MCentral free list.
+//        Moving a bunch amortizes the cost of acquiring the MCentral lock.
+//
+//     3. If the MCentral free list is empty, replenish it by
+//        allocating a run of pages from the MHeap and then
+//        chopping that memory into a objects of the given size.
+//        Allocating many objects amortizes the cost of locking
+//        the heap.
+//
+//     4. If the MHeap is empty or has no page runs large enough,
+//        allocate a new group of pages (at least 1MB) from the
+//        operating system.  Allocating a large run of pages
+//        amortizes the cost of talking to the operating system.
+//
+// Freeing a small object proceeds up the same hierarchy:
+//
+//     1. Look up the size class for the object and add it to
+//        the MCache free list.
+//
+//     2. If the MCache free list is too long or the MCache has
+//        too much memory, return some to the MCentral free lists.
+//
+//     3. If all the objects in a given span have returned to
+//        the MCentral list, return that span to the page heap.
+//
+//     4. If the heap has too much memory, return some to the
+//        operating system.
+//
+//     TODO(rsc): Step 4 is not implemented.
+//
+// Allocating and freeing a large object uses the page heap
+// directly, bypassing the MCache and MCentral free lists.
+//
+// The small objects on the MCache and MCentral free lists
+// may or may not be zeroed.  They are zeroed if and only if
+// the second word of the object is zero.  The spans in the
+// page heap are always zeroed.  When a span full of objects
+// is returned to the page heap, the objects that need to be
+// are zeroed first.  There are two main benefits to delaying the
+// zeroing this way:
+//
+//     1. stack frames allocated from the small object lists
+//        can avoid zeroing altogether.
+//     2. the cost of zeroing when reusing a small object is
+//        charged to the mutator, not the garbage collector.
+//
+// This C code was written with an eye toward translating to Go
+// in the future.  Methods have the form Type_Method(Type *t, ...).
+
+typedef struct FixAlloc        FixAlloc;
+typedef struct MCentral        MCentral;
+typedef struct MHeap   MHeap;
+typedef struct MHeapMap        MHeapMap;
+typedef struct MSpan   MSpan;
+typedef struct MStats  MStats;
+typedef struct MLink   MLink;
+
+enum
+{
+       PageShift       = 12,
+       PageSize        = 1<<PageShift,
+       PageMask        = PageSize - 1,
+};
+typedef        uintptr PageID;         // address >> PageShift
+
+enum
+{
+       // Tunable constants.
+       NumSizeClasses = 67,            // Number of size classes (must match msize.c)
+       MaxSmallSize = 32<<10,
+
+       FixAllocChunk = 128<<10,        // Chunk size for FixAlloc
+       MaxMCacheListLen = 256,         // Maximum objects on MCacheList
+       MaxMCacheSize = 2<<20,          // Maximum bytes in one MCache
+       MaxMHeapList = 1<<(20 - PageShift),     // Maximum page length for fixed-size list in MHeap.
+       HeapAllocChunk = 1<<20,         // Chunk size for heap growth
+};
+
+#if __SIZEOF_POINTER__ == 8
+#include "mheapmap64.h"
+#else
+#include "mheapmap32.h"
+#endif
+
+// A generic linked list of blocks.  (Typically the block is bigger than sizeof(MLink).)
+struct MLink
+{
+       MLink *next;
+};
+
+// SysAlloc obtains a large chunk of zeroed memory from the
+// operating system, typically on the order of a hundred kilobytes
+// or a megabyte.
+//
+// SysUnused notifies the operating system that the contents
+// of the memory region are no longer needed and can be reused
+// for other purposes.  The program reserves the right to start
+// accessing those pages in the future.
+//
+// SysFree returns it unconditionally; this is only used if
+// an out-of-memory error has been detected midway through
+// an allocation.  It is okay if SysFree is a no-op.
+
+void*  runtime_SysAlloc(uintptr nbytes);
+void   runtime_SysFree(void *v, uintptr nbytes);
+void   runtime_SysUnused(void *v, uintptr nbytes);
+void   runtime_SysMemInit(void);
+
+// FixAlloc is a simple free-list allocator for fixed size objects.
+// Malloc uses a FixAlloc wrapped around SysAlloc to manages its
+// MCache and MSpan objects.
+//
+// Memory returned by FixAlloc_Alloc is not zeroed.
+// The caller is responsible for locking around FixAlloc calls.
+// Callers can keep state in the object but the first word is
+// smashed by freeing and reallocating.
+struct FixAlloc
+{
+       uintptr size;
+       void *(*alloc)(uintptr);
+       void (*first)(void *arg, byte *p);      // called first time p is returned
+       void *arg;
+       MLink *list;
+       byte *chunk;
+       uint32 nchunk;
+       uintptr inuse;  // in-use bytes now
+       uintptr sys;    // bytes obtained from system
+};
+
+void   runtime_FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg);
+void*  runtime_FixAlloc_Alloc(FixAlloc *f);
+void   runtime_FixAlloc_Free(FixAlloc *f, void *p);
+
+
+// Statistics.
+// Shared with Go: if you edit this structure, also edit extern.go.
+struct MStats
+{
+       // General statistics.  No locking; approximate.
+       uint64  alloc;          // bytes allocated and still in use
+       uint64  total_alloc;    // bytes allocated (even if freed)
+       uint64  sys;            // bytes obtained from system (should be sum of xxx_sys below)
+       uint64  nlookup;        // number of pointer lookups
+       uint64  nmalloc;        // number of mallocs
+       
+       // Statistics about malloc heap.
+       // protected by mheap.Lock
+       uint64  heap_alloc;     // bytes allocated and still in use
+       uint64  heap_sys;       // bytes obtained from system
+       uint64  heap_idle;      // bytes in idle spans
+       uint64  heap_inuse;     // bytes in non-idle spans
+       uint64  heap_objects;   // total number of allocated objects
+
+       // Statistics about allocation of low-level fixed-size structures.
+       // Protected by FixAlloc locks.
+       uint64  stacks_inuse;   // bootstrap stacks
+       uint64  stacks_sys;
+       uint64  mspan_inuse;    // MSpan structures
+       uint64  mspan_sys;
+       uint64  mcache_inuse;   // MCache structures
+       uint64  mcache_sys;
+       uint64  heapmap_sys;    // heap map
+       uint64  buckhash_sys;   // profiling bucket hash table
+       
+       // Statistics about garbage collector.
+       // Protected by stopping the world during GC.
+       uint64  next_gc;        // next GC (in heap_alloc time)
+       uint64  pause_ns;
+       uint32  numgc;
+       bool    enablegc;
+       bool    debuggc;
+       
+       // Statistics about allocation size classes.
+       // No locking; approximate.
+       struct {
+               uint32 size;
+               uint64 nmalloc;
+               uint64 nfree;
+       } by_size[NumSizeClasses];
+};
+
+extern MStats mstats
+  __asm__ ("libgo_runtime.runtime.MemStats");
+
+
+// Size classes.  Computed and initialized by InitSizes.
+//
+// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
+//     1 <= sizeclass < NumSizeClasses, for n.
+//     Size class 0 is reserved to mean "not small".
+//
+// class_to_size[i] = largest size in class i
+// class_to_allocnpages[i] = number of pages to allocate when
+//     making new objects in class i
+// class_to_transfercount[i] = number of objects to move when
+//     taking a bunch of objects out of the central lists
+//     and putting them in the thread free list.
+
+int32  runtime_SizeToClass(int32);
+extern int32   runtime_class_to_size[NumSizeClasses];
+extern int32   runtime_class_to_allocnpages[NumSizeClasses];
+extern int32   runtime_class_to_transfercount[NumSizeClasses];
+extern void    runtime_InitSizes(void);
+
+
+// Per-thread (in Go, per-M) cache for small objects.
+// No locking needed because it is per-thread (per-M).
+typedef struct MCacheList MCacheList;
+struct MCacheList
+{
+       MLink *list;
+       uint32 nlist;
+       uint32 nlistmin;
+};
+
+struct MCache
+{
+       MCacheList list[NumSizeClasses];
+       uint64 size;
+       int64 local_alloc;      // bytes allocated (or freed) since last lock of heap
+       int64 local_objects;    // objects allocated (or freed) since last lock of heap
+       int32 next_sample;      // trigger heap sample after allocating this many bytes
+};
+
+void*  runtime_MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
+void   runtime_MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
+void   runtime_MCache_ReleaseAll(MCache *c);
+
+// An MSpan is a run of pages.
+enum
+{
+       MSpanInUse = 0,
+       MSpanFree,
+       MSpanListHead,
+       MSpanDead,
+};
+struct MSpan
+{
+       MSpan   *next;          // in a span linked list
+       MSpan   *prev;          // in a span linked list
+       MSpan   *allnext;               // in the list of all spans
+       PageID  start;          // starting page number
+       uintptr npages;         // number of pages in span
+       MLink   *freelist;      // list of free objects
+       uint32  ref;            // number of allocated objects in this span
+       uint32  sizeclass;      // size class
+       uint32  state;          // MSpanInUse etc
+       union {
+               uint32  *gcref; // sizeclass > 0
+               uint32  gcref0; // sizeclass == 0
+       };
+};
+
+void   runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages);
+
+// Every MSpan is in one doubly-linked list,
+// either one of the MHeap's free lists or one of the
+// MCentral's span lists.  We use empty MSpan structures as list heads.
+void   runtime_MSpanList_Init(MSpan *list);
+bool   runtime_MSpanList_IsEmpty(MSpan *list);
+void   runtime_MSpanList_Insert(MSpan *list, MSpan *span);
+void   runtime_MSpanList_Remove(MSpan *span);  // from whatever list it is in
+
+
+// Central list of free objects of a given size.
+struct MCentral
+{
+       Lock;
+       int32 sizeclass;
+       MSpan nonempty;
+       MSpan empty;
+       int32 nfree;
+};
+
+void   runtime_MCentral_Init(MCentral *c, int32 sizeclass);
+int32  runtime_MCentral_AllocList(MCentral *c, int32 n, MLink **first);
+void   runtime_MCentral_FreeList(MCentral *c, int32 n, MLink *first);
+
+// Main malloc heap.
+// The heap itself is the "free[]" and "large" arrays,
+// but all the other global data is here too.
+struct MHeap
+{
+       Lock;
+       MSpan free[MaxMHeapList];       // free lists of given length
+       MSpan large;                    // free lists length >= MaxMHeapList
+       MSpan *allspans;
+
+       // span lookup
+       MHeapMap map;
+
+       // range of addresses we might see in the heap
+       byte *min;
+       byte *max;
+       
+       // range of addresses we might see in a Native Client closure
+       byte *closure_min;
+       byte *closure_max;
+
+       // central free lists for small size classes.
+       // the union makes sure that the MCentrals are
+       // spaced 64 bytes apart, so that each MCentral.Lock
+       // gets its own cache line.
+       union {
+               MCentral;
+               byte pad[64];
+       } central[NumSizeClasses];
+
+       FixAlloc spanalloc;     // allocator for Span*
+       FixAlloc cachealloc;    // allocator for MCache*
+};
+extern MHeap runtime_mheap;
+
+void   runtime_MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
+MSpan* runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct);
+void   runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct);
+MSpan* runtime_MHeap_Lookup(MHeap *h, PageID p);
+MSpan* runtime_MHeap_LookupMaybe(MHeap *h, PageID p);
+void   runtime_MGetSizeClassInfo(int32 sizeclass, int32 *size, int32 *npages, int32 *nobj);
+
+void*  runtime_mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
+int32  runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **s, uint32 **ref);
+void   runtime_gc(int32 force);
+
+void*  runtime_SysAlloc(uintptr);
+void   runtime_SysUnused(void*, uintptr);
+void   runtime_SysFree(void*, uintptr);
+
+enum
+{
+       RefcountOverhead = 4,   // one uint32 per object
+
+       RefFree = 0,    // must be zero
+       RefStack,               // stack segment - don't free and don't scan for pointers
+       RefNone,                // no references
+       RefSome,                // some references
+       RefNoPointers = 0x80000000U,    // flag - no pointers here
+       RefHasFinalizer = 0x40000000U,  // flag - has finalizer
+       RefProfiled = 0x20000000U,      // flag - is in profiling table
+       RefNoProfiling = 0x10000000U,   // flag - must not profile
+       RefFlags = 0xFFFF0000U,
+};
+
+void   runtime_MProf_Malloc(void*, uintptr);
+void   runtime_MProf_Free(void*, uintptr);
+void   runtime_MProf_Mark(void (*scan)(byte *, int64));
+
+// Malloc profiling settings.
+// Must match definition in extern.go.
+enum {
+       MProf_None = 0,
+       MProf_Sample = 1,
+       MProf_All = 2,
+};
+extern int32 runtime_malloc_profile;
+
+typedef struct Finalizer Finalizer;
+struct Finalizer
+{
+       Finalizer *next;        // for use by caller of getfinalizer
+       void (*fn)(void*);
+       void *arg;
+       const struct __go_func_type *ft;
+};
+
+Finalizer*     runtime_getfinalizer(void*, bool);
diff --git a/libgo/runtime/map.goc b/libgo/runtime/map.goc
new file mode 100644 (file)
index 0000000..d6308cb
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "map.h"
+#define nil NULL
+
+typedef unsigned char byte;
+typedef _Bool bool;
+
+typedef struct __go_map hmap;
+typedef struct __go_hash_iter hiter;
+
+/* Access a value in a map, returning a value and a presence indicator.  */
+
+func mapaccess2(h *hmap, key *byte, val *byte) (present bool) {
+       byte *mapval;
+       size_t valsize;
+
+       mapval = __go_map_index(h, key, 0);
+       valsize = h->__descriptor->__map_descriptor->__val_type->__size;
+       if (mapval == nil) {
+               __builtin_memset(val, 0, valsize);
+               present = 0;
+       } else {
+               __builtin_memcpy(val, mapval, valsize);
+               present = 1;
+       }
+}
+
+/* Optionally assign a value to a map (m[k] = v, p).  */
+
+func mapassign2(h *hmap, key *byte, val *byte, p bool) {
+       if (!p) {
+               __go_map_delete(h, key);
+       } else {
+               byte *mapval;
+               size_t valsize;
+
+               mapval = __go_map_index(h, key, 1);
+               valsize = h->__descriptor->__map_descriptor->__val_type->__size;
+               __builtin_memcpy(mapval, val, valsize);
+       }
+}
+
+/* Initialize a range over a map.  */
+
+func mapiterinit(h *hmap, it *hiter) {
+       __go_mapiterinit(h, it);
+}
+
+/* Move to the next iteration, updating *HITER.  */
+
+func mapiternext(it *hiter) {
+       __go_mapiternext(it);
+}
+
+/* Get the key of the current iteration.  */
+
+func mapiter1(it *hiter, key *byte) {
+       __go_mapiter1(it, key);
+}
+
+/* Get the key and value of the current iteration.  */
+
+func mapiter2(it *hiter, key *byte, val *byte) {
+       __go_mapiter2(it, key, val);
+}
diff --git a/libgo/runtime/map.h b/libgo/runtime/map.h
new file mode 100644 (file)
index 0000000..a0c834a
--- /dev/null
@@ -0,0 +1,86 @@
+/* map.h -- the map type for Go.
+
+   Copyright 2009, 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <stddef.h>
+
+#include "go-type.h"
+
+/* A map descriptor is what we need to manipulate the map.  This is
+   constant for a given map type.  */
+
+struct __go_map_descriptor
+{
+  /* A pointer to the type descriptor for the type of the map itself.  */
+  const struct __go_map_type *__map_descriptor;
+
+  /* A map entry is a struct with three fields:
+       map_entry_type *next_entry;
+       key_type key;
+       value_type value;
+     This is the size of that struct.  */
+  size_t __entry_size;
+
+  /* The offset of the key field in a map entry struct.  */
+  size_t __key_offset;
+
+  /* The offset of the value field in a map entry struct (the value
+     field immediately follows the key field, but there may be some
+     bytes inserted for alignment).  */
+  size_t __val_offset;
+};
+
+struct __go_map
+{
+  /* The constant descriptor for this map.  */
+  const struct __go_map_descriptor *__descriptor;
+
+  /* The number of elements in the hash table.  */
+  size_t __element_count;
+
+  /* The number of entries in the __buckets array.  */
+  size_t __bucket_count;
+
+  /* Each bucket is a pointer to a linked list of map entries.  */
+  void **__buckets;
+};
+
+/* For a map iteration the compiled code will use a pointer to an
+   iteration structure.  The iteration structure will be allocated on
+   the stack.  The Go code must allocate at least enough space.  */
+
+struct __go_hash_iter
+{
+  /* A pointer to the current entry.  This will be set to NULL when
+     the range has completed.  The Go will test this field, so it must
+     be the first one in the structure.  */
+  const void *entry;
+  /* The map we are iterating over.  */
+  const struct __go_map *map;
+  /* A pointer to the next entry in the current bucket.  This permits
+     deleting the current entry.  This will be NULL when we have seen
+     all the entries in the current bucket.  */
+  const void *next_entry;
+  /* The bucket index of the current and next entry.  */
+  size_t bucket;
+};
+
+extern struct __go_map *__go_new_map (const struct __go_map_descriptor *,
+                                     size_t);
+
+extern unsigned long __go_map_next_prime (unsigned long);
+
+extern void *__go_map_index (struct __go_map *, const void *, _Bool);
+
+extern void __go_map_delete (struct __go_map *, const void *);
+
+extern void __go_mapiterinit (const struct __go_map *, struct __go_hash_iter *);
+
+extern void __go_mapiternext (struct __go_hash_iter *);
+
+extern void __go_mapiter1 (struct __go_hash_iter *it, unsigned char *key);
+
+extern void __go_mapiter2 (struct __go_hash_iter *it, unsigned char *key,
+                          unsigned char *val);
diff --git a/libgo/runtime/mcache.c b/libgo/runtime/mcache.c
new file mode 100644 (file)
index 0000000..ce65757
--- /dev/null
@@ -0,0 +1,131 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Per-thread (in Go, per-M) malloc cache for small objects.
+//
+// See malloc.h for an overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+void*
+runtime_MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
+{
+       MCacheList *l;
+       MLink *first, *v;
+       int32 n;
+
+       // Allocate from list.
+       l = &c->list[sizeclass];
+       if(l->list == nil) {
+               // Replenish using central lists.
+               n = runtime_MCentral_AllocList(&runtime_mheap.central[sizeclass],
+                       runtime_class_to_transfercount[sizeclass], &first);
+               l->list = first;
+               l->nlist = n;
+               c->size += n*size;
+       }
+       v = l->list;
+       l->list = v->next;
+       l->nlist--;
+       if(l->nlist < l->nlistmin)
+               l->nlistmin = l->nlist;
+       c->size -= size;
+
+       // v is zeroed except for the link pointer
+       // that we used above; zero that.
+       v->next = nil;
+       if(zeroed) {
+               // block is zeroed iff second word is zero ...
+               if(size > sizeof(uintptr) && ((uintptr*)v)[1] != 0)
+                       runtime_memclr((byte*)v, size);
+               else {
+                       // ... except for the link pointer
+                       // that we used above; zero that.
+                       v->next = nil;
+               }
+       }
+       c->local_alloc += size;
+       c->local_objects++;
+       return v;
+}
+
+// Take n elements off l and return them to the central free list.
+static void
+ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass)
+{
+       MLink *first, **lp;
+       int32 i;
+
+       // Cut off first n elements.
+       first = l->list;
+       lp = &l->list;
+       for(i=0; i<n; i++)
+               lp = &(*lp)->next;
+       l->list = *lp;
+       *lp = nil;
+       l->nlist -= n;
+       if(l->nlist < l->nlistmin)
+               l->nlistmin = l->nlist;
+       c->size -= n*runtime_class_to_size[sizeclass];
+
+       // Return them to central free list.
+       runtime_MCentral_FreeList(&runtime_mheap.central[sizeclass], n, first);
+}
+
+void
+runtime_MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+{
+       int32 i, n;
+       MCacheList *l;
+       MLink *p;
+
+       // Put back on list.
+       l = &c->list[sizeclass];
+       p = v;
+       p->next = l->list;
+       l->list = p;
+       l->nlist++;
+       c->size += size;
+       c->local_alloc -= size;
+       c->local_objects--;
+
+       if(l->nlist >= MaxMCacheListLen) {
+               // Release a chunk back.
+               ReleaseN(c, l, runtime_class_to_transfercount[sizeclass], sizeclass);
+       }
+
+       if(c->size >= MaxMCacheSize) {
+               // Scavenge.
+               for(i=0; i<NumSizeClasses; i++) {
+                       l = &c->list[i];
+                       n = l->nlistmin;
+
+                       // n is the minimum number of elements we've seen on
+                       // the list since the last scavenge.  If n > 0, it means that
+                       // we could have gotten by with n fewer elements
+                       // without needing to consult the central free list.
+                       // Move toward that situation by releasing n/2 of them.
+                       if(n > 0) {
+                               if(n > 1)
+                                       n /= 2;
+                               ReleaseN(c, l, n, i);
+                       }
+                       l->nlistmin = l->nlist;
+               }
+       }
+}
+
+void
+runtime_MCache_ReleaseAll(MCache *c)
+{
+       int32 i;
+       MCacheList *l;
+
+       for(i=0; i<NumSizeClasses; i++) {
+               l = &c->list[i];
+               ReleaseN(c, l, l->nlist, i);
+               l->nlistmin = 0;
+       }
+}
diff --git a/libgo/runtime/mcentral.c b/libgo/runtime/mcentral.c
new file mode 100644 (file)
index 0000000..81e54b0
--- /dev/null
@@ -0,0 +1,209 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Central free lists.
+//
+// See malloc.h for an overview.
+//
+// The MCentral doesn't actually contain the list of free objects; the MSpan does.
+// Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
+// and those that are completely allocated (c->empty).
+//
+// TODO(rsc): tcmalloc uses a "transfer cache" to split the list
+// into sections of class_to_transfercount[sizeclass] objects
+// so that it is faster to move those lists between MCaches and MCentrals.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static bool MCentral_Grow(MCentral *c);
+static void* MCentral_Alloc(MCentral *c);
+static void MCentral_Free(MCentral *c, void *v);
+
+// Initialize a single central free list.
+void
+runtime_MCentral_Init(MCentral *c, int32 sizeclass)
+{
+       runtime_initlock(c);
+       c->sizeclass = sizeclass;
+       runtime_MSpanList_Init(&c->nonempty);
+       runtime_MSpanList_Init(&c->empty);
+}
+
+// Allocate up to n objects from the central free list.
+// Return the number of objects allocated.
+// The objects are linked together by their first words.
+// On return, *pstart points at the first object and *pend at the last.
+int32
+runtime_MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
+{
+       MLink *first, *last, *v;
+       int32 i;
+
+       runtime_lock(c);
+       // Replenish central list if empty.
+       if(runtime_MSpanList_IsEmpty(&c->nonempty)) {
+               if(!MCentral_Grow(c)) {
+                       runtime_unlock(c);
+                       *pfirst = nil;
+                       return 0;
+               }
+       }
+
+       // Copy from list, up to n.
+       // First one is guaranteed to work, because we just grew the list.
+       first = MCentral_Alloc(c);
+       last = first;
+       for(i=1; i<n && (v = MCentral_Alloc(c)) != nil; i++) {
+               last->next = v;
+               last = v;
+       }
+       last->next = nil;
+       c->nfree -= i;
+
+       runtime_unlock(c);
+       *pfirst = first;
+       return i;
+}
+
+// Helper: allocate one object from the central free list.
+static void*
+MCentral_Alloc(MCentral *c)
+{
+       MSpan *s;
+       MLink *v;
+
+       if(runtime_MSpanList_IsEmpty(&c->nonempty))
+               return nil;
+       s = c->nonempty.next;
+       s->ref++;
+       v = s->freelist;
+       s->freelist = v->next;
+       if(s->freelist == nil) {
+               runtime_MSpanList_Remove(s);
+               runtime_MSpanList_Insert(&c->empty, s);
+       }
+       return v;
+}
+
+// Free n objects back into the central free list.
+// Return the number of objects allocated.
+// The objects are linked together by their first words.
+// On return, *pstart points at the first object and *pend at the last.
+void
+runtime_MCentral_FreeList(MCentral *c, int32 n, MLink *start)
+{
+       MLink *v, *next;
+
+       // Assume next == nil marks end of list.
+       // n and end would be useful if we implemented
+       // the transfer cache optimization in the TODO above.
+       USED(n);
+
+       runtime_lock(c);
+       for(v=start; v; v=next) {
+               next = v->next;
+               MCentral_Free(c, v);
+       }
+       runtime_unlock(c);
+}
+
+// Helper: free one object back into the central free list.
+static void
+MCentral_Free(MCentral *c, void *v)
+{
+       MSpan *s;
+       PageID page;
+       MLink *p, *next;
+       int32 size;
+
+       // Find span for v.
+       page = (uintptr)v >> PageShift;
+       s = runtime_MHeap_Lookup(&runtime_mheap, page);
+       if(s == nil || s->ref == 0)
+               runtime_throw("invalid free");
+
+       // Move to nonempty if necessary.
+       if(s->freelist == nil) {
+               runtime_MSpanList_Remove(s);
+               runtime_MSpanList_Insert(&c->nonempty, s);
+       }
+
+       // Add v back to s's free list.
+       p = v;
+       p->next = s->freelist;
+       s->freelist = p;
+       c->nfree++;
+
+       // If s is completely freed, return it to the heap.
+       if(--s->ref == 0) {
+               size = runtime_class_to_size[c->sizeclass];
+               runtime_MSpanList_Remove(s);
+               // The second word of each freed block indicates
+               // whether it needs to be zeroed.  The first word
+               // is the link pointer and must always be cleared.
+               for(p=s->freelist; p; p=next) {
+                       next = p->next;
+                       if(size > (int32)sizeof(uintptr) && ((uintptr*)p)[1] != 0)
+                               runtime_memclr((byte*)p, size);
+                       else
+                               p->next = nil;
+               }
+               s->freelist = nil;
+               c->nfree -= (s->npages << PageShift) / size;
+               runtime_unlock(c);
+               runtime_MHeap_Free(&runtime_mheap, s, 0);
+               runtime_lock(c);
+       }
+}
+
+void
+runtime_MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32 *nobj)
+{
+       int32 size;
+       int32 npages;
+
+       npages = runtime_class_to_allocnpages[sizeclass];
+       size = runtime_class_to_size[sizeclass];
+       *npagesp = npages;
+       *sizep = size;
+       *nobj = (npages << PageShift) / (size + RefcountOverhead);
+}
+
+// Fetch a new span from the heap and
+// carve into objects for the free list.
+static bool
+MCentral_Grow(MCentral *c)
+{
+       int32 i, n, npages, size;
+       MLink **tailp, *v;
+       byte *p;
+       MSpan *s;
+
+       runtime_unlock(c);
+       runtime_MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
+       s = runtime_MHeap_Alloc(&runtime_mheap, npages, c->sizeclass, 0);
+       if(s == nil) {
+               // TODO(rsc): Log out of memory
+               runtime_lock(c);
+               return false;
+       }
+
+       // Carve span into sequence of blocks.
+       tailp = &s->freelist;
+       p = (byte*)(s->start << PageShift);
+       s->gcref = (uint32*)(p + size*n);
+       for(i=0; i<n; i++) {
+               v = (MLink*)p;
+               *tailp = v;
+               tailp = &v->next;
+               p += size;
+       }
+       *tailp = nil;
+
+       runtime_lock(c);
+       c->nfree += n;
+       runtime_MSpanList_Insert(&c->nonempty, s);
+       return true;
+}
diff --git a/libgo/runtime/mem.c b/libgo/runtime/mem.c
new file mode 100644 (file)
index 0000000..29cf495
--- /dev/null
@@ -0,0 +1,50 @@
+#include <errno.h>
+
+#include "runtime.h"
+#include "malloc.h"
+
+void*
+runtime_SysAlloc(uintptr n)
+{
+       void *p;
+
+       mstats.sys += n;
+       p = runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+       if (p == MAP_FAILED) {
+               if(errno == EACCES) {
+                       printf("mmap: access denied\n");
+                       printf("If you're running SELinux, enable execmem for this process.\n");
+               } else {
+                       printf("mmap: errno=%d\n", errno);
+               }
+               exit(2);
+       }
+       return p;
+}
+
+void
+runtime_SysUnused(void *v, uintptr n)
+{
+       USED(v);
+       USED(n);
+       // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+runtime_SysFree(void *v, uintptr n)
+{
+       mstats.sys -= n;
+       runtime_munmap(v, n);
+}
+
+void
+runtime_SysMemInit(void)
+{
+       // Code generators assume that references to addresses
+       // on the first page will fault.  Map the page explicitly with
+       // no permissions, to head off possible bugs like the system
+       // allocating that page as the virtual address space fills.
+       // Ignore any error, since other systems might be smart
+       // enough to never allow anything there.
+       runtime_mmap(nil, 4096, PROT_NONE, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
+}
diff --git a/libgo/runtime/mem_posix_memalign.c b/libgo/runtime/mem_posix_memalign.c
new file mode 100644 (file)
index 0000000..3855dfc
--- /dev/null
@@ -0,0 +1,38 @@
+#include <errno.h>
+
+#include "runtime.h"
+#include "malloc.h"
+
+void*
+runtime_SysAlloc(uintptr n)
+{
+       void *p;
+
+       mstats.sys += n;
+       errno = posix_memalign(&p, PageSize, n);
+       if (errno > 0) {
+               perror("posix_memalign");
+               exit(2);
+       }
+       return p;
+}
+
+void
+runtime_SysUnused(void *v, uintptr n)
+{
+       USED(v);
+       USED(n);
+       // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+runtime_SysFree(void *v, uintptr n)
+{
+       mstats.sys -= n;
+       free(v);
+}
+
+void
+runtime_SysMemInit(void)
+{
+}
diff --git a/libgo/runtime/mfinal.c b/libgo/runtime/mfinal.c
new file mode 100644 (file)
index 0000000..3f3a610
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static Lock finlock = LOCK_INITIALIZER;
+
+// Finalizer hash table.  Direct hash, linear scan, at most 3/4 full.
+// Table size is power of 3 so that hash can be key % max.
+// Key[i] == (void*)-1 denotes free but formerly occupied entry
+// (doesn't stop the linear scan).
+// Key and val are separate tables because the garbage collector
+// must be instructed to ignore the pointers in key but follow the
+// pointers in val.
+typedef struct Fintab Fintab;
+struct Fintab
+{
+       void **key;
+       Finalizer **val;
+       int32 nkey;     // number of non-nil entries in key
+       int32 ndead;    // number of dead (-1) entries in key
+       int32 max;      // size of key, val allocations
+};
+
+static void
+addfintab(Fintab *t, void *k, Finalizer *v)
+{
+       int32 i, j;
+
+       i = (uintptr)k % (uintptr)t->max;
+       for(j=0; j<t->max; j++) {
+               if(t->key[i] == nil) {
+                       t->nkey++;
+                       goto ret;
+               }
+               if(t->key[i] == (void*)-1) {
+                       t->ndead--;
+                       goto ret;
+               }
+               if(++i == t->max)
+                       i = 0;
+       }
+
+       // cannot happen - table is known to be non-full
+       runtime_throw("finalizer table inconsistent");
+
+ret:
+       t->key[i] = k;
+       t->val[i] = v;
+}
+
+static Finalizer*
+lookfintab(Fintab *t, void *k, bool del)
+{
+       int32 i, j;
+       Finalizer *v;
+
+       if(t->max == 0)
+               return nil;
+       i = (uintptr)k % (uintptr)t->max;
+       for(j=0; j<t->max; j++) {
+               if(t->key[i] == nil)
+                       return nil;
+               if(t->key[i] == k) {
+                       v = t->val[i];
+                       if(del) {
+                               t->key[i] = (void*)-1;
+                               t->val[i] = nil;
+                               t->ndead++;
+                       }
+                       return v;
+               }
+               if(++i == t->max)
+                       i = 0;
+       }
+
+       // cannot happen - table is known to be non-full
+       runtime_throw("finalizer table inconsistent");
+       return nil;
+}
+
+static Fintab fintab;
+
+// add finalizer; caller is responsible for making sure not already in table
+void
+runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft)
+{
+       Fintab newtab;
+       int32 i;
+       uint32 *ref;
+       byte *base;
+       Finalizer *e;
+       
+       e = nil;
+       if(f != nil) {
+               e = runtime_mal(sizeof *e);
+               e->fn = f;
+               e->ft = ft;
+       }
+
+       runtime_lock(&finlock);
+       if(!runtime_mlookup(p, &base, nil, nil, &ref) || p != base) {
+               runtime_unlock(&finlock);
+               runtime_throw("addfinalizer on invalid pointer");
+       }
+       if(f == nil) {
+               if(*ref & RefHasFinalizer) {
+                       lookfintab(&fintab, p, 1);
+                       *ref &= ~RefHasFinalizer;
+               }
+               runtime_unlock(&finlock);
+               return;
+       }
+
+       if(*ref & RefHasFinalizer) {
+               runtime_unlock(&finlock);
+               runtime_throw("double finalizer");
+       }
+       *ref |= RefHasFinalizer;
+
+       if(fintab.nkey >= fintab.max/2+fintab.max/4) {
+               // keep table at most 3/4 full:
+               // allocate new table and rehash.
+
+               runtime_memclr((byte*)&newtab, sizeof newtab);
+               newtab.max = fintab.max;
+               if(newtab.max == 0)
+                       newtab.max = 3*3*3;
+               else if(fintab.ndead < fintab.nkey/2) {
+                       // grow table if not many dead values.
+                       // otherwise just rehash into table of same size.
+                       newtab.max *= 3;
+               }
+
+               newtab.key = runtime_mallocgc(newtab.max*sizeof newtab.key[0], RefNoPointers, 0, 1);
+               newtab.val = runtime_mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
+
+               for(i=0; i<fintab.max; i++) {
+                       void *k;
+
+                       k = fintab.key[i];
+                       if(k != nil && k != (void*)-1)
+                               addfintab(&newtab, k, fintab.val[i]);
+               }
+               runtime_free(fintab.key);
+               runtime_free(fintab.val);
+               fintab = newtab;
+       }
+
+       addfintab(&fintab, p, e);
+       runtime_unlock(&finlock);
+}
+
+// get finalizer; if del, delete finalizer.
+// caller is responsible for updating RefHasFinalizer bit.
+Finalizer*
+runtime_getfinalizer(void *p, bool del)
+{
+       Finalizer *f;
+       
+       runtime_lock(&finlock);
+       f = lookfintab(&fintab, p, del);
+       runtime_unlock(&finlock);
+       return f;
+}
+
+void
+runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64))
+{
+       void **key;
+       void **ekey;
+
+       scan((byte*)&fintab, sizeof fintab);
+       runtime_lock(&finlock);
+       key = fintab.key;
+       ekey = key + fintab.max;
+       for(; key < ekey; key++)
+               if(*key != nil && *key != ((void*)-1))
+                       fn(*key);
+       runtime_unlock(&finlock);
+}
diff --git a/libgo/runtime/mfixalloc.c b/libgo/runtime/mfixalloc.c
new file mode 100644 (file)
index 0000000..c05583d
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Fixed-size object allocator.  Returned memory is not zeroed.
+//
+// See malloc.h for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+// Initialize f to allocate objects of the given size,
+// using the allocator to obtain chunks of memory.
+void
+runtime_FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg)
+{
+       f->size = size;
+       f->alloc = alloc;
+       f->first = first;
+       f->arg = arg;
+       f->list = nil;
+       f->chunk = nil;
+       f->nchunk = 0;
+       f->inuse = 0;
+       f->sys = 0;
+}
+
+void*
+runtime_FixAlloc_Alloc(FixAlloc *f)
+{
+       void *v;
+
+       if(f->list) {
+               v = f->list;
+               f->list = *(void**)f->list;
+               f->inuse += f->size;
+               return v;
+       }
+       if(f->nchunk < f->size) {
+               f->sys += FixAllocChunk;
+               f->chunk = f->alloc(FixAllocChunk);
+               if(f->chunk == nil)
+                       runtime_throw("out of memory (FixAlloc)");
+               f->nchunk = FixAllocChunk;
+       }
+       v = f->chunk;
+       if(f->first)
+               f->first(f->arg, v);
+       f->chunk += f->size;
+       f->nchunk -= f->size;
+       f->inuse += f->size;
+       return v;
+}
+
+void
+runtime_FixAlloc_Free(FixAlloc *f, void *p)
+{
+       f->inuse -= f->size;
+       *(void**)p = f->list;
+       f->list = p;
+}
+
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
new file mode 100644 (file)
index 0000000..06e557f
--- /dev/null
@@ -0,0 +1,405 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Garbage collector -- step 0.
+//
+// Stop the world, mark and sweep garbage collector.
+// NOT INTENDED FOR PRODUCTION USE.
+//
+// A mark and sweep collector provides a way to exercise
+// and test the memory allocator and the stack walking machinery
+// without also needing to get reference counting
+// exactly right.
+
+#include "runtime.h"
+#include "malloc.h"
+
+enum {
+       Debug = 0
+};
+
+typedef struct BlockList BlockList;
+struct BlockList
+{
+       byte *obj;
+       uintptr size;
+};
+
+static bool finstarted;
+static Lock finqlock = LOCK_INITIALIZER;
+static pthread_cond_t finqcond = PTHREAD_COND_INITIALIZER;
+static Finalizer *finq;
+static int32 fingwait;
+static BlockList *bl, *ebl;
+
+static void runfinq(void*);
+
+enum {
+       PtrSize = sizeof(void*)
+};
+
+static void
+scanblock(byte *b, int64 n)
+{
+       int32 off;
+       void *obj;
+       uintptr size;
+       uint32 *refp, ref;
+       void **vp;
+       int64 i;
+       BlockList *w;
+
+       w = bl;
+       w->obj = b;
+       w->size = n;
+       w++;
+
+       while(w > bl) {
+               w--;
+               b = w->obj;
+               n = w->size;
+
+               if(Debug > 1)
+                       runtime_printf("scanblock %p %lld\n", b, (long long) n);
+               off = (uint32)(uintptr)b & (PtrSize-1);
+               if(off) {
+                       b += PtrSize - off;
+                       n -= PtrSize - off;
+               }
+       
+               vp = (void**)b;
+               n /= PtrSize;
+               for(i=0; i<n; i++) {
+                       obj = vp[i];
+                       if(obj == nil)
+                               continue;
+                       if(runtime_mheap.closure_min != nil && runtime_mheap.closure_min <= (byte*)obj && (byte*)obj < runtime_mheap.closure_max) {
+                               if((((uintptr)obj) & 63) != 0)
+                                       continue;
+       
+                               // Looks like a Native Client closure.
+                               // Actual pointer is pointed at by address in first instruction.
+                               // Embedded pointer starts at byte 2.
+                               // If it is f4f4f4f4 then that space hasn't been
+                               // used for a closure yet (f4 is the HLT instruction).
+                               // See nacl/386/closure.c for more.
+                               void **pp;
+                               pp = *(void***)((byte*)obj+2);
+                               if(pp == (void**)0xf4f4f4f4)    // HLT... - not a closure after all
+                                       continue;
+                               obj = *pp;
+                       }
+                       if(runtime_mheap.min <= (byte*)obj && (byte*)obj < runtime_mheap.max) {
+                               if(runtime_mlookup(obj, (byte**)&obj, &size, nil, &refp)) {
+                                       ref = *refp;
+                                       switch(ref & ~RefFlags) {
+                                       case RefNone:
+                                               if(Debug > 1)
+                                                       runtime_printf("found at %p: ", &vp[i]);
+                                               *refp = RefSome | (ref & RefFlags);
+                                               if(!(ref & RefNoPointers)) {
+                                                       if(w >= ebl)
+                                                               runtime_throw("scanblock: garbage collection stack overflow");
+                                                       w->obj = obj;
+                                                       w->size = size;
+                                                       w++;
+                                               }
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+static void
+markfin(void *v)
+{
+       uintptr size;
+       uint32 *refp;
+
+       size = 0;
+       refp = nil;
+       if(!runtime_mlookup(v, (byte**)&v, &size, nil, &refp) || !(*refp & RefHasFinalizer))
+               runtime_throw("mark - finalizer inconsistency");
+       
+       // do not mark the finalizer block itself.  just mark the things it points at.
+       scanblock(v, size);
+}
+
+struct root_list {
+       struct root_list *next;
+       struct root {
+               void *decl;
+               size_t size;
+       } roots[];
+};
+
+static struct root_list* roots;
+
+void
+__go_register_gc_roots (struct root_list* r)
+{
+       // FIXME: This needs locking if multiple goroutines can call
+       // dlopen simultaneously.
+       r->next = roots;
+       roots = r;
+}
+
+static void
+mark(void)
+{
+       uintptr blsize, nobj;
+       struct root_list *pl;
+
+       // Figure out how big an object stack we need.
+       // Get a new one if we need more than we have
+       // or we need significantly less than we have.
+       nobj = mstats.heap_objects;
+       if(nobj > (uintptr)(ebl - bl) || nobj < (uintptr)(ebl-bl)/4) {
+               if(bl != nil)
+                       runtime_SysFree(bl, (byte*)ebl - (byte*)bl);
+               
+               // While we're allocated a new object stack,
+               // add 20% headroom and also round up to
+               // the nearest page boundary, since mmap
+               // will anyway.
+               nobj = nobj * 12/10;
+               blsize = nobj * sizeof *bl;
+               blsize = (blsize + 4095) & ~4095;
+               nobj = blsize / sizeof *bl;
+               bl = runtime_SysAlloc(blsize);
+               ebl = bl + nobj;
+       }
+
+       for(pl = roots; pl != nil; pl = pl->next) {
+               struct root* pr = &pl->roots[0];
+               while(1) {
+                       void *decl = pr->decl;
+                       if(decl == nil)
+                               break;
+                       scanblock(decl, pr->size);
+                       pr++;
+               }
+       }
+
+       scanblock((byte*)&m0, sizeof m0);
+       scanblock((byte*)&finq, sizeof finq);
+       runtime_MProf_Mark(scanblock);
+
+       // mark stacks
+       __go_scanstacks(scanblock);
+
+       // mark things pointed at by objects with finalizers
+       runtime_walkfintab(markfin, scanblock);
+}
+
+// free RefNone, free & queue finalizers for RefNone|RefHasFinalizer, reset RefSome
+static void
+sweepspan(MSpan *s)
+{
+       int32 n, npages, size;
+       byte *p;
+       uint32 ref, *gcrefp, *gcrefep;
+       MCache *c;
+       Finalizer *f;
+
+       p = (byte*)(s->start << PageShift);
+       if(s->sizeclass == 0) {
+               // Large block.
+               ref = s->gcref0;
+               switch(ref & ~(RefFlags^RefHasFinalizer)) {
+               case RefNone:
+                       // Free large object.
+                       mstats.alloc -= s->npages<<PageShift;
+                       runtime_memclr(p, s->npages<<PageShift);
+                       if(ref & RefProfiled)
+                               runtime_MProf_Free(p, s->npages<<PageShift);
+                       s->gcref0 = RefFree;
+                       runtime_MHeap_Free(&runtime_mheap, s, 1);
+                       break;
+               case RefNone|RefHasFinalizer:
+                       f = runtime_getfinalizer(p, 1);
+                       if(f == nil)
+                               runtime_throw("finalizer inconsistency");
+                       f->arg = p;
+                       f->next = finq;
+                       finq = f;
+                       ref &= ~RefHasFinalizer;
+                       // fall through
+               case RefSome:
+               case RefSome|RefHasFinalizer:
+                       s->gcref0 = RefNone | (ref&RefFlags);
+                       break;
+               }
+               return;
+       }
+
+       // Chunk full of small blocks.
+       runtime_MGetSizeClassInfo(s->sizeclass, &size, &npages, &n);
+       gcrefp = s->gcref;
+       gcrefep = s->gcref + n;
+       for(; gcrefp < gcrefep; gcrefp++, p += size) {
+               ref = *gcrefp;
+               if(ref < RefNone)       // RefFree or RefStack
+                       continue;
+               switch(ref & ~(RefFlags^RefHasFinalizer)) {
+               case RefNone:
+                       // Free small object.
+                       if(ref & RefProfiled)
+                               runtime_MProf_Free(p, size);
+                       *gcrefp = RefFree;
+                       c = m->mcache;
+                       if(size > (int32)sizeof(uintptr))
+                               ((uintptr*)p)[1] = 1;   // mark as "needs to be zeroed"
+                       mstats.alloc -= size;
+                       mstats.by_size[s->sizeclass].nfree++;
+                       runtime_MCache_Free(c, p, s->sizeclass, size);
+                       break;
+               case RefNone|RefHasFinalizer:
+                       f = runtime_getfinalizer(p, 1);
+                       if(f == nil)
+                               runtime_throw("finalizer inconsistency");
+                       f->arg = p;
+                       f->next = finq;
+                       finq = f;
+                       ref &= ~RefHasFinalizer;
+                       // fall through
+               case RefSome:
+               case RefSome|RefHasFinalizer:
+                       *gcrefp = RefNone | (ref&RefFlags);
+                       break;
+               }
+       }
+}
+
+static void
+sweep(void)
+{
+       MSpan *s;
+
+       for(s = runtime_mheap.allspans; s != nil; s = s->allnext)
+               if(s->state == MSpanInUse)
+                       sweepspan(s);
+}
+
+static Lock gcsema = LOCK_INITIALIZER;
+
+// Initialized from $GOGC.  GOGC=off means no gc.
+//
+// Next gc is after we've allocated an extra amount of
+// memory proportional to the amount already in use.
+// If gcpercent=100 and we're using 4M, we'll gc again
+// when we get to 8M.  This keeps the gc cost in linear
+// proportion to the allocation cost.  Adjusting gcpercent
+// just changes the linear constant (and also the amount of
+// extra memory used).
+static int32 gcpercent = -2;
+
+void
+runtime_gc(int32 force __attribute__ ((unused)))
+{
+       int64 t0, t1;
+       char *p;
+       Finalizer *fp;
+
+       // The gc is turned off (via enablegc) until
+       // the bootstrap has completed.
+       // Also, malloc gets called in the guts
+       // of a number of libraries that might be
+       // holding locks.  To avoid priority inversion
+       // problems, don't bother trying to run gc
+       // while holding a lock.  The next mallocgc
+       // without a lock will do the gc instead.
+       if(!mstats.enablegc || m->locks > 0 /* || runtime_panicking */)
+               return;
+
+       if(gcpercent == -2) {   // first time through
+               p = runtime_getenv("GOGC");
+               if(p == nil || p[0] == '\0')
+                       gcpercent = 100;
+               else if(runtime_strcmp(p, "off") == 0)
+                       gcpercent = -1;
+               else
+                       gcpercent = runtime_atoi(p);
+       }
+       if(gcpercent < 0)
+               return;
+
+       runtime_lock(&finqlock);
+       runtime_lock(&gcsema);
+       m->locks++;     // disable gc during the mallocs in newproc
+       t0 = runtime_nanotime();
+       runtime_stoptheworld();
+       if(force || mstats.heap_alloc >= mstats.next_gc) {
+               __go_cachestats();
+               mark();
+               sweep();
+               __go_stealcache();
+               mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
+       }
+
+       t1 = runtime_nanotime();
+       mstats.numgc++;
+       mstats.pause_ns += t1 - t0;
+       if(mstats.debuggc)
+               runtime_printf("pause %llu\n", (unsigned long long)t1-t0);
+       runtime_unlock(&gcsema);
+       runtime_starttheworld();
+
+       // finqlock is still held.
+       fp = finq;
+       if(fp != nil) {
+               // kick off or wake up goroutine to run queued finalizers
+               if(!finstarted) {
+                       __go_go(runfinq, nil);
+                       finstarted = 1;
+               }
+               else if(fingwait) {
+                       fingwait = 0;
+                       pthread_cond_signal(&finqcond);
+               }
+       }
+       m->locks--;
+       runtime_unlock(&finqlock);
+}
+
+static void
+runfinq(void* dummy)
+{
+       Finalizer *f, *next;
+
+       USED(dummy);
+
+       for(;;) {
+               runtime_lock(&finqlock);
+               f = finq;
+               finq = nil;
+               if(f == nil) {
+                       fingwait = 1;
+                       pthread_cond_wait(&finqcond, &finqlock.mutex);
+                       runtime_unlock(&finqlock);
+                       continue;
+               }
+               runtime_unlock(&finqlock);
+               for(; f; f=next) {
+                       void *params[1];
+
+                       next = f->next;
+                       params[0] = &f->arg;
+                       reflect_call(f->ft, (void*)f->fn, 0, params, nil);
+                       f->fn = nil;
+                       f->arg = nil;
+                       f->next = nil;
+                       runtime_free(f);
+               }
+               runtime_gc(1);  // trigger another gc to clean up the finalized objects, if possible
+       }
+}
+
+void
+__go_enable_gc()
+{
+  mstats.enablegc = 1;
+}
diff --git a/libgo/runtime/mheap.c b/libgo/runtime/mheap.c
new file mode 100644 (file)
index 0000000..a375cad
--- /dev/null
@@ -0,0 +1,350 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Page heap.
+//
+// See malloc.h for overview.
+//
+// When a MSpan is in the heap free list, state == MSpanFree
+// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
+//
+// When a MSpan is allocated, state == MSpanInUse
+// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32);
+static bool MHeap_Grow(MHeap*, uintptr);
+static void MHeap_FreeLocked(MHeap*, MSpan*);
+static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
+static MSpan *BestFit(MSpan*, uintptr, MSpan*);
+
+static void
+RecordSpan(void *vh, byte *p)
+{
+       MHeap *h;
+       MSpan *s;
+
+       h = vh;
+       s = (MSpan*)p;
+       s->allnext = h->allspans;
+       h->allspans = s;
+}
+
+// Initialize the heap; fetch memory using alloc.
+void
+runtime_MHeap_Init(MHeap *h, void *(*alloc)(uintptr))
+{
+       uint32 i;
+
+       runtime_initlock(h);
+       runtime_FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h);
+       runtime_FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil);
+       runtime_MHeapMap_Init(&h->map, alloc);
+       // h->mapcache needs no init
+       for(i=0; i<nelem(h->free); i++)
+               runtime_MSpanList_Init(&h->free[i]);
+       runtime_MSpanList_Init(&h->large);
+       for(i=0; i<nelem(h->central); i++)
+               runtime_MCentral_Init(&h->central[i], i);
+}
+
+// Allocate a new span of npage pages from the heap
+// and record its size class in the HeapMap and HeapMapCache.
+MSpan*
+runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct)
+{
+       MSpan *s;
+
+       runtime_lock(h);
+       mstats.heap_alloc += m->mcache->local_alloc;
+       m->mcache->local_alloc = 0;
+       mstats.heap_objects += m->mcache->local_objects;
+       m->mcache->local_objects = 0;
+       s = MHeap_AllocLocked(h, npage, sizeclass);
+       if(s != nil) {
+               mstats.heap_inuse += npage<<PageShift;
+               if(acct) {
+                       mstats.heap_objects++;
+                       mstats.heap_alloc += npage<<PageShift;
+               }
+       }
+       runtime_unlock(h);
+       return s;
+}
+
+static MSpan*
+MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
+{
+       uintptr n;
+       MSpan *s, *t;
+
+       // Try in fixed-size lists up to max.
+       for(n=npage; n < nelem(h->free); n++) {
+               if(!runtime_MSpanList_IsEmpty(&h->free[n])) {
+                       s = h->free[n].next;
+                       goto HaveSpan;
+               }
+       }
+
+       // Best fit in list of large spans.
+       if((s = MHeap_AllocLarge(h, npage)) == nil) {
+               if(!MHeap_Grow(h, npage))
+                       return nil;
+               if((s = MHeap_AllocLarge(h, npage)) == nil)
+                       return nil;
+       }
+
+HaveSpan:
+       // Mark span in use.
+       if(s->state != MSpanFree)
+               runtime_throw("MHeap_AllocLocked - MSpan not free");
+       if(s->npages < npage)
+               runtime_throw("MHeap_AllocLocked - bad npages");
+       runtime_MSpanList_Remove(s);
+       s->state = MSpanInUse;
+
+       if(s->npages > npage) {
+               // Trim extra and put it back in the heap.
+               t = runtime_FixAlloc_Alloc(&h->spanalloc);
+               mstats.mspan_inuse = h->spanalloc.inuse;
+               mstats.mspan_sys = h->spanalloc.sys;
+               runtime_MSpan_Init(t, s->start + npage, s->npages - npage);
+               s->npages = npage;
+               runtime_MHeapMap_Set(&h->map, t->start - 1, s);
+               runtime_MHeapMap_Set(&h->map, t->start, t);
+               runtime_MHeapMap_Set(&h->map, t->start + t->npages - 1, t);
+               t->state = MSpanInUse;
+               MHeap_FreeLocked(h, t);
+       }
+
+       // Record span info, because gc needs to be
+       // able to map interior pointer to containing span.
+       s->sizeclass = sizeclass;
+       for(n=0; n<npage; n++)
+               runtime_MHeapMap_Set(&h->map, s->start+n, s);
+       return s;
+}
+
+// Allocate a span of exactly npage pages from the list of large spans.
+static MSpan*
+MHeap_AllocLarge(MHeap *h, uintptr npage)
+{
+       return BestFit(&h->large, npage, nil);
+}
+
+// Search list for smallest span with >= npage pages.
+// If there are multiple smallest spans, take the one
+// with the earliest starting address.
+static MSpan*
+BestFit(MSpan *list, uintptr npage, MSpan *best)
+{
+       MSpan *s;
+
+       for(s=list->next; s != list; s=s->next) {
+               if(s->npages < npage)
+                       continue;
+               if(best == nil
+               || s->npages < best->npages
+               || (s->npages == best->npages && s->start < best->start))
+                       best = s;
+       }
+       return best;
+}
+
+// Try to add at least npage pages of memory to the heap,
+// returning whether it worked.
+static bool
+MHeap_Grow(MHeap *h, uintptr npage)
+{
+       uintptr ask;
+       void *v;
+       MSpan *s;
+
+       // Ask for a big chunk, to reduce the number of mappings
+       // the operating system needs to track; also amortizes
+       // the overhead of an operating system mapping.
+       // For Native Client, allocate a multiple of 64kB (16 pages).
+       npage = (npage+15)&~15;
+       ask = npage<<PageShift;
+       if(ask < HeapAllocChunk)
+               ask = HeapAllocChunk;
+
+       v = runtime_SysAlloc(ask);
+       if(v == nil) {
+               if(ask > (npage<<PageShift)) {
+                       ask = npage<<PageShift;
+                       v = runtime_SysAlloc(ask);
+               }
+               if(v == nil)
+                       return false;
+       }
+       mstats.heap_sys += ask;
+
+       if((byte*)v < h->min || h->min == nil)
+               h->min = v;
+       if((byte*)v+ask > h->max)
+               h->max = (byte*)v+ask;
+
+       // NOTE(rsc): In tcmalloc, if we've accumulated enough
+       // system allocations, the heap map gets entirely allocated
+       // in 32-bit mode.  (In 64-bit mode that's not practical.)
+       if(!runtime_MHeapMap_Preallocate(&h->map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) {
+               runtime_SysFree(v, ask);
+               return false;
+       }
+
+       // Create a fake "in use" span and free it, so that the
+       // right coalescing happens.
+       s = runtime_FixAlloc_Alloc(&h->spanalloc);
+       mstats.mspan_inuse = h->spanalloc.inuse;
+       mstats.mspan_sys = h->spanalloc.sys;
+       runtime_MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
+       runtime_MHeapMap_Set(&h->map, s->start, s);
+       runtime_MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
+       s->state = MSpanInUse;
+       MHeap_FreeLocked(h, s);
+       return true;
+}
+
+// Look up the span at the given page number.
+// Page number is guaranteed to be in map
+// and is guaranteed to be start or end of span.
+MSpan*
+runtime_MHeap_Lookup(MHeap *h, PageID p)
+{
+       return runtime_MHeapMap_Get(&h->map, p);
+}
+
+// Look up the span at the given page number.
+// Page number is *not* guaranteed to be in map
+// and may be anywhere in the span.
+// Map entries for the middle of a span are only
+// valid for allocated spans.  Free spans may have
+// other garbage in their middles, so we have to
+// check for that.
+MSpan*
+runtime_MHeap_LookupMaybe(MHeap *h, PageID p)
+{
+       MSpan *s;
+
+       s = runtime_MHeapMap_GetMaybe(&h->map, p);
+       if(s == nil || p < s->start || p - s->start >= s->npages)
+               return nil;
+       if(s->state != MSpanInUse)
+               return nil;
+       return s;
+}
+
+// Free the span back into the heap.
+void
+runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct)
+{
+       runtime_lock(h);
+       mstats.heap_alloc += m->mcache->local_alloc;
+       m->mcache->local_alloc = 0;
+       mstats.heap_objects += m->mcache->local_objects;
+       m->mcache->local_objects = 0;
+       mstats.heap_inuse -= s->npages<<PageShift;
+       if(acct) {
+               mstats.heap_alloc -= s->npages<<PageShift;
+               mstats.heap_objects--;
+       }
+       MHeap_FreeLocked(h, s);
+       runtime_unlock(h);
+}
+
+static void
+MHeap_FreeLocked(MHeap *h, MSpan *s)
+{
+       MSpan *t;
+
+       if(s->state != MSpanInUse || s->ref != 0) {
+               // runtime_printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
+               runtime_throw("MHeap_FreeLocked - invalid free");
+       }
+       s->state = MSpanFree;
+       runtime_MSpanList_Remove(s);
+
+       // Coalesce with earlier, later spans.
+       if((t = runtime_MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) {
+               s->start = t->start;
+               s->npages += t->npages;
+               runtime_MHeapMap_Set(&h->map, s->start, s);
+               runtime_MSpanList_Remove(t);
+               t->state = MSpanDead;
+               runtime_FixAlloc_Free(&h->spanalloc, t);
+               mstats.mspan_inuse = h->spanalloc.inuse;
+               mstats.mspan_sys = h->spanalloc.sys;
+       }
+       if((t = runtime_MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) {
+               s->npages += t->npages;
+               runtime_MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
+               runtime_MSpanList_Remove(t);
+               t->state = MSpanDead;
+               runtime_FixAlloc_Free(&h->spanalloc, t);
+               mstats.mspan_inuse = h->spanalloc.inuse;
+               mstats.mspan_sys = h->spanalloc.sys;
+       }
+
+       // Insert s into appropriate list.
+       if(s->npages < nelem(h->free))
+               runtime_MSpanList_Insert(&h->free[s->npages], s);
+       else
+               runtime_MSpanList_Insert(&h->large, s);
+
+       // TODO(rsc): IncrementalScavenge() to return memory to OS.
+}
+
+// Initialize a new span with the given start and npages.
+void
+runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages)
+{
+       span->next = nil;
+       span->prev = nil;
+       span->start = start;
+       span->npages = npages;
+       span->freelist = nil;
+       span->ref = 0;
+       span->sizeclass = 0;
+       span->state = 0;
+}
+
+// Initialize an empty doubly-linked list.
+void
+runtime_MSpanList_Init(MSpan *list)
+{
+       list->state = MSpanListHead;
+       list->next = list;
+       list->prev = list;
+}
+
+void
+runtime_MSpanList_Remove(MSpan *span)
+{
+       if(span->prev == nil && span->next == nil)
+               return;
+       span->prev->next = span->next;
+       span->next->prev = span->prev;
+       span->prev = nil;
+       span->next = nil;
+}
+
+bool
+runtime_MSpanList_IsEmpty(MSpan *list)
+{
+       return list->next == list;
+}
+
+void
+runtime_MSpanList_Insert(MSpan *list, MSpan *span)
+{
+       if(span->next != nil || span->prev != nil)
+               runtime_throw("MSpanList_Insert");
+       span->next = list->next;
+       span->prev = list;
+       span->next->prev = span;
+       span->prev->next = span;
+}
diff --git a/libgo/runtime/mheapmap32.c b/libgo/runtime/mheapmap32.c
new file mode 100644 (file)
index 0000000..547c602
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Heap map, 32-bit version
+// See malloc.h and mheap.c for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+#if __SIZEOF_POINTER__ == 4
+
+// 3-level radix tree mapping page ids to Span*.
+void
+runtime_MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
+{
+       m->allocator = allocator;
+}
+
+MSpan*
+runtime_MHeapMap_Get(MHeapMap *m, PageID k)
+{
+       int32 i1, i2;
+
+       i2 = k & MHeapMap_Level2Mask;
+       k >>= MHeapMap_Level2Bits;
+       i1 = k & MHeapMap_Level1Mask;
+       k >>= MHeapMap_Level1Bits;
+       if(k != 0)
+               runtime_throw("MHeapMap_Get");
+
+       return m->p[i1]->s[i2];
+}
+
+MSpan*
+runtime_MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+{
+       int32 i1, i2;
+       MHeapMapNode2 *p2;
+
+       i2 = k & MHeapMap_Level2Mask;
+       k >>= MHeapMap_Level2Bits;
+       i1 = k & MHeapMap_Level1Mask;
+       k >>= MHeapMap_Level1Bits;
+       if(k != 0)
+               runtime_throw("MHeapMap_Get");
+
+       p2 = m->p[i1];
+       if(p2 == nil)
+               return nil;
+       return p2->s[i2];
+}
+
+void
+runtime_MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+{
+       int32 i1, i2;
+
+       i2 = k & MHeapMap_Level2Mask;
+       k >>= MHeapMap_Level2Bits;
+       i1 = k & MHeapMap_Level1Mask;
+       k >>= MHeapMap_Level1Bits;
+       if(k != 0)
+               runtime_throw("MHeapMap_Set");
+
+       m->p[i1]->s[i2] = s;
+}
+
+// Allocate the storage required for entries [k, k+1, ..., k+len-1]
+// so that Get and Set calls need not check for nil pointers.
+bool
+runtime_MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
+{
+       uintptr end;
+       int32 i1;
+       MHeapMapNode2 *p2;
+
+       end = k+len;
+       while(k < end) {
+               if((k >> MHeapMap_TotalBits) != 0)
+                       return false;
+               i1 = (k >> MHeapMap_Level2Bits) & MHeapMap_Level1Mask;
+
+               // first-level pointer
+               if(m->p[i1] == nil) {
+                       p2 = m->allocator(sizeof *p2);
+                       if(p2 == nil)
+                               return false;
+                       mstats.heapmap_sys += sizeof *p2;
+                       m->p[i1] = p2;
+               }
+
+               // advance key past this leaf node
+               k = ((k >> MHeapMap_Level2Bits) + 1) << MHeapMap_Level2Bits;
+       }
+       return true;
+}
+
+#endif /* __SIZEOF_POINTER__ == 4 */
diff --git a/libgo/runtime/mheapmap32.h b/libgo/runtime/mheapmap32.h
new file mode 100644 (file)
index 0000000..2861624
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Free(v) must be able to determine the MSpan containing v.
+// The MHeapMap is a 2-level radix tree mapping page numbers to MSpans.
+
+typedef struct MHeapMapNode2 MHeapMapNode2;
+
+enum
+{
+       // 32 bit address - 12 bit page size = 20 bits to map
+       MHeapMap_Level1Bits = 10,
+       MHeapMap_Level2Bits = 10,
+
+       MHeapMap_TotalBits =
+               MHeapMap_Level1Bits +
+               MHeapMap_Level2Bits,
+
+       MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1,
+       MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1,
+};
+
+struct MHeapMap
+{
+       void *(*allocator)(uintptr);
+       MHeapMapNode2 *p[1<<MHeapMap_Level1Bits];
+};
+
+struct MHeapMapNode2
+{
+       MSpan *s[1<<MHeapMap_Level2Bits];
+};
+
+void   runtime_MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool   runtime_MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* runtime_MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* runtime_MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void   runtime_MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+
+
diff --git a/libgo/runtime/mheapmap64.c b/libgo/runtime/mheapmap64.c
new file mode 100644 (file)
index 0000000..d630595
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Heap map, 64-bit version 
+// See malloc.h and mheap.c for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+#if __SIZEOF_POINTER__ == 8
+
+// 3-level radix tree mapping page ids to Span*.
+void
+runtime_MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
+{
+       m->allocator = allocator;
+}
+
+MSpan*
+runtime_MHeapMap_Get(MHeapMap *m, PageID k)
+{
+       int32 i1, i2, i3;
+
+       i3 = k & MHeapMap_Level3Mask;
+       k >>= MHeapMap_Level3Bits;
+       i2 = k & MHeapMap_Level2Mask;
+       k >>= MHeapMap_Level2Bits;
+       i1 = k & MHeapMap_Level1Mask;
+       k >>= MHeapMap_Level1Bits;
+       if(k != 0)
+               runtime_throw("MHeapMap_Get");
+
+       return m->p[i1]->p[i2]->s[i3];
+}
+
+MSpan*
+runtime_MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+{
+       int32 i1, i2, i3;
+       MHeapMapNode2 *p2;
+       MHeapMapNode3 *p3;
+
+       i3 = k & MHeapMap_Level3Mask;
+       k >>= MHeapMap_Level3Bits;
+       i2 = k & MHeapMap_Level2Mask;
+       k >>= MHeapMap_Level2Bits;
+       i1 = k & MHeapMap_Level1Mask;
+       k >>= MHeapMap_Level1Bits;
+       if(k != 0)
+               runtime_throw("MHeapMap_Get");
+
+       p2 = m->p[i1];
+       if(p2 == nil)
+               return nil;
+       p3 = p2->p[i2];
+       if(p3 == nil)
+               return nil;
+       return p3->s[i3];
+}
+
+void
+runtime_MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+{
+       int32 i1, i2, i3;
+
+       i3 = k & MHeapMap_Level3Mask;
+       k >>= MHeapMap_Level3Bits;
+       i2 = k & MHeapMap_Level2Mask;
+       k >>= MHeapMap_Level2Bits;
+       i1 = k & MHeapMap_Level1Mask;
+       k >>= MHeapMap_Level1Bits;
+       if(k != 0)
+               runtime_throw("MHeapMap_Set");
+
+       m->p[i1]->p[i2]->s[i3] = s;
+}
+
+// Allocate the storage required for entries [k, k+1, ..., k+len-1]
+// so that Get and Set calls need not check for nil pointers.
+bool
+runtime_MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
+{
+       uintptr end;
+       int32 i1, i2;
+       MHeapMapNode2 *p2;
+       MHeapMapNode3 *p3;
+
+       end = k+len;
+       while(k < end) {
+               if((k >> MHeapMap_TotalBits) != 0)
+                       return false;
+               i2 = (k >> MHeapMap_Level3Bits) & MHeapMap_Level2Mask;
+               i1 = (k >> (MHeapMap_Level3Bits + MHeapMap_Level2Bits)) & MHeapMap_Level1Mask;
+
+               // first-level pointer
+               if((p2 = m->p[i1]) == nil) {
+                       p2 = m->allocator(sizeof *p2);
+                       if(p2 == nil)
+                               return false;
+                       mstats.heapmap_sys += sizeof *p2;
+                       m->p[i1] = p2;
+               }
+
+               // second-level pointer
+               if(p2->p[i2] == nil) {
+                       p3 = m->allocator(sizeof *p3);
+                       if(p3 == nil)
+                               return false;
+                       mstats.heapmap_sys += sizeof *p3;
+                       p2->p[i2] = p3;
+               }
+
+               // advance key past this leaf node
+               k = ((k >> MHeapMap_Level3Bits) + 1) << MHeapMap_Level3Bits;
+       }
+       return true;
+}
+
+#endif /* __SIZEOF_POINTER__ == 8 */
diff --git a/libgo/runtime/mheapmap64.h b/libgo/runtime/mheapmap64.h
new file mode 100644 (file)
index 0000000..be304cb
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Free(v) must be able to determine the MSpan containing v.
+// The MHeapMap is a 3-level radix tree mapping page numbers to MSpans.
+//
+// NOTE(rsc): On a 32-bit platform (= 20-bit page numbers),
+// we can swap in a 2-level radix tree.
+//
+// NOTE(rsc): We use a 3-level tree because tcmalloc does, but
+// having only three levels requires approximately 1 MB per node
+// in the tree, making the minimum map footprint 3 MB.
+// Using a 4-level tree would cut the minimum footprint to 256 kB.
+// On the other hand, it's just virtual address space: most of
+// the memory is never going to be touched, thus never paged in.
+
+typedef struct MHeapMapNode2 MHeapMapNode2;
+typedef struct MHeapMapNode3 MHeapMapNode3;
+
+enum
+{
+       // 64 bit address - 12 bit page size = 52 bits to map
+       MHeapMap_Level1Bits = 18,
+       MHeapMap_Level2Bits = 18,
+       MHeapMap_Level3Bits = 16,
+
+       MHeapMap_TotalBits =
+               MHeapMap_Level1Bits +
+               MHeapMap_Level2Bits +
+               MHeapMap_Level3Bits,
+
+       MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1,
+       MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1,
+       MHeapMap_Level3Mask = (1<<MHeapMap_Level3Bits) - 1,
+};
+
+struct MHeapMap
+{
+       void *(*allocator)(uintptr);
+       MHeapMapNode2 *p[1<<MHeapMap_Level1Bits];
+};
+
+struct MHeapMapNode2
+{
+       MHeapMapNode3 *p[1<<MHeapMap_Level2Bits];
+};
+
+struct MHeapMapNode3
+{
+       MSpan *s[1<<MHeapMap_Level3Bits];
+};
+
+void   runtime_MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool   runtime_MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* runtime_MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* runtime_MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void   runtime_MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+
+
diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc
new file mode 100644 (file)
index 0000000..5ee6b0f
--- /dev/null
@@ -0,0 +1,299 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Malloc profiling.
+// Patterned after tcmalloc's algorithms; shorter code.
+
+package runtime
+#include "runtime.h"
+#include "malloc.h"
+#include "defs.h"
+#include "go-type.h"
+
+typedef struct __go_open_array Slice;
+
+// NOTE(rsc): Everything here could use cas if contention became an issue.
+static Lock proflock = LOCK_INITIALIZER;
+
+// Per-call-stack allocation information.
+// Lookup by hashing call stack into a linked-list hash table.
+typedef struct Bucket Bucket;
+struct Bucket
+{
+       Bucket  *next;  // next in hash list
+       Bucket  *allnext;       // next in list of all buckets
+       uintptr allocs;
+       uintptr frees;
+       uintptr alloc_bytes;
+       uintptr free_bytes;
+       uintptr hash;
+       uintptr nstk;
+       uintptr stk[1];
+};
+enum {
+       BuckHashSize = 179999,
+};
+static Bucket **buckhash;
+static Bucket *buckets;
+static uintptr bucketmem;
+
+// Return the bucket for stk[0:nstk], allocating new bucket if needed.
+static Bucket*
+stkbucket(uintptr *stk, int32 nstk)
+{
+       int32 i;
+       uintptr h;
+       Bucket *b;
+
+       if(buckhash == nil) {
+               buckhash = runtime_SysAlloc(BuckHashSize*sizeof buckhash[0]);
+               mstats.buckhash_sys += BuckHashSize*sizeof buckhash[0];
+       }
+
+       // Hash stack.
+       h = 0;
+       for(i=0; i<nstk; i++) {
+               h += stk[i];
+               h += h<<10;
+               h ^= h>>6;
+       }
+       h += h<<3;
+       h ^= h>>11;
+
+       i = h%BuckHashSize;
+       for(b = buckhash[i]; b; b=b->next)
+               if(b->hash == h && b->nstk == (uintptr)nstk &&
+                  runtime_mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
+                       return b;
+
+       b = runtime_mallocgc(sizeof *b + nstk*sizeof stk[0], RefNoProfiling, 0, 1);
+       bucketmem += sizeof *b + nstk*sizeof stk[0];
+       runtime_memmove(b->stk, stk, nstk*sizeof stk[0]);
+       b->hash = h;
+       b->nstk = nstk;
+       b->next = buckhash[i];
+       buckhash[i] = b;
+       b->allnext = buckets;
+       buckets = b;
+       return b;
+}
+
+// Map from pointer to Bucket* that allocated it.
+// Three levels:
+//     Linked-list hash table for top N-20 bits.
+//     Array index for next 13 bits.
+//     Linked list for next 7 bits.
+// This is more efficient than using a general map,
+// because of the typical clustering of the pointer keys.
+
+typedef struct AddrHash AddrHash;
+typedef struct AddrEntry AddrEntry;
+
+struct AddrHash
+{
+       AddrHash *next; // next in top-level hash table linked list
+       uintptr addr;   // addr>>20
+       AddrEntry *dense[1<<13];
+};
+
+struct AddrEntry
+{
+       AddrEntry *next;        // next in bottom-level linked list
+       uint32 addr;
+       Bucket *b;
+};
+
+enum {
+       AddrHashBits = 12       // 1MB per entry, so good for 4GB of used address space
+};
+static AddrHash *addrhash[1<<AddrHashBits];
+static AddrEntry *addrfree;
+static uintptr addrmem;
+
+// Multiplicative hash function:
+// hashMultiplier is the bottom 32 bits of int((sqrt(5)-1)/2 * (1<<32)).
+// This is a good multiplier as suggested in CLR, Knuth.  The hash
+// value is taken to be the top AddrHashBits bits of the bottom 32 bits
+// of the muliplied value.
+enum {
+       HashMultiplier = 2654435769U
+};
+
+// Set the bucket associated with addr to b.
+static void
+setaddrbucket(uintptr addr, Bucket *b)
+{
+       int32 i;
+       uint32 h;
+       AddrHash *ah;
+       AddrEntry *e;
+
+       h = (uint32)((addr>>20)*HashMultiplier) >> (32-AddrHashBits);
+       for(ah=addrhash[h]; ah; ah=ah->next)
+               if(ah->addr == (addr>>20))
+                       goto found;
+
+       ah = runtime_mallocgc(sizeof *ah, RefNoProfiling, 0, 1);
+       addrmem += sizeof *ah;
+       ah->next = addrhash[h];
+       ah->addr = addr>>20;
+       addrhash[h] = ah;
+
+found:
+       if((e = addrfree) == nil) {
+               e = runtime_mallocgc(64*sizeof *e, RefNoProfiling, 0, 0);
+               addrmem += 64*sizeof *e;
+               for(i=0; i+1<64; i++)
+                       e[i].next = &e[i+1];
+               e[63].next = nil;
+       }
+       addrfree = e->next;
+       e->addr = (uint32)~(addr & ((1<<20)-1));
+       e->b = b;
+       h = (addr>>7)&(nelem(ah->dense)-1);     // entry in dense is top 13 bits of low 20.
+       e->next = ah->dense[h];
+       ah->dense[h] = e;
+}
+
+// Get the bucket associated with addr and clear the association.
+static Bucket*
+getaddrbucket(uintptr addr)
+{
+       uint32 h;
+       AddrHash *ah;
+       AddrEntry *e, **l;
+       Bucket *b;
+
+       h = (uint32)((addr>>20)*HashMultiplier) >> (32-AddrHashBits);
+       for(ah=addrhash[h]; ah; ah=ah->next)
+               if(ah->addr == (addr>>20))
+                       goto found;
+       return nil;
+
+found:
+       h = (addr>>7)&(nelem(ah->dense)-1);     // entry in dense is top 13 bits of low 20.
+       for(l=&ah->dense[h]; (e=*l) != nil; l=&e->next) {
+               if(e->addr == (uint32)~(addr & ((1<<20)-1))) {
+                       *l = e->next;
+                       b = e->b;
+                       e->next = addrfree;
+                       addrfree = e;
+                       return b;
+               }
+       }
+       return nil;
+}
+
+// Called by malloc to record a profiled block.
+void
+runtime_MProf_Malloc(void *p, uintptr size)
+{
+       int32 nstk;
+       uintptr stk[32];
+       Bucket *b;
+
+       if(!__sync_bool_compare_and_swap(&m->nomemprof, 0, 1))
+               return;
+#if 0
+       nstk = runtime_callers(1, stk, 32);
+#else
+       nstk = 0;
+#endif
+       runtime_lock(&proflock);
+       b = stkbucket(stk, nstk);
+       b->allocs++;
+       b->alloc_bytes += size;
+       setaddrbucket((uintptr)p, b);
+       runtime_unlock(&proflock);
+       __sync_bool_compare_and_swap(&m->nomemprof, 1, 0);
+
+       if(__sync_bool_compare_and_swap(&m->gcing_for_prof, 1, 0))
+               __go_run_goroutine_gc(100);
+}
+
+// Called when freeing a profiled block.
+void
+runtime_MProf_Free(void *p, uintptr size)
+{
+       Bucket *b;
+
+       if(!__sync_bool_compare_and_swap(&m->nomemprof, 0, 1))
+               return;
+
+       runtime_lock(&proflock);
+       b = getaddrbucket((uintptr)p);
+       if(b != nil) {
+               b->frees++;
+               b->free_bytes += size;
+       }
+       runtime_unlock(&proflock);
+       __sync_bool_compare_and_swap(&m->nomemprof, 1, 0);
+
+       if(__sync_bool_compare_and_swap(&m->gcing_for_prof, 1, 0))
+               __go_run_goroutine_gc(101);
+}
+
+
+// Go interface to profile data.  (Declared in extern.go)
+// Assumes Go sizeof(int) == sizeof(int32)
+
+// Must match MemProfileRecord in extern.go.
+typedef struct Record Record;
+struct Record {
+       int64 alloc_bytes, free_bytes;
+       int64 alloc_objects, free_objects;
+       uintptr stk[32];
+};
+
+// Write b's data to r.
+static void
+record(Record *r, Bucket *b)
+{
+       uint32 i;
+
+       r->alloc_bytes = b->alloc_bytes;
+       r->free_bytes = b->free_bytes;
+       r->alloc_objects = b->allocs;
+       r->free_objects = b->frees;
+       for(i=0; i<b->nstk && i<nelem(r->stk); i++)
+               r->stk[i] = b->stk[i];
+       for(; i<nelem(r->stk); i++)
+               r->stk[i] = 0;
+}
+
+func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) {
+       Bucket *b;
+       Record *r;
+
+       __sync_bool_compare_and_swap(&m->nomemprof, 0, 1);
+
+       runtime_lock(&proflock);
+       n = 0;
+       for(b=buckets; b; b=b->allnext)
+               if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
+                       n++;
+       ok = false;
+       if(n <= p.__count) {
+               ok = true;
+               r = (Record*)p.__values;
+               for(b=buckets; b; b=b->allnext)
+                       if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
+                               record(r++, b);
+       }
+       runtime_unlock(&proflock);
+
+       __sync_bool_compare_and_swap(&m->nomemprof, 1, 0);
+
+       if(__sync_bool_compare_and_swap(&m->gcing_for_prof, 1, 0))
+               __go_run_goroutine_gc(102);
+}
+
+void
+runtime_MProf_Mark(void (*scan)(byte *, int64))
+{
+       // buckhash is not allocated via mallocgc.
+       scan((byte*)&buckets, sizeof buckets);
+       scan((byte*)&addrhash, sizeof addrhash);
+       scan((byte*)&addrfree, sizeof addrfree);
+}
diff --git a/libgo/runtime/msize.c b/libgo/runtime/msize.c
new file mode 100644 (file)
index 0000000..8b021a2
--- /dev/null
@@ -0,0 +1,169 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Malloc small size classes.
+//
+// See malloc.h for overview.
+//
+// The size classes are chosen so that rounding an allocation
+// request up to the next size class wastes at most 12.5% (1.125x).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory.  It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+#include "runtime.h"
+#include "malloc.h"
+
+int32 runtime_class_to_size[NumSizeClasses];
+int32 runtime_class_to_allocnpages[NumSizeClasses];
+int32 runtime_class_to_transfercount[NumSizeClasses];
+
+// The SizeToClass lookup is implemented using two arrays,
+// one mapping sizes <= 1024 to their class and one mapping
+// sizes >= 1024 and <= MaxSmallSize to their class.
+// All objects are 8-aligned, so the first array is indexed by
+// the size divided by 8 (rounded up).  Objects >= 1024 bytes
+// are 128-aligned, so the second array is indexed by the
+// size divided by 128 (rounded up).  The arrays are filled in
+// by InitSizes.
+
+static int32 size_to_class8[1024/8 + 1];
+static int32 size_to_class128[(MaxSmallSize-1024)/128 + 1];
+
+int32
+runtime_SizeToClass(int32 size)
+{
+       if(size > MaxSmallSize)
+               runtime_throw("SizeToClass - invalid size");
+       if(size > 1024-8)
+               return size_to_class128[(size-1024+127) >> 7];
+       return size_to_class8[(size+7)>>3];
+}
+
+void
+runtime_InitSizes(void)
+{
+       int32 align, sizeclass, size, osize, nextsize, n;
+       uint32 i;
+       uintptr allocsize, npages;
+
+       // Initialize the runtime_class_to_size table (and choose class sizes in the process).
+       runtime_class_to_size[0] = 0;
+       sizeclass = 1;  // 0 means no class
+       align = 8;
+       for(size = align; size <= MaxSmallSize; size += align) {
+               if((size&(size-1)) == 0) {      // bump alignment once in a while
+                       if(size >= 2048)
+                               align = 256;
+                       else if(size >= 128)
+                               align = size / 8;
+                       else if(size >= 16)
+                               align = 16;     // required for x86 SSE instructions, if we want to use them
+               }
+               if((align&(align-1)) != 0)
+                       runtime_throw("InitSizes - bug");
+
+               // Make the allocnpages big enough that
+               // the leftover is less than 1/8 of the total,
+               // so wasted space is at most 12.5%.
+               allocsize = PageSize;
+               osize = size + RefcountOverhead;
+               while(allocsize%osize > (allocsize/8))
+                       allocsize += PageSize;
+               npages = allocsize >> PageShift;
+
+               // If the previous sizeclass chose the same
+               // allocation size and fit the same number of
+               // objects into the page, we might as well
+               // use just this size instead of having two
+               // different sizes.
+               if(sizeclass > 1
+               && (int32)npages == runtime_class_to_allocnpages[sizeclass-1]
+               && allocsize/osize == allocsize/(runtime_class_to_size[sizeclass-1]+RefcountOverhead)) {
+                       runtime_class_to_size[sizeclass-1] = size;
+                       continue;
+               }
+
+               runtime_class_to_allocnpages[sizeclass] = npages;
+               runtime_class_to_size[sizeclass] = size;
+               sizeclass++;
+       }
+       if(sizeclass != NumSizeClasses) {
+               // runtime_printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
+               runtime_throw("InitSizes - bad NumSizeClasses");
+       }
+
+       // Initialize the size_to_class tables.
+       nextsize = 0;
+       for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+               for(; nextsize < 1024 && nextsize <= runtime_class_to_size[sizeclass]; nextsize+=8)
+                       size_to_class8[nextsize/8] = sizeclass;
+               if(nextsize >= 1024)
+                       for(; nextsize <= runtime_class_to_size[sizeclass]; nextsize += 128)
+                               size_to_class128[(nextsize-1024)/128] = sizeclass;
+       }
+
+       // Double-check SizeToClass.
+       if(0) {
+               for(n=0; n < MaxSmallSize; n++) {
+                       sizeclass = runtime_SizeToClass(n);
+                       if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime_class_to_size[sizeclass] < n) {
+                               // runtime_printf("size=%d sizeclass=%d runtime_class_to_size=%d\n", n, sizeclass, runtime_class_to_size[sizeclass]);
+                               // runtime_printf("incorrect SizeToClass");
+                               goto dump;
+                       }
+                       if(sizeclass > 1 && runtime_class_to_size[sizeclass-1] >= n) {
+                               // runtime_printf("size=%d sizeclass=%d runtime_class_to_size=%d\n", n, sizeclass, runtime_class_to_size[sizeclass]);
+                               // runtime_printf("SizeToClass too big");
+                               goto dump;
+                       }
+               }
+       }
+
+       // Copy out for statistics table.
+       for(i=0; i<nelem(runtime_class_to_size); i++)
+               mstats.by_size[i].size = runtime_class_to_size[i];
+
+       // Initialize the runtime_class_to_transfercount table.
+       for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+               n = 64*1024 / runtime_class_to_size[sizeclass];
+               if(n < 2)
+                       n = 2;
+               if(n > 32)
+                       n = 32;
+               runtime_class_to_transfercount[sizeclass] = n;
+       }
+       return;
+
+dump:
+       if(1){
+               runtime_printf("NumSizeClasses=%d\n", NumSizeClasses);
+               runtime_printf("runtime_class_to_size:");
+               for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
+                       runtime_printf(" %d", runtime_class_to_size[sizeclass]);
+               runtime_printf("\n\n");
+               runtime_printf("size_to_class8:");
+               for(i=0; i<nelem(size_to_class8); i++)
+                       runtime_printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], runtime_class_to_size[size_to_class8[i]]);
+               runtime_printf("\n");
+               runtime_printf("size_to_class128:");
+               for(i=0; i<nelem(size_to_class128); i++)
+                       runtime_printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], runtime_class_to_size[size_to_class128[i]]);
+               runtime_printf("\n");
+       }
+       runtime_throw("InitSizes failed");
+}
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
new file mode 100644 (file)
index 0000000..191fac6
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "malloc.h"    /* so that acid generated from proc.c includes malloc data structures */
+
+typedef struct Sched Sched;
+
+M      m0;
+
+#ifdef __rtems__
+#define __thread
+#endif
+
+__thread M *m = &m0;
diff --git a/libgo/runtime/reflect.goc b/libgo/runtime/reflect.goc
new file mode 100644 (file)
index 0000000..01d218a
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect
+#include "go-type.h"
+#include "interface.h"
+#define nil NULL
+typedef unsigned char byte;
+
+typedef struct __go_interface Iface;
+typedef struct __go_empty_interface Eface;
+
+func setiface(typ *byte, x *byte, ret *byte) {
+       struct __go_interface_type *t;
+       const struct __go_type_descriptor* xt;
+
+       /* FIXME: We should check __type_descriptor to verify that
+          this is really a type descriptor.  */
+       t = (struct __go_interface_type *)typ;
+       if(t->__methods.__count == 0) {
+               // already an empty interface
+               *(Eface*)ret = *(Eface*)x;
+               return;
+       }
+       xt = ((Eface*)x)->__type_descriptor;
+       if(xt == nil) {
+               // can assign nil to any interface
+               ((Iface*)ret)->__methods = nil;
+               ((Iface*)ret)->__object = nil;
+               return;
+       }
+       ((Iface*)ret)->__methods = __go_convert_interface(&t->__common, xt);
+       ((Iface*)ret)->__object = ((Eface*)x)->__object;
+}
diff --git a/libgo/runtime/rtems-task-variable-add.c b/libgo/runtime/rtems-task-variable-add.c
new file mode 100644 (file)
index 0000000..89dbb00
--- /dev/null
@@ -0,0 +1,24 @@
+/* rtems-task-variable-add.c -- adding a task specific variable in RTEMS OS.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <rtems/error.h>
+#include <rtems/system.h>
+#include <rtems/rtems/tasks.h>
+
+#include "go-assert.h"
+
+/* RTEMS does not support GNU TLS extension __thread.  */
+void
+__wrap_rtems_task_variable_add (void **var)
+{
+  rtems_status_code sc = rtems_task_variable_add (RTEMS_SELF, var, NULL);
+  if (sc != RTEMS_SUCCESSFUL)
+    {
+      rtems_error (sc, "rtems_task_variable_add failed");
+      __go_assert (0);
+    }
+}
+
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
new file mode 100644 (file)
index 0000000..e062bd6
--- /dev/null
@@ -0,0 +1,190 @@
+/* runtime.h -- runtime support for Go.
+
+   Copyright 2009 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "config.h"
+
+#define _GNU_SOURCE
+#include "go-assert.h"
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "go-alloc.h"
+#include "go-panic.h"
+#include "go-string.h"
+
+typedef struct __go_string String;
+
+/* This file supports C files copied from the 6g runtime library.
+   This is a version of the 6g runtime.h rewritten for gccgo's version
+   of the code.  */
+
+typedef signed int   int8    __attribute__ ((mode (QI)));
+typedef unsigned int uint8   __attribute__ ((mode (QI)));
+typedef signed int   int16   __attribute__ ((mode (HI)));
+typedef unsigned int uint16  __attribute__ ((mode (HI)));
+typedef signed int   int32   __attribute__ ((mode (SI)));
+typedef unsigned int uint32  __attribute__ ((mode (SI)));
+typedef signed int   int64   __attribute__ ((mode (DI)));
+typedef unsigned int uint64  __attribute__ ((mode (DI)));
+typedef float        float32 __attribute__ ((mode (SF)));
+typedef double       float64 __attribute__ ((mode (DF)));
+typedef unsigned int uintptr __attribute__ ((mode (pointer)));
+
+/* Defined types.  */
+
+typedef        uint8                   bool;
+typedef        uint8                   byte;
+typedef        struct  M               M;
+typedef        struct  MCache          MCache;
+typedef        struct  Lock            Lock;
+
+/* We use mutexes for locks.  6g uses futexes directly, and perhaps
+   someday we will do that too.  */
+
+struct Lock
+{
+       pthread_mutex_t mutex;
+};
+
+/* A Note.  */
+
+typedef        struct  Note            Note;
+
+struct Note {
+       int32 woken;
+};
+
+/* Per CPU declarations.  */
+
+#ifdef __rtems__
+#define __thread
+#endif
+
+extern __thread                M*      m;
+
+extern M       m0;
+
+#ifdef __rtems__
+#undef __thread
+#endif
+
+/* Constants.  */
+
+enum
+{
+       true    = 1,
+       false   = 0,
+};
+
+/* Structures.  */
+
+struct M
+{
+       int32   mallocing;
+       int32   gcing;
+       int32   locks;
+       int32   nomemprof;
+       int32   gcing_for_prof;
+       MCache  *mcache;
+
+       /* For the list of all threads.  */
+       struct __go_thread_id *list_entry;
+
+       /* For the garbage collector.  */
+       void    *gc_sp;
+       size_t  gc_len;
+       void    *gc_next_segment;
+       void    *gc_next_sp;
+       void    *gc_initial_sp;
+       struct __go_panic_defer_struct *gc_panic_defer;
+};
+
+/* Macros.  */
+#define        nelem(x)        (sizeof(x)/sizeof((x)[0]))
+#define        nil             ((void*)0)
+#define USED(v)                ((void) v)
+
+/* We map throw to assert.  */
+#define runtime_throw(s) __go_assert(s == 0)
+
+void*  runtime_mal(uintptr);
+void   runtime_mallocinit(void);
+void   siginit(void);
+bool   __go_sigsend(int32 sig);
+int64  runtime_nanotime(void);
+
+void   runtime_stoptheworld(void);
+void   runtime_starttheworld(void);
+void   __go_go(void (*pfn)(void*), void*);
+void   __go_gc_goroutine_init(void*);
+void   __go_enable_gc(void);
+int    __go_run_goroutine_gc(int);
+void   __go_scanstacks(void (*scan)(byte *, int64));
+void   __go_stealcache(void);
+void   __go_cachestats(void);
+
+/*
+ * mutual exclusion locks.  in the uncontended case,
+ * as fast as spin locks (just a few user-level instructions),
+ * but on the contention path they sleep in the kernel.
+ */
+#define        LOCK_INITIALIZER        { PTHREAD_MUTEX_INITIALIZER }
+void   runtime_initlock(Lock*);
+void   runtime_lock(Lock*);
+void   runtime_unlock(Lock*);
+void   runtime_destroylock(Lock*);
+bool   runtime_trylock(Lock*);
+
+void semacquire (uint32 *) asm ("libgo_runtime.runtime.Semacquire");
+void semrelease (uint32 *) asm ("libgo_runtime.runtime.Semrelease");
+
+/*
+ * sleep and wakeup on one-time events.
+ * before any calls to notesleep or notewakeup,
+ * must call noteclear to initialize the Note.
+ * then, any number of threads can call notesleep
+ * and exactly one thread can call notewakeup (once).
+ * once notewakeup has been called, all the notesleeps
+ * will return.  future notesleeps will return immediately.
+ */
+void   noteclear(Note*);
+void   notesleep(Note*);
+void   notewakeup(Note*);
+
+/* Functions.  */
+#define runtime_printf printf
+#define runtime_malloc(s) __go_alloc(s)
+#define runtime_free(p) __go_free(p)
+#define runtime_memclr(buf, size) __builtin_memset((buf), 0, (size))
+#define runtime_strcmp(s1, s2) __builtin_strcmp((s1), (s2))
+#define runtime_getenv(s) getenv(s)
+#define runtime_atoi(s) atoi(s)
+#define runtime_mcmp(a, b, s) __builtin_memcmp((a), (b), (s))
+#define runtime_memmove(a, b, s) __builtin_memmove((a), (b), (s))
+MCache*        runtime_allocmcache(void);
+void   free(void *v);
+struct __go_func_type;
+void   runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *);
+void   runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64));
+#define runtime_mmap mmap
+#define runtime_munmap(p, s) munmap((p), (s))
+#define cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
+
+struct __go_func_type;
+void reflect_call(const struct __go_func_type *, const void *, _Bool, void **,
+                 void **)
+  asm ("libgo_reflect.reflect.call");
+
+#ifdef __rtems__
+void __wrap_rtems_task_variable_add(void **);
+#endif
diff --git a/libgo/runtime/sigqueue.goc b/libgo/runtime/sigqueue.goc
new file mode 100644 (file)
index 0000000..0f758ac
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements runtime support for signal handling.
+//
+// Most synchronization primitives are not available from
+// the signal handler (it cannot block and cannot use locks)
+// so the handler communicates with a processing goroutine
+// via struct sig, below.
+//
+// Ownership for sig.Note passes back and forth between
+// the signal handler and the signal goroutine in rounds.
+// The initial state is that sig.note is cleared (setup by siginit).
+// At the beginning of each round, mask == 0.
+// The round goes through three stages:
+//
+// (In parallel)
+// 1a) One or more signals arrive and are handled
+// by sigsend using cas to set bits in sig.mask.
+// The handler that changes sig.mask from zero to non-zero
+// calls notewakeup(&sig).
+// 1b) Sigrecv calls notesleep(&sig) to wait for the wakeup.
+//
+// 2) Having received the wakeup, sigrecv knows that sigsend
+// will not send another wakeup, so it can noteclear(&sig)
+// to prepare for the next round. (Sigsend may still be adding
+// signals to sig.mask at this point, which is fine.)
+//
+// 3) Sigrecv uses cas to grab the current sig.mask and zero it,
+// triggering the next round.
+//
+// The signal handler takes ownership of the note by atomically
+// changing mask from a zero to non-zero value. It gives up
+// ownership by calling notewakeup. The signal goroutine takes
+// ownership by returning from notesleep (caused by the notewakeup)
+// and gives up ownership by clearing mask.
+
+package runtime
+#include "config.h"
+#include "runtime.h"
+#include "malloc.h"
+#include "defs.h"
+
+static struct {
+       Note;
+       uint32 mask;
+       bool inuse;
+} sig;
+
+void
+siginit(void)
+{
+       noteclear(&sig);
+}
+
+// Called from sighandler to send a signal back out of the signal handling thread.
+bool
+__go_sigsend(int32 s)
+{
+       uint32 bit, mask;
+
+       if(!sig.inuse)
+               return false;
+       bit = 1 << s;
+       for(;;) {
+               mask = sig.mask;
+               if(mask & bit)
+                       break;          // signal already in queue
+               if(cas(&sig.mask, mask, mask|bit)) {
+                       // Added to queue.
+                       // Only send a wakeup for the first signal in each round.
+                       if(mask == 0)
+                               notewakeup(&sig);
+                       break;
+               }
+       }
+       return true;
+}
+
+// Called to receive a bitmask of queued signals.
+func Sigrecv() (m uint32) {
+       // runtime·entersyscall();
+       notesleep(&sig);
+       // runtime·exitsyscall();
+       noteclear(&sig);
+       for(;;) {
+               m = sig.mask;
+               if(cas(&sig.mask, m, 0))
+                       break;
+       }
+}
+
+func Signame(sig int32) (name String) {
+       const char* s = NULL;
+       char buf[100];
+#if defined(HAVE_STRSIGNAL)
+       s = strsignal(sig);
+#endif
+       if (s == NULL) {
+               snprintf(buf, sizeof buf, "signal %d", sig);
+               s = buf;
+       }
+       int32 len = __builtin_strlen(s);
+       unsigned char *data = runtime_mallocgc(len, RefNoPointers, 0, 0);
+       __builtin_memcpy(data, s, len);
+       name.__data = data;
+       name.__length = len;
+}
+
+func Siginit() {
+       sig.inuse = true;       // enable reception of signals; cannot disable
+}
diff --git a/libgo/runtime/string.goc b/libgo/runtime/string.goc
new file mode 100644 (file)
index 0000000..332277c
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2009, 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "runtime.h"
+#define charntorune(pv, str, len) __go_get_rune(str, len, pv)
+
+enum
+{
+       Runeself        = 0x80,
+};
+
+func stringiter(s String, k int32) (retk int32) {
+       int32 l, n;
+
+       if(k >= s.__length) {
+               // retk=0 is end of iteration
+               retk = 0;
+               goto out;
+       }
+
+       l = s.__data[k];
+       if(l < Runeself) {
+               retk = k+1;
+               goto out;
+       }
+
+       // multi-char rune
+       n = charntorune(&l, s.__data+k, s.__length-k);
+       retk = k + (n ? n : 1);
+
+out:
+}
+
+func stringiter2(s String, k int32) (retk int32, retv int32) {
+       int32 n;
+
+       if(k >= s.__length) {
+               // retk=0 is end of iteration
+               retk = 0;
+               retv = 0;
+               goto out;
+       }
+
+       retv = s.__data[k];
+       if(retv < Runeself) {
+               retk = k+1;
+               goto out;
+       }
+
+       // multi-char rune
+       n = charntorune(&retv, s.__data+k, s.__length-k);
+       retk = k + (n ? n : 1);
+
+out:
+}
diff --git a/libgo/runtime/thread.c b/libgo/runtime/thread.c
new file mode 100644 (file)
index 0000000..5651217
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+void
+runtime_initlock(Lock *l)
+{
+       if(pthread_mutex_init(&l->mutex, NULL) != 0)
+               runtime_throw("pthread_mutex_init failed");
+}
+
+void
+runtime_lock(Lock *l)
+{
+       if(pthread_mutex_lock(&l->mutex) != 0)
+               runtime_throw("lock failed");
+}
+
+void
+runtime_unlock(Lock *l)
+{
+       if(pthread_mutex_unlock(&l->mutex) != 0)
+               runtime_throw("unlock failed");
+}
+
+void
+runtime_destroylock(Lock *l)
+{
+       pthread_mutex_destroy(&l->mutex);
+}
+
+bool
+runtime_trylock(Lock *l)
+{
+       return pthread_mutex_trylock(&l->mutex) == 0;
+}
diff --git a/libgo/syscalls/errno.c b/libgo/syscalls/errno.c
new file mode 100644 (file)
index 0000000..34771a0
--- /dev/null
@@ -0,0 +1,25 @@
+/* errno.c -- functions for getting and setting errno
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <errno.h>
+
+/* errno is typically a macro. These functions set 
+   and get errno specific to the libc being used.  */
+
+int GetErrno() asm ("libgo_syscalls.syscall.GetErrno");
+void SetErrno(int) asm ("libgo_syscalls.syscall.SetErrno");
+
+int 
+GetErrno()
+{
+  return errno;
+}
+
+void
+SetErrno(int value)
+{
+  errno = value;
+}
diff --git a/libgo/syscalls/errstr.go b/libgo/syscalls/errstr.go
new file mode 100644 (file)
index 0000000..961df40
--- /dev/null
@@ -0,0 +1,29 @@
+// errstr.go -- Error strings.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const ENONE = 0
+
+func GetErrno() int
+func SetErrno(int)
+
+func Errstr(errno int) string {
+       for len := Size_t(128); ; len *= 2 {
+               b := make([]byte, len)
+               r := libc_strerror_r(errno, &b[0], len)
+               if r >= 0 {
+                       i := 0
+                       for b[i] != 0 {
+                               i++
+                       }
+                       return string(b[:i])
+               }
+               if GetErrno() != ERANGE {
+                       return "Errstr failure"
+               }
+       }
+}
diff --git a/libgo/syscalls/errstr_decl.go b/libgo/syscalls/errstr_decl.go
new file mode 100644 (file)
index 0000000..b6bff0f
--- /dev/null
@@ -0,0 +1,9 @@
+// errstr.go -- Declare strerror_r.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func libc_strerror_r(int, *byte, Size_t) int __asm__ ("strerror_r")
diff --git a/libgo/syscalls/errstr_decl_linux.go b/libgo/syscalls/errstr_decl_linux.go
new file mode 100644 (file)
index 0000000..4c1cb82
--- /dev/null
@@ -0,0 +1,9 @@
+// errstr_decl_linux.go -- Declare strerror_r for GNU/Linux.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func libc_strerror_r(int, *byte, Size_t) int __asm__ ("__xpg_strerror_r")
diff --git a/libgo/syscalls/errstr_decl_rtems.go b/libgo/syscalls/errstr_decl_rtems.go
new file mode 100644 (file)
index 0000000..b83eedc
--- /dev/null
@@ -0,0 +1,10 @@
+// errstr.go -- Declare strerror_r for RTEMS.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// RTEMS uses strerror_r in newlib, which is a GNU extension returning a char *.
+func libc_strerror_r(int, *byte, Size_t) *byte __asm__ ("strerror_r")
diff --git a/libgo/syscalls/errstr_rtems.go b/libgo/syscalls/errstr_rtems.go
new file mode 100644 (file)
index 0000000..b933360
--- /dev/null
@@ -0,0 +1,31 @@
+// errstr_rtems.go -- RTEMS specific error strings.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const ENONE = 0
+
+func GetErrno() int
+func SetErrno(int)
+
+func Errstr(errno int) string {
+       for len := Size_t(128); ; len *= 2 {
+               b := make([]byte, len+1)
+
+               // The newlib strerror_r always returns the string in buffer.
+               libc_strerror_r(errno, &b[0], len)
+               b[len] = 0
+
+               i := 0
+               for b[i] != 0 {
+                       i++
+               }
+
+               if Size_t(i) < len {
+                       return string(b[0:i])
+               }
+       }
+}
diff --git a/libgo/syscalls/exec.go b/libgo/syscalls/exec.go
new file mode 100644 (file)
index 0000000..d0f56d3
--- /dev/null
@@ -0,0 +1,248 @@
+// exec.go -- fork/exec syscall support.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Fork, exec, wait, etc.
+
+package syscall
+
+import "unsafe"
+
+func libc_fcntl(fd int, cmd int, arg int) int __asm__ ("fcntl")
+func libc_fork() Pid_t __asm__ ("fork")
+func libc_chdir(name *byte) int __asm__ ("chdir");
+func libc_dup2(int, int) int __asm__ ("dup2")
+func libc_execve(*byte, **byte, **byte) int __asm__ ("execve")
+func libc_sysexit(int) __asm__ ("_exit")
+func libc_wait4(Pid_t, *int, int, *Rusage) Pid_t __asm__ ("wait4")
+
+// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
+// If a dup or exec fails, write the errno int to pipe.
+// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork.  This means
+// no rescheduling, no malloc calls, and no new stack segments.
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, traceme bool, dir *byte, fd []int, pipe int) (pid int, err int) {
+       // Declare all variables at top in case any
+       // declarations require heap allocation (e.g., err1).
+       var r1, r2, err1 uintptr;
+       var nextfd int;
+       var i int;
+
+       darwin := OS == "darwin";
+
+       // About to call fork.
+       // No more allocation or calls of non-assembly functions.
+       child := libc_fork();
+       if child == -1 {
+               return 0, GetErrno();
+       }
+
+       if child != 0 {
+               // parent; return PID
+               return int(child), 0
+       }
+
+       // Fork succeeded, now in child.
+
+       // Enable tracing if requested.
+       if traceme {
+               if libc_ptrace(_PTRACE_TRACEME, 0, 0, nil) < 0 {
+                       goto childerror;
+               }
+       }
+
+       // Chdir
+       if dir != nil {
+               r := libc_chdir(dir);
+               if r < 0 {
+                       goto childerror;
+               }
+       }
+
+       // Pass 1: look for fd[i] < i and move those up above len(fd)
+       // so that pass 2 won't stomp on an fd it needs later.
+       nextfd = int(len(fd));
+       if pipe < nextfd {
+               r := libc_dup2(pipe, nextfd);
+               if r == -1 {
+                       goto childerror;
+               }
+               libc_fcntl(nextfd, F_SETFD, FD_CLOEXEC);
+               pipe = nextfd;
+               nextfd++;
+       }
+       for i = 0; i < len(fd); i++ {
+               if fd[i] >= 0 && fd[i] < int(i) {
+                       r := libc_dup2(fd[i], nextfd);
+                       if r == -1 {
+                               goto childerror;
+                       }
+                       libc_fcntl(nextfd, F_SETFD, FD_CLOEXEC);
+                       fd[i] = nextfd;
+                       nextfd++;
+                       if nextfd == pipe {     // don't stomp on pipe
+                               nextfd++;
+                       }
+               }
+       }
+
+       // Pass 2: dup fd[i] down onto i.
+       for i = 0; i < len(fd); i++ {
+               if fd[i] == -1 {
+                       libc_close(i);
+                       continue;
+               }
+               if fd[i] == int(i) {
+                       // dup2(i, i) won't clear close-on-exec flag on Linux,
+                       // probably not elsewhere either.
+                       r := libc_fcntl(fd[i], F_SETFD, 0);
+                       if r != 0 {
+                               goto childerror;
+                       }
+                       continue;
+               }
+               // The new fd is created NOT close-on-exec,
+               // which is exactly what we want.
+               r := libc_dup2(fd[i], i);
+               if r == -1 {
+                       goto childerror;
+               }
+       }
+
+       // By convention, we don't close-on-exec the fds we are
+       // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
+       // Programs that know they inherit fds >= 3 will need
+       // to set them close-on-exec.
+       for i = len(fd); i < 3; i++ {
+               libc_close(i);
+       }
+
+       // Time to exec.
+       libc_execve(argv0, &argv[0], &envv[0]);
+
+childerror:
+       // send error code on pipe
+       var e uintptr = uintptr(GetErrno());
+       libc_write(pipe, (*byte)(unsafe.Pointer(&e)),
+                  Size_t(unsafe.Sizeof(err1)));
+       for {
+               libc_sysexit(253)
+       }
+
+       // Calling panic is not actually safe,
+       // but the for loop above won't break
+       // and this shuts up the compiler.
+       panic("unreached");
+}
+
+func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int) (pid int, err int) {
+       var p [2]int;
+       var r1 int;
+       var err1 uintptr;
+       var wstatus WaitStatus;
+
+       p[0] = -1;
+       p[1] = -1;
+
+       // Convert args to C form.
+       argv0p := StringBytePtr(argv0);
+       argvp := StringArrayPtr(argv);
+       envvp := StringArrayPtr(envv);
+       var dirp *byte;
+       if len(dir) > 0 {
+               dirp = StringBytePtr(dir);
+       }
+
+       // Acquire the fork lock so that no other threads
+       // create new fds that are not yet close-on-exec
+       // before we fork.
+       ForkLock.Lock();
+
+       // Allocate child status pipe close on exec.
+       if err = Pipe(p[0:]); err != 0 {
+               goto error;
+       }
+       var val int;
+       if val, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 {
+               goto error;
+       }
+       if val, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 {
+               goto error;
+       }
+
+       // Kick off child.
+       pid, err = forkAndExecInChild(argv0p, argvp, envvp, traceme, dirp, fd, p[1]);
+       if err != 0 {
+       error:
+               if p[0] >= 0 {
+                       Close(p[0]);
+                       Close(p[1]);
+               }
+               ForkLock.Unlock();
+               return 0, err
+       }
+       ForkLock.Unlock();
+
+       // Read child error status from pipe.
+       Close(p[1]);
+       n := libc_read(p[0], (*byte)(unsafe.Pointer(&err1)),
+                      Size_t(unsafe.Sizeof(err1)));
+       err = 0;
+       if n < 0 {
+               err = GetErrno();
+       }
+       Close(p[0]);
+       if err != 0 || n != 0 {
+               if int(n) == unsafe.Sizeof(err1) {
+                       err = int(err1);
+               }
+               if err == 0 {
+                       err = EPIPE;
+               }
+
+               // Child failed; wait for it to exit, to make sure
+               // the zombies don't accumulate.
+               pid1, err1 := Wait4(pid, &wstatus, 0, nil);
+               for err1 == EINTR {
+                       pid1, err1 = Wait4(pid, &wstatus, 0, nil);
+               }
+               return 0, err
+       }
+
+       // Read got EOF, so pipe closed on exec, so exec succeeded.
+       return pid, 0
+}
+
+// Combination of fork and exec, careful to be thread safe.
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+       return forkExec(argv0, argv, envv, false, dir, fd);
+}
+
+// PtraceForkExec is like ForkExec, but starts the child in a traced state.
+func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+       return forkExec(argv0, argv, envv, true, dir, fd);
+}
+
+// Ordinary exec.
+func Exec(argv0 string, argv []string, envv []string) (err int) {
+       argv_arg := StringArrayPtr(argv);
+       envv_arg := StringArrayPtr(envv);
+       libc_execve(StringBytePtr(argv0), &argv_arg[0], &envv_arg[0]);
+       return GetErrno();
+}
+
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+       var status int;
+       r := libc_wait4(Pid_t(pid), &status, options, rusage);
+       wpid = int(r);
+       if r < 0 {
+               errno = GetErrno();
+       }
+       if wstatus != nil {
+               *wstatus = WaitStatus(status);
+       }
+       return;
+}
diff --git a/libgo/syscalls/exec_helpers.go b/libgo/syscalls/exec_helpers.go
new file mode 100644 (file)
index 0000000..c8a68a0
--- /dev/null
@@ -0,0 +1,154 @@
+// exec_helpers.go -- helper functions used with fork, exec, wait.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "sync"
+
+// Lock synchronizing creation of new file descriptors with fork.
+//
+// We want the child in a fork/exec sequence to inherit only the
+// file descriptors we intend.  To do that, we mark all file
+// descriptors close-on-exec and then, in the child, explicitly
+// unmark the ones we want the exec'ed program to keep.
+// Unix doesn't make this easy: there is, in general, no way to
+// allocate a new file descriptor close-on-exec.  Instead you
+// have to allocate the descriptor and then mark it close-on-exec.
+// If a fork happens between those two events, the child's exec
+// will inherit an unwanted file descriptor.
+//
+// This lock solves that race: the create new fd/mark close-on-exec
+// operation is done holding ForkLock for reading, and the fork itself
+// is done holding ForkLock for writing.  At least, that's the idea.
+// There are some complications.
+//
+// Some system calls that create new file descriptors can block
+// for arbitrarily long times: open on a hung NFS server or named
+// pipe, accept on a socket, and so on.  We can't reasonably grab
+// the lock across those operations.
+//
+// It is worse to inherit some file descriptors than others.
+// If a non-malicious child accidentally inherits an open ordinary file,
+// that's not a big deal.  On the other hand, if a long-lived child
+// accidentally inherits the write end of a pipe, then the reader
+// of that pipe will not see EOF until that child exits, potentially
+// causing the parent program to hang.  This is a common problem
+// in threaded C programs that use popen.
+//
+// Luckily, the file descriptors that are most important not to
+// inherit are not the ones that can take an arbitrarily long time
+// to create: pipe returns instantly, and the net package uses
+// non-blocking I/O to accept on a listening socket.
+// The rules for which file descriptor-creating operations use the
+// ForkLock are as follows:
+//
+// 1) Pipe.    Does not block.  Use the ForkLock.
+// 2) Socket.  Does not block.  Use the ForkLock.
+// 3) Accept.  If using non-blocking mode, use the ForkLock.
+//             Otherwise, live with the race.
+// 4) Open.    Can block.  Use O_CLOEXEC if available (Linux).
+//             Otherwise, live with the race.
+// 5) Dup.     Does not block.  Use the ForkLock.
+//             On Linux, could use fcntl F_DUPFD_CLOEXEC
+//             instead of the ForkLock, but only for dup(fd, -1).
+
+type WaitStatus int
+
+var ForkLock sync.RWMutex
+
+// Convert array of string to array
+// of NUL-terminated byte pointer.
+func StringArrayPtr(ss []string) []*byte {
+       bb := make([]*byte, len(ss)+1);
+       for i := 0; i < len(ss); i++ {
+               bb[i] = StringBytePtr(ss[i]);
+       }
+       bb[len(ss)] = nil;
+       return bb;
+}
+
+func CloseOnExec(fd int) {
+       fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+func SetNonblock(fd int, nonblocking bool) (errno int) {
+       flag, err := fcntl(fd, F_GETFL, 0);
+       if err != 0 {
+               return err;
+       }
+       if nonblocking {
+               flag |= O_NONBLOCK;
+       } else {
+               flag &= ^O_NONBLOCK;
+       }
+       flag, err = fcntl(fd, F_SETFL, flag);
+       return err;
+}
+
+// Wait status is 7 bits at bottom, either 0 (exited),
+// 0x7F (stopped), or a signal number that caused an exit.
+// The 0x80 bit is whether there was a core dump.
+// An extra number (exit code, signal causing a stop)
+// is in the high bits.  At least that's the idea.
+// There are various irregularities.  For example, the
+// "continued" status is 0xFFFF, distinguishing itself
+// from stopped via the core dump bit.
+
+const (
+       mask = 0x7F;
+       core = 0x80;
+       exited = 0x00;
+       stopped = 0x7F;
+       shift = 8;
+)
+
+func (w WaitStatus) Exited() bool {
+       return w&mask == exited;
+}
+
+func (w WaitStatus) Signaled() bool {
+       return w&mask != stopped && w&mask != exited;
+}
+
+func (w WaitStatus) Stopped() bool {
+       return w&0xFF == stopped;
+}
+
+func (w WaitStatus) Continued() bool {
+       return w == 0xFFFF;
+}
+
+func (w WaitStatus) CoreDump() bool {
+       return w.Signaled() && w&core != 0;
+}
+
+func (w WaitStatus) ExitStatus() int {
+       if !w.Exited() {
+               return -1;
+       }
+       return int(w >> shift) & 0xFF;
+}
+
+func (w WaitStatus) Signal() int {
+       if !w.Signaled() {
+               return -1;
+       }
+       return int(w & mask);
+}
+
+func (w WaitStatus) StopSignal() int {
+       if !w.Stopped() {
+               return -1;
+       }
+       return int(w >> shift) & 0xFF;
+}
+
+func (w WaitStatus) TrapCause() int {
+       if w.StopSignal() != SIGTRAP {
+               return -1;
+       }
+       return int(w >> shift) >> 8;
+}
diff --git a/libgo/syscalls/exec_stubs.go b/libgo/syscalls/exec_stubs.go
new file mode 100644 (file)
index 0000000..7b4346c
--- /dev/null
@@ -0,0 +1,25 @@
+// exec_stubs.go -- fork/exec stubs.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Stubs for fork, exec and wait.
+
+package syscall
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+       return -1, ENOSYS;
+}
+
+func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+       return -1, ENOSYS;
+}
+
+func Exec(argv0 string, argv []string, envv []string) (err int) {
+       return ENOSYS;
+}
+
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+       return -1, ENOSYS;
+}
diff --git a/libgo/syscalls/socket.go b/libgo/syscalls/socket.go
new file mode 100644 (file)
index 0000000..5550800
--- /dev/null
@@ -0,0 +1,205 @@
+// socket.go -- Socket handling.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Low-level socket interface.
+// Only for implementing net package.
+// DO NOT USE DIRECTLY.
+
+package syscall
+
+import "unsafe"
+
+const SizeofSockaddrInet4 = 16
+const SizeofSockaddrInet6 = 28
+const SizeofSockaddrUnix = 110
+
+type RawSockaddrAny struct {
+       Addr RawSockaddr;
+       Pad [12]int8;
+}
+
+const SizeofSockaddrAny = 0x1c;
+
+// For testing: clients can set this flag to force
+// creation of IPv6 sockets to return EAFNOSUPPORT.
+var SocketDisableIPv6 bool
+
+type Sockaddr interface {
+       sockaddr() (ptr *RawSockaddrAny, len Socklen_t, errno int);     // lowercase; only we can define Sockaddrs
+}
+
+type SockaddrInet4 struct {
+       Port int;
+       Addr [4]byte;
+       raw RawSockaddrInet4;
+}
+
+type SockaddrInet6 struct {
+       Port int;
+       Addr [16]byte;
+       raw RawSockaddrInet6;
+}
+
+type SockaddrUnix struct {
+       Name string;
+       raw RawSockaddrUnix;
+}
+
+type Linger struct {
+       Onoff int32;
+       Linger int32;
+}
+
+func libc_accept(fd int, sa *RawSockaddrAny, len *Socklen_t) int __asm__ ("accept");
+func libc_bind(fd int, sa *RawSockaddrAny, len Socklen_t) int __asm__ ("bind");
+func libc_connect(fd int, sa *RawSockaddrAny, len Socklen_t) int __asm__ ("connect");
+func libc_socket(domain, typ, protocol int) int __asm__ ("socket");
+func libc_setsockopt(fd, level, optname int, optval *byte, optlen Socklen_t) int __asm__ ("setsockopt");
+func libc_listen(fd, backlog int) int __asm__ ("listen");
+func libc_getsockopt(fd, level, optname int, optval *byte, optlen *Socklen_t) int __asm__ ("getsockopt");
+func libc_getsockname(fd int, sa *RawSockaddrAny, len *Socklen_t) int __asm__ ("getsockname");
+func libc_getpeername(fd int, sa *RawSockaddrAny, len *Socklen_t) int __asm__ ("getpeername");
+func libc_recv(fd int, buf *byte, len Size_t, flags int) Ssize_t __asm__ ("recv");
+func libc_recvfrom(fd int, buf *byte, len Size_t, flags int,
+       from *RawSockaddrAny, fromlen *Socklen_t) Ssize_t __asm__("recvfrom");
+func libc_send(fd int, buf *byte, len Size_t, flags int) Ssize_t __asm__("send");
+func libc_sendto(fd int, buf *byte, len Size_t, flags int,
+       to *RawSockaddrAny, tolen Socklen_t) Ssize_t __asm__("sendto");
+func libc_shutdown(fd int, how int) int __asm__ ("shutdown");
+
+func Accept(fd int) (nfd int, sa Sockaddr, errno int) {
+       var rsa RawSockaddrAny;
+       var len Socklen_t = SizeofSockaddrAny;
+       nfd = libc_accept(fd, &rsa, &len);
+       if nfd < 0 {
+               errno = GetErrno();
+               return;
+       }
+       sa, errno = anyToSockaddr(&rsa);
+       if errno != 0 {
+               Close(nfd);
+               nfd = 0;
+       }
+       return;
+}
+
+func Bind(fd int, sa Sockaddr) (errno int) {
+       ptr, n, err := sa.sockaddr();
+       if err != 0 {
+               return err;
+       }
+       if libc_bind(fd, ptr, n) < 0 {
+               errno = GetErrno();
+       }
+       return;
+}
+
+func Connect(fd int, sa Sockaddr) (errno int) {
+       ptr, n, err := sa.sockaddr();
+       if err != 0 {
+               return err;
+       }
+       if libc_connect(fd, ptr, n) < 0 {
+               errno = GetErrno();
+       }
+       return;
+}
+
+func Socket(domain, typ, proto int) (fd, errno int) {
+  if domain == AF_INET6 && SocketDisableIPv6 {
+    return -1, EAFNOSUPPORT
+  }
+  fd = libc_socket(int(domain), int(typ), int(proto));
+  if fd < 0 {
+    errno = GetErrno();
+  }
+  return;
+}
+
+func Listen(fd int, n int) (errno int) {
+  r := libc_listen(int(fd), int(n));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func setsockopt(fd, level, opt int, valueptr uintptr, length Socklen_t) (errno int) {
+  r := libc_setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(valueptr)),
+                      length);
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func SetsockoptInt(fd, level, opt int, value int) (errno int) {
+       var n = int32(value);
+       return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), 4);
+}
+
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int) {
+       return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(tv)), Socklen_t(unsafe.Sizeof(*tv)));
+}
+
+func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
+       return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), Socklen_t(unsafe.Sizeof(*l)));
+}
+
+func SetsockoptString(fd, level, opt int, s string) (errno int) {
+       return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), Socklen_t(len(s)))
+}
+
+func Getsockname(fd int) (sa Sockaddr, errno int) {
+       var rsa RawSockaddrAny;
+       var len Socklen_t = SizeofSockaddrAny;
+       if libc_getsockname(fd, &rsa, &len) != 0 {
+               errno = GetErrno();
+               return;
+       }
+       return anyToSockaddr(&rsa);
+}
+
+func Getpeername(fd int) (sa Sockaddr, errno int) {
+       var rsa RawSockaddrAny;
+       var len Socklen_t = SizeofSockaddrAny;
+       if libc_getpeername(fd, &rsa, &len) != 0 {
+               errno = GetErrno();
+               return;
+       }
+       return anyToSockaddr(&rsa);
+}
+
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) {
+       var rsa RawSockaddrAny;
+       var slen Socklen_t = SizeofSockaddrAny;
+       var _p0 *byte;
+       if len(p) > 0 { _p0 = &p[0]; }
+       r := libc_recvfrom(fd, _p0, Size_t(len(p)), flags, &rsa, &slen);
+       n = int(r);
+       if r == -1 {
+               errno = GetErrno();
+       } else {
+               from, errno = anyToSockaddr(&rsa);
+       }
+       return;
+}
+
+func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
+       ptr, n, err := to.sockaddr();
+       if err != 0 {
+               return err;
+       }
+       var _p0 *byte;
+       if len(p) > 0 { _p0 = &p[0]; }
+       r := libc_sendto(fd, _p0, Size_t(len(p)), flags, ptr, n);
+       if r == -1 { errno = GetErrno(); }
+       return;
+}
+
+func Shutdown(fd int, how int) (errno int) {
+       r := libc_shutdown(fd, how);
+       if r < 0 { errno = GetErrno() }
+       return;
+}
+
+// FIXME: No getsockopt.
diff --git a/libgo/syscalls/socket_bsd.go b/libgo/syscalls/socket_bsd.go
new file mode 100644 (file)
index 0000000..eaf20f9
--- /dev/null
@@ -0,0 +1,139 @@
+// socket_bsd.go -- Socket handling specific to *BSD based systems.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Low-level socket interface.
+// Only for implementing net package.
+// DO NOT USE DIRECTLY.
+
+package syscall
+
+import "unsafe"
+
+type RawSockaddrInet4 struct {
+       Len uint8;
+       Family uint8;
+       Port uint16;
+       Addr [4]byte /* in_addr */;
+       Zero [8]uint8;
+}
+
+type RawSockaddrInet6 struct {
+       Len uint8;
+       Family uint8;
+       Port uint16;
+       Flowinfo uint32;
+       Addr [16]byte /* in6_addr */;
+       Scope_id uint32;
+}
+
+type RawSockaddrUnix struct {
+       Len uint8;
+       Family uint8;
+       Path [108]int8;
+}
+
+type RawSockaddr struct {
+       Len uint8;
+       Family uint8;
+       Data [14]int8;
+}
+
+func (sa *SockaddrInet4) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+       if sa.Port < 0 || sa.Port > 0xFFFF {
+               return nil, 0, EINVAL;
+       }
+       sa.raw.Len = SizeofSockaddrInet4;
+       sa.raw.Family = AF_INET;
+       p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port));
+       p[0] = byte(sa.Port>>8);
+       p[1] = byte(sa.Port);
+       for i := 0; i < len(sa.Addr); i++ {
+               sa.raw.Addr[i] = sa.Addr[i];
+       }
+       return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), Socklen_t(sa.raw.Len), 0;
+}
+
+func (sa *SockaddrInet6) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+       if sa.Port < 0 || sa.Port > 0xFFFF {
+               return nil, 0, EINVAL;
+       }
+       sa.raw.Len = SizeofSockaddrInet6;
+       sa.raw.Family = AF_INET6;
+       p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port));
+       p[0] = byte(sa.Port>>8);
+       p[1] = byte(sa.Port);
+       for i := 0; i < len(sa.Addr); i++ {
+               sa.raw.Addr[i] = sa.Addr[i];
+       }
+       return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), Socklen_t(sa.raw.Len), 0;
+}
+
+func (sa *SockaddrUnix) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+       name := sa.Name;
+       n := len(name);
+       if n >= len(sa.raw.Path) || n == 0 {
+               return nil, 0, EINVAL;
+       }
+       sa.raw.Len = byte(3 + n); // 2 for Family, Len; 1 for NUL.
+       sa.raw.Family = AF_UNIX;
+       for i := 0; i < n; i++ {
+               sa.raw.Path[i] = int8(name[i]);
+       }
+       if sa.raw.Path[0] == '@' {
+               sa.raw.Path[0] = 0;
+       }
+
+       // length is family, name, NUL.
+       return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), Socklen_t(sa.raw.Len), 0;
+}
+
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
+       switch rsa.Addr.Family {
+       case AF_UNIX:
+               pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+               if pp.Len < 3 || pp.Len > SizeofSockaddrUnix {
+                       return nil, EINVAL
+               }
+               sa := new(SockaddrUnix)
+               n := int(pp.Len) - 3 // subtract leading Family, Len, terminating NUL.
+               for i := 0; i < n; i++ {
+                       if pp.Path[i] == 0 {
+                               // found early NUL; assume Len is overestimating.
+                               n = i
+                               break
+                       }
+               }
+               bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))
+               sa.Name = string(bytes[0:n])
+               return sa, 0
+
+       case AF_INET:
+               pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa));
+               sa := new(SockaddrInet4);
+               p := (*[2]byte)(unsafe.Pointer(&pp.Port));
+               sa.Port = int(p[0])<<8 + int(p[1]);
+               for i := 0; i < len(sa.Addr); i++ {
+                       sa.Addr[i] = pp.Addr[i];
+               }
+               return sa, 0;
+
+       case AF_INET6:
+               pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa));
+               sa := new(SockaddrInet6);
+               p := (*[2]byte)(unsafe.Pointer(&pp.Port));
+               sa.Port = int(p[0])<<8 + int(p[1]);
+               for i := 0; i < len(sa.Addr); i++ {
+                       sa.Addr[i] = pp.Addr[i];
+               }
+               return sa, 0;
+       }
+       return nil, EAFNOSUPPORT;
+}
+
+// BindToDevice binds the socket associated with fd to device.
+func BindToDevice(fd int, device string) (errno int) {
+       return ENOSYS
+}
diff --git a/libgo/syscalls/socket_epoll.go b/libgo/syscalls/socket_epoll.go
new file mode 100644 (file)
index 0000000..0013f33
--- /dev/null
@@ -0,0 +1,50 @@
+// socket_epoll.go -- GNU/Linux epoll handling.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Support for GNU/Linux epoll.
+// Only for implementing net package.
+// DO NOT USE DIRECTLY.
+
+package syscall
+
+// We don't take this type directly from the header file because it
+// uses a union.  FIXME.
+
+type EpollEvent struct {
+  Events uint32;
+  Fd int32;
+  Pad int32;
+};
+
+func libc_epoll_create(size int) int __asm__ ("epoll_create");
+func libc_epoll_ctl(epfd, op, fd int, event *EpollEvent) int __asm__ ("epoll_ctl");
+func libc_epoll_wait(epfd int, events *EpollEvent, maxevents int,
+                     timeout int) int __asm__ ("epoll_wait");
+
+
+func EpollCreate(size int) (fd int, errno int) {
+  fd = libc_epoll_create(int(size));
+  if fd < 0 { errno = GetErrno() }
+  return;
+}
+
+func EpollCtl(epfd, op, fd int, ev *EpollEvent) (errno int) {
+  r := libc_epoll_ctl(epfd, op, fd, ev);
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func EpollWait(epfd int, ev []EpollEvent, msec int) (n int, errno int) {
+  var events *EpollEvent;
+  var maxevents int;
+  if len(ev) > 0 {
+    maxevents = len(ev);
+    events = &ev[0]
+  }
+  n = libc_epoll_wait(epfd, events, maxevents, msec);
+  if n < 0 { errno = GetErrno() }
+  return;
+}
diff --git a/libgo/syscalls/socket_linux.go b/libgo/syscalls/socket_linux.go
new file mode 100644 (file)
index 0000000..bc196a2
--- /dev/null
@@ -0,0 +1,140 @@
+// socket_linux.go -- Socket handling specific to Linux.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Low-level socket interface.
+// Only for implementing net package.
+
+// DO NOT USE DIRECTLY.
+
+package syscall
+
+import "unsafe"
+
+type RawSockaddrInet4 struct {
+       Family uint16;
+       Port uint16;
+       Addr [4]byte /* in_addr */;
+       Zero [8]uint8;
+}
+
+type RawSockaddrInet6 struct {
+       Family uint16;
+       Port uint16;
+       Flowinfo uint32;
+       Addr [16]byte /* in6_addr */;
+       Scope_id uint32;
+}
+
+type RawSockaddrUnix struct {
+       Family uint16;
+       Path [108]int8;
+}
+
+type RawSockaddr struct {
+       Family uint16;
+       Data [14]int8;
+}
+
+func (sa *SockaddrInet4) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+       if sa.Port < 0 || sa.Port > 0xFFFF {
+               return nil, 0, EINVAL;
+       }
+       sa.raw.Family = AF_INET;
+       p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port));
+       p[0] = byte(sa.Port>>8);
+       p[1] = byte(sa.Port);
+       for i := 0; i < len(sa.Addr); i++ {
+               sa.raw.Addr[i] = sa.Addr[i];
+       }
+       return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet4, 0;
+}
+
+func (sa *SockaddrInet6) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+       if sa.Port < 0 || sa.Port > 0xFFFF {
+               return nil, 0, EINVAL;
+       }
+       sa.raw.Family = AF_INET6;
+       p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port));
+       p[0] = byte(sa.Port>>8);
+       p[1] = byte(sa.Port);
+       for i := 0; i < len(sa.Addr); i++ {
+               sa.raw.Addr[i] = sa.Addr[i];
+       }
+       return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet6, 0;
+}
+
+func (sa *SockaddrUnix) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+       name := sa.Name;
+       n := len(name);
+       if n >= len(sa.raw.Path) || n == 0 {
+               return nil, 0, EINVAL;
+       }
+       sa.raw.Family = AF_UNIX;
+       for i := 0; i < n; i++ {
+               sa.raw.Path[i] = int8(name[i]);
+       }
+       if sa.raw.Path[0] == '@' {
+               sa.raw.Path[0] = 0;
+       }
+
+       // length is family, name, NUL.
+       return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), 1 + Socklen_t(n) + 1, 0;
+}
+
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
+       switch rsa.Addr.Family {
+       case AF_UNIX:
+               pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa));
+               sa := new(SockaddrUnix);
+               if pp.Path[0] == 0 {
+                       // "Abstract" Unix domain socket.
+                       // Rewrite leading NUL as @ for textual display.
+                       // (This is the standard convention.)
+                       // Not friendly to overwrite in place,
+                       // but the callers below don't care.
+                       pp.Path[0] = '@';
+               }
+
+               // Assume path ends at NUL.
+               // This is not technically the Linux semantics for
+               // abstract Unix domain sockets--they are supposed
+               // to be uninterpreted fixed-size binary blobs--but
+               // everyone uses this convention.
+               n := 0;
+               for n < len(pp.Path) - 3 && pp.Path[n] != 0 {
+                       n++;
+               }
+               bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]));
+               sa.Name = string(bytes[0:n]);
+               return sa, 0;
+
+       case AF_INET:
+               pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa));
+               sa := new(SockaddrInet4);
+               p := (*[2]byte)(unsafe.Pointer(&pp.Port));
+               sa.Port = int(p[0])<<8 + int(p[1]);
+               for i := 0; i < len(sa.Addr); i++ {
+                       sa.Addr[i] = pp.Addr[i];
+               }
+               return sa, 0;
+
+       case AF_INET6:
+               pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa));
+               sa := new(SockaddrInet6);
+               p := (*[2]byte)(unsafe.Pointer(&pp.Port));
+               sa.Port = int(p[0])<<8 + int(p[1]);
+               for i := 0; i < len(sa.Addr); i++ {
+                       sa.Addr[i] = pp.Addr[i];
+               }
+               return sa, 0;
+       }
+       return nil, EAFNOSUPPORT;
+}
+
+// BindToDevice binds the socket associated with fd to device.
+func BindToDevice(fd int, device string) (errno int) {
+       return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device)
+}
diff --git a/libgo/syscalls/stringbyte.go b/libgo/syscalls/stringbyte.go
new file mode 100644 (file)
index 0000000..b673c9b
--- /dev/null
@@ -0,0 +1,24 @@
+// stringbyte.go -- string to bytes functions.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// StringByteSlice returns a NUL-terminated slice of bytes
+// containing the text of s.
+func StringByteSlice(s string) []byte {
+       a := make([]byte, len(s)+1);
+       for i := 0; i < len(s); i++ {
+               a[i] = s[i];
+       }
+       return a;
+}
+
+// StringBytePtr returns a pointer to a NUL-terminated array of bytes
+// containing the text of s.
+func StringBytePtr(s string) *byte {
+       p := StringByteSlice(s);
+       return &p[0];
+}
diff --git a/libgo/syscalls/syscall.go b/libgo/syscalls/syscall.go
new file mode 100644 (file)
index 0000000..fa7d9d0
--- /dev/null
@@ -0,0 +1,48 @@
+// syscall.go -- Basic syscall interface.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package contains an interface to the low-level operating system
+// primitives.  The details vary depending on the underlying system.
+// Its primary use is inside other packages that provide a more portable
+// interface to the system, such as "os", "time" and "net".  Use those
+// packages rather than this one if you can.
+// For details of the functions and data types in this package consult
+// the manuals for the appropriate operating system.
+package syscall
+
+import "unsafe"
+
+func libc_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32 __asm__ ("syscall");
+func libc_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64 __asm__ ("syscall");
+
+// Do a system call.  We look at the size of uintptr to see how to pass
+// the arguments, so that we don't pass a 64-bit value when the function
+// expects a 32-bit one.
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
+  var r uintptr;
+  if unsafe.Sizeof(r) == 4 {
+    r1 := libc_syscall32(int32(trap), int32(a1), int32(a2), int32(a3), 0, 0, 0);
+    r = uintptr(r1);
+  } else {
+    r1 := libc_syscall64(int64(trap), int64(a1), int64(a2), int64(a3), 0, 0, 0);
+    r = uintptr(r1);
+  }
+  return r, 0, uintptr(GetErrno());
+}
+
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
+  var r uintptr;
+  if unsafe.Sizeof(r) == 4 {
+    r1 := libc_syscall32(int32(trap), int32(a1), int32(a2), int32(a3),
+                        int32(a4), int32(a5), int32(a6));
+    r = uintptr(r1);
+  } else {
+    r1 := libc_syscall64(int64(trap), int64(a1), int64(a2), int64(a3),
+                        int64(a4), int64(a5), int64(a6));
+    r = uintptr(r1);
+  }
+  return r, 0, uintptr(GetErrno());
+}
diff --git a/libgo/syscalls/syscall_linux.go b/libgo/syscalls/syscall_linux.go
new file mode 100644 (file)
index 0000000..bdb92c5
--- /dev/null
@@ -0,0 +1,188 @@
+// syscall_linux.go -- GNU/Linux specific syscall interface.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+func libc_ptrace(request int, pid Pid_t, addr uintptr, data *byte) _C_long __asm__ ("ptrace")
+
+var dummy *byte
+const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
+
+func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) {
+       // The peek requests are machine-size oriented, so we wrap it
+       // to retrieve arbitrary-length data.
+
+       var buf [sizeofPtr]byte;
+
+       // Leading edge.  PEEKTEXT/PEEKDATA don't require aligned
+       // access (PEEKUSER warns that it might), but if we don't
+       // align our reads, we might straddle an unmapped page
+       // boundary and not get the bytes leading up to the page
+       // boundary.
+       n := 0;
+       if addr % sizeofPtr != 0 {
+               SetErrno(0);
+               val := libc_ptrace(req, Pid_t(pid), addr - addr%sizeofPtr, nil);
+               if errno := GetErrno(); errno != 0 {
+                       return 0, errno;
+               }
+               *(*_C_long)(unsafe.Pointer(&buf[0])) = val;
+               n += copy(out, buf[addr%sizeofPtr:]);
+               out = out[n:];
+       }
+
+       // Remainder.
+       for len(out) > 0 {
+               // We use an internal buffer to gaurantee alignment.
+               // It's not documented if this is necessary, but we're paranoid.
+               SetErrno(0);
+               val := libc_ptrace(req, Pid_t(pid), addr+uintptr(n), nil);
+               if errno = GetErrno(); errno != 0 {
+                       return n, errno;
+               }
+               *(*_C_long)(unsafe.Pointer(&buf[0])) = val;
+               copied := copy(out, buf[0:]);
+               n += copied;
+               out = out[copied:];
+       }
+
+       return n, 0;
+}
+
+func PtracePeekText(pid int, addr uintptr, out []byte) (count int, errno int) {
+       return ptracePeek(_PTRACE_PEEKTEXT, pid, addr, out);
+}
+
+func PtracePeekData(pid int, addr uintptr, out []byte) (count int, errno int) {
+       return ptracePeek(_PTRACE_PEEKDATA, pid, addr, out);
+}
+
+func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, errno int) {
+       // As for ptracePeek, we need to align our accesses to deal
+       // with the possibility of straddling an invalid page.
+
+       // Leading edge.
+       n := 0;
+       if addr % sizeofPtr != 0 {
+               var buf [sizeofPtr]byte;
+               if libc_ptrace(peekReq, Pid_t(pid), addr - addr%sizeofPtr, &buf[0]) < 0 {
+                       return 0, GetErrno();
+               }
+               n += copy(buf[addr%sizeofPtr:], data);
+               word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&buf[0])))));
+               if libc_ptrace(pokeReq, Pid_t(pid), addr - addr%sizeofPtr, word) < 0 {
+                       return 0, GetErrno();
+               }
+               data = data[n:len(data)];
+       }
+
+       // Interior.
+       for uintptr(len(data)) > sizeofPtr {
+               word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&data[0])))));
+               if libc_ptrace(pokeReq, Pid_t(pid), addr+uintptr(n), word) < 0 {
+                       return n, GetErrno();
+               }
+               n += int(sizeofPtr);
+               data = data[sizeofPtr:len(data)];
+       }
+
+       // Trailing edge.
+       if len(data) > 0 {
+               var buf [sizeofPtr]byte;
+               if libc_ptrace(peekReq, Pid_t(pid), addr+uintptr(n), &buf[0]) < 0 {
+                       return n, GetErrno();
+               }
+               copy(buf[0:], data);
+               word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&buf[0])))));
+               if libc_ptrace(pokeReq, Pid_t(pid), addr+uintptr(n), word) < 0 {
+                       return n, GetErrno();
+               }
+               n += len(data);
+       }
+
+       return n, 0;
+}
+
+func PtracePokeText(pid int, addr uintptr, data []byte) (count int, errno int) {
+       return ptracePoke(_PTRACE_POKETEXT, _PTRACE_PEEKTEXT, pid, addr, data);
+}
+
+func PtracePokeData(pid int, addr uintptr, data []byte) (count int, errno int) {
+       return ptracePoke(_PTRACE_POKEDATA, _PTRACE_PEEKDATA, pid, addr, data);
+}
+
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (errno int) {
+       if libc_ptrace(_PTRACE_GETREGS, Pid_t(pid), 0, (*byte)(unsafe.Pointer(regsout))) < 0 {
+               return GetErrno();
+       } else {
+               return 0;
+       }
+}
+
+func PtraceSetRegs(pid int, regs *PtraceRegs) (errno int) {
+       if libc_ptrace(_PTRACE_SETREGS, Pid_t(pid), 0, (*byte)(unsafe.Pointer(regs))) < 0 {
+               return GetErrno();
+       } else {
+               return 0;
+       }
+}
+
+func PtraceSetOptions(pid int, options int) (errno int) {
+       if libc_ptrace(_PTRACE_SETOPTIONS, Pid_t(pid), 0, (*byte)(unsafe.Pointer(uintptr(options)))) < 0 {
+               return GetErrno();
+       } else {
+               return 0;
+       }
+}
+
+func PtraceGetEventMsg(pid int) (msg uint, errno int) {
+       var data _C_long;
+       if libc_ptrace(_PTRACE_GETEVENTMSG, Pid_t(pid), 0, (*byte)(unsafe.Pointer(&data))) < 0 {
+               errno = GetErrno();
+       }
+       msg = uint(data);
+       return;
+}
+
+func PtraceCont(pid int, signal int) (errno int) {
+       if libc_ptrace(_PTRACE_CONT, Pid_t(pid), 0, (*byte)(unsafe.Pointer(uintptr(signal)))) < 0 {
+               return GetErrno();
+       } else {
+               return 0;
+       }
+}
+
+func PtraceSingleStep(pid int) (errno int) {
+       if libc_ptrace(_PTRACE_SINGLESTEP, Pid_t(pid), 0, nil) < 0 {
+               return GetErrno();
+       } else {
+               return 0;
+       }
+}
+
+func PtraceAttach(pid int) (errno int) {
+       if libc_ptrace(_PTRACE_ATTACH, Pid_t(pid), 0, nil) < 0 {
+               return GetErrno();
+       } else {
+               return 0;
+       }
+}
+
+func PtraceDetach(pid int) (errno int) {
+       if libc_ptrace(_PTRACE_DETACH, Pid_t(pid), 0, nil) < 0 {
+               return GetErrno();
+       } else {
+               return 0;
+       }
+}
+
+func Tgkill(tgid int, tid int, sig int) (errno int) {
+       r1, r2, err := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid),
+                                uintptr(sig));
+       return int(err);
+}
diff --git a/libgo/syscalls/syscall_linux_386.go b/libgo/syscalls/syscall_linux_386.go
new file mode 100644 (file)
index 0000000..05e93c4
--- /dev/null
@@ -0,0 +1,17 @@
+// syscall_linux_386.go -- GNU/Linux 386 specific support
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const ARCH = "386"
+
+func (r *PtraceRegs) PC() uint64 {
+       return uint64(uint32(r.Eip));
+}
+
+func (r *PtraceRegs) SetPC(pc uint64) {
+       r.Eip = int32(pc);
+}
diff --git a/libgo/syscalls/syscall_linux_amd64.go b/libgo/syscalls/syscall_linux_amd64.go
new file mode 100644 (file)
index 0000000..a2ede00
--- /dev/null
@@ -0,0 +1,17 @@
+// syscall_linux_amd64.go -- GNU/Linux 386 specific support
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const ARCH = "amd64"
+
+func (r *PtraceRegs) PC() uint64 {
+       return r.Rip;
+}
+
+func (r *PtraceRegs) SetPC(pc uint64) {
+       r.Rip = pc;
+}
diff --git a/libgo/syscalls/syscall_stubs.go b/libgo/syscalls/syscall_stubs.go
new file mode 100644 (file)
index 0000000..d864902
--- /dev/null
@@ -0,0 +1,33 @@
+// syscall_stubs.go -- Stubs of the basic syscall interface.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package contains an interface to the low-level operating system
+// primitives.  The details vary depending on the underlying system.
+// Its primary use is inside other packages that provide a more portable
+// interface to the system, such as "os", "time" and "net".  Use those
+// packages rather than this one if you can.
+// For details of the functions and data types in this package consult
+// the manuals for the appropriate operating system.
+
+// These are stubs.
+
+package syscall
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
+  var r uintptr;
+  var i int;
+  i = -1;
+  r = uintptr(i);
+  return r, 0, uintptr(ENOSYS);
+}
+
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
+  var r uintptr;
+  var i int;
+  i = -1;
+  r = uintptr(i);
+  return r, 0, uintptr(ENOSYS);
+}
diff --git a/libgo/syscalls/syscall_unix.go b/libgo/syscalls/syscall_unix.go
new file mode 100644 (file)
index 0000000..3e9d293
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+var (
+       Stdin  = 0
+       Stdout = 1
+       Stderr = 2
+)
+
+func libc_uname(buf *Utsname) (errno int) __asm__("uname")
+
+func Uname(buf *Utsname) (errno int) {
+       r := libc_uname(buf)
+       if r < 0 {
+               errno = GetErrno()
+       }
+       return
+}
diff --git a/libgo/syscalls/sysfile_linux.go b/libgo/syscalls/sysfile_linux.go
new file mode 100644 (file)
index 0000000..3e77e90
--- /dev/null
@@ -0,0 +1,38 @@
+// sysfile_linux.go -- Linux specific file handling.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Support for basic Unix file operations.  This file simply
+// translates from Go data types to Unix data types, and handles
+// errno.  FIXME: This could probably be done mechanically.
+
+package syscall
+
+const OS = "linux"
+
+func libc_pread(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm__ ("pread64")
+func libc_pwrite(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm__ ("pwrite64")
+func libc_lseek64(int, Offset_t, int) Offset_t __asm__ ("lseek64")
+func libc_truncate64(path *byte, length Offset_t) int __asm__ ("truncate64")
+func libc_ftruncate64(fd int, length Offset_t) int __asm__ ("ftruncate64")
+func libc_setgroups(size Size_t, list *Gid_t) int __asm__ ("setgroups")
+
+func Sleep(nsec int64) (errno int) {
+       tv := NsecToTimeval(nsec);
+       n, err := Select(0, nil, nil, nil, &tv);
+       return err;
+}
+
+func Setgroups(gids []int) (errno int) {
+       if len(gids) == 0 {
+               return libc_setgroups(0, nil);
+       }
+
+       a := make([]Gid_t, len(gids));
+       for i, v := range gids {
+               a[i] = Gid_t(v);
+       }
+       return libc_setgroups(Size_t(len(a)), &a[0]);
+}
diff --git a/libgo/syscalls/sysfile_posix.go b/libgo/syscalls/sysfile_posix.go
new file mode 100644 (file)
index 0000000..4e44c5b
--- /dev/null
@@ -0,0 +1,422 @@
+// sysfile_posix.go -- POSIX File handling.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Support for basic Unix file operations.  This file simply
+// translates from Go data types to Unix data types, and handles
+// errno.  FIXME: This could probably be done mechanically.
+
+package syscall
+
+import "unsafe"
+
+func libc_open(name *byte, mode int, perm Mode_t) int __asm__ ("open");
+func libc_close(fd int) int __asm__ ("close");
+func libc_read(fd int, buf *byte, count Size_t) Ssize_t __asm__ ("read");
+func libc_write(fd int, buf *byte, count Size_t) Ssize_t __asm__ ("write");
+func libc_pipe(filedes *int) int __asm__("pipe");
+func libc_stat(name *byte, buf *Stat_t) int __asm__ ("stat");
+func libc_fstat(fd int, buf *Stat_t) int __asm__ ("fstat");
+func libc_lstat(name *byte, buf *Stat_t) int __asm__ ("lstat");
+func libc_unlink(name *byte) int __asm__ ("unlink");
+func libc_rmdir(name *byte) int __asm__ ("rmdir");
+func libc_fcntl(fd int, cmd int, arg int) int __asm__ ("fcntl");
+func libc_mkdir(name *byte, perm Mode_t) int __asm__ ("mkdir");
+func libc_dup(int) int __asm__ ("dup")
+func libc_gettimeofday(tv *Timeval, tz *byte) int __asm__ ("gettimeofday");
+func libc_select(int, *byte, *byte, *byte, *Timeval) int __asm__ ("select");
+func libc_chdir(name *byte) int __asm__ ("chdir");
+func libc_fchdir(int) int __asm__ ("fchdir");
+func libc_getcwd(*byte, Size_t) *byte __asm__ ("getcwd");
+func libc_link(oldpath *byte, newpath *byte) int __asm__ ("link");
+func libc_symlink(oldpath *byte, newpath *byte) int __asm__ ("symlink");
+func libc_readlink(*byte, *byte, Size_t) Ssize_t  __asm__ ("readlink");
+func libc_rename(oldpath *byte, newpath *byte) int __asm__ ("rename");
+func libc_chmod(path *byte, mode Mode_t) int __asm__ ("chmod");
+func libc_fchmod(fd int, mode Mode_t) int __asm__ ("fchmod");
+func libc_chown(path *byte, owner Uid_t, group Gid_t) int __asm__ ("chown");
+func libc_fchown(fd int, owner Uid_t, group Gid_t) int __asm__ ("fchown");
+func libc_lchown(path *byte, owner Uid_t, group Gid_t) int __asm__ ("lchown");
+func libc_utimes(filename *byte, times *[2]Timeval) int __asm__ ("utimes");
+func libc_getuid() Uid_t __asm__ ("getuid");
+func libc_geteuid() Uid_t __asm__ ("geteuid");
+func libc_getgid() Gid_t __asm__ ("getgid");
+func libc_getegid() Gid_t __asm__ ("getegid");
+func libc_getgroups(size int, list *Gid_t) int __asm__ ("getgroups");
+func libc_getpagesize() int __asm__ ("getpagesize");
+func libc_exit(status int) __asm__ ("exit")
+func libc_getpid() Pid_t __asm__ ("getpid")
+func libc_getppid() Pid_t __asm__ ("getppid")
+func libc_kill(Pid_t, int) int __asm__ ("kill")
+
+func Open(name string, mode int, perm uint32) (fd int, errno int) {
+  fd = libc_open(StringBytePtr(name), mode, Mode_t(perm));
+  if fd < 0 { errno = GetErrno() }
+  return;
+}
+
+func Creat(name string, perm uint32) (fd int, errno int) {
+  fd = libc_open(StringBytePtr(name), O_CREAT | O_WRONLY | O_TRUNC, Mode_t(perm));
+  if fd < 0 { errno = GetErrno() }
+  return;
+}
+
+func Close(fd int) (errno int) {
+  r := libc_close(fd);
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Read(fd int, p []byte) (n int, errno int) {
+  var _p0 *byte;
+  if len(p) > 0 { _p0 = &p[0]; }
+  r := libc_read(fd, _p0, Size_t(len(p)));
+  if r == -1 { errno = GetErrno() }
+  n = int(r);
+  return;
+}
+
+func Write(fd int, p []byte) (n int, errno int) {
+  var _p0 *byte;
+  if len(p) > 0 { _p0 = &p[0]; }
+  r := libc_write(fd, _p0, Size_t(len(p)));
+  if r == -1 { errno = GetErrno() }
+  n = int(r);
+  return;
+}
+
+func Pread(fd int, p []byte, offset int64) (n int, errno int) {
+  var _p0 *byte;
+  if len(p) > 0 { _p0 = &p[0]; }
+  r := libc_pread(fd, _p0, Size_t(len(p)), Offset_t(offset));
+  if r == -1 { errno = GetErrno() }
+  n = int(r);
+  return;
+}
+
+func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
+  var _p0 *byte;
+  if len(p) > 0 { _p0 = &p[0]; }
+  r := libc_pwrite(fd, _p0, Size_t(len(p)), Offset_t(offset));
+  if r == -1 { errno = GetErrno() }
+  n = int(r);
+  return;
+}
+
+func Seek(fd int, offset int64, whence int) (off int64, errno int) {
+  r := libc_lseek64(fd, Offset_t(offset), whence);
+  if r == -1 { errno = GetErrno() }
+  off = int64(r);
+  return;
+}
+
+func Pipe(p []int) (errno int) {
+  if len(p) != 2 {
+    return EINVAL;
+  }
+  var pp [2]int;
+  r := libc_pipe(&pp[0]);
+  if r < 0 {
+    errno = GetErrno();
+  }
+  p[0] = pp[0];
+  p[1] = pp[1];
+  return;
+}
+
+func Stat(name string, buf *Stat_t) (errno int) {
+  r := libc_stat(StringBytePtr(name), buf);
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Lstat(name string, buf *Stat_t) (errno int) {
+  r := libc_lstat(StringBytePtr(name), buf);
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Fstat(fd int, buf *Stat_t) (errno int) {
+  r := libc_fstat(fd, buf);
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Unlink(name string) (errno int) {
+  r := libc_unlink(StringBytePtr(name));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Rmdir(name string) (errno int) {
+  r := libc_rmdir(StringBytePtr(name));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Mkdir(path string, mode uint32) (errno int) {
+  r := libc_mkdir(StringBytePtr(path), Mode_t(mode));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Dup(oldfd int) (fd int, errno int) {
+       fd = libc_dup(oldfd)
+       if fd < 0 {
+               errno = GetErrno()
+       }
+       return
+}
+
+func Gettimeofday(tv *Timeval) (errno int) {
+  r := libc_gettimeofday(tv, nil);
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+type FdSet_t struct {
+       Fds_bits [(FD_SETSIZE + 63) / 64]int64;
+}
+
+func FDSet(fd int, set *FdSet_t) {
+       set.Fds_bits[fd / 64] |= (1 << (uint)(fd % 64))
+}
+
+func FDClr(fd int, set *FdSet_t) {
+       set.Fds_bits[fd / 64] &= ^(1 << (uint)(fd % 64))
+}
+
+func FDIsSet(fd int, set *FdSet_t) bool {
+       if set.Fds_bits[fd / 64] & (1 << (uint)(fd % 64)) != 0 {
+               return true
+       } else {
+               return false
+       }
+}
+
+func FDZero(set *FdSet_t) {
+       for i := 0; i < ((FD_SETSIZE + 63) / 64); i++ {
+               set.Fds_bits[i] = 0
+       }
+}
+
+func Select(nfds int, r *FdSet_t, w *FdSet_t, e *FdSet_t, timeout *Timeval) (n int, errno int) {
+  n = libc_select(nfds, (*byte)(unsafe.Pointer(r)),
+                 (*byte)(unsafe.Pointer(e)),
+                 (*byte)(unsafe.Pointer(e)), timeout);
+  if n < 0 { errno = GetErrno() }
+  return;
+}
+
+func Chdir(path string) (errno int) {
+  r := libc_chdir(StringBytePtr(path));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Fchdir(fd int) (errno int) {
+  r := libc_fchdir(int(fd));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+const ImplementsGetwd = true
+
+func Getwd() (ret string, errno int) {
+       for len := Size_t(4096); ; len *= 2 {
+               b := make([]byte, len);
+               p := libc_getcwd(&b[0], len);
+               if p != nil {
+                       i := 0;
+                       for b[i] != 0 {
+                               i++;
+                       }
+                       return string(b[0:i]), 0;
+               }
+               e := GetErrno();
+               if e != ERANGE {
+                       return "", e;
+               }
+       }
+}
+
+func Link(oldpath, newpath string) (errno int) {
+  r := libc_link(StringBytePtr(oldpath), StringBytePtr(newpath));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Symlink(oldpath, newpath string) (errno int) {
+  r := libc_symlink(StringBytePtr(oldpath), StringBytePtr(newpath));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Readlink(path string, buf []byte) (n int, errno int) {
+  var _p0 *byte;
+  if len(buf) > 0 { _p0 = &buf[0]; }
+  r := libc_readlink(StringBytePtr(path), _p0, Size_t(len(buf)));
+  if r < 0 { errno = GetErrno() }
+  n = int(r);
+  return;
+}
+
+func Rename(oldpath, newpath string) (errno int) {
+       r := libc_rename(StringBytePtr(oldpath), StringBytePtr(newpath));
+       if r < 0 { errno = GetErrno() }
+       return 
+}
+
+func Chmod(path string, mode uint32) (errno int) {
+  r := libc_chmod(StringBytePtr(path), Mode_t(mode));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Fchmod(fd int, mode uint32) (errno int) {
+  r := libc_fchmod(fd, Mode_t(mode));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Chown(path string, uid int, gid int) (errno int) {
+  r := libc_chown(StringBytePtr(path), Uid_t(uid), Gid_t(gid));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Lchown(path string, uid int, gid int) (errno int) {
+  r := libc_lchown(StringBytePtr(path), Uid_t(uid), Gid_t(gid));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Fchown(fd int, uid int, gid int) (errno int) {
+  r := libc_fchown(fd, Uid_t(uid), Gid_t(gid));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Truncate(path string, length int64) (errno int) {
+  r := libc_truncate64(StringBytePtr(path), Offset_t(length));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Ftruncate(fd int, length int64) (errno int) {
+  r := libc_ftruncate64(fd, Offset_t(length));
+  if r < 0 { errno = GetErrno() }
+  return;
+}
+
+func Utimes(path string, tv []Timeval) (errno int) {
+  if len(tv) != 2 {
+    return EINVAL;
+  }
+  r := libc_utimes(StringBytePtr(path),
+                  (*[2]Timeval)(unsafe.Pointer(&tv[0])));
+  if r < 0 {
+    errno = GetErrno();
+  }
+  return;
+}
+
+// Getuid returns the numeric user id of the caller.
+func Getuid() int {
+  return int(libc_getuid());
+}
+
+// Geteuid returns the numeric effective user id of the caller.
+func Geteuid() int {
+  return int(libc_geteuid());
+}
+
+// Getgid returns the numeric group id of the caller.
+func Getgid() int {
+  return int(libc_getgid());
+}
+
+// Getegid returns the numeric effective group id of the caller.
+func Getegid() int {
+  return int(libc_getegid());
+}
+
+// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
+func Getgroups() (gids []int, errno int) {
+       n := libc_getgroups(0, nil);
+       if n < 0 {
+               return nil, GetErrno();
+       }
+       if n == 0 {
+               return nil, 0;
+       }
+
+       // Sanity check group count.  Max is 1<<16 on Linux.
+       if n < 0 || n > 1<<20 {
+               return nil, EINVAL;
+       }
+
+       a := make([]Gid_t, n);
+       n = libc_getgroups(n, &a[0]);
+       if n < 0 {
+               return nil, GetErrno();
+       }
+       gids = make([]int, n);
+       for i, v := range a[0:n] {
+               gids[i] = int(v);
+       }
+       return;
+}
+
+func Getpagesize() int {
+       return libc_getpagesize();
+}
+
+func TimespecToNsec(ts Timespec) int64 {
+       return int64(ts.Sec)*1e9 + int64(ts.Nsec);
+}
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+       ts.Sec = Timespec_sec_t(nsec / 1e9);
+       ts.Nsec = Timespec_nsec_t(nsec % 1e9);
+       return;
+}
+
+func TimevalToNsec(tv Timeval) int64 {
+       return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3;
+}
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+       nsec += 999;    // round up to microsecond
+       tv.Sec = Timeval_sec_t(nsec/1e9);
+       tv.Usec = Timeval_usec_t(nsec%1e9 / 1e3);
+       return;
+}
+
+func Exit(code int) {
+       libc_exit(code);
+}
+
+func fcntl(fd, cmd, arg int) (val int, errno int) {
+  val = libc_fcntl(int(fd), int(cmd), int(arg));
+  if val == -1 { errno = GetErrno() }
+  return;
+}
+
+func Getpid() (pid int) {
+  return int(libc_getpid());
+}
+
+func Getppid() (ppid int) {
+  return int(libc_getppid());
+}
+
+func Kill(pid int, sig int) (errno int) {
+       r := libc_kill(Pid_t(pid), sig)
+       if r < 0 {
+               errno = GetErrno()
+       }
+       return
+}
diff --git a/libgo/syscalls/sysfile_rtems.go b/libgo/syscalls/sysfile_rtems.go
new file mode 100644 (file)
index 0000000..3768b6d
--- /dev/null
@@ -0,0 +1,34 @@
+// sysfile_rtems.go -- RTEMS specific file handling.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Support for basic Unix file operations.  This file simply
+// translates from Go data types to Unix data types, and handles
+// errno.  FIXME: This could probably be done mechanically.
+
+package syscall
+
+const (
+       OS = "rtems"
+       // No support for async I/O in RTEMS.
+       O_ASYNC = 0
+)
+
+func libc_pread(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm__ ("pread")
+func libc_pwrite(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm__ ("pwrite")
+func libc_lseek64(int, Offset_t, int) Offset_t __asm__ ("lseek")
+func libc_truncate64(path *byte, length Offset_t) int __asm__ ("truncate")
+func libc_ftruncate64(fd int, length Offset_t) int __asm__ ("ftruncate")
+func libc_nanosleep(req *Timespec, rem *Timespec) int __asm__ ("nanosleep")
+
+func Sleep(nsec int64) (errno int) {
+       errno = 0
+       ts := NsecToTimespec(nsec)
+       r := libc_nanosleep(&ts, nil)
+       if r < 0 {
+               errno = GetErrno()
+       }
+       return
+}
diff --git a/libgo/testsuite/Makefile.am b/libgo/testsuite/Makefile.am
new file mode 100644 (file)
index 0000000..8c6249d
--- /dev/null
@@ -0,0 +1,21 @@
+## 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`
+
+# When running the tests we set GCC_EXEC_PREFIX to the install tree so that
+# files that have already been installed there will be found.  The -B option
+# overrides it, so use of GCC_EXEC_PREFIX will not result in using GCC files
+# from the install tree.
+
+AM_RUNTESTFLAGS = "TEST_GCC_EXEC_PREFIX=$(libdir)/gcc"
+
+CLEANFILES = *.log *.sum
diff --git a/libgo/testsuite/Makefile.in b/libgo/testsuite/Makefile.in
new file mode 100644 (file)
index 0000000..1c6d18d
--- /dev/null
@@ -0,0 +1,438 @@
+# 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)/../config/depstand.m4 \
+       $(top_srcdir)/../config/lead-dot.m4 \
+       $(top_srcdir)/../config/multi.m4 \
+       $(top_srcdir)/../config/override.m4 \
+       $(top_srcdir)/../config/unwind_ipinfo.m4 \
+       $(top_srcdir)/config/go.m4 $(top_srcdir)/config/libtool.m4 \
+       $(top_srcdir)/config/ltoptions.m4 \
+       $(top_srcdir)/config/ltsugar.m4 \
+       $(top_srcdir)/config/ltversion.m4 \
+       $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.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@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+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@
+GOC = @GOC@
+GOCFLAGS = @GOCFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBFFI = @LIBFFI@
+LIBFFIINCS = @LIBFFIINCS@
+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@
+OBJCOPY = @OBJCOPY@
+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@
+SPLIT_STACK = @SPLIT_STACK@
+STRINGOPS_FLAG = @STRINGOPS_FLAG@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_FLAGS = @WARN_FLAGS@
+WERROR = @WERROR@
+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@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
+exec_prefix = @exec_prefix@
+glibgo_prefixdir = @glibgo_prefixdir@
+glibgo_toolexecdir = @glibgo_toolexecdir@
+glibgo_toolexeclibdir = @glibgo_toolexeclibdir@
+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@
+libtool_VERSION = @libtool_VERSION@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+multi_basedir = @multi_basedir@
+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@
+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`
+
+
+# When running the tests we set GCC_EXEC_PREFIX to the install tree so that
+# files that have already been installed there will be found.  The -B option
+# overrides it, so use of GCC_EXEC_PREFIX will not result in using GCC files
+# from the install tree.
+AM_RUNTESTFLAGS = "TEST_GCC_EXEC_PREFIX=$(libdir)/gcc"
+CLEANFILES = *.log *.sum
+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/libgo/testsuite/config/default.exp b/libgo/testsuite/config/default.exp
new file mode 100644 (file)
index 0000000..c82d658
--- /dev/null
@@ -0,0 +1,17 @@
+#   Copyright (C) 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib "standard.exp"
diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest
new file mode 100755 (executable)
index 0000000..13211d0
--- /dev/null
@@ -0,0 +1,329 @@
+#!/bin/sh
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Using all the *_test.go files in the current directory, write out a file
+# _testmain.go that runs all its tests. Compile everything and run the
+# tests.
+# If files are named on the command line, use them instead of *_test.go.
+
+# Makes egrep,grep work better in general if we put them
+# in ordinary C mode instead of what the current language is.
+unset LANG
+export LC_ALL=C
+export LC_CTYPE=C
+
+GC=${GC:-gccgo}
+GL=${GL:-${GC-gccgo}}
+GOLIBS=
+export GC GL GOLIBS
+
+# srcdir is where the source files are found.  basedir is where the
+# source file paths are relative to.
+# gofiles are the test files.  pkgfiles are the source files.
+srcdir=.
+basedir=.
+gofiles=""
+pkgfiles=""
+loop=true
+keep=false
+prefix=
+dejagnu=no
+while $loop; do
+       case "x$1" in
+        x--srcdir)
+               srcdir=$2
+               shift
+               shift
+               ;;
+       x--srcdir=*)
+               srcdir=`echo $1 | sed -e 's/^--srcdir=//'`
+               shift
+               ;;
+        x--basedir)
+               basedir=$2
+               shift
+               shift
+               ;;
+       x--basedir=*)
+               basedir=`echo $1 | sed -e 's/^--basedir=//'`
+               shift
+               ;;
+       x--prefix)
+               prefix=$2
+               shift
+               shift
+               ;;
+       x--prefix=*)
+               prefix=`echo $1 | sed -e 's/^--prefix=//'`
+               shift
+               ;;
+       x--keep)
+               keep=true
+                shift
+               ;;
+       x--pkgfiles)
+               pkgfiles=$2
+               shift
+               shift
+               ;;
+       x--pkgfiles=*)
+               pkgfiles=`echo $1 | sed -e 's/^--pkgfiles=//'`
+               shift
+               ;;
+       x--dejagnu)
+               dejagnu=$2
+               shift
+               shift
+               ;;
+       x--dejagnu=*)
+               dejagnu=`echo $1 | sed -e 's/^--dejagnu=//'`
+               shift
+               ;;
+       x-*)
+               loop=false
+               ;;
+       x)
+               loop=false
+               ;;
+       *)
+               gofiles="$gofiles $1"
+               shift
+               ;;
+       esac
+done
+
+DIR=gotest$$
+rm -rf $DIR
+mkdir $DIR
+
+cd $DIR
+
+if test $keep = false; then
+  trap "cd ..; rm -rf $DIR" 0 1 2 3 14 15
+else
+  trap "cd ..; echo Keeping $DIR" 0 1 2 3 14 15
+fi
+
+case "$srcdir" in
+       /*)
+               ;;
+       *)
+               srcdir="../$srcdir"
+                ;;
+esac
+
+SRCDIR=$srcdir
+export SRCDIR
+
+case "$basedir" in
+       /*)
+               ;;
+       *)
+               basedir="../$basedir"
+                ;;
+esac
+
+# Link all the files/directories in srcdir into our working directory,
+# so that the tests do not have to refer to srcdir to find test data.
+ln -s $srcdir/* .
+
+# Copy the .go files because io/utils_test.go expects a regular file.
+case "x$gofiles" in
+x)
+       case "x$pkgfiles" in
+       x)
+               for f in `cd $srcdir; ls *.go`; do
+                   rm -f $f;
+                   cp $srcdir/$f .
+               done
+               ;;
+       *)
+               for f in $pkgfiles; do
+                   if test -f $basedir/$f; then
+                       b=`basename $f`
+                       rm -f $b
+                       cp $basedir/$f $b
+                   elif test -f ../$f; then
+                       b=`basename $f`
+                       rm -f $b
+                       cp ../$f $b
+                   else
+                       echo "file $f not found" 1>&2
+                       exit 1
+                   fi
+               done
+               for f in `cd $srcdir; ls *_test.go`; do
+                   rm -f $f
+                   cp $srcdir/$f .
+               done
+               ;;
+       esac
+       ;;
+*)
+       for f in $gofiles; do
+           b=`basename $f`
+           rm -f $b
+           cp $basedir/$f $b
+       done
+       case "x$pkgfiles" in
+       x)
+               for f in `cd $srcdir; ls *.go | grep -v *_test.go`; do
+                   rm -f $f
+                   cp $srcdir/$f .
+               done
+               ;;
+       *)
+               for f in $pkgfiles; do
+                   if test -f $basedir/$f; then
+                       b=`basename $f`
+                       rm -f $b
+                       cp $basedir/$f $b
+                   elif test -f ../$f; then
+                       b=`basename $f`
+                       rm -f $b
+                       cp ../$f $b
+                   else
+                       echo "file $f not found" 1>&2
+                       exit 1
+                   fi
+               done
+               ;;
+       esac
+       ;;
+esac
+
+# Some tests expect the _obj directory created by the gc Makefiles.
+mkdir _obj
+
+# Some tests expect the _test directory created by the gc Makefiles.
+mkdir _test
+
+case "x$gofiles" in
+x)
+       gofiles=$(echo -n $(ls *_test.go 2>/dev/null))
+esac
+
+case "x$gofiles" in
+x)
+       echo 'no test files found' 1>&2
+       exit 1
+esac
+
+# Run any commands given in sources, like
+#   // gotest: $GC foo.go
+# to build any test-only dependencies.
+holdGC="$GC"
+GC="$GC -g -c -I ."
+sed -n 's/^\/\/ gotest: //p' $gofiles | sh
+GC="$holdGC"
+
+case "x$pkgfiles" in
+x)
+       pkgbasefiles=$(echo -n $(ls *.go | grep -v _test.go 2>/dev/null))
+       ;;
+*)
+       for f in $pkgfiles; do
+           pkgbasefiles="$pkgbasefiles `basename $f`"
+       done
+       ;;
+esac
+
+case "x$pkgfiles" in
+x)
+       echo 'no source files found' 1>&2
+       exit 1
+       ;;
+esac
+
+# Split $gofiles into external gofiles (those in *_test packages)
+# and internal ones (those in the main package).
+xgofiles=$(echo $(grep '^package[      ]' $gofiles /dev/null | grep ':.*_test' | sed 's/:.*//'))
+gofiles=$(echo $(grep '^package[       ]' $gofiles /dev/null | grep -v ':.*_test' | sed 's/:.*//'))
+
+# External $O file
+xofile=""
+havex=false
+if [ "x$xgofiles" != "x" ]; then
+       xofile="_xtest_.o"
+       havex=true
+fi
+
+set -e
+
+package=`echo ${srcdir} | sed -e 's|^.*libgo/go/||'`
+
+prefixarg=
+if test -n "$prefix"; then
+       prefixarg="-fgo-prefix=$prefix"
+fi
+
+$GC -g $prefixarg -c -I . -o _gotest_.o $gofiles $pkgbasefiles
+if $havex; then
+       mkdir -p `dirname $package`
+       cp _gotest_.o `dirname $package`/lib`basename $package`.a
+       $GC -g -c -I . -o $xofile $xgofiles
+fi
+
+# They all compile; now generate the code to call them.
+{
+       # test functions are named TestFoo
+       # the grep -v eliminates methods and other special names
+       # that have multiple dots.
+       pattern='Test([^a-z].*)?'
+       tests=$(nm -s _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
+       if [ "x$tests" = x ]; then
+               echo 'gotest: warning: no tests matching '$pattern in _gotest_.o $xofile 1>&2
+               exit 2
+       fi
+
+       # package spec
+       echo 'package main'
+       echo
+       # imports
+       if echo "$tests" | egrep -v '_test\.' >/dev/null; then
+               echo 'import "./_gotest_"'
+       fi
+       if $havex; then
+               echo 'import "./_xtest_"'
+       fi
+       if [ $package != "testing" ]; then
+               echo 'import "testing"'
+               echo 'import __regexp__ "regexp"' # rename in case tested package is called regexp
+       fi
+       # test array
+       echo
+       echo 'var tests = []testing.InternalTest {'
+       for i in $tests
+       do
+               echo '  { "'$i'", '$i' },'
+       done
+       echo '}'
+       # body
+       echo
+       echo 'func main() {'
+       echo '  testing.Main(__regexp__.MatchString, tests)'
+       echo '}'
+}>_testmain.go
+
+case "x$dejagnu" in
+xno)
+       ${GC} -g -c _testmain.go
+       ${GL} *.o ${GOLIBS}
+       ./a.out "$@"
+       ;;
+xyes)
+       # This is the only file which is optionally made.
+       # All others are overwritten on copying/building,
+       # but this may remain and cause conflicts if not
+       # deleted.
+       rm -rf ../testsuite/_xtest_.o
+       cp *.o _testmain.go ../testsuite
+       cd ../testsuite
+       $MAKE check RUNTESTFLAGS="$RUNTESTFLAGS GOTEST_TMPDIR=$DIR"
+       # Useful when using make check-target-libgo
+       cat libgo.log >> libgo-all.log
+       cat libgo.sum >> libgo-all.sum
+       ;;
+esac
diff --git a/libgo/testsuite/lib/libgo.exp b/libgo/testsuite/lib/libgo.exp
new file mode 100644 (file)
index 0000000..e4be342
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright (C) 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a]
+if {$gccdir != ""} {
+    set gccdir [file dirname $gccdir]
+}
+set GO_UNDER_TEST "$gccdir/gccgo -B$gccdir/"
+set TESTING_IN_BUILD_TREE 1
+
+proc go_maybe_build_wrapper { args } {
+    libgo_maybe_build_wrapper $args
+}
+
+# DejaGnu does not have proper library search paths for load_lib.
+# We have to explicitly load everything that go.exp wants to load.
+
+proc load_gcc_lib { filename } {
+    global srcdir loaded_libs
+
+    load_file $srcdir/../../gcc/testsuite/lib/$filename
+    set loaded_libs($filename) ""
+}
+
+load_gcc_lib prune.exp
+load_gcc_lib target-libpath.exp
+load_gcc_lib wrapper.exp
+load_gcc_lib gcc-defs.exp
+load_gcc_lib go.exp
+
+proc libgo_init { args } {
+    go_init $args
+}
diff --git a/libgo/testsuite/libgo.testmain/testmain.exp b/libgo/testsuite/libgo.testmain/testmain.exp
new file mode 100644 (file)
index 0000000..318ad49
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (C) 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib libgo.exp
+
+lappend options "additional_flags=-I. -w -g"
+lappend ld_options "ldflags=-lgotesting"
+
+if [istarget "*-*-rtems*"] {
+    global options
+
+    verbose -log "Executing on host: tar cf FilesystemImage -h -C \
+                         $tool_root_dir/$tool/${GOTEST_TMPDIR} ." 
+    if [catch "exec tar cf FilesystemImage -h -C \
+                        $tool_root_dir/$tool/${GOTEST_TMPDIR} ." error] {
+       perror "Error during tar of local filesystem: $error"
+       exit 1
+    }
+
+    verbose -log "Executing on host: ${RTEMS_BIN2C} FilesystemImage FilesystemImage"
+    if [catch "exec ${RTEMS_BIN2C} FilesystemImage FilesystemImage" error] {
+       perror "Error when creating FilesystemImage source file: $error"
+       exit 1
+    }
+    set comp_output [target_compile "${RTEMS_LIBGO_INIT}" \
+                        "./rtems_libgo_init.o" "object" $options]
+    if ![ string match "" $comp_output ] {
+       verbose -log $comp_output
+       exit 1
+    }
+}
+
+set object_files [glob -nocomplain "*.o"]
+regsub $gluefile $object_files "" object_files
+
+lappend options $ld_options
+
+set comp_output [go_target_compile "$object_files _testmain.go" \
+                        "./a.exe" "executable" $options]
+if ![ string match "" $comp_output ] {
+    verbose -log $comp_output
+    exit 1
+}
+
+libgo_load "./a.exe" "" ""